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