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