1 : /******************************************************************************
2 : * $Id: ogrmultipoint.cpp 21298 2010-12-20 10:58:34Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: The OGRMultiPoint 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: ogrmultipoint.cpp 21298 2010-12-20 10:58:34Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRMultiPoint() */
38 : /************************************************************************/
39 :
40 465 : OGRMultiPoint::OGRMultiPoint()
41 : {
42 465 : }
43 :
44 : /************************************************************************/
45 : /* getGeometryType() */
46 : /************************************************************************/
47 :
48 951 : OGRwkbGeometryType OGRMultiPoint::getGeometryType() const
49 :
50 : {
51 951 : if( getCoordinateDimension() == 3 )
52 285 : return wkbMultiPoint25D;
53 : else
54 666 : return wkbMultiPoint;
55 : }
56 :
57 : /************************************************************************/
58 : /* getGeometryName() */
59 : /************************************************************************/
60 :
61 224 : const char * OGRMultiPoint::getGeometryName() const
62 :
63 : {
64 224 : return "MULTIPOINT";
65 : }
66 :
67 : /************************************************************************/
68 : /* addGeometryDirectly() */
69 : /* */
70 : /* Add a new geometry to a collection. Subclasses should */
71 : /* override this to verify the type of the new geometry, and */
72 : /* then call this method to actually add it. */
73 : /************************************************************************/
74 :
75 691 : OGRErr OGRMultiPoint::addGeometryDirectly( OGRGeometry * poNewGeom )
76 :
77 : {
78 896 : if( poNewGeom->getGeometryType() != wkbPoint
79 205 : && poNewGeom->getGeometryType() != wkbPoint25D )
80 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
81 :
82 691 : return OGRGeometryCollection::addGeometryDirectly( poNewGeom );
83 : }
84 :
85 : /************************************************************************/
86 : /* clone() */
87 : /************************************************************************/
88 :
89 99 : OGRGeometry *OGRMultiPoint::clone() const
90 :
91 : {
92 : OGRMultiPoint *poNewGC;
93 :
94 99 : poNewGC = new OGRMultiPoint;
95 99 : poNewGC->assignSpatialReference( getSpatialReference() );
96 :
97 290 : for( int i = 0; i < getNumGeometries(); i++ )
98 : {
99 191 : poNewGC->addGeometry( getGeometryRef(i) );
100 : }
101 :
102 99 : return poNewGC;
103 : }
104 :
105 : /************************************************************************/
106 : /* exportToWkt() */
107 : /* */
108 : /* Translate this structure into it's well known text format */
109 : /* equivelent. This could be made alot more CPU efficient! */
110 : /************************************************************************/
111 :
112 68 : OGRErr OGRMultiPoint::exportToWkt( char ** ppszDstText ) const
113 :
114 : {
115 68 : int nMaxString = getNumGeometries() * 20 + 128;
116 68 : int nRetLen = 0;
117 :
118 : /* -------------------------------------------------------------------- */
119 : /* Return MULTIPOINT EMPTY if we get no valid points. */
120 : /* -------------------------------------------------------------------- */
121 68 : if( IsEmpty() )
122 : {
123 20 : *ppszDstText = CPLStrdup("MULTIPOINT EMPTY");
124 20 : return OGRERR_NONE;
125 : }
126 :
127 48 : *ppszDstText = (char *) VSIMalloc( nMaxString );
128 48 : if( *ppszDstText == NULL )
129 0 : return OGRERR_NOT_ENOUGH_MEMORY;
130 :
131 48 : sprintf( *ppszDstText, "%s (", getGeometryName() );
132 :
133 48 : int bMustWriteComma = FALSE;
134 149 : for( int i = 0; i < getNumGeometries(); i++ )
135 : {
136 101 : OGRPoint *poPoint = (OGRPoint *) getGeometryRef( i );
137 :
138 101 : if (poPoint->IsEmpty())
139 : {
140 7 : CPLDebug( "OGR", "OGRMultiPoint::exportToWkt() - skipping POINT EMPTY.");
141 7 : continue;
142 : }
143 :
144 94 : if( bMustWriteComma )
145 46 : strcat( *ppszDstText + nRetLen, "," );
146 94 : bMustWriteComma = TRUE;
147 :
148 94 : nRetLen += strlen(*ppszDstText + nRetLen);
149 :
150 94 : if( nMaxString < nRetLen + 100 )
151 : {
152 0 : nMaxString = nMaxString * 2;
153 0 : *ppszDstText = (char *) CPLRealloc(*ppszDstText,nMaxString);
154 : }
155 :
156 : OGRMakeWktCoordinate( *ppszDstText + nRetLen,
157 : poPoint->getX(),
158 : poPoint->getY(),
159 : poPoint->getZ(),
160 94 : poPoint->getCoordinateDimension() );
161 : }
162 :
163 48 : strcat( *ppszDstText+nRetLen, ")" );
164 :
165 48 : return OGRERR_NONE;
166 : }
167 :
168 : /************************************************************************/
169 : /* importFromWkt() */
170 : /************************************************************************/
171 :
172 120 : OGRErr OGRMultiPoint::importFromWkt( char ** ppszInput )
173 :
174 : {
175 :
176 : char szToken[OGR_WKT_TOKEN_MAX];
177 120 : const char *pszInput = *ppszInput;
178 : int iGeom;
179 120 : OGRErr eErr = OGRERR_NONE;
180 :
181 : /* -------------------------------------------------------------------- */
182 : /* Clear existing Geoms. */
183 : /* -------------------------------------------------------------------- */
184 120 : empty();
185 :
186 : /* -------------------------------------------------------------------- */
187 : /* Read and verify the type keyword, and ensure it matches the */
188 : /* actual type of this container. */
189 : /* -------------------------------------------------------------------- */
190 120 : pszInput = OGRWktReadToken( pszInput, szToken );
191 :
192 120 : if( !EQUAL(szToken,getGeometryName()) )
193 0 : return OGRERR_CORRUPT_DATA;
194 :
195 :
196 : /* -------------------------------------------------------------------- */
197 : /* Check for EMPTY ... */
198 : /* -------------------------------------------------------------------- */
199 : const char *pszPreScan;
200 120 : int bHasZ = FALSE, bHasM = FALSE;
201 :
202 120 : pszPreScan = OGRWktReadToken( pszInput, szToken );
203 120 : if( EQUAL(szToken,"EMPTY") )
204 : {
205 14 : *ppszInput = (char *) pszPreScan;
206 14 : empty();
207 14 : return OGRERR_NONE;
208 : }
209 :
210 : /* -------------------------------------------------------------------- */
211 : /* Check for Z, M or ZM. Will ignore the Measure */
212 : /* -------------------------------------------------------------------- */
213 106 : else if( EQUAL(szToken,"Z") )
214 : {
215 13 : bHasZ = TRUE;
216 : }
217 93 : else if( EQUAL(szToken,"M") )
218 : {
219 2 : bHasM = TRUE;
220 : }
221 91 : else if( EQUAL(szToken,"ZM") )
222 : {
223 2 : bHasZ = TRUE;
224 2 : bHasM = TRUE;
225 : }
226 :
227 106 : if (bHasZ || bHasM)
228 : {
229 17 : pszInput = pszPreScan;
230 17 : pszPreScan = OGRWktReadToken( pszInput, szToken );
231 17 : if( EQUAL(szToken,"EMPTY") )
232 : {
233 4 : *ppszInput = (char *) pszPreScan;
234 4 : empty();
235 : /* FIXME?: In theory we should store the dimension and M presence */
236 : /* if we want to allow round-trip with ExportToWKT v1.2 */
237 4 : return OGRERR_NONE;
238 : }
239 : }
240 :
241 102 : if( !EQUAL(szToken,"(") )
242 4 : return OGRERR_CORRUPT_DATA;
243 :
244 98 : if ( !bHasZ && !bHasM )
245 : {
246 : /* Test for old-style MULTIPOINT(EMPTY) */
247 87 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
248 87 : if( EQUAL(szToken,"EMPTY") )
249 : {
250 9 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
251 :
252 9 : if( EQUAL(szToken,",") )
253 : {
254 : /* This is OK according to SFSQL SPEC. */
255 : }
256 4 : else if( !EQUAL(szToken,")") )
257 1 : return OGRERR_CORRUPT_DATA;
258 : else
259 : {
260 3 : *ppszInput = (char *) pszPreScan;
261 3 : empty();
262 3 : return OGRERR_NONE;
263 : }
264 : }
265 : }
266 :
267 94 : pszPreScan = OGRWktReadToken( pszInput, szToken );
268 94 : OGRWktReadToken( pszPreScan, szToken );
269 :
270 : // Do we have an inner bracket?
271 94 : if (EQUAL(szToken,"(") || EQUAL(szToken, "EMPTY") )
272 22 : return importFromWkt_Bracketed( ppszInput, bHasM, bHasZ );
273 :
274 72 : if (bHasZ || bHasM)
275 : {
276 5 : return OGRERR_CORRUPT_DATA;
277 : }
278 :
279 : /* -------------------------------------------------------------------- */
280 : /* Read the point list which should consist of exactly one point. */
281 : /* -------------------------------------------------------------------- */
282 67 : int nMaxPoint = 0;
283 67 : int nPointCount = 0;
284 67 : OGRRawPoint *paoPoints = NULL;
285 67 : double *padfZ = NULL;
286 :
287 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoint,
288 67 : &nPointCount );
289 67 : if( pszInput == NULL )
290 : {
291 7 : OGRFree( paoPoints );
292 7 : OGRFree( padfZ );
293 7 : return OGRERR_CORRUPT_DATA;
294 : }
295 :
296 : /* -------------------------------------------------------------------- */
297 : /* Transform raw points into point objects. */
298 : /* -------------------------------------------------------------------- */
299 182 : for( iGeom = 0; iGeom < nPointCount && eErr == OGRERR_NONE; iGeom++ )
300 : {
301 : OGRGeometry *poGeom;
302 122 : if( padfZ )
303 39 : poGeom = new OGRPoint( paoPoints[iGeom].x,
304 39 : paoPoints[iGeom].y,
305 117 : padfZ[iGeom] );
306 : else
307 83 : poGeom = new OGRPoint( paoPoints[iGeom].x,
308 166 : paoPoints[iGeom].y );
309 :
310 122 : eErr = addGeometryDirectly( poGeom );
311 : }
312 :
313 60 : OGRFree( paoPoints );
314 60 : if( padfZ )
315 19 : OGRFree( padfZ );
316 :
317 60 : if( eErr != OGRERR_NONE )
318 0 : return eErr;
319 :
320 60 : *ppszInput = (char *) pszInput;
321 :
322 60 : return OGRERR_NONE;
323 : }
324 :
325 :
326 : /************************************************************************/
327 : /* importFromWkt_Bracketed() */
328 : /* */
329 : /* This operates similar to importFromWkt(), but reads a format */
330 : /* with brackets around each point. This is the form defined */
331 : /* in the BNF of the SFSQL spec. It is called from */
332 : /* importFromWkt(). */
333 : /************************************************************************/
334 :
335 22 : OGRErr OGRMultiPoint::importFromWkt_Bracketed( char ** ppszInput, int bHasM, int bHasZ )
336 :
337 : {
338 :
339 : char szToken[OGR_WKT_TOKEN_MAX];
340 22 : const char *pszInput = *ppszInput;
341 22 : OGRErr eErr = OGRERR_NONE;
342 :
343 : /* -------------------------------------------------------------------- */
344 : /* Skip MULTIPOINT keyword. */
345 : /* -------------------------------------------------------------------- */
346 22 : pszInput = OGRWktReadToken( pszInput, szToken );
347 :
348 22 : if (bHasZ || bHasM)
349 : {
350 : /* Skip Z, M or ZM */
351 6 : pszInput = OGRWktReadToken( pszInput, szToken );
352 : }
353 :
354 : /* -------------------------------------------------------------------- */
355 : /* Read points till we get to the closing bracket. */
356 : /* -------------------------------------------------------------------- */
357 22 : int nMaxPoint = 0;
358 22 : int nPointCount = 0;
359 22 : OGRRawPoint *paoPoints = NULL;
360 22 : double *padfZ = NULL;
361 :
362 86 : while( (pszInput = OGRWktReadToken( pszInput, szToken )) != NULL
363 : && (EQUAL(szToken,"(") || EQUAL(szToken,",")) )
364 : {
365 : OGRGeometry *poGeom;
366 :
367 45 : const char* pszNext = OGRWktReadToken( pszInput, szToken );
368 45 : if (EQUAL(szToken,"EMPTY"))
369 : {
370 11 : poGeom = new OGRPoint(0,0);
371 11 : poGeom->empty();
372 11 : eErr = addGeometryDirectly( poGeom );
373 11 : if( eErr != OGRERR_NONE )
374 0 : return eErr;
375 :
376 11 : pszInput = pszNext;
377 :
378 11 : continue;
379 : }
380 :
381 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoint,
382 34 : &nPointCount );
383 :
384 34 : if( pszInput == NULL || nPointCount != 1 )
385 : {
386 3 : OGRFree( paoPoints );
387 3 : OGRFree( padfZ );
388 3 : return OGRERR_CORRUPT_DATA;
389 : }
390 :
391 : /* Ignore Z array when we have a MULTIPOINT M */
392 35 : if( padfZ && !(bHasM && !bHasZ))
393 4 : poGeom = new OGRPoint( paoPoints[0].x,
394 4 : paoPoints[0].y,
395 12 : padfZ[0] );
396 : else
397 27 : poGeom = new OGRPoint( paoPoints[0].x,
398 54 : paoPoints[0].y );
399 :
400 31 : eErr = addGeometryDirectly( poGeom );
401 31 : if( eErr != OGRERR_NONE )
402 0 : return eErr;
403 : }
404 :
405 : /* -------------------------------------------------------------------- */
406 : /* Cleanup. */
407 : /* -------------------------------------------------------------------- */
408 19 : OGRFree( paoPoints );
409 19 : if( padfZ )
410 3 : OGRFree( padfZ );
411 :
412 19 : if( !EQUAL(szToken,")") )
413 6 : return OGRERR_CORRUPT_DATA;
414 :
415 13 : *ppszInput = (char *) pszInput;
416 :
417 13 : return OGRERR_NONE;
418 : }
419 :
420 :
|