1 : /******************************************************************************
2 : * $Id: ogrmultilinestring.cpp 14336 2008-04-20 14:36:09Z 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 14336 2008-04-20 14:36:09Z rouault $");
34 :
35 : /************************************************************************/
36 : /* OGRMultiLineString() */
37 : /************************************************************************/
38 :
39 235 : OGRMultiLineString::OGRMultiLineString()
40 : {
41 235 : }
42 :
43 : /************************************************************************/
44 : /* ~OGRMultiLineString() */
45 : /************************************************************************/
46 :
47 424 : OGRMultiLineString::~OGRMultiLineString()
48 : {
49 424 : }
50 :
51 : /************************************************************************/
52 : /* getGeometryType() */
53 : /************************************************************************/
54 :
55 381 : OGRwkbGeometryType OGRMultiLineString::getGeometryType() const
56 :
57 : {
58 381 : if( getCoordinateDimension() == 3 )
59 55 : return wkbMultiLineString25D;
60 : else
61 326 : return wkbMultiLineString;
62 : }
63 :
64 : /************************************************************************/
65 : /* getGeometryName() */
66 : /************************************************************************/
67 :
68 93 : const char * OGRMultiLineString::getGeometryName() const
69 :
70 : {
71 93 : return "MULTILINESTRING";
72 : }
73 :
74 : /************************************************************************/
75 : /* addGeometryDirectly() */
76 : /************************************************************************/
77 :
78 414 : OGRErr OGRMultiLineString::addGeometryDirectly( OGRGeometry * poNewGeom )
79 :
80 : {
81 456 : if( poNewGeom->getGeometryType() != wkbLineString
82 42 : && poNewGeom->getGeometryType() != wkbLineString25D )
83 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
84 :
85 414 : return OGRGeometryCollection::addGeometryDirectly( poNewGeom );
86 : }
87 :
88 : /************************************************************************/
89 : /* clone() */
90 : /************************************************************************/
91 :
92 95 : OGRGeometry *OGRMultiLineString::clone() const
93 :
94 : {
95 : OGRMultiLineString *poNewGC;
96 :
97 95 : poNewGC = new OGRMultiLineString;
98 95 : poNewGC->assignSpatialReference( getSpatialReference() );
99 :
100 286 : for( int i = 0; i < getNumGeometries(); i++ )
101 : {
102 191 : poNewGC->addGeometry( getGeometryRef(i) );
103 : }
104 :
105 95 : return poNewGC;
106 : }
107 :
108 : /************************************************************************/
109 : /* importFromWkt() */
110 : /* */
111 : /* Instantiate from well known text format. Currently this is */
112 : /* `MULTILINESTRING ((x y, x y, ...),(x y, ...),...)'. */
113 : /************************************************************************/
114 :
115 42 : OGRErr OGRMultiLineString::importFromWkt( char ** ppszInput )
116 :
117 : {
118 : char szToken[OGR_WKT_TOKEN_MAX];
119 42 : const char *pszInput = *ppszInput;
120 : OGRErr eErr;
121 :
122 : /* -------------------------------------------------------------------- */
123 : /* Clear existing rings. */
124 : /* -------------------------------------------------------------------- */
125 42 : empty();
126 :
127 : /* -------------------------------------------------------------------- */
128 : /* Read and verify the ``MULTILINESTRING'' keyword token. */
129 : /* -------------------------------------------------------------------- */
130 42 : pszInput = OGRWktReadToken( pszInput, szToken );
131 :
132 42 : if( !EQUAL(szToken,getGeometryName()) )
133 0 : return OGRERR_CORRUPT_DATA;
134 :
135 : /* -------------------------------------------------------------------- */
136 : /* The next character should be a ( indicating the start of the */
137 : /* list of linestrings. */
138 : /* -------------------------------------------------------------------- */
139 42 : pszInput = OGRWktReadToken( pszInput, szToken );
140 :
141 42 : if( EQUAL(szToken,"EMPTY") )
142 : {
143 7 : *ppszInput = (char *) pszInput;
144 7 : return OGRERR_NONE;
145 : }
146 :
147 35 : if( szToken[0] != '(' )
148 0 : return OGRERR_CORRUPT_DATA;
149 :
150 : /* -------------------------------------------------------------------- */
151 : /* If the next token is EMPTY, then verify that we have proper */
152 : /* EMPTY format will a trailing closing bracket. */
153 : /* -------------------------------------------------------------------- */
154 35 : OGRWktReadToken( pszInput, szToken );
155 35 : if( EQUAL(szToken,"EMPTY") )
156 : {
157 1 : pszInput = OGRWktReadToken( pszInput, szToken );
158 1 : pszInput = OGRWktReadToken( pszInput, szToken );
159 :
160 1 : *ppszInput = (char *) pszInput;
161 :
162 1 : if( !EQUAL(szToken,")") )
163 0 : return OGRERR_CORRUPT_DATA;
164 : else
165 1 : return OGRERR_NONE;
166 : }
167 :
168 : /* ==================================================================== */
169 : /* Read each line in turn. Note that we try to reuse the same */
170 : /* point list buffer from ring to ring to cut down on */
171 : /* allocate/deallocate overhead. */
172 : /* ==================================================================== */
173 34 : OGRRawPoint *paoPoints = NULL;
174 34 : int nMaxPoints = 0;
175 34 : double *padfZ = NULL;
176 :
177 174 : do
178 : {
179 104 : int nPoints = 0;
180 :
181 : /* -------------------------------------------------------------------- */
182 : /* Read points for one line from input. */
183 : /* -------------------------------------------------------------------- */
184 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoints,
185 104 : &nPoints );
186 :
187 104 : if( pszInput == NULL )
188 : {
189 0 : eErr = OGRERR_CORRUPT_DATA;
190 0 : break;
191 : }
192 :
193 : /* -------------------------------------------------------------------- */
194 : /* Create the new line, and add to collection. */
195 : /* -------------------------------------------------------------------- */
196 : OGRLineString *poLine;
197 :
198 104 : poLine = new OGRLineString();
199 104 : poLine->setPoints( nPoints, paoPoints, padfZ );
200 :
201 104 : eErr = addGeometryDirectly( poLine );
202 :
203 : /* -------------------------------------------------------------------- */
204 : /* Read the delimeter following the ring. */
205 : /* -------------------------------------------------------------------- */
206 :
207 104 : pszInput = OGRWktReadToken( pszInput, szToken );
208 104 : } while( szToken[0] == ',' && eErr == OGRERR_NONE );
209 :
210 : /* -------------------------------------------------------------------- */
211 : /* freak if we don't get a closing bracket. */
212 : /* -------------------------------------------------------------------- */
213 34 : CPLFree( paoPoints );
214 34 : CPLFree( padfZ );
215 :
216 34 : if( eErr != OGRERR_NONE )
217 0 : return eErr;
218 :
219 34 : if( szToken[0] != ')' )
220 0 : return OGRERR_CORRUPT_DATA;
221 :
222 34 : *ppszInput = (char *) pszInput;
223 34 : return OGRERR_NONE;
224 : }
225 :
226 : /************************************************************************/
227 : /* exportToWkt() */
228 : /* */
229 : /* Translate this structure into it's well known text format */
230 : /* equivelent. This could be made alot more CPU efficient! */
231 : /************************************************************************/
232 :
233 19 : OGRErr OGRMultiLineString::exportToWkt( char ** ppszDstText ) const
234 :
235 : {
236 : char **papszLines;
237 19 : int iLine, nCumulativeLength = 0, nValidLineStrings=0;
238 : OGRErr eErr;
239 :
240 : /* -------------------------------------------------------------------- */
241 : /* Build a list of strings containing the stuff for each ring. */
242 : /* -------------------------------------------------------------------- */
243 19 : papszLines = (char **) CPLCalloc(sizeof(char *),getNumGeometries());
244 :
245 64 : for( iLine = 0; iLine < getNumGeometries(); iLine++ )
246 : {
247 45 : eErr = getGeometryRef(iLine)->exportToWkt( &(papszLines[iLine]) );
248 45 : if( eErr != OGRERR_NONE )
249 0 : return eErr;
250 :
251 45 : if( !EQUALN(papszLines[iLine],"LINESTRING (", 12) )
252 : {
253 : CPLDebug( "OGR", "OGRMultiLineString::exportToWkt() - skipping %s.",
254 5 : papszLines[iLine] );
255 5 : CPLFree( papszLines[iLine] );
256 5 : papszLines[iLine] = NULL;
257 5 : continue;
258 : }
259 :
260 40 : nCumulativeLength += strlen(papszLines[iLine] + 11);
261 40 : nValidLineStrings++;
262 : }
263 :
264 : /* -------------------------------------------------------------------- */
265 : /* Return MULTILINESTRING EMPTY if we get no valid line string. */
266 : /* -------------------------------------------------------------------- */
267 19 : if( nValidLineStrings == 0 )
268 : {
269 6 : CPLFree( papszLines );
270 6 : *ppszDstText = CPLStrdup("MULTILINESTRING EMPTY");
271 6 : return OGRERR_NONE;
272 : }
273 :
274 : /* -------------------------------------------------------------------- */
275 : /* Allocate exactly the right amount of space for the */
276 : /* aggregated string. */
277 : /* -------------------------------------------------------------------- */
278 13 : *ppszDstText = (char *) VSIMalloc(nCumulativeLength+getNumGeometries()+20);
279 :
280 13 : if( *ppszDstText == NULL )
281 0 : return OGRERR_NOT_ENOUGH_MEMORY;
282 :
283 : /* -------------------------------------------------------------------- */
284 : /* Build up the string, freeing temporary strings as we go. */
285 : /* -------------------------------------------------------------------- */
286 13 : char *pszAppendPoint = *ppszDstText;
287 :
288 13 : strcpy( pszAppendPoint, "MULTILINESTRING (" );
289 :
290 13 : int bMustWriteComma = FALSE;
291 56 : for( iLine = 0; iLine < getNumGeometries(); iLine++ )
292 : {
293 43 : if( papszLines[iLine] == NULL )
294 3 : continue;
295 :
296 40 : if( bMustWriteComma )
297 27 : strcat( pszAppendPoint, "," );
298 40 : bMustWriteComma = TRUE;
299 :
300 40 : strcat( pszAppendPoint, papszLines[iLine] + 11 );
301 40 : pszAppendPoint += strlen(pszAppendPoint);
302 :
303 40 : VSIFree( papszLines[iLine] );
304 : }
305 :
306 13 : strcat( pszAppendPoint, ")" );
307 :
308 13 : CPLFree( papszLines );
309 :
310 13 : return OGRERR_NONE;
311 : }
312 :
|