Hi,
Unfortunately there's no rule or metric about which operations will fail on invalid geometry. It all comes down to the details of the algorithm. For instance, overlay ops are likely to fail, whereas buffer is relatively robust (although with the caveat that for an invalid geometry the result may not be what is "expected"). In some cases this is noted in the Javadoc.
From my experience, TopologyException are also more likely to happen while working with an integer PrecisionModel than with the double precision model.
The bottom line is that geometry passed to any non-trivial JTS operation should be known to be valid. There is a performance hit for doing this, for sure. Perhaps an even bigger issue is: what do you do with an invalid geometry? (Of course there are various heuristic ways of cleaning it up, but in general this is context-dependent). Generally it's best to ensure validity as early as possible in the system, so that subsequent processing can proceed robustly. That's why JTS leaves the question of when to do validity checking to the client, since only they can know when it is appropriate and efficient to do it.
A clear separation between validating and processing geometries is probably a good thing. What is a bit frustrating for the user is that JTS does not offer much tools to fix invalid geometries before processing. I agree that there is not always one way to fix invalid geometries, but even when the user knows what he wants, the work to do it may be tedious. From my experience, the most frequent problems are :
- polygon with self-intersecting rings
    most obvious solution : noding the rings and creating a MultiPolygon
    doing it with JTS is difficult
- linestring with two identical points
    most obvious solution : creating a Point
    doing it with JTS is not difficult
- multipolygon with overlapping polygons
    no obvious solution : merging ? making hole when possible ?
    creating several features ?
- polygon with less than 4 points
    most obvious solution : creating a LineString or even a Point
    doing it with JTS is not difficult
...
Don't know what postgis ST_MakeValid does exactly, but a method to solve the first case would be great in JTS.

My 2 cents,

Michaƫl


On Wed, May 21, 2014 at 8:00 AM, Rob Emanuele <[email protected] <mailto:[email protected]>> wrote:

    Thanks Martin. We were doing isValid checks other places in the
    code (inside the wrapped geometry initializations), and I assumed
    that was happening for MultiPolygon too, which it wasn't. And I
    haven't quite internalized what vector data is invalid and what's
    valid.

    Is it the case that most operations will throw a TopologyException
    for invalid geometries? I've been debating not putting the isValid
    check inside the wrapped Geometry class initializers, since this
    article:
    http://www.vividsolutions.com/jts/caseStudy_largePolyValidation.htm worries
    me about the potential performance hit of validating each geometry
    on creation. But if most operations you would do with an invalid
    polygon would throw TopologyExceptions, it might be worth it to
    eat the performance hit and make sure everything is valid before
    letting the user start working with the geometry, for the scala
    wrapper.



    On Tue, May 20, 2014 at 5:30 PM, Martin Davis <[email protected]
    <mailto:[email protected]>> wrote:

        The TopologyException occurs because the MultiPolygon is not
        valid.  The two components overlap (precisely, the first
        polygon contains the second).


        On Tue, May 20, 2014 at 2:17 PM, Rob Emanuele
        <[email protected] <mailto:[email protected]>> wrote:

            Hello,

            I was wondering if I could get some insight on why this
            would be throwing a TopologyException. I've been looking
            through the JTS source, and trying different variations on
            the MultiPolygon, but I can't seem to nail down what about
            this is causing the issue (sorry for the scala code, I did
            this example in the interpreter, but I think it should be
            clear):

            import com.vividsolutions.jts.geom._

            val f = new GeometryFactory()
            val l = f.createLineString(Array(new Coordinate(0,0), new
            Coordinate(2,2)))

            val exterior1 = f.createLinearRing(Array(new
            Coordinate(0,0), new Coordinate(0,2), new Coordinate(2,2),
            new Coordinate(2,0), new Coordinate(0,0)))

            val exterior2 = f.createLinearRing(Array(new
            Coordinate(0,0), new Coordinate(0,1), new Coordinate(2,1),
            new Coordinate(2,0), new Coordinate(0,0)))


            val p1 = f.createPolygon(exterior1, Array())

            val p2 = f.createPolygon(exterior2, Array())


            val mp = f.createMultiPolygon(Array(p1, p2))

            mp.union(l)

            Here is the exception thrown in the interpreter:
            com.vividsolutions.jts.geom.TopologyException: side
            location conflict [ (0.0, 1.0, NaN) ]
                    at
            
com.vividsolutions.jts.geomgraph.EdgeEndStar.propagateSideLabels(EdgeEndStar.java:300)
                    at
            
com.vividsolutions.jts.geomgraph.EdgeEndStar.computeLabelling(EdgeEndStar.java:136)
                    at
            
