[geos-devel] Patch that adds reading/writing WKB hex format

Charlie Savage cfis at interserv.com
Sun Jan 8 19:25:09 EST 2006


I'm using geos in a stand-alone library that gets data from a remote 
PostGIS server and then does some additional processing.  As a result it 
would be helpful if geos could read in the wkb hex format that PostGIS 
produces.  Looking through the GEOS/PostGIS code, I see that the wkb hex 
interpretation code is in PostGIS and not geos.

As a result, I have added to geos the methods WKBReader.readHex, 
WKBWriter.writeHEX (under the covers it calls WKBReader.printHEX which 
already exists, although I'm not sure why its on WKBReader).   I also 
added a constructor to Envelope that takes a string - the same string 
produced by Envelope.toString().  This makes it easy to serialize an 
envelope to a string, and then recreate the Envelope later.

Since I thought these changes might be generally useful, I've attached a 
patch below.  The patch also fixes a few spelling mistakes that I 
noticed in some error messages and in the DOxygen API comments.

Thanks,

Charlie

Index:  source/headers/geos/io.h
===================================================================
RCS file: /home/cvs/postgis/geos/source/headers/geos/io.h,v
retrieving revision 1.18
diff -u -r1.18 io.h
---  source/headers/geos/io.h    29 Nov 2005 13:39:56 -0000    1.18
+++  source/headers/geos/io.h    8 Jan 2006 23:34:01 -0000
@@ -265,7 +265,7 @@
     {
         stream->read(reinterpret_cast<char *>(buf), 1);
         if ( stream->eof() )
-            throw new ParseException("Unespected EOF parsing WKB");
+            throw new ParseException("Unexpected EOF parsing WKB");
         return buf[0];
     }
 
@@ -273,7 +273,7 @@
     {
         stream->read(reinterpret_cast<char *>(buf), 4);
         if ( stream->eof() )
-            throw new ParseException("Unespected EOF parsing WKB");
+            throw new ParseException("Unexpected EOF parsing WKB");
         return ByteOrderValues::getInt(buf, byteOrder);
     }
 
@@ -281,7 +281,7 @@
     {
         stream->read(reinterpret_cast<char *>(buf), 8);
         if ( stream->eof() )
-            throw new ParseException("Unespected EOF parsing WKB");
+            throw new ParseException("Unexpected EOF parsing WKB");
         return ByteOrderValues::getLong(buf, byteOrder);
     }
 
@@ -289,7 +289,7 @@
     {
         stream->read(reinterpret_cast<char *>(buf), 8);
         if ( stream->eof() )
-            throw new ParseException("Unespected EOF parsing WKB");
+            throw new ParseException("Unexpected EOF parsing WKB");
         return ByteOrderValues::getDouble(buf, byteOrder);
     }
 
@@ -336,6 +336,17 @@
         // throws IOException, ParseException
 
     /**
+     * \brief Reads a Geometry from an istream in hex format.
+     *
+     * @param is the stream to read from
+     * @return the Geometry read
+     * @throws IOException
+     * @throws ParseException
+     */
+    Geometry *readHEX(istream &is);
+        // throws IOException, ParseException
+
+    /**
      * \brief Print WKB in HEX form to out stream
      *
      * @param is is the stream to read from
@@ -419,6 +430,16 @@
     WKBWriter(int dims=2, int bo=getMachineByteOrder());
 
     /**
+       * \brief Write a Geometry to an ostream in binary hex format.
+     *
+     * @param g the geometry to write
+     * @param os the output stream
+     * @throws IOException
+     */
+    void
+    WKBWriter::writeHEX(const Geometry &g, ostream &os);
+
+    /**
      * \brief Write a Geometry to an ostream.
      *
      * @param g the geometry to write
Index:  source/headers/geos/geom.h
===================================================================
RCS file: /home/cvs/postgis/geos/source/headers/geos/geom.h,v
retrieving revision 1.57
diff -u -r1.57 geom.h
---  source/headers/geos/geom.h    8 Dec 2005 14:14:07 -0000    1.57
+++  source/headers/geos/geom.h    8 Jan 2006 23:30:03 -0000
@@ -1023,6 +1023,7 @@
     Envelope(const Coordinate& p1, const Coordinate& p2);
     Envelope(const Coordinate& p);
     Envelope(const Envelope &env);
+    Envelope::Envelope(const string &str);
     ~Envelope(void);
     static bool intersects(const Coordinate& p1,const Coordinate& 
p2,const Coordinate& q);
     static bool intersects(const Coordinate& p1,const Coordinate& 
p2,const Coordinate& q1,const Coordinate& q2);
@@ -1070,31 +1071,31 @@
 
     /**
      * Check if the point p
-     * overlaps (lies inside) the region of this Envelope.
+     * intersects (lies inside) the region of this Envelope.
      *
      * @param  p      the Coordinate to be tested
-     * @return true if the point overlaps this Envelope
+     * @return true if the point intersects this Envelope
      */
     inline bool intersects(const Coordinate& p) const;
 
     /**
      *  Check if the point (x, y)
-     *  overlaps (lies inside) the region of this Envelope.
+     *  intersects (lies inside) the region of this Envelope.
      *
      * @param  x  the x-ordinate of the point
      * @param  y  the y-ordinate of the point
-     * @return <code>true</code> if the point overlaps this Envelope
+     * @return <code>true</code> if the point intersects this Envelope
      */
     inline bool intersects(double x, double y) const;
 
     /**
      * Check if the region defined by other Envelope
-     * overlaps (intersects) the region of this Envelope.
+     * intersects (intersects) the region of this Envelope.
      *
      * @param other the Envelope which this Envelope is
-     *              being checked for overlapping
+     *              being checked for intersection
      *
-     * @return      true if the Envelopes overlap
+     * @return      true if the Envelopes intersects
      */
     inline bool intersects(const Envelope* other) const;
 
@@ -1104,6 +1105,7 @@
     int hashCode() const;
 
 private:
+    vector<string> split(const string &str, const string &delimiters = 
" ");
     static double distance(double x0,double y0,double x1,double y1);
     double minx;    /// the minimum x-coordinate
     double maxx;    /// the maximum x-coordinate
Index: source/geom/Envelope.cpp
===================================================================
RCS file: /home/cvs/postgis/geos/source/geom/Envelope.cpp,v
retrieving revision 1.21
diff -u -r1.21 Envelope.cpp
--- source/geom/Envelope.cpp    8 Nov 2005 10:03:28 -0000    1.21
+++ source/geom/Envelope.cpp    8 Jan 2006 23:18:09 -0000
@@ -135,6 +135,32 @@
     init(env.minx, env.maxx, env.miny, env.maxy);
 }
 
