1 : /******************************************************************************
2 : * $Id: ogrmultipoint.cpp 18913 2010-02-24 23:41:17Z 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 18913 2010-02-24 23:41:17Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRMultiPoint() */
38 : /************************************************************************/
39 :
40 195 : OGRMultiPoint::OGRMultiPoint()
41 : {
42 195 : }
43 :
44 : /************************************************************************/
45 : /* getGeometryType() */
46 : /************************************************************************/
47 :
48 319 : OGRwkbGeometryType OGRMultiPoint::getGeometryType() const
49 :
50 : {
51 319 : if( getCoordinateDimension() == 3 )
52 67 : return wkbMultiPoint25D;
53 : else
54 252 : return wkbMultiPoint;
55 : }
56 :
57 : /************************************************************************/
58 : /* getGeometryName() */
59 : /************************************************************************/
60 :
61 157 : const char * OGRMultiPoint::getGeometryName() const
62 :
63 : {
64 157 : 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 284 : OGRErr OGRMultiPoint::addGeometryDirectly( OGRGeometry * poNewGeom )
76 :
77 : {
78 284 : if( poNewGeom->getGeometryType() != wkbPoint
79 : && poNewGeom->getGeometryType() != wkbPoint25D )
80 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
81 :
82 284 : return OGRGeometryCollection::addGeometryDirectly( poNewGeom );
83 : }
84 :
85 : /************************************************************************/
86 : /* clone() */
87 : /************************************************************************/
88 :
89 57 : OGRGeometry *OGRMultiPoint::clone() const
90 :
91 : {
92 : OGRMultiPoint *poNewGC;
93 :
94 57 : poNewGC = new OGRMultiPoint;
95 57 : poNewGC->assignSpatialReference( getSpatialReference() );
96 :
97 174 : for( int i = 0; i < getNumGeometries(); i++ )
98 : {
99 117 : poNewGC->addGeometry( getGeometryRef(i) );
100 : }
101 :
102 57 : 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 41 : OGRErr OGRMultiPoint::exportToWkt( char ** ppszDstText ) const
113 :
114 : {
115 41 : int nMaxString = getNumGeometries() * 20 + 128;
116 41 : int nRetLen = 0;
117 :
118 : /* -------------------------------------------------------------------- */
119 : /* Return MULTIPOINT EMPTY if we get no valid points. */
120 : /* -------------------------------------------------------------------- */
121 41 : if( IsEmpty() )
122 : {
123 13 : *ppszDstText = CPLStrdup("MULTIPOINT EMPTY");
124 13 : return OGRERR_NONE;
125 : }
126 :
127 28 : *ppszDstText = (char *) VSIMalloc( nMaxString );
128 28 : if( *ppszDstText == NULL )
129 0 : return OGRERR_NOT_ENOUGH_MEMORY;
130 :
131 28 : sprintf( *ppszDstText, "%s (", getGeometryName() );
132 :
133 28 : int bMustWriteComma = FALSE;
134 99 : for( int i = 0; i < getNumGeometries(); i++ )
135 : {
136 71 : OGRPoint *poPoint = (OGRPoint *) getGeometryRef( i );
137 :
138 71 : if (poPoint->IsEmpty())
139 : {
140 7 : CPLDebug( "OGR", "OGRMultiPoint::exportToWkt() - skipping POINT EMPTY.");
141 7 : continue;
142 : }
143 :
144 64 : if( bMustWriteComma )
145 36 : strcat( *ppszDstText + nRetLen, "," );
146 64 : bMustWriteComma = TRUE;
147 :
148 64 : nRetLen += strlen(*ppszDstText + nRetLen);
149 :
150 64 : 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 64 : poPoint->getCoordinateDimension() );
161 : }
162 :
163 28 : strcat( *ppszDstText+nRetLen, ")" );
164 :
165 28 : return OGRERR_NONE;
166 : }
167 :
168 : /************************************************************************/
169 : /* importFromWkt() */
170 : /************************************************************************/
171 :
172 85 : OGRErr OGRMultiPoint::importFromWkt( char ** ppszInput )
173 :
174 : {
175 :
176 : char szToken[OGR_WKT_TOKEN_MAX];
177 85 : const char *pszInput = *ppszInput;
178 : int iGeom;
179 85 : OGRErr eErr = OGRERR_NONE;
180 :
181 : /* -------------------------------------------------------------------- */
182 : /* Clear existing Geoms. */
183 : /* -------------------------------------------------------------------- */
184 85 : empty();
185 :
186 : /* -------------------------------------------------------------------- */
187 : /* Read and verify the type keyword, and ensure it matches the */
188 : /* actual type of this container. */
189 : /* -------------------------------------------------------------------- */
190 85 : pszInput = OGRWktReadToken( pszInput, szToken );
191 :
192 85 : if( !EQUAL(szToken,getGeometryName()) )
193 0 : return OGRERR_CORRUPT_DATA;
194 :
195 :
196 : /* -------------------------------------------------------------------- */
197 : /* Check for EMPTY ... */
198 : /* -------------------------------------------------------------------- */
199 : const char *pszPreScan;
200 85 : int bHasZ = FALSE, bHasM = FALSE;
201 :
202 85 : pszPreScan = OGRWktReadToken( pszInput, szToken );
203 85 : if( EQUAL(szToken,"EMPTY") )
204 : {
205 9 : *ppszInput = (char *) pszPreScan;
206 9 : empty();
207 9 : return OGRERR_NONE;
208 : }
209 :
210 : /* -------------------------------------------------------------------- */
211 : /* Check for Z, M or ZM. Will ignore the Measure */
212 : /* -------------------------------------------------------------------- */
213 76 : else if( EQUAL(szToken,"Z") )
214 : {
215 13 : bHasZ = TRUE;
216 : }
217 63 : else if( EQUAL(szToken,"M") )
218 : {
219 2 : bHasM = TRUE;
220 : }
221 61 : else if( EQUAL(szToken,"ZM") )
222 : {
223 2 : bHasZ = TRUE;
224 2 : bHasM = TRUE;
225 : }
226 :
227 76 : 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 72 : if( !EQUAL(szToken,"(") )
242 4 : return OGRERR_CORRUPT_DATA;
243 :
244 68 : if ( !bHasZ && !bHasM )
245 : {
246 : /* Test for old-style MULTIPOINT(EMPTY) */
247 57 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
248 57 : 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 64 : pszPreScan = OGRWktReadToken( pszInput, szToken );
268 64 : OGRWktReadToken( pszPreScan, szToken );
269 :
270 : // Do we have an inner bracket?
271 64 : if (EQUAL(szToken,"(") || EQUAL(szToken, "EMPTY") )
272 22 : return importFromWkt_Bracketed( ppszInput, bHasM, bHasZ );
273 :
274 42 : 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 37 : int nMaxPoint = 0;
283 37 : int nPointCount = 0;
284 37 : OGRRawPoint *paoPoints = NULL;
285 37 : double *padfZ = NULL;
286 :
287 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoint,
288 37 : &nPointCount );
289 37 : if( pszInput == NULL )
290 7 : return OGRERR_CORRUPT_DATA;
291 :
292 : /* -------------------------------------------------------------------- */
293 : /* Transform raw points into point objects. */
294 : /* -------------------------------------------------------------------- */
295 98 : for( iGeom = 0; iGeom < nPointCount && eErr == OGRERR_NONE; iGeom++ )
296 : {
297 : OGRGeometry *poGeom;
298 68 : if( padfZ )
299 : poGeom = new OGRPoint( paoPoints[iGeom].x,
300 : paoPoints[iGeom].y,
301 23 : padfZ[iGeom] );
302 : else
303 : poGeom = new OGRPoint( paoPoints[iGeom].x,
304 45 : paoPoints[iGeom].y );
305 :
306 68 : eErr = addGeometryDirectly( poGeom );
307 : }
308 :
309 30 : OGRFree( paoPoints );
310 30 : if( padfZ )
311 10 : OGRFree( padfZ );
312 :
313 30 : if( eErr != OGRERR_NONE )
314 0 : return eErr;
315 :
316 30 : *ppszInput = (char *) pszInput;
317 :
318 30 : return OGRERR_NONE;
319 : }
320 :
321 :
322 : /************************************************************************/
323 : /* importFromWkt_Bracketed() */
324 : /* */
325 : /* This operates similar to importFromWkt(), but reads a format */
326 : /* with brackets around each point. This is the form defined */
327 : /* in the BNF of the SFSQL spec. It is called from */
328 : /* importFromWkt(). */
329 : /************************************************************************/
330 :
331 22 : OGRErr OGRMultiPoint::importFromWkt_Bracketed( char ** ppszInput, int bHasM, int bHasZ )
332 :
333 : {
334 :
335 : char szToken[OGR_WKT_TOKEN_MAX];
336 22 : const char *pszInput = *ppszInput;
337 22 : OGRErr eErr = OGRERR_NONE;
338 :
339 : /* -------------------------------------------------------------------- */
340 : /* Skip MULTIPOINT keyword. */
341 : /* -------------------------------------------------------------------- */
342 22 : pszInput = OGRWktReadToken( pszInput, szToken );
343 :
344 22 : if (bHasZ || bHasM)
345 : {
346 : /* Skip Z, M or ZM */
347 6 : pszInput = OGRWktReadToken( pszInput, szToken );
348 : }
349 :
350 : /* -------------------------------------------------------------------- */
351 : /* Read points till we get to the closing bracket. */
352 : /* -------------------------------------------------------------------- */
353 22 : int nMaxPoint = 0;
354 22 : int nPointCount = 0;
355 22 : OGRRawPoint *paoPoints = NULL;
356 22 : double *padfZ = NULL;
357 :
358 86 : while( (pszInput = OGRWktReadToken( pszInput, szToken ))
359 : && (EQUAL(szToken,"(") || EQUAL(szToken,",")) )
360 : {
361 : OGRGeometry *poGeom;
362 :
363 45 : const char* pszNext = OGRWktReadToken( pszInput, szToken );
364 45 : if (EQUAL(szToken,"EMPTY"))
365 : {
366 11 : poGeom = new OGRPoint(0,0);
367 11 : poGeom->empty();
368 11 : eErr = addGeometryDirectly( poGeom );
369 11 : if( eErr != OGRERR_NONE )
370 0 : return eErr;
371 :
372 11 : pszInput = pszNext;
373 :
374 11 : continue;
375 : }
376 :
377 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoint,
378 34 : &nPointCount );
379 :
380 34 : if( pszInput == NULL || nPointCount != 1 )
381 3 : return OGRERR_CORRUPT_DATA;
382 :
383 : /* Ignore Z array when we have a MULTIPOINT M */
384 35 : if( padfZ && !(bHasM && !bHasZ))
385 : poGeom = new OGRPoint( paoPoints[0].x,
386 : paoPoints[0].y,
387 4 : padfZ[0] );
388 : else
389 : poGeom = new OGRPoint( paoPoints[0].x,
390 27 : paoPoints[0].y );
391 :
392 31 : eErr = addGeometryDirectly( poGeom );
393 31 : if( eErr != OGRERR_NONE )
394 0 : return eErr;
395 : }
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* Cleanup. */
399 : /* -------------------------------------------------------------------- */
400 19 : OGRFree( paoPoints );
401 19 : if( padfZ )
402 3 : OGRFree( padfZ );
403 :
404 19 : if( !EQUAL(szToken,")") )
405 6 : return OGRERR_CORRUPT_DATA;
406 :
407 13 : *ppszInput = (char *) pszInput;
408 :
409 13 : return OGRERR_NONE;
410 : }
411 :
412 :
|