1 : /******************************************************************************
2 : * $Id: ogrlinestring.cpp 17792 2009-10-11 17:44:13Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: The OGRLineString 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 : #include <assert.h>
33 :
34 : CPL_CVSID("$Id: ogrlinestring.cpp 17792 2009-10-11 17:44:13Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRLineString() */
38 : /************************************************************************/
39 :
40 : /**
41 : * \brief Create an empty line string.
42 : */
43 :
44 14474 : OGRLineString::OGRLineString()
45 :
46 : {
47 14474 : nPointCount = 0;
48 14474 : paoPoints = NULL;
49 14474 : padfZ = NULL;
50 14474 : }
51 :
52 : /************************************************************************/
53 : /* ~OGRLineString() */
54 : /************************************************************************/
55 :
56 24678 : OGRLineString::~OGRLineString()
57 :
58 : {
59 14474 : if( paoPoints != NULL )
60 14364 : OGRFree( paoPoints );
61 14474 : if( padfZ != NULL )
62 587 : OGRFree( padfZ );
63 24678 : }
64 :
65 : /************************************************************************/
66 : /* getGeometryType() */
67 : /************************************************************************/
68 :
69 41708 : OGRwkbGeometryType OGRLineString::getGeometryType() const
70 :
71 : {
72 41708 : if( getCoordinateDimension() == 3 )
73 8102 : return wkbLineString25D;
74 : else
75 33606 : return wkbLineString;
76 : }
77 :
78 : /************************************************************************/
79 : /* flattenTo2D() */
80 : /************************************************************************/
81 :
82 18 : void OGRLineString::flattenTo2D()
83 :
84 : {
85 18 : Make2D();
86 18 : }
87 :
88 : /************************************************************************/
89 : /* getGeometryName() */
90 : /************************************************************************/
91 :
92 490 : const char * OGRLineString::getGeometryName() const
93 :
94 : {
95 490 : return "LINESTRING";
96 : }
97 :
98 : /************************************************************************/
99 : /* clone() */
100 : /************************************************************************/
101 :
102 473 : OGRGeometry *OGRLineString::clone() const
103 :
104 : {
105 : OGRLineString *poNewLineString;
106 :
107 473 : poNewLineString = new OGRLineString();
108 :
109 473 : poNewLineString->assignSpatialReference( getSpatialReference() );
110 473 : poNewLineString->setPoints( nPointCount, paoPoints, padfZ );
111 473 : poNewLineString->setCoordinateDimension( getCoordinateDimension() );
112 :
113 473 : return poNewLineString;
114 : }
115 :
116 : /************************************************************************/
117 : /* empty() */
118 : /************************************************************************/
119 :
120 74 : void OGRLineString::empty()
121 :
122 : {
123 74 : setNumPoints( 0 );
124 74 : }
125 :
126 : /************************************************************************/
127 : /* getDimension() */
128 : /************************************************************************/
129 :
130 0 : int OGRLineString::getDimension() const
131 :
132 : {
133 0 : return 1;
134 : }
135 :
136 : /************************************************************************/
137 : /* setCoordinateDimension() */
138 : /************************************************************************/
139 :
140 2060 : void OGRLineString::setCoordinateDimension( int nNewDimension )
141 :
142 : {
143 2060 : nCoordDimension = nNewDimension;
144 2060 : if( nNewDimension == 2 )
145 1944 : Make2D();
146 116 : else if( nNewDimension == 3 )
147 116 : Make3D();
148 2060 : }
149 :
150 : /************************************************************************/
151 : /* WkbSize() */
152 : /* */
153 : /* Return the size of this object in well known binary */
154 : /* representation including the byte order, and type information. */
155 : /************************************************************************/
156 :
157 293 : int OGRLineString::WkbSize() const
158 :
159 : {
160 293 : return 5 + 4 + 8 * nPointCount * getCoordinateDimension();
161 : }
162 :
163 : /************************************************************************/
164 : /* Make2D() */
165 : /************************************************************************/
166 :
167 2288 : void OGRLineString::Make2D()
168 :
169 : {
170 2288 : if( padfZ != NULL )
171 : {
172 981 : OGRFree( padfZ );
173 981 : padfZ = NULL;
174 : }
175 2288 : nCoordDimension = 2;
176 2288 : }
177 :
178 : /************************************************************************/
179 : /* Make3D() */
180 : /************************************************************************/
181 :
182 6217 : void OGRLineString::Make3D()
183 :
184 : {
185 6217 : if( padfZ == NULL )
186 : {
187 1543 : if( nPointCount == 0 )
188 1202 : padfZ = (double *) OGRCalloc(sizeof(double),1);
189 : else
190 341 : padfZ = (double *) OGRCalloc(sizeof(double),nPointCount);
191 : }
192 6217 : nCoordDimension = 3;
193 6217 : }
194 :
195 : /************************************************************************/
196 : /* getPoint() */
197 : /************************************************************************/
198 :
199 : /**
200 : * \brief Fetch a point in line string.
201 : *
202 : * This method relates to the SFCOM ILineString::get_Point() method.
203 : *
204 : * @param i the vertex to fetch, from 0 to getNumPoints()-1.
205 : * @param poPoint a point to initialize with the fetched point.
206 : */
207 :
208 470 : void OGRLineString::getPoint( int i, OGRPoint * poPoint ) const
209 :
210 : {
211 470 : assert( i >= 0 );
212 470 : assert( i < nPointCount );
213 470 : assert( poPoint != NULL );
214 :
215 470 : poPoint->setX( paoPoints[i].x );
216 470 : poPoint->setY( paoPoints[i].y );
217 :
218 470 : if( getCoordinateDimension() == 3 && padfZ != NULL )
219 62 : poPoint->setZ( padfZ[i] );
220 470 : }
221 :
222 : /**
223 : * \fn int OGRLineString::getNumPoints() const;
224 : *
225 : * \brief Fetch vertex count.
226 : *
227 : * Returns the number of vertices in the line string.
228 : *
229 : * @return vertex count.
230 : */
231 :
232 : /**
233 : * \fn double OGRLineString::getX( int iVertex ) const;
234 : *
235 : * \brief Get X at vertex.
236 : *
237 : * Returns the X value at the indicated vertex. If iVertex is out of range a
238 : * crash may occur, no internal range checking is performed.
239 : *
240 : * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
241 : *
242 : * @return X value.
243 : */
244 :
245 : /**
246 : * \fn double OGRLineString::getY( int iVertex ) const;
247 : *
248 : * \brief Get Y at vertex.
249 : *
250 : * Returns the Y value at the indicated vertex. If iVertex is out of range a
251 : * crash may occur, no internal range checking is performed.
252 : *
253 : * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
254 : *
255 : * @return X value.
256 : */
257 :
258 : /************************************************************************/
259 : /* getZ() */
260 : /************************************************************************/
261 :
262 : /**
263 : * \brief Get Z at vertex.
264 : *
265 : * Returns the Z (elevation) value at the indicated vertex. If no Z
266 : * value is available, 0.0 is returned. If iVertex is out of range a
267 : * crash may occur, no internal range checking is performed.
268 : *
269 : * @param iVertex the vertex to return, between 0 and getNumPoints()-1.
270 : *
271 : * @return Z value.
272 : */
273 :
274 19754 : double OGRLineString::getZ( int iVertex ) const
275 :
276 : {
277 19754 : if( padfZ != NULL && iVertex >= 0 && iVertex < nPointCount
278 : && nCoordDimension >= 3 )
279 5514 : return( padfZ[iVertex] );
280 : else
281 14240 : return 0.0;
282 : }
283 :
284 : /************************************************************************/
285 : /* setNumPoints() */
286 : /************************************************************************/
287 :
288 : /**
289 : * \brief Set number of points in geometry.
290 : *
291 : * This method primary exists to preset the number of points in a linestring
292 : * geometry before setPoint() is used to assign them to avoid reallocating
293 : * the array larger with each call to addPoint().
294 : *
295 : * This method has no SFCOM analog.
296 : *
297 : * @param nNewPointCount the new number of points for geometry.
298 : */
299 :
300 35953 : void OGRLineString::setNumPoints( int nNewPointCount )
301 :
302 : {
303 35953 : if( nNewPointCount == 0 )
304 : {
305 102 : OGRFree( paoPoints );
306 102 : paoPoints = NULL;
307 :
308 102 : OGRFree( padfZ );
309 102 : padfZ = NULL;
310 :
311 102 : nPointCount = 0;
312 102 : return;
313 : }
314 :
315 35851 : if( nNewPointCount > nPointCount )
316 : {
317 : paoPoints = (OGRRawPoint *)
318 26954 : OGRRealloc(paoPoints, sizeof(OGRRawPoint) * nNewPointCount);
319 :
320 26954 : assert( paoPoints != NULL );
321 :
322 : memset( paoPoints + nPointCount,
323 26954 : 0, sizeof(OGRRawPoint) * (nNewPointCount - nPointCount) );
324 :
325 26954 : if( getCoordinateDimension() == 3 )
326 : {
327 : padfZ = (double *)
328 1866 : OGRRealloc( padfZ, sizeof(double)*nNewPointCount );
329 : memset( padfZ + nPointCount, 0,
330 1866 : sizeof(double) * (nNewPointCount - nPointCount) );
331 : }
332 : }
333 :
334 35851 : nPointCount = nNewPointCount;
335 : }
336 :
337 : /************************************************************************/
338 : /* setPoint() */
339 : /************************************************************************/
340 :
341 : /**
342 : * \brief Set the location of a vertex in line string.
343 : *
344 : * If iPoint is larger than the number of necessary the number of existing
345 : * points in the line string, the point count will be increased to
346 : * accomodate the request.
347 : *
348 : * There is no SFCOM analog to this method.
349 : *
350 : * @param iPoint the index of the vertex to assign (zero based).
351 : * @param poPoint the value to assign to the vertex.
352 : */
353 :
354 0 : void OGRLineString::setPoint( int iPoint, OGRPoint * poPoint )
355 :
356 : {
357 0 : setPoint( iPoint, poPoint->getX(), poPoint->getY(), poPoint->getZ() );
358 0 : }
359 :
360 : /************************************************************************/
361 : /* setPoint() */
362 : /************************************************************************/
363 :
364 : /**
365 : * \brief Set the location of a vertex in line string.
366 : *
367 : * If iPoint is larger than the number of necessary the number of existing
368 : * points in the line string, the point count will be increased to
369 : * accomodate the request.
370 : *
371 : * There is no SFCOM analog to this method.
372 : *
373 : * @param iPoint the index of the vertex to assign (zero based).
374 : * @param xIn input X coordinate to assign.
375 : * @param yIn input Y coordinate to assign.
376 : * @param zIn input Z coordinate to assign (defaults to zero).
377 : */
378 :
379 5528 : void OGRLineString::setPoint( int iPoint, double xIn, double yIn, double zIn )
380 :
381 : {
382 5528 : if( getCoordinateDimension() == 2 )
383 199 : Make3D();
384 :
385 5528 : if( iPoint >= nPointCount )
386 844 : setNumPoints( iPoint+1 );
387 :
388 5528 : paoPoints[iPoint].x = xIn;
389 5528 : paoPoints[iPoint].y = yIn;
390 :
391 5528 : if( zIn != 0.0 )
392 : {
393 4589 : Make3D();
394 4589 : padfZ[iPoint] = zIn;
395 : }
396 939 : else if( getCoordinateDimension() == 3 )
397 : {
398 939 : padfZ[iPoint] = 0.0;
399 : }
400 5528 : }
401 :
402 118354 : void OGRLineString::setPoint( int iPoint, double xIn, double yIn )
403 :
404 : {
405 118354 : if( iPoint >= nPointCount )
406 12589 : setNumPoints( iPoint+1 );
407 :
408 118354 : paoPoints[iPoint].x = xIn;
409 118354 : paoPoints[iPoint].y = yIn;
410 118354 : }
411 :
412 : /************************************************************************/
413 : /* addPoint() */
414 : /************************************************************************/
415 :
416 : /**
417 : * \brief Add a point to a line string.
418 : *
419 : * The vertex count of the line string is increased by one, and assigned from
420 : * the passed location value.
421 : *
422 : * There is no SFCOM analog to this method.
423 : *
424 : * @param poPoint the point to assign to the new vertex.
425 : */
426 :
427 40 : void OGRLineString::addPoint( OGRPoint * poPoint )
428 :
429 : {
430 40 : setPoint( nPointCount, poPoint->getX(), poPoint->getY(), poPoint->getZ() );
431 40 : }
432 :
433 : /************************************************************************/
434 : /* addPoint() */
435 : /************************************************************************/
436 :
437 : /**
438 : * \brief Add a point to a line string.
439 : *
440 : * The vertex count of the line string is increased by one, and assigned from
441 : * the passed location value.
442 : *
443 : * There is no SFCOM analog to this method.
444 : *
445 : * @param x the X coordinate to assign to the new point.
446 : * @param y the Y coordinate to assign to the new point.
447 : * @param z the Z coordinate to assign to the new point (defaults to zero).
448 : */
449 :
450 248 : void OGRLineString::addPoint( double x, double y, double z )
451 :
452 : {
453 248 : setPoint( nPointCount, x, y, z );
454 248 : }
455 :
456 12381 : void OGRLineString::addPoint( double x, double y )
457 :
458 : {
459 12381 : setPoint( nPointCount, x, y );
460 12381 : }
461 :
462 : /************************************************************************/
463 : /* setPoints() */
464 : /************************************************************************/
465 :
466 : /**
467 : * \brief Assign all points in a line string.
468 : *
469 : * This method clears any existing points assigned to this line string,
470 : * and assigns a whole new set. It is the most efficient way of assigning
471 : * the value of a line string.
472 : *
473 : * There is no SFCOM analog to this method.
474 : *
475 : * @param nPointsIn number of points being passed in paoPointsIn
476 : * @param paoPointsIn list of points being assigned.
477 : * @param padfZ the Z values that go with the points (optional, may be NULL).
478 : */
479 :
480 1171 : void OGRLineString::setPoints( int nPointsIn, OGRRawPoint * paoPointsIn,
481 : double * padfZ )
482 :
483 : {
484 1171 : setNumPoints( nPointsIn );
485 1171 : memcpy( paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
486 :
487 : /* -------------------------------------------------------------------- */
488 : /* Check 2D/3D. */
489 : /* -------------------------------------------------------------------- */
490 1171 : if( padfZ == NULL && getCoordinateDimension() > 2 )
491 : {
492 0 : Make2D();
493 : }
494 1171 : else if( padfZ )
495 : {
496 183 : Make3D();
497 183 : memcpy( this->padfZ, padfZ, sizeof(double) * nPointsIn );
498 : }
499 1171 : }
500 :
501 : /************************************************************************/
502 : /* setPoints() */
503 : /************************************************************************/
504 :
505 : /**
506 : * \brief Assign all points in a line string.
507 : *
508 : * This method clear any existing points assigned to this line string,
509 : * and assigns a whole new set.
510 : *
511 : * There is no SFCOM analog to this method.
512 : *
513 : * @param nPointsIn number of points being passed in padfX and padfY.
514 : * @param padfX list of X coordinates of points being assigned.
515 : * @param padfY list of Y coordinates of points being assigned.
516 : * @param padfZ list of Z coordinates of points being assigned (defaults to
517 : * NULL for 2D objects).
518 : */
519 :
520 1034 : void OGRLineString::setPoints( int nPointsIn, double * padfX, double * padfY,
521 : double * padfZ )
522 :
523 : {
524 : int i;
525 :
526 : /* -------------------------------------------------------------------- */
527 : /* Check 2D/3D. */
528 : /* -------------------------------------------------------------------- */
529 1034 : if( padfZ == NULL )
530 14 : Make2D();
531 : else
532 1020 : Make3D();
533 :
534 : /* -------------------------------------------------------------------- */
535 : /* Assign values. */
536 : /* -------------------------------------------------------------------- */
537 1034 : setNumPoints( nPointsIn );
538 :
539 26678 : for( i = 0; i < nPointsIn; i++ )
540 : {
541 25644 : paoPoints[i].x = padfX[i];
542 25644 : paoPoints[i].y = padfY[i];
543 : }
544 :
545 1034 : if( this->padfZ != NULL )
546 1020 : memcpy( this->padfZ, padfZ, sizeof(double) * nPointsIn );
547 1034 : }
548 :
549 : /************************************************************************/
550 : /* getPoints() */
551 : /************************************************************************/
552 :
553 : /**
554 : * \brief Returns all points of line string.
555 : *
556 : * This method copies all points into user list. This list must be at
557 : * least sizeof(OGRRawPoint) * OGRGeometry::getNumPoints() byte in size.
558 : * It also copies all Z coordinates.
559 : *
560 : * There is no SFCOM analog to this method.
561 : *
562 : * @param paoPointsOut a buffer into which the points is written.
563 : * @param padfZ the Z values that go with the points (optional, may be NULL).
564 : */
565 :
566 0 : void OGRLineString::getPoints( OGRRawPoint * paoPointsOut, double * padfZ ) const
567 : {
568 0 : if ( ! paoPointsOut )
569 0 : return;
570 :
571 0 : memcpy( paoPointsOut, paoPoints, sizeof(OGRRawPoint) * nPointCount );
572 :
573 : /* -------------------------------------------------------------------- */
574 : /* Check 2D/3D. */
575 : /* -------------------------------------------------------------------- */
576 0 : if( padfZ )
577 : {
578 0 : if ( this->padfZ )
579 0 : memcpy( padfZ, this->padfZ, sizeof(double) * nPointCount );
580 : else
581 0 : memset( padfZ, 0, sizeof(double) * nPointCount );
582 : }
583 : }
584 :
585 :
586 : /************************************************************************/
587 : /* addSubLineString() */
588 : /************************************************************************/
589 :
590 : /**
591 : * \brief Add a segment of another linestring to this one.
592 : *
593 : * Adds the request range of vertices to the end of this line string
594 : * in an efficient manner. If the nStartVertex is larger than the
595 : * nEndVertex then the vertices will be reversed as they are copied.
596 : *
597 : * @param poOtherLine the other OGRLineString.
598 : * @param nStartVertex the first vertex to copy, defaults to 0 to start
599 : * with the first vertex in the other linestring.
600 : * @param nEndVertex the last vertex to copy, defaults to -1 indicating
601 : * the last vertex of the other line string.
602 : */
603 :
604 26 : void OGRLineString::addSubLineString( const OGRLineString *poOtherLine,
605 : int nStartVertex, int nEndVertex )
606 :
607 : {
608 : /* -------------------------------------------------------------------- */
609 : /* Do a bit of argument defaulting and validation. */
610 : /* -------------------------------------------------------------------- */
611 26 : if( nEndVertex == -1 )
612 1 : nEndVertex = poOtherLine->getNumPoints() - 1;
613 :
614 26 : if( nStartVertex < 0 || nEndVertex < 0
615 : || nStartVertex >= poOtherLine->getNumPoints()
616 : || nEndVertex >= poOtherLine->getNumPoints() )
617 : {
618 : CPLAssert( FALSE );
619 0 : return;
620 : }
621 :
622 : /* -------------------------------------------------------------------- */
623 : /* Grow this linestring to hold the additional points. */
624 : /* -------------------------------------------------------------------- */
625 26 : int nOldPoints = nPointCount;
626 26 : int nPointsToAdd = ABS(nEndVertex-nStartVertex) + 1;
627 :
628 26 : setNumPoints( nPointsToAdd + nOldPoints );
629 :
630 : /* -------------------------------------------------------------------- */
631 : /* Copy the x/y points - forward copies use memcpy. */
632 : /* -------------------------------------------------------------------- */
633 26 : if( nEndVertex >= nStartVertex )
634 : {
635 : memcpy( paoPoints + nOldPoints,
636 : poOtherLine->paoPoints + nStartVertex,
637 20 : sizeof(OGRRawPoint) * nPointsToAdd );
638 20 : if( poOtherLine->padfZ != NULL )
639 : {
640 0 : Make3D();
641 : memcpy( padfZ + nOldPoints, poOtherLine->padfZ + nStartVertex,
642 0 : sizeof(double) * nPointsToAdd );
643 : }
644 : }
645 :
646 : /* -------------------------------------------------------------------- */
647 : /* Copy the x/y points - reverse copies done double by double. */
648 : /* -------------------------------------------------------------------- */
649 : else
650 : {
651 : int i;
652 :
653 26 : for( i = 0; i < nPointsToAdd; i++ )
654 : {
655 20 : paoPoints[i+nOldPoints].x =
656 20 : poOtherLine->paoPoints[nStartVertex-i].x;
657 20 : paoPoints[i+nOldPoints].y =
658 20 : poOtherLine->paoPoints[nStartVertex-i].y;
659 : }
660 :
661 6 : if( poOtherLine->padfZ != NULL )
662 : {
663 0 : Make3D();
664 :
665 0 : for( i = 0; i < nPointsToAdd; i++ )
666 : {
667 0 : padfZ[i+nOldPoints] = poOtherLine->padfZ[nStartVertex-i];
668 : }
669 : }
670 : }
671 : }
672 :
673 : /************************************************************************/
674 : /* importFromWkb() */
675 : /* */
676 : /* Initialize from serialized stream in well known binary */
677 : /* format. */
678 : /************************************************************************/
679 :
680 126 : OGRErr OGRLineString::importFromWkb( unsigned char * pabyData,
681 : int nSize )
682 :
683 : {
684 : OGRwkbByteOrder eByteOrder;
685 :
686 126 : if( nSize < 9 && nSize != -1 )
687 0 : return OGRERR_NOT_ENOUGH_DATA;
688 :
689 : /* -------------------------------------------------------------------- */
690 : /* Get the byte order byte. */
691 : /* -------------------------------------------------------------------- */
692 126 : eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
693 126 : if (!( eByteOrder == wkbXDR || eByteOrder == wkbNDR ))
694 0 : return OGRERR_CORRUPT_DATA;
695 :
696 : /* -------------------------------------------------------------------- */
697 : /* Get the geometry feature type. For now we assume that */
698 : /* geometry type is between 0 and 255 so we only have to fetch */
699 : /* one byte. */
700 : /* -------------------------------------------------------------------- */
701 : OGRwkbGeometryType eGeometryType;
702 126 : int bIs3D = FALSE;
703 :
704 126 : if( eByteOrder == wkbNDR )
705 : {
706 114 : eGeometryType = (OGRwkbGeometryType) pabyData[1];
707 114 : bIs3D = pabyData[4] & 0x80 || pabyData[2] & 0x80;
708 : }
709 : else
710 : {
711 12 : eGeometryType = (OGRwkbGeometryType) pabyData[4];
712 12 : bIs3D = pabyData[1] & 0x80 || pabyData[3] & 0x80;
713 : }
714 :
715 126 : if( eGeometryType != wkbLineString )
716 0 : return OGRERR_CORRUPT_DATA;
717 :
718 : /* -------------------------------------------------------------------- */
719 : /* Get the vertex count. */
720 : /* -------------------------------------------------------------------- */
721 : int nNewNumPoints;
722 :
723 126 : memcpy( &nNewNumPoints, pabyData + 5, 4 );
724 :
725 126 : if( OGR_SWAP( eByteOrder ) )
726 12 : nNewNumPoints = CPL_SWAP32(nNewNumPoints);
727 :
728 : /* Check if the wkb stream buffer is big enough to store
729 : * fetched number of points.
730 : * 16 or 24 - size of point structure
731 : */
732 126 : int nPointSize = (bIs3D ? 24 : 16);
733 126 : if (nNewNumPoints < 0 || nNewNumPoints > INT_MAX / nPointSize)
734 0 : return OGRERR_CORRUPT_DATA;
735 126 : int nBufferMinSize = nPointSize * nNewNumPoints;
736 :
737 126 : if( nSize != -1 && nBufferMinSize > nSize-9 )
738 : {
739 : CPLError( CE_Failure, CPLE_AppDefined,
740 0 : "Length of input WKB is too small" );
741 0 : return OGRERR_NOT_ENOUGH_DATA;
742 : }
743 :
744 126 : setNumPoints( nNewNumPoints );
745 :
746 126 : if( bIs3D )
747 21 : Make3D();
748 : else
749 105 : Make2D();
750 :
751 : /* -------------------------------------------------------------------- */
752 : /* Get the vertex. */
753 : /* -------------------------------------------------------------------- */
754 126 : int i = 0;
755 :
756 126 : if( bIs3D )
757 : {
758 83 : for( i = 0; i < nPointCount; i++ )
759 : {
760 62 : memcpy( paoPoints + i, pabyData + 9 + i*24, 16 );
761 62 : memcpy( padfZ + i, pabyData + 9 + 16 + i*24, 8 );
762 : }
763 : }
764 : else
765 : {
766 105 : memcpy( paoPoints, pabyData + 9, 16 * nPointCount );
767 : }
768 :
769 : /* -------------------------------------------------------------------- */
770 : /* Byte swap if needed. */
771 : /* -------------------------------------------------------------------- */
772 126 : if( OGR_SWAP( eByteOrder ) )
773 : {
774 82 : for( i = 0; i < nPointCount; i++ )
775 : {
776 70 : CPL_SWAPDOUBLE( &(paoPoints[i].x) );
777 70 : CPL_SWAPDOUBLE( &(paoPoints[i].y) );
778 : }
779 :
780 12 : if( bIs3D )
781 : {
782 8 : for( i = 0; i < nPointCount; i++ )
783 : {
784 6 : CPL_SWAPDOUBLE( padfZ + i );
785 : }
786 : }
787 : }
788 :
789 126 : return OGRERR_NONE;
790 : }
791 :
792 : /************************************************************************/
793 : /* exportToWkb() */
794 : /* */
795 : /* Build a well known binary representation of this object. */
796 : /************************************************************************/
797 :
798 60 : OGRErr OGRLineString::exportToWkb( OGRwkbByteOrder eByteOrder,
799 : unsigned char * pabyData ) const
800 :
801 : {
802 : /* -------------------------------------------------------------------- */
803 : /* Set the byte order. */
804 : /* -------------------------------------------------------------------- */
805 60 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
806 :
807 : /* -------------------------------------------------------------------- */
808 : /* Set the geometry feature type. */
809 : /* -------------------------------------------------------------------- */
810 60 : GUInt32 nGType = getGeometryType();
811 :
812 60 : if( eByteOrder == wkbNDR )
813 49 : nGType = CPL_LSBWORD32( nGType );
814 : else
815 11 : nGType = CPL_MSBWORD32( nGType );
816 :
817 60 : memcpy( pabyData + 1, &nGType, 4 );
818 :
819 : /* -------------------------------------------------------------------- */
820 : /* Copy in the data count. */
821 : /* -------------------------------------------------------------------- */
822 60 : memcpy( pabyData+5, &nPointCount, 4 );
823 :
824 : /* -------------------------------------------------------------------- */
825 : /* Copy in the raw data. */
826 : /* -------------------------------------------------------------------- */
827 : int i;
828 :
829 60 : if( getCoordinateDimension() == 3 )
830 : {
831 26 : for( i = 0; i < nPointCount; i++ )
832 : {
833 20 : memcpy( pabyData + 9 + 24*i, paoPoints+i, 16 );
834 20 : memcpy( pabyData + 9 + 16 + 24*i, padfZ+i, 8 );
835 : }
836 : }
837 : else
838 54 : memcpy( pabyData+9, paoPoints, 16 * nPointCount );
839 :
840 : /* -------------------------------------------------------------------- */
841 : /* Swap if needed. */
842 : /* -------------------------------------------------------------------- */
843 60 : if( OGR_SWAP( eByteOrder ) )
844 : {
845 : int nCount;
846 :
847 11 : nCount = CPL_SWAP32( nPointCount );
848 11 : memcpy( pabyData+5, &nCount, 4 );
849 :
850 149 : for( i = getCoordinateDimension() * nPointCount - 1; i >= 0; i-- )
851 : {
852 138 : CPL_SWAP64PTR( pabyData + 9 + 8 * i );
853 : }
854 : }
855 :
856 60 : return OGRERR_NONE;
857 : }
858 :
859 : /************************************************************************/
860 : /* importFromWkt() */
861 : /* */
862 : /* Instantiate from well known text format. Currently this is */
863 : /* `LINESTRING ( x y, x y, ...)', */
864 : /************************************************************************/
865 :
866 128 : OGRErr OGRLineString::importFromWkt( char ** ppszInput )
867 :
868 : {
869 : char szToken[OGR_WKT_TOKEN_MAX];
870 128 : const char *pszInput = *ppszInput;
871 :
872 128 : if( paoPoints != NULL )
873 : {
874 0 : nPointCount = 0;
875 :
876 0 : CPLFree( paoPoints );
877 0 : paoPoints = NULL;
878 :
879 0 : CPLFree( padfZ );
880 0 : padfZ = NULL;
881 : }
882 :
883 : /* -------------------------------------------------------------------- */
884 : /* Read and verify the ``LINESTRING'' keyword token. */
885 : /* -------------------------------------------------------------------- */
886 128 : pszInput = OGRWktReadToken( pszInput, szToken );
887 :
888 128 : if( !EQUAL(szToken,getGeometryName()) )
889 0 : return OGRERR_CORRUPT_DATA;
890 :
891 : /* -------------------------------------------------------------------- */
892 : /* Check for EMPTY or (EMPTY). */
893 : /* -------------------------------------------------------------------- */
894 : const char *pszPreScan;
895 :
896 128 : pszPreScan = OGRWktReadToken( pszInput, szToken );
897 128 : if( EQUAL(szToken,"EMPTY") )
898 : {
899 7 : *ppszInput = (char *) pszPreScan;
900 7 : return OGRERR_NONE;
901 : }
902 :
903 121 : if( !EQUAL(szToken,"(") )
904 0 : return OGRERR_CORRUPT_DATA;
905 :
906 121 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
907 121 : if( EQUAL(szToken,"EMPTY") )
908 : {
909 1 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
910 :
911 1 : *ppszInput = (char *) pszPreScan;
912 :
913 1 : if( !EQUAL(szToken,")") )
914 0 : return OGRERR_CORRUPT_DATA;
915 : else
916 1 : return OGRERR_NONE;
917 : }
918 :
919 : /* -------------------------------------------------------------------- */
920 : /* Read the point list. */
921 : /* -------------------------------------------------------------------- */
922 120 : int nMaxPoint = 0;
923 :
924 120 : nPointCount = 0;
925 :
926 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoint,
927 120 : &nPointCount );
928 120 : if( pszInput == NULL )
929 0 : return OGRERR_CORRUPT_DATA;
930 :
931 120 : *ppszInput = (char *) pszInput;
932 :
933 120 : if( padfZ == NULL )
934 95 : nCoordDimension = 2;
935 : else
936 25 : nCoordDimension = 3;
937 :
938 120 : return OGRERR_NONE;
939 : }
940 :
941 : /************************************************************************/
942 : /* exportToWkt() */
943 : /* */
944 : /* Translate this structure into it's well known text format */
945 : /* equivelent. This could be made alot more CPU efficient! */
946 : /************************************************************************/
947 :
948 330 : OGRErr OGRLineString::exportToWkt( char ** ppszDstText ) const
949 :
950 : {
951 330 : int nMaxString = nPointCount * 40 * 3 + 20;
952 330 : int nRetLen = 0;
953 :
954 : /* -------------------------------------------------------------------- */
955 : /* Handle special empty case. */
956 : /* -------------------------------------------------------------------- */
957 330 : if( nPointCount == 0 )
958 : {
959 10 : CPLString osEmpty;
960 10 : osEmpty.Printf("%s EMPTY",getGeometryName());
961 10 : *ppszDstText = CPLStrdup(osEmpty);
962 10 : return OGRERR_NONE;
963 : }
964 :
965 : /* -------------------------------------------------------------------- */
966 : /* General case. */
967 : /* -------------------------------------------------------------------- */
968 320 : *ppszDstText = (char *) VSIMalloc( nMaxString );
969 320 : if( *ppszDstText == NULL )
970 0 : return OGRERR_NOT_ENOUGH_MEMORY;
971 :
972 320 : sprintf( *ppszDstText, "%s (", getGeometryName() );
973 :
974 3807 : for( int i = 0; i < nPointCount; i++ )
975 : {
976 3487 : if( nMaxString <= (int) strlen(*ppszDstText+nRetLen) + 32 + nRetLen )
977 : {
978 : CPLDebug( "OGR",
979 : "OGRLineString::exportToWkt() ... buffer overflow.\n"
980 : "nMaxString=%d, strlen(*ppszDstText) = %d, i=%d\n"
981 : "*ppszDstText = %s",
982 0 : nMaxString, (int) strlen(*ppszDstText), i, *ppszDstText );
983 :
984 0 : VSIFree( *ppszDstText );
985 0 : *ppszDstText = NULL;
986 0 : return OGRERR_NOT_ENOUGH_MEMORY;
987 : }
988 :
989 3487 : if( i > 0 )
990 3167 : strcat( *ppszDstText + nRetLen, "," );
991 :
992 3487 : nRetLen += strlen(*ppszDstText + nRetLen);
993 3487 : if( getCoordinateDimension() == 3 )
994 : OGRMakeWktCoordinate( *ppszDstText + nRetLen,
995 497 : paoPoints[i].x,
996 497 : paoPoints[i].y,
997 : padfZ[i],
998 1491 : nCoordDimension );
999 : else
1000 : OGRMakeWktCoordinate( *ppszDstText + nRetLen,
1001 2990 : paoPoints[i].x,
1002 2990 : paoPoints[i].y,
1003 : 0.0,
1004 8970 : nCoordDimension );
1005 :
1006 3487 : nRetLen += strlen(*ppszDstText + nRetLen);
1007 : }
1008 :
1009 320 : strcat( *ppszDstText+nRetLen, ")" );
1010 :
1011 320 : return OGRERR_NONE;
1012 : }
1013 :
1014 : /************************************************************************/
1015 : /* get_Length() */
1016 : /* */
1017 : /* For now we return a simple euclidian 2D distance. */
1018 : /************************************************************************/
1019 :
1020 0 : double OGRLineString::get_Length() const
1021 :
1022 : {
1023 0 : double dfLength = 0;
1024 : int i;
1025 :
1026 0 : for( i = 0; i < nPointCount-1; i++ )
1027 : {
1028 : double dfDeltaX, dfDeltaY;
1029 :
1030 0 : dfDeltaX = paoPoints[i+1].x - paoPoints[i].x;
1031 0 : dfDeltaY = paoPoints[i+1].y - paoPoints[i].y;
1032 0 : dfLength += sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY);
1033 : }
1034 :
1035 0 : return dfLength;
1036 : }
1037 :
1038 : /************************************************************************/
1039 : /* StartPoint() */
1040 : /************************************************************************/
1041 :
1042 0 : void OGRLineString::StartPoint( OGRPoint * poPoint ) const
1043 :
1044 : {
1045 0 : getPoint( 0, poPoint );
1046 0 : }
1047 :
1048 : /************************************************************************/
1049 : /* EndPoint() */
1050 : /************************************************************************/
1051 :
1052 0 : void OGRLineString::EndPoint( OGRPoint * poPoint ) const
1053 :
1054 : {
1055 0 : getPoint( nPointCount-1, poPoint );
1056 0 : }
1057 :
1058 : /************************************************************************/
1059 : /* Value() */
1060 : /* */
1061 : /* Get an interpolated point at some distance along the curve. */
1062 : /************************************************************************/
1063 :
1064 0 : void OGRLineString::Value( double dfDistance, OGRPoint * poPoint ) const
1065 :
1066 : {
1067 0 : double dfLength = 0;
1068 : int i;
1069 :
1070 0 : if( dfDistance < 0 )
1071 : {
1072 0 : StartPoint( poPoint );
1073 0 : return;
1074 : }
1075 :
1076 0 : for( i = 0; i < nPointCount-1; i++ )
1077 : {
1078 : double dfDeltaX, dfDeltaY, dfSegLength;
1079 :
1080 0 : dfDeltaX = paoPoints[i+1].x - paoPoints[i].x;
1081 0 : dfDeltaY = paoPoints[i+1].y - paoPoints[i].y;
1082 0 : dfSegLength = sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY);
1083 :
1084 0 : if (dfSegLength > 0)
1085 : {
1086 0 : if( (dfLength <= dfDistance) && ((dfLength + dfSegLength) >=
1087 : dfDistance) )
1088 : {
1089 : double dfRatio;
1090 :
1091 0 : dfRatio = (dfDistance - dfLength) / dfSegLength;
1092 :
1093 0 : poPoint->setX( paoPoints[i].x * (1 - dfRatio)
1094 0 : + paoPoints[i+1].x * dfRatio );
1095 0 : poPoint->setY( paoPoints[i].y * (1 - dfRatio)
1096 0 : + paoPoints[i+1].y * dfRatio );
1097 :
1098 0 : if( getCoordinateDimension() == 3 )
1099 0 : poPoint->setZ( padfZ[i] * (1 - dfRatio)
1100 0 : + padfZ[i] * dfRatio );
1101 :
1102 0 : return;
1103 : }
1104 :
1105 0 : dfLength += dfSegLength;
1106 : }
1107 : }
1108 :
1109 0 : EndPoint( poPoint );
1110 : }
1111 :
1112 : /************************************************************************/
1113 : /* getEnvelope() */
1114 : /************************************************************************/
1115 :
1116 860 : void OGRLineString::getEnvelope( OGREnvelope * psEnvelope ) const
1117 :
1118 : {
1119 : double dfMinX, dfMinY, dfMaxX, dfMaxY;
1120 :
1121 860 : if( nPointCount == 0 )
1122 1 : return;
1123 :
1124 859 : dfMinX = dfMaxX = paoPoints[0].x;
1125 859 : dfMinY = dfMaxY = paoPoints[0].y;
1126 :
1127 87403 : for( int iPoint = 1; iPoint < nPointCount; iPoint++ )
1128 : {
1129 86544 : if( dfMaxX < paoPoints[iPoint].x )
1130 10970 : dfMaxX = paoPoints[iPoint].x;
1131 86544 : if( dfMaxY < paoPoints[iPoint].y )
1132 11091 : dfMaxY = paoPoints[iPoint].y;
1133 86544 : if( dfMinX > paoPoints[iPoint].x )
1134 2985 : dfMinX = paoPoints[iPoint].x;
1135 86544 : if( dfMinY > paoPoints[iPoint].y )
1136 5595 : dfMinY = paoPoints[iPoint].y;
1137 : }
1138 :
1139 859 : psEnvelope->MinX = dfMinX;
1140 859 : psEnvelope->MaxX = dfMaxX;
1141 859 : psEnvelope->MinY = dfMinY;
1142 859 : psEnvelope->MaxY = dfMaxY;
1143 : }
1144 :
1145 : /************************************************************************/
1146 : /* Equals() */
1147 : /************************************************************************/
1148 :
1149 3 : OGRBoolean OGRLineString::Equals( OGRGeometry * poOther ) const
1150 :
1151 : {
1152 3 : OGRLineString *poOLine = (OGRLineString *) poOther;
1153 :
1154 3 : if( poOLine == this )
1155 0 : return TRUE;
1156 :
1157 3 : if( poOther->getGeometryType() != getGeometryType() )
1158 0 : return FALSE;
1159 :
1160 : // we should eventually test the SRS.
1161 :
1162 3 : if( getNumPoints() != poOLine->getNumPoints() )
1163 0 : return FALSE;
1164 :
1165 15 : for( int iPoint = 0; iPoint < getNumPoints(); iPoint++ )
1166 : {
1167 12 : if( getX(iPoint) != poOLine->getX(iPoint)
1168 : || getY(iPoint) != poOLine->getY(iPoint)
1169 : || getZ(iPoint) != poOLine->getZ(iPoint) )
1170 0 : return FALSE;
1171 : }
1172 :
1173 3 : return TRUE;
1174 : }
1175 :
1176 : /************************************************************************/
1177 : /* transform() */
1178 : /************************************************************************/
1179 :
1180 14 : OGRErr OGRLineString::transform( OGRCoordinateTransformation *poCT )
1181 :
1182 : {
1183 : #ifdef DISABLE_OGRGEOM_TRANSFORM
1184 : return OGRERR_FAILURE;
1185 : #else
1186 : double *xyz;
1187 : int i;
1188 :
1189 : /* -------------------------------------------------------------------- */
1190 : /* Because we don't want to partially transform this geometry */
1191 : /* (if some points fail after some have succeeded) we will */
1192 : /* instead make a copy of the points to operate on. */
1193 : /* -------------------------------------------------------------------- */
1194 14 : xyz = (double *) CPLMalloc(sizeof(double) * nPointCount * 3);
1195 14 : if( xyz == NULL )
1196 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1197 :
1198 279 : for( i = 0; i < nPointCount; i++ )
1199 : {
1200 265 : xyz[i ] = paoPoints[i].x;
1201 265 : xyz[i+nPointCount] = paoPoints[i].y;
1202 265 : if( padfZ )
1203 0 : xyz[i+nPointCount*2] = padfZ[i];
1204 : else
1205 265 : xyz[i+nPointCount*2] = 0.0;
1206 : }
1207 :
1208 : /* -------------------------------------------------------------------- */
1209 : /* Transform and reapply. */
1210 : /* -------------------------------------------------------------------- */
1211 14 : if( !poCT->Transform( nPointCount, xyz, xyz + nPointCount,
1212 14 : xyz+nPointCount*2 ) )
1213 : {
1214 0 : CPLFree( xyz );
1215 0 : return OGRERR_FAILURE;
1216 : }
1217 : else
1218 : {
1219 : setPoints( nPointCount, xyz, xyz+nPointCount,
1220 14 : ( padfZ ) ? xyz+nPointCount*2 : NULL);
1221 14 : CPLFree( xyz );
1222 :
1223 14 : assignSpatialReference( poCT->GetTargetCS() );
1224 :
1225 14 : return OGRERR_NONE;
1226 : }
1227 : #endif
1228 : }
1229 :
1230 : /************************************************************************/
1231 : /* IsEmpty() */
1232 : /************************************************************************/
1233 :
1234 830 : OGRBoolean OGRLineString::IsEmpty( ) const
1235 : {
1236 830 : return (nPointCount == 0);
1237 : }
1238 :
1239 : /************************************************************************/
1240 : /* OGRLineString::segmentize() */
1241 : /************************************************************************/
1242 :
1243 11 : void OGRLineString::segmentize( double dfMaxLength )
1244 : {
1245 11 : if (dfMaxLength <= 0)
1246 : {
1247 : CPLError(CE_Failure, CPLE_AppDefined,
1248 0 : "dfMaxLength must be strictly positive");
1249 0 : return;
1250 : }
1251 :
1252 : int i;
1253 11 : OGRRawPoint* paoNewPoints = NULL;
1254 11 : double* padfNewZ = NULL;
1255 11 : int nNewPointCount = 0;
1256 11 : double dfSquareMaxLength = dfMaxLength * dfMaxLength;
1257 :
1258 247 : for( i = 0; i < nPointCount; i++ )
1259 : {
1260 : paoNewPoints = (OGRRawPoint *)
1261 247 : OGRRealloc(paoNewPoints, sizeof(OGRRawPoint) * (nNewPointCount + 1));
1262 247 : paoNewPoints[nNewPointCount] = paoPoints[i];
1263 :
1264 247 : if( getCoordinateDimension() == 3 )
1265 : {
1266 : padfNewZ = (double *)
1267 0 : OGRRealloc(padfNewZ, sizeof(double) * (nNewPointCount + 1));
1268 0 : padfNewZ[nNewPointCount] = padfZ[i];
1269 : }
1270 :
1271 247 : nNewPointCount++;
1272 :
1273 247 : if (i == nPointCount - 1)
1274 11 : break;
1275 :
1276 236 : double dfX = paoPoints[i+1].x - paoPoints[i].x;
1277 236 : double dfY = paoPoints[i+1].y - paoPoints[i].y;
1278 236 : double dfSquareDist = dfX * dfX + dfY * dfY;
1279 236 : if (dfSquareDist > dfSquareMaxLength)
1280 : {
1281 97 : int nIntermediatePoints = (int)floor(sqrt(dfSquareDist / dfSquareMaxLength));
1282 : int j;
1283 :
1284 : paoNewPoints = (OGRRawPoint *)
1285 97 : OGRRealloc(paoNewPoints, sizeof(OGRRawPoint) * (nNewPointCount + nIntermediatePoints));
1286 97 : if( getCoordinateDimension() == 3 )
1287 : {
1288 : padfNewZ = (double *)
1289 0 : OGRRealloc(padfNewZ, sizeof(double) * (nNewPointCount + nIntermediatePoints));
1290 : }
1291 :
1292 273 : for(j=1;j<=nIntermediatePoints;j++)
1293 : {
1294 176 : paoNewPoints[nNewPointCount + j - 1].x = paoPoints[i].x + j * dfX / (nIntermediatePoints + 1);
1295 176 : paoNewPoints[nNewPointCount + j - 1].y = paoPoints[i].y + j * dfY / (nIntermediatePoints + 1);
1296 176 : if( getCoordinateDimension() == 3 )
1297 : {
1298 : /* No interpolation */
1299 0 : padfNewZ[nNewPointCount + j - 1] = 0;
1300 : }
1301 : }
1302 :
1303 97 : nNewPointCount += nIntermediatePoints;
1304 : }
1305 : }
1306 :
1307 11 : OGRFree(paoPoints);
1308 11 : paoPoints = paoNewPoints;
1309 11 : nPointCount = nNewPointCount;
1310 :
1311 11 : if( getCoordinateDimension() == 3 )
1312 : {
1313 0 : OGRFree(padfZ);
1314 0 : padfZ = padfNewZ;
1315 : }
1316 : }
|