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
00026 #ifndef GEOMETRY_HPP
00027 #define GEOMETRY_HPP
00028
00029
00030 #include <mapnik/vertex_vector.hpp>
00031 #include <mapnik/ctrans.hpp>
00032 #include <mapnik/geom_util.hpp>
00033
00034 #include <boost/shared_ptr.hpp>
00035 #include <boost/utility.hpp>
00036 #include <boost/ptr_container/ptr_vector.hpp>
00037
00038 namespace mapnik {
00039 enum GeomType {
00040 Point = 1,
00041 LineString = 2,
00042 Polygon = 3
00043 };
00044
00045 template <typename T>
00046 class geometry : private boost::noncopyable
00047 {
00048 public:
00049 typedef T vertex_type;
00050 typedef typename vertex_type::type value_type;
00051 public:
00052 geometry () {}
00053
00054 Envelope<double> envelope()
00055 {
00056 Envelope<double> result;
00057 double x,y;
00058 rewind(0);
00059 for (unsigned i=0;i<num_points();++i)
00060 {
00061 vertex(&x,&y);
00062 if (i==0)
00063 {
00064 result.init(x,y,x,y);
00065 }
00066 else
00067 {
00068 result.expand_to_include(x,y);
00069 }
00070 }
00071 return result;
00072 }
00073
00074 virtual int type() const=0;
00075 virtual bool hit_test(value_type x,value_type y, double tol) const=0;
00076 virtual void label_position(double *x, double *y) const=0;
00077 virtual void move_to(value_type x,value_type y)=0;
00078 virtual void line_to(value_type x,value_type y)=0;
00079 virtual unsigned num_points() const = 0;
00080 virtual unsigned vertex(double* x, double* y) const=0;
00081 virtual void rewind(unsigned) const=0;
00082 virtual void set_capacity(size_t size)=0;
00083 virtual ~geometry() {}
00084 };
00085
00086 template <typename T>
00087 class point : public geometry<T>
00088 {
00089 typedef geometry<T> geometry_base;
00090 typedef typename geometry<T>::vertex_type vertex_type;
00091 typedef typename geometry<T>::value_type value_type;
00092 private:
00093 vertex_type pt_;
00094 public:
00095 point() : geometry<T>() {}
00096
00097 int type() const
00098 {
00099 return Point;
00100 }
00101
00102 void label_position(double *x, double *y) const
00103 {
00104 *x = pt_.x;
00105 *y = pt_.y;
00106 }
00107
00108 void move_to(value_type x,value_type y)
00109 {
00110 pt_.x = x;
00111 pt_.y = y;
00112 }
00113
00114 void line_to(value_type ,value_type ) {}
00115
00116 unsigned num_points() const
00117 {
00118 return 1;
00119 }
00120
00121 unsigned vertex(double* x, double* y) const
00122 {
00123 *x = pt_.x;
00124 *y = pt_.y;
00125 return SEG_LINETO;
00126 }
00127
00128 void rewind(unsigned ) const {}
00129
00130 bool hit_test(value_type x,value_type y, double tol) const
00131 {
00132 return point_in_circle(pt_.x,pt_.y, x,y,tol);
00133 }
00134
00135 void set_capacity(size_t) {}
00136 virtual ~point() {}
00137 };
00138
00139 template <typename T, template <typename> class Container=vertex_vector2>
00140 class polygon : public geometry<T>
00141 {
00142 typedef geometry<T> geometry_base;
00143 typedef typename geometry<T>::vertex_type vertex_type;
00144 typedef typename geometry_base::value_type value_type;
00145 typedef Container<vertex_type> container_type;
00146 private:
00147 container_type cont_;
00148 mutable unsigned itr_;
00149 public:
00150 polygon()
00151 : geometry_base(),
00152 itr_(0)
00153 {}
00154
00155 int type() const
00156 {
00157 return Polygon;
00158 }
00159
00160 void label_position(double *x, double *y) const
00161 {
00162 unsigned size = cont_.size();
00163 if (size < 3)
00164 {
00165 cont_.get_vertex(0,x,y);
00166 return;
00167 }
00168
00169 double ai;
00170 double atmp = 0;
00171 double xtmp = 0;
00172 double ytmp = 0;
00173 double x0 =0;
00174 double y0 =0;
00175 double x1 =0;
00176 double y1 =0;
00177
00178 unsigned i,j;
00179 for (i = size-1,j = 0; j < size; i = j, ++j)
00180 {
00181 cont_.get_vertex(i,&x0,&y0);
00182 cont_.get_vertex(j,&x1,&y1);
00183 ai = x0 * y1 - x1 * y0;
00184 atmp += ai;
00185 xtmp += (x1 + x0) * ai;
00186 ytmp += (y1 + y0) * ai;
00187 }
00188 if (atmp != 0)
00189 {
00190 *x = xtmp/(3*atmp);
00191 *y = ytmp /(3*atmp);
00192 return;
00193 }
00194 *x=x0;
00195 *y=y0;
00196 }
00197
00198 void line_to(value_type x,value_type y)
00199 {
00200 cont_.push_back(x,y,SEG_LINETO);
00201 }
00202
00203 void move_to(value_type x,value_type y)
00204 {
00205 cont_.push_back(x,y,SEG_MOVETO);
00206 }
00207
00208 unsigned num_points() const
00209 {
00210 return cont_.size();
00211 }
00212
00213 unsigned vertex(double* x, double* y) const
00214 {
00215 return cont_.get_vertex(itr_++,x,y);
00216 }
00217
00218 void rewind(unsigned ) const
00219 {
00220 itr_=0;
00221 }
00222
00223 bool hit_test(value_type x,value_type y, double) const
00224 {
00225 return point_inside_path(x,y,cont_.begin(),cont_.end());
00226 }
00227
00228 void set_capacity(size_t size)
00229 {
00230 cont_.set_capacity(size);
00231 }
00232 virtual ~polygon() {}
00233 };
00234
00235 template <typename T, template <typename> class Container=vertex_vector2>
00236 class line_string : public geometry<T>
00237 {
00238 typedef geometry<T> geometry_base;
00239 typedef typename geometry_base::value_type value_type;
00240 typedef typename geometry<T>::vertex_type vertex_type;
00241 typedef Container<vertex_type> container_type;
00242 private:
00243 container_type cont_;
00244 mutable unsigned itr_;
00245 public:
00246 line_string()
00247 : geometry_base(),
00248 itr_(0)
00249 {}
00250
00251 int type() const
00252 {
00253 return LineString;
00254 }
00255 void label_position(double *x, double *y) const
00256 {
00257
00258 double x0=0;
00259 double y0=0;
00260 double x1=0;
00261 double y1=0;
00262
00263 unsigned size = cont_.size();
00264 if (size == 1)
00265 {
00266 cont_.get_vertex(0,x,y);
00267 }
00268 else if (size == 2)
00269 {
00270
00271 cont_.get_vertex(0,&x0,&y0);
00272 cont_.get_vertex(1,&x1,&y1);
00273 *x = 0.5 * (x1 + x0);
00274 *y = 0.5 * (y1 + y0);
00275 }
00276 else
00277 {
00278 double len=0.0;
00279 for (unsigned pos = 1; pos < size; ++pos)
00280 {
00281 cont_.get_vertex(pos-1,&x0,&y0);
00282 cont_.get_vertex(pos,&x1,&y1);
00283 double dx = x1 - x0;
00284 double dy = y1 - y0;
00285 len += sqrt(dx * dx + dy * dy);
00286 }
00287 double midlen = 0.5 * len;
00288 double dist = 0.0;
00289 for (unsigned pos = 1; pos < size;++pos)
00290 {
00291 cont_.get_vertex(pos-1,&x0,&y0);
00292 cont_.get_vertex(pos,&x1,&y1);
00293 double dx = x1 - x0;
00294 double dy = y1 - y0;
00295 double seg_len = sqrt(dx * dx + dy * dy);
00296 if (( dist + seg_len) >= midlen)
00297 {
00298 double r = (midlen - dist)/seg_len;
00299 *x = x0 + (x1 - x0) * r;
00300 *y = y0 + (y1 - y0) * r;
00301 break;
00302 }
00303 dist += seg_len;
00304 }
00305 }
00306 }
00307 void line_to(value_type x,value_type y)
00308 {
00309 cont_.push_back(x,y,SEG_LINETO);
00310 }
00311
00312 void move_to(value_type x,value_type y)
00313 {
00314 cont_.push_back(x,y,SEG_MOVETO);
00315 }
00316
00317 unsigned num_points() const
00318 {
00319 return cont_.size();
00320 }
00321
00322 unsigned vertex(double* x, double* y) const
00323 {
00324 return cont_.get_vertex(itr_++,x,y);
00325 }
00326
00327 void rewind(unsigned ) const
00328 {
00329 itr_=0;
00330 }
00331
00332 bool hit_test(value_type x,value_type y, double tol) const
00333 {
00334 return point_on_path(x,y,cont_.begin(),cont_.end(),tol);
00335 }
00336
00337 void set_capacity(size_t size)
00338 {
00339 cont_.set_capacity(size);
00340 }
00341 virtual ~line_string() {}
00342 };
00343
00344 typedef point<vertex2d> point_impl;
00345 typedef line_string<vertex2d,vertex_vector2> line_string_impl;
00346 typedef polygon<vertex2d,vertex_vector2> polygon_impl;
00347
00348 typedef geometry<vertex2d> geometry2d;
00349 typedef boost::shared_ptr<geometry2d> geometry_ptr;
00350 typedef boost::ptr_vector<geometry2d> geometry_containter;
00351 }
00352
00353 #endif //GEOMETRY_HPP