GeoTessCPP  2.0.0
Software to facilitate storage and retrieval of 3D information about the Earth.
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros
GeoTessPolygon.h
Go to the documentation of this file.
1 //- ****************************************************************************
2 //-
3 //- Copyright 2009 Sandia Corporation. Under the terms of Contract
4 //- DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
5 //- retains certain rights in this software.
6 //-
7 //- BSD Open Source License.
8 //- All rights reserved.
9 //-
10 //- Redistribution and use in source and binary forms, with or without
11 //- modification, are permitted provided that the following conditions are met:
12 //-
13 //- * Redistributions of source code must retain the above copyright notice,
14 //- this list of conditions and the following disclaimer.
15 //- * Redistributions in binary form must reproduce the above copyright
16 //- notice, this list of conditions and the following disclaimer in the
17 //- documentation and/or other materials provided with the distribution.
18 //- * Neither the name of Sandia National Laboratories nor the names of its
19 //- contributors may be used to endorse or promote products derived from
20 //- this software without specific prior written permission.
21 //-
22 //- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 //- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 //- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 //- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26 //- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 //- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 //- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 //- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 //- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 //- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 //- POSSIBILITY OF SUCH DAMAGE.
33 //-
34 //- ****************************************************************************
35 
36 #ifndef POLYGON_H_
37 #define POLYGON_H_
38 
39 // **** _SYSTEM INCLUDES_ ******************************************************
40 
41 #include <cstdio>
42 #include <iostream>
43 #include <iomanip>
44 #include <vector>
45 
46 // use standard library objects
47 using namespace std;
48 
49 // **** _LOCAL INCLUDES_ *******************************************************
50 
51 #include "CPPUtils.h"
52 #include "GeoTessUtils.h"
53 #include "GeoTessGreatCircle.h"
54 #include "IFStreamAscii.h"
55 
56 // **** _BEGIN GEOTESS NAMESPACE_ **********************************************
57 
58 namespace geotess {
59 
60 // **** _FORWARD REFERENCES_ ***************************************************
61 
62 // **** _CLASS DEFINITION_ *****************************************************
63 
112 {
113 protected:
114 
118  vector<GeoTessGreatCircle*> edges;
119 
126  double* referencePoint;
127 
132 
136  static double TOLERANCE;
137 
142  bool global;
143 
147  bool lonFirst;
148 
152  void setup(vector<double*>& points);
153 
154  int edgeCrossings(GeoTessGreatCircle& gcRef);
155 
159  int refCount;
160 
161  public:
162 
163  virtual ~GeoTessPolygon();
164 
169  void* attachment;
170 
171  GeoTessPolygon();
172 
186  GeoTessPolygon(vector<double*>& points);
187 
202  GeoTessPolygon(const double* center, double radius, int nEdges);
203 
212  GeoTessPolygon(string filename);
213 
217  virtual string class_name() { return "Polygon"; };
218 
222  void addReference() { ++refCount; }
223 
227  void removeReference()
228  {
229  if (isNotReferenced())
230  {
231  ostringstream os;
232  os << endl << "ERROR in Polygon::removeReference" << endl
233  << "Reference count (" << refCount << ") is already zero." << endl;
234  throw GeoTessException(os, __FILE__, __LINE__, 10001);
235  }
236 
237  --refCount;
238  }
239 
243  bool isNotReferenced() { return refCount == 0; }
244 
245  int getRefCount() { return refCount; }
246 
254  int size()
255  {
256  return edges.size();
257  }
258 
262  static double getTolerance()
263  {
264  return TOLERANCE;
265  }
266 
273  const double* const getReferencePoint()
274  {
275  return referencePoint;
276  }
277 
284  const void getReferencePoint(double *u)
285  {
286  u[0] = referencePoint[0];
287  u[1] = referencePoint[1];
288  u[2] = referencePoint[2];
289  }
290 
295  bool getReferencePointIn()
296  {
297  return referenceIn;
298  }
299 
304  void invert()
305  {
306  referenceIn = !referenceIn;
307  }
308 
321  void setReferencePoint(const double* refPoint, const bool &inside)
322  {
323  if (referencePoint == NULL)
324  referencePoint = new double[3];
325 
326  referencePoint[0] = refPoint[0];
327  referencePoint[1] = refPoint[1];
328  referencePoint[2] = refPoint[2];
329  referenceIn = inside;
330  }
331 
341  void setReferencePoint(double lat, double lon, bool inside)
342  {
343  double r[3];
344  GeoTessUtils::getVectorDegrees(lat, lon, r);
345  setReferencePoint(r, inside);
346  }
347 
356  bool containsAny(const vector<double*>& points)
357  {
358  for (int i=0; i<(int)points.size(); ++i)
359  if (contains(points[i]))
360  return true;
361  return false;
362  }
363 
370  bool containsAll(const vector<double*>& positions)
371  {
372  for (int i=0; i<(int)positions.size(); ++i)
373  if (!contains(positions[i]))
374  return false;
375  return true;
376  }
377 
384  bool contains(const double* x)
385  {
386  if (global || GeoTessUtils::dot(referencePoint, x) > cos(TOLERANCE))
387  return referenceIn;
388 
389  GeoTessGreatCircle gcRef(referencePoint, x);
390 
391  return onBoundary(gcRef) || ((edgeCrossings(gcRef) % 2 == 0) == referenceIn);
392  }
393 
401  bool onBoundary(GeoTessGreatCircle& gcRef)
402  {
403  // point being evaluated is gcRef.getLast()
404  for (int i=0; i<(int)edges.size(); ++i)
405  {
406  // if point is very close to a polygon point, return true
407  if (GeoTessUtils::dot(gcRef.getLast(), edges[i]->getFirst()) >= cos(TOLERANCE))
408  return true;
409 
410  // if gcRef and edge are coincident, i.e., their normals are parallel or
411  // anti-parallel, and the point being evaluated is between first and last
412  // point of the edge, then return true;
413  if (abs(GeoTessUtils::dot(gcRef.getNormal(), edges[i]->getNormal())) >= cos(TOLERANCE)
414  && edges[i]->getDistance(gcRef.getLast()) <= edges[i]->getDistance())
415  return true;
416  }
417  return false;
418  }
419 
427  bool onBoundary(const double* x)
428  {
429  GeoTessGreatCircle gc(referencePoint, x);
430  return onBoundary(gc);
431  }
432 
447  void getPoints(vector<double*> &points, const bool &repeatFirstPoint)
448  {
449  points.reserve(points.size()+edges.size()+1);
450 
451  for (int i = 0; i < (int)edges.size(); ++i)
452  {
453  double* point = new double[3];
454  point[0] = edges[i]->getFirst()[0];
455  point[1] = edges[i]->getFirst()[1];
456  point[2] = edges[i]->getFirst()[2];
457  points.push_back(point);
458  }
459 
460  if (repeatFirstPoint)
461  {
462  double* point = new double[3];
463  point[0] = edges[0]->getFirst()[0];
464  point[1] = edges[0]->getFirst()[1];
465  point[2] = edges[0]->getFirst()[2];
466  points.push_back(point);
467  }
468  }
469 
485  void getPoints(vector<double*> &points, const bool &repeatFirstPoint, const double &maxSpacing)
486  {
487  points.reserve(points.size()+edges.size()+1);
488 
489  int n;
490  double dx;
491  for (int i = 0; i < (int)edges.size(); ++i)
492  {
493  n = (int)ceil(edges[i]->getDistance()/maxSpacing);
494  dx = edges[i]->getDistance()/n;
495  for (int j=0; j<n; ++j)
496  points.push_back(edges[i]->getPoint(j*dx));
497  }
498 
499  if (repeatFirstPoint)
500  {
501  double* point = new double[3];
502  point[0] = edges[0]->getFirst()[0];
503  point[1] = edges[0]->getFirst()[1];
504  point[2] = edges[0]->getFirst()[2];
505  points.push_back(point);
506  }
507  }
508 
516  const double* getPoint(int index)
517  {
518  return edges[index]->getFirst();
519  }
520 
533  double getArea()
534  {
535  double a, area = 0;
536  GeoTessGreatCircle* edge;
537  GeoTessGreatCircle* previous = edges[edges.size()-1];
538 
539  for (int i=0; i<(int)edges.size(); ++i)
540  {
541  edge = edges[i];
542  a = PI - GeoTessUtils::angle(previous->getNormal(), edge->getNormal());
543 
544  if (GeoTessUtils::scalarTripleProduct(previous->getNormal(), edge->getNormal(),
545  edge->getFirst()) < 0)
546  area += a;
547  else
548  area += 2*PI - a;
549 
550  previous = edge;
551  }
552  area -= (edges.size()-2)*PI;
553  return area;
554  }
555 
565  double getAreaSmall()
566  {
567  double area = getArea();
568  return area <= 2*PI ? area : 4*PI-area;
569  }
570 
580  double getAreaLarge()
581  {
582  double area = getArea();
583  return area >= 2*PI ? area : 4*PI-area;
584  }
585 
604  string str(const bool& repeatFirstPoint, const bool& latFirst,
605  const double& minLongitude = -180);
606 
607  virtual void write(const string& outputFileName);
608 
610 
611  virtual void loadAscii(vector<string>& records);
612 
614 
615 }; // end class Polygon
616 
617 } // end namespace geotess
618 
619 #endif /* POLYGON_H_ */