1 //*****************************************************************************
2 // FILE: ossimPolygon.h
3 //
4 // License:  See top level LICENSE.txt file.
5 //
6 // AUTHOR: Garrett Potts
7 //
8 //*****************************************************************************
9 //  $Id: ossimGeoPolygon.cpp 23170 2015-02-25 20:59:10Z dburken $
10 
11 #include <ostream>
12 #include <sstream>
13 #include <algorithm>
14 #include <ossim/base/ossimGeoPolygon.h>
15 #include <ossim/base/ossimDatumFactoryRegistry.h>
16 #include <ossim/base/ossimDatum.h>
17 #include <ossim/base/ossimKeywordlist.h>
18 #include <ossim/base/ossimKeywordNames.h>
19 
20 static const char* NUMBER_VERTICES_KW = "number_vertices";
21 
operator <<(std::ostream & out,const ossimGeoPolygon & poly)22 std::ostream& operator <<(std::ostream& out, const ossimGeoPolygon& poly)
23 {
24    if(poly.size())
25    {
26       if(poly.size() >1)
27       {
28          for(ossim_uint32 i = 0; i <  poly.size()-1; ++i)
29          {
30             out << "P" << i << ": " << poly[i] << std::endl;
31          }
32          out << "P"  << (poly.size()-1)
33              << ": " << poly[poly.size()-1] << std::endl;
34       }
35       else
36       {
37          out << "P0: " << poly[0] << std::endl;
38       }
39    }
40 
41    return out;
42 }
43 
ossimGeoPolygon()44 ossimGeoPolygon::ossimGeoPolygon()
45    :
46    theVertexList(),
47    theAttributeList(),
48    theHoleList(),
49    theCurrentVertex(-1),
50    theOrderingType(OSSIM_VERTEX_ORDER_UNKNOWN)
51 {
52 }
53 
ossimGeoPolygon(const std::vector<ossimGpt> & points)54 ossimGeoPolygon::ossimGeoPolygon(const std::vector<ossimGpt>& points)
55    :
56    theVertexList(points),
57    theAttributeList(),
58    theHoleList(),
59    theCurrentVertex(0),
60    theOrderingType(OSSIM_VERTEX_ORDER_UNKNOWN)
61 {
62 }
63 
ossimGeoPolygon(const ossimGeoPolygon & rhs)64 ossimGeoPolygon::ossimGeoPolygon(const ossimGeoPolygon& rhs)
65    :
66    theVertexList(rhs.theVertexList),
67    theAttributeList(rhs.theAttributeList),
68    theHoleList(rhs.theHoleList),
69    theCurrentVertex(rhs.theCurrentVertex),
70    theOrderingType(rhs.theOrderingType)
71 {
72 }
73 
operator =(const ossimGeoPolygon & rhs)74 const ossimGeoPolygon& ossimGeoPolygon::operator=(const ossimGeoPolygon& rhs)
75 {
76    if ( this != &rhs )
77    {
78       theVertexList    = rhs.theVertexList;
79       theAttributeList = rhs.theAttributeList;
80       theHoleList      = rhs.theHoleList;
81       theCurrentVertex = rhs.theCurrentVertex;
82       theOrderingType  = rhs.theOrderingType;
83    }
84    return *this;
85 }
86 
addWmsBbox(const ossimString & wmsBbox)87 bool ossimGeoPolygon::addWmsBbox(const ossimString& wmsBbox)
88 {
89    std::vector<ossimString> splitArray = wmsBbox.split(",");
90    bool result = true;
91    if(splitArray.size()>=4)
92    {
93       double minx = splitArray[0].trim().toDouble();
94       double miny = splitArray[1].trim().toDouble();
95       double maxx = splitArray[2].trim().toDouble();
96       double maxy = splitArray[3].trim().toDouble();
97 
98       addPoint(miny, minx);//lower left
99       addPoint(maxy, minx);//upper left
100       addPoint(maxy, maxx);//upper right
101       addPoint(miny, maxx);//lower right
102    }
103    else
104    {
105       // error
106       result = false;
107    }
108 
109    return result;
110 }
111 
hasNans() const112 bool ossimGeoPolygon::hasNans()const
113 {
114    int upper = (int)theVertexList.size();
115    int i = 0;
116 
117    for(i = 0; i < upper; ++i)
118    {
119       if(theVertexList[i].hasNans())
120       {
121          return true;
122       }
123    }
124 
125    return false;
126 }
127 
vertex(int index,ossimGpt & v) const128 bool ossimGeoPolygon::vertex(int index, ossimGpt& v) const
129 {
130    if((index >= (int)theVertexList.size()) ||
131       (index < 0))
132    {
133       return false;
134    }
135 
136    v = theVertexList[index];
137    theCurrentVertex = index;
138 
139    return true;
140 }
141 
nextVertex(ossimDpt & v) const142 bool ossimGeoPolygon::nextVertex(ossimDpt& v) const
143 {
144    ++theCurrentVertex;
145    if(theCurrentVertex >= (ossim_int32)theVertexList.size())
146    {
147       return false;
148    }
149    v = theVertexList[theCurrentVertex];
150 
151    return true;
152 }
153 
stretchOut(ossimGeoPolygon & newPolygon,double displacement)154 void ossimGeoPolygon::stretchOut(ossimGeoPolygon& newPolygon,
155                                  double displacement)
156 {
157    newPolygon.resize(size());
158    if(size() >= 3)
159    {
160       const ossimDatum* datum = theVertexList[0].datum();
161       checkOrdering();
162       double signMult = 1.0;
163       if(theOrderingType == OSSIM_COUNTERCLOCKWISE_ORDER)
164       {
165          signMult = -1.0;
166       }
167 
168       ossimDpt prev, current, next;
169 
170       ossim_uint32 prevI;
171       ossim_uint32 currentI;
172       ossim_uint32 nextI;
173       ossim_uint32 i = 0;
174       ossim_uint32 upper = size();
175 
176       bool equalEndsFlag = false;
177       if(theVertexList[0] == theVertexList[theVertexList.size()-1])
178       {
179          equalEndsFlag = true;
180          prevI    = 0;
181          currentI = 1;
182          nextI    = 2;
183          i = 1;
184          --upper;
185       }
186       else
187       {
188          equalEndsFlag = false;
189          prevI    = size()-1;
190          currentI = 0;
191          nextI    = 1;
192       }
193       for(; i < upper;++i)
194       {
195          prev    = theVertexList[prevI];
196          current = theVertexList[currentI];
197          next    = theVertexList[nextI];
198 
199          ossimDpt averageNormal;
200 
201          ossimDpt diffPrev = current - prev;
202          ossimDpt diffNext = next - current;
203 
204          diffPrev = diffPrev*(1.0/diffPrev.length());
205          diffNext = diffNext*(1.0/diffNext.length());
206 
207          ossimDpt diffPrevNormal(-diffPrev.y,
208                                  diffPrev.x);
209          ossimDpt diffNextNormal(-diffNext.y,
210                                  diffNext.x);
211 
212          averageNormal     = (diffPrevNormal + diffNextNormal);
213          averageNormal     = averageNormal*(signMult*(1.0/averageNormal.length()));
214          ossimDpt newPoint = ossimDpt( theVertexList[i].lond(),
215                                        theVertexList[i].latd()) +
216                              averageNormal*displacement;
217          newPolygon[i].latd(newPoint.lat);
218          newPolygon[i].lond(newPoint.lon);
219          newPolygon[i].height(theVertexList[i].height());
220          newPolygon[i].datum(datum);
221 
222          ++prevI;
223          ++currentI;
224          ++nextI;
225 
226          prevI%=size();
227          nextI%=size();
228       }
229       if(equalEndsFlag)
230       {
231 
232          prev    = theVertexList[theVertexList.size()-2];
233          current = theVertexList[0];
234          next    = theVertexList[1];
235 
236          ossimDpt averageNormal;
237 
238          ossimDpt diffPrev = current - prev;
239          ossimDpt diffNext = next - current;
240 
241          diffPrev = diffPrev*(1.0/diffPrev.length());
242          diffNext = diffNext*(1.0/diffNext.length());
243 
244          ossimDpt diffPrevNormal(-diffPrev.y,
245                                  diffPrev.x);
246          ossimDpt diffNextNormal(-diffNext.y,
247                                  diffNext.x);
248 
249          averageNormal     = (diffPrevNormal + diffNextNormal);
250          averageNormal     = averageNormal*(signMult*(1.0/averageNormal.length()));
251          ossimDpt newPoint = ossimDpt( theVertexList[i].lond(),
252                                        theVertexList[i].latd()) +
253                              averageNormal*displacement;
254          newPolygon[0].latd(newPoint.lat);
255          newPolygon[0].lond(newPoint.lon);
256          newPolygon[0].height(theVertexList[i].height());
257          newPolygon[0].datum(datum);
258 
259          newPolygon[(int)theVertexList.size()-1] = newPolygon[0];
260       }
261    }
262 }
263 
264 
area() const265 double ossimGeoPolygon::area()const
266 {
267    double area = 0;
268    ossim_uint32 i=0;
269    ossim_uint32 j=0;
270    ossim_uint32 size = (ossim_uint32)theVertexList.size();
271 
272    for (i=0;i<size;i++)
273    {
274       j = (i + 1) % size;
275       area += theVertexList[i].lon * theVertexList[j].lat;
276       area -= theVertexList[i].lat * theVertexList[j].lon;
277    }
278 
279    area /= 2;
280 
281    return area;
282 }
283 
reverseOrder()284 void ossimGeoPolygon::reverseOrder()
285 {
286    std::reverse(theVertexList.begin(), theVertexList.end());
287 
288    if(theOrderingType == OSSIM_COUNTERCLOCKWISE_ORDER)
289    {
290       theOrderingType = OSSIM_CLOCKWISE_ORDER;
291    }
292    else if(theOrderingType == OSSIM_CLOCKWISE_ORDER)
293    {
294       theOrderingType =  OSSIM_COUNTERCLOCKWISE_ORDER;
295    }
296 
297 }
298 
checkOrdering() const299 void ossimGeoPolygon::checkOrdering()const
300 {
301    if(theOrderingType == OSSIM_VERTEX_ORDER_UNKNOWN)
302    {
303       double areaValue = area();
304       if(areaValue > 0)
305       {
306          theOrderingType = OSSIM_COUNTERCLOCKWISE_ORDER;
307       }
308       else if(areaValue <= 0)
309       {
310          theOrderingType = OSSIM_CLOCKWISE_ORDER;
311       }
312    }
313 }
314 
computeCentroid() const315 ossimGpt ossimGeoPolygon::computeCentroid()const
316 {
317    if(!size())
318    {
319       return ossimGpt();
320    }
321    ossimDpt average(0.0,0.0);
322    double height=0.0;
323    for(ossim_uint32 i = 0; i < size(); ++i)
324    {
325       average += ossimDpt(theVertexList[i]);
326       height  += theVertexList[i].height();
327    }
328 
329 
330    average.x /= size();
331    average.y /= size();
332    height    /= size();
333 
334    return ossimGpt(average.y, average.x, height, theVertexList[0].datum());
335 }
336 
saveState(ossimKeywordlist & kwl,const char * prefix) const337 bool ossimGeoPolygon::saveState(ossimKeywordlist& kwl,
338                                 const char* prefix)const
339 {
340    int i = 0;
341 
342    kwl.add(prefix,
343            ossimKeywordNames::TYPE_KW,
344            "ossimGeoPolygon",
345            true);
346    kwl.add(prefix,
347            NUMBER_VERTICES_KW,
348            static_cast<ossim_uint32>(theVertexList.size()),
349            true);
350    if(theVertexList.size())
351    {
352       kwl.add(prefix,
353               ossimKeywordNames::DATUM_KW,
354               theVertexList[0].datum()->code(),
355               true);
356    }
357    else
358    {
359       kwl.add(prefix,
360               ossimKeywordNames::DATUM_KW,
361               "WGE",
362               true);
363    }
364 
365    for(i = 0; i < (int)theVertexList.size();++i)
366    {
367       ossimString vert = "v"+ossimString::toString(i);
368       ossimString value = (ossimString::toString(theVertexList[i].latd()) + " " +
369                            ossimString::toString(theVertexList[i].lond())  + " " +
370                            ( theVertexList[i].isHgtNan()?ossimString("nan"):ossimString::toString(theVertexList[i].height())));
371       kwl.add(prefix,
372               vert.c_str(),
373               value.c_str(),
374               true);
375    }
376 
377    return true;
378 }
379 
loadState(const ossimKeywordlist & kwl,const char * prefix)380 bool ossimGeoPolygon::loadState(const ossimKeywordlist& kwl,
381                                 const char* prefix)
382 {
383    const char* number_vertices = kwl.find(prefix, NUMBER_VERTICES_KW);
384    ossimString datumStr = kwl.find(prefix, ossimKeywordNames::DATUM_KW);
385    const ossimDatum* datum = ossimDatumFactoryRegistry::instance()->create(datumStr);
386 
387    theVertexList.clear();
388    int i = 0;
389    int vertexCount = ossimString(number_vertices).toLong();
390    ossimString lat, lon, height;
391    for(i = 0; i < vertexCount; ++i)
392    {
393       ossimString v = kwl.find(prefix, (ossimString("v")+ossimString::toString(i)).c_str());
394       ossimString latString, lonString, heightString;
395       v = v.trim();
396       std::istringstream in(v);
397       in>>lat>>lon>>height;
398       theVertexList.push_back(ossimGpt(lat.toDouble(), lon.toDouble(), height.toDouble(), datum));
399    }
400 
401    return true;
402 }
403