[jts] 11/23: Imported Upstream version 1.12+ds

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Wed Aug 5 14:12:56 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 ba5380ee9cc4f40930a1724419b6a73ce3834d22
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Tue Aug 4 23:50:08 2015 +0200

    Imported Upstream version 1.12+ds
---
 bin/testbuilder.sh                                 |   20 +
 bin/testrunner.sh                                  |   20 +
 doc/JTS Version History.html                       |  126 +-
 jtsio/doc/javadoc/allclasses-frame.html            |   34 -
 jtsio/doc/javadoc/allclasses-noframe.html          |   34 -
 .../vividsolutions/jts/io/oracle/OraReader.html    |  378 ------
 .../vividsolutions/jts/io/oracle/OraWriter.html    |  353 ------
 .../jts/io/oracle/package-frame.html               |   34 -
 .../jts/io/oracle/package-summary.html             |  165 ---
 .../vividsolutions/jts/io/oracle/package-tree.html |  143 ---
 .../com/vividsolutions/jts/io/sde/SdeReader.html   |  346 ------
 .../vividsolutions/jts/io/sde/package-frame.html   |   32 -
 .../vividsolutions/jts/io/sde/package-summary.html |  161 ---
 .../vividsolutions/jts/io/sde/package-tree.html    |  143 ---
 jtsio/doc/javadoc/constant-values.html             |  164 ---
 jtsio/doc/javadoc/deprecated-list.html             |  132 --
 jtsio/doc/javadoc/help-doc.html                    |  187 ---
 jtsio/doc/javadoc/index-all.html                   |  212 ----
 jtsio/doc/javadoc/index.html                       |   26 -
 jtsio/doc/javadoc/overview-frame.html              |   44 -
 jtsio/doc/javadoc/overview-summary.html            |  146 ---
 jtsio/doc/javadoc/overview-tree.html               |  142 ---
 jtsio/doc/javadoc/package-list                     |    2 -
 jtsio/doc/javadoc/packages.html                    |   31 -
 jtsio/doc/javadoc/resources/inherit.gif            |  Bin 57 -> 0 bytes
 jtsio/doc/javadoc/stylesheet.css                   |   29 -
 src/com/vividsolutions/jts/JTSVersion.java         |    4 +-
 .../jts/algorithm/BoundaryNodeRule.java            |    2 +
 .../vividsolutions/jts/algorithm/CGAlgorithms.java |   54 +-
 .../vividsolutions/jts/algorithm/ConvexHull.java   |   31 +-
 .../jts/algorithm/LineIntersector.java             |   16 +-
 .../jts/algorithm/MCPointInRing.java               |    2 +-
 .../jts/algorithm/NonRobustLineIntersector.java    |    2 +-
 .../vividsolutions/jts/algorithm/PointInRing.java  |    2 +-
 .../jts/algorithm/RayCrossingCounter.java          |    1 +
 .../jts/algorithm/RobustDeterminant.java           |   38 +-
 .../jts/algorithm/RobustLineIntersector.java       |    2 +-
 .../vividsolutions/jts/algorithm/VectorMath.java   |   86 --
 .../jts/awt/GeometryCollectionShape.java           |    2 +-
 .../vividsolutions/jts/awt/PointShapeFactory.java  |  368 +++++-
 src/com/vividsolutions/jts/awt/PolygonShape.java   |  110 +-
 src/com/vividsolutions/jts/awt/ShapeWriter.java    |   74 +-
 .../jts/awt/SqarePointShapeFactory.java            |   93 --
 src/com/vividsolutions/jts/densify/Densifier.java  |    7 +-
 src/com/vividsolutions/jts/geom/Coordinate.java    |    2 +-
 .../vividsolutions/jts/geom/CoordinateArrays.java  |   24 +-
 .../jts/geom/CoordinateSequence.java               |   31 +-
 .../jts/geom/CoordinateSequences.java              |   61 +
 src/com/vividsolutions/jts/geom/Envelope.java      |   58 +-
 src/com/vividsolutions/jts/geom/Geometry.java      |  407 ++++--
 .../jts/geom/GeometryCollection.java               |    4 +-
 .../jts/geom/GeometryCollectionIterator.java       |   41 +-
 .../jts/geom/GeometryComponentFilter.java          |    4 +-
 .../vividsolutions/jts/geom/GeometryFactory.java   |   15 +-
 src/com/vividsolutions/jts/geom/LineSegment.java   |   43 +-
 src/com/vividsolutions/jts/geom/Lineal.java        |    2 +-
 src/com/vividsolutions/jts/geom/LinearRing.java    |   17 +-
 .../vividsolutions/jts/geom/MultiLineString.java   |    4 +-
 src/com/vividsolutions/jts/geom/MultiPoint.java    |    4 +-
 src/com/vividsolutions/jts/geom/MultiPolygon.java  |    9 +-
 src/com/vividsolutions/jts/geom/Point.java         |   21 +-
 .../vividsolutions/jts/geom/PrecisionModel.java    |   26 +-
 src/com/vividsolutions/jts/geom/Puntal.java        |    2 +-
 src/com/vividsolutions/jts/geom/Triangle.java      |   74 +-
 .../jts/geom/impl/CoordinateArraySequence.java     |    1 +
 .../jts/geom/impl/PackedCoordinateSequence.java    |    1 +
 .../geom/prep/AbstractPreparedPolygonContains.java |    2 +-
 .../jts/geom/prep/BasicPreparedGeometry.java       |    2 +-
 .../geom/prep/PreparedLineStringIntersects.java    |    2 +-
 .../jts/geom/prep/PreparedPolygon.java             |    4 +
 .../jts/geom/prep/PreparedPolygonContains.java     |    2 +-
 .../geom/prep/PreparedPolygonContainsProperly.java |    2 +-
 .../jts/geom/prep/PreparedPolygonCovers.java       |    2 +-
 .../jts/geom/prep/PreparedPolygonIntersects.java   |    2 +-
 .../jts/geom/prep/PreparedPolygonPredicate.java    |    2 +-
 .../jts/geom/util/AffineTransformation.java        |   51 +-
 .../jts/geom/util/AffineTransformationBuilder.java |    1 +
 .../geom/util/ComponentCoordinateExtracter.java    |    2 +-
 .../jts/geom/util/GeometryCollectionMapper.java    |    8 +
 .../jts/geom/util/GeometryEditor.java              |   25 +-
 .../jts/geom/util/GeometryMapper.java              |   99 ++
 .../jts/geom/util/GeometryTransformer.java         |    4 +-
 .../jts/geom/util/LineStringExtracter.java         |    1 -
 .../jts/geom/util/LinearComponentExtracter.java    |   29 +-
 .../jts/geom/util/SineStarFactory.java             |    2 +-
 .../vividsolutions/jts/geomgraph/EdgeEndStar.java  |    3 +-
 .../jts/geomgraph/GeometryGraph.java               |   15 +-
 .../jts/geomgraph/index/MonotoneChainIndexer.java  |    6 +-
 .../jts/index/chain/MonotoneChain.java             |   27 +-
 .../jts/index/chain/MonotoneChainSelectAction.java |    5 +-
 .../intervalrtree/SortedPackedIntervalRTree.java   |    2 +-
 .../vividsolutions/jts/index/kdtree/KdTree.java    |    2 +-
 .../jts/index/quadtree/NodeBase.java               |    2 +-
 .../jts/index/strtree/AbstractNode.java            |    4 +-
 .../jts/index/strtree/BoundablePair.java           |  232 ++++
 .../jts/index/strtree/GeometryItemDistance.java    |   31 +
 .../jts/index/strtree/ItemDistance.java            |   25 +
 .../vividsolutions/jts/index/strtree/STRtree.java  |  122 ++
 .../vividsolutions/jts/io/ByteArrayInStream.java   |   17 +-
 src/com/vividsolutions/jts/io/WKBReader.java       |   58 +-
 src/com/vividsolutions/jts/io/WKBWriter.java       |  191 ++-
 src/com/vividsolutions/jts/io/WKTReader.java       |    3 +-
 src/com/vividsolutions/jts/io/WKTWriter.java       |   12 +-
 src/com/vividsolutions/jts/io/gml2/GMLReader.java  |    4 +-
 .../jts/linearref/LinearIterator.java              |   21 +-
 src/com/vividsolutions/jts/math/DD.java            | 1301 ++++++++++++++++++++
 src/com/vividsolutions/jts/math/MathUtil.java      |   93 ++
 .../jts/{geom/util => math}/Matrix.java            |   36 +-
 src/com/vividsolutions/jts/math/Vector2D.java      |  345 ++++++
 .../jts/noding/FastNodingValidator.java            |   30 +-
 .../noding/FastSegmentSetIntersectionFinder.java   |    2 +-
 .../jts/noding/InteriorIntersectionFinder.java     |   19 +-
 .../jts/noding/IntersectionAdder.java              |    2 +-
 .../jts/noding/IntersectionFinderAdder.java        |    2 +-
 .../vividsolutions/jts/noding/IteratedNoder.java   |    9 +-
 .../vividsolutions/jts/noding/MCIndexNoder.java    |    4 +-
 .../noding/MCIndexSegmentSetMutualIntersector.java |    2 +-
 src/com/vividsolutions/jts/noding/Noder.java       |    2 +-
 .../jts/noding/SegmentIntersectionDetector.java    |    4 +-
 .../jts/noding/SegmentIntersector.java             |    2 +-
 .../noding/SimpleSegmentSetMutualIntersector.java  |    2 +-
 .../vividsolutions/jts/noding/SinglePassNoder.java |    2 +-
 .../jts/noding/snapround/GeometryNoder.java        |   27 +-
 .../jts/noding/snapround/HotPixel.java             |   34 +-
 .../jts/noding/snapround/MCIndexSnapRounder.java   |    8 +-
 .../jts/noding/snapround/SimpleSnapRounder.java    |   13 +-
 .../buffer/BufferInputLineSimplifier.java          |   11 +-
 .../jts/operation/buffer/BufferOp.java             |   11 +-
 .../jts/operation/buffer/BufferParameters.java     |   34 +-
 ...urveBuilder.java => OLDOffsetCurveBuilder.java} |  126 +-
 .../jts/operation/buffer/OffsetCurveBuilder.java   |  782 +++---------
 .../operation/buffer/OffsetCurveSetBuilder.java    |   44 +-
 .../operation/buffer/OffsetSegmentGenerator.java   |  676 ++++++++++
 ...rveVertexList.java => OffsetSegmentString.java} |   47 +-
 .../buffer/validate/BufferDistanceValidator.java   |   19 +-
 .../buffer/validate/BufferResultValidator.java     |   22 +
 .../jts/operation/distance/DistanceOp.java         |    4 +-
 .../jts/operation/distance/FacetSequence.java      |  157 +++
 .../distance/FacetSequenceTreeBuilder.java         |   73 ++
 .../jts/operation/distance/GeometryLocation.java   |    8 +-
 .../operation/distance/IndexedFacetDistance.java   |  155 +++
 .../jts/operation/linemerge/LineMergeGraph.java    |   11 +-
 .../jts/operation/linemerge/LineMerger.java        |   37 +-
 .../jts/operation/linemerge/LineSequencer.java     |   24 +-
 .../operation/overlay/snap/GeometrySnapper.java    |  109 +-
 .../operation/overlay/snap/LineStringSnapper.java  |   82 +-
 .../overlay/snap/SnapIfNeededOverlayOp.java        |   17 +-
 .../jts/operation/overlay/snap/SnapOverlayOp.java  |   14 +-
 .../jts/operation/polygonize/EdgeRing.java         |    2 +-
 .../polygonize/PolygonizeDirectedEdge.java         |    2 +-
 .../jts/operation/predicate/RectangleContains.java |   26 +-
 .../operation/predicate/RectangleIntersects.java   |   47 +-
 .../predicate/SegmentIntersectionTester.java       |   66 +-
 .../jts/operation/union/UnaryUnionOp.java          |   15 +-
 .../operation/valid/IndexedNestedRingTester.java   |   15 +-
 .../jts/operation/valid/IsValidOp.java             |   23 +-
 .../operation/valid/TopologyValidationError.java   |   12 +-
 .../jts/planargraph/DirectedEdgeStar.java          |   22 +-
 .../jts/planargraph/PlanarGraph.java               |    3 +-
 .../jts/precision/CommonBitsRemover.java           |   27 +-
 .../jts/precision/GeometryPrecisionReducer.java    |  225 ++++
 .../jts/precision/MinimumClearance.java            |  334 +++++
 .../PrecisionReducerCoordinateOperation.java       |   98 ++
 .../precision/SimpleGeometryPrecisionReducer.java  |   11 +-
 .../jts/precision/SimpleMinimumClearance.java      |  181 +++
 .../jts/precision/doc-files/minClearance.png       |  Bin 0 -> 6539 bytes
 src/com/vividsolutions/jts/precision/package.html  |    3 +-
 .../jts/shape/GeometricShapeBuilder.java           |   78 ++
 .../jts/shape/fractal/KochSnowflakeBuilder.java    |   87 ++
 .../jts/shape/fractal/SierpinskiCarpetBuilder.java |   80 ++
 .../jts/shape/random/RandomPointsBuilder.java      |   90 ++
 .../shape/random/RandomPointsInGridBuilder.java    |  116 ++
 .../jts/simplify/DouglasPeuckerLineSimplifier.java |    2 +-
 .../jts/simplify/LineSegmentIndex.java             |    2 +-
 .../jts/simplify/TaggedLineSegment.java            |    2 +-
 .../jts/simplify/TaggedLineString.java             |    2 +-
 .../jts/simplify/TaggedLineStringSimplifier.java   |    2 +-
 .../jts/simplify/TaggedLinesSimplifier.java        |    2 +-
 .../jts/simplify/TopologyPreservingSimplifier.java |   11 +-
 .../IncrementalDelaunayTriangulator.java           |    2 +-
 .../triangulate/quadedge/QuadEdgeSubdivision.java  |   34 +-
 .../jts/triangulate/quadedge/QuadEdgeTriangle.java |  534 ++++----
 .../triangulate/quadedge/TrianglePredicate.java    |  302 +++++
 .../jts/triangulate/quadedge/Vertex.java           |  238 +---
 .../jts/util/GeometricShapeFactory.java            |  116 +-
 .../geom/ExtendedCoordinateSequence.java           |   18 +-
 .../geom/prep/PreparedGeometryExample.java         |    4 +-
 .../jtsexample/io/gml2/KMLReaderExample.java       |    5 +-
 .../technique/PolygonUnionUsingBuffer.java         |    3 +-
 .../SearchUsingPreparedGeometryIndex.java          |  244 ++++
 testxml/external/geos-bug356-buffer.xml            |   25 +
 testxml/failure/TestBufferFailure.xml              |   47 +
 testxml/failure/TestOverlay.xml                    |   86 ++
 testxml/failure/bug368jts.xml                      |   33 +
 testxml/failure/geos-bug368-union.xml              |   31 +
 testxml/general/TestBuffer.xml                     |   16 +
 testxml/general/TestEqualsExact.xml                |  157 +++
 testxml/general/TestMinimumClearance.xml           |   89 ++
 testxml/general/TestRectanglePredicate.xml         |   18 +
 testxml/general/TestValid.xml                      |   46 +
 testxml/robust/MagnifyTopology.xml                 |   86 ++
 201 files changed, 9107 insertions(+), 4888 deletions(-)

diff --git a/bin/testbuilder.sh b/bin/testbuilder.sh
new file mode 100644
index 0000000..eba464f
--- /dev/null
+++ b/bin/testbuilder.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+if test "x$JTS_LIB_DIR" = "x"; then
+        JTS_LIB_DIR=`dirname $0`/../lib/
+fi
+
+#---------------------------------#
+# dynamically build the classpath #
+#---------------------------------#
+THE_CLASSPATH=
+for i in `ls ${JTS_LIB_DIR}/*.jar`
+do
+  THE_CLASSPATH=${THE_CLASSPATH}:${i}
+done
+
+#---------------------------#
+# run the program           #
+#---------------------------#
+java -cp ".:${THE_CLASSPATH}" \
+com.vividsolutions.jtstest.testbuilder.JTSTestBuilder
diff --git a/bin/testrunner.sh b/bin/testrunner.sh
new file mode 100644
index 0000000..ca2dafd
--- /dev/null
+++ b/bin/testrunner.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+if test "x$JTS_LIB_DIR" = "x"; then
+	JTS_LIB_DIR=`dirname $0`/../lib/
+fi
+
+#---------------------------------#
+# dynamically build the classpath #
+#---------------------------------#
+THE_CLASSPATH=
+for i in `ls ${JTS_LIB_DIR}/*.jar`
+do
+  THE_CLASSPATH=${THE_CLASSPATH}:${i}
+done
+
+#---------------------------#
+# run the program           #
+#---------------------------#
+java -cp ".:${THE_CLASSPATH}" \
+com.vividsolutions.jtstest.testrunner.TopologyTestApp $@
diff --git a/doc/JTS Version History.html b/doc/JTS Version History.html
index 710898b..50e1451 100644
--- a/doc/JTS Version History.html	
+++ b/doc/JTS Version History.html	
@@ -4,16 +4,131 @@
 <title>JTS Version History</title>
 </head>
 
-<body bgcolor='lightblue'>
-<h1 style='text-align:center;'>
+<body bgcolor='#DFF0FF'>
+<h1 style='text-align:center; color:darkblue;'>
 JTS TOPOLOGY SUITE
 <br>
 <i>Version History</i>
 </h1>
 
 
-This document lists the change history of release versions of the JTS Topology Suite
+This document lists the change history of release versions of the
+<span style='color:darkblue;'><b>JTS Topology Suite</b></span>.
 <p>
+Further information on JTS can be found at <b>Tsusiat Software's
+<a href='http://tsusiatsoftware.net/jts/main.html'>JTS pages</a></b>.
+<p>
+The current and archived JTS distributions can be obtained at the
+<a href='http://sourceforge.net/projects/jts-topo-suite/'><b>SourceForge JTS site</b></a>.
+
+<!-- ================================================================ -->
+<hr size='4' color='darkblue'>
+<h2>Version 1.12</h2>
+
+<i>Release Date:  June 30, 2011</i>
+
+<h3>Functionality Improvements</h3>
+<ul>
+<li>Added new names for methods for computing <tt>Geometry</tt> equality:
+<ul>
+<li><tt>equals(Object)</tt> is a synonym for <tt>equalsExact(Geometry)</tt>
+<li><tt>equalsNorm(Geometry)</tt> automatically normalizes the operands
+<li><tt>equalsTopo(Geometry)</tt> computes topological equality,
+and is a synonym for the original <tt>equals(Geometry)</tt>
+</ul>
+<li>Added <tt>Geometry.norm()</tt> to provide non-mutating normalization
+<li>Added <tt>Geometry.hashCode()</tt> to fulfill Java conventions
+<li>Added <tt>LineIntersector.getEndpoint()</tt> method
+<li>Added methods to <tt>CoordinateSequences</tt> to test for and create valid rings
+<li>Added <tt>minExtent</tt> and <tt>maxExtent</tt> to <tt>Envelope</tt>
+<li>Added ability to compute Single-Sided Buffers (invoked via <tt>BufferOp</tt> and <tt>BufferParameters</tt>)
+<li>Added <tt>GeometryPrecisionReducer</tt>
+<li>Added ExtendedWKB SRID support to <tt>WKBWriter</tt> (thanks to Justin Deoliviera)
+<li>Improved <tt>PolygonShape</tt> to support floating-point coordinates
+<li>Added <tt>GeometryShapeFactory.setRotation(double radians)</tt> method
+<li>Added <tt>GeometricShapeBuilder</tt> API to support shape builder development
+<li>Added <tt>RandomPointsBuilder</tt> to allow generating various random point sets
+<li>Added <tt>RandomPointsInGridBuilder</tt> to allow generating various random point sets constrained to a grid
+<li>Added <tt>KochSnowflakeBuilder</tt>
+<li>Added <tt>SierpinskiCarpetBuilder</tt>
+<li>Added <tt>MathUtil</tt> containing mathematics and numerical utility functions
+<li>Added <tt>Vector2D</tt> class providing vector operations
+<li>Added <tt>DirectedEdgeStar.getNextCWEdge()</tt> method to <tt>planargraph</tt> API
+<li><tt>AffineTransformation</tt> enhanced to avoid numeric precision issues in case of reflection in X=Y (coordinate flipping)
+<li>Added <tt>LineSequencer.sequence()</tt> static convenience method
+<li>Added error indicators to <tt>BufferDistanceValidator</tt> and <tt>BufferResultValidator</tt>
+<li>Added <tt>MinimumClearance</tt> class
+<li>Added <tt>nearestNeighbours</tt> methods to <tt>STRtree</tt>
+</ul>
+
+<h3>Performance Improvements</h3>
+<ul>
+<li>Improved memory performance of <tt>ShapeWriter</tt> conversions (by tuning coordinate and polygon conversion)
+<li>Improved performance of <tt>RectangleIntersects</tt> by refining <tt>SegmentIntersectionTester</tt>
+</ul>
+
+<h3>Robustness Improvements</h3>
+<ul>
+<li>Delaunay triangulation uses more robust formulation for the inCircle test
+<li>Voronoi computation now uses more robust formulation for the circumcentre computation
+<li>Force RectangleIntersects to always use segment-scanning to improve robustness
+</ul>
+
+<h3>API Changes</h3>
+<ul>
+<li>Reduced visibility of internal classes in <tt>com.vividsolutions.jts.geom.prep</tt>
+<li>Reduced visibility of internal classes in <tt>com.vividsolutions.jts.simplify</tt>
+<li>Moved <tt>Matrix</tt> class into <tt>jts.math</tt> package
+<li>Refactored internal offset curve generation classes
+in <tt>com.vividsolutions.jts.operation.buffer</tt> package
+</ul>
+
+<h3>Bug Fixes</h3>
+<ul>
+<li>Fixed <tt>CoordinateArraySequence</tt> and <tt>PackedCoordinateSequence</tt>
+to correctly handle Z ordinate in <tt>getCoordinate(int, Coordinate)</tt>
+<li>Fixed <tt>LinearRing</tt> to have <tt>isClosed()</tt> return <tt>true</tt> for empty rings
+<li>Fixed <tt>Geometry.union()</tt> to use more robust union algorithm.
+    This provides behaviour consistent with <tt>union(Geometry)</tt>.
+<li>Fixed <tt>Point.isValid()</tt> to validate POINT EMPTY correctly
+<li>Fixed <tt>SnapIfNeededOverlayOp</tt> to throw the originating exception,which contains meaningful coordinates
+<li>Fixed <tt>GeometrySnapper</tt> to allow final vertices of LineStrings to snap correctly
+<li>Fixed buffer (<tt>OffsetCurveSetBuilder</tt>) to handle "flat" rings correctly
+<li>Fixed <tt>IsValidOp</tt> to handle reporting "Not Closed" errors on empty rings correctly
+<li>Fixed <tt>NestedRingTester</tt> (used by <tt>IsValidOp</tt>)
+to correctly handle the case where a hole touches all the vertices of another hole (which is invalid)
+<li>Fixed <tt>ConvexHull</tt> to handle large geometries with fewer than 3 unique points
+<li>Fixed <tt>GeometryGraph</tt> to ignore empty hole rings when building graph
+<li>Fixed <tt>LineMerger</tt> to skip lines with only a single unique coordinate
+<li>Fixed <tt>ByteArrayInStream</tt> to pad byte buffers with zeroes
+<li>Corrected spelling of <tt>SquarePointShapeFactory</tt>
+<li>Fixed tolerance check in <tt>KdTree</tt>
+<li>Updated <tt>MasterTester</tt> to include more unit tests
+</ul>
+
+<!------- TestBuilder -------------------->
+<hr size='0' color='darkblue'>
+<h3 style='font-family:sans-serif; color:darkblue'>JTS TestBuilder</h3>
+
+<h3>Functionality Improvements</h3>
+<ul>
+<li>Added <tt>[Zoom To Result]</tt> button
+<li>Improved mark display, with floating point label
+<li>Added more random geometry creation functions
+<li>Added fractal geometry creation functions
+<li>Improved threaded rendering handling to ensure only one frame drawn
+<li>Added Magnify Topology capability
+<li>Added Geometry Inspector dialog
+<li>Better startup script, with auto-home directory detection
+and JTS_LIB_DIR environment variable (thanks to strk)
+<li>Added logging Info window behaviour
+</ul>
+
+<h3>Bug Fixes</h3>
+<ul>
+<li>Fixed Stats panel to update when current test changes
+<li>Fixed deleting single test case
+</ul>
 
 <!-- ================================================================ -->
 <hr size='4' color='darkblue'>
@@ -57,7 +172,7 @@ This document lists the change history of release versions of the JTS Topology S
 
 <h3>API Changes</h3>
 <ul>
-<li>Deprecated <tt>WKBWriter.bytesToHex</tt> in favour of <tt>WKBWriter.toHex</tt>to regularize and simplify method name
+<li>Deprecated <tt>WKBWriter.bytesToHex</tt> in favour of <tt>WKBWriter.toHex</tt> to regularize and simplify method name
 </ul>
 
 <h3>Bug Fixes</h3>
@@ -127,7 +242,7 @@ This document lists the change history of release versions of the JTS Topology S
 <li>Improved performance for <code>ByteArrayInStream</code> (by avoiding use of <tt>java.io.ByteArrayInputStream</tt>)
 <li>Unrolled intersection computation in <tt>HCoordinate</tt> to avoid object allocation
 <li>Improved performance for buffering via better offset curve generation and simplification.
-<li>Improved performance for <tt>IsValipOp</tt> by switching to use <tt>STRtree</tt> for nested hole checking
+<li>Improved performance for <tt>IsValidOp</tt> by switching to use <tt>STRtree</tt> for nested hole checking
 </ul>
 
 <h3>Bug Fixes</h3>
@@ -172,6 +287,7 @@ simplified using <tt>TopologyPreservingSimplifier</tt> to be invalid in certain
 <li>Added Stats panel
 <li>Added Scalar functions panel, with extensible function list
 <li>Added <b>Save as PNG...</b>
+<li>Added stream digitizing to Polygon and Line Draw tools
 </ul>
 
 <!------- TestRunner -------------------->
diff --git a/jtsio/doc/javadoc/allclasses-frame.html b/jtsio/doc/javadoc/allclasses-frame.html
deleted file mode 100644
index 001dd08..0000000
--- a/jtsio/doc/javadoc/allclasses-frame.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-All Classes
-</TITLE>
-
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
-
-
-</HEAD>
-
-<BODY BGCOLOR="white">
-<FONT size="+1" CLASS="FrameHeadingFont">
-<B>All Classes</B></FONT>
-<BR>
-
-<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
-<TR>
-<TD NOWRAP><FONT CLASS="FrameItemFont"><A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle" target="classFrame">OraReader</A>
-<BR>
-<A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle" target="classFrame">OraWriter</A>
-<BR>
-<A HREF="com/vividsolutions/jts/io/sde/SdeReader.html" title="class in com.vividsolutions.jts.io.sde" target="classFrame">SdeReader</A>
-<BR>
-</FONT></TD>
-</TR>
-</TABLE>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/allclasses-noframe.html b/jtsio/doc/javadoc/allclasses-noframe.html
deleted file mode 100644
index 8e2e54e..0000000
--- a/jtsio/doc/javadoc/allclasses-noframe.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-All Classes
-</TITLE>
-
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
-
-
-</HEAD>
-
-<BODY BGCOLOR="white">
-<FONT size="+1" CLASS="FrameHeadingFont">
-<B>All Classes</B></FONT>
-<BR>
-
-<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
-<TR>
-<TD NOWRAP><FONT CLASS="FrameItemFont"><A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle">OraReader</A>
-<BR>
-<A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle">OraWriter</A>
-<BR>
-<A HREF="com/vividsolutions/jts/io/sde/SdeReader.html" title="class in com.vividsolutions.jts.io.sde">SdeReader</A>
-<BR>
-</FONT></TD>
-</TR>
-</TABLE>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/OraReader.html b/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/OraReader.html
deleted file mode 100644
index 132d17d..0000000
--- a/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/OraReader.html
+++ /dev/null
@@ -1,378 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-OraReader
-</TITLE>
-
-<META NAME="keywords" CONTENT="com.vividsolutions.jts.io.oracle.OraReader class">
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="OraReader";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV CLASS 
- <A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle"><B>NEXT CLASS</B></A></FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="OraReader.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-<TR>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-  SUMMARY: NESTED | <A HREF="#field_summary">FIELD</A> | <A HREF="#constructor_summary">CONSTR</A> | <A HREF="#method_summary">METHOD</A></FONT></TD>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-DETAIL: <A HREF="#field_detail">FIELD</A> | <A HREF="#constructor_detail">CONSTR</A> | <A HREF="#method_detail">METHOD</A></FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-<!-- ======== START OF CLASS DATA ======== -->
-<H2>
-<FONT SIZE="-1">
-com.vividsolutions.jts.io.oracle</FONT>
-<BR>
-Class OraReader</H2>
-<PRE>
-java.lang.Object
-  <IMG SRC="../../../../../resources/inherit.gif" ALT="extended by"><B>com.vividsolutions.jts.io.oracle.OraReader</B>
-</PRE>
-<HR>
-<DL>
-<DT>public class <B>OraReader</B><DT>extends java.lang.Object</DL>
-
-<P>
-Reads a <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>Geometry</CODE></A> from an Oracle <tt>MDSYS.GEOMETRY</tt> object.
-
- A <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>GeometryFactory</CODE></A> may be provided, otherwise
- a default one will be used.
- The provided GeometryFactory will be used, with the exception of the SRID field.
- This will be extracted from the Geometry.
- <p>
- If a <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/PrecisionModel.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>PrecisionModel</CODE></A> is supplied it is the callers's responsibility
- to ensure that it matches the precision of the incoming data.
- If a lower precision for the data is required, a subsequent
- process must be run on the data to reduce its precision.
- <p>
- To use this class a suitable Oracle JDBC driver JAR must be present.
-<P>
-
-<P>
-<DL>
-<DT><B>Version:</B></DT>
-  <DD>9i</DD>
-<DT><B>Author:</B></DT>
-  <DD>David Zwiers, Vivid Solutions., Martin Davis</DD>
-</DL>
-<HR>
-
-<P>
-<!-- ======== NESTED CLASS SUMMARY ======== -->
-
-
-<!-- =========== FIELD SUMMARY =========== -->
-
-<A NAME="field_summary"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=2><FONT SIZE="+2">
-<B>Field Summary</B></FONT></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
-<CODE>static int</CODE></FONT></TD>
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraReader.html#NULL_DIMENSION">NULL_DIMENSION</A></B></CODE>
-
-<BR>
-           </TD>
-</TR>
-</TABLE>
- 
-<!-- ======== CONSTRUCTOR SUMMARY ======== -->
-
-<A NAME="constructor_summary"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=2><FONT SIZE="+2">
-<B>Constructor Summary</B></FONT></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraReader.html#OraReader()">OraReader</A></B>()</CODE>
-
-<BR>
-          Creates a new reader, with a default GeometryFactory.</TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraReader.html#OraReader(com.vividsolutions.jts.geom.GeometryFactory)">OraReader</A></B>(<A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom">GeometryFactory</A> gf)</CODE>
-
-<BR>
-          Creates a new reader, with the supplied <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>GeometryFactory</CODE></A>.</TD>
-</TR>
-</TABLE>
- 
-<!-- ========== METHOD SUMMARY =========== -->
-
-<A NAME="method_summary"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=2><FONT SIZE="+2">
-<B>Method Summary</B></FONT></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
-<CODE> int</CODE></FONT></TD>
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraReader.html#getDimension()">getDimension</A></B>()</CODE>
-
-<BR>
-          Gets the number of coordinate dimensions which will be read.</TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
-<CODE> <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom">Geometry</A></CODE></FONT></TD>
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraReader.html#read(oracle.sql.STRUCT)">read</A></B>(oracle.sql.STRUCT struct)</CODE>
-
-<BR>
-          This method will attempt to create a JTS Geometry for the MDSYS.GEOMETRY
- provided.</TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
-<CODE> void</CODE></FONT></TD>
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraReader.html#setDimension(int)">setDimension</A></B>(int dimension)</CODE>
-
-<BR>
-          Sets the number of coordinate dimensions to read.</TD>
-</TR>
-</TABLE>
- <A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
-<TD><B>Methods inherited from class java.lang.Object</B></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
-</TR>
-</TABLE>
- 
-<P>
-
-<!-- ============ FIELD DETAIL =========== -->
-
-<A NAME="field_detail"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=1><FONT SIZE="+2">
-<B>Field Detail</B></FONT></TD>
-</TR>
-</TABLE>
-
-<A NAME="NULL_DIMENSION"><!-- --></A><H3>
-NULL_DIMENSION</H3>
-<PRE>
-public static final int <B>NULL_DIMENSION</B></PRE>
-<DL>
-<DL>
-<DT><B>See Also:</B><DD><A HREF="../../../../../constant-values.html#com.vividsolutions.jts.io.oracle.OraReader.NULL_DIMENSION">Constant Field Values</A></DL>
-</DL>
-
-<!-- ========= CONSTRUCTOR DETAIL ======== -->
-
-<A NAME="constructor_detail"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=1><FONT SIZE="+2">
-<B>Constructor Detail</B></FONT></TD>
-</TR>
-</TABLE>
-
-<A NAME="OraReader()"><!-- --></A><H3>
-OraReader</H3>
-<PRE>
-public <B>OraReader</B>()</PRE>
-<DL>
-<DD>Creates a new reader, with a default GeometryFactory.
-<P>
-<DT><B>See Also:</B><DD><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraReader.html#OraReader(com.vividsolutions.jts.geom.GeometryFactory)"><CODE>OraReader(GeometryFactory)</CODE></A></DL>
-<HR>
-
-<A NAME="OraReader(com.vividsolutions.jts.geom.GeometryFactory)"><!-- --></A><H3>
-OraReader</H3>
-<PRE>
-public <B>OraReader</B>(<A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom">GeometryFactory</A> gf)</PRE>
-<DL>
-<DD>Creates a new reader, with the supplied <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>GeometryFactory</CODE></A>.
- It is assumed that the supplied <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/PrecisionModel.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>PrecisionModel</CODE></A>
- matches the precision of the incoming data -
- coordinates are <b>not</b> made precise.
-<P>
-<DT><B>Parameters:</B><DD><CODE>gf</CODE> - A non-null geometry factory for later use.
-<DT><B>Throws:</B>
-<DD><CODE>java.lang.NullPointerException</CODE> - when the geometry factory is null.</DL>
-
-<!-- ============ METHOD DETAIL ========== -->
-
-<A NAME="method_detail"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=1><FONT SIZE="+2">
-<B>Method Detail</B></FONT></TD>
-</TR>
-</TABLE>
-
-<A NAME="getDimension()"><!-- --></A><H3>
-getDimension</H3>
-<PRE>
-public int <B>getDimension</B>()</PRE>
-<DL>
-<DD>Gets the number of coordinate dimensions which will be read.
-<P>
-<DD><DL>
-
-<DT><B>Returns:</B><DD>the dimension which will be read</DL>
-</DD>
-</DL>
-<HR>
-
-<A NAME="setDimension(int)"><!-- --></A><H3>
-setDimension</H3>
-<PRE>
-public void <B>setDimension</B>(int dimension)</PRE>
-<DL>
-<DD>Sets the number of coordinate dimensions to read.
-<P>
-<DD><DL>
-<DT><B>Parameters:</B><DD><CODE>dimension</CODE> - the dimension to read</DL>
-</DD>
-</DL>
-<HR>
-
-<A NAME="read(oracle.sql.STRUCT)"><!-- --></A><H3>
-read</H3>
-<PRE>
-public <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom">Geometry</A> <B>read</B>(oracle.sql.STRUCT struct)
-              throws java.sql.SQLException</PRE>
-<DL>
-<DD>This method will attempt to create a JTS Geometry for the MDSYS.GEOMETRY
- provided. The Type of gemetry returned will depend on the input datum,
- where the Geometry type is specified within the STRUCT.
-<P>
-<DD><DL>
-<DT><B>Parameters:</B><DD><CODE>struct</CODE> - The MDSYS.GEOMETRY Object to decode
-<DT><B>Returns:</B><DD>A JTS Geometry if one could be created, null otherwise
-<DT><B>Throws:</B>
-<DD><CODE>java.sql.SQLException</CODE> - When a read error occured within the struct</DL>
-</DD>
-</DL>
-<!-- ========= END OF CLASS DATA ========= -->
-<HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV CLASS 
- <A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle"><B>NEXT CLASS</B></A></FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="OraReader.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-<TR>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-  SUMMARY: NESTED | <A HREF="#field_summary">FIELD</A> | <A HREF="#constructor_summary">CONSTR</A> | <A HREF="#method_summary">METHOD</A></FONT></TD>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-DETAIL: <A HREF="#field_detail">FIELD</A> | <A HREF="#constructor_detail">CONSTR</A> | <A HREF="#method_detail">METHOD</A></FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/OraWriter.html b/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/OraWriter.html
deleted file mode 100644
index 2a3e6cf..0000000
--- a/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/OraWriter.html
+++ /dev/null
@@ -1,353 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-OraWriter
-</TITLE>
-
-<META NAME="keywords" CONTENT="com.vividsolutions.jts.io.oracle.OraWriter class">
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="OraWriter";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- <A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle"><B>PREV CLASS</B></A> 
- NEXT CLASS</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="OraWriter.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-<TR>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-  SUMMARY: NESTED | FIELD | <A HREF="#constructor_summary">CONSTR</A> | <A HREF="#method_summary">METHOD</A></FONT></TD>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-DETAIL: FIELD | <A HREF="#constructor_detail">CONSTR</A> | <A HREF="#method_detail">METHOD</A></FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-<!-- ======== START OF CLASS DATA ======== -->
-<H2>
-<FONT SIZE="-1">
-com.vividsolutions.jts.io.oracle</FONT>
-<BR>
-Class OraWriter</H2>
-<PRE>
-java.lang.Object
-  <IMG SRC="../../../../../resources/inherit.gif" ALT="extended by"><B>com.vividsolutions.jts.io.oracle.OraWriter</B>
-</PRE>
-<HR>
-<DL>
-<DT>public class <B>OraWriter</B><DT>extends java.lang.Object</DL>
-
-<P>
-Translates a JTS Geometry into an Oracle STRUCT representing an MDSYS.GEOMETRY object. 
- 
- A connection to an oracle instance with access to the definition of the MDSYS.GEOMETRY 
- object is required by the oracle driver.
-<P>
-
-<P>
-<DL>
-<DT><B>Version:</B></DT>
-  <DD>9i</DD>
-<DT><B>Author:</B></DT>
-  <DD>David Zwiers, Vivid Solutions.</DD>
-</DL>
-<HR>
-
-<P>
-<!-- ======== NESTED CLASS SUMMARY ======== -->
-
-
-<!-- =========== FIELD SUMMARY =========== -->
-
-
-<!-- ======== CONSTRUCTOR SUMMARY ======== -->
-
-<A NAME="constructor_summary"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=2><FONT SIZE="+2">
-<B>Constructor Summary</B></FONT></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraWriter.html#OraWriter(oracle.jdbc.OracleConnection)">OraWriter</A></B>(oracle.jdbc.OracleConnection con)</CODE>
-
-<BR>
-          Initialize the Oracle MDSYS.GEOMETRY Encoder with a valid oracle connection.</TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraWriter.html#OraWriter(oracle.jdbc.OracleConnection, int)">OraWriter</A></B>(oracle.jdbc.OracleConnection con,
-          int dimension)</CODE>
-
-<BR>
-          Initialize the Oracle MDSYS.GEOMETRY Encoder with a valid oracle connection.</TD>
-</TR>
-</TABLE>
- 
-<!-- ========== METHOD SUMMARY =========== -->
-
-<A NAME="method_summary"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=2><FONT SIZE="+2">
-<B>Method Summary</B></FONT></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
-<CODE> void</CODE></FONT></TD>
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraWriter.html#setDimension(int)">setDimension</A></B>(int dimension)</CODE>
-
-<BR>
-           </TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
-<CODE> void</CODE></FONT></TD>
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraWriter.html#setSRID(int)">setSRID</A></B>(int srid)</CODE>
-
-<BR>
-          Provides the oppotunity to force all geometries written using this writter to be written using the 
- specified srid.</TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
-<CODE> oracle.sql.STRUCT</CODE></FONT></TD>
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraWriter.html#write(com.vividsolutions.jts.geom.Geometry)">write</A></B>(<A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom">Geometry</A> geom)</CODE>
-
-<BR>
-          This routine will translate the JTS Geometry into an Oracle MDSYS.GEOMETRY STRUCT.</TD>
-</TR>
-</TABLE>
- <A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
-<TD><B>Methods inherited from class java.lang.Object</B></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
-</TR>
-</TABLE>
- 
-<P>
-
-<!-- ============ FIELD DETAIL =========== -->
-
-
-<!-- ========= CONSTRUCTOR DETAIL ======== -->
-
-<A NAME="constructor_detail"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=1><FONT SIZE="+2">
-<B>Constructor Detail</B></FONT></TD>
-</TR>
-</TABLE>
-
-<A NAME="OraWriter(oracle.jdbc.OracleConnection)"><!-- --></A><H3>
-OraWriter</H3>
-<PRE>
-public <B>OraWriter</B>(oracle.jdbc.OracleConnection con)</PRE>
-<DL>
-<DD>Initialize the Oracle MDSYS.GEOMETRY Encoder with a valid oracle connection. 
- 
- The connection should have sufficient priveledges to view the description of the MDSYS.GEOMETRY type.
- 
- The dimension is set to 2
-<P>
-<DT><B>Parameters:</B><DD><CODE>con</CODE> - </DL>
-<HR>
-
-<A NAME="OraWriter(oracle.jdbc.OracleConnection, int)"><!-- --></A><H3>
-OraWriter</H3>
-<PRE>
-public <B>OraWriter</B>(oracle.jdbc.OracleConnection con,
-                 int dimension)</PRE>
-<DL>
-<DD>Initialize the Oracle MDSYS.GEOMETRY Encoder with a valid oracle connection. 
- 
- The connection should have sufficient priveledges to view the description of the MDSYS.GEOMETRY type.
-<P>
-<DT><B>Parameters:</B><DD><CODE>con</CODE> - <DD><CODE>dimension</CODE> - </DL>
-
-<!-- ============ METHOD DETAIL ========== -->
-
-<A NAME="method_detail"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=1><FONT SIZE="+2">
-<B>Method Detail</B></FONT></TD>
-</TR>
-</TABLE>
-
-<A NAME="setSRID(int)"><!-- --></A><H3>
-setSRID</H3>
-<PRE>
-public void <B>setSRID</B>(int srid)</PRE>
-<DL>
-<DD>Provides the oppotunity to force all geometries written using this writter to be written using the 
- specified srid. This is useful in two cases: 1) when you do not want the geometry's srid to be 
- over-written or 2) when you want to ensure an entire layer is always written using a constant srid.
-<P>
-<DD><DL>
-<DT><B>Parameters:</B><DD><CODE>srid</CODE> - </DL>
-</DD>
-</DL>
-<HR>
-
-<A NAME="write(com.vividsolutions.jts.geom.Geometry)"><!-- --></A><H3>
-write</H3>
-<PRE>
-public oracle.sql.STRUCT <B>write</B>(<A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom">Geometry</A> geom)
-                        throws java.sql.SQLException</PRE>
-<DL>
-<DD>This routine will translate the JTS Geometry into an Oracle MDSYS.GEOMETRY STRUCT.
- 
- Although invalid geometries may be encoded, and inserted into an Oracle DB, this is 
- not recomended. It is the responsibility of the user to ensure the geometry is valid 
- prior to calling this method. The user should also ensure the the geometry's SRID 
- field contains the correct value, if an SRID is desired. An incorrect SRID value may 
- cause index exceptions during an insert or update. 
- 
- When a null Geometry is passed in, a non-null, empty STRUCT is returned. Therefore, 
- inserting the the result of calling this method directly into a table will never result 
- in null insertions. 
- (March 2006)
- 
- To pass a NULL Geometry into an oracle geometry parameter using jdbc, use 
- java.sql.CallableStatement.setNull(index,java.sql.Types.STRUCT,"MDSYS.SDO_GEOMETRY")
- (April 2006)
-<P>
-<DD><DL>
-<DT><B>Parameters:</B><DD><CODE>geom</CODE> - JTS Geometry to encode
-<DT><B>Returns:</B><DD>Oracle MDSYS.GEOMETRY STRUCT
-<DT><B>Throws:</B>
-<DD><CODE>java.sql.SQLException</CODE></DL>
-</DD>
-</DL>
-<HR>
-
-<A NAME="setDimension(int)"><!-- --></A><H3>
-setDimension</H3>
-<PRE>
-public void <B>setDimension</B>(int dimension)</PRE>
-<DL>
-<DD><DL>
-<DT><B>Parameters:</B><DD><CODE>dimension</CODE> - The dimension to set.</DL>
-</DD>
-</DL>
-<!-- ========= END OF CLASS DATA ========= -->
-<HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- <A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle"><B>PREV CLASS</B></A> 
- NEXT CLASS</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="OraWriter.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-<TR>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-  SUMMARY: NESTED | FIELD | <A HREF="#constructor_summary">CONSTR</A> | <A HREF="#method_summary">METHOD</A></FONT></TD>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-DETAIL: FIELD | <A HREF="#constructor_detail">CONSTR</A> | <A HREF="#method_detail">METHOD</A></FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/package-frame.html b/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/package-frame.html
deleted file mode 100644
index a19e5e9..0000000
--- a/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/package-frame.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-com.vividsolutions.jts.io.oracle
-</TITLE>
-
-<META NAME="keywords" CONTENT="com.vividsolutions.jts.io.oracle package">
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
-
-
-</HEAD>
-
-<BODY BGCOLOR="white">
-<FONT size="+1" CLASS="FrameTitleFont">
-<A HREF="../../../../../com/vividsolutions/jts/io/oracle/package-summary.html" target="classFrame">com.vividsolutions.jts.io.oracle</A></FONT>
-<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
-<TR>
-<TD NOWRAP><FONT size="+1" CLASS="FrameHeadingFont">
-Classes</FONT> 
-<FONT CLASS="FrameItemFont">
-<BR>
-<A HREF="OraReader.html" title="class in com.vividsolutions.jts.io.oracle" target="classFrame">OraReader</A>
-<BR>
-<A HREF="OraWriter.html" title="class in com.vividsolutions.jts.io.oracle" target="classFrame">OraWriter</A></FONT></TD>
-</TR>
-</TABLE>
-
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/package-summary.html b/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/package-summary.html
deleted file mode 100644
index 19c05fa..0000000
--- a/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/package-summary.html
+++ /dev/null
@@ -1,165 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-com.vividsolutions.jts.io.oracle
-</TITLE>
-
-<META NAME="keywords" CONTENT="com.vividsolutions.jts.io.oracle package">
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="com.vividsolutions.jts.io.oracle";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Package</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV PACKAGE 
- <A HREF="../../../../../com/vividsolutions/jts/io/sde/package-summary.html"><B>NEXT PACKAGE</B></A></FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-<H2>
-Package com.vividsolutions.jts.io.oracle
-</H2>
-Classes to read and write Oracle SDO_GEOMETRY object structures.
-<P>
-<B>See:</B>
-<BR>
-          <A HREF="#package_description"><B>Description</B></A>
-<P>
-
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=2><FONT SIZE="+2">
-<B>Class Summary</B></FONT></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD WIDTH="15%"><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle">OraReader</A></B></TD>
-<TD>Reads a <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>Geometry</CODE></A> from an Oracle <tt>MDSYS.GEOMETRY</tt> object.</TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD WIDTH="15%"><B><A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle">OraWriter</A></B></TD>
-<TD>Translates a JTS Geometry into an Oracle STRUCT representing an MDSYS.GEOMETRY object.</TD>
-</TR>
-</TABLE>
- 
-
-<P>
-<A NAME="package_description"><!-- --></A><H2>
-Package com.vividsolutions.jts.io.oracle Description
-</H2>
-
-<P>
-Classes to read and write Oracle SDO_GEOMETRY object structures.
-<P>
-
-<P>
-<HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Package</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV PACKAGE 
- <A HREF="../../../../../com/vividsolutions/jts/io/sde/package-summary.html"><B>NEXT PACKAGE</B></A></FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/package-tree.html b/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/package-tree.html
deleted file mode 100644
index a4689f2..0000000
--- a/jtsio/doc/javadoc/com/vividsolutions/jts/io/oracle/package-tree.html
+++ /dev/null
@@ -1,143 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-com.vividsolutions.jts.io.oracle Class Hierarchy
-</TITLE>
-
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="com.vividsolutions.jts.io.oracle Class Hierarchy";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- <A HREF="../../../../../com/vividsolutions/jts/io/sde/package-tree.html"><B>NEXT</B></A></FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="package-tree.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-<CENTER>
-<H2>
-Hierarchy For Package com.vividsolutions.jts.io.oracle
-</H2>
-</CENTER>
-<DL>
-<DT><B>Package Hierarchies:</B><DD><A HREF="../../../../../overview-tree.html">All Packages</A></DL>
-<HR>
-<H2>
-Class Hierarchy
-</H2>
-<UL>
-<LI TYPE="circle">class java.lang.Object<UL>
-<LI TYPE="circle">class com.vividsolutions.jts.io.oracle.<A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle"><B>OraReader</B></A><LI TYPE="circle">class com.vividsolutions.jts.io.oracle.<A HREF="../../../../../com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle"><B>OraWriter</B></A></UL>
-</UL>
-<HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- <A HREF="../../../../../com/vividsolutions/jts/io/sde/package-tree.html"><B>NEXT</B></A></FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="package-tree.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/SdeReader.html b/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/SdeReader.html
deleted file mode 100644
index c113908..0000000
--- a/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/SdeReader.html
+++ /dev/null
@@ -1,346 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-SdeReader
-</TITLE>
-
-<META NAME="keywords" CONTENT="com.vividsolutions.jts.io.sde.SdeReader class">
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="SdeReader";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV CLASS 
- NEXT CLASS</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="SdeReader.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-<TR>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-  SUMMARY: NESTED | FIELD | <A HREF="#constructor_summary">CONSTR</A> | <A HREF="#method_summary">METHOD</A></FONT></TD>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-DETAIL: FIELD | <A HREF="#constructor_detail">CONSTR</A> | <A HREF="#method_detail">METHOD</A></FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-<!-- ======== START OF CLASS DATA ======== -->
-<H2>
-<FONT SIZE="-1">
-com.vividsolutions.jts.io.sde</FONT>
-<BR>
-Class SdeReader</H2>
-<PRE>
-java.lang.Object
-  <IMG SRC="../../../../../resources/inherit.gif" ALT="extended by"><B>com.vividsolutions.jts.io.sde.SdeReader</B>
-</PRE>
-<HR>
-<DL>
-<DT>public class <B>SdeReader</B><DT>extends java.lang.Object</DL>
-
-<P>
-Reads a <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>Geometry</CODE></A> from an ESRI SDE Shape.
- <p>
- The SDE geometry model differs from the OGC model used by JTS.
- In particular:
- <ul>
- <li>Simple lines are read as <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/LineString.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>LineString</CODE></A>s
- <li>Inverted Polygons and Exverted Holes are read as is.
- These create invalid JTS polygons, and must be
- rectified if further operations are to be performed on them.
- </ul>
- <p>
- This class allows specifying the maximum number of coordinate dimensions to read.
- If dimensions higher than 2 are not required, it may be more efficient to not read them.
- <p>
- To use this class the ESRI SDE Java libraries must be present.
- <p>
- Currently reading measure (M) ordinates is not supported.
-<P>
-
-<P>
-<DL>
-<DT><B>Author:</B></DT>
-  <DD>Martin Davis</DD>
-</DL>
-<HR>
-
-<P>
-<!-- ======== NESTED CLASS SUMMARY ======== -->
-
-
-<!-- =========== FIELD SUMMARY =========== -->
-
-
-<!-- ======== CONSTRUCTOR SUMMARY ======== -->
-
-<A NAME="constructor_summary"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=2><FONT SIZE="+2">
-<B>Constructor Summary</B></FONT></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/sde/SdeReader.html#SdeReader()">SdeReader</A></B>()</CODE>
-
-<BR>
-          Creates a reader that creates geometries using the default <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>GeometryFactory</CODE></A>.</TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/sde/SdeReader.html#SdeReader(com.vividsolutions.jts.geom.GeometryFactory)">SdeReader</A></B>(<A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom">GeometryFactory</A> geometryFactory)</CODE>
-
-<BR>
-          Creates a reader that creates geometries using the given <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>GeometryFactory</CODE></A>.</TD>
-</TR>
-</TABLE>
- 
-<!-- ========== METHOD SUMMARY =========== -->
-
-<A NAME="method_summary"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=2><FONT SIZE="+2">
-<B>Method Summary</B></FONT></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
-<CODE> int</CODE></FONT></TD>
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/sde/SdeReader.html#getDimension()">getDimension</A></B>()</CODE>
-
-<BR>
-          Gets the maximum number of coordinate dimensions which will be read.</TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
-<CODE> <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom">Geometry</A></CODE></FONT></TD>
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/sde/SdeReader.html#read(com.esri.sde.sdk.client.SeShape)">read</A></B>(com.esri.sde.sdk.client.SeShape shape)</CODE>
-
-<BR>
-          Reads a <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>Geometry</CODE></A> from a given SDE shape.</TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
-<CODE> void</CODE></FONT></TD>
-<TD><CODE><B><A HREF="../../../../../com/vividsolutions/jts/io/sde/SdeReader.html#setDimension(int)">setDimension</A></B>(int dimension)</CODE>
-
-<BR>
-          Sets the maximum number of coordinate dimensions to read.</TD>
-</TR>
-</TABLE>
- <A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
-<TD><B>Methods inherited from class java.lang.Object</B></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
-</TR>
-</TABLE>
- 
-<P>
-
-<!-- ============ FIELD DETAIL =========== -->
-
-
-<!-- ========= CONSTRUCTOR DETAIL ======== -->
-
-<A NAME="constructor_detail"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=1><FONT SIZE="+2">
-<B>Constructor Detail</B></FONT></TD>
-</TR>
-</TABLE>
-
-<A NAME="SdeReader()"><!-- --></A><H3>
-SdeReader</H3>
-<PRE>
-public <B>SdeReader</B>()</PRE>
-<DL>
-<DD>Creates a reader that creates geometries using the default <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>GeometryFactory</CODE></A>.
-<P>
-</DL>
-<HR>
-
-<A NAME="SdeReader(com.vividsolutions.jts.geom.GeometryFactory)"><!-- --></A><H3>
-SdeReader</H3>
-<PRE>
-public <B>SdeReader</B>(<A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom">GeometryFactory</A> geometryFactory)</PRE>
-<DL>
-<DD>Creates a reader that creates geometries using the given <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>GeometryFactory</CODE></A>.
-<P>
-<DT><B>Parameters:</B><DD><CODE>geometryFactory</CODE> - </DL>
-
-<!-- ============ METHOD DETAIL ========== -->
-
-<A NAME="method_detail"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=1><FONT SIZE="+2">
-<B>Method Detail</B></FONT></TD>
-</TR>
-</TABLE>
-
-<A NAME="getDimension()"><!-- --></A><H3>
-getDimension</H3>
-<PRE>
-public int <B>getDimension</B>()</PRE>
-<DL>
-<DD>Gets the maximum number of coordinate dimensions which will be read.
-<P>
-<DD><DL>
-
-<DT><B>Returns:</B><DD>the dimension which will be read</DL>
-</DD>
-</DL>
-<HR>
-
-<A NAME="setDimension(int)"><!-- --></A><H3>
-setDimension</H3>
-<PRE>
-public void <B>setDimension</B>(int dimension)</PRE>
-<DL>
-<DD>Sets the maximum number of coordinate dimensions to read.
- If this is larger than the number of dimensions actually 
- present in the input geometry, the higher ordinates will not
- be read, and NaN will be returned as their value.
- <p>
- The default is to read only the X and Y ordinates (dimension = 2).
-<P>
-<DD><DL>
-<DT><B>Parameters:</B><DD><CODE>dimension</CODE> - the dimension to read</DL>
-</DD>
-</DL>
-<HR>
-
-<A NAME="read(com.esri.sde.sdk.client.SeShape)"><!-- --></A><H3>
-read</H3>
-<PRE>
-public <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom">Geometry</A> <B>read</B>(com.esri.sde.sdk.client.SeShape shape)
-              throws com.esri.sde.sdk.client.SeException</PRE>
-<DL>
-<DD>Reads a <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>Geometry</CODE></A> from a given SDE shape.
-<P>
-<DD><DL>
-<DT><B>Parameters:</B><DD><CODE>shape</CODE> - the shape to read
-<DT><B>Returns:</B><DD>the geometry which represents the input shape
-<DT><B>Throws:</B>
-<DD><CODE>com.esri.sde.sdk.client.SeException</CODE></DL>
-</DD>
-</DL>
-<!-- ========= END OF CLASS DATA ========= -->
-<HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV CLASS 
- NEXT CLASS</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="SdeReader.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-<TR>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-  SUMMARY: NESTED | FIELD | <A HREF="#constructor_summary">CONSTR</A> | <A HREF="#method_summary">METHOD</A></FONT></TD>
-<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
-DETAIL: FIELD | <A HREF="#constructor_detail">CONSTR</A> | <A HREF="#method_detail">METHOD</A></FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/package-frame.html b/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/package-frame.html
deleted file mode 100644
index 3b1cec2..0000000
--- a/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/package-frame.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-com.vividsolutions.jts.io.sde
-</TITLE>
-
-<META NAME="keywords" CONTENT="com.vividsolutions.jts.io.sde package">
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
-
-
-</HEAD>
-
-<BODY BGCOLOR="white">
-<FONT size="+1" CLASS="FrameTitleFont">
-<A HREF="../../../../../com/vividsolutions/jts/io/sde/package-summary.html" target="classFrame">com.vividsolutions.jts.io.sde</A></FONT>
-<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
-<TR>
-<TD NOWRAP><FONT size="+1" CLASS="FrameHeadingFont">
-Classes</FONT> 
-<FONT CLASS="FrameItemFont">
-<BR>
-<A HREF="SdeReader.html" title="class in com.vividsolutions.jts.io.sde" target="classFrame">SdeReader</A></FONT></TD>
-</TR>
-</TABLE>
-
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/package-summary.html b/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/package-summary.html
deleted file mode 100644
index 9f3dd94..0000000
--- a/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/package-summary.html
+++ /dev/null
@@ -1,161 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-com.vividsolutions.jts.io.sde
-</TITLE>
-
-<META NAME="keywords" CONTENT="com.vividsolutions.jts.io.sde package">
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="com.vividsolutions.jts.io.sde";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Package</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- <A HREF="../../../../../com/vividsolutions/jts/io/oracle/package-summary.html"><B>PREV PACKAGE</B></A> 
- NEXT PACKAGE</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-<H2>
-Package com.vividsolutions.jts.io.sde
-</H2>
-Classes to read and write ESRI SDE shapes.
-<P>
-<B>See:</B>
-<BR>
-          <A HREF="#package_description"><B>Description</B></A>
-<P>
-
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=2><FONT SIZE="+2">
-<B>Class Summary</B></FONT></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD WIDTH="15%"><B><A HREF="../../../../../com/vividsolutions/jts/io/sde/SdeReader.html" title="class in com.vividsolutions.jts.io.sde">SdeReader</A></B></TD>
-<TD>Reads a <A HREF="../../../../../../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>Geometry</CODE></A> from an ESRI SDE Shape.</TD>
-</TR>
-</TABLE>
- 
-
-<P>
-<A NAME="package_description"><!-- --></A><H2>
-Package com.vividsolutions.jts.io.sde Description
-</H2>
-
-<P>
-Classes to read and write ESRI SDE shapes.
-<P>
-
-<P>
-<HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Package</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- <A HREF="../../../../../com/vividsolutions/jts/io/oracle/package-summary.html"><B>PREV PACKAGE</B></A> 
- NEXT PACKAGE</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/package-tree.html b/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/package-tree.html
deleted file mode 100644
index 5258b0a..0000000
--- a/jtsio/doc/javadoc/com/vividsolutions/jts/io/sde/package-tree.html
+++ /dev/null
@@ -1,143 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-com.vividsolutions.jts.io.sde Class Hierarchy
-</TITLE>
-
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="com.vividsolutions.jts.io.sde Class Hierarchy";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- <A HREF="../../../../../com/vividsolutions/jts/io/oracle/package-tree.html"><B>PREV</B></A> 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="package-tree.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-<CENTER>
-<H2>
-Hierarchy For Package com.vividsolutions.jts.io.sde
-</H2>
-</CENTER>
-<DL>
-<DT><B>Package Hierarchies:</B><DD><A HREF="../../../../../overview-tree.html">All Packages</A></DL>
-<HR>
-<H2>
-Class Hierarchy
-</H2>
-<UL>
-<LI TYPE="circle">class java.lang.Object<UL>
-<LI TYPE="circle">class com.vividsolutions.jts.io.sde.<A HREF="../../../../../com/vividsolutions/jts/io/sde/SdeReader.html" title="class in com.vividsolutions.jts.io.sde"><B>SdeReader</B></A></UL>
-</UL>
-<HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- <A HREF="../../../../../com/vividsolutions/jts/io/oracle/package-tree.html"><B>PREV</B></A> 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="../../../../../index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="package-tree.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/constant-values.html b/jtsio/doc/javadoc/constant-values.html
deleted file mode 100644
index 72f2b3a..0000000
--- a/jtsio/doc/javadoc/constant-values.html
+++ /dev/null
@@ -1,164 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-Constant Field Values
-</TITLE>
-
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="Constant Field Values";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="constant-values.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-<CENTER>
-<H1>
-Constant Field Values</H1>
-</CENTER>
-<HR SIZE="4" NOSHADE>
-<B>Contents</B><UL>
-<LI><A HREF="#com.vividsolutions">com.vividsolutions.*</A>
-</UL>
-
-<A NAME="com.vividsolutions"><!-- --></A>
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD ALIGN="left"><FONT SIZE="+2">
-<B>com.vividsolutions.*</B></FONT></TD>
-</TR>
-</TABLE>
-
-<P>
-
-<TABLE BORDER="0" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
-<TD COLSPAN=3><B>com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle">OraReader</A></B></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<A NAME="com.vividsolutions.jts.io.oracle.OraReader.NULL_DIMENSION"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
-<CODE>public static final int</CODE></FONT></TD>
-<TD ALIGN="left"><CODE><A HREF="com/vividsolutions/jts/io/oracle/OraReader.html#NULL_DIMENSION">NULL_DIMENSION</A></CODE></TD>
-<TD ALIGN="right"><CODE>-1</CODE></TD>
-</TR>
-</FONT></TD>
-</TR>
-</TABLE>
-
-<P>
-
-<P>
-<HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="constant-values.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/deprecated-list.html b/jtsio/doc/javadoc/deprecated-list.html
deleted file mode 100644
index 0c806ea..0000000
--- a/jtsio/doc/javadoc/deprecated-list.html
+++ /dev/null
@@ -1,132 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-Deprecated List
-</TITLE>
-
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="Deprecated List";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Deprecated</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="deprecated-list.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-<CENTER>
-<H2>
-<B>Deprecated API</B></H2>
-</CENTER>
-<HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Deprecated</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="deprecated-list.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/help-doc.html b/jtsio/doc/javadoc/help-doc.html
deleted file mode 100644
index 1b2d844..0000000
--- a/jtsio/doc/javadoc/help-doc.html
+++ /dev/null
@@ -1,187 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-API Help
-</TITLE>
-
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="API Help";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Help</B></FONT> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="help-doc.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-<CENTER>
-<H1>
-How This API Document Is Organized</H1>
-</CENTER>
-This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.<H3>
-Overview</H3>
-<BLOCKQUOTE>
-
-<P>
-The <A HREF="overview-summary.html">Overview</A> page is the front page of this API document and provides a list of all packages with a summary for each.  This page can also contain an overall description of the set of packages.</BLOCKQUOTE>
-<H3>
-Package</H3>
-<BLOCKQUOTE>
-
-<P>
-Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain four categories:<UL>
-<LI>Interfaces (italic)<LI>Classes<LI>Exceptions<LI>Errors</UL>
-</BLOCKQUOTE>
-<H3>
-Class/Interface</H3>
-<BLOCKQUOTE>
-
-<P>
-Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:<UL>
-<LI>Class inheritance diagram<LI>Direct Subclasses<LI>All Known Subinterfaces<LI>All Known Implementing Classes<LI>Class/interface declaration<LI>Class/interface description
-<P>
-<LI>Nested Class Summary<LI>Field Summary<LI>Constructor Summary<LI>Method Summary
-<P>
-<LI>Field Detail<LI>Constructor Detail<LI>Method Detail</UL>
-Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.</BLOCKQUOTE>
-<H3>
-Tree (Class Hierarchy)</H3>
-<BLOCKQUOTE>
-There is a <A HREF="overview-tree.html">Class Hierarchy</A> page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with <code>java.lang.Object</code>. The interfaces do not inherit from <code>java.lang.Object</code>.<UL>
-<LI>When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.<LI>When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.</UL>
-</BLOCKQUOTE>
-<H3>
-Deprecated API</H3>
-<BLOCKQUOTE>
-The <A HREF="deprecated-list.html">Deprecated API</A> page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.</BLOCKQUOTE>
-<H3>
-Index</H3>
-<BLOCKQUOTE>
-The <A HREF="index-all.html">Index</A> contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.</BLOCKQUOTE>
-<H3>
-Prev/Next</H3>
-These links take you to the next or previous class, interface, package, or related page.<H3>
-Frames/No Frames</H3>
-These links show and hide the HTML frames.  All pages are available with or without frames.
-<P>
-<H3>
-Serialized Form</H3>
-Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description.
-<P>
-<FONT SIZE="-1">
-<EM>
-This help file applies to API documentation generated using the standard doclet.</EM>
-</FONT>
-<BR>
-<HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Help</B></FONT> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="help-doc.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/index-all.html b/jtsio/doc/javadoc/index-all.html
deleted file mode 100644
index 5db3f55..0000000
--- a/jtsio/doc/javadoc/index-all.html
+++ /dev/null
@@ -1,212 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-Index
-</TITLE>
-
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="Index";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="index-all.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<A HREF="#_C_">C</A> <A HREF="#_G_">G</A> <A HREF="#_N_">N</A> <A HREF="#_O_">O</A> <A HREF="#_R_">R</A> <A HREF="#_S_">S</A> <A HREF="#_W_">W</A> <HR>
-<A NAME="_C_"><!-- --></A><H2>
-<B>C</B></H2>
-<DL>
-<DT><A HREF="com/vividsolutions/jts/io/oracle/package-summary.html"><B>com.vividsolutions.jts.io.oracle</B></A> - package com.vividsolutions.jts.io.oracle<DD>Classes to read and write Oracle SDO_GEOMETRY object structures.<DT><A HREF="com/vividsolutions/jts/io/sde/package-summary.html"><B>com.vividsolutions.jts.io.sde</B></A> - package com.vividsolutions.jts.io.sde<DD>Classes to read and write ESRI SDE shapes.</DL>
-<HR>
-<A NAME="_G_"><!-- --></A><H2>
-<B>G</B></H2>
-<DL>
-<DT><A HREF="com/vividsolutions/jts/io/oracle/OraReader.html#getDimension()"><B>getDimension()</B></A> - 
-Method in class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle">OraReader</A>
-<DD>Gets the number of coordinate dimensions which will be read.
-<DT><A HREF="com/vividsolutions/jts/io/sde/SdeReader.html#getDimension()"><B>getDimension()</B></A> - 
-Method in class com.vividsolutions.jts.io.sde.<A HREF="com/vividsolutions/jts/io/sde/SdeReader.html" title="class in com.vividsolutions.jts.io.sde">SdeReader</A>
-<DD>Gets the maximum number of coordinate dimensions which will be read.
-</DL>
-<HR>
-<A NAME="_N_"><!-- --></A><H2>
-<B>N</B></H2>
-<DL>
-<DT><A HREF="com/vividsolutions/jts/io/oracle/OraReader.html#NULL_DIMENSION"><B>NULL_DIMENSION</B></A> - 
-Static variable in class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle">OraReader</A>
-<DD> 
-</DL>
-<HR>
-<A NAME="_O_"><!-- --></A><H2>
-<B>O</B></H2>
-<DL>
-<DT><A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle"><B>OraReader</B></A> - class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle">OraReader</A>.<DD>Reads a <A HREF="../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>Geometry</CODE></A> from an Oracle <tt>MDSYS.GE [...]
-Constructor for class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle">OraReader</A>
-<DD>Creates a new reader, with a default GeometryFactory.
-<DT><A HREF="com/vividsolutions/jts/io/oracle/OraReader.html#OraReader(com.vividsolutions.jts.geom.GeometryFactory)"><B>OraReader(GeometryFactory)</B></A> - 
-Constructor for class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle">OraReader</A>
-<DD>Creates a new reader, with the supplied <A HREF="../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>GeometryFactory</CODE></A>.
-<DT><A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle"><B>OraWriter</B></A> - class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle">OraWriter</A>.<DD>Translates a JTS Geometry into an Oracle STRUCT representing an MDSYS.GEOMETRY object.<DT><A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html#OraWriter(oracle.jdbc.OracleConnection)"><B>O [...]
-Constructor for class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle">OraWriter</A>
-<DD>Initialize the Oracle MDSYS.GEOMETRY Encoder with a valid oracle connection.
-<DT><A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html#OraWriter(oracle.jdbc.OracleConnection, int)"><B>OraWriter(OracleConnection, int)</B></A> - 
-Constructor for class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle">OraWriter</A>
-<DD>Initialize the Oracle MDSYS.GEOMETRY Encoder with a valid oracle connection.
-</DL>
-<HR>
-<A NAME="_R_"><!-- --></A><H2>
-<B>R</B></H2>
-<DL>
-<DT><A HREF="com/vividsolutions/jts/io/oracle/OraReader.html#read(oracle.sql.STRUCT)"><B>read(STRUCT)</B></A> - 
-Method in class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle">OraReader</A>
-<DD>This method will attempt to create a JTS Geometry for the MDSYS.GEOMETRY
- provided.
-<DT><A HREF="com/vividsolutions/jts/io/sde/SdeReader.html#read(com.esri.sde.sdk.client.SeShape)"><B>read(SeShape)</B></A> - 
-Method in class com.vividsolutions.jts.io.sde.<A HREF="com/vividsolutions/jts/io/sde/SdeReader.html" title="class in com.vividsolutions.jts.io.sde">SdeReader</A>
-<DD>Reads a <A HREF="../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>Geometry</CODE></A> from a given SDE shape.
-</DL>
-<HR>
-<A NAME="_S_"><!-- --></A><H2>
-<B>S</B></H2>
-<DL>
-<DT><A HREF="com/vividsolutions/jts/io/sde/SdeReader.html" title="class in com.vividsolutions.jts.io.sde"><B>SdeReader</B></A> - class com.vividsolutions.jts.io.sde.<A HREF="com/vividsolutions/jts/io/sde/SdeReader.html" title="class in com.vividsolutions.jts.io.sde">SdeReader</A>.<DD>Reads a <A HREF="../../../doc/javadoc/com/vividsolutions/jts/geom/Geometry.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>Geometry</CODE></A> from an ESRI SDE Shape.<DT><A HREF="com/vi [...]
-Constructor for class com.vividsolutions.jts.io.sde.<A HREF="com/vividsolutions/jts/io/sde/SdeReader.html" title="class in com.vividsolutions.jts.io.sde">SdeReader</A>
-<DD>Creates a reader that creates geometries using the default <A HREF="../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>GeometryFactory</CODE></A>.
-<DT><A HREF="com/vividsolutions/jts/io/sde/SdeReader.html#SdeReader(com.vividsolutions.jts.geom.GeometryFactory)"><B>SdeReader(GeometryFactory)</B></A> - 
-Constructor for class com.vividsolutions.jts.io.sde.<A HREF="com/vividsolutions/jts/io/sde/SdeReader.html" title="class in com.vividsolutions.jts.io.sde">SdeReader</A>
-<DD>Creates a reader that creates geometries using the given <A HREF="../../../doc/javadoc/com/vividsolutions/jts/geom/GeometryFactory.html" title="class or interface in com.vividsolutions.jts.geom"><CODE>GeometryFactory</CODE></A>.
-<DT><A HREF="com/vividsolutions/jts/io/oracle/OraReader.html#setDimension(int)"><B>setDimension(int)</B></A> - 
-Method in class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle">OraReader</A>
-<DD>Sets the number of coordinate dimensions to read.
-<DT><A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html#setDimension(int)"><B>setDimension(int)</B></A> - 
-Method in class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle">OraWriter</A>
-<DD> 
-<DT><A HREF="com/vividsolutions/jts/io/sde/SdeReader.html#setDimension(int)"><B>setDimension(int)</B></A> - 
-Method in class com.vividsolutions.jts.io.sde.<A HREF="com/vividsolutions/jts/io/sde/SdeReader.html" title="class in com.vividsolutions.jts.io.sde">SdeReader</A>
-<DD>Sets the maximum number of coordinate dimensions to read.
-<DT><A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html#setSRID(int)"><B>setSRID(int)</B></A> - 
-Method in class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle">OraWriter</A>
-<DD>Provides the oppotunity to force all geometries written using this writter to be written using the 
- specified srid.
-</DL>
-<HR>
-<A NAME="_W_"><!-- --></A><H2>
-<B>W</B></H2>
-<DL>
-<DT><A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html#write(com.vividsolutions.jts.geom.Geometry)"><B>write(Geometry)</B></A> - 
-Method in class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle">OraWriter</A>
-<DD>This routine will translate the JTS Geometry into an Oracle MDSYS.GEOMETRY STRUCT.
-</DL>
-<HR>
-<A HREF="#_C_">C</A> <A HREF="#_G_">G</A> <A HREF="#_N_">N</A> <A HREF="#_O_">O</A> <A HREF="#_R_">R</A> <A HREF="#_S_">S</A> <A HREF="#_W_">W</A> 
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="index-all.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/index.html b/jtsio/doc/javadoc/index.html
deleted file mode 100644
index 56fa676..0000000
--- a/jtsio/doc/javadoc/index.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc on Mon Mar 01 21:11:45 PST 2010-->
-<TITLE>
-Generated Documentation (Untitled)
-</TITLE>
-</HEAD>
-<FRAMESET cols="20%,80%">
-<FRAMESET rows="30%,70%">
-<FRAME src="overview-frame.html" name="packageListFrame" title="All Packages">
-<FRAME src="allclasses-frame.html" name="packageFrame" title="All classes and interfaces (except non-static nested types)">
-</FRAMESET>
-<FRAME src="overview-summary.html" name="classFrame" title="Package, class and interface descriptions">
-<NOFRAMES>
-<H2>
-Frame Alert</H2>
-
-<P>
-This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
-<BR>
-Link to<A HREF="overview-summary.html">Non-frame version.</A>
-</NOFRAMES>
-</FRAMESET>
-</HTML>
diff --git a/jtsio/doc/javadoc/overview-frame.html b/jtsio/doc/javadoc/overview-frame.html
deleted file mode 100644
index f41763a..0000000
--- a/jtsio/doc/javadoc/overview-frame.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-Overview
-</TITLE>
-
-<META NAME="keywords" CONTENT="Overview">
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
-
-
-</HEAD>
-
-<BODY BGCOLOR="white">
-
-<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
-<TR>
-<TD NOWRAP><FONT size="+1" CLASS="FrameTitleFont">
-<B></B></FONT></TD>
-</TR>
-</TABLE>
-
-<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
-<TR>
-<TD NOWRAP><FONT CLASS="FrameItemFont"><A HREF="allclasses-frame.html" target="packageFrame">All Classes</A></FONT>
-<P>
-<FONT size="+1" CLASS="FrameHeadingFont">
-Packages</FONT>
-<BR>
-<FONT CLASS="FrameItemFont"><A HREF="com/vividsolutions/jts/io/oracle/package-frame.html" target="packageFrame">com.vividsolutions.jts.io.oracle</A></FONT>
-<BR>
-<FONT CLASS="FrameItemFont"><A HREF="com/vividsolutions/jts/io/sde/package-frame.html" target="packageFrame">com.vividsolutions.jts.io.sde</A></FONT>
-<BR>
-</TD>
-</TR>
-</TABLE>
-
-<P>
- 
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/overview-summary.html b/jtsio/doc/javadoc/overview-summary.html
deleted file mode 100644
index ca76b24..0000000
--- a/jtsio/doc/javadoc/overview-summary.html
+++ /dev/null
@@ -1,146 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-Overview
-</TITLE>
-
-<META NAME="keywords" CONTENT="Overview">
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="Overview";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Overview</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="overview-summary.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-
-<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<TD COLSPAN=2><FONT SIZE="+2">
-<B>Packages</B></FONT></TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD WIDTH="20%"><B><A HREF="com/vividsolutions/jts/io/oracle/package-summary.html">com.vividsolutions.jts.io.oracle</A></B></TD>
-<TD>Classes to read and write Oracle SDO_GEOMETRY object structures.</TD>
-</TR>
-<TR BGCOLOR="white" CLASS="TableRowColor">
-<TD WIDTH="20%"><B><A HREF="com/vividsolutions/jts/io/sde/package-summary.html">com.vividsolutions.jts.io.sde</A></B></TD>
-<TD>Classes to read and write ESRI SDE shapes.</TD>
-</TR>
-</TABLE>
-
-<P>
- <HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Overview</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="overview-summary.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/overview-tree.html b/jtsio/doc/javadoc/overview-tree.html
deleted file mode 100644
index c730085..0000000
--- a/jtsio/doc/javadoc/overview-tree.html
+++ /dev/null
@@ -1,142 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-Class Hierarchy
-</TITLE>
-
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
-
-<SCRIPT type="text/javascript">
-function windowTitle()
-{
-    parent.document.title="Class Hierarchy";
-}
-</SCRIPT>
-
-</HEAD>
-
-<BODY BGCOLOR="white" onload="windowTitle();">
-
-
-<!-- ========= START OF TOP NAVBAR ======= -->
-<A NAME="navbar_top"><!-- --></A>
-<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_top_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="overview-tree.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_top"></A>
-<!-- ========= END OF TOP NAVBAR ========= -->
-
-<HR>
-<CENTER>
-<H2>
-Hierarchy For All Packages</H2>
-</CENTER>
-<DL>
-<DT><B>Package Hierarchies:</B><DD><A HREF="com/vividsolutions/jts/io/oracle/package-tree.html">com.vividsolutions.jts.io.oracle</A>, <A HREF="com/vividsolutions/jts/io/sde/package-tree.html">com.vividsolutions.jts.io.sde</A></DL>
-<HR>
-<H2>
-Class Hierarchy
-</H2>
-<UL>
-<LI TYPE="circle">class java.lang.Object<UL>
-<LI TYPE="circle">class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraReader.html" title="class in com.vividsolutions.jts.io.oracle"><B>OraReader</B></A><LI TYPE="circle">class com.vividsolutions.jts.io.oracle.<A HREF="com/vividsolutions/jts/io/oracle/OraWriter.html" title="class in com.vividsolutions.jts.io.oracle"><B>OraWriter</B></A><LI TYPE="circle">class com.vividsolutions.jts.io.sde.<A HREF="com/vividsolutions/jts/io/sde/SdeReader.html" title="class  [...]
-</UL>
-<HR>
-
-
-<!-- ======= START OF BOTTOM NAVBAR ====== -->
-<A NAME="navbar_bottom"><!-- --></A>
-<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
-<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
-<TR>
-<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
-<A NAME="navbar_bottom_firstrow"><!-- --></A>
-<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
-  <TR ALIGN="center" VALIGN="top">
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT> </TD>
-  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">  <FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A> </TD>
-  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A> </TD>
-  </TR>
-</TABLE>
-</TD>
-<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
-</EM>
-</TD>
-</TR>
-
-<TR>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
- PREV 
- NEXT</FONT></TD>
-<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
-  <A HREF="index.html" target="_top"><B>FRAMES</B></A>   
- <A HREF="overview-tree.html" target="_top"><B>NO FRAMES</B></A>   
- <SCRIPT type="text/javascript">
-  <!--
-  if(window==top) {
-    document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
-  }
-  //-->
-</SCRIPT>
-<NOSCRIPT>
-  <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
-</NOSCRIPT>
-
-</FONT></TD>
-</TR>
-</TABLE>
-<A NAME="skip-navbar_bottom"></A>
-<!-- ======== END OF BOTTOM NAVBAR ======= -->
-
-<HR>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/package-list b/jtsio/doc/javadoc/package-list
deleted file mode 100644
index e0eb2d7..0000000
--- a/jtsio/doc/javadoc/package-list
+++ /dev/null
@@ -1,2 +0,0 @@
-com.vividsolutions.jts.io.oracle
-com.vividsolutions.jts.io.sde
diff --git a/jtsio/doc/javadoc/packages.html b/jtsio/doc/javadoc/packages.html
deleted file mode 100644
index 3aaa486..0000000
--- a/jtsio/doc/javadoc/packages.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!--NewPage-->
-<HTML>
-<HEAD>
-<!-- Generated by javadoc (build 1.4.2_09) on Mon Mar 01 21:11:45 PST 2010 -->
-<TITLE>
-
-</TITLE>
-
-
-<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
-
-
-</HEAD>
-
-<BODY BGCOLOR="white">
-
-<BR>
-
-<BR>
-
-<BR>
-<CENTER>
-The front page has been relocated.Please see:
-<BR>
-          <A HREF="index.html">Frame version</A>
-<BR>
-          <A HREF="overview-summary.html">Non-frame version.</A></CENTER>
-
-</BODY>
-</HTML>
diff --git a/jtsio/doc/javadoc/resources/inherit.gif b/jtsio/doc/javadoc/resources/inherit.gif
deleted file mode 100644
index c814867..0000000
Binary files a/jtsio/doc/javadoc/resources/inherit.gif and /dev/null differ
diff --git a/jtsio/doc/javadoc/stylesheet.css b/jtsio/doc/javadoc/stylesheet.css
deleted file mode 100644
index 14c3737..0000000
--- a/jtsio/doc/javadoc/stylesheet.css
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Javadoc style sheet */
-
-/* Define colors, fonts and other style attributes here to override the defaults */
-
-/* Page background color */
-body { background-color: #FFFFFF }
-
-/* Headings */
-h1 { font-size: 145% }
-
-/* Table colors */
-.TableHeadingColor     { background: #CCCCFF } /* Dark mauve */
-.TableSubHeadingColor  { background: #EEEEFF } /* Light mauve */
-.TableRowColor         { background: #FFFFFF } /* White */
-
-/* Font used in left-hand frame lists */
-.FrameTitleFont   { font-size: 100%; font-family: Helvetica, Arial, sans-serif }
-.FrameHeadingFont { font-size:  90%; font-family: Helvetica, Arial, sans-serif }
-.FrameItemFont    { font-size:  90%; font-family: Helvetica, Arial, sans-serif }
-
-/* Navigation bar fonts and colors */
-.NavBarCell1    { background-color:#EEEEFF;} /* Light mauve */
-.NavBarCell1Rev { background-color:#00008B;} /* Dark Blue */
-.NavBarFont1    { font-family: Arial, Helvetica, sans-serif; color:#000000;}
-.NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;}
-
-.NavBarCell2    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
-.NavBarCell3    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
-
diff --git a/src/com/vividsolutions/jts/JTSVersion.java b/src/com/vividsolutions/jts/JTSVersion.java
index 647b239..7d5372d 100644
--- a/src/com/vividsolutions/jts/JTSVersion.java
+++ b/src/com/vividsolutions/jts/JTSVersion.java
@@ -24,7 +24,7 @@ public class JTSVersion {
   /**
    * The minor version number.
    */
-  public static final int MINOR = 11;
+  public static final int MINOR = 12;
 
   /**
    * The patch version number.
@@ -34,7 +34,7 @@ public class JTSVersion {
   /**
    * An optional string providing further release info (such as "alpha 1");
    */
-  private static final String releaseInfo = "alpha";
+  private static final String releaseInfo = "";
 
   /**
    * Prints the current JTS version to stdout.
diff --git a/src/com/vividsolutions/jts/algorithm/BoundaryNodeRule.java b/src/com/vividsolutions/jts/algorithm/BoundaryNodeRule.java
index 8bfb950..6c83ae9 100644
--- a/src/com/vividsolutions/jts/algorithm/BoundaryNodeRule.java
+++ b/src/com/vividsolutions/jts/algorithm/BoundaryNodeRule.java
@@ -32,6 +32,8 @@
  */
 package com.vividsolutions.jts.algorithm;
 
+import com.vividsolutions.jts.geom.*;
+
 /**
  * An interface for rules which determine whether node points
  * which are in boundaries of {@link Lineal} geometry components
diff --git a/src/com/vividsolutions/jts/algorithm/CGAlgorithms.java b/src/com/vividsolutions/jts/algorithm/CGAlgorithms.java
index 6029ac3..e891f1a 100644
--- a/src/com/vividsolutions/jts/algorithm/CGAlgorithms.java
+++ b/src/com/vividsolutions/jts/algorithm/CGAlgorithms.java
@@ -74,10 +74,37 @@ public class CGAlgorithms
    * @return -1 if q is clockwise (right) from p1-p2
    * @return 0 if q is collinear with p1-p2
    */
-  public static int orientationIndex(Coordinate p1, Coordinate p2, Coordinate q) {
-    // travelling along p1->p2, turn counter clockwise to get to q return 1,
-    // travelling along p1->p2, turn clockwise to get to q return -1,
-    // p1, p2 and q are colinear return 0.
+  public static int orientationIndex(Coordinate p1, Coordinate p2, Coordinate q) 
+  {
+  	/**
+  	 * MD - 9 Aug 2010
+  	 * It seems that the basic algorithm is slightly orientation dependent,
+  	 * when computing the orientation of a point very close to a line.
+  	 * This is possibly due to the arithmetic in the translation to the origin.
+  	 * 
+  	 * For instance, the following situation produces identical results 
+  	 * in spite of the inverse orientation of the line segment:
+  	 * 
+  	 * Coordinate p0 = new Coordinate(219.3649559090992, 140.84159161824724);
+  	 * Coordinate p1 = new Coordinate(168.9018919682399, -5.713787599646864);
+  	 * 
+  	 * Coordinate p = new Coordinate(186.80814046338352, 46.28973405831556);
+  	 * int orient = orientationIndex(p0, p1, p);
+  	 * int orientInv = orientationIndex(p1, p0, p);
+
+  	 * A way to force consistent results is to normalize the orientation of the vector
+  	 * using the following code.
+  	 * However, this may make the results of orientationIndex inconsistent
+  	 * through the triangle of points, so it's not clear this is 
+  	 * an appropriate patch.
+  	 * 
+  	 */
+  	/*
+  	 // Normalize orientation of vector to provide consistent results
+    // This produces repeatable results for single cases, but does not fully solve robustness issues
+ 	   if (p2.x < p1.x || (p2.x == p1.x && p2.y < p1.y))
+			return -orientationIndex(p2, p1, q);
+	  //*/
     double dx1 = p2.x - p1.x;
     double dy1 = p2.y - p1.y;
     double dx2 = q.x - p2.x;
@@ -251,8 +278,8 @@ public class CGAlgorithms
    */
   public static double distancePointLine(Coordinate p, Coordinate A, Coordinate B)
   {
-    // if start==end, then use pt distance
-    if (  A.equals(B) ) return p.distance(A);
+    // if start = end, then just compute distance to one of the endpoints
+    if (  A.x == B.x && A.y == B.y ) return p.distance(A);
 
     // otherwise use comp.graphics.algorithms Frequently Asked Questions method
     /*(1)     	      AC dot AB
@@ -435,9 +462,12 @@ limiting conditions:
 
   /**
    * Computes the signed area for a ring.      
-   * The signed area is positive if
-   * the ring is oriented CW, negative if the ring is oriented CCW,
-   * and zero if the ring is degenerate or flat. 
+   * The signed area is:
+   * <ul>
+   * <li>positive if the ring is oriented CW
+   * <li>negative if the ring is oriented CCW
+   * <li>zero if the ring is degenerate or flat
+   * </ul> 
    * 
    * @param ring the coordinates forming the ring
    * @return the signed area of the ring
@@ -446,17 +476,17 @@ limiting conditions:
   {
     int n = ring.size();
     if (n < 3) return 0.0;
-         double sum = 0.0;
+    double sum = 0.0;
     Coordinate p = new Coordinate();
     ring.getCoordinate(0, p);
     double bx = p.x;
     double by = p.y;
-         for (int i = 1; i < n; i++) {
+    for (int i = 1; i < n; i++) {
       ring.getCoordinate(i, p);
       double cx = p.x;
       double cy = p.y;
       sum += (bx + cx) * (cy - by);
-             bx = cx;
+      bx = cx;
       by = cy;
     }
     return -sum  / 2.0;
diff --git a/src/com/vividsolutions/jts/algorithm/ConvexHull.java b/src/com/vividsolutions/jts/algorithm/ConvexHull.java
index 9c10a11..7ddc3c8 100644
--- a/src/com/vividsolutions/jts/algorithm/ConvexHull.java
+++ b/src/com/vividsolutions/jts/algorithm/ConvexHull.java
@@ -131,7 +131,6 @@ public class ConvexHull
     return coordinates;
   }
 
-
   /**
    * Uses a heuristic to reduce the number of points scanned
    * to compute the hull.
@@ -144,9 +143,12 @@ public class ConvexHull
    * <p>
    * Note that even if the method used to determine the polygon vertices
    * is not 100% robust, this does not affect the robustness of the convex hull.
+   * <p>
+   * To satisfy the requirements of the Graham Scan algorithm, 
+   * the returned array has at least 3 entries.
    *
-   * @param pts
-   * @return
+   * @param pts the points to reduce
+   * @return the reduced list of points (at least 3)
    */
   private Coordinate[] reduce(Coordinate[] inputPts)
   {
@@ -178,9 +180,26 @@ public class ConvexHull
       }
     }
     Coordinate[] reducedPts = CoordinateArrays.toCoordinateArray(reducedSet);
+    
+    // ensure that computed array has at least 3 points (not necessarily unique)  
+    if (reducedPts.length < 3)
+      return padArray3(reducedPts); 
     return reducedPts;
   }
 
+  private Coordinate[] padArray3(Coordinate[] pts)
+  {
+    Coordinate[] pad = new Coordinate[3];
+    for (int i = 0; i < pad.length; i++) {
+      if (i < pts.length) {
+        pad[i] = pts[i];
+      }
+      else
+        pad[i] = pts[0];
+    }
+    return pad;
+  }
+    
   private Coordinate[] preSort(Coordinate[] pts) {
     Coordinate t;
 
@@ -202,6 +221,12 @@ public class ConvexHull
     return pts;
   }
 
+  /**
+   * Uses the Graham Scan algorithm to compute the convex hull vertices.
+   * 
+   * @param c a list of points, with at least 3 entries
+   * @return a Stack containing the ordered points of the convex hull ring
+   */
   private Stack grahamScan(Coordinate[] c) {
     Coordinate p;
     Stack ps = new Stack();
diff --git a/src/com/vividsolutions/jts/algorithm/LineIntersector.java b/src/com/vividsolutions/jts/algorithm/LineIntersector.java
index abafe3e..1b8a52e 100644
--- a/src/com/vividsolutions/jts/algorithm/LineIntersector.java
+++ b/src/com/vividsolutions/jts/algorithm/LineIntersector.java
@@ -194,6 +194,18 @@ public abstract class LineIntersector
   }
 
   /**
+   * Gets an endpoint of an input segment.
+   * 
+   * @param segmentIndex the index of the input segment (0 or 1)
+   * @param ptIndex the index of the endpoint (0 or 1)
+   * @return the specified endpoint
+   */
+  public Coordinate getEndpoint(int segmentIndex, int ptIndex)
+  {
+    return inputLines[segmentIndex][ptIndex];
+  }
+  
+  /**
    * Compute the intersection of a point p and the line p1-p2.
    * This function computes the boolean value of the hasIntersection test.
    * The actual value of the intersection (if there is one)
@@ -368,13 +380,13 @@ public abstract class LineIntersector
   }
 
   /**
-   * Computes the index of the intIndex'th intersection point in the direction of
+   * Computes the index (order) of the intIndex'th intersection point in the direction of
    * a specified input line segment
    *
    * @param segmentIndex is 0 or 1
    * @param intIndex is 0 or 1
    *
-   * @return the index of the intersection point along the segment (0 or 1)
+   * @return the index of the intersection point along the input segment (0 or 1)
    */
   public int getIndexAlongSegment(int segmentIndex, int intIndex) {
     computeIntLineIndex();
diff --git a/src/com/vividsolutions/jts/algorithm/MCPointInRing.java b/src/com/vividsolutions/jts/algorithm/MCPointInRing.java
index 53064be..a8e11d4 100644
--- a/src/com/vividsolutions/jts/algorithm/MCPointInRing.java
+++ b/src/com/vividsolutions/jts/algorithm/MCPointInRing.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.index.bintree.*;
 
 /**
  * Implements {@link PointInRing}
- * using {@link MonotoneChain}s and a {@link BinTree} index to
+ * using {@link MonotoneChain}s and a {@link Bintree} index to
  * increase performance.
  *
  * @version 1.7
diff --git a/src/com/vividsolutions/jts/algorithm/NonRobustLineIntersector.java b/src/com/vividsolutions/jts/algorithm/NonRobustLineIntersector.java
index c050f47..de5095b 100644
--- a/src/com/vividsolutions/jts/algorithm/NonRobustLineIntersector.java
+++ b/src/com/vividsolutions/jts/algorithm/NonRobustLineIntersector.java
@@ -43,7 +43,7 @@ import com.vividsolutions.jts.geom.*;
 //import com.vividsolutions.jts.util.Debug;
 
 /**
- * A non-robust version of {@LineIntersector}.
+ * A non-robust version of {@link LineIntersector}.
  *
  * @version 1.7
  */
diff --git a/src/com/vividsolutions/jts/algorithm/PointInRing.java b/src/com/vividsolutions/jts/algorithm/PointInRing.java
index bc6ce52..d6e2104 100644
--- a/src/com/vividsolutions/jts/algorithm/PointInRing.java
+++ b/src/com/vividsolutions/jts/algorithm/PointInRing.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.geom.Coordinate;
  *
  * @version 1.7
  * 
- * @see PointOnGeometryLocator for more general functionality
+ * @see PointOnGeometryLocator
  */
 public interface PointInRing {
 
diff --git a/src/com/vividsolutions/jts/algorithm/RayCrossingCounter.java b/src/com/vividsolutions/jts/algorithm/RayCrossingCounter.java
index e795ac8..76f88d5 100644
--- a/src/com/vividsolutions/jts/algorithm/RayCrossingCounter.java
+++ b/src/com/vividsolutions/jts/algorithm/RayCrossingCounter.java
@@ -167,6 +167,7 @@ public class RayCrossingCounter
 				xIntSign = -xIntSign;
 			// xsave = xInt;
 
+      //System.out.println("xIntSign(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + " = " + xIntSign);
 			// The segment crosses the ray if the sign is strictly positive.
 			if (xIntSign > 0.0) {
 				crossingCount++;
diff --git a/src/com/vividsolutions/jts/algorithm/RobustDeterminant.java b/src/com/vividsolutions/jts/algorithm/RobustDeterminant.java
index 1169bab..bf49d4b 100644
--- a/src/com/vividsolutions/jts/algorithm/RobustDeterminant.java
+++ b/src/com/vividsolutions/jts/algorithm/RobustDeterminant.java
@@ -65,6 +65,39 @@ public class RobustDeterminant {
 
   //public static int callCount = 0; // debugging only
 
+  /*
+  // test point to allow injecting test code
+  public static int signOfDet2x2(double x1, double y1, double x2, double y2) 
+  {
+    int d1 = originalSignOfDet2x2(x1, y1, x2, y2); 
+    int d2 = -originalSignOfDet2x2(y1, x1, x2, y2); 
+    assert d1 == -d2;
+    return d1;
+  }
+   */
+  
+  /*
+   * Test code to force a standard ordering of input ordinates.
+   * A possible fix for a rare problem where evaluation is order-dependent.
+   */
+  /*
+  public static int signOfDet2x2(double x1, double y1, double x2, double y2) 
+  {
+    if (x1 > x2) {
+      return -signOfDet2x2ordX(x2, y2, x1, y1);
+    }
+    return signOfDet2x2ordX(x1, y1, x2, y2);
+  }
+    
+  private static int signOfDet2x2ordX(double x1, double y1, double x2, double y2) 
+  {
+    if (y1 > y2) {
+      return -originalSignOfDet2x2(y1, x1, y2, x2);
+    }
+    return originalSignOfDet2x2(x1, y1, x2, y2);
+  }
+  //  */
+  
   /**
    * Computes the sign of the determinant of the 2x2 matrix
    * with the given entries, in a robust way.
@@ -73,10 +106,11 @@ public class RobustDeterminant {
    * @return  1 if the determinant is positive,
    * @return  0 if the determinant is 0.
    */
-  public static int signOfDet2x2(double x1, double y1, double x2, double y2) {
+   //private static int originalSignOfDet2x2(double x1, double y1, double x2, double y2) {
+   public static int signOfDet2x2(double x1, double y1, double x2, double y2) {
     // returns -1 if the determinant is negative,
     // returns  1 if the determinant is positive,
-    // retunrs  0 if the determinant is null.
+    // returns  0 if the determinant is null.
     int sign;
     double swap;
     double k;
diff --git a/src/com/vividsolutions/jts/algorithm/RobustLineIntersector.java b/src/com/vividsolutions/jts/algorithm/RobustLineIntersector.java
index 84dfdd2..cde9cc6 100644
--- a/src/com/vividsolutions/jts/algorithm/RobustLineIntersector.java
+++ b/src/com/vividsolutions/jts/algorithm/RobustLineIntersector.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.util.Assert;
 
 /**
- * A robust version of {@LineIntersector}.
+ * A robust version of {@link LineIntersector}.
  *
  * @version 1.7
  * @see RobustDeterminant
diff --git a/src/com/vividsolutions/jts/algorithm/VectorMath.java b/src/com/vividsolutions/jts/algorithm/VectorMath.java
deleted file mode 100644
index 595e45d..0000000
--- a/src/com/vividsolutions/jts/algorithm/VectorMath.java
+++ /dev/null
@@ -1,86 +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.jts.algorithm;
-
-import com.vividsolutions.jts.geom.Coordinate;
-
-/**
- * Functions for performing vector mathematics.
- * 
- * @author Martin Davis
- * @version 1.0
- */
-
-public class VectorMath 
-{
-    /**
-     * Computes the normal vector to the triangle p0-p1-p2. In order to compute the normal each
-     * triangle coordinate must have a Z value. If this is not the case, the returned Coordinate
-     * will have NaN values. The returned vector has unit length.
-     * 
-     * @param p0
-     * @param p1
-     * @param p2
-     * @return
-     */
-    public static Coordinate normalToTriangle(Coordinate p0, Coordinate p1, Coordinate p2) {
-        Coordinate v1 = new Coordinate(p1.x - p0.x, p1.y - p0.y, p1.z - p0.z);
-        Coordinate v2 = new Coordinate(p2.x - p0.x, p2.y - p0.y, p2.z - p0.z);
-        Coordinate cp = crossProduct(v1, v2);
-        normalize(cp);
-        return cp;
-    }
-
-    public static void normalize(Coordinate v) {
-        double absVal = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
-        v.x /= absVal;
-        v.y /= absVal;
-        v.z /= absVal;
-    }
-
-    public static Coordinate crossProduct(Coordinate v1, Coordinate v2) {
-        double x = det(v1.y, v1.z, v2.y, v2.z);
-        double y = -det(v1.x, v1.z, v2.x, v2.z);
-        double z = det(v1.x, v1.y, v2.x, v2.y);
-        return new Coordinate(x, y, z);
-    }
-
-    public static double dotProduct(Coordinate v1, Coordinate v2) {
-        return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
-    }
-
-    public static double det(double a1, double a2, double b1, double b2) {
-        return (a1 * b2) - (a2 * b1);
-    }
-}
\ No newline at end of file
diff --git a/src/com/vividsolutions/jts/awt/GeometryCollectionShape.java b/src/com/vividsolutions/jts/awt/GeometryCollectionShape.java
index f6faa23..6247588 100644
--- a/src/com/vividsolutions/jts/awt/GeometryCollectionShape.java
+++ b/src/com/vividsolutions/jts/awt/GeometryCollectionShape.java
@@ -122,7 +122,7 @@ public class GeometryCollectionShape implements Shape {
     }
 
     public PathIterator getPathIterator(AffineTransform at, double flatness) {
-        // since Geomtery are linear, can simply delegate to the simple method
+        // since Geometry is linear, can simply delegate to the simple method
         return getPathIterator(at);
     }
 }
diff --git a/src/com/vividsolutions/jts/awt/PointShapeFactory.java b/src/com/vividsolutions/jts/awt/PointShapeFactory.java
index 23e5823..4511a1d 100644
--- a/src/com/vividsolutions/jts/awt/PointShapeFactory.java
+++ b/src/com/vividsolutions/jts/awt/PointShapeFactory.java
@@ -33,23 +33,365 @@
 package com.vividsolutions.jts.awt;
 
 import java.awt.Shape;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
 import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
 
 /**
- * An interface for classes which create {@link Shape}s to represent point geometries.
- * Java2D does not provide an actual point shape, so some other shape 
- * must be used to render points (e.g. such as a Rectangle or Ellipse).
+ * An interface for classes which create {@link Shape}s to represent 
+ * {@link Point}
+ * geometries. Java2D does not provide an actual point shape, so some other
+ * shape must be used to render points (e.g. such as a Rectangle or Ellipse).
  * 
  * @author Martin Davis
- *
+ * 
  */
-public interface PointShapeFactory 
-{
-	/**
-	 * Creates a shape representing a point.
-	 * 
-	 * @param point the location of the point
-	 * @return a shape
-	 */
-	Shape createPoint(Point2D point);
+public interface PointShapeFactory {
+  /**
+   * Creates a shape representing a {@link Point}.
+   * 
+   * @param point
+   *          the location of the point
+   * @return a shape
+   */
+  Shape createPoint(Point2D point);
+
+  public static abstract class BasePointShapeFactory implements
+      PointShapeFactory {
+    /**
+     * The default size of the shape
+     */
+    public static double DEFAULT_SIZE = 3.0;
+
+    protected double size = DEFAULT_SIZE;
+
+    /**
+     * Creates a new factory for points with default size.
+     * 
+     */
+    public BasePointShapeFactory() {
+    }
+
+    /**
+     * Creates a factory for points of given size.
+     * 
+     * @param size
+     *          the size of the points
+     */
+    public BasePointShapeFactory(double size) {
+      this.size = size;
+    }
+
+    /**
+     * Creates a shape representing a point.
+     * 
+     * @param point
+     *          the location of the point
+     * @return a shape
+     */
+    public abstract Shape createPoint(Point2D point);
+  }
+
+  public static class Point extends BasePointShapeFactory {
+    /**
+     * Creates a new factory for points with default size.
+     * 
+     */
+    public Point() {
+      super();
+    }
+
+    /**
+     * Creates a factory for points of given size.
+     * 
+     * @param size
+     *          the size of the points
+     */
+    public Point(double size) {
+      super(size);
+    }
+
+    /**
+     * Creates a shape representing a point.
+     * 
+     * @param point
+     *          the location of the point
+     * @return a shape
+     */
+    public Shape createPoint(Point2D point) {
+      Line2D.Double pointMarker =
+        new Line2D.Double(
+        	point.getX(),
+        	point.getY(),
+          point.getX(),
+          point.getY());
+      return pointMarker;
+    }
+  }
+  
+  public static class Square extends BasePointShapeFactory {
+    /**
+     * Creates a new factory for squares with default size.
+     * 
+     */
+    public Square() {
+      super();
+    }
+
+    /**
+     * Creates a factory for squares of given size.
+     * 
+     * @param size
+     *          the size of the points
+     */
+    public Square(double size) {
+      super(size);
+    }
+
+    /**
+     * Creates a shape representing a point.
+     * 
+     * @param point
+     *          the location of the point
+     * @return a shape
+     */
+    public Shape createPoint(Point2D point) {
+      Rectangle2D.Double pointMarker =
+        new Rectangle2D.Double(
+          0.0,
+          0.0,
+          size,
+          size);
+      pointMarker.x = (double) (point.getX() - (size / 2));
+      pointMarker.y = (double) (point.getY() - (size / 2));
+
+      return pointMarker;
+    }
+  }
+  
+  public static class Star extends BasePointShapeFactory {
+    /**
+     * Creates a new factory for points with default size.
+     * 
+     */
+    public Star() {
+      super();
+    }
+
+    /**
+     * Creates a factory for points of given size.
+     * 
+     * @param size
+     *          the size of the points
+     */
+    public Star(double size) {
+      super(size);
+    }
+
+    /**
+     * Creates a shape representing a point.
+     * 
+     * @param point
+     *          the location of the point
+     * @return a shape
+     */
+    public Shape createPoint(Point2D point) {
+      GeneralPath path = new GeneralPath();
+      path.moveTo((float) point.getX(), (float) (point.getY() - size/2));
+      path.lineTo((float) (point.getX() + size * 1/8), (float) (point.getY() - size * 1/8));
+      path.lineTo((float) (point.getX() + size/2), (float) (point.getY() - size * 1/8));
+      path.lineTo((float) (point.getX() + size * 2/8), (float) (point.getY() + size * 1/8));
+      path.lineTo((float) (point.getX() + size * 3/8), (float) (point.getY() + size/2));
+      path.lineTo((float) (point.getX()), (float) (point.getY() + size * 2/8));
+      path.lineTo((float) (point.getX() - size * 3/8), (float) (point.getY() + size/2));
+      path.lineTo((float) (point.getX() - size * 2/8), (float) (point.getY() + size * 1/8));
+      path.lineTo((float) (point.getX() - size/2), (float) (point.getY() - size * 1/8));
+      path.lineTo((float) (point.getX() - size * 1/8), (float) (point.getY() - size * 1/8));
+      path.closePath();
+      return path;
+    }
+  }
+  
+  public static class Triangle extends BasePointShapeFactory {
+    /**
+     * Creates a new factory for points with default size.
+     * 
+     */
+    public Triangle() {
+      super();
+    }
+
+    /**
+     * Creates a factory for points of given size.
+     * 
+     * @param size
+     *          the size of the points
+     */
+    public Triangle(double size) {
+      super(size);
+    }
+
+    /**
+     * Creates a shape representing a point.
+     * 
+     * @param point
+     *          the location of the point
+     * @return a shape
+     */
+    public Shape createPoint(Point2D point) {
+
+      GeneralPath path = new GeneralPath();
+      path.moveTo((float) (point.getX()), (float) (point.getY() - size / 2));
+      path.lineTo((float) (point.getX() + size / 2), (float) (point.getY() + size / 2));
+      path.lineTo((float) (point.getX() - size / 2), (float) (point.getY() + size / 2));
+      path.lineTo((float) (point.getX()), (float) (point.getY() - size / 2));
+
+      return path;
+    }
+
+  }
+  public static class Circle extends BasePointShapeFactory {
+    /**
+     * Creates a new factory for points with default size.
+     * 
+     */
+    public Circle() {
+      super();
+    }
+
+    /**
+     * Creates a factory for points of given size.
+     * 
+     * @param size
+     *          the size of the points
+     */
+    public Circle(double size) {
+      super(size);
+    }
+
+    /**
+     * Creates a shape representing a point.
+     * 
+     * @param point
+     *          the location of the point
+     * @return a shape
+     */
+    public Shape createPoint(Point2D point) {
+      Ellipse2D.Double pointMarker =
+        new Ellipse2D.Double(
+          0.0,
+          0.0,
+          size,
+          size);
+      pointMarker.x = (double) (point.getX() - (size / 2));
+      pointMarker.y = (double) (point.getY() - (size / 2));
+
+      return pointMarker;
+    }
+
+  }
+  public static class Cross extends BasePointShapeFactory {
+    /**
+     * Creates a new factory for points with default size.
+     * 
+     */
+    public Cross() {
+      super();
+    }
+
+    /**
+     * Creates a factory for points of given size.
+     * 
+     * @param size
+     *          the size of the points
+     */
+    public Cross(double size) {
+      super(size);
+    }
+
+    /**
+     * Creates a shape representing a point.
+     * 
+     * @param point
+     *          the location of the point
+     * @return a shape
+     */
+    public Shape createPoint(Point2D point) {
+
+      float x1 = (float) (point.getX() - size/2f);
+      float x2 = (float) (point.getX() - size/4f);
+      float x3 = (float) (point.getX() + size/4f);
+      float x4 = (float) (point.getX() + size/2f);
+
+      float y1 = (float) (point.getY() - size/2f);
+      float y2 = (float) (point.getY() - size/4f);
+      float y3 = (float) (point.getY() + size/4f);
+      float y4 = (float) (point.getY() + size/2f);
+
+  GeneralPath path = new GeneralPath();
+      path.moveTo(x2, y1);
+      path.lineTo(x3, y1);
+      path.lineTo(x3, y2);
+      path.lineTo(x4, y2);
+      path.lineTo(x4, y3);
+      path.lineTo(x3, y3);
+      path.lineTo(x3, y4);
+      path.lineTo(x2, y4);
+      path.lineTo(x2, y3);
+      path.lineTo(x1, y3);
+      path.lineTo(x1, y2);
+      path.lineTo(x2, y2);
+      path.lineTo(x2, y1);
+
+      return path;
+    }
+
+  }
+  public static class X extends BasePointShapeFactory {
+    /**
+     * Creates a new factory for points with default size.
+     * 
+     */
+    public X() {
+      super();
+    }
+
+    /**
+     * Creates a factory for points of given size.
+     * 
+     * @param size
+     *          the size of the points
+     */
+    public X(double size) {
+      super(size);
+    }
+
+    /**
+     * Creates a shape representing a point.
+     * 
+     * @param point
+     *          the location of the point
+     * @return a shape
+     */
+    public Shape createPoint(Point2D point) {
+      GeneralPath path = new GeneralPath();
+      path.moveTo((float) (point.getX()), (float) (point.getY() - size * 1/8));
+      path.lineTo((float) (point.getX() + size * 2/8), (float) (point.getY() - size/2));
+      path.lineTo((float) (point.getX() + size/2), (float) (point.getY() - size/2));
+      path.lineTo((float) (point.getX() + size * 1/8), (float) (point.getY()));
+      path.lineTo((float) (point.getX() + size/2), (float) (point.getY() + size/2));
+      path.lineTo((float) (point.getX() + size * 2/8), (float) (point.getY() + size/2));
+      path.lineTo((float) (point.getX()), (float) (point.getY() + size * 1/8));
+      path.lineTo((float) (point.getX() - size * 2/8), (float) (point.getY() + size/2));
+      path.lineTo((float) (point.getX() - size/2), (float) (point.getY() + size/2));
+      path.lineTo((float) (point.getX() - size * 1/8), (float) (point.getY()));
+      path.lineTo((float) (point.getX() - size/2), (float) (point.getY() - size/2));
+      path.lineTo((float) (point.getX() - size * 2/8), (float) (point.getY() - size/2));
+      path.closePath();
+      return path;
+    }
+
+  }
 }
diff --git a/src/com/vividsolutions/jts/awt/PolygonShape.java b/src/com/vividsolutions/jts/awt/PolygonShape.java
index 7145793..c2aaaa3 100644
--- a/src/com/vividsolutions/jts/awt/PolygonShape.java
+++ b/src/com/vividsolutions/jts/awt/PolygonShape.java
@@ -35,108 +35,128 @@ package com.vividsolutions.jts.awt;
 import java.awt.Rectangle;
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 
 import com.vividsolutions.jts.geom.Coordinate;
 
 /**
- * A Shape which represents a polygon which may contain holes.
+ * A {@link Shape} which represents a polygon which may contain holes.
  * Provided because the standard AWT Polygon class does not support holes.
  * 
  * @author Martin Davis
  *
  */
-public class PolygonShape implements Shape {
-    private java.awt.Polygon shell;
-    private ArrayList holes = new ArrayList();
-
+public class PolygonShape implements Shape 
+{
+  // use a GeneralPath with a winding rule, since it supports floating point coordinates
+    private GeneralPath polygonPath;
+    private GeneralPath ringPath;
+    
     /**
-     * Creates a new polygon shape.
+     * Creates a new polygon {@link Shape}.
      * 
      * @param shellVertices the vertices of the shell 
      * @param holeVerticesCollection a collection of Coordinate[] for each hole
      */
     public PolygonShape(Coordinate[] shellVertices,
-        Collection holeVerticesCollection) {
-        shell = toPolygon(shellVertices);
+        Collection holeVerticesCollection) 
+    {
+        polygonPath = toPath(shellVertices);
 
         for (Iterator i = holeVerticesCollection.iterator(); i.hasNext();) {
             Coordinate[] holeVertices = (Coordinate[]) i.next();
-            holes.add(toPolygon(holeVertices));
+            polygonPath.append(toPath(holeVertices), false);
         }
     }
 
-    private java.awt.Polygon toPolygon(Coordinate[] coordinates) {
-        java.awt.Polygon polygon = new java.awt.Polygon();
+    public PolygonShape() 
+    {
+    }
 
+    void addToRing(Point2D p)
+    {
+    	if (ringPath == null) {
+    		ringPath = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
+    		ringPath.moveTo((float) p.getX(), (float) p.getY());
+    	}
+    	else {
+    		ringPath.lineTo((float) p.getX(), (float) p.getY());
+    	}
+    }
+    
+    void endRing()
+    {
+    	if (polygonPath == null) {
+    		polygonPath = ringPath;
+    	}
+    	else {
+    		polygonPath.append(ringPath, false);
+    	}
+    	ringPath = null;
+    }
+    
+    /**
+     * Creates a GeneralPath representing a polygon ring 
+     * having the given coordinate sequence.
+     * Uses the GeneralPath.WIND_EVEN_ODD winding rule.
+     * 
+     * @param coordinates a coordinate sequence
+     * @return the path for the coordinate sequence
+     */
+    private GeneralPath toPath(Coordinate[] coordinates) {
+      GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, coordinates.length);
+
+      if (coordinates.length > 0) {
+        path.moveTo((float) coordinates[0].x, (float) coordinates[0].y);
         for (int i = 0; i < coordinates.length; i++) {
-            polygon.addPoint((int) coordinates[i].x, (int) coordinates[i].y);
+          path.lineTo((float) coordinates[i].x, (float) coordinates[i].y);
         }
-
-        return polygon;
-    }
+      }
+      return path;
+  }
 
     public Rectangle getBounds() {
-        /**@todo Implement this java.awt.Shape method*/
-        throw new java.lang.UnsupportedOperationException(
-            "Method getBounds() not yet implemented.");
+      return polygonPath.getBounds();
     }
 
     public Rectangle2D getBounds2D() {
-        return shell.getBounds2D();
+        return polygonPath.getBounds2D();
     }
 
     public boolean contains(double x, double y) {
-        /**@todo Implement this java.awt.Shape method*/
-        throw new java.lang.UnsupportedOperationException(
-            "Method contains() not yet implemented.");
+      return polygonPath.contains(x, y);
     }
 
     public boolean contains(Point2D p) {
-        /**@todo Implement this java.awt.Shape method*/
-        throw new java.lang.UnsupportedOperationException(
-            "Method contains() not yet implemented.");
+      return polygonPath.contains(p);
     }
 
     public boolean intersects(double x, double y, double w, double h) {
-        /**@todo Implement this java.awt.Shape method*/
-        throw new java.lang.UnsupportedOperationException(
-            "Method intersects() not yet implemented.");
+      return polygonPath.intersects(x, y, w, h);
     }
 
     public boolean intersects(Rectangle2D r) {
-        /**@todo Implement this java.awt.Shape method*/
-        throw new java.lang.UnsupportedOperationException(
-            "Method intersects() not yet implemented.");
+      return polygonPath.intersects(r);
     }
 
     public boolean contains(double x, double y, double w, double h) {
-        /**@todo Implement this java.awt.Shape method*/
-        throw new java.lang.UnsupportedOperationException(
-            "Method contains() not yet implemented.");
+      return polygonPath.contains(x, y, w, h);
     }
 
     public boolean contains(Rectangle2D r) {
-        /**@todo Implement this java.awt.Shape method*/
-        throw new java.lang.UnsupportedOperationException(
-            "Method contains() not yet implemented.");
+      return polygonPath.contains(r);
     }
 
     public PathIterator getPathIterator(AffineTransform at) {
-        ArrayList rings = new ArrayList();
-        rings.add(shell);
-        rings.addAll(holes);
-
-        return new ShapeCollectionPathIterator(rings, at);
+        return polygonPath.getPathIterator(at);
     }
 
     public PathIterator getPathIterator(AffineTransform at, double flatness) {
-      // since Geomtery are linear, can simply delegate to the simple method
-    	return getPathIterator(at);
+    	return getPathIterator(at, flatness);
     }
 }
diff --git a/src/com/vividsolutions/jts/awt/ShapeWriter.java b/src/com/vividsolutions/jts/awt/ShapeWriter.java
index 6e93394..0c9e5a8 100644
--- a/src/com/vividsolutions/jts/awt/ShapeWriter.java
+++ b/src/com/vividsolutions/jts/awt/ShapeWriter.java
@@ -53,12 +53,17 @@ public class ShapeWriter
 	/**
 	 * The point shape factory used by default.
 	 */
-	public static final PointShapeFactory DEFAULT_POINT_FACTORY = new SqarePointShapeFactory(3.0);
+	public static final PointShapeFactory DEFAULT_POINT_FACTORY = new PointShapeFactory.Square(3.0);
 	
 	private PointTransformation pointTransformer = DEFAULT_POINT_TRANSFORMATION;
 	private PointShapeFactory pointFactory = DEFAULT_POINT_FACTORY;
 
 	/**
+	 * Cache a Point2D object to use to transfer coordinates into shape
+	 */
+	private Point2D transPoint = new Point2D.Double();
+
+	/**
 	 * Creates a new ShapeWriter with a specified point transformation
 	 * and point shape factory.
 	 * 
@@ -122,6 +127,29 @@ public class ShapeWriter
 
 	private Shape toShape(Polygon p) 
 	{
+		PolygonShape poly = new PolygonShape();
+		
+		append(poly, p.getExteriorRing().getCoordinates());
+		for (int j = 0; j < p.getNumInteriorRing(); j++) {
+			append(poly, p.getInteriorRingN(j).getCoordinates());
+		}
+
+		return poly;
+	}
+
+	private void append(PolygonShape poly, Coordinate[] coords) 
+	{
+		for (int i = 0; i < coords.length; i++) {
+			transformPoint(coords[i], transPoint);
+			poly.addToRing(transPoint);
+		}
+		poly.endRing();
+	}
+	
+	/*
+	 // Obsolete (slower code)
+	private Shape OLDtoShape(Polygon p) 
+	{
 		ArrayList holeVertexCollection = new ArrayList();
 
 		for (int j = 0; j < p.getNumInteriorRing(); j++) {
@@ -134,6 +162,7 @@ public class ShapeWriter
 			holeVertexCollection);
 	}
 
+	
 	private Coordinate[] toViewCoordinates(Coordinate[] modelCoordinates)
 	{
 		Coordinate[] viewCoordinates = new Coordinate[modelCoordinates.length];
@@ -145,16 +174,16 @@ public class ShapeWriter
 
 		return viewCoordinates;
 	}
-
+*/
+	
 	private Shape toShape(GeometryCollection gc)
 	{
 		GeometryCollectionShape shape = new GeometryCollectionShape();
-
+		// add components to GC shape
 		for (int i = 0; i < gc.getNumGeometries(); i++) {
 			Geometry g = (Geometry) gc.getGeometryN(i);
 			shape.add(toShape(g));
 		}
-
 		return shape;
 	}
 
@@ -172,32 +201,35 @@ public class ShapeWriter
 	private GeneralPath toShape(LineString lineString)
 	{
 		GeneralPath shape = new GeneralPath();
-		Point2D viewPoint = toPoint(lineString.getCoordinateN(0));
-		shape.moveTo((float) viewPoint.getX(), (float) viewPoint.getY());
+		
+		transformPoint(lineString.getCoordinateN(0), transPoint);
+		shape.moveTo((float) transPoint.getX(), (float) transPoint.getY());
 
 		for (int i = 1; i < lineString.getNumPoints(); i++) {
-			viewPoint = toPoint(lineString.getCoordinateN(i));
-			shape.lineTo((float) viewPoint.getX(), (float) viewPoint.getY());
+			transformPoint(lineString.getCoordinateN(i), transPoint);
+			shape.lineTo((float) transPoint.getX(), (float) transPoint.getY());
 		}
 		return shape;
 	}
 
 	private Shape toShape(Point point)
   {
-		Point2D viewPoint = toPoint(point.getCoordinate());
+		Point2D viewPoint = transformPoint(point.getCoordinate());
 		return pointFactory.createPoint(viewPoint);
 	}
 
-  private Point2D toPoint(Coordinate model)
-    {
-    Point2D view = new Point2D.Double();
-    pointTransformer.transform(model, view);
-    /**
-     * Do the rounding now instead of relying on Java 2D rounding.
-     * Java2D seems to do rounding differently for drawing and filling, resulting in the draw
-     * being a pixel off from the fill sometimes.
-     */
-    view.setLocation(Math.round(view.getX()), Math.round(view.getY()));
-    return view;
-  }
+  private Point2D transformPoint(Coordinate model) {
+		return transformPoint(model, new Point2D.Double());
+	}
+  
+  private Point2D transformPoint(Coordinate model, Point2D view) {
+		pointTransformer.transform(model, view);
+		/**
+		 * Do the rounding now instead of relying on Java 2D rounding. Java2D seems
+		 * to do rounding differently for drawing and filling, resulting in the draw
+		 * being a pixel off from the fill sometimes.
+		 */
+		view.setLocation(Math.round(view.getX()), Math.round(view.getY()));
+		return view;
+	}
 }
diff --git a/src/com/vividsolutions/jts/awt/SqarePointShapeFactory.java b/src/com/vividsolutions/jts/awt/SqarePointShapeFactory.java
deleted file mode 100644
index 9271421..0000000
--- a/src/com/vividsolutions/jts/awt/SqarePointShapeFactory.java
+++ /dev/null
@@ -1,93 +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.jts.awt;
-
-import java.awt.Shape;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-
-/**
- * A factory for generating square shapes to represent points.
- * 
- * @author Martin Davis
- *
- */
-public class SqarePointShapeFactory 
-implements PointShapeFactory
-{
-	/**
-	 * The default length of the square's side.
-	 */
-	public static double DEFAULT_SIZE = 3.0;
-	
-	private double squareSize = DEFAULT_SIZE;
-	
-	/**
-	 * Creates a new factory for squares with default size.
-	 *
-	 */
-	public SqarePointShapeFactory()
-	{
-	}
-	
-	/**
-	 * Creates a factory for squares of given size.
-	 * 
-	 * @param squareSize the length of the side of the square
-	 */
-	public SqarePointShapeFactory(double squareSize)
-	{
-		this.squareSize = squareSize;
-	}
-	
-	/**
-	 * Creates a shape representing a point.
-	 * 
-	 * @param point the location of the point
-	 * @return a shape
-	 */
-	public Shape createPoint(Point2D point)
-	{
-		Rectangle2D.Double pointMarker =
-			new Rectangle2D.Double(
-				0.0,
-				0.0,
-				squareSize,
-				squareSize);
-		pointMarker.x = (double) (point.getX() - (squareSize / 2));
-		pointMarker.y = (double) (point.getY() - (squareSize / 2));
-
-		return pointMarker;
-
-	}
-}
diff --git a/src/com/vividsolutions/jts/densify/Densifier.java b/src/com/vividsolutions/jts/densify/Densifier.java
index 89e3f8d..38a8952 100644
--- a/src/com/vividsolutions/jts/densify/Densifier.java
+++ b/src/com/vividsolutions/jts/densify/Densifier.java
@@ -36,9 +36,10 @@ import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.geom.util.GeometryTransformer;
 
 /**
- * Densifies a geometry by inserting extra vertices along the line segments
- * in the geometry. The densified geometry contains no line segment which
- * is longer than the given distance tolerance.
+ * Densifies a {@link Geometry} by inserting extra vertices along the line segments
+ * contained in the geometry. 
+ * All segments in the created densified geometry will be no longer than
+ * than the given distance tolerance.
  * Densified polygonal geometries are guaranteed to be topologically correct.
  * The coordinates created during densification respect the input geometry's
  * {@link PrecisionModel}.
diff --git a/src/com/vividsolutions/jts/geom/Coordinate.java b/src/com/vividsolutions/jts/geom/Coordinate.java
index a0d76e8..6888eb4 100644
--- a/src/com/vividsolutions/jts/geom/Coordinate.java
+++ b/src/com/vividsolutions/jts/geom/Coordinate.java
@@ -313,7 +313,7 @@ public class Coordinate implements Comparable, Cloneable, Serializable {
      * Creates a comparator for 2 or 3 dimensional coordinates, depending
      * on the value provided.
      *
-     * @param dimensionLimit the number of dimensions to test
+     * @param dimensionsToTest the number of dimensions to test
      */
     public DimensionalComparator(int dimensionsToTest)
     {
diff --git a/src/com/vividsolutions/jts/geom/CoordinateArrays.java b/src/com/vividsolutions/jts/geom/CoordinateArrays.java
index 6be8afe..4f67692 100644
--- a/src/com/vividsolutions/jts/geom/CoordinateArrays.java
+++ b/src/com/vividsolutions/jts/geom/CoordinateArrays.java
@@ -36,6 +36,8 @@ package com.vividsolutions.jts.geom;
 
 import java.util.*;
 
+import com.vividsolutions.jts.math.MathUtil;
+
 /**
  * Useful utility functions for handling Coordinate arrays
  *
@@ -84,7 +86,7 @@ public class CoordinateArrays {
    *
    * @param pts1
    * @param pts2
-   * @return
+   * @return an integer indicating the order
    */
   public static int compare(Coordinate[] pts1, Coordinate[] pts2) {
     int i = 0;
@@ -219,7 +221,7 @@ public class CoordinateArrays {
   }
 
   /**
-   * Creates a deep copy of the argument {@link Coordinate) array.
+   * Creates a deep copy of the argument {@link Coordinate} array.
    *
    * @param coordinates an array of Coordinates
    * @return a deep copy of the input
@@ -233,7 +235,7 @@ public class CoordinateArrays {
   }
 
   /**
-   * Creates a deep copy of a given section of a source {@link Coordinate) array
+   * Creates a deep copy of a given section of a source {@link Coordinate} array
    * into a destination Coordinate array.
    * The destination array must be an appropriate size to receive
    * the copied coordinates.
@@ -403,6 +405,9 @@ public class CoordinateArrays {
    * Extracts a subsequence of the input {@link Coordinate} array
    * from indices <code>start</code> to
    * <code>end</code> (inclusive).
+   * The input indices are clamped to the array size;
+   * If the end index is less than the start index,
+   * the extracted array will be empty.
    *
    * @param pts the input array
    * @param start the index of the start of the subsequence to extract
@@ -411,8 +416,17 @@ public class CoordinateArrays {
    */
   public static Coordinate[] extract(Coordinate[] pts, int start, int end)
   {
-    int len = end - start + 1;
-    Coordinate[] extractPts = new Coordinate[len];
+    start = MathUtil.clamp(start, 0, pts.length);
+    end = MathUtil.clamp(end, -1, pts.length);
+    
+    int npts = end - start + 1;
+    if (end < 0) npts = 0;
+    if (start >= pts.length) npts = 0;
+    if (end < start) npts = 0;
+    
+    Coordinate[] extractPts = new Coordinate[npts];
+    if (npts == 0) return extractPts;
+    
     int iPts = 0;
     for (int i = start; i <= end; i++) {
       extractPts[iPts++] = pts[i];
diff --git a/src/com/vividsolutions/jts/geom/CoordinateSequence.java b/src/com/vividsolutions/jts/geom/CoordinateSequence.java
index 6e8215e..f0a4f0f 100644
--- a/src/com/vividsolutions/jts/geom/CoordinateSequence.java
+++ b/src/com/vividsolutions/jts/geom/CoordinateSequence.java
@@ -35,23 +35,28 @@ package com.vividsolutions.jts.geom;
 /**
  * The internal representation of a list of coordinates inside a Geometry.
  * <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
- * that supports extra attributes like M-values.
+ * This allows Geometries to store their
+ * points using something other than the JTS {@link Coordinate} class. 
+ * For example, a storage-efficient implementation
+ * might store coordinate sequences as an array of x's
+ * and an array of y's. 
+ * Or a custom coordinate class might support extra attributes like M-values.
  * <p>
- * You can do this by implementing the CoordinateSequence and
- * CoordinateSequenceFactory interfaces. You would then create a
- * GeometryFactory parameterized by your CoordinateSequenceFactory, and use
- * this GeometryFactory to create new Geometries. All of these new Geometries
- * will use your CoordinateSequence implementation.
+ * Implementing a custom coordinate storage structure
+ * requires implementing the {@link CoordinateSequence} and
+ * {@link CoordinateSequenceFactory} interfaces. 
+ * To use the custom CoordinateSequence, create a
+ * new {@link GeometryFactory} parameterized by the CoordinateSequenceFactory
+ * The {@link GeometryFactory} can then be used to create new {@link Geometry}s.
+ * The new Geometries
+ * will use the custom CoordinateSequence implementation.
  * <p>
  * For an example, see the code for
- * {@link com.vividsolutions.jtsexample.geom.TwoArrayCoordinateSequenceExample}.
+ * {@link ExtendedCoordinateExample}.
  *
- * @see DefaultCoordinateSequenceFactory
- * @see TwoArrayCoordinateSequenceFactory
+ * @see CoordinateArraySequenceFactory
+ * @see PackedCoordinateSequenceFactory
+ * @see ExtendedCoordinateExample
  *
  * @version 1.7
  */
diff --git a/src/com/vividsolutions/jts/geom/CoordinateSequences.java b/src/com/vividsolutions/jts/geom/CoordinateSequences.java
index 7417184..8056f80 100644
--- a/src/com/vividsolutions/jts/geom/CoordinateSequences.java
+++ b/src/com/vividsolutions/jts/geom/CoordinateSequences.java
@@ -102,4 +102,65 @@ public class CoordinateSequences {
 			dest.setOrdinate(destPos, dim, src.getOrdinate(srcPos, dim));
 		}
   }
+  
+  /**
+   * Tests whether a {@link CoordinateSequence} forms a valid {@link LinearRing},
+   * by checking the sequence length and closure
+   * (whether the first and last points are identical in 2D). 
+   * Self-intersection is not checked.
+   * 
+   * @param seq the sequence to test
+   * @return true if the sequence is a ring
+   * @see LinearRing
+   */
+  public static boolean isRing(CoordinateSequence seq) 
+  {
+  	int n = seq.size();
+  	if (n == 0) return true;
+  	// too few points
+  	if (n <= 3) 
+  		return false;
+  	// test if closed
+  	return seq.getOrdinate(0, CoordinateSequence.X) == seq.getOrdinate(n-1, CoordinateSequence.X)
+  		&& seq.getOrdinate(0, CoordinateSequence.Y) == seq.getOrdinate(n-1, CoordinateSequence.Y);
+  }
+  
+  /**
+   * Ensures that a CoordinateSequence forms a valid ring, 
+   * returning a new closed sequence of the correct length if required.
+   * If the input sequence is already a valid ring, it is returned 
+   * without modification.
+   * If the input sequence is too short or is not closed, 
+   * it is extended with one or more copies of the start point.
+   * 
+   * @param fact the CoordinateSequenceFactory to use to create the new sequence
+   * @param seq the sequence to test
+   * @return the original sequence, if it was a valid ring, or a new sequence which is valid.
+   */
+  public static CoordinateSequence ensureValidRing(CoordinateSequenceFactory fact, CoordinateSequence seq)
+  {
+  	int n = seq.size();
+  	if (n == 0) return seq; 
+  	// too short - make a new one
+  	if (n <= 3) 
+  		return createClosedRing(fact, seq, 4);
+  	
+  	boolean isClosed = seq.getOrdinate(0, CoordinateSequence.X) == seq.getOrdinate(n-1, CoordinateSequence.X)
+		&& seq.getOrdinate(0, CoordinateSequence.Y) == seq.getOrdinate(n-1, CoordinateSequence.Y);
+  	if (isClosed) return seq;
+  	// make a new closed ring
+  	return createClosedRing(fact, seq, n+1);
+  }
+  
+  private static CoordinateSequence createClosedRing(CoordinateSequenceFactory fact, CoordinateSequence seq, int size)
+  {
+  	CoordinateSequence newseq = fact.create(size, seq.getDimension());
+  	int n = seq.size();
+  	copy(seq, 0, newseq, 0, n);
+  	// fill remaining coordinates with start point
+  	for (int i = n; i < size; i++)
+  		copy(seq, 0, newseq, i, 1);
+  	return newseq;
+  }
+  
 }
\ No newline at end of file
diff --git a/src/com/vividsolutions/jts/geom/Envelope.java b/src/com/vividsolutions/jts/geom/Envelope.java
index fb31e5f..0a67a6f 100644
--- a/src/com/vividsolutions/jts/geom/Envelope.java
+++ b/src/com/vividsolutions/jts/geom/Envelope.java
@@ -169,7 +169,7 @@ public class Envelope
   /**
    *  Creates an <code>Envelope</code> for a region defined by a single Coordinate.
    *
-   *@param  p1  the Coordinate
+   *@param  p  the Coordinate
    */
   public Envelope(Coordinate p)
   {
@@ -236,8 +236,7 @@ public class Envelope
   /**
    *  Initialize an <code>Envelope</code> to a region defined by a single Coordinate.
    *
-   *@param  p1  the first Coordinate
-   *@param  p2  the second Coordinate
+   *@param  p  the coordinate
    */
   public void init(Coordinate p)
   {
@@ -356,12 +355,39 @@ public class Envelope
   }
   
   /**
+   * Gets the minimum extent of this envelope across both dimensions.
+   * 
+   * @return the minimum extent of this envelope
+   */
+	public double minExtent()
+	{
+		if (isNull()) return 0.0;
+		double w = getWidth();
+		double h = getHeight();
+		if (w < h) return w;
+		return h;
+	}
+	
+  /**
+   * Gets the maximum extent of this envelope across both dimensions.
+   * 
+   * @return the maximum extent of this envelope
+   */
+	public double maxExtent()
+	{
+		if (isNull()) return 0.0;
+		double w = getWidth();
+		double h = getHeight();
+		if (w > h) return w;
+		return h;
+	}
+  
+  /**
    *  Enlarges this <code>Envelope</code> so that it contains
    *  the given {@link Coordinate}. 
    *  Has no effect if the point is already on or within the envelope.
    *
    *@param  p  the Coordinate to expand to include
-   *@param  y  the value to lower the minimum y to or to raise the maximum y to
    */
   public void expandToInclude(Coordinate p)
   {
@@ -373,7 +399,6 @@ public class Envelope
    * Both positive and negative distances are supported.
    *
    * @param distance the distance to expand the envelope
-   * @return this envelope
    */
   public void expandBy(double distance)
   {
@@ -494,7 +519,7 @@ public class Envelope
   }
 
   /**
-   * Computes the intersection of two {@link Envelopes}
+   * Computes the intersection of two {@link Envelope}s.
    *
    * @param env the envelope to intersect with
    * @return a new Envelope representing the intersection of the envelopes (this will be
@@ -541,7 +566,7 @@ public class Envelope
    *  Check if the point <code>p</code>
    *  overlaps (lies inside) the region of this <code>Envelope</code>.
    *
-   *@param  other  the <code>Coordinate</code> to be tested
+   *@param  p  the <code>Coordinate</code> to be tested
    *@return        <code>true</code> if the point overlaps this <code>Envelope</code>
    */
   public boolean intersects(Coordinate p) {
@@ -585,7 +610,7 @@ public class Envelope
    *@param  other the <code>Envelope</code> to check
    *@return true if <code>other</code> is contained in this <code>Envelope</code>
    *
-   *@see covers(Envelope)
+   *@see #covers(Envelope)
    */
   public boolean contains(Envelope other) {
   	return covers(other);
@@ -602,7 +627,7 @@ public class Envelope
    *@return    <code>true</code> if the point lies in the interior or
    *      on the boundary of this <code>Envelope</code>.
    *      
-   *@see covers(Coordinate)
+   *@see #covers(Coordinate)
    */
   public boolean contains(Coordinate p) {
     return covers(p);
@@ -621,7 +646,7 @@ public class Envelope
    *@return    <code>true</code> if <code>(x, y)</code> lies in the interior or
    *      on the boundary of this <code>Envelope</code>.
    *      
-   *@see covers(double, double)
+   *@see #covers(double, double)
    */
   public boolean contains(double x, double y) {
   	return covers(x, y);
@@ -681,12 +706,17 @@ public class Envelope
   public double distance(Envelope env)
   {
     if (intersects(env)) return 0;
+    
     double dx = 0.0;
-    if (maxx < env.minx) dx = env.minx - maxx;
-    if (minx > env.maxx) dx = minx - env.maxx;
+    if (maxx < env.minx) 
+      dx = env.minx - maxx;
+    else if (minx > env.maxx) 
+      dx = minx - env.maxx;
+    
     double dy = 0.0;
-    if (maxy < env.miny) dy = env.miny - maxy;
-    if (miny > env.maxy) dy = miny - env.maxy;
+    if (maxy < env.miny) 
+      dy = env.miny - maxy;
+    else if (miny > env.maxy) dy = miny - env.maxy;
 
     // if either is zero, the envelopes overlap either vertically or horizontally
     if (dx == 0.0) return dy;
diff --git a/src/com/vividsolutions/jts/geom/Geometry.java b/src/com/vividsolutions/jts/geom/Geometry.java
index 36eb327..bab0eff 100644
--- a/src/com/vividsolutions/jts/geom/Geometry.java
+++ b/src/com/vividsolutions/jts/geom/Geometry.java
@@ -41,6 +41,7 @@ import com.vividsolutions.jts.io.WKTWriter;
 import com.vividsolutions.jts.operation.*;
 import com.vividsolutions.jts.operation.buffer.BufferOp;
 import com.vividsolutions.jts.operation.distance.DistanceOp;
+import com.vividsolutions.jts.operation.linemerge.LineMerger;
 import com.vividsolutions.jts.operation.overlay.OverlayOp;
 import com.vividsolutions.jts.operation.union.UnaryUnionOp;
 import com.vividsolutions.jts.operation.overlay.snap.SnapIfNeededOverlayOp;
@@ -51,7 +52,7 @@ import com.vividsolutions.jts.operation.valid.IsValidOp;
 import com.vividsolutions.jts.util.Assert;
 
 /**
- * The base class for all geometric objects.
+ * A representation of a planar, linear vector geometry.
  * <P>
  *
  *  <H3>Binary Predicates</H3>
@@ -62,9 +63,9 @@ import com.vividsolutions.jts.util.Assert;
  *  predicates (other than <code>convexHull</code>) or the <code>relate</code>
  *  method.
  *
- *  <H3>Set-Theoretic Methods</H3>
+ *  <H3>Overlay Methods</H3>
  *
- *  The spatial analysis methods will
+ *  The overlay methods 
  *  return the most specific class possible to represent the result. If the
  *  result is homogeneous, a <code>Point</code>, <code>LineString</code>, or
  *  <code>Polygon</code> will be returned if the result contains a single
@@ -123,9 +124,49 @@ import com.vividsolutions.jts.util.Assert;
  *  analysis methods, it will throw an exception. If possible the exception will
  *  report the location of the collapse. <P>
  *
- *  #equals(Object) and #hashCode are not overridden, so that when two
- *  topologically equal Geometries are added to HashMaps and HashSets, they
- *  remain distinct. This behaviour is desired in many cases.
+ * <h3>Geometry Equality</h3>
+ * 
+ * JTS provides two ways of comparing geometries for equality: 
+ * <b>structural equality</b> and <b>topological equality</b>.
+ * 
+ * <h4>Structural Equality</h4>
+ *
+ * Structural Equality is provided by the 
+ * {@link #equalsExact(Geometry)} method.  
+ * This implements a comparison based on exact, structural pointwise
+ * equality. 
+ * The {@link #equals(Object)} is a synonym for this method, 
+ * to provide structural equality semantics for
+ * use in Java collections.
+ * It is important to note that structural pointwise equality
+ * is easily affected by things like
+ * ring order and component order.  In many situations
+ * it will be desirable to normalize geometries before
+ * comparing them (using the {@link #norm()} 
+ * or {@link #normalize()} methods).
+ * {@link #equalsNorm(Geometry)} is provided
+ * as a convenience method to compute equality over
+ * normalized geometries, but it is expensive to use.
+ * Finally, {@link #equalsExact(Geometry, double)}
+ * allows using a tolerance value for point comparison.
+ * 
+ * 
+ * <h4>Topological Equality</h4>
+ * 
+ * Topological Equality 
+ * implements the SFS definition of point-set equality
+ * defined in terms of the DE-9IM matrix.
+ * It is is provided by the 
+ * {@link #equalsTopo(Geometry)}
+ * method.  
+ * To support the SFS naming convention, the method
+ *  {@link #equals(Geometry)} is also provided as a synonym.  
+ *  However, due to the potential for confusion with {@link #equals(Geometry)}
+ *  its use is discouraged.
+ * <p>
+ *  Since #equals(Object) and #hashCode are overridden, 
+ *  Geometries can be used effectively in 
+ *  Java collections.
  *
  *@version 1.7
  */
@@ -339,7 +380,7 @@ public abstract class Geometry
    *  {@link #geometryChanged} must be called afterwards.
    *
    *@return    the vertices of this <code>Geometry</code>
-   *@see geometryChanged
+   *@see #geometryChanged
    *@see CoordinateSequence#setOrdinate
    */
   public abstract Coordinate[] getCoordinates();
@@ -393,8 +434,7 @@ public abstract class Geometry
    */
   public boolean isValid()
   {
-    IsValidOp isValidOp = new IsValidOp(this);
-    return isValidOp.isValid();
+  	return IsValidOp.isValid(this);
   }
 
   /**
@@ -623,15 +663,15 @@ public abstract class Geometry
   }
 
   /**
-   * Tests whether this geometry is disjoint from the specified geometry.
+   * Tests whether this geometry is disjoint from the argument geometry.
    * <p>
    * The <code>disjoint</code> predicate has the following equivalent definitions:
    * <ul>
    * <li>The two geometries have no point in common
    * <li>The DE-9IM Intersection Matrix for the two geometries matches 
    * <code>[FF*FF****]</code>
-   * <li><code>! g.intersects(this)</code>
-   * (<code>disjoint</code> is the inverse of <code>intersects</code>)
+   * <li><code>! g.intersects(this) = true</code>
+   * <br>(<code>disjoint</code> is the inverse of <code>intersects</code>)
    * </ul>
    *
    *@param  g  the <code>Geometry</code> with which to compare this <code>Geometry</code>
@@ -646,15 +686,21 @@ public abstract class Geometry
 
   /**
    * Tests whether this geometry touches the
-   * specified geometry.
+   * argument geometry.
    * <p>
    * The <code>touches</code> predicate has the following equivalent definitions:
    * <ul>
    * <li>The geometries have at least one point in common, but their interiors do not intersect.
    * <li>The DE-9IM Intersection Matrix for the two geometries matches
-   *   <code>[FT*******]</code> or <code>[F**T*****]</code> or <code>[F***T****]</code>
+   * at least one of the following patterns
+   *  <ul>
+   *   <li><code>[FT*******]</code>
+   *   <li><code>[F**T*****]</code>
+   *   <li><code>[F***T****]</code>
+   *  </ul>
    * </ul>
-   * If both geometries have dimension 0, this predicate returns <code>false</code>
+   * If both geometries have dimension 0, this predicate returns <code>false</code>.
+   * 
    *
    *@param  g  the <code>Geometry</code> with which to compare this <code>Geometry</code>
    *@return        <code>true</code> if the two <code>Geometry</code>s touch;
@@ -668,18 +714,21 @@ public abstract class Geometry
   }
 
   /**
-   * Tests whether this geometry intersects the specified geometry.
+   * Tests whether this geometry intersects the argument geometry.
    * <p>
    * The <code>intersects</code> predicate has the following equivalent definitions:
    * <ul>
    * <li>The two geometries have at least one point in common
    * <li>The DE-9IM Intersection Matrix for the two geometries matches
-   *    <code>[T********]</code>
-   * or <code>[*T*******]</code>
-   * or <code>[***T*****]</code>
-   * or <code>[****T****]</code>
-   * <li><code>! g.disjoint(this)</code>
-   * (<code>intersects</code> is the inverse of <code>disjoint</code>)
+   * at least one of the patterns
+   *  <ul>
+   *   <li><code>[T********]</code>
+   *   <li><code>[*T*******]</code>
+   *   <li><code>[***T*****]</code>
+   *   <li><code>[****T****]</code>
+   *  </ul>
+   * <li><code>! g.disjoint(this) = true</code>
+   * <br>(<code>intersects</code> is the inverse of <code>disjoint</code>)
    * </ul>
    *
    *@param  g  the <code>Geometry</code> with which to compare this <code>Geometry</code>
@@ -722,12 +771,13 @@ public abstract class Geometry
 
   /**
    * Tests whether this geometry crosses the
-   * specified geometry.
+   * argument geometry.
    * <p>
    * The <code>crosses</code> predicate has the following equivalent definitions:
    * <ul>
    * <li>The geometries have some but not all interior points in common.
    * <li>The DE-9IM Intersection Matrix for the two geometries matches
+   * one of the following patterns:
    *   <ul>
    *    <li><code>[T*T******]</code> (for P/L, P/A, and L/A situations)
    *    <li><code>[T*****T**]</code> (for L/P, A/P, and A/L situations)
@@ -737,8 +787,8 @@ public abstract class Geometry
    * For any other combination of dimensions this predicate returns <code>false</code>.
    * <p>
    * The SFS defined this predicate only for P/L, P/A, L/L, and L/A situations.
-   * JTS extends the definition to apply to L/P, A/P and A/L situations as well,
-   * in order to make the relation symmetric.
+   * In order to make the relation symmetric,
+   * JTS extends the definition to apply to L/P, A/P and A/L situations as well.
    *
    *@param  g  the <code>Geometry</code> with which to compare this <code>Geometry</code>
    *@return        <code>true</code> if the two <code>Geometry</code>s cross.
@@ -760,19 +810,23 @@ public abstract class Geometry
    * and the interiors of the two geometries have at least one point in common.
    * <li>The DE-9IM Intersection Matrix for the two geometries matches 
    * <code>[T*F**F***]</code>
-   * <li><code>g.contains(this)</code>
-   * (<code>within</code> is the converse of <code>contains</code>)
+   * <li><code>g.contains(this) = true</code>
+   * <br>(<code>within</code> is the converse of {@link #contains})
    * </ul>
    * An implication of the definition is that
    * "The boundary of a Geometry is not within the Geometry".
    * In other words, if a geometry A is a subset of
    * the points in the boundary of a geomtry B, <code>A.within(B) = false</code>
+   * (As a concrete example, take A to be a LineString which lies in the boundary of a Polygon B.)
+   * For a predicate with similar behaviour but avoiding 
+   * this subtle limitation, see {@link #coveredBy}.
    *
    *@param  g  the <code>Geometry</code> with which to compare this <code>Geometry</code>
    *@return        <code>true</code> if this <code>Geometry</code> is within
-   *      <code>other</code>
+   *      <code>g</code>
    *
    * @see Geometry#contains
+   * @see Geometry#coveredBy
    */
   public boolean within(Geometry g) {
     return g.contains(this);
@@ -780,25 +834,30 @@ public abstract class Geometry
 
   /**
    * Tests whether this geometry contains the
-   * specified geometry.
+   * argument geometry.
    * <p>
    * The <code>contains</code> predicate has the following equivalent definitions:
    * <ul>
    * <li>Every point of the other geometry is a point of this geometry,
    * and the interiors of the two geometries have at least one point in common.
    * <li>The DE-9IM Intersection Matrix for the two geometries matches 
+   * the pattern
    * <code>[T*****FF*]</code>
-   * <li><code>g.within(this)</code>
-   * (<code>contains</code> is the converse of <code>within</code>)
+   * <li><code>g.within(this) = true</code>
+   * <br>(<code>contains</code> is the converse of {@link #within} )
    * </ul>
    * An implication of the definition is that "Geometries do not
    * contain their boundary".  In other words, if a geometry A is a subset of
-   * the points in the boundary of a geometry B, <code>B.contains(A) = false</code>
+   * the points in the boundary of a geometry B, <code>B.contains(A) = false</code>.
+   * (As a concrete example, take A to be a LineString which lies in the boundary of a Polygon B.)
+   * For a predicate with similar behaviour but avoiding 
+   * this subtle limitation, see {@link #covers}.
    *
    *@param  g  the <code>Geometry</code> with which to compare this <code>Geometry</code>
    *@return        <code>true</code> if this <code>Geometry</code> contains <code>g</code>
    *
    * @see Geometry#within
+   * @see Geometry#covers
    */
   public boolean contains(Geometry g) {
     // short-circuit test
@@ -841,18 +900,21 @@ public abstract class Geometry
 
   /**
    * Tests whether this geometry covers the
-   * specified geometry.
+   * argument geometry.
    * <p>
    * The <code>covers</code> predicate has the following equivalent definitions:
    * <ul>
    * <li>Every point of the other geometry is a point of this geometry.
    * <li>The DE-9IM Intersection Matrix for the two geometries matches
-   *    <code>[T*****FF*]</code>
-   * or <code>[*T****FF*]</code>
-   * or <code>[***T**FF*]</code>
-   * or <code>[****T*FF*]</code>
-   * <li><code>g.coveredBy(this)</code>
-   * (<code>covers</code> is the converse of <code>coveredBy</code>)
+   * at least one of the following patterns:
+   *  <ul> 
+   *   <li><code>[T*****FF*]</code>
+   *   <li><code>[*T****FF*]</code>
+   *   <li><code>[***T**FF*]</code>
+   *   <li><code>[****T*FF*]</code>
+   *  </ul>
+   * <li><code>g.coveredBy(this) = true</code>
+   * <br>(<code>covers</code> is the converse of {@link #coveredBy})
    * </ul>
    * If either geometry is empty, the value of this predicate is <tt>false</tt>.
    * <p>
@@ -884,18 +946,21 @@ public abstract class Geometry
 
   /**
    * Tests whether this geometry is covered by the
-   * specified geometry.
+   * argument geometry.
    * <p>
    * The <code>coveredBy</code> predicate has the following equivalent definitions:
    * <ul>
    * <li>Every point of this geometry is a point of the other geometry.
    * <li>The DE-9IM Intersection Matrix for the two geometries matches
-   *    <code>[T*F**F***]</code>
-   * or <code>[*TF**F***]</code>
-   * or <code>[**FT*F***]</code>
-   * or <code>[**F*TF***]</code>
-   * <li><code>g.covers(this)</code>
-   * (<code>coveredBy</code> is the converse of <code>covers</code>)
+   * at least one of the following patterns:
+   *  <ul>
+   *   <li><code>[T*F**F***]</code>
+   *   <li><code>[*TF**F***]</code>
+   *   <li><code>[**FT*F***]</code>
+   *   <li><code>[**F*TF***]</code>
+   *  </ul>
+   * <li><code>g.covers(this) = true</code>
+   * <br>(<code>coveredBy</code> is the converse of {@link #covers})
    * </ul>
    * If either geometry is empty, the value of this predicate is <tt>false</tt>.
    * <p>
@@ -927,7 +992,7 @@ public abstract class Geometry
    *  For more information on the DE-9IM, see the <i>OpenGIS Simple Features
    *  Specification</i>.
    *
-   *@param  other                the <code>Geometry</code> with which to compare
+   *@param  g                the <code>Geometry</code> with which to compare
    *      this <code>Geometry</code>
    *@param  intersectionPattern  the pattern against which to check the
    *      intersection matrix for the two <code>Geometry</code>s
@@ -942,7 +1007,7 @@ public abstract class Geometry
   /**
    *  Returns the DE-9IM {@link IntersectionMatrix} for the two <code>Geometry</code>s.
    *
-   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
+   *@param  g  the <code>Geometry</code> with which to compare this <code>Geometry</code>
    *@return        an {@link IntersectionMatrix} describing the intersections of the interiors,
    *      boundaries and exteriors of the two <code>Geometry</code>s
    */
@@ -953,28 +1018,99 @@ public abstract class Geometry
   }
 
   /**
-   * Tests whether this geometry is equal to the
-   * specified geometry.
+  * Tests whether this geometry is 
+  * topologically equal to the argument geometry.
+   * <p>
+   * This method is included for backward compatibility reasons.
+   * It has been superseded by the {@link #equalsTopo(Geometry)} method,
+   * which has been named to clearly denote its functionality.
    * <p>
-   * The <code>equals</code> predicate has the following equivalent definitions:
+   * This method should NOT be confused with the method 
+   * {@link #equals(Object)}, which implements 
+   * an exact equality comparison.
+   *
+   *@param  g  the <code>Geometry</code> with which to compare this <code>Geometry</code>
+   *@return true if the two <code>Geometry</code>s are topologically equal
+   *
+   *@see #equalsTopo(Geometry)
+   */
+  public boolean equals(Geometry g) {
+    return equalsTopo(g);
+  }
+
+  /**
+   * Tests whether this geometry is topologically equal to the argument geometry
+   * as defined by the SFS <tt>equals</tt> predicate.
+   * <p>
+   * The SFS <code>equals</code> predicate has the following equivalent definitions:
    * <ul>
    * <li>The two geometries have at least one point in common,
    * and no point of either geometry lies in the exterior of the other geometry.
-   * <li>The DE-9IM Intersection Matrix for the two geometries is T*F**FFF*
+   * <li>The DE-9IM Intersection Matrix for the two geometries matches
+   * the pattern <tt>T*F**FFF*</tt> 
+   * <pre>
+   * T*F
+   * **F
+   * FF*
+   * </pre>
    * </ul>
-   * <b>Note</b> that this method computes topologically equality, not structural or
-   * vertex-wise equality.
+   * <b>Note</b> that this method computes <b>topologically equality</b>. 
+   * For structural equality, see {@link #equalsExact(Geometry)}.
    *
-   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
-   *@return        <code>true</code> if the two <code>Geometry</code>s are equal
+   *@param g the <code>Geometry</code> with which to compare this <code>Geometry</code>
+   *@return <code>true</code> if the two <code>Geometry</code>s are topologically equal
+   *
+   *@see #equalsExact(Geometry) 
    */
-  public boolean equals(Geometry g) {
+  public boolean equalsTopo(Geometry g)
+  {
     // short-circuit test
     if (! getEnvelopeInternal().equals(g.getEnvelopeInternal()))
       return false;
     return relate(g).isEquals(getDimension(), g.getDimension());
   }
-
+  
+  /**
+   * Tests whether this geometry is structurally and numerically equal
+   * to a given <tt>Object</tt>.
+   * If the argument <tt>Object</tt> is not a <tt>Geometry</tt>, 
+   * the result is <tt>false</tt>.
+   * Otherwise, the result is computed using
+   * {@link #equalsExact(Geometry)}.
+   * <p>
+   * This method is provided to fulfill the Java contract
+   * for value-based object equality. 
+   * In conjunction with {@link #hashCode()} 
+   * it provides semantics which are most useful 
+   * for using
+   * <tt>Geometry</tt>s as keys and values in Java collections.
+   * <p>
+   * Note that to produce the expected result the input geometries
+   * should be in normal form.  It is the caller's 
+   * responsibility to perform this where required
+   * (using {@link Geometry#norm()
+   * or {@link #normalize()} as appropriate).
+   * 
+   * @param o the Object to compare
+   * @return true if this geometry is exactly equal to the argument 
+   * 
+   * @see #equalsExact(Geometry)
+   * @see #hashCode()
+   * @see #norm()
+   * @see #normalize()
+   */
+  public boolean equals(Object o)
+  {
+    if (! (o instanceof Geometry)) return false;
+    Geometry g = (Geometry) o;
+    return equalsExact(g);
+  }
+  
+  public int hashCode()
+  {
+    return getEnvelopeInternal().hashCode();
+  }
+  
   public String toString() {
     return toText();
   }
@@ -1137,15 +1273,21 @@ public abstract class Geometry
   /**
    * Computes a <code>Geometry</code> representing the points shared by this
    * <code>Geometry</code> and <code>other</code>.
-   * {@link GeometryCollection}s support intersection with 
-   * homogeneous collection types, with the semantics that
-   * the result is a {@link GeometryCollection} of the
+   * <p>
+   * Intersection of {@link GeometryCollection}s is supported
+   * only for homogeneous collection types.
+   * The result is a {@link GeometryCollection} of the
    * intersection of each element of the target with the argument. 
+   * <p>
+   * The intersection of two geometries of different dimension produces a result
+   * geometry of dimension equal to the minimum dimension of the input
+   * geometries. The result geometry is always a homogeneous
+   * {@link GeometryCollection}.
    *
    * @param  other the <code>Geometry</code> with which to compute the intersection
-   * @return the points common to the two <code>Geometry</code>s
+   * @return the point-set common to the two <code>Geometry</code>s
    * @throws TopologyException if a robustness error occurs
-   * @throws IllegalArgumentException if the argument is a non-empty GeometryCollection
+   * @throws IllegalArgumentException if the argument is a non-empty heterogeneous GeometryCollection
    */
   public Geometry intersection(Geometry other)
   {
@@ -1176,14 +1318,35 @@ public abstract class Geometry
   }
 
   /**
-   *  Computes a <code>Geometry</code> representing all the points in this <code>Geometry</code>
-   *  and <code>other</code>.
-   *
-   *@param  other  the <code>Geometry</code> with which to compute the union
-   *@return        a set combining the points of this <code>Geometry</code> and
-   *      the points of <code>other</code>
-   * @throws TopologyException if a robustness error occurs
-   * @throws IllegalArgumentException if either input is a non-empty GeometryCollection
+   * Computes a <tt>Geometry</tt> representing all the points in this
+   * <tt>Geometry</tt> and <tt>other</tt>.
+   * <p>
+   * The method may be used on arguments of different dimension, but it does not
+   * support {@link GeometryCollection} arguments.
+   * <p>
+   * The union of two geometries of different dimension produces a result
+   * geometry of dimension equal to the maximum dimension of the input
+   * geometries. The result geometry may be a heterogenous
+   * {@link GeometryCollection}.
+   * <p>
+   * Unioning {@link LineString}s has the effect of
+   * <b>noding</b> and <b>dissolving</b> the input linework. In this context
+   * "noding" means that there will be a node or endpoint in the result for
+   * every endpoint or line segment crossing in the input. "Dissolving" means
+   * that any duplicate (i.e. coincident) line segments or portions of line
+   * segments will be reduced to a single line segment in the result. 
+   * If <b>merged</b> linework is required, the {@link LineMerger}
+   * class can be used.
+   * 
+   * @param other
+   *          the <code>Geometry</code> with which to compute the union
+   * @return a point-set combining the points of this <code>Geometry</code> and the
+   *         points of <code>other</code>
+   * @throws TopologyException
+   *           if a robustness error occurs
+   * @throws IllegalArgumentException
+   *           if either input is a non-empty GeometryCollection
+   * @see LineMerger
    */
   public Geometry union(Geometry other)
   {
@@ -1249,19 +1412,22 @@ public abstract class Geometry
   }
 
 	/**
-	 * Computes the union of all the elements of this geometry. Heterogeneous
-	 * {@link GeometryCollection}s are fully supported.
+	 * Computes the union of all the elements of this geometry. 
+	 * <p>
+	 * <tt>union()</tt> supports
+	 * {@link GeometryCollection}s 
+	 * (which the other overlay operations currently do not).
 	 * <p>
 	 * The result obeys the following contract:
 	 * <ul>
 	 * <li>Unioning a set of {@link LineString}s has the effect of fully noding
 	 * and dissolving the linework.
 	 * <li>Unioning a set of {@link Polygon}s will always 
-	 * return a {@link Polygonal} geometry (unlike {link #union(Geometry)},
+	 * return a {@link Polygonal} geometry (unlike {@link #union(Geometry)},
 	 * which may return geometrys of lower dimension if a topology collapse occurred.
 	 * </ul>
 	 * 
-	 * @return
+	 * @return the union geometry
 	 * 
 	 * @see UnaryUnionOp
 	 */
@@ -1275,44 +1441,81 @@ public abstract class Geometry
    * Two Geometries are exactly equal within a distance tolerance
    * if and only if:
    * <ul>
-   * <li>they have the same class
+   * <li>they have the same structure
    * <li>they have the same values for their vertices,
    * within the given tolerance distance, in exactly the same order.
    * </ul>
-   * If this and the other <code>Geometry</code>s are
-   * composites and any children are not <code>Geometry</code>s, returns
-   * <code>false</code>.
+   * This method does <i>not</i>
+   * test the values of the <tt>GeometryFactory</tt>, the <tt>SRID</tt>, 
+   * or the <tt>userData</tt> fields.
+   * <p>
+   * To properly test equality between different geometries,
+   * it is usually necessary to {@link #normalize()} them first.
    *
-   * @param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
-   * @parm tolerance distance at or below which two <code>Coordinate</code>s
+   * @param other the <code>Geometry</code> with which to compare this <code>Geometry</code>
+   * @param tolerance distance at or below which two <code>Coordinate</code>s
    *   are considered equal
    * @return <code>true</code> if this and the other <code>Geometry</code>
-   *   are of the same class and have equal internal data.
+   *   have identical structure and point values, up to the distance tolerance.
+   *   
+   * @see #equalsExact(Geometry)
+   * @see #normalize()
+   * @see #norm()
    */
   public abstract boolean equalsExact(Geometry other, double tolerance);
 
   /**
-   *  Returns true if the two <code>Geometry</code>s are exactly equal.
+   * Returns true if the two <code>Geometry</code>s are exactly equal.
    * Two Geometries are exactly equal iff:
    * <ul>
-   * <li>they have the same class
-   * <li>they have the same values of Coordinates in their internal
-   * Coordinate lists, in exactly the same order.
+   * <li>they have the same structure
+   * <li>they have the same values for their vertices,
+   * in exactly the same order.
    * </ul>
-   * If this and the other <code>Geometry</code>s are
-   *  composites and any children are not <code>Geometry</code>s, returns
-   *  false.
+   * This provides a stricter test of equality than
+   * {@link #equalsTopo(Geometry)}, which is more useful
+   * in certain situations
+   * (such as using geometries as keys in collections).
+   * <p>
+   * This method does <i>not</i>
+   * test the values of the <tt>GeometryFactory</tt>, the <tt>SRID</tt>, 
+   * or the <tt>userData</tt> fields.
    * <p>
-   *  This provides a stricter test of equality than
-   *  <code>equals</code>.
+   * To properly test equality between different geometries,
+   * it is usually necessary to {@link #normalize()} them first.
    *
    *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
-   *@return        <code>true</code> if this and the other <code>Geometry</code>
-   *      are of the same class and have equal internal data.
+   *@return <code>true</code> if this and the other <code>Geometry</code>
+   *      have identical structure and point values.
+   *      
+   * @see #equalsExact(Geometry, double)
+   * @see #normalize()
+   * @see #norm()
    */
   public boolean equalsExact(Geometry other) { return equalsExact(other, 0); }
 
   /**
+   * Tests whether two geometries are exactly equal
+   * in their normalized forms.
+   * This is a convenience method which creates normalized
+   * versions of both geometries before computing
+   * {@link #equalsExact(Geometry)}.
+   * This method is relatively expensive to compute.  
+   * For maximum performance, the client 
+   * should instead perform normalization itself
+   * at an appropriate point during execution.
+   * 
+   * @param g a Geometry
+   * @return true if the input geometries are exactly equal in their normalized form
+   */
+  public boolean equalsNorm(Geometry g)
+  {
+    if (g == null) return false;
+    return norm().equalsExact(g.norm());
+  }
+  
+
+  /**
    *  Performs an operation with or on this <code>Geometry</code>'s
    *  coordinates. 
    *  If this method modifies any coordinate values,
@@ -1388,10 +1591,28 @@ public abstract class Geometry
    *  form use the standard lexicographical ordering for coordinates. "Sorted in
    *  order of coordinates" means the obvious extension of this ordering to
    *  sequences of coordinates.
+   *  <p>
+   *  NOTE that this method mutates the value of this geometry in-place.
+   *  If this is not safe and/or wanted, the geometry should be
+   *  cloned prior to normalization.
    */
   public abstract void normalize();
 
   /**
+   * Creates a new Geometry which is a normalized
+   * copy of this Geometry. 
+   * 
+   * @return a normalized copy of this geometry.
+   * @see #normalize()
+   */
+  public Geometry norm()
+  {
+    Geometry copy = (Geometry) clone();
+    copy.normalize();
+    return copy;
+  }
+  
+  /**
    *  Returns whether this <code>Geometry</code> is greater than, equal to,
    *  or less than another <code>Geometry</code>. <P>
    *
diff --git a/src/com/vividsolutions/jts/geom/GeometryCollection.java b/src/com/vividsolutions/jts/geom/GeometryCollection.java
index 16dc3b5..891748f 100644
--- a/src/com/vividsolutions/jts/geom/GeometryCollection.java
+++ b/src/com/vividsolutions/jts/geom/GeometryCollection.java
@@ -40,7 +40,9 @@ import java.util.TreeSet;
 import com.vividsolutions.jts.util.Assert;
 
 /**
- *  Basic implementation of <code>GeometryCollection</code>.
+ * Models a collection of {@link Geometry}s of
+ * arbitrary type and dimension.
+ * 
  *
  *@version 1.7
  */
diff --git a/src/com/vividsolutions/jts/geom/GeometryCollectionIterator.java b/src/com/vividsolutions/jts/geom/GeometryCollectionIterator.java
index c95d402..4a6eed7 100644
--- a/src/com/vividsolutions/jts/geom/GeometryCollectionIterator.java
+++ b/src/com/vividsolutions/jts/geom/GeometryCollectionIterator.java
@@ -38,11 +38,13 @@ import java.util.Iterator;
 import java.util.NoSuchElementException;
 
 /**
- *  Iterates over all {@link Geometry}s in a {@link GeometryCollection}.
- *  Implements a pre-order depth-first traversal of the <code>GeometryCollection</code>
- *  (which may be nested). The original <code>GeometryCollection</code> is
- *  returned as well (as the first object), as are all sub-collections. It is
- *  simple to ignore the <code>GeometryCollection</code> objects if they are not
+ *  Iterates over all {@link Geometry}s in a {@link Geometry},
+ *  (which may be either a collection or an atomic geometry).
+ *  The iteration sequence follows a pre-order, depth-first traversal of the 
+ *  structure of the <code>GeometryCollection</code>
+ *  (which may be nested). The original <code>Geometry</code> object is
+ *  returned as well (as the first object), as are all sub-collections and atomic elements. 
+ *  It is  simple to ignore the intermediate <code>GeometryCollection</code> objects if they are not
  *  needed.
  *
  *@version 1.7
@@ -50,17 +52,16 @@ import java.util.NoSuchElementException;
 public class GeometryCollectionIterator implements Iterator {
 
   /**
-   *  The <code>GeometryCollection</code> being iterated over.
+   *  The <code>Geometry</code> being iterated over.
    */
   private Geometry parent;
   /**
-   *  Indicates whether or not the first element (the <code>GeometryCollection</code>
-   *  ) has been returned.
+   *  Indicates whether or not the first element 
+   *  (the root <code>GeometryCollection</code>) has been returned.
    */
   private boolean atStart;
   /**
-   *  The number of <code>Geometry</code>s in the the <code>GeometryCollection</code>
-   *  .
+   *  The number of <code>Geometry</code>s in the the <code>GeometryCollection</code>.
    */
   private int max;
   /**
@@ -69,16 +70,16 @@ public class GeometryCollectionIterator implements Iterator {
    */
   private int index;
   /**
-   *  The iterator over a nested <code>GeometryCollection</code>, or <code>null</code>
+   *  The iterator over a nested <code>Geometry</code>, or <code>null</code>
    *  if this <code>GeometryCollectionIterator</code> is not currently iterating
    *  over a nested <code>GeometryCollection</code>.
    */
   private GeometryCollectionIterator subcollectionIterator;
 
   /**
-   *  Constructs an iterator over the given <code>GeometryCollection</code>.
+   *  Constructs an iterator over the given <code>Geometry</code>.
    *
-   *@param  parent  the collection over which to iterate; also, the first
+   *@param  parent  the geometry over which to iterate; also, the first
    *      element returned by the iterator.
    */
   public GeometryCollectionIterator(Geometry parent) {
@@ -88,6 +89,11 @@ public class GeometryCollectionIterator implements Iterator {
     max = parent.getNumGeometries();
   }
 
+  /**
+   * Tests whether any geometry elements remain to be returned.
+   * 
+   * @return true if more geometry elements remain
+   */
   public boolean hasNext() {
     if (atStart) {
       return true;
@@ -104,6 +110,11 @@ public class GeometryCollectionIterator implements Iterator {
     return true;
   }
 
+  /**
+   * Gets the next geometry in the iteration sequence.
+   * 
+   * @return the next geometry in the iteration
+   */
   public Object next() {
     // the parent GeometryCollection is the first object returned
     if (atStart) {
@@ -131,9 +142,9 @@ public class GeometryCollectionIterator implements Iterator {
   }
 
   /**
-   *  Not implemented.
+   * Removal is not supported.
    *
-   *@throws  UnsupportedOperationException  This method is not implemented.
+   * @throws  UnsupportedOperationException  This method is not implemented.
    */
   public void remove() {
     throw new UnsupportedOperationException(getClass().getName());
diff --git a/src/com/vividsolutions/jts/geom/GeometryComponentFilter.java b/src/com/vividsolutions/jts/geom/GeometryComponentFilter.java
index 22ab127..0bd4402 100644
--- a/src/com/vividsolutions/jts/geom/GeometryComponentFilter.java
+++ b/src/com/vividsolutions/jts/geom/GeometryComponentFilter.java
@@ -42,8 +42,8 @@ package com.vividsolutions.jts.geom;
  *  The filter is applied to every component of the <code>Geometry</code>
  *  which is itself a <code>Geometry</code>
  *  and which does not itself contain any components.
- * (For instance, all the LinearRings in Polygons are visited,
- * but in a MultiPolygon the Polygons themselves are not visited.)
+ * (For instance, all the {@link LinearRing}s in {@link Polygon}s are visited,
+ * but in a {@link MultiPolygon} the {@link Polygon}s themselves are not visited.)
  * Thus the only classes of Geometry which must be 
  * handled as arguments to {@link #filter}
  * are {@link LineString}s, {@link LinearRing}s and {@link Point}s.
diff --git a/src/com/vividsolutions/jts/geom/GeometryFactory.java b/src/com/vividsolutions/jts/geom/GeometryFactory.java
index 284b8cf..551481d 100644
--- a/src/com/vividsolutions/jts/geom/GeometryFactory.java
+++ b/src/com/vividsolutions/jts/geom/GeometryFactory.java
@@ -303,8 +303,6 @@ public class GeometryFactory
   	return new GeometryCollection(geometries, this);
   }
 
-
-
   /**
    * Creates a MultiPolygon using the given Polygons; a null or empty array
    * will create an empty Polygon. The polygons must conform to the
@@ -320,7 +318,8 @@ public class GeometryFactory
   }
 
   /**
-   * Creates a LinearRing using the given Coordinates; a null or empty array will
+   * Creates a {@link LinearRing} using the given {@link Coordinate}s.
+   * A null or empty array will
    * create an empty LinearRing. The points must form a closed and simple
    * linestring. Consecutive points must not be equal.
    * @param coordinates an array without null elements, or an empty array, or null
@@ -330,20 +329,23 @@ public class GeometryFactory
   }
 
   /**
-   * Creates a LinearRing using the given CoordinateSequence; a null or empty CoordinateSequence will
+   * Creates a {@link LinearRing} using the given {@link CoordinateSequence}. 
+   * A null or empty CoordinateSequence will
    * create an empty LinearRing. The points must form a closed and simple
    * linestring. Consecutive points must not be equal.
+   * 
    * @param coordinates a CoordinateSequence possibly empty, or null
+   * @throws IllegalArgumentException if the ring is not closed, or has too few points
    */
   public LinearRing createLinearRing(CoordinateSequence coordinates) {
     return new LinearRing(coordinates, this);
   }
 
   /**
-   * Creates a MultiPoint using the given Points.
+   * Creates a {@link MultiPoint} using the given {@link Point}s.
    * A null or empty array will create an empty MultiPoint.
    *
-   * @param coordinates an array (without null elements), or an empty array, or <code>null</code>
+   * @param point an array of Points (without null elements), or an empty array, or <code>null</code>
    * @return a MultiPoint object
    */
   public MultiPoint createMultiPoint(Point[] point) {
@@ -393,6 +395,7 @@ public class GeometryFactory
    *            the inner boundaries of the new <code>Polygon</code>, or
    *            <code>null</code> or empty <code>LinearRing</code> s if
    *            the empty geometry is to be created.
+   * @throws IllegalArgumentException if a ring is invalid
    */
   public Polygon createPolygon(LinearRing shell, LinearRing[] holes) {
     return new Polygon(shell, holes, this);
diff --git a/src/com/vividsolutions/jts/geom/LineSegment.java b/src/com/vividsolutions/jts/geom/LineSegment.java
index 4257b48..30656d7 100644
--- a/src/com/vividsolutions/jts/geom/LineSegment.java
+++ b/src/com/vividsolutions/jts/geom/LineSegment.java
@@ -154,11 +154,11 @@ public class LineSegment
    * Determines the orientation index of a {@link Coordinate} relative to this segment.
    * The orientation index is as defined in {@link CGAlgorithms#computeOrientation}.
    *
-   * @param seg the LineSegment to compare
+   * @param p the coordinate to compare
    *
-   * @return 1 if <code>p</code> is to the left of this segment
-   * @return -1 if <code>p</code> is to the right of this segment
-   * @return 0 if <code>p</code> is collinear with this segment
+   * @return 1 (LEFT) if <code>p</code> is to the left of this segment
+   * @return -1 (RIGHT) if <code>p</code> is to the right of this segment
+   * @return 0 (COLLINEAR) if <code>p</code> is collinear with this segment
    * 
    * @see CGAlgorithms#computeOrientation(Coordinate, Coordinate, Coordinate)
    */
@@ -208,6 +208,16 @@ public class LineSegment
    */
   public Coordinate midPoint()
   {
+    return midPoint(p0, p1);
+  }
+
+  /**
+   * Computes the midpoint of a segment
+   *
+   * @return the midpoint of the segment
+   */
+  public static Coordinate midPoint(Coordinate p0, Coordinate p1)
+  {
     return new Coordinate( (p0.x + p1.x) / 2,
                            (p0.y + p1.y) / 2);
   }
@@ -431,7 +441,8 @@ public class LineSegment
   }
   /**
    * Computes the closest points on two line segments.
-   * @param p the point to find the closest point to
+   * 
+   * @param line the segment to find the closest point to
    * @return a pair of Coordinates which are the closest points on the line segments
    */
   public Coordinate[] closestPoints(LineSegment line)
@@ -483,11 +494,12 @@ public class LineSegment
   }
 
   /**
-   * Computes an intersection point between two segments, if there is one.
+   * Computes an intersection point between two line segments, if there is one.
    * There may be 0, 1 or many intersection points between two segments.
-   * If there are 0, null is returned. If there is 1 or more, a single one
-   * is returned (chosen at the discretion of the algorithm).  If
-   * more information is required about the details of the intersection,
+   * If there are 0, null is returned. If there is 1 or more, 
+   * exactly one of them is returned 
+   * (chosen at the discretion of the algorithm).  
+   * If more information is required about the details of the intersection,
    * the {@link RobustLineIntersector} class should be used.
    *
    * @param line a line segment
@@ -505,8 +517,8 @@ public class LineSegment
   }
 
   /**
-   * Computes the intersection point of the lines defined
-   * by two segments, if there is one.
+   * Computes the intersection point of the lines of infinite extent defined
+   * by two line segments (if there is one).
    * There may be 0, 1 or an infinite number of intersection points 
    * between two lines.
    * If there is a unique intersection point, it is returned. 
@@ -514,9 +526,10 @@ public class LineSegment
    * If more information is required about the details of the intersection,
    * the {@link RobustLineIntersector} class should be used.
    *
-   * @param line a line segment defining a straight line
-   * @return an intersection point, or <code>null</code> if there is none
-   * or an infinite number
+   * @param line a line segment defining an straight line with infinite extent
+   * @return an intersection point, 
+   * or <code>null</code> if there is no point of intersection
+   * or an infinite number of intersection points
    * 
    * @see RobustLineIntersector
    */
@@ -547,7 +560,7 @@ public class LineSegment
    *  Returns <code>true</code> if <code>other</code> has the same values for
    *  its points.
    *
-   *@param  other  a <code>LineSegment</code> with which to do the comparison.
+   *@param  o  a <code>LineSegment</code> with which to do the comparison.
    *@return        <code>true</code> if <code>other</code> is a <code>LineSegment</code>
    *      with the same values for the x and y ordinates.
    */
diff --git a/src/com/vividsolutions/jts/geom/Lineal.java b/src/com/vividsolutions/jts/geom/Lineal.java
index 6103dd7..5461ed3 100644
--- a/src/com/vividsolutions/jts/geom/Lineal.java
+++ b/src/com/vividsolutions/jts/geom/Lineal.java
@@ -2,7 +2,7 @@ package com.vividsolutions.jts.geom;
 
 /**
  * Identifies {@link Geometry} subclasses which
- * are 1-dimensional and have components which are {@link LineStrings}. 
+ * are 1-dimensional and have components which are {@link LineString}s. 
  * 
  * @author Martin Davis
  *
diff --git a/src/com/vividsolutions/jts/geom/LinearRing.java b/src/com/vividsolutions/jts/geom/LinearRing.java
index 4e25c77..d6fdae9 100644
--- a/src/com/vividsolutions/jts/geom/LinearRing.java
+++ b/src/com/vividsolutions/jts/geom/LinearRing.java
@@ -51,6 +51,12 @@ package com.vividsolutions.jts.geom;
  */
 public class LinearRing extends LineString
 {
+  /**
+   * The minimum number of vertices allowed in a valid non-empty ring (= 4).
+   * Empty rings with 0 vertices are also valid.
+   */
+  public static final int MINIMUM_VALID_SIZE = 4;
+  
   private static final long serialVersionUID = -4261142084085851829L;
 
   /**
@@ -104,7 +110,7 @@ public class LinearRing extends LineString
     if (!isEmpty() && ! super.isClosed()) {
       throw new IllegalArgumentException("Points of LinearRing do not form a closed linestring");
     }
-    if (getCoordinateSequence().size() >= 1 && getCoordinateSequence().size() <= 3) {
+    if (getCoordinateSequence().size() >= 1 && getCoordinateSequence().size() < MINIMUM_VALID_SIZE) {
       throw new IllegalArgumentException("Invalid number of points in LinearRing (found " 
       		+ getCoordinateSequence().size() + " - must be 0 or >= 4)");
     }
@@ -130,6 +136,15 @@ public class LinearRing extends LineString
     return true;
   }
 
+  public boolean isClosed() {
+    if (isEmpty()) {
+    	// empty LinearRings are closed by definition
+      return true;
+    }
+    return super.isClosed();
+  }
+
+
   public String getGeometryType() {
     return "LinearRing";
   }
diff --git a/src/com/vividsolutions/jts/geom/MultiLineString.java b/src/com/vividsolutions/jts/geom/MultiLineString.java
index 4444ad4..c3783cd 100644
--- a/src/com/vividsolutions/jts/geom/MultiLineString.java
+++ b/src/com/vividsolutions/jts/geom/MultiLineString.java
@@ -35,7 +35,9 @@ package com.vividsolutions.jts.geom;
 import com.vividsolutions.jts.operation.BoundaryOp;
 
 /**
- *  Basic implementation of <code>MultiLineString</code>.
+ * Models a collection of (@link LineString}s.
+ * <p>
+ * Any collection of LineStrings is a valid MultiLineString.
  *
  *@version 1.7
  */
diff --git a/src/com/vividsolutions/jts/geom/MultiPoint.java b/src/com/vividsolutions/jts/geom/MultiPoint.java
index 6f276f0..f8b415a 100644
--- a/src/com/vividsolutions/jts/geom/MultiPoint.java
+++ b/src/com/vividsolutions/jts/geom/MultiPoint.java
@@ -35,7 +35,9 @@
 package com.vividsolutions.jts.geom;
 
 /**
- *  Models a collection of <code>Point</code>s.
+ * Models a collection of {@link Point}s.
+ * <p>
+ * Any collection of Points is a valid MultiPoint.
  *
  *@version 1.7
  */
diff --git a/src/com/vividsolutions/jts/geom/MultiPolygon.java b/src/com/vividsolutions/jts/geom/MultiPolygon.java
index ebc7f44..ef97b59 100644
--- a/src/com/vividsolutions/jts/geom/MultiPolygon.java
+++ b/src/com/vividsolutions/jts/geom/MultiPolygon.java
@@ -37,7 +37,14 @@ package com.vividsolutions.jts.geom;
 import java.util.ArrayList;
 
 /**
- *  Basic implementation of <code>MultiPolygon</code>.
+ * Models a collection of {@link Polygon}s.
+ * <p>
+ * As per the OGC SFS specification, 
+ * the Polygons in a MultiPolygon may not overlap, 
+ * and may only touch at single points.
+ * This allows the topological point-set semantics
+ * to be well-defined.
+ *  
  *
  *@version 1.7
  */
diff --git a/src/com/vividsolutions/jts/geom/Point.java b/src/com/vividsolutions/jts/geom/Point.java
index c9e8563..9eb95a3 100644
--- a/src/com/vividsolutions/jts/geom/Point.java
+++ b/src/com/vividsolutions/jts/geom/Point.java
@@ -38,8 +38,13 @@ import com.vividsolutions.jts.util.Assert;
 import com.vividsolutions.jts.operation.valid.*;
 
 /**
- *  Basic implementation of <code>Point</code>.
+ *  Implementation of <code>Point</code>.
  *
+ * A Point is valid iff:
+ * <ul>
+ * <li>the coordinate which defines it is a valid coordinate (i.e does not have an NaN X or Y ordinate)
+ * </ul>
+ * 
  *@version 1.7
  */
 public class Point 
@@ -105,20 +110,6 @@ public class Point
     return true;
   }
 
-  /**
-   * A Point is valid iff:
-   * <ul>
-   * <li>the coordinate which defines it is a valid coordinate (i.e does not have an NaN X or Y ordinate)
-   * </ul>
-   * 
-   * @return true iff the Point is valid
-   */
-  public boolean isValid() {
-  	if (! IsValidOp.isValid(getCoordinate()))
-  		return false;
-    return true;
-  }
-
   public int getDimension() {
     return 0;
   }
diff --git a/src/com/vividsolutions/jts/geom/PrecisionModel.java b/src/com/vividsolutions/jts/geom/PrecisionModel.java
index 1ae4ec5..9a95806 100644
--- a/src/com/vividsolutions/jts/geom/PrecisionModel.java
+++ b/src/com/vividsolutions/jts/geom/PrecisionModel.java
@@ -43,7 +43,7 @@ import java.util.Map;
  * In other words, specifies the grid of allowable
  *  points for all <code>Geometry</code>s.
  * <p>
- * The {@link makePrecise} method allows rounding a coordinate to
+ * The {@link #makePrecise(Coordinate)} method allows rounding a coordinate to
  * a "precise" value; that is, one whose
  *  precision is known exactly.
  *<p>
@@ -118,8 +118,10 @@ public class PrecisionModel implements Serializable, Comparable
     }
     private String name;
     public String toString() { return name; }
-    /**
-     * @see http://www.javaworld.com/javaworld/javatips/jw-javatip122.html
+    
+    
+    /*
+     * Ssee http://www.javaworld.com/javaworld/javatips/jw-javatip122.html
      */
     private Object readResolve() {
         return nameToTypeMap.get(name);
@@ -235,7 +237,21 @@ public class PrecisionModel implements Serializable, Comparable
   /**
    * Returns the maximum number of significant digits provided by this
    * precision model.
-   * Intended for use by routines which need to print out precise values.
+   * Intended for use by routines which need to print out 
+   * decimal representations of precise values (such as {@link WKTWriter}).
+   * <p>
+   * This method would be more correctly called
+   * <tt>getMinimumDecimalPlaces</tt>, 
+   * since it actually computes the number of decimal places
+   * that is required to correctly display the full
+   * precision of an ordinate value.
+   * <p>
+   * Since it is difficult to compute the required number of
+   * decimal places for scale factors which are not powers of 10,
+   * the algorithm uses a very rough approximation in this case.
+   * This has the side effect that for scale factors which are
+   * powers of 10 the value returned is 1 greater than the true value.
+   * 
    *
    * @return the maximum number of decimal places provided by this precision model
    */
@@ -434,7 +450,7 @@ public class PrecisionModel implements Serializable, Comparable
    *  Compares this {@link PrecisionModel} object with the specified object for order.
    * A PrecisionModel is greater than another if it provides greater precision.
    * The comparison is based on the value returned by the
-   * {@link getMaximumSignificantDigits) method.
+   * {@link #getMaximumSignificantDigits} method.
    * This comparison is not strictly accurate when comparing floating precision models
    * to fixed models; however, it is correct when both models are either floating or fixed.
    *
diff --git a/src/com/vividsolutions/jts/geom/Puntal.java b/src/com/vividsolutions/jts/geom/Puntal.java
index 148294d..6f5318d 100644
--- a/src/com/vividsolutions/jts/geom/Puntal.java
+++ b/src/com/vividsolutions/jts/geom/Puntal.java
@@ -2,7 +2,7 @@ package com.vividsolutions.jts.geom;
 
 /**
  * Identifies {@link Geometry} subclasses which
- * are 0-dimensional and with components which are {@link Points}. 
+ * are 0-dimensional and with components which are {@link Point}s. 
  * 
  * @author Martin Davis
  *
diff --git a/src/com/vividsolutions/jts/geom/Triangle.java b/src/com/vividsolutions/jts/geom/Triangle.java
index f6404bd..9c325f5 100644
--- a/src/com/vividsolutions/jts/geom/Triangle.java
+++ b/src/com/vividsolutions/jts/geom/Triangle.java
@@ -97,6 +97,8 @@ public class Triangle
    * @param c a vertx of the triangle
    * @return the circumcentre of the triangle
    */
+  /*
+   // original non-robust algorithm
   public static Coordinate circumcentre(Coordinate a, Coordinate b, Coordinate c)
   {
     // compute the perpendicular bisector of chord ab
@@ -114,9 +116,70 @@ public class Triangle
       // Idea - can we condition which edges we choose?
       throw new IllegalStateException(ex.getMessage());
     }
+    
+    //System.out.println("Acc = " + a.distance(cc) + ", Bcc = " + b.distance(cc) + ", Ccc = " + c.distance(cc) );
+
     return cc;
   }
-
+  */
+  
+  /**
+   * Computes the circumcentre of a triangle.
+   * The circumcentre is the centre of the circumcircle,
+   * the smallest circle which encloses the triangle.
+   * It is also the common intersection point of the
+   * perpendicular bisectors of the sides of the triangle,
+   * and is the only point which has equal distance to all three
+   * vertices of the triangle.
+   * <p>
+   * The circumcentre does not necessarily lie within the triangle.
+   * <p>
+   * This method uses an algorithm due to J.R.Shewchuk which
+   * uses normalization to the origin
+   * to improve the accuracy of computation.
+   * (See <i>Lecture Notes on Geometric Robustness</i>, 
+   * Jonathan Richard Shewchuk, 1999).
+   *
+   * @param a a vertx of the triangle
+   * @param b a vertx of the triangle
+   * @param c a vertx of the triangle
+   * @return the circumcentre of the triangle
+   */
+  public static Coordinate circumcentre(Coordinate a, Coordinate b, Coordinate c)
+  {
+    double cx = c.x;
+    double cy = c.y;
+    double ax = a.x - cx;
+    double ay = a.y - cy;
+    double bx = b.x - cx;
+    double by = b.y - cy;
+    
+    double denom = 2 * det(ax, ay, bx, by);
+    double numx = det(ay, ax*ax + ay*ay, by, bx*bx + by*by);
+    double numy = det(ax, ax*ax + ay*ay, bx, bx*bx + by*by);
+    
+    double ccx = cx - numx / denom;
+    double ccy = cy + numy / denom;
+    
+    return new Coordinate(ccx, ccy);
+  }
+  
+  /**
+   * Computes the determinant of a 2x2 matrix.
+   * Uses standard double-precision arithmetic, 
+   * so is susceptible to round-off error.
+   * 
+   * @param m00 the [0,0] entry of the matrix
+   * @param m01 the [0,1] entry of the matrix
+   * @param m10 the [1,0] entry of the matrix
+   * @param m11 the [1,1] entry of the matrix
+   * @return the determinant
+   */
+  private static double det(double m00, double m01, double m10, double m11)
+  {
+    return m00 * m11 - m01 * m10;
+  }
+  
   /**
    * Computes the incentre of a triangle.
    * The <i>inCentre</i> of a triangle is the point which is equidistant
@@ -125,6 +188,8 @@ public class Triangle
    * of the triangle's angles meet.
    * It is the centre of the triangle's <i>incircle</i>,
    * which is the unique circle that is tangent to each of the triangle's three sides.
+   * <p>
+   * The incentre always lies within the triangle.
     *
    * @param a a vertx of the triangle
    * @param b a vertx of the triangle
@@ -150,6 +215,7 @@ public class Triangle
    * medians intersect (a triangle median is the segment from a vertex of the triangle to the
    * midpoint of the opposite side).
    * The centroid divides each median in a ratio of 2:1.
+   * <p>
    * The centroid always lies within the triangle.
    *
    *
@@ -221,7 +287,7 @@ public class Triangle
    * @param c a vertex of the triangle
    * @return the area of the triangle
    * 
-   * @see signedArea
+   * @see #signedArea(Coordinate, Coordinate, Coordinate)
    */
   public static double area(Coordinate a, Coordinate b, Coordinate c)
   {
@@ -236,7 +302,7 @@ public class Triangle
    * The signed area value can be used to determine point orientation, but 
    * the implementation in this method
    * is susceptible to round-off errors.  
-   * Use {@link CGAlgorithms#orientationIndex)} for robust orientation
+   * Use {@link CGAlgorithms#orientationIndex(Coordinate, Coordinate, Coordinate)} for robust orientation
    * calculation.
    *
    * @param a a vertex of the triangle
@@ -244,7 +310,7 @@ public class Triangle
    * @param c a vertex of the triangle
    * @return the signed 2D area of the triangle
    * 
-   * @see CGAlgorithms#orientationIndex
+   * @see CGAlgorithms#orientationIndex(Coordinate, Coordinate, Coordinate)
    */
   public static double signedArea(Coordinate a, Coordinate b, Coordinate c)
   {
diff --git a/src/com/vividsolutions/jts/geom/impl/CoordinateArraySequence.java b/src/com/vividsolutions/jts/geom/impl/CoordinateArraySequence.java
index bbe77bf..8ed9f8f 100644
--- a/src/com/vividsolutions/jts/geom/impl/CoordinateArraySequence.java
+++ b/src/com/vividsolutions/jts/geom/impl/CoordinateArraySequence.java
@@ -126,6 +126,7 @@ public class CoordinateArraySequence
   public void getCoordinate(int index, Coordinate coord) {
     coord.x = coordinates[index].x;
     coord.y = coordinates[index].y;
+    coord.z = coordinates[index].z;
   }
 
   /**
diff --git a/src/com/vividsolutions/jts/geom/impl/PackedCoordinateSequence.java b/src/com/vividsolutions/jts/geom/impl/PackedCoordinateSequence.java
index ae48020..13445eb 100644
--- a/src/com/vividsolutions/jts/geom/impl/PackedCoordinateSequence.java
+++ b/src/com/vividsolutions/jts/geom/impl/PackedCoordinateSequence.java
@@ -93,6 +93,7 @@ public abstract class PackedCoordinateSequence
   public void getCoordinate(int i, Coordinate coord) {
     coord.x = getOrdinate(i, 0);
     coord.y = getOrdinate(i, 1);
+    if (dimension > 2) coord.z = getOrdinate(i, 2);
   }
 
   /**
diff --git a/src/com/vividsolutions/jts/geom/prep/AbstractPreparedPolygonContains.java b/src/com/vividsolutions/jts/geom/prep/AbstractPreparedPolygonContains.java
index 0550559..42e3077 100644
--- a/src/com/vividsolutions/jts/geom/prep/AbstractPreparedPolygonContains.java
+++ b/src/com/vividsolutions/jts/geom/prep/AbstractPreparedPolygonContains.java
@@ -60,7 +60,7 @@ import com.vividsolutions.jts.geom.util.*;
  * @author Martin Davis
  *
  */
-public abstract class AbstractPreparedPolygonContains 
+abstract class AbstractPreparedPolygonContains 
 	extends PreparedPolygonPredicate
 {
 	/**
diff --git a/src/com/vividsolutions/jts/geom/prep/BasicPreparedGeometry.java b/src/com/vividsolutions/jts/geom/prep/BasicPreparedGeometry.java
index 272c8f8..7cf3b2f 100644
--- a/src/com/vividsolutions/jts/geom/prep/BasicPreparedGeometry.java
+++ b/src/com/vividsolutions/jts/geom/prep/BasicPreparedGeometry.java
@@ -50,7 +50,7 @@ import com.vividsolutions.jts.geom.util.ComponentCoordinateExtracter;
  * @author Martin Davis
  *
  */
-public class BasicPreparedGeometry 
+class BasicPreparedGeometry 
   implements PreparedGeometry
 {
   private Geometry baseGeom;
diff --git a/src/com/vividsolutions/jts/geom/prep/PreparedLineStringIntersects.java b/src/com/vividsolutions/jts/geom/prep/PreparedLineStringIntersects.java
index aeb4a84..32a690f 100644
--- a/src/com/vividsolutions/jts/geom/prep/PreparedLineStringIntersects.java
+++ b/src/com/vividsolutions/jts/geom/prep/PreparedLineStringIntersects.java
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.geom.util.*;
  * @author Martin Davis
  *
  */
-public class PreparedLineStringIntersects 
+class PreparedLineStringIntersects 
 {
 	/**
 	 * Computes the intersects predicate between a {@link PreparedLineString}
diff --git a/src/com/vividsolutions/jts/geom/prep/PreparedPolygon.java b/src/com/vividsolutions/jts/geom/prep/PreparedPolygon.java
index 7886dac..d80e70c 100644
--- a/src/com/vividsolutions/jts/geom/prep/PreparedPolygon.java
+++ b/src/com/vividsolutions/jts/geom/prep/PreparedPolygon.java
@@ -40,6 +40,10 @@ import com.vividsolutions.jts.operation.predicate.*;
 
 /**
  * A prepared version for {@link Polygonal} geometries.
+ * This class supports both {@link Polygon}s and {@link MultiPolygon}s.
+ * <p>
+ * This class does <b>not</b> support MultiPolygons which are non-valid 
+ * (e.g. with overlapping elements). 
  * 
  * @author mbdavis
  *
diff --git a/src/com/vividsolutions/jts/geom/prep/PreparedPolygonContains.java b/src/com/vividsolutions/jts/geom/prep/PreparedPolygonContains.java
index bce50ff..5bf35e7 100644
--- a/src/com/vividsolutions/jts/geom/prep/PreparedPolygonContains.java
+++ b/src/com/vividsolutions/jts/geom/prep/PreparedPolygonContains.java
@@ -47,7 +47,7 @@ import com.vividsolutions.jts.geom.*;
  * @author Martin Davis
  *
  */
-public class PreparedPolygonContains 
+class PreparedPolygonContains 
 	extends AbstractPreparedPolygonContains
 {
 	/**
diff --git a/src/com/vividsolutions/jts/geom/prep/PreparedPolygonContainsProperly.java b/src/com/vividsolutions/jts/geom/prep/PreparedPolygonContainsProperly.java
index ee2ab7d..bd92d37 100644
--- a/src/com/vividsolutions/jts/geom/prep/PreparedPolygonContainsProperly.java
+++ b/src/com/vividsolutions/jts/geom/prep/PreparedPolygonContainsProperly.java
@@ -57,7 +57,7 @@ import com.vividsolutions.jts.geom.util.*;
  * 
  * @author Martin Davis
  */
-public class PreparedPolygonContainsProperly 
+class PreparedPolygonContainsProperly 
 	extends PreparedPolygonPredicate
 {
 	/**
diff --git a/src/com/vividsolutions/jts/geom/prep/PreparedPolygonCovers.java b/src/com/vividsolutions/jts/geom/prep/PreparedPolygonCovers.java
index d767175..1ca993b 100644
--- a/src/com/vividsolutions/jts/geom/prep/PreparedPolygonCovers.java
+++ b/src/com/vividsolutions/jts/geom/prep/PreparedPolygonCovers.java
@@ -46,7 +46,7 @@ import com.vividsolutions.jts.geom.*;
  * @author Martin Davis
  *
  */
-public class PreparedPolygonCovers 
+class PreparedPolygonCovers 
 	extends AbstractPreparedPolygonContains
 {
 	/**
diff --git a/src/com/vividsolutions/jts/geom/prep/PreparedPolygonIntersects.java b/src/com/vividsolutions/jts/geom/prep/PreparedPolygonIntersects.java
index 8c21cc1..4f7b2e4 100644
--- a/src/com/vividsolutions/jts/geom/prep/PreparedPolygonIntersects.java
+++ b/src/com/vividsolutions/jts/geom/prep/PreparedPolygonIntersects.java
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.geom.util.*;
  * @author Martin Davis
  *
  */
-public class PreparedPolygonIntersects 
+class PreparedPolygonIntersects 
 	extends PreparedPolygonPredicate
 {
 	/**
diff --git a/src/com/vividsolutions/jts/geom/prep/PreparedPolygonPredicate.java b/src/com/vividsolutions/jts/geom/prep/PreparedPolygonPredicate.java
index d4108a5..921eb21 100644
--- a/src/com/vividsolutions/jts/geom/prep/PreparedPolygonPredicate.java
+++ b/src/com/vividsolutions/jts/geom/prep/PreparedPolygonPredicate.java
@@ -14,7 +14,7 @@ import com.vividsolutions.jts.geom.util.*;
  * @author mbdavis
  *
  */
-public abstract class PreparedPolygonPredicate 
+abstract class PreparedPolygonPredicate 
 {
 	protected PreparedPolygon prepPoly;
   private PointOnGeometryLocator targetPointLocator;
diff --git a/src/com/vividsolutions/jts/geom/util/AffineTransformation.java b/src/com/vividsolutions/jts/geom/util/AffineTransformation.java
index 7552753..a2e0f09 100644
--- a/src/com/vividsolutions/jts/geom/util/AffineTransformation.java
+++ b/src/com/vividsolutions/jts/geom/util/AffineTransformation.java
@@ -31,18 +31,22 @@ import com.vividsolutions.jts.util.*;
  * | y' |        | y |
  * | 1  |        | 1 |
  * </pre></blockquote>
+ * <h3>Transformation Composition</h3>
  * Affine transformations can be composed using the {@link #compose} method.
- * The composition of transformations is in general not commutative.
- * transformation matrices as follows:
+ * Composition is computed via multiplication of the 
+ * transformation matrices, and is defined as:
  * <blockquote><pre>
  * A.compose(B) = T<sub>B</sub> x T<sub>A</sub>
  * </pre></blockquote>
  * This produces a transformation whose effect is that of A followed by B.
- * Composition is computed via multiplication of the 
- * The methods {@link #reflect}, {@link #rotate}, {@link #scale}, {@link #shear}, and {@link #translate} 
+ * The methods {@link #reflect}, {@link #rotate}, 
+ * {@link #scale}, {@link #shear}, and {@link #translate} 
  * have the effect of composing a transformation of that type with
  * the transformation they are invoked on.  
  * <p>
+ * The composition of transformations is in general <i>not</i> commutative.
+ * 
+ * <h3>Transformation Inversion</h3>
  * Affine transformations may be invertible or non-invertible.  
  * If a transformation is invertible, then there exists 
  * an inverse transformation which when composed produces 
@@ -460,11 +464,11 @@ public class AffineTransformation
   
   /**
    * Explicitly computes the math for a reflection.  May not work.
-   * @param x0
-   * @param y0
-   * @param x1
-   * @param y1
-   * @return
+   * @param x0 the X ordinate of one point on the reflection line
+   * @param y0 the Y ordinate of one point on the reflection line
+   * @param x1 the X ordinate of another point on the reflection line
+   * @param y1 the Y ordinate of another point on the reflection line
+   * @return this transformation, with an updated matrix
    */
   public AffineTransformation setToReflectionBasic(double x0, double y0, double x1, double y1)
   {
@@ -483,6 +487,16 @@ public class AffineTransformation
     return this;
   }
   
+  /**
+   * Sets this transformation to be a reflection 
+   * about the line defined by a line <tt>(x0,y0) - (x1,y1)</tt>.
+   * 
+   * @param x0 the X ordinate of one point on the reflection line
+   * @param y0 the Y ordinate of one point on the reflection line
+   * @param x1 the X ordinate of another point on the reflection line
+   * @param y1 the Y ordinate of another point on the reflection line
+   * @return this transformation, with an updated matrix
+   */
   public AffineTransformation setToReflection(double x0, double y0, double x1, double y1)
   {
     if (x0 == x1 && y0 == y1) {
@@ -514,7 +528,7 @@ public class AffineTransformation
    * is computed by:
    * <blockquote><pre>
    * d = sqrt(x<sup>2</sup> + y<sup>2</sup>)  
-   * sin = x / d;
+   * sin = y / d;
    * cos = x / d;
    * 
    * T<sub>ref</sub> = T<sub>rot(sin, cos)</sub> x T<sub>scale(1, -1)</sub> x T<sub>rot(-sin, cos)</sub  
@@ -529,6 +543,21 @@ public class AffineTransformation
     if (x == 0.0 && y == 0.0) {
       throw new IllegalArgumentException("Reflection vector must be non-zero");
     }
+    
+    /**
+     * Handle special case - x = y.
+     * This case is specified explicitly to avoid roundoff error.
+     */
+    if (x == y) {
+      m00 = 0.0;
+      m01 = 1.0;
+      m02 = 0.0;
+      m10 = 1.0;
+      m11 = 0.0;
+      m12 = 0.0;
+      return this;
+    }
+    
     // rotate vector to positive x axis direction
     double d = Math.sqrt(x * x + y * y);
     double sin = y / d;
@@ -1006,9 +1035,9 @@ public class AffineTransformation
   */
   public boolean equals(Object obj)
   {
+    if (obj == null) return false;
     if (! (obj instanceof AffineTransformation))
       return false;
-    if (obj == null) return false;
     
     AffineTransformation trans = (AffineTransformation) obj;
     return m00 == trans.m00
diff --git a/src/com/vividsolutions/jts/geom/util/AffineTransformationBuilder.java b/src/com/vividsolutions/jts/geom/util/AffineTransformationBuilder.java
index f62317f..a24d235 100644
--- a/src/com/vividsolutions/jts/geom/util/AffineTransformationBuilder.java
+++ b/src/com/vividsolutions/jts/geom/util/AffineTransformationBuilder.java
@@ -1,6 +1,7 @@
 package com.vividsolutions.jts.geom.util;
 
 import com.vividsolutions.jts.geom.*;
+import com.vividsolutions.jts.math.Matrix;
 import com.vividsolutions.jts.algorithm.*;
 
 /**
diff --git a/src/com/vividsolutions/jts/geom/util/ComponentCoordinateExtracter.java b/src/com/vividsolutions/jts/geom/util/ComponentCoordinateExtracter.java
index bf71801..9e3cca7 100644
--- a/src/com/vividsolutions/jts/geom/util/ComponentCoordinateExtracter.java
+++ b/src/com/vividsolutions/jts/geom/util/ComponentCoordinateExtracter.java
@@ -49,7 +49,7 @@ public class ComponentCoordinateExtracter
   /**
    * Extracts the linear components from a single geometry.
    * If more than one geometry is to be processed, it is more
-   * efficient to create a single {@link LineExtracterFilter} instance
+   * efficient to create a single {@link ComponentCoordinateExtracter} instance
    * and pass it to multiple geometries.
    *
    * @param geom the Geometry from which to extract
diff --git a/src/com/vividsolutions/jts/geom/util/GeometryCollectionMapper.java b/src/com/vividsolutions/jts/geom/util/GeometryCollectionMapper.java
index 29fd7fc..cff0f26 100644
--- a/src/com/vividsolutions/jts/geom/util/GeometryCollectionMapper.java
+++ b/src/com/vividsolutions/jts/geom/util/GeometryCollectionMapper.java
@@ -3,6 +3,14 @@ package com.vividsolutions.jts.geom.util;
 import java.util.*;
 import com.vividsolutions.jts.geom.*;
 
+/**
+ * Maps the members of a {@link GeometryCollection}
+ * into another <tt>GeometryCollection</tt> via a defined
+ * mapping function.
+ * 
+ * @author Martin Davis
+ *
+ */
 public class GeometryCollectionMapper 
 {
   public static GeometryCollection map(GeometryCollection gc, MapOp op)
diff --git a/src/com/vividsolutions/jts/geom/util/GeometryEditor.java b/src/com/vividsolutions/jts/geom/util/GeometryEditor.java
index fc43451..cd1495c 100644
--- a/src/com/vividsolutions/jts/geom/util/GeometryEditor.java
+++ b/src/com/vividsolutions/jts/geom/util/GeometryEditor.java
@@ -46,7 +46,7 @@ import java.util.ArrayList;
  * Geometry objects are intended to be treated as immutable.
  * This class "modifies" Geometrys
  * by traversing them, applying a user-defined
- * {@link GeometryEditOperation} or {@link CoordinateOperation}  
+ * {@link GeometryEditorOperation} or {@link CoordinateOperation}  
  * and creating new Geometrys with the same structure but
  * (possibly) modified components.
  * <p>
@@ -57,7 +57,7 @@ import java.util.ArrayList;
  * <li>the coordinate lists may be changed
  *     (e.g. by adding or deleting coordinates).
  *     The modifed coordinate lists must be consistent with their original parent component
- *     (e.g. a LinearRing must always have at least 4 coordinates, and the first and last
+ *     (e.g. a <tt>LinearRing</tt> must always have at least 4 coordinates, and the first and last
  *     coordinate must be equal)
  * <li>components of the original geometry may be deleted
  * (   e.g. holes may be removed from a Polygon, or LineStrings removed from a MultiLineString).
@@ -68,14 +68,14 @@ import java.util.ArrayList;
  * If changing the structure is required, use a {@link GeometryTransformer}.
  * <p>
  * This class supports the case where an edited Geometry needs to
- * be created under a new GeometryFactory, via the {@link GeometryEditor(GeometryFactory)}
+ * be created under a new GeometryFactory, via the {@link #GeometryEditor(GeometryFactory)}
  * constructor.  
  * Examples of situations where this is required is if the geometry is 
  * transformed to a new SRID and/or a new PrecisionModel.
  * <p>
  * The resulting Geometry is not checked for validity.
  * If validity needs to be enforced, the new Geometry's 
- * {@link #isValid} method should be called.
+ * {@link Geometry#isValid} method should be called.
  *
  * @see GeometryTransformer
  * @see Geometry#isValid
@@ -237,6 +237,23 @@ public class GeometryEditor
   }
 
   /**
+   * A GeometryEditorOperation which does not modify
+   * the input geometry.
+   * This can be used for simple changes of 
+   * GeometryFactory (including PrecisionModel and SRID).
+   * 
+   * @author mbdavis
+   *
+   */
+  public static class NoOpGeometryOperation
+  implements GeometryEditorOperation
+  {
+  	public Geometry edit(Geometry geometry, GeometryFactory factory)
+  	{
+  		return geometry;
+  	}
+  }
+  /**
    * A {@link GeometryEditorOperation} which modifies the coordinate list of a {@link Geometry}.
    * Operates on Geometry subclasses which contains a single coordinate list.
    */
diff --git a/src/com/vividsolutions/jts/geom/util/GeometryMapper.java b/src/com/vividsolutions/jts/geom/util/GeometryMapper.java
new file mode 100644
index 0000000..59f41c7
--- /dev/null
+++ b/src/com/vividsolutions/jts/geom/util/GeometryMapper.java
@@ -0,0 +1,99 @@
+/*
+ * 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.util;
+
+import java.util.*;
+import com.vividsolutions.jts.geom.*;
+
+/**
+ * Methods to map various collections 
+ * of {@link Geometry}s  
+ * via defined mapping functions.
+ * 
+ * @author Martin Davis
+ *
+ */
+public class GeometryMapper 
+{
+  /**
+   * Maps the members of a {@link Geometry}
+   * (which may be atomic or composite)
+   * into another <tt>Geometry</tt> of most specific type.
+   * <tt>null</tt> results are skipped.
+   * In the case of hierarchical {@link GeometryCollection}s,
+   * only the first level of members are mapped.
+   *  
+   * @param geom the input atomic or composite geometry
+   * @param op the mapping operation
+   * @return a result collection or geometry of most specific type
+   */
+  public static Geometry map(Geometry geom, MapOp op)
+  {
+    List mapped = new ArrayList();
+    for (int i = 0; i < geom.getNumGeometries(); i++) {
+      Geometry g = op.map(geom.getGeometryN(i));
+      if (g != null)
+        mapped.add(g);
+    }
+    return geom.getFactory().buildGeometry(mapped);
+  }
+  
+  public static Collection map(Collection geoms, MapOp op)
+  {
+    List mapped = new ArrayList();
+    for (Object o : geoms) {
+      Geometry g = (Geometry) o;
+      Geometry gr = op.map(g);
+      if (gr != null)
+        mapped.add(gr);
+    }
+    return mapped;
+  }
+  
+  /**
+   * An interface for geometry functions used for mapping.
+   * 
+   * @author Martin Davis
+   *
+   */
+  public interface MapOp 
+  {
+    /**
+     * Computes a new geometry value.
+     * 
+     * @param g the input geometry
+     * @return a result geometry
+     */
+    Geometry map(Geometry g);
+  }
+}
diff --git a/src/com/vividsolutions/jts/geom/util/GeometryTransformer.java b/src/com/vividsolutions/jts/geom/util/GeometryTransformer.java
index 7175d0f..45d4b6b 100644
--- a/src/com/vividsolutions/jts/geom/util/GeometryTransformer.java
+++ b/src/com/vividsolutions/jts/geom/util/GeometryTransformer.java
@@ -19,7 +19,7 @@ import com.vividsolutions.jts.geom.*;
  * A typically usage would be a transformation class that transforms <tt>Polygons</tt> into
  * <tt>Polygons</tt>, <tt>LineStrings</tt> or <tt>Points</tt>, depending on the geometry of the input
  * (For instance, a simplification operation).  
- * This class would likely need to override the {@link transformMultiPolygon}
+ * This class would likely need to override the {@link #transformMultiPolygon(MultiPolygon, Geometry)transformMultiPolygon}
  * method to ensure that if input Polygons change type the result is a <tt>GeometryCollection</tt>,
  * not a <tt>MultiPolygon</tt>.
  * <p>
@@ -33,7 +33,7 @@ import com.vividsolutions.jts.geom.*;
  * geometry - if they cannot do this they should return <code>null</code>
  * (for instance, it may not be possible for a transformLineString implementation
  * to return at least two points - in this case, it should return <code>null</code>).
- * The {@link transform} method itself will always
+ * The {@link #transform(Geometry)transform} method itself will always
  * return a non-null Geometry object (but this may be empty).
  *
  * @version 1.7
diff --git a/src/com/vividsolutions/jts/geom/util/LineStringExtracter.java b/src/com/vividsolutions/jts/geom/util/LineStringExtracter.java
index 743b0bc..39dac62 100644
--- a/src/com/vividsolutions/jts/geom/util/LineStringExtracter.java
+++ b/src/com/vividsolutions/jts/geom/util/LineStringExtracter.java
@@ -51,7 +51,6 @@ public class LineStringExtracter
    * 
    * @param geom the geometry from which to extract
    * @param lines the list to add the extracted LineStrings to
-   * @param list the list to add the extracted elements to
    */
   public static List getLines(Geometry geom, List lines)
   {
diff --git a/src/com/vividsolutions/jts/geom/util/LinearComponentExtracter.java b/src/com/vividsolutions/jts/geom/util/LinearComponentExtracter.java
index 8958832..35bdea6 100644
--- a/src/com/vividsolutions/jts/geom/util/LinearComponentExtracter.java
+++ b/src/com/vividsolutions/jts/geom/util/LinearComponentExtracter.java
@@ -49,7 +49,7 @@ public class LinearComponentExtracter
    * Extracts the linear components from a single {@link Geometry}
    * and adds them to the provided {@link Collection}.
    *
-   * @param geoms the Collection of geometries from which to extract linear components
+   * @param geoms the collection of geometries from which to extract linear components
    * @param lines the collection to add the extracted linear components to
    * @return the collection of linear components (LineStrings or LinearRings)
    */
@@ -68,6 +68,7 @@ public class LinearComponentExtracter
    *
    * @param geoms the Collection of geometries from which to extract linear components
    * @param lines the collection to add the extracted linear components to
+   * @param forceToLineString true if LinearRings should be converted to LineStrings
    * @return the collection of linear components (LineStrings or LinearRings)
    */
   public static Collection getLines(Collection geoms, Collection lines, boolean forceToLineString)
@@ -104,6 +105,7 @@ public class LinearComponentExtracter
    *
    * @param geom the geometry from which to extract linear components
    * @param lines the Collection to add the extracted linear components to
+   * @param forceToLineString true if LinearRings should be converted to LineStrings
    * @return the Collection of linear components (LineStrings or LinearRings)
    */
   public static Collection getLines(Geometry geom, Collection lines, boolean forceToLineString)
@@ -115,7 +117,7 @@ public class LinearComponentExtracter
   /**
    * Extracts the linear components from a single geometry.
    * If more than one geometry is to be processed, it is more
-   * efficient to create a single {@link LineExtracterFilter} instance
+   * efficient to create a single {@link LinearComponentExtracter} instance
    * and pass it to multiple geometries.
    *
    * @param geom the geometry from which to extract linear components
@@ -123,8 +125,23 @@ public class LinearComponentExtracter
    */
   public static List getLines(Geometry geom)
   {
+    return getLines(geom, false);
+  }
+
+  /**
+   * Extracts the linear components from a single geometry.
+   * If more than one geometry is to be processed, it is more
+   * efficient to create a single {@link LinearComponentExtracter} instance
+   * and pass it to multiple geometries.
+   *
+   * @param geom the geometry from which to extract linear components
+   * @param forceToLineString true if LinearRings should be converted to LineStrings
+   * @return the list of linear components
+   */
+  public static List getLines(Geometry geom, boolean forceToLineString)
+  {
     List lines = new ArrayList();
-    geom.apply(new LinearComponentExtracter(lines));
+    geom.apply(new LinearComponentExtracter(lines, forceToLineString));
     return lines;
   }
 
@@ -148,6 +165,12 @@ public class LinearComponentExtracter
     this.isForcedToLineString = isForcedToLineString;
   }
 
+  /**
+   * Indicates that LinearRing components should be 
+   * converted to pure LineStrings.
+   * 
+   * @param isForcedToLineString true if LinearRings should be converted to LineStrings
+   */
   public void setForceToLineString(boolean isForcedToLineString)
   {
   	this.isForcedToLineString = isForcedToLineString;
diff --git a/src/com/vividsolutions/jts/geom/util/SineStarFactory.java b/src/com/vividsolutions/jts/geom/util/SineStarFactory.java
index 1608cd8..93c5acd 100644
--- a/src/com/vividsolutions/jts/geom/util/SineStarFactory.java
+++ b/src/com/vividsolutions/jts/geom/util/SineStarFactory.java
@@ -104,7 +104,7 @@ public class SineStarFactory
       double ang = i * (2 * Math.PI / nPts);
       double x = curveRadius * Math.cos(ang) + centreX;
       double y = curveRadius * Math.sin(ang) + centreY;
-      pts[iPt++] = createCoord(x, y);
+      pts[iPt++] = coord(x, y);
     }
     pts[iPt] = new Coordinate(pts[0]);
 
diff --git a/src/com/vividsolutions/jts/geomgraph/EdgeEndStar.java b/src/com/vividsolutions/jts/geomgraph/EdgeEndStar.java
index cfcaf0e..620bdd1 100644
--- a/src/com/vividsolutions/jts/geomgraph/EdgeEndStar.java
+++ b/src/com/vividsolutions/jts/geomgraph/EdgeEndStar.java
@@ -269,6 +269,7 @@ abstract public class EdgeEndStar
     // Since edges are stored in CCW order around the node,
     // As we move around the ring we move from the right to the left side of the edge
     int startLoc = Location.NONE ;
+    
     // initialize loc to location of last L side (if any)
 //System.out.println("finding start location");
     for (Iterator it = iterator(); it.hasNext(); ) {
@@ -277,6 +278,7 @@ abstract public class EdgeEndStar
       if (label.isArea(geomIndex) && label.getLocation(geomIndex, Position.LEFT) != Location.NONE)
         startLoc = label.getLocation(geomIndex, Position.LEFT);
     }
+    
     // no labelled sides found, so no labels to propagate
     if (startLoc == Location.NONE) return;
 
@@ -288,7 +290,6 @@ abstract public class EdgeEndStar
       if (label.getLocation(geomIndex, Position.ON) == Location.NONE)
           label.setLocation(geomIndex, Position.ON, currLoc);
       // set side labels (if any)
-//      if (label.isArea()) {   //ORIGINAL
       if (label.isArea(geomIndex)) {
         int leftLoc   = label.getLocation(geomIndex, Position.LEFT);
         int rightLoc  = label.getLocation(geomIndex, Position.RIGHT);
diff --git a/src/com/vividsolutions/jts/geomgraph/GeometryGraph.java b/src/com/vividsolutions/jts/geomgraph/GeometryGraph.java
index 61855bd..dc69112 100644
--- a/src/com/vividsolutions/jts/geomgraph/GeometryGraph.java
+++ b/src/com/vividsolutions/jts/geomgraph/GeometryGraph.java
@@ -226,13 +226,20 @@ public class GeometryGraph
     Coordinate coord = p.getCoordinate();
     insertPoint(argIndex, coord, Location.INTERIOR);
   }
+  
   /**
+   * Adds a polygon ring to the graph.
+   * Empty rings are ignored.
+   * 
    * The left and right topological location arguments assume that the ring is oriented CW.
    * If the ring is in the opposite orientation,
    * the left and right locations must be interchanged.
    */
   private void addPolygonRing(LinearRing lr, int cwLeft, int cwRight)
   {
+  	// don't bother adding empty holes
+  	if (lr.isEmpty()) return;
+  	
     Coordinate[] coord = CoordinateArrays.removeRepeatedPoints(lr.getCoordinates());
 
     if (coord.length < 4) {
@@ -264,13 +271,15 @@ public class GeometryGraph
             Location.INTERIOR);
 
     for (int i = 0; i < p.getNumInteriorRing(); i++) {
+    	LinearRing hole = (LinearRing) p.getInteriorRingN(i);
+    	
       // Holes are topologically labelled opposite to the shell, since
       // the interior of the polygon lies on their opposite side
       // (on the left, if the hole is oriented CW)
       addPolygonRing(
-            (LinearRing) p.getInteriorRingN(i),
-            Location.INTERIOR,
-            Location.EXTERIOR);
+      		hole,
+          Location.INTERIOR,
+          Location.EXTERIOR);
     }
   }
 
diff --git a/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainIndexer.java b/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainIndexer.java
index 08b25e8..71a593e 100644
--- a/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainIndexer.java
+++ b/src/com/vividsolutions/jts/geomgraph/index/MonotoneChainIndexer.java
@@ -42,7 +42,11 @@ import com.vividsolutions.jts.geomgraph.Quadrant;
 /**
  * MonotoneChains are a way of partitioning the segments of an edge to
  * allow for fast searching of intersections.
- * They have the following properties:
+ * Specifically, a sequence of contiguous line segments
+ * is a monotone chain iff all the vectors defined by the oriented segments
+ * lies in the same quadrant.
+ * <p>
+ * Monotone Chains have the following useful properties:
  * <ol>
  * <li>the segments within a monotone chain will never intersect each other
  * <li>the envelope of any contiguous subset of the segments in a monotone chain
diff --git a/src/com/vividsolutions/jts/index/chain/MonotoneChain.java b/src/com/vividsolutions/jts/index/chain/MonotoneChain.java
index 334de6e..5fce1cd 100644
--- a/src/com/vividsolutions/jts/index/chain/MonotoneChain.java
+++ b/src/com/vividsolutions/jts/index/chain/MonotoneChain.java
@@ -133,7 +133,18 @@ public class MonotoneChain {
 
   /**
    * Determine all the line segments in the chain whose envelopes overlap
-   * the searchEnvelope, and process them
+   * the searchEnvelope, and process them.
+   * <p>
+   * The monotone chain search algorithm attempts to optimize 
+   * performance by not calling the select action on chain segments
+   * which it can determine are not in the search envelope.
+   * However, it *may* call the select action on segments
+   * which do not intersect the search envelope.
+   * This saves on the overhead of checking envelope intersection
+   * each time, since clients may be able to do this more efficiently.
+   * 
+   * @param searchEnv the search envelope
+   * @param mcs the select action to execute on selected segments
    */
   public void select(Envelope searchEnv, MonotoneChainSelectAction mcs)
   {
@@ -173,6 +184,20 @@ public class MonotoneChain {
     }
   }
 
+  /**
+   * Determine all the line segments in two chains which may overlap, and process them.
+   * <p>
+   * The monotone chain search algorithm attempts to optimize 
+   * performance by not calling the overlap action on chain segments
+   * which it can determine do not overlap.
+   * However, it *may* call the overlap action on segments
+   * which do not actually interact.
+   * This saves on the overhead of checking intersection
+   * each time, since clients may be able to do this more efficiently.
+   * 
+   * @param searchEnv the search envelope
+   * @param mco the overlap action to execute on selected segments
+   */
   public void computeOverlaps(MonotoneChain mc, MonotoneChainOverlapAction mco)
   {
     computeOverlaps(start, end, mc, mc.start, mc.end, mco);
diff --git a/src/com/vividsolutions/jts/index/chain/MonotoneChainSelectAction.java b/src/com/vividsolutions/jts/index/chain/MonotoneChainSelectAction.java
index 4c1b3e3..315e959 100644
--- a/src/com/vividsolutions/jts/index/chain/MonotoneChainSelectAction.java
+++ b/src/com/vividsolutions/jts/index/chain/MonotoneChainSelectAction.java
@@ -49,7 +49,7 @@ public class MonotoneChainSelectAction
   LineSegment selectedSegment = new LineSegment();
 
   /**
-   * This function can be overridden if the original chain is needed
+   * This function can be overridden if the original chain is needed.
    */
   public void select(MonotoneChain mc, int start)
   {
@@ -59,7 +59,8 @@ public class MonotoneChainSelectAction
 
   /**
    * This is a convenience function which can be overridden to obtain the actual
-   * line segment which is selected
+   * line segment which is selected.
+   * 
    * @param seg
    */
   public void select(LineSegment seg)
diff --git a/src/com/vividsolutions/jts/index/intervalrtree/SortedPackedIntervalRTree.java b/src/com/vividsolutions/jts/index/intervalrtree/SortedPackedIntervalRTree.java
index a2e8d35..6495261 100644
--- a/src/com/vividsolutions/jts/index/intervalrtree/SortedPackedIntervalRTree.java
+++ b/src/com/vividsolutions/jts/index/intervalrtree/SortedPackedIntervalRTree.java
@@ -70,7 +70,7 @@ public class SortedPackedIntervalRTree
    * @param max the upper bound of the item interval
    * @param item the item to insert
    * 
-   * @throw IllegalStateException if the index has already been queried
+   * @throws IllegalStateException if the index has already been queried
    */
 	public void insert(double min, double max, Object item)
 	{
diff --git a/src/com/vividsolutions/jts/index/kdtree/KdTree.java b/src/com/vividsolutions/jts/index/kdtree/KdTree.java
index df75ba2..f2717fb 100644
--- a/src/com/vividsolutions/jts/index/kdtree/KdTree.java
+++ b/src/com/vividsolutions/jts/index/kdtree/KdTree.java
@@ -127,7 +127,7 @@ public class KdTree
 			}
 			// test if point is already a node
 			if (currentNode != null) {
-				boolean isInTolerance = p.distance(currentNode.getCoordinate()) < tolerance;
+				boolean isInTolerance = p.distance(currentNode.getCoordinate()) <= tolerance;
 
 				// if (isInTolerance && ! p.equals2D(currentNode.getCoordinate())) {
 				// System.out.println("KDTree: Snapped!");
diff --git a/src/com/vividsolutions/jts/index/quadtree/NodeBase.java b/src/com/vividsolutions/jts/index/quadtree/NodeBase.java
index d65b9cd..f74d65e 100644
--- a/src/com/vividsolutions/jts/index/quadtree/NodeBase.java
+++ b/src/com/vividsolutions/jts/index/quadtree/NodeBase.java
@@ -104,7 +104,7 @@ public abstract class NodeBase {
   /**
    * Removes a single item from this subtree.
    *
-   * @param searchEnv the envelope containing the item
+   * @param itemEnv the envelope containing the item
    * @param item the item to remove
    * @return <code>true</code> if the item was found and removed
    */
diff --git a/src/com/vividsolutions/jts/index/strtree/AbstractNode.java b/src/com/vividsolutions/jts/index/strtree/AbstractNode.java
index 1aafaa1..d51beab 100644
--- a/src/com/vividsolutions/jts/index/strtree/AbstractNode.java
+++ b/src/com/vividsolutions/jts/index/strtree/AbstractNode.java
@@ -58,8 +58,8 @@ public abstract class AbstractNode implements Boundable {
   }
 
   /**
-   * Returns either child {@link AbstractNodes}, or if this is a leaf node, real data (wrapped
-   * in {@link ItemBoundables}).
+   * Returns either child {@link AbstractNode}s, or if this is a leaf node, real data (wrapped
+   * in {@link ItemBoundable}s).
    */
   public List getChildBoundables() {
     return childBoundables;
diff --git a/src/com/vividsolutions/jts/index/strtree/BoundablePair.java b/src/com/vividsolutions/jts/index/strtree/BoundablePair.java
new file mode 100644
index 0000000..9629f0a
--- /dev/null
+++ b/src/com/vividsolutions/jts/index/strtree/BoundablePair.java
@@ -0,0 +1,232 @@
+/*
+ * 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.index.strtree;
+
+import java.util.Iterator;
+import java.util.List;
+
+import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.util.PriorityQueue;
+
+/**
+ * A pair of {@link Boundable}s, whose leaf items 
+ * support a distance metric between them.
+ * Used to compute the distance between the members,
+ * and to expand a member relative to the other
+ * in order to produce new branches of the 
+ * Branch-and-Bound evaluation tree.
+ * Provides an ordering based on the distance between the members,
+ * which allows building a priority queue by minimum distance.
+ * 
+ * @author Martin Davis
+ *
+ */
+class BoundablePair
+  implements Comparable
+{
+  private Boundable boundable1;
+  private Boundable boundable2;
+  private double distance;
+  private ItemDistance itemDistance;
+  //private double maxDistance = -1.0;
+  
+  public BoundablePair(Boundable boundable1, Boundable boundable2, ItemDistance itemDistance)
+  {
+    this.boundable1 = boundable1;
+    this.boundable2 = boundable2;
+    this.itemDistance = itemDistance;
+    distance = distance();
+  }
+  
+  /**
+   * Gets one of the member {@link Boundable}s in the pair 
+   * (indexed by [0, 1]).
+   * 
+   * @param i the index of the member to return (0 or 1)
+   * @return the chosen member
+   */
+  public Boundable getBoundable(int i)
+  {
+    if (i == 0) return boundable1;
+    return boundable2;
+  }
+  
+  /**
+   * Computes the distance between the {@link Boundable}s in this pair.
+   * The boundables are either composites or leaves.
+   * If either is composite, the distance is computed as the minimum distance
+   * between the bounds.  
+   * If both are leaves, the distance is computed by {@link #itemDistance(ItemBoundable, ItemBoundable)}.
+   * 
+   * @return
+   */
+  private double distance()
+  {
+    // if items, compute exact distance
+    if (isLeaves()) {
+      return itemDistance.distance((ItemBoundable) boundable1,
+          (ItemBoundable) boundable2);
+    }
+    // otherwise compute distance between bounds of boundables
+    return ((Envelope) boundable1.getBounds()).distance(
+        ((Envelope) boundable2.getBounds()));
+  }
+
+  
+  /*
+  public double getMaximumDistance()
+  {
+  	if (maxDistance < 0.0)
+  		maxDistance = maxDistance();
+  	return maxDistance;
+  }
+  */
+  
+  /*
+  private double maxDistance()
+  {
+    return maximumDistance( 
+        (Envelope) boundable1.getBounds(),
+        (Envelope) boundable2.getBounds());      	
+  }
+  
+  private static double maximumDistance(Envelope env1, Envelope env2)
+  {
+  	double minx = Math.min(env1.getMinX(), env2.getMinX());
+  	double miny = Math.min(env1.getMinY(), env2.getMinY());
+  	double maxx = Math.max(env1.getMaxX(), env2.getMaxX());
+  	double maxy = Math.max(env1.getMaxY(), env2.getMaxY());
+    Coordinate min = new Coordinate(minx, miny);
+    Coordinate max = new Coordinate(maxx, maxy);
+    return min.distance(max);
+  }
+  */
+  
+  /**
+   * Gets the minimum possible distance between the Boundables in
+   * this pair. 
+   * If the members are both items, this will be the
+   * exact distance between them.
+   * Otherwise, this distance will be a lower bound on 
+   * the distances between the items in the members.
+   * 
+   * @return the exact or lower bound distance for this pair
+   */
+  public double getDistance() { return distance; }
+  
+  /**
+   * Compares two pairs based on their minimum distances
+   */
+  public int compareTo(Object o)
+  {
+    BoundablePair nd = (BoundablePair) o;
+    if (distance < nd.distance) return -1;
+    if (distance > nd.distance) return 1;
+    return 0;
+  }
+
+  /**
+   * Tests if both elements of the pair are leaf nodes
+   * 
+   * @return true if both pair elements are leaf nodes
+   */
+  public boolean isLeaves()
+  {
+    return ! (isComposite(boundable1) || isComposite(boundable2));
+  }
+  
+  public static boolean isComposite(Object item)
+  {
+    return (item instanceof AbstractNode); 
+  }
+  
+  private static double area(Boundable b)
+  {
+    return ((Envelope) b.getBounds()).getArea();
+  }
+  
+  /**
+   * For a pair which is not a leaf 
+   * (i.e. has at least one composite boundable)
+   * computes a list of new pairs 
+   * from the expansion of the larger boundable.
+   * 
+   * @return a List of new pairs
+   */
+  public void expandToQueue(PriorityQueue priQ, double minDistance)
+  {
+    boolean isComp1 = isComposite(boundable1);
+    boolean isComp2 = isComposite(boundable2);
+    
+    /**
+     * HEURISTIC: If both boundable are composite,
+     * choose the one with largest area to expand.
+     * Otherwise, simply expand whichever is composite.
+     */
+    if (isComp1 && isComp2) {
+      if (area(boundable1) > area(boundable2)) {
+        expand(boundable1, boundable2, priQ, minDistance);
+        return;
+      }
+      else {
+        expand(boundable2, boundable1, priQ, minDistance);
+        return;
+      }
+    }
+    else if (isComp1) {
+      expand(boundable1, boundable2, priQ, minDistance);
+      return;
+    }
+    else if (isComp2) {
+      expand(boundable2, boundable1, priQ, minDistance);
+      return;
+    }
+    
+    throw new IllegalArgumentException("neither boundable is composite");
+  }
+  
+  private void expand(Boundable bndComposite, Boundable bndOther,
+      PriorityQueue priQ, double minDistance)
+  {
+    List children = ((AbstractNode) bndComposite).getChildBoundables();
+    for (Iterator i = children.iterator(); i.hasNext(); ) {
+      Boundable child = (Boundable) i.next();
+      BoundablePair bp = new BoundablePair(child, bndOther, itemDistance);
+      // only add to queue if this pair might contain the closest points
+      // MD - it's actually faster to construct the object rather than called distance(child, bndOther)!
+      if (bp.getDistance() < minDistance) {
+        priQ.add(bp);
+      }
+    }
+  }
+}
diff --git a/src/com/vividsolutions/jts/index/strtree/GeometryItemDistance.java b/src/com/vividsolutions/jts/index/strtree/GeometryItemDistance.java
new file mode 100644
index 0000000..84f972b
--- /dev/null
+++ b/src/com/vividsolutions/jts/index/strtree/GeometryItemDistance.java
@@ -0,0 +1,31 @@
+package com.vividsolutions.jts.index.strtree;
+
+import com.vividsolutions.jts.geom.Geometry;
+
+/**
+ * An ItemDistance function for 
+ * items which are {@link Geometry}s,
+ * using the {@link Geometry#distance(Geometry)} method.
+ * 
+ * @author Martin Davis
+ *
+ */
+public class GeometryItemDistance
+implements ItemDistance
+{
+  /**
+   * Computes the distance between two {@link Geometry} items,
+   * using the {@link Geometry#distance(Geometry)} method.
+   * 
+   * @param item1 an item which is a Geometry
+   * @param item2 an item which is a Geometry
+   * @return the distance between the geometries
+   * @throws ClassCastException if either item is not a Geometry
+   */
+  public double distance(ItemBoundable item1, ItemBoundable item2) {
+    Geometry g1 = (Geometry) item1.getItem();
+    Geometry g2 = (Geometry) item2.getItem();
+    return g1.distance(g2);    
+  }
+}
+
diff --git a/src/com/vividsolutions/jts/index/strtree/ItemDistance.java b/src/com/vividsolutions/jts/index/strtree/ItemDistance.java
new file mode 100644
index 0000000..4879816
--- /dev/null
+++ b/src/com/vividsolutions/jts/index/strtree/ItemDistance.java
@@ -0,0 +1,25 @@
+package com.vividsolutions.jts.index.strtree;
+
+
+/**
+ * A function method which computes the distance
+ * between two {@link ItemBoundable}s in an {@link STRtree}.
+ * Used for Nearest Neighbour searches.
+ * 
+ * @author Martin Davis
+ *
+ */
+public interface ItemDistance 
+{
+  /**
+   * Computes the distance between two items.
+   * 
+   * @param item1
+   * @param item2
+   * @return the distance between the items
+   * 
+   * @throws IllegalArgumentException if the metric is not applicable to the arguments
+   */
+  double distance(ItemBoundable item1, ItemBoundable item2);
+
+}
diff --git a/src/com/vividsolutions/jts/index/strtree/STRtree.java b/src/com/vividsolutions/jts/index/strtree/STRtree.java
index a4b5305..47e1fba 100644
--- a/src/com/vividsolutions/jts/index/strtree/STRtree.java
+++ b/src/com/vividsolutions/jts/index/strtree/STRtree.java
@@ -37,6 +37,7 @@ import com.vividsolutions.jts.index.strtree.AbstractSTRtree;
 import java.util.*;
 import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.util.*;
+import com.vividsolutions.jts.util.PriorityQueue;
 import com.vividsolutions.jts.index.*;
 
 /**
@@ -243,4 +244,125 @@ public class STRtree extends AbstractSTRtree implements SpatialIndex {
     return yComparator;
   }
 
+  /**
+   * Finds the two nearest items in the tree, 
+   * using {@link ItemDistance} as the distance metric.
+   * A Branch-and-Bound tree traversal algorithm is used
+   * to provide an efficient search.
+   * 
+   * @param itemDist a distance metric applicable to the items in this tree
+   * @return the pair of the nearest items
+   */
+  public Object[] nearestNeighbour(ItemDistance itemDist)
+  {
+    BoundablePair bp = new BoundablePair(this.getRoot(), this.getRoot(), itemDist);
+    return nearestNeighbour(bp);
+  }
+  
+  /**
+   * Finds the nearest item to the given object
+   * in this tree, 
+   * using {@link ItemDistance} as the distance metric.
+   * A Branch-and-Bound tree traversal algorithm is used
+   * to provide an efficient search.
+   * 
+   * @param env the envelope of the query item
+   * @param item the item to find the nearest neighbour of
+   * @param itemDist a distance metric applicable to the items in this tree and the query item
+   * @return the nearest item in this tree
+   */
+  public Object nearestNeighbour(Envelope env, Object item, ItemDistance itemDist)
+  {
+    Boundable bnd = new ItemBoundable(env, item);
+    BoundablePair bp = new BoundablePair(this.getRoot(), bnd, itemDist);
+    return nearestNeighbour(bp)[0];
+  }
+  
+  /**
+   * Finds the two nearest items from this tree 
+   * and another tree,
+   * using {@link ItemDistance} as the distance metric.
+   * A Branch-and-Bound tree traversal algorithm is used
+   * to provide an efficient search.
+   * The result value is a pair of items, 
+   * the first from this tree and the second
+   * from the argument tree.
+   * 
+   * @param tree another tree
+   * @param itemDist a distance metric applicable to the items in the trees
+   * @return the pair of the nearest items, one from each tree
+   */
+  public Object[] nearestNeighbour(STRtree tree, ItemDistance itemDist)
+  {
+    BoundablePair bp = new BoundablePair(this.getRoot(), tree.getRoot(), itemDist);
+    return nearestNeighbour(bp);
+  }
+  
+  private Object[] nearestNeighbour(BoundablePair initBndPair) 
+  {
+    return nearestNeighbour(initBndPair, Double.POSITIVE_INFINITY);
+  }
+  
+  private Object[] nearestNeighbour(BoundablePair initBndPair, double maxDistance) 
+  {
+    double distanceLowerBound = maxDistance;
+    BoundablePair minPair = null;
+    
+    // initialize internal structures
+    PriorityQueue priQ = new PriorityQueue();
+
+    // initialize queue
+    priQ.add(initBndPair);
+
+    while (! priQ.isEmpty() && distanceLowerBound > 0.0) {
+      // pop head of queue and expand one side of pair
+      BoundablePair bndPair = (BoundablePair) priQ.poll();
+      double currentDistance = bndPair.getDistance();
+      
+      /**
+       * If the distance for the first node in the queue
+       * is >= the current minimum distance, all other nodes
+       * in the queue must also have a greater distance.
+       * So the current minDistance must be the true minimum,
+       * and we are done.
+       */
+      if (currentDistance >= distanceLowerBound) 
+        break;  
+
+      /**
+       * If the pair members are leaves
+       * then their distance is the exact lower bound.
+       * Update the distanceLowerBound to reflect this
+       * (which must be smaller, due to the test 
+       * immediately prior to this). 
+       */
+      if (bndPair.isLeaves()) {
+        // assert: currentDistance < minimumDistanceFound
+        distanceLowerBound = currentDistance;
+        minPair = bndPair;
+      }
+      else {
+        // testing - does allowing a tolerance improve speed?
+        // Ans: by only about 10% - not enough to matter
+        /*
+        double maxDist = bndPair.getMaximumDistance();
+        if (maxDist * .99 < lastComputedDistance) 
+          return;
+        //*/
+
+        /**
+         * Otherwise, expand one side of the pair,
+         * (the choice of which side to expand is heuristically determined) 
+         * and insert the new expanded pairs into the queue
+         */
+        bndPair.expandToQueue(priQ, distanceLowerBound);
+      }
+    }
+    // done - return items with min distance
+    return new Object[] {    
+          ((ItemBoundable) minPair.getBoundable(0)).getItem(),
+          ((ItemBoundable) minPair.getBoundable(1)).getItem()
+      };
+  }
+
 }
diff --git a/src/com/vividsolutions/jts/io/ByteArrayInStream.java b/src/com/vividsolutions/jts/io/ByteArrayInStream.java
index 70537df..2db866a 100644
--- a/src/com/vividsolutions/jts/io/ByteArrayInStream.java
+++ b/src/com/vividsolutions/jts/io/ByteArrayInStream.java
@@ -73,12 +73,19 @@ public class ByteArrayInStream
 	 * @param buf the buffer to place the read bytes into
 	 */
 	public void read(final byte[] buf) {
-		int size = buf.length;
+		int numToRead = buf.length;
 		// don't try and copy past the end of the input
-		if ((position + size) > buffer.length) {
-			size = buffer.length - position;
+		if ((position + numToRead) > buffer.length) {
+			numToRead = buffer.length - position;
+			System.arraycopy(buffer, position, buf, 0, numToRead);
+			// zero out the unread bytes
+			for (int i = numToRead; i < buf.length; i++) {
+				buf[i] = 0;
+			}
 		}
-		System.arraycopy(buffer, position, buf, 0, size);
-		position += size;
+		else {
+			System.arraycopy(buffer, position, buf, 0, numToRead);			
+		}
+		position += numToRead;
 	}
 }
diff --git a/src/com/vividsolutions/jts/io/WKBReader.java b/src/com/vividsolutions/jts/io/WKBReader.java
index 6f5e1e6..f2c833c 100644
--- a/src/com/vividsolutions/jts/io/WKBReader.java
+++ b/src/com/vividsolutions/jts/io/WKBReader.java
@@ -41,14 +41,15 @@ import com.vividsolutions.jts.geom.*;
  * with arbitary byte stream sources.
  * <p>
  * This class reads the format describe in {@link WKBWriter}.  
- * It also partiually handles
- * the Extended WKB format used by PostGIS, by parsing and storing SRID values.
+ * It also partially handles
+ * the <b>Extended WKB</b> format used by PostGIS, 
+ * by parsing and storing SRID values.
  * <p>
  * This class is designed to support reuse of a single instance to read multiple
  * geometries. This class is not thread-safe; each thread should create its own
  * instance.
  *
- * @see WKBWriter
+ * @see WKBWriter for a formal format specification
  */
 public class WKBReader
 {
@@ -89,11 +90,13 @@ public class WKBReader
   = "Invalid geometry type encountered in ";
 
   private GeometryFactory factory;
+  private CoordinateSequenceFactory csFactory;
   private PrecisionModel precisionModel;
   // default dimension - will be set on read
   private int inputDimension = 2;
   private boolean hasSRID = false;
   private int SRID = 0;
+  private boolean isRepairRings = false;
   private ByteOrderDataInStream dis = new ByteOrderDataInStream();
   private double[] ordValues;
 
@@ -104,6 +107,7 @@ public class WKBReader
   public WKBReader(GeometryFactory geometryFactory) {
     this.factory = geometryFactory;
     precisionModel = factory.getPrecisionModel();
+    csFactory = factory.getCoordinateSequenceFactory();
   }
 
   /**
@@ -138,7 +142,6 @@ public class WKBReader
   {
     dis.setInStream(is);
     Geometry g = readGeometry();
-    setSRID(g);
     return g;
   }
 
@@ -159,6 +162,7 @@ public class WKBReader
     // determine if SRIDs are present
     hasSRID = (typeInt & 0x20000000) != 0;
 
+    int SRID = 0;
     if (hasSRID) {
       SRID = dis.readInt();
     }
@@ -167,24 +171,34 @@ public class WKBReader
     if (ordValues == null || ordValues.length < inputDimension)
       ordValues = new double[inputDimension];
 
+    Geometry geom = null;
     switch (geometryType) {
       case WKBConstants.wkbPoint :
-        return readPoint();
+        geom = readPoint();
+        break;
       case WKBConstants.wkbLineString :
-        return readLineString();
-      case WKBConstants.wkbPolygon :
-        return readPolygon();
+        geom = readLineString();
+        break;
+     case WKBConstants.wkbPolygon :
+       geom = readPolygon();
+        break;
       case WKBConstants.wkbMultiPoint :
-        return readMultiPoint();
+        geom = readMultiPoint();
+        break;
       case WKBConstants.wkbMultiLineString :
-        return readMultiLineString();
-      case WKBConstants.wkbMultiPolygon :
-        return readMultiPolygon();
+        geom = readMultiLineString();
+        break;
+     case WKBConstants.wkbMultiPolygon :
+        geom = readMultiPolygon();
+        break;
       case WKBConstants.wkbGeometryCollection :
-        return readGeometryCollection();
+        geom = readGeometryCollection();
+        break;
+      default: 
+        throw new ParseException("Unknown WKB type " + geometryType);
     }
-    throw new ParseException("Unknown WKB type " + geometryType);
-    //return null;
+    setSRID(geom, SRID);
+    return geom;
   }
 
   /**
@@ -193,7 +207,7 @@ public class WKBReader
    * @param g the geometry to update
    * @return the geometry with an updated SRID value, if required
    */
-  private Geometry setSRID(Geometry g)
+  private Geometry setSRID(Geometry g, int SRID)
   {
     if (SRID != 0)
       g.setSRID(SRID);
@@ -216,7 +230,7 @@ public class WKBReader
   private LinearRing readLinearRing() throws IOException
   {
     int size = dis.readInt();
-    CoordinateSequence pts = readCoordinateSequence(size);
+    CoordinateSequence pts = readCoordinateSequenceRing(size);
     return factory.createLinearRing(pts);
   }
 
@@ -285,7 +299,7 @@ public class WKBReader
 
   private CoordinateSequence readCoordinateSequence(int size) throws IOException
   {
-    CoordinateSequence seq = factory.getCoordinateSequenceFactory().create(size, inputDimension);
+    CoordinateSequence seq = csFactory.create(size, inputDimension);
     int targetDim = seq.getDimension();
     if (targetDim > inputDimension)
       targetDim = inputDimension;
@@ -298,6 +312,14 @@ public class WKBReader
     return seq;
   }
 
+  private CoordinateSequence readCoordinateSequenceRing(int size) throws IOException
+  {
+  	CoordinateSequence seq = readCoordinateSequence(size);
+  	if (! isRepairRings) return seq;
+  	if (CoordinateSequences.isRing(seq)) return seq;
+  	return CoordinateSequences.ensureValidRing(csFactory, seq);
+  }
+
   /**
    * Reads a coordinate value with the specified dimensionality.
    * Makes the X and Y ordinates precise according to the precision model
diff --git a/src/com/vividsolutions/jts/io/WKBWriter.java b/src/com/vividsolutions/jts/io/WKBWriter.java
index a9bd1f2..9a189d3 100644
--- a/src/com/vividsolutions/jts/io/WKBWriter.java
+++ b/src/com/vividsolutions/jts/io/WKBWriter.java
@@ -41,20 +41,128 @@ import com.vividsolutions.jts.util.Assert;
  * Supports use of an {@link OutStream}, which allows easy use
  * with arbitary byte stream sinks.
  * <p>
- * The WKB format is specified in the OGC Simple Features for SQL specification.
- * This implementation supports the extended WKB standard for representing
- * 3-dimensional coordinates.  The presence of 3D coordinates is signified
- * by setting the high bit of the wkbType word.
+ * The WKB format is specified in the 
+ * OGC <A HREF="http://www.opengis.org/techno/specs.htm"><i>Simple Features for SQL</i></a>
+ * specification.
+ * This implementation also supports the <b>Extended WKB</b> 
+ * standard. Extended WKB allows writing 3-dimensional coordinates
+ * and including the geometry SRID value.  
+ * The presence of 3D coordinates is signified
+ * by setting the high bit of the <tt>wkbType</tt> word.
+ * The presence of an SRID is signified 
+ * by setting the third bit of the <tt>wkbType</tt> word.
+ * EWKB format is upward compatible with the original SFS WKB format.
  * <p>
  * Empty Points cannot be represented in WKB; an
  * {@link IllegalArgumentException} will be thrown if one is
- * written. The WKB specification does not support representing {@link LinearRing}s;
+ * written. 
+ * <p>
+ * The WKB specification does not support representing {@link LinearRing}s;
  * they will be written as {@link LineString}s.
  * <p>
  * This class is designed to support reuse of a single instance to read multiple
  * geometries. This class is not thread-safe; each thread should create its own
  * instance.
- *
+ * 
+ * <h3>Syntax</h3>
+ * The following syntax specification describes the version of Well-Known Binary
+ * supported by JTS.
+ * <p>
+ * <i>The specification uses a syntax language similar to that used in
+ * the C language.  Bitfields are specified from hi-order to lo-order bits.</i>
+ * <p>
+ * <blockquote><pre>
+ * 
+ * <b>byte</b> = 1 byte
+ * <b>uint32</b> = 32 bit unsigned integer (4 bytes)
+ * <b>double</b> = double precision number (8 bytes)
+ * 
+ * abstract Point { }
+ * 
+ * Point2D extends Point {
+ * 	<b>double</b> x;
+ * 	<b>double</b> y;
+ * }
+ * 
+ * Point3D extends Point {
+ * 	<b>double</b> x;
+ * 	<b>double</b> y;
+ * 	<b>double</b> z;
+ * }
+ * 
+ * LinearRing {
+ * 	<b>uint32</b> numPoints;
+ * 	Point points[numPoints];
+ * }
+ * 
+ * enum wkbGeometryType {
+ * 	wkbPoint = 1,
+ * 	wkbLineString = 2,
+ * 	wkbPolygon = 3,
+ * 	wkbMultiPoint = 4,
+ * 	wkbMultiLineString = 5,
+ * 	wkbMultiPolygon = 6,
+ * 	wkbGeometryCollection = 7
+ * }
+ * 
+ * enum byteOrder {
+ * 	wkbXDR = 0,	// Big Endian
+ * 	wkbNDR = 1 	// Little Endian
+ * }
+ * 
+ * WKBType {
+ * 	<b>uint32</b> wkbGeometryType : 8; // values from enum wkbGeometryType
+ * }
+ * 
+ * EWKBType {
+ * 	<b>uint32</b> is3D : 1; 	// 0 = 2D, 1 = 3D
+ * 	<b>uint32</b> noData1 : 1; 
+ * 	<b>uint32</b> hasSRID : 1;  	// 0, no, 1 = yes
+ * 	<b>uint32</b> noData2 : 21; 
+ * 	<b>uint32</b> wkbGeometryType : 8; // values from enum wkbGeometryType
+ * }
+ * 
+ * abstract WKBGeometry {
+ * 	<b>byte</b> byteOrder;		// values from enum byteOrder
+ * 	EWKBType wkbType
+ * 	[ <b>uint32</b> srid; ] 	// only if hasSRID = yes
+ * }
+ * 
+ * WKBPoint extends WKBGeometry {
+ * 	Point point;
+ * }
+ * 
+ * WKBLineString extends WKBGeometry {
+ * 	<b>uint32</b> numCoords;
+ * 	Point points[numCoords];
+ * }
+ * 
+ * WKBPolygon extends WKBGeometry {
+ * 	<b>uint32</b> numRings;
+ * 	LinearRing rings[numRings];
+ * }
+ * 
+ * WKBMultiPoint extends WKBGeometry {
+ * 	<b>uint32</b> numElems;
+ * 	WKBPoint elems[numElems];
+ * }
+ * 
+ * WKBMultiLineString extends WKBGeometry {
+ * 	<b>uint32</b> numElems;
+ * 	WKBLineString elems[numElems];
+ * }
+ * 
+ * wkbMultiPolygon extends WKBGeometry {
+ * 	<b>uint32</b> numElems;
+ * 	WKBPolygon elems[numElems];
+ * }
+ * 
+ * WKBGeometryCollection extends WKBGeometry {
+ * 	<b>uint32</b> numElems;
+ * 	WKBGeometry elems[numElems];
+ * }
+ * 
+ * </pre></blockquote> 
  * @see WKBReader
  */
 public class WKBWriter
@@ -100,6 +208,7 @@ public class WKBWriter
 
   private int outputDimension = 2;
   private int byteOrder;
+  private boolean includeSRID = false;
   private ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
   private OutStream byteArrayOutStream = new OutputStreamOutStream(byteArrayOS);
   // holds output data values
@@ -116,7 +225,7 @@ public class WKBWriter
   /**
    * Creates a writer that writes {@link Geometry}s with
    * the given dimension (2 or 3) for output coordinates
-   * and {@link BIG_ENDIAN} byte order.
+   * and {@link ByteOrderValues#BIG_ENDIAN} byte order.
    * If the input geometry has a small coordinate dimension,
    * coordinates will be padded with {@link NULL_ORDINATE}.
    *
@@ -129,21 +238,54 @@ public class WKBWriter
   /**
    * Creates a writer that writes {@link Geometry}s with
    * the given dimension (2 or 3) for output coordinates
-   * and byte order
+   * and {@link ByteOrderValues#BIG_ENDIAN} byte order. This constructor also
+   * takes a flag to control whether srid information will be
+   * written.
    * If the input geometry has a small coordinate dimension,
    * coordinates will be padded with {@link NULL_ORDINATE}.
    *
    * @param outputDimension the coordinate dimension to output (2 or 3)
+   * @param includeSRID indicates whether SRID should be written
+   */
+  public WKBWriter(int outputDimension, boolean includeSRID) {
+    this(outputDimension, ByteOrderValues.BIG_ENDIAN, includeSRID);
+  }
+  
+  /**
+   * Creates a writer that writes {@link Geometry}s with
+   * the given dimension (2 or 3) for output coordinates
+   * and byte order
+   * If the input geometry has a small coordinate dimension,
+   * coordinates will be padded with {@link Coordinate#NULL_ORDINATE}.
+   *
+   * @param outputDimension the coordinate dimension to output (2 or 3)
    * @param byteOrder the byte ordering to use
    */
   public WKBWriter(int outputDimension, int byteOrder) {
-    this.outputDimension = outputDimension;
-    this.byteOrder = byteOrder;
-
-    if (outputDimension < 2 || outputDimension > 3)
-      throw new IllegalArgumentException("Output dimension must be 2 or 3");
+      this(outputDimension, byteOrder, false);
   }
-
+  
+  /**
+   * Creates a writer that writes {@link Geometry}s with
+   * the given dimension (2 or 3) for output coordinates
+   * and byte order. This constructor also takes a flag to 
+   * control whether srid information will be written.
+   * If the input geometry has a small coordinate dimension,
+   * coordinates will be padded with {@link Coordinate#NULL_ORDINATE}.
+   *
+   * @param outputDimension the coordinate dimension to output (2 or 3)
+   * @param byteOrder the byte ordering to use
+   * @param includeSRID indicates whether SRID should be written
+   */
+  public WKBWriter(int outputDimension, int byteOrder, boolean includeSRID) {
+      this.outputDimension = outputDimension;
+      this.byteOrder = byteOrder;
+      this.includeSRID = includeSRID;
+      
+      if (outputDimension < 2 || outputDimension > 3)
+        throw new IllegalArgumentException("Output dimension must be 2 or 3");
+  }
+  
   /**
    * Writes a {@link Geometry} into a byte array.
    *
@@ -179,7 +321,8 @@ public class WKBWriter
     else if (geom instanceof Polygon)
       writePolygon((Polygon) geom, os);
     else if (geom instanceof MultiPoint)
-      writeGeometryCollection(WKBConstants.wkbMultiPoint, (MultiPoint) geom, os);
+      writeGeometryCollection(WKBConstants.wkbMultiPoint, 
+          (MultiPoint) geom, os);
     else if (geom instanceof MultiLineString)
       writeGeometryCollection(WKBConstants.wkbMultiLineString,
           (MultiLineString) geom, os);
@@ -199,7 +342,7 @@ public class WKBWriter
     if (pt.getCoordinateSequence().size() == 0)
       throw new IllegalArgumentException("Empty Points cannot be represented in WKB");
     writeByteOrder(os);
-    writeGeometryType(WKBConstants.wkbPoint, os);
+    writeGeometryType(WKBConstants.wkbPoint, pt, os);
     writeCoordinateSequence(pt.getCoordinateSequence(), false, os);
   }
 
@@ -207,14 +350,14 @@ public class WKBWriter
       throws IOException
   {
     writeByteOrder(os);
-    writeGeometryType(WKBConstants.wkbLineString, os);
+    writeGeometryType(WKBConstants.wkbLineString, line, os);
     writeCoordinateSequence(line.getCoordinateSequence(), true, os);
   }
 
   private void writePolygon(Polygon poly, OutStream os) throws IOException
   {
     writeByteOrder(os);
-    writeGeometryType(WKBConstants.wkbPolygon, os);
+    writeGeometryType(WKBConstants.wkbPolygon, poly, os);
     writeInt(poly.getNumInteriorRing() + 1, os);
     writeCoordinateSequence(poly.getExteriorRing().getCoordinateSequence(), true, os);
     for (int i = 0; i < poly.getNumInteriorRing(); i++) {
@@ -227,7 +370,7 @@ public class WKBWriter
       OutStream os) throws IOException
   {
     writeByteOrder(os);
-    writeGeometryType(geometryType, os);
+    writeGeometryType(geometryType, gc, os);
     writeInt(gc.getNumGeometries(), os);
     for (int i = 0; i < gc.getNumGeometries(); i++) {
       write(gc.getGeometryN(i), os);
@@ -243,12 +386,16 @@ public class WKBWriter
     os.write(buf, 1);
   }
 
-  private void writeGeometryType(int geometryType, OutStream os)
+  private void writeGeometryType(int geometryType, Geometry g, OutStream os)
       throws IOException
   {
     int flag3D = (outputDimension == 3) ? 0x80000000 : 0;
     int typeInt = geometryType | flag3D;
+    typeInt |= includeSRID ? 0x20000000 : 0;
     writeInt(typeInt, os);
+    if (includeSRID) {
+        writeInt(g.getSRID(), os);
+    }
   }
 
   private void writeInt(int intValue, OutStream os) throws IOException
@@ -278,7 +425,7 @@ public class WKBWriter
     
     // only write 3rd dim if caller has requested it for this writer
     if (outputDimension >= 3) {
-      // if 3rd dim is requested, only access and write it if the CS provides is
+      // if 3rd dim is requested, only write it if the CoordinateSequence provides it
     	double ordVal = Coordinate.NULL_ORDINATE;
     	if (seq.getDimension() >= 3)
     		ordVal = seq.getOrdinate(index, 2);
@@ -286,4 +433,4 @@ public class WKBWriter
       os.write(buf, 8);
     }
   }
-}
\ No newline at end of file
+}
diff --git a/src/com/vividsolutions/jts/io/WKTReader.java b/src/com/vividsolutions/jts/io/WKTReader.java
index a0c17c8..046c689 100644
--- a/src/com/vividsolutions/jts/io/WKTReader.java
+++ b/src/com/vividsolutions/jts/io/WKTReader.java
@@ -61,8 +61,9 @@ import java.util.ArrayList;
  *
  * <h3>Notes:</h3>
  * <ul>
+ * <li>Keywords are case-insensitive.
  * <li>The reader supports non-standard "LINEARRING" tags.
- * <li>The reader uses Double.parseDouble to perform the conversion of ASCII
+ * <li>The reader uses <tt>Double.parseDouble</tt> to perform the conversion of ASCII
  * numbers to floating point.  This means it supports the Java
  * syntax for floating point literals (including scientific notation).
  * </ul>
diff --git a/src/com/vividsolutions/jts/io/WKTWriter.java b/src/com/vividsolutions/jts/io/WKTWriter.java
index 21721b2..c2d0a52 100644
--- a/src/com/vividsolutions/jts/io/WKTWriter.java
+++ b/src/com/vividsolutions/jts/io/WKTWriter.java
@@ -42,8 +42,9 @@ import java.text.DecimalFormatSymbols;
 /**
  * Writes the Well-Known Text representation of a {@link Geometry}.
  * The Well-Known Text format is defined in the
- * <A HREF="http://www.opengis.org/techno/specs.htm">
- * OGC Simple Features Specification for SQL</A>.
+ * OGC <A HREF="http://www.opengis.org/techno/specs.htm">
+ * <i>Simple Features Specification for SQL</i></A>.
+ * See {@link WKTReader} for a formal specification of the format syntax.
  * <p>
  * The <code>WKTWriter</code> outputs coordinates rounded to the precision
  * model. Only the maximum number of decimal places 
@@ -53,7 +54,7 @@ import java.text.DecimalFormatSymbols;
  * The SFS WKT spec does not define a special tag for {@link LinearRing}s.
  * Under the spec, rings are output as <code>LINESTRING</code>s.
  * In order to allow precisely specifying constructed geometries, 
- * JTS supports a non-standard <code>LINEARRING</code> tag which is used 
+ * JTS also supports a non-standard <code>LINEARRING</code> tag which is used 
  * to output LinearRings.
  *
  * @version 1.7
@@ -129,8 +130,9 @@ public class WKTWriter
     // specify decimal separator explicitly to avoid problems in other locales
     DecimalFormatSymbols symbols = new DecimalFormatSymbols();
     symbols.setDecimalSeparator('.');
-    return new DecimalFormat("0" + (decimalPlaces > 0 ? "." : "")
-                 +  stringOfChar('#', decimalPlaces), symbols);
+    String fmtString = "0" + (decimalPlaces > 0 ? "." : "")
+                 +  stringOfChar('#', decimalPlaces);
+    return new DecimalFormat(fmtString, symbols);
   }
 
   /**
diff --git a/src/com/vividsolutions/jts/io/gml2/GMLReader.java b/src/com/vividsolutions/jts/io/gml2/GMLReader.java
index 65ce5fe..0c4c66c 100644
--- a/src/com/vividsolutions/jts/io/gml2/GMLReader.java
+++ b/src/com/vividsolutions/jts/io/gml2/GMLReader.java
@@ -35,12 +35,12 @@ package com.vividsolutions.jts.io.gml2;
 import java.io.*;
 
 import javax.xml.parsers.*;
+
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
-import com.vividsolutions.jts.geom.Geometry;
-import com.vividsolutions.jts.geom.GeometryFactory;
+import com.vividsolutions.jts.geom.*;
 
 /**
  * Reads a GML2 geometry from an XML fragment into a {@link Geometry}.
diff --git a/src/com/vividsolutions/jts/linearref/LinearIterator.java b/src/com/vividsolutions/jts/linearref/LinearIterator.java
index a2aa2ea..13a32d1 100644
--- a/src/com/vividsolutions/jts/linearref/LinearIterator.java
+++ b/src/com/vividsolutions/jts/linearref/LinearIterator.java
@@ -28,11 +28,12 @@ public class LinearIterator
     return loc.getSegmentIndex();
   }
 
-  private Geometry linear;
+  private Geometry linearGeom;
   private final int numLines;
 
   /**
    * Invariant: currentLine <> null if the iterator is pointing at a valid coordinate
+   * @throws IllegalArgumentException if linearGeom is not lineal
    */
   private LineString currentLine;
   private int componentIndex = 0;
@@ -42,6 +43,7 @@ public class LinearIterator
    * Creates an iterator initialized to the start of a linear {@link Geometry}
    *
    * @param linear the linear geometry to iterate over
+   * @throws IllegalArgumentException if linearGeom is not lineal
    */
   public LinearIterator(Geometry linear) {
     this(linear, 0, 0);
@@ -53,6 +55,7 @@ public class LinearIterator
    *
    * @param linear the linear geometry to iterate over
    * @param start the location to start at
+   * @throws IllegalArgumentException if linearGeom is not lineal
    */
   public LinearIterator(Geometry linear, LinearLocation start) {
     this(linear, start.getComponentIndex(), segmentEndVertexIndex(start));
@@ -60,15 +63,19 @@ public class LinearIterator
 
   /**
    * Creates an iterator starting at
-   * a component and vertex in a linear {@link Geometry}
+   * a specified component and vertex in a linear {@link Geometry}
    *
-   * @param linear the linear geometry to iterate over
+   * @param linearGeom the linear geometry to iterate over
    * @param componentIndex the component to start at
    * @param vertexIndex the vertex to start at
+   * @throws IllegalArgumentException if linearGeom is not lineal
    */
-  public LinearIterator(Geometry linear, int componentIndex, int vertexIndex) {
-    this.linear = linear;
-    numLines = linear.getNumGeometries();
+  public LinearIterator(Geometry linearGeom, int componentIndex, int vertexIndex) 
+  {
+  	if (! (linearGeom instanceof Lineal))
+  			throw new IllegalArgumentException("Lineal geometry is required");
+    this.linearGeom = linearGeom;
+    numLines = linearGeom.getNumGeometries();
     this.componentIndex = componentIndex;
     this.vertexIndex = vertexIndex;
     loadCurrentLine();
@@ -80,7 +87,7 @@ public class LinearIterator
       currentLine = null;
       return;
     }
-    currentLine = (LineString) linear.getGeometryN(componentIndex);
+    currentLine = (LineString) linearGeom.getGeometryN(componentIndex);
   }
 
   /**
diff --git a/src/com/vividsolutions/jts/math/DD.java b/src/com/vividsolutions/jts/math/DD.java
new file mode 100644
index 0000000..ec23e72
--- /dev/null
+++ b/src/com/vividsolutions/jts/math/DD.java
@@ -0,0 +1,1301 @@
+/*
+ * 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.math;
+
+import java.io.*;
+
+/**
+ * Implements extended-precision floating-point numbers 
+ * which maintain 106 bits (approximately 30 decimal digits) of precision. 
+ * <p>
+ * A DoubleDouble uses a representation containing two double-precision values.
+ * A number x is represented as a pair of doubles, x.hi and x.lo,
+ * such that the number represented by x is x.hi + x.lo, where
+ * <pre>
+ *    |x.lo| <= 0.5*ulp(x.hi)
+ * </pre>
+ * and ulp(y) means "unit in the last place of y".  
+ * The basic arithmetic operations are implemented using 
+ * convenient properties of IEEE-754 floating-point arithmetic.
+ * <p>
+ * The range of values which can be represented is the same as in IEEE-754.  
+ * The precision of the representable numbers 
+ * is twice as great as IEEE-754 double precision.
+ * <p>
+ * The correctness of the arithmetic algorithms relies on operations
+ * being performed with standard IEEE-754 double precision and rounding.
+ * This is the Java standard arithmetic model, but for performance reasons 
+ * Java implementations are not
+ * constrained to using this standard by default.  
+ * Some processors (notably the Intel Pentium architecure) perform
+ * floating point operations in (non-IEEE-754-standard) extended-precision.
+ * A JVM implementation may choose to use the non-standard extended-precision
+ * as its default arithmetic mode.
+ * To prevent this from happening, this code uses the
+ * Java <tt>strictfp</tt> modifier, 
+ * which forces all operations to take place in the standard IEEE-754 rounding model. 
+ * <p>
+ * The API provides both a set of value-oriented operations 
+ * and a set of mutating operations.
+ * Value-oriented operations treat DoubleDouble values as 
+ * immutable; operations on them return new objects carrying the result
+ * of the operation.  This provides a simple and safe semantics for
+ * writing DoubleDouble expressions.  However, there is a performance
+ * penalty for the object allocations required.
+ * The mutable interface updates object values in-place.
+ * It provides optimum memory performance, but requires
+ * care to ensure that aliasing errors are not created
+ * and constant values are not changed.
+ * <p>
+ * This implementation uses algorithms originally designed variously by 
+ * Knuth, Kahan, Dekker, and Linnainmaa.  
+ * Douglas Priest developed the first C implementation of these techniques. 
+ * Other more recent C++ implementation are due to Keith M. Briggs and David Bailey et al.
+ * 
+ * <h3>References</h3>
+ * <ul>
+ * <li>Priest, D., <i>Algorithms for Arbitrary Precision Floating Point Arithmetic</i>,
+ * in P. Kornerup and D. Matula, Eds., Proc. 10th Symposium on Computer Arithmetic, 
+ * IEEE Computer Society Press, Los Alamitos, Calif., 1991.
+ * <li>Yozo Hida, Xiaoye S. Li and David H. Bailey, 
+ * <i>Quad-Double Arithmetic: Algorithms, Implementation, and Application</i>, 
+ * manuscript, Oct 2000; Lawrence Berkeley National Laboratory Report BNL-46996.
+ * <li>David Bailey, <i>High Precision Software Directory</i>; 
+ * <tt>http://crd.lbl.gov/~dhbailey/mpdist/index.html</tt>
+ * </ul>
+ * 
+ * 
+ * @author Martin Davis
+ *
+ */
+public strictfp final class DD 
+  implements Serializable, Comparable, Cloneable
+{
+  /**
+   * The value nearest to the constant Pi.
+   */
+  public static final DD PI = new DD(
+      3.141592653589793116e+00,
+      1.224646799147353207e-16);
+  
+  /**
+   * The value nearest to the constant 2 * Pi.
+   */ 
+  public static final DD TWO_PI = new DD(
+      6.283185307179586232e+00,
+      2.449293598294706414e-16);
+  
+  /**
+   * The value nearest to the constant Pi / 2.
+   */
+  public static final DD PI_2 = new DD(
+      1.570796326794896558e+00,
+      6.123233995736766036e-17);
+  
+  /**
+   * The value nearest to the constant e (the natural logarithm base). 
+   */
+  public static final DD E = new DD(
+      2.718281828459045091e+00,
+      1.445646891729250158e-16);
+  
+  /**
+   * A value representing the result of an operation which does not return a valid number.
+   */
+  public static final DD NaN = new DD(Double.NaN, Double.NaN);
+  
+  /**
+   * The smallest representable relative difference between two {link @ DoubleDouble} values
+   */
+  public static final double EPS = 1.23259516440783e-32;  /* = 2^-106 */
+  
+  private static DD createNaN()
+  {
+    return new DD(Double.NaN, Double.NaN); 
+  }
+  
+  /**
+   * Converts the string argument to a DoubleDouble number.
+   * 
+   * @param str a string containing a representation of a numeric value
+   * @return the extended precision version of the value
+   * @throws NumberFormatException if <tt>s</tt> is not a valid representation of a number
+   */
+  public static DD valueOf(String str) 
+  throws NumberFormatException
+  { 
+    return parse(str); 
+    }
+  
+  /**
+   * Converts the <tt>double</tt> argument to a DoubleDouble number.
+   * 
+   * @param x a numeric value
+   * @return the extended precision version of the value
+   */
+  public static DD valueOf(double x) { return new DD(x); }
+  
+  /**
+   * The value to split a double-precision value on during multiplication
+   */
+  private static final double SPLIT = 134217729.0D; // 2^27+1, for IEEE double
+  
+  /**
+   * The high-order component of the double-double precision value.
+   */
+  private double hi = 0.0;
+  
+  /**
+   * The low-order component of the double-double precision value.
+   */
+  private double lo = 0.0;
+  
+  /**
+   * Creates a new DoubleDouble with value 0.0.
+   */
+  public DD()
+  {
+    init(0.0);
+  }
+  
+  /**
+   * Creates a new DoubleDouble with value x.
+   * 
+   * @param x the value to initialize
+   */
+  public DD(double x)
+  {
+    init(x);
+  }
+  
+  /**
+   * Creates a new DoubleDouble with value (hi, lo).
+   * 
+   * @param hi the high-order component 
+   * @param lo the high-order component 
+   */
+  public DD(double hi, double lo)
+  {
+    init(hi, lo);
+  }
+  
+  /**
+   * Creates a new DoubleDouble with value equal to the argument.
+   * 
+   * @param dd the value to initialize
+   */
+  public DD(DD dd)
+  {
+    init(dd);
+  }
+  
+  /**
+   * Creates a new DoubleDouble with value equal to the argument.
+   * 
+   * @param str the value to initialize by
+   * @throws NumberFormatException if <tt>str</tt> is not a valid representation of a number
+   */
+  public DD(String str)
+    throws NumberFormatException
+  {
+    this(parse(str));
+  }
+  
+  /**
+   * Creates a new DoubleDouble with the value of the argument.
+   * 
+   * @param dd the DoubleDouble value to copy
+   * @return a copy of the input value
+   */
+  public static DD copy(DD dd)
+  {
+    return new DD(dd);
+  }
+  
+  /**
+   * Creates and returns a copy of this value.
+   * 
+   * @return a copy of this value
+   */
+  public Object clone()
+  {
+    try {
+      return super.clone();
+    }
+    catch (CloneNotSupportedException ex) {
+      // should never reach here
+      return null;
+    }
+  }
+  
+  private void init(double x)
+  {
+    init(x, 0.0);
+  }
+  
+  private void init(double hi, double lo)
+  {
+    this.hi = hi;
+    this.lo = lo;   
+  }
+  
+  private void init(DD dd)
+  {
+    init(dd.hi, dd.lo); 
+  }
+  
+  /*
+  double getHighComponent() { return hi; }
+  
+  double getLowComponent() { return lo; }
+  */
+  
+  // Testing only - should not be public
+  /*
+  public void RENORM()
+  {
+    double s = hi + lo;
+    double err = lo - (s - hi);
+    hi = s;
+    lo = err;
+  }
+  */
+  
+  /**
+   * Returns a DoubleDouble whose value is <tt>(this + y)</tt>.
+   * 
+   * @param y the addend
+   * @return <tt>(this + y)</tt>
+   */ 
+  public DD add(DD y)
+  {
+    return copy(this).selfAdd(y);
+  }
+  
+  /**
+   * Returns a DoubleDouble whose value is <tt>(this + y)</tt>.
+   * 
+   * @param y the addend
+   * @return <tt>(this + y)</tt>
+   */ 
+  public DD add(double y)
+  {
+    return copy(this).selfAdd(y);
+  }
+  
+  /**
+   * Adds the argument to the value of <tt>this</tt>.
+   * To prevent altering constants, 
+   * this method <b>must only</b> be used on values known to 
+   * be newly created. 
+   * 
+   * @param y the addend
+   * @return this object, increased by y
+   */
+  public DD selfAdd(DD y)
+  {
+    return selfAdd(y.hi, y.lo);
+  }
+  
+  /**
+   * Adds the argument to the value of <tt>this</tt>.
+   * To prevent altering constants, 
+   * this method <b>must only</b> be used on values known to 
+   * be newly created. 
+   * 
+   * @param y the addend
+   * @return this object, increased by y
+   */
+  public DD selfAdd(double y)
+  {
+    return selfAdd(y, 0.0);
+  }
+  
+  private DD selfAdd(double yhi, double ylo)
+  {
+    double H, h, T, t, S, s, e, f;
+    S = hi + yhi; 
+    T = lo + ylo; 
+    e = S - hi; 
+    f = T - lo; 
+    s = S-e; 
+    t = T-f; 
+    s = (yhi-e)+(hi-s); 
+    t = (ylo-f)+(lo-t); 
+    e = s+T; H = S+e; h = e+(S-H); e = t+h;
+  
+    double zhi = H + e;
+    double zlo = e + (H - zhi);
+    hi = zhi;
+    lo = zlo;
+    return this;
+  }
+  
+  /**
+   * Computes a new DoubleDouble object whose value is <tt>(this - y)</tt>.
+   * 
+   * @param y the subtrahend
+   * @return <tt>(this - y)</tt>
+   */
+  public DD subtract(DD y)
+  {
+    return add(y.negate());
+  }
+  
+  /**
+   * Computes a new DoubleDouble object whose value is <tt>(this - y)</tt>.
+   * 
+   * @param y the subtrahend
+   * @return <tt>(this - y)</tt>
+   */
+  public DD subtract(double y)
+  {
+    return add(-y);
+  }
+  
+  
+  /**
+   * Subtracts the argument from the value of <tt>this</tt>.
+   * To prevent altering constants, 
+   * this method <b>must only</b> be used on values known to 
+   * be newly created. 
+   * 
+   * @param y the addend
+   * @return this object, decreased by y
+   */
+  public DD selfSubtract(DD y)
+  {
+    if (isNaN()) return this;
+    return selfAdd(-y.hi, -y.lo);
+  }
+  
+  /**
+   * Subtracts the argument from the value of <tt>this</tt>.
+   * To prevent altering constants, 
+   * this method <b>must only</b> be used on values known to 
+   * be newly created. 
+   * 
+   * @param y the addend
+   * @return this object, decreased by y
+   */
+  public DD selfSubtract(double y)
+  {
+    if (isNaN()) return this;
+    return selfAdd(-y, 0.0);
+  }
+  
+  /**
+   * Returns a DoubleDouble whose value is <tt>-this</tt>.
+   * 
+   * @return <tt>-this</tt>
+   */
+  public DD negate()
+  {
+    if (isNaN()) return this;
+    return new DD(-hi, -lo);
+  }
+  
+  /**
+   * Returns a new DoubleDouble whose value is <tt>(this * y)</tt>.
+   * 
+   * @param y the multiplicand
+   * @return <tt>(this * y)</tt>
+   */
+  public DD multiply(DD y)
+  {
+    if (y.isNaN()) return createNaN();
+    return copy(this).selfMultiply(y);
+  }
+  
+  /**
+   * Returns a new DoubleDouble whose value is <tt>(this * y)</tt>.
+   * 
+   * @param y the multiplicand
+   * @return <tt>(this * y)</tt>
+   */
+  public DD multiply(double y)
+  {
+    if (Double.isNaN(y)) return createNaN();
+    return copy(this).selfMultiply(y, 0.0);
+  }
+  
+  /**
+   * Multiplies this object by the argument, returning <tt>this</tt>.
+   * To prevent altering constants, 
+   * this method <b>must only</b> be used on values known to 
+   * be newly created. 
+   * 
+   * @param y the value to multiply by
+   * @return this object, multiplied by y
+   */
+  public DD selfMultiply(DD y)
+  {
+    return selfMultiply(y.hi, y.lo);
+  }
+  
+  /**
+   * Multiplies this object by the argument, returning <tt>this</tt>.
+   * To prevent altering constants, 
+   * this method <b>must only</b> be used on values known to 
+   * be newly created. 
+   * 
+   * @param y the value to multiply by
+   * @return this object, multiplied by y
+   */
+  public DD selfMultiply(double y)
+  {
+    return selfMultiply(y, 0.0);
+  }
+  
+  private DD selfMultiply(double yhi, double ylo)
+  {
+    double hx, tx, hy, ty, C, c;
+    C = SPLIT * hi; hx = C-hi; c = SPLIT * yhi;
+    hx = C-hx; tx = hi-hx; hy = c-yhi; 
+    C = hi*yhi; hy = c-hy; ty = yhi-hy;
+    c = ((((hx*hy-C)+hx*ty)+tx*hy)+tx*ty)+(hi*ylo+lo*yhi);
+    double zhi = C+c; hx = C-zhi; 
+    double zlo = c+hx;
+    hi = zhi;
+    lo = zlo;
+    return this;
+  }
+  
+  /**
+   * Computes a new DoubleDouble whose value is <tt>(this / y)</tt>.
+   * 
+   * @param y the divisor
+   * @return a new object with the value <tt>(this / y)</tt>
+   */
+  public DD divide(DD y)
+  {
+    double hc, tc, hy, ty, C, c, U, u;
+    C = hi/y.hi; c = SPLIT*C; hc =c-C;  u = SPLIT*y.hi; hc = c-hc;
+    tc = C-hc; hy = u-y.hi; U = C * y.hi; hy = u-hy; ty = y.hi-hy;
+    u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty;
+    c = ((((hi-U)-u)+lo)-C*y.lo)/y.hi;
+    u = C+c; 
+    
+    double zhi = u; 
+    double zlo = (C-u)+c;
+    return new DD(zhi, zlo);
+  }
+  
+  /**
+   * Computes a new DoubleDouble whose value is <tt>(this / y)</tt>.
+   * 
+   * @param y the divisor
+   * @return a new object with the value <tt>(this / y)</tt>
+   */
+  public DD divide(double y)
+  {
+    if (Double.isNaN(y)) return createNaN();
+    return copy(this).selfDivide(y, 0.0);  
+  }
+
+  /**
+   * Divides this object by the argument, returning <tt>this</tt>.
+   * To prevent altering constants, 
+   * this method <b>must only</b> be used on values known to 
+   * be newly created. 
+   * 
+   * @param y the value to divide by
+   * @return this object, divided by y
+   */
+  public DD selfDivide(DD y)
+  {
+    return selfDivide(y.hi, y.lo);
+  }
+  
+  /**
+   * Divides this object by the argument, returning <tt>this</tt>.
+   * To prevent altering constants, 
+   * this method <b>must only</b> be used on values known to 
+   * be newly created. 
+   * 
+   * @param y the value to divide by
+   * @return this object, divided by y
+   */
+  public DD selfDivide(double y)
+  {
+    return selfDivide(y, 0.0);
+  }
+  
+  private DD selfDivide(double yhi, double ylo)
+  {
+    double hc, tc, hy, ty, C, c, U, u;
+    C = hi/yhi; c = SPLIT*C; hc =c-C;  u = SPLIT*yhi; hc = c-hc;
+    tc = C-hc; hy = u-yhi; U = C * yhi; hy = u-hy; ty = yhi-hy;
+    u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty;
+    c = ((((hi-U)-u)+lo)-C*ylo)/yhi;
+    u = C+c; 
+    
+    hi = u; 
+    lo = (C-u)+c;
+    return this;
+  }
+  
+  /**
+   * Returns a DoubleDouble whose value is  <tt>1 / this</tt>.
+   * 
+   * @return the reciprocal of this value
+   */
+  public DD reciprocal()
+  {
+    double  hc, tc, hy, ty, C, c, U, u;
+    C = 1.0/hi; 
+    c = SPLIT*C; 
+    hc =c-C;  
+    u = SPLIT*hi;
+    hc = c-hc; tc = C-hc; hy = u-hi; U = C*hi; hy = u-hy; ty = hi-hy;
+    u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty;
+    c = ((((1.0-U)-u))-C*lo)/hi;
+    
+    double  zhi = C+c; 
+    double  zlo = (C-zhi)+c;
+    return new DD(zhi, zlo);
+  }
+  
+  /**
+   * Returns the largest (closest to positive infinity) 
+   * value that is not greater than the argument 
+   * and is equal to a mathematical integer.
+   * Special cases:
+   * <ul>
+   * <li>If this value is NaN, returns NaN.
+   * </ul>
+   * 
+   * @return the largest (closest to positive infinity) 
+   * value that is not greater than the argument 
+   * and is equal to a mathematical integer.
+   */
+  public DD floor()
+  {
+    if (isNaN()) return NaN;
+    double fhi=Math.floor(hi);
+    double flo = 0.0;
+    // Hi is already integral.  Floor the low word
+    if (fhi == hi) {
+      flo = Math.floor(lo);
+    }
+      // do we need to renormalize here?    
+    return new DD(fhi, flo); 
+  }
+  
+  /**
+   * Returns the smallest (closest to negative infinity) value 
+   * that is not less than the argument and is equal to a mathematical integer. 
+   * Special cases:
+   * <ul>
+   * <li>If this value is NaN, returns NaN.
+   * </ul>
+   * 
+   * @return the smallest (closest to negative infinity) value 
+   * that is not less than the argument and is equal to a mathematical integer. 
+   */
+  public DD ceil()
+  {
+    if (isNaN()) return NaN;
+    double fhi=Math.ceil(hi);
+    double flo = 0.0;
+    // Hi is already integral.  Ceil the low word
+    if (fhi == hi) {
+      flo = Math.ceil(lo);
+      // do we need to renormalize here?
+    }
+    return new DD(fhi, flo); 
+  }
+  
+  /**
+   * Returns an integer indicating the sign of this value.
+   * <ul>
+   * <li>if this value is > 0, returns 1
+   * <li>if this value is < 0, returns -1
+   * <li>if this value is = 0, returns 0
+   * <li>if this value is NaN, returns 0
+   * </ul>
+   * 
+   * @return an integer indicating the sign of this value
+   */
+  public int signum()
+  {
+    if (isPositive()) return 1;
+    if (isNegative()) return -1;
+    return 0;
+  }
+  
+  /**
+   * Rounds this value to the nearest integer.
+   * The value is rounded to an integer by adding 1/2 and taking the floor of the result.
+   * Special cases:
+   * <ul>
+   * <li>If this value is NaN, returns NaN.
+   * </ul>
+   *
+   * @return this value rounded to the nearest integer
+   */
+  public DD rint()
+  {
+    if (isNaN()) return this;
+    // may not be 100% correct
+    DD plus5 = this.add(0.5);
+    return plus5.floor();
+  }
+  
+  /**
+   * Returns the integer which is largest in absolute value and not further
+   * from zero than this value.  
+   * Special cases:
+   * <ul>
+   * <li>If this value is NaN, returns NaN.
+   * </ul>
+   *  
+   * @return the integer which is largest in absolute value and not further from zero than this value
+   */
+  public DD trunc()
+  {
+    if (isNaN()) return NaN;
+    if (isPositive()) 
+      return floor();
+    else 
+      return ceil();
+  }
+  
+  /**
+   * Returns the absolute value of this value.
+   * Special cases:
+   * <ul>
+   * <li>If this value is NaN, it is returned.
+   * </ul>
+   * 
+   * @return the absolute value of this value
+   */
+  public DD abs()
+  {
+    if (isNaN()) return NaN;
+    if (isNegative())
+      return negate();
+    return new DD(this);
+  }
+  
+  /**
+   * Computes the square of this value.
+   * 
+   * @return the square of this value.
+   */
+  public DD sqr()
+  {
+    return this.multiply(this);
+  }
+  
+  /**
+   * Computes the square of this value.
+   * 
+   * @return the square of this value.
+   */
+  public static DD sqr(double x)
+  {
+    return valueOf(x).selfMultiply(x);
+  }
+  
+  /**
+   * Computes the positive square root of this value.
+   * If the number is NaN or negative, NaN is returned.
+   * 
+   * @return the positive square root of this number. 
+   * If the argument is NaN or less than zero, the result is NaN.
+   */
+  public DD sqrt()
+  {
+    /* Strategy:  Use Karp's trick:  if x is an approximation
+    to sqrt(a), then
+
+       sqrt(a) = a*x + [a - (a*x)^2] * x / 2   (approx)
+
+    The approximation is accurate to twice the accuracy of x.
+    Also, the multiplication (a*x) and [-]*x can be done with
+    only half the precision.
+ */
+
+    if (isZero())
+      return valueOf(0.0);
+
+    if (isNegative()) {
+      return NaN;
+    }
+
+    double x = 1.0 / Math.sqrt(hi);
+    double ax = hi * x;
+    
+    DD axdd = valueOf(ax);
+    DD diffSq = this.subtract(axdd.sqr());
+    double d2 = diffSq.hi * (x * 0.5);
+    
+    return axdd.add(d2);
+  }
+  
+  public static DD sqrt(double x)
+  {
+    return valueOf(x).sqrt();
+  }
+  
+  /**
+   * Computes the value of this number raised to an integral power.
+   * Follows semantics of Java Math.pow as closely as possible.
+   * 
+   * @param exp the integer exponent
+   * @return x raised to the integral power exp
+   */
+  public DD pow(int exp)
+  {
+    if (exp == 0.0)
+      return valueOf(1.0);
+    
+    DD r = new DD(this);
+    DD s = valueOf(1.0);
+    int n = Math.abs(exp);
+
+    if (n > 1) {
+      /* Use binary exponentiation */
+      while (n > 0) {
+        if (n % 2 == 1) {
+          s.selfMultiply(r);
+        }
+        n /= 2;
+        if (n > 0)
+          r = r.sqr();
+      }
+    } else {
+      s = r;
+    }
+
+    /* Compute the reciprocal if n is negative. */
+    if (exp < 0)
+      return s.reciprocal();
+    return s;
+  }
+  
+  /*------------------------------------------------------------
+   *   Conversion Functions
+   *------------------------------------------------------------
+   */
+  
+  /**
+   * Converts this value to the nearest double-precision number.
+   * 
+   * @return the nearest double-precision number to this value
+   */
+  public double doubleValue()
+  {
+    return hi + lo;
+  }
+     
+  /**
+   * Converts this value to the nearest integer.
+   * 
+   * @return the nearest integer to this value
+   */
+  public int intValue()
+  {
+    return (int) hi;
+  }
+  
+  /*------------------------------------------------------------
+   *   Predicates
+   *------------------------------------------------------------
+   */
+  
+  /**
+   * Tests whether this value is equal to 0.
+   * 
+   * @return true if this value is equal to 0
+   */
+  public boolean isZero() 
+  {
+    return hi == 0.0 && lo == 0.0;
+  }
+
+  /**
+   * Tests whether this value is less than 0.
+   * 
+   * @return true if this value is less than 0
+   */
+  public boolean isNegative()
+  {
+    return hi < 0.0 || (hi == 0.0 && lo < 0.0);
+  }
+  
+  /**
+   * Tests whether this value is greater than 0.
+   * 
+   * @return true if this value is greater than 0
+   */
+  public boolean isPositive()
+  {
+    return hi > 0.0 || (hi == 0.0 && lo > 0.0);
+  }
+  
+  /**
+   * Tests whether this value is NaN.
+   * 
+   * @return true if this value is NaN
+   */
+  public boolean isNaN() { return Double.isNaN(hi); }
+  
+  /**
+   * Tests whether this value is equal to another <tt>DoubleDouble</tt> value.
+   * 
+   * @param y a DoubleDouble value
+   * @return true if this value = y
+   */
+  public boolean equals(DD y)
+  {
+    return hi == y.hi && lo == y.lo;
+  }
+  
+  /**
+   * Tests whether this value is greater than another <tt>DoubleDouble</tt> value.
+   * @param y a DoubleDouble value
+   * @return true if this value > y
+   */
+  public boolean gt(DD y)
+  {
+    return (hi > y.hi) || (hi == y.hi && lo > y.lo);
+  }
+  /**
+   * Tests whether this value is greater than or equals to another <tt>DoubleDouble</tt> value.
+   * @param y a DoubleDouble value
+   * @return true if this value >= y
+   */
+  public boolean ge(DD y)
+  {
+    return (hi > y.hi) || (hi == y.hi && lo >= y.lo);
+  }
+  /**
+   * Tests whether this value is less than another <tt>DoubleDouble</tt> value.
+   * @param y a DoubleDouble value
+   * @return true if this value < y
+   */
+  public boolean lt(DD y)
+  {
+    return (hi < y.hi) || (hi == y.hi && lo < y.lo);
+  }
+  /**
+   * Tests whether this value is less than or equal to another <tt>DoubleDouble</tt> value.
+   * @param y a DoubleDouble value
+   * @return true if this value <= y
+   */
+  public boolean le(DD y)
+  {
+    return (hi < y.hi) || (hi == y.hi && lo <= y.lo);
+  }
+  
+  /**
+   * Compares two DoubleDouble objects numerically.
+   * 
+   * @return -1,0 or 1 depending on whether this value is less than, equal to
+   * or greater than the value of <tt>o</tt>
+   */
+  public int compareTo(Object o) 
+  {
+    DD other = (DD) o;
+
+    if (hi < other.hi) return -1;
+    if (hi > other.hi) return 1;
+    if (lo < other.lo) return -1;
+    if (lo > other.lo) return 1;
+    return 0;
+  }
+  
+  
+  /*------------------------------------------------------------
+   *   Output
+   *------------------------------------------------------------
+   */
+
+  private static final int MAX_PRINT_DIGITS = 32;
+  private static final DD TEN = DD.valueOf(10.0);
+  private static final DD ONE = DD.valueOf(1.0);
+  private static final String SCI_NOT_EXPONENT_CHAR = "E";
+  private static final String SCI_NOT_ZERO = "0.0E0";
+  
+  /**
+   * Dumps the components of this number to a string.
+   * 
+   * @return a string showing the components of the number
+   */
+  public String dump()
+  {
+    return "DD<" + hi + ", " + lo + ">";
+  }
+  
+  /**
+   * Returns a string representation of this number, in either standard or scientific notation.
+   * If the magnitude of the number is in the range [ 10<sup>-3</sup>, 10<sup>8</sup> ]
+   * standard notation will be used.  Otherwise, scientific notation will be used.
+   * 
+   * @return a string representation of this number
+   */
+  public String toString()
+  {
+    int mag = magnitude(hi);
+    if (mag >= -3 && mag <= 20)
+      return toStandardNotation();
+    return toSciNotation();
+  }
+  
+  /**
+   * Returns the string representation of this value in standard notation.
+   * 
+   * @return the string representation in standard notation 
+   */
+  public String toStandardNotation()
+  {
+    String specialStr = getSpecialNumberString();
+    if (specialStr != null)
+      return specialStr;
+    
+    int[] magnitude = new int[1];
+    String sigDigits = extractSignificantDigits(true, magnitude);
+    int decimalPointPos = magnitude[0] + 1;
+
+    String num = sigDigits;
+    // add a leading 0 if the decimal point is the first char
+    if (sigDigits.charAt(0) == '.') {
+      num = "0" + sigDigits;
+    }
+    else if (decimalPointPos < 0) {
+      num = "0." + stringOfChar('0', -decimalPointPos) + sigDigits;
+    }
+    else if (sigDigits.indexOf('.') == -1) {
+      // no point inserted - sig digits must be smaller than magnitude of number
+      // add zeroes to end to make number the correct size
+      int numZeroes = decimalPointPos - sigDigits.length();
+      String zeroes = stringOfChar('0', numZeroes);
+      num = sigDigits + zeroes + ".0";
+    }
+    
+    if (this.isNegative())
+      return "-" + num;
+    return num;
+  }
+  
+  /**
+   * Returns the string representation of this value in scientific notation.
+   * 
+   * @return the string representation in scientific notation 
+   */
+  public String toSciNotation()
+  {
+    // special case zero, to allow as
+    if (isZero())
+      return SCI_NOT_ZERO;
+    
+    String specialStr = getSpecialNumberString();
+    if (specialStr != null)
+      return specialStr;
+    
+    int[] magnitude = new int[1];
+    String digits = extractSignificantDigits(false, magnitude);
+    String expStr = SCI_NOT_EXPONENT_CHAR + magnitude[0];
+    
+    // should never have leading zeroes
+    // MD - is this correct?  Or should we simply strip them if they are present?
+    if (digits.charAt(0) == '0') {
+      throw new IllegalStateException("Found leading zero: " + digits);
+    }
+    
+    // add decimal point
+    String trailingDigits = "";
+    if (digits.length() > 1)
+      trailingDigits = digits.substring(1);
+    String digitsWithDecimal = digits.charAt(0) + "." + trailingDigits;
+    
+    if (this.isNegative())
+      return "-" + digitsWithDecimal + expStr;
+    return digitsWithDecimal + expStr;
+  }
+  
+  
+  /**
+   * Extracts the significant digits in the decimal representation of the argument.
+   * A decimal point may be optionally inserted in the string of digits
+   * (as long as its position lies within the extracted digits
+   * - if not, the caller must prepend or append the appropriate zeroes and decimal point).
+   * 
+   * @param y the number to extract ( >= 0)
+   * @param decimalPointPos the position in which to insert a decimal point
+   * @return the string containing the significant digits and possibly a decimal point
+   */
+  private String extractSignificantDigits(boolean insertDecimalPoint, int[] magnitude)
+  {
+    DD y = this.abs();
+    // compute *correct* magnitude of y
+    int mag = magnitude(y.hi);
+    DD scale = TEN.pow(mag);
+    y = y.divide(scale);
+    
+    // fix magnitude if off by one
+    if (y.gt(TEN)) {
+      y = y.divide(TEN);
+      mag += 1;
+    }
+    else if (y.lt(ONE)) {
+      y = y.multiply(TEN);
+      mag -= 1;   
+    }
+    
+    int decimalPointPos = mag + 1;
+    StringBuffer buf = new StringBuffer();
+    int numDigits = MAX_PRINT_DIGITS - 1;
+    for (int i = 0; i <= numDigits; i++) {
+      if (insertDecimalPoint && i == decimalPointPos) {
+        buf.append('.');
+      }
+      int digit = (int) y.hi;
+//      System.out.println("printDump: [" + i + "] digit: " + digit + "  y: " + y.dump() + "  buf: " + buf);
+
+      /**
+       * This should never happen, due to heuristic checks on remainder below
+       */
+      if (digit < 0 || digit > 9) {
+//        System.out.println("digit > 10 : " + digit);
+//        throw new IllegalStateException("Internal errror: found digit = " + digit);
+      }
+      /**
+       * If a negative remainder is encountered, simply terminate the extraction.  
+       * This is robust, but maybe slightly inaccurate.
+       * My current hypothesis is that negative remainders only occur for very small lo components, 
+       * so the inaccuracy is tolerable
+       */
+      if (digit < 0) {
+        break;
+        // throw new IllegalStateException("Internal errror: found digit = " + digit);
+      }
+      boolean rebiasBy10 = false;
+      char digitChar = 0;
+      if (digit > 9) {
+        // set flag to re-bias after next 10-shift
+        rebiasBy10 = true;
+        // output digit will end up being '9'
+        digitChar = '9';
+      }
+      else {
+       digitChar = (char) ('0' + digit);
+      }
+      buf.append(digitChar);
+      y = (y.subtract(DD.valueOf(digit))
+          .multiply(TEN));
+      if (rebiasBy10)
+        y.selfAdd(TEN);
+      
+      boolean continueExtractingDigits = true;
+      /**
+       * Heuristic check: if the remaining portion of 
+       * y is non-positive, assume that output is complete
+       */
+//      if (y.hi <= 0.0)
+//        if (y.hi < 0.0)
+//        continueExtractingDigits = false;
+      /**
+       * Check if remaining digits will be 0, and if so don't output them.
+       * Do this by comparing the magnitude of the remainder with the expected precision.
+       */
+      int remMag = magnitude(y.hi);
+      if (remMag < 0 && Math.abs(remMag) >= (numDigits - i)) 
+        continueExtractingDigits = false;
+      if (! continueExtractingDigits)
+        break;
+    }
+    magnitude[0] = mag;
+    return buf.toString();
+  }
+
+
+  /**
+   * Creates a string of a given length containing the given character
+   * 
+   * @param ch the character to be repeated
+   * @param len the len of the desired string
+   * @return the string 
+   */
+  private static String stringOfChar(char ch, int len)
+  {
+    StringBuffer buf = new StringBuffer();
+    for (int i = 0; i < len; i++) {
+      buf.append(ch);
+    }
+    return buf.toString();
+  }
+  
+  /**
+   * Returns the string for this value if it has a known representation.
+   * (E.g. NaN or 0.0)
+   * 
+   * @return the string for this special number
+   * @return null if the number is not a special number
+   */
+  private String getSpecialNumberString()
+  {
+    if (isZero()) return "0.0";
+    if (isNaN())  return "NaN ";
+    return null;
+  }
+  
+
+  
+  /**
+   * Determines the decimal magnitude of a number.
+   * The magnitude is the exponent of the greatest power of 10 which is less than
+   * or equal to the number.
+   * 
+   * @param x the number to find the magnitude of
+   * @return the decimal magnitude of x
+   */
+  private static int magnitude(double x)
+  {
+    double xAbs = Math.abs(x);
+    double xLog10 = Math.log(xAbs) / Math.log(10);
+    int xMag = (int) Math.floor(xLog10); 
+    /**
+     * Since log computation is inexact, there may be an off-by-one error
+     * in the computed magnitude. 
+     * Following tests that magnitude is correct, and adjusts it if not
+     */
+    double xApprox = Math.pow(10, xMag);
+    if (xApprox * 10 <= xAbs)
+      xMag += 1;
+    
+    return xMag;
+  }
+  
+
+  /*------------------------------------------------------------
+   *   Input
+   *------------------------------------------------------------
+   */
+
+  /**
+   * Converts a string representation of a real number into a DoubleDouble value.
+   * The format accepted is similar to the standard Java real number syntax.  
+   * It is defined by the following regular expression:
+   * <pre>
+   * [<tt>+</tt>|<tt>-</tt>] {<i>digit</i>} [ <tt>.</tt> {<i>digit</i>} ] [ ( <tt>e</tt> | <tt>E</tt> ) [<tt>+</tt>|<tt>-</tt>] {<i>digit</i>}+
+   * <pre>
+   * 
+   * @param str the string to parse
+   * @return the value of the parsed number
+   * @throws NumberFormatException if <tt>str</tt> is not a valid representation of a number
+   */
+  public static DD parse(String str)
+    throws NumberFormatException
+  {
+    int i = 0;
+    int strlen = str.length();
+    
+    // skip leading whitespace
+    while (Character.isWhitespace(str.charAt(i)))
+      i++;
+    
+    // check for sign
+    boolean isNegative = false;
+    if (i < strlen) {
+      char signCh = str.charAt(i);
+      if (signCh == '-' || signCh == '+') {
+        i++;
+        if (signCh == '-') isNegative = true;
+      }
+    }
+    
+    // scan all digits and accumulate into an integral value
+    // Keep track of the location of the decimal point (if any) to allow scaling later
+    DD val = new DD();
+
+    int numDigits = 0;
+    int numBeforeDec = 0;
+    int exp = 0;
+    while (true) {
+      if (i >= strlen)
+        break;
+      char ch = str.charAt(i);
+      i++;
+      if (Character.isDigit(ch)) {
+        double d = ch - '0';
+        val.selfMultiply(TEN);
+        // MD: need to optimize this
+        val.selfAdd(d);
+        numDigits++;
+        continue;
+      }
+      if (ch == '.') {
+        numBeforeDec = numDigits;
+        continue;
+      }
+      if (ch == 'e' || ch == 'E') {
+        String expStr = str.substring(i);
+        // this should catch any format problems with the exponent
+        try {
+          exp = Integer.parseInt(expStr);
+        }
+        catch (NumberFormatException ex) {
+          throw new NumberFormatException("Invalid exponent " + expStr + " in string " + str);  
+        }
+        break;
+      }
+      throw new NumberFormatException("Unexpected character '" + ch 
+          + "' at position " + i 
+          + " in string " + str);
+    }
+    DD val2 = val;
+    
+    // scale the number correctly
+    int numDecPlaces = numDigits - numBeforeDec - exp;
+    if (numDecPlaces == 0) {
+      val2 = val;
+    }
+    else if (numDecPlaces > 0) {  
+      DD scale = TEN.pow(numDecPlaces);
+      val2 = val.divide(scale);
+    }
+    else if (numDecPlaces < 0) {
+      DD scale = TEN.pow(-numDecPlaces);    
+      val2 = val.multiply(scale);
+    }
+    // apply leading sign, if any
+    if (isNegative) {
+      return val2.negate();
+    }
+    return val2;
+
+  }
+}
\ No newline at end of file
diff --git a/src/com/vividsolutions/jts/math/MathUtil.java b/src/com/vividsolutions/jts/math/MathUtil.java
new file mode 100644
index 0000000..0935a5f
--- /dev/null
+++ b/src/com/vividsolutions/jts/math/MathUtil.java
@@ -0,0 +1,93 @@
+/*
+ * 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.math;
+
+/**
+ * Various utility functions for mathematical and numerical operations.
+ * 
+ * @author mbdavis
+ *
+ */
+public class MathUtil 
+{
+  /**
+   * Clamps a <tt>double</tt> value to a given range.
+   * @param x the value to clamp
+   * @param min the minimum value of the range
+   * @param max the maximum value of the range
+   * @return the clamped value
+   */
+  public static double clamp(double x, double min, double max)
+  {
+    if (x < min) return min;
+    if (x > max) return max;
+    return x;
+  }
+  
+  /**
+   * Clamps an <tt>int</tt> value to a given range.
+   * @param x the value to clamp
+   * @param min the minimum value of the range
+   * @param max the maximum value of the range
+   * @return the clamped value
+   */
+  public static int clamp(int x, int min, int max)
+  {
+    if (x < min) return min;
+    if (x > max) return max;
+    return x;
+  }
+  
+  private static final double LOG_10 = Math.log(10);
+  
+  /**
+   * Computes the base-10 logarithm of a <tt>double</tt> value.
+   * <ul>
+   * <li>If the argument is NaN or less than zero, then the result is NaN.
+   * <li>If the argument is positive infinity, then the result is positive infinity.
+   * <li>If the argument is positive zero or negative zero, then the result is negative infinity.
+   * </ul>
+   *   
+   * @param x a positive number
+   * @return the value log a, the base-10 logarithm of the input value
+   */
+  public static double log10(double x)
+  {
+    double ln = Math.log(x);
+    if (Double.isInfinite(ln)) return ln;
+    if (Double.isNaN(ln)) return ln;
+    return ln / LOG_10;
+  }
+  
+
+}
diff --git a/src/com/vividsolutions/jts/geom/util/Matrix.java b/src/com/vividsolutions/jts/math/Matrix.java
similarity index 63%
rename from src/com/vividsolutions/jts/geom/util/Matrix.java
rename to src/com/vividsolutions/jts/math/Matrix.java
index 179d22a..6e1d887 100644
--- a/src/com/vividsolutions/jts/geom/util/Matrix.java
+++ b/src/com/vividsolutions/jts/math/Matrix.java
@@ -1,4 +1,36 @@
-package com.vividsolutions.jts.geom.util;
+/*
+ * 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.math;
 
 /**
  * Implements some 2D matrix operations 
@@ -32,7 +64,7 @@ public class Matrix
    * In order to avoid overhead the algorithm runs in-place
    * on A - if A should not be modified the client must supply a copy.
    * 
-   * @param A an nxn matrix in row/column order )modified by this method)
+   * @param a an nxn matrix in row/column order )modified by this method)
    * @param b a vector of length n
    * 
    * @return a vector containing the solution (if any)
diff --git a/src/com/vividsolutions/jts/math/Vector2D.java b/src/com/vividsolutions/jts/math/Vector2D.java
new file mode 100644
index 0000000..14e24e0
--- /dev/null
+++ b/src/com/vividsolutions/jts/math/Vector2D.java
@@ -0,0 +1,345 @@
+/*
+ * 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.math;
+
+import com.vividsolutions.jts.algorithm.Angle;
+import com.vividsolutions.jts.algorithm.RobustDeterminant;
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.util.Assert;
+
+/**
+ * A 2-dimensional mathematical vector represented by double-precision X and Y components.
+ * 
+ * @author mbdavis
+ * 
+ */
+public class Vector2D {
+  /**
+   * Creates a new vector with given X and Y components.
+   * 
+   * @param x the x component
+   * @param y the y component
+   * @return a new vector
+   */
+	public static Vector2D create(double x, double y) {
+		return new Vector2D(x, y);
+	}
+
+  /**
+   * Creates a new vector from an existing one.
+   * 
+   * @param v the vector to copy
+   * @return a new vector
+   */
+	public static Vector2D create(Vector2D v) {
+		return new Vector2D(v);
+	}
+
+  /**
+   * Creates a vector from a {@link Coordinate}. 
+   * 
+   * @param coord the Coordinate to copy
+   * @return a new vector
+   */
+	public static Vector2D create(Coordinate coord) {
+		return new Vector2D(coord);
+	}
+
+  /**
+   * Creates a vector with the direction and magnitude
+   * of the difference between the 
+   * <tt>to</tt> and <tt>from</tt> {@link Coordinate}s.
+   * 
+   * @param from the origin Coordinate
+   * @param to the destination Coordinate
+   * @return a new vector
+   */
+	public static Vector2D create(Coordinate from, Coordinate to) {
+		return new Vector2D(from, to);
+	}
+
+	/**
+	 * The X component of this vector.
+	 */
+	private double x;
+
+	/**
+	 * The Y component of this vector.
+	 */
+	private double y;
+
+	public Vector2D() {
+		this(0.0, 0.0);
+	}
+
+	public Vector2D(double x, double y) {
+		this.x = x;
+		this.y = y;
+	}
+
+	public Vector2D(Vector2D v) {
+		x = v.x;
+		y = v.y;
+	}
+
+	public Vector2D(Coordinate from, Coordinate to) {
+		x = to.x - from.x;
+		y = to.y - from.y;
+	}
+
+	public Vector2D(Coordinate v) {
+		x = v.x;
+		y = v.y;
+	}
+
+	public double getX() {
+		return x;
+	}
+
+	public double getY() {
+		return y;
+	}
+
+	public double getComponent(int index) {
+		if (index == 0)
+			return x;
+		return y;
+	}
+
+	public Vector2D add(Vector2D v) {
+		return create(x + v.x, y + v.y);
+	}
+
+	public Vector2D subtract(Vector2D v) {
+		return create(x - v.x, y - v.y);
+	}
+
+  /**
+   * Multiplies the vector by a scalar value.
+   * 
+   * @param d the value to multiply by
+   * @return a new vector with the value v * d
+   */
+	public Vector2D multiply(double d) {
+		return create(x * d, y * d);
+	}
+
+  /**
+   * Divides the vector by a scalar value.
+   * 
+   * @param d the value to divide by
+   * @return a new vector with the value v / d
+   */
+	public Vector2D divide(double d) {
+		return create(x / d, y / d);
+	}
+
+	public Vector2D negate() {
+		return create(-x , -y);
+	}
+
+	public double length() {
+		return Math.sqrt(x * x + y * y);
+	}
+
+	public double lengthSquared() {
+		return x * x + y * y;
+	}
+
+	public Vector2D normalize() {
+		double length = length();
+		if (length > 0.0)
+			return divide(length());
+		return create(0.0, 0.0);
+	}
+
+	public Vector2D average(Vector2D v) {
+		return weightedSum(v, 0.5);
+	}
+  
+	public Vector2D weightedSum(Vector2D v, double frac) {
+		return create(
+				frac * x + (1.0 - frac) * v.x, 
+				frac * y + (1.0 - frac) * v.y);
+	}
+
+  /**
+   * Computes the distance between this vector and another one.
+   * @param v a vector
+   * @return the distance between the vectors
+   */
+  public double distance(Vector2D v)
+  {
+    double delx = v.x - x;
+    double dely = v.y - y;
+    return Math.sqrt(delx * delx + dely * dely);
+  }
+  
+	/**
+	 * Computes the dot-product of two vectors
+	 * 
+	 * @param v a vector
+	 * @return the dot product of the vectors
+	 */
+	public double dot(Vector2D v) {
+		return x * v.x + y * v.y;
+	}
+
+	public double angle()
+	{
+		return Math.atan2(y, x);
+	}
+	
+  public double angle(Vector2D v)
+  {
+    return Angle.diff(v.angle(), angle());
+  }
+  
+  public double angleTo(Vector2D v)
+  {
+    double a1 = angle();
+    double a2 = v.angle();
+    double angDel = a2 - a1;
+    
+    // normalize, maintaining orientation
+    if (angDel <= -Math.PI)
+      return angDel + Angle.PI_TIMES_2;
+    if (angDel > Math.PI)
+      return angDel - Angle.PI_TIMES_2;
+    return angDel;
+  }
+  
+	public Vector2D rotate(double angle)
+	{
+		double cos = Math.cos(angle);
+		double sin = Math.sin(angle);
+		return create(
+				x * cos - y * sin,
+				x * sin + y * cos
+				);
+	}
+	
+	/**
+	 * Rotates a vector by a given number of quarter-circles (i.e. multiples of 90
+	 * degrees or Pi/2 radians). A positive number rotates counter-clockwise, a
+	 * negative number rotates clockwise. Under this operation the magnitude of
+	 * the vector and the absolute values of the ordinates do not change, only
+	 * their sign and ordinate index.
+	 * 
+	 * @param numQuarters
+	 *          the number of quarter-circles to rotate by
+	 * @return the rotated vector.
+	 */
+	public Vector2D rotateByQuarterCircle(int numQuarters) {
+		int nQuad = numQuarters % 4;
+		if (numQuarters < 0 && nQuad != 0) {
+			nQuad = nQuad + 4;
+		}
+		switch (nQuad) {
+		case 0:
+			return create(x, y);
+		case 1:
+			return create(-y, x);
+		case 2:
+			return create(-x, -y);
+		case 3:
+			return create(y, -x);
+		}
+		Assert.shouldNeverReachHere();
+		return null;
+	}
+
+  public boolean isParallel(Vector2D v)
+  {
+    return 0.0 == RobustDeterminant.signOfDet2x2(x, y, v.x, v.y);
+  }
+  
+	public Coordinate translate(Coordinate coord) {
+		return new Coordinate(x + coord.x, y + coord.y);
+	}
+
+	public Coordinate toCoordinate() {
+		return new Coordinate(x, y);
+	}
+
+  /**
+   * Creates a copy of this vector
+   * 
+   * @return a copy of this vector
+   */
+  public Object clone()
+  {
+    return new Vector2D(this);
+  }
+  
+  /**
+   * Gets a string representation of this vector
+   * 
+   * @return a string representing this vector
+   */
+	public String toString() {
+		return "[" + x + ", " + y + "]";
+	}
+	
+	/**
+	 * Tests if a vector <tt>o</tt> has the same values for the x and y
+	 * components.
+	 * 
+	 * @param o
+	 *          a <tt>Vector2D</tt> with which to do the comparison.
+	 * @return true if <tt>other</tt> is a <tt>Vector2D</tt> with the same
+	 *         values for the x and y components.
+	 */
+	public boolean equals(Object o) {
+		if (!(o instanceof Vector2D)) {
+			return false;
+		}
+		Vector2D v = (Vector2D) o;
+		return x == v.x && y == v.y;
+	}
+
+	/**
+	 * Gets a hashcode for this vector.
+	 * 
+	 * @return a hashcode for this vector
+	 */
+	public int hashCode() {
+		// Algorithm from Effective Java by Joshua Bloch
+		int result = 17;
+		result = 37 * result + Coordinate.hashCode(x);
+		result = 37 * result + Coordinate.hashCode(y);
+		return result;
+	}
+
+
+}
diff --git a/src/com/vividsolutions/jts/noding/FastNodingValidator.java b/src/com/vividsolutions/jts/noding/FastNodingValidator.java
index 4ef2d27..653801e 100644
--- a/src/com/vividsolutions/jts/noding/FastNodingValidator.java
+++ b/src/com/vividsolutions/jts/noding/FastNodingValidator.java
@@ -34,6 +34,7 @@
 package com.vividsolutions.jts.noding;
 
 import java.util.*;
+
 import com.vividsolutions.jts.algorithm.*;
 import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.util.*;
@@ -42,15 +43,15 @@ import com.vividsolutions.jts.io.*;
 /**
  * Validates that a collection of {@link SegmentString}s is correctly noded.
  * Indexing is used to improve performance.
- * This class assumes that at least one round of noding has already been performed
- * (which may still leave intersections, due to rounding issues).
+ * In the most common use case, validation stops after a single 
+ * non-noded intersection is detected.
  * Does NOT check a-b-a collapse situations. 
- * Also does not check for endpt-interior vertex intersections.
+ * Also does not check for endpoint-interior vertex intersections.
  * This should not be a problem, since the noders should be
  * able to compute intersections between vertices correctly.
- * User may either test the valid condition, or request that a 
- * {@link TopologyException} 
- * be thrown.
+ * <p>
+ * The client may either test the {@link #isValid} condition, 
+ * or request that a suitable {@link TopologyException} be thrown.
  *
  * @version 1.7
  */
@@ -59,14 +60,30 @@ public class FastNodingValidator
   private LineIntersector li = new RobustLineIntersector();
 
   private Collection segStrings;
+  private boolean findAllIntersections = false;
   private InteriorIntersectionFinder segInt = null;
   private boolean isValid = true;
   
+  /**
+   * Creates a new noding validator for a given set of linework.
+   * 
+   * @param segStrings a collection of {@link SegmentString}s
+   */
   public FastNodingValidator(Collection segStrings)
   {
     this.segStrings = segStrings;
   }
 
+  public void setFindAllIntersections(boolean findAllIntersections)
+  {
+    this.findAllIntersections = findAllIntersections;
+  }
+  
+  public List getIntersections()
+  {
+    return segInt.getIntersections();
+  }
+
   /**
    * Checks for an intersection and 
    * reports if one is found.
@@ -125,6 +142,7 @@ public class FastNodingValidator
   	 */
   	isValid = true;
   	segInt = new InteriorIntersectionFinder(li);
+    segInt.setFindAllIntersections(findAllIntersections);
   	MCIndexNoder noder = new MCIndexNoder();
   	noder.setSegmentIntersector(segInt);
   	noder.computeNodes(segStrings);
diff --git a/src/com/vividsolutions/jts/noding/FastSegmentSetIntersectionFinder.java b/src/com/vividsolutions/jts/noding/FastSegmentSetIntersectionFinder.java
index 6524ee5..c8b5fc2 100644
--- a/src/com/vividsolutions/jts/noding/FastSegmentSetIntersectionFinder.java
+++ b/src/com/vividsolutions/jts/noding/FastSegmentSetIntersectionFinder.java
@@ -4,7 +4,7 @@ import java.util.*;
 import com.vividsolutions.jts.algorithm.*;
 
 /**
- * Finds if two sets of {@link SegmentStrings}s intersect.
+ * Finds if two sets of {@link SegmentString}s intersect.
  * Uses indexing for fast performance and to optimize repeated tests
  * against a target set of lines.
  * Short-circuited to return as soon an intersection is found.
diff --git a/src/com/vividsolutions/jts/noding/InteriorIntersectionFinder.java b/src/com/vividsolutions/jts/noding/InteriorIntersectionFinder.java
index a105b72..cfa7b7d 100644
--- a/src/com/vividsolutions/jts/noding/InteriorIntersectionFinder.java
+++ b/src/com/vividsolutions/jts/noding/InteriorIntersectionFinder.java
@@ -32,6 +32,9 @@
  */
 package com.vividsolutions.jts.noding;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.algorithm.LineIntersector;
 //import com.vividsolutions.jts.util.Debug;
@@ -45,10 +48,12 @@ import com.vividsolutions.jts.algorithm.LineIntersector;
 public class InteriorIntersectionFinder
     implements SegmentIntersector
 {
+	private boolean findAllIntersections = false;
 	private boolean isCheckEndSegmentsOnly = false;
   private LineIntersector li;
   private Coordinate interiorIntersection = null;
   private Coordinate[] intSegments = null;
+  private List intersections = new ArrayList();
 
   /**
    * Creates an intersection finder which finds an interior intersection
@@ -62,6 +67,16 @@ public class InteriorIntersectionFinder
     interiorIntersection = null;
   }
 
+  public void setFindAllIntersections(boolean findAllIntersections)
+  {
+    this.findAllIntersections = findAllIntersections;
+  }
+  
+  public List getIntersections()
+  {
+    return intersections;
+  }
+  
   /**
    * Sets whether only end segments should be tested for interior intersection.
    * This is a performance optimization that may be used if
@@ -110,7 +125,7 @@ public class InteriorIntersectionFinder
   /**
    * This method is called by clients
    * of the {@link SegmentIntersector} class to process
-   * intersections for two segments of the {@link SegmentStrings} being intersected.
+   * intersections for two segments of the {@link SegmentString}s being intersected.
    * Note that some clients (such as {@link MonotoneChain}s) may optimize away
    * this call for segment pairs which they have determined do not intersect
    * (e.g. by an disjoint envelope test).
@@ -154,6 +169,7 @@ public class InteriorIntersectionFinder
       	intSegments[3] = p11;
       	
       	interiorIntersection = li.getIntersection(0);
+      	intersections.add(interiorIntersection);
       }
     }
   }
@@ -175,6 +191,7 @@ public class InteriorIntersectionFinder
   
   public boolean isDone()
   { 
+  	if (findAllIntersections) return false;
   	return interiorIntersection != null;
   }
 }
\ No newline at end of file
diff --git a/src/com/vividsolutions/jts/noding/IntersectionAdder.java b/src/com/vividsolutions/jts/noding/IntersectionAdder.java
index 798d81a..947bb46 100644
--- a/src/com/vividsolutions/jts/noding/IntersectionAdder.java
+++ b/src/com/vividsolutions/jts/noding/IntersectionAdder.java
@@ -136,7 +136,7 @@ public class IntersectionAdder
   /**
    * This method is called by clients
    * of the {@link SegmentIntersector} class to process
-   * intersections for two segments of the {@link SegmentStrings} being intersected.
+   * intersections for two segments of the {@link SegmentString}s being intersected.
    * Note that some clients (such as {@link MonotoneChain}s) may optimize away
    * this call for segment pairs which they have determined do not intersect
    * (e.g. by an disjoint envelope test).
diff --git a/src/com/vividsolutions/jts/noding/IntersectionFinderAdder.java b/src/com/vividsolutions/jts/noding/IntersectionFinderAdder.java
index dcd9c08..1dba8e4 100644
--- a/src/com/vividsolutions/jts/noding/IntersectionFinderAdder.java
+++ b/src/com/vividsolutions/jts/noding/IntersectionFinderAdder.java
@@ -66,7 +66,7 @@ public class IntersectionFinderAdder
   /**
    * This method is called by clients
    * of the {@link SegmentIntersector} class to process
-   * intersections for two segments of the {@link SegmentStrings} being intersected.
+   * intersections for two segments of the {@link SegmentString}s being intersected.
    * Note that some clients (such as {@link MonotoneChain}s) may optimize away
    * this call for segment pairs which they have determined do not intersect
    * (e.g. by an disjoint envelope test).
diff --git a/src/com/vividsolutions/jts/noding/IteratedNoder.java b/src/com/vividsolutions/jts/noding/IteratedNoder.java
index 726e1e3..1d7a4d2 100644
--- a/src/com/vividsolutions/jts/noding/IteratedNoder.java
+++ b/src/com/vividsolutions/jts/noding/IteratedNoder.java
@@ -38,13 +38,14 @@ import com.vividsolutions.jts.geom.*;
 import java.util.*;
 
 /**
- * Nodes a set of SegmentStrings completely.
- * The set of segmentStrings is fully noded;
+ * Nodes a set of {@link NodedSegmentString}s completely.
+ * The set of segment strings is fully noded;
  * i.e. noding is repeated until no further
  * intersections are detected.
  * <p>
  * Iterated noding using a FLOATING precision model is not guaranteed to converge,
- * due to roundoff error.   This problem is detected and an exception is thrown.
+ * 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.7
@@ -83,7 +84,7 @@ public class IteratedNoder
   public Collection getNodedSubstrings()  {    return nodedSegStrings;  }
 
   /**
-   * Fully nodes a list of {@link SegmentStrings}, i.e. peforms noding iteratively
+   * Fully nodes a list of {@link SegmentString}s, i.e. peforms noding iteratively
    * until no intersections are found between segments.
    * Maintains labelling of edges correctly through
    * the noding.
diff --git a/src/com/vividsolutions/jts/noding/MCIndexNoder.java b/src/com/vividsolutions/jts/noding/MCIndexNoder.java
index 2f905a5..bfb22ad 100644
--- a/src/com/vividsolutions/jts/noding/MCIndexNoder.java
+++ b/src/com/vividsolutions/jts/noding/MCIndexNoder.java
@@ -39,11 +39,11 @@ import com.vividsolutions.jts.index.strtree.*;
 import java.util.*;
 
 /**
- * Nodes a set of {@link SegmentStrings} using a index based
+ * Nodes a set of {@link SegmentString}s using a index based
  * on {@link MonotoneChain}s and a {@link SpatialIndex}.
  * The {@link SpatialIndex} used should be something that supports
  * envelope (range) queries efficiently (such as a {@link Quadtree}
- * or {@link STRtree}.
+ * or {@link STRtree} (which is the default index provided).
  *
  * @version 1.7
  */
diff --git a/src/com/vividsolutions/jts/noding/MCIndexSegmentSetMutualIntersector.java b/src/com/vividsolutions/jts/noding/MCIndexSegmentSetMutualIntersector.java
index 67e0afb..b23b2e4 100644
--- a/src/com/vividsolutions/jts/noding/MCIndexSegmentSetMutualIntersector.java
+++ b/src/com/vividsolutions/jts/noding/MCIndexSegmentSetMutualIntersector.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.noding.SegmentIntersector;
 import com.vividsolutions.jts.noding.SegmentString;
 
 /**
- * Intersects two sets of {@link SegmentStrings} using a index based
+ * Intersects two sets of {@link SegmentString}s using a index based
  * on {@link MonotoneChain}s and a {@link SpatialIndex}.
  *
  * @version 1.7
diff --git a/src/com/vividsolutions/jts/noding/Noder.java b/src/com/vividsolutions/jts/noding/Noder.java
index 7245fb3..47cc821 100644
--- a/src/com/vividsolutions/jts/noding/Noder.java
+++ b/src/com/vividsolutions/jts/noding/Noder.java
@@ -57,7 +57,7 @@ public interface Noder
   void computeNodes(Collection segStrings);
 
   /**
-   * Returns a {@link Collection} of fully noded {@link SegmentStrings}.
+   * Returns a {@link Collection} of fully noded {@link SegmentString}s.
    * The SegmentStrings have the same context as their parent.
    *
    * @return a Collection of SegmentStrings
diff --git a/src/com/vividsolutions/jts/noding/SegmentIntersectionDetector.java b/src/com/vividsolutions/jts/noding/SegmentIntersectionDetector.java
index 39df5a3..5a1be70 100644
--- a/src/com/vividsolutions/jts/noding/SegmentIntersectionDetector.java
+++ b/src/com/vividsolutions/jts/noding/SegmentIntersectionDetector.java
@@ -42,7 +42,7 @@ import com.vividsolutions.jts.noding.*;;
  * Detects and records an intersection between two {@link SegmentString}s,
  * if one exists.  Only a single intersection is recorded.
  * This strategy can be configured to search for proper intersections.
- * In this case, the presence of any intersection will still be recorded,
+ * In this case, the presence of <i>any</i> kind of intersection will still be recorded,
  * but searching will continue until either a proper intersection has been found
  * or no intersections are detected.
  *
@@ -137,7 +137,7 @@ public class SegmentIntersectionDetector
   /**
    * This method is called by clients
    * of the {@link SegmentIntersector} class to process
-   * intersections for two segments of the {@link SegmentStrings} being intersected.
+   * intersections for two segments of the {@link SegmentString}s being intersected.
    * Note that some clients (such as {@link MonotoneChain}s) may optimize away
    * this call for segment pairs which they have determined do not intersect
    * (e.g. by an disjoint envelope test).
diff --git a/src/com/vividsolutions/jts/noding/SegmentIntersector.java b/src/com/vividsolutions/jts/noding/SegmentIntersector.java
index f25fcf5..6bd8a46 100644
--- a/src/com/vividsolutions/jts/noding/SegmentIntersector.java
+++ b/src/com/vividsolutions/jts/noding/SegmentIntersector.java
@@ -55,7 +55,7 @@ public interface SegmentIntersector
   /**
    * This method is called by clients
    * of the {@link SegmentIntersector} interface to process
-   * intersections for two segments of the {@link SegmentStrings} being intersected.
+   * intersections for two segments of the {@link SegmentString}s being intersected.
    */
   void processIntersections(
     SegmentString e0,  int segIndex0,
diff --git a/src/com/vividsolutions/jts/noding/SimpleSegmentSetMutualIntersector.java b/src/com/vividsolutions/jts/noding/SimpleSegmentSetMutualIntersector.java
index e79d351..da06206 100644
--- a/src/com/vividsolutions/jts/noding/SimpleSegmentSetMutualIntersector.java
+++ b/src/com/vividsolutions/jts/noding/SimpleSegmentSetMutualIntersector.java
@@ -38,7 +38,7 @@ import com.vividsolutions.jts.geom.Coordinate;
 
 
 /**
- * Intersects two sets of {@link SegmentStrings} using 
+ * Intersects two sets of {@link SegmentString}s using 
  * brute-force comparasion.
  *
  * @version 1.7
diff --git a/src/com/vividsolutions/jts/noding/SinglePassNoder.java b/src/com/vividsolutions/jts/noding/SinglePassNoder.java
index 90707fa..d6749aa 100644
--- a/src/com/vividsolutions/jts/noding/SinglePassNoder.java
+++ b/src/com/vividsolutions/jts/noding/SinglePassNoder.java
@@ -77,7 +77,7 @@ public abstract class SinglePassNoder
   public abstract void computeNodes(Collection segStrings);
 
   /**
-   * Returns a {@link Collection} of fully noded {@link SegmentStrings}.
+   * Returns a {@link Collection} of fully noded {@link SegmentString}s.
    * The SegmentStrings have the same context as their parent.
    *
    * @return a Collection of SegmentStrings
diff --git a/src/com/vividsolutions/jts/noding/snapround/GeometryNoder.java b/src/com/vividsolutions/jts/noding/snapround/GeometryNoder.java
index 6b71cca..add1d20 100644
--- a/src/com/vividsolutions/jts/noding/snapround/GeometryNoder.java
+++ b/src/com/vividsolutions/jts/noding/snapround/GeometryNoder.java
@@ -7,7 +7,20 @@ import com.vividsolutions.jts.noding.*;
 import com.vividsolutions.jts.noding.snapround.*;
 
 /**
- * Nodes a list of {@link Geometry}s using Snap Rounding
+ * Nodes the linework in a list of {@link Geometry}s using Snap-Rounding
+ * to a given {@link PrecisionModel}.
+ * <p>
+ * The input coordinates are expected to be rounded
+ * to the given precision model.
+ * This class does not perform that function.
+ * {@link GeometryPrecisionReducer} may be used to do this.
+ * <p>
+ * This class does <b>not</b> dissolve the output linework,
+ * so there may be duplicate linestrings in the output.  
+ * Subsequent processing (e.g. polygonization) may require
+ * the linework to be unique.  Using {@link UnaryUnion} is one way
+ * to do this (although this is an inefficient approach).
+ * 
  * 
  */
 public class GeometryNoder
@@ -16,10 +29,22 @@ public class GeometryNoder
   private PrecisionModel pm;
   private boolean isValidityChecked = false;
 
+  /**
+   * Creates a new noder which snap-rounds to a grid specified
+   * by the given
+   * {@link PrecisionModel).
+   * 
+   * @param pm the precision model for the grid to snap-round to
+   */
   public GeometryNoder(PrecisionModel pm) {
     this.pm = pm;
   }
 
+  /**
+   * Sets whether noding validity is checked after noding is performed.
+   * 
+   * @param isValidityChecked
+   */
   public void setValidate(boolean isValidityChecked)
   {
   	this.isValidityChecked = isValidityChecked;
diff --git a/src/com/vividsolutions/jts/noding/snapround/HotPixel.java b/src/com/vividsolutions/jts/noding/snapround/HotPixel.java
index 6c7a4f0..9c68eaa 100644
--- a/src/com/vividsolutions/jts/noding/snapround/HotPixel.java
+++ b/src/com/vividsolutions/jts/noding/snapround/HotPixel.java
@@ -36,6 +36,7 @@ public class HotPixel
   private double maxx;
   private double miny;
   private double maxy;
+  
   /**
    * The corners of the hot pixel, in the order:
    *  10
@@ -45,6 +46,13 @@ public class HotPixel
 
   private Envelope safeEnv = null;
 
+  /**
+   * Creates a new hot pixel.
+   * 
+   * @param pt the coordinate at the centre of the pixel
+   * @param scaleFactor the scaleFactor determining the pixel size
+   * @param li the intersector to use for testing intersection with line segments
+   */
   public HotPixel(Coordinate pt, double scaleFactor, LineIntersector li) {
     originalPt = pt;
     this.pt = pt;
@@ -59,16 +67,26 @@ public class HotPixel
     initCorners(this.pt);
   }
 
+  /**
+   * Gets the coordinate this hot pixel is based at.
+   * 
+   * @return the coordinate of the pixel
+   */
   public Coordinate getCoordinate() { return originalPt; }
 
+  private static final double SAFE_ENV_EXPANSION_FACTOR = 0.75;
+  
   /**
-   * Returns a "safe" envelope that is guaranteed to contain the hot pixel
-   * @return
+   * Returns a "safe" envelope that is guaranteed to contain the hot pixel.
+   * The envelope returned will be larger than the exact envelope of the 
+   * pixel.
+   * 
+   * @return an envelope which contains the hot pixel
    */
   public Envelope getSafeEnvelope()
   {
     if (safeEnv == null) {
-      double safeTolerance = .75 / scaleFactor;
+      double safeTolerance = SAFE_ENV_EXPANSION_FACTOR / scaleFactor;
       safeEnv = new Envelope(originalPt.x - safeTolerance,
                              originalPt.x + safeTolerance,
                              originalPt.y - safeTolerance,
@@ -97,6 +115,14 @@ public class HotPixel
     return (double) Math.round(val * scaleFactor);
   }
 
+  /**
+   * Tests whether the line segment (p0-p1) 
+   * intersects this hot pixel.
+   * 
+   * @param p0 the first coordinate of the line segment to test
+   * @param p1 the second coordinate of the line segment to test
+   * @return true if the line segment intersects this hot pixel
+   */
   public boolean intersects(Coordinate p0, Coordinate p1)
   {
     if (scaleFactor == 1.0)
@@ -113,7 +139,7 @@ public class HotPixel
     pScaled.y = scale(p.y);
   }
 
-  public boolean intersectsScaled(Coordinate p0, Coordinate p1)
+  private boolean intersectsScaled(Coordinate p0, Coordinate p1)
   {
     double segMinx = Math.min(p0.x, p1.x);
     double segMaxx = Math.max(p0.x, p1.x);
diff --git a/src/com/vividsolutions/jts/noding/snapround/MCIndexSnapRounder.java b/src/com/vividsolutions/jts/noding/snapround/MCIndexSnapRounder.java
index b54c835..aca1315 100644
--- a/src/com/vividsolutions/jts/noding/snapround/MCIndexSnapRounder.java
+++ b/src/com/vividsolutions/jts/noding/snapround/MCIndexSnapRounder.java
@@ -43,9 +43,9 @@ import com.vividsolutions.jts.noding.*;
  * fully noded arrangement from a set of {@link SegmentString}s.
  * Implements the Snap Rounding technique described in 
  * papers by Hobby, Guibas & Marimont, and Goodrich et al.
- * Snap Rounding assumes that all vertices lie on a uniform grid
- * (hence the precision model of the input must be fixed precision,
- * and all the input vertices must be rounded to that precision).
+ * Snap Rounding assumes that all vertices lie on a uniform grid;
+ * hence the precision model of the input must be fixed precision,
+ * and all the input vertices must be rounded to that precision.
  * <p>
  * This implementation uses a monotone chains and a spatial index to
  * speed up the intersection tests.
@@ -139,7 +139,7 @@ public class MCIndexSnapRounder
    * Computes nodes introduced as a result of
    * snapping segments to vertices of other segments
    *
-   * @param segStrings the list of segment strings to snap together
+   * @param edges the list of segment strings to snap together
    */
   public void computeVertexSnaps(Collection edges)
   {
diff --git a/src/com/vividsolutions/jts/noding/snapround/SimpleSnapRounder.java b/src/com/vividsolutions/jts/noding/snapround/SimpleSnapRounder.java
index d5947d4..2bcbb71 100644
--- a/src/com/vividsolutions/jts/noding/snapround/SimpleSnapRounder.java
+++ b/src/com/vividsolutions/jts/noding/snapround/SimpleSnapRounder.java
@@ -41,13 +41,14 @@ import com.vividsolutions.jts.noding.*;
 /**
  * Uses Snap Rounding to compute a rounded,
  * fully noded arrangement from a set of {@link SegmentString}s.
- * Implements the Snap Rounding technique described in Hobby, Guibas & Marimont,
- * and Goodrich et al.
- * Snap Rounding assumes that all vertices lie on a uniform grid
- * (hence the precision model of the input must be fixed precision,
- * and all the input vertices must be rounded to that precision).
+ * Implements the Snap Rounding technique described in 
+ * the papers by Hobby, Guibas & Marimont, and Goodrich et al.
+ * Snap Rounding assumes that all vertices lie on a uniform grid;
+ * hence the precision model of the input must be fixed precision,
+ * and all the input vertices must be rounded to that precision.
  * <p>
  * This implementation uses simple iteration over the line segments.
+ * This is not the most efficient approach for large sets of segments.
  * <p>
  * This implementation appears to be fully robust using an integer precision model.
  * It will function with non-integer precision models, but the
@@ -153,7 +154,7 @@ public class SimpleSnapRounder
    * Computes nodes introduced as a result of
    * snapping segments to vertices of other segments
    *
-   * @param segStrings the list of segment strings to snap together
+   * @param edges the list of segment strings to snap together
    */
   public void computeVertexSnaps(Collection edges)
   {
diff --git a/src/com/vividsolutions/jts/operation/buffer/BufferInputLineSimplifier.java b/src/com/vividsolutions/jts/operation/buffer/BufferInputLineSimplifier.java
index 7196a41..65df68b 100644
--- a/src/com/vividsolutions/jts/operation/buffer/BufferInputLineSimplifier.java
+++ b/src/com/vividsolutions/jts/operation/buffer/BufferInputLineSimplifier.java
@@ -50,16 +50,19 @@ import com.vividsolutions.jts.geom.*;
  * A key aspect of the simplification is that it
  * affects inside (concave or inward) corners only.  
  * Convex (outward) corners are preserved, since they
- * are required to ensure that the eventual buffer curve
+ * are required to ensure that the generated buffer curve
  * lies at the correct distance from the input geometry.
  * <p>
  * Another important heuristic used is that the end segments
  * of the input are never simplified.  This ensures that
- * the client buffer code is able to generate end caps consistently.
+ * the client buffer code is able to generate end caps faithfully.
  * <p>
  * No attempt is made to avoid self-intersections in the output.
- * This is acceptable for use for generating a buffer offset curve, 
- * but means that this cannot be used as a general-purpose polygon simplification algorithm.
+ * This is acceptable for use for generating a buffer offset curve,
+ * since the buffer algorithm is insensitive to invalid polygonal
+ * geometry.  However, 
+ * this means that this algorithm
+ * cannot be used as a general-purpose polygon simplification technique.
  * 
  * @author Martin Davis
  *
diff --git a/src/com/vividsolutions/jts/operation/buffer/BufferOp.java b/src/com/vividsolutions/jts/operation/buffer/BufferOp.java
index 396e80f..10d51b0 100644
--- a/src/com/vividsolutions/jts/operation/buffer/BufferOp.java
+++ b/src/com/vividsolutions/jts/operation/buffer/BufferOp.java
@@ -45,11 +45,13 @@ import com.vividsolutions.jts.noding.snapround.*;
 /**
  * Computes the buffer of a geometry, for both positive and negative buffer distances.
  * <p>
- * In GIS, the positive buffer of a geometry is defined as
- * the Minkowski sum or difference of the geometry
+ * In GIS, the positive (or negative) buffer of a geometry is defined as
+ * the Minkowski sum (or difference) of the geometry
  * with a circle of radius equal to the absolute value of the buffer distance.
  * In the CAD/CAM world buffers are known as </i>offset curves</i>.
- * In morphological analysis they are known as <i>erosion</i> and <i>dilation</i>
+ * In morphological analysis the 
+ * operation of postive and negative buffering 
+ * is referred to as <i>erosion</i> and <i>dilation</i>
  * <p>
  * The buffer operation always returns a polygonal result.
  * The negative or zero-distance buffer of lines and points is always an empty {@link Polygon}.
@@ -291,6 +293,7 @@ public class BufferOp
         bufferReducedPrecision(precDigits);
       }
       catch (TopologyException ex) {
+      	// update the saved exception to reflect the new input geometry
         saveException = ex;
         // don't propagate the exception - it will be detected by fact that resultGeometry is null
       }
@@ -312,7 +315,7 @@ public class BufferOp
       saveException = ex;
       // don't propagate the exception - it will be detected by fact that resultGeometry is null
 
-      // testing - propagate exception
+      // testing ONLY - propagate exception
       //throw ex;
     }
   }
diff --git a/src/com/vividsolutions/jts/operation/buffer/BufferParameters.java b/src/com/vividsolutions/jts/operation/buffer/BufferParameters.java
index f099f0e..c77d2f3 100644
--- a/src/com/vividsolutions/jts/operation/buffer/BufferParameters.java
+++ b/src/com/vividsolutions/jts/operation/buffer/BufferParameters.java
@@ -86,7 +86,8 @@ public class BufferParameters
   private int endCapStyle = CAP_ROUND;
   private int joinStyle = JOIN_ROUND;
   private double mitreLimit = DEFAULT_MITRE_LIMIT;
-
+  private boolean isSingleSided = false;
+  
   /**
    * Creates a default set of parameters
    *
@@ -291,4 +292,35 @@ public class BufferParameters
     this.mitreLimit = mitreLimit;
   }
 
+  /**
+   * Sets whether the computed buffer should be single-sided.
+   * A single-sided buffer is constructed on only one side of each input line.
+   * <b>
+   * The side used is determined by the sign of the buffer distance:
+   * <ul>
+   * <li>a positive distance indicates the left-hand side
+   * <li>a negative distance indicates the right-hand side
+   * </ul>
+   * The single-sided buffer of point geometries is 
+   * the same as the regular buffer.
+   * <p>
+   * The End Cap Style for single-sided buffers is 
+   * always ignored, 
+   * and forced to the equivalent of <tt>CAP_FLAT</tt>. 
+   * 
+   * @param isSingleSided true if a single-sided buffer should be constructed
+   */
+  public void setSingleSided(boolean isSingleSided)
+  {
+    this.isSingleSided = isSingleSided;
+  }
+
+  /**
+   * Tests whether the buffer is to be generated on a single side only.
+   * 
+   * @return true if the generated buffer is to be single-sided
+   */
+  public boolean isSingleSided() {
+    return isSingleSided;
+  }
 }
diff --git a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java b/src/com/vividsolutions/jts/operation/buffer/OLDOffsetCurveBuilder.java
similarity index 86%
copy from src/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java
copy to src/com/vividsolutions/jts/operation/buffer/OLDOffsetCurveBuilder.java
index b4dd832..e393f63 100644
--- a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java
+++ b/src/com/vividsolutions/jts/operation/buffer/OLDOffsetCurveBuilder.java
@@ -48,7 +48,7 @@ import com.vividsolutions.jts.geomgraph.*;
  *
  * @version 1.7
  */
-public class OffsetCurveBuilder 
+class OLDOffsetCurveBuilder 
 {  
   /**
    * The angle quantum with which to approximate a fillet curve
@@ -80,15 +80,14 @@ public class OffsetCurveBuilder
   /**
    * Factor which determines how short closing segs can be for round buffers
    */
-  private static final int MAX_CLOSING_SEG_FRACTION = 80;
+  private static final int MAX_CLOSING_SEG_LEN_FACTOR = 80;
   
   private double distance = 0.0;
   private PrecisionModel precisionModel;
-  
   private BufferParameters bufParams;
   
   /**
-   * The Closing Segment Factor controls how long
+   * The Closing Segment Length Factor controls how long
    * "closing segments" are.  Closing segments are added
    * at the middle of inside corners to ensure a smoother
    * boundary for the buffer offset curve. 
@@ -103,11 +102,11 @@ public class OffsetCurveBuilder
    * and quadrantSegs >= 8)
    * 
    */
-  private int closingSegFactor = 1;
-  private OffsetCurveVertexList vertexList;
+  private int closingSegLengthFactor = 1;
+  private OffsetSegmentString vertexList;
   private LineIntersector li;
   
-  public OffsetCurveBuilder(
+  public OLDOffsetCurveBuilder(
                 PrecisionModel precisionModel,
                 BufferParameters bufParams
                 )
@@ -127,9 +126,13 @@ public class OffsetCurveBuilder
      */
     if (bufParams.getQuadrantSegments() >= 8 
         && bufParams.getJoinStyle() == BufferParameters.JOIN_ROUND)
-      closingSegFactor = MAX_CLOSING_SEG_FRACTION;
+      closingSegLengthFactor = MAX_CLOSING_SEG_LEN_FACTOR;
   }
 
+  public BufferParameters getBufferParameters()
+  {
+    return bufParams;
+  }
   /**
    * This method handles single points as well as lines.
    * Lines are assumed to <b>not</b> be closed (the function will not
@@ -140,23 +143,32 @@ public class OffsetCurveBuilder
   public List getLineCurve(Coordinate[] inputPts, double distance)
   {
     List lineList = new ArrayList();
+    
     // a zero or negative width buffer of a line/point is empty
-    if (distance <= 0.0) return lineList;
+    if (distance <= 0.0 && ! bufParams.isSingleSided()) return lineList;
 
-    init(distance);
+    double posDistance = Math.abs(distance);
+    init(posDistance);
     if (inputPts.length <= 1) {
       switch (bufParams.getEndCapStyle()) {
         case BufferParameters.CAP_ROUND:
-          addCircle(inputPts[0], distance);
+          addCircle(inputPts[0], posDistance);
           break;
         case BufferParameters.CAP_SQUARE:
-          addSquare(inputPts[0], distance);
+          addSquare(inputPts[0], posDistance);
           break;
           // default is for buffer to be empty (e.g. for a butt line cap);
       }
     }
-    else
-      computeLineBufferCurve(inputPts);
+    else {
+      if (bufParams.isSingleSided()) {
+        boolean isRightSide = distance > 0.0;
+        computeSingleSidedBufferCurve(inputPts, isRightSide);
+      }
+      else
+        computeLineBufferCurve(inputPts);
+    }
+      
     
 //System.out.println(vertexList);
     
@@ -201,7 +213,7 @@ public class OffsetCurveBuilder
   {
     this.distance = distance;
     maxCurveSegmentError = distance * (1 - Math.cos(filletAngleQuantum / 2.0));
-    vertexList = new OffsetCurveVertexList();
+    vertexList = new OffsetSegmentString();
     vertexList.setPrecisionModel(precisionModel);
     /**
      * Choose the min vertex separation as a small fraction of the offset distance.
@@ -225,7 +237,7 @@ public class OffsetCurveBuilder
    * @param distance the buffer distance
    * @return the simplification tolerance
    */
-  private double simplifyTolerance(double bufDistance)
+  private static double simplifyTolerance(double bufDistance)
   {
     return bufDistance / SIMPLIFY_FACTOR;
   }
@@ -241,8 +253,6 @@ public class OffsetCurveBuilder
 //    Coordinate[] simp1 = inputPts;
     
     int n1 = simp1.length - 1;
-
-
     initSideSegments(simp1[0], simp1[1], Position.LEFT);
     for (int i = 2; i <= n1; i++) {
       addNextSegment(simp1[i], true);
@@ -270,6 +280,7 @@ public class OffsetCurveBuilder
     vertexList.closeRing();
   }
 
+  /*
   private void OLDcomputeLineBufferCurve(Coordinate[] inputPts)
   {
     int n = inputPts.length - 1;
@@ -294,6 +305,50 @@ public class OffsetCurveBuilder
 
     vertexList.closeRing();
   }
+  */
+  
+  private void computeSingleSidedBufferCurve(Coordinate[] inputPts, boolean isRightSide)
+  {
+    double distTol = simplifyTolerance(distance);
+    
+    if (isRightSide) {
+      // add original line
+      vertexList.addPts(inputPts, true);
+      
+      //---------- compute points for right side of line
+      // Simplify the appropriate side of the line before generating
+      Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol);
+      // MD - used for testing only (to eliminate simplification)
+  //    Coordinate[] simp2 = inputPts;
+      int n2 = simp2.length - 1;
+     
+      // since we are traversing line in opposite order, offset position is still LEFT
+      initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT);
+      addFirstSegment();
+      for (int i = n2 - 2; i >= 0; i--) {
+        addNextSegment(simp2[i], true);
+      }
+    }
+    else {
+      // add original line
+      vertexList.addPts(inputPts, false);
+      
+      //--------- compute points for left side of line
+      // Simplify the appropriate side of the line before generating
+      Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol);
+      // MD - used for testing only (to eliminate simplification)
+//      Coordinate[] simp1 = inputPts;
+      
+      int n1 = simp1.length - 1;
+      initSideSegments(simp1[0], simp1[1], Position.LEFT);
+      addFirstSegment();
+      for (int i = 2; i <= n1; i++) {
+        addNextSegment(simp1[i], true);
+      }
+    }
+    addLastSegment();
+    vertexList.closeRing();
+  }
 
   private void computeRingBufferCurve(Coordinate[] inputPts, int side)
   {
@@ -330,7 +385,20 @@ public class OffsetCurveBuilder
     computeOffsetSegment(seg1, side, distance, offset1);
   }
 
-  private static double MAX_CLOSING_SEG_LEN = 3.0;
+  private void addFirstSegment()
+  {
+    vertexList.addPt(offset1.p0);
+  }
+  
+  /**
+   * Add last offset point
+   */
+  private void addLastSegment()
+  {
+    vertexList.addPt(offset1.p1);
+  }
+
+  //private static double MAX_CLOSING_SEG_LEN = 3.0;
 
   private void addNextSegment(Coordinate p, boolean addStartPoint)
   {
@@ -461,7 +529,7 @@ public class OffsetCurveBuilder
        * In complex buffer cases the closing segment may cut across many other
        * segments in the generated offset curve.  In order to improve the 
        * performance of the noding, the closing segment should be kept as short as possible.
-       * (But not too short, since that would defeat it's purpose).
+       * (But not too short, since that would defeat its purpose).
        * This is the purpose of the closingSegFactor heuristic value.
        */ 
     	
@@ -483,12 +551,12 @@ public class OffsetCurveBuilder
         /**
          * Add "closing segment" of required length.
          */
-        if (closingSegFactor > 0) {
-          Coordinate mid0 = new Coordinate((closingSegFactor * offset0.p1.x + s1.x)/(closingSegFactor + 1), 
-              (closingSegFactor*offset0.p1.y + s1.y)/(closingSegFactor + 1));
+        if (closingSegLengthFactor > 0) {
+          Coordinate mid0 = new Coordinate((closingSegLengthFactor * offset0.p1.x + s1.x)/(closingSegLengthFactor + 1), 
+              (closingSegLengthFactor*offset0.p1.y + s1.y)/(closingSegLengthFactor + 1));
           vertexList.addPt(mid0);
-          Coordinate mid1 = new Coordinate((closingSegFactor*offset1.p0.x + s1.x)/(closingSegFactor + 1), 
-             (closingSegFactor*offset1.p0.y + s1.y)/(closingSegFactor + 1));
+          Coordinate mid1 = new Coordinate((closingSegLengthFactor*offset1.p0.x + s1.x)/(closingSegLengthFactor + 1), 
+             (closingSegLengthFactor*offset1.p0.y + s1.y)/(closingSegLengthFactor + 1));
           vertexList.addPt(mid1);
         }
         else {
@@ -507,13 +575,6 @@ public class OffsetCurveBuilder
     }
   }
   
-  /**
-   * Add last offset point
-   */
-  private void addLastSegment()
-  {
-  	vertexList.addPt(offset1.p1);
-  }
 
   /**
    * Compute an offset segment for an input segment on a given side and at a given distance.
@@ -783,6 +844,7 @@ public class OffsetCurveBuilder
     Coordinate pt = new Coordinate(p.x + distance, p.y);
     vertexList.addPt(pt);
     addFillet(p, 0.0, 2.0 * Math.PI, -1, distance);
+    vertexList.closeRing();
   }
 
   /**
diff --git a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java b/src/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java
index b4dd832..5270a22 100644
--- a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java
+++ b/src/com/vividsolutions/jts/operation/buffer/OffsetCurveBuilder.java
@@ -44,69 +44,17 @@ import com.vividsolutions.jts.geomgraph.*;
  * it may contain self-intersections (and usually will).
  * The final buffer polygon is computed by forming a topological graph
  * of all the noded raw curves and tracing outside contours.
- * The points in the raw curve are rounded to the required precision model.
+ * The points in the raw curve are rounded 
+ * to a given {@link PrecisionModel}.
  *
  * @version 1.7
  */
 public class OffsetCurveBuilder 
 {  
-  /**
-   * The angle quantum with which to approximate a fillet curve
-   * (based on the input # of quadrant segments)
-   */
-  private double filletAngleQuantum;
-  
-  /**
-   * the max error of approximation (distance) between a quad segment and the true fillet curve
-   */
-  private double maxCurveSegmentError = 0.0;
-  
-  /**
-   * Factor which controls how close curve vertices can be to be snapped
-   */
-  private static final double CURVE_VERTEX_SNAP_DISTANCE_FACTOR = 1.0E-6;
-  
-  /**
-   * Factor which controls how close offset segments can be to
-   * skip adding a filler or mitre.
-   */
-  private static final double OFFSET_SEGMENT_SEPARATION_FACTOR = 1.0E-3;
-  
-  /**
-   * Factor which controls how close curve vertices on inside turns can be to be snapped 
-   */
-  private static final double INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR = 1.0E-3;
-    
-  /**
-   * Factor which determines how short closing segs can be for round buffers
-   */
-  private static final int MAX_CLOSING_SEG_FRACTION = 80;
-  
   private double distance = 0.0;
   private PrecisionModel precisionModel;
-  
   private BufferParameters bufParams;
   
-  /**
-   * The Closing Segment Factor controls how long
-   * "closing segments" are.  Closing segments are added
-   * at the middle of inside corners to ensure a smoother
-   * boundary for the buffer offset curve. 
-   * In some cases (particularly for round joins with default-or-better
-   * quantization) the closing segments can be made quite short.
-   * This substantially improves performance (due to fewer intersections being created).
-   * 
-   * A closingSegFactor of 0 results in lines to the corner vertex
-   * A closingSegFactor of 1 results in lines halfway to the corner vertex
-   * A closingSegFactor of 80 results in lines 1/81 of the way to the corner vertex
-   * (this option is reasonable for the very common default situation of round joins
-   * and quadrantSegs >= 8)
-   * 
-   */
-  private int closingSegFactor = 1;
-  private OffsetCurveVertexList vertexList;
-  private LineIntersector li;
-  
   public OffsetCurveBuilder(
                 PrecisionModel precisionModel,
                 BufferParameters bufParams
@@ -114,78 +62,98 @@ public class OffsetCurveBuilder
   {
     this.precisionModel = precisionModel;
     this.bufParams = bufParams;
-    
-    // compute intersections in full precision, to provide accuracy
-    // the points are rounded as they are inserted into the curve line
-    li = new RobustLineIntersector();
-    filletAngleQuantum = Math.PI / 2.0 / bufParams.getQuadrantSegments();
-    
-    /**
-     * Non-round joins cause issues with short closing segments,
-     * so don't use them.  In any case, non-round joins 
-     * only really make sense for relatively small buffer distances.
-     */
-    if (bufParams.getQuadrantSegments() >= 8 
-        && bufParams.getJoinStyle() == BufferParameters.JOIN_ROUND)
-      closingSegFactor = MAX_CLOSING_SEG_FRACTION;
   }
 
   /**
-   * This method handles single points as well as lines.
-   * Lines are assumed to <b>not</b> be closed (the function will not
+   * Gets the buffer parameters being used to generate the curve.
+   * 
+   * @return the buffer parameters being used
+   */
+  public BufferParameters getBufferParameters()
+  {
+    return bufParams;
+  }
+  
+  /**
+   * This method handles single points as well as LineStrings.
+   * LineStrings are assumed <b>not</b> to be closed (the function will not
    * fail for closed lines, but will generate superfluous line caps).
    *
-   * @return a List of Coordinate[]
+   * @param inputPts the vertices of the line to offset
+   * @param distance the offset distance
+   * 
+   * @return a Coordinate array representing the curve
+   * @return null if the curve is empty
    */
-  public List getLineCurve(Coordinate[] inputPts, double distance)
+  public Coordinate[] getLineCurve(Coordinate[] inputPts, double distance)
   {
-    List lineList = new ArrayList();
+    this.distance = distance;
+    
     // a zero or negative width buffer of a line/point is empty
-    if (distance <= 0.0) return lineList;
+    if (distance < 0.0 && ! bufParams.isSingleSided()) return null;
+    if (distance == 0.0) return null;
 
-    init(distance);
+    double posDistance = Math.abs(distance);
+    OffsetSegmentGenerator segGen = getSegGen(posDistance);
     if (inputPts.length <= 1) {
-      switch (bufParams.getEndCapStyle()) {
-        case BufferParameters.CAP_ROUND:
-          addCircle(inputPts[0], distance);
-          break;
-        case BufferParameters.CAP_SQUARE:
-          addSquare(inputPts[0], distance);
-          break;
-          // default is for buffer to be empty (e.g. for a butt line cap);
+      computePointCurve(inputPts[0], segGen);
+    }
+    else {
+      if (bufParams.isSingleSided()) {
+        boolean isRightSide = distance < 0.0;
+        computeSingleSidedBufferCurve(inputPts, isRightSide, segGen);
       }
+      else
+        computeLineBufferCurve(inputPts, segGen);
     }
-    else
-      computeLineBufferCurve(inputPts);
     
-//System.out.println(vertexList);
-    
-    Coordinate[] lineCoord = vertexList.getCoordinates();
-    lineList.add(lineCoord);
-    return lineList;
+    Coordinate[] lineCoord = segGen.getCoordinates();
+    return lineCoord;
   }
 
   /**
    * This method handles the degenerate cases of single points and lines,
    * as well as rings.
    *
-   * @return a List of Coordinate[]
+   * @return a Coordinate array representing the curve
+   * @return null if the curve is empty
    */
-  public List getRingCurve(Coordinate[] inputPts, int side, double distance)
+  public Coordinate[] getRingCurve(Coordinate[] inputPts, int side, double distance)
   {
-    List lineList = new ArrayList();
-    init(distance);
+    this.distance = distance;
     if (inputPts.length <= 2)
       return getLineCurve(inputPts, distance);
 
     // optimize creating ring for for zero distance
     if (distance == 0.0) {
-      lineList.add(copyCoordinates(inputPts));
-      return lineList;
+      return copyCoordinates(inputPts);
+    }
+    OffsetSegmentGenerator segGen = getSegGen(distance);
+    computeRingBufferCurve(inputPts, side, segGen);
+    return segGen.getCoordinates();
+  }
+
+  public Coordinate[] getOffsetCurve(Coordinate[] inputPts, double distance)
+  {
+    this.distance = distance;
+    
+    // a zero width offset curve is empty
+    if (distance == 0.0) return null;
+
+    boolean isRightSide = distance < 0.0;
+    double posDistance = Math.abs(distance);
+    OffsetSegmentGenerator segGen = getSegGen(posDistance);
+    if (inputPts.length <= 1) {
+      computePointCurve(inputPts[0], segGen);
+    }
+    else {
+      computeOffsetCurve(inputPts, isRightSide, segGen);
     }
-    computeRingBufferCurve(inputPts, side);
-    lineList.add(vertexList.getCoordinates());
-    return lineList;
+    Coordinate[] curvePts = segGen.getCoordinates();
+    // for right side line is traversed in reverse direction, so have to reverse generated line
+    if (isRightSide) 
+      CoordinateArrays.reverse(curvePts);
+    return curvePts;
   }
 
   private static Coordinate[] copyCoordinates(Coordinate[] pts)
@@ -196,17 +164,10 @@ public class OffsetCurveBuilder
     }
     return copy;
   }
-  
-  private void init(double distance)
+    
+  private OffsetSegmentGenerator getSegGen(double distance)
   {
-    this.distance = distance;
-    maxCurveSegmentError = distance * (1 - Math.cos(filletAngleQuantum / 2.0));
-    vertexList = new OffsetCurveVertexList();
-    vertexList.setPrecisionModel(precisionModel);
-    /**
-     * Choose the min vertex separation as a small fraction of the offset distance.
-     */
-    vertexList.setMinimumVertexDistance(distance * CURVE_VERTEX_SNAP_DISTANCE_FACTOR);
+    return new OffsetSegmentGenerator(precisionModel, bufParams, distance);
   }
   
   /**
@@ -225,12 +186,24 @@ public class OffsetCurveBuilder
    * @param distance the buffer distance
    * @return the simplification tolerance
    */
-  private double simplifyTolerance(double bufDistance)
+  private static double simplifyTolerance(double bufDistance)
   {
     return bufDistance / SIMPLIFY_FACTOR;
   }
   
-  private void computeLineBufferCurve(Coordinate[] inputPts)
+  private void computePointCurve(Coordinate pt, OffsetSegmentGenerator segGen) {
+    switch (bufParams.getEndCapStyle()) {
+      case BufferParameters.CAP_ROUND:
+        segGen.createCircle(pt);
+        break;
+      case BufferParameters.CAP_SQUARE:
+        segGen.createSquare(pt);
+        break;
+      // otherwise curve is empty (e.g. for a butt cap);
+    }
+  }
+
+  private void computeLineBufferCurve(Coordinate[] inputPts, OffsetSegmentGenerator segGen)
   {
     double distTol = simplifyTolerance(distance);
     
@@ -241,15 +214,13 @@ public class OffsetCurveBuilder
 //    Coordinate[] simp1 = inputPts;
     
     int n1 = simp1.length - 1;
-
-
-    initSideSegments(simp1[0], simp1[1], Position.LEFT);
+    segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT);
     for (int i = 2; i <= n1; i++) {
-      addNextSegment(simp1[i], true);
+      segGen.addNextSegment(simp1[i], true);
     }
-    addLastSegment();
+    segGen.addLastSegment();
     // add line cap for end of line
-    addLineEndCap(simp1[n1 - 1], simp1[n1]);
+    segGen.addLineEndCap(simp1[n1 - 1], simp1[n1]);
     
     //---------- compute points for right side of line
     // Simplify the appropriate side of the line before generating
@@ -259,17 +230,18 @@ public class OffsetCurveBuilder
     int n2 = simp2.length - 1;
    
     // since we are traversing line in opposite order, offset position is still LEFT
-    initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT);
+    segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT);
     for (int i = n2 - 2; i >= 0; i--) {
-      addNextSegment(simp2[i], true);
+      segGen.addNextSegment(simp2[i], true);
     }
-    addLastSegment();
+    segGen.addLastSegment();
     // add line cap for start of line
-    addLineEndCap(simp2[1], simp2[0]);
+    segGen.addLineEndCap(simp2[1], simp2[0]);
 
-    vertexList.closeRing();
+    segGen.closeRing();
   }
 
+  /*
   private void OLDcomputeLineBufferCurve(Coordinate[] inputPts)
   {
     int n = inputPts.length - 1;
@@ -294,507 +266,105 @@ public class OffsetCurveBuilder
 
     vertexList.closeRing();
   }
-
-  private void computeRingBufferCurve(Coordinate[] inputPts, int side)
+  */
+  
+  private void computeSingleSidedBufferCurve(Coordinate[] inputPts, boolean isRightSide, OffsetSegmentGenerator segGen)
   {
-    // simplify input line to improve performance
     double distTol = simplifyTolerance(distance);
-    // ensure that correct side is simplified
-    if (side == Position.RIGHT)
-      distTol = -distTol;
-    Coordinate[] simp = BufferInputLineSimplifier.simplify(inputPts, distTol);
-//    Coordinate[] simp = inputPts;
     
-    int n = simp.length - 1;
-    initSideSegments(simp[n - 1], simp[0], side);
-    for (int i = 1; i <= n; i++) {
-      boolean addStartPoint = i != 1;
-      addNextSegment(simp[i], addStartPoint);
-    }
-    vertexList.closeRing();
-  }
-
-  private Coordinate s0, s1, s2;
-  private LineSegment seg0 = new LineSegment();
-  private LineSegment seg1 = new LineSegment();
-  private LineSegment offset0 = new LineSegment();
-  private LineSegment offset1 = new LineSegment();
-  private int side = 0;
-
-  private void initSideSegments(Coordinate s1, Coordinate s2, int side)
-  {
-    this.s1 = s1;
-    this.s2 = s2;
-    this.side = side;
-    seg1.setCoordinates(s1, s2);
-    computeOffsetSegment(seg1, side, distance, offset1);
-  }
-
-  private static double MAX_CLOSING_SEG_LEN = 3.0;
-
-  private void addNextSegment(Coordinate p, boolean addStartPoint)
-  {
-    // s0-s1-s2 are the coordinates of the previous segment and the current one
-    s0 = s1;
-    s1 = s2;
-    s2 = p;
-    seg0.setCoordinates(s0, s1);
-    computeOffsetSegment(seg0, side, distance, offset0);
-    seg1.setCoordinates(s1, s2);
-    computeOffsetSegment(seg1, side, distance, offset1);
-
-    // do nothing if points are equal
-    if (s1.equals(s2)) return;
-
-    int orientation = CGAlgorithms.computeOrientation(s0, s1, s2);
-    boolean outsideTurn =
-          (orientation == CGAlgorithms.CLOCKWISE        && side == Position.LEFT)
-      ||  (orientation == CGAlgorithms.COUNTERCLOCKWISE && side == Position.RIGHT);
-
-    if (orientation == 0) { // lines are collinear
-    	addCollinear(addStartPoint);
-		}
-    else if (outsideTurn) 
-		{
-			addOutsideTurn(orientation, addStartPoint);
-		}
-    else { // inside turn
-			addInsideTurn(orientation, addStartPoint);
-    }
-  }
-  
-  private void addCollinear(boolean addStartPoint)
-  {
-  	/**
-  	 * This test could probably be done more efficiently,
-  	 * but the situation of exact collinearity should be fairly rare.
-  	 */
-		li.computeIntersection(s0, s1, s1, s2);
-		int numInt = li.getIntersectionNum();
-		/**
-		 * if numInt is < 2, the lines are parallel and in the same direction. In
-		 * this case the point can be ignored, since the offset lines will also be
-		 * parallel.
-		 */
-		if (numInt >= 2) {
-			/**
-			 * segments are collinear but reversing. 
-			 * Add an "end-cap" fillet
-			 * all the way around to other direction This case should ONLY happen
-			 * for LineStrings, so the orientation is always CW. (Polygons can never
-			 * have two consecutive segments which are parallel but reversed,
-			 * because that would be a self intersection.
-			 * 
-			 */
-			if (bufParams.getJoinStyle() == BufferParameters.JOIN_BEVEL 
-					|| bufParams.getJoinStyle() == BufferParameters.JOIN_MITRE) {
-				if (addStartPoint) vertexList.addPt(offset0.p1);
-				vertexList.addPt(offset1.p0);
-			}
-			else {
-				addFillet(s1, offset0.p1, offset1.p0, CGAlgorithms.CLOCKWISE, distance);
-			}
-		}
-  }
-  
-  /**
-   * Adds the offset points for an outside (convex) turn
-   * 
-   * @param orientation
-   * @param addStartPoint
-   */
-  private void addOutsideTurn(int orientation, boolean addStartPoint)
-  {
-  	/**
-  	 * Heuristic: If offset endpoints are very close together, 
-  	 * just use one of them as the corner vertex.
-  	 * This avoids problems with computing mitre corners in the case
-  	 * where the two segments are almost parallel 
-  	 * (which is hard to compute a robust intersection for).
-  	 */
-    if (offset0.p1.distance(offset1.p0) < distance * OFFSET_SEGMENT_SEPARATION_FACTOR) {
-    	vertexList.addPt(offset0.p1);
-    	return;
-    }
-  	
-		if (bufParams.getJoinStyle() == BufferParameters.JOIN_MITRE) {
-			addMitreJoin(s1, offset0, offset1, distance);
-		}
-		else if (bufParams.getJoinStyle() == BufferParameters.JOIN_BEVEL){
-			addBevelJoin(offset0, offset1);
-		}
-		else {
-		// add a circular fillet connecting the endpoints of the offset segments
-		 if (addStartPoint) vertexList.addPt(offset0.p1);
-      // TESTING - comment out to produce beveled joins
-      addFillet(s1, offset0.p1, offset1.p0, orientation, distance);
-      vertexList.addPt(offset1.p0);
-		}
-  }
-  
-  /**
-   * Adds the offset points for an inside (concave) turn.
-   * 
-   * @param orientation
-   * @param addStartPoint
-   */
-  private void addInsideTurn(int orientation, boolean addStartPoint) {
-    /**
-     * add intersection point of offset segments (if any)
-     */
-    li.computeIntersection(offset0.p0, offset0.p1, offset1.p0, offset1.p1);
-    if (li.hasIntersection()) {
-      vertexList.addPt(li.getIntersection(0));
+    if (isRightSide) {
+      // add original line
+      segGen.addSegments(inputPts, true);
+      
+      //---------- compute points for right side of line
+      // Simplify the appropriate side of the line before generating
+      Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol);
+      // MD - used for testing only (to eliminate simplification)
+  //    Coordinate[] simp2 = inputPts;
+      int n2 = simp2.length - 1;
+     
+      // since we are traversing line in opposite order, offset position is still LEFT
+      segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT);
+      segGen.addFirstSegment();
+      for (int i = n2 - 2; i >= 0; i--) {
+        segGen.addNextSegment(simp2[i], true);
+      }
     }
     else {
-      /**
-       * If no intersection is detected, it means the angle is so small and/or the offset so
-       * large that the offsets segments don't intersect. In this case we must
-       * add a "closing segment" to make sure the buffer curve is continuous,
-       * fairly smooth (e.g. no sharp reversals in direction)
-       * and tracks the buffer correctly around the corner. The curve connects
-       * the endpoints of the segment offsets to points
-       * which lie toward the centre point of the corner.
-       * The joining curve will not appear in the final buffer outline, since it
-       * is completely internal to the buffer polygon.
-       * 
-       * In complex buffer cases the closing segment may cut across many other
-       * segments in the generated offset curve.  In order to improve the 
-       * performance of the noding, the closing segment should be kept as short as possible.
-       * (But not too short, since that would defeat it's purpose).
-       * This is the purpose of the closingSegFactor heuristic value.
-       */ 
-    	
-       /** 
-       * The intersection test above is vulnerable to robustness errors; i.e. it
-       * may be that the offsets should intersect very close to their endpoints,
-       * but aren't reported as such due to rounding. To handle this situation
-       * appropriately, we use the following test: If the offset points are very
-       * close, don't add closing segments but simply use one of the offset
-       * points
-       */
-      if (offset0.p1.distance(offset1.p0) < distance
-          * INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR) {
-        vertexList.addPt(offset0.p1);
-      } else {
-        // add endpoint of this segment offset
-        vertexList.addPt(offset0.p1);
-        
-        /**
-         * Add "closing segment" of required length.
-         */
-        if (closingSegFactor > 0) {
-          Coordinate mid0 = new Coordinate((closingSegFactor * offset0.p1.x + s1.x)/(closingSegFactor + 1), 
-              (closingSegFactor*offset0.p1.y + s1.y)/(closingSegFactor + 1));
-          vertexList.addPt(mid0);
-          Coordinate mid1 = new Coordinate((closingSegFactor*offset1.p0.x + s1.x)/(closingSegFactor + 1), 
-             (closingSegFactor*offset1.p0.y + s1.y)/(closingSegFactor + 1));
-          vertexList.addPt(mid1);
-        }
-        else {
-          /**
-           * This branch is not expected to be used except for testing purposes.
-           * It is equivalent to the JTS 1.9 logic for closing segments
-           * (which results in very poor performance for large buffer distances)
-           */
-          vertexList.addPt(s1);
-        }
-        
-        //*/  
-        // add start point of next segment offset
-        vertexList.addPt(offset1.p0);
+      // add original line
+      segGen.addSegments(inputPts, false);
+      
+      //--------- compute points for left side of line
+      // Simplify the appropriate side of the line before generating
+      Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol);
+      // MD - used for testing only (to eliminate simplification)
+//      Coordinate[] simp1 = inputPts;
+      
+      int n1 = simp1.length - 1;
+      segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT);
+      segGen.addFirstSegment();
+      for (int i = 2; i <= n1; i++) {
+        segGen.addNextSegment(simp1[i], true);
       }
     }
+    segGen.addLastSegment();
+    segGen.closeRing();
   }
-  
-  /**
-   * Add last offset point
-   */
-  private void addLastSegment()
-  {
-  	vertexList.addPt(offset1.p1);
-  }
-
-  /**
-   * Compute an offset segment for an input segment on a given side and at a given distance.
-   * The offset points are computed in full double precision, for accuracy.
-   *
-   * @param seg the segment to offset
-   * @param side the side of the segment ({@link Position}) the offset lies on
-   * @param distance the offset distance
-   * @param offset the points computed for the offset segment
-   */
-  private void computeOffsetSegment(LineSegment seg, int side, double distance, LineSegment offset)
-  {
-    int sideSign = side == Position.LEFT ? 1 : -1;
-    double dx = seg.p1.x - seg.p0.x;
-    double dy = seg.p1.y - seg.p0.y;
-    double len = Math.sqrt(dx * dx + dy * dy);
-    // u is the vector that is the length of the offset, in the direction of the segment
-    double ux = sideSign * distance * dx / len;
-    double uy = sideSign * distance * dy / len;
-    offset.p0.x = seg.p0.x - uy;
-    offset.p0.y = seg.p0.y + ux;
-    offset.p1.x = seg.p1.x - uy;
-    offset.p1.y = seg.p1.y + ux;
-  }
-
-  /**
-   * Add an end cap around point p1, terminating a line segment coming from p0
-   */
-  private void addLineEndCap(Coordinate p0, Coordinate p1)
-  {
-    LineSegment seg = new LineSegment(p0, p1);
-
-    LineSegment offsetL = new LineSegment();
-    computeOffsetSegment(seg, Position.LEFT, distance, offsetL);
-    LineSegment offsetR = new LineSegment();
-    computeOffsetSegment(seg, Position.RIGHT, distance, offsetR);
-
-    double dx = p1.x - p0.x;
-    double dy = p1.y - p0.y;
-    double angle = Math.atan2(dy, dx);
-
-    switch (bufParams.getEndCapStyle()) {
-      case BufferParameters.CAP_ROUND:
-        // add offset seg points with a fillet between them
-      	vertexList.addPt(offsetL.p1);
-        addFillet(p1, angle + Math.PI / 2, angle - Math.PI / 2, CGAlgorithms.CLOCKWISE, distance);
-        vertexList.addPt(offsetR.p1);
-        break;
-      case BufferParameters.CAP_FLAT:
-        // only offset segment points are added
-      	vertexList.addPt(offsetL.p1);
-      	vertexList.addPt(offsetR.p1);
-        break;
-      case BufferParameters.CAP_SQUARE:
-        // add a square defined by extensions of the offset segment endpoints
-        Coordinate squareCapSideOffset = new Coordinate();
-        squareCapSideOffset.x = Math.abs(distance) * Math.cos(angle);
-        squareCapSideOffset.y = Math.abs(distance) * Math.sin(angle);
-
-        Coordinate squareCapLOffset = new Coordinate(
-            offsetL.p1.x + squareCapSideOffset.x,
-            offsetL.p1.y + squareCapSideOffset.y);
-        Coordinate squareCapROffset = new Coordinate(
-            offsetR.p1.x + squareCapSideOffset.x,
-            offsetR.p1.y + squareCapSideOffset.y);
-        vertexList.addPt(squareCapLOffset);
-        vertexList.addPt(squareCapROffset);
-        break;
-
-    }
-  }
-  /**
-   * Adds a mitre join connecting the two reflex offset segments.
-   * The mitre will be beveled if it exceeds the mitre ratio limit.
-   * 
-   * @param offset0 the first offset segment
-   * @param offset1 the second offset segment
-   * @param distance the offset distance
-   */
-  private void addMitreJoin(Coordinate p, 
-  		LineSegment offset0, 
-  		LineSegment offset1,
-  		double distance)
-  {
-  	boolean isMitreWithinLimit = true;
-  	Coordinate intPt = null;
-  
-  	/**
-  	 * This computation is unstable if the offset segments are nearly collinear.
-  	 * Howver, this situation should have been eliminated earlier by the check for 
-  	 * whether the offset segment endpoints are almost coincident
-  	 */
-  	try {
-  	 intPt = HCoordinate.intersection(offset0.p0, 
-  			offset0.p1, offset1.p0, offset1.p1);
-  	 
-  	 double mitreRatio = distance <= 0.0 ? 1.0
-  			 : intPt.distance(p) / Math.abs(distance);
-  	 
-  	 if (mitreRatio > bufParams.getMitreLimit())
-  		 isMitreWithinLimit = false;
-  	}
-  	catch (NotRepresentableException ex) {
-  		intPt = new Coordinate(0,0);
-  		isMitreWithinLimit = false;
-  	}
-  	
-  	if (isMitreWithinLimit) {
-  		vertexList.addPt(intPt);
-  	}
-  	else {
-  		addLimitedMitreJoin(offset0, offset1, distance, bufParams.getMitreLimit());
-//  		addBevelJoin(offset0, offset1);
-  	}
-  }
-  
-  
-  /**
-   * Adds a limited mitre join connecting the two reflex offset segments.
-   * A limited mitre is a mitre which is beveled at the distance
-   * determined by the mitre ratio limit.
-   * 
-   * @param offset0 the first offset segment
-   * @param offset1 the second offset segment
-   * @param distance the offset distance
-   * @param mitreLimit the mitre limit ratio
-   */
-  private void addLimitedMitreJoin( 
-  		LineSegment offset0, 
-  		LineSegment offset1,
-  		double distance,
-  		double mitreLimit)
-  {
-  	Coordinate basePt = seg0.p1;
-  	
-  	double ang0 = Angle.angle(basePt, seg0.p0);
-  	double ang1 = Angle.angle(basePt, seg1.p1);
-  	
-  	// oriented angle between segments
-  	double angDiff = Angle.angleBetweenOriented(seg0.p0, basePt, seg1.p1);
-  	// half of the interior angle
-  	double angDiffHalf = angDiff / 2;
-  
-  	// angle for bisector of the interior angle between the segments
-  	double midAng = Angle.normalize(ang0 + angDiffHalf);
-  	// rotating this by PI gives the bisector of the reflex angle
-  	double mitreMidAng = Angle.normalize(midAng + Math.PI);
-  	
-  	// the miterLimit determines the distance to the mitre bevel
-  	double mitreDist = mitreLimit * distance;
-  	// the bevel delta is the difference between the buffer distance
-  	// and half of the length of the bevel segment
-  	double bevelDelta = mitreDist * Math.abs(Math.sin(angDiffHalf));
-  	double bevelHalfLen = distance - bevelDelta;
 
-  	// compute the midpoint of the bevel segment
-  	double bevelMidX = basePt.x + mitreDist * Math.cos(mitreMidAng);
-  	double bevelMidY = basePt.y + mitreDist * Math.sin(mitreMidAng);
-  	Coordinate bevelMidPt = new Coordinate(bevelMidX, bevelMidY);
-  	
-  	// compute the mitre midline segment from the corner point to the bevel segment midpoint
-  	LineSegment mitreMidLine = new LineSegment(basePt, bevelMidPt);
-  	
-  	// finally the bevel segment endpoints are computed as offsets from 
-    // the mitre midline
-  	Coordinate bevelEndLeft = mitreMidLine.pointAlongOffset(1.0, bevelHalfLen);
-  	Coordinate bevelEndRight = mitreMidLine.pointAlongOffset(1.0, -bevelHalfLen);
-  	
-  	if (side == Position.LEFT) {
-  		vertexList.addPt(bevelEndLeft);
-  		vertexList.addPt(bevelEndRight);
-  	}
-  	else {
-  		vertexList.addPt(bevelEndRight);
-  		vertexList.addPt(bevelEndLeft);  		
-  	}
-  }
-  
-  /**
-   * Adds a bevel join connecting the two offset segments
-   * around a reflex corner.
-   * 
-   * @param offset0 the first offset segment
-   * @param offset1 the second offset segment
-   */
-  private void addBevelJoin( 
-  		LineSegment offset0, 
-  		LineSegment offset1)
+  private void computeOffsetCurve(Coordinate[] inputPts, boolean isRightSide, OffsetSegmentGenerator segGen)
   {
-		 vertexList.addPt(offset0.p1);
-     vertexList.addPt(offset1.p0);				
-  }
-  
-  
-  /**
-   * Add points for a circular fillet around a reflex corner.
-   * Adds the start and end points
-   * 
-   * @param p base point of curve
-   * @param p0 start point of fillet curve
-   * @param p1 endpoint of fillet curve
-   * @param direction the orientation of the fillet
-   * @param radius the radius of the fillet
-   */
-  private void addFillet(Coordinate p, Coordinate p0, Coordinate p1, int direction, double radius)
-  {
-    double dx0 = p0.x - p.x;
-    double dy0 = p0.y - p.y;
-    double startAngle = Math.atan2(dy0, dx0);
-    double dx1 = p1.x - p.x;
-    double dy1 = p1.y - p.y;
-    double endAngle = Math.atan2(dy1, dx1);
-
-    if (direction == CGAlgorithms.CLOCKWISE) {
-      if (startAngle <= endAngle) startAngle += 2.0 * Math.PI;
+    double distTol = simplifyTolerance(distance);
+    
+    if (isRightSide) {
+      //---------- compute points for right side of line
+      // Simplify the appropriate side of the line before generating
+      Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol);
+      // MD - used for testing only (to eliminate simplification)
+  //    Coordinate[] simp2 = inputPts;
+      int n2 = simp2.length - 1;
+     
+      // since we are traversing line in opposite order, offset position is still LEFT
+      segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT);
+      segGen.addFirstSegment();
+      for (int i = n2 - 2; i >= 0; i--) {
+        segGen.addNextSegment(simp2[i], true);
+      }
     }
-    else {    // direction == COUNTERCLOCKWISE
-      if (startAngle >= endAngle) startAngle -= 2.0 * Math.PI;
+    else {
+      //--------- compute points for left side of line
+      // Simplify the appropriate side of the line before generating
+      Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol);
+      // MD - used for testing only (to eliminate simplification)
+//      Coordinate[] simp1 = inputPts;
+      
+      int n1 = simp1.length - 1;
+      segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT);
+      segGen.addFirstSegment();
+      for (int i = 2; i <= n1; i++) {
+        segGen.addNextSegment(simp1[i], true);
+      }
     }
-    vertexList.addPt(p0);
-    addFillet(p, startAngle, endAngle, direction, radius);
-    vertexList.addPt(p1);
+    segGen.addLastSegment();
   }
 
-  /**
-   * Adds points for a circular fillet arc
-   * between two specified angles.  
-   * The start and end point for the fillet are not added -
-   * the caller must add them if required.
-   *
-   * @param direction is -1 for a CW angle, 1 for a CCW angle
-   * @param radius the radius of the fillet
-   */
-  private void addFillet(Coordinate p, double startAngle, double endAngle, int direction, double radius)
+  private void computeRingBufferCurve(Coordinate[] inputPts, int side, OffsetSegmentGenerator segGen)
   {
-    int directionFactor = direction == CGAlgorithms.CLOCKWISE ? -1 : 1;
-
-    double totalAngle = Math.abs(startAngle - endAngle);
-    int nSegs = (int) (totalAngle / filletAngleQuantum + 0.5);
-
-    if (nSegs < 1) return;    // no segments because angle is less than increment - nothing to do!
-
-    double initAngle, currAngleInc;
-
-    // choose angle increment so that each segment has equal length
-    initAngle = 0.0;
-    currAngleInc = totalAngle / nSegs;
-
-    double currAngle = initAngle;
-    Coordinate pt = new Coordinate();
-    while (currAngle < totalAngle) {
-      double angle = startAngle + directionFactor * currAngle;
-      pt.x = p.x + radius * Math.cos(angle);
-      pt.y = p.y + radius * Math.sin(angle);
-      vertexList.addPt(pt);
-      currAngle += currAngleInc;
+    // simplify input line to improve performance
+    double distTol = simplifyTolerance(distance);
+    // ensure that correct side is simplified
+    if (side == Position.RIGHT)
+      distTol = -distTol;
+    Coordinate[] simp = BufferInputLineSimplifier.simplify(inputPts, distTol);
+//    Coordinate[] simp = inputPts;
+    
+    int n = simp.length - 1;
+    segGen.initSideSegments(simp[n - 1], simp[0], side);
+    for (int i = 1; i <= n; i++) {
+      boolean addStartPoint = i != 1;
+      segGen.addNextSegment(simp[i], addStartPoint);
     }
+    segGen.closeRing();
   }
 
 
-  /**
-   * Adds a CW circle around a point
-   */
-  private void addCircle(Coordinate p, double distance)
-  {
-    // add start point
-    Coordinate pt = new Coordinate(p.x + distance, p.y);
-    vertexList.addPt(pt);
-    addFillet(p, 0.0, 2.0 * Math.PI, -1, distance);
-  }
-
-  /**
-   * Adds a CW square around a point
-   */
-  private void addSquare(Coordinate p, double distance)
-  {
-    // add start point
-  	vertexList.addPt(new Coordinate(p.x + distance, p.y + distance));
-  	vertexList.addPt(new Coordinate(p.x + distance, p.y - distance));
-  	vertexList.addPt(new Coordinate(p.x - distance, p.y - distance));
-  	vertexList.addPt(new Coordinate(p.x - distance, p.y + distance));
-  	vertexList.addPt(new Coordinate(p.x + distance, p.y + distance));
-  }
 }
diff --git a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveSetBuilder.java b/src/com/vividsolutions/jts/operation/buffer/OffsetCurveSetBuilder.java
index 9d16fa9..a9022f6 100644
--- a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveSetBuilder.java
+++ b/src/com/vividsolutions/jts/operation/buffer/OffsetCurveSetBuilder.java
@@ -82,14 +82,6 @@ public class OffsetCurveSetBuilder {
     return curveList;
   }
 
-  private void addCurves(List lineList, int leftLoc, int rightLoc)
-  {
-    for (Iterator i = lineList.iterator(); i.hasNext(); ) {
-      Coordinate[] coords = (Coordinate[]) i.next();
-      addCurve(coords, leftLoc, rightLoc);
-    }
-  }
-
   /**
    * Creates a {@link SegmentString} for a coordinate list which is a raw offset curve,
    * and adds it to the list of buffer curves.
@@ -101,8 +93,8 @@ public class OffsetCurveSetBuilder {
    */
   private void addCurve(Coordinate[] coord, int leftLoc, int rightLoc)
   {
-    // don't add null curves!
-    if (coord.length < 2) return;
+    // don't add null or trivial curves
+    if (coord == null || coord.length < 2) return;
     // add the edge for a coordinate list which is a raw offset curve
     SegmentString e = new NodedSegmentString(coord,
                         new Label(0, Location.BOUNDARY, leftLoc, rightLoc));
@@ -136,17 +128,22 @@ public class OffsetCurveSetBuilder {
    */
   private void addPoint(Point p)
   {
-    if (distance <= 0.0) return;
+    // a zero or negative width buffer of a line/point is empty
+    if (distance <= 0.0) 
+      return;
     Coordinate[] coord = p.getCoordinates();
-    List lineList = curveBuilder.getLineCurve(coord, distance);
-    addCurves(lineList, Location.EXTERIOR, Location.INTERIOR);
+    Coordinate[] curve = curveBuilder.getLineCurve(coord, distance);
+    addCurve(curve, Location.EXTERIOR, Location.INTERIOR);
   }
+  
   private void addLineString(LineString line)
   {
-    if (distance <= 0.0) return;
+    // a zero or negative width buffer of a line/point is empty
+    if (distance <= 0.0 && ! curveBuilder.getBufferParameters().isSingleSided()) 
+      return;
     Coordinate[] coord = CoordinateArrays.removeRepeatedPoints(line.getCoordinates());
-    List lineList = curveBuilder.getLineCurve(coord, distance);
-    addCurves(lineList, Location.EXTERIOR, Location.INTERIOR);
+    Coordinate[] curve = curveBuilder.getLineCurve(coord, distance);
+    addCurve(curve, Location.EXTERIOR, Location.INTERIOR);
   }
 
   private void addPolygon(Polygon p)
@@ -196,8 +193,9 @@ public class OffsetCurveSetBuilder {
             Location.EXTERIOR);
     }
   }
+  
   /**
-   * Add an offset curve for a ring.
+   * Adds an offset curve for a polygon ring.
    * The side and left and right topological location arguments
    * assume that the ring is oriented CW.
    * If the ring is in the opposite orientation,
@@ -211,16 +209,20 @@ public class OffsetCurveSetBuilder {
    */
   private void addPolygonRing(Coordinate[] coord, double offsetDistance, int side, int cwLeftLoc, int cwRightLoc)
   {
-    //Coordinate[] coord = CoordinateArrays.removeRepeatedPoints(lr.getCoordinates());
+    // don't bother adding ring if it is "flat" and will disappear in the output
+    if (offsetDistance == 0.0 && coord.length < LinearRing.MINIMUM_VALID_SIZE)
+      return;
+    
     int leftLoc  = cwLeftLoc;
     int rightLoc = cwRightLoc;
-    if (CGAlgorithms.isCCW(coord)) {
+    if (coord.length >= LinearRing.MINIMUM_VALID_SIZE 
+        && CGAlgorithms.isCCW(coord)) {
       leftLoc = cwRightLoc;
       rightLoc = cwLeftLoc;
       side = Position.opposite(side);
     }
-    List lineList = curveBuilder.getRingCurve(coord, side, offsetDistance);
-    addCurves(lineList, leftLoc, rightLoc);
+    Coordinate[] curve = curveBuilder.getRingCurve(coord, side, offsetDistance);
+    addCurve(curve, leftLoc, rightLoc);
   }
 
   /**
diff --git a/src/com/vividsolutions/jts/operation/buffer/OffsetSegmentGenerator.java b/src/com/vividsolutions/jts/operation/buffer/OffsetSegmentGenerator.java
new file mode 100644
index 0000000..b48a956
--- /dev/null
+++ b/src/com/vividsolutions/jts/operation/buffer/OffsetSegmentGenerator.java
@@ -0,0 +1,676 @@
+/*
+ * 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.operation.buffer;
+
+import com.vividsolutions.jts.algorithm.Angle;
+import com.vividsolutions.jts.algorithm.CGAlgorithms;
+import com.vividsolutions.jts.algorithm.HCoordinate;
+import com.vividsolutions.jts.algorithm.LineIntersector;
+import com.vividsolutions.jts.algorithm.NotRepresentableException;
+import com.vividsolutions.jts.algorithm.RobustLineIntersector;
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.LineSegment;
+import com.vividsolutions.jts.geom.PrecisionModel;
+import com.vividsolutions.jts.geomgraph.Position;
+
+/**
+ * Generates segments which form an offset curve.
+ * Supports all end cap and join options 
+ * provided for buffering.
+ * Implements various heuristics to 
+ * produce smoother, simpler curves which are
+ * still within a reasonable tolerance of the 
+ * true curve.
+ * 
+ * @author Martin Davis
+ *
+ */
+class OffsetSegmentGenerator 
+{
+
+  /**
+   * Factor which controls how close offset segments can be to
+   * skip adding a filler or mitre.
+   */
+  private static final double OFFSET_SEGMENT_SEPARATION_FACTOR = 1.0E-3;
+  
+  /**
+   * Factor which controls how close curve vertices on inside turns can be to be snapped 
+   */
+  private static final double INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR = 1.0E-3;
+
+  /**
+   * Factor which controls how close curve vertices can be to be snapped
+   */
+  private static final double CURVE_VERTEX_SNAP_DISTANCE_FACTOR = 1.0E-6;
+
+  /**
+   * Factor which determines how short closing segs can be for round buffers
+   */
+  private static final int MAX_CLOSING_SEG_LEN_FACTOR = 80;
+
+  /**
+   * the max error of approximation (distance) between a quad segment and the true fillet curve
+   */
+  private double maxCurveSegmentError = 0.0;
+
+  /**
+   * The angle quantum with which to approximate a fillet curve
+   * (based on the input # of quadrant segments)
+   */
+  private double filletAngleQuantum;
+
+  /**
+   * The Closing Segment Length Factor controls how long
+   * "closing segments" are.  Closing segments are added
+   * at the middle of inside corners to ensure a smoother
+   * boundary for the buffer offset curve. 
+   * In some cases (particularly for round joins with default-or-better
+   * quantization) the closing segments can be made quite short.
+   * This substantially improves performance (due to fewer intersections being created).
+   * 
+   * A closingSegFactor of 0 results in lines to the corner vertex
+   * A closingSegFactor of 1 results in lines halfway to the corner vertex
+   * A closingSegFactor of 80 results in lines 1/81 of the way to the corner vertex
+   * (this option is reasonable for the very common default situation of round joins
+   * and quadrantSegs >= 8)
+   */
+  private int closingSegLengthFactor = 1;
+
+  private OffsetSegmentString segList;
+  private double distance = 0.0;
+  private PrecisionModel precisionModel;
+  private BufferParameters bufParams;
+  private LineIntersector li;
+
+  private Coordinate s0, s1, s2;
+  private LineSegment seg0 = new LineSegment();
+  private LineSegment seg1 = new LineSegment();
+  private LineSegment offset0 = new LineSegment();
+  private LineSegment offset1 = new LineSegment();
+  private int side = 0;
+  private boolean hasNarrowConcaveAngle = false;
+
+  public OffsetSegmentGenerator(PrecisionModel precisionModel,
+      BufferParameters bufParams, double distance) {
+    this.precisionModel = precisionModel;
+    this.bufParams = bufParams;
+
+    // compute intersections in full precision, to provide accuracy
+    // the points are rounded as they are inserted into the curve line
+    li = new RobustLineIntersector();
+    filletAngleQuantum = Math.PI / 2.0 / bufParams.getQuadrantSegments();
+
+    /**
+     * Non-round joins cause issues with short closing segments, so don't use
+     * them. In any case, non-round joins only really make sense for relatively
+     * small buffer distances.
+     */
+    if (bufParams.getQuadrantSegments() >= 8
+        && bufParams.getJoinStyle() == BufferParameters.JOIN_ROUND)
+      closingSegLengthFactor = MAX_CLOSING_SEG_LEN_FACTOR;
+    init(distance);
+  }
+
+  /**
+   * Tests whether the input has a narrow concave angle
+   * (relative to the offset distance).
+   * In this case the generated offset curve will contain self-intersections
+   * and heuristic closing segments.
+   * This is expected behaviour in the case of buffer curves. 
+   * For pure offset curves,
+   * the output needs to be further treated 
+   * before it can be used. 
+   * 
+   * @return true if the input has a narrow concave angle
+   */
+  public boolean hasNarrowConcaveAngle()
+  {
+    return hasNarrowConcaveAngle;
+  }
+  
+  private void init(double distance)
+  {
+    this.distance = distance;
+    maxCurveSegmentError = distance * (1 - Math.cos(filletAngleQuantum / 2.0));
+    segList = new OffsetSegmentString();
+    segList.setPrecisionModel(precisionModel);
+    /**
+     * Choose the min vertex separation as a small fraction of the offset distance.
+     */
+    segList.setMinimumVertexDistance(distance * CURVE_VERTEX_SNAP_DISTANCE_FACTOR);
+  }
+
+
+  public void initSideSegments(Coordinate s1, Coordinate s2, int side)
+  {
+    this.s1 = s1;
+    this.s2 = s2;
+    this.side = side;
+    seg1.setCoordinates(s1, s2);
+    computeOffsetSegment(seg1, side, distance, offset1);
+  }
+
+  public Coordinate[] getCoordinates()
+  {
+    return segList.getCoordinates();
+  }
+  
+  public void closeRing()
+  {
+    segList.closeRing();
+  }
+  
+  public void addSegments(Coordinate[] pt, boolean isForward)
+  {
+    segList.addPts(pt, isForward);
+  }
+  
+  public void addFirstSegment()
+  {
+    segList.addPt(offset1.p0);
+  }
+  
+  /**
+   * Add last offset point
+   */
+  public void addLastSegment()
+  {
+    segList.addPt(offset1.p1);
+  }
+
+  //private static double MAX_CLOSING_SEG_LEN = 3.0;
+
+  public void addNextSegment(Coordinate p, boolean addStartPoint)
+  {
+    // s0-s1-s2 are the coordinates of the previous segment and the current one
+    s0 = s1;
+    s1 = s2;
+    s2 = p;
+    seg0.setCoordinates(s0, s1);
+    computeOffsetSegment(seg0, side, distance, offset0);
+    seg1.setCoordinates(s1, s2);
+    computeOffsetSegment(seg1, side, distance, offset1);
+
+    // do nothing if points are equal
+    if (s1.equals(s2)) return;
+
+    int orientation = CGAlgorithms.computeOrientation(s0, s1, s2);
+    boolean outsideTurn =
+          (orientation == CGAlgorithms.CLOCKWISE        && side == Position.LEFT)
+      ||  (orientation == CGAlgorithms.COUNTERCLOCKWISE && side == Position.RIGHT);
+
+    if (orientation == 0) { // lines are collinear
+      addCollinear(addStartPoint);
+    }
+    else if (outsideTurn) 
+    {
+      addOutsideTurn(orientation, addStartPoint);
+    }
+    else { // inside turn
+      addInsideTurn(orientation, addStartPoint);
+    }
+  }
+  
+  private void addCollinear(boolean addStartPoint)
+  {
+    /**
+     * This test could probably be done more efficiently,
+     * but the situation of exact collinearity should be fairly rare.
+     */
+    li.computeIntersection(s0, s1, s1, s2);
+    int numInt = li.getIntersectionNum();
+    /**
+     * if numInt is < 2, the lines are parallel and in the same direction. In
+     * this case the point can be ignored, since the offset lines will also be
+     * parallel.
+     */
+    if (numInt >= 2) {
+      /**
+       * segments are collinear but reversing. 
+       * Add an "end-cap" fillet
+       * all the way around to other direction This case should ONLY happen
+       * for LineStrings, so the orientation is always CW. (Polygons can never
+       * have two consecutive segments which are parallel but reversed,
+       * because that would be a self intersection.
+       * 
+       */
+      if (bufParams.getJoinStyle() == BufferParameters.JOIN_BEVEL 
+          || bufParams.getJoinStyle() == BufferParameters.JOIN_MITRE) {
+        if (addStartPoint) segList.addPt(offset0.p1);
+        segList.addPt(offset1.p0);
+      }
+      else {
+        addFillet(s1, offset0.p1, offset1.p0, CGAlgorithms.CLOCKWISE, distance);
+      }
+    }
+  }
+  
+  /**
+   * Adds the offset points for an outside (convex) turn
+   * 
+   * @param orientation
+   * @param addStartPoint
+   */
+  private void addOutsideTurn(int orientation, boolean addStartPoint)
+  {
+    /**
+     * Heuristic: If offset endpoints are very close together, 
+     * just use one of them as the corner vertex.
+     * This avoids problems with computing mitre corners in the case
+     * where the two segments are almost parallel 
+     * (which is hard to compute a robust intersection for).
+     */
+    if (offset0.p1.distance(offset1.p0) < distance * OFFSET_SEGMENT_SEPARATION_FACTOR) {
+      segList.addPt(offset0.p1);
+      return;
+    }
+    
+    if (bufParams.getJoinStyle() == BufferParameters.JOIN_MITRE) {
+      addMitreJoin(s1, offset0, offset1, distance);
+    }
+    else if (bufParams.getJoinStyle() == BufferParameters.JOIN_BEVEL){
+      addBevelJoin(offset0, offset1);
+    }
+    else {
+    // add a circular fillet connecting the endpoints of the offset segments
+     if (addStartPoint) segList.addPt(offset0.p1);
+      // TESTING - comment out to produce beveled joins
+      addFillet(s1, offset0.p1, offset1.p0, orientation, distance);
+      segList.addPt(offset1.p0);
+    }
+  }
+  
+  /**
+   * Adds the offset points for an inside (concave) turn.
+   * 
+   * @param orientation
+   * @param addStartPoint
+   */
+  private void addInsideTurn(int orientation, boolean addStartPoint) {
+    /**
+     * add intersection point of offset segments (if any)
+     */
+    li.computeIntersection(offset0.p0, offset0.p1, offset1.p0, offset1.p1);
+    if (li.hasIntersection()) {
+      segList.addPt(li.getIntersection(0));
+    }
+    else {
+      /**
+       * If no intersection is detected, 
+       * it means the angle is so small and/or the offset so
+       * large that the offsets segments don't intersect. 
+       * In this case we must
+       * add a "closing segment" to make sure the buffer curve is continuous,
+       * fairly smooth (e.g. no sharp reversals in direction)
+       * and tracks the buffer correctly around the corner. The curve connects
+       * the endpoints of the segment offsets to points
+       * which lie toward the centre point of the corner.
+       * The joining curve will not appear in the final buffer outline, since it
+       * is completely internal to the buffer polygon.
+       * 
+       * In complex buffer cases the closing segment may cut across many other
+       * segments in the generated offset curve.  In order to improve the 
+       * performance of the noding, the closing segment should be kept as short as possible.
+       * (But not too short, since that would defeat its purpose).
+       * This is the purpose of the closingSegFactor heuristic value.
+       */ 
+      
+       /** 
+       * The intersection test above is vulnerable to robustness errors; i.e. it
+       * may be that the offsets should intersect very close to their endpoints,
+       * but aren't reported as such due to rounding. To handle this situation
+       * appropriately, we use the following test: If the offset points are very
+       * close, don't add closing segments but simply use one of the offset
+       * points
+       */
+      hasNarrowConcaveAngle = true;
+      //System.out.println("NARROW ANGLE - distance = " + distance);
+      if (offset0.p1.distance(offset1.p0) < distance
+          * INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR) {
+        segList.addPt(offset0.p1);
+      } else {
+        // add endpoint of this segment offset
+        segList.addPt(offset0.p1);
+        
+        /**
+         * Add "closing segment" of required length.
+         */
+        if (closingSegLengthFactor > 0) {
+          Coordinate mid0 = new Coordinate((closingSegLengthFactor * offset0.p1.x + s1.x)/(closingSegLengthFactor + 1), 
+              (closingSegLengthFactor*offset0.p1.y + s1.y)/(closingSegLengthFactor + 1));
+          segList.addPt(mid0);
+          Coordinate mid1 = new Coordinate((closingSegLengthFactor*offset1.p0.x + s1.x)/(closingSegLengthFactor + 1), 
+             (closingSegLengthFactor*offset1.p0.y + s1.y)/(closingSegLengthFactor + 1));
+          segList.addPt(mid1);
+        }
+        else {
+          /**
+           * This branch is not expected to be used except for testing purposes.
+           * It is equivalent to the JTS 1.9 logic for closing segments
+           * (which results in very poor performance for large buffer distances)
+           */
+          segList.addPt(s1);
+        }
+        
+        //*/  
+        // add start point of next segment offset
+        segList.addPt(offset1.p0);
+      }
+    }
+  }
+  
+
+  /**
+   * Compute an offset segment for an input segment on a given side and at a given distance.
+   * The offset points are computed in full double precision, for accuracy.
+   *
+   * @param seg the segment to offset
+   * @param side the side of the segment ({@link Position}) the offset lies on
+   * @param distance the offset distance
+   * @param offset the points computed for the offset segment
+   */
+  private void computeOffsetSegment(LineSegment seg, int side, double distance, LineSegment offset)
+  {
+    int sideSign = side == Position.LEFT ? 1 : -1;
+    double dx = seg.p1.x - seg.p0.x;
+    double dy = seg.p1.y - seg.p0.y;
+    double len = Math.sqrt(dx * dx + dy * dy);
+    // u is the vector that is the length of the offset, in the direction of the segment
+    double ux = sideSign * distance * dx / len;
+    double uy = sideSign * distance * dy / len;
+    offset.p0.x = seg.p0.x - uy;
+    offset.p0.y = seg.p0.y + ux;
+    offset.p1.x = seg.p1.x - uy;
+    offset.p1.y = seg.p1.y + ux;
+  }
+
+  /**
+   * Add an end cap around point p1, terminating a line segment coming from p0
+   */
+  public void addLineEndCap(Coordinate p0, Coordinate p1)
+  {
+    LineSegment seg = new LineSegment(p0, p1);
+
+    LineSegment offsetL = new LineSegment();
+    computeOffsetSegment(seg, Position.LEFT, distance, offsetL);
+    LineSegment offsetR = new LineSegment();
+    computeOffsetSegment(seg, Position.RIGHT, distance, offsetR);
+
+    double dx = p1.x - p0.x;
+    double dy = p1.y - p0.y;
+    double angle = Math.atan2(dy, dx);
+
+    switch (bufParams.getEndCapStyle()) {
+      case BufferParameters.CAP_ROUND:
+        // add offset seg points with a fillet between them
+        segList.addPt(offsetL.p1);
+        addFillet(p1, angle + Math.PI / 2, angle - Math.PI / 2, CGAlgorithms.CLOCKWISE, distance);
+        segList.addPt(offsetR.p1);
+        break;
+      case BufferParameters.CAP_FLAT:
+        // only offset segment points are added
+        segList.addPt(offsetL.p1);
+        segList.addPt(offsetR.p1);
+        break;
+      case BufferParameters.CAP_SQUARE:
+        // add a square defined by extensions of the offset segment endpoints
+        Coordinate squareCapSideOffset = new Coordinate();
+        squareCapSideOffset.x = Math.abs(distance) * Math.cos(angle);
+        squareCapSideOffset.y = Math.abs(distance) * Math.sin(angle);
+
+        Coordinate squareCapLOffset = new Coordinate(
+            offsetL.p1.x + squareCapSideOffset.x,
+            offsetL.p1.y + squareCapSideOffset.y);
+        Coordinate squareCapROffset = new Coordinate(
+            offsetR.p1.x + squareCapSideOffset.x,
+            offsetR.p1.y + squareCapSideOffset.y);
+        segList.addPt(squareCapLOffset);
+        segList.addPt(squareCapROffset);
+        break;
+
+    }
+  }
+  /**
+   * Adds a mitre join connecting the two reflex offset segments.
+   * The mitre will be beveled if it exceeds the mitre ratio limit.
+   * 
+   * @param offset0 the first offset segment
+   * @param offset1 the second offset segment
+   * @param distance the offset distance
+   */
+  private void addMitreJoin(Coordinate p, 
+      LineSegment offset0, 
+      LineSegment offset1,
+      double distance)
+  {
+    boolean isMitreWithinLimit = true;
+    Coordinate intPt = null;
+  
+    /**
+     * This computation is unstable if the offset segments are nearly collinear.
+     * Howver, this situation should have been eliminated earlier by the check for 
+     * whether the offset segment endpoints are almost coincident
+     */
+    try {
+     intPt = HCoordinate.intersection(offset0.p0, 
+        offset0.p1, offset1.p0, offset1.p1);
+     
+     double mitreRatio = distance <= 0.0 ? 1.0
+         : intPt.distance(p) / Math.abs(distance);
+     
+     if (mitreRatio > bufParams.getMitreLimit())
+       isMitreWithinLimit = false;
+    }
+    catch (NotRepresentableException ex) {
+      intPt = new Coordinate(0,0);
+      isMitreWithinLimit = false;
+    }
+    
+    if (isMitreWithinLimit) {
+      segList.addPt(intPt);
+    }
+    else {
+      addLimitedMitreJoin(offset0, offset1, distance, bufParams.getMitreLimit());
+//      addBevelJoin(offset0, offset1);
+    }
+  }
+  
+  
+  /**
+   * Adds a limited mitre join connecting the two reflex offset segments.
+   * A limited mitre is a mitre which is beveled at the distance
+   * determined by the mitre ratio limit.
+   * 
+   * @param offset0 the first offset segment
+   * @param offset1 the second offset segment
+   * @param distance the offset distance
+   * @param mitreLimit the mitre limit ratio
+   */
+  private void addLimitedMitreJoin( 
+      LineSegment offset0, 
+      LineSegment offset1,
+      double distance,
+      double mitreLimit)
+  {
+    Coordinate basePt = seg0.p1;
+    
+    double ang0 = Angle.angle(basePt, seg0.p0);
+    double ang1 = Angle.angle(basePt, seg1.p1);
+    
+    // oriented angle between segments
+    double angDiff = Angle.angleBetweenOriented(seg0.p0, basePt, seg1.p1);
+    // half of the interior angle
+    double angDiffHalf = angDiff / 2;
+  
+    // angle for bisector of the interior angle between the segments
+    double midAng = Angle.normalize(ang0 + angDiffHalf);
+    // rotating this by PI gives the bisector of the reflex angle
+    double mitreMidAng = Angle.normalize(midAng + Math.PI);
+    
+    // the miterLimit determines the distance to the mitre bevel
+    double mitreDist = mitreLimit * distance;
+    // the bevel delta is the difference between the buffer distance
+    // and half of the length of the bevel segment
+    double bevelDelta = mitreDist * Math.abs(Math.sin(angDiffHalf));
+    double bevelHalfLen = distance - bevelDelta;
+
+    // compute the midpoint of the bevel segment
+    double bevelMidX = basePt.x + mitreDist * Math.cos(mitreMidAng);
+    double bevelMidY = basePt.y + mitreDist * Math.sin(mitreMidAng);
+    Coordinate bevelMidPt = new Coordinate(bevelMidX, bevelMidY);
+    
+    // compute the mitre midline segment from the corner point to the bevel segment midpoint
+    LineSegment mitreMidLine = new LineSegment(basePt, bevelMidPt);
+    
+    // finally the bevel segment endpoints are computed as offsets from 
+    // the mitre midline
+    Coordinate bevelEndLeft = mitreMidLine.pointAlongOffset(1.0, bevelHalfLen);
+    Coordinate bevelEndRight = mitreMidLine.pointAlongOffset(1.0, -bevelHalfLen);
+    
+    if (side == Position.LEFT) {
+      segList.addPt(bevelEndLeft);
+      segList.addPt(bevelEndRight);
+    }
+    else {
+      segList.addPt(bevelEndRight);
+      segList.addPt(bevelEndLeft);     
+    }
+  }
+  
+  /**
+   * Adds a bevel join connecting the two offset segments
+   * around a reflex corner.
+   * 
+   * @param offset0 the first offset segment
+   * @param offset1 the second offset segment
+   */
+  private void addBevelJoin( 
+      LineSegment offset0, 
+      LineSegment offset1)
+  {
+     segList.addPt(offset0.p1);
+     segList.addPt(offset1.p0);        
+  }
+  
+  
+  /**
+   * Add points for a circular fillet around a reflex corner.
+   * Adds the start and end points
+   * 
+   * @param p base point of curve
+   * @param p0 start point of fillet curve
+   * @param p1 endpoint of fillet curve
+   * @param direction the orientation of the fillet
+   * @param radius the radius of the fillet
+   */
+  private void addFillet(Coordinate p, Coordinate p0, Coordinate p1, int direction, double radius)
+  {
+    double dx0 = p0.x - p.x;
+    double dy0 = p0.y - p.y;
+    double startAngle = Math.atan2(dy0, dx0);
+    double dx1 = p1.x - p.x;
+    double dy1 = p1.y - p.y;
+    double endAngle = Math.atan2(dy1, dx1);
+
+    if (direction == CGAlgorithms.CLOCKWISE) {
+      if (startAngle <= endAngle) startAngle += 2.0 * Math.PI;
+    }
+    else {    // direction == COUNTERCLOCKWISE
+      if (startAngle >= endAngle) startAngle -= 2.0 * Math.PI;
+    }
+    segList.addPt(p0);
+    addFillet(p, startAngle, endAngle, direction, radius);
+    segList.addPt(p1);
+  }
+
+  /**
+   * Adds points for a circular fillet arc
+   * between two specified angles.  
+   * The start and end point for the fillet are not added -
+   * the caller must add them if required.
+   *
+   * @param direction is -1 for a CW angle, 1 for a CCW angle
+   * @param radius the radius of the fillet
+   */
+  private void addFillet(Coordinate p, double startAngle, double endAngle, int direction, double radius)
+  {
+    int directionFactor = direction == CGAlgorithms.CLOCKWISE ? -1 : 1;
+
+    double totalAngle = Math.abs(startAngle - endAngle);
+    int nSegs = (int) (totalAngle / filletAngleQuantum + 0.5);
+
+    if (nSegs < 1) return;    // no segments because angle is less than increment - nothing to do!
+
+    double initAngle, currAngleInc;
+
+    // choose angle increment so that each segment has equal length
+    initAngle = 0.0;
+    currAngleInc = totalAngle / nSegs;
+
+    double currAngle = initAngle;
+    Coordinate pt = new Coordinate();
+    while (currAngle < totalAngle) {
+      double angle = startAngle + directionFactor * currAngle;
+      pt.x = p.x + radius * Math.cos(angle);
+      pt.y = p.y + radius * Math.sin(angle);
+      segList.addPt(pt);
+      currAngle += currAngleInc;
+    }
+  }
+
+
+  /**
+   * Creates a CW circle around a point
+   */
+  public void createCircle(Coordinate p)
+  {
+    // add start point
+    Coordinate pt = new Coordinate(p.x + distance, p.y);
+    segList.addPt(pt);
+    addFillet(p, 0.0, 2.0 * Math.PI, -1, distance);
+    segList.closeRing();
+  }
+
+  /**
+   * Creates a CW square around a point
+   */
+  public void createSquare(Coordinate p)
+  {
+    segList.addPt(new Coordinate(p.x + distance, p.y + distance));
+    segList.addPt(new Coordinate(p.x + distance, p.y - distance));
+    segList.addPt(new Coordinate(p.x - distance, p.y - distance));
+    segList.addPt(new Coordinate(p.x - distance, p.y + distance));
+    segList.closeRing();
+  }
+}
diff --git a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveVertexList.java b/src/com/vividsolutions/jts/operation/buffer/OffsetSegmentString.java
similarity index 76%
rename from src/com/vividsolutions/jts/operation/buffer/OffsetCurveVertexList.java
rename to src/com/vividsolutions/jts/operation/buffer/OffsetSegmentString.java
index 0fec142..07feb52 100644
--- a/src/com/vividsolutions/jts/operation/buffer/OffsetCurveVertexList.java
+++ b/src/com/vividsolutions/jts/operation/buffer/OffsetSegmentString.java
@@ -36,13 +36,14 @@ import java.util.*;
 import com.vividsolutions.jts.geom.*;
 
 /**
- * A list of the vertices in a constructed offset curve.
- * Automatically removes close adjacent vertices.
+ * A dynamic list of the vertices in a constructed offset curve.
+ * Automatically removes adjacent vertices
+ * which are closer than a given tolerance.
  * 
  * @author Martin Davis
  *
  */
-public class OffsetCurveVertexList 
+class OffsetSegmentString 
 {
   private static final Coordinate[] COORDINATE_ARRAY_TYPE = new Coordinate[0];
 
@@ -56,7 +57,7 @@ public class OffsetCurveVertexList
    */
   private double minimimVertexDistance = 0.0;
 
-  public OffsetCurveVertexList()
+  public OffsetSegmentString()
   {
   	ptList = new ArrayList();
   }
@@ -76,20 +77,35 @@ public class OffsetCurveVertexList
     Coordinate bufPt = new Coordinate(pt);
     precisionModel.makePrecise(bufPt);
     // don't add duplicate (or near-duplicate) points
-    if (isDuplicate(bufPt))
-    		return;
+    if (isRedundant(bufPt))
+        return;
     ptList.add(bufPt);
 //System.out.println(bufPt);
   }
   
+  public void addPts(Coordinate[] pt, boolean isForward)
+  {
+    if (isForward) {
+      for (int i = 0; i < pt.length; i++) {
+        addPt(pt[i]);
+      }
+    }
+    else {
+      for (int i = pt.length - 1; i >= 0; i--) {
+        addPt(pt[i]);
+      }     
+    }
+  }
+  
   /**
-   * Tests whether the given point duplicates the previous
-   * point in the list (up to tolerance)
+   * Tests whether the given point is redundant
+   * relative to the previous
+   * point in the list (up to tolerance).
    * 
    * @param pt
-   * @return true if the point duplicates the previous point
+   * @return true if the point is redundant
    */
-  private boolean isDuplicate(Coordinate pt)
+  private boolean isRedundant(Coordinate pt)
   {
     if (ptList.size() < 1)
     	return false;
@@ -112,14 +128,21 @@ public class OffsetCurveVertexList
     ptList.add(startPt);
   }
 
+  public void reverse()
+  {
+    
+  }
+  
   public Coordinate[] getCoordinates()
   {
-    // check that points are a ring - add the startpoint again if they are not
-    if (ptList.size() > 1) {
+    /*
+     // check that points are a ring - add the startpoint again if they are not
+   if (ptList.size() > 1) {
       Coordinate start  = (Coordinate) ptList.get(0);
       Coordinate end    = (Coordinate) ptList.get(ptList.size() - 1);
       if (! start.equals(end) ) addPt(start);
     }
+    */
     Coordinate[] coord = (Coordinate[]) ptList.toArray(COORDINATE_ARRAY_TYPE);
     return coord;
   }
diff --git a/src/com/vividsolutions/jts/operation/buffer/validate/BufferDistanceValidator.java b/src/com/vividsolutions/jts/operation/buffer/validate/BufferDistanceValidator.java
index 9d71570..2990531 100644
--- a/src/com/vividsolutions/jts/operation/buffer/validate/BufferDistanceValidator.java
+++ b/src/com/vividsolutions/jts/operation/buffer/validate/BufferDistanceValidator.java
@@ -76,6 +76,7 @@ public class BufferDistanceValidator
   private boolean isValid = true;
   private String errMsg = null;
   private Coordinate errorLocation = null;
+  private Geometry errorIndicator = null;
   
   public BufferDistanceValidator(Geometry input, double bufDistance, Geometry result)
   {
@@ -118,7 +119,21 @@ public class BufferDistanceValidator
   
   public Coordinate getErrorLocation()
   {
-  	return errorLocation;
+    return errorLocation;
+  }
+  
+  /**
+   * Gets a geometry which indicates the location and nature of a validation failure.
+   * <p>
+   * The indicator is a line segment showing the location and size
+   * of the distance discrepancy.
+   * 
+   * @return a geometric error indicator
+   * @return null if no error was found
+   */
+  public Geometry getErrorIndicator()
+  {
+    return errorIndicator;
   }
   
   private void checkPositiveValid()
@@ -177,6 +192,7 @@ public class BufferDistanceValidator
   		isValid = false;
   		Coordinate[] pts = distOp.nearestPoints();
   		errorLocation = distOp.nearestPoints()[1];
+  		errorIndicator = g1.getFactory().createLineString(pts);
   		errMsg = "Distance between buffer curve and input is too small "
   			+ "(" + minDistanceFound
   			+ " at " + WKTWriter.toLineString(pts[0], pts[1]) +" )";
@@ -207,6 +223,7 @@ public class BufferDistanceValidator
       isValid = false;
       Coordinate[] pts = haus.getCoordinates();
       errorLocation = pts[1];
+      errorIndicator = input.getFactory().createLineString(pts);
       errMsg = "Distance between buffer curve and input is too large "
         + "(" + maxDistanceFound
         + " at " + WKTWriter.toLineString(pts[0], pts[1]) +")";
diff --git a/src/com/vividsolutions/jts/operation/buffer/validate/BufferResultValidator.java b/src/com/vividsolutions/jts/operation/buffer/validate/BufferResultValidator.java
index 8eaafb3..b2548b3 100644
--- a/src/com/vividsolutions/jts/operation/buffer/validate/BufferResultValidator.java
+++ b/src/com/vividsolutions/jts/operation/buffer/validate/BufferResultValidator.java
@@ -91,6 +91,7 @@ public class BufferResultValidator
   private boolean isValid = true;
   private String errorMsg = null;
   private Coordinate errorLocation = null;
+  private Geometry errorIndicator = null;
   
   public BufferResultValidator(Geometry input, double distance, Geometry result)
   {
@@ -123,6 +124,21 @@ public class BufferResultValidator
   	return errorLocation;
   }
   
+  /**
+   * Gets a geometry which indicates the location and nature of a validation failure.
+   * <p>
+   * If the failure is due to the buffer curve being too far or too close 
+   * to the input, the indicator is a line segment showing the location and size
+   * of the discrepancy.
+   * 
+   * @return a geometric error indicator
+   * @return null if no error was found
+   */
+  public Geometry getErrorIndicator()
+  {
+    return errorIndicator;
+  }
+  
   private void report(String checkName)
   {
     if (! VERBOSE) return;
@@ -136,6 +152,7 @@ public class BufferResultValidator
   			|| result instanceof MultiPolygon))
   	isValid = false;
   	errorMsg = "Result is not polygonal";
+    errorIndicator = result;
     report("Polygonal");
   }
   
@@ -150,6 +167,7 @@ public class BufferResultValidator
   	if (! result.isEmpty()) {
   		isValid = false;
   		errorMsg = "Result is non-empty";
+      errorIndicator = result;
   	}
     report("ExpectedEmpty");
   }
@@ -170,6 +188,7 @@ public class BufferResultValidator
   	if (! bufEnv.contains(expectedEnv)) {
   		isValid = false;
   		errorMsg = "Buffer envelope is incorrect";
+  		errorIndicator = input.getFactory().toGeometry(bufEnv);
   	}
     report("Envelope");
   }
@@ -183,11 +202,13 @@ public class BufferResultValidator
   			&& inputArea > resultArea) {
   		isValid = false;
   		errorMsg = "Area of positive buffer is smaller than input";
+      errorIndicator = result;
   	}
   	if (distance < 0.0
   			&& inputArea < resultArea) {
   		isValid = false;
   		errorMsg = "Area of negative buffer is larger than input";
+  		errorIndicator = result;
   	}
     report("Area");
   }
@@ -199,6 +220,7 @@ public class BufferResultValidator
   		isValid = false;
   		errorMsg = distValid.getErrorMessage();
   		errorLocation = distValid.getErrorLocation();
+  		errorIndicator = distValid.getErrorIndicator();
   	}
     report("Distance");
   }
diff --git a/src/com/vividsolutions/jts/operation/distance/DistanceOp.java b/src/com/vividsolutions/jts/operation/distance/DistanceOp.java
index c39f0ff..09f5248 100644
--- a/src/com/vividsolutions/jts/operation/distance/DistanceOp.java
+++ b/src/com/vividsolutions/jts/operation/distance/DistanceOp.java
@@ -181,7 +181,7 @@ public class DistanceOp
   
   /**
    * 
-   * @return
+   * @return a pair of {@link Coordinate}s of the nearest points
    * @deprecated renamed to nearestPoints
    */
   public Coordinate[] closestPoints()
@@ -203,7 +203,7 @@ public class DistanceOp
 
   /**
    * 
-   * @return
+   * @return a pair of {@link GeometryLocation}s for the nearest points
    * @deprecated renamed to nearestLocations
    */
   public GeometryLocation[] closestLocations()
diff --git a/src/com/vividsolutions/jts/operation/distance/FacetSequence.java b/src/com/vividsolutions/jts/operation/distance/FacetSequence.java
new file mode 100644
index 0000000..b2a4a2d
--- /dev/null
+++ b/src/com/vividsolutions/jts/operation/distance/FacetSequence.java
@@ -0,0 +1,157 @@
+package com.vividsolutions.jts.operation.distance;
+
+import com.vividsolutions.jts.algorithm.CGAlgorithms;
+import com.vividsolutions.jts.geom.*;
+
+/**
+ * Represents a sequence of facets (points or line segments)
+ * of a {@link Geometry}
+ * specified by a subsequence of a {@link CoordinateSequence}.
+ * 
+ * @author Martin Davis
+ *
+ */
+public class FacetSequence
+{
+  private CoordinateSequence pts;
+  private int start;
+  private int end;
+  
+  // temporary Coordinates to materialize points from the CoordinateSequence
+  private Coordinate pt = new Coordinate();
+  private Coordinate seqPt = new Coordinate();
+  
+  /**
+   * Creates a new section based on a CoordinateSequence.
+   * 
+   * @param pts the sequence holding the points in the section
+   * @param start the index of the start point
+   * @param end the index of the end point + 1
+   */
+  public FacetSequence(CoordinateSequence pts, int start, int end) 
+  {
+    this.pts = pts;
+    this.start = start;
+    this.end = end;
+  }
+  
+  /**
+   * Creates a new sequence for a single point from a CoordinateSequence.
+   * 
+   * @param pts the sequence holding the points in the facet sequence
+   * @param start the index of the point
+   */
+  public FacetSequence(CoordinateSequence pts, int start) 
+  {
+    this.pts = pts;
+    this.start = start;
+    this.end = start + 1;
+  }
+  
+  public Envelope getEnvelope()
+  {
+    Envelope env = new Envelope();
+    for (int i = start; i < end; i++) {
+      env.expandToInclude(pts.getX(i), pts.getY(i));
+    }
+    return env;
+  }
+  
+  public int size()
+  {
+    return end - start;
+  }
+  
+  public Coordinate getCoordinate(int index)
+  {
+    return pts.getCoordinate(start + index);
+  }
+  
+  public boolean isPoint()
+  {
+    return end - start == 1;
+  }
+  
+
+  public double distance(FacetSequence facetSeq)
+  {
+    boolean isPoint = isPoint();
+    boolean isPointOther = facetSeq.isPoint();
+    
+    if (isPoint && isPointOther) {
+      pts.getCoordinate(start, pt);
+      facetSeq.pts.getCoordinate(facetSeq.start, seqPt);
+      return pt.distance(seqPt);
+    }
+    else if (isPoint) {
+      pts.getCoordinate(start, pt);      
+      return computePointLineDistance(pt, facetSeq);
+    }
+    else if (isPointOther) {
+      facetSeq.pts.getCoordinate(facetSeq.start, seqPt);
+      return computePointLineDistance(seqPt, this);
+    }
+    return computeLineLineDistance(facetSeq);
+    
+  }
+  
+  // temporary Coordinates to materialize points from the CoordinateSequence
+  private Coordinate p0 = new Coordinate();
+  private Coordinate p1 = new Coordinate();
+  private Coordinate q0 = new Coordinate();
+  private Coordinate q1 = new Coordinate();
+
+  private double computeLineLineDistance(FacetSequence facetSeq)
+  {
+    // both linear - compute minimum segment-segment distance
+    double minDistance = Double.MAX_VALUE;
+
+    for (int i = start; i < end - 1; i++) {
+      for (int j = facetSeq.start; j < facetSeq.end - 1; j++) {
+        pts.getCoordinate(i, p0);
+        pts.getCoordinate(i + 1, p1);
+        facetSeq.pts.getCoordinate(j, q0);
+        facetSeq.pts.getCoordinate(j + 1, q1);
+        
+        double dist = CGAlgorithms.distanceLineLine(p0, p1, q0, q1);
+        if (dist == 0.0) 
+          return 0.0;
+        if (dist < minDistance) {
+          minDistance = dist;
+        }
+      }
+    }
+    return minDistance;
+  }
+
+  private double computePointLineDistance(Coordinate pt, FacetSequence facetSeq) 
+  {
+    double minDistance = Double.MAX_VALUE;
+
+    for (int i = facetSeq.start; i < facetSeq.end - 1; i++) {
+      facetSeq.pts.getCoordinate(i, q0);
+      facetSeq.pts.getCoordinate(i + 1, q1);
+      double dist = CGAlgorithms.distancePointLine(pt, q0, q1);
+      if (dist == 0.0) return 0.0;
+      if (dist < minDistance) {
+        minDistance = dist;
+      }
+    }
+    return minDistance;
+  }
+  
+  public String toString()
+  {
+    StringBuffer buf = new StringBuffer();
+    buf.append("LINESTRING ( ");
+    Coordinate p = new Coordinate();
+    for (int i = start; i < end; i++) {
+      if (i > start)
+        buf.append(", ");
+      pts.getCoordinate(i, p);
+      buf.append(p.x + " " + p.y);
+    }
+    buf.append(" )");
+    return buf.toString();
+  }
+}
diff --git a/src/com/vividsolutions/jts/operation/distance/FacetSequenceTreeBuilder.java b/src/com/vividsolutions/jts/operation/distance/FacetSequenceTreeBuilder.java
new file mode 100644
index 0000000..0d360ac
--- /dev/null
+++ b/src/com/vividsolutions/jts/operation/distance/FacetSequenceTreeBuilder.java
@@ -0,0 +1,73 @@
+package com.vividsolutions.jts.operation.distance;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import com.vividsolutions.jts.geom.CoordinateSequence;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.GeometryComponentFilter;
+import com.vividsolutions.jts.geom.LineString;
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.util.LinearComponentExtracter;
+import com.vividsolutions.jts.index.strtree.STRtree;
+
+public class FacetSequenceTreeBuilder {
+  // 6 seems to be a good facet sequence size
+  private static final int FACET_SEQUENCE_SIZE = 6;
+
+  // Seems to be better to use a minimum node capacity
+  private static final int STR_TREE_NODE_CAPACITY = 4;
+
+  public static STRtree build(Geometry g) {
+    STRtree tree = new STRtree(STR_TREE_NODE_CAPACITY);
+    List sections = computeFacetSequences(g);
+    for (Iterator i = sections.iterator(); i.hasNext();) {
+      FacetSequence section = (FacetSequence) i.next();
+      tree.insert(section.getEnvelope(), section);
+    }
+    tree.build();
+    return tree;
+  }
+
+  /**
+   * Creates facet sequences
+   * 
+   * @param g
+   * @return List<GeometryFacetSequence>
+   */
+  private static List computeFacetSequences(Geometry g) {
+    final List sections = new ArrayList();
+
+    g.apply(new GeometryComponentFilter() {
+
+      public void filter(Geometry geom) {
+        CoordinateSequence seq = null;
+        if (geom instanceof LineString) {
+          seq = ((LineString) geom).getCoordinateSequence();
+          addFacetSequences(seq, sections);
+        }
+        else if (geom instanceof Point) {
+          seq = ((Point) geom).getCoordinateSequence();
+          addFacetSequences(seq, sections);
+        }
+      }
+    });
+    return sections;
+  }
+
+  private static void addFacetSequences(CoordinateSequence pts, List sections) {
+    int i = 0;
+    int size = pts.size();
+    while (i <= size - 1) {
+      int end = i + FACET_SEQUENCE_SIZE + 1;
+      // if only one point remains after this section, include it in this
+      // section
+      if (end >= size - 1)
+        end = size;
+      FacetSequence sect = new FacetSequence(pts, i, end);
+      sections.add(sect);
+      i = i + FACET_SEQUENCE_SIZE;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/com/vividsolutions/jts/operation/distance/GeometryLocation.java b/src/com/vividsolutions/jts/operation/distance/GeometryLocation.java
index 1ec5a7c..ae92f61 100644
--- a/src/com/vividsolutions/jts/operation/distance/GeometryLocation.java
+++ b/src/com/vividsolutions/jts/operation/distance/GeometryLocation.java
@@ -63,11 +63,11 @@ public class GeometryLocation
   /**
    * Constructs a GeometryLocation specifying a point on a geometry, as well as the 
    * segment that the point is on 
-   * (or {@link INSIDE_AREA} if the point is not on a segment).
+   * (or {@link #INSIDE_AREA} if the point is not on a segment).
    * 
    * @param component the component of the geometry containing the point
    * @param segIndex the segment index of the location, or INSIDE_AREA
-   * @param the coordinate of the location
+   * @param pt the coordinate of the location
    */
   public GeometryLocation(Geometry component, int segIndex, Coordinate pt)
   {
@@ -80,7 +80,7 @@ public class GeometryLocation
    * Constructs a GeometryLocation specifying a point inside an area geometry.
    * 
    * @param component the component of the geometry containing the point
-   * @param the coordinate of the location
+   * @param pt the coordinate of the location
    */  
   public GeometryLocation(Geometry component,Coordinate pt)
   {
@@ -94,7 +94,7 @@ public class GeometryLocation
   
   /**
    * Returns the segment index for this location. If the location is inside an
-   * area, the index will have the value {@link INSIDE_AREA};
+   * area, the index will have the value {@link #INSIDE_AREA};
    *
    * @return the segment index for the location, or INSIDE_AREA
    */
diff --git a/src/com/vividsolutions/jts/operation/distance/IndexedFacetDistance.java b/src/com/vividsolutions/jts/operation/distance/IndexedFacetDistance.java
new file mode 100644
index 0000000..ba348e2
--- /dev/null
+++ b/src/com/vividsolutions/jts/operation/distance/IndexedFacetDistance.java
@@ -0,0 +1,155 @@
+package com.vividsolutions.jts.operation.distance;
+
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.Lineal;
+import com.vividsolutions.jts.geom.Polygonal;
+import com.vividsolutions.jts.geom.Puntal;
+import com.vividsolutions.jts.index.strtree.ItemBoundable;
+import com.vividsolutions.jts.index.strtree.ItemDistance;
+import com.vividsolutions.jts.index.strtree.STRtree;
+
+/**
+ * Computes the distance between the facets (segments and vertices) 
+ * of two {@link Geometry}s
+ * using a Branch-and-Bound algorithm.
+ * The Branch-and-Bound algorithm operates over a 
+ * traversal of R-trees built
+ * on the target and possibly also the query geometries.
+ * <p>
+ * This approach provides the following benefits:
+ * <ul>
+ * <li>Performance is improved due to the effects of the 
+ * R-tree index
+ * and the pruning due to the Branch-and-Bound approach
+ * <li>The spatial index on the target geometry can be cached
+ * to allow reuse in an incremental query situation.
+ * </ul>
+ * Using this technique can be much more performant 
+ * than using {@link #getDistance(Geometry)} 
+ * when one or both
+ * input geometries are large, 
+ * or when evaluating many distance computations against 
+ * a single geometry.
+ * <p>
+ * This class is not thread-safe.
+ * 
+ * @author Martin Davis
+ *
+ */
+public class IndexedFacetDistance 
+{
+  /**
+   * Computes the distance between two geometries using
+   * the indexed approach.
+   * <p>
+   * For geometries with many segments or points, 
+   * this can be faster than using a simple distance
+   * algorithm.
+   * 
+   * @param g1 a geometry
+   * @param g2 a geometry
+   * @return the distance between the two geometries
+   */
+  public static double distance(Geometry g1, Geometry g2)
+  {
+    IndexedFacetDistance dist = new IndexedFacetDistance(g1);
+    return dist.getDistance(g2);
+  }
+  
+  private STRtree cachedTree;
+  
+  /**
+   * Creates a new distance-finding instance for a given target {@link Geometry}.
+   * <p>
+   * Distances will be computed to all facets of the input geometry.
+   * The facets of the geometry are the discrete segments and points 
+   * contained in its components.  
+   * In the case of {@link Lineal} and {@link Puntal} inputs,
+   * this is equivalent to computing the conventional distance.
+   * In the case of {@link Polygonal} inputs, this is equivalent 
+   * to computing the distance to the polygons boundaries. 
+   * 
+   * @param g1 a Geometry, which may be of any type.
+   */
+  public IndexedFacetDistance(Geometry g1) {
+    cachedTree = FacetSequenceTreeBuilder.build(g1);
+  }
+
+  /**
+   * Computes the distance from the base geometry to 
+   * the given geometry.
+   *  
+   * @param g the geometry to compute the distance to
+   * 
+   * @return the computed distance
+   */
+  public double getDistance(Geometry g)
+  {
+    STRtree tree2 = FacetSequenceTreeBuilder.build(g);
+    Object[] obj = cachedTree.nearestNeighbour(tree2, 
+        new FacetSequenceDistance());
+    return facetDistance(obj);
+  }
+  
+  private static double facetDistance(Object[] obj)
+  {
+    Object o1 = obj[0];
+    Object o2 = obj[1];
+    return ((FacetSequence) o1).distance((FacetSequence) o2);
+  }
+  
+  /**
+   * Computes the distance from the base geometry to 
+   * the given geometry, up to and including a given 
+   * maximum distance.
+   * 
+   * @param g the geometry to compute the distance to
+   * @param maximumDistance the maximum distance to compute.
+   * 
+   * @return the computed distance,
+   *    or <tt>maximumDistance</tt> if the true distance is determined to be greater
+   */
+  // TODO: implement this
+  /*
+  public double getDistanceWithin(Geometry g, double maximumDistance)
+  {
+    STRtree tree2 = FacetSequenceTreeBuilder.build(g);
+    Object[] obj = cachedTree.nearestNeighbours(tree2, 
+        new FacetSequenceDistance());
+    return facetDistance(obj);
+  }
+  */
+  
+
+  /**
+   * Tests whether the base geometry lies within
+   * a specified distance of the given geometry.
+   * 
+   * @param g the geomtry to test
+   * @param maximumDistance the maximum distance to test
+   * @return true if the geometry lies with the specified distance
+   */
+  // TODO: implement this
+  /*
+  public boolean isWithinDistance(Geometry g, double maximumDistance)
+  {
+    STRtree tree2 = FacetSequenceTreeBuilder.build(g);
+    double dist = findMinDistance(cachedTree.getRoot(), tree2.getRoot(), maximumDistance);
+    if (dist <= maximumDistance)
+      return false;
+    return true;
+  }
+  */
+  
+  private static class FacetSequenceDistance
+  implements ItemDistance
+  {
+    public double distance(ItemBoundable item1, ItemBoundable item2) {
+      FacetSequence fs1 = (FacetSequence) item1.getItem();
+      FacetSequence fs2 = (FacetSequence) item2.getItem();
+      return fs1.distance(fs2);    
+    }
+  }
+}
+
+
diff --git a/src/com/vividsolutions/jts/operation/linemerge/LineMergeGraph.java b/src/com/vividsolutions/jts/operation/linemerge/LineMergeGraph.java
index 1a58f45..cc34686 100644
--- a/src/com/vividsolutions/jts/operation/linemerge/LineMergeGraph.java
+++ b/src/com/vividsolutions/jts/operation/linemerge/LineMergeGraph.java
@@ -49,14 +49,23 @@ import com.vividsolutions.jts.planargraph.PlanarGraph;
  *
  * @version 1.7
  */
-public class LineMergeGraph extends PlanarGraph {
+public class LineMergeGraph extends PlanarGraph 
+{
   /**
    * Adds an Edge, DirectedEdges, and Nodes for the given LineString representation
    * of an edge. 
+   * Empty lines or lines with all coordinates equal are not added.
+   * 
+   * @param lineString the linestring to add to the graph
    */
   public void addEdge(LineString lineString) {
     if (lineString.isEmpty()) { return; }
+    
     Coordinate[] coordinates = CoordinateArrays.removeRepeatedPoints(lineString.getCoordinates());
+    
+    // don't add lines with all coordinates equal
+    if (coordinates.length <= 1) return;
+    
     Coordinate startCoordinate = coordinates[0];
     Coordinate endCoordinate = coordinates[coordinates.length - 1];
     Node startNode = getNode(startCoordinate);
diff --git a/src/com/vividsolutions/jts/operation/linemerge/LineMerger.java b/src/com/vividsolutions/jts/operation/linemerge/LineMerger.java
index 9067ba9..5d8dfa2 100644
--- a/src/com/vividsolutions/jts/operation/linemerge/LineMerger.java
+++ b/src/com/vividsolutions/jts/operation/linemerge/LineMerger.java
@@ -46,18 +46,24 @@ import com.vividsolutions.jts.planargraph.Node;
 import com.vividsolutions.jts.util.Assert;
 
 /**
- * Sews together a set of fully noded LineStrings. Sewing stops at nodes of degree 1
- * or 3 or more -- the exception is an isolated loop, which only has degree-2 nodes,
- * in which case a node is simply chosen as a starting point. The direction of each
+ * Merges a collection of linear components to form maximal-length linestrings. 
+ * <p> 
+ * Merging stops at nodes of degree 1 or degree 3 or more.
+ * In other words, all nodes of degree 2 are merged together. 
+ * The exception is in the case of an isolated loop, which only has degree-2 nodes.
+ * In this case one of the nodes is chosen as a starting point.
+ * <p> 
+ * The direction of each
  * merged LineString will be that of the majority of the LineStrings from which it
  * was derived.
  * <p>
- * Any dimension of Geometry is handled -- the constituent linework is extracted to 
+ * Any dimension of Geometry is handled - the constituent linework is extracted to 
  * form the edges. The edges must be correctly noded; that is, they must only meet
- * at their endpoints.  The LineMerger will still run on incorrectly noded input
- * but will not form polygons from incorrected noded edges.
+ * at their endpoints.  The LineMerger will accept non-noded input
+ * but will not merge non-noded edges.
  * <p>
- * <b>NOTE:</b>once merging has been performed, no more 
+ * Input lines which are empty or contain only a single unique coordinate are not included
+ * in the merging.
  *
  * @version 1.7
  */
@@ -68,9 +74,20 @@ public class LineMerger
   private GeometryFactory factory = null;
   
   /**
+   * Creates a new line merger.
+   *
+   */
+  public LineMerger()
+  {
+  	
+  }
+  
+  /**
    * Adds a Geometry to be processed. May be called multiple times.
    * Any dimension of Geometry may be added; the constituent linework will be
    * extracted.
+   * 
+   * @param geometry geometry to be line-merged
    */  
   public void add(Geometry geometry) {
     geometry.apply(new GeometryComponentFilter() {
@@ -85,6 +102,8 @@ public class LineMerger
    * Adds a collection of Geometries to be processed. May be called multiple times.
    * Any dimension of Geometry may be added; the constituent linework will be
    * extracted.
+   * 
+   * @param geometries the geometries to be line-merged
    */
   public void add(Collection geometries) 
   {
@@ -168,7 +187,9 @@ public class LineMerger
   }
   
   /**
-   * Returns the LineStrings built by the merging process.
+   * Gets the {@link LineString}s created by the merging process.
+   * 
+   * @return the collection of merged LineStrings
    */
   public Collection getMergedLineStrings() {
     merge();
diff --git a/src/com/vividsolutions/jts/operation/linemerge/LineSequencer.java b/src/com/vividsolutions/jts/operation/linemerge/LineSequencer.java
index e6ddaf5..e2f3c5e 100644
--- a/src/com/vividsolutions/jts/operation/linemerge/LineSequencer.java
+++ b/src/com/vividsolutions/jts/operation/linemerge/LineSequencer.java
@@ -45,11 +45,17 @@ import com.vividsolutions.jts.util.Assert;
  * A sequence is a complete non-repeating list of the linear
  * components of the input.  Each linestring is oriented
  * so that identical endpoints are adjacent in the list.
- *
+ * <p>
+ * A typical use case is to convert a set of 
+ * unoriented geometric links 
+ * from a linear network
+ * (e.g. such as block faces on a bus route)
+ * into a continuous oriented path through the network. 
+ * <p>
  * The input linestrings may form one or more connected sets.
  * The input linestrings should be correctly noded, or the results may
  * not be what is expected.
- * The output of this method is a single MultiLineString containing the ordered
+ * The computed output is a single {@link MultiLineString} containing the ordered
  * linestrings in the sequence.
  * <p>
  * The sequencing employs the classic <b>Eulerian path</b> graph algorithm.
@@ -66,11 +72,10 @@ import com.vividsolutions.jts.util.Assert;
  * <li>If the sequence has no degree-1 nodes, use any node as the start
  * </ul>
  *
- * <p>
- * Not all arrangements of lines can be sequenced.
+ * Note that not all arrangements of lines can be sequenced.
  * For a connected set of edges in a graph,
- * Euler's Theorem states that there is a sequence containing each edge once
- * if and only if there are no more than 2 nodes of odd degree.
+ * <i>Euler's Theorem</i> states that there is a sequence containing each edge once
+ * <b>if and only if</b> there are no more than 2 nodes of odd degree.
  * If it is not possible to find a sequence, the {@link #isSequenceable} method
  * will return <code>false</code>.
  *
@@ -78,6 +83,13 @@ import com.vividsolutions.jts.util.Assert;
  */
 public class LineSequencer
 {
+	public static Geometry sequence(Geometry geom)
+	{
+		LineSequencer sequencer = new LineSequencer();
+		sequencer.add(geom);
+		return sequencer.getSequencedLineStrings();
+	}
+	
   /**
    * Tests whether a {@link Geometry} is sequenced correctly.
    * {@link LineString}s are trivially sequenced.
diff --git a/src/com/vividsolutions/jts/operation/overlay/snap/GeometrySnapper.java b/src/com/vividsolutions/jts/operation/overlay/snap/GeometrySnapper.java
index 5122cd1..49e8f71 100644
--- a/src/com/vividsolutions/jts/operation/overlay/snap/GeometrySnapper.java
+++ b/src/com/vividsolutions/jts/operation/overlay/snap/GeometrySnapper.java
@@ -5,16 +5,25 @@ import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.geom.util.GeometryTransformer;
 
 /**
- * Snaps the vertices and segments of a {@link Geometry} to another Geometry's vertices.
- * Improves robustness for overlay operations, by eliminating
- * nearly parallel edges (which cause problems during noding and intersection calculation).
+ * Snaps the vertices and segments of a {@link Geometry} 
+ * to another Geometry's vertices.
+ * A snap distance tolerance is used to control where snapping is performed.
+ * Snapping one geometry to another can improve 
+ * robustness for overlay operations by eliminating
+ * nearly-coincident edges 
+ * (which cause problems during noding and intersection calculation).
+ * Too much snapping can result in invalid topology 
+ * beging created, so the number and location of snapped vertices
+ * is decided using heuristics to determine when it 
+ * is safe to snap.
+ * This can result in some potential snaps being omitted, however.
  *
  * @author Martin Davis
  * @version 1.7
  */
 public class GeometrySnapper
 {
-  private static final double SNAP_PRECISION_FACTOR = 10e-10;
+  private static final double SNAP_PRECISION_FACTOR = 1e-9;
 
   /**
    * Estimates the snap tolerance for a Geometry, taking into account its precision model.
@@ -70,18 +79,23 @@ public class GeometrySnapper
     Geometry[] snapGeom = new Geometry[2];
     GeometrySnapper snapper0 = new GeometrySnapper(g0);
     snapGeom[0] = snapper0.snapTo(g1, snapTolerance);
-
-    GeometrySnapper snapper1 = new GeometrySnapper(g1);
+    
     /**
      * Snap the second geometry to the snapped first geometry
      * (this strategy minimizes the number of possible different points in the result)
      */
+    GeometrySnapper snapper1 = new GeometrySnapper(g1);
     snapGeom[1] = snapper1.snapTo(snapGeom[0], snapTolerance);
 
 //    System.out.println(snap[0]);
 //    System.out.println(snap[1]);
     return snapGeom;
   }
+  public static Geometry snapToSelf(Geometry g0, double snapTolerance, boolean cleanResult)
+  {
+    GeometrySnapper snapper0 = new GeometrySnapper(g0);
+    return snapper0.snapToSelf(snapTolerance, cleanResult);
+  }
   
   private Geometry srcGeom;
 
@@ -95,29 +109,21 @@ public class GeometrySnapper
     this.srcGeom = srcGeom;
   }
 
+
   /**
-   * Computes the snap tolerance based on the input geometries.
+   * Snaps the vertices in the component {@link LineString}s
+   * of the source geometry
+   * to the vertices of the given snap geometry.
    *
-   * @param ringPts
-   * @return
+   * @param snapGeom a geometry to snap the source to
+   * @return a new snapped Geometry
    */
-  private double computeSnapTolerance(Coordinate[] ringPts)
+  public Geometry snapTo(Geometry snapGeom, double snapTolerance)
   {
-    double minSegLen = computeMinimumSegmentLength(ringPts);
-    // use a small percentage of this to be safe
-    double snapTol = minSegLen / 10;
-    return snapTol;
-  }
+    Coordinate[] snapPts = extractTargetCoordinates(snapGeom);
 
-  private double computeMinimumSegmentLength(Coordinate[] pts)
-  {
-    double minSegLen = Double.MAX_VALUE;
-    for (int i = 0; i < pts.length - 1; i++) {
-      double segLen = pts[i].distance(pts[i + 1]);
-      if (segLen < minSegLen)
-        minSegLen = segLen;
-    }
-    return minSegLen;
+    SnapTransformer snapTrans = new SnapTransformer(snapTolerance, snapPts);
+    return snapTrans.transform(srcGeom);
   }
 
   /**
@@ -128,12 +134,18 @@ public class GeometrySnapper
    * @param snapGeom a geometry to snap the source to
    * @return a new snapped Geometry
    */
-  public Geometry snapTo(Geometry snapGeom, double snapTolerance)
+  public Geometry snapToSelf(double snapTolerance, boolean cleanResult)
   {
-    Coordinate[] snapPts = extractTargetCoordinates(snapGeom);
-
-    SnapTransformer snapTrans = new SnapTransformer(snapTolerance, snapPts);
-    return snapTrans.transform(srcGeom);
+    Coordinate[] snapPts = extractTargetCoordinates(srcGeom);
+
+    SnapTransformer snapTrans = new SnapTransformer(snapTolerance, snapPts, true);
+    Geometry snappedGeom = snapTrans.transform(srcGeom);
+    Geometry result = snappedGeom;
+    if (cleanResult && result instanceof Polygonal) {
+      // TODO: use better cleaning approach
+      result = snappedGeom.buffer(0);
+    }
+    return result;
   }
 
   public Coordinate[] extractTargetCoordinates(Geometry g)
@@ -146,13 +158,40 @@ public class GeometrySnapper
     }
     return (Coordinate[]) ptSet.toArray(new Coordinate[0]);
   }
+  
+  /**
+   * Computes the snap tolerance based on the input geometries.
+   *
+   * @param ringPts
+   * @return
+   */
+  private double computeSnapTolerance(Coordinate[] ringPts)
+  {
+    double minSegLen = computeMinimumSegmentLength(ringPts);
+    // use a small percentage of this to be safe
+    double snapTol = minSegLen / 10;
+    return snapTol;
+  }
+
+  private double computeMinimumSegmentLength(Coordinate[] pts)
+  {
+    double minSegLen = Double.MAX_VALUE;
+    for (int i = 0; i < pts.length - 1; i++) {
+      double segLen = pts[i].distance(pts[i + 1]);
+      if (segLen < minSegLen)
+        minSegLen = segLen;
+    }
+    return minSegLen;
+  }
+
 }
 
 class SnapTransformer
     extends GeometryTransformer
 {
-  double snapTolerance;
-  Coordinate[] snapPts;
+  private double snapTolerance;
+  private Coordinate[] snapPts;
+  private boolean isSelfSnap = false;
 
   SnapTransformer(double snapTolerance, Coordinate[] snapPts)
   {
@@ -160,6 +199,13 @@ class SnapTransformer
     this.snapPts = snapPts;
   }
 
+  SnapTransformer(double snapTolerance, Coordinate[] snapPts, boolean isSelfSnap)
+  {
+    this.snapTolerance = snapTolerance;
+    this.snapPts = snapPts;
+    this.isSelfSnap = isSelfSnap;
+  }
+
   protected CoordinateSequence transformCoordinates(CoordinateSequence coords, Geometry parent)
   {
     Coordinate[] srcPts = coords.toCoordinateArray();
@@ -170,6 +216,7 @@ class SnapTransformer
   private Coordinate[] snapLine(Coordinate[] srcPts, Coordinate[] snapPts)
   {
     LineStringSnapper snapper = new LineStringSnapper(srcPts, snapTolerance);
+    snapper.setAllowSnappingToSourceVertices(isSelfSnap);
     return snapper.snapTo(snapPts);
   }
 }
diff --git a/src/com/vividsolutions/jts/operation/overlay/snap/LineStringSnapper.java b/src/com/vividsolutions/jts/operation/overlay/snap/LineStringSnapper.java
index 397090a..4fbc07b 100644
--- a/src/com/vividsolutions/jts/operation/overlay/snap/LineStringSnapper.java
+++ b/src/com/vividsolutions/jts/operation/overlay/snap/LineStringSnapper.java
@@ -3,8 +3,11 @@ package com.vividsolutions.jts.operation.overlay.snap;
 import com.vividsolutions.jts.geom.*;
 
 /**
- * Snaps the vertices and segments of a {@link LineString} to a set of target snap vertices.
- * A snapping distance tolerance is used to control where snapping is performed.
+ * Snaps the vertices and segments of a {@link LineString} 
+ * to a set of target snap vertices.
+ * A snap distance tolerance is used to control where snapping is performed.
+ * <p>
+ * The implementation handles empty geometry and empty snap vertex sets.
  *
  * @author Martin Davis
  * @version 1.7
@@ -15,13 +18,14 @@ public class LineStringSnapper
 
   private Coordinate[] srcPts;
   private LineSegment seg = new LineSegment(); // for reuse during snapping
+  private boolean allowSnappingToSourceVertices = false;
   private boolean isClosed = false;
 
   /**
    * Creates a new snapper using the points in the given {@link LineString}
    * as source snap points.
    * 
-   * @param srcLline a LineString to snap
+   * @param srcLine a LineString to snap (may be empty)
    * @param snapTolerance the snap tolerance to use
    */
   public LineStringSnapper(LineString srcLline, double snapTolerance)
@@ -39,13 +43,22 @@ public class LineStringSnapper
   public LineStringSnapper(Coordinate[] srcPts, double snapTolerance)
   {
     this.srcPts = srcPts;
-    isClosed = srcPts[0].equals2D(srcPts[srcPts.length - 1]);
+    isClosed = isClosed(srcPts);
     this.snapTolerance = snapTolerance;
   }
 
+  public void setAllowSnappingToSourceVertices(boolean allowSnappingToSourceVertices)
+  {
+    this.allowSnappingToSourceVertices = allowSnappingToSourceVertices;
+  }
+  private static boolean isClosed(Coordinate[] pts)
+  {
+    if (pts.length <= 1) return false;
+    return pts[0].equals2D(pts[pts.length - 1]);
+  }
   /**
    * Snaps the vertices and segments of the source LineString 
-   * to the given set of target snap points.
+   * to the given set of snap vertices.
    * 
    * @param snapPts the vertices to snap to
    * @return a list of the snapped points
@@ -70,8 +83,9 @@ public class LineStringSnapper
   private void snapVertices(CoordinateList srcCoords, Coordinate[] snapPts)
   {
     // try snapping vertices
-    // assume src list has a closing point (is a ring)
-    for (int i = 0; i < srcCoords.size() - 1; i++) {
+    // if src is a ring then don't snap final vertex
+    int end = isClosed ? srcCoords.size() - 1 : srcCoords.size();
+    for (int i = 0; i < end; i++) {
       Coordinate srcPt = (Coordinate) srcCoords.get(i);
       Coordinate snapVert = findSnapForVertex(srcPt, snapPts);
       if (snapVert != null) {
@@ -98,21 +112,27 @@ public class LineStringSnapper
 
   /**
    * Snap segments of the source to nearby snap vertices.
-   * Source segments are "cracked" at a snap vertex, and further
-   * snapping takes place on the modified list of segments.
+   * Source segments are "cracked" at a snap vertex.
+   * A single input segment may be snapped several times 
+   * to different snap vertices.
+   * <p>
    * For each distinct snap vertex, at most one source segment
    * is snapped to.  This prevents "cracking" multiple segments 
-   * at the same point, which would almost certainly cause the result to be invalid.
+   * at the same point, which would likely cause 
+   * topology collapse when being used on polygonal linework.
    * 
-   * @param srcCoords
-   * @param snapPts
+   * @param srcCoords the coordinates of the source linestring to be snapped
+   * @param snapPts the target snap vertices
    */
   private void snapSegments(CoordinateList srcCoords, Coordinate[] snapPts)
   {
+    // guard against empty input
+    if (snapPts.length == 0) return;
+    
     int distinctPtCount = snapPts.length;
 
-    // check for duplicate snap pts.  
-    // Need to do this better - need to check all points for dups (using a Set?)
+    // check for duplicate snap pts when they are sourced from a linear ring.  
+    // TODO: Need to do this better - need to check *all* snap points for dups (using a Set?)
     if (snapPts[0].equals2D(snapPts[snapPts.length - 1]))
         distinctPtCount = snapPts.length - 1;
 
@@ -122,7 +142,7 @@ public class LineStringSnapper
       /**
        * If a segment to snap to was found, "crack" it at the snap pt.
        * The new pt is inserted immediately into the src segment list,
-       * so that subsequent snapping will take place on the latest segments.
+       * so that subsequent snapping will take place on the modified segments.
        * Duplicate points are not added.
        */
       if (index >= 0) {
@@ -133,17 +153,23 @@ public class LineStringSnapper
 
 
   /**
-   * Finds a src segment which snaps to (is close to) the given snap point
-   * Only one segment is determined - this is to prevent
-   * snapping to multiple segments, which would almost certainly cause invalid geometry
+   * Finds a src segment which snaps to (is close to) the given snap point.
+   * <p>
+   * Only a single segment is selected for snapping.
+   * This prevents multiple segments snapping to the same snap vertex,
+   * which would almost certainly cause invalid geometry
    * to be created.
-   * (The heuristic approach of snapping is really only appropriate when
+   * (The heuristic approach to snapping used here
+   * is really only appropriate when
    * snap pts snap to a unique spot on the src geometry.)
-   *
+   * <p>
+   * Also, if the snap vertex occurs as a vertex in the src coordinate list,
+   * no snapping is performed.
+   * 
    * @param snapPt the point to snap to
    * @param srcCoords the source segment coordinates
    * @return the index of the snapped segment
-   * @return -1 if no segment snaps
+   * @return -1 if no segment snaps to the snap point
    */
   private int findSegmentIndexToSnap(Coordinate snapPt, CoordinateList srcCoords)
   {
@@ -154,11 +180,17 @@ public class LineStringSnapper
       seg.p1 = (Coordinate) srcCoords.get(i + 1);
 
       /**
-       * If the snap pt is already in the src list, don't snap
+       * Check if the snap pt is equal to one of the segment endpoints.
+       * 
+       * If the snap pt is already in the src list, don't snap at all.
        */
-      if (seg.p0.equals2D(snapPt) || seg.p1.equals2D(snapPt))
-        return -1;
-
+      if (seg.p0.equals2D(snapPt) || seg.p1.equals2D(snapPt)) {
+        if (allowSnappingToSourceVertices)
+          continue;
+        else
+          return -1;
+      }
+      
       double dist = seg.distance(snapPt);
       if (dist < snapTolerance && dist < minDist) {
         minDist = dist;
diff --git a/src/com/vividsolutions/jts/operation/overlay/snap/SnapIfNeededOverlayOp.java b/src/com/vividsolutions/jts/operation/overlay/snap/SnapIfNeededOverlayOp.java
index 6221738..161ba69 100644
--- a/src/com/vividsolutions/jts/operation/overlay/snap/SnapIfNeededOverlayOp.java
+++ b/src/com/vividsolutions/jts/operation/overlay/snap/SnapIfNeededOverlayOp.java
@@ -57,6 +57,7 @@ public class SnapIfNeededOverlayOp
   {
     Geometry result = null;
     boolean isSuccess = false;
+    RuntimeException savedException = null;
     try {
       result = OverlayOp.overlayOp(geom[0], geom[1], opCode); 
       boolean isValid = true;
@@ -66,14 +67,24 @@ public class SnapIfNeededOverlayOp
       	isSuccess = true;
     
     }
-    catch (Exception ex) {
+    catch (RuntimeException ex) {
+    	savedException = ex;
     	// ignore this exception, since the operation will be rerun
 //    	System.out.println(ex.getMessage());
 //    	ex.printStackTrace();
+    	//System.out.println(ex.getMessage());
+    	//System.out.println("Geom 0: " + geom[0]);
+    	//System.out.println("Geom 1: " + geom[1]);
     }
     if (! isSuccess) {
-    	// this may still throw an exception - just let it go if it does
-      result = SnapOverlayOp.overlayOp(geom[0], geom[1], opCode);
+    	// this may still throw an exception
+    	// if so, throw the original exception since it has the input coordinates
+    	try {
+    		result = SnapOverlayOp.overlayOp(geom[0], geom[1], opCode);
+    	}
+    	catch (RuntimeException ex) {
+    		throw savedException;
+    	}
     }
     return result;
   }
diff --git a/src/com/vividsolutions/jts/operation/overlay/snap/SnapOverlayOp.java b/src/com/vividsolutions/jts/operation/overlay/snap/SnapOverlayOp.java
index dc83574..95a6fed 100644
--- a/src/com/vividsolutions/jts/operation/overlay/snap/SnapOverlayOp.java
+++ b/src/com/vividsolutions/jts/operation/overlay/snap/SnapOverlayOp.java
@@ -63,12 +63,22 @@ public class SnapOverlayOp
 
   public Geometry getResultGeometry(int opCode)
   {
-    Geometry[] prepGeom = snap();
+//  	Geometry[] selfSnapGeom = new Geometry[] { selfSnap(geom[0]), selfSnap(geom[1])};
+    Geometry[] prepGeom = snap(geom);
     Geometry result = OverlayOp.overlayOp(prepGeom[0], prepGeom[1], opCode);
     return prepareResult(result);	
   }
   
-  private Geometry[] snap()
+  private Geometry selfSnap(Geometry geom)
+  {
+    GeometrySnapper snapper0 = new GeometrySnapper(geom);
+    Geometry snapGeom = snapper0.snapTo(geom, snapTolerance);
+    //System.out.println("Self-snapped: " + snapGeom);
+    //System.out.println();
+    return snapGeom;
+  }
+  
+  private Geometry[] snap(Geometry[] geom)
   {
     Geometry[] remGeom = removeCommonBits(geom);
   	
diff --git a/src/com/vividsolutions/jts/operation/polygonize/EdgeRing.java b/src/com/vividsolutions/jts/operation/polygonize/EdgeRing.java
index 80309c7..7d4fc65 100644
--- a/src/com/vividsolutions/jts/operation/polygonize/EdgeRing.java
+++ b/src/com/vividsolutions/jts/operation/polygonize/EdgeRing.java
@@ -46,7 +46,7 @@ import com.vividsolutions.jts.planargraph.*;
  *
  * @version 1.7
  */
-public class EdgeRing {
+class EdgeRing {
 
   /**
    * Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any.
diff --git a/src/com/vividsolutions/jts/operation/polygonize/PolygonizeDirectedEdge.java b/src/com/vividsolutions/jts/operation/polygonize/PolygonizeDirectedEdge.java
index 9a47463..6609634 100644
--- a/src/com/vividsolutions/jts/operation/polygonize/PolygonizeDirectedEdge.java
+++ b/src/com/vividsolutions/jts/operation/polygonize/PolygonizeDirectedEdge.java
@@ -44,7 +44,7 @@ import com.vividsolutions.jts.planargraph.Node;
  *
  * @version 1.7
  */
-public class PolygonizeDirectedEdge
+class PolygonizeDirectedEdge
     extends DirectedEdge
 {
 
diff --git a/src/com/vividsolutions/jts/operation/predicate/RectangleContains.java b/src/com/vividsolutions/jts/operation/predicate/RectangleContains.java
index 6131230..f86a6e0 100644
--- a/src/com/vividsolutions/jts/operation/predicate/RectangleContains.java
+++ b/src/com/vividsolutions/jts/operation/predicate/RectangleContains.java
@@ -3,24 +3,33 @@ package com.vividsolutions.jts.operation.predicate;
 import com.vividsolutions.jts.geom.*;
 
 /**
- * Optimized implementation of spatial predicate "contains"
+ * Optimized implementation of the <tt>contains</tt> spatial predicate 
  * for cases where the first {@link Geometry} is a rectangle.
+ * This class works for all input geometries, including
+ * {@link GeometryCollection}s.
  * <p>
  * As a further optimization,
- * this class can be used directly to test many geometries against a single
- * rectangle.
+ * this class can be used to test 
+ * many geometries against a single
+ * rectangle in a slightly more efficient way.
  *
  * @version 1.7
  */
 public class RectangleContains {
 
+  /**
+   * Tests whether a rectangle contains a given geometry.
+   * 
+   * @param rectangle a rectangular Polygon
+   * @param b a Geometry of any type
+   * @return true if the geometries intersect
+   */
   public static boolean contains(Polygon rectangle, Geometry b)
   {
     RectangleContains rc = new RectangleContains(rectangle);
     return rc.contains(b);
   }
 
-  private Polygon rectangle;
   private Envelope rectEnv;
 
   /**
@@ -29,15 +38,20 @@ public class RectangleContains {
    * @param rectangle a rectangular geometry
    */
   public RectangleContains(Polygon rectangle) {
-    this.rectangle = rectangle;
     rectEnv = rectangle.getEnvelopeInternal();
   }
 
   public boolean contains(Geometry geom)
   {
+    // the test geometry must be wholly contained in the rectangle envelope
     if (! rectEnv.contains(geom.getEnvelopeInternal()))
       return false;
-    // check that geom is not contained entirely in the rectangle boundary
+    
+    /**
+     * Check that geom is not contained entirely in the rectangle boundary.
+     * According to the somewhat odd spec of the SFS, if this
+     * is the case the geometry is NOT contained.
+     */
     if (isContainedInBoundary(geom))
       return false;
     return true;
diff --git a/src/com/vividsolutions/jts/operation/predicate/RectangleIntersects.java b/src/com/vividsolutions/jts/operation/predicate/RectangleIntersects.java
index b4ecb02..ab17d39 100644
--- a/src/com/vividsolutions/jts/operation/predicate/RectangleIntersects.java
+++ b/src/com/vividsolutions/jts/operation/predicate/RectangleIntersects.java
@@ -7,25 +7,27 @@ import com.vividsolutions.jts.algorithm.locate.SimplePointInAreaLocator;
 import com.vividsolutions.jts.geom.util.*;
 
 /**
- * Optimized implementation of spatial predicate "intersects"
- * for cases where the first {@link Geometry} is a rectangle.
+ * Optimized implementation of the <tt>intersects</tt> spatial predicate 
+ * for cases where one {@link Geometry} is a rectangle.
+ * This class works for all input geometries, including
+ * {@link GeometryCollection}s.
  * <p>
  * As a further optimization,
- * this class can be used directly to test many geometries against a single
- * rectangle.
+ * this class can be used to test 
+ * many geometries against a single
+ * rectangle in a slightly more efficient way.
  *
  * @version 1.7
  */
-public class RectangleIntersects {
-
+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.
+   * Tests whether a rectangle intersects a given geometry.
+   * 
+   * @param rectangle a rectangular Polygon
+   * @param b a Geometry of any type
+   * @return true if the geometries intersect
    */
-  public static final int MAXIMUM_SCAN_SEGMENT_COUNT = 200;
-
   public static boolean intersects(Polygon rectangle, Geometry b)
   {
     RectangleIntersects rp = new RectangleIntersects(rectangle);
@@ -171,11 +173,15 @@ class ContainsPointVisitor
 
   protected void visit(Geometry geom)
   {
+    // if test geometry is not polygonal this check is not needed
     if (! (geom instanceof Polygon))
       return;
+    
+    // skip if envelopes do not intersect
     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++) {
@@ -206,15 +212,13 @@ class ContainsPointVisitor
 class LineIntersectsVisitor
     extends ShortCircuitedGeometryVisitor
 {
-  private Polygon rectangle;
-  private CoordinateSequence rectSeq;
+  private LineString rectLine;
   private Envelope rectEnv;
   private boolean intersects = false;
 
   public LineIntersectsVisitor(Polygon rectangle)
   {
-    this.rectangle = rectangle;
-    this.rectSeq = rectangle.getExteriorRing().getCoordinateSequence();
+    this.rectLine = rectangle.getExteriorRing();
     rectEnv = rectangle.getEnvelopeInternal();
   }
 
@@ -230,14 +234,11 @@ class LineIntersectsVisitor
   protected void visit(Geometry geom)
   {
     Envelope elementEnv = geom.getEnvelopeInternal();
+    
+    // check for envelope intersection
     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;
-    }
-    // if small enough, test for segment intersection directly
+    
     computeSegmentIntersection(geom);
   }
 
@@ -247,7 +248,7 @@ class LineIntersectsVisitor
     // 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);
+    boolean hasIntersection = si.hasIntersectionWithLineStrings(rectLine, lines);
     if (hasIntersection) {
       intersects = true;
       return;
diff --git a/src/com/vividsolutions/jts/operation/predicate/SegmentIntersectionTester.java b/src/com/vividsolutions/jts/operation/predicate/SegmentIntersectionTester.java
index 53b2607..60e8478 100644
--- a/src/com/vividsolutions/jts/operation/predicate/SegmentIntersectionTester.java
+++ b/src/com/vividsolutions/jts/operation/predicate/SegmentIntersectionTester.java
@@ -5,15 +5,18 @@ import com.vividsolutions.jts.algorithm.*;
 import com.vividsolutions.jts.geom.*;
 
 /**
- * Tests if any line segments in two sets of {@link CoordinateSequence}s intersect.
- * Optimized for use when at least one input is of small size.
- * Short-circuited to return as soon an intersection is found.
+ * Tests if any of the segments in a
+ * {@link LineString} intersect any segment in a set of {@link LineString}s.
+ * <p>
+ * The algorithm is optimized for use when the first input has smaller extent
+ * than the set of test lines.
+ * The code is short-circuited to return as soon an intersection is found.
  *
  * @version 1.7
  */
-public class SegmentIntersectionTester {
-
-  // for purposes of intersection testing, don't need to set precision model
+public class SegmentIntersectionTester 
+{
+  // for intersection testing, don't need to set precision model
   private LineIntersector li = new RobustLineIntersector();
 
   private boolean hasIntersection = false;
@@ -25,18 +28,60 @@ public class SegmentIntersectionTester {
   public SegmentIntersectionTester() {
   }
 
-  public boolean hasIntersectionWithLineStrings(CoordinateSequence seq, List lines)
+  public boolean hasIntersectionWithLineStrings(LineString line, List lines)
   {
     for (Iterator i = lines.iterator(); i.hasNext(); ) {
-      LineString line = (LineString) i.next();
-      hasIntersection(seq, line.getCoordinateSequence());
+      LineString testLine = (LineString) i.next();
+      //hasIntersection(line, testLine);
+      hasIntersectionWithEnvelopeFilter(line, testLine);
       if (hasIntersection)
         break;
     }
     return hasIntersection;
   }
 
-  public boolean hasIntersection(CoordinateSequence seq0, CoordinateSequence seq1) {
+  /**
+   * Tests the segments of a LineString against the segs in 
+   * another LineString for intersection.
+   * Uses the envelope of the query LineString
+   * to filter before testing segments directly.
+   * This is optimized for the case when the query
+   * LineString is a rectangle.
+   * 
+   * Testing shows this is somewhat faster than not checking the envelope.
+   * 
+   * @param line
+   * @param testLine
+   * @return
+   */
+  private boolean hasIntersectionWithEnvelopeFilter(LineString line, LineString testLine) {
+    CoordinateSequence seq0 = line.getCoordinateSequence();
+    CoordinateSequence seq1 = testLine.getCoordinateSequence();
+    Envelope lineEnv = line.getEnvelopeInternal();
+    
+    for (int i = 1; i < seq1.size() && ! hasIntersection; i++) {
+      seq1.getCoordinate(i - 1, pt10);
+      seq1.getCoordinate(i, pt11);
+      
+      // skip test if segment does not intersect query envelope
+      if (! lineEnv.intersects(new Envelope(pt10, pt11)))
+        continue;
+      
+      for (int j = 1; j < seq0.size() && ! hasIntersection; j++) {
+        seq0.getCoordinate(j - 1, pt00);
+        seq0.getCoordinate(j, pt01);
+
+        li.computeIntersection(pt00, pt01, pt10, pt11);
+        if (li.hasIntersection())
+          hasIntersection = true;
+      }
+    }
+    return hasIntersection;
+  }
+  
+  private boolean hasIntersection(LineString line, LineString testLine) {
+    CoordinateSequence seq0 = line.getCoordinateSequence();
+    CoordinateSequence seq1 = testLine.getCoordinateSequence();
     for (int i = 1; i < seq0.size() && ! hasIntersection; i++) {
       seq0.getCoordinate(i - 1, pt00);
       seq0.getCoordinate(i, pt01);
@@ -51,4 +96,5 @@ public class SegmentIntersectionTester {
     }
     return hasIntersection;
   }
+
 }
\ No newline at end of file
diff --git a/src/com/vividsolutions/jts/operation/union/UnaryUnionOp.java b/src/com/vividsolutions/jts/operation/union/UnaryUnionOp.java
index a0353c3..707c7a1 100644
--- a/src/com/vividsolutions/jts/operation/union/UnaryUnionOp.java
+++ b/src/com/vividsolutions/jts/operation/union/UnaryUnionOp.java
@@ -37,6 +37,7 @@ import java.util.*;
 import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.geom.util.*;
 import com.vividsolutions.jts.operation.overlay.OverlayOp;
+import com.vividsolutions.jts.operation.overlay.snap.SnapIfNeededOverlayOp;
 
 /**
  * Unions a collection of Geometry or a single Geometry 
@@ -51,18 +52,18 @@ import com.vividsolutions.jts.operation.overlay.OverlayOp;
  * merging the areas (i.e. the same effect as 
  * iteratively unioning all individual polygons together).
  * 
- * <li>Unioning a set of {@link LineString}s has the effect of <b>fully noding</b> 
+ * <li>Unioning a set of {@link LineString}s has the effect of <b>noding</b> 
  * and <b>dissolving</b> the input linework.
- * In this context "fully noded" means that there will be a node or endpoint in the output 
+ * In this context "fully noded" means that there will be a node or endpoint in the result 
  * for every endpoint or line segment crossing in the input.
- * "Dissolved" means that any duplicate (e.g. coincident) line segments or portions
- * of line segments will be reduced to a single line segment in the output.  
+ * "Dissolved" means that any duplicate (i.e. coincident) line segments or portions
+ * of line segments will be reduced to a single line segment in the result.  
  * This is consistent with the semantics of the 
  * {@link Geometry#union(Geometry)} operation.
  * If <b>merged</b> linework is required, the {@link LineMerger} class can be used.
  * 
  * <li>Unioning a set of {@link Points}s has the effect of merging
- * al identical points (producing a set with no duplicates).
+ * all identical points (producing a set with no duplicates).
  * </ul>
  * 
  * <tt>UnaryUnion</tt> always operates on the individual components of MultiGeometries.
@@ -220,6 +221,8 @@ public class UnaryUnionOp
    * Due to the way the overlay operations 
    * are implemented, this is still efficient in the case of linear 
    * and puntal geometries.
+   * Uses robust version of overlay operation
+   * to ensure identical behaviour to the <tt>union(Geometry)</tt> operation.
    * 
    * @param g0 a geometry
    * @return the union of the input geometry
@@ -227,7 +230,7 @@ public class UnaryUnionOp
 	private Geometry unionNoOpt(Geometry g0)
 	{
     Geometry empty = geomFact.createPoint((Coordinate) null);
-		return OverlayOp.overlayOp(g0, empty, OverlayOp.UNION);
+		return SnapIfNeededOverlayOp.overlayOp(g0, empty, OverlayOp.UNION);
 	}
 	
 }
diff --git a/src/com/vividsolutions/jts/operation/valid/IndexedNestedRingTester.java b/src/com/vividsolutions/jts/operation/valid/IndexedNestedRingTester.java
index ac3b211..4426794 100644
--- a/src/com/vividsolutions/jts/operation/valid/IndexedNestedRingTester.java
+++ b/src/com/vividsolutions/jts/operation/valid/IndexedNestedRingTester.java
@@ -89,8 +89,19 @@ public class IndexedNestedRingTester
           continue;
 
         Coordinate innerRingPt = IsValidOp.findPtNotNode(innerRingPts, searchRing, graph);
-        Assert.isTrue(innerRingPt != null, "Unable to find a ring point not a node of the search ring");
-        //Coordinate innerRingPt = innerRingPts[0];
+        
+        /**
+         * If no non-node pts can be found, this means
+         * that the searchRing touches ALL of the innerRing vertices.
+         * This indicates an invalid polygon, since either
+         * the two holes create a disconnected interior, 
+         * or they touch in an infinite number of points 
+         * (i.e. along a line segment).
+         * Both of these cases are caught by other tests,
+         * so it is safe to simply skip this situation here.
+         */
+        if (innerRingPt == null)
+          continue;
 
         boolean isInside = CGAlgorithms.isPointInRing(innerRingPt, searchRingPts);
         if (isInside) {
diff --git a/src/com/vividsolutions/jts/operation/valid/IsValidOp.java b/src/com/vividsolutions/jts/operation/valid/IsValidOp.java
index 791490f..1452c6d 100644
--- a/src/com/vividsolutions/jts/operation/valid/IsValidOp.java
+++ b/src/com/vividsolutions/jts/operation/valid/IsValidOp.java
@@ -41,7 +41,7 @@ import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.util.*;
 
 /**
- * Implements the algorithsm required to compute the <code>isValid()</code> method
+ * Implements the algorithms required to compute the <code>isValid()</code> method
  * for {@link Geometry}s.
  * See the documentation for the various geometry types for a specification of validity.
  *
@@ -49,6 +49,17 @@ import com.vividsolutions.jts.util.*;
  */
 public class IsValidOp
 {
+	/**
+	 * Tests whether a {@link Geometry} is valid.
+	 * @param geom the Geometry to test
+	 * @return true if the geometry is valid
+	 */
+	public static boolean isValid(Geometry geom)
+	{
+    IsValidOp isValidOp = new IsValidOp(geom);
+    return isValidOp.isValid();
+	}
+	
   /**
    * Checks whether a coordinate is valid for processing.
    * Coordinates are valid iff their x and y ordinates are in the
@@ -95,7 +106,6 @@ public class IsValidOp
    * (the ESRI SDE model)
    */
   private boolean isSelfTouchingRingFormingHoleValid = false;
-  private boolean isChecked = false;
   private TopologyValidationError validErr;
 
   public IsValidOp(Geometry parentGeometry)
@@ -146,7 +156,6 @@ public class IsValidOp
 
   private void checkValid(Geometry g)
   {
-    if (isChecked) return;
     validErr = null;
 
     // empty geometries are always valid!
@@ -314,10 +323,14 @@ public class IsValidOp
 
   private void checkClosedRing(LinearRing ring)
   {
-    if (! ring.isClosed() )
+    if (! ring.isClosed() ) {
+    	Coordinate pt = null;
+    	if (ring.getNumPoints() >= 1)
+    		pt = ring.getCoordinateN(0);
       validErr = new TopologyValidationError(
                         TopologyValidationError.RING_NOT_CLOSED,
-                        ring.getCoordinateN(0));
+                        pt);
+    }
   }
 
   private void checkTooFewPoints(GeometryGraph graph)
diff --git a/src/com/vividsolutions/jts/operation/valid/TopologyValidationError.java b/src/com/vividsolutions/jts/operation/valid/TopologyValidationError.java
index 1580b12..78f8995 100644
--- a/src/com/vividsolutions/jts/operation/valid/TopologyValidationError.java
+++ b/src/com/vividsolutions/jts/operation/valid/TopologyValidationError.java
@@ -112,8 +112,10 @@ public class TopologyValidationError {
    */
   public static final int RING_NOT_CLOSED      = 11;
 
-  // these messages must synch up with the indexes above
-  private static String[] errMsg = {
+  /**
+   * Messages corresponding to error codes
+   */
+  public static final String[] errMsg = {
     "Topology Validation Error",
     "Repeated Point",
     "Hole lies outside shell",
@@ -123,7 +125,7 @@ public class TopologyValidationError {
     "Ring Self-intersection",
     "Nested shells",
     "Duplicate Rings",
-    "Too few points in geometry component",
+    "Too few distinct points in geometry component",
     "Invalid Coordinate",
     "Ring is not closed"
   };
@@ -173,13 +175,13 @@ public class TopologyValidationError {
    * Gets an error message describing this error.
    * The error message does not describe the location of the error.
    *
-   * @return
+   * @return the error message
    */
   public String getMessage() { return errMsg[errorType]; }
 
   /**
    * Gets a message describing the type and location of this error.
-   * @return
+   * @return the error message
    */
   public String toString()
   {
diff --git a/src/com/vividsolutions/jts/planargraph/DirectedEdgeStar.java b/src/com/vividsolutions/jts/planargraph/DirectedEdgeStar.java
index 5e717ed..c79e966 100644
--- a/src/com/vividsolutions/jts/planargraph/DirectedEdgeStar.java
+++ b/src/com/vividsolutions/jts/planargraph/DirectedEdgeStar.java
@@ -143,8 +143,10 @@ public class DirectedEdgeStar
     return -1;
   }
   /**
-   * Returns the remainder when i is divided by the number of edges in this
-   * DirectedEdgeStar. 
+   * Returns value of i modulo the number of edges in this DirectedEdgeStar
+   * (i.e. the remainder when i is divided by the number of edges)
+   * 
+   * @param i an integer (positive, negative or zero)
    */
   public int getIndex(int i)
   {
@@ -155,12 +157,24 @@ public class DirectedEdgeStar
   }
 
   /**
-   * Returns the DirectedEdge on the left-hand side of the given DirectedEdge (which
-   * must be a member of this DirectedEdgeStar). 
+   * Returns the {@link DirectedEdge} on the left-hand (CCW) 
+   * side of the given {@link DirectedEdge} 
+   * (which must be a member of this DirectedEdgeStar). 
    */
   public DirectedEdge getNextEdge(DirectedEdge dirEdge)
   {
     int i = getIndex(dirEdge);
     return (DirectedEdge) outEdges.get(getIndex(i + 1));
   }
+  
+  /**
+   * Returns the {@link DirectedEdge} on the right-hand (CW) 
+   * side of the given {@link DirectedEdge} 
+   * (which must be a member of this DirectedEdgeStar). 
+   */
+  public DirectedEdge getNextCWEdge(DirectedEdge dirEdge)
+  {
+    int i = getIndex(dirEdge);
+    return (DirectedEdge) outEdges.get(getIndex(i - 1));
+  }
 }
diff --git a/src/com/vividsolutions/jts/planargraph/PlanarGraph.java b/src/com/vividsolutions/jts/planargraph/PlanarGraph.java
index 2b3bb01..43e5a1c 100644
--- a/src/com/vividsolutions/jts/planargraph/PlanarGraph.java
+++ b/src/com/vividsolutions/jts/planargraph/PlanarGraph.java
@@ -79,7 +79,8 @@ public abstract class PlanarGraph
   /**
    * Adds a node to the map, replacing any that is already at that location.
    * Only subclasses can add Nodes, to ensure Nodes are of the right type.
-   * @return the added node
+   * 
+   * @param node the node to add
    */
   protected void add(Node node)
   {
diff --git a/src/com/vividsolutions/jts/precision/CommonBitsRemover.java b/src/com/vividsolutions/jts/precision/CommonBitsRemover.java
index bbdf766..736bfcd 100644
--- a/src/com/vividsolutions/jts/precision/CommonBitsRemover.java
+++ b/src/com/vividsolutions/jts/precision/CommonBitsRemover.java
@@ -36,7 +36,31 @@ package com.vividsolutions.jts.precision;
 import com.vividsolutions.jts.geom.*;
 
 /**
- * Allow computing and removing common mantissa bits from one or more Geometries.
+ * Removes common most-significant mantissa bits 
+ * from one or more {@link Geometry}s.
+ * <p>
+ * The CommonBitsRemover "scavenges" precision 
+ * which is "wasted" by a large displacement of the geometry 
+ * from the origin.  
+ * For example, if a small geometry is displaced from the origin 
+ * by a large distance, 
+ * the displacement increases the significant figures in the coordinates, 
+ * but does not affect the <i>relative</i> topology of the geometry.  
+ * Thus the geometry can be translated back to the origin 
+ * without affecting its topology.
+ * In order to compute the translation without affecting 
+ * the full precision of the coordinate values, 
+ * the translation is performed at the bit level by
+ * removing the common leading mantissa bits.
+ * <p>
+ * If the geometry envelope already contains the origin, 
+ * the translation procedure cannot be applied.  
+ * In this case, the common bits value is computed as zero.
+ * <p>
+ * If the geometry crosses the Y axis but not the X axis 
+ * (and <i>mutatis mutandum</i>), 
+ * the common bits for Y are zero, 
+ * but the common bits for X are non-zero.
  *
  * @version 1.7
  */
@@ -93,7 +117,6 @@ public class CommonBitsRemover
    * The coordinates of the Geometry are changed.
    *
    * @param geom the Geometry to which to add the common coordinate bits
-   * @return the shifted Geometry
    */
   public void addCommonBits(Geometry geom)
   {
diff --git a/src/com/vividsolutions/jts/precision/GeometryPrecisionReducer.java b/src/com/vividsolutions/jts/precision/GeometryPrecisionReducer.java
new file mode 100644
index 0000000..577d8dd
--- /dev/null
+++ b/src/com/vividsolutions/jts/precision/GeometryPrecisionReducer.java
@@ -0,0 +1,225 @@
+
+/*
+ * 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.precision;
+
+import com.vividsolutions.jts.geom.*;
+import com.vividsolutions.jts.geom.util.*;
+
+/**
+ * Reduces the precision of a {@link Geometry}
+ * according to the supplied {@link PrecisionModel},
+ * ensuring that the result is topologically valid.
+ *
+ * @version 1.12
+ */
+public class GeometryPrecisionReducer
+{
+	/**
+	 * Convenience method for doing precision reduction 
+   * on a single geometry,
+	 * with collapses removed 
+   * and keeping the geometry precision model the same,
+   * and preserving polygonal topology.
+	 * 
+	 * @param g the geometry to reduce
+	 * @param precModel the precision model to use
+	 * @return the reduced geometry
+	 */
+	public static Geometry reduce(Geometry g, PrecisionModel precModel)
+	{
+		GeometryPrecisionReducer reducer = new GeometryPrecisionReducer(precModel);
+		return reducer.reduce(g);
+	}
+	
+	/**
+	 * Convenience method for doing pointwise precision reduction 
+   * on a single geometry,
+	 * with collapses removed 
+   * and keeping the geometry precision model the same,
+   * but NOT preserving valid polygonal topology.
+	 * 
+	 * @param g the geometry to reduce
+	 * @param precModel the precision model to use
+	 * @return the reduced geometry
+	 */
+	public static Geometry reducePointwise(Geometry g, PrecisionModel precModel)
+	{
+		GeometryPrecisionReducer reducer = new GeometryPrecisionReducer(precModel);
+		reducer.setPointwise(true);
+		return reducer.reduce(g);
+	}
+	
+  private PrecisionModel targetPM;
+  private boolean removeCollapsed = true;
+  private boolean changePrecisionModel = false;
+  private boolean isPointwise = false;
+
+  public GeometryPrecisionReducer(PrecisionModel pm)
+  {
+    targetPM = pm;
+  }
+
+  /**
+   * Sets whether the reduction will result in collapsed components
+   * being removed completely, or simply being collapsed to an (invalid)
+   * Geometry of the same type.
+   * The default is to remove collapsed components.
+   *
+   * @param removeCollapsed if <code>true</code> collapsed components will be removed
+   */
+  public void setRemoveCollapsedComponents(boolean removeCollapsed)
+  {
+    this.removeCollapsed = removeCollapsed;
+  }
+
+  /**
+   * Sets whether the {@link PrecisionModel} of the new reduced Geometry
+   * will be changed to be the {@link PrecisionModel} supplied to
+   * specify the precision reduction.
+   * <p>  
+   * The default is to <b>not</b> change the precision model
+   *
+   * @param changePrecisionModel if <code>true</code> the precision model of the created Geometry will be the
+   * the precisionModel supplied in the constructor.
+   */
+  public void setChangePrecisionModel(boolean changePrecisionModel)
+  {
+    this.changePrecisionModel = changePrecisionModel;
+  }
+
+  /**
+   * Sets whether the precision reduction will be done 
+   * in pointwise fashion only.  
+   * Pointwise precision reduction reduces the precision
+   * of the individual coordinates only, but does
+   * not attempt to recreate valid topology.
+   * This is only relevant for geometries containing polygonal components.
+   * 
+   * @param isPointwise if reduction should be done pointwise only
+   */
+  public void setPointwise(boolean isPointwise)
+  {
+    this.isPointwise = isPointwise;
+  }
+
+  public Geometry reduce(Geometry geom)
+  {
+    Geometry reducePW = reducePointwise(geom);
+    if (isPointwise)
+    	return reducePW;
+    
+    //TODO: handle GeometryCollections containing polys
+    if (! (reducePW instanceof Polygonal))
+    	return reducePW;
+    
+    // Geometry is polygonal - test if topology needs to be fixed
+    if (reducePW.isValid()) return reducePW;
+    
+    // hack to fix topology.  
+    // TODO: implement snap-rounding and use that.
+    return fixPolygonalTopology(reducePW);
+  }
+
+  private Geometry reducePointwise(Geometry geom)
+  {
+    GeometryEditor geomEdit;
+    if (changePrecisionModel) {
+    	GeometryFactory newFactory = createFactory(geom.getFactory(), targetPM);
+      geomEdit = new GeometryEditor(newFactory);
+    }
+    else
+      // don't change geometry factory
+      geomEdit = new GeometryEditor();
+
+    /**
+     * For polygonal geometries, collapses are always removed, in order
+     * to produce correct topology
+     */
+    boolean finalRemoveCollapsed = removeCollapsed;
+    if (geom.getDimension() >= 2)
+    	finalRemoveCollapsed = true;
+    
+    Geometry reduceGeom = geomEdit.edit(geom, 
+    		new PrecisionReducerCoordinateOperation(targetPM, finalRemoveCollapsed));
+    
+    return reduceGeom;
+  }
+  
+  private Geometry fixPolygonalTopology(Geometry geom)
+  {
+  	/**
+  	 * If precision model was *not* changed, need to flip
+  	 * geometry to targetPM, buffer in that model, then flip back
+  	 */
+  	Geometry geomToBuffer = geom;
+  	if (! changePrecisionModel) {
+  		geomToBuffer = changePM(geom, targetPM);
+  	}
+  	
+  	Geometry bufGeom = geomToBuffer.buffer(0);
+  	
+  	Geometry finalGeom = bufGeom;
+  	if (! changePrecisionModel) {
+  		PrecisionModel originalPM = geom.getFactory().getPrecisionModel();
+  		finalGeom = changePM(bufGeom, originalPM);
+  	}
+  	return finalGeom;
+  }
+  
+  private Geometry changePM(Geometry geom, PrecisionModel pm)
+  {
+  	GeometryEditor geomEditor = createEditor(geom.getFactory(), pm);
+  	return geomEditor.edit(geom, new GeometryEditor.NoOpGeometryOperation());
+  }
+  
+  private GeometryEditor createEditor(GeometryFactory geomFactory, PrecisionModel pm)
+  {
+  	if (geomFactory.getPrecisionModel() == pm)
+  		return new GeometryEditor();
+  	// otherwise create a geometry editor which changes PrecisionModel
+  	GeometryFactory newFactory = createFactory(geomFactory, targetPM);
+  	GeometryEditor geomEdit = new GeometryEditor(newFactory);
+    return geomEdit;
+  }
+  
+  private GeometryFactory createFactory(GeometryFactory inputFactory, PrecisionModel pm)
+  {
+    GeometryFactory newFactory 
+  	= new GeometryFactory(pm, 
+  			inputFactory.getSRID(),
+  			inputFactory.getCoordinateSequenceFactory());
+    return newFactory;
+  }
+  
+}
diff --git a/src/com/vividsolutions/jts/precision/MinimumClearance.java b/src/com/vividsolutions/jts/precision/MinimumClearance.java
new file mode 100644
index 0000000..2735f8c
--- /dev/null
+++ b/src/com/vividsolutions/jts/precision/MinimumClearance.java
@@ -0,0 +1,334 @@
+/*
+ * 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.precision;
+
+import com.vividsolutions.jts.algorithm.CGAlgorithms;
+import com.vividsolutions.jts.geom.*;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.LineSegment;
+import com.vividsolutions.jts.geom.LineString;
+import com.vividsolutions.jts.geom.Lineal;
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.index.strtree.ItemBoundable;
+import com.vividsolutions.jts.index.strtree.ItemDistance;
+import com.vividsolutions.jts.index.strtree.STRtree;
+import com.vividsolutions.jts.operation.distance.FacetSequence;
+import com.vividsolutions.jts.operation.distance.FacetSequenceTreeBuilder;
+
+/**
+ * Computes the Minimum Clearance of a {@link Geometry}.
+ * <p>
+ * The <b>Minimum Clearance</b> is a measure of
+ * what magnitude of perturbation of
+ * the vertices of a geometry can be tolerated
+ * before the geometry becomes topologically invalid.
+ * The smaller the Minimum Clearance distance, 
+ * the less vertex pertubation the geometry can tolerate
+ * before becoming invalid.
+ * <p>
+ * The concept was introduced by Thompson and Van Oosterom
+ * [TV06], based on earlier work by Milenkovic [Mi88].
+ * <p>
+ * The Minimum Clearance of a geometry G 
+ * is defined to be the value <i>r</i>
+ * such that "the movement of all points by a distance
+ * of <i>r</i> in any direction will 
+ * guarantee to leave the geometry valid" [TV06].
+ * An equivalent constructive definition [Mi88] is that
+ * <i>r</i> is the largest value such:
+ * <ol>
+ * <li>No two distinct vertices of G are closer than <i>r</i>
+ * <li>No vertex of G is closer than <i>r</i> to an edge of G
+ * of which the vertex is not an endpoint
+ * </ol>
+ * The following image shows an example of the Minimum Clearance
+ * of a simple polygon.
+ * <p>
+ * <center><img src='doc-files/minClearance.png'></center>
+ * <p>
+ * If G has only a single vertex (i.e. is a
+ * {@link Point}), the value of the minimum clearance 
+ * is {@link Double#MAX_VALUE}.
+ * <p>
+ * If G is a {@link Puntal} or {@link Lineal} geometry, 
+ * then in fact no amount of perturbation
+ * will render the geometry invalid.  
+ * In this case a Minimum Clearance is still computed
+ * based on the vertex and segment distances
+ * according to the constructive definition.
+ * <p>
+ * It is possible for no Minimum Clearance to exist.
+ * For instance, a {@link MultiPoint} with all members identical
+ * has no Minimum Clearance
+ * (i.e. no amount of perturbation will cause 
+ * the member points to become non-identical).
+ * Empty geometries also have no such distance.
+ * The lack of a meaningful MinimumClearance distance is detected
+ * and suitable values are returned by 
+ * {@link #getDistance()} and {@link #getLine()}.
+ * <p>
+ * The computation of Minimum Clearance utilizes 
+ * the {@link STRtree#nearestNeighbour(ItemDistance)}
+ * method to provide good performance even for
+ * large inputs.
+ * <p>
+ * An interesting note is that for the case of {@link MultiPoint}s, 
+ * the computed Minimum Clearance line
+ * effectively determines the Nearest Neighbours in the collection. 
+ *
+ * <h3>References</h3>
+ * <ul>
+ * <li>[Mi88] Milenkovic, V. J., 
+ * <i>Verifiable implementations of geometric algorithms 
+ * using finite precision arithmetic</i>.
+ * in Artificial Intelligence, 377-401. 1988
+ * <li>[TV06] Thompson, Rod and van Oosterom, Peter,
+ * <i>Interchange of Spatial Data-Inhibiting Factors</i>,
+ * Agile 2006, Visegrad, Hungary. 2006
+ * </ul>
+ * 
+ * @author Martin Davis
+ *
+ */
+public class MinimumClearance 
+{
+  /**
+   * Computes the Minimum Clearance distance for 
+   * the given Geometry.
+   * 
+   * @param g the input geometry
+   * @return the Minimum Clearance distance
+   */
+  public static double getDistance(Geometry g)
+  {
+    MinimumClearance rp = new MinimumClearance(g);
+    return rp.getDistance();
+  }
+  
+  /**
+   * Gets a LineString containing two points
+   * which are at the Minimum Clearance distance
+   * for the given Geometry.
+   * 
+   * @param g the input geometry
+   * @return the value of the minimum clearance distance
+   * @return <tt>LINESTRING EMPTY</tt> if no Minimum Clearance distance exists
+   */
+  public static Geometry getLine(Geometry g)
+  {
+    MinimumClearance rp = new MinimumClearance(g);
+    return rp.getLine();
+  }
+  
+  private Geometry inputGeom;
+  private double minClearance;
+  private Coordinate[] minClearancePts;
+  
+  /**
+   * Creates an object to compute the Minimum Clearance
+   * for the given Geometry
+   * 
+   * @param geom the input geometry
+   */
+  public MinimumClearance(Geometry geom)
+  {
+    inputGeom = geom;
+  }
+  
+  /**
+   * Gets the Minimum Clearance distance.
+   * <p>
+   * If no distance exists 
+   * (e.g. in the case of two identical points)
+   * <tt>Double.MAX_VALUE</tt> is returned.
+   * 
+   * @return the value of the minimum clearance distance
+   * @return <tt>Double.MAX_VALUE</tt> if no Minimum Clearance distance exists
+   */
+  public double getDistance()
+  {
+    compute();
+    return minClearance;
+  }
+  
+  /**
+   * Gets a LineString containing two points
+   * which are at the Minimum Clearance distance.
+   * <p>
+   * If no distance could be found 
+   * (e.g. in the case of two identical points)
+   * <tt>LINESTRING EMPTY</tt> is returned.
+   * 
+   * @return the value of the minimum clearance distance
+   * @return <tt>LINESTRING EMPTY</tt> if no Minimum Clearance distance exists
+   */
+  public LineString getLine()
+  {
+    compute();
+    // return empty line string if no min pts where found
+    if (minClearancePts == null || minClearancePts[0] == null)
+      return inputGeom.getFactory().createLineString((Coordinate[]) null);
+    return inputGeom.getFactory().createLineString(minClearancePts);
+  }
+  
+  private void compute()
+  {
+    // already computed
+    if (minClearancePts != null) return;
+    
+    // initialize to "No Distance Exists" state
+    minClearancePts = new Coordinate[2];
+    minClearance = Double.MAX_VALUE;
+    
+    // handle empty geometries
+    if (inputGeom.isEmpty()) {
+      return;
+    }
+    
+    STRtree geomTree = FacetSequenceTreeBuilder.build(inputGeom);
+    
+    Object[] nearest = geomTree.nearestNeighbour(new MinClearanceDistance());
+    MinClearanceDistance mcd = new MinClearanceDistance();
+    minClearance = mcd.distance(
+        (FacetSequence) nearest[0],
+        (FacetSequence) nearest[1]);
+    minClearancePts = mcd.getCoordinates();
+  }
+  
+  /**
+   * Implements the MinimumClearance distance function:
+   * <ul>
+   * <li>dist(p1, p2) = 
+   * <ul>
+   * <li>p1 != p2 : p1.distance(p2)
+   * <li>p1 == p2 : Double.MAX
+   * </ul>
+   * <li>dist(p, seg) =
+   * <ul>
+   * <li>p != seq.p1 && p != seg.p2 : seg.distance(p)
+   * <li>ELSE : Double.MAX
+   * </ul>
+   * </ul>
+   * Also computes the values of the nearest points, if any.
+   * 
+   * @author Martin Davis
+   *
+   */
+  private static class MinClearanceDistance
+  implements ItemDistance
+  {
+    private double minDist = Double.MAX_VALUE;
+    private Coordinate[] minPts = new Coordinate[2];
+    
+    public Coordinate[] getCoordinates()
+    {
+      return minPts;
+    }
+    
+    public double distance(ItemBoundable b1, ItemBoundable b2) {
+      FacetSequence fs1 = (FacetSequence) b1.getItem();
+      FacetSequence fs2 = (FacetSequence) b2.getItem();
+      minDist = Double.MAX_VALUE;
+      return distance(fs1, fs2);
+    }
+    
+    public double distance(FacetSequence fs1, FacetSequence fs2) {
+      
+      // compute MinClearance distance metric
+
+      vertexDistance(fs1, fs2);
+      if (fs1.size() == 1 && fs2.size() == 1) return minDist;
+      if (minDist <= 0.0) return minDist;
+      segmentDistance(fs1, fs2);
+      if (minDist <= 0.0) return minDist;
+      segmentDistance(fs2, fs1);
+      return minDist;
+    }
+    
+    private double vertexDistance(FacetSequence fs1, FacetSequence fs2) {
+      for (int i1 = 0; i1 < fs1.size(); i1++) {
+        for (int i2 = 0; i2 < fs2.size(); i2++) {
+          Coordinate p1 = fs1.getCoordinate(i1);
+          Coordinate p2 = fs2.getCoordinate(i2);
+          if (! p1.equals2D(p2)) {
+            double d = p1.distance(p2);
+            if (d < minDist) {
+              minDist = d;
+              minPts[0] = p1;
+              minPts[1] = p2;
+              if (d == 0.0)
+                return d;
+            }
+          }
+        }
+      }
+      return minDist;
+     }
+      
+     private double segmentDistance(FacetSequence fs1, FacetSequence fs2) {
+        for (int i1 = 0; i1 < fs1.size(); i1++) {
+          for (int i2 = 1; i2 < fs2.size(); i2++) {
+            
+            Coordinate p = fs1.getCoordinate(i1);
+            
+            Coordinate seg0 = fs2.getCoordinate(i2-1);
+            Coordinate seg1 = fs2.getCoordinate(i2);
+            
+            if (! (p.equals2D(seg0) || p.equals2D(seg1))) {
+              double d = CGAlgorithms.distancePointLine(p, seg0, seg1);
+              if (d < minDist) {
+                minDist = d;
+                updatePts(p, seg0, seg1);
+                if (d == 0.0)
+                  return d;
+              }
+            }
+          }
+        }
+        return minDist;
+       }
+     
+     private void updatePts(Coordinate p, Coordinate seg0, Coordinate seg1)
+     {
+       minPts[0] = p;
+       LineSegment seg = new LineSegment(seg0, seg1);
+       minPts[1] = new Coordinate(seg.closestPoint(p));       
+     }
+
+       
+     }
+  
+    
+  }
+  
+
diff --git a/src/com/vividsolutions/jts/precision/PrecisionReducerCoordinateOperation.java b/src/com/vividsolutions/jts/precision/PrecisionReducerCoordinateOperation.java
new file mode 100644
index 0000000..a12f89e
--- /dev/null
+++ b/src/com/vividsolutions/jts/precision/PrecisionReducerCoordinateOperation.java
@@ -0,0 +1,98 @@
+/*
+ * 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.precision;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.CoordinateList;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.LineString;
+import com.vividsolutions.jts.geom.LinearRing;
+import com.vividsolutions.jts.geom.PrecisionModel;
+import com.vividsolutions.jts.geom.util.GeometryEditor;
+
+public class PrecisionReducerCoordinateOperation extends
+		GeometryEditor.CoordinateOperation 
+{
+  private PrecisionModel targetPM;
+  private boolean removeCollapsed = true;
+
+	public PrecisionReducerCoordinateOperation(PrecisionModel targetPM, boolean removeCollapsed)
+	{
+		this.targetPM = targetPM;
+		this.removeCollapsed = removeCollapsed;
+	}
+	
+	public Coordinate[] edit(Coordinate[] coordinates, Geometry geom) {
+		if (coordinates.length == 0)
+			return null;
+
+		Coordinate[] reducedCoords = new Coordinate[coordinates.length];
+		// copy coordinates and reduce
+		for (int i = 0; i < coordinates.length; i++) {
+			Coordinate coord = new Coordinate(coordinates[i]);
+			targetPM.makePrecise(coord);
+			reducedCoords[i] = coord;
+		}
+		// remove repeated points, to simplify returned geometry as much as possible
+		CoordinateList noRepeatedCoordList = new CoordinateList(reducedCoords,
+				false);
+		Coordinate[] noRepeatedCoords = noRepeatedCoordList.toCoordinateArray();
+
+		/**
+		 * Check to see if the removal of repeated points collapsed the coordinate
+		 * List to an invalid length for the type of the parent geometry. It is not
+		 * necessary to check for Point collapses, since the coordinate list can
+		 * never collapse to less than one point. If the length is invalid, return
+		 * the full-length coordinate array first computed, or null if collapses are
+		 * being removed. (This may create an invalid geometry - the client must
+		 * handle this.)
+		 */
+		int minLength = 0;
+		if (geom instanceof LineString)
+			minLength = 2;
+		if (geom instanceof LinearRing)
+			minLength = 4;
+
+		Coordinate[] collapsedCoords = reducedCoords;
+		if (removeCollapsed)
+			collapsedCoords = null;
+
+		// return null or orginal length coordinate array
+		if (noRepeatedCoords.length < minLength) {
+			return collapsedCoords;
+		}
+
+		// ok to return shorter coordinate array
+		return noRepeatedCoords;
+	}
+}
diff --git a/src/com/vividsolutions/jts/precision/SimpleGeometryPrecisionReducer.java b/src/com/vividsolutions/jts/precision/SimpleGeometryPrecisionReducer.java
index bf9461a..dfeb4a3 100644
--- a/src/com/vividsolutions/jts/precision/SimpleGeometryPrecisionReducer.java
+++ b/src/com/vividsolutions/jts/precision/SimpleGeometryPrecisionReducer.java
@@ -37,11 +37,12 @@ import com.vividsolutions.jts.geom.*;
 import com.vividsolutions.jts.geom.util.*;
 
 /**
- * Reduces the precision of a {@link Geometry}
+ * Reduces the precision of the coordinates of a {@link Geometry}
  * according to the supplied {@link PrecisionModel}, without
  * attempting to preserve valid topology.
  * <p>
- * The topology of the resulting geometry may be invalid if
+ * In the case of {@link Polygonal} geometries, 
+ * the topology of the resulting geometry may be invalid if
  * topological collapse occurs due to coordinates being shifted.
  * It is up to the client to check this and handle it if necessary.
  * Collapses may not matter for some uses.  An example
@@ -49,6 +50,8 @@ import com.vividsolutions.jts.geom.util.*;
  * The buffer algorithm does not depend on the validity of the input geometry.
  *
  * @version 1.7
+ * 
+ * @deprecated use GeometryPrecisionReducer
  */
 public class SimpleGeometryPrecisionReducer
 {
@@ -91,7 +94,9 @@ public class SimpleGeometryPrecisionReducer
   /**
    * Sets whether the {@link PrecisionModel} of the new reduced Geometry
    * will be changed to be the {@link PrecisionModel} supplied to
-   * specify the reduction.  The default is to not change the precision model
+   * specify the precision reduction.
+   * <p>  
+   * The default is to <b>not</b> change the precision model
    *
    * @param changePrecisionModel if <code>true</code> the precision model of the created Geometry will be the
    * the precisionModel supplied in the constructor.
diff --git a/src/com/vividsolutions/jts/precision/SimpleMinimumClearance.java b/src/com/vividsolutions/jts/precision/SimpleMinimumClearance.java
new file mode 100644
index 0000000..cbdab9d
--- /dev/null
+++ b/src/com/vividsolutions/jts/precision/SimpleMinimumClearance.java
@@ -0,0 +1,181 @@
+/*
+ * 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.precision;
+
+import com.vividsolutions.jts.algorithm.CGAlgorithms;
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.CoordinateFilter;
+import com.vividsolutions.jts.geom.CoordinateSequence;
+import com.vividsolutions.jts.geom.CoordinateSequenceFilter;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.LineSegment;
+import com.vividsolutions.jts.geom.LineString;
+
+/**
+ * Computes the minimum clearance of a geometry or 
+ * set of geometries.
+ * <p>
+ * The <b>Minimum Clearance</b> is a measure of
+ * what magnitude of perturbation of its vertices can be tolerated
+ * by a geometry before it becomes topologically invalid.
+ * <p>
+ * This class uses an inefficient O(N^2) scan.  
+ * It is primarily for testing purposes.
+ * 
+ * 
+ * @see MinimumClearance
+ * @author Martin Davis
+ *
+ */
+public class SimpleMinimumClearance 
+{
+  public static double getDistance(Geometry g)
+  {
+    SimpleMinimumClearance rp = new SimpleMinimumClearance(g);
+    return rp.getDistance();
+  }
+  
+  public static Geometry getLine(Geometry g)
+  {
+    SimpleMinimumClearance rp = new SimpleMinimumClearance(g);
+    return rp.getLine();
+  }
+  
+  private Geometry inputGeom;
+  private double minClearance;
+  private Coordinate[] minClearancePts;
+  
+  public SimpleMinimumClearance(Geometry geom)
+  {
+    inputGeom = geom;
+  }
+  
+  public double getDistance()
+  {
+    compute();
+    return minClearance;
+  }
+  
+  public LineString getLine()
+  {
+    compute();
+    return inputGeom.getFactory().createLineString(minClearancePts);
+  }
+  
+  private void compute()
+  {
+    if (minClearancePts != null) return;
+    minClearancePts = new Coordinate[2];
+    minClearance = Double.MAX_VALUE;
+    inputGeom.apply(new VertexCoordinateFilter());
+  }
+  
+  private void updateClearance(double candidateValue, Coordinate p0, Coordinate p1)
+  {
+    if (candidateValue < minClearance) {
+      minClearance = candidateValue;
+      minClearancePts[0] = new Coordinate(p0);
+      minClearancePts[1] = new Coordinate(p1);
+    }
+  }
+  
+  private void updateClearance(double candidateValue, Coordinate p, 
+      Coordinate seg0, Coordinate seg1)
+  {
+    if (candidateValue < minClearance) {
+      minClearance = candidateValue;
+      minClearancePts[0] = new Coordinate(p);
+      LineSegment seg = new LineSegment(seg0, seg1);
+      minClearancePts[1] = new Coordinate(seg.closestPoint(p));
+    }
+  }
+  
+  private class VertexCoordinateFilter 
+  implements CoordinateFilter
+  {
+    public VertexCoordinateFilter()
+    {
+      
+    }
+    
+    public void filter(Coordinate coord) {
+      inputGeom.apply(new ComputeMCCoordinateSequenceFilter(coord));
+    }
+  }
+  
+  private class ComputeMCCoordinateSequenceFilter 
+  implements CoordinateSequenceFilter 
+  {
+    private Coordinate queryPt;
+    
+    public ComputeMCCoordinateSequenceFilter(Coordinate queryPt)
+    {
+      this.queryPt = queryPt;
+    }
+    public void filter(CoordinateSequence seq, int i) {
+      // compare to vertex
+      checkVertexDistance(seq.getCoordinate(i));
+      
+      // compare to segment, if this is one
+      if (i > 0) {
+        checkSegmentDistance(seq.getCoordinate(i - 1), seq.getCoordinate(i));
+      }
+    }
+    
+    private void checkVertexDistance(Coordinate vertex)
+    {
+      double vertexDist = vertex.distance(queryPt);
+      if (vertexDist > 0) {
+        updateClearance(vertexDist, queryPt, vertex);
+      }
+    }
+    
+    private void checkSegmentDistance(Coordinate seg0, Coordinate seg1)
+    {
+        if (queryPt.equals2D(seg0) || queryPt.equals2D(seg1))
+          return;
+        double segDist = CGAlgorithms.distancePointLine(queryPt, seg1, seg0);
+        if (segDist > 0) 
+          updateClearance(segDist, queryPt, seg1, seg0);
+    }
+    
+    public boolean isDone() {
+      return false;
+    }
+    
+    public boolean isGeometryChanged() {
+      return false;
+    }
+    
+  }
+}
diff --git a/src/com/vividsolutions/jts/precision/doc-files/minClearance.png b/src/com/vividsolutions/jts/precision/doc-files/minClearance.png
new file mode 100644
index 0000000..2547a7e
Binary files /dev/null and b/src/com/vividsolutions/jts/precision/doc-files/minClearance.png differ
diff --git a/src/com/vividsolutions/jts/precision/package.html b/src/com/vividsolutions/jts/precision/package.html
index 4d4ad01..76b9b3b 100644
--- a/src/com/vividsolutions/jts/precision/package.html
+++ b/src/com/vividsolutions/jts/precision/package.html
@@ -7,7 +7,8 @@
 </head>
 <body bgcolor="white">
 
-Provides classes for manipulating the precision model of Geometries
+Provides classes for analyzing and
+manipulating the precision of Geometries.
 
 </body>
 </html>
diff --git a/src/com/vividsolutions/jts/shape/GeometricShapeBuilder.java b/src/com/vividsolutions/jts/shape/GeometricShapeBuilder.java
new file mode 100644
index 0000000..60b18bb
--- /dev/null
+++ b/src/com/vividsolutions/jts/shape/GeometricShapeBuilder.java
@@ -0,0 +1,78 @@
+package com.vividsolutions.jts.shape;
+
+import com.vividsolutions.jts.geom.*;
+
+public abstract class GeometricShapeBuilder 
+{
+	protected Envelope extent = new Envelope(0, 1, 0, 1);
+	protected int numPts = 0;
+	protected GeometryFactory geomFactory;
+	
+	public GeometricShapeBuilder(GeometryFactory geomFactory)
+	{
+		this.geomFactory = geomFactory;
+	}
+	
+	public void setExtent(Envelope extent)
+	{
+		this.extent = extent;
+	}
+	
+	public Envelope getExtent()
+	{
+		return extent;
+	}
+	
+	public Coordinate getCentre()
+	{
+		return extent.centre();
+	}
+	
+	public double getDiameter()
+	{
+		return Math.min(extent.getHeight(), extent.getWidth());
+	}
+	
+	public double getRadius()
+	{
+		return getDiameter() / 2;
+	}
+	
+	public LineSegment getSquareBaseLine()
+	{
+		double radius = getRadius();
+		
+		Coordinate centre = getCentre();
+		Coordinate p0 = new Coordinate(centre.x - radius, centre.y - radius);
+		Coordinate p1 = new Coordinate(centre.x + radius, centre.y - radius);
+		return new LineSegment(p0, p1);
+	}
+	
+	public Envelope getSquareExtent()
+	{
+		double radius = getRadius();
+		
+		Coordinate centre = getCentre();
+		return new Envelope(centre.x - radius, centre.x + radius,
+				centre.y - radius, centre.y + radius);
+	}
+	
+
+  /**
+   * Sets the total number of points in the created {@link Geometry}.
+   * The created geometry will have no more than this number of points,
+   * unless more are needed to create a valid geometry.
+   */
+  public void setNumPoints(int numPts) { this.numPts = numPts; }
+
+  public abstract Geometry getGeometry();
+
+  protected Coordinate createCoord(double x, double y)
+  {
+  	Coordinate pt = new Coordinate(x, y);
+  	geomFactory.getPrecisionModel().makePrecise(pt);
+    return pt;
+  }
+  
+
+}
diff --git a/src/com/vividsolutions/jts/shape/fractal/KochSnowflakeBuilder.java b/src/com/vividsolutions/jts/shape/fractal/KochSnowflakeBuilder.java
new file mode 100644
index 0000000..ec4f2bd
--- /dev/null
+++ b/src/com/vividsolutions/jts/shape/fractal/KochSnowflakeBuilder.java
@@ -0,0 +1,87 @@
+package com.vividsolutions.jts.shape.fractal;
+
+import com.vividsolutions.jts.geom.*;
+import com.vividsolutions.jts.math.Vector2D;
+import com.vividsolutions.jts.shape.*;
+
+public class KochSnowflakeBuilder 
+extends GeometricShapeBuilder
+{
+	private CoordinateList coordList = new CoordinateList();
+	
+	public KochSnowflakeBuilder(GeometryFactory geomFactory)
+	{
+		super(geomFactory);
+	}
+	
+	public static int recursionLevelForSize(int numPts)
+	{
+		double pow4 = numPts / 3;
+		double exp = Math.log(pow4)/Math.log(4);
+		return (int) exp;
+	}
+	
+	public Geometry getGeometry()
+	{
+		int level = recursionLevelForSize(numPts);
+		LineSegment baseLine = getSquareBaseLine();
+		Coordinate[] pts = getBoundary(level, baseLine.getCoordinate(0), baseLine.getLength());
+		return geomFactory.createPolygon(
+				geomFactory.createLinearRing(pts), null);
+	}
+	
+	/**
+	 * The height of an equilateral triangle of side one
+	 */
+	private static double HEIGHT_FACTOR = Math.sin(Math.PI / 3.0);
+	private static final double ONE_THIRD = 1.0/3.0;
+	private static final double THIRD_HEIGHT = HEIGHT_FACTOR/3.0;
+	private static final double TWO_THIRDS = 2.0/3.0;
+	
+	private Coordinate[] getBoundary(int level, Coordinate origin, double width) 
+	{
+		double y = origin.y;
+		// for all levels beyond 0 need to vertically shift shape by height of one "arm" to centre it
+		if (level > 0) {
+			y += THIRD_HEIGHT * width;
+		}
+		
+		Coordinate p0 = new Coordinate(origin.x, y);
+		Coordinate p1 = new Coordinate(origin.x + width/2, y + width * HEIGHT_FACTOR);
+		Coordinate p2 = new Coordinate(origin.x + width, y);
+		addSide(level, p0, p1);
+		addSide(level, p1, p2);
+		addSide(level, p2, p0);
+		coordList.closeRing();
+		return coordList.toCoordinateArray();
+	}
+
+	public void addSide(int level, Coordinate p0, Coordinate p1) {
+		if (level == 0)
+			addSegment(p0, p1);
+		else {
+			Vector2D base = Vector2D.create(p0, p1);
+			Coordinate midPt = base.multiply(0.5).translate(p0);
+			
+			Vector2D heightVec = base.multiply(THIRD_HEIGHT);
+			Vector2D offsetVec = heightVec.rotateByQuarterCircle(1);
+			Coordinate offsetPt = offsetVec.translate(midPt);
+			
+			int n2 = level - 1;
+			Coordinate thirdPt = base.multiply(ONE_THIRD).translate(p0);
+			Coordinate twoThirdPt = base.multiply(TWO_THIRDS).translate(p0);
+			
+			// construct sides recursively
+			addSide(n2, p0, thirdPt);
+			addSide(n2, thirdPt, offsetPt);
+			addSide(n2, offsetPt, twoThirdPt);
+			addSide(n2, twoThirdPt, p1);
+		}
+	}
+		
+	private void addSegment(Coordinate p0, Coordinate p1)
+	{
+		coordList.add(p1);
+	}
+	
+}
diff --git a/src/com/vividsolutions/jts/shape/fractal/SierpinskiCarpetBuilder.java b/src/com/vividsolutions/jts/shape/fractal/SierpinskiCarpetBuilder.java
new file mode 100644
index 0000000..5253447
--- /dev/null
+++ b/src/com/vividsolutions/jts/shape/fractal/SierpinskiCarpetBuilder.java
@@ -0,0 +1,80 @@
+package com.vividsolutions.jts.shape.fractal;
+
+import java.util.*;
+
+import com.vividsolutions.jts.geom.*;
+import com.vividsolutions.jts.shape.*;
+
+public class SierpinskiCarpetBuilder 
+extends GeometricShapeBuilder
+{
+	private CoordinateList coordList = new CoordinateList();
+	
+	public SierpinskiCarpetBuilder(GeometryFactory geomFactory)
+	{
+		super(geomFactory);
+	}
+	
+	public static int recursionLevelForSize(int numPts)
+	{
+		double pow4 = numPts / 3;
+		double exp = Math.log(pow4)/Math.log(4);
+		return (int) exp;
+	}
+	
+	public Geometry getGeometry()
+	{
+		int level = recursionLevelForSize(numPts);
+		LineSegment baseLine = getSquareBaseLine();
+		Coordinate origin = baseLine.getCoordinate(0);
+		LinearRing[] holes = getHoles(level, origin.x, origin.y, getDiameter());
+		LinearRing shell = (LinearRing) ((Polygon) geomFactory.toGeometry(getSquareExtent())).getExteriorRing();
+		return geomFactory.createPolygon(
+				shell, holes);
+	}
+	
+	private LinearRing[] getHoles(int n, double originX, double originY, double width) 
+	{
+		List holeList = new ArrayList();
+		
+		addHoles(n, originX, originY, width, holeList );
+		
+		return GeometryFactory.toLinearRingArray(holeList);
+	}
+
+	private void addHoles(int n, double originX, double originY, double width, List holeList) 
+	{
+		if (n < 0) return;
+		int n2 = n - 1;
+		double widthThird = width / 3.0;
+		double widthTwoThirds = width * 2.0 / 3.0;
+		double widthNinth = width / 9.0;
+		addHoles(n2, originX, 									originY, widthThird, holeList);
+		addHoles(n2, originX + widthThird, 			originY, widthThird, holeList);
+		addHoles(n2, originX + 2 * widthThird, 	originY, widthThird, holeList);
+		
+		addHoles(n2, originX, 									originY + widthThird, widthThird, holeList);
+		addHoles(n2, originX + 2 * widthThird, 	originY + widthThird, widthThird, holeList);
+
+		addHoles(n2, originX, 									originY + 2 * widthThird, widthThird, holeList);
+		addHoles(n2, originX + widthThird, 			originY + 2 * widthThird, widthThird, holeList);
+		addHoles(n2, originX + 2 * widthThird, 	originY + 2 * widthThird, widthThird, holeList);
+
+		// add the centre hole
+		holeList.add(createSquareHole(originX + widthThird, originY + widthThird, widthThird));
+	}
+
+	private LinearRing createSquareHole(double x, double y, double width)
+	{
+		Coordinate[] pts = new Coordinate[]{
+        new Coordinate(x, y),
+        new Coordinate(x + width, y),
+        new Coordinate(x + width, y + width),
+        new Coordinate(x, y + width),
+        new Coordinate(x, y)
+        }	;
+		return geomFactory.createLinearRing(pts); 
+	}
+	
+
+}
diff --git a/src/com/vividsolutions/jts/shape/random/RandomPointsBuilder.java b/src/com/vividsolutions/jts/shape/random/RandomPointsBuilder.java
new file mode 100644
index 0000000..0e17c09
--- /dev/null
+++ b/src/com/vividsolutions/jts/shape/random/RandomPointsBuilder.java
@@ -0,0 +1,90 @@
+package com.vividsolutions.jts.shape.random;
+
+import com.vividsolutions.jts.algorithm.locate.IndexedPointInAreaLocator;
+import com.vividsolutions.jts.algorithm.locate.PointOnGeometryLocator;
+import com.vividsolutions.jts.geom.*;
+import com.vividsolutions.jts.shape.GeometricShapeBuilder;
+
+/**
+ * Creates random point sets contained in a 
+ * region defined by either a rectangular or a polygonal extent. 
+ * 
+ * @author mbdavis
+ *
+ */
+public class RandomPointsBuilder 
+extends GeometricShapeBuilder
+{
+  protected Geometry maskPoly = null;
+  private PointOnGeometryLocator extentLocator;
+
+  /**
+   * Create a shape factory which will create shapes using the default
+   * {@link GeometryFactory}.
+   */
+  public RandomPointsBuilder()
+  {
+    super(new GeometryFactory());
+  }
+
+  /**
+   * Create a shape factory which will create shapes using the given
+   * {@link GeometryFactory}.
+   *
+   * @param geomFact the factory to use
+   */
+  public RandomPointsBuilder(GeometryFactory geomFact)
+  {
+  	super(geomFact);
+  }
+
+  /**
+   * Sets a polygonal mask.
+   * 
+   * @param mask
+   * @ throws IllegalArgumentException if the mask is not polygonal
+   */
+  public void setExtent(Geometry mask)
+  {
+  	if (! (mask instanceof Polygonal))
+  		throw new IllegalArgumentException("Only polygonal extents are supported");
+  	this.maskPoly = mask;
+  	setExtent(mask.getEnvelopeInternal());
+  	extentLocator = new IndexedPointInAreaLocator(mask);
+  }
+  
+  public Geometry getGeometry()
+  {
+  	Coordinate[] pts = new Coordinate[numPts];
+  	int i = 0;
+  	while (i < numPts) {
+  		Coordinate p = createRandomCoord(getExtent());
+  		if (extentLocator != null && ! isInExtent(p))
+  			continue;
+  		pts[i++] = p;
+  	}
+  	return geomFactory.createMultiPoint(pts);
+  }
+  
+  protected boolean isInExtent(Coordinate p)
+  {
+  	if (extentLocator != null) 
+  		return extentLocator.locate(p) != Location.EXTERIOR;
+  	return getExtent().contains(p);
+  }
+  
+  protected Coordinate createCoord(double x, double y)
+  {
+  	Coordinate pt = new Coordinate(x, y);
+  	geomFactory.getPrecisionModel().makePrecise(pt);
+    return pt;
+  }
+  
+  protected Coordinate createRandomCoord(Envelope env)
+  {
+    double x = env.getMinX() + env.getWidth() * Math.random();
+    double y = env.getMinY() + env.getHeight() * Math.random();
+    return createCoord(x, y);
+  }
+
+}
diff --git a/src/com/vividsolutions/jts/shape/random/RandomPointsInGridBuilder.java b/src/com/vividsolutions/jts/shape/random/RandomPointsInGridBuilder.java
new file mode 100644
index 0000000..46c160b
--- /dev/null
+++ b/src/com/vividsolutions/jts/shape/random/RandomPointsInGridBuilder.java
@@ -0,0 +1,116 @@
+package com.vividsolutions.jts.shape.random;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.vividsolutions.jts.algorithm.locate.IndexedPointInAreaLocator;
+import com.vividsolutions.jts.algorithm.locate.PointOnGeometryLocator;
+import com.vividsolutions.jts.geom.*;
+import com.vividsolutions.jts.math.MathUtil;
+import com.vividsolutions.jts.shape.GeometricShapeBuilder;
+
+/**
+ * Creates random point sets 
+ * where the points are constrained to lie in the cells of a grid. 
+ * 
+ * @author mbdavis
+ *
+ */
+public class RandomPointsInGridBuilder 
+extends GeometricShapeBuilder
+{
+	private boolean isConstrainedToCircle = false;
+	private double gutterFraction = 0;
+	
+  /**
+   * Create a builder which will create shapes using the default
+   * {@link GeometryFactory}.
+   */
+  public RandomPointsInGridBuilder()
+  {
+    super(new GeometryFactory());
+  }
+
+  /**
+   * Create a builder which will create shapes using the given
+   * {@link GeometryFactory}.
+   *
+   * @param geomFact the factory to use
+   */
+  public RandomPointsInGridBuilder(GeometryFactory geomFact)
+  {
+  	super(geomFact);
+  }
+
+  public void setConstrainedToCircle(boolean isConstrainedToCircle)
+  {
+  	this.isConstrainedToCircle = isConstrainedToCircle;
+  }
+  
+  public void setGutterFraction(double gutterFraction)
+  {
+  	this.gutterFraction = gutterFraction;
+  }
+  
+  public Geometry getGeometry()
+  {
+    int nCells = (int) Math.sqrt(numPts) + 1;
+
+    double gridDX = getExtent().getWidth() / nCells;
+    double gridDY = getExtent().getHeight() / nCells;
+
+    double gutterFrac = MathUtil.clamp(gutterFraction, 0.0, 1.0);
+    double gutterOffsetX = gridDX * gutterFrac/2;
+    double gutterOffsetY = gridDY * gutterFrac/2;
+    double cellFrac = 1.0 - gutterFrac;
+    double cellDX = cellFrac * gridDX;
+    double cellDY = cellFrac * gridDY;
+    	
+    List pts = new ArrayList();
+
+    for (int i = 0; i < nCells; i++) {
+      for (int j = 0; j < nCells; j++) {
+      	double orgX = getExtent().getMinX() + i * gridDX + gutterOffsetX;
+      	double orgY = getExtent().getMinY() + j * gridDY + gutterOffsetY;
+        pts.add(randomPointInCell(orgX, orgY, cellDX, cellDY));
+      }
+    }
+    return geomFactory.createMultiPoint(CoordinateArrays.toCoordinateArray(pts));
+  }
+  
+  private Coordinate randomPointInCell(double orgX, double orgY, double xLen, double yLen)
+  {
+  	if (isConstrainedToCircle) {
+  		randomPointInCircle(
+  				orgX, 
+  				orgY, 
+  				xLen, yLen);
+  	}
+  	return randomPointInGridCell(orgX, orgY, xLen, yLen);
+  }
+  
+  private Coordinate randomPointInGridCell(double orgX, double orgY, double xLen, double yLen)
+  {
+    double x = orgX + xLen * Math.random();
+    double y = orgY + yLen * Math.random();
+    return createCoord(x, y);
+  }
+
+  private static Coordinate randomPointInCircle(double orgX, double orgY, double width, double height)
+  {
+  	double centreX = orgX + width/2;
+  	double centreY = orgX + height/2;
+  		
+  	double rndAng = 2 * Math.PI * Math.random();
+  	double rndRadius = Math.random();
+    // use square root of radius, since area is proportional to square of radius
+    double rndRadius2 = Math.sqrt(rndRadius);
+  	double rndX = width/2 * rndRadius2 * Math.cos(rndAng); 
+  	double rndY = height/2 * rndRadius2 * Math.sin(rndAng); 
+  	
+    double x0 = centreX + rndX;
+    double y0 = centreY + rndY;
+    return new Coordinate(x0, y0);    
+  }
+
+}
diff --git a/src/com/vividsolutions/jts/simplify/DouglasPeuckerLineSimplifier.java b/src/com/vividsolutions/jts/simplify/DouglasPeuckerLineSimplifier.java
index 7c1cc30..552de40 100644
--- a/src/com/vividsolutions/jts/simplify/DouglasPeuckerLineSimplifier.java
+++ b/src/com/vividsolutions/jts/simplify/DouglasPeuckerLineSimplifier.java
@@ -9,7 +9,7 @@ import com.vividsolutions.jts.geom.*;
  *
  * @version 1.7
  */
-public class DouglasPeuckerLineSimplifier
+class DouglasPeuckerLineSimplifier
 {
   public static Coordinate[] simplify(Coordinate[] pts, double distanceTolerance)
   {
diff --git a/src/com/vividsolutions/jts/simplify/LineSegmentIndex.java b/src/com/vividsolutions/jts/simplify/LineSegmentIndex.java
index a6a0b4d..92c92e7 100644
--- a/src/com/vividsolutions/jts/simplify/LineSegmentIndex.java
+++ b/src/com/vividsolutions/jts/simplify/LineSegmentIndex.java
@@ -11,7 +11,7 @@ import com.vividsolutions.jts.index.quadtree.Quadtree;
  *
  * @author Martin Davis
  */
-public class LineSegmentIndex
+class LineSegmentIndex
 {
   private Quadtree index = new Quadtree();
 
diff --git a/src/com/vividsolutions/jts/simplify/TaggedLineSegment.java b/src/com/vividsolutions/jts/simplify/TaggedLineSegment.java
index f6ab3d9..9db92b1 100644
--- a/src/com/vividsolutions/jts/simplify/TaggedLineSegment.java
+++ b/src/com/vividsolutions/jts/simplify/TaggedLineSegment.java
@@ -7,7 +7,7 @@ import com.vividsolutions.jts.geom.*;
  * Used to index the segments in a geometry and recover the segment locations
  * from the index.
  */
-public class TaggedLineSegment
+class TaggedLineSegment
     extends LineSegment
 {
   private Geometry parent;
diff --git a/src/com/vividsolutions/jts/simplify/TaggedLineString.java b/src/com/vividsolutions/jts/simplify/TaggedLineString.java
index d582d85..378d262 100644
--- a/src/com/vividsolutions/jts/simplify/TaggedLineString.java
+++ b/src/com/vividsolutions/jts/simplify/TaggedLineString.java
@@ -11,7 +11,7 @@ import com.vividsolutions.jts.geom.*;
  * 
  * @version 1.7
  */
-public class TaggedLineString
+class TaggedLineString
 {
 
   private LineString parentLine;
diff --git a/src/com/vividsolutions/jts/simplify/TaggedLineStringSimplifier.java b/src/com/vividsolutions/jts/simplify/TaggedLineStringSimplifier.java
index 3e5ccb8..7ae7210 100644
--- a/src/com/vividsolutions/jts/simplify/TaggedLineStringSimplifier.java
+++ b/src/com/vividsolutions/jts/simplify/TaggedLineStringSimplifier.java
@@ -13,7 +13,7 @@ import com.vividsolutions.jts.util.Debug;
  * @author Martin Davis
  * @version 1.7
  */
-public class TaggedLineStringSimplifier
+class TaggedLineStringSimplifier
 {
   private static LineIntersector li = new RobustLineIntersector();
   private LineSegmentIndex inputIndex = new LineSegmentIndex();
diff --git a/src/com/vividsolutions/jts/simplify/TaggedLinesSimplifier.java b/src/com/vividsolutions/jts/simplify/TaggedLinesSimplifier.java
index 6bceb90..15be2fc 100644
--- a/src/com/vividsolutions/jts/simplify/TaggedLinesSimplifier.java
+++ b/src/com/vividsolutions/jts/simplify/TaggedLinesSimplifier.java
@@ -9,7 +9,7 @@ import com.vividsolutions.jts.algorithm.*;
  * This class is essentially just a container for the common
  * indexes used by {@link TaggedLineStringSimplifier}.
  */
-public class TaggedLinesSimplifier
+class TaggedLinesSimplifier
 {
   private LineSegmentIndex inputIndex = new LineSegmentIndex();
   private LineSegmentIndex outputIndex = new LineSegmentIndex();
diff --git a/src/com/vividsolutions/jts/simplify/TopologyPreservingSimplifier.java b/src/com/vividsolutions/jts/simplify/TopologyPreservingSimplifier.java
index 97b3ff2..756977b 100644
--- a/src/com/vividsolutions/jts/simplify/TopologyPreservingSimplifier.java
+++ b/src/com/vividsolutions/jts/simplify/TopologyPreservingSimplifier.java
@@ -22,7 +22,16 @@ import com.vividsolutions.jts.util.Debug;
  * (The key implication of this constraint is that the 
  * output will be topologically valid if the input was.) 
  * </ul>
- *
+ * <h3>KNOWN BUGS</h3>
+ * <ul>
+ * <li>If a small hole is very near an edge, it is possible for the edge to be moved by
+ * a relatively large tolerance value and end up with the hole outside the result shell.
+ * Similarly, it is possible for a small polygon component to end up inside
+ * a nearby larger polygon.
+ * A workaround is to test for this situation in post-processing and remove
+ * any invalid holes or polygons.
+ * </ul>
+ * 
  * @author Martin Davis
  * @see DouglasPeuckerSimplifier
  *
diff --git a/src/com/vividsolutions/jts/triangulate/IncrementalDelaunayTriangulator.java b/src/com/vividsolutions/jts/triangulate/IncrementalDelaunayTriangulator.java
index 14f104b..f6c1d8e 100644
--- a/src/com/vividsolutions/jts/triangulate/IncrementalDelaunayTriangulator.java
+++ b/src/com/vividsolutions/jts/triangulate/IncrementalDelaunayTriangulator.java
@@ -129,7 +129,7 @@ public class IncrementalDelaunayTriangulator
 		// is satisfied.
 		do {
 			QuadEdge t = e.oPrev();
-			if (t.dest().rightOf(e) && v.inCircle(e.orig(), t.dest(), e.dest())) {
+			if (t.dest().rightOf(e) && v.isInCircle(e.orig(), t.dest(), e.dest())) {
 				QuadEdge.swap(e);
 				e = e.oPrev();
 			} else if (e.oNext() == startEdge) {
diff --git a/src/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeSubdivision.java b/src/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeSubdivision.java
index 5fcaf9a..b59c2c2 100644
--- a/src/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeSubdivision.java
+++ b/src/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeSubdivision.java
@@ -172,7 +172,7 @@ public class QuadEdgeSubdivision {
 	}
 
 	/**
-	 * Gets the collection of base {@link Quadedge}s (one for every pair of
+	 * Gets the collection of base {@link QuadEdge}s (one for every pair of
 	 * vertices which is connected).
 	 * 
 	 * @return a collection of QuadEdges
@@ -631,7 +631,7 @@ public class QuadEdgeSubdivision {
 			Coordinate c = triEdges[2].orig().getCoordinate();
 			
 			// TODO: choose the most accurate circumcentre based on the edges
-			Coordinate cc = Triangle.circumcentre(a, b, c);
+      Coordinate cc = Triangle.circumcentre(a, b, c);
 			Vertex ccVertex = new Vertex(cc);
 			// save the circumcentre as the origin for the dual edges originating in this triangle
 			for (int i = 0; i < 3; i++) {
@@ -797,16 +797,7 @@ public class QuadEdgeSubdivision {
 				coordList.closeRing();
 				Coordinate[] pts = coordList.toCoordinateArray();
 				if (pts.length != 4) {
-					String loc = "";
-					if (pts.length >= 2)
-						loc = WKTWriter.toLineString(pts[0], pts[1]);
-					else {
-						if (pts.length >= 1)
-							loc = WKTWriter.toPoint(pts[0]);
-					}
-
-					// Assert.isTrue(pts.length == 4, "Too few points for visited triangle at " + loc);
-					//com.vividsolutions.jts.util.Debug.println("too few points for triangle at " + loc);
+					//checkTriangleSize(pts);
 					return;
 				}
 
@@ -814,6 +805,19 @@ public class QuadEdgeSubdivision {
 			}
 		}
 
+		private void checkTriangleSize(Coordinate[] pts)
+		{
+			String loc = "";
+			if (pts.length >= 2)
+				loc = WKTWriter.toLineString(pts[0], pts[1]);
+			else {
+				if (pts.length >= 1)
+					loc = WKTWriter.toPoint(pts[0]);
+			}
+			// Assert.isTrue(pts.length == 4, "Too few points for visited triangle at " + loc);
+			//com.vividsolutions.jts.util.Debug.println("too few points for triangle at " + loc);
+		}
+		
 		public List getTriangles() {
 			return triCoords;
 		}
@@ -933,6 +937,12 @@ public class QuadEdgeSubdivision {
     CoordinateList coordList = new CoordinateList();
     coordList.addAll(cellPts, false);
     coordList.closeRing();
+    
+    if (coordList.size() < 4) {
+      System.out.println(coordList);
+      coordList.add(coordList.get(coordList.size()-1), true);
+    }
+    
     Coordinate[] pts = coordList.toCoordinateArray();
     Polygon cellPoly = geomFact.createPolygon(geomFact.createLinearRing(pts), null);
     
diff --git a/src/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeTriangle.java b/src/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeTriangle.java
index 76f0998..ab10fd0 100644
--- a/src/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeTriangle.java
+++ b/src/com/vividsolutions/jts/triangulate/quadedge/QuadEdgeTriangle.java
@@ -31,7 +31,6 @@
  *     www.vividsolutions.com
  */
 
-
 package com.vividsolutions.jts.triangulate.quadedge;
 
 import java.util.ArrayList;
@@ -46,238 +45,315 @@ import com.vividsolutions.jts.geom.LinearRing;
 import com.vividsolutions.jts.geom.Polygon;
 
 /**
- * Models a triangle formed from {@link Quadedge}s in a {@link Subdivision}. Provides methods to
- * access the topological and geometric properties of the triangle. Triangle edges are oriented CCW.
+ * Models a triangle formed from {@link QuadEdge}s in a {@link QuadEdgeSubdivision}
+ * which forms a triangulation. The class provides methods to access the
+ * topological and geometric properties of the triangle and its neighbours in
+ * the triangulation. Triangle vertices are ordered in CCW orientation in the
+ * structure.
+ * <p>
+ * QuadEdgeTriangles support having an external data attribute attached to them.
+ * Alternatively, this class can be subclassed and attributes can 
+ * be defined in the subclass.  Subclasses will need to define 
+ * their own <tt>BuilderVisitor</tt> class
+ * and <tt>createOn</tt> method.
  * 
  * @author Martin Davis
  * @version 1.0
  */
-public class QuadEdgeTriangle {
-
-    /**
-     * Tests whether the point pt is contained in the triangle defined by 3 {@link Vertex}es.
-     * 
-     * @param tri an array containing at least 3 Vertexes
-     * @param pt the point to test
-     * @return true if the point is contained in the triangle
-     */
-    public static boolean contains(Vertex[] tri, Coordinate pt) {
-        Coordinate[] ring = new Coordinate[]{
-            tri[0].getCoordinate(),
-            tri[1].getCoordinate(),
-            tri[2].getCoordinate(),
-            tri[0].getCoordinate()};
-        return CGAlgorithms.isPointInRing(pt, ring);
-    }
-
-    /**
-     * Tests whether the point pt is contained in the triangle defined by 3 {@link QuadEdge}es.
-     * 
-     * @param tri an array containing at least 3 QuadEdges
-     * @param pt the point to test
-     * @return true if the point is contained in the triangle
-     */
-    public static boolean contains(QuadEdge[] tri, Coordinate pt) {
-        Coordinate[] ring = new Coordinate[]{
-            tri[0].orig().getCoordinate(),
-            tri[1].orig().getCoordinate(),
-            tri[2].orig().getCoordinate(),
-            tri[0].orig().getCoordinate()};
-        return CGAlgorithms.isPointInRing(pt, ring);
-    }
-
-    public static Geometry toPolygon(Vertex[] v) {
-        Coordinate[] ringPts = new Coordinate[]{
-            v[0].getCoordinate(),
-            v[1].getCoordinate(),
-            v[2].getCoordinate(),
-            v[0].getCoordinate()};
-        GeometryFactory fact = new GeometryFactory();
-        LinearRing ring = fact.createLinearRing(ringPts);
-        Polygon tri = fact.createPolygon(ring, null);
-        return tri;
-    }
-
-    public static Geometry toPolygon(QuadEdge[] e) {
-        Coordinate[] ringPts = new Coordinate[]{
-            e[0].orig().getCoordinate(),
-            e[1].orig().getCoordinate(),
-            e[2].orig().getCoordinate(),
-            e[0].orig().getCoordinate()};
-        GeometryFactory fact = new GeometryFactory();
-        LinearRing ring = fact.createLinearRing(ringPts);
-        Polygon tri = fact.createPolygon(ring, null);
-        return tri;
-    }
-
-    /**
-     * Finds the next index around the triangle. Index may be an edge or vertex index.
-     * 
-     * @param index
-     * @return
-     */
-    public static int nextIndex(int index) {
-        return index = (index + 1) % 3;
-    }
-
-    private QuadEdge[] edge;
-
-    public QuadEdgeTriangle(QuadEdge[] edge) {
-        this.edge = (QuadEdge[]) edge.clone();
-    }
-
-    public void kill() {
-        edge = null;
-    }
-
-    public boolean isLive() {
-        return edge != null;
-    }
-
-    public QuadEdge[] getEdges() {
-        return edge;
-    }
-
-    public QuadEdge getEdge(int i) {
-        return edge[i];
-    }
-
-    public Vertex getVertex(int i) {
-        return edge[i].orig();
-    }
-
-    /**
-     * Gets the vertices for this triangle.
-     * 
-     * @return a new array containing the triangle vertices
-     */
-    public Vertex[] getVertices() {
-        Vertex[] vert = new Vertex[3];
-        for (int i = 0; i < 3; i++) {
-            vert[i] = getVertex(i);
-        }
-        return vert;
-    }
-
-    public Coordinate getCoordinate(int i) {
-        return edge[i].orig().getCoordinate();
-    }
-
-    /**
-     * Gets the index for the given edge of this triangle
-     * 
-     * @param e a QuadEdge
-     * @return the index of the edge in this triangle
-     * @return -1 if the edge is not an edge of this triangle
-     */
-    public int getEdgeIndex(QuadEdge e) {
-        for (int i = 0; i < 3; i++) {
-            if (edge[i] == e)
-                return i;
-        }
-        return -1;
-    }
-
-    /**
-     * Gets the index for the edge that starts at vertex v.
-     * 
-     * @param v the vertex to find the edge for
-     * @return the index of the edge starting at the vertex
-     * @return -1 if the vertex is not in the triangle
-     */
-    public int getEdgeIndex(Vertex v) {
-        for (int i = 0; i < 3; i++) {
-            if (edge[i].orig() == v)
-                return i;
-        }
-        return -1;
-    }
-
-    public void getEdgeSegment(int i, LineSegment seg) {
-        seg.p0 = edge[i].orig().getCoordinate();
-        int nexti = (i + 1) % 3;
-        seg.p1 = edge[nexti].orig().getCoordinate();
-    }
-
-    public Coordinate[] getCoordinates() {
-        Coordinate[] pts = new Coordinate[4];
-        for (int i = 0; i < 3; i++) {
-            pts[i] = edge[i].orig().getCoordinate();
-        }
-        pts[3] = new Coordinate(pts[0]);
-        return pts;
+public class QuadEdgeTriangle 
+{
+	/**
+	 * Creates {@link QuadEdgeTriangle}s for all facets of a 
+	 * {@link QuadEdgeSubdivision} representing a triangulation.
+	 * The <tt>data</tt> attributes of the {@link QuadEdge}s in the subdivision
+	 * will be set to point to the triangle which contains that edge.
+	 * This allows tracing the neighbour triangles of any given triangle.
+	 * 
+	 * @param subdiv
+	 * 				the QuadEdgeSubdivision to create the triangles on.
+	 * @return a List of the created QuadEdgeTriangles
+	 */
+	public static List createOn(QuadEdgeSubdivision subdiv)
+	{
+		QuadEdgeTriangleBuilderVisitor visitor = new QuadEdgeTriangleBuilderVisitor();
+		subdiv.visitTriangles(visitor, false);
+		return visitor.getTriangles();
+	}
+
+	/**
+	 * Tests whether the point pt is contained in the triangle defined by 3
+	 * {@link Vertex}es.
+	 * 
+	 * @param tri
+	 *          an array containing at least 3 Vertexes
+	 * @param pt
+	 *          the point to test
+	 * @return true if the point is contained in the triangle
+	 */
+	public static boolean contains(Vertex[] tri, Coordinate pt) {
+		Coordinate[] ring = new Coordinate[] { tri[0].getCoordinate(),
+				tri[1].getCoordinate(), tri[2].getCoordinate(), tri[0].getCoordinate() };
+		return CGAlgorithms.isPointInRing(pt, ring);
+	}
+
+	/**
+	 * Tests whether the point pt is contained in the triangle defined by 3
+	 * {@link QuadEdge}es.
+	 * 
+	 * @param tri
+	 *          an array containing at least 3 QuadEdges
+	 * @param pt
+	 *          the point to test
+	 * @return true if the point is contained in the triangle
+	 */
+	public static boolean contains(QuadEdge[] tri, Coordinate pt) {
+		Coordinate[] ring = new Coordinate[] { tri[0].orig().getCoordinate(),
+				tri[1].orig().getCoordinate(), tri[2].orig().getCoordinate(),
+				tri[0].orig().getCoordinate() };
+		return CGAlgorithms.isPointInRing(pt, ring);
+	}
+
+	public static Geometry toPolygon(Vertex[] v) {
+		Coordinate[] ringPts = new Coordinate[] { v[0].getCoordinate(),
+				v[1].getCoordinate(), v[2].getCoordinate(), v[0].getCoordinate() };
+		GeometryFactory fact = new GeometryFactory();
+		LinearRing ring = fact.createLinearRing(ringPts);
+		Polygon tri = fact.createPolygon(ring, null);
+		return tri;
+	}
+
+	public static Geometry toPolygon(QuadEdge[] e) {
+		Coordinate[] ringPts = new Coordinate[] { e[0].orig().getCoordinate(),
+				e[1].orig().getCoordinate(), e[2].orig().getCoordinate(),
+				e[0].orig().getCoordinate() };
+		GeometryFactory fact = new GeometryFactory();
+		LinearRing ring = fact.createLinearRing(ringPts);
+		Polygon tri = fact.createPolygon(ring, null);
+		return tri;
+	}
+
+	/**
+	 * Finds the next index around the triangle. Index may be an edge or vertex
+	 * index.
+	 * 
+	 * @param index
+	 * @return
+	 */
+	public static int nextIndex(int index) {
+		return index = (index + 1) % 3;
+	}
+
+	private QuadEdge[] edge;
+	private Object data;
+
+	/**
+	 * Creates a new triangle from the given edges.
+	 * 
+	 * @param edge an array of the edges of the triangle in CCW order
+	 */
+	public QuadEdgeTriangle(QuadEdge[] edge) {
+		this.edge = (QuadEdge[]) edge.clone();
+		// link the quadedges back to this triangle
+    for (int i = 0; i < 3; i++) {
+      edge[i].setData(this);
     }
+	}
+
+  /**
+   * Sets the external data value for this triangle.
+   * 
+   * @param data an object containing external data
+   */
+  public void setData(Object data) {
+      this.data = data;
+  }
+  
+  /**
+   * Gets the external data value for this triangle.
+   * 
+   * @return the data object
+   */
+  public Object getData() {
+      return data;
+  }
+
+	public void kill() {
+		edge = null;
+	}
+
+	public boolean isLive() {
+		return edge != null;
+	}
+
+	public QuadEdge[] getEdges() {
+		return edge;
+	}
+
+	public QuadEdge getEdge(int i) {
+		return edge[i];
+	}
+
+	public Vertex getVertex(int i) {
+		return edge[i].orig();
+	}
+
+	/**
+	 * Gets the vertices for this triangle.
+	 * 
+	 * @return a new array containing the triangle vertices
+	 */
+	public Vertex[] getVertices() {
+		Vertex[] vert = new Vertex[3];
+		for (int i = 0; i < 3; i++) {
+			vert[i] = getVertex(i);
+		}
+		return vert;
+	}
+
+	public Coordinate getCoordinate(int i) {
+		return edge[i].orig().getCoordinate();
+	}
+
+	/**
+	 * Gets the index for the given edge of this triangle
+	 * 
+	 * @param e
+	 *          a QuadEdge
+	 * @return the index of the edge in this triangle
+	 * @return -1 if the edge is not an edge of this triangle
+	 */
+	public int getEdgeIndex(QuadEdge e) {
+		for (int i = 0; i < 3; i++) {
+			if (edge[i] == e)
+				return i;
+		}
+		return -1;
+	}
+
+	/**
+	 * Gets the index for the edge that starts at vertex v.
+	 * 
+	 * @param v
+	 *          the vertex to find the edge for
+	 * @return the index of the edge starting at the vertex
+	 * @return -1 if the vertex is not in the triangle
+	 */
+	public int getEdgeIndex(Vertex v) {
+		for (int i = 0; i < 3; i++) {
+			if (edge[i].orig() == v)
+				return i;
+		}
+		return -1;
+	}
+
+	public void getEdgeSegment(int i, LineSegment seg) {
+		seg.p0 = edge[i].orig().getCoordinate();
+		int nexti = (i + 1) % 3;
+		seg.p1 = edge[nexti].orig().getCoordinate();
+	}
+
+	public Coordinate[] getCoordinates() {
+		Coordinate[] pts = new Coordinate[4];
+		for (int i = 0; i < 3; i++) {
+			pts[i] = edge[i].orig().getCoordinate();
+		}
+		pts[3] = new Coordinate(pts[0]);
+		return pts;
+	}
+
+	public boolean contains(Coordinate pt) {
+		Coordinate[] ring = getCoordinates();
+		return CGAlgorithms.isPointInRing(pt, ring);
+	}
+
+	public Polygon getGeometry(GeometryFactory fact) {
+		LinearRing ring = fact.createLinearRing(getCoordinates());
+		Polygon tri = fact.createPolygon(ring, null);
+		return tri;
+	}
+
+	public String toString() {
+		return getGeometry(new GeometryFactory()).toString();
+	}
+
+	/**
+	 * Tests whether this triangle is adjacent to the outside of the subdivision.
+	 * 
+	 * @return true if the triangle is adjacent to the subdivision exterior
+	 */
+	public boolean isBorder() {
+		for (int i = 0; i < 3; i++) {
+			if (getAdjacentTriangleAcrossEdge(i) == null)
+				return true;
+		}
+		return false;
+	}
+
+	public boolean isBorder(int i) {
+		return getAdjacentTriangleAcrossEdge(i) == null;
+	}
+
+	public QuadEdgeTriangle getAdjacentTriangleAcrossEdge(int edgeIndex) {
+		return (QuadEdgeTriangle) getEdge(edgeIndex).sym().getData();
+	}
+
+	public int getAdjacentTriangleEdgeIndex(int i) {
+		return getAdjacentTriangleAcrossEdge(i).getEdgeIndex(getEdge(i).sym());
+	}
+
+	/**
+	 * Gets the triangles which are adjacent (include) to a 
+	 * given vertex of this triangle.
+	 * 
+	 * @param vertexIndex the vertex to query
+	 * @return a list of the vertex-adjacent triangles
+	 */
+	public List getTrianglesAdjacentToVertex(int vertexIndex) {
+		// Assert: isVertex
+		List adjTris = new ArrayList();
+
+		QuadEdge start = getEdge(vertexIndex);
+		QuadEdge qe = start;
+		do {
+			QuadEdgeTriangle adjTri = (QuadEdgeTriangle) qe.getData();
+			if (adjTri != null) {
+				adjTris.add(adjTri);
+			}
+			qe = qe.oNext();
+		} while (qe != start);
+
+		return adjTris;
+
+	}
+
+	/**
+	 * Gets the neighbours of this triangle. If there is no neighbour triangle,
+	 * the array element is <code>null</code>
+	 * 
+	 * @return an array containing the 3 neighbours of this triangle
+	 */
+	public QuadEdgeTriangle[] getNeighbours() {
+		QuadEdgeTriangle[] neigh = new QuadEdgeTriangle[3];
+		for (int i = 0; i < 3; i++) {
+			neigh[i] = (QuadEdgeTriangle) getEdge(i).sym().getData();
+		}
+		return neigh;
+	}
+
+	private static class QuadEdgeTriangleBuilderVisitor implements TriangleVisitor {
+		private List triangles = new ArrayList();
+
+		public QuadEdgeTriangleBuilderVisitor() {
+		}
+
+		public void visit(QuadEdge[] edges) {
+			triangles.add(new QuadEdgeTriangle(edges));
+		}
+
+		public List getTriangles() {
+			return triangles;
+		}
+	}
+}
 
-    public boolean contains(Coordinate pt) {
-        Coordinate[] ring = getCoordinates();
-        return CGAlgorithms.isPointInRing(pt, ring);
-    }
-
-    public Geometry getGeometry(GeometryFactory fact) {
-        LinearRing ring = fact.createLinearRing(getCoordinates());
-        Polygon tri = fact.createPolygon(ring, null);
-        return tri;
-    }
-
-    public String toString() {
-        return getGeometry(new GeometryFactory()).toString();
-    }
-
-    /**
-     * Tests whether this triangle is adjacent to the outside of the subdivision.
-     * 
-     * @return true if the triangle is adjacent to the subdivision exterior
-     */
-    public boolean isBorder() {
-        for (int i = 0; i < 3; i++) {
-            if (getAdjacentTriangleAcrossEdge(i) == null)
-                return true;
-        }
-        return false;
-    }
-
-    public boolean isBorder(int i) {
-        return getAdjacentTriangleAcrossEdge(i) == null;
-    }
-
-    public QuadEdgeTriangle getAdjacentTriangleAcrossEdge(int edgeIndex) {
-        return (QuadEdgeTriangle) getEdge(edgeIndex).sym().getData();
-    }
-
-    public int getAdjacentTriangleEdgeIndex(int i) {
-        return getAdjacentTriangleAcrossEdge(i).getEdgeIndex(getEdge(i).sym());
-    }
-
-    public List getTrianglesAdjacentToVertex(int vertexIndex) {
-        // Assert: isVertex
-        List adjTris = new ArrayList();
-
-        QuadEdge start = getEdge(vertexIndex);
-        QuadEdge qe = start;
-        do {
-            QuadEdgeTriangle adjTri = (QuadEdgeTriangle) qe.getData();
-            if (adjTri != null) {
-                adjTris.add(adjTri);
-            }
-            qe = qe.oNext();
-        } while (qe != start);
-
-        return adjTris;
-
-    }
-
-    /**
-     * Gets the neighbours of this triangle. If there is no neighbour triangle, the array element is
-     * <code>null</code>
-     * 
-     * @return an array containing the 3 neighbours of this triangle
-     */
-    public QuadEdgeTriangle[] getNeighbours() {
-        QuadEdgeTriangle[] neigh = new QuadEdgeTriangle[3];
-        for (int i = 0; i < 3; i++) {
-            neigh[i] = (QuadEdgeTriangle) getEdge(i).sym().getData();
-        }
-        return neigh;
-    }
 
-}
\ No newline at end of file
diff --git a/src/com/vividsolutions/jts/triangulate/quadedge/TrianglePredicate.java b/src/com/vividsolutions/jts/triangulate/quadedge/TrianglePredicate.java
new file mode 100644
index 0000000..1f49663
--- /dev/null
+++ b/src/com/vividsolutions/jts/triangulate/quadedge/TrianglePredicate.java
@@ -0,0 +1,302 @@
+package com.vividsolutions.jts.triangulate.quadedge;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Triangle;
+import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
+import com.vividsolutions.jts.io.WKTWriter;
+import com.vividsolutions.jts.math.DD;
+
+/**
+ * Algorithms for computing values and predicates
+ * associated with triangles.
+ * For some algorithms extended-precision
+ * implementations are provided, which are more robust
+ * (i.e. they produce correct answers in more cases).
+ * Also, some more robust formulations of
+ * some algorithms are provided, which utilize
+ * normalization to the origin.
+ * 
+ * @author Martin Davis
+ *
+ */
+public class TrianglePredicate 
+{
+  /**
+   * Tests if a point is inside the circle defined by 
+   * the triangle with vertices a, b, c (oriented counter-clockwise). 
+   * This test uses simple
+   * double-precision arithmetic, and thus may not be robust.
+   * 
+   * @param a a vertex of the triangle
+   * @param b a vertex of the triangle
+   * @param c a vertex of the triangle
+   * @param P the point to test
+   * @return true if this point is inside the circle defined by the points a, b, c
+   */
+  public static boolean isInCircleNonRobust(
+      Coordinate a, Coordinate b, Coordinate c, 
+      Coordinate p) {
+    boolean isInCircle = 
+              (a.x * a.x + a.y * a.y) * triArea(b, c, p)
+            - (b.x * b.x + b.y * b.y) * triArea(a, c, p)
+            + (c.x * c.x + c.y * c.y) * triArea(a, b, p)
+            - (p.x * p.x + p.y * p.y) * triArea(a, b, c) 
+            > 0;
+    return isInCircle;
+  }
+  
+  /**
+   * Tests if a point is inside the circle defined by 
+   * the triangle with vertices a, b, c (oriented counter-clockwise). 
+   * This test uses simple
+   * double-precision arithmetic, and thus is not 10% robust.
+   * However, by using normalization to the origin
+   * it provides improved robustness and increased performance.
+   * <p>
+   * Based on code by J.R.Shewchuk.
+   * 
+   * 
+   * @param a a vertex of the triangle
+   * @param b a vertex of the triangle
+   * @param c a vertex of the triangle
+   * @param P the point to test
+   * @return true if this point is inside the circle defined by the points a, b, c
+   */
+  public static boolean isInCircleNormalized(
+      Coordinate a, Coordinate b, Coordinate c, 
+      Coordinate p) {
+    double adx = a.x - p.x;
+    double ady = a.y - p.y;
+    double bdx = b.x - p.x;
+    double bdy = b.y - p.y;
+    double cdx = c.x - p.x;
+    double cdy = c.y - p.y;
+
+    double abdet = adx * bdy - bdx * ady;
+    double bcdet = bdx * cdy - cdx * bdy;
+    double cadet = cdx * ady - adx * cdy;
+    double alift = adx * adx + ady * ady;
+    double blift = bdx * bdx + bdy * bdy;
+    double clift = cdx * cdx + cdy * cdy;
+
+    double disc = alift * bcdet + blift * cadet + clift * abdet;
+    return disc > 0;
+  }
+  
+  /**
+   * Computes twice the area of the oriented triangle (a, b, c), i.e., the area is positive if the
+   * triangle is oriented counterclockwise.
+   * 
+   * @param a a vertex of the triangle
+   * @param b a vertex of the triangle
+   * @param c a vertex of the triangle
+   */
+  private static double triArea(Coordinate a, Coordinate b, Coordinate c) {
+      return (b.x - a.x) * (c.y - a.y) 
+           - (b.y - a.y) * (c.x - a.x);
+  }
+
+  /**
+   * Tests if a point is inside the circle defined by 
+   * the triangle with vertices a, b, c (oriented counter-clockwise). 
+   * This method uses more robust computation.
+   * 
+   * @param a a vertex of the triangle
+   * @param b a vertex of the triangle
+   * @param c a vertex of the triangle
+   * @param P the point to test
+   * @return true if this point is inside the circle defined by the points a, b, c
+   */
+  public static boolean isInCircleRobust(
+      Coordinate a, Coordinate b, Coordinate c, 
+      Coordinate p) 
+  {
+    //checkRobustInCircle(a, b, c, p);
+//    return isInCircleNonRobust(a, b, c, p);       
+    return isInCircleNormalized(a, b, c, p);       
+  }
+
+  /**
+   * Tests if a point is inside the circle defined by 
+   * the triangle with vertices a, b, c (oriented counter-clockwise). 
+   * The computation uses {@link DD} arithmetic for robustness.
+   * 
+   * @param a a vertex of the triangle
+   * @param b a vertex of the triangle
+   * @param c a vertex of the triangle
+   * @param P the point to test
+   * @return true if this point is inside the circle defined by the points a, b, c
+   */
+  public static boolean isInCircleDDSlow(
+      Coordinate a, Coordinate b, Coordinate c,
+      Coordinate p) {
+    DD px = DD.valueOf(p.x);
+    DD py = DD.valueOf(p.y);
+    DD ax = DD.valueOf(a.x);
+    DD ay = DD.valueOf(a.y);
+    DD bx = DD.valueOf(b.x);
+    DD by = DD.valueOf(b.y);
+    DD cx = DD.valueOf(c.x);
+    DD cy = DD.valueOf(c.y);
+
+    DD aTerm = (ax.multiply(ax).add(ay.multiply(ay)))
+        .multiply(triAreaDDSlow(bx, by, cx, cy, px, py));
+    DD bTerm = (bx.multiply(bx).add(by.multiply(by)))
+        .multiply(triAreaDDSlow(ax, ay, cx, cy, px, py));
+    DD cTerm = (cx.multiply(cx).add(cy.multiply(cy)))
+        .multiply(triAreaDDSlow(ax, ay, bx, by, px, py));
+    DD pTerm = (px.multiply(px).add(py.multiply(py)))
+        .multiply(triAreaDDSlow(ax, ay, bx, by, cx, cy));
+
+    DD sum = aTerm.subtract(bTerm).add(cTerm).subtract(pTerm);
+    boolean isInCircle = sum.doubleValue() > 0;
+
+    return isInCircle;
+  }
+
+  /**
+   * Computes twice the area of the oriented triangle (a, b, c), i.e., the area
+   * is positive if the triangle is oriented counterclockwise.
+   * The computation uses {@link DD} arithmetic for robustness.
+   * 
+   * @param ax the x ordinate of a vertex of the triangle
+   * @param ay the y ordinate of a vertex of the triangle
+   * @param bx the x ordinate of a vertex of the triangle
+   * @param by the y ordinate of a vertex of the triangle
+   * @param cx the x ordinate of a vertex of the triangle
+   * @param cy the y ordinate of a vertex of the triangle
+   */
+  public static DD triAreaDDSlow(DD ax, DD ay,
+      DD bx, DD by, DD cx, DD cy) {
+    return (bx.subtract(ax).multiply(cy.subtract(ay)).subtract(by.subtract(ay)
+        .multiply(cx.subtract(ax))));
+  }
+
+  public static boolean isInCircleDDFast(
+      Coordinate a, Coordinate b, Coordinate c,
+      Coordinate p) {
+    DD aTerm = (DD.sqr(a.x).selfAdd(DD.sqr(a.y)))
+        .selfMultiply(triAreaDDFast(b, c, p));
+    DD bTerm = (DD.sqr(b.x).selfAdd(DD.sqr(b.y)))
+        .selfMultiply(triAreaDDFast(a, c, p));
+    DD cTerm = (DD.sqr(c.x).selfAdd(DD.sqr(c.y)))
+        .selfMultiply(triAreaDDFast(a, b, p));
+    DD pTerm = (DD.sqr(p.x).selfAdd(DD.sqr(p.y)))
+        .selfMultiply(triAreaDDFast(a, b, c));
+
+    DD sum = aTerm.selfSubtract(bTerm).selfAdd(cTerm).selfSubtract(pTerm);
+    boolean isInCircle = sum.doubleValue() > 0;
+
+    return isInCircle;
+  }
+
+  public static DD triAreaDDFast(
+      Coordinate a, Coordinate b, Coordinate c) {
+    
+    DD t1 = DD.valueOf(b.x).selfSubtract(a.x)
+          .selfMultiply(
+              DD.valueOf(c.y).selfSubtract(a.y));
+    
+    DD t2 = DD.valueOf(b.y).selfSubtract(a.y)
+          .selfMultiply(
+              DD.valueOf(c.x).selfSubtract(a.x));
+    
+    return t1.selfSubtract(t2);
+  }
+
+  public static boolean isInCircleDDNormalized(
+      Coordinate a, Coordinate b, Coordinate c,
+      Coordinate p) {
+    DD adx = DD.valueOf(a.x).selfSubtract(p.x);
+    DD ady = DD.valueOf(a.y).selfSubtract(p.y);
+    DD bdx = DD.valueOf(b.x).selfSubtract(p.x);
+    DD bdy = DD.valueOf(b.y).selfSubtract(p.y);
+    DD cdx = DD.valueOf(c.x).selfSubtract(p.x);
+    DD cdy = DD.valueOf(c.y).selfSubtract(p.y);
+
+    DD abdet = adx.multiply(bdy).selfSubtract(bdx.multiply(ady));
+    DD bcdet = bdx.multiply(cdy).selfSubtract(cdx.multiply(bdy));
+    DD cadet = cdx.multiply(ady).selfSubtract(adx.multiply(cdy));
+    DD alift = adx.multiply(adx).selfAdd(ady.multiply(ady));
+    DD blift = bdx.multiply(bdx).selfAdd(bdy.multiply(bdy));
+    DD clift = cdx.multiply(cdx).selfAdd(cdy.multiply(cdy));
+
+    DD sum = alift.selfMultiply(bcdet)
+    .selfAdd(blift.selfMultiply(cadet))
+    .selfAdd(clift.selfMultiply(abdet));
+    
+    boolean isInCircle = sum.doubleValue() > 0;
+
+    return isInCircle;
+  }
+
+  /**
+   * Computes the inCircle test using distance from the circumcentre. 
+   * Uses standard double-precision arithmetic.
+   * <p>
+   * In general this doesn't
+   * appear to be any more robust than the standard calculation. However, there
+   * is at least one case where the test point is far enough from the
+   * circumcircle that this test gives the correct answer. 
+   * <pre>
+   * LINESTRING
+   * (1507029.9878 518325.7547, 1507022.1120341457 518332.8225183258,
+   * 1507029.9833 518325.7458, 1507029.9896965567 518325.744909031)
+   * </pre>
+   * 
+   * @param a a vertex of the triangle
+   * @param b a vertex of the triangle
+   * @param c a vertex of the triangle
+   * @param p the point to test
+   * @return true if this point is inside the circle defined by the points a, b, c
+   */
+  public static boolean isInCircleCC(Coordinate a, Coordinate b, Coordinate c,
+      Coordinate p) {
+    Coordinate cc = Triangle.circumcentre(a, b, c);
+    double ccRadius = a.distance(cc);
+    double pRadiusDiff = p.distance(cc) - ccRadius;
+    return pRadiusDiff <= 0;
+  }
+  
+  /**
+   * Checks if the computed value for isInCircle is correct, using
+   * double-double precision arithmetic.
+   * 
+   * @param a a vertex of the triangle
+   * @param b a vertex of the triangle
+   * @param c a vertex of the triangle
+   * @param p the point to test
+   */
+private static void checkRobustInCircle(Coordinate a, Coordinate b, Coordinate c,
+    Coordinate p) 
+{
+  boolean nonRobustInCircle = isInCircleNonRobust(a, b, c, p);
+  boolean isInCircleDD = TrianglePredicate.isInCircleDDSlow(a, b, c, p);
+  boolean isInCircleCC = TrianglePredicate.isInCircleCC(a, b, c, p);
+
+  Coordinate circumCentre = Triangle.circumcentre(a, b, c);
+  System.out.println("p radius diff a = "
+      + Math.abs(p.distance(circumCentre) - a.distance(circumCentre))
+      / a.distance(circumCentre));
+
+  if (nonRobustInCircle != isInCircleDD || nonRobustInCircle != isInCircleCC) {
+    System.out.println("inCircle robustness failure (double result = "
+        + nonRobustInCircle 
+        + ", DD result = " + isInCircleDD
+        + ", CC result = " + isInCircleCC + ")");
+    System.out.println(WKTWriter.toLineString(new CoordinateArraySequence(
+        new Coordinate[] { a, b, c, p })));
+    System.out.println("Circumcentre = " + WKTWriter.toPoint(circumCentre)
+        + " radius = " + a.distance(circumCentre));
+    System.out.println("p radius diff a = "
+        + Math.abs(p.distance(circumCentre)/a.distance(circumCentre) - 1));
+    System.out.println("p radius diff b = "
+        + Math.abs(p.distance(circumCentre)/b.distance(circumCentre) - 1));
+    System.out.println("p radius diff c = "
+        + Math.abs(p.distance(circumCentre)/c.distance(circumCentre) - 1));
+    System.out.println();
+  }
+}
+
+
+}
diff --git a/src/com/vividsolutions/jts/triangulate/quadedge/Vertex.java b/src/com/vividsolutions/jts/triangulate/quadedge/Vertex.java
index c95c470..8796875 100644
--- a/src/com/vividsolutions/jts/triangulate/quadedge/Vertex.java
+++ b/src/com/vividsolutions/jts/triangulate/quadedge/Vertex.java
@@ -33,9 +33,12 @@
 
 package com.vividsolutions.jts.triangulate.quadedge;
 
+
 import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Triangle;
+import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
+import com.vividsolutions.jts.io.WKTWriter;
 import com.vividsolutions.jts.algorithm.*;
-import com.vividsolutions.jts.algorithm.NotRepresentableException;
 
 /**
  * Models a site (node) in a {@link QuadEdgeSubdivision}. 
@@ -183,86 +186,56 @@ public class Vertex
         return (new Vertex(p.y, -p.x));
     }
 
-    /** ************************************************************* */
-    /***********************************************************************************************
-     * Geometric primitives /
-     **********************************************************************************************/
-
-    /**
-     * Computes twice the area of the oriented triangle (a, b, c), i.e., the area is positive if the
-     * triangle is oriented counterclockwise.
-     */
-    private final double triArea(Vertex a, Vertex b, Vertex c) {
-        return (b.p.x - a.p.x) * (c.p.y - a.p.y) 
-             - (b.p.y - a.p.y) * (c.p.x - a.p.x);
-    }
-
-    /**
-     * Tests if this is inside the circle defined by the points a, b, c. This test uses simple
-     * double-precision arithmetic, and thus may not be robust.
-     * 
-     * @param a
-     * @param b
-     * @param c
-     * @return true if this point is inside the circle defined by the points a, b, c
-     */
-    public final boolean inCircle(Vertex a, Vertex b, Vertex c) {
-      Vertex d = this;
-      boolean isInCircle = 
-      	        (a.p.x * a.p.x + a.p.y * a.p.y) * triArea(b, c, d)
-              - (b.p.x * b.p.x + b.p.y * b.p.y) * triArea(a, c, d)
-              + (c.p.x * c.p.x + c.p.y * c.p.y) * triArea(a, b, d)
-              - (d.p.x * d.p.x + d.p.y * d.p.y) * triArea(a, b, c) 
-              > 0;
-      return isInCircle;
-    }
-    
-/*
-  public boolean OLDinCircle(Vertex a, Vertex b, Vertex c) {
-      Vertex d = this;
-      boolean isInCircle = (a.getX() * a.getX() + a.getY() * a.getY()) * triArea(b, c, d)
-              - (b.getX() * b.getX() + b.getY() * b.getY()) * triArea(a, c, d)
-              + (c.getX() * c.getX() + c.getY() * c.getY()) * triArea(a, b, d)
-              - (d.getX() * d.getX() + d.getY() * d.getY()) * triArea(a, b, c) 
-              > 0;
-
-      // boolean isInCircleRobust = checkRobustInCircle(a.p, b.p, c.p, p, isInCircle);
-
-      // if (! isInCircle)
-      // System.out.println(WKTWriter.toLineString(new CoordinateArraySequence(new Coordinate[] {
-      // a.p, b.p, c.p, p })));
-
-      return isInCircle;
+  /** ************************************************************* */
+  /***********************************************************************************************
+   * Geometric primitives /
+   **********************************************************************************************/
+
+  /**
+   * Tests if the vertex is inside the circle defined by 
+   * the triangle with vertices a, b, c (oriented counter-clockwise). 
+   * 
+   * @param a a vertex of the triangle
+   * @param b a vertex of the triangle
+   * @param c a vertex of the triangle
+   * @return true if this vertex is in the circumcircle of (a,b,c)
+   */
+  public boolean isInCircle(Vertex a, Vertex b, Vertex c) 
+  {
+    return TrianglePredicate.isInCircleRobust(a.p, b.p, c.p, this.p);
+    // non-robust - best to not use
+    //return TrianglePredicate.isInCircle(a.p, b.p, c.p, this.p);
   }
-*/
 
-    /**
-     * Tests whether the triangle formed by this vertex and two
-     * other vertices is in CCW orientation.
-     * 
-     * @param b a vertex
-     * @param c a vertex
-     * @returns true if the triangle is oriented CCW
-     */
-    public final boolean isCCW(Vertex b, Vertex c) 
-    {
+  /**
+   * Tests whether the triangle formed by this vertex and two
+   * other vertices is in CCW orientation.
+   * 
+   * @param b a vertex
+   * @param c a vertex
+   * @returns true if the triangle is oriented CCW
+   */
+  public final boolean isCCW(Vertex b, Vertex c) 
+  {
+      /*
+      // test code used to check for robustness of triArea 
+      boolean isCCW = (b.p.x - p.x) * (c.p.y - p.y) 
+      - (b.p.y - p.y) * (c.p.x - p.x) > 0;
+     //boolean isCCW = triArea(this, b, c) > 0;
+     boolean isCCWRobust = CGAlgorithms.orientationIndex(p, b.p, c.p) == CGAlgorithms.COUNTERCLOCKWISE; 
+     if (isCCWRobust != isCCW)
+      System.out.println("CCW failure");
+     //*/
+
     	// is equal to the signed area of the triangle
     	
       return (b.p.x - p.x) * (c.p.y - p.y) 
-      - (b.p.y - p.y) * (c.p.x - p.x) > 0;
+           - (b.p.y - p.y) * (c.p.x - p.x) > 0;
       
       // original rolled code
       //boolean isCCW = triArea(this, b, c) > 0;
       //return isCCW;
       
-        /*
-         // MD - used to check for robustness of triArea 
-        boolean isCCW = triArea(this, b, c) > 0;
-        boolean isCCWRobust = CGAlgorithms.orientationIndex(p, b.p, c.p) == CGAlgorithms.COUNTERCLOCKWISE; 
-        if (isCCWRobust != isCCW)
-        	System.out.println("CCW failure");
-        return isCCW;
-        //*/
     }
 
     public final boolean rightOf(QuadEdge e) {
@@ -405,123 +378,10 @@ public class Vertex
         return pz;
     }
 
-    // /**
-    // * Checks if the computed value for isInCircle is correct, using double-double precision
-    // * arithmetic.
-    // *
-    // * @param a
-    // * @param b
-    // * @param c
-    // * @param p
-    // * @param nonRobustInCircle
-    // * @return the robust value
-    // */
-    // private boolean checkRobustInCircle(Coordinate a, Coordinate b, Coordinate c, Coordinate p,
-    // boolean nonRobustInCircle) {
-    // // *
-    // boolean isInCircleDD = inCircleDD(a, b, c, p);
-    // boolean isInCircleCC = inCircleCC(a, b, c, p);
-    //
-    // Coordinate circumCentre = Triangle.circumcentre(a, b, c);
-    // System.out.println("p radius diff a = "
-    // + (p.distance(circumCentre) - a.distance(circumCentre)) / a.distance(circumCentre));
-    //
-    // if (nonRobustInCircle != isInCircleDD || nonRobustInCircle != isInCircleCC) {
-    // System.out.println("inCircle robustness failure (double result = " + nonRobustInCircle
-    // + ", DD result = " + isInCircleDD + ", CC result = " + isInCircleCC + ")");
-    // System.out.println(WKTWriter.toLineString(new CoordinateArraySequence(new Coordinate[]{
-    // a,
-    // b,
-    // c,
-    // p})));
-    // System.out.println("Circumcentre = " + WKTWriter.toPoint(circumCentre)
-    // + " radius = " + a.distance(circumCentre));
-    // System.out.println("p radius diff a = "
-    // + (p.distance(circumCentre) - a.distance(circumCentre)));
-    // System.out.println("p radius diff b = "
-    // + (p.distance(circumCentre) - b.distance(circumCentre)));
-    // System.out.println("p radius diff c = "
-    // + (p.distance(circumCentre) - c.distance(circumCentre)));
-    // }
-    // return isInCircleDD;
-    // }
-
-    // /**
-    // * Computes the inCircle test using the circumcentre. In general this doesn't appear to be any
-    // * more robust than the standard calculation. However, there is at least one case where the
-    // test
-    // * point is far enough from the circumcircle that this test gives the correct answer.
-    // LINESTRING
-    // * (1507029.9878 518325.7547, 1507022.1120341457 518332.8225183258, 1507029.9833 518325.7458,
-    // * 1507029.9896965567 518325.744909031)
-    // *
-    // * @param a
-    // * @param b
-    // * @param c
-    // * @param p
-    // * @return
-    // */
-    // private static boolean inCircleCC(Coordinate a, Coordinate b, Coordinate c, Coordinate p) {
-    // Coordinate cc = Triangle.circumcentre(a, b, c);
-    // double ccRadius = a.distance(cc);
-    // double pRadiusDiff = p.distance(cc) - ccRadius;
-    // return pRadiusDiff <= 0;
-    // }
-    //
-    // private static boolean inCircleDD(Coordinate a, Coordinate b, Coordinate c, Coordinate p) {
-    // DoubleDouble px = new DoubleDouble(p.x);
-    // DoubleDouble py = new DoubleDouble(p.y);
-    // DoubleDouble ax = new DoubleDouble(a.x);
-    // DoubleDouble ay = new DoubleDouble(a.y);
-    // DoubleDouble bx = new DoubleDouble(b.x);
-    // DoubleDouble by = new DoubleDouble(b.y);
-    // DoubleDouble cx = new DoubleDouble(c.x);
-    // DoubleDouble cy = new DoubleDouble(c.y);
-    //
-    // DoubleDouble aTerm = (ax.multiply(ax).add(ay.multiply(ay))).multiply(triAreaDD(
-    // bx,
-    // by,
-    // cx,
-    // cy,
-    // px,
-    // py));
-    // DoubleDouble bTerm = (bx.multiply(bx).add(by.multiply(by))).multiply(triAreaDD(
-    // ax,
-    // ay,
-    // cx,
-    // cy,
-    // px,
-    // py));
-    // DoubleDouble cTerm = (cx.multiply(cx).add(cy.multiply(cy))).multiply(triAreaDD(
-    // ax,
-    // ay,
-    // bx,
-    // by,
-    // px,
-    // py));
-    // DoubleDouble pTerm = (px.multiply(px).add(py.multiply(py))).multiply(triAreaDD(
-    // ax,
-    // ay,
-    // bx,
-    // by,
-    // cx,
-    // cy));
-    //
-    // DoubleDouble sum = aTerm.subtract(bTerm).add(cTerm).subtract(pTerm);
-    // boolean isInCircle = sum.doubleValue() > 0;
-    //
-    // return isInCircle;
-    // }
-
-    // /**
-    // * Computes twice the area of the oriented triangle (a, b, c), i.e., the area is positive if
-    // the
-    // * triangle is oriented counterclockwise.
-    // */
-    // private static DoubleDouble triAreaDD(DoubleDouble ax, DoubleDouble ay, DoubleDouble bx,
-    // DoubleDouble by, DoubleDouble cx, DoubleDouble cy) {
-    // return (bx.subtract(ax).multiply(cy.subtract(ay)).subtract(by.subtract(ay).multiply(
-    // cx.subtract(ax))));
-    // }
+
+
+
+
+
 
 }
diff --git a/src/com/vividsolutions/jts/util/GeometricShapeFactory.java b/src/com/vividsolutions/jts/util/GeometricShapeFactory.java
index 2da7c07..987d291 100644
--- a/src/com/vividsolutions/jts/util/GeometricShapeFactory.java
+++ b/src/com/vividsolutions/jts/util/GeometricShapeFactory.java
@@ -1,4 +1,3 @@
-
 /*
  * The JTS Topology Suite is a collection of Java classes that
  * implement the fundamental operations required to validate a given
@@ -33,22 +32,22 @@
  */
 package com.vividsolutions.jts.util;
 
-/**
- * Methods to create various geometry shapes
- */
 import com.vividsolutions.jts.geom.*;
+import com.vividsolutions.jts.geom.util.AffineTransformation;
 
 /**
  * Computes various kinds of common geometric shapes.
- * Allows various ways of specifying the location and extent of the shapes,
+ * Provides various ways of specifying the location and extent
+ * and rotations of the generated shapes,
  * as well as number of line segments used to form them.
  * <p>
- * Example:
+ * <b>Example of usage:</b>
  * <pre>
  *  GeometricShapeFactory gsf = new GeometricShapeFactory();
  *  gsf.setSize(100);
  *  gsf.setNumPoints(100);
- *  gsf.setBase(new Coordinate(0, 0));
+ *  gsf.setBase(new Coordinate(100, 100));
+ *  gsf.setRotation(0.5);
  *  Polygon rect = gsf.createRectangle();
  * </pre>
  *
@@ -60,6 +59,11 @@ public class GeometricShapeFactory
   protected PrecisionModel precModel = null;
   protected Dimensions dim = new Dimensions();
   protected int nPts = 100;
+  
+  /**
+   * Default is no rotation.
+   */
+  protected double rotationAngle = 0.0;
 
   /**
    * Create a shape factory which will create shapes using the default
@@ -132,6 +136,27 @@ public class GeometricShapeFactory
   public void setHeight(double height) { dim.setHeight(height); }
 
   /**
+   * Sets the rotation angle to use for the shape.
+   * The rotation is applied relative to the centre of the shape.
+   * 
+   * @param radians the rotation angle in radians.
+   */
+  public void setRotation(double radians)
+  {
+    rotationAngle = radians;
+  }
+  
+  protected Geometry rotate(Geometry geom)
+  {
+    if (rotationAngle != 0.0) {
+      AffineTransformation trans = AffineTransformation.rotationInstance(rotationAngle, 
+          dim.getCentre().x, dim.getCentre().y);
+      geom.apply(trans);
+    }
+    return geom;
+  }
+  
+  /**
    * Creates a rectangular {@link Polygon}.
    *
    * @return a rectangular Polygon
@@ -149,43 +174,56 @@ public class GeometricShapeFactory
     Coordinate[] pts = new Coordinate[4 * nSide + 1];
     Envelope env = dim.getEnvelope();
 
-    double maxx = env.getMinX() + nSide * XsegLen;
-    double maxy = env.getMinY() + nSide * XsegLen;
+    //double maxx = env.getMinX() + nSide * XsegLen;
+    //double maxy = env.getMinY() + nSide * XsegLen;
 
     for (i = 0; i < nSide; i++) {
       double x = env.getMinX() + i * XsegLen;
       double y = env.getMinY();
-      pts[ipt++] = createCoord(x, y);
+      pts[ipt++] = coord(x, y);
     }
     for (i = 0; i < nSide; i++) {
       double x = env.getMaxX();
       double y = env.getMinY() + i * YsegLen;
-      pts[ipt++] = createCoord(x, y);
+      pts[ipt++] = coord(x, y);
     }
     for (i = 0; i < nSide; i++) {
       double x = env.getMaxX() - i * XsegLen;
       double y = env.getMaxY();
-      pts[ipt++] = createCoord(x, y);
+      pts[ipt++] = coord(x, y);
     }
     for (i = 0; i < nSide; i++) {
       double x = env.getMinX();
       double y = env.getMaxY() - i * YsegLen;
-      pts[ipt++] = createCoord(x, y);
+      pts[ipt++] = coord(x, y);
     }
     pts[ipt++] = new Coordinate(pts[0]);
 
     LinearRing ring = geomFact.createLinearRing(pts);
     Polygon poly = geomFact.createPolygon(ring, null);
-    return poly;
+    return (Polygon) rotate(poly);
   }
 
+//* @deprecated use {@link createEllipse} instead
   /**
-   * Creates a circular {@link Polygon}.
+   * Creates a circular or elliptical {@link Polygon}.
    *
-   * @return a circle
+   * @return a circle or ellipse
    */
   public Polygon createCircle()
   {
+    return createEllipse();
+  }
+  
+  /**
+   * Creates an elliptical {@link Polygon}.
+   * If the supplied envelope is square the 
+   * result will be a circle. 
+   *
+   * @return an ellipse or circle
+   */
+  public Polygon createEllipse()
+  {
 
     Envelope env = dim.getEnvelope();
     double xRadius = env.getWidth() / 2.0;
@@ -200,13 +238,13 @@ public class GeometricShapeFactory
         double ang = i * (2 * Math.PI / nPts);
         double x = xRadius * Math.cos(ang) + centreX;
         double y = yRadius * Math.sin(ang) + centreY;
-        pts[iPt++] = createCoord(x, y);
+        pts[iPt++] = coord(x, y);
     }
     pts[iPt] = new Coordinate(pts[0]);
 
     LinearRing ring = geomFact.createLinearRing(pts);
     Polygon poly = geomFact.createPolygon(ring, null);
-    return poly;
+    return (Polygon) rotate(poly);
   }
   /**
    * Creates a squircular {@link Polygon}.
@@ -233,8 +271,6 @@ public class GeometricShapeFactory
   {
   	double recipPow = 1.0 / power;
   	
-    Envelope env = dim.getEnvelope();
-
     double radius = dim.getMinSize() / 2;
     Coordinate centre = dim.getCentre();
     
@@ -256,28 +292,30 @@ public class GeometricShapeFactory
     		double x4 = Math.pow(x, power);
     		y = Math.pow(r4 - x4, recipPow);
     	}
-      pts[i] = createCoordTrans(x, y, centre);
-      pts[2 * nSegsInOct - i] = createCoordTrans(y, x, centre);
+      pts[i] = coordTrans(x, y, centre);
+      pts[2 * nSegsInOct - i] = coordTrans(y, x, centre);
       
-      pts[2 * nSegsInOct + i] = createCoordTrans(y, -x, centre);
-      pts[4 * nSegsInOct - i] = createCoordTrans(x, -y, centre);
+      pts[2 * nSegsInOct + i] = coordTrans(y, -x, centre);
+      pts[4 * nSegsInOct - i] = coordTrans(x, -y, centre);
       
-      pts[4 * nSegsInOct + i] = createCoordTrans(-x, -y, centre);
-      pts[6 * nSegsInOct - i] = createCoordTrans(-y, -x, centre);
+      pts[4 * nSegsInOct + i] = coordTrans(-x, -y, centre);
+      pts[6 * nSegsInOct - i] = coordTrans(-y, -x, centre);
       
-      pts[6 * nSegsInOct + i] = createCoordTrans(-y, x, centre);
-      pts[8 * nSegsInOct - i] = createCoordTrans(-x, y, centre);
+      pts[6 * nSegsInOct + i] = coordTrans(-y, x, centre);
+      pts[8 * nSegsInOct - i] = coordTrans(-x, y, centre);
     }
     pts[pts.length-1] = new Coordinate(pts[0]);
 
     LinearRing ring = geomFact.createLinearRing(pts);
     Polygon poly = geomFact.createPolygon(ring, null);
-    return poly;
+    return (Polygon) rotate(poly);
   }
 
    /**
     * Creates an elliptical arc, as a {@link LineString}.
     * The arc is always created in a counter-clockwise direction.
+    * This can easily be reversed if required by using 
+    * {#link LineString.reverse()}
     *
     * @param startAng start angle in radians
     * @param angExtent size of angle in radians
@@ -305,10 +343,10 @@ public class GeometricShapeFactory
          double ang = startAng + i * angInc;
          double x = xRadius * Math.cos(ang) + centreX;
          double y = yRadius * Math.sin(ang) + centreY;
-         pts[iPt++] = createCoord(x, y);
+         pts[iPt++] = coord(x, y);
      }
      LineString line = geomFact.createLineString(pts);
-     return line;
+     return (LineString) rotate(line);
    }
 
   /**
@@ -338,30 +376,30 @@ public class GeometricShapeFactory
     Coordinate[] pts = new Coordinate[nPts + 2];
 
     int iPt = 0;
-    pts[iPt++] = createCoord(centreX, centreY);
+    pts[iPt++] = coord(centreX, centreY);
     for (int i = 0; i < nPts; i++) {
       double ang = startAng + angInc * i;
 
       double x = xRadius * Math.cos(ang) + centreX;
       double y = yRadius * Math.sin(ang) + centreY;
-      pts[iPt++] = createCoord(x, y);
+      pts[iPt++] = coord(x, y);
     }
-    pts[iPt++] = createCoord(centreX, centreY);
+    pts[iPt++] = coord(centreX, centreY);
     LinearRing ring = geomFact.createLinearRing(pts);
-    Polygon geom = geomFact.createPolygon(ring, null);
-    return geom;
+    Polygon poly = geomFact.createPolygon(ring, null);
+    return (Polygon) rotate(poly);
   }
 
-  protected Coordinate createCoord(double x, double y)
+  protected Coordinate coord(double x, double y)
   {
   	Coordinate pt = new Coordinate(x, y);
     precModel.makePrecise(pt);
     return pt;
   }
   
-  protected Coordinate createCoordTrans(double x, double y, Coordinate trans)
+  protected Coordinate coordTrans(double x, double y, Coordinate trans)
   {
-  	return createCoord(x + trans.x, y + trans.y);
+  	return coord(x + trans.x, y + trans.y);
   }
   
   protected class Dimensions
diff --git a/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequence.java b/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequence.java
index eb70d6d..3aa414e 100644
--- a/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequence.java
+++ b/src/com/vividsolutions/jtsexample/geom/ExtendedCoordinateSequence.java
@@ -150,7 +150,7 @@ public class ExtendedCoordinateSequence
       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();
+      case CoordinateSequence.M:  return coordinates[index].getM();
     }
     return Double.NaN;
   }
@@ -161,10 +161,18 @@ public class ExtendedCoordinateSequence
   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);
+      case CoordinateSequence.X:  
+        coordinates[index].x = value;
+        break;
+      case CoordinateSequence.Y:  
+        coordinates[index].y = value;
+        break;
+      case CoordinateSequence.Z:  
+        coordinates[index].z = value;
+        break;
+      case CoordinateSequence.M:  
+        coordinates[index].setM(value);
+        break;
     }
   }
 
diff --git a/src/com/vividsolutions/jtsexample/geom/prep/PreparedGeometryExample.java b/src/com/vividsolutions/jtsexample/geom/prep/PreparedGeometryExample.java
index fdf5cfc..35d76ae 100644
--- a/src/com/vividsolutions/jtsexample/geom/prep/PreparedGeometryExample.java
+++ b/src/com/vividsolutions/jtsexample/geom/prep/PreparedGeometryExample.java
@@ -73,10 +73,10 @@ public class PreparedGeometryExample
   		//System.out.println("Approximation to PI: " + (4.0 * inCount / (double) count));
   	}
   	double approxPi = 4.0 * inCount / (double) count;
-  	double approxDiff = 1.0 - approxPi/Math.PI;
+  	double approxDiffPct = 1.0 - approxPi/Math.PI;
   	
 		System.out.println("Approximation to PI: " + approxPi
-				+ "  (difference from actual = " + approxDiff
+				+ "  ( % difference from actual = " + 100 * approxDiffPct + " )"
 				); 
 
   }
diff --git a/src/com/vividsolutions/jtsexample/io/gml2/KMLReaderExample.java b/src/com/vividsolutions/jtsexample/io/gml2/KMLReaderExample.java
index 4a12a17..849d349 100644
--- a/src/com/vividsolutions/jtsexample/io/gml2/KMLReaderExample.java
+++ b/src/com/vividsolutions/jtsexample/io/gml2/KMLReaderExample.java
@@ -6,6 +6,7 @@ import java.util.*;
 import java.io.*;
 import org.xml.sax.*;
 import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
 
 /**
  * An example of using the {@link GMLHandler} class
@@ -38,7 +39,9 @@ class KMLReader
 	throws IOException, SAXException
 	{
     XMLReader xr; 
-    xr = new org.apache.xerces.parsers.SAXParser();
+    
+    xr = XMLReaderFactory.createXMLReader();
+    //xr = new org.apache.xerces.parsers.SAXParser();
     KMLHandler kmlHandler = new KMLHandler();
     xr.setContentHandler(kmlHandler);
     xr.setErrorHandler(kmlHandler);
diff --git a/src/com/vividsolutions/jtsexample/technique/PolygonUnionUsingBuffer.java b/src/com/vividsolutions/jtsexample/technique/PolygonUnionUsingBuffer.java
index 1af86fa..a120256 100644
--- a/src/com/vividsolutions/jtsexample/technique/PolygonUnionUsingBuffer.java
+++ b/src/com/vividsolutions/jtsexample/technique/PolygonUnionUsingBuffer.java
@@ -17,10 +17,11 @@ import com.vividsolutions.jts.io.WKTReader;
  * <li>may not preserve input coordinate precision in some cases
  * <li>only works for polygons
  * </ul>
+ * 
+ * @deprecated It is now recommended to use Geometry.union() (unary union) instead of this technique.
  *
  * @version 1.7
  */
-
 public class PolygonUnionUsingBuffer {
 
   public static void main(String[] args)
diff --git a/src/com/vividsolutions/jtsexample/technique/SearchUsingPreparedGeometryIndex.java b/src/com/vividsolutions/jtsexample/technique/SearchUsingPreparedGeometryIndex.java
new file mode 100644
index 0000000..c93502b
--- /dev/null
+++ b/src/com/vividsolutions/jtsexample/technique/SearchUsingPreparedGeometryIndex.java
@@ -0,0 +1,244 @@
+
+/*
+ * 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.technique;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import com.vividsolutions.jts.geom.*;
+import com.vividsolutions.jts.geom.prep.*;
+import com.vividsolutions.jts.index.SpatialIndex;
+import com.vividsolutions.jts.index.strtree.STRtree;
+import com.vividsolutions.jts.util.Stopwatch;
+
+
+/**
+ * Demonstrates use of {@link PreparedGeometry}s in a spatial index
+ * to optimize spatial search.
+ * 
+ * The example creates a grid of circular polygons, packed into the 1 x 1 square.
+ * This set of polygons is spatially indexed as PreparedGeometrys in an STRtree index.
+ * A series of random points in the square is generated, and the index
+ * is used to determine whether each point intersects any circles.
+ * The fraction of points which intersect will approximate the 
+ * fraction of area covered by the circles.
+ * 
+ * @version 1.12
+ */
+public class SearchUsingPreparedGeometryIndex
+{
+	static GeometryFactory geomFact = new GeometryFactory();
+	
+	static final int MAX_ITER = 200000; 
+	static final int GRID_SIZE = 10; 
+	static final int POLYGON_SIZE = 100;
+
+  public static void main(String[] args)
+      throws Exception
+  {
+  	List circleGrid = createCircleGrid(GRID_SIZE);
+  	
+  	PreparedGeometryIndex pgIndex = new PreparedGeometryIndex();
+  	pgIndex.insert(circleGrid);
+  	
+  	Stopwatch sw = new Stopwatch();
+  	int inCount = runIndexedQuery(pgIndex);
+  	String indexTime = sw.getTimeString();
+  	
+		System.out.println("Number of iterations       = " + MAX_ITER ); 
+		System.out.println("Number of circles in grid  = " + circleGrid.size() ); 
+		System.out.println();
+  	System.out.println("The fraction of intersecting points should approximate the total area of the circles:");
+  	System.out.println();
+		System.out.println("Area of circles                = " + area(circleGrid) ); 
+		System.out.println("Fraction of points in circles  = " + inCount / (double) MAX_ITER ); 
+		System.out.println(); 
+		System.out.println("Indexed Execution time: " + indexTime ); 
+		
+		/**
+		 * For comparison purposes run the same query without using an index
+		 */ 
+  	Stopwatch sw2 = new Stopwatch();
+  	int inCount2 = runBruteForceQuery(circleGrid);
+  	String bruteForceTime = sw2.getTimeString();
+  	
+		System.out.println(); 
+		System.out.println("Execution time: " + bruteForceTime ); 
+
+  }
+  
+  static int runIndexedQuery(PreparedGeometryIndex pgIndex)
+  {
+  	int inCount = 0;
+  	for (int i = 0; i < MAX_ITER; i++) 
+  	{
+  		Point randPt = createRandomPoint();
+  		if (pgIndex.intersects(randPt).size() > 0) {
+				inCount++;
+  		}
+  	}
+  	return inCount;
+  }
+  
+  static int runBruteForceQuery(Collection geoms)
+  {
+  	int inCount = 0;
+  	for (int i = 0; i < MAX_ITER; i++) 
+  	{
+  		Point randPt = createRandomPoint();
+  		if (findIntersecting(geoms, randPt).size() > 0) {
+				inCount++;
+  		}
+  	}
+  	return inCount;
+  }
+  
+  static double area(Collection geoms)
+  {
+  	double area = 0.0;
+		for (Iterator i = geoms.iterator(); i.hasNext(); ) {
+			Geometry geom = (Geometry) i.next();
+			area += geom.getArea();
+		}
+		return area;
+  }
+  
+  static List createCircleGrid(int gridSize)
+  {
+  	double diameter = 1.0 / gridSize;
+  	double radius = diameter / 2;
+  	
+  	List circles = new ArrayList();
+  	for (int i = 0; i < gridSize; i++) {
+    	for (int j = 0; j < gridSize; j++) {
+    		Coordinate centre = new Coordinate(radius + i * diameter, radius + j * diameter);
+    		Geometry circle = createCircle(centre, radius);
+    		circles.add(circle);
+    	}
+  	}
+  	return circles;
+  }
+  
+  static Geometry createCircle(Coordinate centre, double radius)
+  {
+  	Geometry centrePt = geomFact.createPoint(centre);
+  	return centrePt.buffer(radius, POLYGON_SIZE);
+  }
+
+  static Point createRandomPoint()
+  {
+  	return geomFact.createPoint(new Coordinate(Math.random(), Math.random()));
+  }
+   
+  static List findIntersecting(Collection targetGeoms, Geometry queryGeom)
+  {
+		List result = new ArrayList();
+		for (Iterator it = targetGeoms.iterator(); it.hasNext(); ) {
+			Geometry test = (Geometry) it.next();
+			if (test.intersects(queryGeom)) {
+				result.add(test);
+			}
+		}
+  	return result;
+  }
+}
+
+/**
+ * A spatial index which indexes {@link PreparedGeometry}s 
+ * created from a set of {@link Geometry}s.
+ * This can be used for efficient testing
+ * for intersection with a series of target geomtries. 
+ *  
+ * @author Martin Davis
+ *
+ */
+class PreparedGeometryIndex
+{
+	private SpatialIndex index = new STRtree();
+	
+	/**
+	 * Creates a new index
+	 *
+	 */
+	public PreparedGeometryIndex()
+	{
+		
+	}
+	
+	/**
+	 * Inserts a collection of Geometrys into the index.
+	 * 
+	 * @param geoms a collection of Geometrys to insert
+	 */
+	public void insert(Collection geoms)
+	{
+		for (Iterator i = geoms.iterator(); i.hasNext(); ) {
+			Geometry geom = (Geometry) i.next();
+			index.insert(geom.getEnvelopeInternal(), PreparedGeometryFactory.prepare(geom));
+		}
+	}
+	
+	/**
+	 * Finds all {@link PreparedGeometry}s which might 
+	 * interact with a query {@link Geometry}.
+	 * 
+	 * @param g the geometry to query by
+	 * @return a list of candidate PreparedGeometrys
+	 */
+	public List query(Geometry g)
+	{
+		return index.query(g.getEnvelopeInternal());
+	}
+	
+	/**
+	 * Finds all {@link PreparedGeometry}s which intersect a given {@link Geometry}
+	 * 
+	 * @param g the geometry to query by
+	 * @return a list of intersecting PreparedGeometrys 
+	 */
+	public List intersects(Geometry g)
+	{
+		List result = new ArrayList();
+		List candidates = query(g);
+		for (Iterator it = candidates.iterator(); it.hasNext(); ) {
+			PreparedGeometry prepGeom = (PreparedGeometry) it.next();
+			if (prepGeom.intersects(g)) {
+				result.add(prepGeom);
+			}
+		}
+		return result;
+	}
+}
diff --git a/testxml/external/geos-bug356-buffer.xml b/testxml/external/geos-bug356-buffer.xml
new file mode 100644
index 0000000..8a74494
--- /dev/null
+++ b/testxml/external/geos-bug356-buffer.xml
@@ -0,0 +1,25 @@
+<run>
+  <desc>
+http://trac.osgeo.org/geos/ticket/356
+  </desc>
+  <precisionModel type="FLOATING" />
+  <resultMatcher>com.vividsolutions.jtstest.testrunner.BufferResultMatcher</resultMatcher>
+
+<case>
+  <desc>
+http://trac.osgeo.org/geos/ticket/356
+multilinestring buffer artifacts
+  </desc>
+  <a>
+MULTILINESTRING((1676339.95971128 4847443.67952346, 1676340.19 4847443.54, 1676338.44 4847440.65, 1676335.37 4847442.52, 1676337.12 4847445.4, 1676339.95971128 4847443.67952346))
+  </a>
+<test>
+  <op name='buffer' arg1='A' arg2='1.0' arg3='8'>
+POLYGON ((1676334.370908338 4847442.47738721, 1676334.381771572 4847442.672985536, 1676334.430559768 4847442.86271278, 1676334.515400594 4847443.039287834, 1676336.265400594 4847445.919287834, 1676336.383019845 4847446.075914382, 1676336.528914198 4847446.206608688, 1676336.697486246 4847446.306356514, 1676336.882268526 4847446.371330916, 1676337.07617165 4847446.399039078, 1676337.2717563 4847446.388417942, 1676337.461518643 4847446.339875002, 1676337.638178226 4847446.255272662, 167634 [...]
+(1676338.816753609 4847443.202781668, 1676337.455985112 4847444.027221212, 1676336.743325995 4847442.854387922, 1676338.10393518 4847442.025612946, 1676338.816753609 4847443.202781668))
+  </op>
+</test>
+</case>
+
+
+</run>
diff --git a/testxml/failure/TestBufferFailure.xml b/testxml/failure/TestBufferFailure.xml
new file mode 100644
index 0000000..d9e2cc5
--- /dev/null
+++ b/testxml/failure/TestBufferFailure.xml
@@ -0,0 +1,47 @@
+<run>
+  <desc>
+    Various cases which have been reported or identified as causing buffer failures.
+  </desc>
+  <precisionModel type="FLOATING" />
+  <resultMatcher>com.vividsolutions.jtstest.testrunner.BufferResultMatcher</resultMatcher>
+
+<case>
+  <desc>
+  	Discovered on Feb 25, 2011.  An incorrect hole is generated
+  	Result provided is correct output.
+  	The test works correctly for slightly smaller (0.7) and larger (1.1) distance values.
+  </desc>
+  <a>
+POLYGON ((1676334.370908338 4847442.47738721, 1676334.381771572 4847442.672985536, 1676334.430559768 4847442.86271278, 1676334.515400594 4847443.039287834, 1676336.265400594 4847445.919287834, 
+  1676336.383019845 4847446.075914382, 1676336.528914198 4847446.206608688, 1676336.697486246 4847446.306356514, 1676336.882268526 4847446.371330916, 1676337.07617165 4847446.399039078, 
+  1676337.2717563 4847446.388417942, 1676337.461518643 4847446.339875002, 1676337.638178226 4847446.255272662, 1676340.477889498 4847444.534796128, 1676340.477889507 4847444.534796122, 
+  1676340.708178227 4847444.395272662, 1676340.865054944 4847444.277767458, 1676340.995997551 4847444.13191887, 1676341.095975523 4847443.963330074, 1676341.16114793 4847443.778477878, 
+  1676341.189010992 4847443.584463894, 1676341.178494273 4847443.388741704, 1676341.130001801 4847443.19883052, 1676341.04539655 4847443.022026312, 1676339.29539655 4847440.132026312, 
+  1676339.177687757 4847439.974857962, 1676339.031535752 4847439.843721232, 1676338.862575756 4847439.743672394, 1676338.6773224 4847439.678569058, 1676338.482918545 4847439.650921426, 
+  1676338.286859869 4847439.661795518, 1676338.096705855 4847439.710772058, 1676337.91978832 4847439.795962644, 1676334.84978832 4847441.665962642, 1676334.693269131 4847441.783769514, 
+  1676334.56272065 4847441.92983049, 1676334.463152898 4847442.098540236, 1676334.398386959 4847442.283424222, 1676334.370908338 4847442.47738721), 
+  (1676338.816753609 4847443.202781668, 1676337.455985112 4847444.027221212, 1676336.743325995 4847442.854387922, 1676338.10393518 4847442.025612946, 1676338.816753609 4847443.202781668))
+  </a>
+<test>
+  <op name='buffer' arg1='A' arg2='1.0'>
+POLYGON ((1676333.3807948758 4847442.337118426, 1676333.3724470409 4847442.532840234, 1676333.3833102747 4847442.72843856, 1676333.4132801052 4847442.922032276, 1676333.4620683014 4847443.11175952, 
+  1676333.5292056508 4847443.29579563, 1676333.6140464768 4847443.472370684, 1676333.6608011876 4847443.558575668, 1676335.4108011876 4847446.438575668, 1676335.4657667114 4847446.51977568, 
+  1676335.5833859623 4847446.676402228, 1676335.715779222 4847446.820756614, 1676335.8616735751 4847446.951450921, 1676336.0196662978 4847447.067228568, 1676336.1882383458 4847447.166976393, 
+  1676336.3657689604 4847447.249735357, 1676336.5505512403 4847447.314709759, 1676336.7408085682 4847447.361274894, 1676336.9347116924 4847447.388983056, 1676337.1303962986 4847447.397567839, 
+  1676337.3259809485 4847447.386946704, 1676337.519585165 4847447.357221768, 1676337.709347508 4847447.308678828, 1676337.893443487 4847447.241784604, 1676338.07010307 4847447.157182264, 
+  1676338.156356451 4847447.110545325, 1676340.996067723 4847445.390068791, 1676341.2263564568 4847445.250545322, 1676341.307680706 4847445.195645561, 1676341.464557423 4847445.0781403575, 
+  1676341.6091631844 4847444.945826532, 1676341.7401057913 4847444.799977944, 1676341.856124575 4847444.641998768, 1676341.9561025472 4847444.473409972, 1676342.0390771602 4847444.295834664, 
+  1676342.104249567 4847444.110982468, 1676342.1509923122 4847443.920633071, 1676342.1788553742 4847443.726619087, 1676342.1875704988 4847443.530808406, 1676342.1770537798 4847443.335086215, 
+  1676342.147406468 4847443.141336856, 1676342.098913996 4847442.9514256725, 1676342.0320432307 4847442.767181057, 1676341.9474379797 4847442.590376848, 1676341.9007930998 4847442.504052622, 
+  1676340.1507930998 4847439.614052623, 1676340.0958057414 4847439.532572288, 1676339.9780969482 4847439.375403938, 1676339.8455260543 4847439.230551568, 1676339.6993740492 4847439.0994148385, 
+  1676339.5410531552 4847438.983260881, 1676339.3720931592 4847438.883212043, 1676339.1941266607 4847438.800235063, 1676339.0088733048 4847438.735131727, 1676338.8181231327 4847438.688531103, 
+  1676338.6237192776 4847438.66088347, 1676338.4275401966 4847438.652455984, 1676338.2314815207 4847438.663330076, 1676338.03743769 4847438.693400673, 1676337.847283676 4847438.742377212, 
+  1676337.6628568775 4847438.809786451, 1676337.4859393425 4847438.894977037, 1676337.3995766402 4847438.941925286, 1676334.3295766402 4847440.811925285, 1676334.2484252925 4847440.866986729, 
+  1676334.0919061035 4847440.984793602, 1676333.9476787418 4847441.1173650045, 1676333.8171302609 4847441.26342598, 1676333.701516191 4847441.421571815, 1676333.601948439 4847441.590281562, 
+  1676333.519384575 4847441.767932686, 1676333.454618636 4847441.952816672, 1676333.4082734967 4847442.143155438, 1676333.3807948758 4847442.337118426))
+  </op>
+</test>
+</case>
+
+
+</run>
diff --git a/testxml/failure/TestOverlay.xml b/testxml/failure/TestOverlay.xml
index 8a89c4d..4a1ab5c 100644
--- a/testxml/failure/TestOverlay.xml
+++ b/testxml/failure/TestOverlay.xml
@@ -109,4 +109,90 @@ POLYGON EMPTY
 	</op>
 </test>
 </case>
+
+
+<case>
+  <desc>
+    http://lists.osgeo.org/pipermail/geos-devel/2010-September/004949.html
+    
+    Fails because B is invalid
+  </desc>
+<a>
+
+0106000000010000000103000000010000009F0100009031772D4C6639418E06F0763C7352417524970F63663941411361A736735241075F980C76663941DF718AFA31735241F4FDD4D88466394135EF38B12E735241083D9B358E663941B7F3FDAC2C7352417E8CB9EB9B66394183E2C7C029735241DE9387E59B663941D9F0F4BE297352410BB5A6E99B6639415DFE43BE2973524103098AEF9B663941D9CEF7BF29735241AA825129B166394187A7572A257352416BBC7423B1663941797AA52825735241E4141D29B1663941C6FEB22725735241B5C8762EB1663941C74B372925735241E561A1C6C0663941850D4FBB21735241 [...]
+</a>
+
+<b>
+010600000005000000010300000001000000A900000086EB51F8B265394115AE47A99472524186EB51F8BD65394115AE47C99372524186EB51F8DF65394115AE47798072524186EB5178DF65394115AE47497E72524186EB5178DF65394115AE47697D72524186EB5138DE65394115AE47A97C72524186EB51B8DB65394115AE47497B72524186EB5178D965394115AE47797972524186EB51B8D865394115AE47197772524186EB51B8D865394115AE47A972725241ACCFD506D9653941D44D62106D7252418B1F63CED66539411383C0D66B7252412D651902D16539410D71AC3769725241F56C56CDC565394168B3EAFB64725241 [...]
+</b>
+<test>
+	<op name="difference" arg1="A" arg2="B">
+POLYGON EMPTY
+	</op>
+</test>
+</case>
+
+<case>
+  <desc>A.union(B) fails, but B.union(A) works!
+    
+    Lowering the precision slightly works.
+    
+    Possibly due to ordering issues in RobustDeterminant?
+    Or due to robustness issue with ordering points along line segments?
+    
+http://sourceforge.net/mailarchive/forum.php?thread_name=4DD83610.70607%40telus.net&forum_name=jts-topo-suite-user    
+  </desc>
+<a>
+
+POLYGON ((-73.16540347748551 -94.50735621934908, -74 -95, -76.23310243744803 -100.58620689655172, -76.23310243744801 -100.5862068965517, -76.23310243744801 -100.58620689655172, 100 -30, 30 90, -73.16540347748551 -94.50735621934908))</a>
+
+<b>
+POLYGON ((-76.23310243744803 -100.58620689655172, 70 -7, -100 -90, -76.23310243744803 -100.58620689655172))</b>
+<test>
+	<op name="union" arg1="A" arg2="B">
+POLYGON ((-100 -90, -76.23310243744803 -100.58620689655172, 100 -30, 30 90, -59.62241169305726 -70.28623629719854, -100 -90))
+	</op>
+</test>
+</case>
+
+<case>
+  <desc>A.intersection(B) fails, since it computes a result equal to A
+   
+   This is a  case which exhibits a (luckily VERY rare) issue 
+   with the RobustDeterminant code in JTS.  
+   This code is sensitive to the order of the input coordinates, in some cases.  
+   Due to the way JTS computes topology, 
+   this can cause an inconsistency in the evaluation of how two polygons intersect. 
+   
+   As a demonstration of this, 
+   notice that if the triangle in the example is reversed, 
+   the intersection computation produces a more reasonable result:
+   
+   polyA = POLYGON ((0 0, 40 0, 40 10.883854, 15.552673 10.883854, 15.552673 20.540905, 0 20.540905, 0 0))
+   
+   tri = POLYGON ((-20.43142161511487 -186.3790522565901, -20.43142161511487 13.620947743409914, 279.56857838488514 -186.3790522565901, -20.43142161511487 -186.3790522565901))
+   
+   polyA.intersection(tri) = POINT (0 0)
+   
+   I have noticed this once before, 
+   but wasn't sure of the best way to address this issue.  
+   It may be best to always force a standard ordering of the inputs to 
+   the RobustDeterminant calculation, in order to at least be consistent.  
+   Hopefully if this proves out I can address this in a future version of JTS.
+
+http://sourceforge.net/mailarchive/forum.php?thread_name=BANLkTi%3D0UrBPmBSg%3Duy4M0ng9Pdptm%2BaYQ%40mail.gmail.com&forum_name=jts-topo-suite-user
+</desc>
+<a>
+POLYGON ((0 0, 40 0, 40 10.883854, 15.552673 10.883854, 15.552673 20.540905, 0 20.540905, 0 0))
+</a>
+<b>
+POLYGON ((-20.43142161511487 -186.3790522565901, 279.56857838488514 -186.3790522565901, -20.43142161511487 13.620947743409914, -20.43142161511487 -186.3790522565901))
+</b>
+<test>
+<op name="intersection" arg1="A" arg2="B">
+GEOMETRYCOLLECTION EMPTY	
+</op>
+</test>
+</case>
+
 </run>
diff --git a/testxml/failure/bug368jts.xml b/testxml/failure/bug368jts.xml
new file mode 100644
index 0000000..ea908c0
--- /dev/null
+++ b/testxml/failure/bug368jts.xml
@@ -0,0 +1,33 @@
+<run>
+  <desc>
+  Result of unioning two polygons is invalid.
+  
+http://trac.osgeo.org/geos/ticket/368
+  </desc>
+  <precisionModel type="FLOATING" />
+
+<case>
+  <desc>
+http://trac.osgeo.org/geos/ticket/368
+  </desc>
+  <a>
+010300000001000000210000007711061EC4DE06C1B56E2A7A590F0F4124BB1E1EC4DE06C14E21D979590F0F410000000028E406C100000000900C0F410000000078EA06C10000000070090F410000000038ED06C10000000020080F4100000000C0F706C10000000050030F4100000000580C07C10000000048FB0E4100000000F03307C10000000010F10E4100000000306C07C10000000048EE0E410000000080AA07C10000000000FA0E4100000000B8FF07C100000000901E0F4100000000785208C10000000078510F4100000000E8A308C100000000308B0F4174C9FEC2BFF408C12FD8B0D3E7C50F4113C7FEC2BFF408C196 [...]
+  </a>
+  <b>
+01060000000100000001030000000100000021000000A887CB005F6908C10000000020620F412CD0BB18626908C1EEF84F9700620F410A9F1D426B6908C1E6B79F63E2610F410A3CCF227A6908C108190F8EC6610F4129F772288E6908C129F77228AE610F4108190F8EA66908C10A3CCF229A610F41E6B79F63C26908C10A9F1D428B610F41EEF84F97E06908C12CD0BB1882610F4100000000006A08C1A887CB007F610F411207B0681F6A08C12CD0BB1882610F411A48609C3D6A08C10A9F1D428B610F41F8E6F071596A08C10A3CCF229A610F41D7088DD7716A08C129F77228AE610F41F6C330DD856A08C108190F8EC6610F41 [...]
+  </b>
+<test>
+  <op name="isValid" arg1="A">true</op>
+</test>
+<test>
+  <op name="isValid" arg1="B">true</op>
+</test>
+<test>
+ <op name="union" arg1="A" arg2="B">
+POLYGON ((-187352.51466001172 254443.18465124597, -187352.51470705227 254443.18449617404, -187525 254354, -187727 254254, -187815 254212, -188152 254058, -188811 253801, -190078 253474, -191878 253385, -193872 253760, -196599 254930, -199247 256559, -199983.26344477304 257080.82601016725, -199983.266996831 257080.81936473423, -199985.76975052923 257077.76975052923, -199988.81936473423 257075.266996831, -199992.29864448233 257073.40728306054, -199996.07388300396 257072.2620769752, -200000 [...]
+ </op>
+</test>
+</case>
+
+
+</run>
diff --git a/testxml/failure/geos-bug368-union.xml b/testxml/failure/geos-bug368-union.xml
new file mode 100644
index 0000000..4087b03
--- /dev/null
+++ b/testxml/failure/geos-bug368-union.xml
@@ -0,0 +1,31 @@
+<run>
+  <desc>
+http://trac.osgeo.org/geos/ticket/368
+  </desc>
+  <precisionModel type="FLOATING" />
+
+<case>
+  <desc>
+http://trac.osgeo.org/geos/ticket/368
+  </desc>
+  <a>
+010600000003000000010300000001000000210000007711061EC4DE06C1B56E2A7A590F0F4124BB1E1EC4DE06C14E21D979590F0F410000000028E406C100000000900C0F410000000078EA06C10000000070090F410000000038ED06C10000000020080F4100000000C0F706C10000000050030F4100000000580C07C10000000048FB0E4100000000F03307C10000000010F10E4100000000306C07C10000000048EE0E410000000080AA07C10000000000FA0E4100000000B8FF07C100000000901E0F4100000000785208C10000000078510F4100000000E8A308C100000000308B0F4174C9FEC2BFF408C12FD8B0D3E7C50F41 [...]
+  </a>
+  <b>
+01060000000100000001030000000100000021000000A887CB005F6908C10000000020620F412CD0BB18626908C1EEF84F9700620F410A9F1D426B6908C1E6B79F63E2610F410A3CCF227A6908C108190F8EC6610F4129F772288E6908C129F77228AE610F4108190F8EA66908C10A3CCF229A610F41E6B79F63C26908C10A9F1D428B610F41EEF84F97E06908C12CD0BB1882610F4100000000006A08C1A887CB007F610F411207B0681F6A08C12CD0BB1882610F411A48609C3D6A08C10A9F1D428B610F41F8E6F071596A08C10A3CCF229A610F41D7088DD7716A08C129F77228AE610F41F6C330DD856A08C108190F8EC6610F41 [...]
+  </b>
+<test>
+  <op name="isValid" arg1="A">true</op>
+</test>
+<test>
+  <op name="isValid" arg1="B">true</op>
+</test>
+<test>
+ <op name="union" arg1="A" arg2="B">
+GEOMETRYCOLLECTION EMPTY
+ </op>
+</test>
+</case>
+
+
+</run>
diff --git a/testxml/general/TestBuffer.xml b/testxml/general/TestBuffer.xml
index 9711f49..32c533d 100644
--- a/testxml/general/TestBuffer.xml
+++ b/testxml/general/TestBuffer.xml
@@ -115,5 +115,21 @@ POLYGON EMPTY
   </op></test>
 </case>
 
+<case>
+  <desc>
+  	Degenerate polygon - ring is flat.
+  	This case tests a fix made in ver 1.12
+  </desc>
+  <a>
+    POLYGON ((100 100, 200 100, 200 100, 100 100))
+  </a>
+<test><op name='buffer' arg1='A' arg2='0.0'>   
+POLYGON EMPTY
+  </op></test>
+<test><op name='buffer' arg1='A' arg2='10.0'>   
+POLYGON ((100 90, 98.04909677983872 90.19214719596769, 96.1731656763491 90.76120467488714, 94.44429766980397 91.68530387697454, 92.92893218813452 92.92893218813452, 91.68530387697454 94.44429766980397, 90.76120467488713 96.1731656763491, 90.19214719596769 98.04909677983872, 90 100, 90.19214719596769 101.95090322016128, 90.76120467488713 103.8268343236509, 91.68530387697454 105.55570233019603, 92.92893218813452 107.07106781186548, 94.44429766980397 108.31469612302546, 96.1731656763491 109 [...]
+  </op></test>
+</case>
+
 
 </run>
diff --git a/testxml/general/TestEqualsExact.xml b/testxml/general/TestEqualsExact.xml
new file mode 100644
index 0000000..970c813
--- /dev/null
+++ b/testxml/general/TestEqualsExact.xml
@@ -0,0 +1,157 @@
+<run>
+<description> 
+Tests of exact equality and exact equality with normalization
+</description>
+
+<case>
+  <desc>P - point</desc>
+  <a>    POINT(10 10)  </a>
+  <b>    POINT(10 10)  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>P - point</desc>
+  <a>    POINT(10 10)  </a>
+  <b>    POINT(10 11)  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    false  </op></test>
+</case>
+
+<case>
+  <desc>mP - MultiPoint</desc>
+  <a>    MULTIPOINT((10 10), (20 20))  </a>
+  <b>    MULTIPOINT((10 10), (20 20))  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>mP - MultiPoint, permuted</desc>
+  <a>    MULTIPOINT((10 10), (20 20))  </a>
+  <b>    MULTIPOINT((20 20), (10 10))  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    false  </op></test>
+<test><op name="equalsNorm"  arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>mP - MultiPoint empty</desc>
+  <a>    MULTIPOINT EMPTY </a>
+  <b>    MULTIPOINT EMPTY </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<!-- =========================================================== -->
+
+<case>
+  <desc>L - Line</desc>
+  <a>    LINESTRING(10 10, 20 20, 30 30)  </a>
+  <b>    LINESTRING(10 10, 20 20, 30 30)  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>L - Line, permuted</desc>
+  <a>    LINESTRING(10 10, 20 20, 30 30)  </a>
+  <b>    LINESTRING(30 30, 20 20, 10 10)  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    false  </op></test>
+<test><op name="equalsNorm"  arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>L - closed</desc>
+  <a>    LINESTRING(10 10, 20 20, 20 10, 10 10)  </a>
+  <b>    LINESTRING(10 10, 20 20, 20 10, 10 10)  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>L - empty</desc>
+  <a>    LINESTRING EMPTY  </a>
+  <b>    LINESTRING EMPTY  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>mL - 2 lines with common endpoint</desc>
+  <a> MULTILINESTRING(
+      (10 10, 20 20), 
+      (20 20, 30 30)) </a>
+  <b> MULTILINESTRING(
+      (10 10, 20 20), 
+      (20 20, 30 30)) </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>mL - 2 lines with common endpoint, permuted</desc>
+  <a> MULTILINESTRING(
+      (10 10, 20 20), 
+      (20 20, 30 30)) </a>
+  <b> MULTILINESTRING(
+      (30 30, 20 20),
+      (10 10, 20 20)) </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    false  </op></test>
+<test><op name="equalsNorm"  arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<!-- =========================================================== -->
+
+<case>
+  <desc>A - polygon with no holes</desc>
+  <a>  POLYGON((40 60, 420 60, 420 320, 40 320, 40 60))  </a>
+  <b>  POLYGON((40 60, 420 60, 420 320, 40 320, 40 60))  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>A - polygon with no holes, permuted</desc>
+  <a>  POLYGON((40 60, 420 60, 420 320, 40 320, 40 60))  </a>
+  <b>  POLYGON((420 60, 420 320, 40 320, 40 60, 420 60))  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    false  </op></test>
+<test><op name="equalsNorm"  arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>A - polygon with 1 hole</desc>
+  <a>
+    POLYGON(
+      (40 60, 420 60, 420 320, 40 320, 40 60), 
+      (200 140, 160 220, 260 200, 200 140))
+  </a>
+  <b>
+    POLYGON(
+      (40 60, 420 60, 420 320, 40 320, 40 60), 
+      (200 140, 160 220, 260 200, 200 140))
+  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>A - empty</desc>
+  <a>    POLYGON EMPTY  </a>
+  <b>    POLYGON EMPTY  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>mA</desc>
+  <a>    MULTIPOLYGON (((50 100, 100 100, 100 50, 50 50, 50 100)), ((150 100, 200 100, 200 50, 150 50, 150 100)))  </a>
+  <b>    MULTIPOLYGON (((50 100, 100 100, 100 50, 50 50, 50 100)), ((150 100, 200 100, 200 50, 150 50, 150 100)))  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>mA - permuted</desc>
+  <a>    MULTIPOLYGON (((50 100, 100 100, 100 50, 50 50, 50 100)), ((150 100, 200 100, 200 50, 150 50, 150 100)))  </a>
+  <b>    MULTIPOLYGON (((150 100, 200 100, 200 50, 150 50, 150 100)), ((50 100, 100 100, 100 50, 50 50, 50 100)))  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    false  </op></test>
+<test><op name="equalsNorm"  arg1="A" arg2="B">    true  </op></test>
+</case>
+
+<case>
+  <desc>mA - empty</desc>
+  <a>    MULTIPOLYGON EMPTY  </a>
+  <b>    MULTIPOLYGON EMPTY  </b>
+<test><op name="equalsExact" arg1="A" arg2="B">    true  </op></test>
+</case>
+
+</run>
diff --git a/testxml/general/TestMinimumClearance.xml b/testxml/general/TestMinimumClearance.xml
new file mode 100644
index 0000000..4c75ff5
--- /dev/null
+++ b/testxml/general/TestMinimumClearance.xml
@@ -0,0 +1,89 @@
+<run>
+  <precisionModel type="FLOATING" />
+
+<case>
+  <desc>P - empty point</desc>
+  <a>    POINT EMPTY </a>
+<test><op name="minClearance" arg1='A' >  1.7976931348623157E308	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING EMPTY </op></test>
+</case>
+
+<case>
+  <desc>P - single point</desc>
+  <a>    POINT (100 100) </a>
+<test><op name="minClearance" arg1='A' >  1.7976931348623157E308	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING EMPTY </op></test>
+</case>
+
+<case>
+  <desc>mP - points</desc>
+  <a>    MULTIPOINT ( (100 100), (10 100) ) </a>
+<test><op name="minClearance" arg1='A' >  90	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING (100 100, 10 100) </op></test>
+</case>
+
+<case>
+  <desc>mP - two identical points</desc>
+  <a>    MULTIPOINT ( (100 100), (100 100) ) </a>
+<test><op name="minClearance" arg1='A' >  1.7976931348623157E308	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING EMPTY </op></test>
+</case>
+
+<case>
+  <desc>mP - points</desc>
+  <a>    MULTIPOINT ((100 100), (10 100), (30 100)) </a>
+<test><op name="minClearance" arg1='A' >  20	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING (10 100, 30 100) </op></test>
+</case>
+
+<case>
+  <desc>L - linestring</desc>
+  <a>    LINESTRING (100 100, 200 100, 200 200, 150 150) </a>
+<test><op name="minClearance" arg1='A' >  50	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING (150 150, 150 100)	</op></test>
+</case>
+
+<case>
+  <desc>L - empty linestring</desc>
+  <a>    LINESTRING EMPTY </a>
+<test><op name="minClearance" arg1='A' >  1.7976931348623157E308	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING EMPTY	</op></test>
+</case>
+
+<case>
+  <desc>ML - linestring</desc>
+  <a>    MULTILINESTRING ((100 100, 200 100, 200 200, 150 150), 
+  (100 200, 150 170)) </a>
+<test><op name="minClearance" arg1='A' >  14.142135623730951	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING (150 170, 160 160) </op></test>
+</case>
+
+<case>
+  <desc>A - empty polygon</desc>
+  <a>    POLYGON EMPTY </a>
+<test><op name="minClearance" arg1='A' >  1.7976931348623157E308	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING EMPTY </op></test>
+</case>
+
+<case>
+  <desc>A - single polygon #1</desc>
+  <a>    POLYGON ((100 100, 300 100, 200 200, 100 100)) </a>
+<test><op name="minClearance" arg1='A' >  100	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING (200 200, 200 100) </op></test>
+</case>
+
+<case>
+  <desc>A - single polygon #2</desc>
+  <a>    POLYGON ((300 400, 100 350, 250 320, 50 250, 298 200, 50 150, 150 100, 300 50, 300 50, 300 50, 300 400)) </a>
+<test><op name="minClearance" arg1='A' >  2	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING (298 200, 300 200) </op></test>
+</case>
+
+<case>
+  <desc>mA - multiple polygons</desc>
+  <a>    MULTIPOLYGON (((100 100, 300 100, 200 200, 100 100)), ((150 250, 250 250, 200 220, 150 250))) </a>
+<test><op name="minClearance" arg1='A' >  20	</op></test>
+<test><op name="minClearanceLine" arg1='A' >  LINESTRING (200 200, 200 220) </op></test>
+</case>
+
+</run>
diff --git a/testxml/general/TestRectanglePredicate.xml b/testxml/general/TestRectanglePredicate.xml
index 511b6ae..29071ef 100644
--- a/testxml/general/TestRectanglePredicate.xml
+++ b/testxml/general/TestRectanglePredicate.xml
@@ -215,6 +215,24 @@
 <test>  <op name="coveredBy" arg1="B" arg2="A">   true   </op> </test>
 </case>
 
+<case>
+  <desc>GC as argument</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0)) 
+  </a>
+  <b>
+  GEOMETRYCOLLECTION (
+    POLYGON((10 10, 10 90, 90 90, 90 10, 10 10)),
+    LINESTRING(10 10, 10 20),
+    MULTIPOINT((50 100), (60 60)) 
+  )
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="covers" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="coveredBy" arg1="B" arg2="A">   true   </op> </test>
+</case>
+
 
 
 
diff --git a/testxml/general/TestValid.xml b/testxml/general/TestValid.xml
index f60e493..2e32835 100644
--- a/testxml/general/TestValid.xml
+++ b/testxml/general/TestValid.xml
@@ -26,6 +26,14 @@
    </case>
 
    <case>
+      <desc>P - empty point</desc>
+      <a>
+    POINT EMPTY
+  </a>
+      <test>         <op name="isValid" arg1="A">    true  </op>      </test>
+   </case>
+
+   <case>
       <desc>P - point with invalid X ordinate</desc>
       <a>
     POINT(NaN 10)
@@ -98,6 +106,22 @@ LINESTRING (40 180, 120 120, 140 200, 140 200, 200 140, 240 200)
          <op name="isValid" arg1="A">      false      </op>
       </test>
    </case>
+   
+   <case>
+      <desc>mL - MultiLinestring with two identical points in first component</desc>
+      <a>MULTILINESTRING((1 1, 0 0), (0 0, 0 0))</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mL - MultiLinestring with two identical points in second component</desc>
+      <a>MULTILINESTRING((1 1, 0 0), (0 0, 0 0))</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
 
    <case>
       <desc>A - zero-area polygon </desc>
@@ -516,6 +540,28 @@ POLYGON ((190 190, 360 20, 20 20, 190 190),
    </case>
 
    <case>
+      <desc>A - one holes touches another at all vertices </desc>
+      <a>
+POLYGON( (0 0, 0 5, 6 5, 6 0, 0 0), (2 1, 4 1, 3 2, 2 1), (2 1, 1 4, 5 4, 4 1, 4 3, 3 2, 2 3, 2 1) )
+</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - one holes touches another at several vertices </desc>
+      <a>
+POLYGON ((0 0, 0 5, 6 5, 6 0, 0 0), 
+  (2.5 1, 3.5 1, 3.5 2, 2.5 2, 2.5 1), 
+  (2.5 1.5, 1 4, 5 4, 3.5 1.5, 4 3, 3 2, 2 3, 2.5 1.5))
+  </a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
       <desc>A - hole disconnects interiors </desc>
       <a>
 POLYGON ((0 0, 10 10, 10 0, 0 0), 
diff --git a/testxml/robust/MagnifyTopology.xml b/testxml/robust/MagnifyTopology.xml
new file mode 100644
index 0000000..4ba849a
--- /dev/null
+++ b/testxml/robust/MagnifyTopology.xml
@@ -0,0 +1,86 @@
+<!-- 
+
+Test cases to demonstrate that the TestBuilder Magnify Topology function is working 
+
+-->
+<run>
+
+<case>
+  <desc>Overlapping squares </desc>
+  <a>
+POLYGON ((0 0, 0 -100, -100 -100, -100 0, 0 0)) </a>
+  <b>
+POLYGON ((100 100, 100 0, -0.01 -0.01, 0 100, 100 100)) </b>
+</case>
+
+<case>
+  <desc>Flat corner - Displaced in Quadrant 3 </desc>
+  <a>
+LINESTRING (-10 0, 0 0, 10 0)  </a>
+  <b>
+LINESTRING (-10 10, 0.001 -0.001, 10 10)  </b>
+</case>
+
+
+<case>
+  <desc>Displaced in Quadrant 2 </desc>
+  <a>
+LINESTRING (0 100, 100 100, 100 0)  </a>
+  <b>
+LINESTRING (150 150, 100.0001 100.0001)  </b>
+</case>
+
+
+<case>
+  <desc>Displaced in Quadrant 0 </desc>
+  <a>
+LINESTRING (0 100, 100 100, 100 0)  </a>
+  <b>
+LINESTRING (150 150, 99.999 99.999)  </b>
+</case>
+
+<case>
+  <desc>Displaced in Quadrant 1 </desc>
+  <a>
+LINESTRING (0 100, 100 100, 100 0)  </a>
+  <b>
+LINESTRING (150 150, 100.0001 99.999)  </b>
+</case>
+
+<case>
+  <desc>Displaced in Quadrant 3 </desc>
+  <a>
+LINESTRING (0 100, 100 100, 100 0)  </a>
+  <b>
+LINESTRING (150 150, 99.999 100.0001)  </b>
+</case>
+
+<case>
+  <desc>Flat corner - Displaced in Quadrant 3 </desc>
+  <a>
+LINESTRING (0 10, 30 10, 60 10)  </a>
+  <b>
+LINESTRING (10 30, 30.001 9.9999, 50 30)  </b>
+</case>
+
+<case>
+  <desc>From PostGIS list (Fabio Renzo Panettieri - Snapped polygon) </desc>
+  <a>
+    POLYGON ((518340.401248796 3820650.80532367, 518350.693588019 3820628.81714442, 518355.570889645 3820612.85506637, 518360.747754687 3820584.83016526, 518360.747754687 3820554.66766526, 518359.689421353 3820481.64266527, 518456.526921353 3820479.5259986, 518462.281608853 3820479.5259986, 518467.639421354 3820508.1009986, 518471.343588019 3820510.21766527, 518475.576921353 3820510.74683193, 518558.126921353 3820505.45516527, 518565.799838019 3820504.66141527, 518573.208171353 3820501.2 [...]
+  </a>
+  <b>
+    POLYGON ((518603.689825253 3820863.05709336, 518625.678177319 3820862.68015018, 518625.678177319 3820857.90553659, 518631.834915897 3820857.90553659, 518631.960563623 3820852.12574119, 518635.60434768 3820852.12574119, 518635.356376888 3820858.85350875, 518627.976921353 3820858.73997866, 518627.976921353 3820858.74006108, 518627.976921353 3820861.65039533, 518627.976921353 3820861.65047775, 518639.772795288 3820861.87732148, 518639.76077524 3820863.05860999, 518654.074563415 3820863. [...]
+  </b>
+</case>
+
+<case>
+  <desc>Almost coincident string of vertices </desc>
+  <a>
+POLYGON ((609978.2305618008 2367350.3099981956, 609061.0000000028 2368332.9999981974, 609151.0000000028 2368684.9999981993, 608919.0000000028 2368811.9999982, 608801.0000000027 2369192.9999982, 610415.3287640482 2370467.010222916, 609978.2305618008 2367350.3099981956))  
+  </a>
+  <b>
+POLYGON ((608128.000000002 2370312.9999982, 608801.000000003 2369192.9999982, 608919.000000003 2368811.9999982, 609151.000000003 2368684.9999982, 609061.000000003 2368332.9999982, 607980.000000002 2367585.9999982, 608128.000000002 2370312.9999982))
+</b>
+</case>
+
+</run>

-- 
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