/**
   * Parse a geometry starting at offset.
   *
   * @param data ValueGetter with the data to be parsed
   * @return the parsed geometry
   */
  protected Geometry parseGeometry(ValueGetter data) {
    byte endian = data.getByte(); // skip and test endian flag
    if (endian != data.endian) {
      throw new IllegalArgumentException("Endian inconsistency!");
    }
    int typeword = data.getInt();

    int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits

    boolean haveZ = (typeword & 0x80000000) != 0;
    boolean haveM = (typeword & 0x40000000) != 0;
    boolean haveS = (typeword & 0x20000000) != 0;

    int srid = Geometry.UNKNOWN_SRID;

    if (haveS) {
      srid = Geometry.parseSRID(data.getInt());
    }
    Geometry result1;
    switch (realtype) {
      case Geometry.POINT:
        result1 = parsePoint(data, haveZ, haveM);
        break;
      case Geometry.LINESTRING:
        result1 = parseLineString(data, haveZ, haveM);
        break;
      case Geometry.POLYGON:
        result1 = parsePolygon(data, haveZ, haveM);
        break;
      case Geometry.MULTIPOINT:
        result1 = parseMultiPoint(data);
        break;
      case Geometry.MULTILINESTRING:
        result1 = parseMultiLineString(data);
        break;
      case Geometry.MULTIPOLYGON:
        result1 = parseMultiPolygon(data);
        break;
      case Geometry.GEOMETRYCOLLECTION:
        result1 = parseCollection(data);
        break;
      default:
        throw new IllegalArgumentException("Unknown Geometry Type: " + realtype);
    }

    Geometry result = result1;

    if (srid != Geometry.UNKNOWN_SRID) {
      result.setSrid(srid);
    }
    return result;
  }
 private Polygon parsePolygon(ValueGetter data, boolean haveZ, boolean haveM) {
   int count = data.getInt();
   LinearRing[] rings = new LinearRing[count];
   for (int i = 0; i < count; i++) {
     rings[i] = parseLinearRing(data, haveZ, haveM);
   }
   return new Polygon(rings);
 }
 /**
  * Parse an Array of "slim" Points (without endianness and type, part of LinearRing and
  * Linestring, but not MultiPoint!
  *
  * @param haveZ
  * @param haveM
  */
 private Point[] parsePointArray(ValueGetter data, boolean haveZ, boolean haveM) {
   int count = data.getInt();
   Point[] result = new Point[count];
   for (int i = 0; i < count; i++) {
     result[i] = parsePoint(data, haveZ, haveM);
   }
   return result;
 }
  private Point parsePoint(ValueGetter data, boolean haveZ, boolean haveM) {
    double X = data.getDouble();
    double Y = data.getDouble();
    Point result;
    if (haveZ) {
      double Z = data.getDouble();
      result = new Point(X, Y, Z);
    } else {
      result = new Point(X, Y);
    }

    if (haveM) {
      result.setM(data.getDouble());
    }

    return result;
  }
 private GeometryCollection parseCollection(ValueGetter data) {
   int count = data.getInt();
   Geometry[] geoms = new Geometry[count];
   parseGeometryArray(data, geoms);
   return new GeometryCollection(geoms);
 }
 private MultiPolygon parseMultiPolygon(ValueGetter data) {
   int count = data.getInt();
   Polygon[] polys = new Polygon[count];
   parseGeometryArray(data, polys);
   return new MultiPolygon(polys);
 }
 private MultiLineString parseMultiLineString(ValueGetter data) {
   int count = data.getInt();
   LineString[] strings = new LineString[count];
   parseGeometryArray(data, strings);
   return new MultiLineString(strings);
 }
 private MultiPoint parseMultiPoint(ValueGetter data) {
   Point[] points = new Point[data.getInt()];
   parseGeometryArray(data, points);
   return new MultiPoint(points);
 }