All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
EWKBReader.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/sqlite/EWKBReader.cpp
22 
23  \brief An utility class for reading a SpatiaLite EWKB geometry.
24 */
25 
26 // TerraLib
27 #include "../common/ByteSwapUtils.h"
28 #include "../common/Enums.h"
29 #include "../common/Globals.h"
30 #include "../common/HexUtils.h"
31 #include "../common/Translator.h"
32 #include "../dataaccess/Exception.h"
33 #include "../geometry.h"
34 #include "EWKBReader.h"
35 #include "Utils.h"
36 
37 // STL
38 #include <cassert>
39 #include <cstring>
40 
41 // SQLite
42 #include <sqlite3.h>
43 
44 #ifdef TE_ENABLE_SPATIALITE
45 // SpatiaLite
46 #include <spatialite/gaiageo.h>
47 
48 namespace te
49 {
50  namespace sqlite
51  {
52  template<class T> inline T* GetCoordSequence(const unsigned char* ewkb,
53  const unsigned char** endptr,
54  unsigned int gtype,
55  unsigned char ewkbByteOrder,
56  int srid,
57  te::gm::Envelope* mbr)
58  {
59  assert(ewkb && endptr);
60 
61  unsigned int nPts = 0;
62  memcpy(&nPts, ewkb, 4);
63  ewkb += 4;
64 
65  if(te::common::Globals::sm_machineByteOrder != ewkbByteOrder)
67 
68  T* cs = new T(nPts, static_cast<te::gm::GeomType>(gtype), srid, mbr);
69 
70  switch(gtype)
71  {
72  case GAIA_LINESTRING :
73  memcpy(cs->getCoordinates(), ewkb, 16 * nPts);
74  ewkb += nPts * 16;
75  break;
76 
77  case GAIA_LINESTRINGZ :
78  for(unsigned int i = 0; i < nPts; ++i)
79  {
80  memcpy(&(cs->getCoordinates()[i]), ewkb, 16);
81  memcpy(&(cs->getZ()[i]), ewkb + 16, 8);
82  ewkb += 24;
83  }
84  break;
85 
86  case GAIA_LINESTRINGM :
87  for(unsigned int i = 0; i < nPts; ++i)
88  {
89  memcpy(&(cs->getCoordinates()[i]), ewkb, 16);
90  memcpy(&(cs->getM()[i]), ewkb + 16, 8);
91  ewkb += 24;
92  }
93  break;
94 
95  case GAIA_LINESTRINGZM :
96  for(unsigned int i = 0; i < nPts; ++i)
97  {
98  memcpy(&(cs->getCoordinates()[i]), ewkb, 16);
99  memcpy(&(cs->getZ()[i]), ewkb + 16, 8);
100  memcpy(&(cs->getM()[i]), ewkb + 24, 8);
101  ewkb += 32;
102  }
103  break;
104  }
105 
106  if(te::common::Globals::sm_machineByteOrder != ewkbByteOrder)
107  {
108  for(unsigned int i = 0; i < nPts; ++i)
109  {
110  te::common::SwapBytes(cs->getCoordinates()[i].x);
111  te::common::SwapBytes(cs->getCoordinates()[i].y);
112  }
113 
114  if(cs->getZ())
115  for(unsigned int i = 0; i < nPts; ++i)
116  te::common::SwapBytes(cs->getZ()[i]);
117 
118  if(cs->getM())
119  for(unsigned int i = 0; i < nPts; ++i)
120  te::common::SwapBytes(cs->getM()[i]);
121  }
122 
123  *endptr = ewkb;
124 
125  return cs;
126  }
127  }
128 }
129 
130 te::gm::Geometry* te::sqlite::EWKBReader::read(const unsigned char* ewkb)
131 {
132  const unsigned char* ewkbb = ewkb;
133 
134  if((ewkb[0] != GAIA_MARK_START) || (ewkb[38] != GAIA_MARK_MBR))
135  throw te::da::Exception(TR_COMMON("It is an invalid SpatiaLite geometry!"));
136 
137  int srid = -1;
138  double llx = 0.0, lly = 0.0, urx = 0.0, ury = 0.0;
139  memcpy(&srid, ewkb + 2, 4);
140  memcpy(&llx, ewkb + 6, 8);
141  memcpy(&lly, ewkb + 14, 8);
142  memcpy(&urx, ewkb + 22, 8);
143  memcpy(&ury, ewkb + 30, 8);
144 
146  {
147  te::common::SwapBytes(srid);
152  }
153 
154  te::gm::Envelope* mbr = new te::gm::Envelope(llx, lly, urx, ury);
155 
156  te::gm::Geometry* g = getGeometry(ewkb + 39, &ewkbb, ewkb[1], srid, mbr);
157 
158  if(ewkbb[0] != GAIA_MARK_END)
159  {
160  delete g;
161  throw te::da::Exception(TR_COMMON("It is an invalid SpatiaLite geometry!"));
162  }
163 
164  return g;
165 }
166 
167 te::gm::Geometry* te::sqlite::EWKBReader::readHex(const unsigned char* hewkb)
168 {
169  char* ewkb = te::common::Hex2Binary((const char*)hewkb);
170 
171  te::gm::Geometry* g = read((const unsigned char*)ewkb);
172 
173  delete [] ewkb;
174 
175  return g;
176 }
177 
178 te::gm::Geometry* te::sqlite::EWKBReader::getGeometry(const unsigned char* ewkb,
179  const unsigned char** endptr,
180  unsigned char ewkbByteOrder,
181  int srid,
182  te::gm::Envelope* mbr)
183 {
184  unsigned int gType = GAIA_UNKNOWN;
185 
186  memcpy(&gType, ewkb, 4);
187 
188  if(te::common::Globals::sm_machineByteOrder != ewkbByteOrder)
189  te::common::SwapBytes(gType);
190 
191  ewkb += 4;
192  *endptr = ewkb;
193 
194  switch(gType)
195  {
196  case GAIA_POINT:
197  case GAIA_POINTZ:
198  case GAIA_POINTM:
199  case GAIA_POINTZM:
200  return getPoint(ewkb, endptr, ewkbByteOrder, gType, srid, mbr);
201 
202  case GAIA_LINESTRING:
203  case GAIA_LINESTRINGZ:
204  case GAIA_LINESTRINGM:
205  case GAIA_LINESTRINGZM:
206  return getLineString(ewkb, endptr, ewkbByteOrder, gType, srid, mbr);
207 
208  case GAIA_POLYGON:
209  case GAIA_POLYGONZ:
210  case GAIA_POLYGONM:
211  case GAIA_POLYGONZM:
212  return getPolygon(ewkb, endptr, ewkbByteOrder, gType, srid, mbr);
213 
214  case GAIA_MULTIPOINT:
215  case GAIA_MULTIPOINTZ:
216  case GAIA_MULTIPOINTM:
217  case GAIA_MULTIPOINTZM:
218  case GAIA_MULTILINESTRING:
219  case GAIA_MULTILINESTRINGZ:
220  case GAIA_MULTILINESTRINGM:
221  case GAIA_MULTILINESTRINGZM:
222  case GAIA_MULTIPOLYGON:
223  case GAIA_MULTIPOLYGONZ:
224  case GAIA_MULTIPOLYGONM:
225  case GAIA_MULTIPOLYGONZM:
226  case GAIA_GEOMETRYCOLLECTION:
227  case GAIA_GEOMETRYCOLLECTIONZ:
228  case GAIA_GEOMETRYCOLLECTIONM:
229  case GAIA_GEOMETRYCOLLECTIONZM:
230  return getGeometryCollection(ewkb, endptr, ewkbByteOrder, gType, srid, mbr);
231 
232  default:
233  throw te::da::Exception(TR_COMMON("This kind of geometry id not supported by SpatiaLite!"));
234  }
235 }
236 
237 te::gm::Point* te::sqlite::EWKBReader::getPoint(const unsigned char* ewkb,
238  const unsigned char** endptr,
239  unsigned char ewkbByteOrder,
240  unsigned int gtype,
241  int srid,
242  te::gm::Envelope* mbr)
243 {
244  double x = 0.0;
245  double y = 0.0;
246  double z = 0.0;
247  double m = 0.0;
248 
249  memcpy(&x, ewkb, 8);
250  memcpy(&y, ewkb + 8, 8);
251 
252  ewkb += 16;
253 
254  if(gtype != GAIA_POINT)
255  {
256  switch(gtype)
257  {
258  case GAIA_POINTZ:
259  memcpy(&z, ewkb, 8);
260  ewkb += 8;
261  break;
262 
263  case GAIA_POINTM:
264  memcpy(&m, ewkb, 8);
265  ewkb += 8;
266  break;
267 
268  default:
269  assert(gtype == GAIA_POINTZM);
270  memcpy(&z, ewkb, 8);
271  memcpy(&m, ewkb + 8, 8);
272  ewkb += 16;
273  }
274  }
275 
276  *endptr = ewkb;
277 
278  if(te::common::Globals::sm_machineByteOrder != ewkbByteOrder)
279  {
280  te::common::SwapBytes(srid);
285  }
286 
287  switch(gtype)
288  {
289  case GAIA_POINT:
290  return new te::gm::Point(x, y, srid, mbr);
291 
292  case GAIA_POINTZ:
293  return new te::gm::PointZ(x, y, z, srid, mbr);
294 
295  case GAIA_POINTM:
296  return new te::gm::PointM(x, y, m, srid, mbr);
297 
298  case GAIA_POINTZM:
299  return new te::gm::PointZM(x, y, z, m, srid, mbr);
300 
301  default:
302  throw te::da::Exception(TR_COMMON("This kind of geometry id not supported by SpatiaLite!"));
303  }
304 }
305 
306 te::gm::LineString* te::sqlite::EWKBReader::getLineString(const unsigned char* ewkb,
307  const unsigned char** endptr,
308  unsigned char ewkbByteOrder,
309  unsigned int gtype,
310  int srid,
311  te::gm::Envelope* mbr)
312 {
313  te::gm::LineString* l = GetCoordSequence<te::gm::LineString>(ewkb, endptr, gtype, ewkbByteOrder, srid, mbr);
314  return l;
315 }
316 
317 te::gm::LinearRing* te::sqlite::EWKBReader::getLinearRing(const unsigned char* ewkb,
318  unsigned int gtype,
319  const unsigned char** endptr,
320  unsigned char ewkbByteOrder,
321  int srid)
322 {
323  te::gm::LinearRing* r = GetCoordSequence<te::gm::LinearRing>(ewkb, endptr, gtype, ewkbByteOrder, srid, 0);
324  return r;
325 }
326 
327 te::gm::Polygon* te::sqlite::EWKBReader::getPolygon(const unsigned char* ewkb,
328  const unsigned char** endptr,
329  unsigned char ewkbByteOrder,
330  unsigned int gtype,
331  int srid,
332  te::gm::Envelope* mbr)
333 {
334  unsigned int nRings = 0;
335  memcpy(&nRings, ewkb, 4);
336  ewkb += 4;
337 
338  if(te::common::Globals::sm_machineByteOrder != ewkbByteOrder)
339  te::common::SwapBytes(nRings);
340 
341  te::gm::Polygon* p = 0;
342 
343  unsigned int rType = GAIA_UNKNOWN;
344 
345  switch(gtype)
346  {
347  case GAIA_POLYGON:
348  rType = GAIA_LINESTRING;
349  p = new te::gm::Polygon(nRings, te::gm::PolygonType, srid, mbr);
350  break;
351 
352  case GAIA_POLYGONZ:
353  rType = GAIA_LINESTRINGZ;
354  p = new te::gm::Polygon(nRings, te::gm::PolygonZType, srid, mbr);
355  break;
356 
357  case GAIA_POLYGONM:
358  rType = GAIA_LINESTRINGM;
359  p = new te::gm::Polygon(nRings, te::gm::PolygonMType, srid, mbr);
360  break;
361 
362  case GAIA_POLYGONZM:
363  rType = GAIA_LINESTRINGZM;
364  p = new te::gm::Polygon(nRings, te::gm::PolygonZMType, srid, mbr);
365  break;
366 
367  default:
368  throw te::da::Exception(TR_COMMON("This kind of geometry id not supported by SpatiaLite!"));
369  }
370 
371  *endptr = ewkb;
372 
373  if(p == 0)
374  return 0;
375 
376  for(unsigned int i = 0; i < nRings; ++i)
377  {
378  te::gm::LinearRing* r = getLinearRing(ewkb, rType, endptr, ewkbByteOrder, srid);
379  ewkb = *endptr;
380  p->getRings()[i] = r;
381  }
382 
383  return p;
384 }
385 
386 te::gm::GeometryCollection* te::sqlite::EWKBReader::getGeometryCollection(const unsigned char* ewkb,
387  const unsigned char** endptr,
388  unsigned char ewkbByteOrder,
389  unsigned int gtype,
390  int srid,
391  te::gm::Envelope* mbr)
392 {
393  unsigned int nGeoms = 0;
394  memcpy(&nGeoms, ewkb, 4);
395  ewkb += 4;
396 
397  if(te::common::Globals::sm_machineByteOrder != ewkbByteOrder)
398  te::common::SwapBytes(nGeoms);
399 
401 
402  switch(gtype)
403  {
404  case GAIA_MULTIPOLYGON:
405  case GAIA_MULTIPOLYGONZ:
406  case GAIA_MULTIPOLYGONM:
407  case GAIA_MULTIPOLYGONZM:
408  gc = new te::gm::MultiPolygon(nGeoms, static_cast<te::gm::GeomType>(gtype), srid, mbr);
409  break;
410 
411  case GAIA_MULTIPOINT:
412  case GAIA_MULTIPOINTZ:
413  case GAIA_MULTIPOINTM:
414  case GAIA_MULTIPOINTZM:
415  gc = new te::gm::MultiPoint(nGeoms, static_cast<te::gm::GeomType>(gtype), srid, mbr);
416  break;
417 
418  case GAIA_MULTILINESTRING:
419  case GAIA_MULTILINESTRINGZ:
420  case GAIA_MULTILINESTRINGM:
421  case GAIA_MULTILINESTRINGZM:
422  gc = new te::gm::MultiLineString(nGeoms, static_cast<te::gm::GeomType>(gtype), srid, mbr);
423  break;
424 
425  case GAIA_GEOMETRYCOLLECTION:
426  case GAIA_GEOMETRYCOLLECTIONZ:
427  case GAIA_GEOMETRYCOLLECTIONM:
428  case GAIA_GEOMETRYCOLLECTIONZM:
429  gc = new te::gm::GeometryCollection(nGeoms, static_cast<te::gm::GeomType>(gtype), srid, mbr);
430  break;
431 
432  default:
433  throw te::da::Exception(TR_COMMON("This kind of geometry id not supported by SpatiaLite!"));
434  }
435 
436  *endptr = ewkb;
437 
438  if(gc == 0)
439  throw te::da::Exception(TR_COMMON("This kind of geometry id not supported by SpatiaLite!"));
440 
441  for(unsigned int i = 0; i < nGeoms; ++i)
442  {
443  if(ewkb[0] != GAIA_MARK_ENTITY)
444  return gc;
445 
446  unsigned int classtype = GAIA_UNKNOWN;
447 
448  memcpy(&classtype, ewkb + 1, 4);
449  ewkb += 5;
450 
451  if(te::common::Globals::sm_machineByteOrder != ewkbByteOrder)
452  te::common::SwapBytes(classtype);
453 
454  te::gm::Geometry* g = 0;
455 
456  switch(classtype)
457  {
458  case GAIA_POINT:
459  case GAIA_POINTZ:
460  case GAIA_POINTM:
461  case GAIA_POINTZM:
462  g = getPoint(ewkb, endptr, ewkbByteOrder, classtype, srid, 0);
463  break;
464 
465  case GAIA_LINESTRING:
466  case GAIA_LINESTRINGZ:
467  case GAIA_LINESTRINGM:
468  case GAIA_LINESTRINGZM:
469  g = getLineString(ewkb, endptr, ewkbByteOrder, classtype, srid, 0);
470  break;
471 
472  case GAIA_POLYGON:
473  case GAIA_POLYGONZ:
474  case GAIA_POLYGONM:
475  case GAIA_POLYGONZM:
476  g = getPolygon(ewkb, endptr, ewkbByteOrder, GAIA_POLYGON, srid, 0);
477  break;
478 
479  default:
480  throw te::da::Exception(TR_COMMON("This kind of geometry is not handled by TerraLib SpatiaLite driver yet!"));
481  }
482 
483  g->setSRID(srid);
484  ewkb = *endptr;
485  gc->getGeometries()[i] = g;
486  }
487 
488  return gc;
489 }
490 
491 #endif // TE_ENABLE_SPATIALITE
492 
MultiPolygon is a MultiSurface whose elements are Polygons.
Definition: MultiPolygon.h:50
std::vector< Curve * > & getRings()
It returns the polygon rings.
Definition: CurvePolygon.h:300
static const MachineByteOrder sm_machineByteOrder
A flag that indicates the machine byte order (Big Endian or Little Endian).
Definition: Globals.h:54
A point with a z-coordinate value and an associated measurement.
Definition: PointZM.h:51
A point with an associated measure.
Definition: PointM.h:51
A LinearRing is a LineString that is both closed and simple.
Definition: LinearRing.h:53
MultiPoint is a GeometryCollection whose elements are restricted to points.
Definition: MultiPoint.h:50
A point with z-coordinate value.
Definition: PointZ.h:51
LineString is a curve with linear interpolation between points.
Definition: LineString.h:62
A point with x and y coordinate values.
Definition: Point.h:50
An Envelope defines a 2D rectangular region.
Definition: Envelope.h:51
Utility functions for the TerraLib SQLite Data Access driver.
Geometry is the root class of the geometries hierarchy, it follows OGC and ISO standards.
Definition: Geometry.h:73
MultiLineString is a MultiCurve whose elements are LineStrings.
Polygon is a subclass of CurvePolygon whose rings are defined by linear rings.
Definition: Polygon.h:50
const std::vector< Geometry * > & getGeometries() const
It returns a reference to the internal list of geometries.
T * GetCoordSequence(const char *ewkb, const char **endptr, unsigned int gType, char byteOrder)
Definition: EWKBReader.cpp:44
char * Hex2Binary(const char *hex)
It converts each pair of hex characters from a NULL-terminated string of hex characters into a binary...
Definition: HexUtils.h:469
It is a collection of other geometric objects.
virtual void setSRID(int srid)=0
It sets the Spatial Reference System ID of the geometry and all its parts if it is a GeometryCollecti...
void SwapBytes(T &v)
It swaps the bytes in local.
An utility class for reading a SpatiaLite EWKB geometry.