/home/andreas/src/svn/mapnik/include/mapnik/geom_util.hpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * 
00003  * This file is part of Mapnik (c++ mapping toolkit)
00004  *
00005  * Copyright (C) 2006 Artem Pavlenko
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020  *
00021  *****************************************************************************/
00022 
00023 //$Id: geom_util.hpp 39 2005-04-10 20:39:53Z pavlenko $
00024 
00025 #ifndef GEOM_UTIL_HPP
00026 #define GEOM_UTIL_HPP
00027 // stl
00028 #include <cmath>
00029 // boost
00030 #include <boost/tuple/tuple.hpp>
00031 // mapnik
00032 #include <mapnik/envelope.hpp>
00033 #include <mapnik/vertex.hpp>
00034 
00035 namespace mapnik
00036 {
00037     template <typename T>
00038     bool clip_test(T p,T q,double& tmin,double& tmax)
00039     {
00040         double r;
00041         bool result=true;
00042         if (p<0.0)
00043         {
00044             r=q/p;
00045             if (r>tmax) result=false;
00046             else if (r>tmin) tmin=r;
00047         }
00048         else if (p>0.0)
00049         {
00050             r=q/p;
00051             if (r<tmin) result=false;
00052             else if (r<tmax) tmax=r;
00053         } else if (q<0.0) result=false;
00054         return result;
00055     }
00056     
00057     template <typename T,typename Image>
00058     bool clip_line(T& x0,T& y0,T& x1,T& y1,Envelope<T> const& box)
00059     {
00060         double tmin=0.0;
00061         double tmax=1.0;
00062         double dx=x1-x0;
00063         if (clip_test<double>(-dx,x0,tmin,tmax))
00064         {
00065             if (clip_test<double>(dx,box.width()-x0,tmin,tmax))
00066             {
00067                 double dy=y1-y0;
00068                 if (clip_test<double>(-dy,y0,tmin,tmax))
00069                 {
00070                     if (clip_test<double>(dy,box.height()-y0,tmin,tmax))
00071                     {
00072                         if (tmax<1.0)
00073                         {
00074                             x1=static_cast<T>(x0+tmax*dx);
00075                             y1=static_cast<T>(y0+tmax*dy);
00076                         }
00077                         if (tmin>0.0)
00078                         {
00079                             x0+=static_cast<T>(tmin*dx);
00080                             y0+=static_cast<T>(tmin*dy);
00081                         }
00082                         return true;
00083                     }
00084                 }
00085             }
00086         }
00087         return false;
00088     }
00089     
00090     template <typename Iter> 
00091     inline bool point_inside_path(double x,double y,Iter start,Iter end)
00092     {
00093         bool inside=false;
00094         double x0=boost::get<0>(*start);
00095         double y0=boost::get<1>(*start);
00096         
00097         double x1,y1;
00098         while (++start!=end) 
00099         {
00100             if ( boost::get<2>(*start) == SEG_MOVETO)
00101             {
00102                 x0 = boost::get<0>(*start);
00103                 y0 = boost::get<1>(*start);
00104                 continue;
00105             }           
00106             x1=boost::get<0>(*start);
00107             y1=boost::get<1>(*start);
00108             
00109             if ((((y1 <= y) && (y < y0)) ||
00110                  ((y0 <= y) && (y < y1))) &&
00111                 ( x < (x0 - x1) * (y - y1)/ (y0 - y1) + x1))
00112                 inside=!inside;
00113             x0=x1;
00114             y0=y1;
00115         }
00116         return inside;
00117     }
00118 
00119     inline bool point_in_circle(double x,double y,double cx,double cy,double r)
00120     {
00121         double dx = x - cx;
00122         double dy = y - cy;
00123         double d2 = dx * dx + dy * dy;
00124         return (d2 <= r * r);
00125     }
00126     
00127     template <typename T>
00128     inline T sqr(T x)
00129     {
00130         return x * x;
00131     }
00132 
00133     inline double distance2(double x0,double y0,double x1,double y1)
00134     {
00135         double dx = x1 - x0;
00136         double dy = y1 - y0;
00137         return sqr(dx) + sqr(dy);
00138     }
00139     
00140     inline double distance(double x0,double y0, double x1,double y1)
00141     {
00142         return sqrt(distance2(x0,y0,x1,y1));
00143     }
00144     
00145     inline double point_to_segment_distance(double x, double y, 
00146                                             double ax, double ay, 
00147                                             double bx, double by)
00148     {
00149         double len2 = distance2(ax,ay,bx,by);
00150         
00151         if (len2 < 1e-14) 
00152         {
00153             return distance(x,y,ax,ay);
00154         }
00155         
00156         double r = ((x - ax)*(bx - ax) + (y - ay)*(by -ay))/len2;
00157         if ( r < 0 )
00158         {
00159             return distance(x,y,ax,ay);
00160         }
00161         else if (r > 1)
00162         {
00163             return distance(x,y,bx,by);
00164         }
00165         double s = ((ay - y)*(bx - ax) - (ax - x)*(by - ay))/len2;
00166         return fabs(s) * sqrt(len2);
00167     }
00168         
00169     template <typename Iter> 
00170     inline bool point_on_path(double x,double y,Iter start,Iter end, double tol)
00171     {
00172         double x0=boost::get<0>(*start);
00173         double y0=boost::get<1>(*start);
00174         double x1,y1;
00175         while (++start != end) 
00176         {
00177             if ( boost::get<2>(*start) == SEG_MOVETO)
00178             {
00179                 x0 = boost::get<0>(*start);
00180                 y0 = boost::get<1>(*start);
00181                 continue;
00182             }           
00183             x1=boost::get<0>(*start);
00184             y1=boost::get<1>(*start);
00185             
00186             double distance = point_to_segment_distance(x,y,x0,y0,x1,y1);
00187             if (distance < tol)
00188                 return true;
00189             x0=x1;
00190             y0=y1;
00191         }
00192         return false;
00193     }
00194     
00195     // filters
00196     struct filter_in_box
00197     {
00198         Envelope<double> box_;
00199         explicit filter_in_box(const Envelope<double>& box)
00200             : box_(box) {}
00201 
00202         bool pass(const Envelope<double>& extent) const
00203         {
00204             return extent.intersects(box_);
00205         }
00206     };
00207 
00208     struct filter_at_point
00209     {
00210         coord2d pt_;
00211         explicit filter_at_point(const coord2d& pt)
00212             : pt_(pt) {}
00213         bool pass(const Envelope<double>& extent) const
00214         {
00215             return extent.contains(pt_);
00216         }
00217     };
00218 }
00219 
00220 #endif //GEOM_UTIL_HPP

Generated on Thu Jul 19 17:59:26 2007 for Mapnik by  doxygen 1.4.7