1 : /******************************************************************************
2 : * $Id: ogrlinestring.cpp 22464 2011-05-29 21:33:41Z 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 22464 2011-05-29 21:33:41Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRLineString() */
38 : /************************************************************************/
39 :
40 : /**
41 : * \brief Create an empty line string.
42 : */
43 :
44 540237 : OGRLineString::OGRLineString()
45 :
46 : {
47 540237 : nPointCount = 0;
48 540237 : paoPoints = NULL;
49 540237 : padfZ = NULL;
50 540237 : }
51 :
52 : /************************************************************************/
53 : /* ~OGRLineString() */
54 : /************************************************************************/
55 :
56 540237 : OGRLineString::~OGRLineString()
57 :
58 : {
59 540237 : if( paoPoints != NULL )
60 539868 : OGRFree( paoPoints );
61 540237 : if( padfZ != NULL )
62 273271 : OGRFree( padfZ );
63 540237 : }
64 :
65 : /************************************************************************/
66 : /* getGeometryType() */
67 : /************************************************************************/
68 :
69 118796 : OGRwkbGeometryType OGRLineString::getGeometryType() const
70 :
71 : {
72 118796 : if( getCoordinateDimension() == 3 )
73 30651 : return wkbLineString25D;
74 : else
75 88145 : return wkbLineString;
76 : }
77 :
78 : /************************************************************************/
79 : /* flattenTo2D() */
80 : /************************************************************************/
81 :
82 29 : void OGRLineString::flattenTo2D()
83 :
84 : {
85 29 : Make2D();
86 29 : }
87 :
88 : /************************************************************************/
89 : /* getGeometryName() */
90 : /************************************************************************/
91 :
92 960 : const char * OGRLineString::getGeometryName() const
93 :
94 : {
95 960 : return "LINESTRING";
96 : }
97 :
98 : /************************************************************************/
99 : /* clone() */
100 : /************************************************************************/
101 :
102 77859 : OGRGeometry *OGRLineString::clone() const
103 :
104 : {
105 : OGRLineString *poNewLineString;
106 :
107 77859 : poNewLineString = new OGRLineString();
108 :
109 77859 : poNewLineString->assignSpatialReference( getSpatialReference() );
110 77859 : poNewLineString->setPoints( nPointCount, paoPoints, padfZ );
111 77859 : poNewLineString->setCoordinateDimension( getCoordinateDimension() );
112 :
113 77859 : return poNewLineString;
114 : }
115 :
116 : /************************************************************************/
117 : /* empty() */
118 : /************************************************************************/
119 :
120 477 : void OGRLineString::empty()
121 :
122 : {
123 477 : setNumPoints( 0 );
124 477 : }
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 286194 : void OGRLineString::setCoordinateDimension( int nNewDimension )
141 :
142 : {
143 286194 : nCoordDimension = nNewDimension;
144 286194 : if( nNewDimension == 2 )
145 20879 : Make2D();
146 265315 : else if( nNewDimension == 3 )
147 265315 : Make3D();
148 286194 : }
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 412 : int OGRLineString::WkbSize() const
158 :
159 : {
160 412 : return 5 + 4 + 8 * nPointCount * getCoordinateDimension();
161 : }
162 :
163 : /************************************************************************/
164 : /* Make2D() */
165 : /************************************************************************/
166 :
167 23696 : void OGRLineString::Make2D()
168 :
169 : {
170 23696 : if( padfZ != NULL )
171 : {
172 218 : OGRFree( padfZ );
173 218 : padfZ = NULL;
174 : }
175 23696 : nCoordDimension = 2;
176 23696 : }
177 :
178 : /************************************************************************/
179 : /* Make3D() */
180 : /************************************************************************/
181 :
182 565430 : void OGRLineString::Make3D()
183 :
184 : {
185 565430 : if( padfZ == NULL )
186 : {
187 273412 : if( nPointCount == 0 )
188 210020 : padfZ = (double *) OGRCalloc(sizeof(double),1);
189 : else
190 63392 : padfZ = (double *) OGRCalloc(sizeof(double),nPointCount);
191 : }
192 565430 : nCoordDimension = 3;
193 565430 : }
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 840 : void OGRLineString::getPoint( int i, OGRPoint * poPoint ) const
209 :
210 : {
211 840 : assert( i >= 0 );
212 840 : assert( i < nPointCount );
213 840 : assert( poPoint != NULL );
214 :
215 840 : poPoint->setX( paoPoints[i].x );
216 840 : poPoint->setY( paoPoints[i].y );
217 :
218 840 : if( getCoordinateDimension() == 3 && padfZ != NULL )
219 142 : poPoint->setZ( padfZ[i] );
220 840 : }
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 90811 : double OGRLineString::getZ( int iVertex ) const
275 :
276 : {
277 90811 : if( padfZ != NULL && iVertex >= 0 && iVertex < nPointCount
278 : && nCoordDimension >= 3 )
279 59233 : return( padfZ[iVertex] );
280 : else
281 31578 : 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 3212817 : void OGRLineString::setNumPoints( int nNewPointCount )
301 :
302 : {
303 3212817 : if( nNewPointCount == 0 )
304 : {
305 574 : OGRFree( paoPoints );
306 574 : paoPoints = NULL;
307 :
308 574 : OGRFree( padfZ );
309 574 : padfZ = NULL;
310 :
311 574 : nPointCount = 0;
312 574 : return;
313 : }
314 :
315 3212243 : if( nNewPointCount > nPointCount )
316 : {
317 : OGRRawPoint* paoNewPoints = (OGRRawPoint *)
318 3203311 : VSIRealloc(paoPoints, sizeof(OGRRawPoint) * nNewPointCount);
319 3203311 : 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 3203311 : paoPoints = paoNewPoints;
326 :
327 : memset( paoPoints + nPointCount,
328 3203311 : 0, sizeof(OGRRawPoint) * (nNewPointCount - nPointCount) );
329 :
330 3203311 : if( getCoordinateDimension() == 3 )
331 : {
332 : double* padfNewZ = (double *)
333 214899 : VSIRealloc( padfZ, sizeof(double)*nNewPointCount );
334 214899 : 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 214899 : padfZ = padfNewZ;
341 : memset( padfZ + nPointCount, 0,
342 214899 : sizeof(double) * (nNewPointCount - nPointCount) );
343 : }
344 : }
345 :
346 3212243 : 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 216 : void OGRLineString::setPoint( int iPoint, OGRPoint * poPoint )
367 :
368 : {
369 216 : setPoint( iPoint, poPoint->getX(), poPoint->getY(), poPoint->getZ() );
370 216 : }
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 112809 : void OGRLineString::setPoint( int iPoint, double xIn, double yIn, double zIn )
392 :
393 : {
394 112809 : if( getCoordinateDimension() == 2 )
395 5991 : Make3D();
396 :
397 112809 : if( iPoint >= nPointCount )
398 : {
399 6137 : setNumPoints( iPoint+1 );
400 6137 : if (nPointCount < iPoint + 1)
401 0 : return;
402 : }
403 :
404 112809 : paoPoints[iPoint].x = xIn;
405 112809 : paoPoints[iPoint].y = yIn;
406 :
407 112809 : if( zIn != 0.0 )
408 : {
409 26725 : Make3D();
410 26725 : padfZ[iPoint] = zIn;
411 : }
412 86084 : else if( getCoordinateDimension() == 3 )
413 : {
414 86084 : padfZ[iPoint] = 0.0;
415 : }
416 : }
417 :
418 5076768 : void OGRLineString::setPoint( int iPoint, double xIn, double yIn )
419 :
420 : {
421 5076768 : if( iPoint >= nPointCount )
422 : {
423 2872349 : setNumPoints( iPoint+1 );
424 2872349 : if (nPointCount < iPoint + 1)
425 0 : return;
426 : }
427 :
428 5076768 : paoPoints[iPoint].x = xIn;
429 5076768 : 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 48 : void OGRLineString::addPoint( OGRPoint * poPoint )
448 :
449 : {
450 48 : if ( poPoint->getCoordinateDimension() < 3 )
451 48 : setPoint( nPointCount, poPoint->getX(), poPoint->getY() );
452 : else
453 0 : setPoint( nPointCount, poPoint->getX(), poPoint->getY(), poPoint->getZ() );
454 48 : }
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 4430 : void OGRLineString::addPoint( double x, double y, double z )
474 :
475 : {
476 4430 : setPoint( nPointCount, x, y, z );
477 4430 : }
478 :
479 2659574 : void OGRLineString::addPoint( double x, double y )
480 :
481 : {
482 2659574 : setPoint( nPointCount, x, y );
483 2659574 : }
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 78961 : void OGRLineString::setPoints( int nPointsIn, OGRRawPoint * paoPointsIn,
504 : double * padfZ )
505 :
506 : {
507 78961 : setNumPoints( nPointsIn );
508 78961 : if (nPointCount < nPointsIn)
509 0 : return;
510 :
511 78961 : memcpy( paoPoints, paoPointsIn, sizeof(OGRRawPoint) * nPointsIn);
512 :
513 : /* -------------------------------------------------------------------- */
514 : /* Check 2D/3D. */
515 : /* -------------------------------------------------------------------- */
516 78961 : if( padfZ == NULL && getCoordinateDimension() > 2 )
517 : {
518 0 : Make2D();
519 : }
520 78961 : else if( padfZ )
521 : {
522 58075 : Make3D();
523 58075 : 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 210783 : 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 210783 : if( padfZ == NULL )
556 2010 : Make2D();
557 : else
558 208773 : Make3D();
559 :
560 : /* -------------------------------------------------------------------- */
561 : /* Assign values. */
562 : /* -------------------------------------------------------------------- */
563 210783 : setNumPoints( nPointsIn );
564 210783 : if (nPointCount < nPointsIn)
565 0 : return;
566 :
567 1087795 : for( i = 0; i < nPointsIn; i++ )
568 : {
569 877012 : paoPoints[i].x = padfX[i];
570 877012 : paoPoints[i].y = padfY[i];
571 : }
572 :
573 210783 : if( this->padfZ != NULL )
574 208773 : 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 22 : void OGRLineString::getPoints( OGRRawPoint * paoPointsOut, double * padfZ ) const
595 : {
596 22 : if ( ! paoPointsOut )
597 0 : return;
598 :
599 22 : memcpy( paoPointsOut, paoPoints, sizeof(OGRRawPoint) * nPointCount );
600 :
601 : /* -------------------------------------------------------------------- */
602 : /* Check 2D/3D. */
603 : /* -------------------------------------------------------------------- */
604 22 : if( padfZ )
605 : {
606 6 : if ( this->padfZ )
607 5 : memcpy( padfZ, this->padfZ, sizeof(double) * nPointCount );
608 : else
609 1 : 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 4 : void OGRLineString::getPoints( void* pabyX, int nXStride,
639 : void* pabyY, int nYStride,
640 : void* pabyZ, int nZStride) const
641 : {
642 : int i;
643 4 : if (pabyX != NULL && nXStride == 0)
644 0 : return;
645 4 : if (pabyY != NULL && nYStride == 0)
646 0 : return;
647 4 : if (pabyZ != NULL && nZStride == 0)
648 0 : return;
649 4 : 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 4 : getPoints((OGRRawPoint *)pabyX, (double*)pabyZ);
655 4 : 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 : /* addSubLineString() */
674 : /************************************************************************/
675 :
676 : /**
677 : * \brief Add a segment of another linestring to this one.
678 : *
679 : * Adds the request range of vertices to the end of this line string
680 : * in an efficient manner. If the nStartVertex is larger than the
681 : * nEndVertex then the vertices will be reversed as they are copied.
682 : *
683 : * @param poOtherLine the other OGRLineString.
684 : * @param nStartVertex the first vertex to copy, defaults to 0 to start
685 : * with the first vertex in the other linestring.
686 : * @param nEndVertex the last vertex to copy, defaults to -1 indicating
687 : * the last vertex of the other line string.
688 : */
689 :
690 6047 : void OGRLineString::addSubLineString( const OGRLineString *poOtherLine,
691 : int nStartVertex, int nEndVertex )
692 :
693 : {
694 6047 : int nOtherLineNumPoints = poOtherLine->getNumPoints();
695 6047 : if (nOtherLineNumPoints == 0)
696 0 : return;
697 :
698 : /* -------------------------------------------------------------------- */
699 : /* Do a bit of argument defaulting and validation. */
700 : /* -------------------------------------------------------------------- */
701 6047 : if( nEndVertex == -1 )
702 6010 : nEndVertex = nOtherLineNumPoints - 1;
703 :
704 6047 : if( nStartVertex < 0 || nEndVertex < 0
705 : || nStartVertex >= nOtherLineNumPoints
706 : || nEndVertex >= nOtherLineNumPoints )
707 : {
708 0 : CPLAssert( FALSE );
709 0 : return;
710 : }
711 :
712 : /* -------------------------------------------------------------------- */
713 : /* Grow this linestring to hold the additional points. */
714 : /* -------------------------------------------------------------------- */
715 6047 : int nOldPoints = nPointCount;
716 6047 : int nPointsToAdd = ABS(nEndVertex-nStartVertex) + 1;
717 :
718 6047 : setNumPoints( nPointsToAdd + nOldPoints );
719 6047 : if (nPointCount < nPointsToAdd + nOldPoints)
720 0 : return;
721 :
722 : /* -------------------------------------------------------------------- */
723 : /* Copy the x/y points - forward copies use memcpy. */
724 : /* -------------------------------------------------------------------- */
725 6047 : if( nEndVertex >= nStartVertex )
726 : {
727 : memcpy( paoPoints + nOldPoints,
728 : poOtherLine->paoPoints + nStartVertex,
729 6041 : sizeof(OGRRawPoint) * nPointsToAdd );
730 6041 : if( poOtherLine->padfZ != NULL )
731 : {
732 9 : Make3D();
733 : memcpy( padfZ + nOldPoints, poOtherLine->padfZ + nStartVertex,
734 9 : sizeof(double) * nPointsToAdd );
735 : }
736 : }
737 :
738 : /* -------------------------------------------------------------------- */
739 : /* Copy the x/y points - reverse copies done double by double. */
740 : /* -------------------------------------------------------------------- */
741 : else
742 : {
743 : int i;
744 :
745 26 : for( i = 0; i < nPointsToAdd; i++ )
746 : {
747 20 : paoPoints[i+nOldPoints].x =
748 20 : poOtherLine->paoPoints[nStartVertex-i].x;
749 20 : paoPoints[i+nOldPoints].y =
750 20 : poOtherLine->paoPoints[nStartVertex-i].y;
751 : }
752 :
753 6 : if( poOtherLine->padfZ != NULL )
754 : {
755 0 : Make3D();
756 :
757 0 : for( i = 0; i < nPointsToAdd; i++ )
758 : {
759 0 : padfZ[i+nOldPoints] = poOtherLine->padfZ[nStartVertex-i];
760 : }
761 : }
762 : }
763 : }
764 :
765 : /************************************************************************/
766 : /* importFromWkb() */
767 : /* */
768 : /* Initialize from serialized stream in well known binary */
769 : /* format. */
770 : /************************************************************************/
771 :
772 319 : OGRErr OGRLineString::importFromWkb( unsigned char * pabyData,
773 : int nSize )
774 :
775 : {
776 : OGRwkbByteOrder eByteOrder;
777 :
778 319 : if( nSize < 9 && nSize != -1 )
779 0 : return OGRERR_NOT_ENOUGH_DATA;
780 :
781 : /* -------------------------------------------------------------------- */
782 : /* Get the byte order byte. */
783 : /* -------------------------------------------------------------------- */
784 319 : eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
785 319 : if (!( eByteOrder == wkbXDR || eByteOrder == wkbNDR ))
786 0 : return OGRERR_CORRUPT_DATA;
787 :
788 : /* -------------------------------------------------------------------- */
789 : /* Get the geometry feature type. For now we assume that */
790 : /* geometry type is between 0 and 255 so we only have to fetch */
791 : /* one byte. */
792 : /* -------------------------------------------------------------------- */
793 : OGRwkbGeometryType eGeometryType;
794 319 : int bIs3D = FALSE;
795 :
796 319 : if( eByteOrder == wkbNDR )
797 : {
798 305 : eGeometryType = (OGRwkbGeometryType) pabyData[1];
799 305 : bIs3D = pabyData[4] & 0x80 || pabyData[2] & 0x80;
800 : }
801 : else
802 : {
803 14 : eGeometryType = (OGRwkbGeometryType) pabyData[4];
804 14 : bIs3D = pabyData[1] & 0x80 || pabyData[3] & 0x80;
805 : }
806 :
807 319 : if( eGeometryType != wkbLineString )
808 0 : return OGRERR_CORRUPT_DATA;
809 :
810 : /* -------------------------------------------------------------------- */
811 : /* Get the vertex count. */
812 : /* -------------------------------------------------------------------- */
813 : int nNewNumPoints;
814 :
815 319 : memcpy( &nNewNumPoints, pabyData + 5, 4 );
816 :
817 319 : if( OGR_SWAP( eByteOrder ) )
818 14 : nNewNumPoints = CPL_SWAP32(nNewNumPoints);
819 :
820 : /* Check if the wkb stream buffer is big enough to store
821 : * fetched number of points.
822 : * 16 or 24 - size of point structure
823 : */
824 319 : int nPointSize = (bIs3D ? 24 : 16);
825 319 : if (nNewNumPoints < 0 || nNewNumPoints > INT_MAX / nPointSize)
826 0 : return OGRERR_CORRUPT_DATA;
827 319 : int nBufferMinSize = nPointSize * nNewNumPoints;
828 :
829 319 : if( nSize != -1 && nBufferMinSize > nSize-9 )
830 : {
831 : CPLError( CE_Failure, CPLE_AppDefined,
832 0 : "Length of input WKB is too small" );
833 0 : return OGRERR_NOT_ENOUGH_DATA;
834 : }
835 :
836 319 : setNumPoints( nNewNumPoints );
837 319 : if (nPointCount < nNewNumPoints)
838 0 : return OGRERR_FAILURE;
839 :
840 319 : if( bIs3D )
841 107 : Make3D();
842 : else
843 212 : Make2D();
844 :
845 : /* -------------------------------------------------------------------- */
846 : /* Get the vertex. */
847 : /* -------------------------------------------------------------------- */
848 319 : int i = 0;
849 :
850 319 : if( bIs3D )
851 : {
852 414 : for( i = 0; i < nPointCount; i++ )
853 : {
854 307 : memcpy( paoPoints + i, pabyData + 9 + i*24, 16 );
855 307 : memcpy( padfZ + i, pabyData + 9 + 16 + i*24, 8 );
856 : }
857 : }
858 : else
859 : {
860 212 : memcpy( paoPoints, pabyData + 9, 16 * nPointCount );
861 : }
862 :
863 : /* -------------------------------------------------------------------- */
864 : /* Byte swap if needed. */
865 : /* -------------------------------------------------------------------- */
866 319 : if( OGR_SWAP( eByteOrder ) )
867 : {
868 88 : for( i = 0; i < nPointCount; i++ )
869 : {
870 74 : CPL_SWAPDOUBLE( &(paoPoints[i].x) );
871 74 : CPL_SWAPDOUBLE( &(paoPoints[i].y) );
872 : }
873 :
874 14 : if( bIs3D )
875 : {
876 8 : for( i = 0; i < nPointCount; i++ )
877 : {
878 6 : CPL_SWAPDOUBLE( padfZ + i );
879 : }
880 : }
881 : }
882 :
883 319 : return OGRERR_NONE;
884 : }
885 :
886 : /************************************************************************/
887 : /* exportToWkb() */
888 : /* */
889 : /* Build a well known binary representation of this object. */
890 : /************************************************************************/
891 :
892 108 : OGRErr OGRLineString::exportToWkb( OGRwkbByteOrder eByteOrder,
893 : unsigned char * pabyData ) const
894 :
895 : {
896 : /* -------------------------------------------------------------------- */
897 : /* Set the byte order. */
898 : /* -------------------------------------------------------------------- */
899 108 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
900 :
901 : /* -------------------------------------------------------------------- */
902 : /* Set the geometry feature type. */
903 : /* -------------------------------------------------------------------- */
904 108 : GUInt32 nGType = getGeometryType();
905 :
906 108 : if( eByteOrder == wkbNDR )
907 95 : nGType = CPL_LSBWORD32( nGType );
908 : else
909 13 : nGType = CPL_MSBWORD32( nGType );
910 :
911 108 : memcpy( pabyData + 1, &nGType, 4 );
912 :
913 : /* -------------------------------------------------------------------- */
914 : /* Copy in the data count. */
915 : /* -------------------------------------------------------------------- */
916 108 : memcpy( pabyData+5, &nPointCount, 4 );
917 :
918 : /* -------------------------------------------------------------------- */
919 : /* Copy in the raw data. */
920 : /* -------------------------------------------------------------------- */
921 : int i;
922 :
923 108 : if( getCoordinateDimension() == 3 )
924 : {
925 162 : for( i = 0; i < nPointCount; i++ )
926 : {
927 126 : memcpy( pabyData + 9 + 24*i, paoPoints+i, 16 );
928 126 : memcpy( pabyData + 9 + 16 + 24*i, padfZ+i, 8 );
929 : }
930 : }
931 : else
932 72 : memcpy( pabyData+9, paoPoints, 16 * nPointCount );
933 :
934 : /* -------------------------------------------------------------------- */
935 : /* Swap if needed. */
936 : /* -------------------------------------------------------------------- */
937 108 : if( OGR_SWAP( eByteOrder ) )
938 : {
939 : int nCount;
940 :
941 13 : nCount = CPL_SWAP32( nPointCount );
942 13 : memcpy( pabyData+5, &nCount, 4 );
943 :
944 159 : for( i = getCoordinateDimension() * nPointCount - 1; i >= 0; i-- )
945 : {
946 146 : CPL_SWAP64PTR( pabyData + 9 + 8 * i );
947 : }
948 : }
949 :
950 108 : return OGRERR_NONE;
951 : }
952 :
953 : /************************************************************************/
954 : /* importFromWkt() */
955 : /* */
956 : /* Instantiate from well known text format. Currently this is */
957 : /* `LINESTRING ( x y, x y, ...)', */
958 : /************************************************************************/
959 :
960 312 : OGRErr OGRLineString::importFromWkt( char ** ppszInput )
961 :
962 : {
963 : char szToken[OGR_WKT_TOKEN_MAX];
964 312 : const char *pszInput = *ppszInput;
965 :
966 312 : empty();
967 :
968 : /* -------------------------------------------------------------------- */
969 : /* Read and verify the ``LINESTRING'' keyword token. */
970 : /* -------------------------------------------------------------------- */
971 312 : pszInput = OGRWktReadToken( pszInput, szToken );
972 :
973 312 : if( !EQUAL(szToken,getGeometryName()) )
974 0 : return OGRERR_CORRUPT_DATA;
975 :
976 : /* -------------------------------------------------------------------- */
977 : /* Check for EMPTY */
978 : /* -------------------------------------------------------------------- */
979 : const char *pszPreScan;
980 312 : int bHasZ = FALSE, bHasM = FALSE;
981 :
982 312 : pszPreScan = OGRWktReadToken( pszInput, szToken );
983 312 : if( EQUAL(szToken,"EMPTY") )
984 : {
985 17 : *ppszInput = (char *) pszPreScan;
986 17 : return OGRERR_NONE;
987 : }
988 :
989 : /* -------------------------------------------------------------------- */
990 : /* Check for Z, M or ZM. Will ignore the Measure */
991 : /* -------------------------------------------------------------------- */
992 295 : else if( EQUAL(szToken,"Z") )
993 : {
994 12 : bHasZ = TRUE;
995 : }
996 283 : else if( EQUAL(szToken,"M") )
997 : {
998 3 : bHasM = TRUE;
999 : }
1000 280 : else if( EQUAL(szToken,"ZM") )
1001 : {
1002 3 : bHasZ = TRUE;
1003 3 : bHasM = TRUE;
1004 : }
1005 :
1006 295 : if (bHasZ || bHasM)
1007 : {
1008 18 : pszInput = pszPreScan;
1009 18 : pszPreScan = OGRWktReadToken( pszInput, szToken );
1010 18 : if( EQUAL(szToken,"EMPTY") )
1011 : {
1012 4 : *ppszInput = (char *) pszPreScan;
1013 4 : empty();
1014 : /* FIXME?: In theory we should store the dimension and M presence */
1015 : /* if we want to allow round-trip with ExportToWKT v1.2 */
1016 4 : return OGRERR_NONE;
1017 : }
1018 : }
1019 :
1020 291 : if( !EQUAL(szToken,"(") )
1021 4 : return OGRERR_CORRUPT_DATA;
1022 :
1023 287 : if ( !bHasZ && !bHasM )
1024 : {
1025 : /* Test for old-style LINESTRING(EMPTY) */
1026 275 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
1027 275 : if( EQUAL(szToken,"EMPTY") )
1028 : {
1029 3 : pszInput = OGRWktReadToken( pszPreScan, szToken );
1030 :
1031 3 : if( !EQUAL(szToken,")") )
1032 1 : return OGRERR_CORRUPT_DATA;
1033 : else
1034 : {
1035 2 : *ppszInput = (char *) pszInput;
1036 2 : empty();
1037 2 : return OGRERR_NONE;
1038 : }
1039 : }
1040 : }
1041 :
1042 : /* -------------------------------------------------------------------- */
1043 : /* Read the point list. */
1044 : /* -------------------------------------------------------------------- */
1045 284 : int nMaxPoint = 0;
1046 :
1047 284 : nPointCount = 0;
1048 :
1049 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoint,
1050 284 : &nPointCount );
1051 284 : if( pszInput == NULL )
1052 15 : return OGRERR_CORRUPT_DATA;
1053 :
1054 269 : *ppszInput = (char *) pszInput;
1055 :
1056 269 : if( padfZ == NULL )
1057 190 : nCoordDimension = 2;
1058 : else
1059 : {
1060 : /* Ignore Z array when we have a LINESTRING M */
1061 81 : if (bHasM && !bHasZ)
1062 : {
1063 2 : nCoordDimension = 2;
1064 2 : CPLFree(padfZ);
1065 2 : padfZ = NULL;
1066 : }
1067 : else
1068 77 : nCoordDimension = 3;
1069 : }
1070 :
1071 269 : return OGRERR_NONE;
1072 : }
1073 :
1074 : /************************************************************************/
1075 : /* exportToWkt() */
1076 : /* */
1077 : /* Translate this structure into it's well known text format */
1078 : /* equivelent. This could be made alot more CPU efficient! */
1079 : /************************************************************************/
1080 :
1081 556 : OGRErr OGRLineString::exportToWkt( char ** ppszDstText ) const
1082 :
1083 : {
1084 556 : int nMaxString = nPointCount * 40 * 3 + 20;
1085 556 : int nRetLen = 0;
1086 :
1087 : /* -------------------------------------------------------------------- */
1088 : /* Handle special empty case. */
1089 : /* -------------------------------------------------------------------- */
1090 556 : if( nPointCount == 0 )
1091 : {
1092 34 : CPLString osEmpty;
1093 34 : osEmpty.Printf("%s EMPTY",getGeometryName());
1094 34 : *ppszDstText = CPLStrdup(osEmpty);
1095 34 : return OGRERR_NONE;
1096 : }
1097 :
1098 : /* -------------------------------------------------------------------- */
1099 : /* General case. */
1100 : /* -------------------------------------------------------------------- */
1101 522 : *ppszDstText = (char *) VSIMalloc( nMaxString );
1102 522 : if( *ppszDstText == NULL )
1103 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1104 :
1105 522 : sprintf( *ppszDstText, "%s (", getGeometryName() );
1106 :
1107 5614 : for( int i = 0; i < nPointCount; i++ )
1108 : {
1109 5092 : if( nMaxString <= (int) strlen(*ppszDstText+nRetLen) + 32 + nRetLen )
1110 : {
1111 : CPLDebug( "OGR",
1112 : "OGRLineString::exportToWkt() ... buffer overflow.\n"
1113 : "nMaxString=%d, strlen(*ppszDstText) = %d, i=%d\n"
1114 : "*ppszDstText = %s",
1115 0 : nMaxString, (int) strlen(*ppszDstText), i, *ppszDstText );
1116 :
1117 0 : VSIFree( *ppszDstText );
1118 0 : *ppszDstText = NULL;
1119 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1120 : }
1121 :
1122 5092 : if( i > 0 )
1123 4570 : strcat( *ppszDstText + nRetLen, "," );
1124 :
1125 5092 : nRetLen += strlen(*ppszDstText + nRetLen);
1126 5092 : if( getCoordinateDimension() == 3 )
1127 : OGRMakeWktCoordinate( *ppszDstText + nRetLen,
1128 497 : paoPoints[i].x,
1129 497 : paoPoints[i].y,
1130 : padfZ[i],
1131 1491 : nCoordDimension );
1132 : else
1133 : OGRMakeWktCoordinate( *ppszDstText + nRetLen,
1134 4595 : paoPoints[i].x,
1135 4595 : paoPoints[i].y,
1136 : 0.0,
1137 13785 : nCoordDimension );
1138 :
1139 5092 : nRetLen += strlen(*ppszDstText + nRetLen);
1140 : }
1141 :
1142 522 : strcat( *ppszDstText+nRetLen, ")" );
1143 :
1144 522 : return OGRERR_NONE;
1145 : }
1146 :
1147 : /************************************************************************/
1148 : /* get_Length() */
1149 : /* */
1150 : /* For now we return a simple euclidian 2D distance. */
1151 : /************************************************************************/
1152 :
1153 7 : double OGRLineString::get_Length() const
1154 :
1155 : {
1156 7 : double dfLength = 0;
1157 : int i;
1158 :
1159 12 : for( i = 0; i < nPointCount-1; i++ )
1160 : {
1161 : double dfDeltaX, dfDeltaY;
1162 :
1163 5 : dfDeltaX = paoPoints[i+1].x - paoPoints[i].x;
1164 5 : dfDeltaY = paoPoints[i+1].y - paoPoints[i].y;
1165 5 : dfLength += sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY);
1166 : }
1167 :
1168 7 : return dfLength;
1169 : }
1170 :
1171 : /************************************************************************/
1172 : /* StartPoint() */
1173 : /************************************************************************/
1174 :
1175 14 : void OGRLineString::StartPoint( OGRPoint * poPoint ) const
1176 :
1177 : {
1178 14 : getPoint( 0, poPoint );
1179 14 : }
1180 :
1181 : /************************************************************************/
1182 : /* EndPoint() */
1183 : /************************************************************************/
1184 :
1185 14 : void OGRLineString::EndPoint( OGRPoint * poPoint ) const
1186 :
1187 : {
1188 14 : getPoint( nPointCount-1, poPoint );
1189 14 : }
1190 :
1191 : /************************************************************************/
1192 : /* Value() */
1193 : /* */
1194 : /* Get an interpolated point at some distance along the curve. */
1195 : /************************************************************************/
1196 :
1197 0 : void OGRLineString::Value( double dfDistance, OGRPoint * poPoint ) const
1198 :
1199 : {
1200 0 : double dfLength = 0;
1201 : int i;
1202 :
1203 0 : if( dfDistance < 0 )
1204 : {
1205 0 : StartPoint( poPoint );
1206 0 : return;
1207 : }
1208 :
1209 0 : for( i = 0; i < nPointCount-1; i++ )
1210 : {
1211 : double dfDeltaX, dfDeltaY, dfSegLength;
1212 :
1213 0 : dfDeltaX = paoPoints[i+1].x - paoPoints[i].x;
1214 0 : dfDeltaY = paoPoints[i+1].y - paoPoints[i].y;
1215 0 : dfSegLength = sqrt(dfDeltaX*dfDeltaX + dfDeltaY*dfDeltaY);
1216 :
1217 0 : if (dfSegLength > 0)
1218 : {
1219 0 : if( (dfLength <= dfDistance) && ((dfLength + dfSegLength) >=
1220 : dfDistance) )
1221 : {
1222 : double dfRatio;
1223 :
1224 0 : dfRatio = (dfDistance - dfLength) / dfSegLength;
1225 :
1226 0 : poPoint->setX( paoPoints[i].x * (1 - dfRatio)
1227 0 : + paoPoints[i+1].x * dfRatio );
1228 0 : poPoint->setY( paoPoints[i].y * (1 - dfRatio)
1229 0 : + paoPoints[i+1].y * dfRatio );
1230 :
1231 0 : if( getCoordinateDimension() == 3 )
1232 0 : poPoint->setZ( padfZ[i] * (1 - dfRatio)
1233 0 : + padfZ[i] * dfRatio );
1234 :
1235 0 : return;
1236 : }
1237 :
1238 0 : dfLength += dfSegLength;
1239 : }
1240 : }
1241 :
1242 0 : EndPoint( poPoint );
1243 : }
1244 :
1245 : /************************************************************************/
1246 : /* getEnvelope() */
1247 : /************************************************************************/
1248 :
1249 188296 : void OGRLineString::getEnvelope( OGREnvelope * psEnvelope ) const
1250 :
1251 : {
1252 : double dfMinX, dfMinY, dfMaxX, dfMaxY;
1253 :
1254 188296 : if( nPointCount == 0 )
1255 : {
1256 3 : psEnvelope->MinX = 0;
1257 3 : psEnvelope->MaxX = 0;
1258 3 : psEnvelope->MinY = 0;
1259 3 : psEnvelope->MaxY = 0;
1260 3 : return;
1261 : }
1262 :
1263 188293 : dfMinX = dfMaxX = paoPoints[0].x;
1264 188293 : dfMinY = dfMaxY = paoPoints[0].y;
1265 :
1266 2331760 : for( int iPoint = 1; iPoint < nPointCount; iPoint++ )
1267 : {
1268 2143467 : if( dfMaxX < paoPoints[iPoint].x )
1269 757403 : dfMaxX = paoPoints[iPoint].x;
1270 2143467 : if( dfMaxY < paoPoints[iPoint].y )
1271 860533 : dfMaxY = paoPoints[iPoint].y;
1272 2143467 : if( dfMinX > paoPoints[iPoint].x )
1273 760123 : dfMinX = paoPoints[iPoint].x;
1274 2143467 : if( dfMinY > paoPoints[iPoint].y )
1275 608705 : dfMinY = paoPoints[iPoint].y;
1276 : }
1277 :
1278 188293 : psEnvelope->MinX = dfMinX;
1279 188293 : psEnvelope->MaxX = dfMaxX;
1280 188293 : psEnvelope->MinY = dfMinY;
1281 188293 : psEnvelope->MaxY = dfMaxY;
1282 : }
1283 :
1284 :
1285 : /************************************************************************/
1286 : /* getEnvelope() */
1287 : /************************************************************************/
1288 :
1289 42 : void OGRLineString::getEnvelope( OGREnvelope3D * psEnvelope ) const
1290 :
1291 : {
1292 42 : getEnvelope((OGREnvelope*)psEnvelope);
1293 :
1294 : double dfMinZ, dfMaxZ;
1295 :
1296 42 : if( nPointCount == 0 || padfZ == NULL )
1297 : {
1298 15 : psEnvelope->MinZ = 0;
1299 15 : psEnvelope->MaxZ = 0;
1300 15 : return;
1301 : }
1302 :
1303 27 : dfMinZ = dfMaxZ = padfZ[0];
1304 :
1305 519 : for( int iPoint = 1; iPoint < nPointCount; iPoint++ )
1306 : {
1307 492 : if( dfMinZ > padfZ[iPoint] )
1308 2 : dfMinZ = padfZ[iPoint];
1309 492 : if( dfMaxZ < padfZ[iPoint] )
1310 0 : dfMaxZ = padfZ[iPoint];
1311 : }
1312 :
1313 27 : psEnvelope->MinZ = dfMinZ;
1314 27 : psEnvelope->MaxZ = dfMaxZ;
1315 : }
1316 :
1317 : /************************************************************************/
1318 : /* Equals() */
1319 : /************************************************************************/
1320 :
1321 127 : OGRBoolean OGRLineString::Equals( OGRGeometry * poOther ) const
1322 :
1323 : {
1324 127 : OGRLineString *poOLine = (OGRLineString *) poOther;
1325 :
1326 127 : if( poOLine == this )
1327 0 : return TRUE;
1328 :
1329 127 : if( poOther->getGeometryType() != getGeometryType() )
1330 0 : return FALSE;
1331 :
1332 : // we should eventually test the SRS.
1333 :
1334 127 : if( getNumPoints() != poOLine->getNumPoints() )
1335 0 : return FALSE;
1336 :
1337 2775 : for( int iPoint = 0; iPoint < getNumPoints(); iPoint++ )
1338 : {
1339 2648 : if( getX(iPoint) != poOLine->getX(iPoint)
1340 : || getY(iPoint) != poOLine->getY(iPoint)
1341 : || getZ(iPoint) != poOLine->getZ(iPoint) )
1342 0 : return FALSE;
1343 : }
1344 :
1345 127 : return TRUE;
1346 : }
1347 :
1348 : /************************************************************************/
1349 : /* transform() */
1350 : /************************************************************************/
1351 :
1352 49 : OGRErr OGRLineString::transform( OGRCoordinateTransformation *poCT )
1353 :
1354 : {
1355 : #ifdef DISABLE_OGRGEOM_TRANSFORM
1356 : return OGRERR_FAILURE;
1357 : #else
1358 : double *xyz;
1359 : int *pabSuccess;
1360 : int i, j;
1361 :
1362 : /* -------------------------------------------------------------------- */
1363 : /* Make a copy of the points to operate on, so as to be able to */
1364 : /* keep only valid reprojected points if partial reprojection enabled */
1365 : /* or keeping intact the original geometry if only full reprojection */
1366 : /* allowed. */
1367 : /* -------------------------------------------------------------------- */
1368 49 : xyz = (double *) VSIMalloc(sizeof(double) * nPointCount * 3);
1369 49 : pabSuccess = (int *) VSICalloc(sizeof(int), nPointCount);
1370 49 : if( xyz == NULL || pabSuccess == NULL )
1371 : {
1372 0 : VSIFree(xyz);
1373 0 : VSIFree(pabSuccess);
1374 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1375 : }
1376 :
1377 610 : for( i = 0; i < nPointCount; i++ )
1378 : {
1379 561 : xyz[i ] = paoPoints[i].x;
1380 561 : xyz[i+nPointCount] = paoPoints[i].y;
1381 561 : if( padfZ )
1382 43 : xyz[i+nPointCount*2] = padfZ[i];
1383 : else
1384 518 : xyz[i+nPointCount*2] = 0.0;
1385 : }
1386 :
1387 : /* -------------------------------------------------------------------- */
1388 : /* Transform and reapply. */
1389 : /* -------------------------------------------------------------------- */
1390 : poCT->TransformEx( nPointCount, xyz, xyz + nPointCount,
1391 49 : xyz+nPointCount*2, pabSuccess );
1392 :
1393 49 : const char* pszEnablePartialReprojection = NULL;
1394 :
1395 610 : for( i = 0, j = 0; i < nPointCount; i++ )
1396 : {
1397 561 : if (pabSuccess[i])
1398 : {
1399 561 : xyz[j] = xyz[i];
1400 561 : xyz[j+nPointCount] = xyz[i+nPointCount];
1401 561 : xyz[j+2*nPointCount] = xyz[i+2*nPointCount];
1402 561 : j ++;
1403 : }
1404 : else
1405 : {
1406 0 : if (pszEnablePartialReprojection == NULL)
1407 : pszEnablePartialReprojection =
1408 0 : CPLGetConfigOption("OGR_ENABLE_PARTIAL_REPROJECTION", NULL);
1409 0 : if (pszEnablePartialReprojection == NULL)
1410 : {
1411 : static int bHasWarned = FALSE;
1412 0 : if (!bHasWarned)
1413 : {
1414 : /* Check that there is at least one valid reprojected point */
1415 : /* and issue an error giving an hint to use OGR_ENABLE_PARTIAL_REPROJECTION */
1416 0 : int bHasOneValidPoint = (j != 0);
1417 0 : for( ; i < nPointCount && !bHasOneValidPoint; i++ )
1418 : {
1419 0 : if (pabSuccess[i])
1420 0 : bHasOneValidPoint = TRUE;
1421 : }
1422 0 : if (bHasOneValidPoint)
1423 : {
1424 0 : bHasWarned = TRUE;
1425 : CPLError(CE_Failure, CPLE_AppDefined,
1426 : "Full reprojection failed, but partial is possible if you define "
1427 0 : "OGR_ENABLE_PARTIAL_REPROJECTION configuration option to TRUE");
1428 : }
1429 : }
1430 :
1431 0 : CPLFree( xyz );
1432 0 : CPLFree( pabSuccess );
1433 0 : return OGRERR_FAILURE;
1434 : }
1435 0 : else if (!CSLTestBoolean(pszEnablePartialReprojection))
1436 : {
1437 0 : CPLFree( xyz );
1438 0 : CPLFree( pabSuccess );
1439 0 : return OGRERR_FAILURE;
1440 : }
1441 : }
1442 : }
1443 :
1444 49 : if (j == 0 && nPointCount != 0)
1445 : {
1446 0 : CPLFree( xyz );
1447 0 : CPLFree( pabSuccess );
1448 0 : return OGRERR_FAILURE;
1449 : }
1450 :
1451 : setPoints( j, xyz, xyz+nPointCount,
1452 49 : ( padfZ ) ? xyz+nPointCount*2 : NULL);
1453 49 : CPLFree( xyz );
1454 49 : CPLFree( pabSuccess );
1455 :
1456 49 : assignSpatialReference( poCT->GetTargetCS() );
1457 :
1458 49 : return OGRERR_NONE;
1459 : #endif
1460 : }
1461 :
1462 : /************************************************************************/
1463 : /* IsEmpty() */
1464 : /************************************************************************/
1465 :
1466 67012 : OGRBoolean OGRLineString::IsEmpty( ) const
1467 : {
1468 67012 : return (nPointCount == 0);
1469 : }
1470 :
1471 : /************************************************************************/
1472 : /* OGRLineString::segmentize() */
1473 : /************************************************************************/
1474 :
1475 11 : void OGRLineString::segmentize( double dfMaxLength )
1476 : {
1477 11 : if (dfMaxLength <= 0)
1478 : {
1479 : CPLError(CE_Failure, CPLE_AppDefined,
1480 0 : "dfMaxLength must be strictly positive");
1481 0 : return;
1482 : }
1483 :
1484 : int i;
1485 11 : OGRRawPoint* paoNewPoints = NULL;
1486 11 : double* padfNewZ = NULL;
1487 11 : int nNewPointCount = 0;
1488 11 : double dfSquareMaxLength = dfMaxLength * dfMaxLength;
1489 :
1490 247 : for( i = 0; i < nPointCount; i++ )
1491 : {
1492 : paoNewPoints = (OGRRawPoint *)
1493 247 : OGRRealloc(paoNewPoints, sizeof(OGRRawPoint) * (nNewPointCount + 1));
1494 247 : paoNewPoints[nNewPointCount] = paoPoints[i];
1495 :
1496 247 : if( getCoordinateDimension() == 3 )
1497 : {
1498 : padfNewZ = (double *)
1499 0 : OGRRealloc(padfNewZ, sizeof(double) * (nNewPointCount + 1));
1500 0 : padfNewZ[nNewPointCount] = padfZ[i];
1501 : }
1502 :
1503 247 : nNewPointCount++;
1504 :
1505 247 : if (i == nPointCount - 1)
1506 11 : break;
1507 :
1508 236 : double dfX = paoPoints[i+1].x - paoPoints[i].x;
1509 236 : double dfY = paoPoints[i+1].y - paoPoints[i].y;
1510 236 : double dfSquareDist = dfX * dfX + dfY * dfY;
1511 236 : if (dfSquareDist > dfSquareMaxLength)
1512 : {
1513 97 : int nIntermediatePoints = (int)floor(sqrt(dfSquareDist / dfSquareMaxLength));
1514 : int j;
1515 :
1516 : paoNewPoints = (OGRRawPoint *)
1517 97 : OGRRealloc(paoNewPoints, sizeof(OGRRawPoint) * (nNewPointCount + nIntermediatePoints));
1518 97 : if( getCoordinateDimension() == 3 )
1519 : {
1520 : padfNewZ = (double *)
1521 0 : OGRRealloc(padfNewZ, sizeof(double) * (nNewPointCount + nIntermediatePoints));
1522 : }
1523 :
1524 273 : for(j=1;j<=nIntermediatePoints;j++)
1525 : {
1526 176 : paoNewPoints[nNewPointCount + j - 1].x = paoPoints[i].x + j * dfX / (nIntermediatePoints + 1);
1527 176 : paoNewPoints[nNewPointCount + j - 1].y = paoPoints[i].y + j * dfY / (nIntermediatePoints + 1);
1528 176 : if( getCoordinateDimension() == 3 )
1529 : {
1530 : /* No interpolation */
1531 0 : padfNewZ[nNewPointCount + j - 1] = 0;
1532 : }
1533 : }
1534 :
1535 97 : nNewPointCount += nIntermediatePoints;
1536 : }
1537 : }
1538 :
1539 11 : OGRFree(paoPoints);
1540 11 : paoPoints = paoNewPoints;
1541 11 : nPointCount = nNewPointCount;
1542 :
1543 11 : if( getCoordinateDimension() == 3 )
1544 : {
1545 0 : OGRFree(padfZ);
1546 0 : padfZ = padfNewZ;
1547 : }
1548 : }
1549 :
1550 : /************************************************************************/
1551 : /* swapXY() */
1552 : /************************************************************************/
1553 :
1554 28 : void OGRLineString::swapXY()
1555 : {
1556 : int i;
1557 154 : for( i = 0; i < nPointCount; i++ )
1558 : {
1559 126 : double dfTemp = paoPoints[i].x;
1560 126 : paoPoints[i].x = paoPoints[i].y;
1561 126 : paoPoints[i].y = dfTemp;
1562 : }
1563 28 : }
|