1 : /******************************************************************************
2 : * $Id: ogrgeomediageometry.cpp 24656 2012-07-03 17:35:34Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements decoder of geomedia geometry blobs
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2011, Even Rouault, <even dot rouault at mines dash paris dot org>
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 "ogrgeomediageometry.h"
31 : #include "cpl_string.h"
32 :
33 : CPL_CVSID("$Id: ogrgeomediageometry.cpp 24656 2012-07-03 17:35:34Z rouault $");
34 :
35 : #define GEOMEDIA_POINT 0xC0
36 : #define GEOMEDIA_ORIENTED_POINT 0xC8
37 : #define GEOMEDIA_POLYLINE 0xC2
38 : #define GEOMEDIA_POLYGON 0xC3
39 : #define GEOMEDIA_BOUNDARY 0xC5
40 : #define GEOMEDIA_COLLECTION 0xC6
41 : #define GEOMEDIA_MULTILINE 0xCB
42 : #define GEOMEDIA_MULTIPOLYGON 0xCC
43 :
44 : /************************************************************************/
45 : /* OGRCreateFromGeomedia() */
46 : /************************************************************************/
47 :
48 0 : OGRErr OGRCreateFromGeomedia( GByte *pabyGeom,
49 : OGRGeometry **ppoGeom,
50 : int nBytes )
51 :
52 : {
53 0 : *ppoGeom = NULL;
54 :
55 0 : if( nBytes < 16 )
56 0 : return OGRERR_FAILURE;
57 :
58 0 : if( !(pabyGeom[1] == 0xFF && pabyGeom[2] == 0xD2 && pabyGeom[3] == 0x0F) )
59 0 : return OGRERR_FAILURE;
60 :
61 0 : int nGeomType = pabyGeom[0];
62 0 : pabyGeom += 16;
63 0 : nBytes -= 16;
64 :
65 0 : if( nGeomType == GEOMEDIA_POINT ||
66 : nGeomType == GEOMEDIA_ORIENTED_POINT )
67 : {
68 0 : if (nBytes < 3 * 8)
69 0 : return OGRERR_FAILURE;
70 :
71 : double dfX, dfY, dfZ;
72 0 : memcpy(&dfX, pabyGeom, 8);
73 : CPL_LSBPTR64(&dfX);
74 0 : memcpy(&dfY, pabyGeom + 8, 8);
75 : CPL_LSBPTR64(&dfY);
76 0 : memcpy(&dfZ, pabyGeom + 16, 8);
77 : CPL_LSBPTR64(&dfZ);
78 :
79 0 : *ppoGeom = new OGRPoint( dfX, dfY, dfZ );
80 :
81 0 : return OGRERR_NONE;
82 : }
83 0 : else if ( nGeomType == GEOMEDIA_POLYLINE )
84 : {
85 0 : if (nBytes < 4)
86 0 : return OGRERR_FAILURE;
87 :
88 : int nPoints;
89 0 : memcpy(&nPoints, pabyGeom, 4);
90 : CPL_LSBPTR32(&nPoints);
91 :
92 0 : pabyGeom += 4;
93 0 : nBytes -= 4;
94 :
95 0 : if (nPoints < 0 || nPoints > INT_MAX / 24 || nBytes < nPoints * 24)
96 0 : return OGRERR_FAILURE;
97 :
98 0 : OGRLineString* poLS = new OGRLineString();
99 0 : poLS->setNumPoints(nPoints);
100 : int i;
101 0 : for(i=0;i<nPoints;i++)
102 : {
103 : double dfX, dfY, dfZ;
104 0 : memcpy(&dfX, pabyGeom, 8);
105 : CPL_LSBPTR64(&dfX);
106 0 : memcpy(&dfY, pabyGeom + 8, 8);
107 : CPL_LSBPTR64(&dfY);
108 0 : memcpy(&dfZ, pabyGeom + 16, 8);
109 : CPL_LSBPTR64(&dfZ);
110 :
111 0 : poLS->setPoint(i, dfX, dfY, dfZ);
112 :
113 0 : pabyGeom += 24;
114 : }
115 :
116 0 : *ppoGeom = poLS;
117 :
118 0 : return OGRERR_NONE;
119 : }
120 0 : else if ( nGeomType == GEOMEDIA_POLYGON )
121 : {
122 0 : if (nBytes < 4)
123 0 : return OGRERR_FAILURE;
124 :
125 : int nPoints;
126 0 : memcpy(&nPoints, pabyGeom, 4);
127 : CPL_LSBPTR32(&nPoints);
128 :
129 0 : pabyGeom += 4;
130 0 : nBytes -= 4;
131 :
132 0 : if (nPoints < 0 || nPoints > INT_MAX / 24 || nBytes < nPoints * 24)
133 0 : return OGRERR_FAILURE;
134 :
135 0 : OGRLinearRing* poRing = new OGRLinearRing();
136 0 : poRing->setNumPoints(nPoints);
137 : int i;
138 0 : for(i=0;i<nPoints;i++)
139 : {
140 : double dfX, dfY, dfZ;
141 0 : memcpy(&dfX, pabyGeom, 8);
142 : CPL_LSBPTR64(&dfX);
143 0 : memcpy(&dfY, pabyGeom + 8, 8);
144 : CPL_LSBPTR64(&dfY);
145 0 : memcpy(&dfZ, pabyGeom + 16, 8);
146 : CPL_LSBPTR64(&dfZ);
147 :
148 0 : poRing->setPoint(i, dfX, dfY, dfZ);
149 :
150 0 : pabyGeom += 24;
151 : }
152 :
153 0 : OGRPolygon* poPoly = new OGRPolygon();
154 0 : poPoly->addRingDirectly(poRing);
155 0 : *ppoGeom = poPoly;
156 :
157 0 : return OGRERR_NONE;
158 : }
159 0 : else if ( nGeomType == GEOMEDIA_BOUNDARY )
160 : {
161 0 : if (nBytes < 4)
162 0 : return OGRERR_FAILURE;
163 :
164 : int nExteriorSize;
165 0 : memcpy(&nExteriorSize, pabyGeom, 4);
166 : CPL_LSBPTR32(&nExteriorSize);
167 :
168 0 : pabyGeom += 4;
169 0 : nBytes -= 4;
170 :
171 0 : if (nBytes < nExteriorSize)
172 0 : return OGRERR_FAILURE;
173 :
174 0 : OGRGeometry* poExteriorGeom = NULL;
175 0 : if (OGRCreateFromGeomedia( pabyGeom, &poExteriorGeom, nExteriorSize ) != OGRERR_NONE)
176 0 : return OGRERR_FAILURE;
177 :
178 0 : if ( wkbFlatten( poExteriorGeom->getGeometryType() ) != wkbPolygon )
179 : {
180 0 : delete poExteriorGeom;
181 0 : return OGRERR_FAILURE;
182 : }
183 :
184 0 : pabyGeom += nExteriorSize;
185 0 : nBytes -= nExteriorSize;
186 :
187 0 : if (nBytes < 4)
188 : {
189 0 : delete poExteriorGeom;
190 0 : return OGRERR_FAILURE;
191 : }
192 :
193 : int nInteriorSize;
194 0 : memcpy(&nInteriorSize, pabyGeom, 4);
195 : CPL_LSBPTR32(&nInteriorSize);
196 :
197 0 : pabyGeom += 4;
198 0 : nBytes -= 4;
199 :
200 0 : if (nBytes < nInteriorSize)
201 : {
202 0 : delete poExteriorGeom;
203 0 : return OGRERR_FAILURE;
204 : }
205 :
206 0 : OGRGeometry* poInteriorGeom = NULL;
207 0 : if (OGRCreateFromGeomedia( pabyGeom, &poInteriorGeom, nInteriorSize ) != OGRERR_NONE)
208 : {
209 0 : delete poExteriorGeom;
210 0 : return OGRERR_FAILURE;
211 : }
212 :
213 0 : OGRwkbGeometryType interiorGeomType = wkbFlatten( poInteriorGeom->getGeometryType() );
214 0 : if ( interiorGeomType == wkbPolygon )
215 : {
216 0 : ((OGRPolygon*)poExteriorGeom)->addRing(((OGRPolygon*)poInteriorGeom)->getExteriorRing());
217 : }
218 0 : else if ( interiorGeomType == wkbMultiPolygon )
219 : {
220 0 : int numGeom = ((OGRMultiPolygon*)poInteriorGeom)->getNumGeometries();
221 0 : for ( int i = 0; i < numGeom; ++i )
222 : {
223 : OGRPolygon* poInteriorPolygon =
224 0 : (OGRPolygon*)((OGRMultiPolygon*)poInteriorGeom)->getGeometryRef(i);
225 0 : ((OGRPolygon*)poExteriorGeom)->addRing( poInteriorPolygon->getExteriorRing() );
226 : }
227 : }
228 : else
229 : {
230 0 : delete poExteriorGeom;
231 0 : delete poInteriorGeom;
232 0 : return OGRERR_FAILURE;
233 : }
234 :
235 0 : delete poInteriorGeom;
236 0 : *ppoGeom = poExteriorGeom;
237 :
238 0 : return OGRERR_NONE;
239 : }
240 0 : else if ( nGeomType == GEOMEDIA_COLLECTION ||
241 : nGeomType == GEOMEDIA_MULTILINE ||
242 : nGeomType == GEOMEDIA_MULTIPOLYGON )
243 : {
244 0 : if (nBytes < 4)
245 0 : return OGRERR_FAILURE;
246 :
247 : int i;
248 : int nParts;
249 0 : memcpy(&nParts, pabyGeom, 4);
250 : CPL_LSBPTR32(&nParts);
251 :
252 0 : pabyGeom += 4;
253 0 : nBytes -= 4;
254 :
255 0 : if (nParts < 0 || nParts > INT_MAX / (4 + 16) || nBytes < nParts * (4 + 16))
256 0 : return OGRERR_FAILURE;
257 :
258 : /* Can this collection be considered as a multipolyline or multipolygon ? */
259 0 : if ( nGeomType == GEOMEDIA_COLLECTION )
260 : {
261 0 : GByte* pabyGeomBackup = pabyGeom;
262 0 : int nBytesBackup = nBytes;
263 :
264 0 : int bAllPolyline = TRUE;
265 0 : int bAllPolygon = TRUE;
266 :
267 0 : for(i=0;i<nParts;i++)
268 : {
269 0 : if (nBytes < 4)
270 0 : return OGRERR_FAILURE;
271 : int nSubBytes;
272 0 : memcpy(&nSubBytes, pabyGeom, 4);
273 : CPL_LSBPTR32(&nSubBytes);
274 :
275 0 : if (nSubBytes < 0)
276 : {
277 0 : return OGRERR_FAILURE;
278 : }
279 :
280 0 : pabyGeom += 4;
281 0 : nBytes -= 4;
282 :
283 0 : if (nBytes < nSubBytes)
284 : {
285 0 : return OGRERR_FAILURE;
286 : }
287 :
288 0 : if( nSubBytes < 16 )
289 0 : return OGRERR_FAILURE;
290 :
291 0 : if( !(pabyGeom[1] == 0xFF && pabyGeom[2] == 0xD2 && pabyGeom[3] == 0x0F) )
292 0 : return OGRERR_FAILURE;
293 :
294 0 : int nSubGeomType = pabyGeom[0];
295 0 : if ( nSubGeomType != GEOMEDIA_POLYLINE )
296 0 : bAllPolyline = FALSE;
297 0 : if ( nSubGeomType != GEOMEDIA_POLYGON )
298 0 : bAllPolygon = FALSE;
299 :
300 0 : pabyGeom += nSubBytes;
301 0 : nBytes -= nSubBytes;
302 : }
303 :
304 0 : pabyGeom = pabyGeomBackup;
305 0 : nBytes = nBytesBackup;
306 :
307 0 : if (bAllPolyline)
308 0 : nGeomType = GEOMEDIA_MULTILINE;
309 0 : else if (bAllPolygon)
310 0 : nGeomType = GEOMEDIA_MULTIPOLYGON;
311 : }
312 :
313 : OGRGeometryCollection* poColl = (nGeomType == GEOMEDIA_MULTILINE) ? new OGRMultiLineString() :
314 : (nGeomType == GEOMEDIA_MULTIPOLYGON) ? new OGRMultiPolygon() :
315 0 : new OGRGeometryCollection();
316 :
317 0 : for(i=0;i<nParts;i++)
318 : {
319 0 : if (nBytes < 4)
320 0 : return OGRERR_FAILURE;
321 : int nSubBytes;
322 0 : memcpy(&nSubBytes, pabyGeom, 4);
323 : CPL_LSBPTR32(&nSubBytes);
324 :
325 0 : if (nSubBytes < 0)
326 : {
327 0 : delete poColl;
328 0 : return OGRERR_FAILURE;
329 : }
330 :
331 0 : pabyGeom += 4;
332 0 : nBytes -= 4;
333 :
334 0 : if (nBytes < nSubBytes)
335 : {
336 0 : delete poColl;
337 0 : return OGRERR_FAILURE;
338 : }
339 :
340 0 : OGRGeometry* poSubGeom = NULL;
341 0 : if (OGRCreateFromGeomedia( pabyGeom, &poSubGeom, nSubBytes ) == OGRERR_NONE)
342 : {
343 0 : if (wkbFlatten(poColl->getGeometryType()) == wkbMultiPolygon &&
344 0 : wkbFlatten(poSubGeom->getGeometryType()) == wkbLineString)
345 : {
346 0 : OGRPolygon* poPoly = new OGRPolygon();
347 0 : OGRLinearRing* poRing = new OGRLinearRing();
348 0 : poRing->addSubLineString((OGRLineString*)poSubGeom);
349 0 : poPoly->addRingDirectly(poRing);
350 0 : delete poSubGeom;
351 0 : poSubGeom = poPoly;
352 : }
353 :
354 0 : if (poColl->addGeometryDirectly(poSubGeom) != OGRERR_NONE)
355 : {
356 : //printf("%d %d\n", poColl->getGeometryType() & ~wkb25DBit, poSubGeom->getGeometryType() & ~wkb25DBit);
357 0 : delete poSubGeom;
358 : }
359 : }
360 :
361 0 : pabyGeom += nSubBytes;
362 0 : nBytes -= nSubBytes;
363 : }
364 :
365 0 : *ppoGeom = poColl;
366 :
367 0 : return OGRERR_NONE;
368 : }
369 : else
370 : {
371 0 : CPLDebug("GEOMEDIA", "Unhandled type %d", nGeomType);
372 : }
373 :
374 0 : return OGRERR_FAILURE;
375 : }
376 :
377 :
378 : /************************************************************************/
379 : /* OGRGetGeomediaSRS() */
380 : /************************************************************************/
381 :
382 0 : OGRSpatialReference* OGRGetGeomediaSRS(OGRFeature* poFeature)
383 : {
384 0 : if (poFeature == NULL)
385 0 : return NULL;
386 :
387 0 : int nGeodeticDatum = poFeature->GetFieldAsInteger("GeodeticDatum");
388 0 : int nEllipsoid = poFeature->GetFieldAsInteger("Ellipsoid");
389 0 : int nProjAlgorithm = poFeature->GetFieldAsInteger("ProjAlgorithm");
390 :
391 0 : if (nGeodeticDatum == 17 && nEllipsoid == 22)
392 : {
393 0 : if (nProjAlgorithm == 12)
394 : {
395 0 : OGRSpatialReference* poSRS = new OGRSpatialReference();
396 :
397 0 : const char* pszDescription = poFeature->GetFieldAsString("Description");
398 0 : if (pszDescription && pszDescription[0] != 0)
399 0 : poSRS->SetNode( "PROJCS", pszDescription );
400 0 : poSRS->SetWellKnownGeogCS("WGS84");
401 :
402 0 : double dfStdP1 = poFeature->GetFieldAsDouble("StandPar1");
403 0 : double dfStdP2 = poFeature->GetFieldAsDouble("StandPar2");
404 0 : double dfCenterLat = poFeature->GetFieldAsDouble("LatOfOrigin");
405 0 : double dfCenterLong = poFeature->GetFieldAsDouble("LonOfOrigin");
406 0 : double dfFalseEasting = poFeature->GetFieldAsDouble("FalseX");
407 0 : double dfFalseNorthing = poFeature->GetFieldAsDouble("FalseY");
408 : poSRS->SetACEA( dfStdP1, dfStdP2,
409 : dfCenterLat, dfCenterLong,
410 0 : dfFalseEasting, dfFalseNorthing );
411 0 : return poSRS;
412 : }
413 : }
414 :
415 0 : return NULL;
416 : }
|