1 : /******************************************************************************
2 : * $Id: ogrmultilinestring.cpp 25426 2013-01-01 17:51:35Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: The OGRMultiLineString class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_geometry.h"
31 : #include "ogr_p.h"
32 :
33 : CPL_CVSID("$Id: ogrmultilinestring.cpp 25426 2013-01-01 17:51:35Z rouault $");
34 :
35 : /************************************************************************/
36 : /* OGRMultiLineString() */
37 : /************************************************************************/
38 :
39 1187 : OGRMultiLineString::OGRMultiLineString()
40 : {
41 1187 : }
42 :
43 : /************************************************************************/
44 : /* ~OGRMultiLineString() */
45 : /************************************************************************/
46 :
47 1187 : OGRMultiLineString::~OGRMultiLineString()
48 : {
49 1187 : }
50 :
51 : /************************************************************************/
52 : /* getGeometryType() */
53 : /************************************************************************/
54 :
55 1203 : OGRwkbGeometryType OGRMultiLineString::getGeometryType() const
56 :
57 : {
58 1203 : if( getCoordinateDimension() == 3 )
59 137 : return wkbMultiLineString25D;
60 : else
61 1066 : return wkbMultiLineString;
62 : }
63 :
64 : /************************************************************************/
65 : /* getDimension() */
66 : /************************************************************************/
67 :
68 0 : int OGRMultiLineString::getDimension() const
69 :
70 : {
71 0 : return 1;
72 : }
73 :
74 : /************************************************************************/
75 : /* getGeometryName() */
76 : /************************************************************************/
77 :
78 238 : const char * OGRMultiLineString::getGeometryName() const
79 :
80 : {
81 238 : return "MULTILINESTRING";
82 : }
83 :
84 : /************************************************************************/
85 : /* addGeometryDirectly() */
86 : /************************************************************************/
87 :
88 1925 : OGRErr OGRMultiLineString::addGeometryDirectly( OGRGeometry * poNewGeom )
89 :
90 : {
91 2138 : if( poNewGeom->getGeometryType() != wkbLineString
92 213 : && poNewGeom->getGeometryType() != wkbLineString25D )
93 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
94 :
95 1925 : return OGRGeometryCollection::addGeometryDirectly( poNewGeom );
96 : }
97 :
98 : /************************************************************************/
99 : /* clone() */
100 : /************************************************************************/
101 :
102 198 : OGRGeometry *OGRMultiLineString::clone() const
103 :
104 : {
105 : OGRMultiLineString *poNewGC;
106 :
107 198 : poNewGC = new OGRMultiLineString;
108 198 : poNewGC->assignSpatialReference( getSpatialReference() );
109 :
110 635 : for( int i = 0; i < getNumGeometries(); i++ )
111 : {
112 437 : poNewGC->addGeometry( getGeometryRef(i) );
113 : }
114 :
115 198 : return poNewGC;
116 : }
117 :
118 : /************************************************************************/
119 : /* importFromWkt() */
120 : /* */
121 : /* Instantiate from well known text format. Currently this is */
122 : /* `MULTILINESTRING ((x y, x y, ...),(x y, ...),...)'. */
123 : /************************************************************************/
124 :
125 143 : OGRErr OGRMultiLineString::importFromWkt( char ** ppszInput )
126 :
127 : {
128 : char szToken[OGR_WKT_TOKEN_MAX];
129 143 : const char *pszInput = *ppszInput;
130 : OGRErr eErr;
131 :
132 : /* -------------------------------------------------------------------- */
133 : /* Clear existing rings. */
134 : /* -------------------------------------------------------------------- */
135 143 : empty();
136 :
137 : /* -------------------------------------------------------------------- */
138 : /* Read and verify the ``MULTILINESTRING'' keyword token. */
139 : /* -------------------------------------------------------------------- */
140 143 : pszInput = OGRWktReadToken( pszInput, szToken );
141 :
142 143 : if( !EQUAL(szToken,getGeometryName()) )
143 0 : return OGRERR_CORRUPT_DATA;
144 :
145 : /* -------------------------------------------------------------------- */
146 : /* Check for EMPTY ... */
147 : /* -------------------------------------------------------------------- */
148 : const char *pszPreScan;
149 143 : int bHasZ = FALSE, bHasM = FALSE;
150 :
151 143 : pszPreScan = OGRWktReadToken( pszInput, szToken );
152 143 : if( EQUAL(szToken,"EMPTY") )
153 : {
154 16 : *ppszInput = (char *) pszPreScan;
155 16 : empty();
156 16 : return OGRERR_NONE;
157 : }
158 :
159 : /* -------------------------------------------------------------------- */
160 : /* Check for Z, M or ZM. Will ignore the Measure */
161 : /* -------------------------------------------------------------------- */
162 127 : else if( EQUAL(szToken,"Z") )
163 : {
164 13 : bHasZ = TRUE;
165 : }
166 114 : else if( EQUAL(szToken,"M") )
167 : {
168 2 : bHasM = TRUE;
169 : }
170 112 : else if( EQUAL(szToken,"ZM") )
171 : {
172 2 : bHasZ = TRUE;
173 2 : bHasM = TRUE;
174 : }
175 :
176 127 : if (bHasZ || bHasM)
177 : {
178 17 : pszInput = pszPreScan;
179 17 : pszPreScan = OGRWktReadToken( pszInput, szToken );
180 17 : if( EQUAL(szToken,"EMPTY") )
181 : {
182 4 : *ppszInput = (char *) pszPreScan;
183 4 : empty();
184 : /* FIXME?: In theory we should store the dimension and M presence */
185 : /* if we want to allow round-trip with ExportToWKT v1.2 */
186 4 : return OGRERR_NONE;
187 : }
188 : }
189 :
190 123 : if( !EQUAL(szToken,"(") )
191 4 : return OGRERR_CORRUPT_DATA;
192 :
193 119 : if ( !bHasZ && !bHasM )
194 : {
195 : /* Test for old-style MULTILINESTRING(EMPTY) */
196 108 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
197 108 : if( EQUAL(szToken,"EMPTY") )
198 : {
199 8 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
200 :
201 8 : if( EQUAL(szToken,",") )
202 : {
203 : /* This is OK according to SFSQL SPEC. */
204 : }
205 4 : else if( !EQUAL(szToken,")") )
206 1 : return OGRERR_CORRUPT_DATA;
207 : else
208 : {
209 3 : *ppszInput = (char *) pszPreScan;
210 3 : empty();
211 3 : return OGRERR_NONE;
212 : }
213 : }
214 : }
215 :
216 : /* Skip first '(' */
217 115 : pszInput = OGRWktReadToken( pszInput, szToken );
218 :
219 : /* ==================================================================== */
220 : /* Read each line in turn. Note that we try to reuse the same */
221 : /* point list buffer from ring to ring to cut down on */
222 : /* allocate/deallocate overhead. */
223 : /* ==================================================================== */
224 115 : OGRRawPoint *paoPoints = NULL;
225 115 : int nMaxPoints = 0;
226 115 : double *padfZ = NULL;
227 :
228 219 : do
229 : {
230 240 : int nPoints = 0;
231 :
232 240 : const char* pszNext = OGRWktReadToken( pszInput, szToken );
233 240 : if (EQUAL(szToken,"EMPTY"))
234 : {
235 10 : eErr = addGeometryDirectly( new OGRLineString() );
236 10 : if( eErr != OGRERR_NONE )
237 0 : return eErr;
238 :
239 10 : pszInput = OGRWktReadToken( pszNext, szToken );
240 10 : if ( !EQUAL(szToken, ",") )
241 5 : break;
242 :
243 5 : continue;
244 : }
245 : /* -------------------------------------------------------------------- */
246 : /* Read points for one line from input. */
247 : /* -------------------------------------------------------------------- */
248 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoints,
249 230 : &nPoints );
250 :
251 230 : if( pszInput == NULL || nPoints == 0 )
252 : {
253 16 : eErr = OGRERR_CORRUPT_DATA;
254 16 : break;
255 : }
256 :
257 : /* -------------------------------------------------------------------- */
258 : /* Create the new line, and add to collection. */
259 : /* -------------------------------------------------------------------- */
260 : OGRLineString *poLine;
261 :
262 214 : poLine = new OGRLineString();
263 : /* Ignore Z array when we have a MULTILINESTRING M */
264 217 : if (bHasM && !bHasZ)
265 1 : poLine->setPoints( nPoints, paoPoints, NULL );
266 : else
267 213 : poLine->setPoints( nPoints, paoPoints, padfZ );
268 :
269 214 : eErr = addGeometryDirectly( poLine );
270 :
271 : /* -------------------------------------------------------------------- */
272 : /* Read the delimeter following the ring. */
273 : /* -------------------------------------------------------------------- */
274 :
275 214 : pszInput = OGRWktReadToken( pszInput, szToken );
276 219 : } while( szToken[0] == ',' && eErr == OGRERR_NONE );
277 :
278 : /* -------------------------------------------------------------------- */
279 : /* freak if we don't get a closing bracket. */
280 : /* -------------------------------------------------------------------- */
281 115 : CPLFree( paoPoints );
282 115 : CPLFree( padfZ );
283 :
284 115 : if( eErr != OGRERR_NONE )
285 16 : return eErr;
286 :
287 99 : if( szToken[0] != ')' )
288 6 : return OGRERR_CORRUPT_DATA;
289 :
290 93 : *ppszInput = (char *) pszInput;
291 93 : return OGRERR_NONE;
292 : }
293 :
294 : /************************************************************************/
295 : /* exportToWkt() */
296 : /* */
297 : /* Translate this structure into it's well known text format */
298 : /* equivelent. This could be made alot more CPU efficient! */
299 : /************************************************************************/
300 :
301 62 : OGRErr OGRMultiLineString::exportToWkt( char ** ppszDstText ) const
302 :
303 : {
304 : char **papszLines;
305 62 : int iLine, nCumulativeLength = 0, nValidLineStrings=0;
306 : OGRErr eErr;
307 :
308 : /* -------------------------------------------------------------------- */
309 : /* Build a list of strings containing the stuff for each ring. */
310 : /* -------------------------------------------------------------------- */
311 62 : papszLines = (char **) CPLCalloc(sizeof(char *),getNumGeometries());
312 :
313 146 : for( iLine = 0; iLine < getNumGeometries(); iLine++ )
314 : {
315 84 : eErr = getGeometryRef(iLine)->exportToWkt( &(papszLines[iLine]) );
316 84 : if( eErr != OGRERR_NONE )
317 0 : return eErr;
318 :
319 84 : if( !EQUALN(papszLines[iLine],"LINESTRING (", 12) )
320 : {
321 : CPLDebug( "OGR", "OGRMultiLineString::exportToWkt() - skipping %s.",
322 10 : papszLines[iLine] );
323 10 : CPLFree( papszLines[iLine] );
324 10 : papszLines[iLine] = NULL;
325 10 : continue;
326 : }
327 :
328 74 : nCumulativeLength += strlen(papszLines[iLine] + 11);
329 74 : nValidLineStrings++;
330 : }
331 :
332 : /* -------------------------------------------------------------------- */
333 : /* Return MULTILINESTRING EMPTY if we get no valid line string. */
334 : /* -------------------------------------------------------------------- */
335 62 : if( nValidLineStrings == 0 )
336 : {
337 23 : CPLFree( papszLines );
338 23 : *ppszDstText = CPLStrdup("MULTILINESTRING EMPTY");
339 23 : return OGRERR_NONE;
340 : }
341 :
342 : /* -------------------------------------------------------------------- */
343 : /* Allocate exactly the right amount of space for the */
344 : /* aggregated string. */
345 : /* -------------------------------------------------------------------- */
346 39 : *ppszDstText = (char *) VSIMalloc(nCumulativeLength+getNumGeometries()+20);
347 :
348 39 : if( *ppszDstText == NULL )
349 0 : return OGRERR_NOT_ENOUGH_MEMORY;
350 :
351 : /* -------------------------------------------------------------------- */
352 : /* Build up the string, freeing temporary strings as we go. */
353 : /* -------------------------------------------------------------------- */
354 39 : char *pszAppendPoint = *ppszDstText;
355 :
356 39 : strcpy( pszAppendPoint, "MULTILINESTRING (" );
357 :
358 39 : int bMustWriteComma = FALSE;
359 120 : for( iLine = 0; iLine < getNumGeometries(); iLine++ )
360 : {
361 81 : if( papszLines[iLine] == NULL )
362 7 : continue;
363 :
364 74 : if( bMustWriteComma )
365 35 : strcat( pszAppendPoint, "," );
366 74 : bMustWriteComma = TRUE;
367 :
368 74 : strcat( pszAppendPoint, papszLines[iLine] + 11 );
369 74 : pszAppendPoint += strlen(pszAppendPoint);
370 :
371 74 : VSIFree( papszLines[iLine] );
372 : }
373 :
374 39 : strcat( pszAppendPoint, ")" );
375 :
376 39 : CPLFree( papszLines );
377 :
378 39 : return OGRERR_NONE;
379 : }
380 :
|