1 : /******************************************************************************
2 : * $Id: ogrpoint.cpp 22448 2011-05-28 18:49:54Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: The Point geometry class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_geometry.h"
31 : #include "ogr_p.h"
32 :
33 : CPL_CVSID("$Id: ogrpoint.cpp 22448 2011-05-28 18:49:54Z rouault $");
34 :
35 : /************************************************************************/
36 : /* OGRPoint() */
37 : /************************************************************************/
38 :
39 : /**
40 : * \brief Create a (0,0) point.
41 : */
42 :
43 23297 : OGRPoint::OGRPoint()
44 :
45 : {
46 23297 : empty();
47 23297 : }
48 :
49 : /************************************************************************/
50 : /* OGRPoint() */
51 : /* */
52 : /* Initialize point to value. */
53 : /************************************************************************/
54 :
55 46118 : OGRPoint::OGRPoint( double xIn, double yIn, double zIn )
56 :
57 : {
58 46118 : x = xIn;
59 46118 : y = yIn;
60 46118 : z = zIn;
61 46118 : nCoordDimension = 3;
62 46118 : }
63 :
64 : /************************************************************************/
65 : /* OGRPoint() */
66 : /* */
67 : /* Initialize point to value. */
68 : /************************************************************************/
69 :
70 77532 : OGRPoint::OGRPoint( double xIn, double yIn )
71 :
72 : {
73 77532 : x = xIn;
74 77532 : y = yIn;
75 77532 : z = 0.0;
76 77532 : nCoordDimension = 2;
77 77532 : }
78 :
79 : /************************************************************************/
80 : /* ~OGRPoint() */
81 : /************************************************************************/
82 :
83 147029 : OGRPoint::~OGRPoint()
84 :
85 : {
86 147029 : }
87 :
88 : /************************************************************************/
89 : /* clone() */
90 : /* */
91 : /* Make a new object that is a copy of this object. */
92 : /************************************************************************/
93 :
94 20264 : OGRGeometry *OGRPoint::clone() const
95 :
96 : {
97 20264 : OGRPoint *poNewPoint = new OGRPoint( x, y, z );
98 :
99 20264 : poNewPoint->assignSpatialReference( getSpatialReference() );
100 20264 : poNewPoint->setCoordinateDimension( nCoordDimension );
101 :
102 20264 : return poNewPoint;
103 : }
104 :
105 : /************************************************************************/
106 : /* empty() */
107 : /************************************************************************/
108 23326 : void OGRPoint::empty()
109 :
110 : {
111 23326 : x = y = z = 0.0;
112 23326 : nCoordDimension = 0;
113 23326 : }
114 :
115 : /************************************************************************/
116 : /* getDimension() */
117 : /************************************************************************/
118 :
119 1 : int OGRPoint::getDimension() const
120 :
121 : {
122 1 : return 0;
123 : }
124 :
125 : /************************************************************************/
126 : /* getGeometryType() */
127 : /************************************************************************/
128 :
129 71268 : OGRwkbGeometryType OGRPoint::getGeometryType() const
130 :
131 : {
132 71268 : if( nCoordDimension < 3 )
133 15588 : return wkbPoint;
134 : else
135 55680 : return wkbPoint25D;
136 : }
137 :
138 : /************************************************************************/
139 : /* getGeometryName() */
140 : /************************************************************************/
141 :
142 719 : const char * OGRPoint::getGeometryName() const
143 :
144 : {
145 719 : return "POINT";
146 : }
147 :
148 : /************************************************************************/
149 : /* flattenTo2D() */
150 : /************************************************************************/
151 :
152 2299 : void OGRPoint::flattenTo2D()
153 :
154 : {
155 2299 : z = 0;
156 2299 : if (nCoordDimension > 2)
157 2 : nCoordDimension = 2;
158 2299 : }
159 :
160 : /************************************************************************/
161 : /* setCoordinateDimension() */
162 : /************************************************************************/
163 :
164 20925 : void OGRPoint::setCoordinateDimension( int nNewDimension )
165 :
166 : {
167 20925 : nCoordDimension = nNewDimension;
168 :
169 20925 : if( nCoordDimension == 2 )
170 5660 : z = 0;
171 20925 : }
172 :
173 : /************************************************************************/
174 : /* WkbSize() */
175 : /* */
176 : /* Return the size of this object in well known binary */
177 : /* representation including the byte order, and type information. */
178 : /************************************************************************/
179 :
180 479 : int OGRPoint::WkbSize() const
181 :
182 : {
183 479 : if( nCoordDimension != 3 )
184 288 : return 21;
185 : else
186 191 : return 29;
187 : }
188 :
189 : /************************************************************************/
190 : /* importFromWkb() */
191 : /* */
192 : /* Initialize from serialized stream in well known binary */
193 : /* format. */
194 : /************************************************************************/
195 :
196 403 : OGRErr OGRPoint::importFromWkb( unsigned char * pabyData,
197 : int nSize )
198 :
199 : {
200 : OGRwkbByteOrder eByteOrder;
201 :
202 403 : if( nSize < 21 && nSize != -1 )
203 0 : return OGRERR_NOT_ENOUGH_DATA;
204 :
205 : /* -------------------------------------------------------------------- */
206 : /* Get the byte order byte. */
207 : /* -------------------------------------------------------------------- */
208 403 : eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
209 403 : if (!( eByteOrder == wkbXDR || eByteOrder == wkbNDR ))
210 0 : return OGRERR_CORRUPT_DATA;
211 :
212 : /* -------------------------------------------------------------------- */
213 : /* Get the geometry feature type. For now we assume that */
214 : /* geometry type is between 0 and 255 so we only have to fetch */
215 : /* one byte. */
216 : /* -------------------------------------------------------------------- */
217 : OGRwkbGeometryType eGeometryType;
218 : int bIs3D;
219 :
220 403 : if( eByteOrder == wkbNDR )
221 : {
222 382 : eGeometryType = (OGRwkbGeometryType) pabyData[1];
223 382 : bIs3D = pabyData[4] & 0x80 || pabyData[2] & 0x80;
224 : }
225 : else
226 : {
227 21 : eGeometryType = (OGRwkbGeometryType) pabyData[4];
228 21 : bIs3D = pabyData[1] & 0x80 || pabyData[3] & 0x80;
229 : }
230 :
231 403 : if( eGeometryType != wkbPoint )
232 0 : return OGRERR_CORRUPT_DATA;
233 :
234 : /* -------------------------------------------------------------------- */
235 : /* Get the vertex. */
236 : /* -------------------------------------------------------------------- */
237 403 : memcpy( &x, pabyData + 5, 16 );
238 :
239 403 : if( OGR_SWAP( eByteOrder ) )
240 : {
241 21 : CPL_SWAPDOUBLE( &x );
242 21 : CPL_SWAPDOUBLE( &y );
243 : }
244 :
245 403 : if( bIs3D )
246 : {
247 166 : if ( nSize < 29 && nSize != -1 )
248 0 : return OGRERR_NOT_ENOUGH_DATA;
249 :
250 166 : memcpy( &z, pabyData + 5 + 16, 8 );
251 166 : if( OGR_SWAP( eByteOrder ) )
252 : {
253 3 : CPL_SWAPDOUBLE( &z );
254 : }
255 166 : nCoordDimension = 3;
256 : }
257 : else
258 : {
259 237 : z = 0;
260 237 : nCoordDimension = 2;
261 : }
262 :
263 403 : return OGRERR_NONE;
264 : }
265 :
266 : /************************************************************************/
267 : /* exportToWkb() */
268 : /* */
269 : /* Build a well known binary representation of this object. */
270 : /************************************************************************/
271 :
272 134 : OGRErr OGRPoint::exportToWkb( OGRwkbByteOrder eByteOrder,
273 : unsigned char * pabyData ) const
274 :
275 : {
276 : /* -------------------------------------------------------------------- */
277 : /* Set the byte order. */
278 : /* -------------------------------------------------------------------- */
279 134 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
280 :
281 : /* -------------------------------------------------------------------- */
282 : /* Set the geometry feature type. */
283 : /* -------------------------------------------------------------------- */
284 134 : GUInt32 nGType = getGeometryType();
285 :
286 134 : if( eByteOrder == wkbNDR )
287 115 : nGType = CPL_LSBWORD32( nGType );
288 : else
289 19 : nGType = CPL_MSBWORD32( nGType );
290 :
291 134 : memcpy( pabyData + 1, &nGType, 4 );
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Copy in the raw data. */
295 : /* -------------------------------------------------------------------- */
296 134 : memcpy( pabyData+5, &x, 16 );
297 :
298 134 : if( nCoordDimension == 3 )
299 : {
300 31 : memcpy( pabyData + 5 + 16, &z, 8 );
301 : }
302 :
303 : /* -------------------------------------------------------------------- */
304 : /* Swap if needed. */
305 : /* -------------------------------------------------------------------- */
306 134 : if( OGR_SWAP( eByteOrder ) )
307 : {
308 19 : CPL_SWAPDOUBLE( pabyData + 5 );
309 19 : CPL_SWAPDOUBLE( pabyData + 5 + 8 );
310 :
311 19 : if( nCoordDimension == 3 )
312 3 : CPL_SWAPDOUBLE( pabyData + 5 + 16 );
313 : }
314 :
315 134 : return OGRERR_NONE;
316 : }
317 :
318 : /************************************************************************/
319 : /* importFromWkt() */
320 : /* */
321 : /* Instantiate point from well known text format ``POINT */
322 : /* (x,y)''. */
323 : /************************************************************************/
324 :
325 16931 : OGRErr OGRPoint::importFromWkt( char ** ppszInput )
326 :
327 : {
328 : char szToken[OGR_WKT_TOKEN_MAX];
329 16931 : const char *pszInput = *ppszInput;
330 :
331 : /* -------------------------------------------------------------------- */
332 : /* Read and verify the ``POINT'' keyword token. */
333 : /* -------------------------------------------------------------------- */
334 16931 : pszInput = OGRWktReadToken( pszInput, szToken );
335 :
336 16931 : if( !EQUAL(szToken,"POINT") )
337 0 : return OGRERR_CORRUPT_DATA;
338 :
339 : /* -------------------------------------------------------------------- */
340 : /* Check for EMPTY ... but treat like a point at 0,0. */
341 : /* -------------------------------------------------------------------- */
342 : const char *pszPreScan;
343 16931 : int bHasZ = FALSE, bHasM = FALSE;
344 :
345 16931 : pszPreScan = OGRWktReadToken( pszInput, szToken );
346 16931 : if( EQUAL(szToken,"EMPTY") )
347 : {
348 9 : *ppszInput = (char *) pszPreScan;
349 9 : empty();
350 9 : return OGRERR_NONE;
351 : }
352 :
353 : /* -------------------------------------------------------------------- */
354 : /* Check for Z, M or ZM. Will ignore the Measure */
355 : /* -------------------------------------------------------------------- */
356 16922 : else if( EQUAL(szToken,"Z") )
357 : {
358 11 : bHasZ = TRUE;
359 : }
360 16911 : else if( EQUAL(szToken,"M") )
361 : {
362 3 : bHasM = TRUE;
363 : }
364 16908 : else if( EQUAL(szToken,"ZM") )
365 : {
366 3 : bHasZ = TRUE;
367 3 : bHasM = TRUE;
368 : }
369 :
370 16922 : if (bHasZ || bHasM)
371 : {
372 17 : pszInput = pszPreScan;
373 17 : pszPreScan = OGRWktReadToken( pszInput, szToken );
374 17 : if( EQUAL(szToken,"EMPTY") )
375 : {
376 4 : *ppszInput = (char *) pszPreScan;
377 4 : empty();
378 : /* FIXME?: In theory we should store the dimension and M presence */
379 : /* if we want to allow round-trip with ExportToWKT v1.2 */
380 4 : return OGRERR_NONE;
381 : }
382 : }
383 :
384 16918 : if( !EQUAL(szToken,"(") )
385 4 : return OGRERR_CORRUPT_DATA;
386 :
387 16914 : if ( !bHasZ && !bHasM )
388 : {
389 : /* Test for old-style POINT(EMPTY) */
390 16903 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
391 16903 : if( EQUAL(szToken,"EMPTY") )
392 : {
393 3 : pszInput = OGRWktReadToken( pszPreScan, szToken );
394 :
395 3 : if( !EQUAL(szToken,")") )
396 1 : return OGRERR_CORRUPT_DATA;
397 : else
398 : {
399 2 : *ppszInput = (char *) pszInput;
400 2 : empty();
401 2 : return OGRERR_NONE;
402 : }
403 : }
404 : }
405 :
406 : /* -------------------------------------------------------------------- */
407 : /* Read the point list which should consist of exactly one point. */
408 : /* -------------------------------------------------------------------- */
409 16911 : OGRRawPoint *poPoints = NULL;
410 16911 : double *padfZ = NULL;
411 16911 : int nMaxPoint = 0, nPoints = 0;
412 :
413 : pszInput = OGRWktReadPoints( pszInput, &poPoints, &padfZ,
414 16911 : &nMaxPoint, &nPoints );
415 16911 : if( pszInput == NULL || nPoints != 1 )
416 : {
417 15 : CPLFree( poPoints );
418 15 : CPLFree( padfZ );
419 15 : return OGRERR_CORRUPT_DATA;
420 : }
421 :
422 16896 : x = poPoints[0].x;
423 16896 : y = poPoints[0].y;
424 :
425 16896 : CPLFree( poPoints );
426 :
427 16896 : if( padfZ != NULL )
428 : {
429 : /* If there's a 3rd value, and it is not a POINT M, */
430 : /* then assume it is the Z */
431 29508 : if ((!(bHasM && !bHasZ)))
432 : {
433 14753 : z = padfZ[0];
434 14753 : nCoordDimension = 3;
435 : }
436 : else
437 2 : nCoordDimension = 2;
438 14755 : CPLFree( padfZ );
439 : }
440 2141 : else if ( bHasZ )
441 : {
442 : /* In theory we should have a z coordinate for POINT Z */
443 : /* oh well, let be tolerant */
444 0 : nCoordDimension = 3;
445 : }
446 : else
447 2141 : nCoordDimension = 2;
448 :
449 16896 : *ppszInput = (char *) pszInput;
450 :
451 16896 : return OGRERR_NONE;
452 : }
453 :
454 : /************************************************************************/
455 : /* exportToWkt() */
456 : /* */
457 : /* Translate this structure into it's well known text format */
458 : /* equivelent. */
459 : /************************************************************************/
460 :
461 724 : OGRErr OGRPoint::exportToWkt( char ** ppszDstText ) const
462 :
463 : {
464 : char szTextEquiv[140];
465 : char szCoordinate[80];
466 :
467 724 : if (nCoordDimension == 0)
468 12 : *ppszDstText = CPLStrdup( "POINT EMPTY" );
469 : else
470 : {
471 712 : OGRMakeWktCoordinate(szCoordinate, x, y, z, nCoordDimension );
472 712 : sprintf( szTextEquiv, "POINT (%s)", szCoordinate );
473 712 : *ppszDstText = CPLStrdup( szTextEquiv );
474 : }
475 :
476 724 : return OGRERR_NONE;
477 : }
478 :
479 : /************************************************************************/
480 : /* getEnvelope() */
481 : /************************************************************************/
482 :
483 27753 : void OGRPoint::getEnvelope( OGREnvelope * psEnvelope ) const
484 :
485 : {
486 27753 : psEnvelope->MinX = psEnvelope->MaxX = getX();
487 27753 : psEnvelope->MinY = psEnvelope->MaxY = getY();
488 27753 : }
489 :
490 : /************************************************************************/
491 : /* getEnvelope() */
492 : /************************************************************************/
493 :
494 77 : void OGRPoint::getEnvelope( OGREnvelope3D * psEnvelope ) const
495 :
496 : {
497 77 : psEnvelope->MinX = psEnvelope->MaxX = getX();
498 77 : psEnvelope->MinY = psEnvelope->MaxY = getY();
499 77 : psEnvelope->MinZ = psEnvelope->MaxZ = getZ();
500 77 : }
501 :
502 :
503 : /**
504 : * \fn double OGRPoint::getX() const;
505 : *
506 : * \brief Fetch X coordinate.
507 : *
508 : * Relates to the SFCOM IPoint::get_X() method.
509 : *
510 : * @return the X coordinate of this point.
511 : */
512 :
513 : /**
514 : * \fn double OGRPoint::getY() const;
515 : *
516 : * \brief Fetch Y coordinate.
517 : *
518 : * Relates to the SFCOM IPoint::get_Y() method.
519 : *
520 : * @return the Y coordinate of this point.
521 : */
522 :
523 : /**
524 : * \fn double OGRPoint::getZ() const;
525 : *
526 : * \brief Fetch Z coordinate.
527 : *
528 : * Relates to the SFCOM IPoint::get_Z() method.
529 : *
530 : * @return the Z coordinate of this point, or zero if it is a 2D point.
531 : */
532 :
533 : /**
534 : * \fn void OGRPoint::setX( double xIn );
535 : *
536 : * \brief Assign point X coordinate.
537 : *
538 : * There is no corresponding SFCOM method.
539 : */
540 :
541 : /**
542 : * \fn void OGRPoint::setY( double yIn );
543 : *
544 : * \brief Assign point Y coordinate.
545 : *
546 : * There is no corresponding SFCOM method.
547 : */
548 :
549 : /**
550 : * \fn void OGRPoint::setZ( double zIn );
551 : *
552 : * \brief Assign point Z coordinate.
553 : * Calling this method will force the geometry
554 : * coordinate dimension to 3D (wkbPoint|wkbZ).
555 : *
556 : * There is no corresponding SFCOM method.
557 : */
558 :
559 : /************************************************************************/
560 : /* Equal() */
561 : /************************************************************************/
562 :
563 1186 : OGRBoolean OGRPoint::Equals( OGRGeometry * poOther ) const
564 :
565 : {
566 1186 : OGRPoint *poOPoint = (OGRPoint *) poOther;
567 :
568 1186 : if( poOPoint== this )
569 0 : return TRUE;
570 :
571 1186 : if( poOther->getGeometryType() != getGeometryType() )
572 0 : return FALSE;
573 :
574 : // we should eventually test the SRS.
575 :
576 1186 : if( poOPoint->getX() != getX()
577 : || poOPoint->getY() != getY()
578 : || poOPoint->getZ() != getZ() )
579 25 : return FALSE;
580 : else
581 1161 : return TRUE;
582 : }
583 :
584 : /************************************************************************/
585 : /* transform() */
586 : /************************************************************************/
587 :
588 285 : OGRErr OGRPoint::transform( OGRCoordinateTransformation *poCT )
589 :
590 : {
591 : #ifdef DISABLE_OGRGEOM_TRANSFORM
592 : return OGRERR_FAILURE;
593 : #else
594 285 : if( poCT->Transform( 1, &x, &y, &z ) )
595 : {
596 285 : assignSpatialReference( poCT->GetTargetCS() );
597 285 : return OGRERR_NONE;
598 : }
599 : else
600 0 : return OGRERR_FAILURE;
601 : #endif
602 : }
603 :
604 : /************************************************************************/
605 : /* IsEmpty() */
606 : /************************************************************************/
607 :
608 29702 : OGRBoolean OGRPoint::IsEmpty( ) const
609 : {
610 29702 : return nCoordDimension == 0;
611 : }
612 :
613 : /************************************************************************/
614 : /* swapXY() */
615 : /************************************************************************/
616 :
617 55 : void OGRPoint::swapXY()
618 : {
619 55 : double dfTemp = x;
620 55 : x = y;
621 55 : y = dfTemp;
622 55 : }
|