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 19180 : OGRPoint::OGRPoint()
44 :
45 : {
46 19180 : empty();
47 19180 : }
48 :
49 : /************************************************************************/
50 : /* OGRPoint() */
51 : /* */
52 : /* Initialize point to value. */
53 : /************************************************************************/
54 :
55 45399 : OGRPoint::OGRPoint( double xIn, double yIn, double zIn )
56 :
57 : {
58 45399 : x = xIn;
59 45399 : y = yIn;
60 45399 : z = zIn;
61 45399 : nCoordDimension = 3;
62 45399 : }
63 :
64 : /************************************************************************/
65 : /* OGRPoint() */
66 : /* */
67 : /* Initialize point to value. */
68 : /************************************************************************/
69 :
70 63693 : OGRPoint::OGRPoint( double xIn, double yIn )
71 :
72 : {
73 63693 : x = xIn;
74 63693 : y = yIn;
75 63693 : z = 0.0;
76 63693 : nCoordDimension = 2;
77 63693 : }
78 :
79 : /************************************************************************/
80 : /* ~OGRPoint() */
81 : /************************************************************************/
82 :
83 128423 : OGRPoint::~OGRPoint()
84 :
85 : {
86 128423 : }
87 :
88 : /************************************************************************/
89 : /* clone() */
90 : /* */
91 : /* Make a new object that is a copy of this object. */
92 : /************************************************************************/
93 :
94 20986 : OGRGeometry *OGRPoint::clone() const
95 :
96 : {
97 20986 : OGRPoint *poNewPoint = new OGRPoint( x, y, z );
98 :
99 20986 : poNewPoint->assignSpatialReference( getSpatialReference() );
100 20986 : poNewPoint->setCoordinateDimension( nCoordDimension );
101 :
102 20986 : return poNewPoint;
103 : }
104 :
105 : /************************************************************************/
106 : /* empty() */
107 : /************************************************************************/
108 19206 : void OGRPoint::empty()
109 :
110 : {
111 19206 : x = y = z = 0.0;
112 19206 : nCoordDimension = 0;
113 19206 : }
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 63329 : OGRwkbGeometryType OGRPoint::getGeometryType() const
130 :
131 : {
132 63329 : if( nCoordDimension < 3 )
133 9217 : return wkbPoint;
134 : else
135 54112 : return wkbPoint25D;
136 : }
137 :
138 : /************************************************************************/
139 : /* getGeometryName() */
140 : /************************************************************************/
141 :
142 378 : const char * OGRPoint::getGeometryName() const
143 :
144 : {
145 378 : return "POINT";
146 : }
147 :
148 : /************************************************************************/
149 : /* flattenTo2D() */
150 : /************************************************************************/
151 :
152 1997 : void OGRPoint::flattenTo2D()
153 :
154 : {
155 1997 : z = 0;
156 1997 : if (nCoordDimension > 2)
157 2 : nCoordDimension = 2;
158 1997 : }
159 :
160 : /************************************************************************/
161 : /* setCoordinateDimension() */
162 : /************************************************************************/
163 :
164 21268 : void OGRPoint::setCoordinateDimension( int nNewDimension )
165 :
166 : {
167 21268 : nCoordDimension = nNewDimension;
168 :
169 21268 : if( nCoordDimension == 2 )
170 6256 : z = 0;
171 21268 : }
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 398 : int OGRPoint::WkbSize() const
181 :
182 : {
183 398 : if( nCoordDimension != 3 )
184 241 : return 21;
185 : else
186 157 : return 29;
187 : }
188 :
189 : /************************************************************************/
190 : /* importFromWkb() */
191 : /* */
192 : /* Initialize from serialized stream in well known binary */
193 : /* format. */
194 : /************************************************************************/
195 :
196 344 : OGRErr OGRPoint::importFromWkb( unsigned char * pabyData,
197 : int nSize )
198 :
199 : {
200 : OGRwkbByteOrder eByteOrder;
201 :
202 344 : if( nSize < 21 && nSize != -1 )
203 0 : return OGRERR_NOT_ENOUGH_DATA;
204 :
205 : /* -------------------------------------------------------------------- */
206 : /* Get the byte order byte. */
207 : /* -------------------------------------------------------------------- */
208 344 : eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
209 344 : 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 344 : if( eByteOrder == wkbNDR )
221 : {
222 323 : eGeometryType = (OGRwkbGeometryType) pabyData[1];
223 323 : 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 344 : if( eGeometryType != wkbPoint )
232 0 : return OGRERR_CORRUPT_DATA;
233 :
234 : /* -------------------------------------------------------------------- */
235 : /* Get the vertex. */
236 : /* -------------------------------------------------------------------- */
237 344 : memcpy( &x, pabyData + 5, 16 );
238 :
239 344 : if( OGR_SWAP( eByteOrder ) )
240 : {
241 21 : CPL_SWAPDOUBLE( &x );
242 21 : CPL_SWAPDOUBLE( &y );
243 : }
244 :
245 344 : if( bIs3D )
246 : {
247 142 : if ( nSize < 29 && nSize != -1 )
248 0 : return OGRERR_NOT_ENOUGH_DATA;
249 :
250 142 : memcpy( &z, pabyData + 5 + 16, 8 );
251 142 : if( OGR_SWAP( eByteOrder ) )
252 : {
253 3 : CPL_SWAPDOUBLE( &z );
254 : }
255 142 : nCoordDimension = 3;
256 : }
257 : else
258 : {
259 202 : z = 0;
260 202 : nCoordDimension = 2;
261 : }
262 :
263 344 : return OGRERR_NONE;
264 : }
265 :
266 : /************************************************************************/
267 : /* exportToWkb() */
268 : /* */
269 : /* Build a well known binary representation of this object. */
270 : /************************************************************************/
271 :
272 108 : OGRErr OGRPoint::exportToWkb( OGRwkbByteOrder eByteOrder,
273 : unsigned char * pabyData ) const
274 :
275 : {
276 : /* -------------------------------------------------------------------- */
277 : /* Set the byte order. */
278 : /* -------------------------------------------------------------------- */
279 108 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
280 :
281 : /* -------------------------------------------------------------------- */
282 : /* Set the geometry feature type. */
283 : /* -------------------------------------------------------------------- */
284 108 : GUInt32 nGType = getGeometryType();
285 :
286 108 : if( eByteOrder == wkbNDR )
287 89 : nGType = CPL_LSBWORD32( nGType );
288 : else
289 19 : nGType = CPL_MSBWORD32( nGType );
290 :
291 108 : memcpy( pabyData + 1, &nGType, 4 );
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Copy in the raw data. */
295 : /* -------------------------------------------------------------------- */
296 108 : memcpy( pabyData+5, &x, 16 );
297 :
298 108 : if( nCoordDimension == 3 )
299 : {
300 25 : memcpy( pabyData + 5 + 16, &z, 8 );
301 : }
302 :
303 : /* -------------------------------------------------------------------- */
304 : /* Swap if needed. */
305 : /* -------------------------------------------------------------------- */
306 108 : 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 108 : return OGRERR_NONE;
316 : }
317 :
318 : /************************************************************************/
319 : /* importFromWkt() */
320 : /* */
321 : /* Instantiate point from well known text format ``POINT */
322 : /* (x,y)''. */
323 : /************************************************************************/
324 :
325 15678 : OGRErr OGRPoint::importFromWkt( char ** ppszInput )
326 :
327 : {
328 : char szToken[OGR_WKT_TOKEN_MAX];
329 15678 : const char *pszInput = *ppszInput;
330 :
331 : /* -------------------------------------------------------------------- */
332 : /* Read and verify the ``POINT'' keyword token. */
333 : /* -------------------------------------------------------------------- */
334 15678 : pszInput = OGRWktReadToken( pszInput, szToken );
335 :
336 15678 : 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 15678 : int bHasZ = FALSE, bHasM = FALSE;
344 :
345 15678 : pszPreScan = OGRWktReadToken( pszInput, szToken );
346 15678 : 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 15669 : else if( EQUAL(szToken,"Z") )
357 : {
358 11 : bHasZ = TRUE;
359 : }
360 15658 : else if( EQUAL(szToken,"M") )
361 : {
362 3 : bHasM = TRUE;
363 : }
364 15655 : else if( EQUAL(szToken,"ZM") )
365 : {
366 3 : bHasZ = TRUE;
367 3 : bHasM = TRUE;
368 : }
369 :
370 15669 : 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 15665 : if( !EQUAL(szToken,"(") )
385 4 : return OGRERR_CORRUPT_DATA;
386 :
387 15661 : if ( !bHasZ && !bHasM )
388 : {
389 : /* Test for old-style POINT(EMPTY) */
390 15650 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
391 15650 : 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 15658 : OGRRawPoint *poPoints = NULL;
410 15658 : double *padfZ = NULL;
411 15658 : int nMaxPoint = 0, nPoints = 0;
412 :
413 : pszInput = OGRWktReadPoints( pszInput, &poPoints, &padfZ,
414 15658 : &nMaxPoint, &nPoints );
415 15658 : if( pszInput == NULL || nPoints != 1 )
416 : {
417 15 : CPLFree( poPoints );
418 15 : CPLFree( padfZ );
419 15 : return OGRERR_CORRUPT_DATA;
420 : }
421 :
422 15643 : x = poPoints[0].x;
423 15643 : y = poPoints[0].y;
424 :
425 15643 : CPLFree( poPoints );
426 :
427 15643 : 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 29492 : if ((!(bHasM && !bHasZ)))
432 : {
433 14745 : z = padfZ[0];
434 14745 : nCoordDimension = 3;
435 : }
436 : else
437 2 : nCoordDimension = 2;
438 14747 : CPLFree( padfZ );
439 : }
440 896 : 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 896 : nCoordDimension = 2;
448 :
449 15643 : *ppszInput = (char *) pszInput;
450 :
451 15643 : 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 694 : OGRErr OGRPoint::exportToWkt( char ** ppszDstText ) const
462 :
463 : {
464 : char szTextEquiv[140];
465 : char szCoordinate[80];
466 :
467 694 : if (nCoordDimension == 0)
468 10 : *ppszDstText = CPLStrdup( "POINT EMPTY" );
469 : else
470 : {
471 684 : OGRMakeWktCoordinate(szCoordinate, x, y, z, nCoordDimension );
472 684 : sprintf( szTextEquiv, "POINT (%s)", szCoordinate );
473 684 : *ppszDstText = CPLStrdup( szTextEquiv );
474 : }
475 :
476 694 : return OGRERR_NONE;
477 : }
478 :
479 : /************************************************************************/
480 : /* getEnvelope() */
481 : /************************************************************************/
482 :
483 23816 : void OGRPoint::getEnvelope( OGREnvelope * psEnvelope ) const
484 :
485 : {
486 23816 : psEnvelope->MinX = psEnvelope->MaxX = getX();
487 23816 : psEnvelope->MinY = psEnvelope->MaxY = getY();
488 23816 : }
489 :
490 : /************************************************************************/
491 : /* getEnvelope() */
492 : /************************************************************************/
493 :
494 17 : void OGRPoint::getEnvelope( OGREnvelope3D * psEnvelope ) const
495 :
496 : {
497 17 : psEnvelope->MinX = psEnvelope->MaxX = getX();
498 17 : psEnvelope->MinY = psEnvelope->MaxY = getY();
499 17 : psEnvelope->MinZ = psEnvelope->MaxZ = getZ();
500 17 : }
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 206 : OGRBoolean OGRPoint::Equals( OGRGeometry * poOther ) const
564 :
565 : {
566 206 : OGRPoint *poOPoint = (OGRPoint *) poOther;
567 :
568 206 : if( poOPoint== this )
569 0 : return TRUE;
570 :
571 206 : if( poOther->getGeometryType() != getGeometryType() )
572 0 : return FALSE;
573 :
574 : // we should eventually test the SRS.
575 :
576 206 : if( poOPoint->getX() != getX()
577 : || poOPoint->getY() != getY()
578 : || poOPoint->getZ() != getZ() )
579 142 : return FALSE;
580 : else
581 64 : return TRUE;
582 : }
583 :
584 : /************************************************************************/
585 : /* transform() */
586 : /************************************************************************/
587 :
588 8 : OGRErr OGRPoint::transform( OGRCoordinateTransformation *poCT )
589 :
590 : {
591 : #ifdef DISABLE_OGRGEOM_TRANSFORM
592 : return OGRERR_FAILURE;
593 : #else
594 8 : if( poCT->Transform( 1, &x, &y, &z ) )
595 : {
596 8 : assignSpatialReference( poCT->GetTargetCS() );
597 8 : return OGRERR_NONE;
598 : }
599 : else
600 0 : return OGRERR_FAILURE;
601 : #endif
602 : }
603 :
604 : /************************************************************************/
605 : /* IsEmpty() */
606 : /************************************************************************/
607 :
608 25435 : OGRBoolean OGRPoint::IsEmpty( ) const
609 : {
610 25435 : return nCoordDimension == 0;
611 : }
612 :
613 : /************************************************************************/
614 : /* swapXY() */
615 : /************************************************************************/
616 :
617 45 : void OGRPoint::swapXY()
618 : {
619 45 : double dfTemp = x;
620 45 : x = y;
621 45 : y = dfTemp;
622 45 : }
|