/**
   * make sure outer ring is CCW and holes are CW for all the polygons in the Geometry
   *
   * @param mp set of polygons to check
   */
  MultiPolygon makeGoodSHAPEMultiPolygon(MultiPolygon mp) {
    MultiPolygon result;
    Polygon[] ps = new Polygon[mp.getNumGeometries()];

    // check each sub-polygon
    for (int t = 0; t < mp.getNumGeometries(); t++) {
      ps[t] = makeGoodSHAPEPolygon((Polygon) mp.getGeometryN(t));
    }

    result = new MultiPolygon(ps, new PrecisionModel(), 0);

    return result;
  }
  public Geobuf.Data.Geometry multiPolyToGeobuf(MultiPolygon poly) {
    Geobuf.Data.Geometry.Builder builder =
        Geobuf.Data.Geometry.newBuilder().setType(Geobuf.Data.Geometry.Type.MULTIPOLYGON);

    // first we specify the number of polygons
    builder.addLengths(poly.getNumGeometries());

    for (int i = 0; i < poly.getNumGeometries(); i++) {
      Polygon p = (Polygon) poly.getGeometryN(i);
      // how many rings there are
      builder.addLengths(p.getNumInteriorRing() + 1);

      Stream<LineString> interiorRings =
          IntStream.range(0, p.getNumInteriorRing()).<LineString>mapToObj(p::getInteriorRingN);

      Stream.concat(Stream.of(p.getExteriorRing()), interiorRings)
          .forEach(r -> addRing(r, builder));
    }

    return builder.build();
  }