/***************************************************************************** * * This file is part of Mapnik (c++ mapping toolkit) * * Copyright (C) 2006 Artem Pavlenko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ //$Id: wkb.cpp 19 2005-03-22 13:53:27Z pavlenko $ #include #include #include namespace mapnik { struct wkb_reader { private: enum wkbByteOrder { wkbXDR=0, wkbNDR=1 }; const char* wkb_; unsigned size_; unsigned pos_; wkbByteOrder byteOrder_; bool needSwap_; wkbFormat format_; public: enum wkbGeometryType { wkbPoint=1, wkbLineString=2, wkbPolygon=3, wkbMultiPoint=4, wkbMultiLineString=5, wkbMultiPolygon=6, wkbGeometryCollection=7 }; wkb_reader(const char* wkb,unsigned size,wkbFormat format) : wkb_(wkb), size_(size), pos_(0), format_(format) { if (format_ == wkbAutodetect) { // XXX - todo } switch (format_) { case wkbSQLite: byteOrder_ = (wkbByteOrder) wkb_[1]; pos_ = 39; break; case wkbGeneric: default: byteOrder_ = (wkbByteOrder) wkb_[0]; pos_ = 1; break; } #ifndef WORDS_BIGENDIAN needSwap_=byteOrder_?wkbXDR:wkbNDR; #else needSwap_=byteOrder_?wkbNDR:wkbXDR; #endif } ~wkb_reader() {} void read_multi(Feature & feature) { int type=read_integer(); switch (type) { case wkbPoint: read_point(feature); break; case wkbLineString: read_linestring(feature); break; case wkbPolygon: read_polygon(feature); break; case wkbMultiPoint: read_multipoint(feature); break; case wkbMultiLineString: read_multilinestring(feature); break; case wkbMultiPolygon: read_multipolygon(feature); break; case wkbGeometryCollection: break; default: break; } } void read(Feature & feature) { int type=read_integer(); switch (type) { case wkbPoint: read_point(feature); break; case wkbLineString: read_linestring(feature); break; case wkbPolygon: read_polygon(feature); break; case wkbMultiPoint: read_multipoint_2(feature); break; case wkbMultiLineString: read_multilinestring_2(feature); break; case wkbMultiPolygon: read_multipolygon_2(feature); break; case wkbGeometryCollection: break; default: break; } } private: wkb_reader(const wkb_reader&); wkb_reader& operator=(const wkb_reader&); int read_integer() { int n; if (!needSwap_) { memcpy(&n,wkb_+pos_,4); } else { const char* b=wkb_+pos_; n = (b[3]&0xff) | ((b[2]&0xff)<<8) | ((b[1]&0xff)<<16) | ((b[0]&0xff)<<24); } pos_+=4; return n; } double read_double() { double d; if (!needSwap_) { memcpy(&d,wkb_+pos_,8); } else { // we rely on the fact that "long long" is in C standard, // but not in C++ yet // this is not quite portable const char* b= wkb_+pos_; long long n = ((long long)b[7]&0xff) | (((long long)b[6]&0xff)<<8) | (((long long)b[5]&0xff)<<16) | (((long long)b[4]&0xff)<<24) | (((long long)b[3]&0xff)<<32) | (((long long)b[2]&0xff)<<40) | (((long long)b[1]&0xff)<<48) | (((long long)b[0]&0xff)<<56); memcpy(&d,&n,8); } pos_+=8; return d; } void read_coords(CoordinateArray& ar) { int size=sizeof(coord)*ar.size(); if (!needSwap_) { std::memcpy(&ar[0],wkb_+pos_,size); } else { for (unsigned i=0;i; double x = read_double(); double y = read_double(); pt->move_to(x,y); feature.add_geometry(pt); } void read_multipoint(Feature & feature) { int num_points = read_integer(); for (int i=0;i; int num_points = read_integer(); for (int i=0;imove_to(x,y); } feature.add_geometry(pt); } void read_linestring(Feature & feature) { geometry2d * line = new line_string; int num_points=read_integer(); CoordinateArray ar(num_points); read_coords(ar); line->set_capacity(num_points); line->move_to(ar[0].x,ar[0].y); for (int i=1;iline_to(ar[i].x,ar[i].y); } feature.add_geometry(line); } void read_multilinestring(Feature & feature) { int num_lines=read_integer(); for (int i=0;i; int num_lines=read_integer(); unsigned capacity = 0; for (int i=0;iset_capacity(capacity); line->move_to(ar[0].x,ar[0].y); for (int i=1;iline_to(ar[i].x,ar[i].y); } } feature.add_geometry(line); } void read_polygon(Feature & feature) { geometry2d * poly = new polygon; int num_rings=read_integer(); unsigned capacity = 0; for (int i=0;iset_capacity(capacity); poly->move_to(ar[0].x,ar[0].y); for (int j=1;jline_to(ar[j].x,ar[j].y); } } feature.add_geometry(poly); } void read_multipolygon(Feature & feature) { int num_polys=read_integer(); for (int i=0;i; int num_polys=read_integer(); unsigned capacity = 0; for (int i=0;iset_capacity(capacity); poly->move_to(ar[0].x,ar[0].y); for (int j=1;jline_to(ar[j].x,ar[j].y); } poly->line_to(ar[0].x,ar[0].y); } } feature.add_geometry(poly); } }; void geometry_utils::from_wkb (Feature & feature, const char* wkb, unsigned size, bool multiple_geometries, wkbFormat format) { wkb_reader reader(wkb,size,format); if (multiple_geometries) return reader.read_multi(feature); else return reader.read(feature); } }