1 : /******************************************************************************
2 : * $Id: ogrmultipolygon.cpp 16898 2009-05-01 12:23:36Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: The OGRMultiPolygon 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: ogrmultipolygon.cpp 16898 2009-05-01 12:23:36Z rouault $");
34 :
35 : /************************************************************************/
36 : /* OGRMultiPolygon() */
37 : /************************************************************************/
38 :
39 224 : OGRMultiPolygon::OGRMultiPolygon()
40 : {
41 224 : }
42 :
43 : /************************************************************************/
44 : /* getGeometryType() */
45 : /************************************************************************/
46 :
47 498 : OGRwkbGeometryType OGRMultiPolygon::getGeometryType() const
48 :
49 : {
50 498 : if( getCoordinateDimension() == 3 )
51 39 : return wkbMultiPolygon25D;
52 : else
53 459 : return wkbMultiPolygon;
54 : }
55 :
56 : /************************************************************************/
57 : /* getGeometryName() */
58 : /************************************************************************/
59 :
60 133 : const char * OGRMultiPolygon::getGeometryName() const
61 :
62 : {
63 133 : return "MULTIPOLYGON";
64 : }
65 :
66 : /************************************************************************/
67 : /* addGeometryDirectly() */
68 : /************************************************************************/
69 :
70 427 : OGRErr OGRMultiPolygon::addGeometryDirectly( OGRGeometry * poNewGeom )
71 :
72 : {
73 487 : if( poNewGeom->getGeometryType() != wkbPolygon
74 60 : && poNewGeom->getGeometryType() != wkbPolygon25D )
75 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
76 :
77 427 : return OGRGeometryCollection::addGeometryDirectly( poNewGeom );
78 : }
79 :
80 : /************************************************************************/
81 : /* clone() */
82 : /************************************************************************/
83 :
84 61 : OGRGeometry *OGRMultiPolygon::clone() const
85 :
86 : {
87 : OGRMultiPolygon *poNewGC;
88 :
89 61 : poNewGC = new OGRMultiPolygon;
90 61 : poNewGC->assignSpatialReference( getSpatialReference() );
91 :
92 198 : for( int i = 0; i < getNumGeometries(); i++ )
93 : {
94 137 : poNewGC->addGeometry( getGeometryRef(i) );
95 : }
96 :
97 61 : return poNewGC;
98 : }
99 :
100 : /************************************************************************/
101 : /* importFromWkt() */
102 : /* */
103 : /* Instantiate from well known text format. Currently this is */
104 : /* `MULTIPOLYGON ((x y, x y, ...),(x y, ...),...)'. */
105 : /************************************************************************/
106 :
107 54 : OGRErr OGRMultiPolygon::importFromWkt( char ** ppszInput )
108 :
109 : {
110 : char szToken[OGR_WKT_TOKEN_MAX];
111 54 : const char *pszInput = *ppszInput;
112 54 : OGRErr eErr = OGRERR_NONE;
113 :
114 : /* -------------------------------------------------------------------- */
115 : /* Clear existing rings. */
116 : /* -------------------------------------------------------------------- */
117 54 : empty();
118 :
119 : /* -------------------------------------------------------------------- */
120 : /* Read and verify the MULTIPOLYGON keyword token. */
121 : /* -------------------------------------------------------------------- */
122 54 : pszInput = OGRWktReadToken( pszInput, szToken );
123 :
124 54 : if( !EQUAL(szToken,getGeometryName()) )
125 0 : return OGRERR_CORRUPT_DATA;
126 :
127 : /* -------------------------------------------------------------------- */
128 : /* The next character should be a ( indicating the start of the */
129 : /* list of polygons. */
130 : /* -------------------------------------------------------------------- */
131 54 : pszInput = OGRWktReadToken( pszInput, szToken );
132 :
133 54 : if( EQUAL(szToken,"EMPTY") )
134 : {
135 5 : *ppszInput = (char *) pszInput;
136 5 : return OGRERR_NONE;
137 : }
138 :
139 49 : if( szToken[0] != '(' )
140 0 : return OGRERR_CORRUPT_DATA;
141 :
142 : /* -------------------------------------------------------------------- */
143 : /* If the next token is EMPTY, then verify that we have proper */
144 : /* EMPTY format will a trailing closing bracket. */
145 : /* -------------------------------------------------------------------- */
146 49 : OGRWktReadToken( pszInput, szToken );
147 49 : if( EQUAL(szToken,"EMPTY") )
148 : {
149 1 : pszInput = OGRWktReadToken( pszInput, szToken );
150 1 : pszInput = OGRWktReadToken( pszInput, szToken );
151 :
152 1 : *ppszInput = (char *) pszInput;
153 :
154 1 : if( !EQUAL(szToken,")") )
155 0 : return OGRERR_CORRUPT_DATA;
156 : else
157 1 : return OGRERR_NONE;
158 : }
159 :
160 : /* ==================================================================== */
161 : /* Read each polygon in turn. Note that we try to reuse the same */
162 : /* point list buffer from ring to ring to cut down on */
163 : /* allocate/deallocate overhead. */
164 : /* ==================================================================== */
165 48 : OGRRawPoint *paoPoints = NULL;
166 48 : int nMaxPoints = 0;
167 48 : double *padfZ = NULL;
168 :
169 94 : do
170 : {
171 94 : OGRPolygon *poPolygon = new OGRPolygon();
172 :
173 : /* -------------------------------------------------------------------- */
174 : /* The next character should be a ( indicating the start of the */
175 : /* list of polygons. */
176 : /* -------------------------------------------------------------------- */
177 94 : pszInput = OGRWktReadToken( pszInput, szToken );
178 94 : if( szToken[0] != '(' )
179 : {
180 0 : eErr = OGRERR_CORRUPT_DATA;
181 0 : delete poPolygon;
182 0 : break;
183 : }
184 :
185 : /* -------------------------------------------------------------------- */
186 : /* Loop over each ring in this polygon. */
187 : /* -------------------------------------------------------------------- */
188 150 : do
189 : {
190 122 : int nPoints = 0;
191 :
192 : /* -------------------------------------------------------------------- */
193 : /* Read points for one line from input. */
194 : /* -------------------------------------------------------------------- */
195 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoints,
196 122 : &nPoints );
197 :
198 122 : if( pszInput == NULL )
199 : {
200 0 : eErr = OGRERR_CORRUPT_DATA;
201 0 : break;
202 : }
203 :
204 : /* -------------------------------------------------------------------- */
205 : /* Create the new line, and add to collection. */
206 : /* -------------------------------------------------------------------- */
207 : OGRLinearRing *poLine;
208 :
209 122 : poLine = new OGRLinearRing();
210 122 : poLine->setPoints( nPoints, paoPoints, padfZ );
211 :
212 122 : poPolygon->addRingDirectly( poLine );
213 :
214 : /* -------------------------------------------------------------------- */
215 : /* Read the delimeter following the ring. */
216 : /* -------------------------------------------------------------------- */
217 :
218 122 : pszInput = OGRWktReadToken( pszInput, szToken );
219 122 : } while( szToken[0] == ',' && eErr == OGRERR_NONE );
220 :
221 : /* -------------------------------------------------------------------- */
222 : /* Verify that we have a closing bracket. */
223 : /* -------------------------------------------------------------------- */
224 94 : if( eErr == OGRERR_NONE )
225 : {
226 94 : if( szToken[0] != ')' )
227 0 : eErr = OGRERR_CORRUPT_DATA;
228 : else
229 94 : pszInput = OGRWktReadToken( pszInput, szToken );
230 : }
231 :
232 : /* -------------------------------------------------------------------- */
233 : /* Add the polygon to the MULTIPOLYGON. */
234 : /* -------------------------------------------------------------------- */
235 94 : if( eErr == OGRERR_NONE )
236 94 : eErr = addGeometryDirectly( poPolygon );
237 : else
238 0 : delete poPolygon;
239 :
240 94 : } while( szToken[0] == ',' && eErr == OGRERR_NONE );
241 :
242 : /* -------------------------------------------------------------------- */
243 : /* freak if we don't get a closing bracket. */
244 : /* -------------------------------------------------------------------- */
245 48 : CPLFree( paoPoints );
246 48 : CPLFree( padfZ );
247 :
248 48 : if( eErr != OGRERR_NONE )
249 0 : return eErr;
250 :
251 48 : if( szToken[0] != ')' )
252 0 : return OGRERR_CORRUPT_DATA;
253 :
254 48 : *ppszInput = (char *) pszInput;
255 48 : return OGRERR_NONE;
256 : }
257 :
258 : /************************************************************************/
259 : /* exportToWkt() */
260 : /* */
261 : /* Translate this structure into it's well known text format */
262 : /* equivelent. This could be made alot more CPU efficient! */
263 : /************************************************************************/
264 :
265 27 : OGRErr OGRMultiPolygon::exportToWkt( char ** ppszDstText ) const
266 :
267 : {
268 : char **papszPolygons;
269 27 : int iPoly, nCumulativeLength = 0, nValidPolys=0;
270 : OGRErr eErr;
271 27 : int bMustWriteComma = FALSE;
272 :
273 : /* -------------------------------------------------------------------- */
274 : /* Build a list of strings containing the stuff for each ring. */
275 : /* -------------------------------------------------------------------- */
276 27 : papszPolygons = (char **) CPLCalloc(sizeof(char *),getNumGeometries());
277 :
278 76 : for( iPoly = 0; iPoly < getNumGeometries(); iPoly++ )
279 : {
280 49 : eErr = getGeometryRef(iPoly)->exportToWkt( &(papszPolygons[iPoly]) );
281 49 : if( eErr != OGRERR_NONE )
282 0 : goto error;
283 :
284 49 : if( !EQUALN(papszPolygons[iPoly],"POLYGON (", 9) )
285 : {
286 : CPLDebug( "OGR", "OGRMultiPolygon::exportToWkt() - skipping %s.",
287 4 : papszPolygons[iPoly] );
288 4 : CPLFree( papszPolygons[iPoly] );
289 4 : papszPolygons[iPoly] = NULL;
290 4 : continue;
291 : }
292 :
293 45 : nCumulativeLength += strlen(papszPolygons[iPoly] + 8);
294 45 : nValidPolys++;
295 : }
296 :
297 : /* -------------------------------------------------------------------- */
298 : /* Return MULTIPOLYGON EMPTY if we get no valid polygons. */
299 : /* -------------------------------------------------------------------- */
300 27 : if( nValidPolys == 0 )
301 : {
302 4 : CPLFree( papszPolygons );
303 4 : *ppszDstText = CPLStrdup("MULTIPOLYGON EMPTY");
304 4 : return OGRERR_NONE;
305 : }
306 :
307 : /* -------------------------------------------------------------------- */
308 : /* Allocate exactly the right amount of space for the */
309 : /* aggregated string. */
310 : /* -------------------------------------------------------------------- */
311 23 : *ppszDstText = (char *) VSIMalloc(nCumulativeLength+getNumGeometries()+20);
312 :
313 23 : if( *ppszDstText == NULL )
314 : {
315 0 : eErr = OGRERR_NOT_ENOUGH_MEMORY;
316 0 : goto error;
317 : }
318 :
319 : /* -------------------------------------------------------------------- */
320 : /* Build up the string, freeing temporary strings as we go. */
321 : /* -------------------------------------------------------------------- */
322 23 : strcpy( *ppszDstText, "MULTIPOLYGON (" );
323 23 : nCumulativeLength = strlen(*ppszDstText);
324 :
325 72 : for( iPoly = 0; iPoly < getNumGeometries(); iPoly++ )
326 : {
327 49 : if( papszPolygons[iPoly] == NULL )
328 4 : continue;
329 :
330 45 : if( bMustWriteComma )
331 22 : (*ppszDstText)[nCumulativeLength++] = ',';
332 45 : bMustWriteComma = TRUE;
333 :
334 45 : int nPolyLength = strlen(papszPolygons[iPoly] + 8);
335 45 : memcpy( *ppszDstText + nCumulativeLength, papszPolygons[iPoly] + 8, nPolyLength );
336 45 : nCumulativeLength += nPolyLength;
337 45 : VSIFree( papszPolygons[iPoly] );
338 : }
339 :
340 23 : (*ppszDstText)[nCumulativeLength++] = ')';
341 23 : (*ppszDstText)[nCumulativeLength] = '\0';
342 :
343 23 : CPLFree( papszPolygons );
344 :
345 23 : return OGRERR_NONE;
346 :
347 : error:
348 0 : for( iPoly = 0; iPoly < getNumGeometries(); iPoly++ )
349 0 : CPLFree( papszPolygons[iPoly] );
350 0 : CPLFree( papszPolygons );
351 0 : return eErr;
352 : }
353 :
354 : /************************************************************************/
355 : /* get_Area() */
356 : /************************************************************************/
357 :
358 : /**
359 : * Compute area of multipolygon.
360 : *
361 : * The area is computed as the sum of the areas of all polygon members
362 : * in this collection.
363 : *
364 : * @return computed area.
365 : */
366 :
367 1 : double OGRMultiPolygon::get_Area() const
368 :
369 : {
370 1 : double dfArea = 0.0;
371 : int iPoly;
372 :
373 3 : for( iPoly = 0; iPoly < getNumGeometries(); iPoly++ )
374 : {
375 2 : OGRPolygon *poPoly = (OGRPolygon *) getGeometryRef( iPoly );
376 :
377 2 : dfArea += poPoly->get_Area();
378 : }
379 :
380 1 : return dfArea;
381 : }
382 :
|