libidx
/home/rex/ebltrunk/core/libidx/include/geometry.hpp
00001 /***************************************************************************
00002  *   Copyright (C) 2008 by Pierre Sermanet *
00003  *   pierre.sermanet@gmail.com *
00004  *   All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Redistribution under a license not approved by the Open Source
00014  *       Initiative (http://www.opensource.org) must display the
00015  *       following acknowledgement in all advertising material:
00016  *        This product includes software developed at the Courant
00017  *        Institute of Mathematical Sciences (http://cims.nyu.edu).
00018  *     * The names of the authors may not be used to endorse or promote products
00019  *       derived from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00023  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00024  * DISCLAIMED. IN NO EVENT SHALL ThE AUTHORS BE LIABLE FOR ANY
00025  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00028  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00029  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  ***************************************************************************/
00032 
00033 #ifndef GEOMETRY_HPP_
00034 #define GEOMETRY_HPP_
00035 
00036 #include <math.h>
00037 #include "numerics.h"
00038 
00039 namespace ebl {
00040   
00042   // rect
00043 
00044   template <typename T>
00045   rect<T>::rect(T h0_, T w0_, T height_, T width_)
00046     : h0(h0_), w0(w0_), height(height_), width(width_) {
00047   }
00048   
00049   template <typename T>
00050   rect<T>::rect() : h0(0), w0(0), height(0), width(0) {
00051   }
00052   
00053   template <typename T>
00054   rect<T>::rect(const rect<T> &r)
00055   : h0(r.h0), w0(r.w0), height(r.height), width(r.width) {
00056   }
00057 
00058   template <typename T>
00059   rect<T>::~rect() {
00060   }
00061 
00062   template <typename T>
00063   T rect<T>::h1() const {
00064     return h0 + height;
00065   }
00066 
00067   template <typename T>
00068   T rect<T>::w1() const {
00069     return w0 + width;
00070   }
00071 
00072   template <typename T>
00073   float rect<T>::hcenter() const {
00074     return h0 + height / (float) 2.0;
00075   }
00076 
00077   template <typename T>
00078   float rect<T>::wcenter() const {
00079     return w0 + width / (float) 2.0;
00080   }
00081 
00082   template <typename T>
00083   T rect<T>::area() const {
00084     return height * width;
00085   }
00086   
00087   template <typename T>
00088   float rect<T>::center_distance(const rect<T> &r) const {
00089     float a = r.hcenter() - hcenter();
00090     float b = r.wcenter() - wcenter();
00091     return sqrt(a * a + b * b);
00092   }
00093 
00094   template <typename T>
00095   float rect<T>::center_hdistance(const rect<T> &r) const {
00096     if (height == 0) eblerror("unexpected 0 height");
00097     return fabs(hcenter() - r.hcenter()) / height;
00098   }
00099 
00100   template <typename T>
00101   float rect<T>::center_wdistance(const rect<T> &r) const {
00102     if (width == 0) eblerror("unexpected 0 width");
00103     return fabs(wcenter() - r.wcenter()) / width;
00104   }
00105 
00106   template <typename T>
00107   T rect<T>::intersection_area(const rect<T> &r) const {
00108     // check height intersection exists
00109     T nh0 = (std::max)(h0, r.h0);
00110     T nh1 = (std::min)(h0 + height, r.h0 + r.height);
00111     if (nh0 >= nh1) // empty intersection
00112       return (T) 0;
00113     // check width intersection exists
00114     T nw0 = (std::max)(w0, r.w0);
00115     T nw1 = (std::min)(w0 + width, r.w0 + r.width);
00116     if (nw0 >= nw1) // empty intersection
00117       return (T) 0;
00118     // intersection exists
00119     return (nh1 - nh0)  * (nw1 - nw0);
00120   }
00121   
00122   template <typename T>
00123   T rect<T>::union_area(const rect<T> &r) const {
00124     return area() + r.area() - intersection_area(r);
00125   }
00126   
00127   template <typename T>
00128   float rect<T>::match(const rect<T> &r) const {
00129     float u = (float) union_area(r);
00130     if (u == 0) return 0;
00131     return intersection_area(r) / u;
00132   }
00133 
00134   template <typename T>
00135   float rect<T>::min_match(const rect<T> &r) {
00136     float a1 = (float) area(), a2 = (float) r.area();
00137     if (a1 == 0 && a2 == 0) return 0;
00138     return intersection_area(r) / std::min(a1, a2);
00139   }
00140 
00141   template <typename T>
00142   bool rect<T>::overlap(const rect<T> &r) const {
00143     if (((h0 <= r.h0 + r.height) && (h0 + height >= r.h0)) &&
00144         ((w0 <= r.w0 + r.width) && (w0 + width >= r.w0)))
00145       return true;
00146     return false;
00147   }
00148 
00149   template <typename T>
00150   float rect<T>::overlap_ratio(const rect<T> &r) const {
00151     T area1 = height * width;
00152     T inter = intersection_area(r);
00153     if (area1 == 0) return 0;
00154     return inter / (float) area1;
00155   }
00156   
00157   template <typename T>
00158   bool rect<T>::min_overlap(const rect<T> &r, float minarea) const {
00159     T area1 = height * width;
00160     T area2 = r.height * r.width;
00161     T inter = intersection_area(r);
00162     float min_area =  (std::min)(area1, area2);
00163     if (min_area == 0) return 0;
00164     if ((inter / min_area) > minarea)
00165       return true;
00166     return false;
00167   }
00168   
00169   template <typename T>
00170   float rect<T>::min_overlap(const rect<T> &r) const {
00171     T area1 = height * width;
00172     T area2 = r.height * r.width;
00173     T inter = intersection_area(r);
00174     float min_area = (float) (std::min)(area1, area2);
00175     if (min_area == 0) return 0;
00176     return inter / min_area;
00177   }
00178   
00179   template <typename T>
00180   bool rect<T>::min_overlap(const rect<T> &r, float hmin, float wmin) const {
00181     if (((h0 <= r.h0 + r.height) && (h0 + height >= r.h0)) &&
00182         ((w0 <= r.w0 + r.width) && (w0 + width >= r.w0))) {
00183       // there is overlap, now check how much is authorized.
00184       T hoverlap = std::min(h0 + height, r.h0 + r.height)
00185         - std::min(h0, r.h0);
00186       T woverlap = std::min(w0 + width, r.w0 + r.width) - std::max(w0, r.w0);
00187       float min_height = (float) std::min(height, r.height);
00188       float min_width = (float) std::min(width, r.width);
00189       if (min_height == 0 || min_width == 0) return true;
00190       float hratio = hoverlap / (float) std::min(height, r.height);
00191       float wratio = woverlap / (float) std::min(width, r.width);
00192       if (hratio >= hmin || wratio >= wmin)
00193         return true;
00194     }
00195     return false;
00196   }
00197   
00198   template <typename T>
00199   bool rect<T>::is_within(const rect<T> &r) {
00200     if (((h0 >= r.h0) && (h0 + height <= r.h0 + r.height)) &&
00201         ((w0 >= r.w0) && (w0 + width <= r.w0 + r.width)))
00202       return true;
00203     return false;
00204   }
00205   
00206   template <typename T>
00207   void rect<T>::scale_centered(float sh, float sw) {
00208     T addh = (T) (height * ((float)sh - (float)1.0));
00209     T addw = (T) (width * ((float)sw - (float)1.0));
00210     h0 -= (T) (addh / (float)2);
00211     w0 -= (T) (addw / (float)2);
00212     height += addh;
00213     width += addw;
00214   }
00215   
00216   template <typename T>
00217   void rect<T>::scale_width(float woverh) {
00218     float addw = height * woverh - width;
00219     w0 -= (T) addw/2;
00220     width += (T) addw;
00221   }
00222 
00223   template <typename T>
00224   void rect<T>::scale_height(float woverh) {
00225     float addh = width * woverh - height;
00226     h0 -= (T) addh/2;
00227     height += (T) addh;
00228   }
00229 
00230   template <typename T>
00231   float rect<T>::radius() {
00232     float a = h0 - hcenter();
00233     float b = w0 - wcenter();
00234     return sqrt(a * a + b * b);
00235   }
00236 
00237   template <typename T>
00238   void rect<T>::rotate(float alpha) {
00239     // convert alpha from degrees to radians
00240     alpha = (alpha / (float) 180) * PI;
00241     // center on rotation center
00242     float hc = hcenter(), wc = wcenter();
00243     float h = h0 - hc, w = w0 - wc;
00244     // rotate all 4 corners
00245     float h1 = h, w1 = w;
00246     float h2 = h + height, w2 = w;
00247     float h3 = h, w3 = w + width;
00248     float h4 = h + height, w4 = w + width;
00249     rotate_point(alpha, h1, w1);
00250     rotate_point(alpha, h2, w2);
00251     rotate_point(alpha, h3, w3);
00252     rotate_point(alpha, h4, w4);
00253     // take min/max of all points
00254     h0 = (T) (hc + std::min(h1, std::min(h2, std::min(h3, h4))));
00255     w0 = (T) (wc + std::min(w1, std::min(w2, std::min(w3, w4))));
00256     height = (T) (std::max(h1, std::max(h2, std::max(h3, h4))) - h0 + hc);
00257     width = (T) (std::max(w1, std::max(w2, std::max(w3, w4))) - w0 + wc);
00258   }
00259 
00260   template <typename T>
00261   void rect<T>::rotate_point(float alpha, float &h, float &w) {
00262     float d = sqrt(h * h + w * w);
00263     if (d == 0) // point in the center, do nothing
00264       return ;
00265     float beta = acos(w / d);
00266     if (h < 0) beta = -beta;
00267     float b = beta - alpha;
00268     h = sin(b) * d;
00269     w = cos(b) * d;
00270   }
00271 
00273   // operators
00274   
00275   template <typename T>
00276   std::string& operator<<(std::string& out, rect<T>& r) {
00277     out << "rect:<(" << r.h0 << "," << r.w0 << ")," << r.height;
00278     out << "x" << r.width << ">";
00279     return out;
00280   }
00281 
00282   template <typename T>
00283   std::string& operator<<(std::string& out, const rect<T>& r) {
00284     out << "rect:<(" << r.h0 << "," << r.w0 << ")," << r.height;
00285     out << "x" << r.width << ">";
00286     return out;
00287   }
00288 
00289   template <typename T>
00290   std::ostream& operator<<(std::ostream& out, rect<T>& r) {
00291     out << "rect:<(" << r.h0 << "," << r.w0 << ")," << r.height;
00292     out << "x" << r.width << ">";
00293     return out;
00294   }
00295 
00296   template <typename T>
00297   std::ostream& operator<<(std::ostream& out, const rect<T>& r) {
00298     out << "rect:<(" << r.h0 << "," << r.w0 << ")," << r.height;
00299     out << "x" << r.width << ">";
00300     return out;
00301   }
00302 
00303   template <typename T>
00304   rect<T> rect<T>::operator/(double d) {
00305     if (d == 0) eblerror("unexpected division by 0");
00306     rect<T> newr((T) (h0 / d), (T) (w0 / d),
00307               (T) (height / d), (T) (width / d));
00308     return newr;
00309   }
00310 
00311   template <typename T>
00312   rect<T> rect<T>::operator*(double d) {
00313     rect<T> newr((T) (h0 * d), (T) (w0 * d),
00314               (T) (height * d), (T) (width * d));
00315     return newr;
00316   }
00317 
00318   template <typename T> template <typename T2>
00319   rect<T> rect<T>::operator=(rect<T2> &r2) {
00320     h0 = (T) r2.h0;
00321     w0 = (T) r2.w0;
00322     height = (T) r2.height;
00323     width = (T) r2.width;
00324     return *this;
00325   }
00326 
00327   template <typename T>
00328   void rect<T>::shift(T h, T w) {
00329     h0 += h;
00330     w0 += w;
00331   }
00332 
00333 } // end namespace ebl
00334 
00335 #endif /* GEOMETRY_HPP_ */