1 /******************************************************************************
2  *
3  * Project:  OpenGIS Simple Features Reference Implementation
4  * Purpose:  The OGRLinearRing geometry class.
5  * Author:   Frank Warmerdam, warmerda@home.com
6  *
7  ******************************************************************************
8  * Copyright (c) 1999, Frank Warmerdam
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ******************************************************************************
28  *
29  * $Log: ogrlinearring.cpp,v $
30  * Revision 1.1.1.1  2006/08/21 05:52:19  dsr
31  * Initial import as opencpn, GNU Automake compliant.
32  *
33  * Revision 1.1.1.1  2006/04/19 03:23:28  dsr
34  * Rename/Import to OpenCPN
35  *
36  * Revision 1.16  2004/02/21 15:36:14  warmerda
37  * const correctness updates for geometry: bug 289
38  *
39  * Revision 1.15  2003/09/11 22:47:54  aamici
40  * add class constructors and destructors where needed in order to
41  * let the mingw/cygwin binutils produce sensible partially linked objet files
42  * with 'ld -r'.
43  *
44  * Revision 1.14  2003/07/08 13:59:35  warmerda
45  * added poSrcRing check in copy constructor, bug 361
46  *
47  * Revision 1.13  2003/05/28 19:16:42  warmerda
48  * fixed up argument names and stuff for docs
49  *
50  * Revision 1.12  2003/01/14 22:13:35  warmerda
51  * added isClockwise() method on OGRLinearRing
52  *
53  * Revision 1.11  2002/10/24 20:38:45  warmerda
54  * fixed bug byte swapping point count in exporttowkb
55  *
56  * Revision 1.10  2002/05/02 19:44:53  warmerda
57  * fixed 3D binary support for polygon/linearring
58  *
59  * Revision 1.9  2002/04/17 21:46:22  warmerda
60  * Ensure padfZ copied in copy constructor.
61  *
62  * Revision 1.8  2002/02/22 22:24:31  warmerda
63  * fixed 3d support in clone
64  *
65  * Revision 1.7  2001/07/18 05:03:05  warmerda
66  *
67  * Revision 1.6  1999/11/18 19:02:19  warmerda
68  * expanded tabs
69  *
70  * Revision 1.5  1999/07/08 20:25:39  warmerda
71  * Remove getGeometryType() method ... now returns wkbLineString.
72  *
73  * Revision 1.4  1999/06/25 20:44:43  warmerda
74  * implemented assignSpatialReference, carry properly
75  *
76  * Revision 1.3  1999/05/23 05:34:40  warmerda
77  * added support for clone(), multipolygons and geometry collections
78  *
79  * Revision 1.2  1999/05/20 14:35:44  warmerda
80  * added support for well known text format
81  *
82  * Revision 1.1  1999/03/30 21:21:05  warmerda
83  * New
84  *
85  */
86 
87 #include "ogr_geometry.h"
88 #include "ogr_p.h"
89 
90 /************************************************************************/
91 /*                           OGRLinearRing()                            */
92 /************************************************************************/
93 
OGRLinearRing()94 OGRLinearRing::OGRLinearRing()
95 
96 {
97 }
98 
99 /************************************************************************/
100 /*                          ~OGRLinearRing()                            */
101 /************************************************************************/
~OGRLinearRing()102 OGRLinearRing::~OGRLinearRing()
103 
104 {
105 }
106 
107 /************************************************************************/
108 /*                           OGRLinearRing()                            */
109 /************************************************************************/
110 
OGRLinearRing(OGRLinearRing * poSrcRing)111 OGRLinearRing::OGRLinearRing( OGRLinearRing * poSrcRing )
112 
113 {
114     if( poSrcRing == NULL )
115     {
116         CPLDebug( "OGR", "OGRLinearRing::OGRLinearRing(OGRLinearRing*poSrcRing) - passed in ring is NULL!" );
117         return;
118     }
119 
120     setNumPoints( poSrcRing->getNumPoints() );
121 
122     memcpy( paoPoints, poSrcRing->paoPoints,
123             sizeof(OGRRawPoint) * getNumPoints() );
124 
125     if( poSrcRing->padfZ )
126     {
127         Make3D();
128         memcpy( padfZ, poSrcRing->padfZ, sizeof(double) * getNumPoints() );
129     }
130 }
131 
132 /************************************************************************/
133 /*                          getGeometryName()                           */
134 /************************************************************************/
135 
getGeometryName() const136 const char * OGRLinearRing::getGeometryName() const
137 
138 {
139     return "LINEARRING";
140 }
141 
142 /************************************************************************/
143 /*                              WkbSize()                               */
144 /*                                                                      */
145 /*      Disable this method.                                            */
146 /************************************************************************/
147 
WkbSize() const148 int OGRLinearRing::WkbSize() const
149 
150 {
151     return 0;
152 }
153 
154 /************************************************************************/
155 /*                           importFromWkb()                            */
156 /*                                                                      */
157 /*      Disable method for this class.                                  */
158 /************************************************************************/
159 
importFromWkb(unsigned char * pabyData,int nSize)160 OGRErr OGRLinearRing::importFromWkb( unsigned char *pabyData, int nSize )
161 
162 {
163     (void) pabyData;
164     (void) nSize;
165 
166     return OGRERR_UNSUPPORTED_OPERATION;
167 }
168 
169 /************************************************************************/
170 /*                            exportToWkb()                             */
171 /*                                                                      */
172 /*      Disable method for this class.                                  */
173 /************************************************************************/
174 
exportToWkb(OGRwkbByteOrder eByteOrder,unsigned char * pabyData) const175 OGRErr OGRLinearRing::exportToWkb( OGRwkbByteOrder eByteOrder,
176                                    unsigned char * pabyData ) const
177 
178 {
179     (void) eByteOrder;
180     (void) pabyData;
181 
182     return OGRERR_UNSUPPORTED_OPERATION;
183 }
184 
185 /************************************************************************/
186 /*                           _importFromWkb()                           */
187 /*                                                                      */
188 /*      Helper method for OGRPolygon.  NOT A NORMAL importFromWkb()     */
189 /*      method!                                                         */
190 /************************************************************************/
191 
_importFromWkb(OGRwkbByteOrder eByteOrder,int b3D,unsigned char * pabyData,int nBytesAvailable)192 OGRErr OGRLinearRing::_importFromWkb( OGRwkbByteOrder eByteOrder, int b3D,
193                                       unsigned char * pabyData,
194                                       int nBytesAvailable )
195 
196 {
197     if( nBytesAvailable < 4 && nBytesAvailable != -1 )
198         return OGRERR_NOT_ENOUGH_DATA;
199 
200 /* -------------------------------------------------------------------- */
201 /*      Get the vertex count.                                           */
202 /* -------------------------------------------------------------------- */
203     int         nNewNumPoints;
204 
205     memcpy( &nNewNumPoints, pabyData, 4 );
206 
207     if( OGR_SWAP( eByteOrder ) )
208         nNewNumPoints = CPL_SWAP32(nNewNumPoints);
209 
210     setNumPoints( nNewNumPoints );
211 
212     if( b3D )
213         Make3D();
214     else
215         Make2D();
216 
217 /* -------------------------------------------------------------------- */
218 /*      Get the vertices                                                */
219 /* -------------------------------------------------------------------- */
220     int i;
221 
222     if( !b3D )
223         memcpy( paoPoints, pabyData + 4, 16 * nPointCount );
224     else
225     {
226         for( int i = 0; i < nPointCount; i++ )
227         {
228             memcpy( &(paoPoints[i].x), pabyData + 4 + 24 * i, 8 );
229             memcpy( &(paoPoints[i].y), pabyData + 4 + 24 * i + 8, 8 );
230             memcpy( padfZ + i, pabyData + 4 + 24 * i + 16, 8 );
231         }
232     }
233 
234 /* -------------------------------------------------------------------- */
235 /*      Byte swap if needed.                                            */
236 /* -------------------------------------------------------------------- */
237     if( OGR_SWAP( eByteOrder ) )
238     {
239         for( i = 0; i < nPointCount; i++ )
240         {
241             CPL_SWAPDOUBLE( &(paoPoints[i].x) );
242             CPL_SWAPDOUBLE( &(paoPoints[i].y) );
243 
244             if( b3D )
245             {
246                 CPL_SWAPDOUBLE( padfZ + i );
247             }
248         }
249     }
250 
251     return OGRERR_NONE;
252 }
253 
254 /************************************************************************/
255 /*                            _exportToWkb()                            */
256 /*                                                                      */
257 /*      Helper method for OGRPolygon.  THIS IS NOT THE NORMAL           */
258 /*      exportToWkb() METHOD!                                           */
259 /************************************************************************/
260 
_exportToWkb(OGRwkbByteOrder eByteOrder,int b3D,unsigned char * pabyData) const261 OGRErr  OGRLinearRing::_exportToWkb( OGRwkbByteOrder eByteOrder, int b3D,
262                                      unsigned char * pabyData ) const
263 
264 {
265     int   i, nWords;
266 
267 /* -------------------------------------------------------------------- */
268 /*      Copy in the raw data.                                           */
269 /* -------------------------------------------------------------------- */
270     memcpy( pabyData, &nPointCount, 4 );
271 
272 /* -------------------------------------------------------------------- */
273 /*      Copy in the raw data.                                           */
274 /* -------------------------------------------------------------------- */
275     if( b3D )
276     {
277         nWords = 3 * nPointCount;
278         for( i = 0; i < nPointCount; i++ )
279         {
280             memcpy( pabyData+4+i*24, &(paoPoints[i].x), 8 );
281             memcpy( pabyData+4+i*24+8, &(paoPoints[i].y), 8 );
282             if( padfZ == NULL )
283                 memset( pabyData+4+i*24+16, 0, 8 );
284             else
285                 memcpy( pabyData+4+i*24+16, padfZ + i, 8 );
286         }
287     }
288     else
289     {
290         nWords = 2 * nPointCount;
291         memcpy( pabyData+4, paoPoints, 16 * nPointCount );
292     }
293 
294 /* -------------------------------------------------------------------- */
295 /*      Swap if needed.                                                 */
296 /* -------------------------------------------------------------------- */
297     if( OGR_SWAP( eByteOrder ) )
298     {
299         int     nCount;
300 
301         nCount = CPL_SWAP32( nPointCount );
302         memcpy( pabyData, &nCount, 4 );
303 
304         for( i = 0; i < nWords; i++ )
305         {
306             CPL_SWAPDOUBLE( pabyData + 4 + 8 * i );
307         }
308     }
309 
310     return OGRERR_NONE;
311 }
312 
313 /************************************************************************/
314 /*                              _WkbSize()                              */
315 /*                                                                      */
316 /*      Helper method for OGRPolygon.  NOT THE NORMAL WkbSize() METHOD! */
317 /************************************************************************/
318 
_WkbSize(int b3D) const319 int OGRLinearRing::_WkbSize( int b3D ) const
320 
321 {
322     if( b3D )
323         return 4 + 24 * nPointCount;
324     else
325         return 4 + 16 * nPointCount;
326 }
327 
328 /************************************************************************/
329 /*                               clone()                                */
330 /*                                                                      */
331 /*      We override the OGRCurve clone() to ensure that we get the      */
332 /*      correct virtual table.                                          */
333 /************************************************************************/
334 
clone() const335 OGRGeometry *OGRLinearRing::clone() const
336 
337 {
338     OGRLinearRing       *poNewLinearRing;
339 
340     poNewLinearRing = new OGRLinearRing();
341     poNewLinearRing->assignSpatialReference( getSpatialReference() );
342 
343     poNewLinearRing->setPoints( nPointCount, paoPoints, padfZ );
344 
345     return poNewLinearRing;
346 }
347 
348 /************************************************************************/
349 /*                            isClockwise()                             */
350 /************************************************************************/
351 
352 /**
353  * Returns TRUE if the ring has clockwise winding.
354  *
355  * @return TRUE if clockwise otherwise FALSE.
356  */
357 
isClockwise() const358 int OGRLinearRing::isClockwise() const
359 
360 {
361     double dfSum = 0.0;
362 
363     for( int iVert = 0; iVert < nPointCount-1; iVert++ )
364     {
365         dfSum += paoPoints[iVert].x * paoPoints[iVert+1].y
366             - paoPoints[iVert].y * paoPoints[iVert+1].x;
367     }
368 
369     dfSum += paoPoints[nPointCount-1].x * paoPoints[0].y
370         - paoPoints[nPointCount-1].y * paoPoints[0].x;
371 
372     return dfSum < 0.0;
373 }
374 
375