GeoTessCPP  2.0.0
Software to facilitate storage and retrieval of 3D information about the Earth.
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines
include/GeoTessPolygon.h
Go to the documentation of this file.
00001 //- ****************************************************************************
00002 //- 
00003 //- Copyright 2009 Sandia Corporation. Under the terms of Contract
00004 //- DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
00005 //- retains certain rights in this software.
00006 //- 
00007 //- BSD Open Source License.
00008 //- All rights reserved.
00009 //- 
00010 //- Redistribution and use in source and binary forms, with or without
00011 //- modification, are permitted provided that the following conditions are met:
00012 //- 
00013 //-    * Redistributions of source code must retain the above copyright notice,
00014 //-      this list of conditions and the following disclaimer.
00015 //-    * Redistributions in binary form must reproduce the above copyright
00016 //-      notice, this list of conditions and the following disclaimer in the
00017 //-      documentation and/or other materials provided with the distribution.
00018 //-    * Neither the name of Sandia National Laboratories nor the names of its
00019 //-      contributors may be used to endorse or promote products derived from
00020 //-      this software without specific prior written permission.
00021 //- 
00022 //- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00023 //- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024 //- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025 //- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00026 //- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00027 //- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00028 //- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00029 //- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00030 //- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00031 //- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 //- POSSIBILITY OF SUCH DAMAGE.
00033 //-
00034 //- ****************************************************************************
00035 
00036 #ifndef POLYGON_H_
00037 #define POLYGON_H_
00038 
00039 // **** _SYSTEM INCLUDES_ ******************************************************
00040 
00041 #include <cstdio>
00042 #include <iostream>
00043 #include <iomanip>
00044 #include <vector>
00045 
00046 // use standard library objects
00047 using namespace std;
00048 
00049 // **** _LOCAL INCLUDES_ *******************************************************
00050 
00051 #include "CPPUtils.h"
00052 #include "GeoTessUtils.h"
00053 #include "GeoTessGreatCircle.h"
00054 #include "IFStreamAscii.h"
00055 
00056 // **** _BEGIN GEOTESS NAMESPACE_ **********************************************
00057 
00058 namespace geotess {
00059 
00060 // **** _FORWARD REFERENCES_ ***************************************************
00061 
00062 // **** _CLASS DEFINITION_ *****************************************************
00063 
00111 class GEOTESS_EXP_IMP GeoTessPolygon
00112 {
00113 protected:
00114 
00118         vector<GeoTessGreatCircle*> edges;
00119 
00126         double* referencePoint;
00127 
00131         bool referenceIn;
00132 
00136          static double TOLERANCE;
00137 
00142          bool global;
00143 
00147          bool lonFirst;
00148 
00152         void setup(vector<double*>& points);
00153 
00154         int edgeCrossings(GeoTessGreatCircle& gcRef);
00155 
00159         int refCount;
00160 
00161   public:
00162 
00163         virtual ~GeoTessPolygon();
00164 
00169         void* attachment;
00170 
00171         GeoTessPolygon();
00172 
00186         GeoTessPolygon(vector<double*>& points);
00187 
00202         GeoTessPolygon(const double* center, double radius, int nEdges);
00203 
00212         GeoTessPolygon(string filename);
00213 
00217         virtual string class_name() { return "Polygon"; };
00218 
00222         void addReference() { ++refCount; }
00223 
00227         void removeReference()
00228         {
00229                 if (isNotReferenced())
00230                 {
00231                         ostringstream os;
00232                         os << endl << "ERROR in Polygon::removeReference" << endl
00233                                         << "Reference count (" << refCount << ") is already zero." << endl;
00234                         throw GeoTessException(os, __FILE__, __LINE__, 10001);
00235                 }
00236 
00237                 --refCount;
00238         }
00239 
00243         bool isNotReferenced() { return refCount == 0; }
00244 
00245         int getRefCount() { return refCount; }
00246 
00254         int size()
00255         {
00256                 return edges.size();
00257         }
00258 
00262         static double getTolerance()
00263         {
00264                 return TOLERANCE;
00265         }
00266 
00273         const double* const getReferencePoint()
00274         {
00275                 return referencePoint;
00276         }
00277 
00284         const void getReferencePoint(double *u)
00285         {
00286                 u[0] = referencePoint[0];
00287                 u[1] = referencePoint[1];
00288                 u[2] = referencePoint[2];
00289         }
00290 
00295         bool getReferencePointIn()
00296         {
00297                 return referenceIn;
00298         }
00299 
00304         void invert()
00305         {
00306                 referenceIn = !referenceIn;
00307         }
00308 
00321         void setReferencePoint(const double* refPoint, const bool &inside)
00322         {
00323                 if (referencePoint == NULL)
00324                         referencePoint = new double[3];
00325 
00326                 referencePoint[0] = refPoint[0];
00327                 referencePoint[1] = refPoint[1];
00328                 referencePoint[2] = refPoint[2];
00329                 referenceIn = inside;
00330         }
00331 
00341         void setReferencePoint(double lat, double lon, bool inside)
00342         {
00343                 double r[3];
00344                 GeoTessUtils::getVectorDegrees(lat, lon, r);
00345                 setReferencePoint(r, inside);
00346         }
00347 
00356         bool containsAny(const vector<double*>& points)
00357         {
00358                 for (int i=0; i<(int)points.size(); ++i)
00359                         if (contains(points[i]))
00360                                 return true;
00361                 return false;
00362         }
00363 
00370         bool containsAll(const vector<double*>& positions)
00371         {
00372                 for (int i=0; i<(int)positions.size(); ++i)
00373                         if (!contains(positions[i]))
00374                                 return false;
00375                 return true;
00376         }
00377 
00384         bool contains(const double* x)
00385         {
00386                 if (global || GeoTessUtils::dot(referencePoint, x) > cos(TOLERANCE))
00387                         return referenceIn;
00388 
00389                 GeoTessGreatCircle gcRef(referencePoint, x);
00390 
00391                 return onBoundary(gcRef) || ((edgeCrossings(gcRef) % 2 == 0) == referenceIn);
00392         }
00393 
00401         bool onBoundary(GeoTessGreatCircle& gcRef)
00402         {
00403                 // point being evaluated is gcRef.getLast()
00404                 for (int i=0; i<(int)edges.size(); ++i)
00405                 {
00406                         // if point is very close to a polygon point, return true
00407                         if (GeoTessUtils::dot(gcRef.getLast(), edges[i]->getFirst()) >= cos(TOLERANCE))
00408                                 return true;
00409 
00410                         // if gcRef and edge are coincident, i.e., their normals are parallel or
00411                         // anti-parallel, and the point being evaluated is between first and last
00412                         // point of the edge, then return true;
00413                         if (abs(GeoTessUtils::dot(gcRef.getNormal(), edges[i]->getNormal())) >= cos(TOLERANCE)
00414                                         && edges[i]->getDistance(gcRef.getLast()) <= edges[i]->getDistance())
00415                                 return true;
00416                 }
00417                 return false;
00418         }
00419 
00427         bool onBoundary(const double* x)
00428         {
00429                 GeoTessGreatCircle gc(referencePoint, x);
00430                 return onBoundary(gc);
00431         }
00432 
00447         void getPoints(vector<double*> &points, const bool &repeatFirstPoint)
00448         {
00449                 points.reserve(points.size()+edges.size()+1);
00450 
00451                 for (int i = 0; i < (int)edges.size(); ++i)
00452                 {
00453                         double* point = new double[3];
00454                         point[0] = edges[i]->getFirst()[0];
00455                         point[1] = edges[i]->getFirst()[1];
00456                         point[2] = edges[i]->getFirst()[2];
00457                         points.push_back(point);
00458                 }
00459 
00460                 if (repeatFirstPoint)
00461                 {
00462                         double* point = new double[3];
00463                         point[0] = edges[0]->getFirst()[0];
00464                         point[1] = edges[0]->getFirst()[1];
00465                         point[2] = edges[0]->getFirst()[2];
00466                         points.push_back(point);
00467                 }
00468         }
00469 
00485         void getPoints(vector<double*> &points, const bool &repeatFirstPoint, const double &maxSpacing)
00486         {
00487                 points.reserve(points.size()+edges.size()+1);
00488 
00489                 int n;
00490                 double dx;
00491                 for (int i = 0; i < (int)edges.size(); ++i)
00492                 {
00493                         n = (int)ceil(edges[i]->getDistance()/maxSpacing);
00494                         dx = edges[i]->getDistance()/n;
00495                         for (int j=0; j<n; ++j)
00496                                 points.push_back(edges[i]->getPoint(j*dx));
00497                 }
00498 
00499                 if (repeatFirstPoint)
00500                 {
00501                         double* point = new double[3];
00502                         point[0] = edges[0]->getFirst()[0];
00503                         point[1] = edges[0]->getFirst()[1];
00504                         point[2] = edges[0]->getFirst()[2];
00505                         points.push_back(point);
00506                 }
00507         }
00508 
00516         const double* getPoint(int index)
00517         {
00518                 return edges[index]->getFirst();
00519         }
00520 
00533         double getArea()
00534         {
00535                 double a, area = 0;
00536                 GeoTessGreatCircle* edge;
00537                 GeoTessGreatCircle* previous = edges[edges.size()-1];
00538 
00539                 for (int i=0; i<(int)edges.size(); ++i)
00540                 {
00541                         edge = edges[i];
00542                         a = PI - GeoTessUtils::angle(previous->getNormal(), edge->getNormal());
00543 
00544                         if (GeoTessUtils::scalarTripleProduct(previous->getNormal(), edge->getNormal(),
00545                                         edge->getFirst()) < 0)
00546                                 area += a;
00547                         else
00548                                 area += 2*PI - a;
00549 
00550                         previous = edge;
00551                 }
00552                 area -= (edges.size()-2)*PI;
00553                 return area;
00554         }
00555 
00565         double getAreaSmall()
00566         {
00567                 double area = getArea();
00568                 return area <= 2*PI ? area : 4*PI-area;
00569         }
00570 
00580         double getAreaLarge()
00581         {
00582                 double area = getArea();
00583                 return area >= 2*PI ? area : 4*PI-area;
00584         }
00585 
00604         string str(const bool& repeatFirstPoint, const bool& latFirst,
00605                         const double& minLongitude = -180);
00606 
00607         virtual void write(const string& outputFileName);
00608 
00610 
00611         virtual void loadAscii(vector<string>& records);
00612 
00614 
00615 }; // end class Polygon
00616 
00617 } // end namespace geotess
00618 
00619 #endif /* POLYGON_H_ */