1 : /******************************************************************************
2 : * $Id: ogrgeomediageometry.cpp 21561 2011-01-23 12:22:58Z 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 21561 2011-01-23 12:22:58Z 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 (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 : if (poInteriorGeom->getGeometryType() == wkbPolygon)
214 : {
215 0 : ((OGRPolygon*)poExteriorGeom)->addRing(((OGRPolygon*)poInteriorGeom)->getExteriorRing());
216 0 : delete poInteriorGeom;
217 0 : *ppoGeom = poExteriorGeom;
218 : }
219 : else
220 : {
221 0 : delete poExteriorGeom;
222 0 : delete poInteriorGeom;
223 0 : return OGRERR_FAILURE;
224 : }
225 :
226 0 : return OGRERR_NONE;
227 : }
228 0 : else if ( nGeomType == GEOMEDIA_COLLECTION ||
229 : nGeomType == GEOMEDIA_MULTILINE ||
230 : nGeomType == GEOMEDIA_MULTIPOLYGON )
231 : {
232 0 : if (nBytes < 4)
233 0 : return OGRERR_FAILURE;
234 :
235 : int i;
236 : int nParts;
237 0 : memcpy(&nParts, pabyGeom, 4);
238 : CPL_LSBPTR32(&nParts);
239 :
240 0 : pabyGeom += 4;
241 0 : nBytes -= 4;
242 :
243 0 : if (nParts < 0 || nParts > INT_MAX / (4 + 16) || nBytes < nParts * (4 + 16))
244 0 : return OGRERR_FAILURE;
245 :
246 : /* Can this collection be considered as a multipolyline or multipolygon ? */
247 0 : if ( nGeomType == GEOMEDIA_COLLECTION )
248 : {
249 0 : GByte* pabyGeomBackup = pabyGeom;
250 0 : int nBytesBackup = nBytes;
251 :
252 0 : int bAllPolyline = TRUE;
253 0 : int bAllPolygon = TRUE;
254 :
255 0 : for(i=0;i<nParts;i++)
256 : {
257 0 : if (nBytes < 4)
258 0 : return OGRERR_FAILURE;
259 : int nSubBytes;
260 0 : memcpy(&nSubBytes, pabyGeom, 4);
261 : CPL_LSBPTR32(&nSubBytes);
262 :
263 0 : if (nSubBytes < 0)
264 : {
265 0 : return OGRERR_FAILURE;
266 : }
267 :
268 0 : pabyGeom += 4;
269 0 : nBytes -= 4;
270 :
271 0 : if (nBytes < nSubBytes)
272 : {
273 0 : return OGRERR_FAILURE;
274 : }
275 :
276 0 : if( nSubBytes < 16 )
277 0 : return OGRERR_FAILURE;
278 :
279 0 : if( !(pabyGeom[1] == 0xFF && pabyGeom[2] == 0xD2 && pabyGeom[3] == 0x0F) )
280 0 : return OGRERR_FAILURE;
281 :
282 0 : int nSubGeomType = pabyGeom[0];
283 0 : if ( nSubGeomType != GEOMEDIA_POLYLINE )
284 0 : bAllPolyline = FALSE;
285 0 : if ( nSubGeomType != GEOMEDIA_POLYGON )
286 0 : bAllPolygon = FALSE;
287 :
288 0 : pabyGeom += nSubBytes;
289 0 : nBytes -= nSubBytes;
290 : }
291 :
292 0 : pabyGeom = pabyGeomBackup;
293 0 : nBytes = nBytesBackup;
294 :
295 0 : if (bAllPolyline)
296 0 : nGeomType = GEOMEDIA_MULTILINE;
297 0 : else if (bAllPolygon)
298 0 : nGeomType = GEOMEDIA_MULTIPOLYGON;
299 : }
300 :
301 : OGRGeometryCollection* poColl = (nGeomType == GEOMEDIA_MULTILINE) ? new OGRMultiLineString() :
302 : (nGeomType == GEOMEDIA_MULTIPOLYGON) ? new OGRMultiPolygon() :
303 0 : new OGRGeometryCollection();
304 :
305 0 : for(i=0;i<nParts;i++)
306 : {
307 0 : if (nBytes < 4)
308 0 : return OGRERR_FAILURE;
309 : int nSubBytes;
310 0 : memcpy(&nSubBytes, pabyGeom, 4);
311 : CPL_LSBPTR32(&nSubBytes);
312 :
313 0 : if (nSubBytes < 0)
314 : {
315 0 : delete poColl;
316 0 : return OGRERR_FAILURE;
317 : }
318 :
319 0 : pabyGeom += 4;
320 0 : nBytes -= 4;
321 :
322 0 : if (nBytes < nSubBytes)
323 : {
324 0 : delete poColl;
325 0 : return OGRERR_FAILURE;
326 : }
327 :
328 0 : OGRGeometry* poSubGeom = NULL;
329 0 : if (OGRCreateFromGeomedia( pabyGeom, &poSubGeom, nSubBytes ) == OGRERR_NONE)
330 : {
331 0 : if (wkbFlatten(poColl->getGeometryType()) == wkbMultiPolygon &&
332 0 : wkbFlatten(poSubGeom->getGeometryType()) == wkbLineString)
333 : {
334 0 : OGRPolygon* poPoly = new OGRPolygon();
335 0 : OGRLinearRing* poRing = new OGRLinearRing();
336 0 : poRing->addSubLineString((OGRLineString*)poSubGeom);
337 0 : poPoly->addRingDirectly(poRing);
338 0 : delete poSubGeom;
339 0 : poSubGeom = poPoly;
340 : }
341 :
342 0 : if (poColl->addGeometryDirectly(poSubGeom) != OGRERR_NONE)
343 : {
344 : //printf("%d %d\n", poColl->getGeometryType() & ~wkb25DBit, poSubGeom->getGeometryType() & ~wkb25DBit);
345 0 : delete poSubGeom;
346 : }
347 : }
348 :
349 0 : pabyGeom += nSubBytes;
350 0 : nBytes -= nSubBytes;
351 : }
352 :
353 0 : *ppoGeom = poColl;
354 :
355 0 : return OGRERR_NONE;
356 : }
357 : else
358 : {
359 0 : CPLDebug("GEOMEDIA", "Unhandled type %d", nGeomType);
360 : }
361 :
362 0 : return OGRERR_FAILURE;
363 : }
364 :
365 :
366 : /************************************************************************/
367 : /* OGRGetGeomediaSRS() */
368 : /************************************************************************/
369 :
370 0 : OGRSpatialReference* OGRGetGeomediaSRS(OGRFeature* poFeature)
371 : {
372 0 : if (poFeature == NULL)
373 0 : return NULL;
374 :
375 0 : int nGeodeticDatum = poFeature->GetFieldAsInteger("GeodeticDatum");
376 0 : int nEllipsoid = poFeature->GetFieldAsInteger("Ellipsoid");
377 0 : int nProjAlgorithm = poFeature->GetFieldAsInteger("ProjAlgorithm");
378 :
379 0 : if (nGeodeticDatum == 17 && nEllipsoid == 22)
380 : {
381 0 : if (nProjAlgorithm == 12)
382 : {
383 0 : OGRSpatialReference* poSRS = new OGRSpatialReference();
384 :
385 0 : const char* pszDescription = poFeature->GetFieldAsString("Description");
386 0 : if (pszDescription && pszDescription[0] != 0)
387 0 : poSRS->SetNode( "PROJCS", pszDescription );
388 0 : poSRS->SetWellKnownGeogCS("WGS84");
389 :
390 0 : double dfStdP1 = poFeature->GetFieldAsDouble("StandPar1");
391 0 : double dfStdP2 = poFeature->GetFieldAsDouble("StandPar2");
392 0 : double dfCenterLat = poFeature->GetFieldAsDouble("LatOfOrigin");
393 0 : double dfCenterLong = poFeature->GetFieldAsDouble("LonOfOrigin");
394 0 : double dfFalseEasting = poFeature->GetFieldAsDouble("FalseX");
395 0 : double dfFalseNorthing = poFeature->GetFieldAsDouble("FalseY");
396 : poSRS->SetACEA( dfStdP1, dfStdP2,
397 : dfCenterLat, dfCenterLong,
398 0 : dfFalseEasting, dfFalseNorthing );
399 0 : return poSRS;
400 : }
401 : }
402 :
403 0 : return NULL;
404 : }
|