1 : /******************************************************************************
2 : * $Id: ogrpoint.cpp 18913 2010-02-24 23:41:17Z 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 18913 2010-02-24 23:41:17Z rouault $");
34 :
35 : /************************************************************************/
36 : /* OGRPoint() */
37 : /************************************************************************/
38 :
39 : /**
40 : * \brief Create a (0,0) point.
41 : */
42 :
43 15887 : OGRPoint::OGRPoint()
44 :
45 : {
46 15887 : empty();
47 15887 : }
48 :
49 : /************************************************************************/
50 : /* OGRPoint() */
51 : /* */
52 : /* Initialize point to value. */
53 : /************************************************************************/
54 :
55 30127 : OGRPoint::OGRPoint( double xIn, double yIn, double zIn )
56 :
57 : {
58 30127 : x = xIn;
59 30127 : y = yIn;
60 30127 : z = zIn;
61 30127 : nCoordDimension = 3;
62 30127 : }
63 :
64 : /************************************************************************/
65 : /* OGRPoint() */
66 : /* */
67 : /* Initialize point to value. */
68 : /************************************************************************/
69 :
70 11666 : OGRPoint::OGRPoint( double xIn, double yIn )
71 :
72 : {
73 11666 : x = xIn;
74 11666 : y = yIn;
75 11666 : z = 0.0;
76 11666 : nCoordDimension = 2;
77 11666 : }
78 :
79 : /************************************************************************/
80 : /* ~OGRPoint() */
81 : /************************************************************************/
82 :
83 57831 : OGRPoint::~OGRPoint()
84 :
85 : {
86 57831 : }
87 :
88 : /************************************************************************/
89 : /* clone() */
90 : /* */
91 : /* Make a new object that is a copy of this object. */
92 : /************************************************************************/
93 :
94 15241 : OGRGeometry *OGRPoint::clone() const
95 :
96 : {
97 15241 : OGRPoint *poNewPoint = new OGRPoint( x, y, z );
98 :
99 15241 : poNewPoint->assignSpatialReference( getSpatialReference() );
100 15241 : poNewPoint->setCoordinateDimension( nCoordDimension );
101 :
102 15241 : return poNewPoint;
103 : }
104 :
105 : /************************************************************************/
106 : /* empty() */
107 : /************************************************************************/
108 15912 : void OGRPoint::empty()
109 :
110 : {
111 15912 : x = y = z = 0.0;
112 15912 : nCoordDimension = 0;
113 15912 : }
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 47031 : OGRwkbGeometryType OGRPoint::getGeometryType() const
130 :
131 : {
132 47031 : if( nCoordDimension < 3 )
133 2386 : return wkbPoint;
134 : else
135 44645 : return wkbPoint25D;
136 : }
137 :
138 : /************************************************************************/
139 : /* getGeometryName() */
140 : /************************************************************************/
141 :
142 310 : const char * OGRPoint::getGeometryName() const
143 :
144 : {
145 310 : return "POINT";
146 : }
147 :
148 : /************************************************************************/
149 : /* flattenTo2D() */
150 : /************************************************************************/
151 :
152 120 : void OGRPoint::flattenTo2D()
153 :
154 : {
155 120 : z = 0;
156 120 : if (nCoordDimension > 2)
157 2 : nCoordDimension = 2;
158 120 : }
159 :
160 : /************************************************************************/
161 : /* setCoordinateDimension() */
162 : /************************************************************************/
163 :
164 15310 : void OGRPoint::setCoordinateDimension( int nNewDimension )
165 :
166 : {
167 15310 : nCoordDimension = nNewDimension;
168 :
169 15310 : if( nCoordDimension == 2 )
170 553 : z = 0;
171 15310 : }
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 305 : int OGRPoint::WkbSize() const
181 :
182 : {
183 305 : if( nCoordDimension != 3 )
184 226 : return 21;
185 : else
186 79 : return 29;
187 : }
188 :
189 : /************************************************************************/
190 : /* importFromWkb() */
191 : /* */
192 : /* Initialize from serialized stream in well known binary */
193 : /* format. */
194 : /************************************************************************/
195 :
196 : OGRErr OGRPoint::importFromWkb( unsigned char * pabyData,
197 145 : int nSize )
198 :
199 : {
200 : OGRwkbByteOrder eByteOrder;
201 :
202 145 : if( nSize < 21 && nSize != -1 )
203 0 : return OGRERR_NOT_ENOUGH_DATA;
204 :
205 : /* -------------------------------------------------------------------- */
206 : /* Get the byte order byte. */
207 : /* -------------------------------------------------------------------- */
208 145 : eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
209 145 : 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 145 : if( eByteOrder == wkbNDR )
221 : {
222 128 : eGeometryType = (OGRwkbGeometryType) pabyData[1];
223 128 : bIs3D = pabyData[4] & 0x80 || pabyData[2] & 0x80;
224 : }
225 : else
226 : {
227 17 : eGeometryType = (OGRwkbGeometryType) pabyData[4];
228 17 : bIs3D = pabyData[1] & 0x80 || pabyData[3] & 0x80;
229 : }
230 :
231 145 : if( eGeometryType != wkbPoint )
232 0 : return OGRERR_CORRUPT_DATA;
233 :
234 : /* -------------------------------------------------------------------- */
235 : /* Get the vertex. */
236 : /* -------------------------------------------------------------------- */
237 145 : memcpy( &x, pabyData + 5, 16 );
238 :
239 145 : if( OGR_SWAP( eByteOrder ) )
240 : {
241 17 : CPL_SWAPDOUBLE( &x );
242 17 : CPL_SWAPDOUBLE( &y );
243 : }
244 :
245 145 : if( bIs3D )
246 : {
247 30 : if ( nSize < 29 && nSize != -1 )
248 0 : return OGRERR_NOT_ENOUGH_DATA;
249 :
250 30 : memcpy( &z, pabyData + 5 + 16, 8 );
251 30 : if( OGR_SWAP( eByteOrder ) )
252 : {
253 3 : CPL_SWAPDOUBLE( &z );
254 : }
255 30 : nCoordDimension = 3;
256 : }
257 : else
258 : {
259 115 : z = 0;
260 115 : nCoordDimension = 2;
261 : }
262 :
263 145 : return OGRERR_NONE;
264 : }
265 :
266 : /************************************************************************/
267 : /* exportToWkb() */
268 : /* */
269 : /* Build a well known binary representation of this object. */
270 : /************************************************************************/
271 :
272 : OGRErr OGRPoint::exportToWkb( OGRwkbByteOrder eByteOrder,
273 85 : unsigned char * pabyData ) const
274 :
275 : {
276 : /* -------------------------------------------------------------------- */
277 : /* Set the byte order. */
278 : /* -------------------------------------------------------------------- */
279 85 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
280 :
281 : /* -------------------------------------------------------------------- */
282 : /* Set the geometry feature type. */
283 : /* -------------------------------------------------------------------- */
284 85 : GUInt32 nGType = getGeometryType();
285 :
286 85 : if( eByteOrder == wkbNDR )
287 69 : nGType = CPL_LSBWORD32( nGType );
288 : else
289 16 : nGType = CPL_MSBWORD32( nGType );
290 :
291 85 : memcpy( pabyData + 1, &nGType, 4 );
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Copy in the raw data. */
295 : /* -------------------------------------------------------------------- */
296 85 : memcpy( pabyData+5, &x, 16 );
297 :
298 85 : if( nCoordDimension == 3 )
299 : {
300 15 : memcpy( pabyData + 5 + 16, &z, 8 );
301 : }
302 :
303 : /* -------------------------------------------------------------------- */
304 : /* Swap if needed. */
305 : /* -------------------------------------------------------------------- */
306 85 : if( OGR_SWAP( eByteOrder ) )
307 : {
308 16 : CPL_SWAPDOUBLE( pabyData + 5 );
309 16 : CPL_SWAPDOUBLE( pabyData + 5 + 8 );
310 :
311 16 : if( nCoordDimension == 3 )
312 3 : CPL_SWAPDOUBLE( pabyData + 5 + 16 );
313 : }
314 :
315 85 : return OGRERR_NONE;
316 : }
317 :
318 : /************************************************************************/
319 : /* importFromWkt() */
320 : /* */
321 : /* Instantiate point from well known text format ``POINT */
322 : /* (x,y)''. */
323 : /************************************************************************/
324 :
325 15058 : OGRErr OGRPoint::importFromWkt( char ** ppszInput )
326 :
327 : {
328 : char szToken[OGR_WKT_TOKEN_MAX];
329 15058 : const char *pszInput = *ppszInput;
330 :
331 : /* -------------------------------------------------------------------- */
332 : /* Read and verify the ``POINT'' keyword token. */
333 : /* -------------------------------------------------------------------- */
334 15058 : pszInput = OGRWktReadToken( pszInput, szToken );
335 :
336 15058 : 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 15058 : int bHasZ = FALSE, bHasM = FALSE;
344 :
345 15058 : pszPreScan = OGRWktReadToken( pszInput, szToken );
346 15058 : if( EQUAL(szToken,"EMPTY") )
347 : {
348 8 : *ppszInput = (char *) pszPreScan;
349 8 : empty();
350 8 : return OGRERR_NONE;
351 : }
352 :
353 : /* -------------------------------------------------------------------- */
354 : /* Check for Z, M or ZM. Will ignore the Measure */
355 : /* -------------------------------------------------------------------- */
356 15050 : else if( EQUAL(szToken,"Z") )
357 : {
358 11 : bHasZ = TRUE;
359 : }
360 15039 : else if( EQUAL(szToken,"M") )
361 : {
362 3 : bHasM = TRUE;
363 : }
364 15036 : else if( EQUAL(szToken,"ZM") )
365 : {
366 3 : bHasZ = TRUE;
367 3 : bHasM = TRUE;
368 : }
369 :
370 15050 : 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 15046 : if( !EQUAL(szToken,"(") )
385 4 : return OGRERR_CORRUPT_DATA;
386 :
387 15042 : if ( !bHasZ && !bHasM )
388 : {
389 : /* Test for old-style POINT(EMPTY) */
390 15031 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
391 15031 : 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 15039 : OGRRawPoint *poPoints = NULL;
410 15039 : double *padfZ = NULL;
411 15039 : int nMaxPoint = 0, nPoints = 0;
412 :
413 : pszInput = OGRWktReadPoints( pszInput, &poPoints, &padfZ,
414 15039 : &nMaxPoint, &nPoints );
415 15039 : if( pszInput == NULL || nPoints != 1 )
416 15 : return OGRERR_CORRUPT_DATA;
417 :
418 15024 : x = poPoints[0].x;
419 15024 : y = poPoints[0].y;
420 :
421 15024 : CPLFree( poPoints );
422 :
423 15024 : if( padfZ != NULL )
424 : {
425 : /* If there's a 3rd value, and it is not a POINT M, */
426 : /* then assume it is the Z */
427 29432 : if ((!(bHasM && !bHasZ)))
428 : {
429 14715 : z = padfZ[0];
430 14715 : nCoordDimension = 3;
431 : }
432 : else
433 2 : nCoordDimension = 2;
434 14717 : CPLFree( padfZ );
435 : }
436 307 : else if ( bHasZ )
437 : {
438 : /* In theory we should have a z coordinate for POINT Z */
439 : /* oh well, let be tolerant */
440 0 : nCoordDimension = 3;
441 : }
442 : else
443 307 : nCoordDimension = 2;
444 :
445 15024 : *ppszInput = (char *) pszInput;
446 :
447 15024 : return OGRERR_NONE;
448 : }
449 :
450 : /************************************************************************/
451 : /* exportToWkt() */
452 : /* */
453 : /* Translate this structure into it's well known text format */
454 : /* equivelent. */
455 : /************************************************************************/
456 :
457 136 : OGRErr OGRPoint::exportToWkt( char ** ppszDstText ) const
458 :
459 : {
460 : char szTextEquiv[140];
461 : char szCoordinate[80];
462 :
463 136 : if (nCoordDimension == 0)
464 10 : *ppszDstText = CPLStrdup( "POINT EMPTY" );
465 : else
466 : {
467 126 : OGRMakeWktCoordinate(szCoordinate, x, y, z, nCoordDimension );
468 126 : sprintf( szTextEquiv, "POINT (%s)", szCoordinate );
469 126 : *ppszDstText = CPLStrdup( szTextEquiv );
470 : }
471 :
472 136 : return OGRERR_NONE;
473 : }
474 :
475 : /************************************************************************/
476 : /* getEnvelope() */
477 : /************************************************************************/
478 :
479 323 : void OGRPoint::getEnvelope( OGREnvelope * psEnvelope ) const
480 :
481 : {
482 323 : psEnvelope->MinX = psEnvelope->MaxX = getX();
483 323 : psEnvelope->MinY = psEnvelope->MaxY = getY();
484 323 : }
485 :
486 :
487 :
488 : /**
489 : * \fn double OGRPoint::getX() const;
490 : *
491 : * \brief Fetch X coordinate.
492 : *
493 : * Relates to the SFCOM IPoint::get_X() method.
494 : *
495 : * @return the X coordinate of this point.
496 : */
497 :
498 : /**
499 : * \fn double OGRPoint::getY() const;
500 : *
501 : * \brief Fetch Y coordinate.
502 : *
503 : * Relates to the SFCOM IPoint::get_Y() method.
504 : *
505 : * @return the Y coordinate of this point.
506 : */
507 :
508 : /**
509 : * \fn double OGRPoint::getZ() const;
510 : *
511 : * \brief Fetch Z coordinate.
512 : *
513 : * Relates to the SFCOM IPoint::get_Z() method.
514 : *
515 : * @return the Z coordinate of this point, or zero if it is a 2D point.
516 : */
517 :
518 : /**
519 : * \fn void OGRPoint::setX( double xIn );
520 : *
521 : * \brief Assign point X coordinate.
522 : *
523 : * There is no corresponding SFCOM method.
524 : */
525 :
526 : /**
527 : * \fn void OGRPoint::setY( double yIn );
528 : *
529 : * \brief Assign point Y coordinate.
530 : *
531 : * There is no corresponding SFCOM method.
532 : */
533 :
534 : /**
535 : * \fn void OGRPoint::setZ( double zIn );
536 : *
537 : * \brief Assign point Z coordinate.
538 : * Calling this method will force the geometry
539 : * coordinate dimension to 3D (wkbPoint|wkbZ).
540 : *
541 : * There is no corresponding SFCOM method.
542 : */
543 :
544 : /************************************************************************/
545 : /* Equal() */
546 : /************************************************************************/
547 :
548 155 : OGRBoolean OGRPoint::Equals( OGRGeometry * poOther ) const
549 :
550 : {
551 155 : OGRPoint *poOPoint = (OGRPoint *) poOther;
552 :
553 155 : if( poOPoint== this )
554 0 : return TRUE;
555 :
556 155 : if( poOther->getGeometryType() != getGeometryType() )
557 0 : return FALSE;
558 :
559 : // we should eventually test the SRS.
560 :
561 155 : if( poOPoint->getX() != getX()
562 : || poOPoint->getY() != getY()
563 : || poOPoint->getZ() != getZ() )
564 142 : return FALSE;
565 : else
566 13 : return TRUE;
567 : }
568 :
569 : /************************************************************************/
570 : /* transform() */
571 : /************************************************************************/
572 :
573 4 : OGRErr OGRPoint::transform( OGRCoordinateTransformation *poCT )
574 :
575 : {
576 : #ifdef DISABLE_OGRGEOM_TRANSFORM
577 : return OGRERR_FAILURE;
578 : #else
579 4 : if( poCT->Transform( 1, &x, &y, &z ) )
580 : {
581 4 : assignSpatialReference( poCT->GetTargetCS() );
582 4 : return OGRERR_NONE;
583 : }
584 : else
585 0 : return OGRERR_FAILURE;
586 : #endif
587 : }
588 :
589 : /************************************************************************/
590 : /* IsEmpty() */
591 : /************************************************************************/
592 :
593 14901 : OGRBoolean OGRPoint::IsEmpty( ) const
594 : {
595 14901 : return nCoordDimension == 0;
596 : }
|