libosmscout  1.1.1
Geometry.h
Go to the documentation of this file.
1 #ifndef OSMSCOUT_UTIL_GEOMETRY_H
2 #define OSMSCOUT_UTIL_GEOMETRY_H
3 
4 /*
5  This source is part of the libosmscout library
6  Copyright (C) 2009 Tim Teulings
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Lesser General Public
10  License as published by the Free Software Foundation; either
11  version 2.1 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public
19  License along with this library; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22 
23 #include <algorithm>
24 #include <array>
25 #include <functional>
26 #include <list>
27 #include <unordered_map>
28 #include <utility>
29 #include <vector>
30 #include <tuple>
31 
33 
34 #include <osmscout/system/Assert.h>
35 #include <osmscout/system/Math.h>
37 
38 #include <osmscout/GeoCoord.h>
39 #include <osmscout/Point.h>
40 #include <osmscout/OSMScoutTypes.h>
41 
42 #include <osmscout/util/GeoBox.h>
43 #include <osmscout/util/Distance.h>
44 #include <osmscout/util/Bearing.h>
45 
46 namespace osmscout {
47 
61  inline double DegToRad(double deg)
62  {
63  return deg*M_PI/180.0;
64  }
65 
71  inline double RadToDeg(double rad)
72  {
73  return rad*180.0/M_PI;
74  }
75 
84  inline double AngleDiff(double a, double b)
85  {
86  double diff = std::abs(a - b);
87 
88  if (diff > M_PI) {
89  return 2 * M_PI - diff;
90  }
91 
92  return diff;
93  }
94 
106  template<typename N>
107  void GetBoundingBox(const std::vector<N>& nodes,
108  double& minLon,
109  double& maxLon,
110  double& minLat,
111  double& maxLat)
112  {
113  assert(!nodes.empty());
114 
115  minLon=nodes[0].GetLon();
116  maxLon=nodes[0].GetLon();
117  minLat=nodes[0].GetLat();
118  maxLat=nodes[0].GetLat();
119 
120  for (size_t i=1; i<nodes.size(); i++) {
121  minLon=std::min(minLon,nodes[i].GetLon());
122  maxLon=std::max(maxLon,nodes[i].GetLon());
123  minLat=std::min(minLat,nodes[i].GetLat());
124  maxLat=std::max(maxLat,nodes[i].GetLat());
125  }
126  }
127 
138  template< class InputIt >
139  void GetBoundingBox(const InputIt first,
140  const InputIt last,
141  GeoBox& boundingBox)
142  {
143  assert(first!=last);
144 
145  double minLon=first->GetLon();
146  double maxLon=minLon;
147  double minLat=first->GetLat();
148  double maxLat=minLat;
149 
150  for (InputIt i=first; i!=last; i++) {
151  minLon=std::min(minLon,i->GetLon());
152  maxLon=std::max(maxLon,i->GetLon());
153  minLat=std::min(minLat,i->GetLat());
154  maxLat=std::max(maxLat,i->GetLat());
155  }
156 
157  boundingBox.Set(GeoCoord(minLat,minLon),
158  GeoCoord(maxLat,maxLon));
159  }
160 
172  template<typename N>
173  void GetBoundingBox(const std::vector<N>& nodes,
174  GeoBox& boundingBox)
175  {
176  assert(!nodes.empty());
177 
178  double minLon=nodes[0].GetLon();
179  double maxLon=minLon;
180  double minLat=nodes[0].GetLat();
181  double maxLat=minLat;
182 
183  for (size_t i=1; i<nodes.size(); i++) {
184  minLon=std::min(minLon,nodes[i].GetLon());
185  maxLon=std::max(maxLon,nodes[i].GetLon());
186  minLat=std::min(minLat,nodes[i].GetLat());
187  maxLat=std::max(maxLat,nodes[i].GetLat());
188  }
189 
190  boundingBox.Set(GeoCoord(minLat,minLon),
191  GeoCoord(maxLat,maxLon));
192  }
193 
199  template<typename N>
200  bool LinesIntersect(const N& a1,
201  const N& a2,
202  const N& b1,
203  const N& b2)
204  {
205  if (a1.IsEqual(b1) ||
206  a1.IsEqual(b2) ||
207  a2.IsEqual(b1) ||
208  a2.IsEqual(b2)) {
209  return true;
210  }
211  if (a1.IsEqual(a2) &&
212  b1.IsEqual(b2)){
213  // two different zero size vectors can't intersects
214  return false;
215  }
216 
217  // denominator, see GetLineIntersection for more details
218  double denr=(b2.GetLat()-b1.GetLat())*(a2.GetLon()-a1.GetLon())-
219  (b2.GetLon()-b1.GetLon())*(a2.GetLat()-a1.GetLat());
220 
221  double ua_numr=(b2.GetLon()-b1.GetLon())*(a1.GetLat()-b1.GetLat())-
222  (b2.GetLat()-b1.GetLat())*(a1.GetLon()-b1.GetLon());
223  double ub_numr=(a2.GetLon()-a1.GetLon())*(a1.GetLat()-b1.GetLat())-
224  (a2.GetLat()-a1.GetLat())*(a1.GetLon()-b1.GetLon());
225 
226  if (denr==0.0) { // parallels
227  if (ua_numr==0.0 && ub_numr==0.0) {
228  // two lines are on one straight line, check the bounds
229  GeoBox aBox(GeoCoord(a1.GetLat(),a1.GetLon()),
230  GeoCoord(a2.GetLat(),a2.GetLon()));
231  GeoBox bBox(GeoCoord(b1.GetLat(),b1.GetLon()),
232  GeoCoord(b2.GetLat(),b2.GetLon()));
233 
234  return bBox.Includes(a1,false) ||
235  bBox.Includes(a2,false) ||
236  aBox.Includes(b1,false) ||
237  aBox.Includes(b2,false);
238  }
239 
240  return false;
241  }
242 
243  double ua=ua_numr/denr;
244  double ub=ub_numr/denr;
245 
246  return ua>=0.0 &&
247  ua<=1.0 &&
248  ub>=0.0 &&
249  ub<=1.0;
250  }
251 
257  template<typename N,typename I>
258  bool GetLineIntersection(const N& a1,
259  const N& a2,
260  const N& b1,
261  const N& b2,
262  I& intersection)
263  {
264  if (a1.IsEqual(b1) ||
265  a1.IsEqual(b2)){
266  intersection.Set(a1.GetLat(),a1.GetLon());
267  return true;
268  }
269  if (a2.IsEqual(b1) ||
270  a2.IsEqual(b2)) {
271  intersection.Set(a2.GetLat(),a2.GetLon());
272  return true;
273  }
274  if (a1.IsEqual(a2) &&
275  b1.IsEqual(b2)){
276  // two different zero size vectors can't intersects
277  return false;
278  }
279 
280  // for geographic, expect point.x=lon and point.y=lat
281 
282  // see https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
283  // and http://www.geeksforgeeks.org/orientation-3-ordered-points/
284 
285  // denominator < 0 : left angle
286  // denominator == 0 : parallels
287  // denominator > 0 : right angle
288  double denr=(b2.GetLat()-b1.GetLat())*(a2.GetLon()-a1.GetLon())-
289  (b2.GetLon()-b1.GetLon())*(a2.GetLat()-a1.GetLat());
290 
291  double ua_numr=(b2.GetLon()-b1.GetLon())*(a1.GetLat()-b1.GetLat())-
292  (b2.GetLat()-b1.GetLat())*(a1.GetLon()-b1.GetLon());
293  double ub_numr=(a2.GetLon()-a1.GetLon())*(a1.GetLat()-b1.GetLat())-
294  (a2.GetLat()-a1.GetLat())*(a1.GetLon()-b1.GetLon());
295 
296  if (denr==0.0) {
297  if (ua_numr==0.0 && ub_numr==0.0) {
298  // two lines are on one straight line, check the bounds
299  GeoBox aBox(GeoCoord(a1.GetLat(),a1.GetLon()),
300  GeoCoord(a2.GetLat(),a2.GetLon()));
301  GeoBox bBox(GeoCoord(b1.GetLat(),b1.GetLon()),
302  GeoCoord(b2.GetLat(),b2.GetLon()));
303  if (bBox.Includes(a1,false)){
304  intersection.Set(a1.GetLat(),a1.GetLon());
305  return true;
306  }
307  if (bBox.Includes(a2,false)){
308  intersection.Set(a2.GetLat(),a2.GetLon());
309  return true;
310  }
311  if (aBox.Includes(b1,false)){
312  intersection.Set(b1.GetLat(),b1.GetLon());
313  return true;
314  }
315  if (aBox.Includes(b2,false)){
316  intersection.Set(b2.GetLat(),b2.GetLon());
317  return true;
318  }
319 
320  return false;
321  }
322 
323  return false;
324  }
325 
326  double ua=ua_numr/denr;
327  double ub=ub_numr/denr;
328 
329  if (ua>=0.0 &&
330  ua<=1.0 &&
331  ub>=0.0 &&
332  ub<=1.0) {
333  intersection.Set(a1.GetLat()+ua*(a2.GetLat()-a1.GetLat()),
334  a1.GetLon()+ua*(a2.GetLon()-a1.GetLon()));
335  return true;
336  }
337 
338  return false;
339  }
340 
346  template<typename N>
347  bool GetLineIntersectionPixel(const N& a1,
348  const N& a2,
349  const N& b1,
350  const N& b2,
351  N& intersection)
352  {
353  if (a1.IsEqual(b1) ||
354  a1.IsEqual(b2)){
355  intersection.Set(a1.GetX(),a1.GetY());
356  return true;
357  }
358  if (a2.IsEqual(b1) ||
359  a2.IsEqual(b2)) {
360  intersection.Set(a2.GetX(),a2.GetY());
361  return true;
362  }
363  if (a1.IsEqual(a2) &&
364  b1.IsEqual(b2)){
365  // two different zero size vectors can't intersects
366  return false;
367  }
368 
369  double denr=(b2.GetY()-b1.GetY())*(a2.GetX()-a1.GetX())-
370  (b2.GetX()-b1.GetX())*(a2.GetY()-a1.GetY());
371 
372  double ua_numr=(b2.GetX()-b1.GetX())*(a1.GetY()-b1.GetY())-
373  (b2.GetY()-b1.GetY())*(a1.GetX()-b1.GetX());
374  double ub_numr=(a2.GetX()-a1.GetX())*(a1.GetY()-b1.GetY())-
375  (a2.GetY()-a1.GetY())*(a1.GetX()-b1.GetX());
376 
377  if (denr==0.0) {
378  // This gives currently false hits because of number resolution problems, if two lines are very
379  // close together and for example are part of a very details node curve intersections are detected.
380 
381  // FIXME: setup intersection
382  return ua_numr==0.0 && ub_numr==0.0;
383  }
384 
385  double ua=ua_numr/denr;
386  double ub=ub_numr/denr;
387 
388  if (ua>=0.0 &&
389  ua<=1.0 &&
390  ub>=0.0 &&
391  ub<=1.0) {
392  intersection.Set(a1.GetX()+ua*(a2.GetX()-a1.GetX()),
393  a1.GetY()+ua*(a2.GetY()-a1.GetY()));
394  return true;
395  }
396 
397  return false;
398  }
399 
400  template<typename N>
401  double DistanceSquare(const N& a,
402  const N& b)
403  {
404  double lonDelta=a.GetLon()-b.GetLon();
405  double latDelta=a.GetLat()-b.GetLat();
406 
407  return lonDelta*lonDelta+latDelta*latDelta;
408  }
409 
417 /*
418  template<typename N, typename M>
419  inline double IsLeft(const N& p0,
420  const N& p1,
421  const M& p2)
422  {
423  if ((p2.GetLat()==p0.GetLat() &&
424  p2.GetLon()==p0.GetLon()) ||
425  (p2.GetLat()==p1.GetLat() &&
426  p2.GetLon()==p1.GetLon())) {
427  return 0;
428  }
429 
430  return (p1.GetLon()-p0.GetLon())*(p2.GetLat()-p0.GetLat())-
431  (p2.GetLon()-p0.GetLon())*(p1.GetLat()-p0.GetLat());
432  }
433 
434  template<typename N, typename M>
435  inline bool IsCoordInArea(const N& point,
436  const std::vector<M>& nodes)
437  {
438  for (int i=0; i<(int)nodes.size()-1; i++) {
439  if (point.GetLat()==nodes[i].GetLat() &&
440  point.GetLon()==nodes[i].GetLon()) {
441  return true;
442  }
443  }
444 
445  int wn=0; // the winding number counter
446 
447  // loop through all edges of the polygon
448  for (int i=0; i<(int)nodes.size()-1; i++) { // edge from V[i] to V[i+1]
449  if (nodes[i].GetLat()<=point.GetLat()) { // start y <= P.y
450  if (nodes[i+1].GetLat()>point.GetLat()) { // an upward crossing
451  if (IsLeft(nodes[i],nodes[i+1],point) > 0) { // P left of edge
452  ++wn; // have a valid up intersect
453  }
454  }
455  }
456  else { // start y > P.y (no test needed)
457  if (nodes[i+1].GetLat()<=point.GetLat()) { // a downward crossing
458  if (IsLeft(nodes[i],nodes[i+1],point) < 0) { // P right of edge
459  --wn; // have a valid down intersect
460  }
461  }
462  }
463  }
464 
465  return wn!=0;
466  }*/
467 
475  template<typename N, typename M>
476  inline bool IsCoordInArea(const N& point,
477  const std::vector<M>& nodes)
478  {
479  size_t i;
480  size_t j;
481  bool c=false;
482 
483  for (i=0, j=nodes.size()-1; i<nodes.size(); j=i++) {
484  if (point.GetLat()==nodes[i].GetLat() &&
485  point.GetLon()==nodes[i].GetLon()) {
486  return true;
487  }
488 
489  if ((((nodes[i].GetLat()<=point.GetLat()) && (point.GetLat()<nodes[j].GetLat())) ||
490  ((nodes[j].GetLat()<=point.GetLat()) && (point.GetLat()<nodes[i].GetLat()))) &&
491  (point.GetLon()<(nodes[j].GetLon()-nodes[i].GetLon())*(point.GetLat()-nodes[i].GetLat())/(nodes[j].GetLat()-nodes[i].GetLat())+
492  nodes[i].GetLon())) {
493  c=!c;
494  }
495  }
496 
497  return c;
498  }
499 
507  template<typename N,typename M>
508  inline int GetRelationOfPointToArea(const N& point,
509  const std::vector<M>& nodes)
510  {
511  size_t i;
512  size_t j;
513  bool c=false;
514 
515  for (i=0, j=nodes.size()-1; i<nodes.size(); j=i++) {
516  if (point.GetLat()==nodes[i].GetLat() &&
517  point.GetLon()==nodes[i].GetLon()) {
518  return 0;
519  }
520 
521  if ((((nodes[i].GetLat()<=point.GetLat()) && (point.GetLat()<nodes[j].GetLat())) ||
522  ((nodes[j].GetLat()<=point.GetLat()) && (point.GetLat()<nodes[i].GetLat()))) &&
523  (point.GetLon()<(nodes[j].GetLon()-nodes[i].GetLon())*(point.GetLat()-nodes[i].GetLat())/(nodes[j].GetLat()-nodes[i].GetLat())+
524  nodes[i].GetLon())) {
525  c=!c;
526  }
527  }
528 
529  return c ? 1 : -1;
530  }
531 
536  template<typename N,typename M>
537  inline bool IsAreaCompletelyInArea(const std::vector<N>& a,
538  const std::vector<M>& b)
539  {
540  for (const auto& node : a) {
541  if (GetRelationOfPointToArea(node,b)<0) {
542  return false;
543  }
544  }
545 
546  return true;
547  }
548 
553  template<typename N,typename M>
554  inline bool IsAreaAtLeastPartlyInArea(const std::vector<N>& a,
555  const std::vector<M>& b,
556  const GeoBox& aBox,
557  const GeoBox& bBox)
558  {
559  if (!aBox.Intersects(bBox)){
560  return false;
561  }
562 
563  for (const auto& node : a) {
564  if (bBox.Includes(node, /*openInterval*/ false) && GetRelationOfPointToArea(node,b)>=0) {
565  return true;
566  }
567  }
568 
569  return false;
570  }
571 
576  template<typename N,typename M>
577  inline bool IsAreaAtLeastPartlyInArea(const std::vector<N>& a,
578  const std::vector<M>& b)
579  {
580  GeoBox aBox;
581  GeoBox bBox;
582  GetBoundingBox(a, aBox);
583  GetBoundingBox(b, bBox);
584 
585  return IsAreaAtLeastPartlyInArea(a,b,aBox,bBox);
586  }
587 
596  template<typename N,typename M>
597  inline bool IsAreaSubOfArea(const std::vector<N>& a,
598  const std::vector<M>& b)
599  {
600  for (const auto& node : a) {
601  int relPos=GetRelationOfPointToArea(node,b);
602 
603  if (relPos>0) {
604  return true;
605  }
606 
607  if (relPos<0) {
608  return false;
609  }
610  }
611 
612  return false;
613  }
614 
623  template<typename N,typename M>
624  inline bool IsAreaSubOfAreaQuorum(const std::vector<N>& a,
625  const std::vector<M>& b)
626  {
627  size_t pro=0;
628  size_t contra=0;
629  size_t count=0;
630 
631  for (const auto& node : a) {
632  int relPos=GetRelationOfPointToArea(node,b);
633 
634  ++count;
635 
636  if (relPos>0) {
637  ++pro;
638  }
639  else if (relPos<0) {
640  ++contra;
641  }
642 
643  if (count>=100 && double(pro)/20.0>double(contra)) {
644  return true;
645  }
646  }
647 
648  return double(pro)/20.0>double(contra);
649  }
650 
660  template<typename N,typename M>
661  inline bool IsAreaSubOfAreaOrSame(const std::vector<N>& a,
662  const std::vector<M>& b)
663  {
664  size_t pro=0;
665  size_t contra=0;
666  size_t count=0;
667 
668  pro=0;
669  contra=0;
670  count=0;
671 
672  for (const auto& node : a) {
673  int relPos=GetRelationOfPointToArea(node,b);
674 
675  ++count;
676 
677  if (relPos>0) {
678  ++pro;
679  }
680  else if (relPos<0) {
681  ++contra;
682  }
683 
684  if (count>=100 && pro/20>contra) {
685  return true;
686  }
687  }
688 
689  if (pro == 0 && contra == 0 && count > 0) {
690  return true;
691  }
692 
693  return pro/20.0>contra;
694  }
695 
705  template<typename N>
706  bool AreaIsSimple(std::vector<N> points)
707  {
708  if (points.size()<3) {
709  return false;
710  }
711 
712  points.push_back(points[0]);
713 
714  size_t edgesIntersect=0;
715 
716  for (size_t i=0; i<points.size()-1; i++) {
717  edgesIntersect=0;
718 
719  for (size_t j=i+1; j<points.size()-1; j++) {
720  if (LinesIntersect(points[i],
721  points[i+1],
722  points[j],
723  points[j+1])) {
724  edgesIntersect++;
725 
726  if (i==0) {
727  if (edgesIntersect>2) {
728  return false;
729  }
730  }
731  else {
732  if (edgesIntersect>1) {
733  return false;
734  }
735  }
736  }
737  }
738  }
739 
740  return true;
741  }
742 
752  template<typename N>
753  bool AreaIsSimple(const std::vector<std::pair<N,N> >& edges,
754  const std::vector<bool>& edgeStartsNewPoly)
755  {
756  size_t edgesIntersect=0;
757 
758  for (size_t i=0; i<edges.size(); i++) {
759  edgesIntersect=0;
760 
761  for (size_t j=i+1; j<edges.size(); j++) {
762  if (LinesIntersect(edges[i].first,
763  edges[i].second,
764  edges[j].first,
765  edges[j].second)) {
766  edgesIntersect++;
767 
768  // we check the first edge of a sole polygon against every
769  // other edge and expect to see 2 intersections for
770  // adjacent edges; polygon is complex if there are more
771  // intersections
772  if (edgeStartsNewPoly[i]) {
773  if (edgesIntersect>2) {
774  return false;
775  }
776  }
777 
778  // otherwise we check an edge that isn't the first
779  // edge against every other edge excluding those that
780  // have already been tested (this means one adjacent
781  // edge); polygon is complex if there is more than one
782  // intersection
783  else {
784  if (edgesIntersect>1) {
785  return false;
786  }
787  }
788  }
789  }
790  }
791 
792  return true;
793  }
794 
799  template<typename N>
800  bool AreaIsCCW(const std::vector<N> &edges)
801  {
802  // based on http://en.wikipedia.org/wiki/Curve_orientation
803  // and http://local.wasp.uwa.edu.au/~pbourke/geometry/clockwise/
804 
805  // note: polygon must be simple
806  // note: this assumes 2d cartesian coordinate space is used;
807  // for geographic, expect Vec2.x=lon and Vec2.y=lat!
808 
809  size_t ptIdx=0;
810 
811  for (size_t i=1; i<edges.size(); i++) {
812  // find the point with the smallest y value,
813  if (edges[i].y<edges[ptIdx].y) {
814  ptIdx=i;
815  }
816  // if y values are equal save the point with greatest x
817  else if (edges[i].y==edges[ptIdx].y) {
818  if (edges[i].x<edges[ptIdx].x) {
819  ptIdx=i;
820  }
821  }
822  }
823 
824  size_t prevIdx=(ptIdx==0) ? edges.size()-1 : ptIdx-1;
825  size_t nextIdx=(ptIdx==edges.size()-1) ? 0 : ptIdx+1;
826 
827  double signedArea=(edges[ptIdx].x-edges[prevIdx].x)*
828  (edges[nextIdx].y-edges[ptIdx].y)-
829  (edges[ptIdx].y-edges[prevIdx].y)*
830  (edges[nextIdx].x-edges[ptIdx].x);
831 
832  return signedArea>0.0;
833  }
834 
842  template<typename N>
843  bool AreaIsValid(std::vector<N>& outerPoints,
844  std::vector<std::vector<N> >& innerPoints)
845  {
846  if (outerPoints.size()<3) {
847  return false;
848  }
849 
850  size_t numEdges=outerPoints.size();
851 
852  for (size_t i=0; i<innerPoints.size(); i++) {
853  numEdges+=innerPoints[i].size();
854  }
855 
856  std::vector<bool> edgeStartsNewPoly(numEdges,false);
857  std::vector<std::pair<N,N> > listEdges(numEdges);
858  size_t cEdge=0;
859 
860  // temporarily wrap around vertices
861  // (first == last) to generate edge lists
862  outerPoints.push_back(outerPoints[0]);
863  for (size_t i=0; i<innerPoints.size(); i++) {
864  innerPoints[i].push_back(innerPoints[i][0]);
865  }
866 
867  // outer poly
868  edgeStartsNewPoly[0]=true;
869  for (size_t i=1; i<outerPoints.size(); i++) {
870  std::pair<N, N> outerEdge;
871 
872  outerEdge.first=outerPoints[i-1];
873  outerEdge.second=outerPoints[i];
874  listEdges[cEdge]=outerEdge;
875 
876  cEdge++;
877  }
878 
879  // inner polys
880  for (size_t i=0; i<innerPoints.size(); i++) {
881  edgeStartsNewPoly[cEdge]=true;
882 
883  for (size_t j=1; j<innerPoints[i].size(); j++) {
884  std::pair<N, N> innerEdge;
885 
886  innerEdge.first=innerPoints[i][j-1];
887  innerEdge.second=innerPoints[i][j];
888  listEdges[cEdge]=innerEdge;
889 
890  cEdge++;
891  }
892  }
893 
894  // revert vertex list modifications (not
895  // really the 'nicest' way of doing this)
896  outerPoints.pop_back();
897  for (size_t i=0; i<innerPoints.size(); i++) {
898  innerPoints[i].pop_back();
899  }
900 
901  if (AreaIsSimple(listEdges,edgeStartsNewPoly))
902  {
903  // expect listOuterPts to be CCW and innerPts
904  // to be CW, if not then reverse point order
905 
906  if (!AreaIsCCW(outerPoints)) {
907  std::reverse(outerPoints.begin(),
908  outerPoints.end());
909  }
910 
911  for (int i=0; i<innerPoints.size(); i++) {
912  if (AreaIsCCW(innerPoints[i])) {
913  std::reverse(innerPoints[i].begin(),
914  innerPoints[i].end());
915  }
916  }
917  }
918  else {
919  return false;
920  }
921 
922  return true;
923  }
924 
931  inline void Normalize(double x,
932  double y,
933  double& nx,
934  double& ny)
935  {
936  double length=sqrt(x*x+y*y);
937 
938  if (length!=0) {
939  nx=x/length;
940  ny=y/length;
941  }
942  }
943 
948  inline double Det(double x1,
949  double y1,
950  double x2,
951  double y2)
952  {
953  return x1*y2-y1*x2;
954  }
955 
956 
961  extern OSMSCOUT_API size_t Pow(size_t a, size_t b);
962 
971  template<typename N>
972  bool AreaIsClockwise(const std::vector<N>& edges)
973  {
974  assert(edges.size()>=3);
975  // based on http://en.wikipedia.org/wiki/Curve_orientation
976  // and http://local.wasp.uwa.edu.au/~pbourke/geometry/clockwise/
977 
978  // note: polygon must be simple
979 
980  size_t ptIdx=0;
981 
982  for (size_t i=1; i<edges.size(); i++) {
983  // find the point with the smallest y value,
984  if (edges[i].GetLat()<edges[ptIdx].GetLat()) {
985  ptIdx=i;
986  }
987  // if y values are equal save the point with greatest x
988  else if (edges[i].GetLat()==edges[ptIdx].GetLat()) {
989  if (edges[i].GetLon()<edges[ptIdx].GetLon()) {
990  ptIdx=i;
991  }
992  }
993  }
994 
995  size_t prevIdx=(ptIdx==0) ? edges.size()-1 : ptIdx-1;
996  size_t nextIdx=(ptIdx==edges.size()-1) ? 0 : ptIdx+1;
997 
998  double signedArea=(edges[ptIdx].GetLon()-edges[prevIdx].GetLon())*
999  (edges[nextIdx].GetLat()-edges[ptIdx].GetLat())-
1000  (edges[ptIdx].GetLat()-edges[prevIdx].GetLat())*
1001  (edges[nextIdx].GetLon()-edges[ptIdx].GetLon());
1002 
1003  return signedArea<0.0;
1004  }
1005 
1006 
1018  template<typename N>
1020  const N& a,
1021  const N& b)
1022  {
1023  double xdelta=b.GetLon()-a.GetLon();
1024  double ydelta=b.GetLat()-a.GetLat();
1025 
1026  if (xdelta==0 && ydelta==0) {
1027  return std::numeric_limits<double>::infinity();
1028  }
1029 
1030  double u=((p.GetLon()-a.GetLon())*xdelta+(p.GetLat()-a.GetLat())*ydelta)/(xdelta*xdelta+ydelta*ydelta);
1031 
1032  double cx;
1033  double cy;
1034 
1035  if (u<0) {
1036  cx=a.GetLon();
1037  cy=a.GetLat();
1038  }
1039  else if (u>1) {
1040  cx=b.GetLon();
1041  cy=b.GetLat();
1042  }
1043  else {
1044  cx=a.GetLon()+u*xdelta;
1045  cy=a.GetLat()+u*ydelta;
1046  }
1047 
1048  double dx=cx-p.GetLon();
1049  double dy=cy-p.GetLat();
1050 
1051  return sqrt(dx*dx+dy*dy);
1052  }
1053 
1054  extern OSMSCOUT_API double CalculateDistancePointToLineSegment(const GeoCoord& p,
1055  const GeoCoord& a,
1056  const GeoCoord& b,
1057  GeoCoord& intersection);
1058 
1064  extern OSMSCOUT_API Distance GetSphericalDistance(const GeoCoord& a,
1065  const GeoCoord& b);
1066 
1072  extern OSMSCOUT_API Distance GetEllipsoidalDistance(double aLon, double aLat,
1073  double bLon, double bLat);
1074 
1080  extern OSMSCOUT_API Distance GetEllipsoidalDistance(const GeoCoord& a,
1081  const GeoCoord& b);
1082 
1088  extern OSMSCOUT_API void GetEllipsoidalDistance(double lat1, double lon1,
1089  const Bearing &bearing,
1090  const Distance &distance,
1091  double& lat2, double& lon2);
1092 
1098  extern OSMSCOUT_API GeoCoord GetEllipsoidalDistance(const GeoCoord& position,
1099  const Bearing &bearing,
1100  const Distance &distance);
1101 
1107  extern OSMSCOUT_API Bearing GetSphericalBearingInitial(const GeoCoord& a,
1108  const GeoCoord& b);
1109 
1115  extern OSMSCOUT_API Bearing GetSphericalBearingFinal(const GeoCoord& a,
1116  const GeoCoord& b);
1117 
1125  extern OSMSCOUT_API double GetDistanceInLonDegrees(const Distance &d,
1126  double latitude=0);
1127 
1132  extern OSMSCOUT_API double NormalizeRelativeAngle(double angle);
1133 
1135  {
1136  int x;
1137  int y;
1138 
1139  ScanCell(int x, int y);
1140 
1141  void Set(int x, int y)
1142  {
1143  this->x=x;
1144  this->y=y;
1145  }
1146 
1147  bool operator==(const ScanCell& other) const
1148  {
1149  return x==other.x && y==other.y;
1150  }
1151 
1152  bool operator<(const ScanCell& other) const
1153  {
1154  return std::tie(y, x) < std::tie(other.y, other.x);
1155  }
1156 
1157  bool IsEqual(const ScanCell& other) const
1158  {
1159  return x==other.x && y==other.y;
1160  }
1161 
1162  int GetX() const
1163  {
1164  return x;
1165  }
1166 
1167  int GetY() const
1168  {
1169  return y;
1170  }
1171  };
1172 
1174  {
1175  size_t from;
1176  size_t to;
1177  GeoBox bbox;
1178  };
1179 
1184  void OSMSCOUT_API ScanConvertLine(int x1, int y1,
1185  int x2, int y2,
1186  std::vector<ScanCell>& cells);
1187 
1194  extern OSMSCOUT_API double DistanceToSegment(double px, double py,
1195  double p1x, double p1y,
1196  double p2x, double p2y,
1197  double& r,
1198  double& qx, double& qy);
1199 
1200  extern OSMSCOUT_API double DistanceToSegment(const GeoCoord& point,
1201  const GeoCoord& segmentStart,
1202  const GeoCoord& segmentEnd,
1203  double& r,
1204  GeoCoord& intersection);
1205 
1206  extern OSMSCOUT_API double DistanceToSegment(const std::vector<Point>& points,
1207  const GeoCoord& segmentStart,
1208  const GeoCoord& segmentEnd,
1209  GeoCoord& location,
1210  GeoCoord& intersection);
1211 
1212  extern OSMSCOUT_API double DistanceToSegment(const GeoBox& boundingBox,
1213  const GeoCoord& segmentStart,
1214  const GeoCoord& segmentEnd,
1215  GeoCoord& location,
1216  GeoCoord& intersection);
1217 
1223  {
1224  GeoCoord point;
1225  size_t aIndex;
1226  size_t bIndex;
1227  double orientation;
1228  double aDistanceSquare;
1231  };
1232 
1239  template<typename N>
1240  void GetSegmentBoundingBox(const std::vector<N>& path,
1241  size_t from, size_t to,
1242  GeoBox& boundingBox)
1243  {
1244  if (path.empty() || from>=to){
1245  boundingBox.Invalidate();
1246  }
1247 
1248  double minLon=path[from%path.size()].GetLon();
1249  double maxLon=minLon;
1250  double minLat=path[from%path.size()].GetLat();
1251  double maxLat=minLat;
1252 
1253  for (size_t i=from; i<to; i++) {
1254  minLon=std::min(minLon,path[i%path.size()].GetLon());
1255  maxLon=std::max(maxLon,path[i%path.size()].GetLon());
1256  minLat=std::min(minLat,path[i%path.size()].GetLat());
1257  maxLat=std::max(maxLat,path[i%path.size()].GetLat());
1258  }
1259 
1260  boundingBox.Set(GeoCoord(minLat,minLon),
1261  GeoCoord(maxLat,maxLon));
1262  }
1263 
1270  template<typename N>
1271  void ComputeSegmentBoxes(const std::vector<N>& path,
1272  std::vector<SegmentGeoBox> &segmentBoxes,
1273  size_t bound,
1274  size_t segmentSize = 1000)
1275  {
1276  assert(segmentSize>0);
1277  for (size_t i=0;i<bound;i+=segmentSize){
1278  SegmentGeoBox box;
1279  box.from = i;
1280  box.to = std::min(i+segmentSize,bound);
1281  GetSegmentBoundingBox(path, box.from, box.to, box.bbox);
1282  segmentBoxes.push_back(box);
1283  }
1284  }
1285 
1292  template<typename N>
1293  void FindPathIntersections(const std::vector<N> &aPath,
1294  const std::vector<N> &bPath,
1295  bool aClosed,
1296  bool bClosed,
1297  std::vector<PathIntersection> &intersections,
1298  size_t aStartIndex=0,
1299  size_t bStartIndex=0)
1300  {
1301  size_t aIndex=aStartIndex;
1302  size_t bIndex=bStartIndex;
1303  // bounds are inclusive
1304  size_t aBound=aClosed?aIndex+aPath.size():aPath.size()-1;
1305  size_t bBound=bClosed?bIndex+bPath.size():bPath.size()-1;
1306  size_t bStart=bIndex;
1307 
1308  if (bStart>=bBound || aIndex>=aBound){
1309  return;
1310  }
1311 
1312  GeoBox bBox;
1313  GetSegmentBoundingBox(bPath,bIndex,bBound+1,bBox);
1314  GeoBox aLineBox;
1315  GeoBox bLineBox;
1316 
1317  // compute b-boxes for B path, each 1000 point-long segment
1318  std::vector<SegmentGeoBox> bSegmentBoxes;
1319  ComputeSegmentBoxes(bPath,bSegmentBoxes,bBound+1, 1000);
1320 
1321  for (;aIndex<aBound;aIndex++){
1322  N a1=aPath[aIndex%aPath.size()];
1323  N a2=aPath[(aIndex+1)%aPath.size()];
1324  aLineBox.Set(GeoCoord(a1.GetLat(),a1.GetLon()),
1325  GeoCoord(a2.GetLat(),a2.GetLon()));
1326  if (!bBox.Intersects(aLineBox,/*openInterval*/false)){
1327  continue;
1328  }
1329  for (bIndex=bStart;bIndex<bBound;bIndex++){
1330  N b1=bPath[bIndex%bPath.size()];
1331  N b2=bPath[(bIndex+1)%bPath.size()];
1332  bLineBox.Set(GeoCoord(b1.GetLat(),b1.GetLon()),
1333  GeoCoord(b2.GetLat(),b2.GetLon()));
1334 
1335  if (!bSegmentBoxes[bIndex/1000].bbox.Intersects(aLineBox,/*openInterval*/false) &&
1336  !aLineBox.Intersects(bLineBox,/*openInterval*/false)){
1337  // round up
1338  bIndex+=std::max(0, 998-(int)(bIndex%1000));
1339  continue;
1340  }
1341  if (!aLineBox.Intersects(bLineBox,/*openInterval*/false)){
1342  continue;
1343  }
1344  PathIntersection pi;
1345  if (GetLineIntersection(a1,a2,
1346  b1,b2,
1347  pi.point)){
1348 
1349  // if b2==pi or a1==pi, orientation is zero then
1350  // for that reason, we prolong both lines for computation
1351  // of intersection orientation
1352  GeoCoord pointBefore(a1.GetLat()-(a2.GetLat()-a1.GetLat()),
1353  a1.GetLon()-(a2.GetLon()-a1.GetLon()));
1354  GeoCoord pointAfter(b2.GetLat()+(b2.GetLat()-b1.GetLat()),
1355  b2.GetLon()+(b2.GetLon()-b1.GetLon()));
1356  pi.orientation=(pi.point.GetLon()-pointBefore.GetLon())*
1357  (pointAfter.GetLat()-pi.point.GetLat())-
1358  (pi.point.GetLat()-pointBefore.GetLat())*
1359  (pointAfter.GetLon()-pi.point.GetLon());
1360 
1361  pi.aIndex=aIndex;
1362  pi.bIndex=bIndex;
1363  pi.aDistanceSquare=DistanceSquare(GeoCoord(a1.GetLat(),a1.GetLon()),pi.point);
1364  pi.bDistanceSquare=DistanceSquare(GeoCoord(b1.GetLat(),b1.GetLon()),pi.point);
1365 
1366  intersections.push_back(pi);
1367  }
1368  }
1369  }
1370  }
1371 
1378  template<typename N>
1379  bool FindIntersection(const std::vector<N> &way,
1380  size_t &i,
1381  size_t &j)
1382  {
1383  GeoBox lineBox;
1384 
1385  // compute b-boxes for path, each 1000 point-long segment
1386  std::vector<SegmentGeoBox> segmentBoxes;
1387  ComputeSegmentBoxes(way,segmentBoxes,way.size(),1000);
1388 
1389  for (; i<way.size()-1; i++) {
1390  N i1=way[i];
1391  N i2=way[i+1];
1392  lineBox.Set(GeoCoord(i1.GetLat(),i1.GetLon()),
1393  GeoCoord(i2.GetLat(),i2.GetLon()));
1394 
1395  for (j=i+1; j<way.size()-1; j++) {
1396  if (!segmentBoxes[j/1000].bbox.Intersects(lineBox,/*openInterval*/false) &&
1397  !segmentBoxes[(j+1)/1000].bbox.Intersects(lineBox,/*openInterval*/false)){
1398  // round up
1399  j+=std::max(0, 998-(int)(j%1000));
1400  continue;
1401  }
1402  if (LinesIntersect(way[i],
1403  way[i+1],
1404  way[j],
1405  way[j+1])) {
1406 
1407  if (way[i].IsEqual(way[j]) ||
1408  way[i].IsEqual(way[j+1]) ||
1409  way[i+1].IsEqual(way[j]) ||
1410  way[i+1].IsEqual(way[j+1])) {
1411  continue; // ignore sibling edges
1412  }
1413 
1414  return true;
1415  }
1416  }
1417  }
1418  return false;
1419  }
1420 
1422  {
1423  private:
1424  struct Edge
1425  {
1426  size_t fromIndex;
1427  size_t toIndex;
1428  };
1429 
1430  public:
1431  struct Polygon
1432  {
1433  std::vector<Point> coords;
1434  };
1435 
1436  private:
1437  std::unordered_map<Id,size_t> nodeIdIndexMap;
1438  std::vector<Point> nodes;
1439  std::list<Edge> edges;
1440 
1441  private:
1442  void RemoveEliminatingEdges();
1443 
1444  public:
1445  void AddPolygon(const std::vector<Point>& polygonsCoords);
1446 
1447  bool Merge(std::list<Polygon>& result);
1448  };
1449 
1451  {
1452  double width;
1453  double height;
1454  };
1455 
1456  const size_t CELL_DIMENSION_MAX = 25;
1458 
1459  extern OSMSCOUT_API const std::array<CellDimension,CELL_DIMENSION_COUNT> cellDimension;
1460 
1471  {
1472  public:
1473  enum class Direction
1474  {
1475  HORIZONTAL,
1476  VERTICAL
1477  };
1478 
1479  private:
1480  GeoBox box;
1481  Direction direction;
1482  double parts;
1483  size_t currentIndex=0;
1484  GeoBox currentBox;
1485 
1486  private:
1487  void CalculateBox();
1488 
1489  public:
1490  GeoBoxPartitioner(const GeoBox& box,
1491  Direction direction,
1492  size_t parts)
1493  : box(box),
1494  direction(direction),
1495  parts((double)parts)
1496  {
1497  assert(currentIndex<parts);
1498  CalculateBox();
1499  }
1500 
1501  void Advance()
1502  {
1503  currentIndex++;
1504 
1505  if (currentIndex<parts) {
1506  CalculateBox();
1507  }
1508  }
1509 
1510  GeoBox GetCurrentGeoBox() const
1511  {
1512  assert(currentIndex<parts);
1513  return currentBox;
1514  }
1515 
1516  size_t GetCurrentIndex() const
1517  {
1518  assert(currentIndex<parts);
1519  return currentIndex;
1520  }
1521  };
1522 }
1523 
1524 namespace std {
1525  template <>
1526  struct hash<osmscout::ScanCell>
1527  {
1528  size_t operator()(const osmscout::ScanCell& cell) const
1529  {
1530  return hash<int>{}(cell.GetX()) ^ (hash<int>{}(cell.GetY()) << 1);
1531  }
1532  };
1533 }
1534 
1535 #endif
double aDistanceSquare
distance^2 between "a path" point and intersection
Definition: Geometry.h:1229
bool IsAreaSubOfArea(const std::vector< N > &a, const std::vector< M > &b)
Definition: Geometry.h:597
bool IsAreaCompletelyInArea(const std::vector< N > &a, const std::vector< M > &b)
Definition: Geometry.h:537
void GetSegmentBoundingBox(const std::vector< N > &path, size_t from, size_t to, GeoBox &boundingBox)
Definition: Geometry.h:1240
bool AreaIsValid(std::vector< N > &outerPoints, std::vector< std::vector< N > > &innerPoints)
Definition: Geometry.h:843
void Normalize(double x, double y, double &nx, double &ny)
Definition: Geometry.h:931
double width
Definition: Geometry.h:1452
OSMSCOUT_API Distance GetSphericalDistance(const GeoCoord &a, const GeoCoord &b)
size_t bIndex
"b path" point index before intersection
Definition: Geometry.h:1226
OSMSCOUT_API double GetDistanceInLonDegrees(const Distance &d, double latitude=0)
bool operator==(const ScanCell &other) const
Definition: Geometry.h:1147
int GetY() const
Definition: Geometry.h:1167
double DistanceSquare(const N &a, const N &b)
Definition: Geometry.h:401
GeoBoxPartitioner(const GeoBox &box, Direction direction, size_t parts)
Definition: Geometry.h:1490
int y
Definition: Geometry.h:1137
Definition: Geometry.h:1222
STL namespace.
double RadToDeg(double rad)
Definition: Geometry.h:71
OSMSCOUT_API const std::array< CellDimension, CELL_DIMENSION_COUNT > cellDimension
void Set(int x, int y)
Definition: Geometry.h:1141
size_t aIndex
"a path" point index before intersection
Definition: Geometry.h:1225
bool IsAreaAtLeastPartlyInArea(const std::vector< N > &a, const std::vector< M > &b, const GeoBox &aBox, const GeoBox &bBox)
Definition: Geometry.h:554
OSMSCOUT_API Distance GetEllipsoidalDistance(double aLon, double aLat, double bLon, double bLat)
bool IsCoordInArea(const N &point, const std::vector< M > &nodes)
Definition: Geometry.h:476
bool LinesIntersect(const N &a1, const N &a2, const N &b1, const N &b2)
Definition: Geometry.h:200
void GetBoundingBox(const std::vector< N > &nodes, double &minLon, double &maxLon, double &minLat, double &maxLat)
Definition: Geometry.h:107
bool GetLineIntersection(const N &a1, const N &a2, const N &b1, const N &b2, I &intersection)
Definition: Geometry.h:258
bool FindIntersection(const std::vector< N > &way, size_t &i, size_t &j)
Definition: Geometry.h:1379
double Det(double x1, double y1, double x2, double y2)
Definition: Geometry.h:948
bool AreaIsSimple(std::vector< N > points)
Definition: Geometry.h:706
const size_t CELL_DIMENSION_COUNT
Definition: Geometry.h:1457
Definition: Area.h:38
GeoBox bbox
Definition: Geometry.h:1177
int GetX() const
Definition: Geometry.h:1162
double CalculateDistancePointToLineSegment(const N &p, const N &a, const N &b)
Definition: Geometry.h:1019
OSMSCOUT_API double DistanceToSegment(double px, double py, double p1x, double p1y, double p2x, double p2y, double &r, double &qx, double &qy)
size_t operator()(const osmscout::ScanCell &cell) const
Definition: Geometry.h:1528
std::vector< Point > coords
Definition: Geometry.h:1433
OSMSCOUT_API double NormalizeRelativeAngle(double angle)
double height
Definition: Geometry.h:1453
#define OSMSCOUT_API
Definition: CoreImportExport.h:45
int x
Definition: Geometry.h:1136
bool AreaIsCCW(const std::vector< N > &edges)
Definition: Geometry.h:800
double AngleDiff(double a, double b)
Definition: Geometry.h:84
OSMSCOUT_API Bearing GetSphericalBearingInitial(const GeoCoord &a, const GeoCoord &b)
GeoCoord point
intersection point
Definition: Geometry.h:1224
bool operator<(const ScanCell &other) const
Definition: Geometry.h:1152
bool IsAreaSubOfAreaOrSame(const std::vector< N > &a, const std::vector< M > &b)
Definition: Geometry.h:661
Direction
Definition: Geometry.h:1473
bool IsAreaSubOfAreaQuorum(const std::vector< N > &a, const std::vector< M > &b)
Definition: Geometry.h:624
Definition: Geometry.h:1470
void ComputeSegmentBoxes(const std::vector< N > &path, std::vector< SegmentGeoBox > &segmentBoxes, size_t bound, size_t segmentSize=1000)
Definition: Geometry.h:1271
Definition: Geometry.h:1431
GeoBox GetCurrentGeoBox() const
Definition: Geometry.h:1510
int GetRelationOfPointToArea(const N &point, const std::vector< M > &nodes)
Definition: Geometry.h:508
void OSMSCOUT_API ScanConvertLine(int x1, int y1, int x2, int y2, std::vector< ScanCell > &cells)
double DegToRad(double deg)
Definition: Geometry.h:61
bool AreaIsClockwise(const std::vector< N > &edges)
Definition: Geometry.h:972
bool IsEqual(const ScanCell &other) const
Definition: Geometry.h:1157
OSMSCOUT_API Bearing GetSphericalBearingFinal(const GeoCoord &a, const GeoCoord &b)
OSMSCOUT_API size_t Pow(size_t a, size_t b)
size_t to
exclusive
Definition: Geometry.h:1176
double orientation
Definition: Geometry.h:1227
size_t GetCurrentIndex() const
Definition: Geometry.h:1516
Definition: Geometry.h:1173
double bDistanceSquare
distance^2 between "b path" point and intersection
Definition: Geometry.h:1230
size_t from
Definition: Geometry.h:1175
void FindPathIntersections(const std::vector< N > &aPath, const std::vector< N > &bPath, bool aClosed, bool bClosed, std::vector< PathIntersection > &intersections, size_t aStartIndex=0, size_t bStartIndex=0)
Definition: Geometry.h:1293
Definition: Geometry.h:1450
Definition: Geometry.h:1421
bool GetLineIntersectionPixel(const N &a1, const N &a2, const N &b1, const N &b2, N &intersection)
Definition: Geometry.h:347
Definition: Geometry.h:1134
const size_t CELL_DIMENSION_MAX
Definition: Geometry.h:1456
void Advance()
Definition: Geometry.h:1501