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 41594 : OGRPoint::OGRPoint()
44 :
45 : {
46 41594 : empty();
47 41594 : }
48 :
49 : /************************************************************************/
50 : /* OGRPoint() */
51 : /* */
52 : /* Initialize point to value. */
53 : /************************************************************************/
54 :
55 93338 : OGRPoint::OGRPoint( double xIn, double yIn, double zIn )
56 :
57 : {
58 93338 : x = xIn;
59 93338 : y = yIn;
60 93338 : z = zIn;
61 93338 : nCoordDimension = 3;
62 93338 : }
63 :
64 : /************************************************************************/
65 : /* OGRPoint() */
66 : /* */
67 : /* Initialize point to value. */
68 : /************************************************************************/
69 :
70 128540 : OGRPoint::OGRPoint( double xIn, double yIn )
71 :
72 : {
73 128540 : x = xIn;
74 128540 : y = yIn;
75 128540 : z = 0.0;
76 128540 : nCoordDimension = 2;
77 128540 : }
78 :
79 : /************************************************************************/
80 : /* ~OGRPoint() */
81 : /************************************************************************/
82 :
83 263774 : OGRPoint::~OGRPoint()
84 :
85 : {
86 263774 : }
87 :
88 : /************************************************************************/
89 : /* clone() */
90 : /* */
91 : /* Make a new object that is a copy of this object. */
92 : /************************************************************************/
93 :
94 44296 : OGRGeometry *OGRPoint::clone() const
95 :
96 : {
97 44296 : OGRPoint *poNewPoint = new OGRPoint( x, y, z );
98 :
99 44296 : poNewPoint->assignSpatialReference( getSpatialReference() );
100 44296 : poNewPoint->setCoordinateDimension( nCoordDimension );
101 :
102 44296 : return poNewPoint;
103 : }
104 :
105 : /************************************************************************/
106 : /* empty() */
107 : /************************************************************************/
108 41650 : void OGRPoint::empty()
109 :
110 : {
111 41650 : x = y = z = 0.0;
112 41650 : nCoordDimension = 0;
113 41650 : }
114 :
115 : /************************************************************************/
116 : /* getDimension() */
117 : /************************************************************************/
118 :
119 2 : int OGRPoint::getDimension() const
120 :
121 : {
122 2 : return 0;
123 : }
124 :
125 : /************************************************************************/
126 : /* getGeometryType() */
127 : /************************************************************************/
128 :
129 131978 : OGRwkbGeometryType OGRPoint::getGeometryType() const
130 :
131 : {
132 131978 : if( nCoordDimension < 3 )
133 23180 : return wkbPoint;
134 : else
135 108798 : return wkbPoint25D;
136 : }
137 :
138 : /************************************************************************/
139 : /* getGeometryName() */
140 : /************************************************************************/
141 :
142 756 : const char * OGRPoint::getGeometryName() const
143 :
144 : {
145 756 : return "POINT";
146 : }
147 :
148 : /************************************************************************/
149 : /* flattenTo2D() */
150 : /************************************************************************/
151 :
152 3974 : void OGRPoint::flattenTo2D()
153 :
154 : {
155 3974 : z = 0;
156 3974 : if (nCoordDimension > 2)
157 4 : nCoordDimension = 2;
158 3974 : }
159 :
160 : /************************************************************************/
161 : /* setCoordinateDimension() */
162 : /************************************************************************/
163 :
164 45390 : void OGRPoint::setCoordinateDimension( int nNewDimension )
165 :
166 : {
167 45390 : nCoordDimension = nNewDimension;
168 :
169 45390 : if( nCoordDimension == 2 )
170 15084 : z = 0;
171 45390 : }
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 802 : int OGRPoint::WkbSize() const
181 :
182 : {
183 802 : if( nCoordDimension != 3 )
184 488 : return 21;
185 : else
186 314 : return 29;
187 : }
188 :
189 : /************************************************************************/
190 : /* importFromWkb() */
191 : /* */
192 : /* Initialize from serialized stream in well known binary */
193 : /* format. */
194 : /************************************************************************/
195 :
196 692 : OGRErr OGRPoint::importFromWkb( unsigned char * pabyData,
197 : int nSize )
198 :
199 : {
200 : OGRwkbByteOrder eByteOrder;
201 :
202 692 : if( nSize < 21 && nSize != -1 )
203 0 : return OGRERR_NOT_ENOUGH_DATA;
204 :
205 : /* -------------------------------------------------------------------- */
206 : /* Get the byte order byte. */
207 : /* -------------------------------------------------------------------- */
208 692 : eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
209 692 : 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 692 : if( eByteOrder == wkbNDR )
221 : {
222 650 : eGeometryType = (OGRwkbGeometryType) pabyData[1];
223 650 : bIs3D = pabyData[4] & 0x80 || pabyData[2] & 0x80;
224 : }
225 : else
226 : {
227 42 : eGeometryType = (OGRwkbGeometryType) pabyData[4];
228 42 : bIs3D = pabyData[1] & 0x80 || pabyData[3] & 0x80;
229 : }
230 :
231 692 : if( eGeometryType != wkbPoint )
232 0 : return OGRERR_CORRUPT_DATA;
233 :
234 : /* -------------------------------------------------------------------- */
235 : /* Get the vertex. */
236 : /* -------------------------------------------------------------------- */
237 692 : memcpy( &x, pabyData + 5, 16 );
238 :
239 692 : if( OGR_SWAP( eByteOrder ) )
240 : {
241 42 : CPL_SWAPDOUBLE( &x );
242 42 : CPL_SWAPDOUBLE( &y );
243 : }
244 :
245 692 : if( bIs3D )
246 : {
247 286 : if ( nSize < 29 && nSize != -1 )
248 0 : return OGRERR_NOT_ENOUGH_DATA;
249 :
250 286 : memcpy( &z, pabyData + 5 + 16, 8 );
251 286 : if( OGR_SWAP( eByteOrder ) )
252 : {
253 6 : CPL_SWAPDOUBLE( &z );
254 : }
255 286 : nCoordDimension = 3;
256 : }
257 : else
258 : {
259 406 : z = 0;
260 406 : nCoordDimension = 2;
261 : }
262 :
263 692 : return OGRERR_NONE;
264 : }
265 :
266 : /************************************************************************/
267 : /* exportToWkb() */
268 : /* */
269 : /* Build a well known binary representation of this object. */
270 : /************************************************************************/
271 :
272 220 : OGRErr OGRPoint::exportToWkb( OGRwkbByteOrder eByteOrder,
273 : unsigned char * pabyData ) const
274 :
275 : {
276 : /* -------------------------------------------------------------------- */
277 : /* Set the byte order. */
278 : /* -------------------------------------------------------------------- */
279 220 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
280 :
281 : /* -------------------------------------------------------------------- */
282 : /* Set the geometry feature type. */
283 : /* -------------------------------------------------------------------- */
284 220 : GUInt32 nGType = getGeometryType();
285 :
286 220 : if( eByteOrder == wkbNDR )
287 182 : nGType = CPL_LSBWORD32( nGType );
288 : else
289 38 : nGType = CPL_MSBWORD32( nGType );
290 :
291 220 : memcpy( pabyData + 1, &nGType, 4 );
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Copy in the raw data. */
295 : /* -------------------------------------------------------------------- */
296 220 : memcpy( pabyData+5, &x, 16 );
297 :
298 220 : if( nCoordDimension == 3 )
299 : {
300 50 : memcpy( pabyData + 5 + 16, &z, 8 );
301 : }
302 :
303 : /* -------------------------------------------------------------------- */
304 : /* Swap if needed. */
305 : /* -------------------------------------------------------------------- */
306 220 : if( OGR_SWAP( eByteOrder ) )
307 : {
308 38 : CPL_SWAPDOUBLE( pabyData + 5 );
309 38 : CPL_SWAPDOUBLE( pabyData + 5 + 8 );
310 :
311 38 : if( nCoordDimension == 3 )
312 6 : CPL_SWAPDOUBLE( pabyData + 5 + 16 );
313 : }
314 :
315 220 : return OGRERR_NONE;
316 : }
317 :
318 : /************************************************************************/
319 : /* importFromWkt() */
320 : /* */
321 : /* Instantiate point from well known text format ``POINT */
322 : /* (x,y)''. */
323 : /************************************************************************/
324 :
325 33376 : OGRErr OGRPoint::importFromWkt( char ** ppszInput )
326 :
327 : {
328 : char szToken[OGR_WKT_TOKEN_MAX];
329 33376 : const char *pszInput = *ppszInput;
330 :
331 : /* -------------------------------------------------------------------- */
332 : /* Read and verify the ``POINT'' keyword token. */
333 : /* -------------------------------------------------------------------- */
334 33376 : pszInput = OGRWktReadToken( pszInput, szToken );
335 :
336 33376 : 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 33376 : int bHasZ = FALSE, bHasM = FALSE;
344 :
345 33376 : pszPreScan = OGRWktReadToken( pszInput, szToken );
346 33376 : if( EQUAL(szToken,"EMPTY") )
347 : {
348 18 : *ppszInput = (char *) pszPreScan;
349 18 : empty();
350 18 : return OGRERR_NONE;
351 : }
352 :
353 : /* -------------------------------------------------------------------- */
354 : /* Check for Z, M or ZM. Will ignore the Measure */
355 : /* -------------------------------------------------------------------- */
356 33358 : else if( EQUAL(szToken,"Z") )
357 : {
358 22 : bHasZ = TRUE;
359 : }
360 33336 : else if( EQUAL(szToken,"M") )
361 : {
362 6 : bHasM = TRUE;
363 : }
364 33330 : else if( EQUAL(szToken,"ZM") )
365 : {
366 6 : bHasZ = TRUE;
367 6 : bHasM = TRUE;
368 : }
369 :
370 33358 : if (bHasZ || bHasM)
371 : {
372 34 : pszInput = pszPreScan;
373 34 : pszPreScan = OGRWktReadToken( pszInput, szToken );
374 34 : if( EQUAL(szToken,"EMPTY") )
375 : {
376 8 : *ppszInput = (char *) pszPreScan;
377 8 : 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 8 : return OGRERR_NONE;
381 : }
382 : }
383 :
384 33350 : if( !EQUAL(szToken,"(") )
385 8 : return OGRERR_CORRUPT_DATA;
386 :
387 33342 : if ( !bHasZ && !bHasM )
388 : {
389 : /* Test for old-style POINT(EMPTY) */
390 33320 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
391 33320 : if( EQUAL(szToken,"EMPTY") )
392 : {
393 6 : pszInput = OGRWktReadToken( pszPreScan, szToken );
394 :
395 6 : if( !EQUAL(szToken,")") )
396 2 : return OGRERR_CORRUPT_DATA;
397 : else
398 : {
399 4 : *ppszInput = (char *) pszInput;
400 4 : empty();
401 4 : return OGRERR_NONE;
402 : }
403 : }
404 : }
405 :
406 : /* -------------------------------------------------------------------- */
407 : /* Read the point list which should consist of exactly one point. */
408 : /* -------------------------------------------------------------------- */
409 33336 : OGRRawPoint *poPoints = NULL;
410 33336 : double *padfZ = NULL;
411 33336 : int nMaxPoint = 0, nPoints = 0;
412 :
413 : pszInput = OGRWktReadPoints( pszInput, &poPoints, &padfZ,
414 33336 : &nMaxPoint, &nPoints );
415 33336 : if( pszInput == NULL || nPoints != 1 )
416 : {
417 30 : CPLFree( poPoints );
418 30 : CPLFree( padfZ );
419 30 : return OGRERR_CORRUPT_DATA;
420 : }
421 :
422 33306 : x = poPoints[0].x;
423 33306 : y = poPoints[0].y;
424 :
425 33306 : CPLFree( poPoints );
426 :
427 33306 : 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 59000 : if ((!(bHasM && !bHasZ)))
432 : {
433 29498 : z = padfZ[0];
434 29498 : nCoordDimension = 3;
435 : }
436 : else
437 4 : nCoordDimension = 2;
438 29502 : CPLFree( padfZ );
439 : }
440 3804 : 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 3804 : nCoordDimension = 2;
448 :
449 33306 : *ppszInput = (char *) pszInput;
450 :
451 33306 : 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 1386 : OGRErr OGRPoint::exportToWkt( char ** ppszDstText ) const
462 :
463 : {
464 : char szTextEquiv[140];
465 : char szCoordinate[80];
466 :
467 1386 : if (nCoordDimension == 0)
468 24 : *ppszDstText = CPLStrdup( "POINT EMPTY" );
469 : else
470 : {
471 1362 : OGRMakeWktCoordinate(szCoordinate, x, y, z, nCoordDimension );
472 1362 : sprintf( szTextEquiv, "POINT (%s)", szCoordinate );
473 1362 : *ppszDstText = CPLStrdup( szTextEquiv );
474 : }
475 :
476 1386 : return OGRERR_NONE;
477 : }
478 :
479 : /************************************************************************/
480 : /* getEnvelope() */
481 : /************************************************************************/
482 :
483 50824 : void OGRPoint::getEnvelope( OGREnvelope * psEnvelope ) const
484 :
485 : {
486 50824 : psEnvelope->MinX = psEnvelope->MaxX = getX();
487 50824 : psEnvelope->MinY = psEnvelope->MaxY = getY();
488 50824 : }
489 :
490 : /************************************************************************/
491 : /* getEnvelope() */
492 : /************************************************************************/
493 :
494 106 : void OGRPoint::getEnvelope( OGREnvelope3D * psEnvelope ) const
495 :
496 : {
497 106 : psEnvelope->MinX = psEnvelope->MaxX = getX();
498 106 : psEnvelope->MinY = psEnvelope->MaxY = getY();
499 106 : psEnvelope->MinZ = psEnvelope->MaxZ = getZ();
500 106 : }
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 448 : OGRBoolean OGRPoint::Equals( OGRGeometry * poOther ) const
564 :
565 : {
566 448 : OGRPoint *poOPoint = (OGRPoint *) poOther;
567 :
568 448 : if( poOPoint== this )
569 0 : return TRUE;
570 :
571 448 : if( poOther->getGeometryType() != getGeometryType() )
572 0 : return FALSE;
573 :
574 : // we should eventually test the SRS.
575 :
576 448 : if( poOPoint->getX() != getX()
577 : || poOPoint->getY() != getY()
578 : || poOPoint->getZ() != getZ() )
579 284 : return FALSE;
580 : else
581 164 : return TRUE;
582 : }
583 :
584 : /************************************************************************/
585 : /* transform() */
586 : /************************************************************************/
587 :
588 16 : OGRErr OGRPoint::transform( OGRCoordinateTransformation *poCT )
589 :
590 : {
591 : #ifdef DISABLE_OGRGEOM_TRANSFORM
592 : return OGRERR_FAILURE;
593 : #else
594 16 : if( poCT->Transform( 1, &x, &y, &z ) )
595 : {
596 16 : assignSpatialReference( poCT->GetTargetCS() );
597 16 : return OGRERR_NONE;
598 : }
599 : else
600 0 : return OGRERR_FAILURE;
601 : #endif
602 : }
603 :
604 : /************************************************************************/
605 : /* IsEmpty() */
606 : /************************************************************************/
607 :
608 56110 : OGRBoolean OGRPoint::IsEmpty( ) const
609 : {
610 56110 : return nCoordDimension == 0;
611 : }
612 :
613 : /************************************************************************/
614 : /* swapXY() */
615 : /************************************************************************/
616 :
617 80 : void OGRPoint::swapXY()
618 : {
619 80 : double dfTemp = x;
620 80 : x = y;
621 80 : y = dfTemp;
622 80 : }
|