1 : /******************************************************************************
2 : * $Id: ogrmultipoint.cpp 14336 2008-04-20 14:36:09Z 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 14336 2008-04-20 14:36:09Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRMultiPoint() */
38 : /************************************************************************/
39 :
40 100 : OGRMultiPoint::OGRMultiPoint()
41 : {
42 100 : }
43 :
44 : /************************************************************************/
45 : /* getGeometryType() */
46 : /************************************************************************/
47 :
48 268 : OGRwkbGeometryType OGRMultiPoint::getGeometryType() const
49 :
50 : {
51 268 : if( getCoordinateDimension() == 3 )
52 49 : return wkbMultiPoint25D;
53 : else
54 219 : return wkbMultiPoint;
55 : }
56 :
57 : /************************************************************************/
58 : /* getGeometryName() */
59 : /************************************************************************/
60 :
61 93 : const char * OGRMultiPoint::getGeometryName() const
62 :
63 : {
64 93 : 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 171 : OGRErr OGRMultiPoint::addGeometryDirectly( OGRGeometry * poNewGeom )
76 :
77 : {
78 213 : if( poNewGeom->getGeometryType() != wkbPoint
79 42 : && poNewGeom->getGeometryType() != wkbPoint25D )
80 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
81 :
82 171 : return OGRGeometryCollection::addGeometryDirectly( poNewGeom );
83 : }
84 :
85 : /************************************************************************/
86 : /* clone() */
87 : /************************************************************************/
88 :
89 30 : OGRGeometry *OGRMultiPoint::clone() const
90 :
91 : {
92 : OGRMultiPoint *poNewGC;
93 :
94 30 : poNewGC = new OGRMultiPoint;
95 30 : poNewGC->assignSpatialReference( getSpatialReference() );
96 :
97 96 : for( int i = 0; i < getNumGeometries(); i++ )
98 : {
99 66 : poNewGC->addGeometry( getGeometryRef(i) );
100 : }
101 :
102 30 : 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 23 : OGRErr OGRMultiPoint::exportToWkt( char ** ppszDstText ) const
113 :
114 : {
115 23 : int nMaxString = getNumGeometries() * 20 + 128;
116 23 : int nRetLen = 0;
117 :
118 : /* -------------------------------------------------------------------- */
119 : /* Return MULTIPOINT EMPTY if we get no valid points. */
120 : /* -------------------------------------------------------------------- */
121 23 : if( IsEmpty() )
122 : {
123 4 : *ppszDstText = CPLStrdup("MULTIPOINT EMPTY");
124 4 : return OGRERR_NONE;
125 : }
126 :
127 19 : *ppszDstText = (char *) VSIMalloc( nMaxString );
128 19 : if( *ppszDstText == NULL )
129 0 : return OGRERR_NOT_ENOUGH_MEMORY;
130 :
131 19 : sprintf( *ppszDstText, "%s (", getGeometryName() );
132 :
133 19 : int bMustWriteComma = FALSE;
134 71 : for( int i = 0; i < getNumGeometries(); i++ )
135 : {
136 52 : OGRPoint *poPoint = (OGRPoint *) getGeometryRef( i );
137 :
138 52 : if (poPoint->IsEmpty())
139 : {
140 3 : CPLDebug( "OGR", "OGRMultiPoint::exportToWkt() - skipping POINT EMPTY.");
141 3 : continue;
142 : }
143 :
144 49 : if( bMustWriteComma )
145 30 : strcat( *ppszDstText + nRetLen, "," );
146 49 : bMustWriteComma = TRUE;
147 :
148 49 : nRetLen += strlen(*ppszDstText + nRetLen);
149 :
150 49 : 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 49 : poPoint->getCoordinateDimension() );
161 : }
162 :
163 19 : strcat( *ppszDstText+nRetLen, ")" );
164 :
165 19 : return OGRERR_NONE;
166 : }
167 :
168 : /************************************************************************/
169 : /* importFromWkt() */
170 : /************************************************************************/
171 :
172 36 : OGRErr OGRMultiPoint::importFromWkt( char ** ppszInput )
173 :
174 : {
175 :
176 : char szToken[OGR_WKT_TOKEN_MAX];
177 36 : const char *pszInput = *ppszInput;
178 : int iGeom;
179 36 : OGRErr eErr = OGRERR_NONE;
180 :
181 : /* -------------------------------------------------------------------- */
182 : /* Clear existing Geoms. */
183 : /* -------------------------------------------------------------------- */
184 36 : empty();
185 :
186 : /* -------------------------------------------------------------------- */
187 : /* Read and verify the type keyword, and ensure it matches the */
188 : /* actual type of this container. */
189 : /* -------------------------------------------------------------------- */
190 36 : pszInput = OGRWktReadToken( pszInput, szToken );
191 :
192 36 : if( !EQUAL(szToken,getGeometryName()) )
193 0 : return OGRERR_CORRUPT_DATA;
194 :
195 : /* -------------------------------------------------------------------- */
196 : /* Skip past first bracket for checking purposes, but don't */
197 : /* alter pszInput. */
198 : /* -------------------------------------------------------------------- */
199 36 : const char *pszPreScan = pszInput;
200 :
201 : // skip white space.
202 72 : while( *pszPreScan == ' ' || *pszPreScan == '\t' )
203 0 : pszPreScan++;
204 :
205 : // Handle the proper EMPTY syntax.
206 36 : if( EQUALN(pszPreScan,"EMPTY",5) )
207 : {
208 5 : *ppszInput = (char *) pszPreScan+5;
209 5 : return OGRERR_NONE;
210 : }
211 :
212 : // Skip outer bracket.
213 31 : if( *pszPreScan != '(' )
214 0 : return OGRERR_CORRUPT_DATA;
215 :
216 31 : pszPreScan++;
217 :
218 : /* -------------------------------------------------------------------- */
219 : /* If the next token is EMPTY, then verify that we have proper */
220 : /* EMPTY format will a trailing closing bracket. */
221 : /* -------------------------------------------------------------------- */
222 31 : OGRWktReadToken( pszPreScan, szToken );
223 31 : if( EQUAL(szToken,"EMPTY") )
224 : {
225 1 : pszInput = OGRWktReadToken( pszPreScan, szToken );
226 1 : pszInput = OGRWktReadToken( pszInput, szToken );
227 :
228 1 : *ppszInput = (char *) pszInput;
229 :
230 1 : if( !EQUAL(szToken,")") )
231 0 : return OGRERR_CORRUPT_DATA;
232 : else
233 1 : return OGRERR_NONE;
234 : }
235 :
236 : /* -------------------------------------------------------------------- */
237 : /* Check for inner bracket indicating the improper bracketed */
238 : /* format which we still want to support. */
239 : /* -------------------------------------------------------------------- */
240 : // skip white space.
241 60 : while( *pszPreScan == ' ' || *pszPreScan == '\t' )
242 0 : pszPreScan++;
243 :
244 : // Do we have an inner bracket?
245 30 : if( *pszPreScan == '(' )
246 4 : return importFromWkt_Bracketed( ppszInput );
247 :
248 : /* -------------------------------------------------------------------- */
249 : /* Read the point list which should consist of exactly one point. */
250 : /* -------------------------------------------------------------------- */
251 26 : int nMaxPoint = 0;
252 26 : int nPointCount = 0;
253 26 : OGRRawPoint *paoPoints = NULL;
254 26 : double *padfZ = NULL;
255 :
256 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoint,
257 26 : &nPointCount );
258 26 : if( pszInput == NULL )
259 0 : return OGRERR_CORRUPT_DATA;
260 :
261 : /* -------------------------------------------------------------------- */
262 : /* Transform raw points into point objects. */
263 : /* -------------------------------------------------------------------- */
264 87 : for( iGeom = 0; iGeom < nPointCount && eErr == OGRERR_NONE; iGeom++ )
265 : {
266 : OGRGeometry *poGeom;
267 61 : if( padfZ )
268 20 : poGeom = new OGRPoint( paoPoints[iGeom].x,
269 20 : paoPoints[iGeom].y,
270 60 : padfZ[iGeom] );
271 : else
272 41 : poGeom = new OGRPoint( paoPoints[iGeom].x,
273 82 : paoPoints[iGeom].y );
274 :
275 61 : eErr = addGeometryDirectly( poGeom );
276 : }
277 :
278 26 : OGRFree( paoPoints );
279 26 : if( padfZ )
280 8 : OGRFree( padfZ );
281 :
282 26 : if( eErr != OGRERR_NONE )
283 0 : return eErr;
284 :
285 26 : *ppszInput = (char *) pszInput;
286 :
287 26 : return OGRERR_NONE;
288 : }
289 :
290 :
291 : /************************************************************************/
292 : /* importFromWkt_Bracketed() */
293 : /* */
294 : /* This operates similar to importFromWkt(), but reads a format */
295 : /* with brackets around each point. This is the form defined */
296 : /* in the BNF of the SFSQL spec. It is called from */
297 : /* importFromWkt(). */
298 : /************************************************************************/
299 :
300 4 : OGRErr OGRMultiPoint::importFromWkt_Bracketed( char ** ppszInput )
301 :
302 : {
303 :
304 : char szToken[OGR_WKT_TOKEN_MAX];
305 4 : const char *pszInput = *ppszInput;
306 4 : OGRErr eErr = OGRERR_NONE;
307 :
308 : /* -------------------------------------------------------------------- */
309 : /* Skip MULTIPOINT keyword. */
310 : /* -------------------------------------------------------------------- */
311 4 : pszInput = OGRWktReadToken( pszInput, szToken );
312 :
313 : /* -------------------------------------------------------------------- */
314 : /* Read points till we get to the closing bracket. */
315 : /* -------------------------------------------------------------------- */
316 4 : int nMaxPoint = 0;
317 4 : int nPointCount = 0;
318 4 : OGRRawPoint *paoPoints = NULL;
319 4 : double *padfZ = NULL;
320 :
321 19 : while( (pszInput = OGRWktReadToken( pszInput, szToken ))
322 : && (EQUAL(szToken,"(") || EQUAL(szToken,",")) )
323 : {
324 : OGRGeometry *poGeom;
325 :
326 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoint,
327 11 : &nPointCount );
328 :
329 11 : if( pszInput == NULL || nPointCount != 1 )
330 0 : return OGRERR_CORRUPT_DATA;
331 :
332 11 : if( padfZ )
333 0 : poGeom = new OGRPoint( paoPoints[0].x,
334 0 : paoPoints[0].y,
335 0 : padfZ[0] );
336 : else
337 11 : poGeom = new OGRPoint( paoPoints[0].x,
338 22 : paoPoints[0].y );
339 :
340 11 : eErr = addGeometryDirectly( poGeom );
341 11 : if( eErr != OGRERR_NONE )
342 0 : return eErr;
343 : }
344 :
345 : /* -------------------------------------------------------------------- */
346 : /* Cleanup. */
347 : /* -------------------------------------------------------------------- */
348 4 : OGRFree( paoPoints );
349 4 : if( padfZ )
350 0 : OGRFree( padfZ );
351 :
352 4 : if( !EQUAL(szToken,")") )
353 0 : return OGRERR_CORRUPT_DATA;
354 :
355 4 : *ppszInput = (char *) pszInput;
356 :
357 4 : return OGRERR_NONE;
358 : }
359 :
360 :
|