protected Geometry transformPolygon(Polygon geom, Geometry parent) {
    boolean isAllValidLinearRings = true;
    Geometry shell = transformLinearRing((LinearRing) geom.getExteriorRing(), geom);

    if (shell == null || !(shell instanceof LinearRing) || shell.isEmpty())
      isAllValidLinearRings = false;
    // return factory.createPolygon(null, null);

    ArrayList holes = new ArrayList();
    for (int i = 0; i < geom.getNumInteriorRing(); i++) {
      Geometry hole = transformLinearRing((LinearRing) geom.getInteriorRingN(i), geom);
      if (hole == null || hole.isEmpty()) {
        continue;
      }
      if (!(hole instanceof LinearRing)) isAllValidLinearRings = false;

      holes.add(hole);
    }

    if (isAllValidLinearRings)
      return factory.createPolygon(
          (LinearRing) shell, (LinearRing[]) holes.toArray(new LinearRing[] {}));
    else {
      List components = new ArrayList();
      if (shell != null) components.add(shell);
      components.addAll(holes);
      return factory.buildGeometry(components);
    }
  }
 private static Geometry convertSegStrings(Iterator it) {
   GeometryFactory fact = new GeometryFactory();
   List lines = new ArrayList();
   while (it.hasNext()) {
     SegmentString ss = (SegmentString) it.next();
     LineString line = fact.createLineString(ss.getCoordinates());
     lines.add(line);
   }
   return fact.buildGeometry(lines);
 }
 protected Geometry transformMultiPolygon(MultiPolygon geom, Geometry parent) {
   List transGeomList = new ArrayList();
   for (int i = 0; i < geom.getNumGeometries(); i++) {
     Geometry transformGeom = transformPolygon((Polygon) geom.getGeometryN(i), geom);
     if (transformGeom == null) continue;
     if (transformGeom.isEmpty()) continue;
     transGeomList.add(transformGeom);
   }
   return factory.buildGeometry(transGeomList);
 }
 protected Geometry transformGeometryCollection(GeometryCollection geom, Geometry parent) {
   List transGeomList = new ArrayList();
   for (int i = 0; i < geom.getNumGeometries(); i++) {
     Geometry transformGeom = transform(geom.getGeometryN(i));
     if (transformGeom == null) continue;
     if (pruneEmptyGeometry && transformGeom.isEmpty()) continue;
     transGeomList.add(transformGeom);
   }
   if (preserveGeometryCollectionType)
     return factory.createGeometryCollection(GeometryFactory.toGeometryArray(transGeomList));
   return factory.buildGeometry(transGeomList);
 }
  /**
   * @return a single geometry product of unioning all the bounding boxes acquired while traversing
   *     the diff
   */
  public Geometry buildGeometry() {
    List<Geometry> geomList = nonPoints;
    nonPoints = null;
    if (!points.isEmpty()) {
      geomList.add(points);
    }
    points = null;

    Geometry buildGeometry = GEOM_FACTORY.buildGeometry(geomList);
    geomList.clear();
    Geometry union = buildGeometry.union();
    return union;
  }
  public Geometry buffer(Geometry g, double distance) {
    PrecisionModel precisionModel = workingPrecisionModel;
    if (precisionModel == null) precisionModel = g.getPrecisionModel();

    // factory must be the same as the one used by the input
    geomFact = g.getFactory();

    OffsetCurveBuilder curveBuilder = new OffsetCurveBuilder(precisionModel, bufParams);

    OffsetCurveSetBuilder curveSetBuilder = new OffsetCurveSetBuilder(g, distance, curveBuilder);

    List bufferSegStrList = curveSetBuilder.getCurves();

    // short-circuit test
    if (bufferSegStrList.size() <= 0) {
      return createEmptyResultGeometry();
    }

    // BufferDebug.runCount++;
    // String filename = "run" + BufferDebug.runCount + "_curves";
    // System.out.println("saving " + filename);
    // BufferDebug.saveEdges(bufferEdgeList, filename);
    // DEBUGGING ONLY
    // WKTWriter wktWriter = new WKTWriter();
    // Debug.println("Rings: " + wktWriter.write(convertSegStrings(bufferSegStrList.iterator())));
    // wktWriter.setMaxCoordinatesPerLine(10);
    // System.out.println(wktWriter.writeFormatted(convertSegStrings(bufferSegStrList.iterator())));

    computeNodedEdges(bufferSegStrList, precisionModel);
    graph = new PlanarGraph(new OverlayNodeFactory());
    graph.addEdges(edgeList.getEdges());

    List subgraphList = createSubgraphs(graph);
    PolygonBuilder polyBuilder = new PolygonBuilder(geomFact);
    buildSubgraphs(subgraphList, polyBuilder);
    List resultPolyList = polyBuilder.getPolygons();

    // just in case...
    if (resultPolyList.size() <= 0) {
      return createEmptyResultGeometry();
    }

    Geometry resultGeom = geomFact.buildGeometry(resultPolyList);
    return resultGeom;
  }
  /**
   * Only return the lines contained on the given geometry, the non lines geometry are rejected.
   *
   * @param geometry Intersection geometry between split line and source geometry.
   * @return The valid geometries needed for the graph, those are lines and multiLines.
   */
  private Geometry filterLineString(Geometry geometry) {

    List<Geometry> filteredLines = new ArrayList<Geometry>();
    for (int i = 0; i < geometry.getNumGeometries(); i++) {

      Geometry possibleLine = geometry.getGeometryN(i);

      // if there are point geometries, discard it.
      if (possibleLine instanceof LineString || possibleLine instanceof MultiLineString) {

        // also remove very very short liens.
        if (possibleLine.getLength() > UsefulSplitLineBuilder.DEPRECIATE_VALUE) {

          filteredLines.add(possibleLine);
        }
      }
    }
    GeometryFactory gf = geometry.getFactory();

    return gf.buildGeometry(filteredLines);
  }
  @Override
  public void run() {
    /*
     * This tool places the nodes (vertices) from a shapefile of polygons or
     * lines into a shapefile of Point ShapeType.
     */

    amIActive = true;
    String inputFile;
    String outputFile;
    int progress;
    int i, n;
    int numFeatures;
    int oneHundredthTotal;
    ShapeType shapeType, outputShapeType;
    GeometryFactory factory = new GeometryFactory();
    double distTolerance = 10;
    boolean loseNoFeatures = false;

    if (args.length <= 0) {
      showFeedback("Plugin parameters have not been set.");
      return;
    }

    inputFile = args[0];
    outputFile = args[1];
    distTolerance = Double.parseDouble(args[2]);
    loseNoFeatures = Boolean.parseBoolean(args[3]);

    // check to see that the inputHeader and outputHeader are not null.
    if ((inputFile == null) || (outputFile == null)) {
      showFeedback("One or more of the input parameters have not been set properly.");
      return;
    }

    try {
      // set up the input shapefile.
      ShapeFile input = new ShapeFile(inputFile);
      shapeType = input.getShapeType();

      // make sure that the shapetype is either a flavour of polyline or polygon.
      if (shapeType.getBaseType() != ShapeType.POLYGON
          && shapeType.getBaseType() != ShapeType.POLYLINE) {
        showFeedback("This tool only works with shapefiles of a polygon or line base shape type.");
        return;
      }

      // set up the output files of the shapefile and the dbf
      if (shapeType.getBaseType() == ShapeType.POLYGON) {
        outputShapeType = ShapeType.POLYGON;
      } else if (shapeType.getBaseType() == ShapeType.POLYLINE) {
        outputShapeType = ShapeType.POLYLINE;
      } else {
        showFeedback("This tool only works with shapefiles of a polygon or line base shape type.");
        return;
      }

      int numOutputFields = input.getAttributeTable().getFieldCount() + 1;
      int numInputFields = input.getAttributeTable().getFieldCount();
      DBFField[] inputFields = input.getAttributeTable().getAllFields();
      DBFField fields[] = new DBFField[numOutputFields];

      fields[0] = new DBFField();
      fields[0].setName("PARENT_ID");
      fields[0].setDataType(DBFField.DBFDataType.NUMERIC);
      fields[0].setFieldLength(10);
      fields[0].setDecimalCount(0);

      System.arraycopy(inputFields, 0, fields, 1, numInputFields);

      ShapeFile output = new ShapeFile(outputFile, outputShapeType, fields);

      numFeatures = input.getNumberOfRecords();
      oneHundredthTotal = numFeatures / 100;
      n = 0;
      progress = 0;
      com.vividsolutions.jts.geom.Geometry[] recJTS = null;
      int recordNum;
      for (ShapeFileRecord record : input.records) {
        recordNum = record.getRecordNumber();
        Object[] attData = input.getAttributeTable().getRecord(recordNum - 1);
        // featureNum++;
        recJTS = record.getGeometry().getJTSGeometries();

        ArrayList<com.vividsolutions.jts.geom.Geometry> geomList = new ArrayList<>();
        for (int a = 0; a < recJTS.length; a++) {
          geomList.add(recJTS[a]);
        }

        DouglasPeuckerSimplifier dps =
            new DouglasPeuckerSimplifier(factory.buildGeometry(geomList));
        dps.setDistanceTolerance(distTolerance);
        com.vividsolutions.jts.geom.Geometry outputGeom = dps.getResultGeometry();

        if (outputGeom.isEmpty() && loseNoFeatures) {
          outputGeom = factory.buildGeometry(geomList);
        }
        if (!outputGeom.isEmpty()) {
          for (int a = 0; a < outputGeom.getNumGeometries(); a++) {
            // parentRecNum = 0;
            com.vividsolutions.jts.geom.Geometry g = outputGeom.getGeometryN(a);
            if (g instanceof com.vividsolutions.jts.geom.Polygon && !g.isEmpty()) {
              com.vividsolutions.jts.geom.Polygon p = (com.vividsolutions.jts.geom.Polygon) g;
              ArrayList<ShapefilePoint> pnts = new ArrayList<>();
              int[] parts = new int[p.getNumInteriorRing() + 1];

              Coordinate[] buffCoords = p.getExteriorRing().getCoordinates();
              if (!Topology.isLineClosed(buffCoords)) {
                System.out.println("Exterior ring not closed.");
              }
              if (Topology.isClockwisePolygon(buffCoords)) {
                for (i = 0; i < buffCoords.length; i++) {
                  pnts.add(new ShapefilePoint(buffCoords[i].x, buffCoords[i].y));
                }
              } else {
                for (i = buffCoords.length - 1; i >= 0; i--) {
                  pnts.add(new ShapefilePoint(buffCoords[i].x, buffCoords[i].y));
                }
              }

              for (int b = 0; b < p.getNumInteriorRing(); b++) {
                parts[b + 1] = pnts.size();
                buffCoords = p.getInteriorRingN(b).getCoordinates();
                if (!Topology.isLineClosed(buffCoords)) {
                  System.out.println("Interior ring not closed.");
                }
                if (Topology.isClockwisePolygon(buffCoords)) {
                  for (i = buffCoords.length - 1; i >= 0; i--) {
                    pnts.add(new ShapefilePoint(buffCoords[i].x, buffCoords[i].y));
                  }
                } else {
                  for (i = 0; i < buffCoords.length; i++) {
                    pnts.add(new ShapefilePoint(buffCoords[i].x, buffCoords[i].y));
                  }
                }
              }

              PointsList pl = new PointsList(pnts);
              whitebox.geospatialfiles.shapefile.Polygon wbPoly =
                  new whitebox.geospatialfiles.shapefile.Polygon(parts, pl.getPointsArray());
              Object[] rowData = new Object[numOutputFields];
              rowData[0] = new Double(recordNum - 1);
              System.arraycopy(attData, 0, rowData, 1, numInputFields);
              output.addRecord(wbPoly, rowData);
            } else if (g instanceof com.vividsolutions.jts.geom.LineString && !g.isEmpty()) {
              LineString ls = (LineString) g;
              ArrayList<ShapefilePoint> pnts = new ArrayList<>();

              int[] parts = {0};

              Coordinate[] coords = ls.getCoordinates();
              for (i = 0; i < coords.length; i++) {
                pnts.add(new ShapefilePoint(coords[i].x, coords[i].y));
              }

              PointsList pl = new PointsList(pnts);
              whitebox.geospatialfiles.shapefile.PolyLine wbGeometry =
                  new whitebox.geospatialfiles.shapefile.PolyLine(parts, pl.getPointsArray());
              Object[] rowData = new Object[numOutputFields];
              rowData[0] = new Double(recordNum - 1);
              System.arraycopy(attData, 0, rowData, 1, numInputFields);
              output.addRecord(wbGeometry, rowData);
            }
          }
        }
        n++;
        if (n >= oneHundredthTotal) {
          n = 0;
          if (cancelOp) {
            cancelOperation();
            return;
          }
          progress++;
          updateProgress(progress);
        }
      }

      output.write();

      // returning a header file string displays the image.
      updateProgress("Displaying vector: ", 0);
      returnData(outputFile);

    } catch (OutOfMemoryError oe) {
      myHost.showFeedback("An out-of-memory error has occurred during operation.");
    } catch (Exception e) {
      myHost.showFeedback("An error has occurred during operation. See log file for details.");
      myHost.logException("Error in " + getDescriptiveName(), e);
    } finally {
      updateProgress("Progress: ", 0);
      // tells the main application that this process is completed.
      amIActive = false;
      myHost.pluginComplete();
    }
  }