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;
  }
 /**
  * Completes the building of the input subgraphs by depth-labelling them, and adds them to the
  * PolygonBuilder. The subgraph list must be sorted in rightmost-coordinate order.
  *
  * @param subgraphList the subgraphs to build
  * @param polyBuilder the PolygonBuilder which will build the final polygons
  */
 private void buildSubgraphs(List subgraphList, PolygonBuilder polyBuilder) {
   List processedGraphs = new ArrayList();
   for (Iterator i = subgraphList.iterator(); i.hasNext(); ) {
     BufferSubgraph subgraph = (BufferSubgraph) i.next();
     Coordinate p = subgraph.getRightmostCoordinate();
     //      int outsideDepth = 0;
     //      if (polyBuilder.containsPoint(p))
     //        outsideDepth = 1;
     SubgraphDepthLocater locater = new SubgraphDepthLocater(processedGraphs);
     int outsideDepth = locater.getDepth(p);
     //      try {
     subgraph.computeDepth(outsideDepth);
     //      }
     //      catch (RuntimeException ex) {
     //        // debugging only
     //        //subgraph.saveDirEdges();
     //        throw ex;
     //      }
     subgraph.findResultEdges();
     processedGraphs.add(subgraph);
     polyBuilder.add(subgraph.getDirectedEdges(), subgraph.getNodes());
   }
 }