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