00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef GEOM_UTIL_HPP
00026 #define GEOM_UTIL_HPP
00027
00028 #include <mapnik/envelope.hpp>
00029 #include <mapnik/vertex.hpp>
00030
00031 #include <boost/tuple/tuple.hpp>
00032
00033 #include <cmath>
00034
00035
00036 #ifdef __SUNPRO_CC
00037 using std::fabs;
00038 using std::sqrt;
00039 #endif
00040
00041 namespace mapnik
00042 {
00043 template <typename T>
00044 bool clip_test(T p,T q,double& tmin,double& tmax)
00045 {
00046 double r;
00047 bool result=true;
00048 if (p<0.0)
00049 {
00050 r=q/p;
00051 if (r>tmax) result=false;
00052 else if (r>tmin) tmin=r;
00053 }
00054 else if (p>0.0)
00055 {
00056 r=q/p;
00057 if (r<tmin) result=false;
00058 else if (r<tmax) tmax=r;
00059 } else if (q<0.0) result=false;
00060 return result;
00061 }
00062
00063 template <typename T,typename Image>
00064 bool clip_line(T& x0,T& y0,T& x1,T& y1,Envelope<T> const& box)
00065 {
00066 double tmin=0.0;
00067 double tmax=1.0;
00068 double dx=x1-x0;
00069 if (clip_test<double>(-dx,x0,tmin,tmax))
00070 {
00071 if (clip_test<double>(dx,box.width()-x0,tmin,tmax))
00072 {
00073 double dy=y1-y0;
00074 if (clip_test<double>(-dy,y0,tmin,tmax))
00075 {
00076 if (clip_test<double>(dy,box.height()-y0,tmin,tmax))
00077 {
00078 if (tmax<1.0)
00079 {
00080 x1=static_cast<T>(x0+tmax*dx);
00081 y1=static_cast<T>(y0+tmax*dy);
00082 }
00083 if (tmin>0.0)
00084 {
00085 x0+=static_cast<T>(tmin*dx);
00086 y0+=static_cast<T>(tmin*dy);
00087 }
00088 return true;
00089 }
00090 }
00091 }
00092 }
00093 return false;
00094 }
00095
00096 template <typename Iter>
00097 inline bool point_inside_path(double x,double y,Iter start,Iter end)
00098 {
00099 bool inside=false;
00100 double x0=boost::get<0>(*start);
00101 double y0=boost::get<1>(*start);
00102
00103 double x1,y1;
00104 while (++start!=end)
00105 {
00106 if ( boost::get<2>(*start) == SEG_MOVETO)
00107 {
00108 x0 = boost::get<0>(*start);
00109 y0 = boost::get<1>(*start);
00110 continue;
00111 }
00112 x1=boost::get<0>(*start);
00113 y1=boost::get<1>(*start);
00114
00115 if ((((y1 <= y) && (y < y0)) ||
00116 ((y0 <= y) && (y < y1))) &&
00117 ( x < (x0 - x1) * (y - y1)/ (y0 - y1) + x1))
00118 inside=!inside;
00119 x0=x1;
00120 y0=y1;
00121 }
00122 return inside;
00123 }
00124
00125 inline bool point_in_circle(double x,double y,double cx,double cy,double r)
00126 {
00127 double dx = x - cx;
00128 double dy = y - cy;
00129 double d2 = dx * dx + dy * dy;
00130 return (d2 <= r * r);
00131 }
00132
00133 template <typename T>
00134 inline T sqr(T x)
00135 {
00136 return x * x;
00137 }
00138
00139 inline double distance2(double x0,double y0,double x1,double y1)
00140 {
00141 double dx = x1 - x0;
00142 double dy = y1 - y0;
00143 return sqr(dx) + sqr(dy);
00144 }
00145
00146 inline double distance(double x0,double y0, double x1,double y1)
00147 {
00148 return sqrt(distance2(x0,y0,x1,y1));
00149 }
00150
00151 inline double point_to_segment_distance(double x, double y,
00152 double ax, double ay,
00153 double bx, double by)
00154 {
00155 double len2 = distance2(ax,ay,bx,by);
00156
00157 if (len2 < 1e-14)
00158 {
00159 return distance(x,y,ax,ay);
00160 }
00161
00162 double r = ((x - ax)*(bx - ax) + (y - ay)*(by -ay))/len2;
00163 if ( r < 0 )
00164 {
00165 return distance(x,y,ax,ay);
00166 }
00167 else if (r > 1)
00168 {
00169 return distance(x,y,bx,by);
00170 }
00171 double s = ((ay - y)*(bx - ax) - (ax - x)*(by - ay))/len2;
00172 return fabs(s) * sqrt(len2);
00173 }
00174
00175 template <typename Iter>
00176 inline bool point_on_path(double x,double y,Iter start,Iter end, double tol)
00177 {
00178 double x0=boost::get<0>(*start);
00179 double y0=boost::get<1>(*start);
00180 double x1,y1;
00181 while (++start != end)
00182 {
00183 if ( boost::get<2>(*start) == SEG_MOVETO)
00184 {
00185 x0 = boost::get<0>(*start);
00186 y0 = boost::get<1>(*start);
00187 continue;
00188 }
00189 x1=boost::get<0>(*start);
00190 y1=boost::get<1>(*start);
00191
00192 double distance = point_to_segment_distance(x,y,x0,y0,x1,y1);
00193 if (distance < tol)
00194 return true;
00195 x0=x1;
00196 y0=y1;
00197 }
00198 return false;
00199 }
00200
00201
00202 struct filter_in_box
00203 {
00204 Envelope<double> box_;
00205 explicit filter_in_box(const Envelope<double>& box)
00206 : box_(box) {}
00207
00208 bool pass(const Envelope<double>& extent) const
00209 {
00210 return extent.intersects(box_);
00211 }
00212 };
00213
00214 struct filter_at_point
00215 {
00216 coord2d pt_;
00217 explicit filter_at_point(const coord2d& pt)
00218 : pt_(pt) {}
00219 bool pass(const Envelope<double>& extent) const
00220 {
00221 return extent.contains(pt_);
00222 }
00223 };
00224 }
00225
00226 #endif //GEOM_UTIL_HPP