[jts] 03/10: Imported Upstream version 1.6

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Tue Aug 4 17:08:45 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository jts.

commit de1e1dd5049d6a3f06a81855d853df58c4aef059
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Tue Aug 4 19:06:17 2015 +0200

    Imported Upstream version 1.6
---
 bin/test_robust.bat                                |   25 +
 doc/JTS Developer Guide.pdf                        |  Bin 261007 -> 565884 bytes
 doc/JTS Technical Specs.pdf                        |  Bin 318452 -> 804075 bytes
 doc/JTS TestBuilder & TestRunner User Guide.pdf    |  Bin 1837712 -> 598039 bytes
 doc/JTS Version History.html                       |  301 ++
 doc/JTS Version History.pdf                        |  Bin 361171 -> 0 bytes
 doc/LICENSE.txt                                    |  504 ---
 src/MANIFEST.MF                                    |    2 +-
 .../vividsolutions/jts/algorithm/CGAlgorithms.java |   68 +-
 .../vividsolutions/jts/algorithm/CentroidArea.java |    2 +-
 .../vividsolutions/jts/algorithm/CentroidLine.java |    2 +-
 .../jts/algorithm/CentroidPoint.java               |    2 +-
 .../vividsolutions/jts/algorithm/ConvexHull.java   |    2 +-
 .../vividsolutions/jts/algorithm/HCoordinate.java  |    4 +-
 .../jts/algorithm/InteriorPointArea.java           |    2 +-
 .../jts/algorithm/InteriorPointLine.java           |    2 +-
 .../jts/algorithm/InteriorPointPoint.java          |    2 +-
 .../jts/algorithm/LineIntersector.java             |    4 +-
 .../jts/algorithm/MCPointInRing.java               |    2 +-
 .../jts/algorithm/MinimumDiameter.java             |    2 +-
 .../jts/algorithm/NonRobustCGAlgorithms.java       |    3 +-
 .../jts/algorithm/NonRobustLineIntersector.java    |    4 +-
 .../jts/algorithm/NotRepresentableException.java   |    2 +-
 .../vividsolutions/jts/algorithm/PointInRing.java  |    2 +-
 .../vividsolutions/jts/algorithm/PointLocator.java |    2 +-
 .../jts/algorithm/RobustCGAlgorithms.java          |    7 +-
 .../jts/algorithm/RobustDeterminant.java           |    4 +-
 .../jts/algorithm/RobustLineIntersector.java       |    4 +-
 .../jts/algorithm/SIRtreePointInRing.java          |    2 +-
 .../jts/algorithm/SimplePointInAreaLocator.java    |    2 +-
 .../jts/algorithm/SimplePointInRing.java           |    2 +-
 src/com/vividsolutions/jts/geom/Coordinate.java    |    2 +-
 .../vividsolutions/jts/geom/CoordinateArrays.java  |    2 +-
 .../vividsolutions/jts/geom/CoordinateFilter.java  |    2 +-
 .../vividsolutions/jts/geom/CoordinateList.java    |    2 +-
 .../jts/geom/CoordinateSequence.java               |  221 +-
 .../jts/geom/CoordinateSequenceFactory.java        |  105 +-
 .../jts/geom/DefaultCoordinateSequence.java        |  310 +-
 .../jts/geom/DefaultCoordinateSequenceFactory.java |  120 +-
 src/com/vividsolutions/jts/geom/Dimension.java     |    2 +-
 src/com/vividsolutions/jts/geom/Envelope.java      |    2 +-
 src/com/vividsolutions/jts/geom/Geometry.java      |  116 +-
 .../jts/geom/GeometryCollection.java               |   10 +-
 .../jts/geom/GeometryCollectionIterator.java       |    6 +-
 .../jts/geom/GeometryComponentFilter.java          |    2 +-
 .../vividsolutions/jts/geom/GeometryFactory.java   |   12 +-
 .../vividsolutions/jts/geom/GeometryFilter.java    |    2 +-
 .../jts/geom/IntersectionMatrix.java               |    2 +-
 src/com/vividsolutions/jts/geom/LineSegment.java   |    2 +-
 src/com/vividsolutions/jts/geom/LineString.java    |   41 +-
 src/com/vividsolutions/jts/geom/LinearRing.java    |   16 +-
 src/com/vividsolutions/jts/geom/Location.java      |    2 +-
 .../vividsolutions/jts/geom/MultiLineString.java   |   16 +-
 src/com/vividsolutions/jts/geom/MultiPoint.java    |   16 +-
 src/com/vividsolutions/jts/geom/MultiPolygon.java  |   12 +-
 src/com/vividsolutions/jts/geom/Point.java         |   25 +-
 src/com/vividsolutions/jts/geom/Polygon.java       |   53 +-
 .../vividsolutions/jts/geom/PrecisionModel.java    |   13 +-
 .../vividsolutions/jts/geom/TopologyException.java |    2 +-
 src/com/vividsolutions/jts/geom/Triangle.java      |    2 +-
 .../jts/geom/impl/CoordinateArraySequence.java     |  223 ++
 .../geom/impl/CoordinateArraySequenceFactory.java  |   92 +
 .../jts/geom/impl/PackedCoordinateSequence.java    |  435 +++
 .../geom/impl/PackedCoordinateSequenceFactory.java |  137 +
 .../jts/geom/util/GeometryEditor.java              |    4 +-
 .../jts/geom/util/GeometryTransformer.java         |    4 +-
 .../jts/geom/util/LinearComponentExtracter.java    |    2 +-
 .../jts/geom/util/PointExtracter.java              |    2 +-
 .../jts/geom/util/PolygonExtracter.java            |    2 +-
 .../geom/util/ShortCircuitedGeometryVisitor.java   |   36 +
 src/com/vividsolutions/jts/geomgraph/Depth.java    |    2 +-
 .../vividsolutions/jts/geomgraph/DirectedEdge.java |   18 +-
 .../jts/geomgraph/DirectedEdgeStar.java            |    2 +-
 src/com/vividsolutions/jts/geomgraph/Edge.java     |    2 +-
 src/com/vividsolutions/jts/geomgraph/EdgeEnd.java  |    2 +-
 .../vividsolutions/jts/geomgraph/EdgeEndStar.java  |    2 +-
 .../jts/geomgraph/EdgeIntersection.java            |    2 +-
 .../jts/geomgraph/EdgeIntersectionList.java        |    2 +-
 src/com/vividsolutions/jts/geomgraph/EdgeList.java |    2 +-
 .../jts/geomgraph/EdgeNodingValidator.java         |    2 +-
 src/com/vividsolutions/jts/geomgraph/EdgeRing.java |    2 +-
 .../jts/geomgraph/GeometryGraph.java               |    2 +-
 .../jts/geomgraph/GraphComponent.java              |    2 +-
 src/com/vividsolutions/jts/geomgraph/Label.java    |    2 +-
 src/com/vividsolutions/jts/geomgraph/Node.java     |    2 +-
 .../vividsolutions/jts/geomgraph/NodeFactory.java  |    2 +-
 src/com/vividsolutions/jts/geomgraph/NodeMap.java  |    2 +-
 .../vividsolutions/jts/geomgraph/PlanarGraph.java  |    4 +-
 src/com/vividsolutions/jts/geomgraph/Position.java |    2 +-
 src/com/vividsolutions/jts/geomgraph/Quadrant.java |    4 +-
 .../jts/geomgraph/TopologyLocation.java            |    2 +-
 .../jts/geomgraph/index/EdgeSetIntersector.java    |    4 +-
 .../jts/geomgraph/index/MonotoneChain.java         |    2 +-
 .../jts/geomgraph/index/MonotoneChainEdge.java     |    2 +-
 .../jts/geomgraph/index/MonotoneChainIndexer.java  |    2 +-
 .../jts/geomgraph/index/SegmentIntersector.java    |    2 +-
 .../geomgraph/index/SimpleEdgeSetIntersector.java  |    2 +-
 .../index/SimpleMCSweepLineIntersector.java        |    4 +-
 .../index/SimpleSweepLineIntersector.java          |    4 +-
 .../jts/geomgraph/index/SweepLineEvent.java        |    2 +-
 .../jts/geomgraph/index/SweepLineSegment.java      |    2 +-
 .../vividsolutions/jts/index/ArrayListVisitor.java |    2 +-
 src/com/vividsolutions/jts/index/IndexVisitor.java |    2 +-
 src/com/vividsolutions/jts/index/ItemVisitor.java  |    2 +-
 src/com/vividsolutions/jts/index/SpatialIndex.java |    2 +-
 .../vividsolutions/jts/index/bintree/Bintree.java  |    2 +-
 .../vividsolutions/jts/index/bintree/Interval.java |    2 +-
 src/com/vividsolutions/jts/index/bintree/Key.java  |    2 +-
 src/com/vividsolutions/jts/index/bintree/Node.java |    2 +-
 .../vividsolutions/jts/index/bintree/NodeBase.java |    2 +-
 src/com/vividsolutions/jts/index/bintree/Root.java |    2 +-
 .../jts/index/chain/MonotoneChain.java             |    2 +-
 .../jts/index/chain/MonotoneChainBuilder.java      |    2 +-
 .../index/chain/MonotoneChainOverlapAction.java    |    2 +-
 .../jts/index/chain/MonotoneChainSelectAction.java |    2 +-
 .../jts/index/quadtree/DoubleBits.java             |    2 +-
 .../jts/index/quadtree/IntervalSize.java           |    2 +-
 src/com/vividsolutions/jts/index/quadtree/Key.java |    3 +-
 .../vividsolutions/jts/index/quadtree/Node.java    |    2 +-
 .../jts/index/quadtree/NodeBase.java               |    2 +-
 .../jts/index/quadtree/Quadtree.java               |    2 +-
 .../vividsolutions/jts/index/quadtree/Root.java    |    2 +-
 .../jts/index/strtree/AbstractNode.java            |    2 +-
 .../jts/index/strtree/AbstractSTRtree.java         |    2 +-
 .../jts/index/strtree/Boundable.java               |    2 +-
 .../vividsolutions/jts/index/strtree/Interval.java |    2 +-
 .../jts/index/strtree/ItemBoundable.java           |    2 +-
 .../vividsolutions/jts/index/strtree/SIRtree.java  |    2 +-
 .../vividsolutions/jts/index/strtree/STRtree.java  |    2 +-
 .../jts/index/sweepline/SweepLineEvent.java        |    2 +-
 .../jts/index/sweepline/SweepLineIndex.java        |    2 +-
 .../jts/index/sweepline/SweepLineInterval.java     |    2 +-
 .../index/sweepline/SweepLineOverlapAction.java    |    2 +-
 src/com/vividsolutions/jts/io/ParseException.java  |    2 +-
 src/com/vividsolutions/jts/io/WKTReader.java       |    2 +-
 src/com/vividsolutions/jts/io/WKTWriter.java       |    2 +-
 .../vividsolutions/jts/noding/IteratedNoder.java   |    2 +-
 .../vividsolutions/jts/noding/MCQuadtreeNoder.java |    2 +-
 src/com/vividsolutions/jts/noding/Noder.java       |    2 +-
 .../vividsolutions/jts/noding/NodingValidator.java |    2 +-
 .../jts/noding/SegmentIntersector.java             |    2 +-
 src/com/vividsolutions/jts/noding/SegmentNode.java |    4 +-
 .../vividsolutions/jts/noding/SegmentNodeList.java |    2 +-
 .../vividsolutions/jts/noding/SegmentString.java   |    2 +-
 src/com/vividsolutions/jts/noding/SimpleNoder.java |    2 +-
 .../jts/noding/snapround/SegmentSnapper.java       |    2 +-
 .../snapround/SimpleSegmentStringsSnapper.java     |    2 +-
 .../jts/noding/snapround/SnapRounder.java          |    2 +-
 .../jts/operation/GeometryGraphOperation.java      |    2 +-
 .../vividsolutions/jts/operation/IsSimpleOp.java   |    2 +-
 .../jts/operation/buffer/BufferBuilder.java        |    4 +-
 .../jts/operation/buffer/BufferOp.java             |    4 +-
 .../jts/operation/buffer/BufferSubgraph.java       |    4 +-
 .../jts/operation/buffer/OffsetCurveBuilder.java   |    2 +-
 .../operation/buffer/OffsetCurveSetBuilder.java    |    4 +-
 .../jts/operation/buffer/RightmostEdgeFinder.java  |    4 +-
 .../jts/operation/buffer/SubgraphDepthLocater.java |    2 +-
 .../distance/ConnectedElementLocationFilter.java   |    2 +-
 .../distance/ConnectedElementPointFilter.java      |    2 +-
 .../jts/operation/distance/DistanceOp.java         |    2 +-
 .../jts/operation/distance/GeometryLocation.java   |    2 +-
 .../jts/operation/linemerge/EdgeString.java        |    2 +-
 .../operation/linemerge/LineMergeDirectedEdge.java |    2 +-
 .../jts/operation/linemerge/LineMergeEdge.java     |    2 +-
 .../jts/operation/linemerge/LineMergeGraph.java    |    2 +-
 .../jts/operation/linemerge/LineMerger.java        |    2 +-
 .../jts/operation/overlay/EdgeSetNoder.java        |    2 +-
 .../jts/operation/overlay/LineBuilder.java         |   59 +-
 .../jts/operation/overlay/MaximalEdgeRing.java     |    2 +-
 .../jts/operation/overlay/MinimalEdgeRing.java     |    2 +-
 .../jts/operation/overlay/OverlayNodeFactory.java  |    4 +-
 .../jts/operation/overlay/OverlayOp.java           |    2 +-
 .../jts/operation/overlay/PointBuilder.java        |    2 +-
 .../jts/operation/overlay/PolygonBuilder.java      |    6 +-
 .../jts/operation/polygonize/EdgeRing.java         |    2 +-
 .../polygonize/PolygonizeDirectedEdge.java         |    2 +-
 .../jts/operation/polygonize/PolygonizeEdge.java   |    2 +-
 .../jts/operation/polygonize/PolygonizeGraph.java  |    2 +-
 .../jts/operation/polygonize/Polygonizer.java      |    2 +-
 .../jts/operation/predicate/RectangleContains.java |  122 +
 .../operation/predicate/RectangleIntersects.java   |  211 ++
 .../predicate/SegmentIntersectionTester.java       |   54 +
 .../jts/operation/relate/EdgeEndBuilder.java       |    4 +-
 .../jts/operation/relate/EdgeEndBundle.java        |    4 +-
 .../jts/operation/relate/EdgeEndBundleStar.java    |    2 +-
 .../jts/operation/relate/RelateComputer.java       |    4 +-
 .../jts/operation/relate/RelateNode.java           |    4 +-
 .../jts/operation/relate/RelateNodeFactory.java    |    2 +-
 .../jts/operation/relate/RelateNodeGraph.java      |    4 +-
 .../jts/operation/relate/RelateOp.java             |    4 +-
 .../operation/valid/ConnectedInteriorTester.java   |    2 +-
 .../jts/operation/valid/ConsistentAreaTester.java  |    2 +-
 .../jts/operation/valid/IsValidOp.java             |    2 +-
 .../operation/valid/QuadtreeNestedRingTester.java  |    2 +-
 .../jts/operation/valid/RepeatedPointTester.java   |    2 +-
 .../operation/valid/SimpleNestedRingTester.java    |    2 +-
 .../operation/valid/SweeplineNestedRingTester.java |    2 +-
 .../operation/valid/TopologyValidationError.java   |    2 +-
 .../jts/planargraph/DirectedEdge.java              |    2 +-
 .../jts/planargraph/DirectedEdgeStar.java          |    2 +-
 src/com/vividsolutions/jts/planargraph/Edge.java   |    2 +-
 .../jts/planargraph/GraphComponent.java            |    2 +-
 src/com/vividsolutions/jts/planargraph/Node.java   |    2 +-
 .../vividsolutions/jts/planargraph/NodeMap.java    |    2 +-
 .../jts/planargraph/PlanarGraph.java               |    2 +-
 .../vividsolutions/jts/precision/CommonBits.java   |    2 +-
 .../vividsolutions/jts/precision/CommonBitsOp.java |    2 +-
 .../jts/precision/CommonBitsRemover.java           |    2 +-
 .../jts/precision/EnhancedPrecisionOp.java         |    2 +-
 .../precision/SimpleGeometryPrecisionReducer.java  |    4 +-
 .../jts/simplify/DouglasPeuckerLineSimplifier.java |   11 +-
 .../jts/simplify/DouglasPeuckerSimplifier.java     |   12 +-
 .../jts/simplify/TaggedLineString.java             |    2 +-
 .../jts/simplify/TaggedLineStringSimplifier.java   |   35 +-
 .../jts/simplify/TaggedLinesSimplifier.java        |    6 +-
 .../jts/simplify/TopologyPreservingSimplifier.java |    7 +
 src/com/vividsolutions/jts/util/Assert.java        |    2 +-
 .../jts/util/AssertionFailedException.java         |    2 +-
 .../jts/util/CoordinateArrayFilter.java            |    2 +-
 .../jts/util/CoordinateCountFilter.java            |    2 +-
 src/com/vividsolutions/jts/util/Debug.java         |   28 +-
 .../jts/util/GeometricShapeFactory.java            |    2 +-
 src/com/vividsolutions/jts/util/Stopwatch.java     |    2 +-
 .../jts/util/UniqueCoordinateArrayFilter.java      |    2 +-
 .../jtsexample/geom/BasicExample.java              |    2 +-
 .../jtsexample/geom/ConstructionExample.java       |    2 +-
 .../jtsexample/geom/ExtendedCoordinate.java        |    7 +-
 .../jtsexample/geom/ExtendedCoordinateExample.java |    2 +-
 .../geom/ExtendedCoordinateSequence.java           |  108 +-
 .../geom/ExtendedCoordinateSequenceFactory.java    |   19 +-
 .../jtsexample/geom/PrecisionModelExample.java     |    2 +-
 .../jtsexample/geom/SimpleMethodsExample.java      |    2 +-
 .../geom/TwoArrayCoordinateSequenceExample.java    |   89 -
 .../geom/TwoArrayCoordinateSequenceFactory.java    |  118 -
 .../operation/distance/ClosestPointExample.java    |    2 +-
 .../operation/linemerge/LineMergeExample.java      |    2 +-
 .../operation/polygonize/PolygonizeExample.java    |    2 +-
 .../precision/EnhancedPrecisionOpExample.java      |    2 +-
 .../technique/LineStringSelfIntersections.java     |    2 +-
 .../jtsexample/technique/UnionUsingBuffer.java     |    2 +-
 test/robust/TestRobustOverlayFixed.xml             |   18 +
 test/robust/TestRobustOverlayFloat.xml             |   94 +
 test/robust/TestRobustRelate.xml                   |   19 +
 test/validate/TestRelateLL.xml                     | 3890 ++++++++++----------
 test/validate/TestRelatePA.xml                     | 1238 +++----
 test/validate/TestRelatePL.xml                     | 2560 ++++++-------
 test/validate/TestRelatePP.xml                     |  340 +-
 test/vivid/TestBoundary.xml                        |    3 +-
 test/vivid/TestCentroid.xml                        |    4 +-
 test/vivid/TestFunctionAA.xml                      |   38 +-
 test/vivid/TestFunctionAAPrec.xml                  |    3 +-
 test/vivid/TestFunctionLAPrec.xml                  |    3 +-
 test/vivid/TestFunctionLLPrec.xml                  |   12 +-
 test/vivid/TestRectanglePredicate.xml              |  101 +
 test/vivid/TestValid.xml                           |   11 +-
 255 files changed, 7122 insertions(+), 5482 deletions(-)

diff --git a/bin/test_robust.bat b/bin/test_robust.bat
new file mode 100644
index 0000000..daa95a0
--- /dev/null
+++ b/bin/test_robust.bat
@@ -0,0 +1,25 @@
+ at echo off
+rem A batch file to run the XML test files written by Geographic Data BC.
+
+set CLASSPATH=
+for %%i in (..\lib\*.*) do (
+ set jarfile=%%i
+
+ rem If we append to a variable inside the for, only the last entry will
+ rem be kept. So append to the variable outside the for.
+ rem See http://www.experts-exchange.com/Operating_Systems/MSDOS/Q_20561701.html.
+ rem [Jon Aquino]
+
+ call :setclass
+)  
+
+java com.vividsolutions.jtstest.testrunner.TopologyTestApp -Files ..\test\robust
+pause
+
+goto :eof
+
+:setclass
+set CLASSPATH=%jarfile%;%CLASSPATH%
+set jarfile=
+
+:eof
\ No newline at end of file
diff --git a/doc/JTS Developer Guide.pdf b/doc/JTS Developer Guide.pdf
index 362d333..314ea4f 100644
Binary files a/doc/JTS Developer Guide.pdf and b/doc/JTS Developer Guide.pdf differ
diff --git a/doc/JTS Technical Specs.pdf b/doc/JTS Technical Specs.pdf
index 8b71d0c..57d17c2 100644
Binary files a/doc/JTS Technical Specs.pdf and b/doc/JTS Technical Specs.pdf differ
diff --git a/doc/JTS TestBuilder & TestRunner User Guide.pdf b/doc/JTS TestBuilder & TestRunner User Guide.pdf
index d2e863d..719bbf6 100644
Binary files a/doc/JTS TestBuilder & TestRunner User Guide.pdf and b/doc/JTS TestBuilder & TestRunner User Guide.pdf differ
diff --git a/doc/JTS Version History.html b/doc/JTS Version History.html
new file mode 100644
index 0000000..92eb99e
--- /dev/null
+++ b/doc/JTS Version History.html	
@@ -0,0 +1,301 @@
+<html>
+
+<head>
+<title>JTS Version History</title>
+</head>
+
+<body bgcolor='lightblue'>
+<h1 style='text-align:center;'>
+JTS TOPOLOGY SUITE
+<br>
+Version History
+</h1>
+
+
+This document lists the change history of release versions of the JTS Topology Suite
+
+<hr>
+<h2>Version 1.6</h2>
+
+Release Date: February 3, 2005
+
+<h3>API Changes</h3>
+<ul>
+<li>Changed to using <code>CoordinateArraySequence</code> instead of <code>DefaultCoordinateSequence</code>
+(to provide a more descriptive name).
+</ul>
+
+<h3>Semantics Changes</h3>
+<ul>
+<li>PrecisionModel#makePrecise changed to use Symmetric Arithmetic Rounding rather than Banker's Rounding
+</ul>
+
+<h3>Functionality Improvements</h3>
+<ul>
+<li>Added ability to enable <code>Debug</code> methods by setting a system property
+<li>Added <code>getNumGeometries</code> and <code>getGeometryN</code> methods to Geometry class, to make API more uniform
+<li>Improved API for <code>CoordinateSequence</code> allows more options for improving memory usage and handling custom coordinate storage methods
+<li>Added <code>PackedCoordinateSequence</code> to provide reduced memory footprint for geometry objects if desired
+<li>Added optimized spatial predicates for rectangles
+<li>Added Debug#isDebugging method
+</ul>
+
+<h3>Bug Fixes</h3>
+<ul>
+<li>Fixed bug in <code>Geometry#within()</code> short circuiting
+<li>Fixed bug causing <code>Geometry#isValid</code> to throw IllegalArgumentException for certain kinds of holes with invalid rings
+<li>Fixed bug causing redundant linestrings to be returned in the result of overlaying polygons containing holes touching their shell.
+<li><code>Polygon#getBoundary</code> now returns a <code>LinearRing</code> if the polygon does not have holes
+</ul>
+
+<h3>Architecture Changes</h3>
+<ul>
+<li>Removed a proliferation of references to the default <code>CoordinateSequenceFactory</code>
+</ul>
+
+<h2>Contributors</h2>
+<ul>
+<li>Andrea Aime
+</ul>
+
+<h2>Version 1.5</h2>
+Release Date: September 22, 2004
+<p>
+This version is upwards compatible with Version 1.4
+
+<h3>API Changes</h3>
+<ul>
+<li>None
+</ul>
+
+<h3>Semantics Changes</h3>
+<ul>
+<li>None
+</ul>
+
+<h3>Functionality Improvements</h3>
+<ul>
+<li>CGAlgorithms#isCCW now handles coordinate lists with repeated points.  Also throws an IllegalArgumentException if the input ring does not have 3 distinct points
+<li>isValid now checks for invalid coordinates (e.g. ones with Nan or infinite numbers)
+<li>added copyDeep() method to CoordinateArrays
+<li>added geometry simplification operations DouglasPeuckerSimplifier and TopologyPreservingSimplifier
+<li>added methods to Quadtree and STRtree to remove items and query using the Visitor pattern
+</ul>
+
+<h3>Performance Improvements</h3>
+<ul>
+<li>Added short-circuit tests in geometry named predicates based on envelope tests
+</ul>
+<h3>Bug Fixes</h3>
+<ul>
+<li>Fixed bugs in Geometry serialization
+<li>Fixed bug in ValidOp which reported some MultiPolygons with shells nested inside a hole as invalid
+<li>Fixed bug in buffer which caused buffers of some polygons with small & large holes to not contain any holes
+<li>Fixed bug in Polygonizer which caused exception if no lines were supplied
+</ul>
+<h3>Architecture Changes</h3>
+<ul>
+<li>Basic CG algorithm methods made static in the in CGAlgorithms class
+<li>Various utility methods made public in CoordinateArrays class
+</ul>
+<h3>Documentation</h3>
+<ul>
+<li>More examples provided in com.vividsolutions.jtsexamples package
+</ul>
+
+<h2>Version 1.4</h2>
+
+Release Date: November 4, 2003
+<h3>Semantics Changes</h3>
+<ul>
+<li>none
+</ul>
+<h3>Functionality Improvements</h3>
+<ul>
+<li>Added "LINEARRING" tag to WKT syntax
+<li>Added GeometryEditor class to allow easy copy/modify of Geometrys
+<li>Added GeometricShapeFactory class to easily create standard geometric shapes
+<li>Geometries can now carry arbitrary user-defined data objects (via Geometry#get/setUserData(Object) method)
+<li>Added CoordinateSequence and CoordinateSequenceFactory interfaces, and default implementations (BasicCoordinateSequence, BasicCoordinateSequenceFactory)
+<li>Added Geometry#getFactory
+<li>Added new PrecisionModel type of FLOATING_SINGLE, for rounding to single precision floating point
+<li>Added DistanceOp#getClosestPoints method, which returns the closest points between two Geometries
+<li>Added com.vividsolutions.jts.noding package containing classes to perform fast indexed noding of linestrings
+<li>Added com.vividsolutions.jts.operation.polygonize package containing classes to perform polygonization
+<li>Added com.vividsolutions.jts.operation.linemerge package containing classes to perform line merging
+<li>Added SimpleGeometryPrecisionReducer to allow reducing precision of coordinates of a Geometry
+<li>Added LineSegment#closestPoints method to compute the closest points between two line segments
+<li>Added MinimumDiameter class to compute minimum diameters of Geometries
+<li>Added geom.Triangle class to contain algorithms for Triangles
+<li>BufferOp now allows end cap styles to be specified.  Three types are supported: round, butt and square.
+</ul>
+<h3>Performance Improvements</h3>
+<ul>
+<li>EdgeList now provides a findEqualEdge method which is substantially faster than findEdgeIndex, for large lists
+<li>Buffering is now faster and much more robust
+<li>Overlap operations are now more robust
+</ul>
+<h3>Bug Fixes</h3>
+<ul>
+<li>Envelope#init(Envelope) now handles null Envelopes correctly
+<li>CoordinateList#add() now correctly ignores the z-value of Coordinates in determining equality
+<li>Geometry#isValid now correctly handles checking validity of LinearRings
+<li>Fixed infinite loop bug causing Out Of Memory errors during polygon intersection
+<li>Geometry#clone now correctly clones the Geometry's Envelope
+<li>LineIntersector#computeEdgeDistance now correctly computes a non-zero edge distance in certain situations when a fixed precision model was being used and the line segment was a single unit in length
+<li>Fixed incorrect calculation of depths in DirectedEdgeStar#computeDepths
+<li>Fixed BufferSubgraph#addReachable to use explicit stack to avoid stack overflow problems
+<li>Fixed various bugs causing some kinds of buffers to be computed incorrectly
+</ul>
+<h3>API Changes</h3>
+<ul>
+<li>WKTReader/Writer: changed protected members to private
+<li>PrecisionModel type is now an object rather than an int
+<li>ConvexHull API changed to remove requirement to pass in CGAlgorithms object
+</ul>
+<h3>Code Architecture Changes</h3>
+<ul>
+<li>geom.util package added for utility classes which parse and modify geometries
+</ul>
+<h3>Documentation</h3>
+<ul>
+<li>More examples provided in com.vividsolutions.jtsexamples package
+<li>Added JTS Developers Guide
+</ul>
+
+<h2>Version 1.3</h2>
+Release Date: April 4, 2003
+<h3>Semantics Changes</h3>
+<ul>
+<li>all Geometry methods are now reentrant (thread-safe)
+<li>Fixed-precision coordinates are now stored in a rounded but non-scaled form.  This makes them compatible with non-precise (Floating) coordinates, and simplifies working with precise coordinates directly.  Mixed precision models are now supported in Geometry methods; method results are in the more precise of the input precision models.
+<li>Offsets are no longer supported in the Fixed precision model.  This is necessary to allow storing fixed precision coordinates in a non-scaled form.  This does not reduce the total precision available, since coordinates are stored in a floating-point format.
+<li>SRID and Precision Model are no longer checked for equality during Geometry operations.  This removes a limitation which provided little semantic benefit.
+</ul>
+
+<h3>Functionality Improvements</h3>
+<ul>
+<li>added Geometry.isWithinDistance(Geometry g, double distance) method, to provide optimized proximity queries
+<li>added Geometry.buffer(double distance, int quadrantSegments) method, allowing control over accuracy of buffer approximation
+<li>added Geometry.getCentroid() method
+<li>added Geometry.getInteriorPoint() method, which uses heuristic methods to return a point in the interior of a Geometry
+<li>GeometryFactory.toGeometryArray now returns null if the argument is null
+</ul>
+<h3>Performance Improvements</h3>
+<ul>
+<li>Removed unnecessary string construction in EdgeEndStar.propagateSideLabels()
+<li>Eliminated unnecessary computation of self-intersections in rings during relate and spatial functions.  This provides a large increase in speed when working with large rings and polygons.  (Note that IsValid still checks for these self-intersections, which are illegal in LinearRings)
+<li>Add short-circuit code to RobustLineIntersector to detect non-intersections more efficiently
+</ul>
+<h3>Bug Fixes</h3>
+<ul>
+<li>Fixed ClassCastException occurring in GeometryCollection.getLength()
+<li>Fixed bug in Edge Intersection insertion (replaced Coordinate#equals with equals2D to ensure that intersection creation is not sensitive to Z-value).
+<li>Fixed handling LineStrings with too few points in GeometryGraph.addLineString
+<li>Fixed: was not checking that MultiPolygons don't contain components with too few points.
+<li>Fixed Envelope.distance() to return correct distance for all envelopes.
+<li>Fixed a few Geometry methods to make them re-entrant.
+<li>Fixed CoordinateList.closeRing() to ensure endpoints are not duplicated
+<li>Fixed CGAlgorithms.signedArea() to use a simpler algorithm which is more robust and faster.
+<li>Fixed bug preventing validating Rings containing an initial repeated point.
+</ul>
+<h3>API Changes</h3>
+<ul>
+<li>Added default constructor to WKTReader.  It uses the default GeometryFactory
+<li>Add two static intersects() methods to Envelope, to allow computing intersections with envelopes defined by points only.
+<li>Dropped BinaryPower; its functionality is provided by DoubleBits in a more robust fashion.
+<li>Removed a couple of redundant private static methods from Geometry; they have been replaced by methods in CoordinateArrays
+<li>The Geometry class is now marked as Serializable
+</ul>
+
+<h2>Version 1.2</h2>
+Release Date: 7 October 2002
+<h3>Semantics Changes</h3>
+<ul>
+<li>JTS now allows Geometrys to have repeated points.  All operations will continue to perform as before.  This removes a significant incompatibility with the OGC spatial data model.
+<li>TopologyExceptions may now be thrown by spatial overlay methods.  This helps to distinguish between code bugs and known robustness problems.  It also provides a machine-readable coordinate for the error location.
+</ul>
+<h3>Functionality Improvements</h3>
+<ul>
+<li>RobustLineIntersector now uses "normalized" coordinates to maximize the accuracy of intersection computation.
+<li>Upgraded Quadtree with more robust implementation
+<li>Replaced IntervalTree with a more robust implementation of BinTree
+<li>Added STRTree 2-D spatial index, which exhibits better performance than QuadTrees in many situations.
+<li>Added EnhancePrecisionOp, which uses precisioning enhancing techniques to reduce the number of failure cases due to robustness problems.
+</ul>
+<h3>Bug Fixes</h3>
+<ul>
+<li>fixed ConvexHull to use TreeSet instead of HashSet for coordinates
+<li>Fixed isValid for GeometryCollections containing Polygons, which were sometimes erroneously returning a validity failure for correct Geometrys.
+<li>Fixed bug in LineSegment.distancePointLine() which would return the incorrect distance for a LineSegment with two identical points
+<li>Improved error handling in CGAlgorithms.isCCW()
+<li>IsValid now checks for too few points in a geometry component (e.g. due to repeated points in a ring)
+</ul>
+<h3>API Changes</h3>
+<ul>
+<li>added Stopwatch class
+<li>added Geometry.getArea() and Geometry.getLength() methods
+<li>added CGAlgorithms.signedArea() method
+<li>added methods to LineSegment - closestPoint(), getLength()
+<li>added CoordinateArrrays and CoordinateLists utility classes
+<li>Added TopologyValidationError.getErrorType() method
+<li>Added Envelope#intersects; deprecated Envelope#overlaps.
+<li>Added Geometry#geometryChanged() method to allow signaling when Geometry coordinates have been mutated by a client class
+<li>Added STRTree class implementing a Sort-Tile-Recursive spatial index (a variant of a packed R-tree)
+<li>Deleted IntervalTree 1-D spatial index (replaced by BinTree)
+<li>Add BinTree 1-D spatial index
+</ul>
+
+<h2>Version 1.1.1</h2>
+Release Date: 9 April 2002
+<h3>Bug Fixes</h3>
+<ul>
+<li>fixed decimal-point symbol localization bug in WKTWriter
+<li>fixed bug in Envelope.int(Envelope env)
+<li>fixed filename case of SFSMultiLineString.java and IntervalTree.java
+</ul>
+<h3>API Changes</h3>
+<ul>
+<li>deleted TopologyException class
+<li>renamed CGAlgorithms.isPointInPolygon to isPointInRing (a more accurate description of what the method computes)
+</ul>
+<h3>API Additions</h3>
+<ul>
+<li>added Geometry.getCoordinate() method
+<li>added Geometry.distance() method
+<li>added GeometryComponentFilter interface and Geometry.apply(GeometryComponentFilter) method
+</ul>
+
+<h2>Version 1.1</h2>
+Release Date: 28 March 2002
+<h3>New Features</h3>
+<ul>
+<li>added Geometry.isSimple() and Geometry.isValid() methods
+<li>improved design of topological data structures
+<li>added Geometry.setSRID() method
+<li>improved functionality of the Envelope class
+<li>added ability to write to an arbitrary java.io.Writer object to WKTWriter
+<li>added Validate and Mark Location functionality to TestBuilder
+</ul>
+
+<h2>Version 1.0</h2>
+Release Date: 1 February 2002
+<ul>
+<li>Removed some non-compatibilities with Java 1.1
+<li>Fixed bug in constructing buffer outline around inside of angles
+<li>In TestBuilder vertices are now displayed with fixed size in view units
+<li>Improved code for WKTWriter.writeFormatted()
+<li>Fixed bug in constructor for LinearRing
+<li>Improved implementation of sweepline intersection algorithm to avoid use of dynamic set.
+<li>Fixed bug in ConvexHull.cleanRing()
+<li>Refactored RobustLineIntersector and NonRobustLineIntersector
+</ul>
+
+<h2>Version 0.0</h2>
+Release Date: 30 May 2001
+
+<p>
+<i>Baseline version</i>
+
+</body>
+</html>
diff --git a/doc/JTS Version History.pdf b/doc/JTS Version History.pdf
deleted file mode 100644
index 2a456b7..0000000
Binary files a/doc/JTS Version History.pdf and /dev/null differ
diff --git a/doc/LICENSE.txt b/doc/LICENSE.txt
deleted file mode 100644
index b1e3f5a..0000000
--- a/doc/LICENSE.txt
+++ /dev/null
@@ -1,504 +0,0 @@
-		  GNU LESSER GENERAL PUBLIC LICENSE
-		       Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
-     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL.  It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
-  This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it.  You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
-  When we speak of free software, we are referring to freedom of use,
-not price.  Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
-  To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights.  These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
-  For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you.  You must make sure that they, too, receive or can get the source
-code.  If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it.  And you must show them these terms so they know their rights.
-
-  We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
-  To protect each distributor, we want to make it very clear that
-there is no warranty for the free library.  Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-

-  Finally, software patents pose a constant threat to the existence of
-any free program.  We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder.  Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
-  Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License.  This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License.  We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
-  When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library.  The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom.  The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
-  We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License.  It also provides other free software developers Less
-of an advantage over competing non-free programs.  These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries.  However, the Lesser license provides advantages in certain
-special circumstances.
-
-  For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard.  To achieve this, non-free programs must be
-allowed to use the library.  A more frequent case is that a free
-library does the same job as widely used non-free libraries.  In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
-  In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software.  For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
-  Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.  Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library".  The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-

-		  GNU LESSER GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
-  A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
-  The "Library", below, refers to any such software library or work
-which has been distributed under these terms.  A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language.  (Hereinafter, translation is
-included without limitation in the term "modification".)
-
-  "Source code" for a work means the preferred form of the work for
-making modifications to it.  For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
-  Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it).  Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-  
-  1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
-  You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-

-  2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) The modified work must itself be a software library.
-
-    b) You must cause the files modified to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    c) You must cause the whole of the work to be licensed at no
-    charge to all third parties under the terms of this License.
-
-    d) If a facility in the modified Library refers to a function or a
-    table of data to be supplied by an application program that uses
-    the facility, other than as an argument passed when the facility
-    is invoked, then you must make a good faith effort to ensure that,
-    in the event an application does not supply such function or
-    table, the facility still operates, and performs whatever part of
-    its purpose remains meaningful.
-
-    (For example, a function in a library to compute square roots has
-    a purpose that is entirely well-defined independent of the
-    application.  Therefore, Subsection 2d requires that any
-    application-supplied function or table used by this function must
-    be optional: if the application does not supply it, the square
-    root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library.  To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License.  (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.)  Do not make any other change in
-these notices.
-

-  Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
-  This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
-  4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
-  If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library".  Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
-  However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library".  The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
-  When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library.  The
-threshold for this to be true is not precisely defined by law.
-
-  If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work.  (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
-  Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-

-  6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
-  You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License.  You must supply a copy of this License.  If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License.  Also, you must do one
-of these things:
-
-    a) Accompany the work with the complete corresponding
-    machine-readable source code for the Library including whatever
-    changes were used in the work (which must be distributed under
-    Sections 1 and 2 above); and, if the work is an executable linked
-    with the Library, with the complete machine-readable "work that
-    uses the Library", as object code and/or source code, so that the
-    user can modify the Library and then relink to produce a modified
-    executable containing the modified Library.  (It is understood
-    that the user who changes the contents of definitions files in the
-    Library will not necessarily be able to recompile the application
-    to use the modified definitions.)
-
-    b) Use a suitable shared library mechanism for linking with the
-    Library.  A suitable mechanism is one that (1) uses at run time a
-    copy of the library already present on the user's computer system,
-    rather than copying library functions into the executable, and (2)
-    will operate properly with a modified version of the library, if
-    the user installs one, as long as the modified version is
-    interface-compatible with the version that the work was made with.
-
-    c) Accompany the work with a written offer, valid for at
-    least three years, to give the same user the materials
-    specified in Subsection 6a, above, for a charge no more
-    than the cost of performing this distribution.
-
-    d) If distribution of the work is made by offering access to copy
-    from a designated place, offer equivalent access to copy the above
-    specified materials from the same place.
-
-    e) Verify that the user has already received a copy of these
-    materials or that you have already sent this user a copy.
-
-  For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it.  However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
-  It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system.  Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-

-  7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
-    a) Accompany the combined library with a copy of the same work
-    based on the Library, uncombined with any other library
-    facilities.  This must be distributed under the terms of the
-    Sections above.
-
-    b) Give prominent notice with the combined library of the fact
-    that part of it is a work based on the Library, and explaining
-    where to find the accompanying uncombined form of the same work.
-
-  8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License.  Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License.  However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-  9. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Library or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
-  10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-

-  11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded.  In such case, this License incorporates the limitation as if
-written in the body of this License.
-
-  13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation.  If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-

-  14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission.  For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this.  Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
-			    NO WARRANTY
-
-  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-

-           How to Apply These Terms to Your New Libraries
-
-  If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change.  You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
-  To apply these terms, attach the following notices to the library.  It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the library's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Lesser General Public
-    License as published by the Free Software Foundation; either
-    version 2.1 of the License, or (at your option) any later version.
-
-    This library is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-    Lesser General Public License for more details.
-
-    You should have received a copy of the GNU Lesser General Public
-    License along with this library; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the
-  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
-  <signature of Ty Coon>, 1 April 1990
-  Ty Coon, President of Vice
-
-That's all there is to it!
-
-
diff --git a/src/MANIFEST.MF b/src/MANIFEST.MF
index 29aef23..78e8373 100644
--- a/src/MANIFEST.MF
+++ b/src/MANIFEST.MF
@@ -1,4 +1,4 @@
 Manifest-version: 1.0
 Implementation-Title: Java Topology Suite
-Implementation-Version: 1.5
+Implementation-Version: 1.6
 Implementation-Vendor: Vivid Solutions
diff --git a/src/com/vividsolutions/jts/algorithm/CGAlgorithms.java b/src/com/vividsolutions/jts/algorithm/CGAlgorithms.java
index f5143b9..ebb6479 100644
--- a/src/com/vividsolutions/jts/algorithm/CGAlgorithms.java
+++ b/src/com/vividsolutions/jts/algorithm/CGAlgorithms.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.geom.CoordinateSequence;
  * Specifies and implements various fundamental Computational Geometric algorithms.
  * The algorithms supplied in this class are robust for double-precision floating point.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class CGAlgorithms
 {
@@ -100,39 +100,30 @@ public class CGAlgorithms
    * @return <code>true</code> if p is inside ring
    */
   public static boolean isPointInRing(Coordinate p, Coordinate[] ring) {
-    int i;
-    int i1;       // point index; i1 = i-1
-    double xInt;  // x intersection of segment with ray
-    int crossings = 0;  // number of segment/ray crossings
-    double x1;    // translated coordinates
-    double y1;
-    double x2;
-    double y2;
-    int nPts = ring.length;
-
     /*
      *  For each segment l = (i-1, i), see if it crosses ray from test point in positive x direction.
      */
-    for (i = 1; i < nPts; i++) {
-      i1 = i - 1;
+    int crossings = 0;  // number of segment/ray crossings
+    for (int i = 1; i < ring.length; i++) {
+      int i1 = i - 1;
       Coordinate p1 = ring[i];
       Coordinate p2 = ring[i1];
-      x1 = p1.x - p.x;
-      y1 = p1.y - p.y;
-      x2 = p2.x - p.x;
-      y2 = p2.y - p.y;
 
-      if (((y1 > 0) && (y2 <= 0)) ||
-          ((y2 > 0) && (y1 <= 0))) {
+      if (((p1.y > p.y) && (p2.y <= p.y)) ||
+          ((p2.y > p.y) && (p1.y <= p.y))) {
+        double x1 = p1.x - p.x;
+        double y1 = p1.y - p.y;
+        double x2 = p2.x - p.x;
+        double y2 = p2.y - p.y;
         /*
-         *  segment straddles x axis, so compute intersection.
+        *  segment straddles x axis, so compute intersection with x-axis.
          */
-        xInt = RobustDeterminant.signOfDet2x2(x1, y1, x2, y2) / (y2 - y1);
+        double xInt = RobustDeterminant.signOfDet2x2(x1, y1, x2, y2) / (y2 - y1);
         //xsave = xInt;
         /*
-         *  crosses ray if strictly positive intersection.
+        *  crosses ray if strictly positive intersection.
          */
-        if (0.0 < xInt) {
+        if (xInt > 0.0) {
           crossings++;
         }
       }
@@ -170,23 +161,16 @@ public class CGAlgorithms
   }
 
   /**
-   * Tests whether a ring (simple polygon) is oriented counter-clockwise.
-   * The list of points is assumed to have the first and last points equal.
-   * If the point list does not form a valid ring the result is undefined.
-   * This method is not guaranteed to work on coordinate lists which contain repeated points.
-   *
-   * @param ring an array of coordinates forming a ring
-   * @return <code>true</code> if the ring is oriented counter-clockwise
-   */
-  /**
    * Computes whether a ring defined by an array of {@link Coordinate} is
    * oriented counter-clockwise.
-   * <p>
-   * This will handle coordinate lists which contain repeated points.
+   * <ul>
+   * <li>The list of points is assumed to have the first and last points equal.
+   * <li>This will handle coordinate lists which contain repeated points.
+   * <li>If the ring is invalid, the answer returned may not be correct.
+   * </ul>
    *
    * @param ring an array of coordinates forming a ring
    * @return <code>true</code> if the ring is oriented counter-clockwise.
-   * @throws IllegalArgumentException if the ring is degenerate (does not contain 3 distinct points)
    */
   public static boolean isCCW(Coordinate[] ring) {
     // # of points without closing endpoint
@@ -219,10 +203,16 @@ public class CGAlgorithms
     Coordinate prev = ring[iPrev];
     Coordinate next = ring[iNext];
 
-    // this will catch all cases where there are not 3 distinct points,
-    // including the case where the input array has fewer than 4 elements
+    /**
+     * This check catches cases where the ring contains an A-B-A configuration of points.
+     * This can happen if the ring does not contain 3 distinct points
+     * (including the case where the input array has fewer than 4 elements),
+     * or it contains coincident line segments.
+     */
     if (prev.equals(hip) || next.equals(hip) || prev.equals(next))
-        throw new IllegalArgumentException("degenerate ring (does not contain 3 distinct points)");
+      return false;
+    // MD - don't bother throwing exception, since this isn't a complete check for ring validity
+//  throw new IllegalArgumentException("Invalid ring (contains repeated line segments)");
 
     int disc = computeOrientation(prev, hip, next);
 
@@ -232,7 +222,7 @@ public class CGAlgorithms
      *  (2) the lines lie on top of one another
      *
      *  (1) is handled by checking if next is left of prev ==> CCW
-     *  (2) should never happen, so we're going to ignore it!
+     *  (2) will never happen if the ring is valid, so don't check for it
      *  (Might want to assert this)
      */
     boolean isCCW = false;
diff --git a/src/com/vividsolutions/jts/algorithm/CentroidArea.java b/src/com/vividsolutions/jts/algorithm/CentroidArea.java
index 1c32752..061e87c 100644
--- a/src/com/vividsolutions/jts/algorithm/CentroidArea.java
+++ b/src/com/vividsolutions/jts/algorithm/CentroidArea.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.geom.*;
  * See <code>http://www.faqs.org/faqs/graphics/algorithms-faq/</code>
  * for further details of the basic approach.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class CentroidArea
 {
diff --git a/src/com/vividsolutions/jts/algorithm/CentroidLine.java b/src/com/vividsolutions/jts/algorithm/CentroidLine.java
index a1caf88..0cc2c56 100644
--- a/src/com/vividsolutions/jts/algorithm/CentroidLine.java
+++ b/src/com/vividsolutions/jts/algorithm/CentroidLine.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.geom.*;
  * Compute the average of the midpoints
  * of all line segments weighted by the segment length.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class CentroidLine
 {
diff --git a/src/com/vividsolutions/jts/algorithm/CentroidPoint.java b/src/com/vividsolutions/jts/algorithm/CentroidPoint.java
index 5359ebd..1b9a172 100644
--- a/src/com/vividsolutions/jts/algorithm/CentroidPoint.java
+++ b/src/com/vividsolutions/jts/algorithm/CentroidPoint.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.geom.*;
  * <h2>Algorithm</h2>
  * Compute the average of all points.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class CentroidPoint
 {
diff --git a/src/com/vividsolutions/jts/algorithm/ConvexHull.java b/src/com/vividsolutions/jts/algorithm/ConvexHull.java
index d769f73..00cf3de 100644
--- a/src/com/vividsolutions/jts/algorithm/ConvexHull.java
+++ b/src/com/vividsolutions/jts/algorithm/ConvexHull.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.util.UniqueCoordinateArrayFilter;
  * points in the input Geometry.
  * Uses the Graham Scan algorithm.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class ConvexHull
 {
diff --git a/src/com/vividsolutions/jts/algorithm/HCoordinate.java b/src/com/vividsolutions/jts/algorithm/HCoordinate.java
index e1f44a0..5a515b4 100644
--- a/src/com/vividsolutions/jts/algorithm/HCoordinate.java
+++ b/src/com/vividsolutions/jts/algorithm/HCoordinate.java
@@ -36,14 +36,14 @@
 package com.vividsolutions.jts.algorithm;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import com.vividsolutions.jts.geom.*;
 
 /**
  * Represents a homogeneous coordinate for 2-D coordinates.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class HCoordinate
 {
diff --git a/src/com/vividsolutions/jts/algorithm/InteriorPointArea.java b/src/com/vividsolutions/jts/algorithm/InteriorPointArea.java
index d8d2c91..5021d93 100644
--- a/src/com/vividsolutions/jts/algorithm/InteriorPointArea.java
+++ b/src/com/vividsolutions/jts/algorithm/InteriorPointArea.java
@@ -52,7 +52,7 @@ import com.vividsolutions.jts.geom.*;
  * which does not lie in the interior.
  * </b>
  *
- * @version 1.5
+ * @version 1.6
  */
 public class InteriorPointArea {
 
diff --git a/src/com/vividsolutions/jts/algorithm/InteriorPointLine.java b/src/com/vividsolutions/jts/algorithm/InteriorPointLine.java
index 23a6900..c6aec93 100644
--- a/src/com/vividsolutions/jts/algorithm/InteriorPointLine.java
+++ b/src/com/vividsolutions/jts/algorithm/InteriorPointLine.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.geom.*;
  * closest to the centroid.
  * </ul>
  *
- * @version 1.5
+ * @version 1.6
  */
 public class InteriorPointLine {
 
diff --git a/src/com/vividsolutions/jts/algorithm/InteriorPointPoint.java b/src/com/vividsolutions/jts/algorithm/InteriorPointPoint.java
index 9ec4cc4..49abc6a 100644
--- a/src/com/vividsolutions/jts/algorithm/InteriorPointPoint.java
+++ b/src/com/vividsolutions/jts/algorithm/InteriorPointPoint.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.geom.*;
  * <h2>Algorithm</h2>
  * Find a point which is closest to the centroid of the geometry.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class InteriorPointPoint {
 
diff --git a/src/com/vividsolutions/jts/algorithm/LineIntersector.java b/src/com/vividsolutions/jts/algorithm/LineIntersector.java
index fad4f3d..15c0394 100644
--- a/src/com/vividsolutions/jts/algorithm/LineIntersector.java
+++ b/src/com/vividsolutions/jts/algorithm/LineIntersector.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.algorithm;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.util.*;
@@ -50,7 +50,7 @@ import com.vividsolutions.jts.util.*;
  * that the input coordinates have been made precise by scaling them to
  * an integer grid.)
  *
- * @version 1.5
+ * @version 1.6
  */
 public abstract class LineIntersector {
 
diff --git a/src/com/vividsolutions/jts/algorithm/MCPointInRing.java b/src/com/vividsolutions/jts/algorithm/MCPointInRing.java
index d2f7604..00fa608 100644
--- a/src/com/vividsolutions/jts/algorithm/MCPointInRing.java
+++ b/src/com/vividsolutions/jts/algorithm/MCPointInRing.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.index.bintree.Interval;
  * using {@link MonotoneChain}s and a {@link BinTree} index to
  * increase performance.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class MCPointInRing   implements PointInRing {
 
diff --git a/src/com/vividsolutions/jts/algorithm/MinimumDiameter.java b/src/com/vividsolutions/jts/algorithm/MinimumDiameter.java
index acf3df6..c3e8a60 100644
--- a/src/com/vividsolutions/jts/algorithm/MinimumDiameter.java
+++ b/src/com/vividsolutions/jts/algorithm/MinimumDiameter.java
@@ -51,7 +51,7 @@ import com.vividsolutions.jts.geom.*;
  *
  * @see ConvexHull
  *
- * @version 1.5
+ * @version 1.6
  */
 public class MinimumDiameter
 {
diff --git a/src/com/vividsolutions/jts/algorithm/NonRobustCGAlgorithms.java b/src/com/vividsolutions/jts/algorithm/NonRobustCGAlgorithms.java
index 5b5c75e..196d1bc 100644
--- a/src/com/vividsolutions/jts/algorithm/NonRobustCGAlgorithms.java
+++ b/src/com/vividsolutions/jts/algorithm/NonRobustCGAlgorithms.java
@@ -32,7 +32,6 @@
  */
 package com.vividsolutions.jts.algorithm;
 
-import com.vividsolutions.jts.geom.DefaultCoordinateSequenceFactory;
 import com.vividsolutions.jts.geom.Coordinate;
 import com.vividsolutions.jts.geom.CoordinateSequence;
 
@@ -41,7 +40,7 @@ import com.vividsolutions.jts.geom.CoordinateSequence;
  * <b>FOR TESTING PURPOSES ONLY!</b>.
  * The non-robustness is due to rounding error in floating point computation.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class NonRobustCGAlgorithms
   extends CGAlgorithms
diff --git a/src/com/vividsolutions/jts/algorithm/NonRobustLineIntersector.java b/src/com/vividsolutions/jts/algorithm/NonRobustLineIntersector.java
index 32ad4af..7b00766 100644
--- a/src/com/vividsolutions/jts/algorithm/NonRobustLineIntersector.java
+++ b/src/com/vividsolutions/jts/algorithm/NonRobustLineIntersector.java
@@ -36,7 +36,7 @@ package com.vividsolutions.jts.algorithm;
 import com.vividsolutions.jts.algorithm.LineIntersector;
 
 /**
- *@version 1.5
+ *@version 1.6
  */
 
 import com.vividsolutions.jts.geom.*;
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.util.Debug;
 /**
  * A non-robust version of {@LineIntersector}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class NonRobustLineIntersector
     extends LineIntersector
diff --git a/src/com/vividsolutions/jts/algorithm/NotRepresentableException.java b/src/com/vividsolutions/jts/algorithm/NotRepresentableException.java
index 3eb7902..af6efa5 100644
--- a/src/com/vividsolutions/jts/algorithm/NotRepresentableException.java
+++ b/src/com/vividsolutions/jts/algorithm/NotRepresentableException.java
@@ -39,7 +39,7 @@ package com.vividsolutions.jts.algorithm;
  * Indicates that a {@link HCoordinate} has been computed which is
  * not representable on the Cartesian plane.
  *
- * @version 1.5
+ * @version 1.6
  * @see HCoordinate
  */
 public class NotRepresentableException extends Exception {
diff --git a/src/com/vividsolutions/jts/algorithm/PointInRing.java b/src/com/vividsolutions/jts/algorithm/PointInRing.java
index e8e5562..b9fdfff 100644
--- a/src/com/vividsolutions/jts/algorithm/PointInRing.java
+++ b/src/com/vividsolutions/jts/algorithm/PointInRing.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.geom.Coordinate;
  * An interface for classes which test whether a {@link Coordinate} lies inside
  * a ring.
  *
- * @version 1.5
+ * @version 1.6
  */
 public interface PointInRing {
 
diff --git a/src/com/vividsolutions/jts/algorithm/PointLocator.java b/src/com/vividsolutions/jts/algorithm/PointLocator.java
index 32c9aac..ca86dff 100644
--- a/src/com/vividsolutions/jts/algorithm/PointLocator.java
+++ b/src/com/vividsolutions/jts/algorithm/PointLocator.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.geomgraph.GeometryGraph;
  * The algorithm obeys the SFS boundaryDetermination rule to correctly determine
  * whether the point lies on the boundary or not.
  * Note that instances of this class are not reentrant.
- * @version 1.5
+ * @version 1.6
  */
 public class PointLocator {
 
diff --git a/src/com/vividsolutions/jts/algorithm/RobustCGAlgorithms.java b/src/com/vividsolutions/jts/algorithm/RobustCGAlgorithms.java
index 337a609..c7aba52 100644
--- a/src/com/vividsolutions/jts/algorithm/RobustCGAlgorithms.java
+++ b/src/com/vividsolutions/jts/algorithm/RobustCGAlgorithms.java
@@ -34,16 +34,13 @@
  */
 package com.vividsolutions.jts.algorithm;
 
-import com.vividsolutions.jts.geom.DefaultCoordinateSequenceFactory;
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.CoordinateSequence;
-import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.*;
 
 /**
  * Stub version of RobustCGAlgorithms for backwards compatibility.
  * Will be deprecated in next release - use CGAlgorithms instead.
  *
- * @version 1.5
+ * @version 1.6
  *
  */
 public class RobustCGAlgorithms extends CGAlgorithms {
diff --git a/src/com/vividsolutions/jts/algorithm/RobustDeterminant.java b/src/com/vividsolutions/jts/algorithm/RobustDeterminant.java
index ec81210..634b216 100644
--- a/src/com/vividsolutions/jts/algorithm/RobustDeterminant.java
+++ b/src/com/vividsolutions/jts/algorithm/RobustDeterminant.java
@@ -35,7 +35,7 @@
 package com.vividsolutions.jts.algorithm;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 
 /**
@@ -59,7 +59,7 @@ package com.vividsolutions.jts.algorithm;
  **************************************************************************
  * </pre>
  *
- * @version 1.5
+ * @version 1.6
  */
 public class RobustDeterminant {
 
diff --git a/src/com/vividsolutions/jts/algorithm/RobustLineIntersector.java b/src/com/vividsolutions/jts/algorithm/RobustLineIntersector.java
index de07869..9bdb4f2 100644
--- a/src/com/vividsolutions/jts/algorithm/RobustLineIntersector.java
+++ b/src/com/vividsolutions/jts/algorithm/RobustLineIntersector.java
@@ -35,7 +35,7 @@
 package com.vividsolutions.jts.algorithm;
 
 /**
- *@version 1.5
+ *@version 1.6
  */
 
 import com.vividsolutions.jts.geom.*;
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.util.Assert;
 /**
  * A robust version of {@LineIntersector}.
  *
- * @version 1.5
+ * @version 1.6
  * @see RobustDeterminant
  */
 public class RobustLineIntersector
diff --git a/src/com/vividsolutions/jts/algorithm/SIRtreePointInRing.java b/src/com/vividsolutions/jts/algorithm/SIRtreePointInRing.java
index 008abbb..9ca4b79 100644
--- a/src/com/vividsolutions/jts/algorithm/SIRtreePointInRing.java
+++ b/src/com/vividsolutions/jts/algorithm/SIRtreePointInRing.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.index.strtree.*;
  * using a {@link SIRtree} index to
  * increase performance.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SIRtreePointInRing implements PointInRing {
 
diff --git a/src/com/vividsolutions/jts/algorithm/SimplePointInAreaLocator.java b/src/com/vividsolutions/jts/algorithm/SimplePointInAreaLocator.java
index 709ccaf..8322de4 100644
--- a/src/com/vividsolutions/jts/algorithm/SimplePointInAreaLocator.java
+++ b/src/com/vividsolutions/jts/algorithm/SimplePointInAreaLocator.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.geom.*;
  * The algorithm used is only guaranteed to return correct results
  * for points which are <b>not</b> on the boundary of the Geometry.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SimplePointInAreaLocator
 {
diff --git a/src/com/vividsolutions/jts/algorithm/SimplePointInRing.java b/src/com/vividsolutions/jts/algorithm/SimplePointInRing.java
index b130fce..b9a8d1c 100644
--- a/src/com/vividsolutions/jts/algorithm/SimplePointInRing.java
+++ b/src/com/vividsolutions/jts/algorithm/SimplePointInRing.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.geom.*;
  * Tests whether a {@link Coordinate} lies inside
  * a ring, using a linear-time algorithm.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SimplePointInRing
   implements PointInRing
diff --git a/src/com/vividsolutions/jts/geom/Coordinate.java b/src/com/vividsolutions/jts/geom/Coordinate.java
index a1685d9..1f56b46 100644
--- a/src/com/vividsolutions/jts/geom/Coordinate.java
+++ b/src/com/vividsolutions/jts/geom/Coordinate.java
@@ -52,7 +52,7 @@ import com.vividsolutions.jts.util.Assert;
  *  z-ordinate of <code>NaN</code>.  The standard comparison functions will ignore
  *  the z-ordinate.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class Coordinate implements Comparable, Cloneable, Serializable {
     private static final long serialVersionUID = 6683108902428366910L;
diff --git a/src/com/vividsolutions/jts/geom/CoordinateArrays.java b/src/com/vividsolutions/jts/geom/CoordinateArrays.java
index 096865a..28fb2ba 100644
--- a/src/com/vividsolutions/jts/geom/CoordinateArrays.java
+++ b/src/com/vividsolutions/jts/geom/CoordinateArrays.java
@@ -39,7 +39,7 @@ import java.util.List;
 /**
  * Useful utility functions for handling Coordinate arrays
  *
- * @version 1.5
+ * @version 1.6
  */
 public class CoordinateArrays {
 
diff --git a/src/com/vividsolutions/jts/geom/CoordinateFilter.java b/src/com/vividsolutions/jts/geom/CoordinateFilter.java
index a530b5f..9a9a8c1 100644
--- a/src/com/vividsolutions/jts/geom/CoordinateFilter.java
+++ b/src/com/vividsolutions/jts/geom/CoordinateFilter.java
@@ -45,7 +45,7 @@ package com.vividsolutions.jts.geom;
  *  used to implement such things as coordinate transformations, centroid and
  *  envelope computation, and many other functions.
  *
- *@version 1.5
+ *@version 1.6
  */
 public interface CoordinateFilter {
 
diff --git a/src/com/vividsolutions/jts/geom/CoordinateList.java b/src/com/vividsolutions/jts/geom/CoordinateList.java
index 0e0c1c0..24c4776 100644
--- a/src/com/vividsolutions/jts/geom/CoordinateList.java
+++ b/src/com/vividsolutions/jts/geom/CoordinateList.java
@@ -43,7 +43,7 @@ import java.util.Iterator;
  * be set to prevent repeated coordinates from occuring in the list.
  *
  *
- * @version 1.5
+ * @version 1.6
  */
 public class CoordinateList
   extends ArrayList
diff --git a/src/com/vividsolutions/jts/geom/CoordinateSequence.java b/src/com/vividsolutions/jts/geom/CoordinateSequence.java
index 4cf9b44..167288c 100644
--- a/src/com/vividsolutions/jts/geom/CoordinateSequence.java
+++ b/src/com/vividsolutions/jts/geom/CoordinateSequence.java
@@ -1,35 +1,34 @@
-
 /*
- * The JTS Topology Suite is a collection of Java classes that
- * implement the fundamental operations required to validate a given
- * geo-spatial data set to a known topological specification.
- *
- * Copyright (C) 2001 Vivid Solutions
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * For more information, contact:
- *
- *     Vivid Solutions
- *     Suite #1A
- *     2328 Government Street
- *     Victoria BC  V8T 5G5
- *     Canada
- *
- *     (250)385-6040
- *     www.vividsolutions.com
+* The JTS Topology Suite is a collection of Java classes that
+* implement the fundamental operations required to validate a given
+* geo-spatial data set to a known topological specification.
+*
+* Copyright (C) 2001 Vivid Solutions
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*
+* For more information, contact:
+*
+*     Vivid Solutions
+*     Suite #1A
+*     2328 Government Street
+*     Victoria BC  V8T 5G5
+*     Canada
+*
+*     (250)385-6040
+*     www.vividsolutions.com
  */
 package com.vividsolutions.jts.geom;
 
@@ -38,8 +37,8 @@ package com.vividsolutions.jts.geom;
  * <p>
  * There are some cases in which you might want Geometries to store their
  * points using something other than the JTS Coordinate class. For example, you
- * may want to experiment with another implementation, such as an array of x�s
- * and an array of y�s. or you might want to use your own coordinate class, one
+ * may want to experiment with another implementation, such as an array of x's
+ * and an array of y's. Or you might want to use your own coordinate class, one
  * that supports extra attributes like M-values.
  * <p>
  * You can do this by implementing the CoordinateSequence and
@@ -50,50 +49,126 @@ package com.vividsolutions.jts.geom;
  * <p>
  * For an example, see the code for
  * {@link com.vividsolutions.jtsexample.geom.TwoArrayCoordinateSequenceExample}.
- * <p>
- * A note on performance. If your CoordinateSequence is not based on an array
- * of Coordinates, it may incur a performance penalty when its #toArray method
- * is called because the array needs to be built from scratch.
- * 
+ *
  * @see DefaultCoordinateSequenceFactory
  * @see TwoArrayCoordinateSequenceFactory
  *
- * @version 1.5
+ * @version 1.6
  */
-public interface CoordinateSequence extends Cloneable {   
+public interface CoordinateSequence
+    extends Cloneable
+{
+  /**
+   * Standard ordinate index values
+   */
+  public static final int X = 0;
+  public static final int Y = 1;
+  public static final int Z = 2;
+  public static final int M = 3;
+
+  /**
+   * Returns (possibly a copy of) the i'th coordinate in this sequence.
+   * Whether or not the Coordinate returned is the actual underlying
+   * Coordinate or merely a copy depends on the implementation.
+   * <p>
+   * Note that in the future the semantics of this method may change
+   * to guarantee that the Coordinate returned is always a copy.
+   * Callers should not to assume that they can modify a CoordinateSequence by
+   * modifying the object returned by this method.
+   *
+   * @param i the index of the coordinate to retrieve
+   * @return the i'th coordinate in the sequence
+   */
+  public Coordinate getCoordinate(int i);
+
+  /**
+   * Returns a copy of the i'th coordinate in this sequence.
+   * This method optimizes the situation where the caller is
+   * going to make a copy anyway - if the implementation
+   * has already created a new Coordinate object, no further copy is needed.
+   *
+   * @param i the index of the coordinate to retrieve
+   * @return a copy of the i'th coordinate in the sequence
+   */
+  public Coordinate getCoordinateCopy(int i);
+
+  /**
+   * Copies the i'th coordinate in the sequence to the supplied
+   * {@link Coordinate}.  Only the first two dimensions are copied.
+   *
+   * @param index the index of the coordinate to copy
+   * @param coord a {@link Coordinate} to receive the value
+   */
+  public void getCoordinate(int index, Coordinate coord);
+
+  /**
+   * Returns ordinate X (0) of the specified coordinate.
+   *
+   * @param index
+   * @return the value of the X ordinate in the index'th coordinate
+   */
+  public double getX(int index);
+
+  /**
+   * Returns ordinate Y (1) of the specified coordinate.
+   *
+   * @param index
+   * @return the value of the Y ordinate in the index'th coordinate
+   */
+  public double getY(int index);
+
+  /**
+   * Returns the ordinate of a coordinate in this sequence.
+   * Ordinate indices 0 and 1 are assumed to be X and Y.
+   * Ordinates indices greater than 1 have user-defined semantics
+   * (for instance, they may contain other dimensions or measure values).
+   *
+   * @param index  the coordinate index in the sequence
+   * @param ordinateIndex the ordinate index in the coordinate (in range [0, dimension-1])
+   */
+  public double getOrdinate(int index, int ordinateIndex);
+
+  /**
+   * Returns the number of coordinates in this sequence.
+   * @return the size of the sequence
+   */
+  public int size();
+
+  /**
+   * Sets the value for a given ordinate of a coordinate in this sequence.
+   *
+   * @param index  the coordinate index in the sequence
+   * @param ordinateIndex the ordinate index in the coordinate (in range [0, dimension-1])
+   * @param value  the new ordinate value
+   */
+  public void setOrdinate(int index, int ordinateIndex, double value);
+
+  /**
+   * Returns (possibly copies of) the Coordinates in this collection.
+   * Whether or not the Coordinates returned are the actual underlying
+   * Coordinates or merely copies depends on the implementation. Note that
+   * if this implementation does not store its data as an array of Coordinates,
+   * this method will incur a performance penalty because the array needs to
+   * be built from scratch.
+   *
+   * @return a array of coordinates containing the point values in this sequence
+   */
+  public Coordinate[] toCoordinateArray();
 
-    /**
-     * Returns (possibly a copy of) the ith Coordinate in this collection.
-     * Whether or not the Coordinate returned is the actual underlying
-     * Coordinate or merely a copy depends on the implementation.
-     * <p>
-     * Note that in the future the semantics of this method may change
-     * to guarantee that the Coordinate returned is always a copy. Callers are
-     * advised not to assume that they can modify a CoordinateSequence by
-     * modifying the Coordinate returned by this method.
-     */
-    public Coordinate getCoordinate(int i);
+  /**
+   * Expands the given {@link Envelope} to include the coordinates in the sequence.
+   * Allows implementing classes to optimize access to coordinate values.
+   *
+   * @param env the envelope to expand
+   * @return a ref to the expanded envelope
+   */
+  public Envelope expandEnvelope(Envelope env);
 
-    /**
-     * Returns the number of Coordinates (actual or
-     * otherwise, as this implementation may not store its data in Coordinate
-     * objects). 
-     */
-    public int size();
-    
-    /**
-     * Returns (possibly copies of) the Coordinates in this collection.
-     * Whether or not the Coordinates returned are the actual underlying
-     * Coordinates or merely copies depends on the implementation. Note that
-     * if this implementation does not store its data as an array of Coordinates,
-     * this method will incur a performance penalty because the array needs to
-     * be built from scratch.
-     */
-    public Coordinate[] toCoordinateArray();
-    
-    /**
-     * Returns a deep copy of this collection. Called by Geometry#clone.
-     */
-    public Object clone();
-        
+  /**
+   * Returns a deep copy of this collection.
+   * Called by Geometry#clone.
+   *
+   * @return a copy of the coordinate sequence containing copies of all points
+   */
+  public Object clone();
 }
diff --git a/src/com/vividsolutions/jts/geom/CoordinateSequenceFactory.java b/src/com/vividsolutions/jts/geom/CoordinateSequenceFactory.java
index ca382dd..3bda335 100644
--- a/src/com/vividsolutions/jts/geom/CoordinateSequenceFactory.java
+++ b/src/com/vividsolutions/jts/geom/CoordinateSequenceFactory.java
@@ -1,52 +1,73 @@
-
 /*
- * The JTS Topology Suite is a collection of Java classes that
- * implement the fundamental operations required to validate a given
- * geo-spatial data set to a known topological specification.
- *
- * Copyright (C) 2001 Vivid Solutions
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * For more information, contact:
- *
- *     Vivid Solutions
- *     Suite #1A
- *     2328 Government Street
- *     Victoria BC  V8T 5G5
- *     Canada
- *
- *     (250)385-6040
- *     www.vividsolutions.com
+* The JTS Topology Suite is a collection of Java classes that
+* implement the fundamental operations required to validate a given
+* geo-spatial data set to a known topological specification.
+*
+* Copyright (C) 2001 Vivid Solutions
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*
+* For more information, contact:
+*
+*     Vivid Solutions
+*     Suite #1A
+*     2328 Government Street
+*     Victoria BC  V8T 5G5
+*     Canada
+*
+*     (250)385-6040
+*     www.vividsolutions.com
  */
 package com.vividsolutions.jts.geom;
 
 /**
- * An object that knows how to build a particular implementation of 
- * CoordinateSequence from an array of Coordinates.
+ * A factory to create concrete instances of {@link CoordinateSequence}s.
  *
- * @version 1.5
+ * @version 1.6
  */
-public interface CoordinateSequenceFactory {
-    
+public interface CoordinateSequenceFactory
+{
+
+  /**
+   * Returns a {@link CoordinateSequence} based on the given array.
+   * Whether the array is copied or simply referenced
+   * is implementation-dependent.
+   * This method must handle null arguments by creating an empty sequence.
+   *
+   * @param coordinates the coordinates
+   */
+  public CoordinateSequence create(Coordinate[] coordinates);
+
   /**
-   * Returns a CoordinateSequence based on the given array; whether or not the
-   * array is copied is implementation-dependent.
-   * @param coordinates
-   *            the coordinates, which may not be null nor contain null
-   *            elements
+   * Creates a {@link CoordinateSequence} which is a copy
+   * of the given {@link CoordinateSequence}.
+   * This method must handle null arguments by creating an empty sequence.
+   *
+   * @param coordSeq the coordinate sequence to copy
    */
-    public CoordinateSequence create(Coordinate[] coordinates);
+  public CoordinateSequence create(CoordinateSequence coordSeq);
+
+  /**
+   * Creates a {@link CoordinateSequence} of the specified size and dimension.
+   * For this to be useful, the {@link CoordinateSequence} implementation must
+   * be mutable.
+   *
+   * @param size the number of coordinates in the sequence
+   * @param dimension the dimension of the coordinates in the sequence (if user-specifiable,
+   * otherwise ignored)
+   */
+  public CoordinateSequence create(int size, int dimension);
+
 }
diff --git a/src/com/vividsolutions/jts/geom/DefaultCoordinateSequence.java b/src/com/vividsolutions/jts/geom/DefaultCoordinateSequence.java
index 038f72c..901cc38 100644
--- a/src/com/vividsolutions/jts/geom/DefaultCoordinateSequence.java
+++ b/src/com/vividsolutions/jts/geom/DefaultCoordinateSequence.java
@@ -1,118 +1,214 @@
 /*
- * The JTS Topology Suite is a collection of Java classes that
- * implement the fundamental operations required to validate a given
- * geo-spatial data set to a known topological specification.
- *
- * Copyright (C) 2001 Vivid Solutions
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * For more information, contact:
- *
- *     Vivid Solutions
- *     Suite #1A
- *     2328 Government Street
- *     Victoria BC  V8T 5G5
- *     Canada
- *
- *     (250)385-6040
- *     www.vividsolutions.com
+* The JTS Topology Suite is a collection of Java classes that
+* implement the fundamental operations required to validate a given
+* geo-spatial data set to a known topological specification.
+*
+* Copyright (C) 2001 Vivid Solutions
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*
+* For more information, contact:
+*
+*     Vivid Solutions
+*     Suite #1A
+*     2328 Government Street
+*     Victoria BC  V8T 5G5
+*     Canada
+*
+*     (250)385-6040
+*     www.vividsolutions.com
  */
 package com.vividsolutions.jts.geom;
 import java.io.Serializable;
+
 /**
  * The CoordinateSequence implementation that Geometries use by default. In
  * this implementation, Coordinates returned by #toArray and #get are live --
  * parties that change them are actually changing the
  * DefaultCoordinateSequence's underlying data.
- * 
- * @version 1.5
+ *
+ * @version 1.6
+ *
+ * @deprecated no longer used
  */
-class DefaultCoordinateSequence implements CoordinateSequence, Serializable {
-    //With contributions from Markus Schaber [schabios at logi-track.com] 2004-03-26	
-	private static final long serialVersionUID = -915438501601840650L;
-	private Coordinate[] coordinates;
-	/**
-	 * Constructs a DefaultCoordinateSequence based on the given array (the
-	 * array is not copied).
-	 * 
-	 * @param coordinates
-	 *                  The coordinate array that will be assimilated.
-	 */
-	public DefaultCoordinateSequence(Coordinate[] coordinates) {
-		if (Geometry.hasNullElements(coordinates)) {
-			throw new IllegalArgumentException("Null coordinate");
-		}
-		this.coordinates = coordinates;
-	}
-	/**
-	 * Get the Coordinate with index i.
-	 * 
-	 * @param i
-	 *                  the index of the coordinate
-	 * @return the requested Coordinate instance
-	 */
-	public Coordinate getCoordinate(int i) {
-		return coordinates[i];
-	}
-	/**
-	 * Creates a deep copy of the Object
-	 * 
-	 * @return The deep copy
-	 */
-	public Object clone() {
-		Coordinate[] cloneCoordinates = new Coordinate[size()];
-		for (int i = 0; i < coordinates.length; i++) {
-			cloneCoordinates[i] = (Coordinate) coordinates[i].clone();
-		}
-		return new DefaultCoordinateSequence(cloneCoordinates);
-	}
-	/**
-	 * Returns the size of the coordinate sequence
-	 * 
-	 * @return the number of coordinates
-	 */
-	public int size() {
-		return coordinates.length;
-	}
-	/**
-	 * This method exposes the internal Array of Coordinate Objects
-	 * 
-	 * @return the Coordinate[] array.
-	 */
-	public Coordinate[] toCoordinateArray() {
-		return coordinates;
-	}
-	/**
-	 * Returns the string Representation of the coordinate array
-	 * 
-	 * @return The string
-	 */
-	public String toString() {
-		if (coordinates.length > 0) {
-			StringBuffer strBuf = new StringBuffer(17 * coordinates.length);
-			strBuf.append('(');
-			strBuf.append(coordinates[0]);
-			for (int i = 1; i < coordinates.length; i++) {
-				strBuf.append(", ");
-				strBuf.append(coordinates[i]);
-			}
-			strBuf.append(')');
-			return strBuf.toString();
-		} else {
-			return "()";
-		}
-	}
+class DefaultCoordinateSequence
+    implements CoordinateSequence, Serializable
+{
+  //With contributions from Markus Schaber [schabios at logi-track.com] 2004-03-26
+  private static final long serialVersionUID = -915438501601840650L;
+  private Coordinate[] coordinates;
+
+  /**
+   * Constructs a DefaultCoordinateSequence based on the given array (the
+   * array is not copied).
+   *
+   * @param coordinates the coordinate array that will be referenced.
+   */
+  public DefaultCoordinateSequence(Coordinate[] coordinates) {
+    if (Geometry.hasNullElements(coordinates)) {
+      throw new IllegalArgumentException("Null coordinate");
+    }
+    this.coordinates = coordinates;
+  }
+
+  /**
+   * Constructs a DefaultCoordinateSequence based on the given array (the
+   * array is not copied).
+   *
+   * @param coordinates the coordinate array that will be referenced.
+   */
+  public DefaultCoordinateSequence(CoordinateSequence coordSeq) {
+    coordinates = new Coordinate[coordSeq.size()];
+    for (int i = 0; i < coordinates.length; i++) {
+      coordinates[i] = coordSeq.getCoordinateCopy(i);
+    }
+  }
+
+  /**
+   * Constructs a sequence of a given size, populated
+   * with new {@link Coordinate}s.
+   *
+   * @param size the size of the sequence to create
+   */
+  public DefaultCoordinateSequence(int size) {
+    coordinates = new Coordinate[size];
+    for (int i = 0; i < size; i++) {
+      coordinates[i] = new Coordinate();
+    }
+  }
+
+  /**
+   * Get the Coordinate with index i.
+   *
+   * @param i
+   *                  the index of the coordinate
+   * @return the requested Coordinate instance
+   */
+  public Coordinate getCoordinate(int i) {
+    return coordinates[i];
+  }
+  /**
+   * Get a copy of the Coordinate with index i.
+   *
+   * @param i  the index of the coordinate
+   * @return a copy of the requested Coordinate
+   */
+  public Coordinate getCoordinateCopy(int i) {
+    return new Coordinate(coordinates[i]);
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int)
+   */
+  public void getCoordinate(int index, Coordinate coord) {
+    coord.x = coordinates[index].x;
+    coord.y = coordinates[index].y;
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int)
+   */
+  public double getX(int index) {
+    return coordinates[index].x;
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getY(int)
+   */
+  public double getY(int index) {
+    return coordinates[index].y;
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int, int)
+   */
+  public double getOrdinate(int index, int ordinateIndex)
+  {
+    switch (ordinateIndex) {
+      case CoordinateSequence.X:  return coordinates[index].x;
+      case CoordinateSequence.Y:  return coordinates[index].y;
+      case CoordinateSequence.Z:  return coordinates[index].z;
+    }
+    return Double.NaN;
+  }
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#setOrdinate(int, int, double)
+   */
+  public void setOrdinate(int index, int ordinateIndex, double value)
+  {
+    switch (ordinateIndex) {
+      case CoordinateSequence.X:  coordinates[index].x = value;
+      case CoordinateSequence.Y:  coordinates[index].y = value;
+      case CoordinateSequence.Z:  coordinates[index].z = value;
+    }
+  }
+  /**
+   * Creates a deep copy of the Object
+   *
+   * @return The deep copy
+   */
+  public Object clone() {
+    Coordinate[] cloneCoordinates = new Coordinate[size()];
+    for (int i = 0; i < coordinates.length; i++) {
+      cloneCoordinates[i] = (Coordinate) coordinates[i].clone();
+    }
+    return new DefaultCoordinateSequence(cloneCoordinates);
+  }
+  /**
+   * Returns the size of the coordinate sequence
+   *
+   * @return the number of coordinates
+   */
+  public int size() {
+    return coordinates.length;
+  }
+  /**
+   * This method exposes the internal Array of Coordinate Objects
+   *
+   * @return the Coordinate[] array.
+   */
+  public Coordinate[] toCoordinateArray() {
+    return coordinates;
+  }
+
+  public Envelope expandEnvelope(Envelope env)
+  {
+    for (int i = 0; i < coordinates.length; i++ ) {
+      env.expandToInclude(coordinates[i]);
+    }
+    return env;
+  }
+
+  /**
+   * Returns the string Representation of the coordinate array
+   *
+   * @return The string
+   */
+  public String toString() {
+    if (coordinates.length > 0) {
+      StringBuffer strBuf = new StringBuffer(17 * coordinates.length);
+      strBuf.append('(');
+      strBuf.append(coordinates[0]);
+      for (int i = 1; i < coordinates.length; i++) {
+        strBuf.append(", ");
+        strBuf.append(coordinates[i]);
+      }
+      strBuf.append(')');
+      return strBuf.toString();
+    } else {
+      return "()";
+    }
+  }
 }
diff --git a/src/com/vividsolutions/jts/geom/DefaultCoordinateSequenceFactory.java b/src/com/vividsolutions/jts/geom/DefaultCoordinateSequenceFactory.java
index bcf0a19..80f2c2c 100644
--- a/src/com/vividsolutions/jts/geom/DefaultCoordinateSequenceFactory.java
+++ b/src/com/vividsolutions/jts/geom/DefaultCoordinateSequenceFactory.java
@@ -1,68 +1,69 @@
 
 /*
- * The JTS Topology Suite is a collection of Java classes that
- * implement the fundamental operations required to validate a given
- * geo-spatial data set to a known topological specification.
- *
- * Copyright (C) 2001 Vivid Solutions
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * For more information, contact:
- *
- *     Vivid Solutions
- *     Suite #1A
- *     2328 Government Street
- *     Victoria BC  V8T 5G5
- *     Canada
- *
- *     (250)385-6040
- *     www.vividsolutions.com
+* The JTS Topology Suite is a collection of Java classes that
+* implement the fundamental operations required to validate a given
+* geo-spatial data set to a known topological specification.
+*
+* Copyright (C) 2001 Vivid Solutions
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*
+* For more information, contact:
+*
+*     Vivid Solutions
+*     Suite #1A
+*     2328 Government Street
+*     Victoria BC  V8T 5G5
+*     Canada
+*
+*     (250)385-6040
+*     www.vividsolutions.com
  */
 package com.vividsolutions.jts.geom;
 
 import java.io.Serializable;
 
 /**
- * Creates CoordinateSequences internally represented as an array of x's and
- * an array of y's.
+ * Creates CoordinateSequences represented as an array of {@link Coordinate}s.
  *
- * @version 1.5
+ * @version 1.6
+ *
+ * @deprecated no longer used
  */
 public class DefaultCoordinateSequenceFactory
     implements CoordinateSequenceFactory, Serializable
 {
-    private static final long serialVersionUID = -4099577099607551657L;
-    private static DefaultCoordinateSequenceFactory instance = new DefaultCoordinateSequenceFactory();
+  private static final long serialVersionUID = -4099577099607551657L;
+  private static final DefaultCoordinateSequenceFactory instance = new DefaultCoordinateSequenceFactory();
+
+  public DefaultCoordinateSequenceFactory() {
+  }
 
-    private DefaultCoordinateSequenceFactory() {
-    }
-    
-    /**
-     * @see http://www.javaworld.com/javaworld/javatips/jw-javatip122.html
-     */
-    private Object readResolve() {
-        return DefaultCoordinateSequenceFactory.instance();
-    }    
+  /**
+   * @see http://www.javaworld.com/javaworld/javatips/jw-javatip122.html
+   */
+  private Object readResolve() {
+    return DefaultCoordinateSequenceFactory.instance();
+  }
 
-    /**
-     * Returns the singleton instance of DefaultCoordinateSequenceFactory
-     */
-    public static DefaultCoordinateSequenceFactory instance() {
-        return instance;
-    }
+  /**
+   * Returns the singleton instance of DefaultCoordinateSequenceFactory
+   */
+  public static DefaultCoordinateSequenceFactory instance() {
+    return instance;
+  }
 
 
 
@@ -74,8 +75,21 @@ public class DefaultCoordinateSequenceFactory
    *            the coordinates, which may not be null nor contain null
    *            elements
    */
+  public CoordinateSequence create(Coordinate[] coordinates) {
+    return new DefaultCoordinateSequence(coordinates);
+  }
 
-    public CoordinateSequence create(Coordinate[] coordinates) {
-        return new DefaultCoordinateSequence(coordinates);
-    }
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(com.vividsolutions.jts.geom.CoordinateSequence)
+   */
+  public CoordinateSequence create(CoordinateSequence coordSeq) {
+    return new DefaultCoordinateSequence(coordSeq);
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(int, int)
+   */
+  public CoordinateSequence create(int size, int dimension) {
+    return new DefaultCoordinateSequence(size);
+  }
 }
diff --git a/src/com/vividsolutions/jts/geom/Dimension.java b/src/com/vividsolutions/jts/geom/Dimension.java
index a777f89..0feda20 100644
--- a/src/com/vividsolutions/jts/geom/Dimension.java
+++ b/src/com/vividsolutions/jts/geom/Dimension.java
@@ -39,7 +39,7 @@ package com.vividsolutions.jts.geom;
  * Also, constants representing the dimensions of the empty geometry and
  * non-empty geometries, and a wildcard dimension meaning "any dimension".
  * 
- * @version 1.5
+ * @version 1.6
  */
 public class Dimension {
 
diff --git a/src/com/vividsolutions/jts/geom/Envelope.java b/src/com/vividsolutions/jts/geom/Envelope.java
index bcf6751..47bcc11 100644
--- a/src/com/vividsolutions/jts/geom/Envelope.java
+++ b/src/com/vividsolutions/jts/geom/Envelope.java
@@ -47,7 +47,7 @@ import java.io.Serializable;
  *  When Envelope objects are created or initialized,
  *  the supplies extent values are automatically sorted into the correct order.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class Envelope
     implements Serializable
diff --git a/src/com/vividsolutions/jts/geom/Geometry.java b/src/com/vividsolutions/jts/geom/Geometry.java
index b2df75a..f938524 100644
--- a/src/com/vividsolutions/jts/geom/Geometry.java
+++ b/src/com/vividsolutions/jts/geom/Geometry.java
@@ -43,6 +43,8 @@ import com.vividsolutions.jts.io.WKTWriter;
 import com.vividsolutions.jts.operation.buffer.BufferOp;
 import com.vividsolutions.jts.operation.distance.DistanceOp;
 import com.vividsolutions.jts.operation.overlay.OverlayOp;
+import com.vividsolutions.jts.operation.predicate.RectangleIntersects;
+import com.vividsolutions.jts.operation.predicate.RectangleContains;
 import com.vividsolutions.jts.operation.relate.RelateOp;
 import com.vividsolutions.jts.operation.valid.IsValidOp;
 import com.vividsolutions.jts.util.Assert;
@@ -124,7 +126,7 @@ import com.vividsolutions.jts.util.Assert;
  *  topologically equal Geometries are added to HashMaps and HashSets, they
  *  remain distinct. This behaviour is desired in many cases.
  *
- *@version 1.5
+ *@version 1.6
  */
 public abstract class Geometry
     implements Cloneable, Comparable, Serializable
@@ -160,7 +162,8 @@ public abstract class Geometry
 
   private GeometryFactory factory;
 
-  private static final GeometryFactory INTERNAL_GEOMETRY_FACTORY = new GeometryFactory();
+  // MD - no longer used.  Remove in next version
+  //private static final GeometryFactory INTERNAL_GEOMETRY_FACTORY = new GeometryFactory();
 
   /**
    *  The ID of the Spatial Reference System used by this <code>Geometry</code>
@@ -261,6 +264,28 @@ public abstract class Geometry
   }
 
   /**
+   * Returns the number of {@link Geometry}s in a {@link GeometryCollection}
+   * (or 1, if the geometry is not a collection).
+   *
+   * @return the number of geometries contained in this geometry
+   */
+  public int getNumGeometries() {
+    return 1;
+  }
+
+  /**
+   * Returns an element {@link Geometry} from a {@link GeometryCollection}
+   * (or <code>this</code>, if the geometry is not a collection).
+   *
+   * @param n the index of the geometry element
+   * @return the n'th geometry contained in this geometry
+   */
+  public Geometry getGeometryN(int n) {
+    return this;
+  }
+
+
+  /**
    * A simple scheme for applications to add their own custom data to a Geometry.
    * An example use might be to add an object representing a Coordinate Reference System.
    * <p>
@@ -339,7 +364,7 @@ public abstract class Geometry
    */
   public boolean isValid()
   {
-    IsValidOp isValidOp = new IsValidOp(toInternalGeometry(this));
+    IsValidOp isValidOp = new IsValidOp(this);
     return isValidOp.isValid();
   }
 
@@ -360,7 +385,7 @@ public abstract class Geometry
    */
   public double distance(Geometry g)
   {
-    return DistanceOp.distance(toInternalGeometry(this), toInternalGeometry(g));
+    return DistanceOp.distance(this, g);
   }
 
   /**
@@ -382,6 +407,13 @@ public abstract class Geometry
       return false;
     return true;
   }
+
+  public boolean isRectangle()
+  {
+    // Polygon overrides to check for actual rectangle
+    return false;
+  }
+
   /**
    *  Returns the area of this <code>Geometry</code>.
    *  Areal Geometries have a non-zero area.
@@ -425,17 +457,17 @@ public abstract class Geometry
     int dim = getDimension();
     if (dim == 0) {
       CentroidPoint cent = new CentroidPoint();
-      cent.add(toInternalGeometry(this));
+      cent.add(this);
       centPt = cent.getCentroid();
     }
     else if (dim == 1) {
       CentroidLine cent = new CentroidLine();
-      cent.add(toInternalGeometry(this));
+      cent.add(this);
       centPt = cent.getCentroid();
     }
     else {
       CentroidArea cent = new CentroidArea();
-      cent.add(toInternalGeometry(this));
+      cent.add(this);
       centPt = cent.getCentroid();
     }
     return createPointFromInternalCoord(centPt, this);
@@ -455,15 +487,15 @@ public abstract class Geometry
     Coordinate interiorPt = null;
     int dim = getDimension();
     if (dim == 0) {
-      InteriorPointPoint intPt = new InteriorPointPoint(toInternalGeometry(this));
+      InteriorPointPoint intPt = new InteriorPointPoint(this);
       interiorPt = intPt.getInteriorPoint();
     }
     else if (dim == 1) {
-      InteriorPointLine intPt = new InteriorPointLine(toInternalGeometry(this));
+      InteriorPointLine intPt = new InteriorPointLine(this);
       interiorPt = intPt.getInteriorPoint();
     }
     else {
-      InteriorPointArea intPt = new InteriorPointArea(toInternalGeometry(this));
+      InteriorPointArea intPt = new InteriorPointArea(this);
       interiorPt = intPt.getInteriorPoint();
     }
     return createPointFromInternalCoord(interiorPt, this);
@@ -552,10 +584,7 @@ public abstract class Geometry
    *      disjoint
    */
   public boolean disjoint(Geometry g) {
-    // short-circuit test
-    if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
-      return true;
-    return relate(g).isDisjoint();
+    return ! intersects(g);
   }
 
   /**
@@ -580,9 +609,17 @@ public abstract class Geometry
    *@return        <code>true</code> if the two <code>Geometry</code>s intersect
    */
   public boolean intersects(Geometry g) {
-    // short-circuit test
+    // short-circuit envelope test
     if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
       return false;
+    // optimizations for rectangle arguments
+    if (isRectangle()) {
+      return RectangleIntersects.intersects((Polygon) this, g);
+    }
+    if (g.isRectangle()) {
+      return RectangleIntersects.intersects((Polygon) g, this);
+    }
+    // general case
     return relate(g).isIntersects();
   }
 
@@ -618,10 +655,7 @@ public abstract class Geometry
    *      <code>other</code>
    */
   public boolean within(Geometry g) {
-    // short-circuit test
-    if (! getEnvelopeInternal().contains(g.getEnvelopeInternal()))
-      return false;
-    return relate(g).isWithin();
+    return g.contains(this);
   }
 
   /**
@@ -636,6 +670,11 @@ public abstract class Geometry
     // short-circuit test
     if (! getEnvelopeInternal().contains(g.getEnvelopeInternal()))
       return false;
+    // optimizations for rectangle arguments
+    if (isRectangle()) {
+      return RectangleContains.contains((Polygon) this, g);
+    }
+    // general case
     return relate(g).isContains();
   }
 
@@ -696,7 +735,7 @@ public abstract class Geometry
   public IntersectionMatrix relate(Geometry g) {
     checkNotGeometryCollection(this);
     checkNotGeometryCollection(g);
-    return RelateOp.relate(toInternalGeometry(this), toInternalGeometry(g));
+    return RelateOp.relate(this, g);
   }
 
   /**
@@ -745,32 +784,11 @@ public abstract class Geometry
    *      are less than or equal to <code>distance</code>
    */
   public Geometry buffer(double distance) {
-    return fromInternalGeometry(BufferOp.bufferOp(toInternalGeometry(this), distance));
-  }
-
-  /**
-   * The JTS algorithms assume that Geometry#getCoordinate and #getCoordinates
-   * are fast, which may not be the case if the CoordinateSequence is not a
-   * BasicCoordinateSequence (e.g. if it were implemented using separate arrays
-   * for the x- and y-values), in which case frequent construction of Coordinates
-   * takes up much space and time. To solve this performance problem,
-   * #toInternalGeometry converts the Geometry to a BasicCoordinateSequence
-   * implementation before sending it to the JTS algorithms.
-   */
-  protected Geometry toInternalGeometry(Geometry g) {
-      if (DefaultCoordinateSequenceFactory.instance().equals(
-        factory.getCoordinateSequenceFactory())) { return g; }
-      return INTERNAL_GEOMETRY_FACTORY.createGeometry(g);
-  }
-
-  protected Geometry fromInternalGeometry(Geometry g) {
-      if (DefaultCoordinateSequenceFactory.instance().equals(
-        factory.getCoordinateSequenceFactory())) { return g; }
-      return getFactory().createGeometry(g);
+    return BufferOp.bufferOp(this, distance);
   }
 
   /**
-   *  Returns a buffer region around this <code>Geometry</code> having the given
+   *  Returns a buffer region around this {@link Geometry} having the given
    *  width and with a specified number of segments used to approximate curves.
    * The buffer of a Geometry is the Minkowski sum of the Geometry with
    * a disc of radius <code>distance</code>.  Curves in the buffer polygon are
@@ -784,7 +802,7 @@ public abstract class Geometry
    *      are less than or equal to <code>distance</code>
    */
   public Geometry buffer(double distance, int quadrantSegments) {
-    return fromInternalGeometry(BufferOp.bufferOp(toInternalGeometry(this), distance, quadrantSegments));
+    return BufferOp.bufferOp(this, distance, quadrantSegments);
   }
 
   /**
@@ -818,7 +836,7 @@ public abstract class Geometry
    *      s points
    */
   public Geometry convexHull() {
-    return fromInternalGeometry((new ConvexHull(toInternalGeometry(this))).getConvexHull());
+    return (new ConvexHull(this)).getConvexHull();
   }
 
   /**
@@ -832,7 +850,7 @@ public abstract class Geometry
   public Geometry intersection(Geometry other) {
     checkNotGeometryCollection(this);
     checkNotGeometryCollection(other);
-    return fromInternalGeometry(OverlayOp.overlayOp(toInternalGeometry(this), toInternalGeometry(other), OverlayOp.INTERSECTION));
+    return OverlayOp.overlayOp(this, other, OverlayOp.INTERSECTION);
   }
 
   /**
@@ -846,7 +864,7 @@ public abstract class Geometry
   public Geometry union(Geometry other) {
     checkNotGeometryCollection(this);
     checkNotGeometryCollection(other);
-    return fromInternalGeometry(OverlayOp.overlayOp(toInternalGeometry(this), toInternalGeometry(other), OverlayOp.UNION));
+    return OverlayOp.overlayOp(this, other, OverlayOp.UNION);
   }
 
   /**
@@ -862,7 +880,7 @@ public abstract class Geometry
   public Geometry difference(Geometry other) {
     checkNotGeometryCollection(this);
     checkNotGeometryCollection(other);
-    return fromInternalGeometry(OverlayOp.overlayOp(toInternalGeometry(this), toInternalGeometry(other), OverlayOp.DIFFERENCE));
+    return OverlayOp.overlayOp(this, other, OverlayOp.DIFFERENCE);
   }
 
   /**
@@ -879,7 +897,7 @@ public abstract class Geometry
   public Geometry symDifference(Geometry other) {
     checkNotGeometryCollection(this);
     checkNotGeometryCollection(other);
-    return fromInternalGeometry(OverlayOp.overlayOp(toInternalGeometry(this), toInternalGeometry(other), OverlayOp.SYMDIFFERENCE));
+    return OverlayOp.overlayOp(this, other, OverlayOp.SYMDIFFERENCE);
   }
 
   /**
diff --git a/src/com/vividsolutions/jts/geom/GeometryCollection.java b/src/com/vividsolutions/jts/geom/GeometryCollection.java
index 23589c7..b730461 100644
--- a/src/com/vividsolutions/jts/geom/GeometryCollection.java
+++ b/src/com/vividsolutions/jts/geom/GeometryCollection.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.util.Assert;
 /**
  *  Basic implementation of <code>GeometryCollection</code>.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class GeometryCollection extends Geometry {
 //  With contributions from Markus Schaber [schabios at logi-track.com] 2004-03-26
@@ -54,7 +54,7 @@ public class GeometryCollection extends Geometry {
 
   /** @deprecated Use GeometryFactory instead */
   public GeometryCollection(Geometry[] geometries, PrecisionModel precisionModel, int SRID) {
-      this(geometries, new GeometryFactory(precisionModel, SRID, DefaultCoordinateSequenceFactory.instance()));
+      this(geometries, new GeometryFactory(precisionModel, SRID));
   }
 
 
@@ -83,11 +83,11 @@ public class GeometryCollection extends Geometry {
 
   /**
    * Collects all coordinates of all subgeometries into an Array.
-   * 
+   *
    * Note that while changes to the coordinate objects themselves
-   * may modify the Geometries in place, the returned Array as such 
+   * may modify the Geometries in place, the returned Array as such
    * is only a temporary container which is not synchronized back.
-   * 
+   *
    * @return the collected coordinates
    *    */
   public Coordinate[] getCoordinates() {
diff --git a/src/com/vividsolutions/jts/geom/GeometryCollectionIterator.java b/src/com/vividsolutions/jts/geom/GeometryCollectionIterator.java
index 0be438f..8fd21e3 100644
--- a/src/com/vividsolutions/jts/geom/GeometryCollectionIterator.java
+++ b/src/com/vividsolutions/jts/geom/GeometryCollectionIterator.java
@@ -45,14 +45,14 @@ import java.util.NoSuchElementException;
  *  simple to ignore the <code>GeometryCollection</code> objects if they are not
  *  needed.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class GeometryCollectionIterator implements Iterator {
 
   /**
    *  The <code>GeometryCollection</code> being iterated over.
    */
-  private GeometryCollection parent;
+  private Geometry parent;
   /**
    *  Indicates whether or not the first element (the <code>GeometryCollection</code>
    *  ) has been returned.
@@ -81,7 +81,7 @@ public class GeometryCollectionIterator implements Iterator {
    *@param  parent  the collection over which to iterate; also, the first
    *      element returned by the iterator.
    */
-  public GeometryCollectionIterator(GeometryCollection parent) {
+  public GeometryCollectionIterator(Geometry parent) {
     this.parent = parent;
     atStart = true;
     index = 0;
diff --git a/src/com/vividsolutions/jts/geom/GeometryComponentFilter.java b/src/com/vividsolutions/jts/geom/GeometryComponentFilter.java
index 7c5947e..6eb8058 100644
--- a/src/com/vividsolutions/jts/geom/GeometryComponentFilter.java
+++ b/src/com/vividsolutions/jts/geom/GeometryComponentFilter.java
@@ -49,7 +49,7 @@ package com.vividsolutions.jts.geom;
  *  <code>GeometryComponentFilter</code>
  *  is an example of the Gang-of-Four Visitor pattern.
  *
- *@version 1.5
+ *@version 1.6
  */
 public interface GeometryComponentFilter {
 
diff --git a/src/com/vividsolutions/jts/geom/GeometryFactory.java b/src/com/vividsolutions/jts/geom/GeometryFactory.java
index 00e2a53..967d56b 100644
--- a/src/com/vividsolutions/jts/geom/GeometryFactory.java
+++ b/src/com/vividsolutions/jts/geom/GeometryFactory.java
@@ -36,6 +36,7 @@ package com.vividsolutions.jts.geom;
 
 import java.util.*;
 import java.io.Serializable;
+import com.vividsolutions.jts.geom.impl.*;
 import com.vividsolutions.jts.geom.util.*;
 import com.vividsolutions.jts.util.Assert;
 
@@ -43,7 +44,7 @@ import com.vividsolutions.jts.util.Assert;
  * Supplies a set of utility methods for building Geometry objects from lists
  * of Coordinates.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class GeometryFactory
     implements Serializable
@@ -88,7 +89,7 @@ public class GeometryFactory
    * @param precisionModel the PrecisionModel to use
    */
   public GeometryFactory(PrecisionModel precisionModel) {
-    this(precisionModel, 0, DefaultCoordinateSequenceFactory.instance());
+    this(precisionModel, 0, getDefaultCoordinateSequenceFactory());
   }
 
   /**
@@ -100,7 +101,7 @@ public class GeometryFactory
    * @param SRID the SRID to use
    */
   public GeometryFactory(PrecisionModel precisionModel, int SRID) {
-    this(precisionModel, SRID, DefaultCoordinateSequenceFactory.instance());
+    this(precisionModel, SRID, getDefaultCoordinateSequenceFactory());
   }
 
   /**
@@ -111,6 +112,11 @@ public class GeometryFactory
     this(new PrecisionModel(), 0);
   }
 
+  private static CoordinateSequenceFactory getDefaultCoordinateSequenceFactory()
+  {
+    return CoordinateArraySequenceFactory.instance();
+  }
+
   /**
    *  Converts the <code>List</code> to an array.
    *
diff --git a/src/com/vividsolutions/jts/geom/GeometryFilter.java b/src/com/vividsolutions/jts/geom/GeometryFilter.java
index 52f9aa8..8eaec5e 100644
--- a/src/com/vividsolutions/jts/geom/GeometryFilter.java
+++ b/src/com/vividsolutions/jts/geom/GeometryFilter.java
@@ -44,7 +44,7 @@ package com.vividsolutions.jts.geom;
  *  <code>GeometryFilter</code>
  *  is an example of the Gang-of-Four Visitor pattern.
  *
- *@version 1.5
+ *@version 1.6
  */
 public interface GeometryFilter {
 
diff --git a/src/com/vividsolutions/jts/geom/IntersectionMatrix.java b/src/com/vividsolutions/jts/geom/IntersectionMatrix.java
index 50c45c1..7033a73 100644
--- a/src/com/vividsolutions/jts/geom/IntersectionMatrix.java
+++ b/src/com/vividsolutions/jts/geom/IntersectionMatrix.java
@@ -52,7 +52,7 @@ package com.vividsolutions.jts.geom;
  *  HREF="http://www.opengis.org/techno/specs.htm">OpenGIS Simple Features
  *  Specification for SQL</A> .
  *
- *@version 1.5
+ *@version 1.6
  */
 public class IntersectionMatrix implements Cloneable {
   /**
diff --git a/src/com/vividsolutions/jts/geom/LineSegment.java b/src/com/vividsolutions/jts/geom/LineSegment.java
index 305948b..49c40bf 100644
--- a/src/com/vividsolutions/jts/geom/LineSegment.java
+++ b/src/com/vividsolutions/jts/geom/LineSegment.java
@@ -49,7 +49,7 @@ import com.vividsolutions.jts.algorithm.*;
  * object as a way of computing segment properties on the
  * segments defined by arrays or lists of {@link Coordinate}s.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class LineSegment
   implements Comparable, Serializable
diff --git a/src/com/vividsolutions/jts/geom/LineString.java b/src/com/vividsolutions/jts/geom/LineString.java
index c9d4407..3e998ab 100644
--- a/src/com/vividsolutions/jts/geom/LineString.java
+++ b/src/com/vividsolutions/jts/geom/LineString.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.operation.IsSimpleOp;
 /**
  *  Basic implementation of <code>LineString</code>.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class LineString extends Geometry {
   private static final long serialVersionUID = 3110669828065365560L;
@@ -60,32 +60,36 @@ public class LineString extends Geometry {
    *@param  SRID            the ID of the Spatial Reference System used by this
    *      <code>LineString</code>
    */
-  /** @deprecated Use GeometryFactory instead */  
-  public LineString(Coordinate points[], PrecisionModel precisionModel, int SRID) {
-      this(DefaultCoordinateSequenceFactory.instance()
-      .create(points == null ? new Coordinate[]{} : points), 
-      new GeometryFactory(precisionModel, SRID, DefaultCoordinateSequenceFactory.instance()));
+  /** @deprecated Use GeometryFactory instead */
+  public LineString(Coordinate points[], PrecisionModel precisionModel, int SRID)
+  {
+    super(new GeometryFactory(precisionModel, SRID));
+    init(getFactory().getCoordinateSequenceFactory().create(points));
   }
-    
+
   /**
    *@param  points          the points of the linestring, or <code>null</code>
    *      to create the empty geometry. Consecutive points may not be equal.
-   */  
+   */
   public LineString(CoordinateSequence points, GeometryFactory factory) {
     super(factory);
+    init(points);
+  }
+
+  private void init(CoordinateSequence points)
+  {
     if (points == null) {
-      points = factory.getCoordinateSequenceFactory().create(new Coordinate[]{});
-    }    
+      points = getFactory().getCoordinateSequenceFactory().create(new Coordinate[]{});
+    }
     if (points.size() == 1) {
       throw new IllegalArgumentException("point array must contain 0 or >1 elements");
     }
     this.points = points;
   }
-    
   public Coordinate[] getCoordinates() {
     return points.toCoordinateArray();
-  }        
-  
+  }
+
   public CoordinateSequence getCoordinateSequence() {
       return points;
   }
@@ -158,13 +162,13 @@ public class LineString extends Geometry {
    *@return the area of the polygon
    */
   public double getLength()
-  {     
+  {
    return CGAlgorithms.length(points);
   }
 
   public boolean isSimple()
   {
-    return (new IsSimpleOp()).isSimple((LineString)toInternalGeometry(this));
+    return (new IsSimpleOp()).isSimple(this);
   }
 
   public Geometry getBoundary() {
@@ -201,6 +205,8 @@ public class LineString extends Geometry {
     if (isEmpty()) {
       return new Envelope();
     }
+    return points.expandEnvelope(new Envelope());
+    /*
     //Convert to array, then access array directly, to avoid the function-call overhead
     //of calling #get millions of times. #toArray may be inefficient for
     //non-BasicCoordinateSequence CoordinateSequences. [Jon Aquino]
@@ -210,7 +216,7 @@ public class LineString extends Geometry {
     double maxx = coordinates[0].x;
     double maxy = coordinates[0].y;
     //OptimizeIt shows that Math#min and Math#max here are a bottleneck.
-    //Replace with direct comparisons. [Jon Aquino] 
+    //Replace with direct comparisons. [Jon Aquino]
     for (int i = 1; i < coordinates.length; i++) {
       minx = minx < coordinates[i].x ? minx : coordinates[i].x;
       maxx = maxx > coordinates[i].x ? maxx : coordinates[i].x;
@@ -218,8 +224,9 @@ public class LineString extends Geometry {
       maxy = maxy > coordinates[i].y ? maxy : coordinates[i].y;
     }
     return new Envelope(minx, maxx, miny, maxy);
+    */
   }
-  
+
   public boolean equalsExact(Geometry other, double tolerance) {
     if (!isEquivalentClass(other)) {
       return false;
diff --git a/src/com/vividsolutions/jts/geom/LinearRing.java b/src/com/vividsolutions/jts/geom/LinearRing.java
index 894ac28..990df10 100644
--- a/src/com/vividsolutions/jts/geom/LinearRing.java
+++ b/src/com/vividsolutions/jts/geom/LinearRing.java
@@ -40,7 +40,7 @@ package com.vividsolutions.jts.geom;
  * Either orientation of the ring is allowed.
  * A valid ring must not self-intersect.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class LinearRing extends LineString
 {
@@ -60,9 +60,17 @@ public class LinearRing extends LineString
    */
   public LinearRing(Coordinate points[], PrecisionModel precisionModel,
                     int SRID) {
-    this(DefaultCoordinateSequenceFactory.instance()
-          .create(points == null ? new Coordinate[]{} : points), 
-          new GeometryFactory(precisionModel, SRID, DefaultCoordinateSequenceFactory.instance()));
+    this(points, new GeometryFactory(precisionModel, SRID));
+    validateConstruction();
+  }
+
+  /**
+   * This method is ONLY used to avoid deprecation warnings.
+   * @param points
+   * @param factory
+   */
+  private LinearRing(Coordinate points[], GeometryFactory factory) {
+    this(factory.getCoordinateSequenceFactory().create(points), factory);
   }
 
 
diff --git a/src/com/vividsolutions/jts/geom/Location.java b/src/com/vividsolutions/jts/geom/Location.java
index f3c644f..59ad532 100644
--- a/src/com/vividsolutions/jts/geom/Location.java
+++ b/src/com/vividsolutions/jts/geom/Location.java
@@ -41,7 +41,7 @@ package com.vividsolutions.jts.geom;
  *  HREF="http://www.opengis.org/techno/specs.htm">OpenGIS Simple Features
  *  Specification for SQL</A> .
  *
- *@version 1.5
+ *@version 1.6
  */
 public class Location {
   /**
diff --git a/src/com/vividsolutions/jts/geom/MultiLineString.java b/src/com/vividsolutions/jts/geom/MultiLineString.java
index 280f55f..7ee1daa 100644
--- a/src/com/vividsolutions/jts/geom/MultiLineString.java
+++ b/src/com/vividsolutions/jts/geom/MultiLineString.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.operation.IsSimpleOp;
 /**
  *  Basic implementation of <code>MultiLineString</code>.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class MultiLineString extends GeometryCollection {
   private static final long serialVersionUID = 8166665132445433741L;
@@ -59,11 +59,11 @@ public class MultiLineString extends GeometryCollection {
    * @deprecated Use GeometryFactory instead
    */
   public MultiLineString(LineString[] lineStrings, PrecisionModel precisionModel, int SRID) {
-    super(lineStrings, new GeometryFactory(precisionModel, SRID, DefaultCoordinateSequenceFactory.instance()));
+    super(lineStrings, new GeometryFactory(precisionModel, SRID));
   }
-  
-  
-  
+
+
+
   /**
    * @param lineStrings
    *            the <code>LineString</code>s for this <code>MultiLineString</code>,
@@ -73,7 +73,7 @@ public class MultiLineString extends GeometryCollection {
    */
   public MultiLineString(LineString[] lineStrings, GeometryFactory factory) {
     super(lineStrings, factory);
-  }  
+  }
 
   public int getDimension() {
     return 1;
@@ -104,14 +104,14 @@ public class MultiLineString extends GeometryCollection {
 
   public boolean isSimple()
   {
-    return (new IsSimpleOp()).isSimple((MultiLineString)toInternalGeometry(this));
+    return (new IsSimpleOp()).isSimple(this);
   }
 
   public Geometry getBoundary() {
     if (isEmpty()) {
       return getFactory().createGeometryCollection(null);
     }
-    GeometryGraph g = new GeometryGraph(0, toInternalGeometry(this));
+    GeometryGraph g = new GeometryGraph(0, this);
     Coordinate[] pts = g.getBoundaryPoints();
     return getFactory().createMultiPoint(pts);
   }
diff --git a/src/com/vividsolutions/jts/geom/MultiPoint.java b/src/com/vividsolutions/jts/geom/MultiPoint.java
index c49e755..2fe0e4d 100644
--- a/src/com/vividsolutions/jts/geom/MultiPoint.java
+++ b/src/com/vividsolutions/jts/geom/MultiPoint.java
@@ -39,13 +39,13 @@ import com.vividsolutions.jts.operation.IsSimpleOp;
 /**
  *  Models a collection of <code>Point</code>s.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class MultiPoint
   extends GeometryCollection
 {
-    
-  private static final long serialVersionUID = -8048474874175355449L;  
+
+  private static final long serialVersionUID = -8048474874175355449L;
 
   /**
    *  Constructs a <code>MultiPoint</code>.
@@ -60,9 +60,9 @@ public class MultiPoint
    * @deprecated Use GeometryFactory instead
    */
   public MultiPoint(Point[] points, PrecisionModel precisionModel, int SRID) {
-    super(points, new GeometryFactory(precisionModel, SRID, DefaultCoordinateSequenceFactory.instance()));
+    super(points, new GeometryFactory(precisionModel, SRID));
   }
-  
+
   /**
    *@param  points          the <code>Point</code>s for this <code>MultiPoint</code>
    *      , or <code>null</code> or an empty array to create the empty geometry.
@@ -70,7 +70,7 @@ public class MultiPoint
    */
   public MultiPoint(Point[] points, GeometryFactory factory) {
     super(points, factory);
-  }  
+  }
 
   public int getDimension() {
     return 0;
@@ -84,12 +84,12 @@ public class MultiPoint
     return "MultiPoint";
   }
 
-  public Geometry getBoundary() {      
+  public Geometry getBoundary() {
     return getFactory().createGeometryCollection(null);
   }
 
   public boolean isSimple() {
-    return (new IsSimpleOp()).isSimple((MultiPoint)toInternalGeometry(this));
+    return (new IsSimpleOp()).isSimple(this);
   }
 
   public boolean isValid() {
diff --git a/src/com/vividsolutions/jts/geom/MultiPolygon.java b/src/com/vividsolutions/jts/geom/MultiPolygon.java
index 94debea..bbc1c71 100644
--- a/src/com/vividsolutions/jts/geom/MultiPolygon.java
+++ b/src/com/vividsolutions/jts/geom/MultiPolygon.java
@@ -39,7 +39,7 @@ import java.util.ArrayList;
 /**
  *  Basic implementation of <code>MultiPolygon</code>.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class MultiPolygon extends GeometryCollection {
   private static final long serialVersionUID = -551033529766975875L;
@@ -59,10 +59,10 @@ public class MultiPolygon extends GeometryCollection {
    * @deprecated Use GeometryFactory instead
    */
   public MultiPolygon(Polygon[] polygons, PrecisionModel precisionModel, int SRID) {
-    this(polygons, new GeometryFactory(precisionModel, SRID, DefaultCoordinateSequenceFactory.instance()));
+    this(polygons, new GeometryFactory(precisionModel, SRID));
   }
-  
-    
+
+
   /**
    * @param polygons
    *            the <code>Polygon</code>s for this <code>MultiPolygon</code>,
@@ -75,7 +75,7 @@ public class MultiPolygon extends GeometryCollection {
    */
   public MultiPolygon(Polygon[] polygons, GeometryFactory factory) {
     super(polygons, factory);
-  }  
+  }
 
   public int getDimension() {
     return 2;
@@ -100,7 +100,7 @@ public class MultiPolygon extends GeometryCollection {
     ArrayList allRings = new ArrayList();
     for (int i = 0; i < geometries.length; i++) {
       Polygon polygon = (Polygon) geometries[i];
-      GeometryCollection rings = (GeometryCollection) polygon.getBoundary();
+      Geometry rings = polygon.getBoundary();
       for (int j = 0; j < rings.getNumGeometries(); j++) {
         allRings.add(rings.getGeometryN(j));
       }
diff --git a/src/com/vividsolutions/jts/geom/Point.java b/src/com/vividsolutions/jts/geom/Point.java
index c37c5d2..f2a64e3 100644
--- a/src/com/vividsolutions/jts/geom/Point.java
+++ b/src/com/vividsolutions/jts/geom/Point.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.util.Assert;
 /**
  *  Basic implementation of <code>Point</code>.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class Point extends Geometry {
   private static final long serialVersionUID = 4902022702746614570L;
@@ -60,20 +60,25 @@ public class Point extends Geometry {
    * @deprecated Use GeometryFactory instead
    */
   public Point(Coordinate coordinate, PrecisionModel precisionModel, int SRID) {
-      this(DefaultCoordinateSequenceFactory.instance().create(
-          coordinate != null ? new Coordinate[]{coordinate} : new Coordinate[]{}), 
-          new GeometryFactory(precisionModel, SRID, DefaultCoordinateSequenceFactory.instance()));
+    super(new GeometryFactory(precisionModel, SRID));
+    init(getFactory().getCoordinateSequenceFactory().create(
+          coordinate != null ? new Coordinate[]{coordinate} : new Coordinate[]{}));
   }
 
   /**
    *@param  coordinates      contains the single coordinate on which to base this <code>Point</code>
    *      , or <code>null</code> to create the empty geometry.
-   */  
+   */
   public Point(CoordinateSequence coordinates, GeometryFactory factory) {
-    super(factory);    
+    super(factory);
+    init(coordinates);
+  }
+
+  private void init(CoordinateSequence coordinates)
+  {
     if (coordinates == null) {
-      coordinates = factory.getCoordinateSequenceFactory().create(new Coordinate[]{});
-    }        
+      coordinates = getFactory().getCoordinateSequenceFactory().create(new Coordinate[]{});
+    }
     Assert.isTrue(coordinates.size() <= 1);
     this.coordinates = coordinates;
   }
@@ -138,7 +143,9 @@ public class Point extends Geometry {
     if (isEmpty()) {
       return new Envelope();
     }
-    return new Envelope(getCoordinate().x, getCoordinate().x, getCoordinate().y, getCoordinate().y);
+    Envelope env = new Envelope();
+    env.expandToInclude(coordinates.getX(0), coordinates.getY(0));
+    return env;
   }
 
   public boolean equalsExact(Geometry other, double tolerance) {
diff --git a/src/com/vividsolutions/jts/geom/Polygon.java b/src/com/vividsolutions/jts/geom/Polygon.java
index af27d95..7742106 100644
--- a/src/com/vividsolutions/jts/geom/Polygon.java
+++ b/src/com/vividsolutions/jts/geom/Polygon.java
@@ -49,18 +49,22 @@ import com.vividsolutions.jts.algorithm.*;
  *  HREF="http://www.opengis.org/techno/specs.htm">OpenGIS Simple Features
  *  Specification for SQL</A> .
  *
- *@version 1.5
+ *@version 1.6
  */
 public class Polygon extends Geometry {
-  private static final long serialVersionUID = -3494792200821764533L;  
+  private static final long serialVersionUID = -3494792200821764533L;
+
   /**
-   *  The exterior boundary, or <code>null</code> if this <code>Polygon</code>
-   *  is the empty geometry.
+   *  The exterior boundary,
+   * or <code>null</code> if this <code>Polygon</code>
+   *  is empty.
    */
   protected LinearRing shell = null;
 
   /**
-   *  The interior boundaries, if any.
+   * The interior boundaries, if any.
+   * This instance var is never null.
+   * If there are no holes, the array is of zero length.
    */
   protected LinearRing[] holes;
 
@@ -77,7 +81,7 @@ public class Polygon extends Geometry {
    * @deprecated Use GeometryFactory instead
    */
   public Polygon(LinearRing shell, PrecisionModel precisionModel, int SRID) {
-    this(shell, new LinearRing[]{}, new GeometryFactory(precisionModel, SRID, DefaultCoordinateSequenceFactory.instance()));
+    this(shell, new LinearRing[]{}, new GeometryFactory(precisionModel, SRID));
   }
 
   /**
@@ -97,7 +101,7 @@ public class Polygon extends Geometry {
    * @deprecated Use GeometryFactory instead
    */
   public Polygon(LinearRing shell, LinearRing[] holes, PrecisionModel precisionModel, int SRID) {
-      this(shell, holes, new GeometryFactory(precisionModel, SRID, DefaultCoordinateSequenceFactory.instance()));
+      this(shell, holes, new GeometryFactory(precisionModel, SRID));
   }
 
   /**
@@ -178,6 +182,39 @@ public class Polygon extends Geometry {
     return true;
   }
 
+  public boolean isRectangle()
+  {
+    if (getNumInteriorRing() != 0) return false;
+    if (shell == null) return false;
+    if (shell.getNumPoints() != 5) return false;
+
+    CoordinateSequence seq = shell.getCoordinateSequence();
+
+    // check vertices have correct values
+    Envelope env = getEnvelopeInternal();
+    for (int i = 0; i < 5; i++) {
+      double x = seq.getX(i);
+      if (! (x == env.getMinX() || x == env.getMaxX())) return false;
+      double y = seq.getX(i);
+      if (! (y == env.getMinY() || y == env.getMaxY())) return false;
+    }
+
+    // check vertices are in right order
+    double prevX = seq.getX(0);
+    double prevY = seq.getX(0);
+    for (int i = 1; i <= 4; i++) {
+      double x = seq.getX(i);
+      double y = seq.getY(i);
+      boolean xChanged = x != prevX;
+      boolean yChanged = y != prevY;
+      if (xChanged == yChanged)
+        return false;
+      prevX = x;
+      prevY = y;
+    }
+    return true;
+  }
+
   public LineString getExteriorRing() {
     return shell;
   }
@@ -233,6 +270,8 @@ public class Polygon extends Geometry {
     for (int i = 0; i < holes.length; i++) {
       rings[i + 1] = holes[i];
     }
+    if (rings.length <= 1)
+      return getFactory().createLinearRing(rings[0].getCoordinateSequence());
     return getFactory().createMultiLineString(rings);
   }
 
diff --git a/src/com/vividsolutions/jts/geom/PrecisionModel.java b/src/com/vividsolutions/jts/geom/PrecisionModel.java
index 388fdd5..8a4aa32 100644
--- a/src/com/vividsolutions/jts/geom/PrecisionModel.java
+++ b/src/com/vividsolutions/jts/geom/PrecisionModel.java
@@ -79,7 +79,7 @@ import java.util.Map;
  *<p>
  *  JTS methods currently do not handle inputs with different precision models.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class PrecisionModel implements Serializable, Comparable
 {
@@ -357,10 +357,14 @@ public class PrecisionModel implements Serializable, Comparable
       external.y = internal.y;
   }
 
-
-
   /**
    * Rounds a numeric value to the PrecisionModel grid.
+   * Symmetric Arithmetic Rounding is used, to provide
+   * uniform rounding behaviour no matter where the number is
+   * on the number line.
+   * <p>
+   * <b>Note:</b> Java's <code>Math#rint</code> uses the "banker's rounding" algorithm,
+   * which is not suitable for precision operations elsewhere in JTS.
    */
   public double makePrecise(double val) {
   	if (modelType == FLOATING_SINGLE) {
@@ -368,7 +372,8 @@ public class PrecisionModel implements Serializable, Comparable
   		return (double) floatSingleVal;
   	}
   	if (modelType == FIXED) {
-  		return Math.rint(val * scale) / scale;
+            return Math.round(val * scale) / scale;
+//  		return Math.rint(val * scale) / scale;
   	}
   	// modelType == FLOATING - no rounding necessary
   	return val;
diff --git a/src/com/vividsolutions/jts/geom/TopologyException.java b/src/com/vividsolutions/jts/geom/TopologyException.java
index a8d70dc..a6d282d 100644
--- a/src/com/vividsolutions/jts/geom/TopologyException.java
+++ b/src/com/vividsolutions/jts/geom/TopologyException.java
@@ -38,7 +38,7 @@ package com.vividsolutions.jts.geom;
 /**
  * Indicates an invalid or inconsistent topological situation encountered during processing
  *
- * @version 1.5
+ * @version 1.6
  */
 public class TopologyException
   extends RuntimeException
diff --git a/src/com/vividsolutions/jts/geom/Triangle.java b/src/com/vividsolutions/jts/geom/Triangle.java
index 875da24..489068c 100644
--- a/src/com/vividsolutions/jts/geom/Triangle.java
+++ b/src/com/vividsolutions/jts/geom/Triangle.java
@@ -37,7 +37,7 @@ package com.vividsolutions.jts.geom;
  * Represents a planar triangle, and provides methods for calculating various
  * properties of triangles.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Triangle
 {
diff --git a/src/com/vividsolutions/jts/geom/impl/CoordinateArraySequence.java b/src/com/vividsolutions/jts/geom/impl/CoordinateArraySequence.java
new file mode 100644
index 0000000..e8880da
--- /dev/null
+++ b/src/com/vividsolutions/jts/geom/impl/CoordinateArraySequence.java
@@ -0,0 +1,223 @@
+/*
+* The JTS Topology Suite is a collection of Java classes that
+* implement the fundamental operations required to validate a given
+* geo-spatial data set to a known topological specification.
+*
+* Copyright (C) 2001 Vivid Solutions
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*
+* For more information, contact:
+*
+*     Vivid Solutions
+*     Suite #1A
+*     2328 Government Street
+*     Victoria BC  V8T 5G5
+*     Canada
+*
+*     (250)385-6040
+*     www.vividsolutions.com
+ */
+package com.vividsolutions.jts.geom.impl;
+
+import java.io.Serializable;
+import com.vividsolutions.jts.geom.*;
+
+/**
+ * The {@link CoordinateSequence} implementation that {@link Geometry}s use by default.
+ * In this implementation, Coordinates returned by #toArray and #getCoordinate are live --
+ * modifications to them are actually changing the
+ * CoordinateSequence's underlying data.
+ *
+ * @version 1.6
+ */
+public class CoordinateArraySequence
+    implements CoordinateSequence, Serializable
+{
+  //With contributions from Markus Schaber [schabios at logi-track.com] 2004-03-26
+  private static final long serialVersionUID = -915438501601840650L;
+
+  private Coordinate[] coordinates;
+
+  /**
+   * Constructs a sequence based on the given array (the
+   * array is not copied).
+   *
+   * @param coordinates the coordinate array that will be referenced.
+   */
+  public CoordinateArraySequence(Coordinate[] coordinates) {
+    this.coordinates = coordinates;
+    if (coordinates == null)
+      this.coordinates = new Coordinate[0];
+  }
+
+  /**
+   * Constructs a sequence of a given size, populated
+   * with new {@link Coordinate}s.
+   *
+   * @param size the size of the sequence to create
+   */
+  public CoordinateArraySequence(int size) {
+    coordinates = new Coordinate[size];
+    for (int i = 0; i < size; i++) {
+      coordinates[i] = new Coordinate();
+    }
+  }
+
+  /**
+   * Constructs a sequence based on the given array (the
+   * array is not copied).
+   *
+   * @param coordinates the coordinate array that will be referenced.
+   */
+  public CoordinateArraySequence(CoordinateSequence coordSeq)
+  {
+    if (coordSeq != null)
+      coordinates = new Coordinate[coordSeq.size()];
+    else
+      coordinates = new Coordinate[0];
+
+    for (int i = 0; i < coordinates.length; i++) {
+      coordinates[i] = coordSeq.getCoordinateCopy(i);
+    }
+  }
+
+  /**
+   * Get the Coordinate with index i.
+   *
+   * @param i
+   *                  the index of the coordinate
+   * @return the requested Coordinate instance
+   */
+  public Coordinate getCoordinate(int i) {
+    return coordinates[i];
+  }
+
+  /**
+   * Get a copy of the Coordinate with index i.
+   *
+   * @param i  the index of the coordinate
+   * @return a copy of the requested Coordinate
+   */
+  public Coordinate getCoordinateCopy(int i) {
+    return new Coordinate(coordinates[i]);
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int)
+   */
+  public void getCoordinate(int index, Coordinate coord) {
+    coord.x = coordinates[index].x;
+    coord.y = coordinates[index].y;
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int)
+   */
+  public double getX(int index) {
+    return coordinates[index].x;
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getY(int)
+   */
+  public double getY(int index) {
+    return coordinates[index].y;
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int, int)
+   */
+  public double getOrdinate(int index, int ordinateIndex)
+  {
+    switch (ordinateIndex) {
+      case CoordinateSequence.X:  return coordinates[index].x;
+      case CoordinateSequence.Y:  return coordinates[index].y;
+      case CoordinateSequence.Z:  return coordinates[index].z;
+    }
+    return Double.NaN;
+  }
+
+  /**
+   * Creates a deep copy of the Object
+   *
+   * @return The deep copy
+   */
+  public Object clone() {
+    Coordinate[] cloneCoordinates = new Coordinate[size()];
+    for (int i = 0; i < coordinates.length; i++) {
+      cloneCoordinates[i] = (Coordinate) coordinates[i].clone();
+    }
+    return new CoordinateArraySequence(cloneCoordinates);
+  }
+  /**
+   * Returns the size of the coordinate sequence
+   *
+   * @return the number of coordinates
+   */
+  public int size() {
+    return coordinates.length;
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#setOrdinate(int, int, double)
+   */
+  public void setOrdinate(int index, int ordinateIndex, double value)
+  {
+    switch (ordinateIndex) {
+      case CoordinateSequence.X:  coordinates[index].x = value;
+      case CoordinateSequence.Y:  coordinates[index].y = value;
+      case CoordinateSequence.Z:  coordinates[index].z = value;
+    }
+  }
+
+  /**
+   * This method exposes the internal Array of Coordinate Objects
+   *
+   * @return the Coordinate[] array.
+   */
+  public Coordinate[] toCoordinateArray() {
+    return coordinates;
+  }
+
+  public Envelope expandEnvelope(Envelope env)
+  {
+    for (int i = 0; i < coordinates.length; i++ ) {
+      env.expandToInclude(coordinates[i]);
+    }
+    return env;
+  }
+
+  /**
+   * Returns the string Representation of the coordinate array
+   *
+   * @return The string
+   */
+  public String toString() {
+    if (coordinates.length > 0) {
+      StringBuffer strBuf = new StringBuffer(17 * coordinates.length);
+      strBuf.append('(');
+      strBuf.append(coordinates[0]);
+      for (int i = 1; i < coordinates.length; i++) {
+        strBuf.append(", ");
+        strBuf.append(coordinates[i]);
+      }
+      strBuf.append(')');
+      return strBuf.toString();
+    } else {
+      return "()";
+    }
+  }
+}
diff --git a/src/com/vividsolutions/jts/geom/impl/CoordinateArraySequenceFactory.java b/src/com/vividsolutions/jts/geom/impl/CoordinateArraySequenceFactory.java
new file mode 100644
index 0000000..86813f8
--- /dev/null
+++ b/src/com/vividsolutions/jts/geom/impl/CoordinateArraySequenceFactory.java
@@ -0,0 +1,92 @@
+
+/*
+* The JTS Topology Suite is a collection of Java classes that
+* implement the fundamental operations required to validate a given
+* geo-spatial data set to a known topological specification.
+*
+* Copyright (C) 2001 Vivid Solutions
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*
+* For more information, contact:
+*
+*     Vivid Solutions
+*     Suite #1A
+*     2328 Government Street
+*     Victoria BC  V8T 5G5
+*     Canada
+*
+*     (250)385-6040
+*     www.vividsolutions.com
+ */
+package com.vividsolutions.jts.geom.impl;
+
+import java.io.Serializable;
+import com.vividsolutions.jts.geom.*;
+
+/**
+ * Creates CoordinateSequences represented as an array of {@link Coordinate}s.
+ *
+ * @version 1.6
+ */
+public final class CoordinateArraySequenceFactory
+    implements CoordinateSequenceFactory, Serializable
+{
+  private static final long serialVersionUID = -4099577099607551657L;
+  private static CoordinateArraySequenceFactory instance = new CoordinateArraySequenceFactory();
+
+  private CoordinateArraySequenceFactory() {
+  }
+
+  /**
+   * @see http://www.javaworld.com/javaworld/javatips/jw-javatip122.html
+   */
+  private Object readResolve() {
+    return CoordinateArraySequenceFactory.instance();
+  }
+
+  /**
+   * Returns the singleton instance of {@link CoordinateArraySequenceFactory}
+   */
+  public static CoordinateArraySequenceFactory instance() {
+    return instance;
+  }
+
+  /**
+   * Returns a {@link CoordinateArraySequence} based on the given array (the array is
+   * not copied).
+   *
+   * @param coordinates
+   *            the coordinates, which may not be null nor contain null
+   *            elements
+   */
+  public CoordinateSequence create(Coordinate[] coordinates) {
+    return new CoordinateArraySequence(coordinates);
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(com.vividsolutions.jts.geom.CoordinateSequence)
+   */
+  public CoordinateSequence create(CoordinateSequence coordSeq) {
+    return new CoordinateArraySequence(coordSeq);
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(int, int)
+   */
+  public CoordinateSequence create(int size, int dimension) {
+    return new CoordinateArraySequence(size);
+  }
+}
diff --git a/src/com/vividsolutions/jts/geom/impl/PackedCoordinateSequence.java b/src/com/vividsolutions/jts/geom/impl/PackedCoordinateSequence.java
new file mode 100644
index 0000000..ecab30e
--- /dev/null
+++ b/src/com/vividsolutions/jts/geom/impl/PackedCoordinateSequence.java
@@ -0,0 +1,435 @@
+package com.vividsolutions.jts.geom.impl;
+
+import com.vividsolutions.jts.geom.*;
+
+import java.lang.ref.SoftReference;
+
+/**
+ * A {@link CoordinateSequence} implementation based on a packed arrays.
+ * In this implementation, {@link Coordinate}s returned by #toArray and #get are copies
+ * of the internal values.
+ * To change the actual values, use the provided setters.
+ * <p>
+ * For efficiency, created Coordinate arrays
+ * are cached using a soft reference.
+ * The cache is cleared each time the coordinate sequence contents are
+ * modified through a setter method.
+ *
+ * @version 1.6
+ */
+public abstract class PackedCoordinateSequence
+    implements CoordinateSequence
+{
+  /**
+   * The dimensions of the coordinates hold in the packed array
+   */
+  protected int dimension;
+
+  /**
+   * A soft reference to the Coordinate[] representation of this sequence.
+   * Makes repeated coordinate array accesses more efficient.
+   */
+  protected SoftReference coordRef;
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getDimension()
+   */
+  public int getDimension() {
+    return this.dimension;
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinate(int)
+   */
+  public Coordinate getCoordinate(int i) {
+    Coordinate[] coords = getCachedCoords();
+    if(coords != null)
+      return coords[i];
+    else
+      return getCoordinateInternal(i);
+  }
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinate(int)
+   */
+  public Coordinate getCoordinateCopy(int i) {
+    return getCoordinateInternal(i);
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinate(int)
+   */
+  public void getCoordinate(int i, Coordinate coord) {
+    coord.x = getOrdinate(i, 0);
+    coord.y = getOrdinate(i, 1);
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#toCoordinateArray()
+   */
+  public Coordinate[] toCoordinateArray() {
+    Coordinate[] coords = getCachedCoords();
+// testing - never cache
+    if (coords != null)
+      return coords;
+
+    coords = new Coordinate[size()];
+    for (int i = 0; i < coords.length; i++) {
+      coords[i] = getCoordinateInternal(i);
+    }
+    coordRef = new SoftReference(coords);
+
+    return coords;
+  }
+
+  /**
+   * @return
+   */
+  private Coordinate[] getCachedCoords() {
+    if (coordRef != null) {
+      Coordinate[] coords = (Coordinate[]) coordRef.get();
+      if (coords != null) {
+        return coords;
+      } else {
+        // System.out.print("-");
+        coordRef = null;
+        return null;
+      }
+    } else {
+      // System.out.print("-");
+      return null;
+    }
+
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int)
+   */
+  public double getX(int index) {
+    return getOrdinate(index, 0);
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getY(int)
+   */
+  public double getY(int index) {
+    return getOrdinate(index, 1);
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int, int)
+   */
+  public abstract double getOrdinate(int index, int ordinateIndex);
+
+  /**
+   * Sets the first ordinate of a coordinate in this sequence.
+   *
+   * @param index  the coordinate index
+   * @param value  the new ordinate value
+   */
+  public void setX(int index, double value) {
+    coordRef = null;
+    setOrdinate(index, 0, value);
+  }
+
+  /**
+   * Sets the second ordinate of a coordinate in this sequence.
+   *
+   * @param index  the coordinate index
+   * @param value  the new ordinate value
+   */
+  public void setY(int index, double value) {
+    coordRef = null;
+    setOrdinate(index, 1, value);
+  }
+
+  /**
+   * Returns a Coordinate representation of the specified coordinate, by always
+   * building a new Coordinate object
+   *
+   * @param index
+   * @return
+   */
+  protected abstract Coordinate getCoordinateInternal(int index);
+
+  /**
+   * @see java.lang.Object#clone()
+   */
+  public abstract Object clone();
+
+  /**
+   * Sets the ordinate of a coordinate in this sequence.
+   * <br>
+   * Warning: for performance reasons the ordinate index is not checked
+   * - if it is over dimensions you may not get an exception but a meaningless value.
+   *
+   * @param index
+   *          the coordinate index
+   * @param ordinate
+   *          the ordinate index in the coordinate, 0 based, smaller than the
+   *          number of dimensions
+   * @param value
+   *          the new ordinate value
+   */
+  public abstract void setOrdinate(int index, int ordinate, double value);
+
+  /**
+   * Packed coordinate sequence implementation based on doubles
+   */
+  public static class Double extends PackedCoordinateSequence {
+
+    /**
+     * The packed coordinate array
+     */
+    double[] coords;
+
+    /**
+     * Builds a new packed coordinate sequence
+     *
+     * @param coords
+     * @param dimensions
+     */
+    public Double(double[] coords, int dimensions) {
+      if (dimensions < 2) {
+        throw new IllegalArgumentException("Must have at least 2 dimensions");
+      }
+      if (coords.length % dimensions != 0) {
+        throw new IllegalArgumentException("Packed array does not contain "
+            + "an integral number of coordinates");
+      }
+      this.dimension = dimensions;
+      this.coords = coords;
+    }
+
+    /**
+     * Builds a new packed coordinate sequence out of a float coordinate array
+     *
+     * @param coordinates
+     */
+    public Double(float[] coordinates, int dimensions) {
+      this.coords = new double[coordinates.length];
+      this.dimension = dimensions;
+      for (int i = 0; i < coordinates.length; i++) {
+        this.coords[i] = coordinates[i];
+      }
+    }
+
+    /**
+     * Builds a new packed coordinate sequence out of a coordinate array
+     *
+     * @param coordinates
+     */
+    public Double(Coordinate[] coordinates, int dimension) {
+      if (coordinates == null)
+        coordinates = new Coordinate[0];
+      this.dimension = dimension;
+
+      coords = new double[coordinates.length * this.dimension];
+      for (int i = 0; i < coordinates.length; i++) {
+        coords[i * this.dimension] = coordinates[i].x;
+        if (this.dimension >= 2)
+          coords[i * this.dimension + 1] = coordinates[i].y;
+        if (this.dimension >= 3)
+          coords[i * this.dimension + 2] = coordinates[i].z;
+      }
+    }
+    /**
+     * Builds a new packed coordinate sequence out of a coordinate array
+     *
+     * @param coordinates
+     */
+    public Double(Coordinate[] coordinates) {
+      this(coordinates, 3);
+    }
+
+    /**
+     * Builds a new empty packed coordinate sequence of a given size and dimension
+     *
+     * @param coordinates
+     */
+    public Double(int size, int dimension) {
+      this.dimension = dimension;
+      coords = new double[size * this.dimension];
+    }
+
+    /**
+     * @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinate(int)
+     */
+    public Coordinate getCoordinateInternal(int i) {
+      double x = coords[i * dimension];
+      double y = coords[i * dimension + 1];
+      double z = dimension == 2 ? 0.0 : coords[i * dimension + 2];
+      return new Coordinate(x, y, z);
+    }
+
+    /**
+     * @see com.vividsolutions.jts.geom.CoordinateSequence#size()
+     */
+    public int size() {
+      return coords.length / dimension;
+    }
+
+    /**
+     * @see java.lang.Object#clone()
+     */
+    public Object clone() {
+      double[] clone = new double[coords.length];
+      System.arraycopy(coords, 0, clone, 0, coords.length);
+      return new Double(clone, dimension);
+    }
+
+    /**
+     * @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int, int)
+     *      Beware, for performace reasons the ordinate index is not checked, if
+     *      it's over dimensions you may not get an exception but a meaningless
+     *      value.
+     */
+    public double getOrdinate(int index, int ordinate) {
+      return coords[index * dimension + ordinate];
+    }
+
+    /**
+     * @see com.vividsolutions.jts.geom.PackedCoordinateSequence#setOrdinate(int,
+     *      int, double)
+     */
+    public void setOrdinate(int index, int ordinate, double value) {
+      coordRef = null;
+      coords[index * dimension + ordinate] = value;
+    }
+
+    public Envelope expandEnvelope(Envelope env)
+    {
+      for (int i = 0; i < coords.length; i += dimension ) {
+        env.expandToInclude(coords[i], coords[i + 1]);
+      }
+      return env;
+    }
+  }
+
+  /**
+   * Packed coordinate sequence implementation based on floats
+   */
+  public static class Float extends PackedCoordinateSequence {
+
+    /**
+     * The packed coordinate array
+     */
+    float[] coords;
+
+    /**
+     * Constructs a packed coordinate sequence from an array of <code>float<code>s
+     *
+     * @param coords
+     * @param dimensions
+     */
+    public Float(float[] coords, int dimensions) {
+      if (dimensions < 2) {
+        throw new IllegalArgumentException("Must have at least 2 dimensions");
+      }
+      if (coords.length % dimensions != 0) {
+        throw new IllegalArgumentException("Packed array does not contain "
+            + "an integral number of coordinates");
+      }
+      this.dimension = dimensions;
+      this.coords = coords;
+    }
+
+    /**
+     * Constructs a packed coordinate sequence from an array of <code>double<code>s
+     *
+     * @param coordinates
+     * @param dimension
+     */
+    public Float(double[] coordinates, int dimensions) {
+      this.coords = new float[coordinates.length];
+      this.dimension = dimensions;
+      for (int i = 0; i < coordinates.length; i++) {
+        this.coords[i] = (float) coordinates[i];
+      }
+    }
+
+    /**
+     * Constructs a packed coordinate sequence out of a coordinate array
+     *
+     * @param coordinates
+     */
+    public Float(Coordinate[] coordinates, int dimension) {
+      if (coordinates == null)
+        coordinates = new Coordinate[0];
+      this.dimension = dimension;
+
+      coords = new float[coordinates.length * this.dimension];
+      for (int i = 0; i < coordinates.length; i++) {
+        coords[i * this.dimension] = (float) coordinates[i].x;
+        if (this.dimension >= 2)
+          coords[i * this.dimension + 1] = (float) coordinates[i].y;
+        if (this.dimension >= 3)
+          coords[i * this.dimension + 2] = (float) coordinates[i].z;
+      }
+    }
+
+    /**
+     * Constructs an empty packed coordinate sequence of a given size and dimension
+     *
+     * @param coordinates
+     */
+    public Float(int size, int dimension) {
+      this.dimension = dimension;
+      coords = new float[size * this.dimension];
+    }
+
+    /**
+     * @see com.vividsolutions.jts.geom.CoordinateSequence#getCoordinate(int)
+     */
+    public Coordinate getCoordinateInternal(int i) {
+      double x = coords[i * dimension];
+      double y = coords[i * dimension + 1];
+      double z = dimension == 2 ? 0.0 : coords[i * dimension + 2];
+      return new Coordinate(x, y, z);
+    }
+
+    /**
+     * @see com.vividsolutions.jts.geom.CoordinateSequence#size()
+     */
+    public int size() {
+      return coords.length / dimension;
+    }
+
+    /**
+     * @see java.lang.Object#clone()
+     */
+    public Object clone() {
+      float[] clone = new float[coords.length];
+      System.arraycopy(coords, 0, clone, 0, coords.length);
+      return new Float(clone, dimension);
+    }
+
+    /**
+     * @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int, int)
+     *      Beware, for performace reasons the ordinate index is not checked, if
+     *      it's over dimensions you may not get an exception but a meaningless
+     *      value.
+     */
+    public double getOrdinate(int index, int ordinate) {
+      return coords[index * dimension + ordinate];
+    }
+
+    /**
+     * @see com.vividsolutions.jts.geom.PackedCoordinateSequence#setOrdinate(int,
+     *      int, double)
+     */
+    public void setOrdinate(int index, int ordinate, double value) {
+      coordRef = null;
+      coords[index * dimension + ordinate] = (float) value;
+    }
+
+    public Envelope expandEnvelope(Envelope env)
+    {
+      for (int i = 0; i < coords.length; i += dimension ) {
+        env.expandToInclude(coords[i], coords[i + 1]);
+      }
+      return env;
+    }
+
+  }
+
+}
diff --git a/src/com/vividsolutions/jts/geom/impl/PackedCoordinateSequenceFactory.java b/src/com/vividsolutions/jts/geom/impl/PackedCoordinateSequenceFactory.java
new file mode 100644
index 0000000..bab987d
--- /dev/null
+++ b/src/com/vividsolutions/jts/geom/impl/PackedCoordinateSequenceFactory.java
@@ -0,0 +1,137 @@
+package com.vividsolutions.jts.geom.impl;
+
+import com.vividsolutions.jts.geom.*;
+
+/**
+ * Builds packed array coordinate sequences. The array data type can be either
+ * double or float, and defaults to float.
+ */
+public class PackedCoordinateSequenceFactory implements
+    CoordinateSequenceFactory
+{
+  public static final int DOUBLE = 0;
+  public static final int FLOAT = 1;
+
+  public static final PackedCoordinateSequenceFactory DOUBLE_FACTORY =
+      new PackedCoordinateSequenceFactory(DOUBLE);
+  public static final PackedCoordinateSequenceFactory FLOAT_FACTORY =
+      new PackedCoordinateSequenceFactory(FLOAT);
+
+  private int type = DOUBLE;
+  private int dimension = 3;
+
+  /**
+   * Creates a new PackedCoordinateSequenceFactory
+   * of type DOUBLE.
+   */
+  public PackedCoordinateSequenceFactory()
+  {
+    this(DOUBLE);
+  }
+
+  /**
+   * Creates a new PackedCoordinateSequenceFactory
+   * of the given type.
+   * Acceptable type values are
+   * {@linkplain PackedCoordinateSequenceFactory#Float}or
+   * {@linkplain PackedCoordinateSequenceFactory#Double}
+   */
+  public PackedCoordinateSequenceFactory(int type)
+  {
+    this(type, 3);
+  }
+  /**
+   * Creates a new PackedCoordinateSequenceFactory
+   * of the given type.
+   * Acceptable type values are
+   * {@linkplain PackedCoordinateSequenceFactory#FLOAT}or
+   * {@linkplain PackedCoordinateSequenceFactory#DOUBLE}
+   */
+  public PackedCoordinateSequenceFactory(int type, int dimension)
+  {
+    setType(type);
+    setDimension(dimension);
+  }
+
+  /**
+   * Returns the type of packed coordinate sequences this factory builds, either
+   * {@linkplain PackedCoordinateSequenceFactory#Float} or
+   * {@linkplain PackedCoordinateSequenceFactory#Double}
+   */
+  public int getType() {
+    return type;
+  }
+
+  /**
+   * Sets the type of packed coordinate sequences this factory builds,
+   * acceptable values are {@linkplain PackedCoordinateSequenceFactory#Float}or
+   * {@linkplain PackedCoordinateSequenceFactory#Double}
+   */
+  public void setType(int type) {
+    if (type != DOUBLE && type != FLOAT)
+      throw new IllegalArgumentException("Unknown type " + type);
+    this.type = type;
+  }
+
+
+  public int getDimension() { return dimension; }
+
+  public void setDimension(int dimension) { this.dimension = dimension; }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(com.vividsolutions.jts.geom.Coordinate[])
+   */
+  public CoordinateSequence create(Coordinate[] coordinates) {
+    if (type == DOUBLE) {
+      return new PackedCoordinateSequence.Double(coordinates, dimension);
+    } else {
+      return new PackedCoordinateSequence.Float(coordinates, dimension);
+    }
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(com.vividsolutions.jts.geom.CoordinateSequence)
+   */
+  public CoordinateSequence create(CoordinateSequence coordSeq) {
+    if (type == DOUBLE) {
+      return new PackedCoordinateSequence.Double(coordSeq.toCoordinateArray(), dimension);
+    } else {
+      return new PackedCoordinateSequence.Float(coordSeq.toCoordinateArray(), dimension);
+    }
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(double[],
+   *      int)
+   */
+  public CoordinateSequence create(double[] packedCoordinates, int dimension) {
+    if (type == DOUBLE) {
+      return new PackedCoordinateSequence.Double(packedCoordinates, dimension);
+    } else {
+      return new PackedCoordinateSequence.Float(packedCoordinates, dimension);
+    }
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(float[],
+   *      int)
+   */
+  public CoordinateSequence create(float[] packedCoordinates, int dimension) {
+    if (type == DOUBLE) {
+      return new PackedCoordinateSequence.Double(packedCoordinates, dimension);
+    } else {
+      return new PackedCoordinateSequence.Float(packedCoordinates, dimension);
+    }
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(int, int)
+   */
+  public CoordinateSequence create(int size, int dimension) {
+    if (type == DOUBLE) {
+      return new PackedCoordinateSequence.Double(size, dimension);
+    } else {
+      return new PackedCoordinateSequence.Float(size, dimension);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/com/vividsolutions/jts/geom/util/GeometryEditor.java b/src/com/vividsolutions/jts/geom/util/GeometryEditor.java
index 068a3f8..312b1ca 100644
--- a/src/com/vividsolutions/jts/geom/util/GeometryEditor.java
+++ b/src/com/vividsolutions/jts/geom/util/GeometryEditor.java
@@ -67,7 +67,7 @@ import java.util.ArrayList;
  *
  * @see Geometry#isValid
  *
- * @version 1.5
+ * @version 1.6
  */
 public class GeometryEditor
 {
@@ -205,7 +205,7 @@ public class GeometryEditor
   /**
    * A interface which specifies an edit operation for Geometries.
    *
-   * @version 1.5
+   * @version 1.6
    */
   public interface GeometryEditorOperation
   {
diff --git a/src/com/vividsolutions/jts/geom/util/GeometryTransformer.java b/src/com/vividsolutions/jts/geom/util/GeometryTransformer.java
index cff39af..fe73375 100644
--- a/src/com/vividsolutions/jts/geom/util/GeometryTransformer.java
+++ b/src/com/vividsolutions/jts/geom/util/GeometryTransformer.java
@@ -31,7 +31,7 @@ import com.vividsolutions.jts.geom.*;
  * The @link transform} method itself will always
  * return a geometry object.
  *
- * @version 1.5
+ * @version 1.6
  *
  * @see GeometryEditor
  */
@@ -84,7 +84,7 @@ public class GeometryTransformer {
     if (inputGeom instanceof MultiPoint)
       return transformMultiPoint((MultiPoint) inputGeom, null);
     if (inputGeom instanceof LinearRing)
-      return transformLineString((LinearRing) inputGeom, null);
+      return transformLinearRing((LinearRing) inputGeom, null);
     if (inputGeom instanceof LineString)
       return transformLineString((LineString) inputGeom, null);
     if (inputGeom instanceof MultiLineString)
diff --git a/src/com/vividsolutions/jts/geom/util/LinearComponentExtracter.java b/src/com/vividsolutions/jts/geom/util/LinearComponentExtracter.java
index e4c4dab..5acd25c 100644
--- a/src/com/vividsolutions/jts/geom/util/LinearComponentExtracter.java
+++ b/src/com/vividsolutions/jts/geom/util/LinearComponentExtracter.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.geom.*;
 /**
  * Extracts all the 1-dimensional ({@link LineString}) components from a {@link Geometry}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class LinearComponentExtracter
   implements GeometryComponentFilter
diff --git a/src/com/vividsolutions/jts/geom/util/PointExtracter.java b/src/com/vividsolutions/jts/geom/util/PointExtracter.java
index 27428c6..fd734a0 100644
--- a/src/com/vividsolutions/jts/geom/util/PointExtracter.java
+++ b/src/com/vividsolutions/jts/geom/util/PointExtracter.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.geom.*;
 /**
  * Extracts all the 0-dimensional ({@link Point}) components from a {@link Geometry}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class PointExtracter
   implements GeometryFilter
diff --git a/src/com/vividsolutions/jts/geom/util/PolygonExtracter.java b/src/com/vividsolutions/jts/geom/util/PolygonExtracter.java
index 3240789..e01bff9 100644
--- a/src/com/vividsolutions/jts/geom/util/PolygonExtracter.java
+++ b/src/com/vividsolutions/jts/geom/util/PolygonExtracter.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.geom.*;
 /**
  * Extracts all the 2-dimensional ({@link Polygon}) components from a {@link Geometry}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class PolygonExtracter
   implements GeometryFilter
diff --git a/src/com/vividsolutions/jts/geom/util/ShortCircuitedGeometryVisitor.java b/src/com/vividsolutions/jts/geom/util/ShortCircuitedGeometryVisitor.java
new file mode 100644
index 0000000..2b5f845
--- /dev/null
+++ b/src/com/vividsolutions/jts/geom/util/ShortCircuitedGeometryVisitor.java
@@ -0,0 +1,36 @@
+package com.vividsolutions.jts.geom.util;
+
+import com.vividsolutions.jts.geom.*;
+
+/**
+ * A visitor to {@link Geometry} elements which can
+ * be short-circuited by a given condition
+ *
+ * @version 1.6
+ */
+public abstract class ShortCircuitedGeometryVisitor
+{
+  private boolean isDone = false;
+
+  public ShortCircuitedGeometryVisitor() {
+  }
+
+  public void applyTo(Geometry geom) {
+    for (int i = 0; i < geom.getNumGeometries() && ! isDone; i++) {
+      Geometry element = geom.getGeometryN(i);
+      if (! (element instanceof GeometryCollection)) {
+        visit(element);
+        if (isDone()) {
+          isDone = true;
+          return;
+        }
+      }
+      else
+        applyTo(element);
+    }
+  }
+
+  protected abstract void visit(Geometry element);
+
+  protected abstract boolean isDone();
+}
diff --git a/src/com/vividsolutions/jts/geomgraph/Depth.java b/src/com/vividsolutions/jts/geomgraph/Depth.java
index 00421c1..9db637a 100644
--- a/src/com/vividsolutions/jts/geomgraph/Depth.java
+++ b/src/com/vividsolutions/jts/geomgraph/Depth.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.geom.Location;
 /**
  * A Depth object records the topological depth of the sides
  * of an Edge for up to two Geometries.
- * @version 1.5
+ * @version 1.6
  */
 public class Depth {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/DirectedEdge.java b/src/com/vividsolutions/jts/geomgraph/DirectedEdge.java
index 1d921f5..69ad216 100644
--- a/src/com/vividsolutions/jts/geomgraph/DirectedEdge.java
+++ b/src/com/vividsolutions/jts/geomgraph/DirectedEdge.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.geom.*;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class DirectedEdge
   extends EdgeEnd
@@ -216,22 +216,6 @@ public class DirectedEdge
     setDepth(position, depth);
     setDepth(oppositePos, oppositeDepth);
   }
-  /**
-   * Set both edge depths.  One depth for a given side is provided.  The other is
-   * computed depending on the Location transition and the depthDelta of the edge.
-   */
-  public void OLDsetEdgeDepths(int position, int depth)
-  {
-    int depthDelta = getEdge().getDepthDelta();
-    int loc = label.getLocation(0, position);
-    int oppositePos = Position.opposite(position);
-    int oppositeLoc = label.getLocation(0, oppositePos);
-    int delta = Math.abs(depthDelta) * DirectedEdge.depthFactor(loc, oppositeLoc);
-    //TESTINGint delta = depthDelta * DirectedEdge.depthFactor(loc, oppositeLoc);
-    int oppositeDepth = depth + delta;
-    setDepth(position, depth);
-    setDepth(oppositePos, oppositeDepth);
-  }
 
   public void print(PrintStream out)
   {
diff --git a/src/com/vividsolutions/jts/geomgraph/DirectedEdgeStar.java b/src/com/vividsolutions/jts/geomgraph/DirectedEdgeStar.java
index 73f5fa5..c4e9b65 100644
--- a/src/com/vividsolutions/jts/geomgraph/DirectedEdgeStar.java
+++ b/src/com/vividsolutions/jts/geomgraph/DirectedEdgeStar.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.util.*;
  * It supports labelling the edges as well as linking the edges to form both
  * MaximalEdgeRings and MinimalEdgeRings.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class DirectedEdgeStar
   extends EdgeEndStar
diff --git a/src/com/vividsolutions/jts/geomgraph/Edge.java b/src/com/vividsolutions/jts/geomgraph/Edge.java
index 98f03ab..1283137 100644
--- a/src/com/vividsolutions/jts/geomgraph/Edge.java
+++ b/src/com/vividsolutions/jts/geomgraph/Edge.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.geomgraph.index.*;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class Edge
   extends GraphComponent
diff --git a/src/com/vividsolutions/jts/geomgraph/EdgeEnd.java b/src/com/vividsolutions/jts/geomgraph/EdgeEnd.java
index 83b060b..37c444e 100644
--- a/src/com/vividsolutions/jts/geomgraph/EdgeEnd.java
+++ b/src/com/vividsolutions/jts/geomgraph/EdgeEnd.java
@@ -50,7 +50,7 @@ import com.vividsolutions.jts.geomgraph.Edge;
  * EdgeEnds are comparable under the ordering
  * "a has a greater angle with the x-axis than b".
  * This ordering is used to sort EdgeEnds around a node.
- * @version 1.5
+ * @version 1.6
  */
 public class EdgeEnd
   implements Comparable
diff --git a/src/com/vividsolutions/jts/geomgraph/EdgeEndStar.java b/src/com/vividsolutions/jts/geomgraph/EdgeEndStar.java
index d62189e..0be6378 100644
--- a/src/com/vividsolutions/jts/geomgraph/EdgeEndStar.java
+++ b/src/com/vividsolutions/jts/geomgraph/EdgeEndStar.java
@@ -46,7 +46,7 @@ import com.vividsolutions.jts.util.*;
  * They are maintained in CCW order (starting with the positive x-axis) around the node
  * for efficient lookup and topology building.
  *
- * @version 1.5
+ * @version 1.6
  */
 abstract public class EdgeEndStar
 {
diff --git a/src/com/vividsolutions/jts/geomgraph/EdgeIntersection.java b/src/com/vividsolutions/jts/geomgraph/EdgeIntersection.java
index afecd8f..0d50883 100644
--- a/src/com/vividsolutions/jts/geomgraph/EdgeIntersection.java
+++ b/src/com/vividsolutions/jts/geomgraph/EdgeIntersection.java
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.geom.Coordinate;
  * the edge from this point forwards, until the next
  * intersection or the end of the edge.
  * The intersection point must be precise.
- * @version 1.5
+ * @version 1.6
  */
 public class EdgeIntersection
     implements Comparable
diff --git a/src/com/vividsolutions/jts/geomgraph/EdgeIntersectionList.java b/src/com/vividsolutions/jts/geomgraph/EdgeIntersectionList.java
index d7887bb..1791abc 100644
--- a/src/com/vividsolutions/jts/geomgraph/EdgeIntersectionList.java
+++ b/src/com/vividsolutions/jts/geomgraph/EdgeIntersectionList.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.util.Debug;
 
 /**
  * A list of edge intersections along an Edge
- * @version 1.5
+ * @version 1.6
  */
 public class EdgeIntersectionList
 {
diff --git a/src/com/vividsolutions/jts/geomgraph/EdgeList.java b/src/com/vividsolutions/jts/geomgraph/EdgeList.java
index 9196686..dbdb3b9 100644
--- a/src/com/vividsolutions/jts/geomgraph/EdgeList.java
+++ b/src/com/vividsolutions/jts/geomgraph/EdgeList.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.index.quadtree.Quadtree;
 /**
  * A EdgeList is a list of Edges.  It supports locating edges
  * that are pointwise equals to a target edge.
- * @version 1.5
+ * @version 1.6
  */
 public class EdgeList
 {
diff --git a/src/com/vividsolutions/jts/geomgraph/EdgeNodingValidator.java b/src/com/vividsolutions/jts/geomgraph/EdgeNodingValidator.java
index 66e4270..a7ae4f5 100644
--- a/src/com/vividsolutions/jts/geomgraph/EdgeNodingValidator.java
+++ b/src/com/vividsolutions/jts/geomgraph/EdgeNodingValidator.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.noding.*;
  * Validates that a collection of SegmentStrings is correctly noded.
  * Throws an appropriate exception if an noding error is found.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class EdgeNodingValidator {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/EdgeRing.java b/src/com/vividsolutions/jts/geomgraph/EdgeRing.java
index 59ddd83..f20d6e9 100644
--- a/src/com/vividsolutions/jts/geomgraph/EdgeRing.java
+++ b/src/com/vividsolutions/jts/geomgraph/EdgeRing.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.util.Assert;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public abstract class EdgeRing {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/GeometryGraph.java b/src/com/vividsolutions/jts/geomgraph/GeometryGraph.java
index ed630a3..285e8d5 100644
--- a/src/com/vividsolutions/jts/geomgraph/GeometryGraph.java
+++ b/src/com/vividsolutions/jts/geomgraph/GeometryGraph.java
@@ -43,7 +43,7 @@ import com.vividsolutions.jts.util.*;
 
 /**
  * A GeometryGraph is a graph that models a given Geometry
- * @version 1.5
+ * @version 1.6
  */
 public class GeometryGraph
   extends PlanarGraph
diff --git a/src/com/vividsolutions/jts/geomgraph/GraphComponent.java b/src/com/vividsolutions/jts/geomgraph/GraphComponent.java
index 16e500e..bd0a026 100644
--- a/src/com/vividsolutions/jts/geomgraph/GraphComponent.java
+++ b/src/com/vividsolutions/jts/geomgraph/GraphComponent.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.util.Assert;
  * A GraphComponent is the parent class for the objects'
  * that form a graph.  Each GraphComponent can carry a
  * Label.
- * @version 1.5
+ * @version 1.6
  */
 abstract public class GraphComponent {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/Label.java b/src/com/vividsolutions/jts/geomgraph/Label.java
index 2a90a96..7b59f23 100644
--- a/src/com/vividsolutions/jts/geomgraph/Label.java
+++ b/src/com/vividsolutions/jts/geomgraph/Label.java
@@ -58,7 +58,7 @@ import com.vividsolutions.jts.geom.Location;
  * <P>
  * It is up to the client code to associate the 0 and 1 <code>TopologyLocation</code>s
  * with specific geometries.
- * @version 1.5
+ * @version 1.6
  *
  */
 public class Label {
diff --git a/src/com/vividsolutions/jts/geomgraph/Node.java b/src/com/vividsolutions/jts/geomgraph/Node.java
index ca5a1a5..2e7f296 100644
--- a/src/com/vividsolutions/jts/geomgraph/Node.java
+++ b/src/com/vividsolutions/jts/geomgraph/Node.java
@@ -46,7 +46,7 @@ import com.vividsolutions.jts.util.*;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class Node
   extends GraphComponent
diff --git a/src/com/vividsolutions/jts/geomgraph/NodeFactory.java b/src/com/vividsolutions/jts/geomgraph/NodeFactory.java
index 125df54..b717b2a 100644
--- a/src/com/vividsolutions/jts/geomgraph/NodeFactory.java
+++ b/src/com/vividsolutions/jts/geomgraph/NodeFactory.java
@@ -37,7 +37,7 @@ import com.vividsolutions.jts.geom.Coordinate;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class NodeFactory {
 /**
diff --git a/src/com/vividsolutions/jts/geomgraph/NodeMap.java b/src/com/vividsolutions/jts/geomgraph/NodeMap.java
index ad9b923..c1f87a4 100644
--- a/src/com/vividsolutions/jts/geomgraph/NodeMap.java
+++ b/src/com/vividsolutions/jts/geomgraph/NodeMap.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.geomgraph.Node;
 
 /**
  * A map of nodes, indexed by the coordinate of the node
- * @version 1.5
+ * @version 1.6
  */
 public class NodeMap
 
diff --git a/src/com/vividsolutions/jts/geomgraph/PlanarGraph.java b/src/com/vividsolutions/jts/geomgraph/PlanarGraph.java
index ef5dc13..b65d5c3 100644
--- a/src/com/vividsolutions/jts/geomgraph/PlanarGraph.java
+++ b/src/com/vividsolutions/jts/geomgraph/PlanarGraph.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.geomgraph;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import java.io.PrintStream;
 import java.util.*;
@@ -61,7 +61,7 @@ import com.vividsolutions.jts.geom.*;
  *   <LI>Computing the intersections between the edges and nodes of two different graphs
  * </UL>
  *
- * @version 1.5
+ * @version 1.6
  */
 public class PlanarGraph {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/Position.java b/src/com/vividsolutions/jts/geomgraph/Position.java
index 02cf232..655566b 100644
--- a/src/com/vividsolutions/jts/geomgraph/Position.java
+++ b/src/com/vividsolutions/jts/geomgraph/Position.java
@@ -38,7 +38,7 @@ package com.vividsolutions.jts.geomgraph;
 /**
  * A Position indicates the position of a Location relative to a graph component
  * (Node, Edge, or Area).
- * @version 1.5
+ * @version 1.6
  */
 public class Position {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/Quadrant.java b/src/com/vividsolutions/jts/geomgraph/Quadrant.java
index a3d77c3..8593c4c 100644
--- a/src/com/vividsolutions/jts/geomgraph/Quadrant.java
+++ b/src/com/vividsolutions/jts/geomgraph/Quadrant.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.geomgraph;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import com.vividsolutions.jts.geom.Coordinate;
 
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.geom.Coordinate;
  * 2 | 3
  * <pre>
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Quadrant {
   /**
diff --git a/src/com/vividsolutions/jts/geomgraph/TopologyLocation.java b/src/com/vividsolutions/jts/geomgraph/TopologyLocation.java
index 8d60265..89ff3d3 100644
--- a/src/com/vividsolutions/jts/geomgraph/TopologyLocation.java
+++ b/src/com/vividsolutions/jts/geomgraph/TopologyLocation.java
@@ -59,7 +59,7 @@ import com.vividsolutions.jts.geom.Location;
   * <p>
   * The labelling is stored in an array location[j] where
   * where j has the values ON, LEFT, RIGHT
-  * @version 1.5
+  * @version 1.6
  */
 public class TopologyLocation {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/index/EdgeSetIntersector.java b/src/com/vividsolutions/jts/geomgraph/index/EdgeSetIntersector.java
index 172c49f..ffcbe32 100644
--- a/src/com/vividsolutions/jts/geomgraph/index/EdgeSetIntersector.java
+++ b/src/com/vividsolutions/jts/geomgraph/index/EdgeSetIntersector.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.geomgraph.index;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import java.util.*;
 import com.vividsolutions.jts.geomgraph.*;
@@ -52,7 +52,7 @@ import com.vividsolutions.jts.geomgraph.*;
  * It uses a {@link SegmentIntersector} to compute the intersections between
  * segments and to record statistics about what kinds of intersections were found.
  *
- * @version 1.5
+ * @version 1.6
  */
 public abstract class EdgeSetIntersector {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/index/MonotoneChain.java b/src/com/vividsolutions/jts/geomgraph/index/MonotoneChain.java
index 7510226..b7ca2e5 100644
--- a/src/com/vividsolutions/jts/geomgraph/index/MonotoneChain.java
+++ b/src/com/vividsolutions/jts/geomgraph/index/MonotoneChain.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.geomgraph.index;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class MonotoneChain {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainEdge.java b/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainEdge.java
index 5778eb7..121a20c 100644
--- a/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainEdge.java
+++ b/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainEdge.java
@@ -57,7 +57,7 @@ import com.vividsolutions.jts.util.Debug;
  * binary search to be used to find the intersection points of two monotone chains.
  * For many types of real-world data, these properties eliminate a large number of
  * segment comparisons, producing substantial speed gains.
- * @version 1.5
+ * @version 1.6
  */
 public class MonotoneChainEdge {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainIndexer.java b/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainIndexer.java
index 1825255..0153549 100644
--- a/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainIndexer.java
+++ b/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainIndexer.java
@@ -55,7 +55,7 @@ import com.vividsolutions.jts.geomgraph.Quadrant;
  * For many types of real-world data, these properties eliminate a large number of
  * segment comparisons, producing substantial speed gains.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class MonotoneChainIndexer {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/index/SegmentIntersector.java b/src/com/vividsolutions/jts/geomgraph/index/SegmentIntersector.java
index edeb5c1..3247202 100644
--- a/src/com/vividsolutions/jts/geomgraph/index/SegmentIntersector.java
+++ b/src/com/vividsolutions/jts/geomgraph/index/SegmentIntersector.java
@@ -43,7 +43,7 @@ import com.vividsolutions.jts.util.Debug;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class SegmentIntersector {
 
diff --git a/src/com/vividsolutions/jts/geomgraph/index/SimpleEdgeSetIntersector.java b/src/com/vividsolutions/jts/geomgraph/index/SimpleEdgeSetIntersector.java
index 21bef44..ff452dd 100644
--- a/src/com/vividsolutions/jts/geomgraph/index/SimpleEdgeSetIntersector.java
+++ b/src/com/vividsolutions/jts/geomgraph/index/SimpleEdgeSetIntersector.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.geomgraph.*;
  * using the straightforward method of
  * comparing all segments.
  * This algorithm is too slow for production use, but is useful for testing purposes.
- * @version 1.5
+ * @version 1.6
  */
 public class SimpleEdgeSetIntersector
   extends EdgeSetIntersector
diff --git a/src/com/vividsolutions/jts/geomgraph/index/SimpleMCSweepLineIntersector.java b/src/com/vividsolutions/jts/geomgraph/index/SimpleMCSweepLineIntersector.java
index 8be527f..bd110ec 100644
--- a/src/com/vividsolutions/jts/geomgraph/index/SimpleMCSweepLineIntersector.java
+++ b/src/com/vividsolutions/jts/geomgraph/index/SimpleMCSweepLineIntersector.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.geomgraph.index;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import java.util.*;
 import com.vividsolutions.jts.geomgraph.*;
@@ -49,7 +49,7 @@ import com.vividsolutions.jts.geomgraph.*;
  * The use of MonotoneChains as the items in the index
  * seems to offer an improvement in performance over a sweep-line alone.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SimpleMCSweepLineIntersector
   extends EdgeSetIntersector
diff --git a/src/com/vividsolutions/jts/geomgraph/index/SimpleSweepLineIntersector.java b/src/com/vividsolutions/jts/geomgraph/index/SimpleSweepLineIntersector.java
index ccd36cf..b41f5c8 100644
--- a/src/com/vividsolutions/jts/geomgraph/index/SimpleSweepLineIntersector.java
+++ b/src/com/vividsolutions/jts/geomgraph/index/SimpleSweepLineIntersector.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.geomgraph.index;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import java.util.*;
 import com.vividsolutions.jts.geom.Coordinate;
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.geomgraph.*;
  * While still O(n^2) in the worst case, this algorithm
  * drastically improves the average-case time.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SimpleSweepLineIntersector
   extends EdgeSetIntersector
diff --git a/src/com/vividsolutions/jts/geomgraph/index/SweepLineEvent.java b/src/com/vividsolutions/jts/geomgraph/index/SweepLineEvent.java
index 3e47514..1072a3e 100644
--- a/src/com/vividsolutions/jts/geomgraph/index/SweepLineEvent.java
+++ b/src/com/vividsolutions/jts/geomgraph/index/SweepLineEvent.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.geomgraph.index;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class SweepLineEvent
   implements Comparable
diff --git a/src/com/vividsolutions/jts/geomgraph/index/SweepLineSegment.java b/src/com/vividsolutions/jts/geomgraph/index/SweepLineSegment.java
index 9c9ddc5..9bd2a88 100644
--- a/src/com/vividsolutions/jts/geomgraph/index/SweepLineSegment.java
+++ b/src/com/vividsolutions/jts/geomgraph/index/SweepLineSegment.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.geomgraph.*;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class SweepLineSegment {
 
diff --git a/src/com/vividsolutions/jts/index/ArrayListVisitor.java b/src/com/vividsolutions/jts/index/ArrayListVisitor.java
index c9f2c43..39065bc 100644
--- a/src/com/vividsolutions/jts/index/ArrayListVisitor.java
+++ b/src/com/vividsolutions/jts/index/ArrayListVisitor.java
@@ -4,7 +4,7 @@ import java.util.*;
 import com.vividsolutions.jts.index.ItemVisitor;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class ArrayListVisitor
     implements ItemVisitor
diff --git a/src/com/vividsolutions/jts/index/IndexVisitor.java b/src/com/vividsolutions/jts/index/IndexVisitor.java
index af0b628..d7f7042 100644
--- a/src/com/vividsolutions/jts/index/IndexVisitor.java
+++ b/src/com/vividsolutions/jts/index/IndexVisitor.java
@@ -3,7 +3,7 @@ package com.vividsolutions.jts.index;
 /**
  * A visitor for nodes and items in an index.
  *
- * @version 1.5
+ * @version 1.6
  */
 
 public interface IndexVisitor {
diff --git a/src/com/vividsolutions/jts/index/ItemVisitor.java b/src/com/vividsolutions/jts/index/ItemVisitor.java
index e4c095c..60a7b04 100644
--- a/src/com/vividsolutions/jts/index/ItemVisitor.java
+++ b/src/com/vividsolutions/jts/index/ItemVisitor.java
@@ -3,7 +3,7 @@ package com.vividsolutions.jts.index;
 /**
  * A visitor for items in an index.
  *
- * @version 1.5
+ * @version 1.6
  */
 
 public interface ItemVisitor
diff --git a/src/com/vividsolutions/jts/index/SpatialIndex.java b/src/com/vividsolutions/jts/index/SpatialIndex.java
index 7baec29..a464a44 100644
--- a/src/com/vividsolutions/jts/index/SpatialIndex.java
+++ b/src/com/vividsolutions/jts/index/SpatialIndex.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.geom.Envelope;
  * secondary filter may consist of other tests besides intersection, such as
  * testing other kinds of spatial relationships.
  *
- * @version 1.5
+ * @version 1.6
  */
 public interface SpatialIndex
 {
diff --git a/src/com/vividsolutions/jts/index/bintree/Bintree.java b/src/com/vividsolutions/jts/index/bintree/Bintree.java
index d5e070a..10e007e 100644
--- a/src/com/vividsolutions/jts/index/bintree/Bintree.java
+++ b/src/com/vividsolutions/jts/index/bintree/Bintree.java
@@ -52,7 +52,7 @@ import java.util.List;
  * This index is different to the Interval Tree of Edelsbrunner
  * or the Segment Tree of Bentley.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Bintree
 {
diff --git a/src/com/vividsolutions/jts/index/bintree/Interval.java b/src/com/vividsolutions/jts/index/bintree/Interval.java
index 80adcdc..41fe202 100644
--- a/src/com/vividsolutions/jts/index/bintree/Interval.java
+++ b/src/com/vividsolutions/jts/index/bintree/Interval.java
@@ -36,7 +36,7 @@ package com.vividsolutions.jts.index.bintree;
 /**
  * Represents an (1-dimensional) closed interval on the Real number line.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Interval {
 
diff --git a/src/com/vividsolutions/jts/index/bintree/Key.java b/src/com/vividsolutions/jts/index/bintree/Key.java
index 4c17dc5..84299ad 100644
--- a/src/com/vividsolutions/jts/index/bintree/Key.java
+++ b/src/com/vividsolutions/jts/index/bintree/Key.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.index.quadtree.DoubleBits;
  * It contains a lower-left point and a level number. The level number
  * is the power of two for the size of the node envelope
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Key {
 
diff --git a/src/com/vividsolutions/jts/index/bintree/Node.java b/src/com/vividsolutions/jts/index/bintree/Node.java
index 96da3a7..1489b29 100644
--- a/src/com/vividsolutions/jts/index/bintree/Node.java
+++ b/src/com/vividsolutions/jts/index/bintree/Node.java
@@ -38,7 +38,7 @@ import com.vividsolutions.jts.util.Assert;
 /**
  * A node of a {@link Bintree}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Node
   extends NodeBase
diff --git a/src/com/vividsolutions/jts/index/bintree/NodeBase.java b/src/com/vividsolutions/jts/index/bintree/NodeBase.java
index 458c0d4..d70f26a 100644
--- a/src/com/vividsolutions/jts/index/bintree/NodeBase.java
+++ b/src/com/vividsolutions/jts/index/bintree/NodeBase.java
@@ -41,7 +41,7 @@ import java.util.List;
 /**
  * The base class for nodes in a {@link Bintree}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public abstract class NodeBase {
 
diff --git a/src/com/vividsolutions/jts/index/bintree/Root.java b/src/com/vividsolutions/jts/index/bintree/Root.java
index 4e31d99..d9942be 100644
--- a/src/com/vividsolutions/jts/index/bintree/Root.java
+++ b/src/com/vividsolutions/jts/index/bintree/Root.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.util.Assert;
  * It is centred at the origin,
  * and does not have a defined extent.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Root
   extends NodeBase
diff --git a/src/com/vividsolutions/jts/index/chain/MonotoneChain.java b/src/com/vividsolutions/jts/index/chain/MonotoneChain.java
index 410453a..5fe6566 100644
--- a/src/com/vividsolutions/jts/index/chain/MonotoneChain.java
+++ b/src/com/vividsolutions/jts/index/chain/MonotoneChain.java
@@ -75,7 +75,7 @@ import com.vividsolutions.jts.geom.*;
  * returned by the query.
  * However, it does mean that the queries are not thread-safe.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class MonotoneChain {
 
diff --git a/src/com/vividsolutions/jts/index/chain/MonotoneChainBuilder.java b/src/com/vividsolutions/jts/index/chain/MonotoneChainBuilder.java
index 4951ff6..c003b4a 100644
--- a/src/com/vividsolutions/jts/index/chain/MonotoneChainBuilder.java
+++ b/src/com/vividsolutions/jts/index/chain/MonotoneChainBuilder.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.geomgraph.Quadrant;
  * A MonotoneChainBuilder implements functions to determine the monotone chains
  * in a sequence of points.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class MonotoneChainBuilder {
 
diff --git a/src/com/vividsolutions/jts/index/chain/MonotoneChainOverlapAction.java b/src/com/vividsolutions/jts/index/chain/MonotoneChainOverlapAction.java
index ca105c3..9650317 100644
--- a/src/com/vividsolutions/jts/index/chain/MonotoneChainOverlapAction.java
+++ b/src/com/vividsolutions/jts/index/chain/MonotoneChainOverlapAction.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.geom.*;
  * The action for the internal iterator for performing
  * overlap queries on a MonotoneChain
  *
- * @version 1.5
+ * @version 1.6
  */
 public class MonotoneChainOverlapAction
 {
diff --git a/src/com/vividsolutions/jts/index/chain/MonotoneChainSelectAction.java b/src/com/vividsolutions/jts/index/chain/MonotoneChainSelectAction.java
index 2b90d88..2e8a80d 100644
--- a/src/com/vividsolutions/jts/index/chain/MonotoneChainSelectAction.java
+++ b/src/com/vividsolutions/jts/index/chain/MonotoneChainSelectAction.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.geom.*;
  * The action for the internal iterator for performing
  * envelope select queries on a MonotoneChain
  *
- * @version 1.5
+ * @version 1.6
  */
 public class MonotoneChainSelectAction
 {
diff --git a/src/com/vividsolutions/jts/index/quadtree/DoubleBits.java b/src/com/vividsolutions/jts/index/quadtree/DoubleBits.java
index e36a7f3..6319141 100644
--- a/src/com/vividsolutions/jts/index/quadtree/DoubleBits.java
+++ b/src/com/vividsolutions/jts/index/quadtree/DoubleBits.java
@@ -43,7 +43,7 @@ package com.vividsolutions.jts.index.quadtree;
  * The algorithms and constants in this class
  * apply only to IEEE-754 double-precision floating point format.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class DoubleBits {
 
diff --git a/src/com/vividsolutions/jts/index/quadtree/IntervalSize.java b/src/com/vividsolutions/jts/index/quadtree/IntervalSize.java
index 9ad7ef0..6299a21 100644
--- a/src/com/vividsolutions/jts/index/quadtree/IntervalSize.java
+++ b/src/com/vividsolutions/jts/index/quadtree/IntervalSize.java
@@ -42,7 +42,7 @@ package com.vividsolutions.jts.index.quadtree;
  * computing a midpoint value which does not lie strictly between the
  * endpoints.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class IntervalSize {
 
diff --git a/src/com/vividsolutions/jts/index/quadtree/Key.java b/src/com/vividsolutions/jts/index/quadtree/Key.java
index 5a77c1c..a2ab714 100644
--- a/src/com/vividsolutions/jts/index/quadtree/Key.java
+++ b/src/com/vividsolutions/jts/index/quadtree/Key.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.geom.Envelope;
  * It contains a lower-left point and a level number. The level number
  * is the power of two for the size of the node envelope
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Key {
 
@@ -95,7 +95,6 @@ public class Key {
   private void computeKey(int level, Envelope itemEnv)
   {
     double quadSize = DoubleBits.powerOf2(level);
-    //double quadSize = pow2.power(level);
     pt.x = Math.floor(itemEnv.getMinX() / quadSize) * quadSize;
     pt.y = Math.floor(itemEnv.getMinY() / quadSize) * quadSize;
     env.init(pt.x, pt.x + quadSize, pt.y, pt.y + quadSize);
diff --git a/src/com/vividsolutions/jts/index/quadtree/Node.java b/src/com/vividsolutions/jts/index/quadtree/Node.java
index 88ed0d1..ea9ac8c 100644
--- a/src/com/vividsolutions/jts/index/quadtree/Node.java
+++ b/src/com/vividsolutions/jts/index/quadtree/Node.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.util.Assert;
  * items which have a spatial extent corresponding to the node's position
  * in the quadtree.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Node
   extends NodeBase
diff --git a/src/com/vividsolutions/jts/index/quadtree/NodeBase.java b/src/com/vividsolutions/jts/index/quadtree/NodeBase.java
index c7817ec..e2501e7 100644
--- a/src/com/vividsolutions/jts/index/quadtree/NodeBase.java
+++ b/src/com/vividsolutions/jts/index/quadtree/NodeBase.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.index.*;
 /**
  * The base class for nodes in a {@link Quadtree}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public abstract class NodeBase {
 
diff --git a/src/com/vividsolutions/jts/index/quadtree/Quadtree.java b/src/com/vividsolutions/jts/index/quadtree/Quadtree.java
index b557291..0e5c7a2 100644
--- a/src/com/vividsolutions/jts/index/quadtree/Quadtree.java
+++ b/src/com/vividsolutions/jts/index/quadtree/Quadtree.java
@@ -59,7 +59,7 @@ import com.vividsolutions.jts.index.*;
  * This data structure is also known as an <i>MX-CIF quadtree</i>
  * following the usage of Samet and others.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Quadtree
     implements SpatialIndex
diff --git a/src/com/vividsolutions/jts/index/quadtree/Root.java b/src/com/vividsolutions/jts/index/quadtree/Root.java
index 5dcea4f..1e37a3a 100644
--- a/src/com/vividsolutions/jts/index/quadtree/Root.java
+++ b/src/com/vividsolutions/jts/index/quadtree/Root.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.util.Assert;
  * QuadRoot is the root of a single Quadtree.  It is centred at the origin,
  * and does not have a defined extent.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Root
   extends NodeBase
diff --git a/src/com/vividsolutions/jts/index/strtree/AbstractNode.java b/src/com/vividsolutions/jts/index/strtree/AbstractNode.java
index a7170dd..6b71e49 100644
--- a/src/com/vividsolutions/jts/index/strtree/AbstractNode.java
+++ b/src/com/vividsolutions/jts/index/strtree/AbstractNode.java
@@ -41,7 +41,7 @@ import java.util.*;
  * (AbstractNodes) or real data (ItemBoundables). If this node contains real data
  * (rather than nodes), then we say that this node is a "leaf node".
  *
- * @version 1.5
+ * @version 1.6
  */
 public abstract class AbstractNode implements Boundable {
   private ArrayList childBoundables = new ArrayList();
diff --git a/src/com/vividsolutions/jts/index/strtree/AbstractSTRtree.java b/src/com/vividsolutions/jts/index/strtree/AbstractSTRtree.java
index e375bba..c0adc99 100644
--- a/src/com/vividsolutions/jts/index/strtree/AbstractSTRtree.java
+++ b/src/com/vividsolutions/jts/index/strtree/AbstractSTRtree.java
@@ -48,7 +48,7 @@ import java.util.List;
  * @see STRtree
  * @see SIRtree
  *
- * @version 1.5
+ * @version 1.6
  */
 public abstract class AbstractSTRtree {
 
diff --git a/src/com/vividsolutions/jts/index/strtree/Boundable.java b/src/com/vividsolutions/jts/index/strtree/Boundable.java
index 383a261..200cded 100644
--- a/src/com/vividsolutions/jts/index/strtree/Boundable.java
+++ b/src/com/vividsolutions/jts/index/strtree/Boundable.java
@@ -36,7 +36,7 @@ package com.vividsolutions.jts.index.strtree;
 /**
  * A spatial object in an AbstractSTRtree.
  *
- * @version 1.5
+ * @version 1.6
  */
 public interface Boundable {
   /**
diff --git a/src/com/vividsolutions/jts/index/strtree/Interval.java b/src/com/vividsolutions/jts/index/strtree/Interval.java
index 1913be4..165cf26 100644
--- a/src/com/vividsolutions/jts/index/strtree/Interval.java
+++ b/src/com/vividsolutions/jts/index/strtree/Interval.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.util.*;
  * A contiguous portion of 1D-space. Used internally by SIRtree.
  * @see SIRtree
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Interval {
 
diff --git a/src/com/vividsolutions/jts/index/strtree/ItemBoundable.java b/src/com/vividsolutions/jts/index/strtree/ItemBoundable.java
index cf4af05..fd9a75a 100644
--- a/src/com/vividsolutions/jts/index/strtree/ItemBoundable.java
+++ b/src/com/vividsolutions/jts/index/strtree/ItemBoundable.java
@@ -37,7 +37,7 @@ package com.vividsolutions.jts.index.strtree;
  * Boundable wrapper for a non-Boundable spatial object. Used internally by
  * AbstractSTRtree.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class ItemBoundable implements Boundable {
   private Object bounds;
diff --git a/src/com/vividsolutions/jts/index/strtree/SIRtree.java b/src/com/vividsolutions/jts/index/strtree/SIRtree.java
index 225dbd9..adb6a66 100644
--- a/src/com/vividsolutions/jts/index/strtree/SIRtree.java
+++ b/src/com/vividsolutions/jts/index/strtree/SIRtree.java
@@ -44,7 +44,7 @@ import java.util.List;
  * Application To GIS. Morgan Kaufmann, San Francisco, 2002.
  * @see STRtree
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SIRtree extends AbstractSTRtree {
 
diff --git a/src/com/vividsolutions/jts/index/strtree/STRtree.java b/src/com/vividsolutions/jts/index/strtree/STRtree.java
index bec887e..58c0be4 100644
--- a/src/com/vividsolutions/jts/index/strtree/STRtree.java
+++ b/src/com/vividsolutions/jts/index/strtree/STRtree.java
@@ -52,7 +52,7 @@ import com.vividsolutions.jts.index.*;
  * Described in: P. Rigaux, Michel Scholl and Agnes Voisard. Spatial Databases With
  *  Application To GIS. Morgan Kaufmann, San Francisco, 2002.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class STRtree extends AbstractSTRtree implements SpatialIndex {
 
diff --git a/src/com/vividsolutions/jts/index/sweepline/SweepLineEvent.java b/src/com/vividsolutions/jts/index/sweepline/SweepLineEvent.java
index 996f716..2c9e6b9 100644
--- a/src/com/vividsolutions/jts/index/sweepline/SweepLineEvent.java
+++ b/src/com/vividsolutions/jts/index/sweepline/SweepLineEvent.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.index.sweepline;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class SweepLineEvent
   implements Comparable
diff --git a/src/com/vividsolutions/jts/index/sweepline/SweepLineIndex.java b/src/com/vividsolutions/jts/index/sweepline/SweepLineIndex.java
index c18fdea..06ff4f1 100644
--- a/src/com/vividsolutions/jts/index/sweepline/SweepLineIndex.java
+++ b/src/com/vividsolutions/jts/index/sweepline/SweepLineIndex.java
@@ -40,7 +40,7 @@ import java.util.*;
  * A sweepline implements a sorted index on a set of intervals.
  * It is used to compute all overlaps between the interval in the index.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SweepLineIndex {
 
diff --git a/src/com/vividsolutions/jts/index/sweepline/SweepLineInterval.java b/src/com/vividsolutions/jts/index/sweepline/SweepLineInterval.java
index 3e3542d..65014ae 100644
--- a/src/com/vividsolutions/jts/index/sweepline/SweepLineInterval.java
+++ b/src/com/vividsolutions/jts/index/sweepline/SweepLineInterval.java
@@ -35,7 +35,7 @@
 package com.vividsolutions.jts.index.sweepline;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class SweepLineInterval {
 
diff --git a/src/com/vividsolutions/jts/index/sweepline/SweepLineOverlapAction.java b/src/com/vividsolutions/jts/index/sweepline/SweepLineOverlapAction.java
index 4009a49..dfd938b 100644
--- a/src/com/vividsolutions/jts/index/sweepline/SweepLineOverlapAction.java
+++ b/src/com/vividsolutions/jts/index/sweepline/SweepLineOverlapAction.java
@@ -37,7 +37,7 @@ package com.vividsolutions.jts.index.sweepline;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public interface SweepLineOverlapAction {
 
diff --git a/src/com/vividsolutions/jts/io/ParseException.java b/src/com/vividsolutions/jts/io/ParseException.java
index de0e106..609f8da 100644
--- a/src/com/vividsolutions/jts/io/ParseException.java
+++ b/src/com/vividsolutions/jts/io/ParseException.java
@@ -37,7 +37,7 @@ package com.vividsolutions.jts.io;
 /**
  *  Thrown by a <code>WKTReader</code> when a parsing problem occurs.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class ParseException extends Exception {
 
diff --git a/src/com/vividsolutions/jts/io/WKTReader.java b/src/com/vividsolutions/jts/io/WKTReader.java
index 61898a8..2a7f153 100644
--- a/src/com/vividsolutions/jts/io/WKTReader.java
+++ b/src/com/vividsolutions/jts/io/WKTReader.java
@@ -73,7 +73,7 @@ import java.util.ArrayList;
  *
  *  Reads non-standard "LINEARRING" tags.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class WKTReader {
   private GeometryFactory geometryFactory;
diff --git a/src/com/vividsolutions/jts/io/WKTWriter.java b/src/com/vividsolutions/jts/io/WKTWriter.java
index 29a9709..192b93d 100644
--- a/src/com/vividsolutions/jts/io/WKTWriter.java
+++ b/src/com/vividsolutions/jts/io/WKTWriter.java
@@ -56,7 +56,7 @@ import java.text.DecimalFormatSymbols;
  * not define a special tag for LinearRings. The standard tag to use is
  * "LINESTRING".
  *
- * @version 1.5
+ * @version 1.6
  */
 public class WKTWriter {
 
diff --git a/src/com/vividsolutions/jts/noding/IteratedNoder.java b/src/com/vividsolutions/jts/noding/IteratedNoder.java
index 271d9fb..b19e8b6 100644
--- a/src/com/vividsolutions/jts/noding/IteratedNoder.java
+++ b/src/com/vividsolutions/jts/noding/IteratedNoder.java
@@ -47,7 +47,7 @@ import com.vividsolutions.jts.geom.*;
  * due to roundoff error.   This problem is detected and an exception is thrown.
  * Clients can choose to rerun the noding using a lower precision model.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class IteratedNoder
 {
diff --git a/src/com/vividsolutions/jts/noding/MCQuadtreeNoder.java b/src/com/vividsolutions/jts/noding/MCQuadtreeNoder.java
index f8008b6..cbd2218 100644
--- a/src/com/vividsolutions/jts/noding/MCQuadtreeNoder.java
+++ b/src/com/vividsolutions/jts/noding/MCQuadtreeNoder.java
@@ -47,7 +47,7 @@ import com.vividsolutions.jts.index.quadtree.Quadtree;
  * envelope (range) queries efficiently (such as a {@link Quadtree}
  * or {@link STRtree}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class MCQuadtreeNoder
     extends Noder
diff --git a/src/com/vividsolutions/jts/noding/Noder.java b/src/com/vividsolutions/jts/noding/Noder.java
index df3eb7e..27d8439 100644
--- a/src/com/vividsolutions/jts/noding/Noder.java
+++ b/src/com/vividsolutions/jts/noding/Noder.java
@@ -43,7 +43,7 @@ import com.vividsolutions.jts.geomgraph.index.*;
  * Intersections found are represented as {@link SegmentNode}s and add to the
  * {@link SegmentString}s in which they occur.
  *
- * @version 1.5
+ * @version 1.6
  */
 public abstract class Noder
 {
diff --git a/src/com/vividsolutions/jts/noding/NodingValidator.java b/src/com/vividsolutions/jts/noding/NodingValidator.java
index 4d66cac..5fa4ddc 100644
--- a/src/com/vividsolutions/jts/noding/NodingValidator.java
+++ b/src/com/vividsolutions/jts/noding/NodingValidator.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.geom.*;
  * Validates that a collection of {@link SegmentString}s is correctly noded.
  * Throws an appropriate exception if an noding error is found.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class NodingValidator {
 
diff --git a/src/com/vividsolutions/jts/noding/SegmentIntersector.java b/src/com/vividsolutions/jts/noding/SegmentIntersector.java
index 8ff67a0..f762b15 100644
--- a/src/com/vividsolutions/jts/noding/SegmentIntersector.java
+++ b/src/com/vividsolutions/jts/noding/SegmentIntersector.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.util.Debug;
  * detects that two SegmentStrings <i>might</i> intersect.
  * This class is an example of the <i>Strategy</i> pattern.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SegmentIntersector
 {
diff --git a/src/com/vividsolutions/jts/noding/SegmentNode.java b/src/com/vividsolutions/jts/noding/SegmentNode.java
index f624607..c8ca36e 100644
--- a/src/com/vividsolutions/jts/noding/SegmentNode.java
+++ b/src/com/vividsolutions/jts/noding/SegmentNode.java
@@ -45,7 +45,7 @@ package com.vividsolutions.jts.noding;
  * the edge from this point forwards, until the next
  * intersection or the end of the edge.
  * The intersection point must be precise.
- * @version 1.5
+ * @version 1.6
  */
 import java.io.PrintStream;
 import com.vividsolutions.jts.geom.Coordinate;
@@ -53,7 +53,7 @@ import com.vividsolutions.jts.geom.Coordinate;
 /**
  * Represents an intersection point between two {@link SegmentString}s.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SegmentNode
     implements Comparable
diff --git a/src/com/vividsolutions/jts/noding/SegmentNodeList.java b/src/com/vividsolutions/jts/noding/SegmentNodeList.java
index 8e741ea..af46a14 100644
--- a/src/com/vividsolutions/jts/noding/SegmentNodeList.java
+++ b/src/com/vividsolutions/jts/noding/SegmentNodeList.java
@@ -43,7 +43,7 @@ import com.vividsolutions.jts.util.Debug;
 /**
  * A list of the {@link SegmentNode}s present along a noded {@link SegmentString}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SegmentNodeList
 {
diff --git a/src/com/vividsolutions/jts/noding/SegmentString.java b/src/com/vividsolutions/jts/noding/SegmentString.java
index 5dfa686..1291b3a 100644
--- a/src/com/vividsolutions/jts/noding/SegmentString.java
+++ b/src/com/vividsolutions/jts/noding/SegmentString.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.geom.Coordinate;
  * The line segments are represented by an array of {@link Coordinate}s.
  *
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SegmentString {
 
diff --git a/src/com/vividsolutions/jts/noding/SimpleNoder.java b/src/com/vividsolutions/jts/noding/SimpleNoder.java
index 56521b1..dc4a50b 100644
--- a/src/com/vividsolutions/jts/noding/SimpleNoder.java
+++ b/src/com/vividsolutions/jts/noding/SimpleNoder.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.geom.*;
  * This has n^2 performance, so is too slow for use on large numbers
  * of segments.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SimpleNoder
     extends Noder
diff --git a/src/com/vividsolutions/jts/noding/snapround/SegmentSnapper.java b/src/com/vividsolutions/jts/noding/snapround/SegmentSnapper.java
index 4affadf..cf3e330 100644
--- a/src/com/vividsolutions/jts/noding/snapround/SegmentSnapper.java
+++ b/src/com/vividsolutions/jts/noding/snapround/SegmentSnapper.java
@@ -38,7 +38,7 @@ import com.vividsolutions.jts.noding.*;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class SegmentSnapper {
 
diff --git a/src/com/vividsolutions/jts/noding/snapround/SimpleSegmentStringsSnapper.java b/src/com/vividsolutions/jts/noding/snapround/SimpleSegmentStringsSnapper.java
index 861360c..8c8f1e0 100644
--- a/src/com/vividsolutions/jts/noding/snapround/SimpleSegmentStringsSnapper.java
+++ b/src/com/vividsolutions/jts/noding/snapround/SimpleSegmentStringsSnapper.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.noding.*;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class SimpleSegmentStringsSnapper {
 
diff --git a/src/com/vividsolutions/jts/noding/snapround/SnapRounder.java b/src/com/vividsolutions/jts/noding/snapround/SnapRounder.java
index ba4662c..6c1c8a7 100644
--- a/src/com/vividsolutions/jts/noding/snapround/SnapRounder.java
+++ b/src/com/vividsolutions/jts/noding/snapround/SnapRounder.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.noding.*;
  * Uses snap rounding to compute a rounded, noded arrangement from a
  * set of linestrings.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SnapRounder
     //extends Noder  // cut this free for now
diff --git a/src/com/vividsolutions/jts/operation/GeometryGraphOperation.java b/src/com/vividsolutions/jts/operation/GeometryGraphOperation.java
index 31ce828..b4fb950 100644
--- a/src/com/vividsolutions/jts/operation/GeometryGraphOperation.java
+++ b/src/com/vividsolutions/jts/operation/GeometryGraphOperation.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.geomgraph.GeometryGraph;
 /**
  * The base class for operations that require {@link GeometryGraph)s.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class GeometryGraphOperation
 {
diff --git a/src/com/vividsolutions/jts/operation/IsSimpleOp.java b/src/com/vividsolutions/jts/operation/IsSimpleOp.java
index 2255142..a54b5ca 100644
--- a/src/com/vividsolutions/jts/operation/IsSimpleOp.java
+++ b/src/com/vividsolutions/jts/operation/IsSimpleOp.java
@@ -47,7 +47,7 @@ import com.vividsolutions.jts.geomgraph.index.SegmentIntersector;
  * by definition, so no test is provided.  To test whether a given Polygon is valid,
  * use <code>Geometry#isValid</code>)
  *
- * @version 1.5
+ * @version 1.6
  */
 public class IsSimpleOp {
 
diff --git a/src/com/vividsolutions/jts/operation/buffer/BufferBuilder.java b/src/com/vividsolutions/jts/operation/buffer/BufferBuilder.java
index 86c527a..0b07be5 100644
--- a/src/com/vividsolutions/jts/operation/buffer/BufferBuilder.java
+++ b/src/com/vividsolutions/jts/operation/buffer/BufferBuilder.java
@@ -35,7 +35,7 @@
 package com.vividsolutions.jts.operation.buffer;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 
 import java.util.*;
@@ -58,7 +58,7 @@ import com.vividsolutions.jts.noding.*;
  * Retrying the computation in a fixed precision
  * can produce more robust results.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class BufferBuilder
 {
diff --git a/src/com/vividsolutions/jts/operation/buffer/BufferOp.java b/src/com/vividsolutions/jts/operation/buffer/BufferOp.java
index 9cdd4e0..53763f8 100644
--- a/src/com/vividsolutions/jts/operation/buffer/BufferOp.java
+++ b/src/com/vividsolutions/jts/operation/buffer/BufferOp.java
@@ -33,7 +33,7 @@
 package com.vividsolutions.jts.operation.buffer;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.precision.SimpleGeometryPrecisionReducer;
@@ -65,7 +65,7 @@ import com.vividsolutions.jts.precision.SimpleGeometryPrecisionReducer;
  * to provide a high degree of robustness.
 
  *
- * @version 1.5
+ * @version 1.6
  */
 public class BufferOp
 {
diff --git a/src/com/vividsolutions/jts/operation/buffer/BufferSubgraph.java b/src/com/vividsolutions/jts/operation/buffer/BufferSubgraph.java
index fc0c57e..908f649 100644
--- a/src/com/vividsolutions/jts/operation/buffer/BufferSubgraph.java
+++ b/src/com/vividsolutions/jts/operation/buffer/BufferSubgraph.java
@@ -35,7 +35,7 @@
 package com.vividsolutions.jts.operation.buffer;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 
 import java.util.*;
@@ -55,7 +55,7 @@ import com.vividsolutions.jts.util.*;
  * </ul>
  *
  *
- * @version 1.5
+ * @version 1.6
  */
 public class BufferSubgraph
   implements Comparable
diff --git a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java b/src/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java
index d2db76c..9ad0642 100644
--- a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java
+++ b/src/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java
@@ -46,7 +46,7 @@ import com.vividsolutions.jts.geomgraph.*;
  * of all the noded raw curves and tracing outside contours.
  * The points in the raw curve are rounded to the required precision model.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class OffsetCurveBuilder {
 
diff --git a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveSetBuilder.java b/src/com/vividsolutions/jts/operation/buffer/OffsetCurveSetBuilder.java
index cd62467..0e33da4 100644
--- a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveSetBuilder.java
+++ b/src/com/vividsolutions/jts/operation/buffer/OffsetCurveSetBuilder.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.operation.buffer;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import java.util.*;
 import com.vividsolutions.jts.geom.*;
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.noding.SegmentString;
  * Creates all the raw offset curves for a buffer of a {@link Geometry}.
  * Raw curves need to be noded together and polygonized to form the final buffer area.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class OffsetCurveSetBuilder {
 
diff --git a/src/com/vividsolutions/jts/operation/buffer/RightmostEdgeFinder.java b/src/com/vividsolutions/jts/operation/buffer/RightmostEdgeFinder.java
index 0d51188..af90e49 100644
--- a/src/com/vividsolutions/jts/operation/buffer/RightmostEdgeFinder.java
+++ b/src/com/vividsolutions/jts/operation/buffer/RightmostEdgeFinder.java
@@ -35,7 +35,7 @@
 package com.vividsolutions.jts.operation.buffer;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import java.util.*;
 import com.vividsolutions.jts.geom.*;
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.util.*;
  * A RightmostEdgeFinder find the DirectedEdge in a list which has the highest coordinate,
  * and which is oriented L to R at that point. (I.e. the right side is on the RHS of the edge.)
  *
- * @version 1.5
+ * @version 1.6
  */
 public class RightmostEdgeFinder {
 
diff --git a/src/com/vividsolutions/jts/operation/buffer/SubgraphDepthLocater.java b/src/com/vividsolutions/jts/operation/buffer/SubgraphDepthLocater.java
index b96d0a8..1f227a5 100644
--- a/src/com/vividsolutions/jts/operation/buffer/SubgraphDepthLocater.java
+++ b/src/com/vividsolutions/jts/operation/buffer/SubgraphDepthLocater.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.algorithm.*;
  * The input subgraphs are assumed to have had depths
  * already calculated for their edges.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SubgraphDepthLocater
 {
diff --git a/src/com/vividsolutions/jts/operation/distance/ConnectedElementLocationFilter.java b/src/com/vividsolutions/jts/operation/distance/ConnectedElementLocationFilter.java
index 79c990d..1dcc7b2 100644
--- a/src/com/vividsolutions/jts/operation/distance/ConnectedElementLocationFilter.java
+++ b/src/com/vividsolutions/jts/operation/distance/ConnectedElementLocationFilter.java
@@ -43,7 +43,7 @@ import com.vividsolutions.jts.geom.*;
  * and returns them in a list. The elements of the list are 
  * {@link com.vividsolutions.jts.operation.distance.GeometryLocation}s.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class ConnectedElementLocationFilter
   implements GeometryFilter
diff --git a/src/com/vividsolutions/jts/operation/distance/ConnectedElementPointFilter.java b/src/com/vividsolutions/jts/operation/distance/ConnectedElementPointFilter.java
index b4e0832..8477c28 100644
--- a/src/com/vividsolutions/jts/operation/distance/ConnectedElementPointFilter.java
+++ b/src/com/vividsolutions/jts/operation/distance/ConnectedElementPointFilter.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.geom.*;
  * (e.g. a polygon, linestring or point)
  * and returns them in a list
  *
- * @version 1.5
+ * @version 1.6
  */
 public class ConnectedElementPointFilter
   implements GeometryFilter
diff --git a/src/com/vividsolutions/jts/operation/distance/DistanceOp.java b/src/com/vividsolutions/jts/operation/distance/DistanceOp.java
index 76329c9..c47e673 100644
--- a/src/com/vividsolutions/jts/operation/distance/DistanceOp.java
+++ b/src/com/vividsolutions/jts/operation/distance/DistanceOp.java
@@ -51,7 +51,7 @@ import com.vividsolutions.jts.algorithm.*;
  * comparisons.  This worst-case performance could be improved on
  * by using Voronoi techniques.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class DistanceOp {
 
diff --git a/src/com/vividsolutions/jts/operation/distance/GeometryLocation.java b/src/com/vividsolutions/jts/operation/distance/GeometryLocation.java
index c77b295..1397461 100644
--- a/src/com/vividsolutions/jts/operation/distance/GeometryLocation.java
+++ b/src/com/vividsolutions/jts/operation/distance/GeometryLocation.java
@@ -43,7 +43,7 @@ import com.vividsolutions.jts.geom.*;
  * Locations inside area Geometrys will not have an associated segment index,
  * so in this case the segment index will have the sentinel value of INSIDE_AREA.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class GeometryLocation
 {
diff --git a/src/com/vividsolutions/jts/operation/linemerge/EdgeString.java b/src/com/vividsolutions/jts/operation/linemerge/EdgeString.java
index f1f84eb..129fba3 100644
--- a/src/com/vividsolutions/jts/operation/linemerge/EdgeString.java
+++ b/src/com/vividsolutions/jts/operation/linemerge/EdgeString.java
@@ -47,7 +47,7 @@ import java.util.List;
  * A sequence of {@link LineMergeDirectedEdge}s forming one of the lines that will
  * be output by the line-merging process.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class EdgeString {
   private GeometryFactory factory;
diff --git a/src/com/vividsolutions/jts/operation/linemerge/LineMergeDirectedEdge.java b/src/com/vividsolutions/jts/operation/linemerge/LineMergeDirectedEdge.java
index e66cf8a..67a2f44 100644
--- a/src/com/vividsolutions/jts/operation/linemerge/LineMergeDirectedEdge.java
+++ b/src/com/vividsolutions/jts/operation/linemerge/LineMergeDirectedEdge.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.util.Assert;
  * A {@link com.vividsolutions.jts.planargraph.DirectedEdge} of a 
  * {@link LineMergeGraph}. 
  *
- * @version 1.5
+ * @version 1.6
  */
 public class LineMergeDirectedEdge extends DirectedEdge {
   /**
diff --git a/src/com/vividsolutions/jts/operation/linemerge/LineMergeEdge.java b/src/com/vividsolutions/jts/operation/linemerge/LineMergeEdge.java
index 7a282ff..7db2192 100644
--- a/src/com/vividsolutions/jts/operation/linemerge/LineMergeEdge.java
+++ b/src/com/vividsolutions/jts/operation/linemerge/LineMergeEdge.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.planargraph.Edge;
  * An edge of a {@link LineMergeGraph}. The <code>marked</code> field indicates
  * whether this Edge has been logically deleted from the graph.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class LineMergeEdge extends Edge {
   private LineString line;
diff --git a/src/com/vividsolutions/jts/operation/linemerge/LineMergeGraph.java b/src/com/vividsolutions/jts/operation/linemerge/LineMergeGraph.java
index 3274478..6d4beee 100644
--- a/src/com/vividsolutions/jts/operation/linemerge/LineMergeGraph.java
+++ b/src/com/vividsolutions/jts/operation/linemerge/LineMergeGraph.java
@@ -47,7 +47,7 @@ import com.vividsolutions.jts.planargraph.PlanarGraph;
  * and @{link com.vividsolutions.planargraph.Node}s indicates whether they have been
  * logically deleted from the graph.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class LineMergeGraph extends PlanarGraph {
   /**
diff --git a/src/com/vividsolutions/jts/operation/linemerge/LineMerger.java b/src/com/vividsolutions/jts/operation/linemerge/LineMerger.java
index 8ad4749..d4b3f9b 100644
--- a/src/com/vividsolutions/jts/operation/linemerge/LineMerger.java
+++ b/src/com/vividsolutions/jts/operation/linemerge/LineMerger.java
@@ -56,7 +56,7 @@ import com.vividsolutions.jts.util.Assert;
  * at their endpoints.  The LineMerger will still run on incorrectly noded input
  * but will not form polygons from incorrected noded edges.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class LineMerger {
   /**
diff --git a/src/com/vividsolutions/jts/operation/overlay/EdgeSetNoder.java b/src/com/vividsolutions/jts/operation/overlay/EdgeSetNoder.java
index 3e3da7a..672ec26 100644
--- a/src/com/vividsolutions/jts/operation/overlay/EdgeSetNoder.java
+++ b/src/com/vividsolutions/jts/operation/overlay/EdgeSetNoder.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.util.*;
  * Takes one or more sets of edges and constructs a
  * new set of edges consisting of all the split edges created by
  * noding the input edges together
- * @version 1.5
+ * @version 1.6
  */
 public class EdgeSetNoder {
 
diff --git a/src/com/vividsolutions/jts/operation/overlay/LineBuilder.java b/src/com/vividsolutions/jts/operation/overlay/LineBuilder.java
index e2e7782..765e420 100644
--- a/src/com/vividsolutions/jts/operation/overlay/LineBuilder.java
+++ b/src/com/vividsolutions/jts/operation/overlay/LineBuilder.java
@@ -1,6 +1,3 @@
-
-
-
 /*
  * The JTS Topology Suite is a collection of Java classes that
  * implement the fundamental operations required to validate a given
@@ -39,12 +36,13 @@ import java.util.*;
 import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.geomgraph.*;
 import com.vividsolutions.jts.algorithm.*;
+import com.vividsolutions.jts.util.*;
 
 /**
  * Forms JTS LineStrings out of a the graph of {@link DirectedEdge}s
  * created by an {@link OverlayOp}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class LineBuilder {
   private OverlayOp op;
@@ -108,21 +106,33 @@ public class LineBuilder {
       collectBoundaryTouchEdge(de, opCode, lineEdgesList);
     }
   }
-  public void collectLineEdge(DirectedEdge de, int opCode, List edges)
+
+  /**
+   * Collect line edges which are in the result.
+   * Line edges are in the result if they are not part of
+   * an area boundary, if they are in the result of the overlay operation,
+   * and if they are not covered by a result area.
+   *
+   * @param de the directed edge to test
+   * @param opCode the overlap operation
+   * @param edges the list of included line edges
+   */
+  private void collectLineEdge(DirectedEdge de, int opCode, List edges)
   {
-      Label label = de.getLabel();
-      Edge e = de.getEdge();
-      // include L edges which are in the result
-      if (de.isLineEdge()) {
-        if (! de.isVisited() && OverlayOp.isResultOfOp(label, opCode) && ! e.isCovered()) {
+    Label label = de.getLabel();
+    Edge e = de.getEdge();
+    // include L edges which are in the result
+    if (de.isLineEdge()) {
+      if (! de.isVisited() && OverlayOp.isResultOfOp(label, opCode) && ! e.isCovered()) {
 //Debug.println("de: " + de.getLabel());
 //Debug.println("edge: " + e.getLabel());
 
-          edges.add(e);
-          de.setVisitedEdge(true);
-        }
+        edges.add(e);
+        de.setVisitedEdge(true);
       }
+    }
   }
+
   /**
    * Collect edges from Area inputs which should be in the result but
    * which have not been included in a result area.
@@ -133,15 +143,19 @@ public class LineBuilder {
    * <li> OR as a result of a dimensional collapse.
    * </ul>
    */
-  public void collectBoundaryTouchEdge(DirectedEdge de, int opCode, List edges)
+  private void collectBoundaryTouchEdge(DirectedEdge de, int opCode, List edges)
   {
     Label label = de.getLabel();
-    // this smells like a bit of a hack, but it seems to work...
-    if (! de.isLineEdge()
-          && ! de.isInteriorAreaEdge()  // added to handle dimensional collapses
-          && ! de.getEdge().isInResult()
-          && ! de.isVisited()
-          && OverlayOp.isResultOfOp(label, opCode)
+    if (de.isLineEdge()) return;  // only interested in area edges
+    if (de.isVisited()) return;  // already processed
+    if (de.isInteriorAreaEdge()) return;  // added to handle dimensional collapses
+    if (de.getEdge().isInResult()) return;  // if the edge linework is already included, don't include it again
+
+    // sanity check for labelling of result edgerings
+    Assert.isTrue(! (de.isInResult() || de.getSym().isInResult()) || ! de.getEdge().isInResult());
+
+    // include the linework if it's in the result of the operation
+    if (OverlayOp.isResultOfOp(label, opCode)
           && opCode == OverlayOp.INTERSECTION)
     {
       edges.add(de.getEdge());
@@ -151,17 +165,12 @@ public class LineBuilder {
 
   private void buildLines(int opCode)
   {
-    // need to simplify lines?
     for (Iterator it = lineEdgesList.iterator(); it.hasNext(); ) {
       Edge e = (Edge) it.next();
       Label label = e.getLabel();
-//e.print(System.out);
- ////System.out.println(label);
-      //if (OverlayGraph.isResultOfOp(label, opCode)) {
         LineString line = geometryFactory.createLineString(e.getCoordinates());
         resultLineList.add(line);
         e.setInResult(true);
-      //}
     }
   }
 
diff --git a/src/com/vividsolutions/jts/operation/overlay/MaximalEdgeRing.java b/src/com/vividsolutions/jts/operation/overlay/MaximalEdgeRing.java
index dad5204..1fb5d39 100644
--- a/src/com/vividsolutions/jts/operation/overlay/MaximalEdgeRing.java
+++ b/src/com/vividsolutions/jts/operation/overlay/MaximalEdgeRing.java
@@ -54,7 +54,7 @@ import com.vividsolutions.jts.geomgraph.*;
  * A MaximalEdgeRing can be converted to a list of MinimalEdgeRings using the
  * {@link #buildMinimalRings() } method.
  *
- * @version 1.5
+ * @version 1.6
  * @see com.vividsolutions.jts.operation.overlay.MinimalEdgeRing
  */
 public class MaximalEdgeRing
diff --git a/src/com/vividsolutions/jts/operation/overlay/MinimalEdgeRing.java b/src/com/vividsolutions/jts/operation/overlay/MinimalEdgeRing.java
index 1f1be94..21166f4 100644
--- a/src/com/vividsolutions/jts/operation/overlay/MinimalEdgeRing.java
+++ b/src/com/vividsolutions/jts/operation/overlay/MinimalEdgeRing.java
@@ -43,7 +43,7 @@ import com.vividsolutions.jts.geomgraph.*;
  * has degree greater than 2.  These are the form of rings required
  * to represent polygons under the OGC SFS spatial data model.
  *
- * @version 1.5
+ * @version 1.6
  * @see com.vividsolutions.jts.operation.overlay.MaximalEdgeRing
  */
 public class MinimalEdgeRing
diff --git a/src/com/vividsolutions/jts/operation/overlay/OverlayNodeFactory.java b/src/com/vividsolutions/jts/operation/overlay/OverlayNodeFactory.java
index 3ae712f..b7e0971 100644
--- a/src/com/vividsolutions/jts/operation/overlay/OverlayNodeFactory.java
+++ b/src/com/vividsolutions/jts/operation/overlay/OverlayNodeFactory.java
@@ -35,7 +35,7 @@
 package com.vividsolutions.jts.operation.overlay;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import com.vividsolutions.jts.geom.Coordinate;
 import com.vividsolutions.jts.geomgraph.*;
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.geomgraph.*;
  * Creates nodes for use in the {@link PlanarGraph}s constructed during
  * overlay operations.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class OverlayNodeFactory
   extends NodeFactory
diff --git a/src/com/vividsolutions/jts/operation/overlay/OverlayOp.java b/src/com/vividsolutions/jts/operation/overlay/OverlayOp.java
index 493ac4f..1665ca6 100644
--- a/src/com/vividsolutions/jts/operation/overlay/OverlayOp.java
+++ b/src/com/vividsolutions/jts/operation/overlay/OverlayOp.java
@@ -46,7 +46,7 @@ import com.vividsolutions.jts.operation.GeometryGraphOperation;
  * Computes the overlay of two {@link Geometry}s.  The overlay
  * can be used to determine any boolean combination of the geometries.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class OverlayOp
   extends GeometryGraphOperation
diff --git a/src/com/vividsolutions/jts/operation/overlay/PointBuilder.java b/src/com/vividsolutions/jts/operation/overlay/PointBuilder.java
index cf5b74c..883bada 100644
--- a/src/com/vividsolutions/jts/operation/overlay/PointBuilder.java
+++ b/src/com/vividsolutions/jts/operation/overlay/PointBuilder.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.geomgraph.*;
 
 /**
  * Constructs {@link Point}s from the nodes of an overlay graph.
- * @version 1.5
+ * @version 1.6
  */
 public class PointBuilder {
   private OverlayOp op;
diff --git a/src/com/vividsolutions/jts/operation/overlay/PolygonBuilder.java b/src/com/vividsolutions/jts/operation/overlay/PolygonBuilder.java
index 463af35..5d180f1 100644
--- a/src/com/vividsolutions/jts/operation/overlay/PolygonBuilder.java
+++ b/src/com/vividsolutions/jts/operation/overlay/PolygonBuilder.java
@@ -43,7 +43,7 @@ import com.vividsolutions.jts.util.*;
  * The edges to use are marked as being in the result Area.
  * <p>
  *
- * @version 1.5
+ * @version 1.6
  */
 public class PolygonBuilder {
 
@@ -105,6 +105,7 @@ public class PolygonBuilder {
         if (de.getEdgeRing() == null) {
           MaximalEdgeRing er = new MaximalEdgeRing(de, geometryFactory, cga);
           maxEdgeRings.add(er);
+          er.setInResult();
 //System.out.println("max node degree = " + er.getMaxDegree());
         }
       }
@@ -121,7 +122,6 @@ public class PolygonBuilder {
         er.linkDirectedEdgesForMinimalEdgeRings();
         List minEdgeRings = er.buildMinimalRings();
         // at this point we can go ahead and attempt to place holes, if this EdgeRing is a polygon
-        //computePoints(minEdgeRings);
         EdgeRing shell = findShell(minEdgeRings);
         if (shell != null) {
           placePolygonHoles(shell, minEdgeRings);
@@ -193,7 +193,7 @@ public class PolygonBuilder {
   {
     for (Iterator it = edgeRings.iterator(); it.hasNext(); ) {
       EdgeRing er = (EdgeRing) it.next();
-      er.setInResult();
+//      er.setInResult();
       if (er.isHole() ) {
         freeHoleList.add(er);
       }
diff --git a/src/com/vividsolutions/jts/operation/polygonize/EdgeRing.java b/src/com/vividsolutions/jts/operation/polygonize/EdgeRing.java
index e506d5c..72d8eb9 100644
--- a/src/com/vividsolutions/jts/operation/polygonize/EdgeRing.java
+++ b/src/com/vividsolutions/jts/operation/polygonize/EdgeRing.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.planargraph.*;
  * Represents a ring of {@link PolygonizeDirectedEdge}s which form
  * a ring of a polygon.  The ring may be either an outer shell or a hole.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class EdgeRing {
 
diff --git a/src/com/vividsolutions/jts/operation/polygonize/PolygonizeDirectedEdge.java b/src/com/vividsolutions/jts/operation/polygonize/PolygonizeDirectedEdge.java
index 4b984be..fb027da 100644
--- a/src/com/vividsolutions/jts/operation/polygonize/PolygonizeDirectedEdge.java
+++ b/src/com/vividsolutions/jts/operation/polygonize/PolygonizeDirectedEdge.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.planargraph.Node;
  * an edge of a polygon formed by the graph.
  * May be logically deleted from the graph by setting the <code>marked</code> flag.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class PolygonizeDirectedEdge
     extends DirectedEdge
diff --git a/src/com/vividsolutions/jts/operation/polygonize/PolygonizeEdge.java b/src/com/vividsolutions/jts/operation/polygonize/PolygonizeEdge.java
index e747d83..630952e 100644
--- a/src/com/vividsolutions/jts/operation/polygonize/PolygonizeEdge.java
+++ b/src/com/vividsolutions/jts/operation/polygonize/PolygonizeEdge.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.planargraph.*;
 /**
  * An edge of a polygonization graph.
  *
- * @version 1.5
+ * @version 1.6
  */
 class PolygonizeEdge
     extends Edge
diff --git a/src/com/vividsolutions/jts/operation/polygonize/PolygonizeGraph.java b/src/com/vividsolutions/jts/operation/polygonize/PolygonizeGraph.java
index d799073..a0f6a8d 100644
--- a/src/com/vividsolutions/jts/operation/polygonize/PolygonizeGraph.java
+++ b/src/com/vividsolutions/jts/operation/polygonize/PolygonizeGraph.java
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.planargraph.*;
  * The marked flag on {@link DirectedEdge}s is used to indicate that a directed edge
  * has be logically deleted from the graph.
  *
- * @version 1.5
+ * @version 1.6
  */
 class PolygonizeGraph
     extends PlanarGraph
diff --git a/src/com/vividsolutions/jts/operation/polygonize/Polygonizer.java b/src/com/vividsolutions/jts/operation/polygonize/Polygonizer.java
index dfbc06a..37e6047 100644
--- a/src/com/vividsolutions/jts/operation/polygonize/Polygonizer.java
+++ b/src/com/vividsolutions/jts/operation/polygonize/Polygonizer.java
@@ -53,7 +53,7 @@ import com.vividsolutions.jts.geom.*;
  * (e.g. the component lines contain a self-intersection)
  * </ul>
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Polygonizer
 {
diff --git a/src/com/vividsolutions/jts/operation/predicate/RectangleContains.java b/src/com/vividsolutions/jts/operation/predicate/RectangleContains.java
new file mode 100644
index 0000000..2f5838a
--- /dev/null
+++ b/src/com/vividsolutions/jts/operation/predicate/RectangleContains.java
@@ -0,0 +1,122 @@
+package com.vividsolutions.jts.operation.predicate;
+
+import com.vividsolutions.jts.geom.*;
+
+/**
+ * Optimized implementation of spatial predicate "contains"
+ * for cases where the first {@link Geometry} is a rectangle.
+ * <p>
+ * As a further optimization,
+ * this class can be used directly to test many geometries against a single
+ * rectangle.
+ *
+ * @version 1.6
+ */
+public class RectangleContains {
+
+  public static boolean contains(Polygon rectangle, Geometry b)
+  {
+    RectangleContains rc = new RectangleContains(rectangle);
+    return rc.contains(b);
+  }
+
+  private Polygon rectangle;
+  private Envelope rectEnv;
+
+  /**
+   * Create a new contains computer for two geometries.
+   *
+   * @param rectangle a rectangular geometry
+   */
+  public RectangleContains(Polygon rectangle) {
+    this.rectangle = rectangle;
+    rectEnv = rectangle.getEnvelopeInternal();
+  }
+
+  public boolean contains(Geometry geom)
+  {
+    if (! rectEnv.contains(geom.getEnvelopeInternal()))
+      return false;
+    // check that geom is not contained entirely in the rectangle boundary
+    if (isContainedInBoundary(geom))
+      return false;
+    return true;
+  }
+
+  private boolean isContainedInBoundary(Geometry geom)
+  {
+    // polygons can never be wholely contained in the boundary
+    if (geom instanceof Polygon) return false;
+    if (geom instanceof Point) return isPointContainedInBoundary((Point) geom);
+    if (geom instanceof LineString) return isLineStringContainedInBoundary((LineString) geom);
+
+    for (int i = 0; i < geom.getNumGeometries(); i++) {
+      Geometry comp = geom.getGeometryN(i);
+      if (! isContainedInBoundary(comp))
+        return false;
+    }
+    return true;
+  }
+
+  private boolean isPointContainedInBoundary(Point point)
+  {
+    return isPointContainedInBoundary(point.getCoordinate());
+  }
+
+  private boolean isPointContainedInBoundary(Coordinate pt)
+  {
+    // we already know that the point is contained in the rectangle envelope
+
+    if (! (pt.x == rectEnv.getMinX() ||
+           pt.x == rectEnv.getMaxX()) )
+      return false;
+    if (! (pt.y == rectEnv.getMinY() ||
+           pt.y == rectEnv.getMaxY()) )
+      return false;
+
+    return true;
+  }
+
+  private boolean isLineStringContainedInBoundary(LineString line)
+  {
+    CoordinateSequence seq = line.getCoordinateSequence();
+    Coordinate p0 = new Coordinate();
+    Coordinate p1 = new Coordinate();
+    for (int i = 0; i < seq.size() - 1; i++) {
+      seq.getCoordinate(i, p0);
+      seq.getCoordinate(i + 1, p1);
+
+      if (! isLineSegmentContainedInBoundary(p0, p1))
+        return false;
+    }
+    return true;
+  }
+
+  private boolean isLineSegmentContainedInBoundary(Coordinate p0, Coordinate p1)
+  {
+    if (p0.equals(p1))
+      return isPointContainedInBoundary(p0);
+
+    // we already know that the segment is contained in the rectangle envelope
+    if (p0.x == p1.x) {
+      if (p0.x == rectEnv.getMinX() ||
+          p0.x == rectEnv.getMaxX() )
+        return true;
+    }
+    else if (p0.y == p1.y) {
+      if (p0.y == rectEnv.getMinY() ||
+          p0.y == rectEnv.getMaxY() )
+        return true;
+    }
+    /**
+     * Either
+     *   both x and y values are different
+     * or
+     *   one of x and y are the same, but the other ordinate is not the same as a boundary ordinate
+     *
+     * In either case, the segment is not wholely in the boundary
+     */
+    return false;
+  }
+
+}
diff --git a/src/com/vividsolutions/jts/operation/predicate/RectangleIntersects.java b/src/com/vividsolutions/jts/operation/predicate/RectangleIntersects.java
new file mode 100644
index 0000000..278a770
--- /dev/null
+++ b/src/com/vividsolutions/jts/operation/predicate/RectangleIntersects.java
@@ -0,0 +1,211 @@
+package com.vividsolutions.jts.operation.predicate;
+
+import java.util.*;
+import com.vividsolutions.jts.geom.*;
+import com.vividsolutions.jts.algorithm.*;
+import com.vividsolutions.jts.geom.util.*;
+
+/**
+ * Optimized implementation of spatial predicate "intersects"
+ * for cases where the first {@link Geometry} is a rectangle.
+ * <p>
+ * As a further optimization,
+ * this class can be used directly to test many geometries against a single
+ * rectangle.
+ *
+ * @version 1.6
+ */
+public class RectangleIntersects {
+
+  /**
+   * Crossover size at which brute-force intersection scanning
+   * is slower than indexed intersection detection.
+   * Must be determined empirically.  Should err on the
+   * safe side by making value smaller rather than larger.
+   */
+  public static final int MAXIMUM_SCAN_SEGMENT_COUNT = 200;
+
+  public static boolean intersects(Polygon rectangle, Geometry b)
+  {
+    RectangleIntersects rp = new RectangleIntersects(rectangle);
+    return rp.intersects(b);
+  }
+
+  private Polygon rectangle;
+  private Envelope rectEnv;
+
+  /**
+   * Create a new intersects computer for a rectangle.
+   *
+   * @param rectangle a rectangular geometry
+   */
+  public RectangleIntersects(Polygon rectangle) {
+    this.rectangle = rectangle;
+    rectEnv = rectangle.getEnvelopeInternal();
+  }
+
+  public boolean intersects(Geometry geom)
+  {
+    if (! rectEnv.intersects(geom.getEnvelopeInternal()))
+        return false;
+    // test envelope relationships
+    EnvelopeIntersectsVisitor visitor = new EnvelopeIntersectsVisitor(rectEnv);
+    visitor.applyTo(geom);
+    if (visitor.intersects())
+      return true;
+
+    // test if any rectangle corner is contained in the target
+    ContainsPointVisitor ecpVisitor = new ContainsPointVisitor(rectangle);
+    ecpVisitor.applyTo(geom);
+    if (ecpVisitor.containsPoint())
+      return true;
+
+    // test if any lines intersect
+    LineIntersectsVisitor liVisitor = new LineIntersectsVisitor(rectangle);
+    liVisitor.applyTo(geom);
+    if (liVisitor.intersects())
+      return true;
+
+    return false;
+  }
+}
+
+class EnvelopeIntersectsVisitor
+    extends ShortCircuitedGeometryVisitor
+{
+  private Envelope rectEnv;
+  private boolean intersects = false;
+
+  public EnvelopeIntersectsVisitor(Envelope rectEnv)
+  {
+    this.rectEnv = rectEnv;
+  }
+
+  public boolean intersects() { return intersects; }
+
+  protected void visit(Geometry element)
+  {
+    Envelope elementEnv = element.getEnvelopeInternal();
+    // disjoint
+    if (! rectEnv.intersects(elementEnv)) {
+      return;
+    }
+    // fully contained - must intersect
+    if (rectEnv.contains(elementEnv)) {
+      intersects = true;
+      return;
+    }
+    /**
+     * Since the envelopes intersect and the test element is connected,
+     * if its envelope is completely bisected by an edge of the rectangle
+     * the element and the rectangle must touch.
+     * (Note it is NOT possible to make this conclusion
+     * if the test envelope is "on a corner" of the rectangle
+     * envelope)
+     */
+    if (elementEnv.getMinX() >= rectEnv.getMinX()
+        && elementEnv.getMaxX() <= rectEnv.getMaxX()) {
+      intersects = true;
+      return;
+    }
+    if (elementEnv.getMinY() >= rectEnv.getMinY()
+        && elementEnv.getMaxY() <= rectEnv.getMaxY()) {
+      intersects = true;
+      return;
+    }
+  }
+
+  protected boolean isDone() {
+    return intersects == true;
+  }
+}
+
+class ContainsPointVisitor
+    extends ShortCircuitedGeometryVisitor
+{
+  private CoordinateSequence rectSeq;
+  private Envelope rectEnv;
+  private boolean containsPoint = false;
+
+  public ContainsPointVisitor(Polygon rectangle)
+  {
+    this.rectSeq = rectangle.getExteriorRing().getCoordinateSequence();
+    rectEnv = rectangle.getEnvelopeInternal();
+  }
+
+  public boolean containsPoint() { return containsPoint; }
+
+  protected void visit(Geometry geom)
+  {
+    if (! (geom instanceof Polygon))
+      return;
+    Envelope elementEnv = geom.getEnvelopeInternal();
+    if (! rectEnv.intersects(elementEnv))
+      return;
+    // test each corner of rectangle for inclusion
+    Coordinate rectPt = new Coordinate();
+    for (int i = 0; i < 4; i++) {
+      rectSeq.getCoordinate(i, rectPt);
+      if (! elementEnv.contains(rectPt))
+        continue;
+      // check rect point in poly (rect is known not to touch polygon at this point)
+      if (SimplePointInAreaLocator.containsPointInPolygon(rectPt, (Polygon) geom)) {
+        containsPoint = true;
+        return;
+      }
+    }
+  }
+
+  protected boolean isDone() {
+    return containsPoint == true;
+  }
+}
+
+class LineIntersectsVisitor
+    extends ShortCircuitedGeometryVisitor
+{
+  private Polygon rectangle;
+  private CoordinateSequence rectSeq;
+  private Envelope rectEnv;
+  private boolean intersects = false;
+
+  public LineIntersectsVisitor(Polygon rectangle)
+  {
+    this.rectangle = rectangle;
+    this.rectSeq = rectangle.getExteriorRing().getCoordinateSequence();
+    rectEnv = rectangle.getEnvelopeInternal();
+  }
+
+  public boolean intersects() { return intersects; }
+
+  protected void visit(Geometry geom)
+  {
+    Envelope elementEnv = geom.getEnvelopeInternal();
+    if (! rectEnv.intersects(elementEnv))
+      return;
+    // check if general relate algorithm should be used, since it's faster for large inputs
+    if (geom.getNumPoints() > RectangleIntersects.MAXIMUM_SCAN_SEGMENT_COUNT) {
+      intersects = rectangle.relate(geom).isIntersects();
+      return;
+    }
+    computeSegmentIntersection(geom);
+  }
+
+  private void computeSegmentIntersection(Geometry geom)
+  {
+    // check segment intersection
+    // get all lines from geom (e.g. if it's a multi-ring polygon)
+    List lines = LinearComponentExtracter.getLines(geom);
+    SegmentIntersectionTester si = new SegmentIntersectionTester();
+    boolean hasIntersection = si.hasIntersectionWithLineStrings(rectSeq, lines);
+    if (hasIntersection) {
+      intersects = true;
+      return;
+    }
+  }
+
+  protected boolean isDone() {
+    return intersects == true;
+  }
+}
+
diff --git a/src/com/vividsolutions/jts/operation/predicate/SegmentIntersectionTester.java b/src/com/vividsolutions/jts/operation/predicate/SegmentIntersectionTester.java
new file mode 100644
index 0000000..c799243
--- /dev/null
+++ b/src/com/vividsolutions/jts/operation/predicate/SegmentIntersectionTester.java
@@ -0,0 +1,54 @@
+package com.vividsolutions.jts.operation.predicate;
+
+import java.util.*;
+import com.vividsolutions.jts.algorithm.*;
+import com.vividsolutions.jts.geom.*;
+
+/**
+ * Tests if any line segments in two sets of CoordinateSequences intersect.
+ * Optimized for small geometry size.
+ * Short-circuited to return as soon an intersection is found.
+ *
+ * @version 1.6
+ */
+public class SegmentIntersectionTester {
+
+  // for purposes of intersection testing, don't need to set precision model
+  private LineIntersector li = new RobustLineIntersector();
+
+  private boolean hasIntersection = false;
+  private Coordinate pt00 = new Coordinate();
+  private Coordinate pt01 = new Coordinate();
+  private Coordinate pt10 = new Coordinate();
+  private Coordinate pt11 = new Coordinate();
+
+  public SegmentIntersectionTester() {
+  }
+
+  public boolean hasIntersectionWithLineStrings(CoordinateSequence seq, List lines)
+  {
+    for (Iterator i = lines.iterator(); i.hasNext(); ) {
+      LineString line = (LineString) i.next();
+      hasIntersection(seq, line.getCoordinateSequence());
+      if (hasIntersection)
+        break;
+    }
+    return hasIntersection;
+  }
+
+  public boolean hasIntersection(CoordinateSequence seq0, CoordinateSequence seq1) {
+    for (int i = 1; i < seq0.size() && ! hasIntersection; i++) {
+      seq0.getCoordinate(i - 1, pt00);
+      seq0.getCoordinate(i, pt01);
+      for (int j = 1; j < seq1.size() && ! hasIntersection; j++) {
+        seq1.getCoordinate(j - 1, pt10);
+        seq1.getCoordinate(j, pt11);
+
+        li.computeIntersection(pt00, pt01, pt10, pt11);
+        if (li.hasIntersection())
+          hasIntersection = true;
+      }
+    }
+    return hasIntersection;
+  }
+}
diff --git a/src/com/vividsolutions/jts/operation/relate/EdgeEndBuilder.java b/src/com/vividsolutions/jts/operation/relate/EdgeEndBuilder.java
index 2709a7b..d32a4a7 100644
--- a/src/com/vividsolutions/jts/operation/relate/EdgeEndBuilder.java
+++ b/src/com/vividsolutions/jts/operation/relate/EdgeEndBuilder.java
@@ -40,7 +40,7 @@ package com.vividsolutions.jts.operation.relate;
  * created by the
  * intersections determined for an Edge.
  *
- * @version 1.5
+ * @version 1.6
  */
 import java.util.*;
 import com.vividsolutions.jts.geom.*;
@@ -50,7 +50,7 @@ import com.vividsolutions.jts.util.*;
 /**
  * Computes the {@link EdgeEnd}s which arise from a noded {@link Edge}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class EdgeEndBuilder {
 
diff --git a/src/com/vividsolutions/jts/operation/relate/EdgeEndBundle.java b/src/com/vividsolutions/jts/operation/relate/EdgeEndBundle.java
index c4720bd..e1f63a0 100644
--- a/src/com/vividsolutions/jts/operation/relate/EdgeEndBundle.java
+++ b/src/com/vividsolutions/jts/operation/relate/EdgeEndBundle.java
@@ -38,7 +38,7 @@ package com.vividsolutions.jts.operation.relate;
 /**
  * A collection of EdgeStubs which obey the following invariant:
  * They originate at the same node and have the same direction.
- * @version 1.5
+ * @version 1.6
  */
 import java.io.PrintStream;
 import java.util.*;
@@ -50,7 +50,7 @@ import com.vividsolutions.jts.util.Assert;
 /**
  * Contains all {@link EdgeEnd}s which start at the same point and are parallel.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class EdgeEndBundle
   extends EdgeEnd
diff --git a/src/com/vividsolutions/jts/operation/relate/EdgeEndBundleStar.java b/src/com/vividsolutions/jts/operation/relate/EdgeEndBundleStar.java
index 8ea7003..f6e2a44 100644
--- a/src/com/vividsolutions/jts/operation/relate/EdgeEndBundleStar.java
+++ b/src/com/vividsolutions/jts/operation/relate/EdgeEndBundleStar.java
@@ -46,7 +46,7 @@ import com.vividsolutions.jts.util.Assert;
  * An ordered list of {@link EdgeEndBundle}s around a {@link RelateNode}.
  * They are maintained in CCW order (starting with the positive x-axis) around the node
  * for efficient lookup and topology building.
- * @version 1.5
+ * @version 1.6
  */
 public class EdgeEndBundleStar
   extends EdgeEndStar
diff --git a/src/com/vividsolutions/jts/operation/relate/RelateComputer.java b/src/com/vividsolutions/jts/operation/relate/RelateComputer.java
index 02784d1..6beb57a 100644
--- a/src/com/vividsolutions/jts/operation/relate/RelateComputer.java
+++ b/src/com/vividsolutions/jts/operation/relate/RelateComputer.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.operation.relate;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import java.util.*;
 import com.vividsolutions.jts.geom.*;
@@ -58,7 +58,7 @@ import com.vividsolutions.jts.geomgraph.index.SegmentIntersector;
  * would first need to be noded and merged (if not explicitly, at least
  * implicitly).
  *
- * @version 1.5
+ * @version 1.6
  */
 public class RelateComputer
 {
diff --git a/src/com/vividsolutions/jts/operation/relate/RelateNode.java b/src/com/vividsolutions/jts/operation/relate/RelateNode.java
index 9fd4cda..ac1109d 100644
--- a/src/com/vividsolutions/jts/operation/relate/RelateNode.java
+++ b/src/com/vividsolutions/jts/operation/relate/RelateNode.java
@@ -39,7 +39,7 @@ package com.vividsolutions.jts.operation.relate;
  * A RelateNode is a Node that maintains a list of EdgeStubs
  * for the edges that are incident on it.
  *
- * @version 1.5
+ * @version 1.6
  */
 
 import java.io.PrintStream;
@@ -51,7 +51,7 @@ import com.vividsolutions.jts.geomgraph.*;
 /**
  * Represents a node in the topological graph used to compute spatial relationships.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class RelateNode
   extends Node
diff --git a/src/com/vividsolutions/jts/operation/relate/RelateNodeFactory.java b/src/com/vividsolutions/jts/operation/relate/RelateNodeFactory.java
index ed1d2ca..520a28d 100644
--- a/src/com/vividsolutions/jts/operation/relate/RelateNodeFactory.java
+++ b/src/com/vividsolutions/jts/operation/relate/RelateNodeFactory.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.geomgraph.*;
 /**
  * Used by the {@link NodeMap} in a {@link RelateNodeGraph} to create {@link RelateNode}s.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class RelateNodeFactory
   extends NodeFactory
diff --git a/src/com/vividsolutions/jts/operation/relate/RelateNodeGraph.java b/src/com/vividsolutions/jts/operation/relate/RelateNodeGraph.java
index 98f8775..30f9cb3 100644
--- a/src/com/vividsolutions/jts/operation/relate/RelateNodeGraph.java
+++ b/src/com/vividsolutions/jts/operation/relate/RelateNodeGraph.java
@@ -34,7 +34,7 @@
 package com.vividsolutions.jts.operation.relate;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 import java.util.*;
 import com.vividsolutions.jts.geom.*;
@@ -59,7 +59,7 @@ import com.vividsolutions.jts.geomgraph.*;
  * have their topology determined implicitly, without creating a Node object
  * to represent them.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class RelateNodeGraph {
 
diff --git a/src/com/vividsolutions/jts/operation/relate/RelateOp.java b/src/com/vividsolutions/jts/operation/relate/RelateOp.java
index 3fc7874..6ede8b0 100644
--- a/src/com/vividsolutions/jts/operation/relate/RelateOp.java
+++ b/src/com/vividsolutions/jts/operation/relate/RelateOp.java
@@ -36,7 +36,7 @@
 package com.vividsolutions.jts.operation.relate;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 
 import com.vividsolutions.jts.geomgraph.*;
@@ -47,7 +47,7 @@ import java.util.*;
 /**
  * Implements the relate() operation on {@link Geometry}s.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class RelateOp
   extends GeometryGraphOperation
diff --git a/src/com/vividsolutions/jts/operation/valid/ConnectedInteriorTester.java b/src/com/vividsolutions/jts/operation/valid/ConnectedInteriorTester.java
index 81ddffc..d3fe9b1 100644
--- a/src/com/vividsolutions/jts/operation/valid/ConnectedInteriorTester.java
+++ b/src/com/vividsolutions/jts/operation/valid/ConnectedInteriorTester.java
@@ -53,7 +53,7 @@ import com.vividsolutions.jts.util.*;
  * If an inconsistency if found the location of the problem
  * is recorded.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class ConnectedInteriorTester {
 
diff --git a/src/com/vividsolutions/jts/operation/valid/ConsistentAreaTester.java b/src/com/vividsolutions/jts/operation/valid/ConsistentAreaTester.java
index 47443bf..a2fda05 100644
--- a/src/com/vividsolutions/jts/operation/valid/ConsistentAreaTester.java
+++ b/src/com/vividsolutions/jts/operation/valid/ConsistentAreaTester.java
@@ -55,7 +55,7 @@ import com.vividsolutions.jts.util.*;
  * If an inconsistency if found the location of the problem
  * is recorded.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class ConsistentAreaTester {
 
diff --git a/src/com/vividsolutions/jts/operation/valid/IsValidOp.java b/src/com/vividsolutions/jts/operation/valid/IsValidOp.java
index 83005f3..d17e4bc 100644
--- a/src/com/vividsolutions/jts/operation/valid/IsValidOp.java
+++ b/src/com/vividsolutions/jts/operation/valid/IsValidOp.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.util.*;
  * Implements the algorithsm required to compute the <code>isValid()</code> method
  * for {@link Geometry}s.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class IsValidOp
 {
diff --git a/src/com/vividsolutions/jts/operation/valid/QuadtreeNestedRingTester.java b/src/com/vividsolutions/jts/operation/valid/QuadtreeNestedRingTester.java
index 0eacc4c..0e2ff23 100644
--- a/src/com/vividsolutions/jts/operation/valid/QuadtreeNestedRingTester.java
+++ b/src/com/vividsolutions/jts/operation/valid/QuadtreeNestedRingTester.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.util.*;
  * nested inside another ring in the set, using a {@link Quadtree}
  * index to speed up the comparisons.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class QuadtreeNestedRingTester
 {
diff --git a/src/com/vividsolutions/jts/operation/valid/RepeatedPointTester.java b/src/com/vividsolutions/jts/operation/valid/RepeatedPointTester.java
index c5f1fbb..f3eec34 100644
--- a/src/com/vividsolutions/jts/operation/valid/RepeatedPointTester.java
+++ b/src/com/vividsolutions/jts/operation/valid/RepeatedPointTester.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.geom.*;
  * (consecutive identical coordinates) as defined in the
  * JTS spec.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class RepeatedPointTester {
 
diff --git a/src/com/vividsolutions/jts/operation/valid/SimpleNestedRingTester.java b/src/com/vividsolutions/jts/operation/valid/SimpleNestedRingTester.java
index f697539..821fc95 100644
--- a/src/com/vividsolutions/jts/operation/valid/SimpleNestedRingTester.java
+++ b/src/com/vividsolutions/jts/operation/valid/SimpleNestedRingTester.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.util.*;
  * nested inside another ring in the set, using a simple O(n^2)
  * comparison.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SimpleNestedRingTester
 {
diff --git a/src/com/vividsolutions/jts/operation/valid/SweeplineNestedRingTester.java b/src/com/vividsolutions/jts/operation/valid/SweeplineNestedRingTester.java
index e729bad..c924e89 100644
--- a/src/com/vividsolutions/jts/operation/valid/SweeplineNestedRingTester.java
+++ b/src/com/vividsolutions/jts/operation/valid/SweeplineNestedRingTester.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.util.*;
  * nested inside another ring in the set, using a {@link SweepLineIndex}
  * index to speed up the comparisons.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SweeplineNestedRingTester
 {
diff --git a/src/com/vividsolutions/jts/operation/valid/TopologyValidationError.java b/src/com/vividsolutions/jts/operation/valid/TopologyValidationError.java
index f066425..a25565c 100644
--- a/src/com/vividsolutions/jts/operation/valid/TopologyValidationError.java
+++ b/src/com/vividsolutions/jts/operation/valid/TopologyValidationError.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.geom.Coordinate;
  * Contains information about the nature and location of a {@link Geometry}
  * validation error
  *
- * @version 1.5
+ * @version 1.6
  */
 public class TopologyValidationError {
 
diff --git a/src/com/vividsolutions/jts/planargraph/DirectedEdge.java b/src/com/vividsolutions/jts/planargraph/DirectedEdge.java
index f48d9ac..f36a5c2 100644
--- a/src/com/vividsolutions/jts/planargraph/DirectedEdge.java
+++ b/src/com/vividsolutions/jts/planargraph/DirectedEdge.java
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.geomgraph.Quadrant;
  * a client using a <code>PlanarGraph</code> will subclass <code>DirectedEdge</code>
  * to add its own application-specific data and methods.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class DirectedEdge
     extends GraphComponent
diff --git a/src/com/vividsolutions/jts/planargraph/DirectedEdgeStar.java b/src/com/vividsolutions/jts/planargraph/DirectedEdgeStar.java
index 62e5a26..924a0e1 100644
--- a/src/com/vividsolutions/jts/planargraph/DirectedEdgeStar.java
+++ b/src/com/vividsolutions/jts/planargraph/DirectedEdgeStar.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.geom.Coordinate;
  * A sorted collection of {@link DirectedEdge}s which leave a {@link Node}
  * in a {@link PlanarGraph}.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class DirectedEdgeStar
 {
diff --git a/src/com/vividsolutions/jts/planargraph/Edge.java b/src/com/vividsolutions/jts/planargraph/Edge.java
index 3cbe2d7..eac8adc 100644
--- a/src/com/vividsolutions/jts/planargraph/Edge.java
+++ b/src/com/vividsolutions/jts/planargraph/Edge.java
@@ -41,7 +41,7 @@ package com.vividsolutions.jts.planargraph;
  * Usually a client using a <code>PlanarGraph</code> will subclass <code>Edge</code>
  * to add its own application-specific data and methods.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Edge
     extends GraphComponent
diff --git a/src/com/vividsolutions/jts/planargraph/GraphComponent.java b/src/com/vividsolutions/jts/planargraph/GraphComponent.java
index 3c5124b..28a9209 100644
--- a/src/com/vividsolutions/jts/planargraph/GraphComponent.java
+++ b/src/com/vividsolutions/jts/planargraph/GraphComponent.java
@@ -46,7 +46,7 @@ package com.vividsolutions.jts.planargraph;
  * graph might use this to indicate that a node has already been traversed.
  * The visited flag may be set and cleared many times during the lifetime of a graph.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class GraphComponent {
 
diff --git a/src/com/vividsolutions/jts/planargraph/Node.java b/src/com/vividsolutions/jts/planargraph/Node.java
index d16f3a6..2f5a5f0 100644
--- a/src/com/vividsolutions/jts/planargraph/Node.java
+++ b/src/com/vividsolutions/jts/planargraph/Node.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.geom.Coordinate;
  * subclass <code>Node</code> to add their own application-specific
  * data and methods.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Node
     extends GraphComponent
diff --git a/src/com/vividsolutions/jts/planargraph/NodeMap.java b/src/com/vividsolutions/jts/planargraph/NodeMap.java
index 4e08c2a..ed904e4 100644
--- a/src/com/vividsolutions/jts/planargraph/NodeMap.java
+++ b/src/com/vividsolutions/jts/planargraph/NodeMap.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.geom.Coordinate;
 /**
  * A map of {@link Node}s, indexed by the coordinate of the node.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class NodeMap
 
diff --git a/src/com/vividsolutions/jts/planargraph/PlanarGraph.java b/src/com/vividsolutions/jts/planargraph/PlanarGraph.java
index 7b072df..cb7a8f8 100644
--- a/src/com/vividsolutions/jts/planargraph/PlanarGraph.java
+++ b/src/com/vividsolutions/jts/planargraph/PlanarGraph.java
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.geom.Coordinate;
  * subclasses for one or more graph components, which hold application-specific
  * data and graph algorithms.
  *
- * @version 1.5
+ * @version 1.6
  */
 public abstract class PlanarGraph
 {
diff --git a/src/com/vividsolutions/jts/precision/CommonBits.java b/src/com/vividsolutions/jts/precision/CommonBits.java
index 7771238..d429799 100644
--- a/src/com/vividsolutions/jts/precision/CommonBits.java
+++ b/src/com/vividsolutions/jts/precision/CommonBits.java
@@ -40,7 +40,7 @@ package com.vividsolutions.jts.precision;
  * is represented by the common bits.
  * If there are no common bits, the number computed is 0.0.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class CommonBits {
 
diff --git a/src/com/vividsolutions/jts/precision/CommonBitsOp.java b/src/com/vividsolutions/jts/precision/CommonBitsOp.java
index 610bdf4..e5562ad 100644
--- a/src/com/vividsolutions/jts/precision/CommonBitsOp.java
+++ b/src/com/vividsolutions/jts/precision/CommonBitsOp.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.geom.*;
  * that the returned Geometry is invalid.
  * Client classes should check the validity of the returned result themselves.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class CommonBitsOp {
 
diff --git a/src/com/vividsolutions/jts/precision/CommonBitsRemover.java b/src/com/vividsolutions/jts/precision/CommonBitsRemover.java
index 11674a2..3268c69 100644
--- a/src/com/vividsolutions/jts/precision/CommonBitsRemover.java
+++ b/src/com/vividsolutions/jts/precision/CommonBitsRemover.java
@@ -38,7 +38,7 @@ import com.vividsolutions.jts.geom.*;
 /**
  * Allow computing and removing common mantissa bits from one or more Geometries.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class CommonBitsRemover
 {
diff --git a/src/com/vividsolutions/jts/precision/EnhancedPrecisionOp.java b/src/com/vividsolutions/jts/precision/EnhancedPrecisionOp.java
index c72ce36..d7abe5e 100644
--- a/src/com/vividsolutions/jts/precision/EnhancedPrecisionOp.java
+++ b/src/com/vividsolutions/jts/precision/EnhancedPrecisionOp.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.operation.overlay.OverlayOp;
   * Provides versions of Geometry spatial functions which use
   * enhanced precision techniques to reduce the likelihood of robustness problems.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class EnhancedPrecisionOp
 {
diff --git a/src/com/vividsolutions/jts/precision/SimpleGeometryPrecisionReducer.java b/src/com/vividsolutions/jts/precision/SimpleGeometryPrecisionReducer.java
index 795706d..aa6f416 100644
--- a/src/com/vividsolutions/jts/precision/SimpleGeometryPrecisionReducer.java
+++ b/src/com/vividsolutions/jts/precision/SimpleGeometryPrecisionReducer.java
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.geom.util.*;
  * is simplifying the input to the buffer algorithm.
  * The buffer algorithm does not depend on the validity of the input geometry.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SimpleGeometryPrecisionReducer
 {
@@ -90,7 +90,7 @@ public class SimpleGeometryPrecisionReducer
   {
     GeometryEditor geomEdit;
     if (changePrecisionModel) {
-      GeometryFactory newFactory = new GeometryFactory(newPrecisionModel, geom.getSRID());
+      GeometryFactory newFactory = new GeometryFactory(newPrecisionModel, geom.getFactory().getSRID());
       geomEdit = new GeometryEditor(newFactory);
     }
     else
diff --git a/src/com/vividsolutions/jts/simplify/DouglasPeuckerLineSimplifier.java b/src/com/vividsolutions/jts/simplify/DouglasPeuckerLineSimplifier.java
index 535f460..d845fcd 100644
--- a/src/com/vividsolutions/jts/simplify/DouglasPeuckerLineSimplifier.java
+++ b/src/com/vividsolutions/jts/simplify/DouglasPeuckerLineSimplifier.java
@@ -4,10 +4,10 @@ import java.util.*;
 import com.vividsolutions.jts.geom.*;
 
 /**
- * Simplifies a line (sequence of points) using
+ * Simplifies a linestring (sequence of points) using
  * the standard Douglas-Peucker algorithm.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class DouglasPeuckerLineSimplifier
 {
@@ -26,6 +26,13 @@ public class DouglasPeuckerLineSimplifier
   {
     this.pts = pts;
   }
+  /**
+   * Sets the distance tolerance for the simplification.
+   * All vertices in the simplified linestring will be within this
+   * distance of the original linestring.
+   *
+   * @param distanceTolerance the approximation tolerance to use
+   */
   public void setDistanceTolerance(double distanceTolerance) {
     this.distanceTolerance = distanceTolerance;
   }
diff --git a/src/com/vividsolutions/jts/simplify/DouglasPeuckerSimplifier.java b/src/com/vividsolutions/jts/simplify/DouglasPeuckerSimplifier.java
index 0fc35f5..5672247 100644
--- a/src/com/vividsolutions/jts/simplify/DouglasPeuckerSimplifier.java
+++ b/src/com/vividsolutions/jts/simplify/DouglasPeuckerSimplifier.java
@@ -13,14 +13,13 @@ import com.vividsolutions.jts.geom.util.*;
  * e.g. polygons can be split, collapse to lines or disappear
  * holes can be created or disappear,
  * and lines can cross.
- * To simplify geometry while preserving topology use {@link TopologySafeSimplifier}.
+ * To simplify geometry while preserving topology use {@link TopologyPreservingSimplifier}.
  * (However, using D-P is significantly faster).
  *
- * @version 1.5
+ * @version 1.6
  */
 public class DouglasPeuckerSimplifier
 {
-  // TODO: prevent polygons and lines from disappearing if they are too flat or small
 
   public static Geometry simplify(Geometry geom, double distanceTolerance)
   {
@@ -37,6 +36,13 @@ public class DouglasPeuckerSimplifier
     this.inputGeom = inputGeom;
   }
 
+  /**
+   * Sets the distance tolerance for the simplification.
+   * All vertices in the simplified geometry will be within this
+   * distance of the original geometry.
+   *
+   * @param distanceTolerance the approximation tolerance to use
+   */
   public void setDistanceTolerance(double distanceTolerance) {
     this.distanceTolerance = distanceTolerance;
   }
diff --git a/src/com/vividsolutions/jts/simplify/TaggedLineString.java b/src/com/vividsolutions/jts/simplify/TaggedLineString.java
index 91abf85..e4caf59 100644
--- a/src/com/vividsolutions/jts/simplify/TaggedLineString.java
+++ b/src/com/vividsolutions/jts/simplify/TaggedLineString.java
@@ -4,7 +4,7 @@ import java.util.*;
 import com.vividsolutions.jts.geom.*;
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class TaggedLineString {
 
diff --git a/src/com/vividsolutions/jts/simplify/TaggedLineStringSimplifier.java b/src/com/vividsolutions/jts/simplify/TaggedLineStringSimplifier.java
index 523bbbf..b1dbde5 100644
--- a/src/com/vividsolutions/jts/simplify/TaggedLineStringSimplifier.java
+++ b/src/com/vividsolutions/jts/simplify/TaggedLineStringSimplifier.java
@@ -8,9 +8,9 @@ import com.vividsolutions.jts.util.Debug;
 /**
  * Simplifies a TaggedLineString, preserving topology
  * (in the sense that no new intersections are introduced).
- * Uses the recursive D-P algorithm.
+ * Uses the recursive Douglas-Peucker algorithm.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class TaggedLineStringSimplifier
 {
@@ -29,6 +29,13 @@ public class TaggedLineStringSimplifier
     this.outputIndex = outputIndex;
   }
 
+  /**
+   * Sets the distance tolerance for the simplification.
+   * All vertices in the simplified geometry will be within this
+   * distance of the original geometry.
+   *
+   * @param distanceTolerance the approximation tolerance to use
+   */
   public void setDistanceTolerance(double distanceTolerance) {
     this.distanceTolerance = distanceTolerance;
   }
@@ -51,23 +58,33 @@ public class TaggedLineStringSimplifier
       return;
     }
 
+    boolean isValidToSimplify = true;
+
+    /**
+     * Following logic ensures that there is enough points in the output line.
+     * If there is already more points than the minimum, there's nothing to check.
+     * Otherwise, if in the worst case there wouldn't be enough points,
+     * don't flatten this segment (which avoids the worst case scenario)
+     */
+    if (line.getResultSize() < line.getMinimumSize()) {
+      int worstCaseSize = depth + 1;
+      if (worstCaseSize < line.getMinimumSize())
+        isValidToSimplify = false;
+    }
+
     double[] distance = new double[1];
     int furthestPtIndex = findFurthestPoint(linePts, i, j, distance);
-    boolean isValidToFlatten = true;
-
-    // must have enough points in the output line
-    if (line.getResultSize() < line.getMinimumSize() && depth < 2) isValidToFlatten = false;
     // flattening must be less than distanceTolerance
-    if (distance[0] > distanceTolerance) isValidToFlatten = false;
+    if (distance[0] > distanceTolerance) isValidToSimplify = false;
     // test if flattened section would cause intersection
     LineSegment candidateSeg = new LineSegment();
     candidateSeg.p0 = linePts[i];
     candidateSeg.p1 = linePts[j];
     sectionIndex[0] = i;
     sectionIndex[1] = j;
-    if (hasBadIntersection(line, sectionIndex, candidateSeg)) isValidToFlatten = false;
+    if (hasBadIntersection(line, sectionIndex, candidateSeg)) isValidToSimplify = false;
 
-    if (isValidToFlatten) {
+    if (isValidToSimplify) {
       LineSegment newSeg = flatten(i, j);
       line.addToResult(newSeg);
       return;
diff --git a/src/com/vividsolutions/jts/simplify/TaggedLinesSimplifier.java b/src/com/vividsolutions/jts/simplify/TaggedLinesSimplifier.java
index 92f8c78..7fbc9d0 100644
--- a/src/com/vividsolutions/jts/simplify/TaggedLinesSimplifier.java
+++ b/src/com/vividsolutions/jts/simplify/TaggedLinesSimplifier.java
@@ -20,10 +20,10 @@ public class TaggedLinesSimplifier
 
   /**
    * Sets the distance tolerance for the simplification.
-   * Points closer than this tolerance to a simplified segment may
-   * be removed.
+   * All vertices in the simplified geometry will be within this
+   * distance of the original geometry.
    *
-   * @param distanceTolerance the distance tolerance
+   * @param distanceTolerance the approximation tolerance to use
    */
   public void setDistanceTolerance(double distanceTolerance) {
     this.distanceTolerance = distanceTolerance;
diff --git a/src/com/vividsolutions/jts/simplify/TopologyPreservingSimplifier.java b/src/com/vividsolutions/jts/simplify/TopologyPreservingSimplifier.java
index 2be4104..3a01f35 100644
--- a/src/com/vividsolutions/jts/simplify/TopologyPreservingSimplifier.java
+++ b/src/com/vividsolutions/jts/simplify/TopologyPreservingSimplifier.java
@@ -42,6 +42,13 @@ public class TopologyPreservingSimplifier
     //inputIndex = new LineSegmentIndex(new STRtree());
   }
 
+  /**
+   * Sets the distance tolerance for the simplification.
+   * All vertices in the simplified geometry will be within this
+   * distance of the original geometry.
+   *
+   * @param distanceTolerance the approximation tolerance to use
+   */
   public void setDistanceTolerance(double distanceTolerance) {
     lineSimplifier.setDistanceTolerance(distanceTolerance);
   }
diff --git a/src/com/vividsolutions/jts/util/Assert.java b/src/com/vividsolutions/jts/util/Assert.java
index 57426ad..88034ac 100644
--- a/src/com/vividsolutions/jts/util/Assert.java
+++ b/src/com/vividsolutions/jts/util/Assert.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.util.AssertionFailedException;
 /**
  *  A utility for making programming assertions.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class Assert {
 
diff --git a/src/com/vividsolutions/jts/util/AssertionFailedException.java b/src/com/vividsolutions/jts/util/AssertionFailedException.java
index 8f48d84..a4f5e96 100644
--- a/src/com/vividsolutions/jts/util/AssertionFailedException.java
+++ b/src/com/vividsolutions/jts/util/AssertionFailedException.java
@@ -38,7 +38,7 @@ package com.vividsolutions.jts.util;
  *  Thrown when the application is in an inconsistent state. Indicates a problem
  *  with the code.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class AssertionFailedException extends RuntimeException {
 
diff --git a/src/com/vividsolutions/jts/util/CoordinateArrayFilter.java b/src/com/vividsolutions/jts/util/CoordinateArrayFilter.java
index fcee0e3..c0e4a50 100644
--- a/src/com/vividsolutions/jts/util/CoordinateArrayFilter.java
+++ b/src/com/vividsolutions/jts/util/CoordinateArrayFilter.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.geom.*;
  *  A {@link CoordinateFilter} that creates an array containing every
  *  coordinate in a {@link Geometry}.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class CoordinateArrayFilter implements CoordinateFilter {
   Coordinate[] pts = null;
diff --git a/src/com/vividsolutions/jts/util/CoordinateCountFilter.java b/src/com/vividsolutions/jts/util/CoordinateCountFilter.java
index 1057cab..30e9c59 100644
--- a/src/com/vividsolutions/jts/util/CoordinateCountFilter.java
+++ b/src/com/vividsolutions/jts/util/CoordinateCountFilter.java
@@ -40,7 +40,7 @@ import com.vividsolutions.jts.geom.*;
  *  A {@link CoordinateFilter} that counts the total number of coordinates
  *  in a <code>Geometry</code>.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class CoordinateCountFilter implements CoordinateFilter {
   private int n = 0;
diff --git a/src/com/vividsolutions/jts/util/Debug.java b/src/com/vividsolutions/jts/util/Debug.java
index c8e6780..657cdc9 100644
--- a/src/com/vividsolutions/jts/util/Debug.java
+++ b/src/com/vividsolutions/jts/util/Debug.java
@@ -35,7 +35,7 @@
 package com.vividsolutions.jts.util;
 
 /**
- *@version 1.5
+ *@version 1.6
  */
 import java.io.*;
 import java.util.*;
@@ -44,11 +44,31 @@ import java.lang.reflect.*;
 /**
  * Provides routines to simplify and localize debugging output.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Debug {
 
-  private static boolean debugOn = true;
+  private static String DEBUG_PROPERTY_NAME = "debug";
+  private static String DEBUG_PROPERTY_VALUE_ON = "on";
+  private static String DEBUG_PROPERTY_VALUE_TRUE = "true";
+
+  private static boolean debugOn = false;
+
+  static {
+    String debugValue = System.getProperty(DEBUG_PROPERTY_NAME);
+    if (debugValue != null) {
+      if (debugValue.equalsIgnoreCase(DEBUG_PROPERTY_VALUE_ON)
+          || debugValue.equalsIgnoreCase(DEBUG_PROPERTY_VALUE_TRUE) )
+        debugOn = true;
+    }
+  }
+
+
+  public static void main(String[] args)
+  {
+    Debug.println("Debugging is ON");
+  }
+
   private static Debug debug = new Debug();
 
   private static final String DEBUG_LINE_TAG = "D! ";
@@ -58,6 +78,8 @@ public class Debug {
   private Object watchObj = null;
   private Object[] args = new Object[1];
 
+  public static boolean isDebugging() { return debugOn; }
+
   public static void print(String str) {
     if (!debugOn) {
       return;
diff --git a/src/com/vividsolutions/jts/util/GeometricShapeFactory.java b/src/com/vividsolutions/jts/util/GeometricShapeFactory.java
index db99c1e..6c98a59 100644
--- a/src/com/vividsolutions/jts/util/GeometricShapeFactory.java
+++ b/src/com/vividsolutions/jts/util/GeometricShapeFactory.java
@@ -43,7 +43,7 @@ import com.vividsolutions.jts.geom.*;
  * Allows various ways of specifying the location and extent of the shapes,
  * as well as number of line segments used to form them.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class GeometricShapeFactory
 {
diff --git a/src/com/vividsolutions/jts/util/Stopwatch.java b/src/com/vividsolutions/jts/util/Stopwatch.java
index 05428a4..43edefc 100644
--- a/src/com/vividsolutions/jts/util/Stopwatch.java
+++ b/src/com/vividsolutions/jts/util/Stopwatch.java
@@ -37,7 +37,7 @@ package com.vividsolutions.jts.util;
  * Implements a timer function which can compute
  * elapsed time as well as split times.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class Stopwatch {
 
diff --git a/src/com/vividsolutions/jts/util/UniqueCoordinateArrayFilter.java b/src/com/vividsolutions/jts/util/UniqueCoordinateArrayFilter.java
index 92ae723..526c8a2 100644
--- a/src/com/vividsolutions/jts/util/UniqueCoordinateArrayFilter.java
+++ b/src/com/vividsolutions/jts/util/UniqueCoordinateArrayFilter.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.geom.CoordinateFilter;
  *  A {@link CoordinateFilter} that builds a set of <code>Coordinate</code>s.
  *  The set of coordinates contains no duplicate points.
  *
- *@version 1.5
+ *@version 1.6
  */
 public class UniqueCoordinateArrayFilter implements CoordinateFilter {
   TreeSet treeSet = new TreeSet();
diff --git a/src/com/vividsolutions/jtsexample/geom/BasicExample.java b/src/com/vividsolutions/jtsexample/geom/BasicExample.java
index cad705b..403511e 100644
--- a/src/com/vividsolutions/jtsexample/geom/BasicExample.java
+++ b/src/com/vividsolutions/jtsexample/geom/BasicExample.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.io.WKTReader;
 /**
  * Shows basic ways of creating and operating on geometries
  *
- * @version 1.5
+ * @version 1.6
  */
 public class BasicExample
 {
diff --git a/src/com/vividsolutions/jtsexample/geom/ConstructionExample.java b/src/com/vividsolutions/jtsexample/geom/ConstructionExample.java
index 4739f5e..931a396 100644
--- a/src/com/vividsolutions/jtsexample/geom/ConstructionExample.java
+++ b/src/com/vividsolutions/jtsexample/geom/ConstructionExample.java
@@ -16,7 +16,7 @@ import com.vividsolutions.jts.geom.*;
  * <li>Insulates your code from changes in the signature of JTS constructors
  * </ol>
  *
- * @version 1.5
+ * @version 1.6
  */
 public class ConstructionExample
 {
diff --git a/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinate.java b/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinate.java
index 8f5a180..bf7d747 100644
--- a/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinate.java
+++ b/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinate.java
@@ -37,7 +37,7 @@ import com.vividsolutions.jts.geom.*;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class ExtendedCoordinate
     extends Coordinate
@@ -63,7 +63,10 @@ public class ExtendedCoordinate
   public ExtendedCoordinate(Coordinate coord)
   {
     super(coord);
-    m = 0.0;
+    if (coord instanceof ExtendedCoordinate)
+      m = ((ExtendedCoordinate) coord).m;
+    else
+      m = Double.NaN;
   }
 
   public ExtendedCoordinate(ExtendedCoordinate coord)
diff --git a/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateExample.java b/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateExample.java
index 3f28b21..5772b55 100644
--- a/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateExample.java
+++ b/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateExample.java
@@ -37,7 +37,7 @@ import com.vividsolutions.jts.geom.*;
 
 
 /**
- * @version 1.5
+ * @version 1.6
  */
 public class ExtendedCoordinateExample
 {
diff --git a/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequence.java b/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequence.java
index e3cb6b1..ca2ae11 100644
--- a/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequence.java
+++ b/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequence.java
@@ -33,19 +33,19 @@
  */
 package com.vividsolutions.jtsexample.geom;
 
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.CoordinateSequence;
+import com.vividsolutions.jts.geom.*;
 
 /**
  * Demonstrates how to implement a CoordinateSequence for a new kind of
  * coordinate (an {@link ExtendedCoordinate} in this example). In this
  * implementation, Coordinates returned by #toArray and #get are live -- parties
- * that change them are actually changing the ExtendedCoordinateSequence's 
+ * that change them are actually changing the ExtendedCoordinateSequence's
  * underlying data.
  *
- * @version 1.5
+ * @version 1.6
  */
-public class ExtendedCoordinateSequence implements CoordinateSequence
+public class ExtendedCoordinateSequence
+    implements CoordinateSequence
 {
   public static ExtendedCoordinate[] copy(Coordinate[] coordinates)
   {
@@ -56,8 +56,17 @@ public class ExtendedCoordinateSequence implements CoordinateSequence
     return copy;
   }
 
+  public static ExtendedCoordinate[] copy(CoordinateSequence coordSeq)
+  {
+    ExtendedCoordinate[] copy = new ExtendedCoordinate[coordSeq.size()];
+    for (int i = 0; i < coordSeq.size(); i++) {
+      copy[i] = new ExtendedCoordinate(coordSeq.getCoordinate(i));
+    }
+    return copy;
+  }
+
   private ExtendedCoordinate[] coordinates;
-  
+
   /**
    * Copy constructor -- simply aliases the input array, for better performance.
    */
@@ -66,7 +75,7 @@ public class ExtendedCoordinateSequence implements CoordinateSequence
   }
 
   /**
-   * Constructor that makes a copy of an existing array of Coordinates.
+   * Constructor that makes a copy of an array of Coordinates.
    * Always makes a copy of the input array, since the actual class
    * of the Coordinates in the input array may be different from ExtendedCoordinate.
    */
@@ -74,10 +83,87 @@ public class ExtendedCoordinateSequence implements CoordinateSequence
     coordinates = copy(copyCoords);
   }
 
+  /**
+   * Constructor that makes a copy of a CoordinateSequence.
+   */
+  public ExtendedCoordinateSequence(CoordinateSequence coordSeq) {
+    coordinates = copy(coordSeq);
+  }
+
+  /**
+   * Constructs a sequence of a given size, populated
+   * with new {@link ExtendedCoordinate}s.
+   *
+   * @param size the size of the sequence to create
+   */
+  public ExtendedCoordinateSequence(int size) {
+    coordinates = new ExtendedCoordinate[size];
+    for (int i = 0; i < size; i++) {
+      coordinates[i] = new ExtendedCoordinate();
+    }
+  }
+
+
   public Coordinate getCoordinate(int i) {
     return coordinates[i];
   }
 
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int)
+   */
+  public Coordinate getCoordinateCopy(int index) {
+    return new Coordinate(coordinates[index]);
+  }
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int)
+   */
+  public void getCoordinate(int index, Coordinate coord) {
+    coord.x = coordinates[index].x;
+    coord.y = coordinates[index].y;
+  }
+
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getX(int)
+   */
+  public double getX(int index) {
+      return coordinates[index].x;
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getY(int)
+   */
+  public double getY(int index) {
+      return coordinates[index].y;
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#getOrdinate(int, int)
+   */
+  public double getOrdinate(int index, int ordinateIndex)
+  {
+    switch (ordinateIndex) {
+      case CoordinateSequence.X:  return coordinates[index].x;
+      case CoordinateSequence.Y:  return coordinates[index].y;
+      case CoordinateSequence.Z:  return coordinates[index].z;
+      case 4:  return coordinates[index].getM();
+    }
+    return Double.NaN;
+  }
+
+  /**
+   * @see com.vividsolutions.jts.geom.CoordinateSequence#setOrdinate(int, int, double)
+   */
+  public void setOrdinate(int index, int ordinateIndex, double value)
+  {
+    switch (ordinateIndex) {
+      case CoordinateSequence.X:  coordinates[index].x = value;
+      case CoordinateSequence.Y:  coordinates[index].y = value;
+      case CoordinateSequence.Z:  coordinates[index].z = value;
+      case 4:  coordinates[index].setM(value);
+    }
+  }
+
   public Object clone() {
     ExtendedCoordinate[] cloneCoordinates = new ExtendedCoordinate[size()];
     for (int i = 0; i < coordinates.length; i++) {
@@ -95,6 +181,14 @@ public class ExtendedCoordinateSequence implements CoordinateSequence
     return coordinates;
   }
 
+  public Envelope expandEnvelope(Envelope env)
+  {
+    for (int i = 0; i < coordinates.length; i++ ) {
+      env.expandToInclude(coordinates[i]);
+    }
+    return env;
+  }
+
   public String toString()
   {
     StringBuffer strBuf = new StringBuffer();
diff --git a/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequenceFactory.java b/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequenceFactory.java
index 7277038..e7e9012 100644
--- a/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequenceFactory.java
+++ b/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequenceFactory.java
@@ -39,7 +39,7 @@ import com.vividsolutions.jts.geom.*;
  * Creates ExtendedCoordinateSequenceFactory internally represented
  * as an array of {@link ExtendedCoordinate}s.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class ExtendedCoordinateSequenceFactory
     implements CoordinateSequenceFactory
@@ -54,8 +54,8 @@ public class ExtendedCoordinateSequenceFactory
      */
     public static ExtendedCoordinateSequenceFactory instance() {
         return instance;
-    }        
-  
+    }
+
     /**
      * Returns an ExtendedCoordinateSequence based on the given array -- the array is used
      * directly if it is an instance of ExtendedCoordinate[]; otherwise it is
@@ -67,4 +67,17 @@ public class ExtendedCoordinateSequenceFactory
           : new ExtendedCoordinateSequence(coordinates);
     }
 
+    public CoordinateSequence create(CoordinateSequence coordSeq) {
+      return coordSeq instanceof ExtendedCoordinateSequence
+          ? new ExtendedCoordinateSequence((ExtendedCoordinateSequence) coordSeq)
+          : new ExtendedCoordinateSequence(coordSeq);
+    }
+
+    /**
+     * @see com.vividsolutions.jts.geom.CoordinateSequenceFactory#create(int, int)
+     */
+    public CoordinateSequence create(int size, int dimension) {
+      return new ExtendedCoordinateSequence(size);
+    }
+
 }
diff --git a/src/com/vividsolutions/jtsexample/geom/PrecisionModelExample.java b/src/com/vividsolutions/jtsexample/geom/PrecisionModelExample.java
index db9d0bc..6418ec8 100644
--- a/src/com/vividsolutions/jtsexample/geom/PrecisionModelExample.java
+++ b/src/com/vividsolutions/jtsexample/geom/PrecisionModelExample.java
@@ -45,7 +45,7 @@ import com.vividsolutions.jts.io.*;
  * The output shows the effects of rounding in the single-precision and fixed-precision
  * models.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class PrecisionModelExample
 {
diff --git a/src/com/vividsolutions/jtsexample/geom/SimpleMethodsExample.java b/src/com/vividsolutions/jtsexample/geom/SimpleMethodsExample.java
index 9de18b2..bd5c71c 100644
--- a/src/com/vividsolutions/jtsexample/geom/SimpleMethodsExample.java
+++ b/src/com/vividsolutions/jtsexample/geom/SimpleMethodsExample.java
@@ -54,7 +54,7 @@ import com.vividsolutions.jts.io.*;
  * ----------------------------------------------------------
  * </pre>
  *
- * @version 1.5
+ * @version 1.6
  */
 public class SimpleMethodsExample
 {
diff --git a/src/com/vividsolutions/jtsexample/geom/TwoArrayCoordinateSequenceExample.java b/src/com/vividsolutions/jtsexample/geom/TwoArrayCoordinateSequenceExample.java
deleted file mode 100644
index 2cd5248..0000000
--- a/src/com/vividsolutions/jtsexample/geom/TwoArrayCoordinateSequenceExample.java
+++ /dev/null
@@ -1,89 +0,0 @@
-
-/*
- * The JTS Topology Suite is a collection of Java classes that
- * implement the fundamental operations required to validate a given
- * geo-spatial data set to a known topological specification.
- *
- * Copyright (C) 2001 Vivid Solutions
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * For more information, contact:
- *
- *     Vivid Solutions
- *     Suite #1A
- *     2328 Government Street
- *     Victoria BC  V8T 5G5
- *     Canada
- *
- *     (250)385-6040
- *     www.vividsolutions.com
- */
-package com.vividsolutions.jtsexample.geom;
-
-import com.vividsolutions.jts.geom.*;
-
-
-/**
- * @version 1.5
- */
-public class TwoArrayCoordinateSequenceExample
-{
-
-  public static void main(String args[])
-  {
-    TwoArrayCoordinateSequenceFactory seqFact = TwoArrayCoordinateSequenceFactory.instance();
-
-    Coordinate[] array1 = new Coordinate[] {
-      new Coordinate(0, 0, 0),
-      new Coordinate(10, 0, 0),
-      new Coordinate(10, 10, 0),
-      new Coordinate(0, 10, 0),
-      new Coordinate(0, 0, 0),
-    };
-    CoordinateSequence seq1 = seqFact.create(array1);
-
-    CoordinateSequence seq2 = seqFact.create(
-    new Coordinate[] {
-      new Coordinate(5, 5, 0),
-      new Coordinate(15, 5, 0),
-      new Coordinate(15, 15, 0),
-      new Coordinate(5, 15, 0),
-      new Coordinate(5, 5, 0),
-    });
-
-    GeometryFactory fact = new GeometryFactory(
-        TwoArrayCoordinateSequenceFactory.instance());
-
-    Geometry g1 = fact.createPolygon(fact.createLinearRing(seq1), null);
-    Geometry g2 = fact.createPolygon(fact.createLinearRing(seq2), null);
-
-    System.out.println("WKT for g1: " + g1);
-    System.out.println("Internal rep for g1: " + ((Polygon) g1).getExteriorRing().getCoordinateSequence());
-
-    System.out.println("WKT for g2: " + g2);
-    System.out.println("Internal rep for g2: " + ((Polygon) g2).getExteriorRing().getCoordinateSequence());
-
-    Geometry gInt = g1.intersection(g2);
-
-    System.out.println("WKT for gInt: " + gInt);
-    System.out.println("Internal rep for gInt: " + ((Polygon) gInt).getExteriorRing().getCoordinateSequence());
-  }
-
-  public TwoArrayCoordinateSequenceExample() {
-  }
-
-
-}
diff --git a/src/com/vividsolutions/jtsexample/geom/TwoArrayCoordinateSequenceFactory.java b/src/com/vividsolutions/jtsexample/geom/TwoArrayCoordinateSequenceFactory.java
deleted file mode 100644
index 8cae371..0000000
--- a/src/com/vividsolutions/jtsexample/geom/TwoArrayCoordinateSequenceFactory.java
+++ /dev/null
@@ -1,118 +0,0 @@
-
-/*
- * The JTS Topology Suite is a collection of Java classes that
- * implement the fundamental operations required to validate a given
- * geo-spatial data set to a known topological specification.
- *
- * Copyright (C) 2001 Vivid Solutions
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * For more information, contact:
- *
- *     Vivid Solutions
- *     Suite #1A
- *     2328 Government Street
- *     Victoria BC  V8T 5G5
- *     Canada
- *
- *     (250)385-6040
- *     www.vividsolutions.com
- */
-package com.vividsolutions.jtsexample.geom;
-
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.CoordinateSequence;
-import com.vividsolutions.jts.geom.CoordinateSequenceFactory;
-
-/**
- * Creates CoordinateSequences internally represented as an array of x's and
- * an array of y's.
- *
- * @version 1.5
- */
-public class TwoArrayCoordinateSequenceFactory implements CoordinateSequenceFactory {
-    private static TwoArrayCoordinateSequenceFactory instance = new TwoArrayCoordinateSequenceFactory();
-	private TwoArrayCoordinateSequenceFactory() {
-    }
-
-    /**
-     * Returns the singleton instance of TwoArrayCoordinateSequenceFactory
-     */
-    public static TwoArrayCoordinateSequenceFactory instance() {
-        return instance;
-    }    
-
-    public CoordinateSequence create(Coordinate[] coordinates) {
-        return new TwoArrayCoordinateSequence(coordinates);
-    }    
-
-    private static class TwoArrayCoordinateSequence implements CoordinateSequence {
-        private double[] xs;
-        private double[] ys;
-
-        public TwoArrayCoordinateSequence(Coordinate[] coordinates) {            
-            xs = new double[coordinates.length];
-            ys = new double[coordinates.length];
-            for (int i = 0; i < coordinates.length; i++) {
-                xs[i] = coordinates[i].x;
-                ys[i] = coordinates[i].y;
-            }
-        }        
-
-        public Coordinate getCoordinate(int i) {
-			return new Coordinate(xs[i], ys[i]);
-		}                
-        
-        public Object clone() {
-            double[] xsClone = new double[xs.length];
-            double[] ysClone = new double[ys.length];
-            System.arraycopy(xs, 0, xsClone, 0, xs.length);
-            System.arraycopy(ys, 0, ysClone, 0, ys.length);
-            return new TwoArrayCoordinateSequence(xsClone, ysClone);
-        }
-
-        public int size() {
-            return xs.length;
-        }
-
-        public Coordinate[] toCoordinateArray() {
-            Coordinate[] array = new Coordinate[xs.length];
-            for (int i = 0; i < array.length; i++) {
-                array[i] = new Coordinate(xs[i], ys[i]);
-            }
-            return array;
-        }
-
-		private TwoArrayCoordinateSequence(double[] xs, double[] ys) {            
-		    this.xs = xs;
-		    this.ys = ys;
-		}
-        
-        public String toString()
-        {
-          StringBuffer strBuf = new StringBuffer();
-          strBuf.append("TwoArrayCoordinateSequence [");
-          for (int i = 0; i < size(); i++) {
-            if (i > 0) strBuf.append(", ");
-            strBuf.append(xs[i] + " " + ys[i]);
-          }
-          strBuf.append("]");
-          return strBuf.toString();
-        }        
-
-    }
-
-}
diff --git a/src/com/vividsolutions/jtsexample/operation/distance/ClosestPointExample.java b/src/com/vividsolutions/jtsexample/operation/distance/ClosestPointExample.java
index 8d13170..bd6047a 100644
--- a/src/com/vividsolutions/jtsexample/operation/distance/ClosestPointExample.java
+++ b/src/com/vividsolutions/jtsexample/operation/distance/ClosestPointExample.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.operation.distance.DistanceOp;
  * Example of computing distance and closest points between geometries
  * using the DistanceOp class.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class ClosestPointExample
 {
diff --git a/src/com/vividsolutions/jtsexample/operation/linemerge/LineMergeExample.java b/src/com/vividsolutions/jtsexample/operation/linemerge/LineMergeExample.java
index 401acb2..0758a9b 100644
--- a/src/com/vividsolutions/jtsexample/operation/linemerge/LineMergeExample.java
+++ b/src/com/vividsolutions/jtsexample/operation/linemerge/LineMergeExample.java
@@ -45,7 +45,7 @@ import java.util.Collection;
  * Example of using the LineMerger class to sew together a set of fully noded 
  * linestrings.
  *
- * @version 1.5
+ * @version 1.6
  */
 public class LineMergeExample {
   private WKTReader reader = new WKTReader();
diff --git a/src/com/vividsolutions/jtsexample/operation/polygonize/PolygonizeExample.java b/src/com/vividsolutions/jtsexample/operation/polygonize/PolygonizeExample.java
index 247b3fe..0ab431a 100644
--- a/src/com/vividsolutions/jtsexample/operation/polygonize/PolygonizeExample.java
+++ b/src/com/vividsolutions/jtsexample/operation/polygonize/PolygonizeExample.java
@@ -43,7 +43,7 @@ import com.vividsolutions.jts.operation.polygonize.Polygonizer;
 /**
  *  Example of using Polygonizer class to polygonize a set of fully noded linestrings
  *
- * @version 1.5
+ * @version 1.6
  */
 public class PolygonizeExample
 {
diff --git a/src/com/vividsolutions/jtsexample/precision/EnhancedPrecisionOpExample.java b/src/com/vividsolutions/jtsexample/precision/EnhancedPrecisionOpExample.java
index cfc93b4..37fd3e1 100644
--- a/src/com/vividsolutions/jtsexample/precision/EnhancedPrecisionOpExample.java
+++ b/src/com/vividsolutions/jtsexample/precision/EnhancedPrecisionOpExample.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.precision.EnhancedPrecisionOp;
 /**
  * Example of using {@link EnhancedPrecisionOp} to avoid robustness problems
  *
- * @version 1.5
+ * @version 1.6
  */
 public class EnhancedPrecisionOpExample
 {
diff --git a/src/com/vividsolutions/jtsexample/technique/LineStringSelfIntersections.java b/src/com/vividsolutions/jtsexample/technique/LineStringSelfIntersections.java
index d29f8a4..f24fa27 100644
--- a/src/com/vividsolutions/jtsexample/technique/LineStringSelfIntersections.java
+++ b/src/com/vividsolutions/jtsexample/technique/LineStringSelfIntersections.java
@@ -8,7 +8,7 @@ import java.util.*;
  * Shows a technique for identifying the location of self-intersections
  * in a non-simple LineString.
  *
- * @version 1.5
+ * @version 1.6
  */
 
 public class LineStringSelfIntersections {
diff --git a/src/com/vividsolutions/jtsexample/technique/UnionUsingBuffer.java b/src/com/vividsolutions/jtsexample/technique/UnionUsingBuffer.java
index c8e0869..7e26ca0 100644
--- a/src/com/vividsolutions/jtsexample/technique/UnionUsingBuffer.java
+++ b/src/com/vividsolutions/jtsexample/technique/UnionUsingBuffer.java
@@ -18,7 +18,7 @@ import java.util.*;
  * <li>may not preserve input coordinate precision in some cases
  * </ul>
  *
- * @version 1.5
+ * @version 1.6
  */
 
 public class UnionUsingBuffer {
diff --git a/test/robust/TestRobustOverlayFixed.xml b/test/robust/TestRobustOverlayFixed.xml
new file mode 100644
index 0000000..1bb9e42
--- /dev/null
+++ b/test/robust/TestRobustOverlayFixed.xml
@@ -0,0 +1,18 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>AA</desc>
+  <a>
+POLYGON ((545 317, 617 379, 581 321, 545 317))
+	  </a>
+  <b>
+POLYGON ((484 290, 558 359, 543 309, 484 290))
+
+  	</b>
+<test>
+  <op name="intersection">    GEOMETRYCOLLECTION EMPTY  </op>
+</test>
+</case>
+
+</run>
diff --git a/test/robust/TestRobustOverlayFloat.xml b/test/robust/TestRobustOverlayFloat.xml
new file mode 100644
index 0000000..8024e14
--- /dev/null
+++ b/test/robust/TestRobustOverlayFloat.xml
@@ -0,0 +1,94 @@
+<run>
+	<precisionModel type="FLOATING" />
+<case>
+  <desc>AA - robustness failure</desc>
+  <a>
+POLYGON ((301949.68 2767249.16, 301936.52 2767241.28, 301938.87 
+2767237.43, 301952.47 2767245.59, 301950.74 2767247.81, 301949.68 
+2767249.16))
+  </a>
+  <b>
+POLYGON ((302041.321 2767264.675, 301938.823 2767237.507, 301941.21 2767233.59, 301943.821 2767229.304, 
+302048.886 2767243.046, 302041.321 2767264.675))  
+  </b>
+<test>
+  <op name="intersection">    GEOMETRYCOLLECTION EMPTY  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - robustness failure</desc>
+  <a>
+POLYGON ((301936.52 2767241.28, 301933.22 2767239.3, 301934.9 
+2767236.51, 301935.54 2767235.44, 301938.87 2767237.43, 301936.52 
+2767241.28))
+  </a>
+  <b>
+POLYGON ((302041.321 2767264.675, 301938.823 2767237.507, 301941.21 2767233.59, 301943.821 2767229.304, 
+302048.886 2767243.046, 302041.321 2767264.675))  
+</b>
+<test>
+  <op name="intersection">    GEOMETRYCOLLECTION EMPTY  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - robustness failure (fails with EnhancedPrecisionOp)</desc>
+  <a>
+POLYGON ((464664.782646596 5362148.87380619, 464664.713299 5362148.758128, 464686.806220838 5362136.92416521, 
+464713.650216607 5362122.5453135, 464711.113332785 5362117.30158834, 464707.408813375 5362110.21553566, 
+464703.323866879 5362103.23305736, 464698.945488413 5362096.31213576, 464694.461274991 5362089.42505804, 
+464625.876674576 5361951.92914952, 464622.430583893 5361944.69388208, 464535.3572 5361970.739, 
+464648.194399372 5362157.89548451, 464664.782646596 5362148.87380619))  </a>
+  <b>
+POLYGON ((464769.977147523 5362187.88829332, 464765.146147008 5362180.84587461, 464754.387021019 5362169.93629911, 
+464747.786455245 5362160.11104076, 464734.810564627 5362148.45253107, 464725.386626381 5362135.71065214, 
+464712.646269 5362123.083073, 464727.794520848 5362149.37983229, 464738.165719397 5362165.72994593, 
+464746.257208116 5362179.45514151, 464752.378040379 5362191.80978275, 464769.977147523 5362187.88829332))  
+</b>
+<test>
+  <op name="intersection">    GEOMETRYCOLLECTION EMPTY  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - robustness failure (fails with EnhancedPrecisionOp)</desc>
+  <a>
+POLYGON ((698400.5682737827 2388494.3828697307, 698402.3209180075 
+2388497.0819257903, 698415.3598714538 2388498.764371397, 
+698413.5003455497 2388495.90071853, 698400.5682737827 
+2388494.3828697307))
+	</a>
+  <b>
+POLYGON ((698231.847335025 2388474.57994264, 698440.416211779 
+2388499.05985776, 698432.582638943 2388300.28294705, 698386.666515791 
+2388303.40346027, 698328.29462841 2388312.88889197, 698231.847335025 
+2388474.57994264))
+	</b>
+<test>
+  <op name="intersection">    GEOMETRYCOLLECTION EMPTY  </op>
+</test>
+</case>
+
+
+<case>
+  <desc>AA - robustness failure (fails with EnhancedPrecisionOp)</desc>
+  <a>
+POLYGON ((698265.5760207245 2388415.007869463, 698266.5171698363 
+2388416.456984281, 698272.2367250263 2388406.868318228, 
+698271.2748419731 2388405.3872787533, 698265.5760207245 
+2388415.007869463))
+	</a>
+  <b>
+POLYGON ((698230.86813842 2388473.60074604, 698104.551776442 
+2388363.93072634, 698321.933422637 2388319.86687914, 698230.86813842 
+2388473.60074604))
+	</b>
+<test>
+  <op name="intersection">    GEOMETRYCOLLECTION EMPTY  </op>
+</test>
+</case>
+
+
+
+</run>
diff --git a/test/robust/TestRobustRelate.xml b/test/robust/TestRobustRelate.xml
new file mode 100644
index 0000000..45a5e23
--- /dev/null
+++ b/test/robust/TestRobustRelate.xml
@@ -0,0 +1,19 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>PP - Point is not on line. Non-robust algorithms fail by erroneously reporting intersects=true.</desc>
+  <a>
+    LINESTRING(-123456789 -40, 381039468754763 123456789)
+  </a>
+  <b>
+    POINT(0 0)
+  </b>
+<test>
+  <op name="intersects">
+    false
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/test/validate/TestRelateLL.xml b/test/validate/TestRelateLL.xml
index b0433ac..6d10521 100644
--- a/test/validate/TestRelateLL.xml
+++ b/test/validate/TestRelateLL.xml
@@ -1,1948 +1,1948 @@
 <run>
 <precisionModel type="FLOATING"/>
-
-<case>
-<desc>L/L.1-3-1: touching at the start points of two lines [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}]</desc>
-  <a>
-    LINESTRING(40 40, 120 120)
-  </a>
-  <b>
-    LINESTRING(40 40, 60 120)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-3-2: start point of one line touching end point of another line [dim(0){A.L.Bdy.SP = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(40 40, 120 120)
-  </a>
-  <b>
-    LINESTRING(60 240, 40 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-3-3: start point of a line touching the interior of another line at a non-vertex [dim(0){A.L.Bdy.SP = B.L.Int.NV}]</desc>
-  <a>
-    LINESTRING(40 40, 180 180)
-  </a>
-  <b>
-    LINESTRING(120 120, 20 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-3-4: touching at the end points of two lines [dim(0){A.L.Bdy.EP = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(40 40, 120 120)
-  </a>
-  <b>
-    LINESTRING(60 240, 120 120)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-3-5: end point of a line touching the interior of another line at a non-vertex [dim(0){A.L.Bdy.EP = B.L.Int.NV}]</desc>
-  <a>
-    LINESTRING(40 40, 180 180)
-  </a>
-  <b>
-    LINESTRING(20 180, 140 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-4-1: two lines crossing at non-vertex [dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
-  <a>
-    LINESTRING(40 40, 120 120)
-  </a>
-  <b>
-    LINESTRING(40 120, 120 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-1-1: equal pointwise [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100)
-  </a>
-  <b>
-    LINESTRING(40 40, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-1-2: equal lines but points in reverse sequence [dim(1){A.L.Int.SP-EP = B.L.Int.EP-SP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100)
-  </a>
-  <b>
-    LINESTRING(100 100, 40 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-2-1: dim(1){A.L.Int.SP-EP = B.L.Ext}</desc>
-  <a>
-    LINESTRING(40 40, 120 120)
-  </a>
-  <b>
-    LINESTRING(40 120, 120 160)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-5-1: line A containing line B [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
-  <a>
-    LINESTRING(20 20, 180 180)
-  </a>
-  <b>
-    LINESTRING(20 20, 180 180)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-5-2: line B is part of line A [dim(1){A.L.Int.SP-NV) = B.L.Int.SP-EP}]</desc>
-  <a>
-    LINESTRING(20 20, 180 180)
-  </a>
-  <b>
-    LINESTRING(20 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101F00FF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-5-3: Line B is part of line A (in the middle portion) [dim(1){A.L.Int.NV-NV = B.L.Int.SP-EP}]</desc>
-  <a>
-    LINESTRING(20 20, 180 180)
-  </a>
-  <b>
-    LINESTRING(50 50, 140 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-6-1: start portions of two lines overlapping [dim(1){A.L.Int.SP-NV = B.L.Int.SP-NV]</desc>
-  <a>
-    LINESTRING(180 180, 40 40)
-  </a>
-  <b>
-    LINESTRING(120 120, 260 260)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-6-2: end portions of two lines overlapping [dim(1){A.L.Int.NV-EP = B.L.Int.NV-EP]</desc>
-  <a>
-    LINESTRING(40 40, 180 180)
-  </a>
-  <b>
-    LINESTRING(260 260, 120 120)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.1-6-3: end portion of line A overlapping the start portion of line B [dim(1){A.L.Int.NV-EP = B.L.Int.SP-NV]</desc>
-  <a>
-    LINESTRING(40 40, 180 180)
-  </a>
-  <b>
-    LINESTRING(120 120, 260 260)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-1: two LineStrings touching at start points [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(40 40, 20 100, 40 160, 20 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-2: start point of LineStrings A touching the end point of LineString B [dim(0){A.L.Bdy.SP = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(20 200, 40 160, 20 100, 40 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-3: two LineStrings touching at end points [dim(0){A.L.Bdy.EP = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(80 240, 200 120, 100 100, 40 40)
-  </a>
-  <b>
-    LINESTRING(20 200, 40 160, 20 100, 40 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-4: both the start and end points of LineString A touching the interior of LineString B at two vertices  [dim(0){A.L.Bdy.SP = B.L.Int.V}, dim(0){A.L.Bdy.EP = B.L.Int.V}]</desc>
-  <a>
-    LINESTRING(60 60, 60 230, 140 230, 250 160)
-  </a>
-  <b>
-    LINESTRING(20 20, 60 60, 250 160, 310 230)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF10FF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-5: both the start and end points of LineString A touching the interior of LineString B at two non-vertices  [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Bdy.EP = B.L.Int.NV}]</desc>
-  <a>
-    LINESTRING(60 60, 60 230, 140 230, 250 160)
-  </a>
-  <b>
-    LINESTRING(20 20, 110 110, 200 110, 320 230)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF10FF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-6: the start and end points of two LineStrings touching each other [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}, dim(0){A.L.Bdy.EP = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(60 110, 60 250, 360 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F0F1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-7: the start and end points of two LineStrings touching each other [dim(0){A.L.Bdy.SP = B.L.Bdy.EP}, dim(0){A.L.Bdy.EP = B.L.Bdy.SP}]</desc>
-  <a>
-    LINESTRING(60 110, 60 250, 360 210)
-  </a>
-  <b>
-    LINESTRING(360 210, 310 160, 110 160, 60 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F0F1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-8: start point of LineString B touching LineString A at a non-vertex [dim(0){A.L.Int.NV = B.L.Bdy.SP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(160 160, 240 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-9: end point of LineString B touching LineString A at a non-vertex [dim(0){A.L.Int.NV = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(240 240, 160 160)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-10: both the start and end points of LineString B touching the interior of LineString A at two non-vertices  [dim(0){A.L.Int.NV = B.L.Bdy.SP}, dim(0){A.L.Int.NV = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(60 60, 60 230, 140 230, 250 160)
-  </a>
-  <b>
-    LINESTRING(60 150, 110 100, 170 100, 110 230)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-11: the start point of LineString B touching the interior of LineString A at a non-vertex and the end point of LineString A touching the interior of LineString B at a vertex  [dim(0){A.L.Int.NV = B.L.Bdy.SP}, dim(0){A.L.Bdy.EP = B.L.Int.V}]</desc>
-  <a>
-    LINESTRING(60 60, 60 230, 140 230, 250 160)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F010F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-12: start point of LineString B touching LineString A at a vertex [dim(0){A.L.Int.V = B.L.Bdy.SP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(200 120, 200 190, 150 240, 200 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-13: end point of LineString B touching LineString A at a vertex [dim(0){A.L.Int.V = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(200 240, 150 240, 200 200, 200 120)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-3-14: both the start and end points of LineString B touching the interior of LineString A at two vertices  [dim(0){A.L.Int.V = B.L.Bdy.SP}, dim(0){A.L.Int.V = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(60 60, 60 230, 140 230, 250 160)
-  </a>
-  <b>
-    LINESTRING(60 230, 80 140, 120 140, 140 230)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-1: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
-  <a>
-    LINESTRING(60 110, 200 110, 250 160, 300 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-2: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.SP}, dim(0){A.L.Int.V = B.L.Int.V}, dim(0){A.L.Bdy.EP = B.L.Int.EP}]</desc>
-  <a>
-    LINESTRING(60 110, 200 110, 250 160, 300 210, 360 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1F0F1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-3: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
-  <a>
-    LINESTRING(60 110, 220 110, 250 160, 280 110)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-4: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Int.SP}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Bdy.EP = B.L.Int.EP}]</desc>
-  <a>
-    LINESTRING(60 110, 150 110, 200 160, 250 110, 360 110, 360 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1F0F1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-5: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
-  <a>
-    LINESTRING(130 160, 160 110, 220 110, 250 160, 250 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-6: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
-  <a>
-    LINESTRING(130 160, 160 110, 190 110, 230 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-7: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Bdy.SP = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(130 160, 160 110, 200 110, 230 160, 260 210, 360 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F100F102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-8: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(130 160, 160 110, 200 110, 230 160, 260 210, 360 210, 380 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0010F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-9: two LineStrings crossing at three points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Int.NV = B.L.Bdy.EP}]</desc>
-  <a>
-    LINESTRING(130 160, 160 110, 200 110, 230 160, 260 210, 380 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0010F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-10: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.V}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
-  <a>
-    LINESTRING(110 160, 160 110, 200 110, 250 160, 250 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-11: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Int.V}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
-  <a>
-    LINESTRING(110 160, 180 110, 250 160, 320 110)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-12: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}]</desc>
-  <a>
-    LINESTRING(140 160, 180 80, 220 160, 250 80)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-13: two LineStrings crossing at a vertex for one of the LineStrings [dim(0){A.L.Int.V = B.L.Int.NV}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 130 190)
-  </a>
-  <b>
-    LINESTRING(20 130, 70 130, 160 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-14: two LineStrings crossing at non-vertices for both of the LineStrings [dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 130 190)
-  </a>
-  <b>
-    LINESTRING(40 160, 40 100, 110 40, 170 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-15: two LineStrings crossing on one side [dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}]</desc>
-  <a>
-    LINESTRING(130 110, 180 160, 230 110, 280 160, 330 110)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-16: two LineStrings crossing at vertices for both LineString  [dim(0){A.L.Int.V = B.L.Int.V}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 130 190)
-  </a>
-  <b>
-    LINESTRING(30 140, 80 140, 100 100, 200 30)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-17: two LineStrings crossing on one side [dim(0){A.L.Int.V = B.L.Int.V}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
-  <a>
-    LINESTRING(110 110, 110 160, 180 110, 250 160, 250 110)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-18: multiple crossings [dim(0){A.L.Int.V = B.L.Int.V}, dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
-  <a>
-    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
-  </a>
-  <b>
-    LINESTRING(20 60, 60 60, 60 140, 80 80, 100 20, 140 140, 180 20, 200 80, 220 20, 
-    240 80, 300 80, 270 110, 200 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-4-19: spiky LineStrings with multiple crossing [dim(0){A.L.Int.V = B.L.Int.V}]</desc>
-  <a>
-    LINESTRING(20 20, 230 20, 20 30, 170 30, 20 40, 230 40, 20 50, 230 60, 60 60, 
-    230 70, 20 70, 180 80, 60 80, 230 90, 20 90, 230 100, 30 100, 210 110, 20 110, 
-    80 120, 20 130, 170 130, 90 120, 230 130, 170 140, 230 140, 80 150, 160 140, 20 140, 
-    70 150, 20 150, 230 160, 80 160, 230 170, 20 160, 180 170, 20 170, 230 180, 20 180, 
-    40 190, 230 190, 20 200, 230 200)
-  </a>
-  <b>
-    LINESTRING(30 210, 30 60, 40 210, 40 30, 50 190, 50 20, 60 160, 60 50, 70 220, 
-    70 50, 80 20, 80 210, 90 50, 90 150, 100 30, 100 210, 110 20, 110 190, 120 50, 
-    120 180, 130 210, 120 20, 140 210, 130 50, 150 210, 130 20, 160 210, 140 30, 170 210, 
-    150 20, 180 210, 160 20, 190 210, 180 80, 170 50, 170 20, 180 70, 180 20, 190 190, 
-    190 30, 200 210, 200 30, 210 210, 210 20, 220 150, 220 20)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="001FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-1-1: two equal LineStrings with equal pointwise [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-1-2: two equal LineStrings with points in reverse sequence [dim(1){A.L.Int.SP-EP = B.L.Int.EP-SP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(80 240, 200 120, 100 100, 40 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-1-3: two equal LineStrings with different number of points [dim(1){A.L.Int.SP-EP = B.L.Int.EP-SP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(80 240, 120 200, 200 120, 100 100, 80 80, 40 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-2-1: disjoint [dim(1){A.L.Int.SP-EP = B.L.Ext}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(260 210, 240 130, 280 120, 260 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-2-2: wrapping around but still disjoint [dim(1){A.L.Int.SP-EP = B.L.Ext}]</desc>
-  <a>
-    LINESTRING(100 20, 20 20, 20 160, 210 160, 210 20, 110 20, 50 120, 120 150, 200 150)
-  </a>
-  <b>
-    LINESTRING(140 130, 100 110, 120 60, 170 60)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-5-1: LineString A containing LineString B, same pointwise [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
-  <a>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-5-2: LineString A containing LineString B, LineString A with less points [dim(1){A.L.Int.SP-V = B.L.Int.SP-EP}]</desc>
-  <a>
-    LINESTRING(60 110, 110 160, 310 160, 360 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-5-3: LineString A containing LineString B [dim(1){A.L.Int.SP-V = B.L.Int.SP-EP}]</desc>
-  <a>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </a>
-  <b>
-    LINESTRING(60 110, 110 160, 250 160)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101F00FF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-5-4: LineString A containing LineString B [dim(1){A.L.Int.NV-NV = B.L.Int.SP-EP}]</desc>
-  <a>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </a>
-  <b>
-    LINESTRING(110 160, 310 160, 340 190)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-5-5: LineString A containing LineString B [dim(1){A.L.Int.V-NV = B.L.Int.SP-EP}]</desc>
-  <a>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </a>
-  <b>
-    LINESTRING(140 160, 250 160, 310 160, 340 190)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-5-6: LineString A containing LineString B [dim(1){A.L.Int.V-V = B.L.Int.SP-EP}]</desc>
-  <a>
-    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
-  </a>
-  <b>
-    LINESTRING(110 160, 250 160, 310 160)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-6-1: start portions of two LineStrings overlapping [dim(1){A.L.Int.SP-V = B.L.Int.SP-V}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(200 120, 100 100, 40 40, 140 80, 200 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-6-2: start portion of LineString A overlapping end portion of LineString B, intersecting at the middle of LineString A [dim(1){A.L.Int.SP-V = B.L.Int.V-EP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(280 240, 240 140, 200 120, 100 100, 40 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-6-3: start portion of LineString A overlapping end portion of LineString B, intersecting at the middle of LineString A [dim(1){A.L.Int.SP-V = B.L.Int.NV-EP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(80 190, 140 140, 40 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-6-4: end portions of two LineStrings overlapping [dim(1){A.L.Int.NV-EP = B.L.Int.V-EP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(240 200, 200 260, 80 240, 140 180)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-6-5: end portion of LineString A overlapping start portion of LineString B [dim(1){A.L.Int.NV-EP = B.L.Int.SP-V}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(140 180, 80 240, 200 260, 240 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-6-6: end portion of LineString A overlapping end portion of LineString B, intersecting at the middle of LineString A [dim(1){A.L.Int.V-EP = B.L.Int.V-EP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(280 240, 240 140, 200 120, 80 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-6-7: middle portions of two LineStrings overlapping [dim(1){A.L.Int.V-NV = B.L.Int.NV-V}]</desc>
-  <a>
-    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
-  </a>
-  <b>
-    LINESTRING(20 80, 120 80, 200 80, 260 20)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-6-8: middle portion of LineString A overlapping start portion of LineString B [dim(1){A.L.Int.V-V = B.L.Int.SP-V}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(100 100, 200 120, 240 140, 280 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-6-9: middle portion of LineString A overlapping end portion of LineString B [dim(1){A.L.Int.V-V = B.L.Int.V-EP}]</desc>
-  <a>
-    LINESTRING(40 40, 100 100, 200 120, 80 240)
-  </a>
-  <b>
-    LINESTRING(280 240, 240 140, 200 120, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-6-10: middle portions of two LineStrings overlapping [dim(1){A.L.Int.V-V = B.L.Int.V-V}]</desc>
-  <a>
-    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
-  </a>
-  <b>
-    LINESTRING(80 20, 80 80, 240 80, 300 20)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/L.2-6-11: middle portions of two LineStrings overlapping, multiple intersects [dim(1){A.L.Int.V-V = B.L.Int.V-NV}, dim(1){A.L.Int.V-V = B.L.Int.V-NV}, dim(1){A.L.Int.V-V = B.L.Int.V-NV}]</desc>
-  <a>
-    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
-  </a>
-  <b>
-    LINESTRING(20 80, 80 80, 120 80, 140 140, 160 80, 200 80, 220 20, 240 80, 270 110, 
-    300 80)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/LR-3-1: a LineString touching a LinearRing [dim(0){A.L.Bdy.SP = B.LR.Int.CP}]</desc>
-  <a>
-    LINESTRING(100 100, 20 180, 180 180)
-  </a>
-  <b>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF10F01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/LR-4-1: a LineString crossing a LinearRing [dim(0){A.L.Int.NV = B.LR.Int.CP}]</desc>
-  <a>
-    LINESTRING(20 100, 180 100, 100 180)
-  </a>
-  <b>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/LR-4-2: a LineString crossing a LinearRing [dim(0){A.L.Int.NV = B.LR.Int.CP}]</desc>
-  <a>
-    LINESTRING(100 40, 100 160, 180 160)
-  </a>
-  <b>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/LR-4-3: a LineString crossing a LinearRing [dim(0){A.L.Int.V = B.LR.Int.CP}]</desc>
-  <a>
-    LINESTRING(20 100, 100 100, 180 100, 100 180)
-  </a>
-  <b>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/LR-5-1: a LineString within a LinearRing [dim(1){A.L.Int.SP-EP = B.LR.Int.SP-NV}]</desc>
-  <a>
-    LINESTRING(100 100, 160 40)
-  </a>
-  <b>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/LR-5-2: a LineString within a LinearRing [dim(1){A.L.Int.SP-EP = B.LR.Int.SP-NV}]</desc>
-  <a>
-    LINESTRING(100 100, 180 20)
-  </a>
-  <b>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/LR-5-3: a LineString within a LinearRing [dim(1){A.L.Int.SP-V-EP = B.LR.Int.NV-CP-NV}]</desc>
-  <a>
-    LINESTRING(60 60, 100 100, 140 60)
-  </a>
-  <b>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/LR-6-1: a LineString crossing a LinearRing [dim(1){A.L.Int.SP-NV = B.LR.Int.SP-V}]</desc>
-  <a>
-    LINESTRING(100 100, 190 10, 190 100)
-  </a>
-  <b>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F10F01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/LR-6-2: a LineString crossing a LinearRing [dim(1){A.L.Int.SP-V = B.LR.Int.SP-NV}]</desc>
-  <a>
-    LINESTRING(100 100, 160 40, 160 100)
-  </a>
-  <b>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F10F01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/LR-6-3: a LineString crossing a LinearRing [dim(1){A.L.Int.NV-V = B.LR.Int.SP-NV}]</desc>
-  <a>
-    LINESTRING(60 140, 160 40, 160 140)
-  </a>
-  <b>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F1FF01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's end point with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Bdy.EPb}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(80 80, 20 80, 140 80, 80 20, 80 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's end point with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Bdy.EPo}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(80 80, 20 80, 140 80)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's end point with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(80 80, 140 80, 80 20, 80 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's closing point with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.CPb}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(80 80, 20 80, 140 80, 80 20, 80 80)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's closing point with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.CPo}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(80 80, 20 80, 140 80, 80 80)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's closing point with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Int.CPx}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(80 80, 20 80, 20 140, 140 20, 80 20, 80 80)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex [dim(0){A.L.Int.NV = B.nsL.Int.NV}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(20 140, 140 20, 100 20, 100 80)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.NVb}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(140 80, 20 80, 120 80, 80 20, 80 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.NVo}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(140 80, 20 80, 140 80)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Int.NVx}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(140 80, 20 80, 80 140, 80 20)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex [dim(0){A.L.Int.NV = B.nsL.Int.V}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(140 80, 80 80, 20 80, 50 140, 50 60)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.Vb}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(140 80, 20 80, 120 80, 80 20, 80 80, 80 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.Vo}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(140 80, 20 80, 80 80, 140 80)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Int.Vx}]</desc>
-  <a>
-    LINESTRING(20 20, 140 140)
-  </a>
-  <b>
-    LINESTRING(140 80, 20 80, 80 140, 80 80, 80 20)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL.1-3-1: start point of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Bdy.SP = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    LINESTRING(130 150, 220 150, 220 240)
-  </a>
-  <b>
-    LINESTRING(130 240, 130 150, 220 20, 50 20, 130 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL.1-3-2: the interior of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Int.V = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    LINESTRING(30 150, 130 150, 250 150)
-  </a>
-  <b>
-    LINESTRING(130 240, 130 150, 220 20, 50 20, 130 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL.1-3-3: the interior of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Int.NV = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    LINESTRING(30 150, 250 150)
-  </a>
-  <b>
-    LINESTRING(130 240, 130 150, 220 20, 50 20, 130 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL.1-3-4: the interior of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Int.V = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    LINESTRING(30 150, 130 150, 250 150)
-  </a>
-  <b>
-    LINESTRING(130 240, 130 20, 30 20, 130 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL.1-4: a Line crossing a non-simple LineString at non-vertices [dim(0){A.L.Int.NV = B.nsL.Int.NV}]</desc>
-  <a>
-    LINESTRING(30 150, 250 150)
-  </a>
-  <b>
-    LINESTRING(120 240, 120 20, 20 20, 120 170)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>nsL.5/L-3-1: switching the geometries for case L/nsL.5-3-1 [dim(0){A.nsL.Bdy.EPx = B.L.Bdy.SP}]</desc>
-  <a>
-    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 200 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL.5-3-2: the start point of a line touching the self-intersecting and self-crossing point of a non-simple LineString [dim(0){A.L.Bdy.SP = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    LINESTRING(110 110, 200 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL.5-3-3: the interior of a line touching the self-intersecting and self-crossing point of a non-simple LineString [dim(0){A.L.Int.NV = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    LINESTRING(20 110, 200 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>nsL.5/L-3-4 touches dim(0){A.nsL.Bdy.EPx = B.L.Int.NV}</desc>
-  <a>
-    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
-  </a>
-  <b>
-    LINESTRING(20 110, 200 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL.10-6-1: the middle portion of a line overlapping from the self-intersecting to the self-crossing a non-simple LineString [dim(1){A.L.Int.V-V = B.nsL.Int.EPx-NVx}]</desc>
-  <a>
-    LINESTRING(90 200, 90 130, 110 110, 150 200)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/nsL.10-6-2: the middle portion of a line overlapping from the self-intersecting to the self-crossing a non-simple LineString [dim(1){A.L.Int.V-V = B.nsL.Int.NVx-EPx}]</desc>
-  <a>
-    LINESTRING(200 110, 110 110, 90 130, 90 200)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>L/mL-3-1: a line's end point touching a non-vertex with crossing line segments of a MultiLineString [dim(0){A.L.Bdy.SP = B.mL.Int.NVx]</desc>
-  <a>
-    LINESTRING(80 80, 150 80, 210 80)
-  </a>
-  <b>
-    MULTILINESTRING(
-      (20 20, 140 140), 
-      (20 140, 140 20))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-1-1: two equal LinearRings, pointwise [dim(1){A.LR.Int.SP-EP = B.LR.Int.SP-EP}, dim(0){A.LR.Int.CP = B.LR.Int.CP}]</desc>
-  <a>
-    LINESTRING(40 80, 160 200, 260 20, 40 80)
-  </a>
-  <b>
-    LINESTRING(40 80, 160 200, 260 20, 40 80)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-1-2: two equal LinearRings with points in reverse sequence [dim(1){A.LR.Int.SP-EP = B.LR.Int.EP-SP}, dim(0){A.LR.Int.CP = B.LR.Int.CP}]</desc>
-  <a>
-    LINESTRING(40 80, 160 200, 260 20, 40 80)
-  </a>
-  <b>
-    LINESTRING(40 80, 260 20, 160 200, 40 80)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-1-3: two equal LinearRings with points in different sequence [dim(1){A.LR.Int.SP-EP = B.LR.Int.SP-EP}, dim(0){A.LR.Int.CP = B.LR.Int.V}, dim(0){A.LR.Int.V = B.LR.Int.CP}]</desc>
-  <a>
-    LINESTRING(40 80, 160 200, 260 20, 40 80)
-  </a>
-  <b>
-    LINESTRING(260 20, 40 80, 160 200, 260 20)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-1-4: two equal LinearRings with different number of points [dim(1){A.LR.Int.SP-EP = B.LR.Int.SP-EP}, dim(0){A.LR.Int.CP = B.LR.Int.V}, dim(0){A.LR.Int.NV = B.LR.Int.CP}]</desc>
-  <a>
-    LINESTRING(40 80, 160 200, 260 20, 40 80)
-  </a>
-  <b>
-    LINESTRING(100 140, 160 200, 260 20, 40 80, 100 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-4-1: two LinearRings crossing at closing points [dim(0){A.LR.Int.CP = B.LR.Int.CP}]</desc>
-  <a>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </a>
-  <b>
-    LINESTRING(100 100, 180 180, 20 180, 100 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-4-2: two LinearRings crossing at two points [dim(0){A.LR.Int.CP = B.LR.Int.CP}, dim(0){A.LR.Int.V = B.LR.Int.V},]</desc>
-  <a>
-    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
-  </a>
-  <b>
-    LINESTRING(40 150, 150 40, 170 20, 170 190, 40 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-4-3: two LinearRings crossing at the closing and a non-vertex [dim(0){A.LR.Int.CP = B.LR.Int.NV}]</desc>
-  <a>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </a>
-  <b>
-    LINESTRING(180 100, 20 100, 100 180, 180 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-4-4: two LinearRings crossing at the closing and a vertex [dim(0){A.LR.Int.CP = B.LR.Int.V}]</desc>
-  <a>
-    LINESTRING(100 100, 180 20, 20 20, 100 100)
-  </a>
-  <b>
-    LINESTRING(180 180, 100 100, 20 180, 180 180)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-4-5: two LinearRings crossing at a vertex and a non-vertex [dim(0){A.LR.Int.V = B.LR.Int.NV}]</desc>
-  <a>
-    LINESTRING(20 180, 100 100, 20 20, 20 180)
-  </a>
-  <b>
-    LINESTRING(100 20, 100 180, 180 100, 100 20)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-4-6: two LinearRings crossing at two points [dim(0){A.LR.Int.V = B.LR.Int.NV}, dim(0){A.LR.Int.V = B.LR.Int.NV},]</desc>
-  <a>
-    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
-  </a>
-  <b>
-    LINESTRING(170 20, 20 170, 170 170, 170 20)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-6-1: two LinearRings overlapping [dim(1){A.LR.Int.CP-V = B.LR.Int.CP-V}]</desc>
-  <a>
-    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
-  </a>
-  <b>
-    LINESTRING(40 150, 150 150, 90 210, 40 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-6-2: two LinearRings overlapping [dim(1){A.LR.Int.CP-V = B.LR.Int.NV-NV}]</desc>
-  <a>
-    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
-  </a>
-  <b>
-    LINESTRING(20 150, 170 150, 90 230, 20 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/LR-6-3: two LinearRings overlapping [dim(1){A.LR.Int.(V-V-V-EP) = B.LR.Int.(NV-V-V-SP)}]</desc>
-  <a>
-    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
-  </a>
-  <b>
-    LINESTRING(40 150, 150 150, 150 40, 20 40, 20 150, 40 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/nsL-3-1: a LinearRing touching a non-simple LineString [dim(0){A.nsL.Int.CP = B.nsL.Bdy.SPb}]</desc>
-  <a>
-    LINESTRING(110 110, 200 20, 20 20, 110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 200 200, 110 110, 20 200, 20 110, 200 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/nsL-3-1: a LinearRing touching a non-simple LineString [dim(0){A.nsL.Int.CP = B.nsL.Bdy.SPo}]</desc>
-  <a>
-    LINESTRING(110 110, 200 20, 20 20, 110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 20 110, 200 110, 50 110, 110 170)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/nsL-3-1: a LinearRing touching a non-simple LineString [dim(0){A.nsL.Int.CP = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    LINESTRING(110 110, 200 20, 20 20, 110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 20 200, 110 200, 110 110, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F01FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/nsL-6-1: a LinearRing and a non-simple LineString overlapping [dim(1){A.nsL.Int.SP-V = B.nsL.Int.NVx-SP}]</desc>
-  <a>
-    LINESTRING(110 110, 200 20, 20 20, 110 110)
-  </a>
-  <b>
-    LINESTRING(200 20, 20 200, 200 200, 110 110, 110 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>LR/nsL-6-2: a LinearRing and a non-simple LineString overlapping [dim(1){A.nsL.Int.SP-V = B.nsL.Int.NVx-SP}, dim(1){A.nsL.Int.V-EP = B.nsL.Int.EP-NVx}]</desc>
-  <a>
-    LINESTRING(110 110, 200 20, 20 20, 110 110)
-  </a>
-  <b>
-    LINESTRING(200 20, 20 200, 200 200, 20 20)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="101FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>nsL/nsL-4-1: non-simple LineStrings crossing at closing points [dim(0){A.nsL.Int.CP = B.nsL.Int.CP}]</desc>
-  <a>
-    LINESTRING(110 110, 20 110, 110 20, 20 20, 110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 200 200, 110 200, 200 110, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>nsL/nsL-4-2: non-simple LineStrings crossing at two points without vertices [dim(0){A.nsL.Int.NV = B.nsL.Int.NV}]</desc>
-  <a>
-    LINESTRING(20 120, 120 120, 20 20, 120 20, 20 120)
-  </a>
-  <b>
-    LINESTRING(170 100, 70 100, 170 170, 70 170, 170 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>nsL/nsL-4-3: non-simple LineStrings crossing at a point [dim(0){A.nsL.Int.NV = B.nsL.Int.V}]</desc>
-  <a>
-    LINESTRING(20 110, 110 110, 20 20, 110 20, 20 110)
-  </a>
-  <b>
-    LINESTRING(110 160, 70 110, 60 160, 20 130, 110 160)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>nsL/nsL-4-4: non-simple LineStrings crossing at self-crossing points [dim(0){A.nsL.Int.NVx = B.nsL.Int.NVx}]</desc>
-  <a>
-    LINESTRING(20 200, 200 200, 20 20, 200 20, 20 200)
-  </a>
-  <b>
-    LINESTRING(20 110, 200 110, 200 160, 20 60, 20 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>nsL/nsL-4-5: non-simple LineStrings crossing at vertices [dim(0){A.nsL.Int.V = B.nsL.Int.V}]</desc>
-  <a>
-    LINESTRING(20 110, 110 110, 20 20, 110 20, 20 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 110 110, 200 110, 110 200, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>nsL/nsL-4-6: non-simple LineStrings crossing at two points with vertices [dim(0){A.nsL.Int.V = B.nsL.Int.V}]</desc>
-  <a>
-    LINESTRING(20 120, 120 120, 20 20, 120 20, 20 120)
-  </a>
-  <b>
-    LINESTRING(220 120, 120 20, 220 20, 120 120, 220 120)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-1: MultiLineString [dim(1){A.mL.Int.SP-EP = B.mL.Int.SP-EP}]</desc>
-  <a>
-    MULTILINESTRING(
-      (70 20, 20 90, 70 170), 
-      (70 170, 120 90, 70 20))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (70 20, 20 90, 70 170), 
-      (70 170, 120 90, 70 20))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-1-1: non-simple MultiLineString  [dim(1){A.mL.Int.SP-EP = B.mL.Int.SP-EP}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 20, 170 20), 
-      (90 20, 90 80, 90 140))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (20 20, 90 20, 170 20), 
-      (90 20, 90 80, 90 140))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-1-2: equal non-simple MultiLineString with different sequence of lines and points [dim(1){A.mL.Int.SP-EP = B.mL.Int.EP-SP}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 20, 170 20), 
-      (90 20, 90 80, 90 140))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (90 140, 90 60, 90 20), 
-      (170 20, 130 20, 20 20))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-3-1: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPb}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 20, 170 20), 
-      (90 20, 90 80, 90 140))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (90 20, 170 100, 170 140), 
-      (170 60, 90 20, 20 60), 
-      (130 100, 130 60, 90 20, 50 90))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-3-2: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPo}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 20, 170 20), 
-      (90 20, 90 80, 90 140))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (90 20, 170 100, 170 140), 
-      (130 140, 130 60, 90 20, 20 90, 90 20, 130 60, 170 60))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-3-3: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPx}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 20, 170 20), 
-      (90 20, 90 80, 90 140))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (90 20, 170 100, 170 140), 
-      (170 60, 90 20, 20 60))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-3-4: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPx}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 20, 170 20), 
-      (90 20, 90 80, 90 140))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (90 20, 170 100, 170 140), 
-      (170 60, 90 20, 20 60), 
-      (130 100, 90 20))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-3-5: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPx}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 20, 170 20), 
-      (90 20, 90 80, 90 140))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (90 20, 170 100, 170 140), 
-      (170 60, 90 20, 20 60), 
-      (120 100, 170 100, 90 20))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-3-6: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Int.SPb}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 20, 170 20), 
-      (90 20, 90 80, 90 140))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (90 20, 170 100, 170 140), 
-      (170 60, 90 20, 20 60), 
-      (120 100, 170 100, 90 20))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-3-7: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Int.SPo}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 20, 170 20), 
-      (90 20, 90 80, 90 140))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (90 20, 170 100, 170 140), 
-      (130 140, 130 60, 90 20, 20 90, 90 20))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-3-8: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Int.SPx}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 20, 170 20), 
-      (90 20, 90 80, 90 140))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (90 20, 170 100, 170 140), 
-      (170 60, 90 20, 20 60, 20 140, 90 20))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-4-1: non-simple MultiLineStrings crossing [dim(0){A.mL.Int.Vx = B.mL.Int.Vb}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 90, 20 160), 
-      (90 160, 90 20))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (160 160, 90 90, 160 20), 
-      (160 120, 120 120, 90 90, 160 60))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-4-2: non-simple MultiLineStrings crossing [dim(0){A.mL.Int.Vx = B.mL.Int.Vo}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 90, 20 160), 
-      (90 160, 90 20))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (160 160, 90 90, 160 20), 
-      (160 120, 120 120, 90 90, 120 60, 160 60))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mL/mL-4-3: non-simple MultiLineStrings crossing [dim(0){A.mL.Int.Vx = B.mL.Int.Vx}]</desc>
-  <a>
-    MULTILINESTRING(
-      (20 20, 90 90, 20 160), 
-      (90 160, 90 20))
-  </a>
-  <b>
-    MULTILINESTRING(
-      (160 160, 90 90, 160 20), 
-      (160 120, 90 90, 160 60))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
-  </test>
-</case>
-
+
+<case>
+<desc>L/L.1-3-1: touching at the start points of two lines [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(40 40, 120 120)
+  </a>
+  <b>
+    LINESTRING(40 40, 60 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-3-2: start point of one line touching end point of another line [dim(0){A.L.Bdy.SP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(40 40, 120 120)
+  </a>
+  <b>
+    LINESTRING(60 240, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-3-3: start point of a line touching the interior of another line at a non-vertex [dim(0){A.L.Bdy.SP = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(40 40, 180 180)
+  </a>
+  <b>
+    LINESTRING(120 120, 20 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-3-4: touching at the end points of two lines [dim(0){A.L.Bdy.EP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(40 40, 120 120)
+  </a>
+  <b>
+    LINESTRING(60 240, 120 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-3-5: end point of a line touching the interior of another line at a non-vertex [dim(0){A.L.Bdy.EP = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(40 40, 180 180)
+  </a>
+  <b>
+    LINESTRING(20 180, 140 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-4-1: two lines crossing at non-vertex [dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(40 40, 120 120)
+  </a>
+  <b>
+    LINESTRING(40 120, 120 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-1-1: equal pointwise [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100)
+  </a>
+  <b>
+    LINESTRING(40 40, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-1-2: equal lines but points in reverse sequence [dim(1){A.L.Int.SP-EP = B.L.Int.EP-SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100)
+  </a>
+  <b>
+    LINESTRING(100 100, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-2-1: dim(1){A.L.Int.SP-EP = B.L.Ext}</desc>
+  <a>
+    LINESTRING(40 40, 120 120)
+  </a>
+  <b>
+    LINESTRING(40 120, 120 160)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-5-1: line A containing line B [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(20 20, 180 180)
+  </a>
+  <b>
+    LINESTRING(20 20, 180 180)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-5-2: line B is part of line A [dim(1){A.L.Int.SP-NV) = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(20 20, 180 180)
+  </a>
+  <b>
+    LINESTRING(20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101F00FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-5-3: Line B is part of line A (in the middle portion) [dim(1){A.L.Int.NV-NV = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(20 20, 180 180)
+  </a>
+  <b>
+    LINESTRING(50 50, 140 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-6-1: start portions of two lines overlapping [dim(1){A.L.Int.SP-NV = B.L.Int.SP-NV]</desc>
+  <a>
+    LINESTRING(180 180, 40 40)
+  </a>
+  <b>
+    LINESTRING(120 120, 260 260)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-6-2: end portions of two lines overlapping [dim(1){A.L.Int.NV-EP = B.L.Int.NV-EP]</desc>
+  <a>
+    LINESTRING(40 40, 180 180)
+  </a>
+  <b>
+    LINESTRING(260 260, 120 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-6-3: end portion of line A overlapping the start portion of line B [dim(1){A.L.Int.NV-EP = B.L.Int.SP-NV]</desc>
+  <a>
+    LINESTRING(40 40, 180 180)
+  </a>
+  <b>
+    LINESTRING(120 120, 260 260)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-1: two LineStrings touching at start points [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(40 40, 20 100, 40 160, 20 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-2: start point of LineStrings A touching the end point of LineString B [dim(0){A.L.Bdy.SP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(20 200, 40 160, 20 100, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-3: two LineStrings touching at end points [dim(0){A.L.Bdy.EP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(80 240, 200 120, 100 100, 40 40)
+  </a>
+  <b>
+    LINESTRING(20 200, 40 160, 20 100, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-4: both the start and end points of LineString A touching the interior of LineString B at two vertices  [dim(0){A.L.Bdy.SP = B.L.Int.V}, dim(0){A.L.Bdy.EP = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(60 60, 60 230, 140 230, 250 160)
+  </a>
+  <b>
+    LINESTRING(20 20, 60 60, 250 160, 310 230)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10FF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-5: both the start and end points of LineString A touching the interior of LineString B at two non-vertices  [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Bdy.EP = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(60 60, 60 230, 140 230, 250 160)
+  </a>
+  <b>
+    LINESTRING(20 20, 110 110, 200 110, 320 230)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10FF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-6: the start and end points of two LineStrings touching each other [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}, dim(0){A.L.Bdy.EP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(60 110, 60 250, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F0F1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-7: the start and end points of two LineStrings touching each other [dim(0){A.L.Bdy.SP = B.L.Bdy.EP}, dim(0){A.L.Bdy.EP = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(60 110, 60 250, 360 210)
+  </a>
+  <b>
+    LINESTRING(360 210, 310 160, 110 160, 60 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F0F1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-8: start point of LineString B touching LineString A at a non-vertex [dim(0){A.L.Int.NV = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(160 160, 240 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-9: end point of LineString B touching LineString A at a non-vertex [dim(0){A.L.Int.NV = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(240 240, 160 160)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-10: both the start and end points of LineString B touching the interior of LineString A at two non-vertices  [dim(0){A.L.Int.NV = B.L.Bdy.SP}, dim(0){A.L.Int.NV = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(60 60, 60 230, 140 230, 250 160)
+  </a>
+  <b>
+    LINESTRING(60 150, 110 100, 170 100, 110 230)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-11: the start point of LineString B touching the interior of LineString A at a non-vertex and the end point of LineString A touching the interior of LineString B at a vertex  [dim(0){A.L.Int.NV = B.L.Bdy.SP}, dim(0){A.L.Bdy.EP = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(60 60, 60 230, 140 230, 250 160)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-12: start point of LineString B touching LineString A at a vertex [dim(0){A.L.Int.V = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(200 120, 200 190, 150 240, 200 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-13: end point of LineString B touching LineString A at a vertex [dim(0){A.L.Int.V = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(200 240, 150 240, 200 200, 200 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-14: both the start and end points of LineString B touching the interior of LineString A at two vertices  [dim(0){A.L.Int.V = B.L.Bdy.SP}, dim(0){A.L.Int.V = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(60 60, 60 230, 140 230, 250 160)
+  </a>
+  <b>
+    LINESTRING(60 230, 80 140, 120 140, 140 230)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-1: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(60 110, 200 110, 250 160, 300 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-2: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.SP}, dim(0){A.L.Int.V = B.L.Int.V}, dim(0){A.L.Bdy.EP = B.L.Int.EP}]</desc>
+  <a>
+    LINESTRING(60 110, 200 110, 250 160, 300 210, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1F0F1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-3: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(60 110, 220 110, 250 160, 280 110)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-4: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Int.SP}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Bdy.EP = B.L.Int.EP}]</desc>
+  <a>
+    LINESTRING(60 110, 150 110, 200 160, 250 110, 360 110, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1F0F1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-5: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(130 160, 160 110, 220 110, 250 160, 250 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-6: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(130 160, 160 110, 190 110, 230 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-7: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Bdy.SP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(130 160, 160 110, 200 110, 230 160, 260 210, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F100F102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-8: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(130 160, 160 110, 200 110, 230 160, 260 210, 360 210, 380 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-9: two LineStrings crossing at three points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Int.NV = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(130 160, 160 110, 200 110, 230 160, 260 210, 380 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-10: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.V}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(110 160, 160 110, 200 110, 250 160, 250 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-11: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Int.V}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(110 160, 180 110, 250 160, 320 110)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-12: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(140 160, 180 80, 220 160, 250 80)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-13: two LineStrings crossing at a vertex for one of the LineStrings [dim(0){A.L.Int.V = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 130 190)
+  </a>
+  <b>
+    LINESTRING(20 130, 70 130, 160 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-14: two LineStrings crossing at non-vertices for both of the LineStrings [dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 130 190)
+  </a>
+  <b>
+    LINESTRING(40 160, 40 100, 110 40, 170 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-15: two LineStrings crossing on one side [dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(130 110, 180 160, 230 110, 280 160, 330 110)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-16: two LineStrings crossing at vertices for both LineString  [dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 130 190)
+  </a>
+  <b>
+    LINESTRING(30 140, 80 140, 100 100, 200 30)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-17: two LineStrings crossing on one side [dim(0){A.L.Int.V = B.L.Int.V}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(110 110, 110 160, 180 110, 250 160, 250 110)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-18: multiple crossings [dim(0){A.L.Int.V = B.L.Int.V}, dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
+  </a>
+  <b>
+    LINESTRING(20 60, 60 60, 60 140, 80 80, 100 20, 140 140, 180 20, 200 80, 220 20, 
+    240 80, 300 80, 270 110, 200 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-19: spiky LineStrings with multiple crossing [dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(20 20, 230 20, 20 30, 170 30, 20 40, 230 40, 20 50, 230 60, 60 60, 
+    230 70, 20 70, 180 80, 60 80, 230 90, 20 90, 230 100, 30 100, 210 110, 20 110, 
+    80 120, 20 130, 170 130, 90 120, 230 130, 170 140, 230 140, 80 150, 160 140, 20 140, 
+    70 150, 20 150, 230 160, 80 160, 230 170, 20 160, 180 170, 20 170, 230 180, 20 180, 
+    40 190, 230 190, 20 200, 230 200)
+  </a>
+  <b>
+    LINESTRING(30 210, 30 60, 40 210, 40 30, 50 190, 50 20, 60 160, 60 50, 70 220, 
+    70 50, 80 20, 80 210, 90 50, 90 150, 100 30, 100 210, 110 20, 110 190, 120 50, 
+    120 180, 130 210, 120 20, 140 210, 130 50, 150 210, 130 20, 160 210, 140 30, 170 210, 
+    150 20, 180 210, 160 20, 190 210, 180 80, 170 50, 170 20, 180 70, 180 20, 190 190, 
+    190 30, 200 210, 200 30, 210 210, 210 20, 220 150, 220 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="001FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-1-1: two equal LineStrings with equal pointwise [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-1-2: two equal LineStrings with points in reverse sequence [dim(1){A.L.Int.SP-EP = B.L.Int.EP-SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(80 240, 200 120, 100 100, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-1-3: two equal LineStrings with different number of points [dim(1){A.L.Int.SP-EP = B.L.Int.EP-SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(80 240, 120 200, 200 120, 100 100, 80 80, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-2-1: disjoint [dim(1){A.L.Int.SP-EP = B.L.Ext}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(260 210, 240 130, 280 120, 260 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-2-2: wrapping around but still disjoint [dim(1){A.L.Int.SP-EP = B.L.Ext}]</desc>
+  <a>
+    LINESTRING(100 20, 20 20, 20 160, 210 160, 210 20, 110 20, 50 120, 120 150, 200 150)
+  </a>
+  <b>
+    LINESTRING(140 130, 100 110, 120 60, 170 60)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-1: LineString A containing LineString B, same pointwise [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-2: LineString A containing LineString B, LineString A with less points [dim(1){A.L.Int.SP-V = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-3: LineString A containing LineString B [dim(1){A.L.Int.SP-V = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101F00FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-4: LineString A containing LineString B [dim(1){A.L.Int.NV-NV = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(110 160, 310 160, 340 190)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-5: LineString A containing LineString B [dim(1){A.L.Int.V-NV = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(140 160, 250 160, 310 160, 340 190)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-6: LineString A containing LineString B [dim(1){A.L.Int.V-V = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(110 160, 250 160, 310 160)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-1: start portions of two LineStrings overlapping [dim(1){A.L.Int.SP-V = B.L.Int.SP-V}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(200 120, 100 100, 40 40, 140 80, 200 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-2: start portion of LineString A overlapping end portion of LineString B, intersecting at the middle of LineString A [dim(1){A.L.Int.SP-V = B.L.Int.V-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(280 240, 240 140, 200 120, 100 100, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-3: start portion of LineString A overlapping end portion of LineString B, intersecting at the middle of LineString A [dim(1){A.L.Int.SP-V = B.L.Int.NV-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(80 190, 140 140, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-4: end portions of two LineStrings overlapping [dim(1){A.L.Int.NV-EP = B.L.Int.V-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(240 200, 200 260, 80 240, 140 180)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-5: end portion of LineString A overlapping start portion of LineString B [dim(1){A.L.Int.NV-EP = B.L.Int.SP-V}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(140 180, 80 240, 200 260, 240 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-6: end portion of LineString A overlapping end portion of LineString B, intersecting at the middle of LineString A [dim(1){A.L.Int.V-EP = B.L.Int.V-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(280 240, 240 140, 200 120, 80 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-7: middle portions of two LineStrings overlapping [dim(1){A.L.Int.V-NV = B.L.Int.NV-V}]</desc>
+  <a>
+    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
+  </a>
+  <b>
+    LINESTRING(20 80, 120 80, 200 80, 260 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-8: middle portion of LineString A overlapping start portion of LineString B [dim(1){A.L.Int.V-V = B.L.Int.SP-V}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(100 100, 200 120, 240 140, 280 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-9: middle portion of LineString A overlapping end portion of LineString B [dim(1){A.L.Int.V-V = B.L.Int.V-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(280 240, 240 140, 200 120, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-10: middle portions of two LineStrings overlapping [dim(1){A.L.Int.V-V = B.L.Int.V-V}]</desc>
+  <a>
+    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
+  </a>
+  <b>
+    LINESTRING(80 20, 80 80, 240 80, 300 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-11: middle portions of two LineStrings overlapping, multiple intersects [dim(1){A.L.Int.V-V = B.L.Int.V-NV}, dim(1){A.L.Int.V-V = B.L.Int.V-NV}, dim(1){A.L.Int.V-V = B.L.Int.V-NV}]</desc>
+  <a>
+    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
+  </a>
+  <b>
+    LINESTRING(20 80, 80 80, 120 80, 140 140, 160 80, 200 80, 220 20, 240 80, 270 110, 
+    300 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-3-1: a LineString touching a LinearRing [dim(0){A.L.Bdy.SP = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(100 100, 20 180, 180 180)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-4-1: a LineString crossing a LinearRing [dim(0){A.L.Int.NV = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(20 100, 180 100, 100 180)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-4-2: a LineString crossing a LinearRing [dim(0){A.L.Int.NV = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(100 40, 100 160, 180 160)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-4-3: a LineString crossing a LinearRing [dim(0){A.L.Int.V = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(20 100, 100 100, 180 100, 100 180)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-5-1: a LineString within a LinearRing [dim(1){A.L.Int.SP-EP = B.LR.Int.SP-NV}]</desc>
+  <a>
+    LINESTRING(100 100, 160 40)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-5-2: a LineString within a LinearRing [dim(1){A.L.Int.SP-EP = B.LR.Int.SP-NV}]</desc>
+  <a>
+    LINESTRING(100 100, 180 20)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-5-3: a LineString within a LinearRing [dim(1){A.L.Int.SP-V-EP = B.LR.Int.NV-CP-NV}]</desc>
+  <a>
+    LINESTRING(60 60, 100 100, 140 60)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-6-1: a LineString crossing a LinearRing [dim(1){A.L.Int.SP-NV = B.LR.Int.SP-V}]</desc>
+  <a>
+    LINESTRING(100 100, 190 10, 190 100)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F10F01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-6-2: a LineString crossing a LinearRing [dim(1){A.L.Int.SP-V = B.LR.Int.SP-NV}]</desc>
+  <a>
+    LINESTRING(100 100, 160 40, 160 100)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F10F01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-6-3: a LineString crossing a LinearRing [dim(1){A.L.Int.NV-V = B.LR.Int.SP-NV}]</desc>
+  <a>
+    LINESTRING(60 140, 160 40, 160 140)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's end point with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Bdy.EPb}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 20 80, 140 80, 80 20, 80 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's end point with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Bdy.EPo}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 20 80, 140 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's end point with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 140 80, 80 20, 80 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's closing point with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.CPb}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 20 80, 140 80, 80 20, 80 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's closing point with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.CPo}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 20 80, 140 80, 80 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's closing point with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Int.CPx}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 20 80, 20 140, 140 20, 80 20, 80 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex [dim(0){A.L.Int.NV = B.nsL.Int.NV}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(20 140, 140 20, 100 20, 100 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.NVb}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 120 80, 80 20, 80 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.NVo}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 140 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Int.NVx}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 80 140, 80 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex [dim(0){A.L.Int.NV = B.nsL.Int.V}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 80 80, 20 80, 50 140, 50 60)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.Vb}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 120 80, 80 20, 80 80, 80 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.Vo}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 80 80, 140 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Int.Vx}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 80 140, 80 80, 80 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.1-3-1: start point of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Bdy.SP = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(130 150, 220 150, 220 240)
+  </a>
+  <b>
+    LINESTRING(130 240, 130 150, 220 20, 50 20, 130 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.1-3-2: the interior of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Int.V = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(30 150, 130 150, 250 150)
+  </a>
+  <b>
+    LINESTRING(130 240, 130 150, 220 20, 50 20, 130 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.1-3-3: the interior of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Int.NV = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(30 150, 250 150)
+  </a>
+  <b>
+    LINESTRING(130 240, 130 150, 220 20, 50 20, 130 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.1-3-4: the interior of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Int.V = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(30 150, 130 150, 250 150)
+  </a>
+  <b>
+    LINESTRING(130 240, 130 20, 30 20, 130 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.1-4: a Line crossing a non-simple LineString at non-vertices [dim(0){A.L.Int.NV = B.nsL.Int.NV}]</desc>
+  <a>
+    LINESTRING(30 150, 250 150)
+  </a>
+  <b>
+    LINESTRING(120 240, 120 20, 20 20, 120 170)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL.5/L-3-1: switching the geometries for case L/nsL.5-3-1 [dim(0){A.nsL.Bdy.EPx = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.5-3-2: the start point of a line touching the self-intersecting and self-crossing point of a non-simple LineString [dim(0){A.L.Bdy.SP = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(110 110, 200 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.5-3-3: the interior of a line touching the self-intersecting and self-crossing point of a non-simple LineString [dim(0){A.L.Int.NV = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(20 110, 200 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL.5/L-3-4 touches dim(0){A.nsL.Bdy.EPx = B.L.Int.NV}</desc>
+  <a>
+    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </a>
+  <b>
+    LINESTRING(20 110, 200 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.10-6-1: the middle portion of a line overlapping from the self-intersecting to the self-crossing a non-simple LineString [dim(1){A.L.Int.V-V = B.nsL.Int.EPx-NVx}]</desc>
+  <a>
+    LINESTRING(90 200, 90 130, 110 110, 150 200)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.10-6-2: the middle portion of a line overlapping from the self-intersecting to the self-crossing a non-simple LineString [dim(1){A.L.Int.V-V = B.nsL.Int.NVx-EPx}]</desc>
+  <a>
+    LINESTRING(200 110, 110 110, 90 130, 90 200)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/mL-3-1: a line's end point touching a non-vertex with crossing line segments of a MultiLineString [dim(0){A.L.Bdy.SP = B.mL.Int.NVx]</desc>
+  <a>
+    LINESTRING(80 80, 150 80, 210 80)
+  </a>
+  <b>
+    MULTILINESTRING(
+      (20 20, 140 140), 
+      (20 140, 140 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-1-1: two equal LinearRings, pointwise [dim(1){A.LR.Int.SP-EP = B.LR.Int.SP-EP}, dim(0){A.LR.Int.CP = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(40 80, 160 200, 260 20, 40 80)
+  </a>
+  <b>
+    LINESTRING(40 80, 160 200, 260 20, 40 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-1-2: two equal LinearRings with points in reverse sequence [dim(1){A.LR.Int.SP-EP = B.LR.Int.EP-SP}, dim(0){A.LR.Int.CP = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(40 80, 160 200, 260 20, 40 80)
+  </a>
+  <b>
+    LINESTRING(40 80, 260 20, 160 200, 40 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-1-3: two equal LinearRings with points in different sequence [dim(1){A.LR.Int.SP-EP = B.LR.Int.SP-EP}, dim(0){A.LR.Int.CP = B.LR.Int.V}, dim(0){A.LR.Int.V = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(40 80, 160 200, 260 20, 40 80)
+  </a>
+  <b>
+    LINESTRING(260 20, 40 80, 160 200, 260 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-1-4: two equal LinearRings with different number of points [dim(1){A.LR.Int.SP-EP = B.LR.Int.SP-EP}, dim(0){A.LR.Int.CP = B.LR.Int.V}, dim(0){A.LR.Int.NV = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(40 80, 160 200, 260 20, 40 80)
+  </a>
+  <b>
+    LINESTRING(100 140, 160 200, 260 20, 40 80, 100 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-1: two LinearRings crossing at closing points [dim(0){A.LR.Int.CP = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 180, 20 180, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-2: two LinearRings crossing at two points [dim(0){A.LR.Int.CP = B.LR.Int.CP}, dim(0){A.LR.Int.V = B.LR.Int.V},]</desc>
+  <a>
+    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
+  </a>
+  <b>
+    LINESTRING(40 150, 150 40, 170 20, 170 190, 40 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-3: two LinearRings crossing at the closing and a non-vertex [dim(0){A.LR.Int.CP = B.LR.Int.NV}]</desc>
+  <a>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </a>
+  <b>
+    LINESTRING(180 100, 20 100, 100 180, 180 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-4: two LinearRings crossing at the closing and a vertex [dim(0){A.LR.Int.CP = B.LR.Int.V}]</desc>
+  <a>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </a>
+  <b>
+    LINESTRING(180 180, 100 100, 20 180, 180 180)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-5: two LinearRings crossing at a vertex and a non-vertex [dim(0){A.LR.Int.V = B.LR.Int.NV}]</desc>
+  <a>
+    LINESTRING(20 180, 100 100, 20 20, 20 180)
+  </a>
+  <b>
+    LINESTRING(100 20, 100 180, 180 100, 100 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-6: two LinearRings crossing at two points [dim(0){A.LR.Int.V = B.LR.Int.NV}, dim(0){A.LR.Int.V = B.LR.Int.NV},]</desc>
+  <a>
+    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
+  </a>
+  <b>
+    LINESTRING(170 20, 20 170, 170 170, 170 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-6-1: two LinearRings overlapping [dim(1){A.LR.Int.CP-V = B.LR.Int.CP-V}]</desc>
+  <a>
+    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
+  </a>
+  <b>
+    LINESTRING(40 150, 150 150, 90 210, 40 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-6-2: two LinearRings overlapping [dim(1){A.LR.Int.CP-V = B.LR.Int.NV-NV}]</desc>
+  <a>
+    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
+  </a>
+  <b>
+    LINESTRING(20 150, 170 150, 90 230, 20 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-6-3: two LinearRings overlapping [dim(1){A.LR.Int.(V-V-V-EP) = B.LR.Int.(NV-V-V-SP)}]</desc>
+  <a>
+    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
+  </a>
+  <b>
+    LINESTRING(40 150, 150 150, 150 40, 20 40, 20 150, 40 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/nsL-3-1: a LinearRing touching a non-simple LineString [dim(0){A.nsL.Int.CP = B.nsL.Bdy.SPb}]</desc>
+  <a>
+    LINESTRING(110 110, 200 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 110, 20 200, 20 110, 200 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/nsL-3-1: a LinearRing touching a non-simple LineString [dim(0){A.nsL.Int.CP = B.nsL.Bdy.SPo}]</desc>
+  <a>
+    LINESTRING(110 110, 200 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 20 110, 200 110, 50 110, 110 170)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/nsL-3-1: a LinearRing touching a non-simple LineString [dim(0){A.nsL.Int.CP = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    LINESTRING(110 110, 200 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 20 200, 110 200, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/nsL-6-1: a LinearRing and a non-simple LineString overlapping [dim(1){A.nsL.Int.SP-V = B.nsL.Int.NVx-SP}]</desc>
+  <a>
+    LINESTRING(110 110, 200 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(200 20, 20 200, 200 200, 110 110, 110 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/nsL-6-2: a LinearRing and a non-simple LineString overlapping [dim(1){A.nsL.Int.SP-V = B.nsL.Int.NVx-SP}, dim(1){A.nsL.Int.V-EP = B.nsL.Int.EP-NVx}]</desc>
+  <a>
+    LINESTRING(110 110, 200 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(200 20, 20 200, 200 200, 20 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-1: non-simple LineStrings crossing at closing points [dim(0){A.nsL.Int.CP = B.nsL.Int.CP}]</desc>
+  <a>
+    LINESTRING(110 110, 20 110, 110 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 200 110, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-2: non-simple LineStrings crossing at two points without vertices [dim(0){A.nsL.Int.NV = B.nsL.Int.NV}]</desc>
+  <a>
+    LINESTRING(20 120, 120 120, 20 20, 120 20, 20 120)
+  </a>
+  <b>
+    LINESTRING(170 100, 70 100, 170 170, 70 170, 170 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-3: non-simple LineStrings crossing at a point [dim(0){A.nsL.Int.NV = B.nsL.Int.V}]</desc>
+  <a>
+    LINESTRING(20 110, 110 110, 20 20, 110 20, 20 110)
+  </a>
+  <b>
+    LINESTRING(110 160, 70 110, 60 160, 20 130, 110 160)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-4: non-simple LineStrings crossing at self-crossing points [dim(0){A.nsL.Int.NVx = B.nsL.Int.NVx}]</desc>
+  <a>
+    LINESTRING(20 200, 200 200, 20 20, 200 20, 20 200)
+  </a>
+  <b>
+    LINESTRING(20 110, 200 110, 200 160, 20 60, 20 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-5: non-simple LineStrings crossing at vertices [dim(0){A.nsL.Int.V = B.nsL.Int.V}]</desc>
+  <a>
+    LINESTRING(20 110, 110 110, 20 20, 110 20, 20 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 110 110, 200 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-6: non-simple LineStrings crossing at two points with vertices [dim(0){A.nsL.Int.V = B.nsL.Int.V}]</desc>
+  <a>
+    LINESTRING(20 120, 120 120, 20 20, 120 20, 20 120)
+  </a>
+  <b>
+    LINESTRING(220 120, 120 20, 220 20, 120 120, 220 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-1: MultiLineString [dim(1){A.mL.Int.SP-EP = B.mL.Int.SP-EP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (70 20, 20 90, 70 170), 
+      (70 170, 120 90, 70 20))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (70 20, 20 90, 70 170), 
+      (70 170, 120 90, 70 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-1-1: non-simple MultiLineString  [dim(1){A.mL.Int.SP-EP = B.mL.Int.SP-EP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-1-2: equal non-simple MultiLineString with different sequence of lines and points [dim(1){A.mL.Int.SP-EP = B.mL.Int.EP-SP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 140, 90 60, 90 20), 
+      (170 20, 130 20, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-1: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPb}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60), 
+      (130 100, 130 60, 90 20, 50 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-2: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPo}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (130 140, 130 60, 90 20, 20 90, 90 20, 130 60, 170 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-3: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPx}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-4: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPx}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60), 
+      (130 100, 90 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-5: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPx}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60), 
+      (120 100, 170 100, 90 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-6: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Int.SPb}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60), 
+      (120 100, 170 100, 90 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-7: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Int.SPo}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (130 140, 130 60, 90 20, 20 90, 90 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-8: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Int.SPx}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60, 20 140, 90 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-4-1: non-simple MultiLineStrings crossing [dim(0){A.mL.Int.Vx = B.mL.Int.Vb}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 90, 20 160), 
+      (90 160, 90 20))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (160 160, 90 90, 160 20), 
+      (160 120, 120 120, 90 90, 160 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-4-2: non-simple MultiLineStrings crossing [dim(0){A.mL.Int.Vx = B.mL.Int.Vo}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 90, 20 160), 
+      (90 160, 90 20))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (160 160, 90 90, 160 20), 
+      (160 120, 120 120, 90 90, 120 60, 160 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-4-3: non-simple MultiLineStrings crossing [dim(0){A.mL.Int.Vx = B.mL.Int.Vx}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 90, 20 160), 
+      (90 160, 90 20))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (160 160, 90 90, 160 20), 
+      (160 120, 90 90, 160 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
 </run>
\ No newline at end of file
diff --git a/test/validate/TestRelatePA.xml b/test/validate/TestRelatePA.xml
index 030edb9..dae0bfe 100644
--- a/test/validate/TestRelatePA.xml
+++ b/test/validate/TestRelatePA.xml
@@ -1,622 +1,622 @@
 <run>
 <precisionModel type="FLOATING"/>
-
-<case>
-<desc>P/A-2-1: a point outside a polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
-  <a>
-    POINT(20 20)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/A-2-2: a point outside a converx polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
-  <a>
-    POINT(70 170)
-  </a>
-  <b>
-    POLYGON(
-      (110 230, 80 160, 20 160, 20 20, 200 20, 200 160, 140 160, 110 230))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/A-2-3: a point outside a concave polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
-  <a>
-    POINT(110 130)
-  </a>
-  <b>
-    POLYGON(
-      (20 160, 80 160, 110 100, 140 160, 200 160, 200 20, 20 20, 20 160))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/A-2-4: dim(0){A.P.Int = B.A.Ext}</desc>
-  <a>
-    POINT(100 70)
-  </a>
-  <b>
-    POLYGON(
-      (20 150, 100 150, 40 50, 170 50, 110 150, 190 150, 190 20, 20 20, 20 150))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/A-2-5: a point outside a concave polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
-  <a>
-    POINT(100 70)
-  </a>
-  <b>
-    POLYGON(
-      (20 150, 100 150, 40 50, 160 50, 100 150, 180 150, 180 20, 20 20, 20 150))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/A-3-1: a point on the closing point of a polygon [dim(0){A.P.Int = B.A.Bdy.CP}]</desc>
-  <a>
-    POINT(60 120)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/A-3-2: a point on the boudary of a polygon at a non-vertex [dim(0){A.P.Int = B.A.Bdy.NV}]</desc>
-  <a>
-    POINT(110 120)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/A-3-3: a point on the boundary of a polygon at a vertex [dim(0){A.P.Int = B.A.Bdy.V]</desc>
-  <a>
-    POINT(160 120)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/A-3-4: a point on the touching point of boudary [dim(0){A.P.Int = B.A.Bdy.TP}]</desc>
-  <a>
-    POINT(100 150)
-  </a>
-  <b>
-    POLYGON(
-      (20 150, 100 150, 40 50, 160 50, 100 150, 180 150, 180 20, 20 20, 20 150))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/A-5: a point on the interior of a polygon [dim(0){A.P.Int = B.A.Int}]</desc>
-  <a>
-    POINT(100 80)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/Ah-2-1: a point outside of polygon with a hole [dim(0){A.P.Int = B.A.Ext}]</desc>
-  <a>
-    POINT(60 160)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/Ah-2-2: a point inside the hole of the polygon [dim(0){A.P.Int = B.A.Ext.h}]</desc>
-  <a>
-    POINT(190 90)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/Ah-3-1: a point on the closing point of the outer boundary of a polygon with a hole [dim(0){A.P.Int = B.A.oBdy.CP}]</desc>
-  <a>
-    POINT(190 190)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/Ah-3-2: a point on the outer boundary of a polygon at a vertex [dim(0){A.P.Int = B.A.oBdy.V}]</desc>
-  <a>
-    POINT(360 20)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/Ah-3-3: a point on the outer boundary of a polygon at a non-vertex [dim(0){A.P.Int = B.A.oBdy.NV}]</desc>
-  <a>
-    POINT(130 130)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/Ah-3-4: a point on the closing point of the inner boundary of a polygon [dim(0){A.P.Int = B.A.iBdy.CP}]</desc>
-  <a>
-    POINT(280 50)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/Ah-3-5: a point on the inner boundary of a polygon at a non-vertex [dim(0){A.P.Int = B.A.iBdy.NV}]</desc>
-  <a>
-    POINT(150 100)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/Ah-3-6: a point on the inner boundary of a polygon at a vertex [dim(0){A.P.Int = B.A.iBdy.V}]</desc>
-  <a>
-    POINT(100 50)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/Ah-5: a point inside the interior of a polygon with a hole [dim(0){A.P.Int = B.A.Int}]</desc>
-  <a>
-    POINT(140 120)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/A2h-3-1: a point on the touching point of two holes in a polygon [dim(0){A.P.Int = B.A.iBdy.TP}]</desc>
-  <a>
-    POINT(190 50)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (90 50, 150 110, 190 50, 90 50), 
-      (190 50, 230 110, 290 50, 190 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/A2h-3-2: a point on the touching point of two holes in a polygon [dim(0){A.P.Int = B.A.iBdy.TP}]</desc>
-  <a>
-    POINT(180 90)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (180 140, 180 40, 80 40, 180 140), 
-      (180 90, 210 140, 310 40, 230 40, 180 90))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-2: 3 points outside a polygon [dim(0){A.2P.Int = B.A.Ext}]</desc>
-  <a>
-    MULTIPOINT(20 80, 110 160, 20 160)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-3-1: one of 3 points on the closing point of the boundary of a polygon [dim(0){A.3P1.Int = B.A.Bdy.CP}]</desc>
-  <a>
-    MULTIPOINT(20 80, 60 120, 20 160)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-3-2: one of 3 points on the boundary of a polygon at a non-vertex [dim(0){A.3P3 = B.A.Bdy.NV}]</desc>
-  <a>
-    MULTIPOINT(10 80, 110 170, 110 120)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-3-3: one of 3 points on the boundary of a polygon at a vertex [dim(0){A.3P1.Int = B.A.Bdy.V}]</desc>
-  <a>
-    MULTIPOINT(10 80, 110 170, 160 120)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-3-4: 3 of the 5 points on the boundary of a polygon [dim(0){A.5P2.Int = B.A.Bdy.CP}, dim(0){A.5P3.Int = B.A.Bdy.NV}, dim(0){A.5P4.Int = B.A.Bdy.V}]</desc>
-  <a>
-    MULTIPOINT(20 120, 60 120, 110 120, 160 120, 200 120)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-3-5: all 3 points on the boundary of a polygon [dim(0){A.3P1.Int = B.A.Bdy.CP}, dim(0){A.3P2.Int = B.A.Bdy.NV}, dim(0){A.3P3.Int = B.A.Bdy.V}]</desc>
-  <a>
-    MULTIPOINT(60 120, 110 120, 160 120)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-3-6: all 4 points on the boundary of a polygon [dim(0){A.4P = B.A.Bdy}]</desc>
-  <a>
-    MULTIPOINT(60 120, 160 120, 160 40, 60 40)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-4-1: 1 point outside a polygon, 1 point on the boundary and 1 point inside [dim(0){A.3P1.Int = B.A.Ext}, dim(0){A.3P2.Int = B.A.Bdy.CP}, dim(0){A.3P3.Int = B.A.Int}]</desc>
-  <a>
-    MULTIPOINT(20 150, 60 120, 110 80)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-4-2: 1 point outside a polygon, 1 point on the boundary and 1 point inside [dim(0){A.3P1.Int = B.A.Ext}, dim(0){A.3P2.Int = B.A.Bdy.V}, dim(0){A.3P3.Int = B.A.Int}]</desc>
-  <a>
-    MULTIPOINT(110 80, 160 120, 200 160)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-4-3: 1 point outside a polygon, 1 point on the boundary and 1 point inside [dim(0){A.3P1.Int = B.A.Ext}, dim(0){A.3P2.Int = B.A.Bdy.NV}, dim(0){A.3P3.Int = B.A.Int}]</desc>
-  <a>
-    MULTIPOINT(110 80, 110 120, 110 160)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-4-4: 1 point outside a polygon, 1 point inside [dim(0){A.2P1.Int = B.A.Ext}, dim(0){A.2P2.Int = B.A.Int}]</desc>
-  <a>
-    MULTIPOINT(110 170, 110 80)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-4-5: 1 point outside a polygon, 2 points on the boundary and 1 point inside [dim(0){A.4P1.Int = B.A.Ext}, dim(0){A.4P2.Int = B.A.Bdy.CP}, dim(0){A.4P3.Int = B.A.Bdy.V}, dim(0){A.4P4.Int = B.A.Int}]</desc>
-  <a>
-    MULTIPOINT(60 120, 160 120, 110 80, 110 170)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-5-1: 2 points within a polygon [dim(0){A.2P.Int = B.A.Int]</desc>
-  <a>
-    MULTIPOINT(90 80, 130 80)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/A-5-2: 1 point on the boundary and 1 point inside a polygon [dim(0){A.2P1.Int = B.A.Bdy.CP}, dim(0){A.2P2.Int = B.A.Int}]</desc>
-  <a>
-    MULTIPOINT(60 120, 160 120, 110 80)
-  </a>
-  <b>
-    POLYGON(
-      (60 120, 60 40, 160 40, 160 120, 60 120))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="00FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/Ah-2-1: 3 points outside a polygon [dim(0){A.3P.Int = B.Ah.Ext}]</desc>
-  <a>
-    MULTIPOINT(40 170, 40 90, 130 170)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/Ah-2-2: 2 points outside a polygon and 1 point inside the hole of the polygon [dim(0){A.3P1.Int = B.Ah.Ext}, dim(0){A.3P2.Int = B.Ah.Ext}, dim(0){A.3P3.Int = B.Ah.Ext.h}]</desc>
-  <a>
-    MULTIPOINT(90 170, 280 170, 190 90)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/Ah-2-3: all 3 points in polygon's hole [dim(0){A.3P.Int = B.Ah.Ext.h}]</desc>
-  <a>
-    MULTIPOINT(190 110, 150 70, 230 70)
-  </a>
-  <b>
-    POLYGON(
-      (190 190, 360 20, 20 20, 190 190), 
-      (280 50, 100 50, 190 140, 280 50))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/mA-3-1: a point on the touching point of two polygons [dim(0){A.P.Int = B.2A.Bdy}]</desc>
-  <a>
-    POINT(100 100)
-  </a>
-  <b>
-    MULTIPOLYGON(
-      (
-        (20 100, 20 20, 100 20, 100 100, 20 100)), 
-      (
-        (100 180, 100 100, 180 100, 180 180, 100 180)))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/mA-3-2: a point on the boundary of one of the 2 polygons [dim(0){A.P.Int = B.2A1.Bdy.CP}]</desc>
-  <a>
-    POINT(20 100)
-  </a>
-  <b>
-    MULTIPOLYGON(
-      (
-        (20 100, 20 20, 100 20, 100 100, 20 100)), 
-      (
-        (100 180, 100 100, 180 100, 180 180, 100 180)))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/mA-3-3: a point on the boundary of one of the 2 polygons [dim(0){A.P.Int = B.2A1.Bdy.V}]</desc>
-  <a>
-    POINT(60 100)
-  </a>
-  <b>
-    MULTIPOLYGON(
-      (
-        (20 100, 20 20, 100 20, 100 100, 20 100)), 
-      (
-        (100 180, 100 100, 180 100, 180 180, 100 180)))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/mA-3-4: a point touching a polygon's boundary where the boundaries touch at a point [dim(0){A.P.Int = B.2A.Bdy.TP}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    MULTIPOLYGON(
-      (
-        (110 110, 20 200, 200 200, 110 110), 
-        (110 110, 80 180, 140 180, 110 110)), 
-      (
-        (110 110, 20 20, 200 20, 110 110), 
-        (110 110, 80 40, 140 40, 110 110)))
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
-  </test>
-</case>
-
+
+<case>
+<desc>P/A-2-1: a point outside a polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-2-2: a point outside a converx polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
+  <a>
+    POINT(70 170)
+  </a>
+  <b>
+    POLYGON(
+      (110 230, 80 160, 20 160, 20 20, 200 20, 200 160, 140 160, 110 230))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-2-3: a point outside a concave polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
+  <a>
+    POINT(110 130)
+  </a>
+  <b>
+    POLYGON(
+      (20 160, 80 160, 110 100, 140 160, 200 160, 200 20, 20 20, 20 160))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-2-4: dim(0){A.P.Int = B.A.Ext}</desc>
+  <a>
+    POINT(100 70)
+  </a>
+  <b>
+    POLYGON(
+      (20 150, 100 150, 40 50, 170 50, 110 150, 190 150, 190 20, 20 20, 20 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-2-5: a point outside a concave polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
+  <a>
+    POINT(100 70)
+  </a>
+  <b>
+    POLYGON(
+      (20 150, 100 150, 40 50, 160 50, 100 150, 180 150, 180 20, 20 20, 20 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-3-1: a point on the closing point of a polygon [dim(0){A.P.Int = B.A.Bdy.CP}]</desc>
+  <a>
+    POINT(60 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-3-2: a point on the boudary of a polygon at a non-vertex [dim(0){A.P.Int = B.A.Bdy.NV}]</desc>
+  <a>
+    POINT(110 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-3-3: a point on the boundary of a polygon at a vertex [dim(0){A.P.Int = B.A.Bdy.V]</desc>
+  <a>
+    POINT(160 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-3-4: a point on the touching point of boudary [dim(0){A.P.Int = B.A.Bdy.TP}]</desc>
+  <a>
+    POINT(100 150)
+  </a>
+  <b>
+    POLYGON(
+      (20 150, 100 150, 40 50, 160 50, 100 150, 180 150, 180 20, 20 20, 20 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-5: a point on the interior of a polygon [dim(0){A.P.Int = B.A.Int}]</desc>
+  <a>
+    POINT(100 80)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-2-1: a point outside of polygon with a hole [dim(0){A.P.Int = B.A.Ext}]</desc>
+  <a>
+    POINT(60 160)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-2-2: a point inside the hole of the polygon [dim(0){A.P.Int = B.A.Ext.h}]</desc>
+  <a>
+    POINT(190 90)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-1: a point on the closing point of the outer boundary of a polygon with a hole [dim(0){A.P.Int = B.A.oBdy.CP}]</desc>
+  <a>
+    POINT(190 190)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-2: a point on the outer boundary of a polygon at a vertex [dim(0){A.P.Int = B.A.oBdy.V}]</desc>
+  <a>
+    POINT(360 20)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-3: a point on the outer boundary of a polygon at a non-vertex [dim(0){A.P.Int = B.A.oBdy.NV}]</desc>
+  <a>
+    POINT(130 130)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-4: a point on the closing point of the inner boundary of a polygon [dim(0){A.P.Int = B.A.iBdy.CP}]</desc>
+  <a>
+    POINT(280 50)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-5: a point on the inner boundary of a polygon at a non-vertex [dim(0){A.P.Int = B.A.iBdy.NV}]</desc>
+  <a>
+    POINT(150 100)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-6: a point on the inner boundary of a polygon at a vertex [dim(0){A.P.Int = B.A.iBdy.V}]</desc>
+  <a>
+    POINT(100 50)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-5: a point inside the interior of a polygon with a hole [dim(0){A.P.Int = B.A.Int}]</desc>
+  <a>
+    POINT(140 120)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A2h-3-1: a point on the touching point of two holes in a polygon [dim(0){A.P.Int = B.A.iBdy.TP}]</desc>
+  <a>
+    POINT(190 50)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (90 50, 150 110, 190 50, 90 50), 
+      (190 50, 230 110, 290 50, 190 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A2h-3-2: a point on the touching point of two holes in a polygon [dim(0){A.P.Int = B.A.iBdy.TP}]</desc>
+  <a>
+    POINT(180 90)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (180 140, 180 40, 80 40, 180 140), 
+      (180 90, 210 140, 310 40, 230 40, 180 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-2: 3 points outside a polygon [dim(0){A.2P.Int = B.A.Ext}]</desc>
+  <a>
+    MULTIPOINT(20 80, 110 160, 20 160)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-1: one of 3 points on the closing point of the boundary of a polygon [dim(0){A.3P1.Int = B.A.Bdy.CP}]</desc>
+  <a>
+    MULTIPOINT(20 80, 60 120, 20 160)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-2: one of 3 points on the boundary of a polygon at a non-vertex [dim(0){A.3P3 = B.A.Bdy.NV}]</desc>
+  <a>
+    MULTIPOINT(10 80, 110 170, 110 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-3: one of 3 points on the boundary of a polygon at a vertex [dim(0){A.3P1.Int = B.A.Bdy.V}]</desc>
+  <a>
+    MULTIPOINT(10 80, 110 170, 160 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-4: 3 of the 5 points on the boundary of a polygon [dim(0){A.5P2.Int = B.A.Bdy.CP}, dim(0){A.5P3.Int = B.A.Bdy.NV}, dim(0){A.5P4.Int = B.A.Bdy.V}]</desc>
+  <a>
+    MULTIPOINT(20 120, 60 120, 110 120, 160 120, 200 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-5: all 3 points on the boundary of a polygon [dim(0){A.3P1.Int = B.A.Bdy.CP}, dim(0){A.3P2.Int = B.A.Bdy.NV}, dim(0){A.3P3.Int = B.A.Bdy.V}]</desc>
+  <a>
+    MULTIPOINT(60 120, 110 120, 160 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-6: all 4 points on the boundary of a polygon [dim(0){A.4P = B.A.Bdy}]</desc>
+  <a>
+    MULTIPOINT(60 120, 160 120, 160 40, 60 40)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-4-1: 1 point outside a polygon, 1 point on the boundary and 1 point inside [dim(0){A.3P1.Int = B.A.Ext}, dim(0){A.3P2.Int = B.A.Bdy.CP}, dim(0){A.3P3.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(20 150, 60 120, 110 80)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-4-2: 1 point outside a polygon, 1 point on the boundary and 1 point inside [dim(0){A.3P1.Int = B.A.Ext}, dim(0){A.3P2.Int = B.A.Bdy.V}, dim(0){A.3P3.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(110 80, 160 120, 200 160)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-4-3: 1 point outside a polygon, 1 point on the boundary and 1 point inside [dim(0){A.3P1.Int = B.A.Ext}, dim(0){A.3P2.Int = B.A.Bdy.NV}, dim(0){A.3P3.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(110 80, 110 120, 110 160)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-4-4: 1 point outside a polygon, 1 point inside [dim(0){A.2P1.Int = B.A.Ext}, dim(0){A.2P2.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(110 170, 110 80)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-4-5: 1 point outside a polygon, 2 points on the boundary and 1 point inside [dim(0){A.4P1.Int = B.A.Ext}, dim(0){A.4P2.Int = B.A.Bdy.CP}, dim(0){A.4P3.Int = B.A.Bdy.V}, dim(0){A.4P4.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(60 120, 160 120, 110 80, 110 170)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-5-1: 2 points within a polygon [dim(0){A.2P.Int = B.A.Int]</desc>
+  <a>
+    MULTIPOINT(90 80, 130 80)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-5-2: 1 point on the boundary and 1 point inside a polygon [dim(0){A.2P1.Int = B.A.Bdy.CP}, dim(0){A.2P2.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(60 120, 160 120, 110 80)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/Ah-2-1: 3 points outside a polygon [dim(0){A.3P.Int = B.Ah.Ext}]</desc>
+  <a>
+    MULTIPOINT(40 170, 40 90, 130 170)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/Ah-2-2: 2 points outside a polygon and 1 point inside the hole of the polygon [dim(0){A.3P1.Int = B.Ah.Ext}, dim(0){A.3P2.Int = B.Ah.Ext}, dim(0){A.3P3.Int = B.Ah.Ext.h}]</desc>
+  <a>
+    MULTIPOINT(90 170, 280 170, 190 90)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/Ah-2-3: all 3 points in polygon's hole [dim(0){A.3P.Int = B.Ah.Ext.h}]</desc>
+  <a>
+    MULTIPOINT(190 110, 150 70, 230 70)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mA-3-1: a point on the touching point of two polygons [dim(0){A.P.Int = B.2A.Bdy}]</desc>
+  <a>
+    POINT(100 100)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 100, 20 20, 100 20, 100 100, 20 100)), 
+      (
+        (100 180, 100 100, 180 100, 180 180, 100 180)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mA-3-2: a point on the boundary of one of the 2 polygons [dim(0){A.P.Int = B.2A1.Bdy.CP}]</desc>
+  <a>
+    POINT(20 100)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 100, 20 20, 100 20, 100 100, 20 100)), 
+      (
+        (100 180, 100 100, 180 100, 180 180, 100 180)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mA-3-3: a point on the boundary of one of the 2 polygons [dim(0){A.P.Int = B.2A1.Bdy.V}]</desc>
+  <a>
+    POINT(60 100)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 100, 20 20, 100 20, 100 100, 20 100)), 
+      (
+        (100 180, 100 100, 180 100, 180 180, 100 180)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mA-3-4: a point touching a polygon's boundary where the boundaries touch at a point [dim(0){A.P.Int = B.2A.Bdy.TP}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (110 110, 20 200, 200 200, 110 110), 
+        (110 110, 80 180, 140 180, 110 110)), 
+      (
+        (110 110, 20 20, 200 20, 110 110), 
+        (110 110, 80 40, 140 40, 110 110)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
 </run>
\ No newline at end of file
diff --git a/test/validate/TestRelatePL.xml b/test/validate/TestRelatePL.xml
index 57b2e77..b732216 100644
--- a/test/validate/TestRelatePL.xml
+++ b/test/validate/TestRelatePL.xml
@@ -1,1283 +1,1283 @@
 <run>
 <precisionModel type="FLOATING"/>
-
-<case>
-<desc>P/L-2: a point and a line disjoint [dim(0){A.P.Int = B.L.Ext}]</desc>
-  <a>
-    POINT(110 200)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/L-3-1: a point touching the start point of a line  [dim(0){A.P.Int = B.L.Bdy.SP}]</desc>
-  <a>
-    POINT(90 80)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/L-3-2: a point touching the end point of a line [dim(0){A.P.Int = B.L.Bdy.EP}]</desc>
-  <a>
-    POINT(340 240)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/L-5-1: a point on the line at a non-vertex [dim(0){A.P.Int = B.L.Int.NV}]</desc>
-  <a>
-    POINT(230 150)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/L-5-2: a point on the line at a vertex [dim(0){A.P.Int = B.L.Int.V}]</desc>
-  <a>
-    POINT(160 150)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/LR-2-1: a point outside a LinearRing [dim(0){A.P.Int = B.LR.Ext}]</desc>
-  <a>
-    POINT(90 150)
-  </a>
-  <b>
-    LINESTRING(150 150, 20 20, 280 20, 150 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/LR-2-2: a point inside a LinearRing  [dim(0){A.P.Int = B.LR.Ext}]</desc>
-  <a>
-    POINT(150 80)
-  </a>
-  <b>
-    LINESTRING(150 150, 20 20, 280 20, 150 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/LR-5-1: a point on the closing point of a LinearRing [dim(0){A.P.Int = B.LR.Int.CP}]</desc>
-  <a>
-    POINT(150 150)
-  </a>
-  <b>
-    LINESTRING(150 150, 20 20, 280 20, 150 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/LR-5-2: a point on a LinearRing at a non-vertex [dim(0){A.P.Int = B.L.Int.NV}]</desc>
-  <a>
-    POINT(100 20)
-  </a>
-  <b>
-    LINESTRING(150 150, 20 20, 280 20, 150 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/LR-5-3: a point on a LinearRing at a vertex [dim(0){A.P.Int = B.L.Int.V}]</desc>
-  <a>
-    POINT(20 20)
-  </a>
-  <b>
-    LINESTRING(150 150, 20 20, 280 20, 150 150)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.1-3-1: a point on a non-simple LineString's end point [dim(0){A.P.Int = B.nsL.Bdy.EP}]</desc>
-  <a>
-    POINT(220 220)
-  </a>
-  <b>
-    LINESTRING(110 110, 220 20, 20 20, 110 110, 220 220)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.1-5-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 220 20, 20 20, 110 110, 220 220)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.1-5-2: a point a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 220 20, 20 20, 220 220)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.1-5-3: a point on a non-simple LineString's interior at a non-vertex [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
-  <a>
-    POINT(110 20)
-  </a>
-  <b>
-    LINESTRING(110 110, 220 20, 20 20, 220 220)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.1-5-4: a point on a non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
-  <a>
-    POINT(220 20)
-  </a>
-  <b>
-    LINESTRING(110 110, 220 20, 20 20, 220 220)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.2-5-2: a point on a non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
-  <a>
-    POINT(110 20)
-  </a>
-  <b>
-    LINESTRING(220 220, 20 20, 220 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.2-5-3: a point on a non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
-  <a>
-    POINT(20 20)
-  </a>
-  <b>
-    LINESTRING(220 220, 20 20, 220 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.2-5-4: a point on a non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
-  <a>
-    POINT(20 110)
-  </a>
-  <b>
-    LINESTRING(20 200, 20 20, 110 20, 20 110, 110 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.3-3-1: a point on a non-simple LineString's start point [dim(0){A.P.Int = B.nsL.Bdy.SP}]</desc>
-  <a>
-    POINT(20 200)
-  </a>
-  <b>
-    LINESTRING(20 200, 200 20, 20 20, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.3-5-1: a point on a non-simple LineString's interior at a non-vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(20 200, 200 20, 140 20, 140 80, 80 140, 20 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.3-5-2: a point on a non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(20 200, 200 20, 20 20, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.3-5-3: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
-  <a>
-    POINT(80 140)
-  </a>
-  <b>
-    LINESTRING(20 200, 110 110, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.3-5-4: a point on a non-simple LineString's interior at a two-vertex point with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vo}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(20 200, 110 110, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.3-5-5: a point on a non-simple LineString's interior at a vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vo}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(20 200, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.3-5-6: a point on a non-simple LineString's interior at a two-vertex point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(20 200, 110 110, 200 20, 20 20, 110 110, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.3-5-7: a point on a non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(20 200, 200 20, 20 20, 110 110, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.3-5-8: a point on a non-simple LineString's interior at a two-vertex point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(20 200, 110 110, 20 20, 200 20, 110 110, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.4-3-1: a point on a non-simple LineString's start point with crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 110 200, 20 200, 110 110, 200 20, 140 20, 140 80, 110 110, 80 140, 
-    20 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.4-3-2: a point on a non-simple LineString's start point with crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 110 200, 20 200, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.4-3-3:a point on a non-simple LineString's start point with crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 110 200, 20 200, 200 20, 140 20, 140 80, 80 140, 20 140)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.4-3-4: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 110 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.4-3-5: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 110 200, 20 200, 200 20, 20 20, 110 110, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.4-3-6: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 110 200, 20 200, 200 20, 20 20, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.4-3-7: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 110 200, 20 200, 110 110, 20 20, 200 20, 110 110, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.4-3-8: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 110 200, 20 200, 200 20, 200 110, 110 110, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.5-3-1: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 110 110, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.5-3-2: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.5-3-3: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 200 20, 20 200, 110 200, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.5-3-4: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 110 110, 200 20, 20 20, 110 110, 20 200, 110 200, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.5-3-5: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 20 110, 110 110, 20 200, 110 200, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.6-3-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(110 160)
-  </a>
-  <b>
-    LINESTRING(110 160, 200 250, 110 250, 110 160, 110 110, 110 20, 20 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.6-3-2: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(110 160)
-  </a>
-  <b>
-    LINESTRING(110 160, 200 250, 110 250, 110 110, 110 20, 20 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.6-3-3: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 160, 200 250, 110 250, 110 160, 110 110, 110 20, 20 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.6-3-4: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 160, 200 250, 110 250, 110 160, 110 20, 20 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.7-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 20 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.7-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 200 200, 110 200, 110 20, 20 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.7-5-3: a point on a closed non-simple LineString's interior at a non-vertex [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
-  <a>
-    POINT(140 200)
-  </a>
-  <b>
-    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 20 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.7-5-4: a point on a closed non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
-  <a>
-    POINT(110 200)
-  </a>
-  <b>
-    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 20 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.8-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 200 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.8-5-2: a point on the interior (at a non-vertex) of a closed non-simple LineString [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
-  <a>
-    POINT(140 200)
-  </a>
-  <b>
-    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 200 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.8-5-3: a point on a closed non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
-  <a>
-    POINT(110 200)
-  </a>
-  <b>
-    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 200 20, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.9-3-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(90 130)
-  </a>
-  <b>
-    LINESTRING(90 130, 20 130, 20 200, 90 130, 200 20, 20 20, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.9-5-1: a point on a non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(90 130, 20 130, 20 200, 90 130, 200 20, 20 20, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.10-3-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(90 130)
-  </a>
-  <b>
-    LINESTRING(90 130, 20 130, 20 200, 200 20, 20 20, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.10-5-1: a point on a non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(90 130, 20 130, 20 200, 200 20, 20 20, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.11-3-1: a point on a closed non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
-  <a>
-    POINT(90 130)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 200 20, 90 130, 20 200, 20 130, 90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.11-5-1: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 200 20, 90 130, 20 200, 20 130, 90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.12-3-1: a point on a closed non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
-  <a>
-    POINT(90 130)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.12-5-1: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.13-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 20 130, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 200 130, 
-    110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.13-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 20 130, 20 200, 200 20, 20 20, 200 200, 200 130, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.14-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 80 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 140 200, 
-    110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.14-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 110, 80 200, 20 200, 200 20, 20 20, 200 200, 140 200, 110 110)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.15-5-1: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 20 20, 200 20, 20 200, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.15-5-2: a point on a closed non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 110 110, 20 20, 200 20, 110 110, 20 200, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.15-5-3: a point on a closed non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(200 200, 110 110, 200 20, 20 20, 110 110, 20 200, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.16-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(90 130)
-  </a>
-  <b>
-    LINESTRING(90 130, 20 130, 20 200, 90 130, 110 110, 200 20, 20 20, 110 110, 200 200, 
-    90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.16-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(90 130)
-  </a>
-  <b>
-    LINESTRING(90 130, 20 130, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.17-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(90 130)
-  </a>
-  <b>
-    LINESTRING(90 130, 90 200, 20 200, 90 130, 110 110, 200 20, 20 20, 110 110, 200 200, 
-    90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.17-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(90 130)
-  </a>
-  <b>
-    LINESTRING(90 130, 90 200, 20 200, 200 20, 20 20, 200 200, 90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.17-5-3: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(90 130)
-  </a>
-  <b>
-    LINESTRING(90 130, 90 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.17-5-4: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
-  <a>
-    POINT(90 130)
-  </a>
-  <b>
-    LINESTRING(90 130, 90 200, 20 200, 200 20, 20 20, 200 200, 90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.17-5-5: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(90 130, 90 200, 20 200, 200 20, 20 20, 200 200, 90 130)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.18-5-1: a point on a non-simple LineString's start point with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb)}]</desc>
-  <a>
-    POINT(110 200)
-  </a>
-  <b>
-    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.18-5-2: a point on a non-simple LineString's interior at a non-vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
-  <a>
-    POINT(110 150)
-  </a>
-  <b>
-    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.18-5-3: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.19-5-1: a point on a non-simple LineString's closing point with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.CPo}]</desc>
-  <a>
-    POINT(110 200)
-  </a>
-  <b>
-    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.19-5-2: a point on a non-simple LineString's interior at a non-vertex overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
-  <a>
-    POINT(110 150)
-  </a>
-  <b>
-    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.19-5-3: a point on a non-simple LineString interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.20-5-1: a point on a non-simple LineString's interior at a non-vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
-  <a>
-    POINT(110 150)
-  </a>
-  <b>
-    LINESTRING(20 200, 110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsL.20-5-2: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
-  <a>
-    POINT(110 110)
-  </a>
-  <b>
-    LINESTRING(20 200, 110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/nsl.20-5-3: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
-  <a>
-    POINT(110 200)
-  </a>
-  <b>
-    LINESTRING(20 200, 110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-2-1: MultiPoint and a line disjoint (points on one side of the line) [dim(0){A.3P.Int = B.L.Ext}]</desc>
-  <a>
-    MULTIPOINT(50 250, 90 220, 130 190)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-2-2: MultiPoint and a line disjoint (points over the line but no intersection) [dim(0){A.3P.Int = B.L.Ext}]</desc>
-  <a>
-    MULTIPOINT(180 180, 230 130, 280 80)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-3-1: one of the points intersecting the start point of a line [dim(0){A.3P2.Int = B.L.Bdy.SP}]</desc>
-  <a>
-    MULTIPOINT(50 120, 90 80, 130 40)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F00FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-3-2: one of the points intersecting the end point of a line [dim(0){A.3P2 = B.L.Bdy.EP}]</desc>
-  <a>
-    MULTIPOINT(300 280, 340 240, 380 200)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="F00FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-4-1: one of the points intersecting the interior of a line at a non-vertex (points on one side of the line) [dim(0){A.3P1.Int = B.L.Int.NV]</desc>
-  <a>
-    MULTIPOINT(230 150, 260 120, 290 90)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-4-2: one of the points intersecting the interior of a line at a non-vertex (points over the line) [dim(0){A.3P2.Int = B.L.Int.NV]</desc>
-  <a>
-    MULTIPOINT(200 190, 240 150, 270 110)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-4-3: one of the points intersecting the interior of a line at a vertex (points on one side of the line) [dim(0){A.3P1.Int = B.L.Int.V]</desc>
-  <a>
-    MULTIPOINT(160 150, 190 120, 220 90)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-4-4: one of the points intersecting the interior of a line at a vertex (points over the line) [dim(0){A.3P2.Int = B.L.Int.V]</desc>
-  <a>
-    MULTIPOINT(120 190, 160 150, 200 110)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-5-1: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Bdy.EP}]</desc>
-  <a>
-    MULTIPOINT(90 80, 160 150, 340 240)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="00FFFF1F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-5-2: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.V}]</desc>
-  <a>
-    MULTIPOINT(90 80, 160 150, 300 150)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-5-3: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
-  <a>
-    MULTIPOINT(90 80, 160 150, 240 150)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-5-4: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.NV}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
-  <a>
-    MULTIPOINT(90 80, 130 120, 210 150)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-5-5: all the points on a line [dim(0){A.3P1.Int = B.L.Int.NV}, dim(0){A.3P2.Int = B.L.Int.NV}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
-  <a>
-    MULTIPOINT(130 120, 210 150, 340 200)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-5-6: all the points on a line [dim(0){A.3P1.Int = B.L.Int.V}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
-  <a>
-    MULTIPOINT(160 150, 240 150, 340 210)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-5-7: all the points on a line [dim(0){A.3P1.Int = B.L.Int.V}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.V}]</desc>
-  <a>
-    MULTIPOINT(160 150, 300 150, 340 150)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/L-5-8: all the points on a line [dim(0){A.3P1.Int = B.L.Int.V}, dim(0){A.3P2.Int = B.L.Int.NV}, dim(0){A.3P3.Int = B.Bdy.EP}]</desc>
-  <a>
-    MULTIPOINT(160 150, 240 150, 340 240)
-  </a>
-  <b>
-    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
-  </test>
-</case>
-
+
+<case>
+<desc>P/L-2: a point and a line disjoint [dim(0){A.P.Int = B.L.Ext}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/L-3-1: a point touching the start point of a line  [dim(0){A.P.Int = B.L.Bdy.SP}]</desc>
+  <a>
+    POINT(90 80)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/L-3-2: a point touching the end point of a line [dim(0){A.P.Int = B.L.Bdy.EP}]</desc>
+  <a>
+    POINT(340 240)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/L-5-1: a point on the line at a non-vertex [dim(0){A.P.Int = B.L.Int.NV}]</desc>
+  <a>
+    POINT(230 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/L-5-2: a point on the line at a vertex [dim(0){A.P.Int = B.L.Int.V}]</desc>
+  <a>
+    POINT(160 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/LR-2-1: a point outside a LinearRing [dim(0){A.P.Int = B.LR.Ext}]</desc>
+  <a>
+    POINT(90 150)
+  </a>
+  <b>
+    LINESTRING(150 150, 20 20, 280 20, 150 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/LR-2-2: a point inside a LinearRing  [dim(0){A.P.Int = B.LR.Ext}]</desc>
+  <a>
+    POINT(150 80)
+  </a>
+  <b>
+    LINESTRING(150 150, 20 20, 280 20, 150 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/LR-5-1: a point on the closing point of a LinearRing [dim(0){A.P.Int = B.LR.Int.CP}]</desc>
+  <a>
+    POINT(150 150)
+  </a>
+  <b>
+    LINESTRING(150 150, 20 20, 280 20, 150 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/LR-5-2: a point on a LinearRing at a non-vertex [dim(0){A.P.Int = B.L.Int.NV}]</desc>
+  <a>
+    POINT(100 20)
+  </a>
+  <b>
+    LINESTRING(150 150, 20 20, 280 20, 150 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/LR-5-3: a point on a LinearRing at a vertex [dim(0){A.P.Int = B.L.Int.V}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    LINESTRING(150 150, 20 20, 280 20, 150 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.1-3-1: a point on a non-simple LineString's end point [dim(0){A.P.Int = B.nsL.Bdy.EP}]</desc>
+  <a>
+    POINT(220 220)
+  </a>
+  <b>
+    LINESTRING(110 110, 220 20, 20 20, 110 110, 220 220)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.1-5-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 220 20, 20 20, 110 110, 220 220)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.1-5-2: a point a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 220 20, 20 20, 220 220)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.1-5-3: a point on a non-simple LineString's interior at a non-vertex [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
+  <a>
+    POINT(110 20)
+  </a>
+  <b>
+    LINESTRING(110 110, 220 20, 20 20, 220 220)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.1-5-4: a point on a non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
+  <a>
+    POINT(220 20)
+  </a>
+  <b>
+    LINESTRING(110 110, 220 20, 20 20, 220 220)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.2-5-2: a point on a non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
+  <a>
+    POINT(110 20)
+  </a>
+  <b>
+    LINESTRING(220 220, 20 20, 220 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.2-5-3: a point on a non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    LINESTRING(220 220, 20 20, 220 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.2-5-4: a point on a non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(20 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 20 20, 110 20, 20 110, 110 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-3-1: a point on a non-simple LineString's start point [dim(0){A.P.Int = B.nsL.Bdy.SP}]</desc>
+  <a>
+    POINT(20 200)
+  </a>
+  <b>
+    LINESTRING(20 200, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-1: a point on a non-simple LineString's interior at a non-vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 200 20, 140 20, 140 80, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-2: a point on a non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-3: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
+  <a>
+    POINT(80 140)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 110, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-4: a point on a non-simple LineString's interior at a two-vertex point with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vo}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 110, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-5: a point on a non-simple LineString's interior at a vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vo}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-6: a point on a non-simple LineString's interior at a two-vertex point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 110, 200 20, 20 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-7: a point on a non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 200 20, 20 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-8: a point on a non-simple LineString's interior at a two-vertex point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 110, 20 20, 200 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-1: a point on a non-simple LineString's start point with crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 110 110, 200 20, 140 20, 140 80, 110 110, 80 140, 
+    20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-2: a point on a non-simple LineString's start point with crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-3:a point on a non-simple LineString's start point with crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 200 20, 140 20, 140 80, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-4: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-5: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 200 20, 20 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-6: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-7: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 110 110, 20 20, 200 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-8: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 200 20, 200 110, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.5-3-1: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 110 110, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.5-3-2: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.5-3-3: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.5-3-4: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 110 110, 200 20, 20 20, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.5-3-5: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 20 110, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.6-3-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 160)
+  </a>
+  <b>
+    LINESTRING(110 160, 200 250, 110 250, 110 160, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.6-3-2: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 160)
+  </a>
+  <b>
+    LINESTRING(110 160, 200 250, 110 250, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.6-3-3: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 160, 200 250, 110 250, 110 160, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.6-3-4: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 160, 200 250, 110 250, 110 160, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.7-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.7-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.7-5-3: a point on a closed non-simple LineString's interior at a non-vertex [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
+  <a>
+    POINT(140 200)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.7-5-4: a point on a closed non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.8-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 200 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.8-5-2: a point on the interior (at a non-vertex) of a closed non-simple LineString [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
+  <a>
+    POINT(140 200)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 200 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.8-5-3: a point on a closed non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 200 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.9-3-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 90 130, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.9-5-1: a point on a non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 90 130, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.10-3-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.10-5-1: a point on a non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.11-3-1: a point on a closed non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 90 130, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.11-5-1: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 90 130, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.12-3-1: a point on a closed non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.12-5-1: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.13-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 20 130, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 200 130, 
+    110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.13-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 20 130, 20 200, 200 20, 20 20, 200 200, 200 130, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.14-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 80 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 140 200, 
+    110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.14-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 80 200, 20 200, 200 20, 20 20, 200 200, 140 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.15-5-1: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.15-5-2: a point on a closed non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 110 110, 20 20, 200 20, 110 110, 20 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.15-5-3: a point on a closed non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 110 110, 200 20, 20 20, 110 110, 20 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.16-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 90 130, 110 110, 200 20, 20 20, 110 110, 200 200, 
+    90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.16-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.17-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 90 200, 20 200, 90 130, 110 110, 200 20, 20 20, 110 110, 200 200, 
+    90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.17-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 90 200, 20 200, 200 20, 20 20, 200 200, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.17-5-3: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 90 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.17-5-4: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 90 200, 20 200, 200 20, 20 20, 200 200, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.17-5-5: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(90 130, 90 200, 20 200, 200 20, 20 20, 200 200, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.18-5-1: a point on a non-simple LineString's start point with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb)}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.18-5-2: a point on a non-simple LineString's interior at a non-vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
+  <a>
+    POINT(110 150)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.18-5-3: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.19-5-1: a point on a non-simple LineString's closing point with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.CPo}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.19-5-2: a point on a non-simple LineString's interior at a non-vertex overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
+  <a>
+    POINT(110 150)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.19-5-3: a point on a non-simple LineString interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.20-5-1: a point on a non-simple LineString's interior at a non-vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
+  <a>
+    POINT(110 150)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.20-5-2: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsl.20-5-3: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-2-1: MultiPoint and a line disjoint (points on one side of the line) [dim(0){A.3P.Int = B.L.Ext}]</desc>
+  <a>
+    MULTIPOINT(50 250, 90 220, 130 190)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-2-2: MultiPoint and a line disjoint (points over the line but no intersection) [dim(0){A.3P.Int = B.L.Ext}]</desc>
+  <a>
+    MULTIPOINT(180 180, 230 130, 280 80)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-3-1: one of the points intersecting the start point of a line [dim(0){A.3P2.Int = B.L.Bdy.SP}]</desc>
+  <a>
+    MULTIPOINT(50 120, 90 80, 130 40)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-3-2: one of the points intersecting the end point of a line [dim(0){A.3P2 = B.L.Bdy.EP}]</desc>
+  <a>
+    MULTIPOINT(300 280, 340 240, 380 200)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-4-1: one of the points intersecting the interior of a line at a non-vertex (points on one side of the line) [dim(0){A.3P1.Int = B.L.Int.NV]</desc>
+  <a>
+    MULTIPOINT(230 150, 260 120, 290 90)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-4-2: one of the points intersecting the interior of a line at a non-vertex (points over the line) [dim(0){A.3P2.Int = B.L.Int.NV]</desc>
+  <a>
+    MULTIPOINT(200 190, 240 150, 270 110)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-4-3: one of the points intersecting the interior of a line at a vertex (points on one side of the line) [dim(0){A.3P1.Int = B.L.Int.V]</desc>
+  <a>
+    MULTIPOINT(160 150, 190 120, 220 90)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-4-4: one of the points intersecting the interior of a line at a vertex (points over the line) [dim(0){A.3P2.Int = B.L.Int.V]</desc>
+  <a>
+    MULTIPOINT(120 190, 160 150, 200 110)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-1: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Bdy.EP}]</desc>
+  <a>
+    MULTIPOINT(90 80, 160 150, 340 240)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-2: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.V}]</desc>
+  <a>
+    MULTIPOINT(90 80, 160 150, 300 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-3: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
+  <a>
+    MULTIPOINT(90 80, 160 150, 240 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-4: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.NV}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
+  <a>
+    MULTIPOINT(90 80, 130 120, 210 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-5: all the points on a line [dim(0){A.3P1.Int = B.L.Int.NV}, dim(0){A.3P2.Int = B.L.Int.NV}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
+  <a>
+    MULTIPOINT(130 120, 210 150, 340 200)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-6: all the points on a line [dim(0){A.3P1.Int = B.L.Int.V}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
+  <a>
+    MULTIPOINT(160 150, 240 150, 340 210)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-7: all the points on a line [dim(0){A.3P1.Int = B.L.Int.V}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.V}]</desc>
+  <a>
+    MULTIPOINT(160 150, 300 150, 340 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-8: all the points on a line [dim(0){A.3P1.Int = B.L.Int.V}, dim(0){A.3P2.Int = B.L.Int.NV}, dim(0){A.3P3.Int = B.Bdy.EP}]</desc>
+  <a>
+    MULTIPOINT(160 150, 240 150, 340 240)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
+  </test>
+</case>
+
 </run>
\ No newline at end of file
diff --git a/test/validate/TestRelatePP.xml b/test/validate/TestRelatePP.xml
index 47360d2..67b14e9 100644
--- a/test/validate/TestRelatePP.xml
+++ b/test/validate/TestRelatePP.xml
@@ -1,173 +1,173 @@
 <run>
 <precisionModel type="FLOATING"/>
-
-<case>
-<desc>P/P: same point [dim(0){A.P.Int = B.P.Int}]</desc>
-  <a>
-    POINT(20 20)
-  </a>
-  <b>
-    POINT(20 20)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/P: different point [dim(0){A.P.Int = B.P.Ext}]</desc>
-  <a>
-    POINT(20 20)
-  </a>
-  <b>
-    POINT(40 60)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF0F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/mP: different points [dim(0){A.P.Int = B.3P.Ext}]</desc>
-  <a>
-    POINT(40 40)
-  </a>
-  <b>
-    MULTIPOINT(20 20, 80 80, 20 120)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF0F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>P/mP: point A within one of B points [dim(0){A.P.Int = B.3P1.Int}]</desc>
-  <a>
-    POINT(20 20)
-  </a>
-  <b>
-    MULTIPOINT(20 20, 80 80, 20 120)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF0F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/mP-1-1: same points [dim(0){A.3P1.Int = B.3P1.Int}, dim(0){A.3P2.Int = B.3P2.Int}, dim(0){A.3P3.Int = B.3P3.Int}]</desc>
-  <a>
-    MULTIPOINT(40 40, 80 60, 120 100)
-  </a>
-  <b>
-    MULTIPOINT(40 40, 80 60, 120 100)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/mP-1-2: same but different sequence of points [dim(0){A.3P1.Int = B.3P1.Int}, dim(0){A.3P1.Int = B.3P3.Int}, dim(0){A.3P3.Int = B.3P2.Int}]</desc>
-  <a>
-    MULTIPOINT(40 40, 80 60, 120 100)
-  </a>
-  <b>
-    MULTIPOINT(40 40, 120 100, 80 60)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/mP-2: different points [dim(0){A.4P.Int = B.4P.Ext}]</desc>
-  <a>
-    MULTIPOINT(40 40, 60 100, 100 60, 120 120)
-  </a>
-  <b>
-    MULTIPOINT(20 120, 60 60, 100 100, 140 40)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF0F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/mP-5-1: same points [dim(0){A.4P.Int = B.4P.Int}]</desc>
-  <a>
-    MULTIPOINT(20 20, 80 70, 140 120, 200 170)
-  </a>
-  <b>
-    MULTIPOINT(20 20, 80 70, 140 120, 200 170)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/mP-5-2: same points but different sequence [dim(0){A.4P.Int = B.4P.Int}]</desc>
-  <a>
-    MULTIPOINT(20 20, 140 120, 80 70, 200 170)
-  </a>
-  <b>
-    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/mP-5-3: some points same [dim(0){A.4P2.Int = B.2P1.Int}, dim(0){A.4P3.Int = B.2P2.Int}]</desc>
-  <a>
-    MULTIPOINT(20 20, 80 70, 140 120, 200 170)
-  </a>
-  <b>
-    MULTIPOINT(80 70, 140 120)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F0FFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/mP-5-4: some points same, in a different sequence [dim(0){A.4P1.Int = B.2P2.Int}, dim(0){A.4P4.Int = B.2P1.Int}]</desc>
-  <a>
-    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
-  </a>
-  <b>
-    MULTIPOINT(140 120, 80 70)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F0FFFFF2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/mP-6-1: some points same, some different [dim(0){A.4P4.Int = B.3P2.Int}]</desc>
-  <a>
-    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
-  </a>
-  <b>
-    MULTIPOINT(80 170, 140 120, 200 80)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF0F2">true</op>
-  </test>
-</case>
-
-<case>
-<desc>mP/mP-6-2: dim(0){A.4P1.Int = B.4P4.Int}, dim(0){A.4P4.Int = B.4P2.Int}</desc>
-  <a>
-    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
-  </a>
-  <b>
-    MULTIPOINT(80 170, 140 120, 200 80, 80 70)
-  </b>
-  <test>
-    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF0F2">true</op>
-  </test>
-</case>
-
+
+<case>
+<desc>P/P: same point [dim(0){A.P.Int = B.P.Int}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    POINT(20 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/P: different point [dim(0){A.P.Int = B.P.Ext}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    POINT(40 60)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF0F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mP: different points [dim(0){A.P.Int = B.3P.Ext}]</desc>
+  <a>
+    POINT(40 40)
+  </a>
+  <b>
+    MULTIPOINT(20 20, 80 80, 20 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF0F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mP: point A within one of B points [dim(0){A.P.Int = B.3P1.Int}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    MULTIPOINT(20 20, 80 80, 20 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF0F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-1-1: same points [dim(0){A.3P1.Int = B.3P1.Int}, dim(0){A.3P2.Int = B.3P2.Int}, dim(0){A.3P3.Int = B.3P3.Int}]</desc>
+  <a>
+    MULTIPOINT(40 40, 80 60, 120 100)
+  </a>
+  <b>
+    MULTIPOINT(40 40, 80 60, 120 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-1-2: same but different sequence of points [dim(0){A.3P1.Int = B.3P1.Int}, dim(0){A.3P1.Int = B.3P3.Int}, dim(0){A.3P3.Int = B.3P2.Int}]</desc>
+  <a>
+    MULTIPOINT(40 40, 80 60, 120 100)
+  </a>
+  <b>
+    MULTIPOINT(40 40, 120 100, 80 60)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-2: different points [dim(0){A.4P.Int = B.4P.Ext}]</desc>
+  <a>
+    MULTIPOINT(40 40, 60 100, 100 60, 120 120)
+  </a>
+  <b>
+    MULTIPOINT(20 120, 60 60, 100 100, 140 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF0F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-5-1: same points [dim(0){A.4P.Int = B.4P.Int}]</desc>
+  <a>
+    MULTIPOINT(20 20, 80 70, 140 120, 200 170)
+  </a>
+  <b>
+    MULTIPOINT(20 20, 80 70, 140 120, 200 170)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-5-2: same points but different sequence [dim(0){A.4P.Int = B.4P.Int}]</desc>
+  <a>
+    MULTIPOINT(20 20, 140 120, 80 70, 200 170)
+  </a>
+  <b>
+    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-5-3: some points same [dim(0){A.4P2.Int = B.2P1.Int}, dim(0){A.4P3.Int = B.2P2.Int}]</desc>
+  <a>
+    MULTIPOINT(20 20, 80 70, 140 120, 200 170)
+  </a>
+  <b>
+    MULTIPOINT(80 70, 140 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-5-4: some points same, in a different sequence [dim(0){A.4P1.Int = B.2P2.Int}, dim(0){A.4P4.Int = B.2P1.Int}]</desc>
+  <a>
+    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
+  </a>
+  <b>
+    MULTIPOINT(140 120, 80 70)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-6-1: some points same, some different [dim(0){A.4P4.Int = B.3P2.Int}]</desc>
+  <a>
+    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
+  </a>
+  <b>
+    MULTIPOINT(80 170, 140 120, 200 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF0F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-6-2: dim(0){A.4P1.Int = B.4P4.Int}, dim(0){A.4P4.Int = B.4P2.Int}</desc>
+  <a>
+    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
+  </a>
+  <b>
+    MULTIPOINT(80 170, 140 120, 200 80, 80 70)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF0F2">true</op>
+  </test>
+</case>
+
 </run>
\ No newline at end of file
diff --git a/test/vivid/TestBoundary.xml b/test/vivid/TestBoundary.xml
index f1071f0..a291c5f 100644
--- a/test/vivid/TestBoundary.xml
+++ b/test/vivid/TestBoundary.xml
@@ -141,8 +141,7 @@
   </a>
 <test>
   <op name="getboundary" arg1="A">
-    MULTILINESTRING(
-      (40 60, 420 60, 420 320, 40 320, 40 60))
+    LINESTRING(40 60, 420 60, 420 320, 40 320, 40 60)
   </op>
 </test>
 </case>
diff --git a/test/vivid/TestCentroid.xml b/test/vivid/TestCentroid.xml
index 2a25a94..d5f740d 100644
--- a/test/vivid/TestCentroid.xml
+++ b/test/vivid/TestCentroid.xml
@@ -84,7 +84,7 @@
   <a>    POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0), 
   (60 180, 20 180, 20 140, 60 140, 60 180))
 	 </a>
-<test><op name="getCentroid" arg1="A" >    POINT (102 98)   </op></test>
+<test><op name="getCentroid" arg1="A" >    POINT (103 98)   </op></test>
 </case>
 
 <case>
@@ -109,7 +109,7 @@
   <a>    GEOMETRYCOLLECTION (POLYGON ((0 200, 20 180, 20 140, 60 140, 200 0, 0 0, 0 200)), 
   POLYGON ((200 200, 0 200, 20 180, 60 180, 60 140, 200 0, 200 200))) 
 	</a>
-<test><op name="getCentroid" arg1="A" >    POINT (102 98)   </op></test>
+<test><op name="getCentroid" arg1="A" >    POINT (103 98)   </op></test>
 </case>
 
 <case>
diff --git a/test/vivid/TestFunctionAA.xml b/test/vivid/TestFunctionAA.xml
index cf66868..4ea6cb2 100644
--- a/test/vivid/TestFunctionAA.xml
+++ b/test/vivid/TestFunctionAA.xml
@@ -335,6 +335,41 @@
 </case>
 
 <case>
+  <desc>AA - simple polygons with hole touching shell</desc>
+  <a>
+    POLYGON ((20 0, 20 160, 200 160, 200 0, 20 0))
+  </a>
+  <b>
+    POLYGON ((220 80, 0 80, 0 240, 220 240, 220 80), 
+  	(100 80, 120 120, 80 120, 100 80))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POLYGON ((20 80, 20 160, 200 160, 200 80, 100 80, 20 80), 
+  (100 80, 120 120, 80 120, 100 80))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON ((20 0, 20 80, 0 80, 0 240, 220 240, 220 80, 200 80, 200 0, 20 0))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTIPOLYGON (((20 0, 20 80, 100 80, 200 80, 200 0, 20 0)), 
+  ((100 80, 80 120, 120 120, 100 80)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON (((20 0, 20 80, 100 80, 200 80, 200 0, 20 0)), 
+  ((200 80, 200 160, 20 160, 20 80, 0 80, 0 240, 220 240, 220 80, 200 80)), 
+  ((100 80, 80 120, 120 120, 100 80)))
+  </op>
+</test>
+</case>
+
+<case>
   <desc>mAmA - complex polygons touching and overlapping</desc>
   <a>
     MULTIPOLYGON(
@@ -554,8 +589,7 @@
   </b>
 <test>
   <op name="getboundary" arg1="A">
-    MULTILINESTRING(
-      (60 160, 140 160, 140 60, 60 60, 60 160))
+    LINESTRING(60 160, 140 160, 140 60, 60 60, 60 160)
   </op>
 </test>
 <test>
diff --git a/test/vivid/TestFunctionAAPrec.xml b/test/vivid/TestFunctionAAPrec.xml
index c42e94a..841a7a9 100644
--- a/test/vivid/TestFunctionAAPrec.xml
+++ b/test/vivid/TestFunctionAAPrec.xml
@@ -781,8 +781,7 @@ GEOMETRYCOLLECTION(
   </b>
 <test>
   <op name="getboundary" arg1="A">
-    MULTILINESTRING(
-      (83 33, 62 402, 68 402, 83 33))
+    LINESTRING(83 33, 62 402, 68 402, 83 33)
   </op>
 </test>
 <test>
diff --git a/test/vivid/TestFunctionLAPrec.xml b/test/vivid/TestFunctionLAPrec.xml
index 04d8617..72e8426 100644
--- a/test/vivid/TestFunctionLAPrec.xml
+++ b/test/vivid/TestFunctionLAPrec.xml
@@ -12,8 +12,7 @@
   </b>
 <test>
   <op name="getboundary" arg1="A">
-    MULTILINESTRING(
-      (95 9, 81 414, 87 414, 95 9))
+    LINESTRING(95 9, 81 414, 87 414, 95 9)
   </op>
 </test>
 <test>
diff --git a/test/vivid/TestFunctionLLPrec.xml b/test/vivid/TestFunctionLLPrec.xml
index f13a0fe..4796658 100644
--- a/test/vivid/TestFunctionLLPrec.xml
+++ b/test/vivid/TestFunctionLLPrec.xml
@@ -1,6 +1,6 @@
 <run>
   <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
-
+
 <case>
   <desc>LL - narrow V</desc>
   <a>
@@ -16,13 +16,13 @@
 </test>
 <test>
   <op name="union" arg1="A" arg2="B">
-    MULTILINESTRING(
-      (0 10, 400 10), 
-      (400 10, 620 10, 400 10), 
-      (400 10, 0 11), 
+    MULTILINESTRING(
+      (0 10, 400 10), 
+      (400 10, 620 10, 400 10), 
+      (400 10, 0 11), 
       (400 60, 400 10))
   </op>
 </test>
 </case>
-
+
 </run>
\ No newline at end of file
diff --git a/test/vivid/TestRectanglePredicate.xml b/test/vivid/TestRectanglePredicate.xml
new file mode 100644
index 0000000..64282a0
--- /dev/null
+++ b/test/vivid/TestRectanglePredicate.xml
@@ -0,0 +1,101 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>A disjoint</desc>
+  <a>
+    POLYGON(
+      (0 0, 80 0, 80 80, 0 80, 0 0))
+  </a>
+  <b>
+    POLYGON(
+      (100 200, 100 140, 180 140, 180 200, 100 200))
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   false   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   false   </op> </test>
+</case>
+
+<case>
+  <desc>A contained in rectangle</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    POLYGON((10 10, 10 90, 90 90, 90 10, 10 10))
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   true   </op> </test>
+</case>
+
+<case>
+  <desc>A containing rectangle</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    POLYGON ((60 180, -100 120, -140 60, -40 20, -100 -80, 40 -20, 140 -100, 140 40, 260 160, 80 120, 60 180))
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   false   </op> </test>
+</case>
+
+<case>
+  <desc>mA containing rectangle</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+	MULTIPOLYGON (((-60 180, -60 -60, 40 -20, 140 -100, 180 120, -20 140, -60 180)), 
+  	((20 280, 0 180, 180 160, 200 280, 20 280)))
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   false   </op> </test>
+</case>
+
+<case>
+  <desc>L overlaps thru Y axis side</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    LINESTRING(10 10, 200 10)
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+</case>
+
+<case>
+  <desc>L overlaps thru X axis side</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    LINESTRING(10 10, 10 2000)
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+</case>
+
+<case>
+  <desc>L line intersection</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    LINESTRING( 10 10, -10 -20 )
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+</case>
+
+<case>
+  <desc>mL with one component contained</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    MULTILINESTRING( (10 10, 10 20), (200 10, 200 20) )
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   false   </op> </test>
+</case>
+
+
+</run>
diff --git a/test/vivid/TestValid.xml b/test/vivid/TestValid.xml
index e08c014..87447bf 100644
--- a/test/vivid/TestValid.xml
+++ b/test/vivid/TestValid.xml
@@ -94,7 +94,7 @@ LINESTRING (40 180, 120 120, 140 200, 140 200, 200 140, 240 200)
    </case>
 
    <case>
-      <desc>A - polygon with repeatd point </desc>
+      <desc>A - polygon with repeated point </desc>
       <a>POLYGON ((107 246, 107 246, 250 285, 294 137, 151 90, 15 125, 157 174, 107 246))</a>
       <test>
          <op name="isValid" arg1="A"> true </op>
@@ -102,6 +102,15 @@ LINESTRING (40 180, 120 120, 140 200, 140 200, 200 140, 240 200)
    </case>
 
    <case>
+      <desc>A - polygon with degenerate hole ring (A-B-A) </desc>
+      <a>POLYGON ((0 0, 0 240, 260 240, 260 0, 0 0), 
+  (220 200, 40 200, 40 20, 40 200, 220 200, 220 200))</a>
+      <test>
+         <op name="isValid" arg1="A"> false </op>
+      </test>
+   </case>
+
+   <case>
       <desc>mA - multipolygon with component with too few points </desc>
       <a>MULTIPOLYGON ( ((100 20, 180 20, 180 100, 100 100, 100 20)),
 ((20 100, 100 100, 100 180, 20 180, 20 100)),

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/jts.git



More information about the Pkg-grass-devel mailing list