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