1 /******************************************************************************
2 * $Id: ogrmultisurface.cpp 27960 2014-11-14 18:31:32Z rouault $
3 *
4 * Project: OpenGIS Simple Features Reference Implementation
5 * Purpose: The OGRMultiSurface class.
6 * Author: Even Rouault <even dot rouault at spatialys dot com>
7 *
8 ******************************************************************************
9 * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
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 "ogr_api.h"
33
34 CPL_CVSID("$Id: ogrmultisurface.cpp 27960 2014-11-14 18:31:32Z rouault $");
35
36 /************************************************************************/
37 /* OGRMultiSurface() */
38 /************************************************************************/
39
40 /**
41 * \brief Create an empty multi surface collection.
42 */
43
OGRMultiSurface()44 OGRMultiSurface::OGRMultiSurface()
45 {
46 }
47
48 /************************************************************************/
49 /* ~OGRMultiSurface() */
50 /************************************************************************/
51
~OGRMultiSurface()52 OGRMultiSurface::~OGRMultiSurface()
53 {
54 }
55
56 /************************************************************************/
57 /* getGeometryType() */
58 /************************************************************************/
59
getGeometryType() const60 OGRwkbGeometryType OGRMultiSurface::getGeometryType() const
61
62 {
63 if( getCoordinateDimension() == 3 )
64 return wkbMultiSurfaceZ;
65 else
66 return wkbMultiSurface;
67 }
68
69 /************************************************************************/
70 /* getDimension() */
71 /************************************************************************/
72
getDimension() const73 int OGRMultiSurface::getDimension() const
74
75 {
76 return 2;
77 }
78
79 /************************************************************************/
80 /* getGeometryName() */
81 /************************************************************************/
82
getGeometryName() const83 const char * OGRMultiSurface::getGeometryName() const
84
85 {
86 return "MULTISURFACE";
87 }
88
89 /************************************************************************/
90 /* isCompatibleSubType() */
91 /************************************************************************/
92
isCompatibleSubType(OGRwkbGeometryType eGeomType) const93 OGRBoolean OGRMultiSurface::isCompatibleSubType( OGRwkbGeometryType eGeomType ) const
94 {
95 return OGR_GT_IsSurface(eGeomType);
96 }
97
98 /************************************************************************/
99 /* importFromWkt() */
100 /* */
101 /* Instantiate from well known text format. */
102 /************************************************************************/
103
importFromWkt(char ** ppszInput)104 OGRErr OGRMultiSurface::importFromWkt( char ** ppszInput )
105
106 {
107 int bHasZ = FALSE, bHasM = FALSE;
108 OGRErr eErr = importPreambuleFromWkt(ppszInput, &bHasZ, &bHasM);
109 if( eErr >= 0 )
110 return eErr;
111
112 if( bHasZ )
113 setCoordinateDimension(3);
114
115 int bIsMultiSurface = (wkbFlatten(getGeometryType()) == wkbMultiSurface);
116
117 char szToken[OGR_WKT_TOKEN_MAX];
118 const char *pszInput = *ppszInput;
119 eErr = OGRERR_NONE;
120
121 /* Skip first '(' */
122 pszInput = OGRWktReadToken( pszInput, szToken );
123
124 /* ==================================================================== */
125 /* Read each surface in turn. Note that we try to reuse the same */
126 /* point list buffer from ring to ring to cut down on */
127 /* allocate/deallocate overhead. */
128 /* ==================================================================== */
129 OGRRawPoint *paoPoints = NULL;
130 int nMaxPoints = 0;
131 double *padfZ = NULL;
132
133 do
134 {
135
136 /* -------------------------------------------------------------------- */
137 /* Get the first token, which should be the geometry type. */
138 /* -------------------------------------------------------------------- */
139 const char* pszInputBefore = pszInput;
140 pszInput = OGRWktReadToken( pszInput, szToken );
141
142 OGRSurface* poSurface;
143
144 /* -------------------------------------------------------------------- */
145 /* Do the import. */
146 /* -------------------------------------------------------------------- */
147 if (EQUAL(szToken,"("))
148 {
149 OGRPolygon *poPolygon = new OGRPolygon();
150 poSurface = poPolygon;
151 pszInput = pszInputBefore;
152 eErr = poPolygon->importFromWKTListOnly( (char**)&pszInput, bHasZ, bHasM,
153 paoPoints, nMaxPoints, padfZ );
154 }
155 else if (EQUAL(szToken, "EMPTY") )
156 {
157 poSurface = new OGRPolygon();
158 }
159 /* We accept POLYGON() but this is an extension to the BNF, also */
160 /* accepted by PostGIS */
161 else if (bIsMultiSurface &&
162 (EQUAL(szToken,"POLYGON") ||
163 EQUAL(szToken,"CURVEPOLYGON")))
164 {
165 OGRGeometry* poGeom = NULL;
166 pszInput = pszInputBefore;
167 eErr = OGRGeometryFactory::createFromWkt( (char **) &pszInput,
168 NULL, &poGeom );
169 poSurface = (OGRSurface*) poGeom;
170 }
171 else
172 {
173 CPLError(CE_Failure, CPLE_AppDefined, "Unexpected token : %s", szToken);
174 eErr = OGRERR_CORRUPT_DATA;
175 break;
176 }
177
178 if( eErr == OGRERR_NONE )
179 eErr = addGeometryDirectly( poSurface );
180 if( eErr != OGRERR_NONE )
181 {
182 delete poSurface;
183 break;
184 }
185
186 /* -------------------------------------------------------------------- */
187 /* Read the delimeter following the surface. */
188 /* -------------------------------------------------------------------- */
189 pszInput = OGRWktReadToken( pszInput, szToken );
190
191 } while( szToken[0] == ',' && eErr == OGRERR_NONE );
192
193 CPLFree( paoPoints );
194 CPLFree( padfZ );
195
196 /* -------------------------------------------------------------------- */
197 /* freak if we don't get a closing bracket. */
198 /* -------------------------------------------------------------------- */
199
200 if( eErr != OGRERR_NONE )
201 return eErr;
202
203 if( szToken[0] != ')' )
204 return OGRERR_CORRUPT_DATA;
205
206 *ppszInput = (char *) pszInput;
207 return OGRERR_NONE;
208 }
209
210 /************************************************************************/
211 /* exportToWkt() */
212 /************************************************************************/
213
exportToWkt(char ** ppszDstText,CPL_UNUSED OGRwkbVariant eWkbVariant) const214 OGRErr OGRMultiSurface::exportToWkt( char ** ppszDstText,
215 CPL_UNUSED OGRwkbVariant eWkbVariant ) const
216
217 {
218 return exportToWktInternal( ppszDstText, wkbVariantIso, "POLYGON" );
219 }
220
221 /************************************************************************/
222 /* hasCurveGeometry() */
223 /************************************************************************/
224
hasCurveGeometry(int bLookForNonLinear) const225 OGRBoolean OGRMultiSurface::hasCurveGeometry(int bLookForNonLinear) const
226 {
227 if( bLookForNonLinear )
228 return OGRGeometryCollection::hasCurveGeometry(TRUE);
229 return TRUE;
230 }
231
232 /************************************************************************/
233 /* PointOnSurface() */
234 /************************************************************************/
235
236 /** \brief This method relates to the SFCOM IMultiSurface::get_PointOnSurface() method.
237 *
238 * NOTE: Only implemented when GEOS included in build.
239 *
240 * @param poPoint point to be set with an internal point.
241 *
242 * @return OGRERR_NONE if it succeeds or OGRERR_FAILURE otherwise.
243 */
244
PointOnSurface(OGRPoint * poPoint) const245 OGRErr OGRMultiSurface::PointOnSurface( OGRPoint * poPoint ) const
246 {
247 OGRMultiPolygon* poMPoly = (OGRMultiPolygon*) getLinearGeometry();
248 OGRErr ret = poMPoly->PointOnSurface(poPoint);
249 delete poMPoly;
250 return ret;
251 }
252
253 /************************************************************************/
254 /* CastToMultiPolygon() */
255 /************************************************************************/
256
257 /**
258 * \brief Cast to multipolygon.
259 *
260 * This method should only be called if the multisurface actually only contains
261 * instances of OGRPolygon. This can be verified if hasCurveGeometry(TRUE)
262 * returns FALSE. It is not intended to approximate curve polygons. For that
263 * use getLinearGeometry().
264 *
265 * The passed in geometry is consumed and a new one returned (or NULL in case
266 * of failure).
267 *
268 * @param poMS the input geometry - ownership is passed to the method.
269 * @return new geometry.
270 */
271
CastToMultiPolygon(OGRMultiSurface * poMS)272 OGRMultiPolygon* OGRMultiSurface::CastToMultiPolygon(OGRMultiSurface* poMS)
273 {
274 for(int i=0;i<poMS->nGeomCount;i++)
275 {
276 poMS->papoGeoms[i] = OGRSurface::CastToPolygon( (OGRSurface*)poMS->papoGeoms[i] );
277 if( poMS->papoGeoms[i] == NULL )
278 {
279 delete poMS;
280 return NULL;
281 }
282 }
283 return (OGRMultiPolygon*) TransferMembersAndDestroy(poMS, new OGRMultiPolygon());
284 }
285