+/**
+ *  Create an <code>Envelope</code> from an Envelope
+ *  string representation produced by Envelope.toString()
+ *
+ * @param  env  the string Envelope to initialize from
+ */
+Envelope::Envelope(const string &str)
+{
+  // The string should be in the format:
+  // Env[7.2:2.3,7.1:8.2]
+
+  // extract out the values between the [ and ] characters
+  int index = str.find("[");
+  string coordString = str.substr(index + 1, str.size() - 1 - 1);
+
+  // now split apart the string on : and , characters
+  vector<string> values = split(coordString, ":,");
+
+  // create a new envelope
+  init(::atof(values[0].c_str()),
+       ::atof(values[1].c_str()),
+       ::atof(values[2].c_str()),
+       ::atof(values[3].c_str()));
+}
+
+
 ///Default destructor
 Envelope::~Envelope(void) {}
 
@@ -464,10 +490,39 @@
     result = 37 * result + Coordinate::hashCode(minx);
     result = 37 * result + Coordinate::hashCode(maxx);
     result = 37 * result + Coordinate::hashCode(miny);
-    result = 37 * result + Coordinate::hashCode(maxy);
+   result = 37 * result + Coordinate::hashCode(maxy);
     return result;
 }
 
+/* This is a generic function that really belongs in a utility
+   file somewhere */
+/**
+ * Splits a string into parts based on the supplied delimiters.
+ */
+vector<string> Envelope::split(const string &str, const string &delimiters)
+{
+  vector<string> tokens;
+
+  // Find first "non-delimiter".
+  string::size_type lastPos = 0;
+  string::size_type pos = str.find_first_of(delimiters, lastPos);
+
+  while (string::npos != pos || string::npos != lastPos)
+  {
+    // Found a token, add it to the vector.
+    tokens.push_back(str.substr(lastPos, pos - lastPos));
+    
+    // Skip delimiters.  Note the "not_of"
+    lastPos = str.find_first_not_of(delimiters, pos);
+
+    // Find next "non-delimiter"
+    pos = str.find_first_of(delimiters, lastPos);
+  }
+
+  return tokens;
+}
+
+
 } // namespace geos
 
 /**********************************************************************
Index: source/io/WKBWriter.cpp
===================================================================
RCS file: /home/cvs/postgis/geos/source/io/WKBWriter.cpp,v
retrieving revision 1.3
diff -u -r1.3 WKBWriter.cpp
--- source/io/WKBWriter.cpp    28 Sep 2005 10:15:34 -0000    1.3
+++ source/io/WKBWriter.cpp    8 Jan 2006 21:00:21 -0000
@@ -27,6 +27,19 @@
 }
 
 void
+WKBWriter::writeHEX(const Geometry &g, ostream &os)
+{
+  // setup input/output stream
+  stringstream stream;
+  
+  // write the geometry in wkb format
+  this->write(g, stream);
+
+  // convert to HEX
+  WKBReader::printHEX(stream, os);
+}
+
+void
 WKBWriter::write(const Geometry &g, ostream &os)
 {
     outStream = &os;
Index: source/io/WKBReader.cpp
===================================================================
RCS file: /home/cvs/postgis/geos/source/io/WKBReader.cpp,v
retrieving revision 1.11
diff -u -r1.11 WKBReader.cpp
--- source/io/WKBReader.cpp    10 Nov 2005 16:26:12 -0000    1.11
+++ source/io/WKBReader.cpp    8 Jan 2006 20:58:34 -0000
@@ -47,6 +47,132 @@
     return os;
 }
 
+Geometry *
+WKBReader::readHEX(istream &is){
+  // setup input/output stream
+  stringstream os;
+
+  unsigned char high, low, result_high, result_low, value;
+
+  while(!is.eof())
+    {
+    // get the high part of the byte
+    is >> high;
+    // geth the low part of the byte
+    is >> low;
+
+    switch (high)
+      {
+          case '0' :
+              result_high = 0;
+              break;
+          case '1' :
+              result_high = 1;
+              break;
+          case '2' :
+              result_high = 2;
+              break;
+          case '3' :
+              result_high = 3;
+              break;
+          case '4' :
+              result_high = 4;
+              break;
+          case '5' :
+              result_high = 5;
+              break;
+          case '6' :
+              result_high = 6;
+              break;
+          case '7' :
+              result_high = 7;
+              break;
+          case '8' :
+              result_high = 8;
+              break;
+          case '9' :
+              result_high = 9;
+              break;
+          case 'A' :
+              result_high = 10;
+              break;
+          case 'B' :
+              result_high = 11;
+              break;
+          case 'C' :
+              result_high = 12;
+              break;
+          case 'D' :
+              result_high = 13;
+              break;
+          case 'E' :
+              result_high = 14;
+              break;
+          case 'F' :
+              result_high = 15;
+              break;
+      }
+
+    switch (low)
+      {
+          case '0' :
+              result_low = 0;
+              break;
+          case '1' :
+              result_low = 1;
+              break;
+          case '2' :
+              result_low = 2;
+              break;
+          case '3' :
+              result_low = 3;
+              break;
+          case '4' :
+              result_low = 4;
+              break;
+          case '5' :
+              result_low = 5;
+              break;
+          case '6' :
+              result_low = 6;
+              break;
+          case '7' :
+              result_low = 7;
+              break;
+          case '8' :
+              result_low = 8;
+              break;
+          case '9' :
+              result_low = 9;
+              break;
+          case 'A' :
+              result_low = 10;
+              break;
+          case 'B' :
+              result_low = 11;
+              break;
+          case 'C' :
+              result_low = 12;
+              break;
+          case 'D' :
+              result_low = 13;
+              break;
+          case 'E' :
+              result_low = 14;
+              break;
+          case 'F' :
+              result_low = 15;
+              break;
+      }
+
+    value = (result_high<<4) + result_low;
+    // write the value to the output stream
+    os << value;
+  }
+  
+  // now call read to convert the geometry
+  return this->read(os);
+}
 
 Geometry *
 WKBReader::read(istream &is)

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 2781 bytes
Desc: S/MIME Cryptographic Signature
Url : http://lists.osgeo.org/pipermail/geos-devel/attachments/20060108/12753795/smime.bin


More information about the geos-devel mailing list