Dear JTS community,

firstly, thank you for an awesome JTS, it's very helpful with my work.

Secondly, I have a problem.
I'm trying to process contours of a 3D surface and plot them in a 2D 
image as lines and filled polygons. In order to do that I'm noding a 
large set of individual contour segments (up to hundreds of thousands) 
together with a bounding rectangle and then polygonize the noded set. My 
problem is sometimes the contouring algorithm is not exact and outputs a 
contour which has a coordinate 1ULP off the correct value. When it 
happens, the noder I'm using is not reporting it as an intersection with 
the bounding rectangle. Therefore, resulting polygonization has dangles 
which is not correct result in my domain.

What is wrong with my approach? Should I use a different noder or 
precision model?

To illustrate the problem, here is an example code:

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.vividsolutions.jts.algorithm.RobustLineIntersector;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.PrecisionModel;
import com.vividsolutions.jts.noding.IntersectionAdder;
import com.vividsolutions.jts.noding.MCIndexNoder;
import com.vividsolutions.jts.noding.NodedSegmentString;
import com.vividsolutions.jts.noding.Noder;
import com.vividsolutions.jts.noding.SegmentString;
import com.vividsolutions.jts.operation.polygonize.Polygonizer;

public class OneULPProblem {
     public static void main(String[] args) {
         GeometryFactory gf = new GeometryFactory(new 
PrecisionModel(PrecisionModel.FLOATING));
         LineString borders = gf.createLineString(new Coordinate[] {
                 new Coordinate(-180D, -90D),
                 new Coordinate(180D, -90D),
                 new Coordinate(180D, 90D),
                 new Coordinate(-180D, 90D),
                 new Coordinate(-180D, -90D), });
         LineString contourA = gf.createLineString(new Coordinate[] {
                 new Coordinate(-180D, 0D),
                 new Coordinate(-90D, -60D),
                 new Coordinate(90D, 60D),
                 new Coordinate(180D, 0D), });
         LineString contourB = gf.createLineString(new Coordinate[] {
                 new Coordinate(-180D, 0D),
                 new Coordinate(-90D, -60D),
                 new Coordinate(90D, 60D),
                 new 
Coordinate(Double.longBitsToDouble(Double.doubleToLongBits(180D) - 1), 
0D), });

         System.out.println("Exact contour:");
         polygonize(gf, borders, contourA);
         System.out.println("\nOff-by-1ULP contour:");
         polygonize(gf, borders, contourB);
     }

     private static void polygonize(GeometryFactory gf, LineString 
borders, LineString contour) {
         List<SegmentString> segments = new ArrayList<SegmentString>();
         segments.add(lineStrToSegmentStr(borders));
         segments.add(lineStrToSegmentStr(contour));
         Noder noder = new MCIndexNoder(new IntersectionAdder(new 
RobustLineIntersector()));
         noder.computeNodes(segments);
         Collection<?> nodedSubstrings = noder.getNodedSubstrings();
         List<LineString> lineStrings = new 
ArrayList<>(nodedSubstrings.size());
         for (Object obj : nodedSubstrings) {
             lineStrings.add(gf.createLineString(((SegmentString) 
obj).getCoordinates()));
         }
         Geometry noded = gf.buildGeometry(lineStrings);
         Polygonizer polygonizer = new Polygonizer();
         polygonizer.add(noded);
         print(polygonizer.getPolygons(), "Polygons");
         print(polygonizer.getDangles(), "Dangles");
         print(polygonizer.getCutEdges(), "Cut Edges");
         print(polygonizer.getInvalidRingLines(), "Invalid Ring Lines");
     }

     private static final SegmentString lineStrToSegmentStr(LineString ls) {
         return new NodedSegmentString(ls.getCoordinates(), null);
     }

     private static final void print(Collection<?> coll, String type) {
         if (coll.isEmpty()) {
             return;
         }
         System.out.println(type + ": ");
         for (Object o : coll) {
             System.out.println(o);
         }
     }
}

The code above outputs this:

Exact contour:
Polygons:
POLYGON ((180 0, 90 60, -90 -60, -180 0, -180 90, 180 90, 180 0))
POLYGON ((-180 -90, -180 0, -90 -60, 90 60, 180 0, 180 -90, -180 -90))

Off-by-1ULP contour:
Polygons:
POLYGON ((-180 -90, -180 0, -180 90, 180 90, 180 -90, -180 -90))
Dangles:
LINESTRING (-180 0, -90 -60, 90 60, 179.99999999999997 0)

What can I do to have both resulting polygonizations identical given 
that I won't change the input?

Thanks,

-- 
Peter Kovac
MicroStep-MIS
Programmer
[email protected]
http://www.microstep-mis.com


------------------------------------------------------------------------------
Comprehensive Server Monitoring with Site24x7.
Monitor 10 servers for $9/Month.
Get alerted through email, SMS, voice calls or mobile push notifications.
Take corrective actions from your mobile device.
http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk
_______________________________________________
Jts-topo-suite-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jts-topo-suite-user

Reply via email to