com.vividsolutions.jts.geomgraph.DirectedEdgeStar.computeLabelling(DirectedEdgeStar.java:127)
                    at
            
com.vividsolutions.jts.operation.overlay.OverlayOp.computeLabelling(OverlayOp.java:373)
                    at
            
com.vividsolutions.jts.operation.overlay.OverlayOp.computeOverlay(OverlayOp.java:173)
                    at
            
com.vividsolutions.jts.operation.overlay.OverlayOp.getResultGeometry(OverlayOp.java:127)
                    at
            
com.vividsolutions.jts.operation.overlay.OverlayOp.overlayOp(OverlayOp.java:66)
                    at
            
com.vividsolutions.jts.operation.overlay.snap.SnapIfNeededOverlayOp.getResultGeometry(SnapIfNeededOverlayOp.java:96)
                    at
            
com.vividsolutions.jts.operation.overlay.snap.SnapIfNeededOverlayOp.overlayOp(SnapIfNeededOverlayOp.java:58)
                    at
            com.vividsolutions.jts.geom.Geometry.union(Geometry.java:1395)
                    at .<init>(<console>:18)
                    at .<clinit>(<console>)
                    at .<init>(<console>:7)
                    at .<clinit>(<console>)
                    at $print(<console>)
                    at
            sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                    at
            
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
                    at
            
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                    at java.lang.reflect.Method.invoke(Method.java:606)
                    at
            
scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734)
                    at
            
scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:983)
                    at
            scala.tools.nsc.interpreter.IMain.loadAndRunReq$1(IMain.scala:573)
                    at
            scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:604)
                    at
            scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:568)
                    at
            scala.tools.nsc.interpreter.ILoop.reallyInterpret$1(ILoop.scala:756)
                    at
            
scala.tools.nsc.interpreter.ILoop.interpretStartingWith(ILoop.scala:801)
                    at
            scala.tools.nsc.interpreter.ILoop.command(ILoop.scala:713)
                    at
            scala.tools.nsc.interpreter.ILoop.processLine$1(ILoop.scala:577)
                    at
            scala.tools.nsc.interpreter.ILoop.innerLoop$1(ILoop.scala:584)
                    at
            scala.tools.nsc.interpreter.ILoop.loop(ILoop.scala:587)
                    at
            
scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply$mcZ$sp(ILoop.scala:878)
                    at
            
scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:833)
                    at
            
scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:833)
                    at
            
scala.tools.nsc.util.ScalaClassLoader$.savingContextLoader(ScalaClassLoader.scala:135)
                    at
            scala.tools.nsc.interpreter.ILoop.process(ILoop.scala:833)
                    at
            scala.tools.nsc.interpreter.ILoop.main(ILoop.scala:900)
                    at
            xsbt.ConsoleInterface.run(ConsoleInterface.scala:57)
                    at
            sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                    at
            
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
                    at
            
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                    at java.lang.reflect.Method.invoke(Method.java:606)
                    at
            sbt.compiler.AnalyzingCompiler.call(AnalyzingCompiler.scala:73)
                    at
            sbt.compiler.AnalyzingCompiler.console(AnalyzingCompiler.scala:64)
                    at sbt.Console.console0$1(Console.scala:23)
                    at
            
sbt.Console$$anonfun$apply$2$$anonfun$apply$1.apply$mcV$sp(Console.scala:24)
                    at sbt.TrapExit$.executeMain$1(TrapExit.scala:33)
                    at sbt.TrapExit$$anon$1.run(TrapExit.scala:42)

            Any insights on why this simple example is throwing?

            Thanks,
            Rob


            
------------------------------------------------------------------------------
            "Accelerate Dev Cycles with Automated Cross-Browser
            Testing - For FREE
            Instantly run your Selenium tests across 300+ browser/OS
            combos.
            Get unparalleled scalability from the best Selenium
            testing platform available
            Simple to use. Nothing to install. Get started now for free."
            http://p.sf.net/sfu/SauceLabs
            _______________________________________________
            Jts-topo-suite-user mailing list
            [email protected]
            <mailto:[email protected]>
            https://lists.sourceforge.net/lists/listinfo/jts-topo-suite-user






------------------------------------------------------------------------------
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.
Get unparalleled scalability from the best Selenium testing platform available
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs


_______________________________________________
Jts-topo-suite-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jts-topo-suite-user

------------------------------------------------------------------------------
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.
Get unparalleled scalability from the best Selenium testing platform available
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs
_______________________________________________
Jts-topo-suite-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jts-topo-suite-user

Reply via email to