/* gg_wkb.c -- Gaia common support for WKB encoded geometries version 5.1.0, 2023 August 4 Author: Sandro Furieri a.furieri@lqt.it ----------------------------------------------------------------------------- Version: MPL 1.1/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is the SpatiaLite library The Initial Developer of the Original Code is Alessandro Furieri Portions created by the Initial Developer are Copyright (C) 2008-2023 the Initial Developer. All Rights Reserved. Contributor(s): Alternatively, the contents of this file may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. */ #include #include #include #include #include #if defined(_WIN32) && !defined(__MINGW32__) #include "config-msvc.h" #else #include "config.h" #endif #include #include #include static void ParseWkbPoint (gaiaGeomCollPtr geo) { /* decodes a POINT from WKB */ double x; double y; if (geo->size < geo->offset + 16) return; x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); geo->offset += 16; gaiaAddPointToGeomColl (geo, x, y); } static void ParseWkbPointZ (gaiaGeomCollPtr geo) { /* decodes a POINTZ from WKB */ double x; double y; double z; if (geo->size < geo->offset + 24) return; x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); geo->offset += 24; gaiaAddPointToGeomCollXYZ (geo, x, y, z); } static void ParseWkbPointM (gaiaGeomCollPtr geo) { /* decodes a POINTM from WKB */ double x; double y; double m; if (geo->size < geo->offset + 24) return; x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); geo->offset += 24; gaiaAddPointToGeomCollXYM (geo, x, y, m); } static void ParseWkbPointZM (gaiaGeomCollPtr geo) { /* decodes a POINTZM from WKB */ double x; double y; double z; double m; if (geo->size < geo->offset + 32) return; x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian, geo->endian_arch); geo->offset += 32; gaiaAddPointToGeomCollXYZM (geo, x, y, z, m); } static void ParseWkbLine (gaiaGeomCollPtr geo) { /* decodes a LINESTRING from WKB */ int points; int iv; double x; double y; gaiaLinestringPtr line; if (geo->size < geo->offset + 4) return; points = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (16 * points)) return; line = gaiaAddLinestringToGeomColl (geo, points); for (iv = 0; iv < points; iv++) { x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); gaiaSetPoint (line->Coords, iv, x, y); geo->offset += 16; } } static void ParseWkbLineZ (gaiaGeomCollPtr geo) { /* decodes a LINESTRINGZ from WKB */ int points; int iv; double x; double y; double z; gaiaLinestringPtr line; if (geo->size < geo->offset + 4) return; points = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (24 * points)) return; line = gaiaAddLinestringToGeomColl (geo, points); for (iv = 0; iv < points; iv++) { x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); gaiaSetPointXYZ (line->Coords, iv, x, y, z); geo->offset += 24; } } static void ParseWkbLineM (gaiaGeomCollPtr geo) { /* decodes a LINESTRINGM from WKB */ int points; int iv; double x; double y; double m; gaiaLinestringPtr line; if (geo->size < geo->offset + 4) return; points = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (24 * points)) return; line = gaiaAddLinestringToGeomColl (geo, points); for (iv = 0; iv < points; iv++) { x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); gaiaSetPointXYM (line->Coords, iv, x, y, m); geo->offset += 24; } } static void ParseWkbLineZM (gaiaGeomCollPtr geo) { /* decodes a LINESTRINGZM from WKB */ int points; int iv; double x; double y; double z; double m; gaiaLinestringPtr line; if (geo->size < geo->offset + 4) return; points = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (32 * points)) return; line = gaiaAddLinestringToGeomColl (geo, points); for (iv = 0; iv < points; iv++) { x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian, geo->endian_arch); gaiaSetPointXYZM (line->Coords, iv, x, y, z, m); geo->offset += 32; } } static void ParseWkbPolygon (gaiaGeomCollPtr geo) { /* decodes a POLYGON from WKB */ int rings; int nverts; int iv; int ib; double x; double y; gaiaPolygonPtr polyg = NULL; gaiaRingPtr ring; if (geo->size < geo->offset + 4) return; rings = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ib = 0; ib < rings; ib++) { if (geo->size < geo->offset + 4) return; nverts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (16 * nverts)) return; if (ib == 0) { polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1); ring = polyg->Exterior; } else ring = gaiaAddInteriorRing (polyg, ib - 1, nverts); for (iv = 0; iv < nverts; iv++) { x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); geo->offset += 16; gaiaSetPoint (ring->Coords, iv, x, y); } } } static void ParseWkbPolygonZ (gaiaGeomCollPtr geo) { /* decodes a POLYGONZ from WKB */ int rings; int nverts; int iv; int ib; double x; double y; double z; gaiaPolygonPtr polyg = NULL; gaiaRingPtr ring; if (geo->size < geo->offset + 4) return; rings = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ib = 0; ib < rings; ib++) { if (geo->size < geo->offset + 4) return; nverts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (24 * nverts)) return; if (ib == 0) { polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1); ring = polyg->Exterior; } else ring = gaiaAddInteriorRing (polyg, ib - 1, nverts); for (iv = 0; iv < nverts; iv++) { x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); geo->offset += 24; gaiaSetPointXYZ (ring->Coords, iv, x, y, z); } } } static void ParseWkbPolygonM (gaiaGeomCollPtr geo) { /* decodes a POLYGONM from WKB */ int rings; int nverts; int iv; int ib; double x; double y; double m; gaiaPolygonPtr polyg = NULL; gaiaRingPtr ring; if (geo->size < geo->offset + 4) return; rings = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ib = 0; ib < rings; ib++) { if (geo->size < geo->offset + 4) return; nverts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (24 * nverts)) return; if (ib == 0) { polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1); ring = polyg->Exterior; } else ring = gaiaAddInteriorRing (polyg, ib - 1, nverts); for (iv = 0; iv < nverts; iv++) { x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); geo->offset += 24; gaiaSetPointXYM (ring->Coords, iv, x, y, m); } } } static void ParseWkbPolygonZM (gaiaGeomCollPtr geo) { /* decodes a POLYGONZM from WKB */ int rings; int nverts; int iv; int ib; double x; double y; double z; double m; gaiaPolygonPtr polyg = NULL; gaiaRingPtr ring; if (geo->size < geo->offset + 4) return; rings = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ib = 0; ib < rings; ib++) { if (geo->size < geo->offset + 4) return; nverts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (32 * nverts)) return; if (ib == 0) { polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1); ring = polyg->Exterior; } else ring = gaiaAddInteriorRing (polyg, ib - 1, nverts); for (iv = 0; iv < nverts; iv++) { x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian, geo->endian_arch); geo->offset += 32; gaiaSetPointXYZM (ring->Coords, iv, x, y, z, m); } } } static void ParseWkbMultiPoint (gaiaGeomCollPtr geo) { /* decodes a MULTIPOINT from WKB */ int ig; int n_pts; int g_type; if (geo->size < geo->offset + 4) return; n_pts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_pts; ig++) { /* parsing all Points one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_POINT) ParseWkbPoint (geo); } } static void ParseWkbMultiLine (gaiaGeomCollPtr geo) { /* decodes a MULTILINESTRING from WKB */ int ig; int n_lns; int g_type; if (geo->size < geo->offset + 4) return; n_lns = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_lns; ig++) { /* parsing all Linestrings one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_LINESTRING) ParseWkbLine (geo); } } static void ParseWkbMultiPolygon (gaiaGeomCollPtr geo) { /* decodes a MULTIPOLYGON from WKB */ int ig; int n_pgs; int g_type; if (geo->size < geo->offset + 4) return; n_pgs = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_pgs; ig++) { /* parsing all Polygons one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_POLYGON) ParseWkbPolygon (geo); } } static void ParseWkbGeomColl (gaiaGeomCollPtr geo) { /* decodes a GEOMETRYCOLLECTION from WKB */ int ig; int n_geoms; if (geo->size < geo->offset + 4) return; n_geoms = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_geoms; ig++) { int g_type; if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; switch (g_type) { case GAIA_POINT: ParseWkbPoint (geo); break; case GAIA_LINESTRING: ParseWkbLine (geo); break; case GAIA_POLYGON: ParseWkbPolygon (geo); break; case GAIA_MULTIPOINT: ParseWkbMultiPoint (geo); break; case GAIA_MULTILINESTRING: ParseWkbMultiLine (geo); break; case GAIA_MULTIPOLYGON: ParseWkbMultiPolygon (geo); break; case GAIA_GEOMETRYCOLLECTION: ParseWkbGeomColl (geo); break; }; } } static void ParseWkbMultiPointZ (gaiaGeomCollPtr geo) { /* decodes a MULTIPOINTZ from WKB */ int ig; int n_pts; int g_type; if (geo->size < geo->offset + 4) return; n_pts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_pts; ig++) { /* parsing all Points one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_POINTZ) ParseWkbPointZ (geo); } } static void ParseWkbMultiLineZ (gaiaGeomCollPtr geo) { /* decodes a MULTILINESTRINGZ from WKB */ int ig; int n_lns; int g_type; if (geo->size < geo->offset + 4) return; n_lns = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_lns; ig++) { /* parsing all Linestrings one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_LINESTRINGZ) ParseWkbLineZ (geo); } } static void ParseWkbMultiPolygonZ (gaiaGeomCollPtr geo) { /* decodes a MULTIPOLYGONZ from WKB */ int ig; int n_pgs; int g_type; if (geo->size < geo->offset + 4) return; n_pgs = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_pgs; ig++) { /* parsing all Polygons one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_POLYGONZ) ParseWkbPolygonZ (geo); } } static void ParseWkbGeomCollZ (gaiaGeomCollPtr geo) { /* decodes a GEOMETRYCOLLECTIONZ from WKB */ int ig; int n_geoms; if (geo->size < geo->offset + 4) return; n_geoms = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_geoms; ig++) { /* parsing all Geometries one by one */ int g_type; if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; switch (g_type) { case GAIA_POINTZ: ParseWkbPointZ (geo); break; case GAIA_LINESTRINGZ: ParseWkbLineZ (geo); break; case GAIA_POLYGONZ: ParseWkbPolygonZ (geo); break; case GAIA_MULTIPOINTZ: ParseWkbMultiPointZ (geo); break; case GAIA_MULTILINESTRINGZ: ParseWkbMultiLineZ (geo); break; case GAIA_MULTIPOLYGONZ: ParseWkbMultiPolygonZ (geo); break; case GAIA_GEOMETRYCOLLECTIONZ: ParseWkbGeomCollZ (geo); break; }; } } static void ParseWkbMultiPointM (gaiaGeomCollPtr geo) { /* decodes a MULTIPOINTM from WKB */ int ig; int n_pts; int g_type; if (geo->size < geo->offset + 4) return; n_pts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_pts; ig++) { /* parsing all Points one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_POINTM) ParseWkbPointM (geo); } } static void ParseWkbMultiLineM (gaiaGeomCollPtr geo) { /* decodes a MULTILINESTRINGM from WKB */ int ig; int n_lns; int g_type; if (geo->size < geo->offset + 4) return; n_lns = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_lns; ig++) { /* parsing all Linestrings one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_LINESTRINGM) ParseWkbLineM (geo); } } static void ParseWkbMultiPolygonM (gaiaGeomCollPtr geo) { /* decodes a MULTIPOLYGONM from WKB */ int ig; int n_pgs; int g_type; if (geo->size < geo->offset + 4) return; n_pgs = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_pgs; ig++) { /* parsing all Polygons one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_POLYGONM) ParseWkbPolygonM (geo); } } static void ParseWkbGeomCollM (gaiaGeomCollPtr geo) { /* decodes a GEOMETRYCOLLECTIONM from WKB */ int ig; int n_geoms; if (geo->size < geo->offset + 4) return; n_geoms = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_geoms; ig++) { /* parsing all Geometries one by one */ int g_type; if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; switch (g_type) { case GAIA_POINTM: ParseWkbPointM (geo); break; case GAIA_LINESTRINGM: ParseWkbLineM (geo); break; case GAIA_POLYGONM: ParseWkbPolygonM (geo); break; case GAIA_MULTIPOINTM: ParseWkbMultiPointM (geo); break; case GAIA_MULTILINESTRINGM: ParseWkbMultiLineM (geo); break; case GAIA_MULTIPOLYGONM: ParseWkbMultiPolygonM (geo); break; case GAIA_GEOMETRYCOLLECTIONM: ParseWkbGeomCollM (geo); break; }; } } static void ParseWkbMultiPointZM (gaiaGeomCollPtr geo) { /* decodes a MULTIPOINTZM from WKB */ int ig; int n_pts; int g_type; if (geo->size < geo->offset + 4) return; n_pts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_pts; ig++) { /* parsing all Points one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_POINTZM) ParseWkbPointZM (geo); } } static void ParseWkbMultiLineZM (gaiaGeomCollPtr geo) { /* decodes a MULTILINESTRINGZM from WKB */ int ig; int n_lns; int g_type; if (geo->size < geo->offset + 4) return; n_lns = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_lns; ig++) { /* parsing all Linestrings one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_LINESTRINGZM) ParseWkbLineZM (geo); } } static void ParseWkbMultiPolygonZM (gaiaGeomCollPtr geo) { /* decodes a MULTIPOLYGONZM from WKB */ int ig; int n_pgs; int g_type; if (geo->size < geo->offset + 4) return; n_pgs = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_pgs; ig++) { /* parsing all Polygons one by one */ if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; if (g_type == GAIA_POLYGONZM) ParseWkbPolygonZM (geo); } } static void ParseWkbGeomCollZM (gaiaGeomCollPtr geo) { /* decodes a GEOMETRYCOLLECTIONZM from WKB */ int ig; int n_geoms; if (geo->size < geo->offset + 4) return; n_geoms = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ig = 0; ig < n_geoms; ig++) { /* parsing all Geometries one by one */ int g_type; if (geo->size < geo->offset + 5) return; /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; g_type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; switch (g_type) { case GAIA_POINTZM: ParseWkbPointZM (geo); break; case GAIA_LINESTRINGZM: ParseWkbLineZM (geo); break; case GAIA_POLYGONZM: ParseWkbPolygonZM (geo); break; case GAIA_MULTIPOINTZM: ParseWkbMultiPointZM (geo); break; case GAIA_MULTILINESTRINGZM: ParseWkbMultiLineZM (geo); break; case GAIA_MULTIPOLYGONZM: ParseWkbMultiPolygonZM (geo); break; case GAIA_GEOMETRYCOLLECTIONZM: ParseWkbGeomCollZM (geo); break; }; } } static void ParseCompressedWkbLine (gaiaGeomCollPtr geo) { /* decodes a COMPRESSED LINESTRING from WKB */ int points; int iv; double x; double y; double last_x = 0.0; double last_y = 0.0; float fx; float fy; gaiaLinestringPtr line; if (geo->size < geo->offset + 4) return; points = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (8 * points) + 16) return; line = gaiaAddLinestringToGeomColl (geo, points); for (iv = 0; iv < points; iv++) { if (iv == 0 || iv == (points - 1)) { /* first and last vertices are uncompressed */ x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); geo->offset += 16; } else { /* any other intermediate vertex is compressed */ fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian, geo->endian_arch); x = last_x + fx; y = last_y + fy; geo->offset += 8; } gaiaSetPoint (line->Coords, iv, x, y); last_x = x; last_y = y; } } static void ParseCompressedWkbLineZ (gaiaGeomCollPtr geo) { /* decodes a COMPRESSED LINESTRINGZ from WKB */ int points; int iv; double x; double y; double z; double last_x = 0.0; double last_y = 0.0; double last_z = 0.0; float fx; float fy; float fz; gaiaLinestringPtr line; if (geo->size < geo->offset + 4) return; points = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (12 * points) + 24) return; line = gaiaAddLinestringToGeomColl (geo, points); for (iv = 0; iv < points; iv++) { if (iv == 0 || iv == (points - 1)) { /* first and last vertices are uncompressed */ x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); geo->offset += 24; } else { /* any other intermediate vertex is compressed */ fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian, geo->endian_arch); fz = gaiaImportF32 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); x = last_x + fx; y = last_y + fy; z = last_z + fz; geo->offset += 12; } gaiaSetPointXYZ (line->Coords, iv, x, y, z); last_x = x; last_y = y; last_z = z; } } static void ParseCompressedWkbLineM (gaiaGeomCollPtr geo) { /* decodes a COMPRESSED LINESTRINGM from WKB */ int points; int iv; double x; double y; double m; double last_x = 0.0; double last_y = 0.0; float fx; float fy; gaiaLinestringPtr line; if (geo->size < geo->offset + 4) return; points = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (16 * points) + 16) return; line = gaiaAddLinestringToGeomColl (geo, points); for (iv = 0; iv < points; iv++) { if (iv == 0 || iv == (points - 1)) { /* first and last vertices are uncompressed */ x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); geo->offset += 24; } else { /* any other intermediate vertex is compressed */ fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); x = last_x + fx; y = last_y + fy; geo->offset += 16; } gaiaSetPointXYM (line->Coords, iv, x, y, m); last_x = x; last_y = y; } } static void ParseCompressedWkbLineZM (gaiaGeomCollPtr geo) { /* decodes a COMPRESSED LINESTRINGZM from WKB */ int points; int iv; double x; double y; double z; double m; double last_x = 0.0; double last_y = 0.0; double last_z = 0.0; float fx; float fy; float fz; gaiaLinestringPtr line; if (geo->size < geo->offset + 4) return; points = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (20 * points) + 24) return; line = gaiaAddLinestringToGeomColl (geo, points); for (iv = 0; iv < points; iv++) { if (iv == 0 || iv == (points - 1)) { /* first and last vertices are uncompressed */ x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian, geo->endian_arch); geo->offset += 32; } else { /* any other intermediate vertex is compressed */ fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian, geo->endian_arch); fz = gaiaImportF32 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 12), geo->endian, geo->endian_arch); x = last_x + fx; y = last_y + fy; z = last_z + fz; geo->offset += 20; } gaiaSetPointXYZM (line->Coords, iv, x, y, z, m); last_x = x; last_y = y; last_z = z; } } static void ParseCompressedWkbPolygon (gaiaGeomCollPtr geo) { /* decodes a COMPRESSED POLYGON from WKB */ int rings; int nverts; int iv; int ib; double x; double y; double last_x = 0.0; double last_y = 0.0; float fx; float fy; gaiaPolygonPtr polyg = NULL; gaiaRingPtr ring; if (geo->size < geo->offset + 4) return; rings = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ib = 0; ib < rings; ib++) { if (geo->size < geo->offset + 4) return; nverts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (8 * nverts) + 16) return; if (ib == 0) { polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1); ring = polyg->Exterior; } else ring = gaiaAddInteriorRing (polyg, ib - 1, nverts); for (iv = 0; iv < nverts; iv++) { if (iv == 0 || iv == (nverts - 1)) { /* first and last vertices are uncompressed */ x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); geo->offset += 16; } else { /* any other intermediate vertex is compressed */ fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian, geo->endian_arch); x = last_x + fx; y = last_y + fy; geo->offset += 8; } gaiaSetPoint (ring->Coords, iv, x, y); last_x = x; last_y = y; } } } static void ParseCompressedWkbPolygonZ (gaiaGeomCollPtr geo) { /* decodes a COMPRESSED POLYGONZ from WKB */ int rings; int nverts; int iv; int ib; double x; double y; double z; double last_x = 0.0; double last_y = 0.0; double last_z = 0.0; float fx; float fy; float fz; gaiaPolygonPtr polyg = NULL; gaiaRingPtr ring; if (geo->size < geo->offset + 4) return; rings = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ib = 0; ib < rings; ib++) { if (geo->size < geo->offset + 4) return; nverts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (12 * nverts) + 24) return; if (ib == 0) { polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1); ring = polyg->Exterior; } else ring = gaiaAddInteriorRing (polyg, ib - 1, nverts); for (iv = 0; iv < nverts; iv++) { if (iv == 0 || iv == (nverts - 1)) { /* first and last vertices are uncompressed */ x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); geo->offset += 24; } else { /* any other intermediate vertex is compressed */ fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian, geo->endian_arch); fz = gaiaImportF32 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); x = last_x + fx; y = last_y + fy; z = last_z + fz; geo->offset += 12; } gaiaSetPointXYZ (ring->Coords, iv, x, y, z); last_x = x; last_y = y; last_z = z; } } } static void ParseCompressedWkbPolygonM (gaiaGeomCollPtr geo) { /* decodes a COMPRESSED POLYGONM from WKB */ int rings; int nverts; int iv; int ib; double x; double y; double m; double last_x = 0.0; double last_y = 0.0; float fx; float fy; gaiaPolygonPtr polyg = NULL; gaiaRingPtr ring; if (geo->size < geo->offset + 4) return; rings = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ib = 0; ib < rings; ib++) { if (geo->size < geo->offset + 4) return; nverts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (16 * nverts) + 16) return; if (ib == 0) { polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1); ring = polyg->Exterior; } else ring = gaiaAddInteriorRing (polyg, ib - 1, nverts); for (iv = 0; iv < nverts; iv++) { if (iv == 0 || iv == (nverts - 1)) { /* first and last vertices are uncompressed */ x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); geo->offset += 24; } else { /* any other intermediate vertex is compressed */ fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); x = last_x + fx; y = last_y + fy; geo->offset += 16; } gaiaSetPointXYM (ring->Coords, iv, x, y, m); last_x = x; last_y = y; } } } static void ParseCompressedWkbPolygonZM (gaiaGeomCollPtr geo) { /* decodes a COMPRESSED POLYGONZM from WKB */ int rings; int nverts; int iv; int ib; double x; double y; double z; double m; double last_x = 0.0; double last_y = 0.0; double last_z = 0.0; float fx; float fy; float fz; gaiaPolygonPtr polyg = NULL; gaiaRingPtr ring; if (geo->size < geo->offset + 4) return; rings = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ib = 0; ib < rings; ib++) { if (geo->size < geo->offset + 4) return; nverts = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; if (geo->size < geo->offset + (20 * nverts) + 24) return; if (ib == 0) { polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1); ring = polyg->Exterior; } else ring = gaiaAddInteriorRing (polyg, ib - 1, nverts); for (iv = 0; iv < nverts; iv++) { if (iv == 0 || iv == (nverts - 1)) { /* first and last vertices are uncompressed */ x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch); y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian, geo->endian_arch); geo->offset += 32; } else { /* any other intermediate vertex is compressed */ fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian, geo->endian_arch); fz = gaiaImportF32 (geo->blob + (geo->offset + 8), geo->endian, geo->endian_arch); m = gaiaImport64 (geo->blob + (geo->offset + 12), geo->endian, geo->endian_arch); x = last_x + fx; y = last_y + fy; z = last_z + fz; geo->offset += 20; } gaiaSetPointXYZM (ring->Coords, iv, x, y, z, m); last_x = x; last_y = y; last_z = z; } } } static void ParseWkbGeometry (gaiaGeomCollPtr geo, int isWKB) { /* decodes a MULTIxx or GEOMETRYCOLLECTION from SpatiaLite BLOB */ int entities; int type; int ie; if (geo->size < geo->offset + 4) return; entities = gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch); geo->offset += 4; for (ie = 0; ie < entities; ie++) { if (geo->size < geo->offset + 5) return; if (isWKB) { /* vanilla WKB could be encoded as mixed big-/little-endian sub-items */ if (*(geo->blob + geo->offset) == 0x01) geo->endian = GAIA_LITTLE_ENDIAN; else geo->endian = GAIA_BIG_ENDIAN; } type = gaiaImport32 (geo->blob + geo->offset + 1, geo->endian, geo->endian_arch); geo->offset += 5; switch (type) { case GAIA_POINT: ParseWkbPoint (geo); break; case GAIA_POINTZ: case GAIA_GEOSWKB_POINTZ: ParseWkbPointZ (geo); break; case GAIA_POINTM: ParseWkbPointM (geo); break; case GAIA_POINTZM: ParseWkbPointZM (geo); break; case GAIA_LINESTRING: ParseWkbLine (geo); break; case GAIA_LINESTRINGZ: case GAIA_GEOSWKB_LINESTRINGZ: ParseWkbLineZ (geo); break; case GAIA_LINESTRINGM: ParseWkbLineM (geo); break; case GAIA_LINESTRINGZM: ParseWkbLineZM (geo); break; case GAIA_POLYGON: ParseWkbPolygon (geo); break; case GAIA_POLYGONZ: case GAIA_GEOSWKB_POLYGONZ: ParseWkbPolygonZ (geo); break; case GAIA_POLYGONM: ParseWkbPolygonM (geo); break; case GAIA_POLYGONZM: ParseWkbPolygonZM (geo); break; case GAIA_MULTIPOINT: ParseWkbMultiPoint (geo); break; case GAIA_MULTIPOINTZ: ParseWkbMultiPointZ (geo); break; case GAIA_MULTIPOINTM: ParseWkbMultiPointM (geo); break; case GAIA_MULTIPOINTZM: ParseWkbMultiPointZM (geo); break; case GAIA_MULTILINESTRING: ParseWkbMultiLine (geo); break; case GAIA_MULTILINESTRINGZ: ParseWkbMultiLineZ (geo); break; case GAIA_MULTILINESTRINGM: ParseWkbMultiLineM (geo); break; case GAIA_MULTILINESTRINGZM: ParseWkbMultiLineZM (geo); break; case GAIA_MULTIPOLYGON: ParseWkbMultiPolygon (geo); break; case GAIA_MULTIPOLYGONZ: ParseWkbMultiPolygonZ (geo); break; case GAIA_MULTIPOLYGONM: ParseWkbMultiPolygonM (geo); break; case GAIA_MULTIPOLYGONZM: ParseWkbMultiPolygonZM (geo); break; case GAIA_GEOMETRYCOLLECTION: ParseWkbGeomColl (geo); break; case GAIA_GEOMETRYCOLLECTIONZ: ParseWkbGeomCollZ (geo); break; case GAIA_GEOMETRYCOLLECTIONM: ParseWkbGeomCollM (geo); break; case GAIA_GEOMETRYCOLLECTIONZM: ParseWkbGeomCollZM (geo); break; case GAIA_COMPRESSED_LINESTRING: ParseCompressedWkbLine (geo); break; case GAIA_COMPRESSED_LINESTRINGZ: ParseCompressedWkbLineZ (geo); break; case GAIA_COMPRESSED_LINESTRINGM: ParseCompressedWkbLineM (geo); break; case GAIA_COMPRESSED_LINESTRINGZM: ParseCompressedWkbLineZM (geo); break; case GAIA_COMPRESSED_POLYGON: ParseCompressedWkbPolygon (geo); break; case GAIA_COMPRESSED_POLYGONZ: ParseCompressedWkbPolygonZ (geo); break; case GAIA_COMPRESSED_POLYGONM: ParseCompressedWkbPolygonM (geo); break; case GAIA_COMPRESSED_POLYGONZM: ParseCompressedWkbPolygonZM (geo); break; default: break; }; } } static gaiaGeomCollPtr doParseTinyPointBlob (const unsigned char *blob, unsigned int size) { /* decoding from SpatiaLite TinyPoint BLOB to GEOMETRY */ unsigned char pointType; int type; int little_endian; int endian_arch = gaiaEndianArch (); gaiaGeomCollPtr geo = NULL; if (size < 24) return NULL; /* cannot be an internal BLOB TinyPoint geometry */ if (*(blob + 0) != GAIA_MARK_START) return NULL; /* failed to recognize START signature */ if (*(blob + (size - 1)) != GAIA_MARK_END) return NULL; /* failed to recognize END signature */ if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN) little_endian = 1; else if (*(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN) little_endian = 0; else return NULL; /* unknown encoding; nor little-endian neither big-endian */ pointType = *(blob + 6); geo = gaiaAllocGeomColl (); geo->Srid = gaiaImport32 (blob + 2, little_endian, endian_arch); geo->endian_arch = (char) endian_arch; geo->endian = (char) little_endian; geo->blob = blob; geo->size = size; geo->offset = 7; switch (pointType) { /* setting up DimensionModel */ case GAIA_TINYPOINT_XYZ: type = GAIA_POINTZ; geo->DimensionModel = GAIA_XY_Z; break; case GAIA_TINYPOINT_XYM: type = GAIA_POINTM; geo->DimensionModel = GAIA_XY_M; break; case GAIA_TINYPOINT_XYZM: type = GAIA_POINTZM; geo->DimensionModel = GAIA_XY_Z_M; break; default: type = GAIA_POINT; geo->DimensionModel = GAIA_XY; break; }; switch (type) { /* parsing elementary geometries */ case GAIA_POINT: ParseWkbPoint (geo); break; case GAIA_POINTZ: ParseWkbPointZ (geo); break; case GAIA_POINTM: ParseWkbPointM (geo); break; case GAIA_POINTZM: ParseWkbPointZM (geo); break; default: break; }; geo->MinX = geo->FirstPoint->X; geo->MinY = geo->FirstPoint->Y; geo->MaxX = geo->FirstPoint->X; geo->MaxY = geo->FirstPoint->Y; geo->DeclaredType = GAIA_POINT; return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaFromSpatiaLiteBlobWkbEx (const unsigned char *blob, unsigned int size, int gpkg_mode, int gpkg_amphibious) { /* decoding from SpatiaLite BLOB to GEOMETRY */ int type; int little_endian; int endian_arch = gaiaEndianArch (); gaiaGeomCollPtr geo = NULL; if (gpkg_amphibious || gpkg_mode) { #ifdef ENABLE_GEOPACKAGE /* GEOPACKAGE enabled: supporting GPKG geometries */ if (gaiaIsValidGPB (blob, size)) { geo = gaiaFromGeoPackageGeometryBlob (blob, size); if (geo != NULL) return geo; } if (gpkg_mode) return NULL; /* must accept only GPKG geometries */ #else ; #endif /* end GEOPACKAGE: supporting GPKG geometries */ } if (size == 24 || size == 32 || size == 40) { /* testing for a possible TinyPoint BLOB */ if (*(blob + 0) == GAIA_MARK_START && (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN) && *(blob + (size - 1)) == GAIA_MARK_END) return doParseTinyPointBlob (blob, size); } if (size < 45) return NULL; /* cannot be an internal BLOB WKB geometry */ if (*(blob + 0) != GAIA_MARK_START) return NULL; /* failed to recognize START signature */ if (*(blob + (size - 1)) != GAIA_MARK_END) return NULL; /* failed to recognize END signature */ if (*(blob + 38) != GAIA_MARK_MBR) return NULL; /* failed to recognize MBR signature */ if (*(blob + 1) == GAIA_LITTLE_ENDIAN) little_endian = 1; else if (*(blob + 1) == GAIA_BIG_ENDIAN) little_endian = 0; else return NULL; /* unknown encoding; nor little-endian neither big-endian */ type = gaiaImport32 (blob + 39, little_endian, endian_arch); geo = gaiaAllocGeomColl (); geo->Srid = gaiaImport32 (blob + 2, little_endian, endian_arch); geo->endian_arch = (char) endian_arch; geo->endian = (char) little_endian; geo->blob = blob; geo->size = size; geo->offset = 43; switch (type) { /* setting up DimensionModel */ case GAIA_POINTZ: case GAIA_LINESTRINGZ: case GAIA_POLYGONZ: case GAIA_MULTIPOINTZ: case GAIA_MULTILINESTRINGZ: case GAIA_MULTIPOLYGONZ: case GAIA_GEOMETRYCOLLECTIONZ: case GAIA_COMPRESSED_LINESTRINGZ: case GAIA_COMPRESSED_POLYGONZ: geo->DimensionModel = GAIA_XY_Z; break; case GAIA_POINTM: case GAIA_LINESTRINGM: case GAIA_POLYGONM: case GAIA_MULTIPOINTM: case GAIA_MULTILINESTRINGM: case GAIA_MULTIPOLYGONM: case GAIA_GEOMETRYCOLLECTIONM: case GAIA_COMPRESSED_LINESTRINGM: case GAIA_COMPRESSED_POLYGONM: geo->DimensionModel = GAIA_XY_M; break; case GAIA_POINTZM: case GAIA_LINESTRINGZM: case GAIA_POLYGONZM: case GAIA_MULTIPOINTZM: case GAIA_MULTILINESTRINGZM: case GAIA_MULTIPOLYGONZM: case GAIA_GEOMETRYCOLLECTIONZM: case GAIA_COMPRESSED_LINESTRINGZM: case GAIA_COMPRESSED_POLYGONZM: geo->DimensionModel = GAIA_XY_Z_M; break; default: geo->DimensionModel = GAIA_XY; break; }; switch (type) { /* parsing elementary geometries */ case GAIA_POINT: ParseWkbPoint (geo); break; case GAIA_POINTZ: ParseWkbPointZ (geo); break; case GAIA_POINTM: ParseWkbPointM (geo); break; case GAIA_POINTZM: ParseWkbPointZM (geo); break; case GAIA_LINESTRING: ParseWkbLine (geo); break; case GAIA_LINESTRINGZ: ParseWkbLineZ (geo); break; case GAIA_LINESTRINGM: ParseWkbLineM (geo); break; case GAIA_LINESTRINGZM: ParseWkbLineZM (geo); break; case GAIA_POLYGON: ParseWkbPolygon (geo); break; case GAIA_POLYGONZ: ParseWkbPolygonZ (geo); break; case GAIA_POLYGONM: ParseWkbPolygonM (geo); break; case GAIA_POLYGONZM: ParseWkbPolygonZM (geo); break; case GAIA_COMPRESSED_LINESTRING: ParseCompressedWkbLine (geo); break; case GAIA_COMPRESSED_LINESTRINGZ: ParseCompressedWkbLineZ (geo); break; case GAIA_COMPRESSED_LINESTRINGM: ParseCompressedWkbLineM (geo); break; case GAIA_COMPRESSED_LINESTRINGZM: ParseCompressedWkbLineZM (geo); break; case GAIA_COMPRESSED_POLYGON: ParseCompressedWkbPolygon (geo); break; case GAIA_COMPRESSED_POLYGONZ: ParseCompressedWkbPolygonZ (geo); break; case GAIA_COMPRESSED_POLYGONM: ParseCompressedWkbPolygonM (geo); break; case GAIA_COMPRESSED_POLYGONZM: ParseCompressedWkbPolygonZM (geo); break; case GAIA_MULTIPOINT: case GAIA_MULTIPOINTZ: case GAIA_MULTIPOINTM: case GAIA_MULTIPOINTZM: case GAIA_MULTILINESTRING: case GAIA_MULTILINESTRINGZ: case GAIA_MULTILINESTRINGM: case GAIA_MULTILINESTRINGZM: case GAIA_MULTIPOLYGON: case GAIA_MULTIPOLYGONZ: case GAIA_MULTIPOLYGONM: case GAIA_MULTIPOLYGONZM: case GAIA_GEOMETRYCOLLECTION: case GAIA_GEOMETRYCOLLECTIONZ: case GAIA_GEOMETRYCOLLECTIONM: case GAIA_GEOMETRYCOLLECTIONZM: ParseWkbGeometry (geo, 0); break; default: break; }; geo->MinX = gaiaImport64 (blob + 6, little_endian, endian_arch); geo->MinY = gaiaImport64 (blob + 14, little_endian, endian_arch); geo->MaxX = gaiaImport64 (blob + 22, little_endian, endian_arch); geo->MaxY = gaiaImport64 (blob + 30, little_endian, endian_arch); switch (type) { /* setting up DeclaredType */ case GAIA_POINT: case GAIA_POINTZ: case GAIA_POINTM: case GAIA_POINTZM: geo->DeclaredType = GAIA_POINT; break; case GAIA_LINESTRING: case GAIA_LINESTRINGZ: case GAIA_LINESTRINGM: case GAIA_LINESTRINGZM: case GAIA_COMPRESSED_LINESTRING: case GAIA_COMPRESSED_LINESTRINGZ: case GAIA_COMPRESSED_LINESTRINGM: case GAIA_COMPRESSED_LINESTRINGZM: geo->DeclaredType = GAIA_LINESTRING; break; case GAIA_POLYGON: case GAIA_POLYGONZ: case GAIA_POLYGONM: case GAIA_POLYGONZM: case GAIA_COMPRESSED_POLYGON: case GAIA_COMPRESSED_POLYGONZ: case GAIA_COMPRESSED_POLYGONM: case GAIA_COMPRESSED_POLYGONZM: geo->DeclaredType = GAIA_POLYGON; break; case GAIA_MULTIPOINT: case GAIA_MULTIPOINTZ: case GAIA_MULTIPOINTM: case GAIA_MULTIPOINTZM: geo->DeclaredType = GAIA_MULTIPOINT; break; case GAIA_MULTILINESTRING: case GAIA_MULTILINESTRINGZ: case GAIA_MULTILINESTRINGM: case GAIA_MULTILINESTRINGZM: geo->DeclaredType = GAIA_MULTILINESTRING; break; case GAIA_MULTIPOLYGON: case GAIA_MULTIPOLYGONZ: case GAIA_MULTIPOLYGONM: case GAIA_MULTIPOLYGONZM: geo->DeclaredType = GAIA_MULTIPOLYGON; break; case GAIA_GEOMETRYCOLLECTION: case GAIA_GEOMETRYCOLLECTIONZ: case GAIA_GEOMETRYCOLLECTIONM: case GAIA_GEOMETRYCOLLECTIONZM: geo->DeclaredType = GAIA_GEOMETRYCOLLECTION; break; default: geo->DeclaredType = GAIA_UNKNOWN; break; }; return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaFromSpatiaLiteBlobWkb (const unsigned char *blob, unsigned int size) { /* * decoding from SpatiaLite BLOB to GEOMETRY * convenience method - always disabling GPKG compatibility Modes */ return gaiaFromSpatiaLiteBlobWkbEx (blob, size, 0, 0); } static gaiaGeomCollPtr doParseTinyPointBlobMbr (const unsigned char *blob, unsigned int size) { /* decoding from SpatiaLite TinyPoint BLOB (MBR only) */ int little_endian; int endian_arch = gaiaEndianArch (); double x; double y; gaiaGeomCollPtr geo = NULL; gaiaPolygonPtr polyg; gaiaRingPtr ring; if (size < 24) return NULL; /* cannot be an internal BLOB TinyPoint geometry */ if (*(blob + 0) != GAIA_MARK_START) return NULL; /* failed to recognize START signature */ if (*(blob + (size - 1)) != GAIA_MARK_END) return NULL; /* failed to recognize END signature */ if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN) little_endian = 1; else if (*(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN) little_endian = 0; else return NULL; /* unknown encoding; nor little-endian neither big-endian */ x = gaiaImport64 (blob + 7, little_endian, endian_arch); y = gaiaImport64 (blob + 15, little_endian, endian_arch); geo = gaiaAllocGeomColl (); polyg = gaiaAddPolygonToGeomColl (geo, 5, 0); ring = polyg->Exterior; gaiaSetPoint (ring->Coords, 0, x, y); /* vertex # 1 */ gaiaSetPoint (ring->Coords, 1, x, y); /* vertex # 2 */ gaiaSetPoint (ring->Coords, 2, x, y); /* vertex # 3 */ gaiaSetPoint (ring->Coords, 3, x, y); /* vertex # 4 */ gaiaSetPoint (ring->Coords, 4, x, y); /* vertex # 5 [same as vertex # 1 to close the polygon] */ return geo; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaFromSpatiaLiteBlobMbr (const unsigned char *blob, unsigned int size) { /* decoding from SpatiaLite BLOB to GEOMETRY [MBR only] */ int little_endian; int endian_arch = gaiaEndianArch (); double minx; double miny; double maxx; double maxy; gaiaGeomCollPtr geo = NULL; gaiaPolygonPtr polyg; gaiaRingPtr ring; if (size == 24 || size == 32 || size == 40) { /* testing for a possible TinyPoint BLOB */ if (*(blob + 0) == GAIA_MARK_START && (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN) && *(blob + (size - 1)) == GAIA_MARK_END) return doParseTinyPointBlobMbr (blob, size); } if (size < 45) return NULL; /* cannot be an internal BLOB WKB geometry */ if (*(blob + 0) != GAIA_MARK_START) return NULL; /* failed to recognize START signature */ if (*(blob + (size - 1)) != GAIA_MARK_END) return NULL; /* failed to recognize END signature */ if (*(blob + 38) != GAIA_MARK_MBR) return NULL; /* failed to recognize MBR signature */ if (*(blob + 1) == GAIA_LITTLE_ENDIAN) little_endian = 1; else if (*(blob + 1) == GAIA_BIG_ENDIAN) little_endian = 0; else return NULL; /* unknown encoding; nor litte-endian neither big-endian */ geo = gaiaAllocGeomColl (); polyg = gaiaAddPolygonToGeomColl (geo, 5, 0); ring = polyg->Exterior; minx = gaiaImport64 (blob + 6, little_endian, endian_arch); miny = gaiaImport64 (blob + 14, little_endian, endian_arch); maxx = gaiaImport64 (blob + 22, little_endian, endian_arch); maxy = gaiaImport64 (blob + 30, little_endian, endian_arch); gaiaSetPoint (ring->Coords, 0, minx, miny); /* vertex # 1 */ gaiaSetPoint (ring->Coords, 1, maxx, miny); /* vertex # 2 */ gaiaSetPoint (ring->Coords, 2, maxx, maxy); /* vertex # 3 */ gaiaSetPoint (ring->Coords, 3, minx, maxy); /* vertex # 4 */ gaiaSetPoint (ring->Coords, 4, minx, miny); /* vertex # 5 [same as vertex # 1 to close the polygon] */ return geo; } GAIAGEO_DECLARE void gaiaToSpatiaLiteBlobWkbEx (gaiaGeomCollPtr geom, unsigned char **result, int *size, int gpkg_mode) { /* simply defaults to gaiaToSpatiaLiteBlobWkbEx2 tiny_point=FALSE */ gaiaToSpatiaLiteBlobWkbEx2 (geom, result, size, gpkg_mode, 0); } static void doEncodeTinyPointBlob (gaiaGeomCollPtr geom, unsigned char **result, int *size) { /* encoding a TinyPoint BLOB */ int sz; unsigned char *blob; unsigned char *ptr; int endian_arch = gaiaEndianArch (); gaiaPointPtr point = geom->FirstPoint; /* compunting the BLOB size */ if (geom->DimensionModel == GAIA_XY_Z) sz = 32; else if (geom->DimensionModel == GAIA_XY_M) sz = 32; else if (geom->DimensionModel == GAIA_XY_Z_M) sz = 40; else sz = 24; /* allocating the BLOB */ blob = malloc (sz); ptr = blob; /* and finally we build the BLOB */ *ptr = GAIA_MARK_START; /* START signature */ ptr++; *(ptr) = GAIA_TINYPOINT_LITTLE_ENDIAN; /* byte ordering */ ptr++; gaiaExport32 (ptr, geom->Srid, 1, endian_arch); /* the SRID */ ptr += 4; if (geom->DimensionModel == GAIA_XY_Z) *ptr = GAIA_TINYPOINT_XYZ; else if (geom->DimensionModel == GAIA_XY_M) *ptr = GAIA_TINYPOINT_XYM; else if (geom->DimensionModel == GAIA_XY_Z_M) *ptr = GAIA_TINYPOINT_XYZM; else *ptr = GAIA_TINYPOINT_XY; ptr++; gaiaExport64 (ptr, point->X, 1, endian_arch); /* X */ ptr += 8; gaiaExport64 (ptr, point->Y, 1, endian_arch); /* Y */ ptr += 8; if (geom->DimensionModel == GAIA_XY_Z) { gaiaExport64 (ptr, point->Z, 1, endian_arch); /* Z */ ptr += 8; } else if (geom->DimensionModel == GAIA_XY_M) { gaiaExport64 (ptr, point->M, 1, endian_arch); /* M */ ptr += 8; } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaExport64 (ptr, point->Z, 1, endian_arch); /* Z */ ptr += 8; gaiaExport64 (ptr, point->M, 1, endian_arch); /* M */ ptr += 8; } *ptr = GAIA_MARK_END; /* END signature */ *result = blob; *size = sz; } GAIAGEO_DECLARE void gaiaToSpatiaLiteBlobWkbEx2 (gaiaGeomCollPtr geom, unsigned char **result, int *size, int gpkg_mode, int tiny_point) { /* builds the SpatiaLite BLOB representation for this GEOMETRY */ int ib; int iv; double x; double y; double z = 0.0; double m = 0.0; int entities = 0; int n_points = 0; int n_linestrings = 0; int n_polygons = 0; int type; unsigned char *ptr; gaiaPointPtr pt; gaiaLinestringPtr ln; gaiaPolygonPtr pg; gaiaRingPtr rng; gaiaPointPtr point = NULL; gaiaLinestringPtr line = NULL; gaiaPolygonPtr polyg = NULL; int endian_arch = gaiaEndianArch (); gaiaMbrGeometry (geom); if (gpkg_mode) { #ifdef ENABLE_GEOPACKAGE /* only if GeoPackage support is enabled */ /* GeoPackage Mode enabled */ gaiaToGPB (geom, result, size); #endif /* end GEOPACKAGE conditional */ return; } /* how many entities, and of what kind, do we have ? */ pt = geom->FirstPoint; while (pt) { point = pt; entities++; n_points++; pt = pt->Next; } ln = geom->FirstLinestring; while (ln) { line = ln; entities++; n_linestrings++; ln = ln->Next; } pg = geom->FirstPolygon; while (pg) { polyg = pg; entities++; n_polygons++; pg = pg->Next; } *size = 0; *result = NULL; if (n_points == 0 && n_polygons == 0 && n_linestrings == 0) return; if (n_points == 1 && n_linestrings == 0 && n_polygons == 0 && entities == 1 && geom->DeclaredType != GAIA_MULTIPOINT && geom->DeclaredType != GAIA_GEOMETRYCOLLECTION && tiny_point) { /* using the TinyPoint BLOB encoding */ doEncodeTinyPointBlob (geom, result, size); return; } /* ok, we can determine the geometry class */ if (n_points == 1 && n_linestrings == 0 && n_polygons == 0) { if (geom->DeclaredType == GAIA_MULTIPOINT) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOINTZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOINTM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOINTZM; else type = GAIA_MULTIPOINT; } else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_POINTZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_POINTM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_POINTZM; else type = GAIA_POINT; } } else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOINTZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOINTM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOINTZM; else type = GAIA_MULTIPOINT; } } else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0) { if (geom->DeclaredType == GAIA_MULTILINESTRING) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTILINESTRINGZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTILINESTRINGM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTILINESTRINGZM; else type = GAIA_MULTILINESTRING; } else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_LINESTRINGZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_LINESTRINGM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_LINESTRINGZM; else type = GAIA_LINESTRING; } } else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTILINESTRINGZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTILINESTRINGM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTILINESTRINGZM; else type = GAIA_MULTILINESTRING; } } else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1) { if (geom->DeclaredType == GAIA_MULTIPOLYGON) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOLYGONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOLYGONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOLYGONZM; else type = GAIA_MULTIPOLYGON; } else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_POLYGONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_POLYGONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_POLYGONZM; else type = GAIA_POLYGON; } } else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOLYGONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOLYGONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOLYGONZM; else type = GAIA_MULTIPOLYGON; } } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } /* and now we compute the size of BLOB */ *size = 44; /* header size */ switch (type) { case GAIA_POINT: *size += (sizeof (double) * 2); /* [x,y] coords */ break; case GAIA_POINTZ: *size += (sizeof (double) * 3); /* [x,y,z] coords */ break; case GAIA_POINTM: *size += (sizeof (double) * 3); /* [x,y,m] coords */ break; case GAIA_POINTZM: *size += (sizeof (double) * 4); /* [x,y,z,m] coords */ break; case GAIA_LINESTRING: *size += (4 + ((sizeof (double) * 2) * line->Points)); /* # points + [x,y] for each vertex */ break; case GAIA_LINESTRINGZ: *size += (4 + ((sizeof (double) * 3) * line->Points)); /* # points + [x,y,z] for each vertex */ break; case GAIA_LINESTRINGM: *size += (4 + ((sizeof (double) * 3) * line->Points)); /* # points + [x,y,m] for each vertex */ break; case GAIA_LINESTRINGZM: *size += (4 + ((sizeof (double) * 4) * line->Points)); /* # points + [x,y,z,m] for each vertex */ break; case GAIA_POLYGON: rng = polyg->Exterior; *size += (8 + ((sizeof (double) * 2) * rng->Points)); /* # rings + # points + [x.y] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; *size += (4 + ((sizeof (double) * 2) * rng->Points)); /* # points + [x,y] array - interior ring */ } break; case GAIA_POLYGONZ: rng = polyg->Exterior; *size += (8 + ((sizeof (double) * 3) * rng->Points)); /* # rings + # points + [x,y,z] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; *size += (4 + ((sizeof (double) * 3) * rng->Points)); /* # points + [x,y,z] array - interior ring */ } break; case GAIA_POLYGONM: rng = polyg->Exterior; *size += (8 + ((sizeof (double) * 3) * rng->Points)); /* # rings + # points + [x,y,m] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; *size += (4 + ((sizeof (double) * 3) * rng->Points)); /* # points + [x,y,m] array - interior ring */ } break; case GAIA_POLYGONZM: rng = polyg->Exterior; *size += (8 + ((sizeof (double) * 4) * rng->Points)); /* # rings + # points + [x,y,z,m] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; *size += (4 + ((sizeof (double) * 4) * rng->Points)); /* # points + [x,y,z,m] array - interior ring */ } break; default: /* this one is not a simple geometry; should be a MULTIxxxx or a GEOMETRYCOLLECTION */ *size += 4; /* # entities */ point = geom->FirstPoint; while (point) { *size += 5; /* entity header */ if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) *size += (sizeof (double) * 3); /* three doubles for each POINT */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (sizeof (double) * 4); /* four doubles for each POINT */ else *size += (sizeof (double) * 2); /* two doubles for each POINT */ point = point->Next; } line = geom->FirstLinestring; while (line) { *size += 5; /* entity header */ if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) *size += (4 + ((sizeof (double) * 3) * line->Points)); /* # points + [x,y,z] for each vertex */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (4 + ((sizeof (double) * 4) * line->Points)); /* # points + [x,y,z,m] for each vertex */ else *size += (4 + ((sizeof (double) * 2) * line->Points)); /* # points + [x,y] for each vertex */ line = line->Next; } polyg = geom->FirstPolygon; while (polyg) { *size += 5; /* entity header */ rng = polyg->Exterior; if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) *size += (8 + ((sizeof (double) * 3) * rng->Points)); /* # rings + # points + [x,y,z] array - exterior ring */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (8 + ((sizeof (double) * 4) * rng->Points)); /* # rings + # points + [x,y,z,m] array - exterior ring */ else *size += (8 + ((sizeof (double) * 2) * rng->Points)); /* # rings + # points + [x,y] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) *size += (4 + ((sizeof (double) * 3) * rng->Points)); /* # points + [x,y,z] array - interior ring */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (4 + ((sizeof (double) * 4) * rng->Points)); /* # points + [x,y,z,m] array - interior ring */ else *size += (4 + ((sizeof (double) * 2) * rng->Points)); /* # points + [x,y] array - interior ring */ } polyg = polyg->Next; } }; *result = malloc (*size); ptr = *result; /* and finally we build the BLOB */ switch (type) { case GAIA_POINT: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POINT, 1, endian_arch); /* class POINT */ gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */ *(ptr + 59) = GAIA_MARK_END; /* END signature */ break; case GAIA_POINTZ: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POINTZ, 1, endian_arch); /* class POINT XYZ */ gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 59, point->Z, 1, endian_arch); /* Z */ *(ptr + 67) = GAIA_MARK_END; /* END signature */ break; case GAIA_POINTM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POINTM, 1, endian_arch); /* class POINT XYM */ gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 59, point->M, 1, endian_arch); /* M */ *(ptr + 67) = GAIA_MARK_END; /* END signature */ break; case GAIA_POINTZM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POINTZM, 1, endian_arch); /* class POINT XYZM */ gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 59, point->Z, 1, endian_arch); /* M */ gaiaExport64 (ptr + 67, point->M, 1, endian_arch); /* Z */ *(ptr + 75) = GAIA_MARK_END; /* END signature */ break; case GAIA_LINESTRING: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_LINESTRING, 1, endian_arch); /* class LINESTRING */ gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */ ptr += 47; for (iv = 0; iv < line->Points; iv++) { gaiaGetPoint (line->Coords, iv, &x, &y); gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); ptr += 16; } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_LINESTRINGZ: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_LINESTRINGZ, 1, endian_arch); /* class LINESTRING XYZ */ gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */ ptr += 47; for (iv = 0; iv < line->Points; iv++) { gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z); gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, z, 1, endian_arch); ptr += 24; } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_LINESTRINGM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_LINESTRINGM, 1, endian_arch); /* class LINESTRING XYM */ gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */ ptr += 47; for (iv = 0; iv < line->Points; iv++) { gaiaGetPointXYM (line->Coords, iv, &x, &y, &m); gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, m, 1, endian_arch); ptr += 24; } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_LINESTRINGZM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_LINESTRINGZM, 1, endian_arch); /* class LINESTRING XYZM */ gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */ ptr += 47; for (iv = 0; iv < line->Points; iv++) { gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m); gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, z, 1, endian_arch); gaiaExport64 (ptr + 24, m, 1, endian_arch); ptr += 32; } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_POLYGON: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POLYGON, 1, endian_arch); /* class POLYGON */ gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ rng = polyg->Exterior; gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */ ptr += 51; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPoint (rng->Coords, iv, &x, &y); gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */ ptr += 16; } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPoint (rng->Coords, iv, &x, &y); gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */ ptr += 16; } } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_POLYGONZ: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POLYGONZ, 1, endian_arch); /* class POLYGON XYZ */ gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ rng = polyg->Exterior; gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */ ptr += 51; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */ gaiaExport64 (ptr + 16, z, 1, endian_arch); /* Z - exterior ring */ ptr += 24; } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */ gaiaExport64 (ptr + 16, z, 1, endian_arch); /* Z - interior ring */ ptr += 24; } } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_POLYGONM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POLYGONM, 1, endian_arch); /* class POLYGON XYM */ gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ rng = polyg->Exterior; gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */ ptr += 51; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */ gaiaExport64 (ptr + 16, m, 1, endian_arch); /* M - exterior ring */ ptr += 24; } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */ gaiaExport64 (ptr + 16, m, 1, endian_arch); /* M - interior ring */ ptr += 24; } } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_POLYGONZM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POLYGONZM, 1, endian_arch); /* class POLYGON */ gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ rng = polyg->Exterior; gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */ ptr += 51; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */ gaiaExport64 (ptr + 16, z, 1, endian_arch); /* Z - exterior ring */ gaiaExport64 (ptr + 24, m, 1, endian_arch); /* M - exterior ring */ ptr += 32; } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */ gaiaExport64 (ptr + 16, z, 1, endian_arch); /* Z - exterior ring */ gaiaExport64 (ptr + 24, m, 1, endian_arch); /* M - exterior ring */ ptr += 32; } } *ptr = GAIA_MARK_END; /* END signature */ break; default: /* this one is a MULTIxxxx or a GEOMETRYCOLLECTION - building the main header */ *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, type, 1, endian_arch); /* geometric class */ gaiaExport32 (ptr + 43, entities, 1, endian_arch); /* # entities */ ptr += 47; point = geom->FirstPoint; while (point) { *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */ if (geom->DimensionModel == GAIA_XY_Z) { gaiaExport32 (ptr + 1, GAIA_POINTZ, 1, endian_arch); /* class POINT XYZ */ gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 21, point->Z, 1, endian_arch); /* Z */ ptr += 29; } else if (geom->DimensionModel == GAIA_XY_M) { gaiaExport32 (ptr + 1, GAIA_POINTM, 1, endian_arch); /* class POINT XYM */ gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 21, point->M, 1, endian_arch); /* M */ ptr += 29; } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaExport32 (ptr + 1, GAIA_POINTZM, 1, endian_arch); /* class POINT XYZM */ gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 21, point->Z, 1, endian_arch); /* Z */ gaiaExport64 (ptr + 29, point->M, 1, endian_arch); /* M */ ptr += 37; } else { gaiaExport32 (ptr + 1, GAIA_POINT, 1, endian_arch); /* class POINT */ gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */ ptr += 21; } point = point->Next; } line = geom->FirstLinestring; while (line) { *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */ if (geom->DimensionModel == GAIA_XY_Z) gaiaExport32 (ptr + 1, GAIA_LINESTRINGZ, 1, endian_arch); /* class LINESTRING XYZ */ else if (geom->DimensionModel == GAIA_XY_M) gaiaExport32 (ptr + 1, GAIA_LINESTRINGM, 1, endian_arch); /* class LINESTRING XYM */ else if (geom->DimensionModel == GAIA_XY_Z_M) gaiaExport32 (ptr + 1, GAIA_LINESTRINGZM, 1, endian_arch); /* class LINESTRING XYZM */ else gaiaExport32 (ptr + 1, GAIA_LINESTRING, 1, endian_arch); /* class LINESTRING */ gaiaExport32 (ptr + 5, line->Points, 1, endian_arch); /* # points */ ptr += 9; for (iv = 0; iv < line->Points; iv++) { if (geom->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z); } else if (geom->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (line->Coords, iv, &x, &y, &m); } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (line->Coords, iv, &x, &y); } gaiaExport64 (ptr, x, 1, endian_arch); /* X */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y */ ptr += 16; if (geom->DimensionModel == GAIA_XY_Z) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_M) { gaiaExport64 (ptr, m, 1, endian_arch); /* M */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M */ ptr += 16; } } line = line->Next; } polyg = geom->FirstPolygon; while (polyg) { *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */ if (geom->DimensionModel == GAIA_XY_Z) gaiaExport32 (ptr + 1, GAIA_POLYGONZ, 1, endian_arch); /* class POLYGON XYZ */ else if (geom->DimensionModel == GAIA_XY_M) gaiaExport32 (ptr + 1, GAIA_POLYGONM, 1, endian_arch); /* class POLYGON XYM */ else if (geom->DimensionModel == GAIA_XY_Z_M) gaiaExport32 (ptr + 1, GAIA_POLYGONZM, 1, endian_arch); /* class POLYGON XYZM */ else gaiaExport32 (ptr + 1, GAIA_POLYGON, 1, endian_arch); /* class POLYGON */ gaiaExport32 (ptr + 5, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ rng = polyg->Exterior; gaiaExport32 (ptr + 9, rng->Points, 1, endian_arch); /* # points - exterior ring */ ptr += 13; for (iv = 0; iv < rng->Points; iv++) { if (geom->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); } else if (geom->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (rng->Coords, iv, &x, &y); } gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */ ptr += 16; if (geom->DimensionModel == GAIA_XY_Z) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_M) { gaiaExport64 (ptr, m, 1, endian_arch); /* M */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M */ ptr += 16; } } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { if (geom->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); } else if (geom->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (rng->Coords, iv, &x, &y); } gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */ ptr += 16; if (geom->DimensionModel == GAIA_XY_Z) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_M) { gaiaExport64 (ptr, m, 1, endian_arch); /* M */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M */ ptr += 16; } } } polyg = polyg->Next; } *ptr = GAIA_MARK_END; /* END signature */ }; } GAIAGEO_DECLARE void gaiaToSpatiaLiteBlobWkb (gaiaGeomCollPtr geom, unsigned char **result, int *size) { /* * builds the SpatiaLite BLOB representation for this GEOMETRY * convenience method - always disabling GPKG compatibility Modes */ gaiaToSpatiaLiteBlobWkbEx (geom, result, size, 0); } GAIAGEO_DECLARE void gaiaToCompressedBlobWkb (gaiaGeomCollPtr geom, unsigned char **result, int *size) { /* / builds the SpatiaLite BLOB representation for this GEOMETRY / geometry-compression will be applied to LINESTRINGs and RINGs */ int ib; int iv; double x; double y; double z; double m; double last_x = 0.0; double last_y = 0.0; double last_z = 0.0; float fx; float fy; float fz; int entities = 0; int n_points = 0; int n_linestrings = 0; int n_polygons = 0; int type; unsigned char *ptr; gaiaPointPtr pt; gaiaLinestringPtr ln; gaiaPolygonPtr pg; gaiaRingPtr rng; gaiaPointPtr point = NULL; gaiaLinestringPtr line = NULL; gaiaPolygonPtr polyg = NULL; int endian_arch = gaiaEndianArch (); gaiaMbrGeometry (geom); /* how many entities, and of what kind, do we have ? */ pt = geom->FirstPoint; while (pt) { point = pt; entities++; n_points++; pt = pt->Next; } ln = geom->FirstLinestring; while (ln) { line = ln; entities++; n_linestrings++; ln = ln->Next; } pg = geom->FirstPolygon; while (pg) { polyg = pg; entities++; n_polygons++; pg = pg->Next; } *size = 0; *result = NULL; if (n_points == 0 && n_polygons == 0 && n_linestrings == 0) return; /* ok, we can determine the geometry class */ if (n_points == 1 && n_linestrings == 0 && n_polygons == 0) { if (geom->DeclaredType == GAIA_MULTIPOINT) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOINTZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOINTM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOINTZM; else type = GAIA_MULTIPOINT; } else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_POINTZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_POINTM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_POINTZM; else type = GAIA_POINT; } } else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOINTZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOINTM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOINTZM; else type = GAIA_MULTIPOINT; } } else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0) { if (geom->DeclaredType == GAIA_MULTILINESTRING) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTILINESTRINGZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTILINESTRINGM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTILINESTRINGZM; else type = GAIA_MULTILINESTRING; } else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_LINESTRINGZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_LINESTRINGM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_LINESTRINGZM; else type = GAIA_LINESTRING; } } else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTILINESTRINGZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTILINESTRINGM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTILINESTRINGZM; else type = GAIA_MULTILINESTRING; } } else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1) { if (geom->DeclaredType == GAIA_MULTIPOLYGON) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOLYGONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOLYGONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOLYGONZM; else type = GAIA_MULTIPOLYGON; } else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_POLYGONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_POLYGONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_POLYGONZM; else type = GAIA_POLYGON; } } else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOLYGONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOLYGONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOLYGONZM; else type = GAIA_MULTIPOLYGON; } } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } /* and now we compute the size of BLOB */ *size = 44; /* header size */ switch (type) { case GAIA_POINT: *size += (sizeof (double) * 2); /* [x,y] coords */ break; case GAIA_POINTZ: *size += (sizeof (double) * 3); /* [x,y,z] coords */ break; case GAIA_POINTM: *size += (sizeof (double) * 3); /* [x,y,m] coords */ break; case GAIA_POINTZM: *size += (sizeof (double) * 4); /* [x,y,z,m] coords */ break; case GAIA_LINESTRING: *size += (4 + (8 * line->Points) + 16); /* # points + [x,y] for each vertex */ break; case GAIA_LINESTRINGZ: *size += (4 + (12 * line->Points) + 24); /* # points + [x,y,z] for each vertex */ break; case GAIA_LINESTRINGM: *size += (4 + (16 * line->Points) + 16); /* # points + [x,y,m] for each vertex */ break; case GAIA_LINESTRINGZM: *size += (4 + (20 * line->Points) + 24); /* # points + [x,y,z,m] for each vertex */ break; case GAIA_POLYGON: rng = polyg->Exterior; *size += (8 + (8 * rng->Points) + 16); /* # rings + # points + [x.y] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; *size += (4 + (8 * rng->Points) + 16); /* # points + [x,y] array - interior ring */ } break; case GAIA_POLYGONZ: rng = polyg->Exterior; *size += (8 + (12 * rng->Points) + 24); /* # rings + # points + [x,y,z] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; *size += (4 + (12 * rng->Points) + 24); /* # points + [x,y,z] array - interior ring */ } break; case GAIA_POLYGONM: rng = polyg->Exterior; *size += (8 + (16 * rng->Points) + 16); /* # rings + # points + [x,y,m] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; *size += (4 + (16 * rng->Points) + 16); /* # points + [x,y,m] array - interior ring */ } break; case GAIA_POLYGONZM: rng = polyg->Exterior; *size += (8 + (20 * rng->Points) + 24); /* # rings + # points + [x,y,z,m] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; *size += (4 + (20 * rng->Points) + 24); /* # points + [x,y,z,m] array - interior ring */ } break; default: /* this one is not a simple geometry; should be a MULTIxxxx or a GEOMETRYCOLLECTION */ *size += 4; /* # entities */ point = geom->FirstPoint; while (point) { *size += 5; /* entity header */ if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) *size += (sizeof (double) * 3); /* three doubles for each POINT */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (sizeof (double) * 4); /* four doubles for each POINT */ else *size += (sizeof (double) * 2); /* two doubles for each POINT */ point = point->Next; } line = geom->FirstLinestring; while (line) { *size += 5; /* entity header */ if (geom->DimensionModel == GAIA_XY_Z) *size += (4 + (12 * line->Points) + 24); /* # points + [x,y,z] for each vertex */ else if (geom->DimensionModel == GAIA_XY_M) *size += (4 + (16 * line->Points) + 16); /* # points + [x,y,m] for each vertex */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (4 + (20 * line->Points) + 24); /* # points + [x,y,z,m] for each vertex */ else *size += (4 + (8 * line->Points) + 16); /* # points + [x,y] for each vertex */ line = line->Next; } polyg = geom->FirstPolygon; while (polyg) { *size += 5; /* entity header */ rng = polyg->Exterior; if (geom->DimensionModel == GAIA_XY_Z) *size += (8 + (12 * rng->Points) + 24); /* # rings + # points + [x,y,z] array - exterior ring */ else if (geom->DimensionModel == GAIA_XY_M) *size += (8 + (16 * rng->Points) + 16); /* # rings + # points + [x,y,m] array - exterior ring */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (8 + (20 * rng->Points) + 24); /* # rings + # points + [x,y,z,m] array - exterior ring */ else *size += (8 + (8 * rng->Points) + 16); /* # rings + # points + [x,y] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; if (geom->DimensionModel == GAIA_XY_Z) *size += (4 + (12 * rng->Points) + 24); /* # points + [x,y,z] array - interior ring */ else if (geom->DimensionModel == GAIA_XY_M) *size += (4 + (16 * rng->Points) + 16); /* # points + [x,y,m] array - interior ring */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (4 + (20 * rng->Points) + 24); /* # points + [x,y,z,m] array - interior ring */ else *size += (4 + (8 * rng->Points) + 16); /* # points + [x,y] array - interior ring */ } polyg = polyg->Next; } }; *result = malloc (*size); ptr = *result; /* and finally we build the BLOB */ switch (type) { case GAIA_POINT: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POINT, 1, endian_arch); /* class POINT */ gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */ *(ptr + 59) = GAIA_MARK_END; /* END signature */ break; case GAIA_POINTZ: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POINTZ, 1, endian_arch); /* class POINT XYZ */ gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 59, point->Z, 1, endian_arch); /* Z */ *(ptr + 67) = GAIA_MARK_END; /* END signature */ break; case GAIA_POINTM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POINTM, 1, endian_arch); /* class POINT XYM */ gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 59, point->M, 1, endian_arch); /* M */ *(ptr + 67) = GAIA_MARK_END; /* END signature */ break; case GAIA_POINTZM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_POINTZM, 1, endian_arch); /* class POINT XYZM */ gaiaExport64 (ptr + 43, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 51, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 59, point->Z, 1, endian_arch); /* M */ gaiaExport64 (ptr + 67, point->M, 1, endian_arch); /* Z */ *(ptr + 75) = GAIA_MARK_END; /* END signature */ break; case GAIA_LINESTRING: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRING, 1, endian_arch); /* class LINESTRING */ gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */ ptr += 47; for (iv = 0; iv < line->Points; iv++) { gaiaGetPoint (line->Coords, iv, &x, &y); if (iv == 0 || iv == (line->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); ptr += 16; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); ptr += 8; } last_x = x; last_y = y; } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_LINESTRINGZ: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRINGZ, 1, endian_arch); /* class LINESTRING XYZ */ gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */ ptr += 47; for (iv = 0; iv < line->Points; iv++) { gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z); if (iv == 0 || iv == (line->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, z, 1, endian_arch); ptr += 24; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); fz = (float) (z - last_z); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); gaiaExportF32 (ptr + 8, fz, 1, endian_arch); ptr += 12; } last_x = x; last_y = y; last_z = z; } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_LINESTRINGM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRINGM, 1, endian_arch); /* class LINESTRING XYM */ gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */ ptr += 47; for (iv = 0; iv < line->Points; iv++) { gaiaGetPointXYM (line->Coords, iv, &x, &y, &m); if (iv == 0 || iv == (line->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, m, 1, endian_arch); ptr += 24; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); gaiaExport64 (ptr + 8, m, 1, endian_arch); ptr += 16; } last_x = x; last_y = y; } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_LINESTRINGZM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRINGZM, 1, endian_arch); /* class LINESTRING XYZM */ gaiaExport32 (ptr + 43, line->Points, 1, endian_arch); /* # points */ ptr += 47; for (iv = 0; iv < line->Points; iv++) { gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m); if (iv == 0 || iv == (line->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, z, 1, endian_arch); gaiaExport64 (ptr + 24, m, 1, endian_arch); ptr += 32; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); fz = (float) (z - last_z); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); gaiaExportF32 (ptr + 8, fz, 1, endian_arch); gaiaExport64 (ptr + 12, m, 1, endian_arch); ptr += 20; } last_x = x; last_y = y; last_z = z; } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_POLYGON: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGON, 1, endian_arch); /* class POLYGON */ gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ rng = polyg->Exterior; gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */ ptr += 51; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPoint (rng->Coords, iv, &x, &y); if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); ptr += 16; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); ptr += 8; } last_x = x; last_y = y; } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPoint (rng->Coords, iv, &x, &y); if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); ptr += 16; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); ptr += 8; } last_x = x; last_y = y; } } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_POLYGONZ: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGONZ, 1, endian_arch); /* class POLYGON XYZ */ gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ rng = polyg->Exterior; gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */ ptr += 51; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, z, 1, endian_arch); ptr += 24; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); fz = (float) (z - last_z); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); gaiaExportF32 (ptr + 8, fz, 1, endian_arch); ptr += 12; } last_x = x; last_y = y; last_z = z; } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, z, 1, endian_arch); ptr += 24; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); fz = (float) (z - last_z); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); gaiaExportF32 (ptr + 8, fz, 1, endian_arch); ptr += 12; } last_x = x; last_y = y; last_z = z; } } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_POLYGONM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGONM, 1, endian_arch); /* class POLYGON XYM */ gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ rng = polyg->Exterior; gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */ ptr += 51; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, m, 1, endian_arch); ptr += 24; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); gaiaExport64 (ptr + 8, m, 1, endian_arch); ptr += 16; } last_x = x; last_y = y; } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, m, 1, endian_arch); ptr += 24; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); gaiaExport64 (ptr + 8, m, 1, endian_arch); ptr += 16; } last_x = x; last_y = y; } } *ptr = GAIA_MARK_END; /* END signature */ break; case GAIA_POLYGONZM: *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGONZM, 1, endian_arch); /* class POLYGON */ gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ rng = polyg->Exterior; gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch); /* # points - exterior ring */ ptr += 51; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, z, 1, endian_arch); gaiaExport64 (ptr + 24, m, 1, endian_arch); ptr += 32; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); fz = (float) (z - last_z); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); gaiaExportF32 (ptr + 8, fz, 1, endian_arch); gaiaExport64 (ptr + 12, m, 1, endian_arch); ptr += 20; } last_x = x; last_y = y; last_z = z; } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); gaiaExport64 (ptr + 8, y, 1, endian_arch); gaiaExport64 (ptr + 16, z, 1, endian_arch); gaiaExport64 (ptr + 24, m, 1, endian_arch); ptr += 32; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); fz = (float) (z - last_z); gaiaExportF32 (ptr, fx, 1, endian_arch); gaiaExportF32 (ptr + 4, fy, 1, endian_arch); gaiaExportF32 (ptr + 8, fz, 1, endian_arch); gaiaExport64 (ptr + 12, m, 1, endian_arch); ptr += 20; } last_x = x; last_y = y; last_z = z; } } *ptr = GAIA_MARK_END; /* END signature */ break; default: /* this one is a MULTIxxxx or a GEOMETRYCOLLECTION - building the main header */ *ptr = GAIA_MARK_START; /* START signature */ *(ptr + 1) = GAIA_LITTLE_ENDIAN; /* byte ordering */ gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch); /* the SRID */ gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch); /* MBR - minimum X */ gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch); /* MBR - minimum Y */ gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch); /* MBR - maximum X */ gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch); /* MBR - maximum Y */ *(ptr + 38) = GAIA_MARK_MBR; /* MBR signature */ gaiaExport32 (ptr + 39, type, 1, endian_arch); /* geometric class */ gaiaExport32 (ptr + 43, entities, 1, endian_arch); /* # entities */ ptr += 47; point = geom->FirstPoint; while (point) { *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */ if (geom->DimensionModel == GAIA_XY_Z) { gaiaExport32 (ptr + 1, GAIA_POINTZ, 1, endian_arch); /* class POINT XYZ */ gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 21, point->Z, 1, endian_arch); /* Z */ ptr += 29; } else if (geom->DimensionModel == GAIA_XY_M) { gaiaExport32 (ptr + 1, GAIA_POINTM, 1, endian_arch); /* class POINT XYM */ gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 21, point->M, 1, endian_arch); /* M */ ptr += 29; } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaExport32 (ptr + 1, GAIA_POINTZM, 1, endian_arch); /* class POINT XYZM */ gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */ gaiaExport64 (ptr + 21, point->Z, 1, endian_arch); /* Z */ gaiaExport64 (ptr + 29, point->M, 1, endian_arch); /* M */ ptr += 37; } else { gaiaExport32 (ptr + 1, GAIA_POINT, 1, endian_arch); /* class POINT */ gaiaExport64 (ptr + 5, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 13, point->Y, 1, endian_arch); /* Y */ ptr += 21; } point = point->Next; } line = geom->FirstLinestring; while (line) { *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */ if (geom->DimensionModel == GAIA_XY_Z) gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRINGZ, 1, endian_arch); /* class LINESTRING XYZ */ else if (geom->DimensionModel == GAIA_XY_M) gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRINGM, 1, endian_arch); /* class LINESTRING XYM */ else if (geom->DimensionModel == GAIA_XY_Z_M) gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRINGZM, 1, endian_arch); /* class LINESTRING XYZM */ else gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRING, 1, endian_arch); /* class LINESTRING */ gaiaExport32 (ptr + 5, line->Points, 1, endian_arch); /* # points */ ptr += 9; for (iv = 0; iv < line->Points; iv++) { z = 0.0; m = 0.0; if (geom->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z); } else if (geom->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (line->Coords, iv, &x, &y, &m); } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (line->Coords, iv, &x, &y); } if (iv == 0 || iv == (line->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); /* X */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y */ ptr += 16; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); gaiaExportF32 (ptr, fx, 1, endian_arch); /* X */ gaiaExportF32 (ptr + 4, fy, 1, endian_arch); /* Y */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_Z) { if (iv == 0 || iv == (line->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ ptr += 8; } else { /* compressing any other intermediate vertex */ fz = (float) (z - last_z); gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */ ptr += 4; } } if (geom->DimensionModel == GAIA_XY_M) { gaiaExport64 (ptr, m, 1, endian_arch); /* M */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_Z_M) { if (iv == 0 || iv == (line->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ ptr += 8; } else { /* compressing any other intermediate vertex */ fz = (float) (z - last_z); gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */ ptr += 4; } gaiaExport64 (ptr, m, 1, endian_arch); /* M */ ptr += 8; } last_x = x; last_y = y; last_z = z; } line = line->Next; } polyg = geom->FirstPolygon; while (polyg) { *ptr = GAIA_MARK_ENTITY; /* ENTITY signature */ if (geom->DimensionModel == GAIA_XY_Z) gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGONZ, 1, endian_arch); /* class POLYGON XYZ */ else if (geom->DimensionModel == GAIA_XY_M) gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGONM, 1, endian_arch); /* class POLYGON XYM */ else if (geom->DimensionModel == GAIA_XY_Z_M) gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGONZM, 1, endian_arch); /* class POLYGON XYZM */ else gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGON, 1, endian_arch); /* class POLYGON */ gaiaExport32 (ptr + 5, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ rng = polyg->Exterior; gaiaExport32 (ptr + 9, rng->Points, 1, endian_arch); /* # points - exterior ring */ ptr += 13; for (iv = 0; iv < rng->Points; iv++) { z = 0.0; m = 0.0; if (geom->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); } else if (geom->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (rng->Coords, iv, &x, &y); } if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */ ptr += 16; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); gaiaExportF32 (ptr, fx, 1, endian_arch); /* X */ gaiaExportF32 (ptr + 4, fy, 1, endian_arch); /* Y */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_Z) { if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ ptr += 8; } else { /* compressing any other intermediate vertex */ fz = (float) (z - last_z); gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */ ptr += 4; } } if (geom->DimensionModel == GAIA_XY_M) { gaiaExport64 (ptr, m, 1, endian_arch); /* M */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_Z_M) { if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ ptr += 8; } else { /* compressing any other intermediate vertex */ fz = (float) (z - last_z); gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */ ptr += 4; } gaiaExport64 (ptr, m, 1, endian_arch); /* M */ ptr += 8; } last_x = x; last_y = y; last_z = z; } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { z = 0.0; m = 0.0; if (geom->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); } else if (geom->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (rng->Coords, iv, &x, &y); } if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */ ptr += 16; } else { /* compressing any other intermediate vertex */ fx = (float) (x - last_x); fy = (float) (y - last_y); gaiaExportF32 (ptr, fx, 1, endian_arch); /* X */ gaiaExportF32 (ptr + 4, fy, 1, endian_arch); /* Y */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_Z) { if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ ptr += 8; } else { /* compressing any other intermediate vertex */ fz = (float) (z - last_z); gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */ ptr += 4; } } if (geom->DimensionModel == GAIA_XY_M) { gaiaExport64 (ptr, m, 1, endian_arch); /* M */ ptr += 8; } if (geom->DimensionModel == GAIA_XY_Z_M) { if (iv == 0 || iv == (rng->Points - 1)) { /* first and last vertices are uncompressed */ gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ ptr += 8; } else { /* compressing any other intermediate vertex */ fz = (float) (z - last_z); gaiaExportF32 (ptr, fz, 1, endian_arch); /* Z */ ptr += 4; } gaiaExport64 (ptr, m, 1, endian_arch); /* M */ ptr += 8; } last_x = x; last_y = y; last_z = z; } } polyg = polyg->Next; } *ptr = GAIA_MARK_END; /* END signature */ }; } static int count_elementaries (gaiaGeomCollPtr geo) { /* counint how many elementary items are there */ gaiaPointPtr pt; gaiaLinestringPtr ln; gaiaPolygonPtr pg; int pts = 0; int lns = 0; int pgs = 0; pt = geo->FirstPoint; while (pt != NULL) { /* counting Points */ pts++; pt = pt->Next; } ln = geo->FirstLinestring; while (ln != NULL) { /* counting Linestring */ lns++; ln = ln->Next; } pg = geo->FirstPolygon; while (pg != NULL) { /* counting Polygons */ pgs++; pg = pg->Next; } return pts + lns + pgs; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaFromWkb (const unsigned char *blob, unsigned int size) { /* decoding from WKB to GEOMETRY */ int type; int little_endian; gaiaGeomCollPtr geo = NULL; int endian_arch = gaiaEndianArch (); if (size < 5) return NULL; if (*(blob + 0) == 0x01) little_endian = GAIA_LITTLE_ENDIAN; else little_endian = GAIA_BIG_ENDIAN; type = gaiaImport32 (blob + 1, little_endian, endian_arch); if (type == GAIA_POINTZ || type == GAIA_LINESTRINGZ || type == GAIA_POLYGONZ || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ || type == GAIA_GEOSWKB_POINTZ || type == GAIA_GEOSWKB_LINESTRINGZ || type == GAIA_GEOSWKB_POLYGONZ || type == GAIA_GEOSWKB_MULTIPOINTZ || type == GAIA_GEOSWKB_MULTILINESTRINGZ || type == GAIA_GEOSWKB_MULTIPOLYGONZ || type == GAIA_GEOSWKB_GEOMETRYCOLLECTIONZ) geo = gaiaAllocGeomCollXYZ (); else if (type == GAIA_POINTM || type == GAIA_LINESTRINGM || type == GAIA_POLYGONM || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM) geo = gaiaAllocGeomCollXYM (); else if (type == GAIA_POINTZM || type == GAIA_LINESTRINGZM || type == GAIA_POLYGONZM || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) geo = gaiaAllocGeomCollXYZM (); else geo = gaiaAllocGeomColl (); geo->Srid = 0; geo->endian_arch = (char) endian_arch; geo->endian = (char) little_endian; geo->blob = blob; geo->size = size; geo->offset = 5; switch (type) { case GAIA_POINT: ParseWkbPoint (geo); break; case GAIA_POINTZ: case GAIA_GEOSWKB_POINTZ: ParseWkbPointZ (geo); break; case GAIA_POINTM: ParseWkbPointM (geo); break; case GAIA_POINTZM: ParseWkbPointZM (geo); break; case GAIA_LINESTRING: ParseWkbLine (geo); break; case GAIA_LINESTRINGZ: case GAIA_GEOSWKB_LINESTRINGZ: ParseWkbLineZ (geo); break; case GAIA_LINESTRINGM: ParseWkbLineM (geo); break; case GAIA_LINESTRINGZM: ParseWkbLineZM (geo); break; case GAIA_POLYGON: ParseWkbPolygon (geo); break; case GAIA_POLYGONZ: case GAIA_GEOSWKB_POLYGONZ: ParseWkbPolygonZ (geo); break; case GAIA_POLYGONM: ParseWkbPolygonM (geo); break; case GAIA_POLYGONZM: ParseWkbPolygonZM (geo); break; case GAIA_MULTIPOINT: case GAIA_MULTILINESTRING: case GAIA_MULTIPOLYGON: case GAIA_GEOMETRYCOLLECTION: case GAIA_MULTIPOINTZ: case GAIA_MULTILINESTRINGZ: case GAIA_MULTIPOLYGONZ: case GAIA_GEOMETRYCOLLECTIONZ: case GAIA_GEOSWKB_MULTIPOINTZ: case GAIA_GEOSWKB_MULTILINESTRINGZ: case GAIA_GEOSWKB_MULTIPOLYGONZ: case GAIA_GEOSWKB_GEOMETRYCOLLECTIONZ: case GAIA_MULTIPOINTM: case GAIA_MULTILINESTRINGM: case GAIA_MULTIPOLYGONM: case GAIA_GEOMETRYCOLLECTIONM: case GAIA_MULTIPOINTZM: case GAIA_MULTILINESTRINGZM: case GAIA_MULTIPOLYGONZM: case GAIA_GEOMETRYCOLLECTIONZM: ParseWkbGeometry (geo, 1); break; default: break; }; gaiaMbrGeometry (geo); switch (type) { case GAIA_POINT: case GAIA_POINTZ: case GAIA_GEOSWKB_POINTZ: case GAIA_POINTM: case GAIA_POINTZM: geo->DeclaredType = GAIA_POINT; break; case GAIA_LINESTRING: case GAIA_LINESTRINGZ: case GAIA_GEOSWKB_LINESTRINGZ: case GAIA_LINESTRINGM: case GAIA_LINESTRINGZM: geo->DeclaredType = GAIA_LINESTRING; break; case GAIA_POLYGON: case GAIA_POLYGONZ: case GAIA_GEOSWKB_POLYGONZ: case GAIA_POLYGONM: case GAIA_POLYGONZM: geo->DeclaredType = GAIA_POLYGON; break; case GAIA_MULTIPOINT: case GAIA_MULTIPOINTZ: case GAIA_GEOSWKB_MULTIPOINTZ: case GAIA_MULTIPOINTM: case GAIA_MULTIPOINTZM: geo->DeclaredType = GAIA_MULTIPOINT; break; case GAIA_MULTILINESTRING: case GAIA_MULTILINESTRINGZ: case GAIA_GEOSWKB_MULTILINESTRINGZ: case GAIA_MULTILINESTRINGM: case GAIA_MULTILINESTRINGZM: geo->DeclaredType = GAIA_MULTILINESTRING; break; case GAIA_MULTIPOLYGON: case GAIA_MULTIPOLYGONZ: case GAIA_GEOSWKB_MULTIPOLYGONZ: case GAIA_MULTIPOLYGONM: case GAIA_MULTIPOLYGONZM: geo->DeclaredType = GAIA_MULTIPOLYGON; break; case GAIA_GEOMETRYCOLLECTION: case GAIA_GEOMETRYCOLLECTIONZ: case GAIA_GEOSWKB_GEOMETRYCOLLECTIONZ: case GAIA_GEOMETRYCOLLECTIONM: case GAIA_GEOMETRYCOLLECTIONZM: geo->DeclaredType = GAIA_GEOMETRYCOLLECTION; break; } /* sandro 2024-02-24: final sanity check */ if (count_elementaries (geo) == 0) { /* this is an illegal empty Geometry !!! */ gaiaFreeGeomColl (geo); return NULL; } return geo; } GAIAGEO_DECLARE char * gaiaToHexWkb (gaiaGeomCollPtr geom) { /* builds the hexadecimal WKB representation for this GEOMETRY */ unsigned char *wkb = NULL; int size = 0; char *hexbuf = NULL; int i; char hex[16]; char *p; gaiaToWkb (geom, &wkb, &size); if (!wkb) return NULL; hexbuf = malloc ((size * 2) + 1); p = hexbuf; for (i = 0; i < size; i++) { sprintf (hex, "%02X", *(wkb + i)); *p++ = hex[0]; *p++ = hex[1]; } *p = '\0'; return hexbuf; } GAIAGEO_DECLARE void gaiaToWkb (gaiaGeomCollPtr geom, unsigned char **result, int *size) { /* builds the WKB representation for this GEOMETRY */ int ib; int iv; double x; double y; double z = 0.0; double m = 0.0; int entities = 0; int n_points = 0; int n_linestrings = 0; int n_polygons = 0; int type; unsigned char *ptr; gaiaPointPtr pt; gaiaLinestringPtr ln; gaiaPolygonPtr pg; gaiaRingPtr rng; gaiaPointPtr point = NULL; gaiaLinestringPtr line = NULL; gaiaPolygonPtr polyg = NULL; int endian_arch = gaiaEndianArch (); gaiaMbrGeometry (geom); /* how many entities, and of what kind, do we have ? */ pt = geom->FirstPoint; while (pt) { point = pt; entities++; n_points++; pt = pt->Next; } ln = geom->FirstLinestring; while (ln) { line = ln; entities++; n_linestrings++; ln = ln->Next; } pg = geom->FirstPolygon; while (pg) { polyg = pg; entities++; n_polygons++; pg = pg->Next; } *size = 0; *result = NULL; if (n_points == 0 && n_polygons == 0 && n_linestrings == 0) return; /* ok, we can determine the geometry class */ if (n_points == 1 && n_linestrings == 0 && n_polygons == 0) { if (geom->DeclaredType == GAIA_MULTIPOINT) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOINTZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOINTM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOINTZM; else type = GAIA_MULTIPOINT; } else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_POINTZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_POINTM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_POINTZM; else type = GAIA_POINT; } } else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOINTZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOINTM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOINTZM; else type = GAIA_MULTIPOINT; } } else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0) { if (geom->DeclaredType == GAIA_MULTILINESTRING) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTILINESTRINGZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTILINESTRINGM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTILINESTRINGZM; else type = GAIA_MULTILINESTRING; } else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_LINESTRINGZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_LINESTRINGM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_LINESTRINGZM; else type = GAIA_LINESTRING; } } else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTILINESTRINGZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTILINESTRINGM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTILINESTRINGZM; else type = GAIA_MULTILINESTRING; } } else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1) { if (geom->DeclaredType == GAIA_MULTIPOLYGON) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOLYGONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOLYGONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOLYGONZM; else type = GAIA_MULTIPOLYGON; } else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_POLYGONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_POLYGONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_POLYGONZM; else type = GAIA_POLYGON; } } else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_MULTIPOLYGONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_MULTIPOLYGONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_MULTIPOLYGONZM; else type = GAIA_MULTIPOLYGON; } } else { if (geom->DimensionModel == GAIA_XY_Z) type = GAIA_GEOMETRYCOLLECTIONZ; else if (geom->DimensionModel == GAIA_XY_M) type = GAIA_GEOMETRYCOLLECTIONM; else if (geom->DimensionModel == GAIA_XY_Z_M) type = GAIA_GEOMETRYCOLLECTIONZM; else type = GAIA_GEOMETRYCOLLECTION; } /* and now we compute the size of WKB */ *size = 5; /* header size */ if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) *size += 4; point = geom->FirstPoint; while (point) { if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) *size += 5; if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) *size += (sizeof (double) * 3); /* three doubles for each POINT */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (sizeof (double) * 4); /* four doubles for each POINT */ else *size += (sizeof (double) * 2); /* two doubles for each POINT */ point = point->Next; } line = geom->FirstLinestring; while (line) { if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) *size += 5; if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) *size += (4 + ((sizeof (double) * 3) * line->Points)); /* # points + [x,y,z] for each vertex */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (4 + ((sizeof (double) * 4) * line->Points)); /* # points + [x,y,z,m] for each vertex */ else *size += (4 + ((sizeof (double) * 2) * line->Points)); /* # points + [x,y] for each vertex */ line = line->Next; } polyg = geom->FirstPolygon; while (polyg) { if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) *size += 5; rng = polyg->Exterior; if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) *size += (8 + ((sizeof (double) * 3) * rng->Points)); /* # rings + # points + [x,y,z] array - exterior ring */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (8 + ((sizeof (double) * 4) * rng->Points)); /* # rings + # points + [x,y,z,m] array - exterior ring */ else *size += (8 + ((sizeof (double) * 2) * rng->Points)); /* # rings + # points + [x,y] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) *size += (4 + ((sizeof (double) * 3) * rng->Points)); /* # points + [x,y,z] array - interior ring */ else if (geom->DimensionModel == GAIA_XY_Z_M) *size += (4 + ((sizeof (double) * 4) * rng->Points)); /* # points + [x,y,z,m] array - interior ring */ else *size += (4 + ((sizeof (double) * 2) * rng->Points)); /* # points + [x,y] array - interior ring */ } polyg = polyg->Next; } *result = malloc (*size); ptr = *result; /* and finally we build the WKB */ *ptr = 0x01; /* little endian byte order */ gaiaExport32 (ptr + 1, type, 1, endian_arch); /* the main CLASS TYPE */ ptr += 5; if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) { gaiaExport32 (ptr, entities, 1, endian_arch); /* it's a collection; # entities */ ptr += 4; } point = geom->FirstPoint; while (point) { if (type == GAIA_MULTIPOINT || type == GAIA_GEOMETRYCOLLECTION || type == GAIA_MULTIPOINTZ || type == GAIA_GEOMETRYCOLLECTIONZ || type == GAIA_MULTIPOINTM || type == GAIA_GEOMETRYCOLLECTIONM || type == GAIA_MULTIPOINTZM || type == GAIA_GEOMETRYCOLLECTIONZM) { *ptr = 0x01; /* it's a collection: the CLASS TYPE for this element */ if (type == GAIA_MULTIPOINTZ || type == GAIA_GEOMETRYCOLLECTIONZ) gaiaExport32 (ptr + 1, GAIA_POINTZ, 1, endian_arch); else if (type == GAIA_MULTIPOINTM || type == GAIA_GEOMETRYCOLLECTIONM) gaiaExport32 (ptr + 1, GAIA_POINTM, 1, endian_arch); else if (type == GAIA_MULTIPOINTZM || type == GAIA_GEOMETRYCOLLECTIONZM) gaiaExport32 (ptr + 1, GAIA_POINTZM, 1, endian_arch); else gaiaExport32 (ptr + 1, GAIA_POINT, 1, endian_arch); ptr += 5; } gaiaExport64 (ptr, point->X, 1, endian_arch); /* X */ gaiaExport64 (ptr + 8, point->Y, 1, endian_arch); /* Y */ ptr += 16; if (type == GAIA_POINTZ || type == GAIA_MULTIPOINTZ || type == GAIA_GEOMETRYCOLLECTIONZ) { gaiaExport64 (ptr, point->Z, 1, endian_arch); /* Z */ ptr += 8; } if (type == GAIA_POINTM || type == GAIA_MULTIPOINTM || type == GAIA_GEOMETRYCOLLECTIONM) { gaiaExport64 (ptr, point->M, 1, endian_arch); /* M */ ptr += 8; } if (type == GAIA_POINTZM || type == GAIA_MULTIPOINTZM || type == GAIA_GEOMETRYCOLLECTIONZM) { gaiaExport64 (ptr, point->Z, 1, endian_arch); /* Z */ gaiaExport64 (ptr + 8, point->M, 1, endian_arch); /* M */ ptr += 16; } point = point->Next; } line = geom->FirstLinestring; while (line) { if (type == GAIA_MULTILINESTRING || type == GAIA_GEOMETRYCOLLECTION || type == GAIA_MULTILINESTRINGZ || type == GAIA_GEOMETRYCOLLECTIONZ || type == GAIA_MULTILINESTRINGM || type == GAIA_GEOMETRYCOLLECTIONM || type == GAIA_MULTILINESTRINGZM || type == GAIA_GEOMETRYCOLLECTIONZM) { *ptr = 0x01; /* it's a collection: the CLASS TYPE for this element */ if (type == GAIA_MULTILINESTRINGZ || type == GAIA_GEOMETRYCOLLECTIONZ) gaiaExport32 (ptr + 1, GAIA_LINESTRINGZ, 1, endian_arch); else if (type == GAIA_MULTILINESTRINGM || type == GAIA_GEOMETRYCOLLECTIONM) gaiaExport32 (ptr + 1, GAIA_LINESTRINGM, 1, endian_arch); else if (type == GAIA_MULTILINESTRINGZM || type == GAIA_GEOMETRYCOLLECTIONZM) gaiaExport32 (ptr + 1, GAIA_LINESTRINGZM, 1, endian_arch); else gaiaExport32 (ptr + 1, GAIA_LINESTRING, 1, endian_arch); ptr += 5; } gaiaExport32 (ptr, line->Points, 1, endian_arch); /* # points */ ptr += 4; for (iv = 0; iv < line->Points; iv++) { if (type == GAIA_LINESTRINGZ || type == GAIA_MULTILINESTRINGZ || type == GAIA_GEOMETRYCOLLECTIONZ) { gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z); } else if (type == GAIA_LINESTRINGM || type == GAIA_MULTILINESTRINGM || type == GAIA_GEOMETRYCOLLECTIONM) { gaiaGetPointXYM (line->Coords, iv, &x, &y, &m); } else if (type == GAIA_LINESTRINGZM || type == GAIA_MULTILINESTRINGZM || type == GAIA_GEOMETRYCOLLECTIONZM) { gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (line->Coords, iv, &x, &y); } gaiaExport64 (ptr, x, 1, endian_arch); /* X */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y */ ptr += 16; if (type == GAIA_LINESTRINGZ || type == GAIA_MULTILINESTRINGZ || type == GAIA_GEOMETRYCOLLECTIONZ) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ ptr += 8; } if (type == GAIA_LINESTRINGM || type == GAIA_MULTILINESTRINGM || type == GAIA_GEOMETRYCOLLECTIONM) { gaiaExport64 (ptr, m, 1, endian_arch); /* M */ ptr += 8; } if (type == GAIA_LINESTRINGZM || type == GAIA_MULTILINESTRINGZM || type == GAIA_GEOMETRYCOLLECTIONZM) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z */ gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M */ ptr += 16; } } line = line->Next; } polyg = geom->FirstPolygon; while (polyg) { if (type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) { *ptr = 0x01; /* it's a collection: the CLASS TYPE for this element */ if (type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ) gaiaExport32 (ptr + 1, GAIA_POLYGONZ, 1, endian_arch); else if (type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM) gaiaExport32 (ptr + 1, GAIA_POLYGONM, 1, endian_arch); else if (type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) gaiaExport32 (ptr + 1, GAIA_POLYGONZM, 1, endian_arch); else gaiaExport32 (ptr + 1, GAIA_POLYGON, 1, endian_arch); ptr += 5; } gaiaExport32 (ptr, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ rng = polyg->Exterior; gaiaExport32 (ptr + 4, rng->Points, 1, endian_arch); /* # points - exterior ring */ ptr += 8; for (iv = 0; iv < rng->Points; iv++) { if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); } else if (type == GAIA_POLYGONM || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); } else if (type == GAIA_POLYGONZM || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (rng->Coords, iv, &x, &y); } gaiaExport64 (ptr, x, 1, endian_arch); /* X - exterior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - exterior ring */ ptr += 16; if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z - exterior ring */ ptr += 8; } if (type == GAIA_POLYGONM || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM) { gaiaExport64 (ptr, m, 1, endian_arch); /* M - exterior ring */ ptr += 8; } if (type == GAIA_POLYGONZM || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z - exterior ring */ gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M - exterior ring */ ptr += 16; } } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); } else if (type == GAIA_POLYGONM || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); } else if (type == GAIA_POLYGONZM || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (rng->Coords, iv, &x, &y); } gaiaExport64 (ptr, x, 1, endian_arch); /* X - interior ring */ gaiaExport64 (ptr + 8, y, 1, endian_arch); /* Y - interior ring */ ptr += 16; if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z - exterior ring */ ptr += 8; } if (type == GAIA_POLYGONM || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM) { gaiaExport64 (ptr, m, 1, endian_arch); /* M - exterior ring */ ptr += 8; } if (type == GAIA_POLYGONZM || type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM) { gaiaExport64 (ptr, z, 1, endian_arch); /* Z - exterior ring */ gaiaExport64 (ptr + 8, m, 1, endian_arch); /* M - exterior ring */ ptr += 16; } } } polyg = polyg->Next; } } GAIAGEO_DECLARE int gaiaEwkbGetPoint (gaiaGeomCollPtr geom, unsigned char *blob, int offset, int blob_size, int endian, int endian_arch, int dims) { /* decodes a POINT from PostGIS EWKB binary GEOMETRY */ double x; double y; double z; double m; switch (dims) { case GAIA_XY_Z_M: if (blob_size < offset + 32) return -1; break; case GAIA_XY_Z: case GAIA_XY_M: if (blob_size < offset + 24) return -1; break; default: if (blob_size < offset + 16) return -1; break; } x = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; y = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; if (dims == GAIA_XY_Z_M) { z = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; m = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; gaiaAddPointToGeomCollXYZM (geom, x, y, z, m); } else if (dims == GAIA_XY_Z) { z = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; gaiaAddPointToGeomCollXYZ (geom, x, y, z); } else if (dims == GAIA_XY_M) { m = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; gaiaAddPointToGeomCollXYM (geom, x, y, m); } else gaiaAddPointToGeomColl (geom, x, y); return offset; } GAIAGEO_DECLARE int gaiaEwkbGetLinestring (gaiaGeomCollPtr geom, unsigned char *blob, int offset, int blob_size, int endian, int endian_arch, int dims) { /* decodes a LINESTRING from PostGIS binary GEOMETRY */ int npoints; int iv; double x; double y; double z; double m; gaiaLinestringPtr ln; if (blob_size < offset + 4) return -1; npoints = gaiaImport32 (blob + offset, endian, endian_arch); offset += 4; switch (dims) { case GAIA_XY_Z_M: if (blob_size < offset + (32 * npoints)) return -1; break; case GAIA_XY_Z: case GAIA_XY_M: if (blob_size < offset + (24 * npoints)) return -1; break; default: if (blob_size < offset + (16 * npoints)) return -1; break; } ln = gaiaAddLinestringToGeomColl (geom, npoints); for (iv = 0; iv < npoints; iv++) { x = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; y = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; if (dims == GAIA_XY_Z_M) { z = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; m = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; gaiaSetPointXYZM (ln->Coords, iv, x, y, z, m); } else if (dims == GAIA_XY_Z) { z = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; gaiaSetPointXYZ (ln->Coords, iv, x, y, z); } else if (dims == GAIA_XY_M) { m = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; gaiaSetPointXYM (ln->Coords, iv, x, y, m); } else gaiaSetPoint (ln->Coords, iv, x, y); } return offset; } GAIAGEO_DECLARE int gaiaEwkbGetPolygon (gaiaGeomCollPtr geom, unsigned char *blob, int offset, int blob_size, int endian, int endian_arch, int dims) { /* decodes a POLYGON from PostGIS binary GEOMETRY */ int rings; int npoints; int iv; int ib; double x; double y; double z; double m; gaiaPolygonPtr polyg = NULL; gaiaRingPtr rng; if (blob_size < offset + 4) return -1; rings = gaiaImport32 (blob + offset, endian, endian_arch); offset += 4; for (ib = 0; ib < rings; ib++) { if (blob_size < offset + 4) return -1; npoints = gaiaImport32 (blob + offset, endian, endian_arch); offset += 4; switch (dims) { case GAIA_XY_Z_M: if (blob_size < offset + (32 * npoints)) return -1; break; case GAIA_XY_Z: case GAIA_XY_M: if (blob_size < offset + (24 * npoints)) return -1; break; default: if (blob_size < offset + (16 * npoints)) return -1; break; } if (ib == 0) { polyg = gaiaAddPolygonToGeomColl (geom, npoints, rings - 1); rng = polyg->Exterior; } else rng = gaiaAddInteriorRing (polyg, ib - 1, npoints); for (iv = 0; iv < npoints; iv++) { x = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; y = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; if (dims == GAIA_XY_Z_M) { z = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; m = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; gaiaSetPointXYZM (rng->Coords, iv, x, y, z, m); } else if (dims == GAIA_XY_Z) { z = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; gaiaSetPointXYZ (rng->Coords, iv, x, y, z); } else if (dims == GAIA_XY_M) { m = gaiaImport64 (blob + offset, endian, endian_arch); offset += 8; gaiaSetPointXYM (rng->Coords, iv, x, y, m); } else gaiaSetPoint (rng->Coords, iv, x, y); } } return offset; } GAIAGEO_DECLARE int gaiaEwkbGetMultiPoint (gaiaGeomCollPtr geom, unsigned char *blob, int offset, int blob_size, int endian, int endian_arch, int dims) { /* decodes a MULTIPOINT from PostGIS EWKB binary GEOMETRY */ int entities; int type; unsigned char xtype[4]; int ie; int off; if (blob_size < offset + 4) return -1; entities = gaiaImport32 (blob + offset, endian, endian_arch); offset += 4; for (ie = 0; ie < entities; ie++) { if (blob_size < offset + 5) return -1; memcpy (xtype, blob + offset + 1, 4); if (endian) xtype[3] = 0x00; else xtype[0] = 0x00; type = gaiaImport32 (xtype, endian, endian_arch); offset += 5; if (type != GAIA_POINT) return -1; off = gaiaEwkbGetPoint (geom, blob, offset, blob_size, endian, endian_arch, dims); if (off < 0) return -1; offset = off; } return offset; } GAIAGEO_DECLARE int gaiaEwkbGetMultiLinestring (gaiaGeomCollPtr geom, unsigned char *blob, int offset, int blob_size, int endian, int endian_arch, int dims) { /* decodes a MULTILINESTRING from PostGIS EWKB binary GEOMETRY */ int entities; int type; unsigned char xtype[4]; int ie; int off; if (blob_size < offset + 4) return -1; entities = gaiaImport32 (blob + offset, endian, endian_arch); offset += 4; for (ie = 0; ie < entities; ie++) { if (blob_size < offset + 5) return -1; memcpy (xtype, blob + offset + 1, 4); if (endian) xtype[3] = 0x00; else xtype[0] = 0x00; type = gaiaImport32 (xtype, endian, endian_arch); offset += 5; if (type != GAIA_LINESTRING) return -1; off = gaiaEwkbGetLinestring (geom, blob, offset, blob_size, endian, endian_arch, dims); if (off < 0) return -1; offset = off; } return offset; } GAIAGEO_DECLARE int gaiaEwkbGetMultiPolygon (gaiaGeomCollPtr geom, unsigned char *blob, int offset, int blob_size, int endian, int endian_arch, int dims) { /* decodes a MULTIPOLYGON from PostGIS EWKB binary GEOMETRY */ int entities; int type; unsigned char xtype[4]; int ie; int off; if (blob_size < offset + 4) return -1; entities = gaiaImport32 (blob + offset, endian, endian_arch); offset += 4; for (ie = 0; ie < entities; ie++) { if (blob_size < offset + 5) return -1; memcpy (xtype, blob + offset + 1, 4); if (endian) xtype[3] = 0x00; else xtype[0] = 0x00; type = gaiaImport32 (xtype, endian, endian_arch); offset += 5; if (type != GAIA_POLYGON) return -1; off = gaiaEwkbGetPolygon (geom, blob, offset, blob_size, endian, endian_arch, dims); if (off < 0) return -1; offset = off; } return offset; } GAIAGEO_DECLARE int gaiaEwkbGetMultiGeometry (gaiaGeomCollPtr geom, unsigned char *blob, int offset, int blob_size, int endian, int endian_arch, int dims) { /* decodes a MultiGeometry from PostGIS EWKB binary GEOMETRY */ int entities; int type; unsigned char xtype[4]; int ie; int off; if (blob_size < offset + 4) return -1; entities = gaiaImport32 (blob + offset, endian, endian_arch); offset += 4; for (ie = 0; ie < entities; ie++) { if (blob_size < offset + 5) return -1; memcpy (xtype, blob + offset + 1, 4); if (endian) xtype[3] = 0x00; else xtype[0] = 0x00; type = gaiaImport32 (xtype, endian, endian_arch); offset += 5; switch (type) { case GAIA_POINT: off = gaiaEwkbGetPoint (geom, blob, offset, blob_size, endian, endian_arch, dims); if (off < 0) return -1; offset = off; break; case GAIA_LINESTRING: off = gaiaEwkbGetLinestring (geom, blob, offset, blob_size, endian, endian_arch, dims); if (off < 0) return -1; offset = off; break; case GAIA_POLYGON: off = gaiaEwkbGetPolygon (geom, blob, offset, blob_size, endian, endian_arch, dims); if (off < 0) return -1; offset = off; break; case GAIA_MULTIPOINT: off = gaiaEwkbGetMultiPoint (geom, blob, offset, blob_size, endian, endian_arch, dims); if (off < 0) return -1; offset = off; break; case GAIA_MULTILINESTRING: off = gaiaEwkbGetMultiLinestring (geom, blob, offset, blob_size, endian, endian_arch, dims); if (off < 0) return -1; offset = off; break; case GAIA_MULTIPOLYGON: off = gaiaEwkbGetMultiPolygon (geom, blob, offset, blob_size, endian, endian_arch, dims); if (off < 0) return -1; offset = off; break; case GAIA_GEOMETRYCOLLECTION: off = gaiaEwkbGetMultiGeometry (geom, blob, offset, blob_size, endian, endian_arch, dims); if (off < 0) return -1; offset = off; break; default: /* unexpected: invalid EWKB */ return -1; }; } return offset; } static int parseHexEwkbByte (const unsigned char high, const unsigned char low, unsigned char *byte) { /* parsing an Hexadecimal byte */ unsigned char hex; switch (high) { case '0': hex = 16 * 0; break; case '1': hex = 16 * 1; break; case '2': hex = 16 * 2; break; case '3': hex = 16 * 3; break; case '4': hex = 16 * 4; break; case '5': hex = 16 * 5; break; case '6': hex = 16 * 6; break; case '7': hex = 16 * 7; break; case '8': hex = 16 * 8; break; case '9': hex = 16 * 9; break; case 'A': case 'a': hex = 16 * 10; break; case 'B': case 'b': hex = 16 * 11; break; case 'C': case 'c': hex = 16 * 12; break; case 'D': case 'd': hex = 16 * 13; break; case 'E': case 'e': hex = 16 * 14; break; case 'F': case 'f': hex = 16 * 15; break; default: return 0; }; switch (low) { case '0': hex += 0; break; case '1': hex += 1; break; case '2': hex += 2; break; case '3': hex += 3; break; case '4': hex += 4; break; case '5': hex += 5; break; case '6': hex += 6; break; case '7': hex += 7; break; case '8': hex += 8; break; case '9': hex += 9; break; case 'A': case 'a': hex += 10; break; case 'B': case 'b': hex += 11; break; case 'C': case 'c': hex += 12; break; case 'D': case 'd': hex += 13; break; case 'E': case 'e': hex += 14; break; case 'F': case 'f': hex += 15; break; default: return 0; }; *byte = hex; return 1; } GAIAGEO_DECLARE unsigned char * gaiaParseHexEWKB (const unsigned char *blob_hex, int *blob_size) { /* parsing an Hexadecimal EWKB Geometry */ unsigned char *blob; unsigned char *p_out; const unsigned char *p_in; char high; char low; unsigned char hex; int size; int len = strlen ((const char *) blob_hex); size = len / 2; if (size * 2 != len) return NULL; blob = malloc (size); if (!blob) return NULL; *blob_size = size; p_in = blob_hex; p_out = blob; while (*p_in != '\0') { high = *p_in++; low = *p_in++; if (!parseHexEwkbByte (high, low, &hex)) { free (blob); return NULL; } *p_out++ = hex; } *blob_size = size; return blob; } gaiaGeomCollPtr gaiaFromEWKB (const unsigned char *in_buffer) { /* creates a Gaia own Geometry from GEOS/PostGIS EWKB */ unsigned char *blob; int blob_size; unsigned char xtype[4]; unsigned char xdims; int type; int has_z = 0; int has_m = 0; int dims = GAIA_XY; int srid; int ret; int endian; int endian_arch = gaiaEndianArch (); gaiaGeomCollPtr geom = NULL; blob = gaiaParseHexEWKB (in_buffer, &blob_size); if (!blob) return NULL; if (blob_size < 9) { free (blob); return NULL; } if (*(blob + 0) == 0x01) endian = 1; else endian = 0; memcpy (xtype, blob + 1, 4); if (endian) { xdims = xtype[3]; xtype[3] = 0x00; } else { xdims = xtype[0]; xtype[0] = 0x00; } type = gaiaImport32 (xtype, endian, endian_arch); if (xdims & 0x40) has_m = 1; if (xdims & 0x80) has_z = 1; if (has_m && has_z) { dims = GAIA_XY_Z_M; geom = gaiaAllocGeomCollXYZM (); } else if (has_m) { dims = GAIA_XY_M; geom = gaiaAllocGeomCollXYM (); } else if (has_z) { dims = GAIA_XY_Z; geom = gaiaAllocGeomCollXYZ (); } else { dims = GAIA_XY; geom = gaiaAllocGeomColl (); } srid = gaiaImport32 (blob + 5, endian, endian_arch); geom->Srid = srid; if (geom->Srid <= 0) geom->Srid = 0; switch (type) { case GAIA_POINT: ret = gaiaEwkbGetPoint (geom, blob, 9, blob_size, endian, endian_arch, dims); break; case GAIA_LINESTRING: ret = gaiaEwkbGetLinestring (geom, blob, 9, blob_size, endian, endian_arch, dims); break; case GAIA_POLYGON: ret = gaiaEwkbGetPolygon (geom, blob, 9, blob_size, endian, endian_arch, dims); break; default: ret = gaiaEwkbGetMultiGeometry (geom, blob, 9, blob_size, endian, endian_arch, dims); break; }; free (blob); if (ret < 0) { /* invalid EWKB !!! */ gaiaFreeGeomColl (geom); return NULL; } return geom; } GAIAGEO_DECLARE void gaiaToEWKB (gaiaOutBufferPtr out_buf, gaiaGeomCollPtr geom) { /* prints the GEOS/PostGIS EWKB text representation of current geometry */ char buf[2048]; unsigned char endian_buf[16]; char byte[3]; char *ptr; int size; int type; int entities = 0; int n_points = 0; int n_linestrings = 0; int n_polygons = 0; int i; int iv; int ib; double x; double y; double z; double m; int endian_arch = gaiaEndianArch (); gaiaPointPtr pt; gaiaLinestringPtr ln; gaiaPolygonPtr pg; gaiaRingPtr rng; gaiaPointPtr point = NULL; gaiaLinestringPtr line = NULL; gaiaPolygonPtr polyg = NULL; /* precomputing the required size */ size = 5; /* SRID and terminating '\0' */ pt = geom->FirstPoint; while (pt) { point = pt; entities++; n_points++; pt = pt->Next; } ln = geom->FirstLinestring; while (ln) { line = ln; entities++; n_linestrings++; ln = ln->Next; } pg = geom->FirstPolygon; while (pg) { polyg = pg; entities++; n_polygons++; pg = pg->Next; } if (n_points == 0 && n_polygons == 0 && n_linestrings == 0) return; /* ok, we can determine the geometry class */ if (n_points == 1 && n_linestrings == 0 && n_polygons == 0) { if (geom->DeclaredType == GAIA_MULTIPOINT) type = GAIA_MULTIPOINT; else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = GAIA_GEOMETRYCOLLECTION; else type = GAIA_POINT; } else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = GAIA_GEOMETRYCOLLECTION; else type = GAIA_MULTIPOINT; } else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0) { if (geom->DeclaredType == GAIA_MULTILINESTRING) type = GAIA_MULTILINESTRING; else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = GAIA_GEOMETRYCOLLECTION; else type = GAIA_LINESTRING; } else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = GAIA_GEOMETRYCOLLECTION; else type = GAIA_MULTILINESTRING; } else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1) { if (geom->DeclaredType == GAIA_MULTIPOLYGON) type = GAIA_MULTIPOLYGON; else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = GAIA_GEOMETRYCOLLECTION; else type = GAIA_POLYGON; } else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = GAIA_GEOMETRYCOLLECTION; else type = GAIA_MULTIPOLYGON; } else type = GAIA_GEOMETRYCOLLECTION; /* and now we compute the size of EWKB */ size += 10; /* header size */ if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION) size += 8; point = geom->FirstPoint; while (point) { if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION) size += 10; if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) size += 48; /* three doubles for each POINT */ else if (geom->DimensionModel == GAIA_XY_Z_M) size += 64; /* four doubles for each POINT */ else size += 32; /* two doubles for each POINT */ point = point->Next; } line = geom->FirstLinestring; while (line) { if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION) size += 10; if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) size += 8 + (line->Points * 48); /* three doubles for each VERTEX */ else if (geom->DimensionModel == GAIA_XY_Z_M) size += 8 + (line->Points * 64); /* four doubles for each VERTEX */ else size += 8 + (line->Points * 32); /* two doubles for each VERTEX */ line = line->Next; } polyg = geom->FirstPolygon; while (polyg) { if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION) size += 10; rng = polyg->Exterior; if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) size += 16 + (rng->Points * 48); /* three doubles for each VERTEX */ else if (geom->DimensionModel == GAIA_XY_Z_M) size += 16 + (rng->Points * 64); /* four doubles for each VERTEX */ else size += 16 + (rng->Points * 32); /* two doubles for each VERTEX */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; if (geom->DimensionModel == GAIA_XY_Z || geom->DimensionModel == GAIA_XY_M) size += 8 + (rng->Points * 48); /* three doubles for each VERTEX */ else if (geom->DimensionModel == GAIA_XY_Z_M) size += 8 + (rng->Points * 64); /* four doubles for each VERTEX */ else size += 8 + (rng->Points * 32); /* two doubles for each VERTEX */ } polyg = polyg->Next; } /* and finally we build the EWKB expression */ ptr = buf; *ptr++ = '0'; /* little endian byte order */ *ptr++ = '1'; gaiaExport32 (endian_buf, type, 1, endian_arch); /* the main CLASS TYPE */ for (i = 0; i < 3; i++) { /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */ sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } /* marking dimensions and M/Z presence */ if (geom->DimensionModel == GAIA_XY_Z) { *ptr++ = 'A'; *ptr++ = '0'; } else if (geom->DimensionModel == GAIA_XY_M) { *ptr++ = '6'; *ptr++ = '0'; } else if (geom->DimensionModel == GAIA_XY_Z_M) { *ptr++ = 'E'; *ptr++ = '0'; } else { *ptr++ = '2'; *ptr++ = '0'; } gaiaExport32 (endian_buf, geom->Srid, 1, endian_arch); for (i = 0; i < 4; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } *ptr++ = '\0'; gaiaAppendToOutBuffer (out_buf, buf); ptr = buf; if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION) { gaiaExport32 (endian_buf, entities, 1, endian_arch); /* it's a collection; # entities */ for (i = 0; i < 4; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } point = geom->FirstPoint; while (point) { if ((ptr - buf) > 1024) { /* flushing the internal buffer */ *ptr++ = '\0'; gaiaAppendToOutBuffer (out_buf, buf); ptr = buf; } if (type == GAIA_MULTIPOINT || type == GAIA_GEOMETRYCOLLECTION) { *ptr++ = '0'; *ptr++ = '1'; /* it's a collection: the CLASS TYPE for this element */ gaiaExport32 (endian_buf, GAIA_POINT, 1, endian_arch); for (i = 0; i < 3; i++) { /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */ sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } /* marking M/Z presence */ if (geom->DimensionModel == GAIA_XY_Z) *ptr++ = '8'; else if (geom->DimensionModel == GAIA_XY_M) *ptr++ = '4'; else if (geom->DimensionModel == GAIA_XY_Z_M) *ptr++ = 'C'; else *ptr++ = '0'; *ptr++ = '0'; } gaiaExport64 (endian_buf, point->X, 1, endian_arch); /* X */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } gaiaExport64 (endian_buf, point->Y, 1, endian_arch); /* Y */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } if (geom->DimensionModel == GAIA_XY_Z) { gaiaExport64 (endian_buf, point->Z, 1, endian_arch); /* Z */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } else if (geom->DimensionModel == GAIA_XY_M) { gaiaExport64 (endian_buf, point->M, 1, endian_arch); /* M */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaExport64 (endian_buf, point->Z, 1, endian_arch); /* Z */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } gaiaExport64 (endian_buf, point->M, 1, endian_arch); /* M */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } point = point->Next; } line = geom->FirstLinestring; while (line) { if ((ptr - buf) > 1024) { /* flushing the internal buffer */ *ptr++ = '\0'; gaiaAppendToOutBuffer (out_buf, buf); ptr = buf; } if (type == GAIA_MULTILINESTRING || type == GAIA_GEOMETRYCOLLECTION) { *ptr++ = '0'; *ptr++ = '1'; /* it's a collection: the CLASS TYPE for this element */ gaiaExport32 (endian_buf, GAIA_LINESTRING, 1, endian_arch); for (i = 0; i < 3; i++) { /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */ sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } /* marking M/Z presence */ if (geom->DimensionModel == GAIA_XY_Z) *ptr++ = '8'; else if (geom->DimensionModel == GAIA_XY_M) *ptr++ = '4'; else if (geom->DimensionModel == GAIA_XY_Z_M) *ptr++ = 'C'; else *ptr++ = '0'; *ptr++ = '0'; } gaiaExport32 (endian_buf, line->Points, 1, endian_arch); /* # points */ for (i = 0; i < 4; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } for (iv = 0; iv < line->Points; iv++) { if ((ptr - buf) > 1024) { /* flushing the internal buffer */ *ptr++ = '\0'; gaiaAppendToOutBuffer (out_buf, buf); ptr = buf; } gaiaLineGetPoint (line, iv, &x, &y, &z, &m); gaiaExport64 (endian_buf, x, 1, endian_arch); /* X */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } gaiaExport64 (endian_buf, y, 1, endian_arch); /* Y */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } if (geom->DimensionModel == GAIA_XY_Z) { gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } else if (geom->DimensionModel == GAIA_XY_M) { gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } } line = line->Next; } polyg = geom->FirstPolygon; while (polyg) { if ((ptr - buf) > 1024) { /* flushing the internal buffer */ *ptr++ = '\0'; gaiaAppendToOutBuffer (out_buf, buf); ptr = buf; } if (type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION) { *ptr++ = '0'; *ptr++ = '1'; /* it's a collection: the CLASS TYPE for this element */ gaiaExport32 (endian_buf, GAIA_POLYGON, 1, endian_arch); for (i = 0; i < 3; i++) { /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */ sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } /* marking M/Z presence */ if (geom->DimensionModel == GAIA_XY_Z) *ptr++ = '8'; else if (geom->DimensionModel == GAIA_XY_M) *ptr++ = '4'; else if (geom->DimensionModel == GAIA_XY_Z_M) *ptr++ = 'C'; else *ptr++ = '0'; *ptr++ = '0'; } gaiaExport32 (endian_buf, polyg->NumInteriors + 1, 1, endian_arch); /* # rings */ for (i = 0; i < 4; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } rng = polyg->Exterior; gaiaExport32 (endian_buf, rng->Points, 1, endian_arch); /* # points - exterior ring */ for (i = 0; i < 4; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } for (iv = 0; iv < rng->Points; iv++) { if ((ptr - buf) > 1024) { /* flushing the internal buffer */ *ptr++ = '\0'; gaiaAppendToOutBuffer (out_buf, buf); ptr = buf; } gaiaRingGetPoint (rng, iv, &x, &y, &z, &m); gaiaExport64 (endian_buf, x, 1, endian_arch); /* X - exterior ring */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } gaiaExport64 (endian_buf, y, 1, endian_arch); /* Y - exterior ring */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } if (geom->DimensionModel == GAIA_XY_Z) { gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } else if (geom->DimensionModel == GAIA_XY_M) { gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (endian_buf, rng->Points, 1, endian_arch); /* # points - interior ring */ for (i = 0; i < 4; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } for (iv = 0; iv < rng->Points; iv++) { if ((ptr - buf) > 1024) { /* flushing the internal buffer */ *ptr++ = '\0'; gaiaAppendToOutBuffer (out_buf, buf); ptr = buf; } gaiaRingGetPoint (rng, iv, &x, &y, &z, &m); gaiaExport64 (endian_buf, x, 1, endian_arch); /* X - interior ring */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } gaiaExport64 (endian_buf, y, 1, endian_arch); /* Y - interior ring */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } if (geom->DimensionModel == GAIA_XY_Z) { gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } else if (geom->DimensionModel == GAIA_XY_M) { gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaExport64 (endian_buf, z, 1, endian_arch); /* Z */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } gaiaExport64 (endian_buf, m, 1, endian_arch); /* M */ for (i = 0; i < 8; i++) { sprintf (byte, "%02X", endian_buf[i]); *ptr++ = byte[0]; *ptr++ = byte[1]; } } } } polyg = polyg->Next; } /* terminating the EWKB string */ *ptr = '\0'; gaiaAppendToOutBuffer (out_buf, buf); } static int checkFgfTypeDims (int fgf_type, int fgf_dims, int *type, int *dims) { /* validating Type and coordinate Dimensions for an FGF Geometry */ int t = -1; int d = -1; switch (fgf_type) { case 1: t = GAIA_POINT; break; case 2: t = GAIA_LINESTRING; break; case 3: t = GAIA_POLYGON; break; case 4: t = GAIA_MULTIPOINT; break; case 5: t = GAIA_MULTILINESTRING; break; case 6: t = GAIA_MULTIPOLYGON; break; case 7: t = GAIA_GEOMETRYCOLLECTION; break; }; switch (fgf_dims) { case 0: d = GAIA_XY; break; case 1: d = GAIA_XY_Z; break; case 2: d = GAIA_XY_M; break; case 3: d = GAIA_XY_Z_M; break; }; if (t < 0 || d < 0) return 0; *type = t; *dims = d; return 1; } static int pointFromFgf (gaiaGeomCollPtr geom, int endian_arch, const unsigned char *blob, unsigned int size, unsigned int *consumed) { /* decoding a POINT Geometry from FGF */ double x; double y; double z; double m; unsigned int sz = size; const unsigned char *ptr = blob; int t; int d; int geom_type; int dims; int ndims; /* checking Geometry Type and Dims */ if (sz < 8) return 0; t = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); d = gaiaImport32 (ptr + 4, GAIA_LITTLE_ENDIAN, endian_arch); if (!checkFgfTypeDims (t, d, &geom_type, &dims)) return 0; if (geom_type != GAIA_POINT) return 0; ptr += 8; sz -= 8; if (dims == GAIA_XY_Z_M) ndims = 4; else if (dims == GAIA_XY_Z || dims == GAIA_XY_M) ndims = 3; else ndims = 2; if (sz < ((unsigned int) ndims * 8)) return 0; if (consumed) *consumed = 8 + (ndims * 8); if (dims == GAIA_XY_Z) { /* parsing a POINT Z */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); z = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); m = 0.0; } else if (dims == GAIA_XY_M) { /* parsing the POINTM */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); m = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); z = 0.0; } else if (dims == GAIA_XY_Z_M) { /* parsing the POINTZM */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); z = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); m = gaiaImport64 (ptr + 24, GAIA_LITTLE_ENDIAN, endian_arch); } else { /* parsing the POINT */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); z = 0.0; m = 0.0; } if (geom->DimensionModel == GAIA_XY_Z_M) gaiaAddPointToGeomCollXYZM (geom, x, y, z, m); else if (geom->DimensionModel == GAIA_XY_Z) gaiaAddPointToGeomCollXYZ (geom, x, y, z); else if (geom->DimensionModel == GAIA_XY_M) gaiaAddPointToGeomCollXYM (geom, x, y, m); else gaiaAddPointToGeomColl (geom, x, y); return 1; } static void setFgfVertex (int dims, double *coords, int iv, double x, double y, double z, double m) { /* setting an FGF vertex accorignly to dimensions */ if (dims == GAIA_XY_Z_M) gaiaSetPointXYZM (coords, iv, x, y, z, m); if (dims == GAIA_XY_Z) gaiaSetPointXYZ (coords, iv, x, y, z); if (dims == GAIA_XY_M) gaiaSetPointXYM (coords, iv, x, y, m); if (dims == GAIA_XY) gaiaSetPoint (coords, iv, x, y); } static int linestringFromFgf (gaiaGeomCollPtr geom, int endian_arch, const unsigned char *blob, unsigned int size, unsigned int *consumed) { /* decoding a LINESTRING Geometry from FGF */ gaiaLinestringPtr ln; int pts; int iv; double x; double y; double z; double m; unsigned int ln_sz; unsigned int sz = size; const unsigned char *ptr = blob; int t; int d; int geom_type; int dims; int ndims; /* checking Geometry Type and Dims */ if (sz < 8) return 0; t = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); d = gaiaImport32 (ptr + 4, GAIA_LITTLE_ENDIAN, endian_arch); if (!checkFgfTypeDims (t, d, &geom_type, &dims)) return 0; if (geom_type != GAIA_LINESTRING) return 0; ptr += 8; sz -= 8; if (dims == GAIA_XY_Z_M) ndims = 4; else if (dims == GAIA_XY_Z || dims == GAIA_XY_M) ndims = 3; else ndims = 2; /* how many points are there ? */ if (sz < 4) return 0; pts = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 4; sz -= 4; ln_sz = pts * ndims * sizeof (double); if (sz < ln_sz) return 0; if (consumed) *consumed = 12 + (pts * (ndims * 8)); ln = gaiaAddLinestringToGeomColl (geom, pts); if (dims == GAIA_XY_Z) { /* parsing the LINESTRINGZ */ for (iv = 0; iv < pts; iv++) { x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); z = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); m = 0.0; ptr += 24; setFgfVertex (dims, ln->Coords, iv, x, y, z, m); } } else if (dims == GAIA_XY_M) { /* parsing the LINESTRINGM */ for (iv = 0; iv < pts; iv++) { x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); m = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); z = 0.0; ptr += 24; setFgfVertex (dims, ln->Coords, iv, x, y, z, m); } } else if (dims == GAIA_XY_Z_M) { /* parsing the LINESTRINGZM */ for (iv = 0; iv < pts; iv++) { x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); z = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); m = gaiaImport64 (ptr + 24, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 32; setFgfVertex (dims, ln->Coords, iv, x, y, z, m); } } else { /* parsing the LINESTRING */ for (iv = 0; iv < pts; iv++) { x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + sizeof (double), GAIA_LITTLE_ENDIAN, endian_arch); z = 0.0; m = 0.0; ptr += 16; setFgfVertex (dims, ln->Coords, iv, x, y, z, m); } } return 1; } static int polygonFromFgf (gaiaGeomCollPtr geom, int endian_arch, const unsigned char *blob, unsigned int size, unsigned int *consumed) { /* decoding a POLYGON Geometry from FGF */ gaiaPolygonPtr pg = NULL; gaiaRingPtr rng; int rings; int ir; int pts; int iv; double x; double y; double z; double m; unsigned int rng_sz; unsigned int sz = size; const unsigned char *ptr = blob; int t; int d; int geom_type; int dims; int ndims; unsigned int bytes = 0; /* checking Geometry Type and Dims */ if (sz < 8) return 0; t = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); d = gaiaImport32 (ptr + 4, GAIA_LITTLE_ENDIAN, endian_arch); if (!checkFgfTypeDims (t, d, &geom_type, &dims)) return 0; if (geom_type != GAIA_POLYGON) return 0; ptr += 8; sz -= 8; bytes += 8; if (dims == GAIA_XY_Z_M) ndims = 4; else if (dims == GAIA_XY_Z || dims == GAIA_XY_M) ndims = 3; else ndims = 2; /* how many rings are there ? */ if (sz < 4) return 0; rings = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 4; sz -= 4; bytes += 4; if (rings < 1) return 0; for (ir = 0; ir < rings; ir++) { /* fetching Polygon's rings */ if (sz < 4) return 0; pts = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 4; sz -= 4; bytes += 4; rng_sz = pts * ndims * 8; if (sz < rng_sz) return 0; bytes += rng_sz; if (ir == 0) { /* creating the Polygon */ pg = gaiaAddPolygonToGeomColl (geom, pts, rings - 1); } if (dims == GAIA_XY_Z) { /* POLYGONZ */ if (ir == 0) { /* parsing the EXTERIOR RING */ rng = pg->Exterior; for (iv = 0; iv < pts; iv++) { /* inserting vertices into the EXTERIOR Ring */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); z = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); m = 0.0; ptr += 24; setFgfVertex (dims, rng->Coords, iv, x, y, z, m); } } else { /* parsing an INTERIOR RING */ rng = gaiaAddInteriorRing (pg, ir - 1, pts); for (iv = 0; iv < pts; iv++) { /* inserting vertices into some INTERIOR Ring */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); z = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); m = 0.0; ptr += 24; setFgfVertex (dims, rng->Coords, iv, x, y, z, m); } } } else if (dims == GAIA_XY_M) { /* POLYGONM */ if (ir == 0) { /* parsing the EXTERIOR RING */ rng = pg->Exterior; for (iv = 0; iv < pts; iv++) { /* inserting vertices into the EXTERIOR Ring */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); m = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); z = 0.0; ptr += 24; setFgfVertex (dims, rng->Coords, iv, x, y, z, m); } } else { /* parsing an INTERIOR RING */ rng = gaiaAddInteriorRing (pg, ir - 1, pts); for (iv = 0; iv < pts; iv++) { /* inserting vertices into some INTERIOR Ring */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); m = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); z = 0.0; ptr += 24; setFgfVertex (dims, rng->Coords, iv, x, y, z, m); } } } else if (dims == GAIA_XY_Z_M) { /* POLYGONZM */ if (ir == 0) { /* parsing the EXTERIOR RING */ rng = pg->Exterior; for (iv = 0; iv < pts; iv++) { /* inserting vertices into the EXTERIOR Ring */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); z = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); m = gaiaImport64 (ptr + 24, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 32; setFgfVertex (dims, rng->Coords, iv, x, y, z, m); } } else { /* parsing an INTERIOR RING */ rng = gaiaAddInteriorRing (pg, ir - 1, pts); for (iv = 0; iv < pts; iv++) { /* inserting vertices into some INTERIOR Ring */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); z = gaiaImport64 (ptr + 16, GAIA_LITTLE_ENDIAN, endian_arch); m = gaiaImport64 (ptr + 24, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 32; setFgfVertex (dims, rng->Coords, iv, x, y, z, m); } } } else { /* POLYGON */ if (ir == 0) { /* parsing the EXTERIOR RING */ rng = pg->Exterior; for (iv = 0; iv < pts; iv++) { /* inserting vertices into the EXTERIOR Ring */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); z = 0.0; m = 0.0; ptr += 16; setFgfVertex (dims, rng->Coords, iv, x, y, z, m); } } else { /* parsing an INTERIOR RING */ rng = gaiaAddInteriorRing (pg, ir - 1, pts); for (iv = 0; iv < pts; iv++) { /* inserting vertices into some INTERIOR Ring */ x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch); z = 0.0; m = 0.0; ptr += 16; setFgfVertex (dims, rng->Coords, iv, x, y, z, m); } } } sz -= rng_sz; } if (consumed) *consumed = bytes; return 1; } static int multiPointFromFgf (gaiaGeomCollPtr geom, int endian_arch, const unsigned char *blob, unsigned int size) { /* decoding a MULTIPOINT Geometry from FGF */ int pts; int ipt; unsigned int sz = size; const unsigned char *ptr = blob; unsigned int consumed; /* checking Geometry Type */ if (sz < 4) return 0; if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_MULTIPOINT) return 0; ptr += 4; sz -= 4; /* how many points are there ? */ if (sz < 4) return 0; pts = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 4; sz -= 4; if (pts < 1) return 0; for (ipt = 0; ipt < pts; ipt++) { /* fetching individual Points from FGF */ if (!pointFromFgf (geom, endian_arch, ptr, sz, &consumed)) return 0; ptr += consumed; sz -= consumed; } return 1; } static int multiLinestringFromFgf (gaiaGeomCollPtr geom, int endian_arch, const unsigned char *blob, unsigned int size) { /* decoding a MULTILINESTRING Geometry from FGF */ int lns; int iln; unsigned int sz = size; const unsigned char *ptr = blob; unsigned int consumed; /* checking Geometry Type */ if (sz < 4) return 0; if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_MULTILINESTRING) return 0; ptr += 4; sz -= 4; /* how many linestrings are there ? */ if (sz < 4) return 0; lns = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 4; sz -= 4; if (lns < 1) return 0; for (iln = 0; iln < lns; iln++) { /* fetching individual Linestrings from FGF */ if (!linestringFromFgf (geom, endian_arch, ptr, sz, &consumed)) return 0; ptr += consumed; sz -= consumed; } return 1; } static int multiPolygonFromFgf (gaiaGeomCollPtr geom, int endian_arch, const unsigned char *blob, unsigned int size) { /* decoding a MULTIPOLYGON Geometry from FGF */ int pgs; int ipg; unsigned int sz = size; const unsigned char *ptr = blob; unsigned int consumed; /* checking Geometry Type */ if (sz < 4) return 0; if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_MULTIPOLYGON) return 0; ptr += 4; sz -= 4; /* how many polygons are there ? */ if (sz < 4) return 0; pgs = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 4; sz -= 4; if (pgs < 1) return 0; for (ipg = 0; ipg < pgs; ipg++) { /* fetching individual Polygons from FGF */ if (!polygonFromFgf (geom, endian_arch, ptr, sz, &consumed)) return 0; ptr += consumed; sz -= consumed; } return 1; } static int geomCollectionFromFgf (gaiaGeomCollPtr geom, int endian_arch, const unsigned char *blob, unsigned int size) { /* decoding a GEOMETRYCOLLECTION Geometry from FGF */ int geoms; int ig; int geom_type; unsigned int sz = size; const unsigned char *ptr = blob; unsigned int consumed; /* checking Geometry Type */ if (sz < 4) return 0; if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_GEOMETRYCOLLECTION) return 0; ptr += 4; sz -= 4; /* how many individual Geometries are there ? */ if (sz < 4) return 0; geoms = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 4; sz -= 4; if (geoms < 1) return 0; for (ig = 0; ig < geoms; ig++) { /* fetching individual Geometries from FGF */ if (sz < 4) return 0; geom_type = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch); switch (geom_type) { case GAIA_POINT: if (!pointFromFgf (geom, endian_arch, ptr, sz, &consumed)) return 0; break; case GAIA_LINESTRING: if (!linestringFromFgf (geom, endian_arch, ptr, sz, &consumed)) return 0; break; case GAIA_POLYGON: if (!polygonFromFgf (geom, endian_arch, ptr, sz, &consumed)) return 0; break; default: /* unsupported geometry type */ return 0; break; }; ptr += consumed; sz -= consumed; } return 1; } GAIAGEO_DECLARE gaiaGeomCollPtr gaiaFromFgf (const unsigned char *blob, unsigned int size) { /* decoding from FGF to GEOMETRY */ gaiaGeomCollPtr geom = NULL; int t; int d; int geom_type; int dims; int endian_arch = gaiaEndianArch (); if (size < 16) return NULL; /* checking FGF type and dimensions */ t = gaiaImport32 (blob, GAIA_LITTLE_ENDIAN, endian_arch); if (t == 1 || t == 2 || t == 3) { /* elementary: POINT, LINESTRING or POLYGON */ d = gaiaImport32 (blob + 4, GAIA_LITTLE_ENDIAN, endian_arch); } else { /* multiple elements */ d = gaiaImport32 (blob + 12, GAIA_LITTLE_ENDIAN, endian_arch); } if (!checkFgfTypeDims (t, d, &geom_type, &dims)) return NULL; /* allocating a Gaia Geometry accordingly to declared Dims */ if (dims == GAIA_XY_Z_M) geom = gaiaAllocGeomCollXYZM (); else if (dims == GAIA_XY_Z) geom = gaiaAllocGeomCollXYZ (); else if (dims == GAIA_XY_M) geom = gaiaAllocGeomCollXYM (); else geom = gaiaAllocGeomColl (); geom->DeclaredType = geom_type; switch (geom_type) { case GAIA_POINT: if (pointFromFgf (geom, endian_arch, blob, size, NULL)) return geom; break; case GAIA_LINESTRING: if (linestringFromFgf (geom, endian_arch, blob, size, NULL)) return geom; break; case GAIA_POLYGON: if (polygonFromFgf (geom, endian_arch, blob, size, NULL)) return geom; break; case GAIA_MULTIPOINT: if (multiPointFromFgf (geom, endian_arch, blob, size)) return geom; break; case GAIA_MULTILINESTRING: if (multiLinestringFromFgf (geom, endian_arch, blob, size)) return geom; break; case GAIA_MULTIPOLYGON: if (multiPolygonFromFgf (geom, endian_arch, blob, size)) return geom; break; case GAIA_GEOMETRYCOLLECTION: if (geomCollectionFromFgf (geom, endian_arch, blob, size)) return geom; break; }; gaiaFreeGeomColl (geom); return NULL; } GAIAGEO_DECLARE void gaiaToFgf (gaiaGeomCollPtr geom, unsigned char **result, int *size) { /* builds the FGF representation for this GEOMETRY */ int ib; int iv; double x; double y; double z; double m; int entities = 0; int n_points = 0; int n_linestrings = 0; int n_polygons = 0; int type; int n_coords; int flag_dims; unsigned char *ptr; int sz = 0; gaiaPointPtr pt; gaiaLinestringPtr ln; gaiaPolygonPtr pg; gaiaRingPtr rng; gaiaPointPtr point = NULL; gaiaLinestringPtr line = NULL; gaiaPolygonPtr polyg = NULL; int endian_arch = gaiaEndianArch (); gaiaMbrGeometry (geom); switch (geom->DimensionModel) { /* determining the Dimensions */ case GAIA_XY: flag_dims = 0; n_coords = 2; break; case GAIA_XY_Z: flag_dims = 1; n_coords = 3; break; case GAIA_XY_M: flag_dims = 2; n_coords = 3; break; case GAIA_XY_Z_M: flag_dims = 3; n_coords = 4; break; default: n_coords = 0; break; } /* how many entities, and of what kind, do we have ? */ pt = geom->FirstPoint; while (pt) { point = pt; entities++; n_points++; pt = pt->Next; } ln = geom->FirstLinestring; while (ln) { line = ln; entities++; n_linestrings++; ln = ln->Next; } pg = geom->FirstPolygon; while (pg) { polyg = pg; entities++; n_polygons++; pg = pg->Next; } *size = 0; sz = 0; *result = NULL; if (n_points == 0 && n_polygons == 0 && n_linestrings == 0) return; /* ok, we can determine the geometry class */ if (n_points == 1 && n_linestrings == 0 && n_polygons == 0) { if (geom->DeclaredType == GAIA_MULTIPOINT) type = 4; else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = 7; else type = 1; } else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = 7; else type = 4; } else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0) { if (geom->DeclaredType == GAIA_MULTILINESTRING) type = 5; else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = 7; else type = 2; } else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = 7; else type = 5; } else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1) { if (geom->DeclaredType == GAIA_MULTIPOLYGON) type = 6; else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = 7; else type = 3; } else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1) { if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION) type = 7; else type = 6; } else type = 7; /* and now we compute the size of FGF */ if (type == 4 || type == 5 || type == 6 || type == 7) sz += 8; point = geom->FirstPoint; while (point) { sz += (8 + (n_coords * 8)); /* the size of each POINT */ point = point->Next; } line = geom->FirstLinestring; while (line) { sz += (12 + ((n_coords * 8) * line->Points)); /* # points + [x,y] for each vertex */ line = line->Next; } polyg = geom->FirstPolygon; while (polyg) { rng = polyg->Exterior; sz += (16 + ((n_coords * 8) * rng->Points)); /* # rings + # points + [x.y] array - exterior ring */ for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; sz += (4 + ((n_coords * 8) * rng->Points)); /* # points + [x,y] array - interior ring */ } polyg = polyg->Next; } *size = sz; ptr = malloc (sz); *result = ptr; /* and finally we build the FGF */ if (type == 4 || type == 5 || type == 6 || type == 7) { gaiaExport32 (ptr, type, GAIA_LITTLE_ENDIAN, endian_arch); /* Geometry Type */ ptr += 4; gaiaExport32 (ptr, entities, GAIA_LITTLE_ENDIAN, endian_arch); /* it's a collection; # entities */ ptr += 4; } point = geom->FirstPoint; while (point) { gaiaExport32 (ptr, 1, GAIA_LITTLE_ENDIAN, endian_arch); /* the CLASS TYPE for this element */ ptr += 4; gaiaExport32 (ptr, flag_dims, GAIA_LITTLE_ENDIAN, endian_arch); /* the CoordDimension flag */ ptr += 4; gaiaExport64 (ptr, point->X, GAIA_LITTLE_ENDIAN, endian_arch); /* X */ ptr += 8; gaiaExport64 (ptr, point->Y, GAIA_LITTLE_ENDIAN, endian_arch); /* Y */ ptr += 8; if (flag_dims == 1) { /* XYZ */ gaiaExport64 (ptr, point->Z, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } else if (flag_dims == 2) { /*XYM */ gaiaExport64 (ptr, point->M, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } else if (flag_dims == 3) { /* XYZM */ gaiaExport64 (ptr, point->Z, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; gaiaExport64 (ptr, point->M, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } point = point->Next; } line = geom->FirstLinestring; while (line) { gaiaExport32 (ptr, GAIA_LINESTRING, GAIA_LITTLE_ENDIAN, endian_arch); /* the CLASS TYPE for this element */ ptr += 4; gaiaExport32 (ptr, flag_dims, GAIA_LITTLE_ENDIAN, endian_arch); /* the CoordDimension flag */ ptr += 4; gaiaExport32 (ptr, line->Points, GAIA_LITTLE_ENDIAN, endian_arch); /* # points */ ptr += 4; for (iv = 0; iv < line->Points; iv++) { z = 0.0; m = 0.0; if (geom->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z); } else if (geom->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (line->Coords, iv, &x, &y, &m); } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (line->Coords, iv, &x, &y); } gaiaExport64 (ptr, x, GAIA_LITTLE_ENDIAN, endian_arch); /* X */ ptr += 8; gaiaExport64 (ptr, y, GAIA_LITTLE_ENDIAN, endian_arch); /* Y */ ptr += 8; if (flag_dims == 1) { /* XYZ */ gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } else if (flag_dims == 2) { /*XYM */ gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } else if (flag_dims == 3) { /* XYZM */ gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } } line = line->Next; } polyg = geom->FirstPolygon; while (polyg) { gaiaExport32 (ptr, GAIA_POLYGON, GAIA_LITTLE_ENDIAN, endian_arch); /* the CLASS TYPE for this element */ ptr += 4; gaiaExport32 (ptr, flag_dims, GAIA_LITTLE_ENDIAN, endian_arch); /* the CoordDimension flag */ ptr += 4; gaiaExport32 (ptr, polyg->NumInteriors + 1, GAIA_LITTLE_ENDIAN, endian_arch); /* # rings */ ptr += 4; rng = polyg->Exterior; gaiaExport32 (ptr, rng->Points, GAIA_LITTLE_ENDIAN, endian_arch); /* # points - exterior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { z = 0.0; m = 0.0; if (geom->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); } else if (geom->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (rng->Coords, iv, &x, &y); } gaiaExport64 (ptr, x, GAIA_LITTLE_ENDIAN, endian_arch); /* X - exterior ring */ ptr += 8; gaiaExport64 (ptr, y, GAIA_LITTLE_ENDIAN, endian_arch); /* Y - exterior ring */ ptr += 8; if (flag_dims == 1) { /* XYZ */ gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } else if (flag_dims == 2) { /*XYM */ gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } else if (flag_dims == 3) { /* XYZM */ gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } } for (ib = 0; ib < polyg->NumInteriors; ib++) { rng = polyg->Interiors + ib; gaiaExport32 (ptr, rng->Points, 1, endian_arch); /* # points - interior ring */ ptr += 4; for (iv = 0; iv < rng->Points; iv++) { z = 0.0; m = 0.0; if (geom->DimensionModel == GAIA_XY_Z) { gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z); } else if (geom->DimensionModel == GAIA_XY_M) { gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m); } else if (geom->DimensionModel == GAIA_XY_Z_M) { gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m); } else { gaiaGetPoint (rng->Coords, iv, &x, &y); } gaiaExport64 (ptr, x, GAIA_LITTLE_ENDIAN, endian_arch); /* X - interior ring */ ptr += 8; gaiaExport64 (ptr, y, GAIA_LITTLE_ENDIAN, endian_arch); /* Y - interior ring */ ptr += 8; if (flag_dims == 1) { /* XYZ */ gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } else if (flag_dims == 2) { /*XYM */ gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } else if (flag_dims == 3) { /* XYZM */ gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN, endian_arch); ptr += 8; } } } polyg = polyg->Next; } }