1 : /******************************************************************************
2 : * $Id: ogrlinestring.cpp 24519 2012-05-30 21:28:53Z 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 24519 2012-05-30 21:28:53Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRLineString() */
38 : /************************************************************************/
39 :
40 : /**
41 : * \brief Create an empty line string.
42 : */
43 :
44 801190 : OGRLineString::OGRLineString()
45 :
46 : {
47 801190 : nPointCount = 0;
48 801190 : paoPoints = NULL;
49 801190 : padfZ = NULL;
50 801190 : }
51 :
52 : /************************************************************************/
53 : /* ~OGRLineString() */
54 : /************************************************************************/
55 :
56 801190 : OGRLineString::~OGRLineString()
57 :
58 : {
59 801190 : if( paoPoints != NULL )
60 800760 : OGRFree( paoPoints );
61 801190 : if( padfZ != NULL )
62 340725 : OGRFree( padfZ );
63 801190 : }
64 :
65 : /************************************************************************/
66 : /* getGeometryType() */
67 : /************************************************************************/
68 :
69 371916 : OGRwkbGeometryType OGRLineString::getGeometryType() const
70 :
71 : {
72 371916 : if( getCoordinateDimension() == 3 )
73 32815 : return wkbLineString25D;
74 : else
75 339101 : return wkbLineString;
76 : }
77 :
78 : /************************************************************************/
79 : /* flattenTo2D() */
80 : /************************************************************************/
81 :
82 31 : void OGRLineString::flattenTo2D()
83 :
84 : {
85 31 : Make2D();
86 31 : }
87 :
88 : /************************************************************************/
89 : /* getGeometryName() */
90 : /************************************************************************/
91 :
92 1160 : const char * OGRLineString::getGeometryName() const
93 :
94 : {
95 1160 : return "LINESTRING";
96 : }
97 :
98 : /************************************************************************/
99 : /* clone() */
100 : /************************************************************************/
101 :
102 62204 : OGRGeometry *OGRLineString::clone() const
103 :
104 : {
105 : OGRLineString *poNewLineString;
106 :
107 62204 : poNewLineString = new OGRLineString();
108 :
109 62204 : poNewLineString->assignSpatialReference( getSpatialReference() );
110 62204 : poNewLineString->setPoints( nPointCount, paoPoints, padfZ );
111 62204 : poNewLineString->setCoordinateDimension( getCoordinateDimension() );
112 :
113 62204 : return poNewLineString;
114 : }
115 :
116 : /************************************************************************/
117 : /* empty() */
118 : /************************************************************************/
119 :
120 543 : void OGRLineString::empty()
121 :
122 : {
123 543 : setNumPoints( 0 );
124 543 : }
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 337030 : void OGRLineString::setCoordinateDimension( int nNewDimension )
141 :
142 : {
143 337030 : nCoordDimension = nNewDimension;
144 337030 : if( nNewDimension == 2 )
145 5536 : Make2D();
146 331494 : else if( nNewDimension == 3 )
147 331494 : Make3D();
148 337030 : }
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 1905 : int OGRLineString::WkbSize() const
158 :
159 : {
160 1905 : return 5 + 4 + 8 * nPointCount * getCoordinateDimension();
161 : }
162 :
163 : /************************************************************************/
164 : /* Make2D() */
165 : /************************************************************************/
166 :
167 63948 : void OGRLineString::Make2D()
168 :
169 : {
170 63948 : if( padfZ != NULL )
171 : {
172 382 : OGRFree( padfZ );
173 382 : padfZ = NULL;
174 : }
175 63948 : nCoordDimension = 2;
176 63948 : }
177 :
178 : /************************************************************************/
179 : /* Make3D() */
180 : /************************************************************************/
181 :
182 700707 : void OGRLineString::Make3D()
183 :
184 : {
185 700707 : if( padfZ == NULL )
186 : {
187 341024 : if( nPointCount == 0 )
188 276554 : padfZ = (double *) OGRCalloc(sizeof(double),1);
189 : else
190 64470 : padfZ = (double *) OGRCalloc(sizeof(double),nPointCount);
191 : }
192 700707 : nCoordDimension = 3;
193 700707 : }
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 2919 : void OGRLineString::getPoint( int i, OGRPoint * poPoint ) const
209 :
210 : {
211 2919 : assert( i >= 0 );
212 2919 : assert( i < nPointCount );
213 2919 : assert( poPoint != NULL );
214 :
215 2919 : poPoint->setX( paoPoints[i].x );
216 2919 : poPoint->setY( paoPoints[i].y );
217 :
218 2919 : if( getCoordinateDimension() == 3 && padfZ != NULL )
219 123 : poPoint->setZ( padfZ[i] );
220 2919 : }
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 760377 : double OGRLineString::getZ( int iVertex ) const
275 :
276 : {
277 760377 : if( padfZ != NULL && iVertex >= 0 && iVertex < nPointCount
278 : && nCoordDimension >= 3 )
279 60388 : return( padfZ[iVertex] );
280 : else
281 699989 : 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 4157233 : void OGRLineString::setNumPoints( int nNewPointCount )
301 :
302 : {
303 4157233 : if( nNewPointCount == 0 )
304 : {
305 658 : OGRFree( paoPoints );
306 658 : paoPoints = NULL;
307 :
308 658 : OGRFree( padfZ );
309 658 : padfZ = NULL;
310 :
311 658 : nPointCount = 0;
312 658 : return;
313 : }
314 :
315 4156575 : if( nNewPointCount > nPointCount )
316 : {
317 : OGRRawPoint* paoNewPoints = (OGRRawPoint *)
318 4147639 : VSIRealloc(paoPoints, sizeof(OGRRawPoint) * nNewPointCount);
319 4147639 : if (paoNewPoints == NULL)
320 : {
321 : CPLError(CE_Failure, CPLE_OutOfMemory,
322 0 : "Could not allocate array for %d points", nNewPointCount);
323 0 : return;
324 : }
325 4147639 : paoPoints = paoNewPoints;
326 :
327 : memset( paoPoints + nPointCount,
328 4147639 : 0, sizeof(OGRRawPoint) * (nNewPointCount - nPointCount) );
329 :
330 4147639 : if( getCoordinateDimension() == 3 )
331 : {
332 : double* padfNewZ = (double *)
333 286012 : VSIRealloc( padfZ, sizeof(double)*nNewPointCount );
334 286012 : if (padfNewZ == NULL)
335 : {
336 : CPLError(CE_Failure, CPLE_OutOfMemory,
337 0 : "Could not allocate array for %d points", nNewPointCount);
338 0 : return;
339 : }
340 286012 : padfZ = padfNewZ;
341 : memset( padfZ + nPointCount, 0,
342 286012 : sizeof(double) * (nNewPointCount - nPointCount) );
343 : }
344 : }
345 :
346 4156575 : nPointCount = nNewPointCount;
347 : }
348 :
349 : /************************************************************************/
350 : /* setPoint() */
351 : /************************************************************************/
352 :
353 : /**
354 : * \brief Set the location of a vertex in line string.
355 : *
356 : * If iPoint is larger than the number of necessary the number of existing
357 : * points in the line string, the point count will be increased to
358 : * accomodate the request.
359 : *
360 : * There is no SFCOM analog to this method.
361 : *
362 : * @param iPoint the index of the vertex to assign (zero based).
363 : * @param poPoint the value to assign to the vertex.
364 : */
365 :
366 562 : void OGRLineString::setPoint( int iPoint, OGRPoint * poPoint )
367 :
368 : {
369 562 : if (poPoint->getCoordinateDimension() < 3)
370 562 : setPoint( iPoint, poPoint->getX(), poPoint->getY() );
371 : else
372 0 : setPoint( iPoint, poPoint->getX(), poPoint->getY(), poPoint->getZ() );
373 562 : }
374 :
375 : /************************************************************************/
376 : /* setPoint() */
377 : /************************************************************************/
378 :
379 : /**
380 : * \brief Set the location of a vertex in line string.
381 : *
382 : * If iPoint is larger than the number of necessary the number of existing
383 : * points in the line string, the point count will be increased to
384 : * accomodate the request.
385 : *
386 : * There is no SFCOM analog to this method.
387 : *
388 : * @param iPoint the index of the vertex to assign (zero based).
389 : * @param xIn input X coordinate to assign.
390 : * @param yIn input Y coordinate to assign.
391 : * @param zIn input Z coordinate to assign (defaults to zero).
392 : */
393 :
394 135905 : void OGRLineString::setPoint( int iPoint, double xIn, double yIn, double zIn )
395 :
396 : {
397 135905 : if( getCoordinateDimension() == 2 )
398 7092 : Make3D();
399 :
400 135905 : if( iPoint >= nPointCount )
401 : {
402 10801 : setNumPoints( iPoint+1 );
403 10801 : if (nPointCount < iPoint + 1)
404 0 : return;
405 : }
406 :
407 135905 : paoPoints[iPoint].x = xIn;
408 135905 : paoPoints[iPoint].y = yIn;
409 :
410 135905 : if( zIn != 0.0 )
411 : {
412 28231 : Make3D();
413 28231 : padfZ[iPoint] = zIn;
414 : }
415 107674 : else if( getCoordinateDimension() == 3 )
416 : {
417 107674 : padfZ[iPoint] = 0.0;
418 : }
419 : }
420 :
421 6209337 : void OGRLineString::setPoint( int iPoint, double xIn, double yIn )
422 :
423 : {
424 6209337 : if( iPoint >= nPointCount )
425 : {
426 3609720 : setNumPoints( iPoint+1 );
427 3609720 : if (nPointCount < iPoint + 1)
428 0 : return;
429 : }
430 :
431 6209337 : paoPoints[iPoint].x = xIn;
432 6209337 : paoPoints[iPoint].y = yIn;
433 : }
434 :
435 : /************************************************************************/
436 : /* addPoint() */
437 : /************************************************************************/
438 :
439 : /**
440 : * \brief Add a point to a line string.
441 : *
442 : * The vertex count of the line string is increased by one, and assigned from
443 : * the passed location value.
444 : *
445 : * There is no SFCOM analog to this method.
446 : *
447 : * @param poPoint the point to assign to the new vertex.
448 : */
449 :
450 740 : void OGRLineString::addPoint( OGRPoint * poPoint )
451 :
452 : {
453 740 : if ( poPoint->getCoordinateDimension() < 3 )
454 739 : setPoint( nPointCount, poPoint->getX(), poPoint->getY() );
455 : else
456 1 : setPoint( nPointCount, poPoint->getX(), poPoint->getY(), poPoint->getZ() );
457 740 : }
458 :
459 : /************************************************************************/
460 : /* addPoint() */
461 : /************************************************************************/
462 :
463 : /**
464 : * \brief Add a point to a line string.
465 : *
466 : * The vertex count of the line string is increased by one, and assigned from
467 : * the passed location value.
468 : *
469 : * There is no SFCOM analog to this method.
470 : *
471 : * @param x the X coordinate to assign to the new point.
472 : * @param y the Y coordinate to assign to the new point.
473 : * @param z the Z coordinate to assign to the new point (defaults to zero).
474 : */
475 :
476 9002 : void OGRLineString::addPoint( double x, double y, double z )
477 :
478 : {
479 9002 : setPoint( nPointCount, x, y, z );
480 9002 : }
481 :
482 3357585 : void OGRLineString::addPoint( double x, double y )
483 :
484 : {
485 3357585 : setPoint( nPointCount, x, y );
486 3357585 : }
487 :
488 : /************************************************************************/
489 : /* setPoints() */
490 : /************************************************************************/
491 :
492 : /**
493 : * \brief Assign all points in a line string.
494 : *
495 : * This method clears any existing points assigned to this line string,
496 : * and assigns a whole new set. It is the most efficient way of assigning
497 : * the value of a line string.
498 : *
499 : * There is no SFCOM analog to this method.
500 : *
501 : * @param nPointsIn number of points being passed in paoPointsIn
502 : * @param paoPointsIn list of points being assigned.
503 : * @param padfZ the Z values that go with the points (optional, may be NULL).
504 : */
505 :
506 75816 : void OGRLineString::setPoints( int nPointsIn, OGRRawPoint * paoPointsIn,
507 : double * padfZ )
508 :
509 : {
510 75816 : setNumPoints( nPointsIn );
511 75816 : if (nPointCount < nPointsIn)
512 0 : return;
513 :
514 75816 : memcpy( paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
515 :
516 : /* -------------------------------------------------------------------- */
517 : /* Check 2D/3D. */
518 : /* -------------------------------------------------------------------- */
519 75816 : if( padfZ == NULL && getCoordinateDimension() > 2 )
520 : {
521 0 : Make2D();
522 : }
523 75816 : else if( padfZ )
524 : {
525 58108 : Make3D();
526 58108 : memcpy( this->padfZ, padfZ, sizeof(double) * nPointsIn );
527 : }
528 : }
529 :
530 : /************************************************************************/
531 : /* setPoints() */
532 : /************************************************************************/
533 :
534 : /**
535 : * \brief Assign all points in a line string.
536 : *
537 : * This method clear any existing points assigned to this line string,
538 : * and assigns a whole new set.
539 : *
540 : * There is no SFCOM analog to this method.
541 : *
542 : * @param nPointsIn number of points being passed in padfX and padfY.
543 : * @param padfX list of X coordinates of points being assigned.
544 : * @param padfY list of Y coordinates of points being assigned.
545 : * @param padfZ list of Z coordinates of points being assigned (defaults to
546 : * NULL for 2D objects).
547 : */
548 :
549 331893 : void OGRLineString::setPoints( int nPointsIn, double * padfX, double * padfY,
550 : double * padfZ )
551 :
552 : {
553 : int i;
554 :
555 : /* -------------------------------------------------------------------- */
556 : /* Check 2D/3D. */
557 : /* -------------------------------------------------------------------- */
558 331893 : if( padfZ == NULL )
559 56736 : Make2D();
560 : else
561 275157 : Make3D();
562 :
563 : /* -------------------------------------------------------------------- */
564 : /* Assign values. */
565 : /* -------------------------------------------------------------------- */
566 331893 : setNumPoints( nPointsIn );
567 331893 : if (nPointCount < nPointsIn)
568 0 : return;
569 :
570 3590607 : for( i = 0; i < nPointsIn; i++ )
571 : {
572 3258714 : paoPoints[i].x = padfX[i];
573 3258714 : paoPoints[i].y = padfY[i];
574 : }
575 :
576 331893 : if( this->padfZ != NULL )
577 275157 : memcpy( this->padfZ, padfZ, sizeof(double) * nPointsIn );
578 : }
579 :
580 : /************************************************************************/
581 : /* getPoints() */
582 : /************************************************************************/
583 :
584 : /**
585 : * \brief Returns all points of line string.
586 : *
587 : * This method copies all points into user list. This list must be at
588 : * least sizeof(OGRRawPoint) * OGRGeometry::getNumPoints() byte in size.
589 : * It also copies all Z coordinates.
590 : *
591 : * There is no SFCOM analog to this method.
592 : *
593 : * @param paoPointsOut a buffer into which the points is written.
594 : * @param padfZ the Z values that go with the points (optional, may be NULL).
595 : */
596 :
597 104 : void OGRLineString::getPoints( OGRRawPoint * paoPointsOut, double * padfZ ) const
598 : {
599 104 : if ( ! paoPointsOut )
600 0 : return;
601 :
602 104 : memcpy( paoPointsOut, paoPoints, sizeof(OGRRawPoint) * nPointCount );
603 :
604 : /* -------------------------------------------------------------------- */
605 : /* Check 2D/3D. */
606 : /* -------------------------------------------------------------------- */
607 104 : if( padfZ )
608 : {
609 45 : if ( this->padfZ )
610 44 : memcpy( padfZ, this->padfZ, sizeof(double) * nPointCount );
611 : else
612 1 : memset( padfZ, 0, sizeof(double) * nPointCount );
613 : }
614 : }
615 :
616 :
617 : /************************************************************************/
618 : /* getPoints() */
619 : /************************************************************************/
620 :
621 : /**
622 : * \brief Returns all points of line string.
623 : *
624 : * This method copies all points into user arrays. The user provides the
625 : * stride between 2 consecutives elements of the array.
626 : *
627 : * On some CPU architectures, care must be taken so that the arrays are properly aligned.
628 : *
629 : * There is no SFCOM analog to this method.
630 : *
631 : * @param pabyX a buffer of at least (sizeof(double) * nXStride * nPointCount) bytes, may be NULL.
632 : * @param nXStride the number of bytes between 2 elements of pabyX.
633 : * @param pabyY a buffer of at least (sizeof(double) * nYStride * nPointCount) bytes, may be NULL.
634 : * @param nYStride the number of bytes between 2 elements of pabyY.
635 : * @param pabyZ a buffer of at last size (sizeof(double) * nZStride * nPointCount) bytes, may be NULL.
636 : * @param nZStride the number of bytes between 2 elements of pabyZ.
637 : *
638 : * @since OGR 1.9.0
639 : */
640 :
641 9 : void OGRLineString::getPoints( void* pabyX, int nXStride,
642 : void* pabyY, int nYStride,
643 : void* pabyZ, int nZStride) const
644 : {
645 : int i;
646 9 : if (pabyX != NULL && nXStride == 0)
647 0 : return;
648 9 : if (pabyY != NULL && nYStride == 0)
649 0 : return;
650 9 : if (pabyZ != NULL && nZStride == 0)
651 0 : return;
652 9 : if (nXStride == 2 * sizeof(double) &&
653 : nYStride == 2 * sizeof(double) &&
654 : (char*)pabyY == (char*)pabyX + sizeof(double) &&
655 : (pabyZ == NULL || nZStride == sizeof(double)))
656 : {
657 9 : getPoints((OGRRawPoint *)pabyX, (double*)pabyZ);
658 9 : return;
659 : }
660 0 : for(i=0;i<nPointCount;i++)
661 : {
662 0 : if (pabyX) *(double*)((char*)pabyX + i * nXStride) = paoPoints[i].x;
663 0 : if (pabyY) *(double*)((char*)pabyY + i * nYStride) = paoPoints[i].y;
664 : }
665 :
666 0 : if (pabyZ)
667 : {
668 0 : for(i=0;i<nPointCount;i++)
669 : {
670 0 : *(double*)((char*)pabyZ + i * nZStride) = (padfZ) ? padfZ[i] : 0.0;
671 : }
672 : }
673 : }
674 :
675 : /************************************************************************/
676 : /* reversePoints() */
677 : /************************************************************************/
678 :
679 : /**
680 : * \brief Reverse point order.
681 : *
682 : * This method updates the points in this line string in place
683 : * reversing the point ordering (first for last, etc).
684 : */
685 :
686 0 : void OGRLineString::reversePoints()
687 :
688 : {
689 : int i;
690 :
691 0 : for( i = 0; i < nPointCount/2; i++ )
692 : {
693 0 : OGRRawPoint sPointTemp = paoPoints[i];
694 :
695 0 : paoPoints[i] = paoPoints[nPointCount-i-1];
696 0 : paoPoints[nPointCount-i-1] = sPointTemp;
697 :
698 0 : if( padfZ )
699 : {
700 0 : double dfZTemp = padfZ[i];
701 :
702 0 : padfZ[i] = padfZ[nPointCount-i-1];
703 0 : padfZ[nPointCount-i-1] = dfZTemp;
704 : }
705 : }
706 0 : }
707 :
708 : /************************************************************************/
709 : /* addSubLineString() */
710 : /************************************************************************/
711 :
712 : /**
713 : * \brief Add a segment of another linestring to this one.
714 : *
715 : * Adds the request range of vertices to the end of this line string
716 : * in an efficient manner. If the nStartVertex is larger than the
717 : * nEndVertex then the vertices will be reversed as they are copied.
718 : *
719 : * @param poOtherLine the other OGRLineString.
720 : * @param nStartVertex the first vertex to copy, defaults to 0 to start
721 : * with the first vertex in the other linestring.
722 : * @param nEndVertex the last vertex to copy, defaults to -1 indicating
723 : * the last vertex of the other line string.
724 : */
725 :
726 6279 : void OGRLineString::addSubLineString( const OGRLineString *poOtherLine,
727 : int nStartVertex, int nEndVertex )
728 :
729 : {
730 6279 : int nOtherLineNumPoints = poOtherLine->getNumPoints();
731 6279 : if (nOtherLineNumPoints == 0)
732 0 : return;
733 :
734 : /* -------------------------------------------------------------------- */
735 : /* Do a bit of argument defaulting and validation. */
736 : /* -------------------------------------------------------------------- */
737 6279 : if( nEndVertex == -1 )
738 6240 : nEndVertex = nOtherLineNumPoints - 1;
739 :
740 6279 : if( nStartVertex < 0 || nEndVertex < 0
741 : || nStartVertex >= nOtherLineNumPoints
742 : || nEndVertex >= nOtherLineNumPoints )
743 : {
744 0 : CPLAssert( FALSE );
745 0 : return;
746 : }
747 :
748 : /* -------------------------------------------------------------------- */
749 : /* Grow this linestring to hold the additional points. */
750 : /* -------------------------------------------------------------------- */
751 6279 : int nOldPoints = nPointCount;
752 6279 : int nPointsToAdd = ABS(nEndVertex-nStartVertex) + 1;
753 :
754 6279 : setNumPoints( nPointsToAdd + nOldPoints );
755 6279 : if (nPointCount < nPointsToAdd + nOldPoints)
756 0 : return;
757 :
758 : /* -------------------------------------------------------------------- */
759 : /* Copy the x/y points - forward copies use memcpy. */
760 : /* -------------------------------------------------------------------- */
761 6279 : if( nEndVertex >= nStartVertex )
762 : {
763 : memcpy( paoPoints + nOldPoints,
764 : poOtherLine->paoPoints + nStartVertex,
765 6273 : sizeof(OGRRawPoint) * nPointsToAdd );
766 6273 : if( poOtherLine->padfZ != NULL )
767 : {
768 9 : Make3D();
769 : memcpy( padfZ + nOldPoints, poOtherLine->padfZ + nStartVertex,
770 9 : sizeof(double) * nPointsToAdd );
771 : }
772 : }
773 :
774 : /* -------------------------------------------------------------------- */
775 : /* Copy the x/y points - reverse copies done double by double. */
776 : /* -------------------------------------------------------------------- */
777 : else
778 : {
779 : int i;
780 :
781 26 : for( i = 0; i < nPointsToAdd; i++ )
782 : {
783 20 : paoPoints[i+nOldPoints].x =
784 20 : poOtherLine->paoPoints[nStartVertex-i].x;
785 20 : paoPoints[i+nOldPoints].y =
786 20 : poOtherLine->paoPoints[nStartVertex-i].y;
787 : }
788 :
789 6 : if( poOtherLine->padfZ != NULL )
790 : {
791 0 : Make3D();
792 :
793 0 : for( i = 0; i < nPointsToAdd; i++ )
794 : {
795 0 : padfZ[i+nOldPoints] = poOtherLine->padfZ[nStartVertex-i];
796 : }
797 : }
798 : }
799 : }
800 :
801 : /************************************************************************/
802 : /* importFromWkb() */
803 : /* */
804 : /* Initialize from serialized stream in well known binary */
805 : /* format. */
806 : /************************************************************************/
807 :
808 386 : OGRErr OGRLineString::importFromWkb( unsigned char * pabyData,
809 : int nSize )
810 :
811 : {
812 : OGRwkbByteOrder eByteOrder;
813 :
814 386 : if( nSize < 9 && nSize != -1 )
815 0 : return OGRERR_NOT_ENOUGH_DATA;
816 :
817 : /* -------------------------------------------------------------------- */
818 : /* Get the byte order byte. */
819 : /* -------------------------------------------------------------------- */
820 386 : eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
821 386 : if (!( eByteOrder == wkbXDR || eByteOrder == wkbNDR ))
822 0 : return OGRERR_CORRUPT_DATA;
823 :
824 : /* -------------------------------------------------------------------- */
825 : /* Get the geometry feature type. For now we assume that */
826 : /* geometry type is between 0 and 255 so we only have to fetch */
827 : /* one byte. */
828 : /* -------------------------------------------------------------------- */
829 : OGRwkbGeometryType eGeometryType;
830 386 : int bIs3D = FALSE;
831 :
832 386 : if( eByteOrder == wkbNDR )
833 : {
834 372 : eGeometryType = (OGRwkbGeometryType) pabyData[1];
835 372 : bIs3D = pabyData[4] & 0x80 || pabyData[2] & 0x80;
836 : }
837 : else
838 : {
839 14 : eGeometryType = (OGRwkbGeometryType) pabyData[4];
840 14 : bIs3D = pabyData[1] & 0x80 || pabyData[3] & 0x80;
841 : }
842 :
843 386 : if( eGeometryType != wkbLineString )
844 0 : return OGRERR_CORRUPT_DATA;
845 :
846 : /* -------------------------------------------------------------------- */
847 : /* Get the vertex count. */
848 : /* -------------------------------------------------------------------- */
849 : int nNewNumPoints;
850 :
851 386 : memcpy( &nNewNumPoints, pabyData + 5, 4 );
852 :
853 386 : if( OGR_SWAP( eByteOrder ) )
854 14 : nNewNumPoints = CPL_SWAP32(nNewNumPoints);
855 :
856 : /* Check if the wkb stream buffer is big enough to store
857 : * fetched number of points.
858 : * 16 or 24 - size of point structure
859 : */
860 386 : int nPointSize = (bIs3D ? 24 : 16);
861 386 : if (nNewNumPoints < 0 || nNewNumPoints > INT_MAX / nPointSize)
862 0 : return OGRERR_CORRUPT_DATA;
863 386 : int nBufferMinSize = nPointSize * nNewNumPoints;
864 :
865 386 : if( nSize != -1 && nBufferMinSize > nSize-9 )
866 : {
867 : CPLError( CE_Failure, CPLE_AppDefined,
868 0 : "Length of input WKB is too small" );
869 0 : return OGRERR_NOT_ENOUGH_DATA;
870 : }
871 :
872 386 : setNumPoints( nNewNumPoints );
873 386 : if (nPointCount < nNewNumPoints)
874 0 : return OGRERR_FAILURE;
875 :
876 386 : if( bIs3D )
877 125 : Make3D();
878 : else
879 261 : Make2D();
880 :
881 : /* -------------------------------------------------------------------- */
882 : /* Get the vertex. */
883 : /* -------------------------------------------------------------------- */
884 386 : int i = 0;
885 :
886 386 : if( bIs3D )
887 : {
888 486 : for( i = 0; i < nPointCount; i++ )
889 : {
890 361 : memcpy( paoPoints + i, pabyData + 9 + i*24, 16 );
891 361 : memcpy( padfZ + i, pabyData + 9 + 16 + i*24, 8 );
892 : }
893 : }
894 : else
895 : {
896 261 : memcpy( paoPoints, pabyData + 9, 16 * nPointCount );
897 : }
898 :
899 : /* -------------------------------------------------------------------- */
900 : /* Byte swap if needed. */
901 : /* -------------------------------------------------------------------- */
902 386 : if( OGR_SWAP( eByteOrder ) )
903 : {
904 88 : for( i = 0; i < nPointCount; i++ )
905 : {
906 74 : CPL_SWAPDOUBLE( &(paoPoints[i].x) );
907 74 : CPL_SWAPDOUBLE( &(paoPoints[i].y) );
908 : }
909 :
910 14 : if( bIs3D )
911 : {
912 8 : for( i = 0; i < nPointCount; i++ )
913 : {
914 6 : CPL_SWAPDOUBLE( padfZ + i );
915 : }
916 : }
917 : }
918 :
919 386 : return OGRERR_NONE;
920 : }
921 :
922 : /************************************************************************/
923 : /* exportToWkb() */
924 : /* */
925 : /* Build a well known binary representation of this object. */
926 : /************************************************************************/
927 :
928 1530 : OGRErr OGRLineString::exportToWkb( OGRwkbByteOrder eByteOrder,
929 : unsigned char * pabyData ) const
930 :
931 : {
932 : /* -------------------------------------------------------------------- */
933 : /* Set the byte order. */
934 : /* -------------------------------------------------------------------- */
935 1530 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
936 :
937 : /* -------------------------------------------------------------------- */
938 : /* Set the geometry feature type. */
939 : /* -------------------------------------------------------------------- */
940 1530 : GUInt32 nGType = getGeometryType();
941 :
942 1530 : if( eByteOrder == wkbNDR )
943 1517 : nGType = CPL_LSBWORD32( nGType );
944 : else
945 13 : nGType = CPL_MSBWORD32( nGType );
946 :
947 1530 : memcpy( pabyData + 1, &nGType, 4 );
948 :
949 : /* -------------------------------------------------------------------- */
950 : /* Copy in the data count. */
951 : /* -------------------------------------------------------------------- */
952 1530 : memcpy( pabyData+5, &nPointCount, 4 );
953 :
954 : /* -------------------------------------------------------------------- */
955 : /* Copy in the raw data. */
956 : /* -------------------------------------------------------------------- */
957 : int i;
958 :
959 1530 : if( getCoordinateDimension() == 3 )
960 : {
961 72 : for( i = 0; i < nPointCount; i++ )
962 : {
963 55 : memcpy( pabyData + 9 + 24*i, paoPoints+i, 16 );
964 55 : memcpy( pabyData + 9 + 16 + 24*i, padfZ+i, 8 );
965 : }
966 : }
967 : else
968 1513 : memcpy( pabyData+9, paoPoints, 16 * nPointCount );
969 :
970 : /* -------------------------------------------------------------------- */
971 : /* Swap if needed. */
972 : /* -------------------------------------------------------------------- */
973 1530 : if( OGR_SWAP( eByteOrder ) )
974 : {
975 : int nCount;
976 :
977 13 : nCount = CPL_SWAP32( nPointCount );
978 13 : memcpy( pabyData+5, &nCount, 4 );
979 :
980 159 : for( i = getCoordinateDimension() * nPointCount - 1; i >= 0; i-- )
981 : {
982 146 : CPL_SWAP64PTR( pabyData + 9 + 8 * i );
983 : }
984 : }
985 :
986 1530 : return OGRERR_NONE;
987 : }
988 :
989 : /************************************************************************/
990 : /* importFromWkt() */
991 : /* */
992 : /* Instantiate from well known text format. Currently this is */
993 : /* `LINESTRING ( x y, x y, ...)', */
994 : /************************************************************************/
995 :
996 378 : OGRErr OGRLineString::importFromWkt( char ** ppszInput )
997 :
998 : {
999 : char szToken[OGR_WKT_TOKEN_MAX];
1000 378 : const char *pszInput = *ppszInput;
1001 :
1002 378 : empty();
1003 :
1004 : /* -------------------------------------------------------------------- */
1005 : /* Read and verify the ``LINESTRING'' keyword token. */
1006 : /* -------------------------------------------------------------------- */
1007 378 : pszInput = OGRWktReadToken( pszInput, szToken );
1008 :
1009 378 : if( !EQUAL(szToken,getGeometryName()) )
1010 0 : return OGRERR_CORRUPT_DATA;
1011 :
1012 : /* -------------------------------------------------------------------- */
1013 : /* Check for EMPTY */
1014 : /* -------------------------------------------------------------------- */
1015 : const char *pszPreScan;
1016 378 : int bHasZ = FALSE, bHasM = FALSE;
1017 :
1018 378 : pszPreScan = OGRWktReadToken( pszInput, szToken );
1019 378 : if( EQUAL(szToken,"EMPTY") )
1020 : {
1021 18 : *ppszInput = (char *) pszPreScan;
1022 18 : return OGRERR_NONE;
1023 : }
1024 :
1025 : /* -------------------------------------------------------------------- */
1026 : /* Check for Z, M or ZM. Will ignore the Measure */
1027 : /* -------------------------------------------------------------------- */
1028 360 : else if( EQUAL(szToken,"Z") )
1029 : {
1030 12 : bHasZ = TRUE;
1031 : }
1032 348 : else if( EQUAL(szToken,"M") )
1033 : {
1034 3 : bHasM = TRUE;
1035 : }
1036 345 : else if( EQUAL(szToken,"ZM") )
1037 : {
1038 3 : bHasZ = TRUE;
1039 3 : bHasM = TRUE;
1040 : }
1041 :
1042 360 : if (bHasZ || bHasM)
1043 : {
1044 18 : pszInput = pszPreScan;
1045 18 : pszPreScan = OGRWktReadToken( pszInput, szToken );
1046 18 : if( EQUAL(szToken,"EMPTY") )
1047 : {
1048 4 : *ppszInput = (char *) pszPreScan;
1049 4 : empty();
1050 : /* FIXME?: In theory we should store the dimension and M presence */
1051 : /* if we want to allow round-trip with ExportToWKT v1.2 */
1052 4 : return OGRERR_NONE;
1053 : }
1054 : }
1055 :
1056 356 : if( !EQUAL(szToken,"(") )
1057 4 : return OGRERR_CORRUPT_DATA;
1058 :
1059 352 : if ( !bHasZ && !bHasM )
1060 : {
1061 : /* Test for old-style LINESTRING(EMPTY) */
1062 340 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
1063 340 : if( EQUAL(szToken,"EMPTY") )
1064 : {
1065 3 : pszInput = OGRWktReadToken( pszPreScan, szToken );
1066 :
1067 3 : if( !EQUAL(szToken,")") )
1068 1 : return OGRERR_CORRUPT_DATA;
1069 : else
1070 : {
1071 2 : *ppszInput = (char *) pszInput;
1072 2 : empty();
1073 2 : return OGRERR_NONE;
1074 : }
1075 : }
1076 : }
1077 :
1078 : /* -------------------------------------------------------------------- */
1079 : /* Read the point list. */
1080 : /* -------------------------------------------------------------------- */
1081 349 : int nMaxPoint = 0;
1082 :
1083 349 : nPointCount = 0;
1084 :
1085 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoint,
1086 349 : &nPointCount );
1087 349 : if( pszInput == NULL )
1088 15 : return OGRERR_CORRUPT_DATA;
1089 :
1090 334 : *ppszInput = (char *) pszInput;
1091 :
1092 334 : if( padfZ == NULL )
1093 249 : nCoordDimension = 2;
1094 : else
1095 : {
1096 : /* Ignore Z array when we have a LINESTRING M */
1097 87 : if (bHasM && !bHasZ)
1098 : {
1099 2 : nCoordDimension = 2;
1100 2 : CPLFree(padfZ);
1101 2 : padfZ = NULL;
1102 : }
1103 : else
1104 83 : nCoordDimension = 3;
1105 : }
1106 :
1107 334 : return OGRERR_NONE;
1108 : }
1109 :
1110 : /************************************************************************/
1111 : /* exportToWkt() */
1112 : /* */
1113 : /* Translate this structure into it's well known text format */
1114 : /* equivelent. This could be made alot more CPU efficient! */
1115 : /************************************************************************/
1116 :
1117 735 : OGRErr OGRLineString::exportToWkt( char ** ppszDstText ) const
1118 :
1119 : {
1120 735 : int nMaxString = nPointCount * 40 * 3 + 20;
1121 735 : int nRetLen = 0;
1122 :
1123 : /* -------------------------------------------------------------------- */
1124 : /* Handle special empty case. */
1125 : /* -------------------------------------------------------------------- */
1126 735 : if( nPointCount == 0 )
1127 : {
1128 36 : CPLString osEmpty;
1129 36 : osEmpty.Printf("%s EMPTY",getGeometryName());
1130 36 : *ppszDstText = CPLStrdup(osEmpty);
1131 36 : return OGRERR_NONE;
1132 : }
1133 :
1134 : /* -------------------------------------------------------------------- */
1135 : /* General case. */
1136 : /* -------------------------------------------------------------------- */
1137 699 : *ppszDstText = (char *) VSIMalloc( nMaxString );
1138 699 : if( *ppszDstText == NULL )
1139 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1140 :
1141 699 : sprintf( *ppszDstText, "%s (", getGeometryName() );
1142 :
1143 6633 : for( int i = 0; i < nPointCount; i++ )
1144 : {
1145 5934 : if( nMaxString <= (int) strlen(*ppszDstText+nRetLen) + 32 + nRetLen )
1146 : {
1147 : CPLDebug( "OGR",
1148 : "OGRLineString::exportToWkt() ... buffer overflow.\n"
1149 : "nMaxString=%d, strlen(*ppszDstText) = %d, i=%d\n"
1150 : "*ppszDstText = %s",
1151 0 : nMaxString, (int) strlen(*ppszDstText), i, *ppszDstText );
1152 :
1153 0 : VSIFree( *ppszDstText );
1154 0 : *ppszDstText = NULL;
1155 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1156 : }
1157 :
1158 5934 : if( i > 0 )
1159 5235 : strcat( *ppszDstText + nRetLen, "," );
1160 :
1161 5934 : nRetLen += strlen(*ppszDstText + nRetLen);
1162 5934 : if( getCoordinateDimension() == 3 )
1163 : OGRMakeWktCoordinate( *ppszDstText + nRetLen,
1164 500 : paoPoints[i].x,
1165 500 : paoPoints[i].y,
1166 : padfZ[i],
1167 1500 : nCoordDimension );
1168 : else
1169 : OGRMakeWktCoordinate( *ppszDstText + nRetLen,
1170 5434 : paoPoints[i].x,
1171 5434 : paoPoints[i].y,
1172 : 0.0,
1173 16302 : nCoordDimension );
1174 :
1175 5934 : nRetLen += strlen(*ppszDstText + nRetLen);
1176 : }
1177 :
1178 699 : strcat( *ppszDstText+nRetLen, ")" );
1179 :
1180 699 : return OGRERR_NONE;
1181 : }
1182 :
1183 : /************************************************************************/
1184 : /* get_Length() */
1185 : /* */
1186 : /* For now we return a simple euclidian 2D distance. */
1187 : /************************************************************************/
1188 :
1189 13 : double OGRLineString::get_Length() const
1190 :
1191 : {
1192 13 : double dfLength = 0;
1193 : int i;
1194 :
1195 956 : for( i = 0; i < nPointCount-1; i++ )
1196 : {
1197 : double dfDeltaX, dfDeltaY;
1198 :
1199 943 : dfDeltaX = paoPoints[i+1].x - paoPoints[i].x;
1200 943 : dfDeltaY = paoPoints[i+1].y - paoPoints[i].y;
1201 943 : dfLength += sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY);
1202 : }
1203 :
1204 13 : return dfLength;
1205 : }
1206 :
1207 : /************************************************************************/
1208 : /* StartPoint() */
1209 : /************************************************************************/
1210 :
1211 68 : void OGRLineString::StartPoint( OGRPoint * poPoint ) const
1212 :
1213 : {
1214 68 : getPoint( 0, poPoint );
1215 68 : }
1216 :
1217 : /************************************************************************/
1218 : /* EndPoint() */
1219 : /************************************************************************/
1220 :
1221 68 : void OGRLineString::EndPoint( OGRPoint * poPoint ) const
1222 :
1223 : {
1224 68 : getPoint( nPointCount-1, poPoint );
1225 68 : }
1226 :
1227 : /************************************************************************/
1228 : /* Value() */
1229 : /* */
1230 : /* Get an interpolated point at some distance along the curve. */
1231 : /************************************************************************/
1232 :
1233 0 : void OGRLineString::Value( double dfDistance, OGRPoint * poPoint ) const
1234 :
1235 : {
1236 0 : double dfLength = 0;
1237 : int i;
1238 :
1239 0 : if( dfDistance < 0 )
1240 : {
1241 0 : StartPoint( poPoint );
1242 0 : return;
1243 : }
1244 :
1245 0 : for( i = 0; i < nPointCount-1; i++ )
1246 : {
1247 : double dfDeltaX, dfDeltaY, dfSegLength;
1248 :
1249 0 : dfDeltaX = paoPoints[i+1].x - paoPoints[i].x;
1250 0 : dfDeltaY = paoPoints[i+1].y - paoPoints[i].y;
1251 0 : dfSegLength = sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY);
1252 :
1253 0 : if (dfSegLength > 0)
1254 : {
1255 0 : if( (dfLength <= dfDistance) && ((dfLength + dfSegLength) >=
1256 : dfDistance) )
1257 : {
1258 : double dfRatio;
1259 :
1260 0 : dfRatio = (dfDistance - dfLength) / dfSegLength;
1261 :
1262 0 : poPoint->setX( paoPoints[i].x * (1 - dfRatio)
1263 0 : + paoPoints[i+1].x * dfRatio );
1264 0 : poPoint->setY( paoPoints[i].y * (1 - dfRatio)
1265 0 : + paoPoints[i+1].y * dfRatio );
1266 :
1267 0 : if( getCoordinateDimension() == 3 )
1268 0 : poPoint->setZ( padfZ[i] * (1 - dfRatio)
1269 0 : + padfZ[i] * dfRatio );
1270 :
1271 0 : return;
1272 : }
1273 :
1274 0 : dfLength += dfSegLength;
1275 : }
1276 : }
1277 :
1278 0 : EndPoint( poPoint );
1279 : }
1280 :
1281 : /************************************************************************/
1282 : /* getEnvelope() */
1283 : /************************************************************************/
1284 :
1285 279086 : void OGRLineString::getEnvelope( OGREnvelope * psEnvelope ) const
1286 :
1287 : {
1288 : double dfMinX, dfMinY, dfMaxX, dfMaxY;
1289 :
1290 279086 : if( nPointCount == 0 )
1291 : {
1292 4 : psEnvelope->MinX = 0;
1293 4 : psEnvelope->MaxX = 0;
1294 4 : psEnvelope->MinY = 0;
1295 4 : psEnvelope->MaxY = 0;
1296 4 : return;
1297 : }
1298 :
1299 279082 : dfMinX = dfMaxX = paoPoints[0].x;
1300 279082 : dfMinY = dfMaxY = paoPoints[0].y;
1301 :
1302 5011433 : for( int iPoint = 1; iPoint < nPointCount; iPoint++ )
1303 : {
1304 4732351 : if( dfMaxX < paoPoints[iPoint].x )
1305 1251250 : dfMaxX = paoPoints[iPoint].x;
1306 4732351 : if( dfMaxY < paoPoints[iPoint].y )
1307 1461892 : dfMaxY = paoPoints[iPoint].y;
1308 4732351 : if( dfMinX > paoPoints[iPoint].x )
1309 1334003 : dfMinX = paoPoints[iPoint].x;
1310 4732351 : if( dfMinY > paoPoints[iPoint].y )
1311 1106733 : dfMinY = paoPoints[iPoint].y;
1312 : }
1313 :
1314 279082 : psEnvelope->MinX = dfMinX;
1315 279082 : psEnvelope->MaxX = dfMaxX;
1316 279082 : psEnvelope->MinY = dfMinY;
1317 279082 : psEnvelope->MaxY = dfMaxY;
1318 : }
1319 :
1320 :
1321 : /************************************************************************/
1322 : /* getEnvelope() */
1323 : /************************************************************************/
1324 :
1325 141 : void OGRLineString::getEnvelope( OGREnvelope3D * psEnvelope ) const
1326 :
1327 : {
1328 141 : getEnvelope((OGREnvelope*)psEnvelope);
1329 :
1330 : double dfMinZ, dfMaxZ;
1331 :
1332 141 : if( nPointCount == 0 || padfZ == NULL )
1333 : {
1334 78 : psEnvelope->MinZ = 0;
1335 78 : psEnvelope->MaxZ = 0;
1336 78 : return;
1337 : }
1338 :
1339 63 : dfMinZ = dfMaxZ = padfZ[0];
1340 :
1341 645 : for( int iPoint = 1; iPoint < nPointCount; iPoint++ )
1342 : {
1343 582 : if( dfMinZ > padfZ[iPoint] )
1344 20 : dfMinZ = padfZ[iPoint];
1345 582 : if( dfMaxZ < padfZ[iPoint] )
1346 0 : dfMaxZ = padfZ[iPoint];
1347 : }
1348 :
1349 63 : psEnvelope->MinZ = dfMinZ;
1350 63 : psEnvelope->MaxZ = dfMaxZ;
1351 : }
1352 :
1353 : /************************************************************************/
1354 : /* Equals() */
1355 : /************************************************************************/
1356 :
1357 50846 : OGRBoolean OGRLineString::Equals( OGRGeometry * poOther ) const
1358 :
1359 : {
1360 50846 : OGRLineString *poOLine = (OGRLineString *) poOther;
1361 :
1362 50846 : if( poOLine == this )
1363 0 : return TRUE;
1364 :
1365 50846 : if( poOther->getGeometryType() != getGeometryType() )
1366 0 : return FALSE;
1367 :
1368 : // we should eventually test the SRS.
1369 :
1370 50846 : if( getNumPoints() != poOLine->getNumPoints() )
1371 14788 : return FALSE;
1372 :
1373 338249 : for( int iPoint = 0; iPoint < getNumPoints(); iPoint++ )
1374 : {
1375 321566 : if( getX(iPoint) != poOLine->getX(iPoint)
1376 : || getY(iPoint) != poOLine->getY(iPoint)
1377 : || getZ(iPoint) != poOLine->getZ(iPoint) )
1378 19375 : return FALSE;
1379 : }
1380 :
1381 16683 : return TRUE;
1382 : }
1383 :
1384 : /************************************************************************/
1385 : /* transform() */
1386 : /************************************************************************/
1387 :
1388 53 : OGRErr OGRLineString::transform( OGRCoordinateTransformation *poCT )
1389 :
1390 : {
1391 : #ifdef DISABLE_OGRGEOM_TRANSFORM
1392 : return OGRERR_FAILURE;
1393 : #else
1394 : double *xyz;
1395 : int *pabSuccess;
1396 : int i, j;
1397 :
1398 : /* -------------------------------------------------------------------- */
1399 : /* Make a copy of the points to operate on, so as to be able to */
1400 : /* keep only valid reprojected points if partial reprojection enabled */
1401 : /* or keeping intact the original geometry if only full reprojection */
1402 : /* allowed. */
1403 : /* -------------------------------------------------------------------- */
1404 53 : xyz = (double *) VSIMalloc(sizeof(double) * nPointCount * 3);
1405 53 : pabSuccess = (int *) VSICalloc(sizeof(int), nPointCount);
1406 53 : if( xyz == NULL || pabSuccess == NULL )
1407 : {
1408 0 : VSIFree(xyz);
1409 0 : VSIFree(pabSuccess);
1410 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1411 : }
1412 :
1413 632 : for( i = 0; i < nPointCount; i++ )
1414 : {
1415 579 : xyz[i ] = paoPoints[i].x;
1416 579 : xyz[i+nPointCount] = paoPoints[i].y;
1417 579 : if( padfZ )
1418 43 : xyz[i+nPointCount*2] = padfZ[i];
1419 : else
1420 536 : xyz[i+nPointCount*2] = 0.0;
1421 : }
1422 :
1423 : /* -------------------------------------------------------------------- */
1424 : /* Transform and reapply. */
1425 : /* -------------------------------------------------------------------- */
1426 : poCT->TransformEx( nPointCount, xyz, xyz + nPointCount,
1427 53 : xyz+nPointCount*2, pabSuccess );
1428 :
1429 53 : const char* pszEnablePartialReprojection = NULL;
1430 :
1431 632 : for( i = 0, j = 0; i < nPointCount; i++ )
1432 : {
1433 579 : if (pabSuccess[i])
1434 : {
1435 579 : xyz[j] = xyz[i];
1436 579 : xyz[j+nPointCount] = xyz[i+nPointCount];
1437 579 : xyz[j+2*nPointCount] = xyz[i+2*nPointCount];
1438 579 : j ++;
1439 : }
1440 : else
1441 : {
1442 0 : if (pszEnablePartialReprojection == NULL)
1443 : pszEnablePartialReprojection =
1444 0 : CPLGetConfigOption("OGR_ENABLE_PARTIAL_REPROJECTION", NULL);
1445 0 : if (pszEnablePartialReprojection == NULL)
1446 : {
1447 : static int bHasWarned = FALSE;
1448 0 : if (!bHasWarned)
1449 : {
1450 : /* Check that there is at least one valid reprojected point */
1451 : /* and issue an error giving an hint to use OGR_ENABLE_PARTIAL_REPROJECTION */
1452 0 : int bHasOneValidPoint = (j != 0);
1453 0 : for( ; i < nPointCount && !bHasOneValidPoint; i++ )
1454 : {
1455 0 : if (pabSuccess[i])
1456 0 : bHasOneValidPoint = TRUE;
1457 : }
1458 0 : if (bHasOneValidPoint)
1459 : {
1460 0 : bHasWarned = TRUE;
1461 : CPLError(CE_Failure, CPLE_AppDefined,
1462 : "Full reprojection failed, but partial is possible if you define "
1463 0 : "OGR_ENABLE_PARTIAL_REPROJECTION configuration option to TRUE");
1464 : }
1465 : }
1466 :
1467 0 : CPLFree( xyz );
1468 0 : CPLFree( pabSuccess );
1469 0 : return OGRERR_FAILURE;
1470 : }
1471 0 : else if (!CSLTestBoolean(pszEnablePartialReprojection))
1472 : {
1473 0 : CPLFree( xyz );
1474 0 : CPLFree( pabSuccess );
1475 0 : return OGRERR_FAILURE;
1476 : }
1477 : }
1478 : }
1479 :
1480 53 : if (j == 0 && nPointCount != 0)
1481 : {
1482 0 : CPLFree( xyz );
1483 0 : CPLFree( pabSuccess );
1484 0 : return OGRERR_FAILURE;
1485 : }
1486 :
1487 : setPoints( j, xyz, xyz+nPointCount,
1488 53 : ( padfZ ) ? xyz+nPointCount*2 : NULL);
1489 53 : CPLFree( xyz );
1490 53 : CPLFree( pabSuccess );
1491 :
1492 53 : assignSpatialReference( poCT->GetTargetCS() );
1493 :
1494 53 : return OGRERR_NONE;
1495 : #endif
1496 : }
1497 :
1498 : /************************************************************************/
1499 : /* IsEmpty() */
1500 : /************************************************************************/
1501 :
1502 165422 : OGRBoolean OGRLineString::IsEmpty( ) const
1503 : {
1504 165422 : return (nPointCount == 0);
1505 : }
1506 :
1507 : /************************************************************************/
1508 : /* OGRLineString::segmentize() */
1509 : /************************************************************************/
1510 :
1511 11 : void OGRLineString::segmentize( double dfMaxLength )
1512 : {
1513 11 : if (dfMaxLength <= 0)
1514 : {
1515 : CPLError(CE_Failure, CPLE_AppDefined,
1516 0 : "dfMaxLength must be strictly positive");
1517 0 : return;
1518 : }
1519 :
1520 : int i;
1521 11 : OGRRawPoint* paoNewPoints = NULL;
1522 11 : double* padfNewZ = NULL;
1523 11 : int nNewPointCount = 0;
1524 11 : double dfSquareMaxLength = dfMaxLength * dfMaxLength;
1525 :
1526 247 : for( i = 0; i < nPointCount; i++ )
1527 : {
1528 : paoNewPoints = (OGRRawPoint *)
1529 247 : OGRRealloc(paoNewPoints, sizeof(OGRRawPoint) * (nNewPointCount + 1));
1530 247 : paoNewPoints[nNewPointCount] = paoPoints[i];
1531 :
1532 247 : if( getCoordinateDimension() == 3 )
1533 : {
1534 : padfNewZ = (double *)
1535 0 : OGRRealloc(padfNewZ, sizeof(double) * (nNewPointCount + 1));
1536 0 : padfNewZ[nNewPointCount] = padfZ[i];
1537 : }
1538 :
1539 247 : nNewPointCount++;
1540 :
1541 247 : if (i == nPointCount - 1)
1542 11 : break;
1543 :
1544 236 : double dfX = paoPoints[i+1].x - paoPoints[i].x;
1545 236 : double dfY = paoPoints[i+1].y - paoPoints[i].y;
1546 236 : double dfSquareDist = dfX * dfX + dfY * dfY;
1547 236 : if (dfSquareDist > dfSquareMaxLength)
1548 : {
1549 97 : int nIntermediatePoints = (int)floor(sqrt(dfSquareDist / dfSquareMaxLength));
1550 : int j;
1551 :
1552 : paoNewPoints = (OGRRawPoint *)
1553 97 : OGRRealloc(paoNewPoints, sizeof(OGRRawPoint) * (nNewPointCount + nIntermediatePoints));
1554 97 : if( getCoordinateDimension() == 3 )
1555 : {
1556 : padfNewZ = (double *)
1557 0 : OGRRealloc(padfNewZ, sizeof(double) * (nNewPointCount + nIntermediatePoints));
1558 : }
1559 :
1560 273 : for(j=1;j<=nIntermediatePoints;j++)
1561 : {
1562 176 : paoNewPoints[nNewPointCount + j - 1].x = paoPoints[i].x + j * dfX / (nIntermediatePoints + 1);
1563 176 : paoNewPoints[nNewPointCount + j - 1].y = paoPoints[i].y + j * dfY / (nIntermediatePoints + 1);
1564 176 : if( getCoordinateDimension() == 3 )
1565 : {
1566 : /* No interpolation */
1567 0 : padfNewZ[nNewPointCount + j - 1] = 0;
1568 : }
1569 : }
1570 :
1571 97 : nNewPointCount += nIntermediatePoints;
1572 : }
1573 : }
1574 :
1575 11 : OGRFree(paoPoints);
1576 11 : paoPoints = paoNewPoints;
1577 11 : nPointCount = nNewPointCount;
1578 :
1579 11 : if( getCoordinateDimension() == 3 )
1580 : {
1581 0 : OGRFree(padfZ);
1582 0 : padfZ = padfNewZ;
1583 : }
1584 : }
1585 :
1586 : /************************************************************************/
1587 : /* swapXY() */
1588 : /************************************************************************/
1589 :
1590 40 : void OGRLineString::swapXY()
1591 : {
1592 : int i;
1593 208 : for( i = 0; i < nPointCount; i++ )
1594 : {
1595 168 : double dfTemp = paoPoints[i].x;
1596 168 : paoPoints[i].x = paoPoints[i].y;
1597 168 : paoPoints[i].y = dfTemp;
1598 : }
1599 40 : }
|