Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: The OGRMultiSurface class.
5 : * Author: Even Rouault <even dot rouault at spatialys dot com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_port.h"
30 : #include "ogr_geometry.h"
31 :
32 : #include <cstddef>
33 :
34 : #include "cpl_conv.h"
35 : #include "cpl_error.h"
36 : #include "ogr_api.h"
37 : #include "ogr_core.h"
38 : #include "ogr_p.h"
39 :
40 : /************************************************************************/
41 : /* OGRMultiSurface() */
42 : /************************************************************************/
43 :
44 : /**
45 : * \brief Create an empty multi surface collection.
46 : */
47 :
48 : OGRMultiSurface::OGRMultiSurface() = default;
49 :
50 : /************************************************************************/
51 : /* ~OGRMultiSurface() */
52 : /************************************************************************/
53 :
54 : OGRMultiSurface::~OGRMultiSurface() = default;
55 :
56 : /************************************************************************/
57 : /* OGRMultiSurface( const OGRMultiSurface& ) */
58 : /************************************************************************/
59 :
60 : /**
61 : * \brief Copy constructor.
62 : *
63 : * Note: before GDAL 2.1, only the default implementation of the constructor
64 : * existed, which could be unsafe to use.
65 : *
66 : * @since GDAL 2.1
67 : */
68 :
69 : OGRMultiSurface::OGRMultiSurface(const OGRMultiSurface &) = default;
70 :
71 : /************************************************************************/
72 : /* operator=( const OGRMultiCurve&) */
73 : /************************************************************************/
74 :
75 : /**
76 : * \brief Assignment operator.
77 : *
78 : * Note: before GDAL 2.1, only the default implementation of the operator
79 : * existed, which could be unsafe to use.
80 : *
81 : * @since GDAL 2.1
82 : */
83 :
84 13 : OGRMultiSurface &OGRMultiSurface::operator=(const OGRMultiSurface &other)
85 : {
86 13 : if (this != &other)
87 : {
88 12 : OGRGeometryCollection::operator=(other);
89 : }
90 13 : return *this;
91 : }
92 :
93 : /************************************************************************/
94 : /* clone() */
95 : /************************************************************************/
96 :
97 123 : OGRMultiSurface *OGRMultiSurface::clone() const
98 :
99 : {
100 123 : return new (std::nothrow) OGRMultiSurface(*this);
101 : }
102 :
103 : /************************************************************************/
104 : /* getGeometryType() */
105 : /************************************************************************/
106 :
107 3776 : OGRwkbGeometryType OGRMultiSurface::getGeometryType() const
108 :
109 : {
110 3776 : if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
111 3031 : return wkbMultiSurfaceZM;
112 745 : else if (flags & OGR_G_MEASURED)
113 13 : return wkbMultiSurfaceM;
114 732 : else if (flags & OGR_G_3D)
115 93 : return wkbMultiSurfaceZ;
116 : else
117 639 : return wkbMultiSurface;
118 : }
119 :
120 : /************************************************************************/
121 : /* getDimension() */
122 : /************************************************************************/
123 :
124 8 : int OGRMultiSurface::getDimension() const
125 :
126 : {
127 8 : return 2;
128 : }
129 :
130 : /************************************************************************/
131 : /* getGeometryName() */
132 : /************************************************************************/
133 :
134 399 : const char *OGRMultiSurface::getGeometryName() const
135 :
136 : {
137 399 : return "MULTISURFACE";
138 : }
139 :
140 : /************************************************************************/
141 : /* isCompatibleSubType() */
142 : /************************************************************************/
143 :
144 : OGRBoolean
145 1378 : OGRMultiSurface::isCompatibleSubType(OGRwkbGeometryType eGeomType) const
146 : {
147 1378 : OGRwkbGeometryType eFlattenGeomType = wkbFlatten(eGeomType);
148 1378 : return eFlattenGeomType == wkbPolygon ||
149 1378 : eFlattenGeomType == wkbCurvePolygon;
150 : }
151 :
152 : /************************************************************************/
153 : /* importFromWkt() */
154 : /* */
155 : /* Instantiate from well known text format. */
156 : /************************************************************************/
157 :
158 1091 : OGRErr OGRMultiSurface::importFromWkt(const char **ppszInput)
159 :
160 : {
161 1091 : int bHasZ = FALSE;
162 1091 : int bHasM = FALSE;
163 1091 : bool bIsEmpty = false;
164 1091 : OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
165 1091 : flags = 0;
166 1091 : if (eErr != OGRERR_NONE)
167 5 : return eErr;
168 1086 : if (bHasZ)
169 179 : flags |= OGR_G_3D;
170 1086 : if (bHasM)
171 107 : flags |= OGR_G_MEASURED;
172 1086 : if (bIsEmpty)
173 61 : return OGRERR_NONE;
174 :
175 1025 : char szToken[OGR_WKT_TOKEN_MAX] = {};
176 1025 : const char *pszInput = *ppszInput;
177 1025 : eErr = OGRERR_NONE;
178 :
179 : // Skip first '('.
180 1025 : pszInput = OGRWktReadToken(pszInput, szToken);
181 :
182 : /* ==================================================================== */
183 : /* Read each surface in turn. Note that we try to reuse the same */
184 : /* point list buffer from ring to ring to cut down on */
185 : /* allocate/deallocate overhead. */
186 : /* ==================================================================== */
187 1025 : OGRRawPoint *paoPoints = nullptr;
188 1025 : int nMaxPoints = 0;
189 1025 : double *padfZ = nullptr;
190 :
191 315 : do
192 : {
193 : /* --------------------------------------------------------------------
194 : */
195 : /* Get the first token, which should be the geometry type. */
196 : /* --------------------------------------------------------------------
197 : */
198 1340 : const char *pszInputBefore = pszInput;
199 1340 : pszInput = OGRWktReadToken(pszInput, szToken);
200 :
201 1340 : OGRSurface *poSurface = nullptr;
202 :
203 : /* --------------------------------------------------------------------
204 : */
205 : /* Do the import. */
206 : /* --------------------------------------------------------------------
207 : */
208 1340 : if (EQUAL(szToken, "("))
209 : {
210 1226 : OGRPolygon *poPolygon = new OGRPolygon();
211 1226 : poSurface = poPolygon;
212 1226 : pszInput = pszInputBefore;
213 1226 : eErr = poPolygon->importFromWKTListOnly(
214 1226 : &pszInput, bHasZ, bHasM, paoPoints, nMaxPoints, padfZ);
215 : }
216 114 : else if (EQUAL(szToken, "EMPTY"))
217 : {
218 8 : poSurface = new OGRPolygon();
219 : }
220 : // We accept POLYGON() but this is an extension to the BNF, also
221 : // accepted by PostGIS.
222 106 : else if (STARTS_WITH_CI(szToken, "POLYGON") ||
223 102 : STARTS_WITH_CI(szToken, "CURVEPOLYGON"))
224 : {
225 91 : OGRGeometry *poGeom = nullptr;
226 91 : pszInput = pszInputBefore;
227 : eErr =
228 91 : OGRGeometryFactory::createFromWkt(&pszInput, nullptr, &poGeom);
229 91 : if (poGeom == nullptr)
230 : {
231 1 : eErr = OGRERR_CORRUPT_DATA;
232 1 : break;
233 : }
234 90 : poSurface = poGeom->toSurface();
235 : }
236 : else
237 : {
238 15 : CPLError(CE_Failure, CPLE_AppDefined, "Unexpected token : %s",
239 : szToken);
240 15 : eErr = OGRERR_CORRUPT_DATA;
241 15 : break;
242 : }
243 :
244 1324 : if (eErr == OGRERR_NONE)
245 1310 : eErr = addGeometryDirectly(poSurface);
246 1324 : if (eErr != OGRERR_NONE)
247 : {
248 14 : delete poSurface;
249 14 : break;
250 : }
251 :
252 : /* --------------------------------------------------------------------
253 : */
254 : /* Read the delimiter following the surface. */
255 : /* --------------------------------------------------------------------
256 : */
257 1310 : pszInput = OGRWktReadToken(pszInput, szToken);
258 1310 : } while (szToken[0] == ',' && eErr == OGRERR_NONE);
259 :
260 1025 : CPLFree(paoPoints);
261 1025 : CPLFree(padfZ);
262 :
263 : /* -------------------------------------------------------------------- */
264 : /* freak if we don't get a closing bracket. */
265 : /* -------------------------------------------------------------------- */
266 :
267 1025 : if (eErr != OGRERR_NONE)
268 30 : return eErr;
269 :
270 995 : if (szToken[0] != ')')
271 3 : return OGRERR_CORRUPT_DATA;
272 :
273 992 : *ppszInput = pszInput;
274 992 : return OGRERR_NONE;
275 : }
276 :
277 : /************************************************************************/
278 : /* exportToWkt() */
279 : /************************************************************************/
280 :
281 74 : std::string OGRMultiSurface::exportToWkt(const OGRWktOptions &opts,
282 : OGRErr *err) const
283 : {
284 74 : OGRWktOptions optsModified(opts);
285 74 : optsModified.variant = wkbVariantIso;
286 74 : return exportToWktInternal(optsModified, err, "POLYGON");
287 : }
288 :
289 : /************************************************************************/
290 : /* hasCurveGeometry() */
291 : /************************************************************************/
292 :
293 1192 : OGRBoolean OGRMultiSurface::hasCurveGeometry(int bLookForNonLinear) const
294 : {
295 1192 : if (bLookForNonLinear)
296 11 : return OGRGeometryCollection::hasCurveGeometry(TRUE);
297 1181 : return TRUE;
298 : }
299 :
300 : /************************************************************************/
301 : /* PointOnSurface() */
302 : /************************************************************************/
303 :
304 : /** \brief This method relates to the SFCOM
305 : * IMultiSurface::get_PointOnSurface() method.
306 : *
307 : * NOTE: Only implemented when GEOS included in build.
308 : *
309 : * @param poPoint point to be set with an internal point.
310 : *
311 : * @return OGRERR_NONE if it succeeds or OGRERR_FAILURE otherwise.
312 : */
313 :
314 0 : OGRErr OGRMultiSurface::PointOnSurface(OGRPoint *poPoint) const
315 : {
316 0 : return PointOnSurfaceInternal(poPoint);
317 : }
318 :
319 : /************************************************************************/
320 : /* CastToMultiPolygon() */
321 : /************************************************************************/
322 :
323 : /**
324 : * \brief Cast to multipolygon.
325 : *
326 : * This method should only be called if the multisurface actually only contains
327 : * instances of OGRPolygon. This can be verified if hasCurveGeometry(TRUE)
328 : * returns FALSE. It is not intended to approximate curve polygons. For that
329 : * use getLinearGeometry().
330 : *
331 : * The passed in geometry is consumed and a new one returned (or NULL in case
332 : * of failure).
333 : *
334 : * @param poMS the input geometry - ownership is passed to the method.
335 : * @return new geometry.
336 : */
337 :
338 58 : OGRMultiPolygon *OGRMultiSurface::CastToMultiPolygon(OGRMultiSurface *poMS)
339 : {
340 118 : for (auto &&poSubGeom : *poMS)
341 : {
342 60 : poSubGeom = OGRSurface::CastToPolygon(poSubGeom);
343 60 : if (poSubGeom == nullptr)
344 : {
345 0 : delete poMS;
346 0 : return nullptr;
347 : }
348 : }
349 :
350 58 : OGRMultiPolygon *poMP = new OGRMultiPolygon();
351 58 : TransferMembersAndDestroy(poMS, poMP);
352 58 : return poMP;
353 : }
|