[med-svn] [r-cran-rgeos] 04/07: New upstream version 0.3-26

Andreas Tille tille at debian.org
Wed Dec 27 17:02:09 UTC 2017


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

tille pushed a commit to branch master
in repository r-cran-rgeos.

commit 87c88d5ea142f3eccb26296bf470ff1a69eb106d
Author: Andreas Tille <tille at debian.org>
Date:   Wed Dec 27 18:00:00 2017 +0100

    New upstream version 0.3-26
---
 ChangeLog                                          | 2904 +++++++++++
 DESCRIPTION                                        |   33 +
 MD5                                                |  154 +
 NAMESPACE                                          |   85 +
 R/AAA.R                                            |  125 +
 R/Rgpc_funcs.R                                     |  358 ++
 R/gpc_geos.R                                       |   87 +
 R/labelpt.R                                        |  217 +
 R/over.R                                           |  139 +
 R/rgeos_buffer.R                                   |   88 +
 R/rgeos_linearref.R                                |   68 +
 R/rgeos_misc.R                                     |  168 +
 R/rgeos_predicate_binary.R                         |  378 ++
 R/rgeos_predicate_unary.R                          |   67 +
 R/rgeos_spExtensions_Classes.R                     |   87 +
 R/rgeos_spExtensions_Methods.R                     |  389 ++
 R/rgeos_topology.R                                 |  242 +
 R/rgeos_topology_binary.R                          |  123 +
 R/rgeos_util.R                                     |  226 +
 R/rgeos_wkt.R                                      |   59 +
 cleanup                                            |    3 +
 configure                                          | 3122 ++++++++++++
 configure.ac                                       |  199 +
 debian/README.test                                 |   10 -
 debian/changelog                                   |    5 -
 debian/compat                                      |    1 -
 debian/control                                     |   25 -
 debian/copyright                                   |   74 -
 debian/docs                                        |    3 -
 debian/rules                                       |    5 -
 debian/source/format                               |    1 -
 debian/tests/control                               |    3 -
 debian/tests/run-unit-test                         |   12 -
 debian/watch                                       |    2 -
 inst/ChangeLog                                     | 2904 +++++++++++
 inst/README                                        |   18 +
 inst/SVN_VERSION                                   |    1 +
 inst/poly-ex-gpc/ex-poly1.txt                      |  107 +
 inst/poly-ex-gpc/ex-poly2.txt                      |   72 +
 inst/poly-ex-gpc/hole-poly.txt                     |   13 +
 inst/test_cases/polys.RData                        |  Bin 0 -> 2297 bytes
 inst/wkts/sline1.wkt                               |    1 +
 inst/wkts/sline2.wkt                               |    1 +
 inst/wkts/sppsp.wkt                                |    1 +
 man/class-Ring.Rd                                  |   42 +
 man/class-SpatialCollections.Rd                    |   46 +
 man/class-SpatialRings.Rd                          |   55 +
 man/class-SpatialRingsDataFrame.Rd                 |   72 +
 man/class-gpc.poly.Rd                              |  152 +
 man/class-gpc.poly.nohole.Rd                       |   49 +
 man/comment-functions.Rd                           |  120 +
 man/constructor-SpatialCollections.Rd              |   28 +
 man/constructor-SpatialRings.Rd                    |   35 +
 man/experimental-functions.Rd                      |   56 +
 man/gpc-new-generics.Rd                            |   96 +
 man/gpc-polyfile.Rd                                |  102 +
 man/labelpt.Rd                                     |  195 +
 man/linref-gInterpolate.Rd                         |   38 +
 man/linref-gProject.Rd                             |   44 +
 man/misc-gArea.Rd                                  |   41 +
 man/misc-gBuffer.Rd                                |   98 +
 man/misc-gDistance.Rd                              |   75 +
 man/misc-gLength.Rd                                |   35 +
 man/misc-gNearestPoints.Rd                         |   37 +
 man/misc-over.Rd                                   |   36 +
 man/pred-binary-gContains.Rd                       |  110 +
 man/pred-binary-gCrosses.Rd                        |   85 +
 man/pred-binary-gEquals.Rd                         |   83 +
 man/pred-binary-gIntersects.Rd                     |   92 +
 man/pred-binary-gRelate.Rd                         |  120 +
 man/pred-binary-gTouches.Rd                        |   76 +
 man/pred-unary-gIsEmpty.Rd                         |   38 +
 man/pred-unary-gIsRing.Rd                          |   49 +
 man/pred-unary-gIsSimple.Rd                        |   78 +
 man/pred-unary-gIsValid.Rd                         |   88 +
 man/topo-bin-gDifference.Rd                        |   43 +
 man/topo-bin-gIntersection.Rd                      |  133 +
 man/topo-bin-gSymdifference.Rd                     |   41 +
 man/topo-bin-gUnion.Rd                             |   84 +
 man/topo-unary-gBoundary.Rd                        |   73 +
 man/topo-unary-gCentroid.Rd                        |   45 +
 man/topo-unary-gConvexHull.Rd                      |   40 +
 man/topo-unary-gDelaunayTriangulation.Rd           |   57 +
 man/topo-unary-gEnvelope.Rd                        |   45 +
 man/topo-unary-gNode.Rd                            |   71 +
 man/topo-unary-gPointOnSurface.Rd                  |   53 +
 man/topo-unary-gPolygonize.Rd                      |   78 +
 man/topo-unary-gSimplify.Rd                        |   46 +
 man/utility-functions.Rd                           |  127 +
 man/wkt-functions.Rd                               |   58 +
 src/Makevars.in                                    |    3 +
 src/Makevars.win                                   |   22 +
 src/dummy.cc                                       |    0
 src/init.c                                         |  119 +
 src/local_stubs.c                                  |    7 +
 src/rgeos.c                                        |  171 +
 src/rgeos.h                                        |  222 +
 src/rgeos_R2geos.c                                 |  403 ++
 src/rgeos_R2geosMP.c                               |   94 +
 src/rgeos_bbox.c                                   |   63 +
 src/rgeos_buffer.c                                 |   90 +
 src/rgeos_coord.c                                  |  305 ++
 src/rgeos_geos2R.c                                 |  873 ++++
 src/rgeos_linearref.c                              |  119 +
 src/rgeos_misc.c                                   |  239 +
 src/rgeos_poly2nb.c                                |  300 ++
 src/rgeos_predicate_binary.c                       |  340 ++
 src/rgeos_predicate_unary.c                        |   96 +
 src/rgeos_topology.c                               |  219 +
 src/rgeos_topology_binary.c                        |  171 +
 src/rgeos_validate.c                               |  172 +
 src/rgeos_wkt.c                                    |   55 +
 tests/test-all.R                                   |    8 +
 tests/testthat/process_testxml.R                   |  147 +
 tests/testthat/test-jts-xml.R                      |   45 +
 tests/testthat/test-linearref.R                    |   80 +
 tests/testthat/test-misc.R                         |   99 +
 tests/testthat/test-translate-empty.R              |  222 +
 tests/testthat/test-translate-lines.R              |   57 +
 tests/testthat/test-translate-points.R             |   58 +
 tests/testthat/test-translate-polygon-collection.R |   92 +
 tests/testthat/test-translate-polygons.R           |   75 +
 tests/testthat/test-translate-rings.R              |   46 +
 tests/testthat/testxml/general/TestBoundary.xml    |  129 +
 tests/testthat/testxml/general/TestCentroid.xml    |  149 +
 .../testxml/general/TestConvexHull-big.xml         |   17 +
 tests/testthat/testxml/general/TestConvexHull.xml  |  181 +
 tests/testthat/testxml/general/TestFunctionAA.xml  |  633 +++
 .../testxml/general/TestFunctionAAPrec.xml         |  828 ++++
 tests/testthat/testxml/general/TestFunctionLA.xml  |  517 ++
 .../testxml/general/TestFunctionLAPrec.xml         |   59 +
 tests/testthat/testxml/general/TestFunctionLL.xml  |  355 ++
 .../testxml/general/TestFunctionLLPrec.xml         |   29 +
 tests/testthat/testxml/general/TestFunctionPA.xml  |  155 +
 tests/testthat/testxml/general/TestFunctionPL.xml  |  295 ++
 .../testxml/general/TestFunctionPLPrec.xml         |   19 +
 tests/testthat/testxml/general/TestFunctionPP.xml  |  214 +
 .../testthat/testxml/general/TestInteriorPoint.xml |   56 +
 .../testxml/general/TestRectanglePredicate.xml     |  121 +
 tests/testthat/testxml/general/TestRelateAA.xml    |  221 +
 tests/testthat/testxml/general/TestRelateAC.xml    |   28 +
 tests/testthat/testxml/general/TestRelateLA.xml    |  190 +
 tests/testthat/testxml/general/TestRelateLC.xml    |   79 +
 tests/testthat/testxml/general/TestRelateLL.xml    |  311 ++
 tests/testthat/testxml/general/TestRelatePA.xml    |  103 +
 tests/testthat/testxml/general/TestRelatePL.xml    |  124 +
 tests/testthat/testxml/general/TestRelatePP.xml    |   64 +
 tests/testthat/testxml/general/TestSimple.xml      |  259 +
 tests/testthat/testxml/general/TestValid.xml       |  663 +++
 tests/testthat/testxml/general/TestValid2-big.xml  |   18 +
 tests/testthat/testxml/general/TestValid2.xml      | 5225 ++++++++++++++++++++
 .../testxml/general/TestWithinDistance.xml         |   92 +
 .../testthat/testxml/robust/ExternalRobustness.xml |  190 +
 .../testxml/robust/TestRobustOverlayFixed.xml      |   18 +
 .../testxml/robust/TestRobustOverlayFloat.xml      |  104 +
 tests/testthat/testxml/robust/TestRobustRelate.xml |   19 +
 .../testthat/testxml/validate/TestRelateAA-big.xml |   34 +
 tests/testthat/testxml/validate/TestRelateAA.xml   | 1793 +++++++
 tests/testthat/testxml/validate/TestRelateAC.xml   |   26 +
 tests/testthat/testxml/validate/TestRelateLA.xml   | 1162 +++++
 tests/testthat/testxml/validate/TestRelateLC.xml   |   71 +
 tests/testthat/testxml/validate/TestRelateLL.xml   | 1949 ++++++++
 tests/testthat/testxml/validate/TestRelatePA.xml   |  623 +++
 tests/testthat/testxml/validate/TestRelatePL.xml   | 1284 +++++
 tests/testthat/testxml/validate/TestRelatePP.xml   |  174 +
 tools/winlibs.R                                    |   11 +
 166 files changed, 39308 insertions(+), 141 deletions(-)

diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..1a8ab10
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,2904 @@
+2017-09-25 10:51  rsbivand
+
+	* configure: updating for stricter autoconf
+
+2017-09-25 10:50  rsbivand
+
+	* DESCRIPTION: updating for stricter autoconf
+
+2017-09-25 10:49  rsbivand
+
+	* configure, configure.ac: updating for stricter autoconf
+
+2017-09-25 10:46  rsbivand
+
+	* configure, configure.ac: updating for stricter autoconf
+
+2017-09-18 08:59  rsbivand
+
+	* DESCRIPTION: tidy
+
+2017-09-18 08:27  rsbivand
+
+	* ChangeLog, configure, inst/ChangeLog: tidy
+
+2017-09-18 08:26  rsbivand
+
+	* DESCRIPTION, tools, tools/winlibs.R: transition to winlibs
+
+2017-09-15 13:09  rsbivand
+
+	* DESCRIPTION, src/Makevars.win: migrate to winlib/gdal
+
+2017-04-05 12:05  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2017-04-05 12:04  rsbivand
+
+	* configure: tidy
+
+2017-04-05 12:03  rsbivand
+
+	* DESCRIPTION, src/rgeos.c, src/rgeos_validate.c: PROTECT issues
+
+2017-01-08 19:11  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2016-12-10 10:02  rsbivand
+
+	* configure: omitted trap in init.c
+
+2016-12-10 10:00  rsbivand
+
+	* DESCRIPTION, src/init.c: omitted trap in init.c
+
+2016-10-19 11:45  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2016-10-11 03:24  rsbivand
+
+	* ChangeLog, R/rgeos_misc.R, man/misc-gNearestPoints.Rd,
+	  src/rgeos.h, src/rgeos_misc.c: checking NearestPoint dependency
+	  on >= 3.4
+
+2016-10-10 07:28  rcs
+
+	* ChangeLog, DESCRIPTION, NAMESPACE, R/rgeos_misc.R, configure,
+	  inst/ChangeLog, man/misc-gNearestPoints.Rd, src/init.c,
+	  src/rgeos.h, src/rgeos_misc.c, tests/testthat/test-misc.R: add
+	  gNearestPoints
+
+2016-10-08 08:14  rcs
+
+	* tests/testthat/test-linearref.R: fix linearref tests
+
+2016-10-07 21:53  rcs
+
+	* tests/testthat/test-linearref.R: fix linearref tests
+
+2016-09-14 11:18  rcs
+
+	* R/rgeos_spExtensions_Methods.R, R/rgeos_topology.R: fix partial
+	  argument match
+
+2016-09-07 13:10  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2016-09-07 13:09  rsbivand
+
+	* src/rgeos_predicate_binary.c: block list output from gRelate
+
+2016-09-07 10:03  rsbivand
+
+	* inst/ChangeLog: tidy
+
+2016-09-07 09:50  rcs
+
+	* ChangeLog, man/topo-unary-gEnvelope.Rd: fix typo
+
+2016-09-07 09:48  rcs
+
+	* ChangeLog, src/rgeos_geos2R.c: fix stack imbalance in
+	  rgeos_geosring2SpatialRings()
+
+2016-09-06 13:13  rcs
+
+	* ChangeLog, R/rgeos_linearref.R, man/linref-gProject.Rd,
+	  src/rgeos_linearref.c: update Rd; fix typo
+
+2016-09-06 11:41  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2016-09-06 11:40  rsbivand
+
+	* configure: tidy
+
+2016-09-06 11:38  rsbivand
+
+	* inst/tests, tests/test-all.R, tests/testthat: moved tests folder
+
+2016-09-06 10:50  rcs
+
+	* ChangeLog, DESCRIPTION, NAMESPACE, R/rgeos_linearref.R,
+	  inst/tests/test-linearref.R, man/linref-gInterpolate.Rd,
+	  man/linref-gProject.Rd, src/init.c, src/rgeos.h,
+	  src/rgeos_linearref.c: added linear referencing functions
+	  (gInterpolate/gProject)
+
+2016-08-30 17:36  rsbivand
+
+	* DESCRIPTION, src/rgeos_coord.c: protect s in src/rgeos_coord.c
+
+2016-04-04 11:37  rsbivand
+
+	* ChangeLog, configure, inst/ChangeLog: tidy
+
+2016-04-04 11:35  rsbivand
+
+	* DESCRIPTION, src/Makevars.win: update to win-4.9.3
+
+2016-02-15 07:38  rsbivand
+
+	* DESCRIPTION, R/rgeos_buffer.R: gBuffer NULL case
+
+2016-02-13 11:26  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2016-02-12 20:31  rsbivand
+
+	* DESCRIPTION, R/rgeos_buffer.R: buffer byid to FALSE if single
+	  feature
+
+2016-02-12 18:58  rsbivand
+
+	* R/rgeos_buffer.R: buffer byid to FALSE if single feature
+
+2016-02-09 12:53  rsbivand
+
+	* ChangeLog, inst/ChangeLog: buffer byid to FALSE if single feature
+
+2016-02-09 12:52  rsbivand
+
+	* DESCRIPTION, R/rgeos_buffer.R, configure, src/rgeos_buffer.c:
+	  buffer byid to FALSE if single feature
+
+2016-01-23 19:12  rsbivand
+
+	* DESCRIPTION, R/rgeos_misc.R: rev 66 oddity partial workaround
+
+2015-11-04 12:46  rsbivand
+
+	* configure: tidy
+
+2015-11-04 12:43  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-11-04 11:10  rsbivand
+
+	* DESCRIPTION, src/rgeos_buffer.c: rgeos_buffer id overrun bug fix
+
+2015-10-26 14:28  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-10-25 10:38  rsbivand
+
+	* man/topo-bin-gIntersection.Rd: fix td bug
+
+2015-10-25 10:28  rsbivand
+
+	* ChangeLog, DESCRIPTION, inst/ChangeLog,
+	  man/topo-bin-gIntersection.Rd, src/rgeos_topology_binary.c: fix
+	  td bug
+
+2015-09-29 07:07  rsbivand
+
+	* man/topo-bin-gIntersection.Rd: extra intersection example
+
+2015-09-28 15:51  rsbivand
+
+	* ChangeLog, configure,
+	  inst/tests/testxml/general/TestFunctionLLPrec.xml,
+	  inst/tests/testxml/validate/TestRelateLL.xml,
+	  inst/tests/testxml/validate/TestRelatePA.xml,
+	  inst/tests/testxml/validate/TestRelatePL.xml,
+	  inst/tests/testxml/validate/TestRelatePP.xml: tidy
+
+2015-09-28 09:49  rsbivand
+
+	* src/rgeos_geos2R.c: SpatialRings stack unbalance
+
+2015-09-26 17:45  rsbivand
+
+	* man/labelpt.Rd, man/pred-binary-gContains.Rd,
+	  man/pred-binary-gCrosses.Rd, man/pred-binary-gEquals.Rd,
+	  man/pred-binary-gIntersects.Rd, man/pred-binary-gRelate.Rd,
+	  man/pred-binary-gTouches.Rd, man/topo-bin-gDifference.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gSymdifference.Rd,
+	  man/topo-bin-gUnion.Rd: tidy
+
+2015-09-26 17:27  rsbivand
+
+	* DESCRIPTION: adding unaryUnion to topo-bin if FALSE byid
+
+2015-09-26 17:27  rsbivand
+
+	* R/rgeos_topology_binary.R, man/topo-bin-gDifference.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gSymdifference.Rd,
+	  man/topo-bin-gUnion.Rd, src/rgeos_topology_binary.c: adding
+	  unaryUnion to topo-bin if FALSE byid
+
+2015-09-20 21:23  rsbivand
+
+	* man/pred-binary-gContains.Rd, man/pred-binary-gCrosses.Rd,
+	  man/pred-binary-gEquals.Rd, man/pred-binary-gIntersects.Rd,
+	  man/pred-binary-gRelate.Rd, man/pred-binary-gTouches.Rd,
+	  man/topo-bin-gDifference.Rd, man/topo-bin-gIntersection.Rd,
+	  man/topo-bin-gSymdifference.Rd, man/topo-bin-gUnion.Rd: note on
+	  0-based indices
+
+2015-09-18 12:13  rsbivand
+
+	* R/rgeos_predicate_binary.R, R/rgeos_topology_binary.R: add
+	  optional validity checking to binary predicates and operations
+
+2015-09-18 12:09  rsbivand
+
+	* DESCRIPTION, R/rgeos_predicate_binary.R,
+	  R/rgeos_topology_binary.R, man/misc-over.Rd,
+	  man/pred-binary-gContains.Rd, man/pred-binary-gCrosses.Rd,
+	  man/pred-binary-gEquals.Rd, man/pred-binary-gIntersects.Rd,
+	  man/pred-binary-gRelate.Rd, man/pred-binary-gTouches.Rd,
+	  man/topo-bin-gDifference.Rd, man/topo-bin-gIntersection.Rd,
+	  man/topo-bin-gSymdifference.Rd, man/topo-bin-gUnion.Rd: add
+	  optional validity checking to binary predicates and operations
+
+2015-09-10 14:06  edzer
+
+	* DESCRIPTION, R/over.R: version bump; let overGeomGeomDF absorb &
+	  pass on minDimension to overGeomGeom
+
+2015-09-01 10:27  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-08-31 19:59  edzer
+
+	* R/over.R: pass on colnames(x) if x is matrix
+
+2015-08-31 16:49  edzer
+
+	* R/over.R: pass names on to returned list
+
+2015-08-31 16:13  edzer
+
+	* R/over.R, man/misc-over.Rd: complete documentation, clean up
+	  code.
+
+2015-08-31 11:49  rsbivand
+
+	* configure, configure.ac: strip dev from version
+
+2015-08-25 11:48  rsbivand
+
+	* DESCRIPTION, man/pred-binary-gContains.Rd,
+	  man/pred-binary-gCrosses.Rd, man/pred-binary-gEquals.Rd,
+	  man/pred-binary-gIntersects.Rd, man/pred-binary-gTouches.Rd,
+	  src/rgeos_predicate_binary.c: block assigning too large matrix
+
+2015-08-25 09:15  edzer
+
+	* R/over.R: default to gIntersects(), because of the performance
+	  penalty
+
+2015-08-22 13:33  edzer
+
+	* R/over.R: move constant check outside loop
+
+2015-08-21 22:13  edzer
+
+	* R/over.R: increase over sanity
+
+2015-08-21 15:03  edzer
+
+	* R/over.R: catch omission on unrealistic dimension requirements
+
+2015-08-20 20:45  edzer
+
+	* R/over.R: clean up over stuff, order by dimension from gRelate
+
+2015-08-20 09:23  edzer
+
+	* R/over.R: some more tweeks for SpatialMultiPoints
+
+2015-08-19 14:52  edzer
+
+	* man/misc-over.Rd: add overGeomGeom doc
+
+2015-08-19 14:11  edzer
+
+	* NAMESPACE: export overGeomGeomDF and overGeomGeom
+
+2015-08-13 09:22  edzer
+
+	* src/rgeos_R2geos.c: clean up
+
+2015-06-28 20:36  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, man/pred-binary-gRelate.Rd: CRAN
+	  _R_CHECK_CODE_USAGE_WITH_ONLY_BASE_ATTACHED_=true NAMESPACE tidy
+
+2015-06-23 07:56  rsbivand
+
+	* R/AAA.R: add utils:: to packageVersion()
+
+2015-06-05 07:54  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-06-05 07:53  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-06-05 07:52  rsbivand
+
+	* DESCRIPTION: tidy
+
+2015-05-29 13:49  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-05-29 13:47  rsbivand
+
+	* DESCRIPTION: tidy
+
+2015-05-05 17:02  rsbivand
+
+	* DESCRIPTION, man/comment-functions.Rd,
+	  man/experimental-functions.Rd, man/labelpt.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gUnion.Rd,
+	  man/topo-unary-gDelaunayTriangulation.Rd: dontrun require issues
+
+2015-04-23 22:19  edzer
+
+	* man/topo-bin-gIntersection.Rd: typo
+
+2015-04-23 21:45  edzer
+
+	* src/rgeos_validate.c: add const declarations for SEXPs
+
+2015-04-23 21:43  edzer
+
+	* R/over.R: fix bug for SpatialPolygons,SpatialPolygonsDataFrame
+
+2015-04-13 15:59  rsbivand
+
+	* .Rbuildignore, R/labelpt.R, configure.ac, svn2cl.xsl: fix
+	  polygonsLabel
+
+2015-04-09 13:59  rsbivand
+
+	* DESCRIPTION, R/AAA.R, src/init.c, src/rgeos.c, src/rgeos.h: add
+	  linking to version
+
+2015-03-11 13:09  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-03-11 13:08  rsbivand
+
+	* R/labelpt.R, man/pred-unary-gIsSimple.Rd,
+	  man/pred-unary-gIsValid.Rd: tidy
+
+2015-03-11 12:48  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-03-10 08:30  rsbivand
+
+	* inst/README, inst/README.windows: OSX install note
+
+2015-03-09 07:37  edzer
+
+	* NAMESPACE, man/class-SpatialCollections.Rd: exportClass
+	  Spatial*NULL classes
+
+2015-03-08 16:04  rsbivand
+
+	* src/rgeos_coord.c, src/rgeos_geos2R.c, src/rgeos_poly2nb.c,
+	  src/rgeos_predicate_binary.c, src/rgeos_topology.c,
+	  src/rgeos_topology_binary.c: added extra geos-config checks
+
+2015-03-08 12:35  rsbivand
+
+	* DESCRIPTION: added extra geos-config checks
+
+2015-03-08 12:34  rsbivand
+
+	* configure, configure.ac: added extra geos-config checks
+
+2015-03-07 17:30  rsbivand
+
+	* configure, configure.ac: added extra geos-config checks
+
+2015-01-29 08:19  edzer
+
+	* R/over.R, man/pred-binary-gIntersects.Rd: improve readability
+	  overGeomGeom
+
+2015-01-28 22:58  edzer
+
+	* R/over.R: fix overGeomGeom for length(x) == 1
+
+2014-09-21 14:09  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-09-21 14:09  rsbivand
+
+	* DESCRIPTION, R/rgeos_topology_binary.R,
+	  man/topo-bin-gIntersection.Rd: deprecate drop_not_poly
+
+2014-09-21 11:19  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-09-21 11:18  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, man/topo-bin-gIntersection.Rd,
+	  man/utility-functions.Rd, src/rgeos_geos2R.c: conditionally drop
+	  slivers
+
+2014-09-20 18:50  rsbivand
+
+	* inst/test_cases, inst/test_cases/polys.RData: drop topological
+	  dimension
+
+2014-09-20 18:35  rsbivand
+
+	* src/rgeos_geos2R.c: drop topological dimension
+
+2014-09-19 20:17  rsbivand
+
+	* R/Rgpc_funcs.R, R/rgeos_misc.R, R/rgeos_topology_binary.R,
+	  man/topo-bin-gDifference.Rd, man/topo-bin-gIntersection.Rd,
+	  man/topo-bin-gSymdifference.Rd, man/topo-bin-gUnion.Rd,
+	  src/rgeos_topology_binary.c: drop topological dimension
+
+2014-09-11 13:08  rsbivand
+
+	* src/rgeos_geos2R.c: slivers
+
+2014-09-06 22:07  rsbivand
+
+	* R/AAA.R, src/rgeos_geos2R.c: drop_not_poly adjustment
+
+2014-09-04 18:30  rsbivand
+
+	* DESCRIPTION, R/AAA.R, R/rgeos_topology_binary.R,
+	  src/rgeos_topology_binary.c: drop_not_poly adjustment
+
+2014-07-08 08:53  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-07-07 22:26  rsbivand
+
+	* DESCRIPTION, R/Rgpc_funcs.R: constrain gpc to polygons
+
+2014-06-05 19:08  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-06-05 19:01  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-06-05 18:59  rsbivand
+
+	* man/pred-binary-gContains.Rd, man/pred-binary-gIntersects.Rd,
+	  src/rgeos_poly2nb.c: tidt
+
+2014-06-05 18:33  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-06-05 18:32  rsbivand
+
+	* DESCRIPTION, R/AAA.R, R/rgeos_predicate_binary.R,
+	  src/rgeos_poly2nb.c, src/rgeos_predicate_binary.c: tidy
+
+2014-03-31 19:58  rsbivand
+
+	* src/rgeos_predicate_binary.c: permit binary predicates to return
+	  lists
+
+2014-03-31 19:46  rsbivand
+
+	* src/rgeos_predicate_binary.c: permit binary predicates to return
+	  lists
+
+2014-03-31 17:15  rsbivand
+
+	* DESCRIPTION, R/AAA.R, R/rgeos_predicate_binary.R, R/rgeos_util.R,
+	  man/experimental-functions.Rd, man/pred-binary-gContains.Rd,
+	  man/pred-binary-gCrosses.Rd, man/pred-binary-gEquals.Rd,
+	  man/pred-binary-gIntersects.Rd, man/pred-binary-gTouches.Rd,
+	  src/rgeos_R2geos.c, src/rgeos_poly2nb.c,
+	  src/rgeos_predicate_binary.c: permit binary predicates to return
+	  lists
+
+2014-03-25 14:00  rsbivand
+
+	* configure: tidy
+
+2014-03-25 13:55  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-03-23 09:22  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/Rgpc_funcs.R, R/rgeos_topology.R,
+	  inst/wkts/sppsp.wkt, man/topo-unary-gDelaunayTriangulation.Rd,
+	  man/topo-unary-gNode.Rd, man/topo-unary-gPolygonize.Rd,
+	  src/init.c, src/rgeos.h, src/rgeos_topology.c: exposing noding
+
+2014-02-13 15:30  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-02-13 15:28  rsbivand
+
+	* src/rgeos_topology_binary.c: cast to remove warnings
+
+2014-02-13 08:52  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-02-13 08:51  rsbivand
+
+	* DESCRIPTION, src/rgeos_coord.c, src/rgeos_geos2R.c: changed
+	  PROTECT code for crdMAT
+
+2014-02-08 15:50  rsbivand
+
+	* DESCRIPTION, R/AAA.R, R/rgeos_topology_binary.R,
+	  man/topo-bin-gDifference.Rd, man/topo-bin-gIntersection.Rd,
+	  man/topo-bin-gSymdifference.Rd, man/topo-bin-gUnion.Rd,
+	  src/rgeos_topology_binary.c: drop not poly intersections if both
+	  poly
+
+2014-01-27 19:35  rsbivand
+
+	* src/rgeos_geos2R.c: added id report on GC in GC
+
+2014-01-27 19:06  rsbivand
+
+	* src/rgeos_geos2R.c, src/rgeos_topology_binary.c: added id report
+	  on GC in GC
+
+2014-01-22 12:13  rsbivand
+
+	* src/rgeos_predicate_binary.c: fix over-generous symmetry in binar
+	  predicates
+
+2014-01-22 12:09  rsbivand
+
+	* DESCRIPTION, src/rgeos.h, src/rgeos_predicate_binary.c: fix
+	  over-generous symmetry in binar predicates
+
+2013-12-06 23:34  crundel
+
+	* R/rgeos_predicate_binary.R: Fix for an edge case of predicates
+	  with multipoint geometries
+	  
+	  There is an issue if some points share in a SpatialPoints object
+	  share an ID since there will be a mismatch between the number of
+	  output IDs
+
+2013-10-06 13:29  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-10-06 13:28  rsbivand
+
+	* R/rgeos_buffer.R, man/misc-gBuffer.Rd: blocking EMPTY
+
+2013-10-05 14:46  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-10-05 14:35  rsbivand
+
+	* inst/tests/test-translate-empty.R,
+	  inst/tests/testxml/general/TestBoundary.xml,
+	  inst/tests/testxml/general/TestFunctionLA.xml,
+	  inst/tests/testxml/general/TestFunctionLL.xml,
+	  inst/tests/testxml/general/TestFunctionPP.xml,
+	  inst/tests/testxml/general/TestSimple.xml,
+	  inst/tests/testxml/general/TestValid.xml,
+	  inst/tests/testxml/general/TestValid2.xml,
+	  inst/tests/testxml/robust/ExternalRobustness.xml,
+	  man/misc-gBuffer.Rd, man/pred-unary-gIsEmpty.Rd,
+	  man/wkt-functions.Rd, src/rgeos_geos2R.c: blocking EMPTY
+
+2013-10-04 19:04  rsbivand
+
+	* R/rgeos_buffer.R, man/misc-gBuffer.Rd, src/rgeos_buffer.c: adding
+	  buffer widths either 1 or n
+
+2013-10-04 12:08  rsbivand
+
+	* DESCRIPTION: removing empty polygons
+
+2013-10-04 12:05  rsbivand
+
+	* DESCRIPTION, R/rgeos_buffer.R, src/rgeos_buffer.c,
+	  src/rgeos_geos2R.c: removing empty polygons
+
+2013-09-16 12:23  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-09-16 12:22  rsbivand
+
+	* man/topo-unary-gDelaunayTriangulation.Rd: tidy
+
+2013-09-16 11:15  rsbivand
+
+	* man/topo-unary-gDelaunayTriangulation.Rd: tidy
+
+2013-09-16 11:01  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-09-03 10:17  rsbivand
+
+	* NAMESPACE, R/rgeos_topology.R,
+	  man/topo-unary-gDelaunayTriangulation.Rd, src/rgeos_topology.c:
+	  Delaunay triangulation
+
+2013-09-02 21:14  rsbivand
+
+	* R/rgeos_topology.R: start incorporating triangulation
+
+2013-09-02 19:18  rsbivand
+
+	* DESCRIPTION, R/rgeos_topology.R, src/init.c, src/rgeos.h,
+	  src/rgeos_topology.c: start incorporating triangulation
+
+2013-09-02 12:29  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-09-02 12:28  rsbivand
+
+	* inst/tests/testxml/general/TestInteriorPoint.xml: revert xml
+	  tests to pass GEOS 3.2.0
+
+2013-09-01 17:47  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-09-01 17:22  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-09-01 17:20  rsbivand
+
+	* DESCRIPTION, cleanup, man/topo-unary-gPointOnSurface.Rd: add
+	  cleanup
+
+2013-09-01 16:40  rsbivand
+
+	* inst/tests/testxml/general/TestInteriorPoint.xml: revert two
+	  changes in gPointOnSurface test to match GEOS 3.4.* to suit < 3.4
+
+2013-09-01 10:31  rsbivand
+
+	* inst/tests/testxml/general/TestInteriorPoint.xml,
+	  man/topo-unary-gPointOnSurface.Rd: change gPointOnSurface test to
+	  match GEOS 3.4.*
+
+2013-08-30 16:52  edzer
+
+	* DESCRIPTION, R/over.R, man/comment-functions.Rd, man/labelpt.Rd,
+	  man/topo-unary-gPolygonize.Rd, man/utility-functions.Rd: moved sp
+	  and methods from Depends: to Imports:
+	  added library(sp) to the examples, where needed
+	  removed the ::: using the exported overDF_for_rgeos from sp
+	  1.0-12
+	  increased sp dependency to 1.0-12
+
+2013-07-18 10:30  rsbivand
+
+	* DESCRIPTION, src/rgeos_R2geos.c: check comment length against
+	  Polygons slot
+
+2013-07-17 13:57  rsbivand
+
+	* man/pred-binary-gContains.Rd: tidy
+
+2013-07-02 20:17  rhijmans
+
+	* R/rgeos_buffer.R:
+
+2013-07-02 20:15  rhijmans
+
+	* man/misc-gBuffer.Rd:
+
+2013-07-02 20:12  rhijmans
+
+	* R/rgeos_buffer.R:
+
+2013-06-22 14:17  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-06-22 14:16  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/labelpt.R, man/labelpt.Rd: update
+	  patched to polygonsLabel
+
+2013-06-22 13:40  rsbivand
+
+	* ChangeLog, inst/ChangeLog: more symbol check issues
+
+2013-06-22 13:39  rsbivand
+
+	* R/AAA.R, R/rgeos_misc.R, R/rgeos_predicate_binary.R,
+	  R/rgeos_predicate_unary.R, R/rgeos_topology.R,
+	  R/rgeos_topology_binary.R: tidy
+
+2013-06-22 12:23  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-06-22 12:23  rsbivand
+
+	* man/comment-functions.Rd, man/constructor-SpatialCollections.Rd,
+	  man/misc-gBuffer.Rd, man/misc-gDistance.Rd,
+	  man/pred-binary-gIntersects.Rd, man/pred-binary-gRelate.Rd,
+	  man/pred-unary-gIsValid.Rd, man/topo-bin-gIntersection.Rd,
+	  man/topo-bin-gUnion.Rd, man/topo-unary-gCentroid.Rd,
+	  man/topo-unary-gConvexHull.Rd, man/topo-unary-gEnvelope.Rd,
+	  man/topo-unary-gPointOnSurface.Rd, man/topo-unary-gSimplify.Rd:
+	  more symbol check issues
+
+2013-06-21 11:44  rsbivand
+
+	* DESCRIPTION, R/AAA.R: tidy
+
+2013-05-05 08:03  rsbivand
+
+	* configure, configure.ac: add Unversioned directory to svn
+	  revision
+
+2013-04-26 09:26  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-04-26 09:26  rsbivand
+
+	* DESCRIPTION: Kirill Müller's reversion to GEOS 3.2.0
+
+2013-04-26 09:25  rsbivand
+
+	* DESCRIPTION, configure, configure.ac: Kirill Müller's reversion
+	  to GEOS 3.2.0
+
+2013-04-09 16:47  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-04-09 13:47  rsbivand
+
+	* src/rgeos_geos2R.c: length of IDs guard
+
+2013-04-08 17:30  rsbivand
+
+	* R/rgeos_topology.R, man/topo-unary-gPolygonize.Rd: fix bug in
+	  gPolygonize ids
+
+2013-04-06 08:05  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-04-06 08:04  rsbivand
+
+	* configure, configure.ac: checking with clang++ in configure
+
+2013-04-05 21:05  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-04-05 20:02  rsbivand
+
+	* configure: update configure.ac to force C++ test linking
+
+2013-04-05 19:58  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-04-05 19:53  rsbivand
+
+	* DESCRIPTION, configure, configure.ac: update configure.ac to
+	  force C++ test linking
+
+2013-03-29 11:00  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-03-29 10:59  rsbivand
+
+	* ChangeLog, DESCRIPTION, inst/ChangeLog, src/rgeos_R2geos.c,
+	  src/rgeos_R2geosMP.c, src/rgeos_bbox.c, src/rgeos_buffer.c,
+	  src/rgeos_coord.c, src/rgeos_geos2R.c, src/rgeos_topology.c,
+	  src/rgeos_topology_binary.c: remove clang warnings
+
+2013-03-04 09:53  rsbivand
+
+	* configure: tidy
+
+2013-02-23 11:39  rsbivand
+
+	* DESCRIPTION, R/rgeos_buffer.R, R/rgeos_misc.R,
+	  R/rgeos_predicate_binary.R, R/rgeos_predicate_unary.R,
+	  R/rgeos_topology.R, R/rgeos_topology_binary.R, R/rgeos_wkt.R:
+	  enforce logical byid
+
+2013-02-06 16:58  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-02-06 09:18  rsbivand
+
+	* DESCRIPTION, R/rgeos_topology.R, man/topo-unary-gPolygonize.Rd:
+	  fix bug in gPolygonize for > 2 output objects
+
+2013-01-31 16:46  rsbivand
+
+	* inst/tests/testxml/general,
+	  inst/tests/testxml/general/TestBoundary.xml,
+	  inst/tests/testxml/general/TestCentroid.xml,
+	  inst/tests/testxml/general/TestConvexHull-big.xml,
+	  inst/tests/testxml/general/TestConvexHull.xml,
+	  inst/tests/testxml/general/TestFunctionAA.xml,
+	  inst/tests/testxml/general/TestFunctionAAPrec.xml,
+	  inst/tests/testxml/general/TestFunctionLA.xml,
+	  inst/tests/testxml/general/TestFunctionLAPrec.xml,
+	  inst/tests/testxml/general/TestFunctionLL.xml,
+	  inst/tests/testxml/general/TestFunctionLLPrec.xml,
+	  inst/tests/testxml/general/TestFunctionPA.xml,
+	  inst/tests/testxml/general/TestFunctionPL.xml,
+	  inst/tests/testxml/general/TestFunctionPLPrec.xml,
+	  inst/tests/testxml/general/TestFunctionPP.xml,
+	  inst/tests/testxml/general/TestInteriorPoint.xml,
+	  inst/tests/testxml/general/TestRectanglePredicate.xml,
+	  inst/tests/testxml/general/TestRelateAA.xml,
+	  inst/tests/testxml/general/TestRelateAC.xml,
+	  inst/tests/testxml/general/TestRelateLA.xml,
+	  inst/tests/testxml/general/TestRelateLC.xml,
+	  inst/tests/testxml/general/TestRelateLL.xml,
+	  inst/tests/testxml/general/TestRelatePA.xml,
+	  inst/tests/testxml/general/TestRelatePL.xml,
+	  inst/tests/testxml/general/TestRelatePP.xml,
+	  inst/tests/testxml/general/TestSimple.xml,
+	  inst/tests/testxml/general/TestValid.xml,
+	  inst/tests/testxml/general/TestValid2-big.xml,
+	  inst/tests/testxml/general/TestValid2.xml,
+	  inst/tests/testxml/general/TestWithinDistance.xml: tidy
+
+2013-01-31 16:45  rsbivand
+
+	* inst/tests/testxml/general: tidy
+
+2013-01-16 09:03  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-01-16 09:02  rsbivand
+
+	* DESCRIPTION, R/AAA.R: move startup message to .onAttach
+
+2012-12-18 14:10  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-12-18 14:09  rsbivand
+
+	* DESCRIPTION: tidy
+
+2012-12-08 17:29  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-12-08 16:53  rsbivand
+
+	* R/AAA.R: versions in startup messages
+
+2012-12-08 16:50  rsbivand
+
+	* R/AAA.R: versions in startup messages
+
+2012-12-08 16:47  rsbivand
+
+	* configure, configure.ac: versions in configure
+
+2012-12-03 20:27  rsbivand
+
+	* R/AAA.R: tidy
+
+2012-11-20 20:13  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-11-20 20:09  rsbivand
+
+	* DESCRIPTION: cumulation change in rgeos_binarytopologyfunc to
+	  avoid collection in collection error
+
+2012-11-20 19:21  rsbivand
+
+	* src/rgeos_topology_binary.c: cumulation change in
+	  rgeos_binarytopologyfunc to avoid collection in collection error
+
+2012-11-12 09:30  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-11-12 08:00  rsbivand
+
+	* R/gpc_geos.R: adding conversion of a NULL to gpc.poly
+
+2012-11-11 19:01  rsbivand
+
+	* DESCRIPTION, R/Rgpc_funcs.R: adding conversion of a NULL to
+	  gpc.poly
+
+2012-11-05 17:30  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-11-05 17:30  rsbivand
+
+	* man/comment-functions.Rd: dontrun part of check holes example
+
+2012-11-05 08:56  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-11-05 08:55  rsbivand
+
+	* DESCRIPTION: tidy
+
+2012-09-30 18:05  edzer
+
+	* DESCRIPTION, NAMESPACE, R/rgeos_wkt.R: removed dependency on
+	  stringr and plyr, replaced two str_ function
+	  calls with the equivalent ones in base R.
+
+2012-09-06 09:30  rsbivand
+
+	* inst/wkts, inst/wkts/sline1.wkt, inst/wkts/sline2.wkt,
+	  man/utility-functions.Rd: setScale example from Mao-Gui Hu
+
+2012-08-19 13:07  edzer
+
+	* NAMESPACE, R/labelpt.R, man/labelpt.Rd: update function name;
+	  cosmetics.
+
+2012-08-17 20:20  edzer
+
+	* DESCRIPTION, NAMESPACE, R/labelpt.R, man/labelpt.Rd: added first
+	  attempt to label points functions, that evolved from
+	  https://stat.ethz.ch/pipermail/r-sig-geo/2012-July/015693.html ;
+	  edited author at R section to DESCRIPTION.
+
+2012-06-24 14:41  rsbivand
+
+	* DESCRIPTION, src/rgeos.c, src/rgeos.h, src/rgeos_R2geosMP.c,
+	  src/rgeos_coord.c, src/rgeos_poly2nb.c: remove some -Wall
+	  warnings
+
+2012-06-24 13:28  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-06-24 13:27  rsbivand
+
+	* DESCRIPTION, src/dummy.cc, src/local_stubs.c: adding src/dummy.cc
+
+2012-05-07 16:48  rsbivand
+
+	* DESCRIPTION, src/rgeos_misc.c: fixed single geometry bug in
+	  gDistance
+
+2012-05-02 09:58  rsbivand
+
+	* ChangeLog, inst/ChangeLog: more configure updates
+
+2012-05-02 09:58  rsbivand
+
+	* configure, configure.ac: more configure updates
+
+2012-04-24 10:56  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-04-24 10:54  rsbivand
+
+	* configure, configure.ac: tidying configure.ac
+
+2012-04-22 11:42  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-04-22 11:42  rsbivand
+
+	* DESCRIPTION: add plyr dependency
+
+2012-04-20 08:32  rsbivand
+
+	* configure, configure.ac: tidy
+
+2012-04-20 07:06  rsbivand
+
+	* R/AAA.R: tidy
+
+2012-04-20 07:01  rsbivand
+
+	* DESCRIPTION: tidy
+
+2012-04-20 07:01  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-04-20 07:00  rsbivand
+
+	* configure, configure.ac, configure.in, src/Makevars.in: upgrading
+	  configure
+
+2012-04-19 13:20  rsbivand
+
+	* inst/tests/test-translate-polygon-collection.R,
+	  src/rgeos_geos2R.c: fixed broken tests
+
+2012-04-17 13:38  rsbivand
+
+	* DESCRIPTION, inst/tests/test-translate-polygons.R,
+	  src/rgeos_geos2R.c: broken tests
+
+2012-04-16 13:21  rsbivand
+
+	* R/rgeos_util.R: using top-level comment to SpatialPolygons for
+	  all member Polygons commented with OGC SFS kludge
+
+2012-04-16 13:13  rsbivand
+
+	* DESCRIPTION, R/rgeos_misc.R, R/rgeos_predicate_binary.R,
+	  R/rgeos_predicate_unary.R, R/rgeos_topology.R,
+	  R/rgeos_topology_binary.R, R/rgeos_util.R: using top-level
+	  comment to SpatialPolygons for all member Polygons commented with
+	  OGC SFS kludge
+
+2012-03-17 15:08  rsbivand
+
+	* ChangeLog, DESCRIPTION, inst/ChangeLog: tidy
+
+2012-03-16 18:53  crundel
+
+	* src/rgeos_R2geos.c: Fixed crashing bug when ignoring holes with
+	  unknown parent poly
+
+2012-03-16 14:46  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-03-16 11:54  rsbivand
+
+	* DESCRIPTION, R/rgeos_misc.R: added createSPComment to
+	  RGEOSMiscFunc
+
+2012-02-22 17:00  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-02-22 16:59  rsbivand
+
+	* DESCRIPTION: tidy
+
+2012-01-30 10:44  rsbivand
+
+	* DESCRIPTION, R/rgeos_topology.R: revise gLineMerge
+
+2012-01-27 12:31  rsbivand
+
+	* man/topo-bin-gUnion.Rd: fix documentation
+
+2012-01-20 10:12  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-01-19 19:25  rsbivand
+
+	* src/rgeos_poly2nb.c: fixing gBinarySTRtreeQuery
+
+2012-01-19 19:08  rsbivand
+
+	* man/experimental-functions.Rd, src/rgeos_poly2nb.c: fixing
+	  gBinarySTRtreeQuery
+
+2012-01-18 19:11  rsbivand
+
+	* DESCRIPTION, src/rgeos_poly2nb.c: fixing gBinarySTRtreeQuery
+
+2012-01-15 13:12  rsbivand
+
+	* ChangeLog, DESCRIPTION, inst/ChangeLog: tidy
+
+2012-01-15 11:37  edzer
+
+	* DESCRIPTION, src/rgeos_predicate_binary.c: added r-forge URL to
+	  DESCRIPTION
+	  added type casts to remove compilation warnings
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_geos2R.c: Cleanup
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_topology.c, src/rgeos_topology_binary.c: Cleanup and
+	  memory leak
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_R2geos.c: memory leak
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_predicate_binary.c, src/rgeos_predicate_unary.c:
+	  cleanup
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_geos2R.c: Small memory leak
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_bbox.c: Fixing what I broke
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_geos2R.c: Cleanup
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_R2geos.c, src/rgeos_R2geosMP.c: Cleanup and moved
+	  multipoint functions to new source file
+
+2012-01-15 09:58  crundel
+
+	* inst/tests/process_testxml.R, inst/tests/test-jts-xml.R: Break up
+	  XML test runner to allow for separate testing
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_bbox.c: Should function for all geometry types now
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos.h, src/rgeos_coord.c: Fixed const correctness for
+	  coordSequence
+
+2012-01-15 09:58  crundel
+
+	* src/gpc_geos.c, src/init.c, src/rgeos.h: Removed gpc_geos
+	  functions since we arn't using them
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos.h: cleanup
+
+2012-01-15 09:58  crundel
+
+	* src/gpc_geos.c, src/rgeos.h: Lots of cleaning and minor
+	  refactoring, changes have not been tested since we don't
+	  currently use any of this functionality
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_coord.c: cleanup
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_geos2R.c: cleanup
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_R2geos.c: cleanup
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_R2geos.c: Don't use the handle here
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_R2geos.c: Removed unused scale variable
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_R2geos.c: Cleaned tabs
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_topology.c: More cleanup, removed unused curtype
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_topology.c: Cleanup and switch to use just one call to
+	  GEOSGeomTypeId_r
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_geos2R.c: Cleaning tabs
+
+2012-01-13 00:02  crundel
+
+	* src/rgeos_geos2R.c: Cleanup and memory leak fix
+
+2012-01-13 00:02  crundel
+
+	* src/rgeos_geos2R.c: Cleanup
+
+2012-01-13 00:02  crundel
+
+	* inst/tests/test-translate-lines.R,
+	  inst/tests/test-translate-points.R,
+	  inst/tests/test-translate-polygon-collection.R,
+	  inst/tests/test-translate-polygons.R,
+	  inst/tests/test-translate-rings.R, inst/tests/test-translate.R:
+	  Break up translate tests into separate files
+
+2012-01-09 07:59  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-01-08 21:42  edzer
+
+	* src/rgeos_geos2R.c: one more memory leak fixed.
+
+2012-01-08 19:46  edzer
+
+	* DESCRIPTION, src/rgeos_bbox.c, src/rgeos_poly2nb.c,
+	  src/rgeos_validate.c: version bump; fixed more memory leaks.
+
+2012-01-07 13:22  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-01-06 23:20  edzer
+
+	* src/rgeos_buffer.c, src/rgeos_geos2R.c: further memory release
+	  hunting...
+
+2012-01-06 18:31  edzer
+
+	* DESCRIPTION, src/rgeos_R2geos.c, src/rgeos_buffer.c,
+	  src/rgeos_coord.c, src/rgeos_geos2R.c, src/rgeos_topology.c,
+	  src/rgeos_wkt.c: version bump; hunt for memory leaks.
+
+2012-01-05 22:07  edzer
+
+	* src/rgeos_buffer.c: un-commented the GEOS_destroy_r() commands in
+	  buffer, after adding conditions.
+
+2012-01-02 09:06  rsbivand
+
+	* ChangeLog, inst/ChangeLog: avoid gpclib suggest via maptools
+
+2012-01-02 09:05  rsbivand
+
+	* DESCRIPTION, man/gpc-new-generics.Rd: avoid gpclib suggest via
+	  maptools
+
+2011-12-14 09:11  rsbivand
+
+	* ChangeLog, inst/ChangeLog: revert destroy in R2geos.c
+
+2011-12-14 09:10  rsbivand
+
+	* DESCRIPTION, src/rgeos_R2geos.c: revert destroy in R2geos.c
+
+2011-12-10 11:37  rsbivand
+
+	* ChangeLog, inst/ChangeLog: clear stringr 0.6 mess
+
+2011-12-10 11:36  rsbivand
+
+	* DESCRIPTION, src/rgeos_R2geos.c: clear stringr 0.6 mess
+
+2011-12-10 07:44  crundel
+
+	* R/rgeos_wkt.R: Changed str_match_all to str_extract_all
+
+2011-12-09 22:04  crundel
+
+	* tests/test-all.R: use test_package from testthat instead of
+	  test_file
+
+2011-12-09 22:04  crundel
+
+	* R/rgeos_wkt.R: Fix to address small change in return type from
+	  stringr str_match_all function
+
+2011-11-28 14:55  rsbivand
+
+	* src/rgeos_buffer.c: moved curgeom inside loop
+
+2011-11-18 03:57  crundel
+
+	* src/rgeos_topology_binary.c: Fix returned id for binary topology
+	  operations
+
+2011-11-14 18:39  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-11-14 18:38  rsbivand
+
+	* DESCRIPTION, configure, configure.in, src/init.c, src/rgeos.h,
+	  src/rgeos_topology.c: move HAVE_UNARYUNION to rgeos.h
+
+2011-11-14 10:55  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-11-10 07:43  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-11-09 10:51  rsbivand
+
+	* DESCRIPTION, src/rgeos_topology_binary.c: drop empty objects
+	  before building Geometry Collection in binary topology ops
+
+2011-10-30 18:59  rsbivand
+
+	* DESCRIPTION, man/topo-unary-gSimplify.Rd, src/gpc_geos.c,
+	  src/rgeos_buffer.c, src/rgeos_geos2R.c: tickling destroy
+
+2011-10-25 21:22  crundel
+
+	* DESCRIPTION: Require stringr >= 0.5
+
+2011-10-19 19:20  rsbivand
+
+	* src/gpc_geos.c, src/rgeos_geos2R.c: add space character for
+	  safety in comment
+
+2011-10-19 18:52  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-10-19 18:51  rsbivand
+
+	* DESCRIPTION, src/gpc_geos.c, src/local_stubs.c,
+	  src/rgeos_geos2R.c: fix comment string length
+
+2011-09-16 07:24  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-09-16 07:22  rsbivand
+
+	* DESCRIPTION: tidy
+
+2011-09-05 12:35  rsbivand
+
+	* src/rgeos_poly2nb.c: STRtree loop simplification (strcmp before
+	  loop)
+
+2011-09-05 08:07  rsbivand
+
+	* src/rgeos_poly2nb.c: STRtree loop simplification (strcmp before
+	  loop)
+
+2011-09-04 18:29  rsbivand
+
+	* R/rgeos_util.R, src/rgeos_poly2nb.c: callback corrections
+
+2011-09-03 14:34  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, R/rgeos_spExtensions_Classes.R,
+	  src/rgeos_buffer.c, src/rgeos_wkt.c: changed dependency load
+	  syntax
+
+2011-09-03 03:32  crundel
+
+	* src/rgeos_poly2nb.c: Cleanup of build warnings from using
+	  callback pointer
+
+2011-09-03 03:32  crundel
+
+	* src/rgeos.h, src/rgeos_misc.c, src/rgeos_predicate_binary.c,
+	  src/rgeos_predicate_unary.c, src/rgeos_topology.c,
+	  src/rgeos_topology_binary.c: Cleanup of build warnings from
+	  function pointers
+
+2011-06-11 06:59  rsbivand
+
+	* ChangeLog, inst/ChangeLog: touch local_stubs.c
+
+2011-06-11 06:59  rsbivand
+
+	* src/local_stubs.c: touch local_stubs.c
+
+2011-06-11 05:26  rsbivand
+
+	* ChangeLog, inst/ChangeLog: permit NA IDs in union
+
+2011-06-11 05:25  rsbivand
+
+	* R/rgeos_topology.R: permit NA IDs in union
+
+2011-06-10 22:06  rsbivand
+
+	* DESCRIPTION, R/rgeos_topology.R, configure.in,
+	  man/topo-bin-gUnion.Rd, src/gpc_geos.c, src/rgeos_geos2R.c: sp
+	  comment buffer overflow fix
+
+2011-06-09 14:04  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-06-09 13:55  rsbivand
+
+	* DESCRIPTION: update sp version
+
+2011-06-09 08:23  rsbivand
+
+	* R/rgeos_topology.R, man/topo-bin-gUnion.Rd: gUnionCascaded
+	  suggestion
+
+2011-06-09 06:21  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, R/rgeos_topology.R, configure,
+	  configure.in, man/pred-binary-gTouches.Rd,
+	  man/topo-bin-gUnion.Rd, man/utility-functions.Rd, src/init.c,
+	  src/rgeos.h, src/rgeos_topology.c: adding UnaryUnion for GEOS
+	  3.3.0
+
+2011-05-24 16:15  rsbivand
+
+	* DESCRIPTION: added version to GEOS required
+
+2011-05-24 11:27  edzer
+
+	* DESCRIPTION: increased dependency on sp 0.9-73, which has over
+	  defined as generic.
+
+2011-05-18 21:07  rsbivand
+
+	* ChangeLog, inst/ChangeLog: RGEOSBinPredFunc single argument fix
+
+2011-05-18 21:06  rsbivand
+
+	* R/rgeos_predicate_binary.R, R/rgeos_predicate_unary.R,
+	  R/rgeos_topology.R, R/rgeos_topology_binary.R: RGEOSBinPredFunc
+	  single argument fix
+
+2011-05-18 20:53  rsbivand
+
+	* ChangeLog, inst/ChangeLog: RGEOSBinPredFunc single argument fix
+
+2011-05-18 20:49  rsbivand
+
+	* DESCRIPTION, R/rgeos_predicate_binary.R: RGEOSBinPredFunc single
+	  argument fix
+
+2011-05-11 12:49  edzer
+
+	* R/over.R: improved over methods for gridded objects
+
+2011-05-09 20:31  edzer
+
+	* R/over.R: added the lines & (grids / pixels) methods for "over"
+	  overlay.
+
+2011-05-09 16:50  edzer
+
+	* DESCRIPTION, R/over.R: added 18 overlay methods for "over" (from
+	  sp)
+
+2011-03-30 14:42  rsbivand
+
+	* ChangeLog, inst/ChangeLog: attempts to limit memory hunger
+
+2011-03-30 14:40  rsbivand
+
+	* R/AAA.R, R/rgeos_util.R, src/rgeos_poly2nb.c,
+	  src/rgeos_predicate_binary.c, src/rgeos_predicate_unary.c:
+	  attempts to limit memory hunger
+
+2011-03-29 08:25  rsbivand
+
+	* DESCRIPTION, R/rgeos_util.R, man/experimental-functions.Rd,
+	  man/topo-bin-gIntersection.Rd, src/rgeos.h, src/rgeos_R2geos.c,
+	  src/rgeos_poly2nb.c: STRtree for Polygons
+
+2011-03-28 09:40  rsbivand
+
+	* ChangeLog, inst/ChangeLog: documenting hole checking for Polygons
+	  objects
+
+2011-03-28 09:39  rsbivand
+
+	* R/AAA.R: documenting hole checking for Polygons objects
+
+2011-03-28 09:29  rsbivand
+
+	* ChangeLog, inst/ChangeLog: documenting hole checking for Polygons
+	  objects
+
+2011-03-28 09:28  rsbivand
+
+	* DESCRIPTION, configure, configure.in, man/comment-functions.Rd:
+	  documenting hole checking for Polygons objects
+
+2011-03-26 19:41  rsbivand
+
+	* R/rgeos_buffer.R, R/rgeos_misc.R: adding projection check for
+	  buffer and misc
+
+2011-03-26 19:29  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, R/rgeos_buffer.R,
+	  R/rgeos_misc.R, R/rgeos_predicate_binary.R,
+	  R/rgeos_predicate_unary.R, R/rgeos_topology.R,
+	  R/rgeos_topology_binary.R, R/rgeos_util.R,
+	  man/comment-functions.Rd, src/rgeos_geos2R.c, tests/test-all.R:
+	  imposing polygon checking unless option set
+
+2011-03-21 10:13  rsbivand
+
+	* ChangeLog, inst/ChangeLog: prerelease
+
+2011-03-21 09:04  rsbivand
+
+	* ChangeLog, inst/ChangeLog: prerelease
+
+2011-03-21 09:03  rsbivand
+
+	* DESCRIPTION: prerelease
+
+2011-02-26 23:03  rsbivand
+
+	* inst/tests/test-jts-xml.R: xml file reading wrapper for 32-bit
+	  libxml2 on F14 in tests
+
+2011-02-06 14:58  rsbivand
+
+	* R/AAA.R: suppress startup messages
+
+2010-11-30 17:38  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2010-11-24 12:31  rsbivand
+
+	* R/rgeos_topology.R, R/rgeos_util.R, man/topo-bin-gUnion.Rd:
+	  g*STRtreeQuery added to experimental
+
+2010-11-24 10:44  rsbivand
+
+	* man/experimental-functions.Rd: g*STRtreeQuery added to
+	  experimental
+
+2010-11-24 10:39  rsbivand
+
+	* ChangeLog, inst/ChangeLog: g*STRtreeQuery added to experimental
+
+2010-11-24 10:39  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/rgeos_util.R,
+	  man/experimental-functions.Rd, src/rgeos_poly2nb.c:
+	  g*STRtreeQuery added to experimental
+
+2010-11-19 21:56  rsbivand
+
+	* .Rbuildignore: add rgeos_unary_STRtree_query and
+	  rgeos_binary_STRtree_query
+
+2010-11-19 21:54  rsbivand
+
+	* src/init.c, src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_poly2nb.c:
+	  add rgeos_unary_STRtree_query and rgeos_binary_STRtree_query
+
+2010-11-19 13:18  rsbivand
+
+	* src/rgeos_poly2nb.c: STRtree attempts
+
+2010-11-18 23:07  crundel
+
+	* inst/tests/testxml/vivid: Removing empty folder
+
+2010-11-08 20:43  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2010-11-08 20:42  rsbivand
+
+	* DESCRIPTION: tidy
+
+2010-11-08 20:39  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2010-11-08 20:05  crundel
+
+	* inst/poly-ex-gpc, inst/poly-ex-gpc/ex-poly1.txt,
+	  inst/poly-ex-gpc/ex-poly2.txt, inst/poly-ex-gpc/hole-poly.txt:
+	  Added gpc polygon example data files
+
+2010-11-08 20:02  crundel
+
+	* data, man/class-gpc.poly.Rd, man/experimental-functions.Rd: More
+	  clean up
+
+2010-11-08 19:44  crundel
+
+	* DESCRIPTION, inst/tests/test-jts-xml.R, man,
+	  man/class-gpc.poly.Rd, tests, tests/test-all.R: Package clean up
+	  for release
+
+2010-11-07 19:38  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2010-11-07 19:18  rsbivand
+
+	* configure.win, src/Makevars.win: Windows static build
+
+2010-11-01 18:02  crundel
+
+	* R/rgeos_misc.R, src/rgeos_R2geos.c: Fixed a bug in handling
+	  polygons with holes but no comment.
+
+2010-09-29 17:51  crundel
+
+	* NAMESPACE, R/rgeos_util.R:
+
+2010-09-26 20:29  crundel
+
+	* R/rgeos_util.R, src/rgeos_R2geos.c, tests/test-all.R: Small fixes
+	  to get CHECK to work
+
+2010-09-09 20:47  crundel
+
+	* src/rgeos_R2geos.c: Changed translate functions so that
+	  unassigned holes are ignored and a warning reported.
+
+2010-09-09 19:56  crundel
+
+	* NAMESPACE, R/gpc_geos.R, R/rgeos.R, R/rgeos_util.R,
+	  man/checkHolesGPC.Rd, man/checkPolygonsGEOS.Rd,
+	  man/comment-functions.Rd, src/init.c, src/rgeos.h,
+	  src/rgeos_R2geos.c, src/rgeos_validate.c: Removed
+	  checkPolygonsGEOS and checkHolesGPC functions and replaced then
+	  with createPolygonsComment and createSPComment functions. Similar
+	  functionality, but removes guessing of hole status for polygons
+	  and focuses on assign ownership via comment attributes.
+
+2010-08-16 12:36  crundel
+
+	* src/rgeos_predicate_binary.c: Added const to prepared geometry to
+	  deal with compiler warning
+
+2010-08-16 12:34  crundel
+
+	* man/pred-binary-gEquals.Rd, man/pred-binary-gRelate.Rd: Small
+	  docs typo fix
+
+2010-08-16 12:31  crundel
+
+	* inst/tests/test-jts-xml.R, tests/test-all.R: Small test fixes
+	  
+	  Some of the tests in the JTS xml files are skipped due to
+	  compatibility issues, see descSkip
+
+2010-08-16 12:27  crundel
+
+	* R/rgeos_predicate_binary.R, man/pred-binary-gEquals.Rd,
+	  man/pred-binary-gRelate.Rd, man/pred-unary-gIsSimple.Rd,
+	  man/pred-unary-gIsValid.Rd, man/topo-unary-gSimplify.Rd: Small
+	  documentation fixes
+	  
+	  Put tol and pattern as 3rd arguments in gEquals and gRelate
+
+2010-08-16 11:46  crundel
+
+	* man/misc-gDistance.Rd, man/pred-binary-gContains.Rd,
+	  man/pred-binary-gCrosses.Rd, man/pred-binary-gEquals.Rd,
+	  man/pred-binary-gIntersects.Rd, man/pred-binary-gRelate.Rd,
+	  man/pred-binary-gTouches.Rd, man/pred-unary-gIsSimple.Rd,
+	  man/pred-unary-gIsValid.Rd, man/topo-bin-gDifference.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gSymdifference.Rd,
+	  man/topo-bin-gUnion.Rd, man/topo-unary-gBoundary.Rd,
+	  man/topo-unary-gCentroid.Rd, man/topo-unary-gConvexHull.Rd,
+	  man/topo-unary-gEnvelope.Rd, man/topo-unary-gPointOnSurface.Rd,
+	  man/topo-unary-gPolygonize.Rd, man/topo-unary-gSimplify.Rd:
+	  Documentation update
+
+2010-08-16 11:45  crundel
+
+	* NAMESPACE: Commented out poly_findInBoxGEOS
+
+2010-08-16 10:25  crundel
+
+	* R/rgeos_topology.R: Simplified function arguments for gSimplify
+	  since byid doesnt really matter.
+
+2010-08-16 09:10  crundel
+
+	* R/rgeos_spExtensions_Methods.R: Added isGenerics checks for
+	  row.names and row.names<-
+
+2010-08-16 09:09  crundel
+
+	* NAMESPACE, R/rgeos_predicate_binary.R: Separated Equals and
+	  EqualsExact back into different functions, had misunderstood how
+	  they worked.
+	  
+	  Removed groupID from NAMESPACE for the time being, probably needs
+	  to be reimplemented in C.
+
+2010-08-15 13:46  crundel
+
+	* man/misc-gArea.Rd, man/misc-gBuffer.Rd, man/misc-gDistance.Rd,
+	  man/misc-gLength.Rd, man/pred-unary-gIsEmpty.Rd,
+	  man/pred-unary-gIsRing.Rd, man/pred-unary-gIsSimple.Rd,
+	  man/pred-unary-gIsValid.Rd, man/topo-bin-gUnion.Rd,
+	  man/topo-unary-gBoundary.Rd, man/topo-unary-gCentroid.Rd,
+	  man/topo-unary-gConvexHull.Rd, man/topo-unary-gEnvelope.Rd:
+	  Documentation update
+
+2010-08-15 13:44  crundel
+
+	* NAMESPACE, R/rgeos_buffer.R, R/rgeos_predicate_binary.R,
+	  src/init.c, src/rgeos.h, src/rgeos_predicate_binary.c: Fixed bug
+	  with gRelate when pattern was specified
+	  
+	  Combined gEquals and gEqualsExact functions by adding tol
+	  argument to gEquals
+	  
+	  Changed default of byid in gBuffer to FALSE for consistency
+
+2010-08-15 10:07  crundel
+
+	* R/rgeos_misc.R: Fixed bug, GEOSArea_r was being called by both
+	  gLength and gArea
+
+2010-08-15 10:06  crundel
+
+	* NAMESPACE: Removed reference for gHasZ, no use for the function
+	  currently as 3d geometries are not supported
+
+2010-08-15 10:05  crundel
+
+	* src/rgeos_predicate_unary.c: Cleaned up code / variable
+	  declarations
+
+2010-08-14 11:47  crundel
+
+	* man/pred-unary-gIsValid.Rd: Fixed extra line in example, and
+	  linearring example
+
+2010-08-14 10:51  crundel
+
+	* man/gpc-new-generics.Rd: Added alias to symdiff function
+
+2010-08-14 10:51  crundel
+
+	* NAMESPACE, R/rgeos_predicate_unary.R, inst/tests/test-jts-xml.R:
+	  Unary Predicate functions renamed
+
+2010-08-14 10:50  crundel
+
+	* man/pred-unary-gIsSimple.Rd, man/pred-unary-gIsValid.Rd,
+	  man/topo-unary-gBoundary.Rd, man/topo-unary-gCentroid.Rd,
+	  man/topo-unary-gConvexHull.Rd, man/topo-unary-gEnvelope.Rd,
+	  man/topo-unary-gPointOnSurface.Rd, man/wkt-functions.Rd:
+	  Documentation update
+
+2010-08-11 13:41  crundel
+
+	* R/rgeos_util.R, man/utility-functions.Rd: Small bugfix / typo fix
+
+2010-08-11 12:46  crundel
+
+	* NAMESPACE, R/rgeos_util.R, man/utility-functions.Rd: Utility
+	  function documentation
+	  
+	  Renamed argument in checkP4S to p4s for the sake of brevity
+
+2010-08-11 12:19  crundel
+
+	* NAMESPACE, R/rgeos_util.R, inst/tests/test-translate-empty.R,
+	  inst/tests/test-translate.R: Renamed function doubletranslate to
+	  translate
+
+2010-08-11 12:18  crundel
+
+	* man/checkHolesGPC.Rd: Removed empty documentation sections
+
+2010-08-11 12:14  crundel
+
+	* NAMESPACE, R/rgeos.R: Removed unused intersection functions
+
+2010-08-11 12:14  crundel
+
+	* man/gpc.poly-class.Rd, man/gpc.poly.nohole-class.Rd,
+	  man/new-generics.Rd, man/polyfile.Rd: Files renamed
+
+2010-08-11 12:13  crundel
+
+	* man/class-Ring.Rd, man/class-SpatialCollections.Rd,
+	  man/class-SpatialRings.Rd, man/class-SpatialRingsDataFrame.Rd,
+	  man/class-gpc.poly.Rd, man/class-gpc.poly.nohole.Rd,
+	  man/constructor-SpatialCollections.Rd,
+	  man/constructor-SpatialRings.Rd, man/gpc-new-generics.Rd,
+	  man/gpc-polyfile.Rd, man/topo-bin-gDifference.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gSymdifference.Rd,
+	  man/topo-bin-gUnion.Rd, man/topo-unary-gBoundary.Rd,
+	  man/topo-unary-gCentroid.Rd, man/topo-unary-gConvexHull.Rd,
+	  man/topo-unary-gEnvelope.Rd, man/topo-unary-gPointOnSurface.Rd:
+	  Documentation update, changed naming convention to keep things
+	  clear
+
+2010-08-10 18:04  crundel
+
+	* man/topo-bin-gUnion.Rd: Fixed function argument ordering in
+	  gLineMerge usage.
+
+2010-08-10 18:02  crundel
+
+	* man/topo-unary-gBoundary.Rd, man/topo-unary-gEnvelope.Rd,
+	  man/topo-unary-gPointOnSurface.Rd: Fixed incorrect function names
+	  in usage section
+
+2010-08-10 17:57  crundel
+
+	* tests/test-all.R: Fixed test path
+
+2010-08-10 17:56  crundel
+
+	* man/gpc.poly-class.Rd: Removed triangulate example
+
+2010-08-10 17:49  crundel
+
+	* man/gIntersection.Rd, man/gUnion.Rd, man/topo-bin-gDifference.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gSymdifference.Rd,
+	  man/topo-bin-gUnion.Rd, man/topo-unary-gBoundary.Rd,
+	  man/topo-unary-gCentroid.Rd, man/topo-unary-gConvexHull.Rd,
+	  man/topo-unary-gEnvelope.Rd, man/topo-unary-gPointOnSurface.Rd:
+	  Preliminary documentation for all topology functions along with
+	  examples.
+	  
+	  Changed Rd file naming scheme for clarity
+
+2010-08-10 17:48  crundel
+
+	* R/rgeos_topology.R: Changed argument order for topology functions
+	  for the sake of consistency.
+
+2010-08-10 13:26  crundel
+
+	* R/rgeos_topology.R: Fixed bug in gPolygonizer
+
+2010-08-10 13:24  crundel
+
+	* man/gpc.poly-class.Rd, man/gpc.poly.nohole-class.Rd,
+	  man/new-generics.Rd, man/polyfile.Rd: Updated documentation files
+	  for gpcpoly functions
+
+2010-07-27 06:08  crundel
+
+	* inst/tests/test-jts-xml.R: Fixed (working) version of jts xml
+	  test processing
+
+2010-07-27 05:15  crundel
+
+	* inst/tests/test-translate-empty.R, inst/tests/test-translate.R:
+	  Added setScale() call to begin of each set of tests to reset
+	  scale option (changed by some of the JTS tests)
+
+2010-07-27 05:14  crundel
+
+	* NAMESPACE, R/rgeos_predicate_binary.R, src/init.c, src/rgeos.h,
+	  src/rgeos_predicate_binary.c: Added prepared geometry functions -
+	  gContainsProperly, gCovers, gCoveredBy and prepared variants of
+	  gIntersects and gContains specified by a flag.
+
+2010-07-27 05:04  crundel
+
+	* R/rgeos_util.R: Fixed bug, extra ) in double translate
+
+2010-07-27 03:44  crundel
+
+	* inst/tests/test-empty-geom.R, inst/tests/test-translate-empty.R,
+	  inst/tests/test-translate.R: Changed phrasing of some of the
+	  tests in translate to make it easier to distinguish between
+	  similar tests.
+	  
+	  Renamed test-empty-geom.R to test-translate-empty.R
+
+2010-07-25 09:15  crundel
+
+	* R/rgeos_util.R, R/rgeos_wkt.R, src/rgeos_R2geos.c,
+	  src/rgeos_geos2R.c: Fixed bug in passing ids during translation
+
+2010-07-25 08:08  crundel
+
+	* R/rgeos_predicate_binary.R: Removed more leftover debug messaging
+
+2010-07-25 07:56  crundel
+
+	* R/rgeos_predicate_binary.R: Fixed bug in gRelate, still called
+	  RGEOSRelate and passed byid instead of pattern as 3rd argument
+
+2010-07-25 06:31  crundel
+
+	* src/rgeos_geos2R.c: Removed leftover debug messages
+
+2010-07-25 06:24  crundel
+
+	* inst/tests/test-empty-geom.R: Added test for GEOMETRYCOLLECTION
+	  EMPTY
+
+2010-07-25 06:23  crundel
+
+	* R/rgeos_wkt.R: Fixed bug to handle null geometries
+
+2010-07-25 06:22  crundel
+
+	* src/rgeos_R2geos.c, src/rgeos_geos2R.c: Fixed bugs handling empty
+	  geometries, collections were getting turned into nulls. Now only
+	  GEOMETRYCOLLECTION EMPTY returns null.
+
+2010-07-24 07:03  crundel
+
+	* NAMESPACE, R/rgeos_topology.R, src/init.c, src/rgeos.h,
+	  src/rgeos_topology.c: Added gSimplify and gPolygonize
+	  functionality, no idea how the latter works
+
+2010-07-24 03:19  crundel
+
+	* src/rgeos_R2geos.c: Fixed bug in R2geos translate function for
+	  SpatialPoints object without row names.
+
+2010-07-19 18:17  crundel
+
+	* NAMESPACE, R/rgeos_spExtensions_Methods.R, R/rgeos_util.R,
+	  R/rgeos_wkt.R: Small fixes for handling SpatialCollections
+
+2010-07-19 06:28  crundel
+
+	* src/rgeos_R2geos.c, src/rgeos_geos2R.c: Initial implementation of
+	  translation of SpatialCollections classes to and from geos.
+
+2010-07-19 04:58  crundel
+
+	* R/rgeos_spExtensions_Methods.R: Fixed bug in SpatialCollections
+	  print method to use NA as default polygon color if col is not
+	  specified.
+
+2010-07-19 04:27  crundel
+
+	* R/rgeos_spExtensions_Methods.R: Fixed bug in SpatialCollections
+	  print method to have the proper range
+
+2010-07-19 04:17  crundel
+
+	* NAMESPACE: Export SpatialCollections classes and constructor
+
+2010-07-19 04:16  crundel
+
+	* R/rgeos_SpatialCollections.R, R/rgeos_SpatialRings.R,
+	  R/rgeos_SpatialRingsDataFrame.R, R/rgeos_spExtensions_Classes.R,
+	  R/rgeos_spExtensions_Methods.R: Combined SpatialCollections and
+	  SpatialRings extension classes into the same file
+	  (SpatialCollections depends on SpatialRings this way we can be
+	  sure that the latter is defined first)
+
+2010-07-19 01:46  crundel
+
+	* R/rgeos_SpatialCollections.R: Initial implementation of
+	  SpatialCollections with plot method missing additional helper
+	  methods
+
+2010-07-17 04:56  crundel
+
+	* R/Rgpc_funcs.R, R/gpc_geos.R, src/gpc_geos.c: Updated gpc
+	  replacement functions, added translation functions to and from
+	  gpc and sp
+
+2010-07-17 04:54  crundel
+
+	* man/LinesIntersections.Rd, man/gIntersection.Rd, man/gUnion.Rd,
+	  man/gpc.poly-class.Rd, man/thinnedSpatialPolyGEOS.Rd,
+	  man/unionSpatialPolygonsGEOS.Rd: Documentation update
+	  -removed thinnedSpatialPolyGEOS.Rd
+	  -replaced LinesIntersections.Rd with gIntersections.Rd
+	  -replaced unionSpatialPolygons.Rd with gUnion.Rd
+	  -removed unnecessary example from gpc.poly-class.Rd
+
+2010-07-17 04:51  crundel
+
+	* NAMESPACE, R/rgeos_buffer.R, R/rgeos_linearref.R, R/rgeos_misc.R,
+	  R/rgeos_predicate_binary.R, R/rgeos_predicate_unary.R,
+	  R/rgeos_topology.R, R/rgeos_topology_binary.R, src/init.c,
+	  src/rgeos.h, src/rgeos_coord.c, src/rgeos_misc.c,
+	  src/rgeos_predicate_binary.c, src/rgeos_topology_binary.c: Major
+	  Update
+	  
+	  switched from RGEOS prefix on functions to gFunction style. Old
+	  function names retained but with Deprecated warning. Removed "is"
+	  prefix from relevant functions
+	  
+	  Added binary topology functions (gUnion, gDifference, etc)
+	  
+	  Combined related functions (hausdorffdistance with distance etc)
+
+2010-07-12 19:00  rsbivand
+
+	* R/AAA.R, configure, configure.in: version
+
+2010-07-12 18:55  rsbivand
+
+	* inst/SVN_VERSION: version
+
+2010-07-12 18:32  rsbivand
+
+	* inst/SVN_VERSION: version
+
+2010-07-12 18:32  rsbivand
+
+	* inst/SVN_VERSION: version
+
+2010-07-12 18:29  rsbivand
+
+	* configure, configure.in: version
+
+2010-07-12 18:24  rsbivand
+
+	* R/AAA.R, configure, configure.in: version
+
+2010-07-10 17:57  rsbivand
+
+	* NAMESPACE: fixed NAMESPACE
+
+2010-07-10 07:05  crundel
+
+	* R/rgeos_wkt.R, src/rgeos_geos2R.c: Fixes for handling
+	  GEOMETRYCOLLECTION EMPTY, now
+	  returns NULL
+
+2010-07-08 21:24  crundel
+
+	* inst/tests/test-empty-geom.R: Bug fix - misnamed variabel
+
+2010-07-08 21:19  crundel
+
+	* R/rgeos_buffer.R, R/rgeos_topology.R, R/rgeos_wkt.R, src/init.c,
+	  src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_buffer.c,
+	  src/rgeos_geos2R.c, src/rgeos_topology.c, src/rgeos_wkt.c:
+	  Removed all references to threshold in geos2R translate functions
+	  and calling functions
+
+2010-07-08 21:17  crundel
+
+	* man/LinesIntersections.Rd, man/thinnedSpatialPolyGEOS.Rd:
+	  Commented out current broken function calls
+
+2010-07-08 21:05  crundel
+
+	* R/rgeos_SpatialRingsDataFrame.R: Small bug fix in
+	  chFIDsSpatialRingsDataFrame
+
+2010-07-08 20:52  crundel
+
+	* R/rgeos_simplify.R, R/rgeos_union.R, src/rgeos_sp.c: Removed
+	  files, functionality will be replicated elsewhere
+
+2010-07-08 20:17  crundel
+
+	* inst/tests/test-empty-geom.R: Updated unit tests for handling
+	  empty geometries (added polygons and a few small fixes)
+
+2010-07-08 20:16  crundel
+
+	* src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_coord.c,
+	  src/rgeos_geos2R.c, src/rgeos_sp.c: Renamed functions for parsing
+	  polygons to and from geos and R to be more consistent
+	  
+	  Added handling for empty polygons to translate functions
+	  
+	  Removed thresholding from R2geos polygon translation functions.
+	  Will re-implement as a separate function.
+	  
+	  FIXME - remove threshold parameter from function calls
+	  
+	  Added rgeos_Pt2xy coordinate function for getting x and y
+	  coordinates from a geos point
+	  
+	  Added rgeos_crdMatFixDir which ensures coordinate direction is
+	  correct in a coordinate matrix depending of if it is a hole or
+	  not
+
+2010-07-08 20:10  crundel
+
+	* R/rgeos_SpatialRings.R: Fixed Ring class constructor to check the
+	  direction of points, if not CW then reverses them.
+
+2010-06-27 22:25  crundel
+
+	* inst/tests/test-empty-geom.R: Unit tests for empty geometries and
+	  their translations
+
+2010-06-27 07:49  crundel
+
+	* src/init.c, src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_coord.c:
+	  Separated LinearRing translate functions from Linestring
+	  functions
+	  Fixed R2geos translation of empty geometries
+
+2010-06-26 22:24  crundel
+
+	* NAMESPACE: Export class constructor functions
+
+2010-06-26 22:23  crundel
+
+	* inst/tests/test-translate.R, src/rgeos_R2geos.c,
+	  src/rgeos_geos2R.c: Translate functions for SpatialRings, fixed
+	  translate unit tests to use the proper class.
+
+2010-06-26 22:23  crundel
+
+	* R/rgeos_buffer.R, R/rgeos_misc.R, R/rgeos_predicate_unary.R,
+	  R/rgeos_topology.R, R/rgeos_util.R: Removed extractIDs function,
+	  uses row.names instead
+
+2010-06-26 18:54  crundel
+
+	* src/rgeos_geos2R.c: Initial handling of empty points and empty
+	  linestrings proof of concept (probably doesn't play well with
+	  existing sp methods)
+
+2010-06-26 18:50  crundel
+
+	* src/rgeos_coord.c: Cleaned code
+
+2010-06-26 18:44  crundel
+
+	* src/rgeos_bbox.c: Cleaned code
+
+2010-06-26 18:42  crundel
+
+	* NAMESPACE, R/rgeos_SpatialRings.R,
+	  R/rgeos_SpatialRingsDataFrame.R: Initial implementation of
+	  SpatialRings and SpatialRingsDataFrame classes based on
+	  SpatialLines
+
+2010-06-26 18:41  crundel
+
+	* R/rgeos_wkt.R: changed readWKT, let GEOS do all parsing/checking
+	  of WKTs instead of trying to sort it out in R.
+
+2010-06-26 02:04  crundel
+
+	* src/rgeos_R2geos.c: Cleaned up c code, no changes in
+	  functionality
+
+2010-06-21 02:36  crundel
+
+	* tests/.Rhistory: Removed .Rhistory
+
+2010-06-15 17:13  rsbivand
+
+	* R/AAA.R: keyword on load
+
+2010-06-15 17:10  rsbivand
+
+	* ChangeLog, inst/ChangeLog: keyword on load
+
+2010-06-15 17:09  rsbivand
+
+	* R/AAA.R: keyword on load
+
+2010-06-14 05:30  crundel
+
+	* src/rgeos_bbox.c, src/rgeos_buffer.c, src/rgeos_coord.c,
+	  src/rgeos_misc.c, src/rgeos_wkt.c: Cleaned c code formatting
+
+2010-06-12 20:38  crundel
+
+	* src/rgeos_area.c, src/rgeos_geos2R.c: Cleaned code in
+	  rgeos_LinearRingPolygon removed dependence on rgeos_csArea. Uses
+	  GEOSArea_r now. Should be slightly faster.
+	  
+	  Removed rgeos_area.c (rgeos_csArea only referenced in
+	  rgeos_LinearRingPolygon)
+
+2010-06-12 19:48  crundel
+
+	* src/rgeos.c, src/rgeos.h: Cleaned code in rgeos.c
+
+2010-06-10 00:50  crundel
+
+	* R/rgeos_misc.R, R/rgeos_predicate_binary.R, src/rgeos_misc.c,
+	  src/rgeos_predicate_binary.c: Modified Binary predicate functions
+	  and distance functions to allow byid to be of length 2 to
+	  indicate if one geometry should be processed by id and the other
+	  not.
+
+2010-06-09 23:25  crundel
+
+	* NAMESPACE: Forgot to add groupID to NAMESPACE
+
+2010-06-09 23:22  crundel
+
+	* NAMESPACE, R/rgeos_topology.R, R/rgeos_util.R,
+	  man/unionSpatialPolygonsGEOS.Rd, src/init.c, src/rgeos.h,
+	  src/rgeos_sp.c, src/rgeos_topology.c: Added RGEOSUnionCascaded,
+	  replicates unionSpatialPolygonsGEOS functionality but is
+	  currently slower.
+	  
+	  Added groupID utility function which restructures a SP object
+	  based on newly assigned IDs, subobjects with the same ID are
+	  grouped together. General solution to the need to flatten
+	  SpatialPolygons for use with RGEOSUnionCascaded, but may be too
+	  slow for practical use.
+
+2010-06-07 09:02  rsbivand
+
+	* inst/ChangeLog: update changelog
+
+2010-06-07 08:54  rsbivand
+
+	* ChangeLog: update changelog
+
+2010-06-07 08:28  rsbivand
+
+	* DESCRIPTION, NAMESPACE, src/gpc_geos.c, src/init.c,
+	  src/rgeos_coord.c, src/rgeos_sp.c: tidying up to run CMD check
+
+2010-06-07 05:01  crundel
+
+	* src/rgeos_topology_binary.c:
+
+2010-06-07 04:28  crundel
+
+	* src/rgeos_R2geos.c: Handles Spatial DataFrame classes, currently
+	  just ignores the data frame
+
+2010-06-07 02:51  crundel
+
+	* R/rgeos_topology_binary.R, R/rgeos_topology_relation.R: Renamed
+	  rgeos_topology_relation to rgeos_topology_binary
+
+2010-06-06 05:48  crundel
+
+	* src/rgeos_topology.c: Fixed error message typos (referred to
+	  wrong parent function)
+
+2010-06-06 05:37  crundel
+
+	* R/rgeos_predicate_binary.R, R/rgeos_topology_relation.R,
+	  src/init.c, src/rgeos.h, src/rgeos_predicate_binary.c,
+	  src/rgeos_predicate_unary.c: Fixed issue with argument number
+	  mismatch in binary predicate function.
+	  
+	  Binary predicate functions take into account when the result is
+	  symmetric and perform only the necessary calculations.
+	  
+	  RGEOSRelate and RGEOSRelatePattern moved to rgeos_binary_
+	  predicate
+
+2010-06-05 21:33  crundel
+
+	* R/rgeos_misc.R, R/rgeos_predicate_binary.R,
+	  R/rgeos_predicate_unary.R, R/rgeos_topology.R,
+	  R/rgeos_topology_relation.R, src/init.c, src/rgeos.c,
+	  src/rgeos.h, src/rgeos_predicate_binary.c,
+	  src/rgeos_predicate_unary.c: Fixed issues with binary predicate
+	  issue (temporarily remove rgeos_relatepattern)
+	  
+	  Added Unary Predicate Functions
+
+2010-06-03 22:46  crundel
+
+	* src/rgeos.h, src/rgeos_misc.c, src/rgeos_predicate_binary.c,
+	  src/rgeos_topology.c: Removed the enum for each function and just
+	  passing a function pointer directly now.
+
+2010-06-02 03:44  crundel
+
+	* R/rgeos_misc.R, R/rgeos_predicate_binary.R, src/init.c,
+	  src/rgeos.h, src/rgeos_predicate_binary.c: Added binary predicate
+	  functions: RGEOSDisjoint, RGEOSTouches, RGEOSIntersects,
+	  RGEOSCrosses, RGEOSWithin, RGEOSContains, RGEOSOverlaps,
+	  RGEOSEquals
+	  
+	  Generalized functions in rgeos_misc
+
+2010-06-02 00:35  crundel
+
+	* R/rgeos_topology.R, src/init.c, src/rgeos.h, src/rgeos_coord.c,
+	  src/rgeos_geos2R.c, src/rgeos_misc.c, src/rgeos_topology.c: Added
+	  RGEOSLineMerge
+	  
+	  Generalized function calls in topology and misc, functions with
+	  the same type of parameters and differ only in the GEOS function
+	  used are processed by the same function.
+	  
+	  Small bug fixes in coord and geos2R
+
+2010-05-31 03:05  crundel
+
+	* R/rgeos_misc.R, src/init.c, src/rgeos.h, src/rgeos_misc.c: Added
+	  RGEOSHausdorffDistance, combined underlying C code with
+	  rgeosdistance since everything is the same except for the geos
+	  function call. FIXME - currently uses function pointers which are
+	  causing gcc warnings, but code appears to work.
+
+2010-05-30 21:53  crundel
+
+	* R/rgeos_misc.R, src/init.c, src/rgeos.h, src/rgeos_misc.c: Added
+	  RGEOSDistance and RGEOSisWithinDistance in rgeos_misc
+
+2010-05-30 21:14  crundel
+
+	* R/rgeos_misc.R, src/init.c, src/rgeos.h, src/rgeos_misc.c: Added
+	  RGEOSArea and RGEOSLength in rgeos_misc
+
+2010-05-30 20:40  crundel
+
+	* src/rgeos.h: More cleaning of rgeos.h
+
+2010-05-30 20:38  crundel
+
+	* src/rgeos_contains.c, src/rgeos_distance.c, src/rgeos_length.c:
+	  Removed rgeos_contains.c, rgeos_distance.c, rgeos_length.c
+	  functionality will be covered by rgeos_misc.c
+
+2010-05-30 20:37  crundel
+
+	* src/init.c, src/rgeos.h: Removed rgeos_contains.c,
+	  rgeos_distance.c, rgeos_length.c functionality will be covered by
+	  rgeos_misc.c
+	  
+	  Cleaned up init.c and rgeos.h
+
+2010-05-30 20:15  crundel
+
+	* R/rgeos_buffer.R, src/rgeos_buffer.c: Added RGEOSBuffer
+
+2010-05-30 20:11  crundel
+
+	* R/rgeos_util.R: Added default value for setScale
+
+2010-05-30 20:10  crundel
+
+	* src/rgeos_poly2nb.c, src/rgeos_sp.c, src/rgeos_validate.c:
+	  Updated function names
+
+2010-05-29 09:38  crundel
+
+	* NAMESPACE, R/rgeos_wkt.R, src/init.c, src/rgeos.h,
+	  src/rgeos_R2geos.c, src/rgeos_geos2R.c, src/rgeos_wkt.c: Added
+	  writeWKT, small fixes to translate functions
+
+2010-05-27 19:47  crundel
+
+	* NAMESPACE, R/rgeos_buffer.R, R/rgeos_linearref.R,
+	  R/rgeos_topology.R, src/init.c, src/rgeos.c, src/rgeos.h,
+	  src/rgeos_buffer.c, src/rgeos_predicate_unary.c,
+	  src/rgeos_topology.c: Added RGEOSBoundary, RGEOSGetCentroid,
+	  RGEOSPointOnSurface, RGEOSBuffer which mostly work
+
+2010-05-26 17:59  rsbivand
+
+	* ChangeLog, inst/ChangeLog: changelogs
+
+2010-05-26 06:06  crundel
+
+	* src/init.c:
+
+2010-05-26 06:06  crundel
+
+	* R/rgeos_topology.R, inst/tests/test-translate.R, src/rgeos.h,
+	  src/rgeos_R2geos.c, src/rgeos_geos2R.c, src/rgeos_sp.c,
+	  src/rgeos_topology.c: Small fixes to translation functions,
+	  everything should be working
+	  
+	  Updated test-translate.R with polygon unit tests
+	  
+	  Added RGEOSConvexHull (untested)
+
+2010-05-24 04:40  crundel
+
+	* R/rgeos_topology.R, R/rgeos_util.R, src/rgeos_topology.c: Added
+	  rgeos_envelope and RGEOSEnvelope functions
+
+2010-05-24 04:25  crundel
+
+	* src/init.c, src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_bbox.c,
+	  src/rgeos_geos2R.c: Unified bounding box functions, geom2bbox
+	  should work for all geometry types now
+
+2010-05-23 08:03  crundel
+
+	* NAMESPACE, R/rgeos_util.R, R/rgeos_wkt.R, inst/tests,
+	  inst/tests/test-jts-xml.R, inst/tests/test-translate.R,
+	  src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_coord.c,
+	  src/rgeos_geos2R.c: Added proper ID handling to translation
+	  functions and readWKT. Currently point ids are stored as row
+	  names which is a design decision that should be revisited later
+	  (current implementation works, but probably doesn't integrate
+	  well with existing sp tools)
+	  
+	  Added fixes to test-translate.R, mostly related to IDs
+	  
+	  Removed SP2WKT (which never worked) and WKT2SP in favor of
+	  readWKT - revisit naming convention?
+
+2010-05-21 22:00  crundel
+
+	* NAMESPACE:
+
+2010-05-21 22:00  crundel
+
+	* R/rgeos_util.R, R/rgeos_wkt.R, inst/tests/test-translate.R,
+	  src/init.c, src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_geos2R.c,
+	  src/rgeos_sp.c, tests/test-all.R: Added rgeos_convert_R2geos -
+	  generic function to translate R sp objects to geos geometries
+	  
+	  Moved rgeos_Polygons_i_2Polygon to rgeos_R2geos.c
+	  
+	  Added rgeos_double_translate which translates R->geos->R for
+	  testing purposes
+	  
+	  Added test-translate.R with unit tests for translations -
+	  currently tests Points, Lines, and Rings
+	  
+	  readWKT fix - if the result is only one object return it and not
+	  a list of objects
+
+2010-05-21 00:59  crundel
+
+	* src/rgeos_coord.c: Broke the geospoint2crdMat in the last commit,
+	  fixes POINT and MULTIPOINT cases
+
+2010-05-20 22:46  crundel
+
+	* src/rgeos_coord.c, src/rgeos_geos2R.c: Cleaned up / clarified
+	  point and line handling code
+
+2010-05-20 21:25  crundel
+
+	* src/rgeos_geos2R.c: Added handling of geometry collections of
+	  Lines and Multilines and Linear Rings
+
+2010-05-20 20:40  rsbivand
+
+	* src/rgeos_sp.c: temp FIXME in Line Intersection
+
+2010-05-19 04:37  crundel
+
+	* src/init.c, src/rgeos.h, src/rgeos_coord.c, src/rgeos_geos2R.c,
+	  src/rgeos_sp.c: Updated handling conversion of geos points to R
+	  to handle geometry collections of points and multipoints
+
+2010-05-17 21:51  crundel
+
+	* src/rgeos_geos2R.c: Fix to rgeos_multiline2SpatialLines,
+	  SpatialLines class was being built incorrectly, Lines class is
+	  now added to a list before being attached
+
+2010-05-17 02:33  crundel
+
+	* R/rgeos_util.R, R/rgeos_wkt.R, src/init.c, src/rgeos.h,
+	  src/rgeos_bbox.c, src/rgeos_geos2R.c, src/rgeos_wkt.c: Added
+	  rgeos_multiline2SpatialLines function to covert LINESTRING and
+	  MULTILINESTRING to SpatialLines
+	  
+	  Added rgeos_convert_geos2R function which is geometry type
+	  agnostic and calls other conversion functions based on geometry
+	  type
+	  
+	  Fixed rgeos_crdMat2bbox function to make updates to an existing
+	  bbox, added rgeos_initbbox and rgeos_formatbbox helper functions
+	  
+	  Added checkP4S for basic proj4string checking and initialization,
+	  should now be handled in R and an initialized CRS class passed to
+	  conversion functions
+	  
+	  Other small code cleanups
+
+2010-05-15 05:41  crundel
+
+	* src/init.c, src/rgeos_R2geos.c: More merge fixes
+
+2010-05-15 05:39  crundel
+
+	* src/rgeos.h: Broke rgeos.h somehow while merging.
+
+2010-05-15 05:28  crundel
+
+	* ., NAMESPACE, R, R/AAA.R, R/rgeos_wkt.R, inst/tests,
+	  inst/tests/test-jts-xml.R, inst/tests/testxml,
+	  inst/tests/testxml/general,
+	  inst/tests/testxml/general/TestBoundary.xml,
+	  inst/tests/testxml/general/TestCentroid.xml,
+	  inst/tests/testxml/general/TestConvexHull-big.xml,
+	  inst/tests/testxml/general/TestConvexHull.xml,
+	  inst/tests/testxml/general/TestFunctionAA.xml,
+	  inst/tests/testxml/general/TestFunctionAAPrec.xml,
+	  inst/tests/testxml/general/TestFunctionLA.xml,
+	  inst/tests/testxml/general/TestFunctionLAPrec.xml,
+	  inst/tests/testxml/general/TestFunctionLL.xml,
+	  inst/tests/testxml/general/TestFunctionLLPrec.xml,
+	  inst/tests/testxml/general/TestFunctionPA.xml,
+	  inst/tests/testxml/general/TestFunctionPL.xml,
+	  inst/tests/testxml/general/TestFunctionPLPrec.xml,
+	  inst/tests/testxml/general/TestFunctionPP.xml,
+	  inst/tests/testxml/general/TestInteriorPoint.xml,
+	  inst/tests/testxml/general/TestRectanglePredicate.xml,
+	  inst/tests/testxml/general/TestRelateAA.xml,
+	  inst/tests/testxml/general/TestRelateAC.xml,
+	  inst/tests/testxml/general/TestRelateLA.xml,
+	  inst/tests/testxml/general/TestRelateLC.xml,
+	  inst/tests/testxml/general/TestRelateLL.xml,
+	  inst/tests/testxml/general/TestRelatePA.xml,
+	  inst/tests/testxml/general/TestRelatePL.xml,
+	  inst/tests/testxml/general/TestRelatePP.xml,
+	  inst/tests/testxml/general/TestSimple.xml,
+	  inst/tests/testxml/general/TestValid.xml,
+	  inst/tests/testxml/general/TestValid2-big.xml,
+	  inst/tests/testxml/general/TestValid2.xml,
+	  inst/tests/testxml/general/TestWithinDistance.xml,
+	  inst/tests/testxml/robust,
+	  inst/tests/testxml/robust/ExternalRobustness.xml,
+	  inst/tests/testxml/robust/TestRobustOverlayFixed.xml,
+	  inst/tests/testxml/robust/TestRobustOverlayFloat.xml,
+	  inst/tests/testxml/robust/TestRobustRelate.xml,
+	  inst/tests/testxml/validate,
+	  inst/tests/testxml/validate/TestRelateAA-big.xml,
+	  inst/tests/testxml/validate/TestRelateAA.xml,
+	  inst/tests/testxml/validate/TestRelateAC.xml,
+	  inst/tests/testxml/validate/TestRelateLA.xml,
+	  inst/tests/testxml/validate/TestRelateLC.xml,
+	  inst/tests/testxml/validate/TestRelateLL.xml,
+	  inst/tests/testxml/validate/TestRelatePA.xml,
+	  inst/tests/testxml/validate/TestRelatePL.xml,
+	  inst/tests/testxml/validate/TestRelatePP.xml,
+	  inst/tests/testxml/vivid, src, src/gpc_geos.c, src/init.c,
+	  src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_bbox.c,
+	  src/rgeos_coord.c, src/rgeos_geos2R.c, src/rgeos_length.c,
+	  src/rgeos_sp.c, src/rgeos_wkt.c, tests, tests/.Rhistory,
+	  tests/test-all.R: Fixed issue where CoordSeq were not being
+	  destroyed
+	  
+	  Added some initial work on UnitTests using testthat package,
+	  testxml folder contains xml test files from JTS
+	  
+	  General cleaning and reorganization of C code.
+	  
+	  Added functions to convert point and multipoint geos geometries
+	  
+	  Added readWKT functions that are geometry agnostic
+
+2010-05-13 20:10  crundel
+
+	* R/rgeos_misc.R, R/rgeos_predicate_binary.R,
+	  R/rgeos_predicate_unary.R, R/rgeos_topology.R,
+	  R/rgeos_topology_relation.R: Created new files with basic rgeos
+	  functions organized by task, each file contains empty function
+	  definitions.
+
+2010-05-06 16:19  rsbivand
+
+	* ChangeLog, inst/ChangeLog: use points not polygons for b-box
+	  intersection envelope in poly2nb
+
+2010-05-06 16:19  rsbivand
+
+	* R/rgeos.R, src/init.c, src/rgeos.h, src/rgeos_R2geos.c,
+	  src/rgeos_poly2nb.c: use points not polygons for b-box
+	  intersection envelope in poly2nb
+
+2010-05-05 08:42  rsbivand
+
+	* ChangeLog, inst/ChangeLog: bounding box intersections
+
+2010-05-05 08:41  rsbivand
+
+	* NAMESPACE, R/rgeos.R, src/init.c, src/rgeos.h,
+	  src/rgeos_poly2nb.c: bounding box intersections
+
+2010-05-03 17:19  rsbivand
+
+	* DESCRIPTION: increment DESCRIPTION version #
+
+2010-05-03 16:35  rsbivand
+
+	* DESCRIPTION, R/AAA.R, R/rgeos.R: increment DESCRIPTION version #
+
+2010-05-03 14:04  rsbivand
+
+	* src/rgeos.c, src/rgeos.h, src/rgeos_coord.c, src/rgeos_geos2R.c,
+	  src/rgeos_validate.c, src/rgeos_wkt.c: removing inline
+	  declaration in rgeos.h - see comment
+
+2010-05-03 13:33  rsbivand
+
+	* src/Makevars: removing pkg/src/Makevars - auto-generated from
+	  Makevars.in
+
+2010-05-03 05:24  crundel
+
+	* NAMESPACE, R/AAA.R, R/rgeos.R, R/rgeos_util.R, R/rgeos_wkt.R,
+	  src/Makevars, src/init.c, src/rgeos.c, src/rgeos.h,
+	  src/rgeos_R2geos.c, src/rgeos_area.c, src/rgeos_coord.c,
+	  src/rgeos_geos2R.c, src/rgeos_sp.c, src/rgeos_validate.c,
+	  src/rgeos_wkt.c: Tidying existing functions, roughly grouped into
+	  files by task.
+	  
+	  Added functions for WKT output.
+	  
+	  Fixed precision issue leading to small polygons not being joined.
+	  Added functionality to get, set, and use a scale variable that
+	  determines min precision with appropriate rounding functions from
+	  GEOS.
+
+2010-04-29 14:35  rsbivand
+
+	* R/rgeos.R, man/LinesIntersections.Rd: fix poly2nb framework
+	  (non-operational)
+
+2010-04-28 08:44  rsbivand
+
+	* R/AAA.R, R/rgeos.R, R/rgeos_simplify.R, R/rgeos_union.R,
+	  src/gpc_geos.c, src/rgeos.c, src/rgeos.h, src/rgeos_distance.c,
+	  src/rgeos_length.c, src/rgeos_sp.c: tidy
+
+2010-04-26 08:32  rsbivand
+
+	* R/rgeos.R: starting poly2nb
+
+2010-02-12 12:27  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, R/Rgpc_funcs.R, R/gpc_geos.R,
+	  R/rgeos.R, R/rgeos_simplify.R, R/rgeos_union.R, data,
+	  data/poly_ex.rda, man/checkHolesGPC.Rd, man/gpc.poly-class.Rd,
+	  man/new-generics.Rd, man/unionSpatialPolygonsGEOS.Rd,
+	  src/gpc_geos.c, src/init.c, src/rgeos.c, src/rgeos.h,
+	  src/rgeos_contains.c, src/rgeos_distance.c, src/rgeos_length.c,
+	  src/rgeos_sp.c: adding gpc.poly <-> GEOS interface
+
+2010-02-08 14:55  rsbivand
+
+	* configure.win, src/Makevars.win: Windows DLL to static
+
+2010-02-01 18:01  rsbivand
+
+	* R/Rgpc_funcs.R: Rgpc functions
+
+2010-02-01 12:21  rsbivand
+
+	* configure.win: Win binaries to 320
+
+2010-01-31 19:22  rsbivand
+
+	* ChangeLog, inst/ChangeLog: union buffer scale problem
+
+2010-01-31 19:21  rsbivand
+
+	* man/checkHolesGPC.Rd: union buffer scale problem
+
+2010-01-31 19:19  rsbivand
+
+	* R/gpc_geos.R, R/rgeos.R, R/rgeos_union.R,
+	  man/checkPolygonsGEOS.Rd, man/unionSpatialPolygonsGEOS.Rd,
+	  src/gpc_geos.c, src/init.c, src/rgeos.h, src/rgeos_sp.c: union
+	  buffer scale problem
+
+2010-01-27 10:53  rsbivand
+
+	* R/gpc_geos.R, src/gpc_geos.c: refactoring for gpcpoly objects
+
+2010-01-27 10:20  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/rgeos.R, src/init.c, src/rgeos.h,
+	  src/rgeos_sp.c: refactoring for gpcpoly objects
+
+2010-01-14 07:41  rsbivand
+
+	* ChangeLog, inst/ChangeLog: declaration for Windows binary
+
+2010-01-14 07:41  rsbivand
+
+	* inst/README.windows: declaration for Windows binary
+
+2010-01-13 19:37  rsbivand
+
+	* ChangeLog, inst/ChangeLog: rgeos_finish declaration in init.c
+
+2010-01-13 19:37  rsbivand
+
+	* src/init.c: rgeos_finish declaration in init.c
+
+2010-01-10 19:01  rsbivand
+
+	* ChangeLog, inst/ChangeLog: hole verification fix
+
+2010-01-10 19:00  rsbivand
+
+	* DESCRIPTION, R/rgeos.R, man/checkPolygonsGEOS.Rd: hole
+	  verification fix
+
+2010-01-07 18:50  rsbivand
+
+	* ChangeLog, inst/ChangeLog: union dim fix
+
+2010-01-07 18:49  rsbivand
+
+	* ChangeLog, inst/ChangeLog: union dim fix
+
+2010-01-07 18:49  rsbivand
+
+	* R/rgeos_union.R: union dim fix
+
+2010-01-07 18:14  rsbivand
+
+	* ChangeLog, inst/ChangeLog: missing man file
+
+2010-01-07 18:11  rsbivand
+
+	* man/LinesIntersections.Rd: missing man file
+
+2010-01-07 12:08  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/rgeos.R, src/init.c, src/rgeos.h,
+	  src/rgeos_sp.c: maptools integration
+
+2010-01-04 09:35  rsbivand
+
+	* configure.win: prepare for Windows binary
+
+2010-01-04 07:48  rsbivand
+
+	* configure.win: preparing for Windows build
+
+2010-01-04 07:21  rsbivand
+
+	* configure.win, src/Makevars.win, src/init.c, src/rgeos.h,
+	  src/rgeos_sp.c: preparing for Windows build
+
+2010-01-03 16:41  rsbivand
+
+	* src/init.c: tightening sp dependence
+
+2010-01-03 16:36  rsbivand
+
+	* DESCRIPTION, src/init.c, src/rgeos.c, src/rgeos.h,
+	  src/rgeos_sp.c, src/sp_rgeos.c: tightening sp dependence
+
+2009-12-17 18:46  rsbivand
+
+	* ChangeLog, inst/ChangeLog: C API tidy
+
+2009-12-17 18:44  rsbivand
+
+	* src/init.c, src/local_stubs.c: C API tidy
+
+2009-12-17 18:42  rsbivand
+
+	* DESCRIPTION, R/AAA.R, src/rgeos.h, src/rgeos_sp.c: C API tidy
+
+2009-12-04 09:11  rsbivand
+
+	* ChangeLog, inst/ChangeLog: small fixes from sp transition
+
+2009-12-04 09:10  rsbivand
+
+	* DESCRIPTION: small fixes from sp transition
+
+2009-12-04 09:08  rsbivand
+
+	* src/rgeos_sp.c: small fixes from sp transition
+
+2009-12-03 08:50  rsbivand
+
+	* svn2cl.xsl: first release
+
+2009-12-03 08:47  rsbivand
+
+	* ChangeLog, inst/ChangeLog: first release
+
+2009-12-03 08:47  rsbivand
+
+	* src/sp_rgeos.c: first release
+
+2009-12-03 08:42  rsbivand
+
+	* ChangeLog, inst, inst/ChangeLog: first release
+
+2009-12-03 08:39  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, R/rgeos_simplify.R,
+	  R/rgeos_union.R, configure, configure.in, man,
+	  man/checkPolygonsGEOS.Rd, man/thinnedSpatialPolyGEOS.Rd,
+	  man/unionSpatialPolygonsGEOS.Rd, src/Makevars.in,
+	  src/rgeos_length.c: first release
+
+2009-12-02 21:03  rsbivand
+
+	* R/rgeos.R, src/rgeos.h, src/rgeos_sp.c: status
+
+2009-11-30 15:55  rsbivand
+
+	* src/rgeos.h, src/rgeos_sp.c: simplify in and out
+
+2009-11-29 20:52  rsbivand
+
+	* src/rgeos.c, src/rgeos.h, src/rgeos_sp.c: simplify in and out
+
+2009-11-28 20:34  rsbivand
+
+	* src/rgeos.c, src/rgeos.h, src/rgeos_sp.c: simplify in and out
+
+2009-11-25 20:52  rsbivand
+
+	* src/rgeos.h, src/rgeos_sp.c: parse comment in C
+
+2009-11-25 17:43  rsbivand
+
+	* R/rgeos.R, src/rgeos.c, src/rgeos.h, src/rgeos_sp.c: parse
+	  comment in C
+
+2009-11-24 20:53  rsbivand
+
+	* R/rgeos.R, src/rgeos.h, src/rgeos_sp.c: contains
+
+2009-11-21 14:52  rsbivand
+
+	* R/rgeos.R, src/rgeos.c, src/rgeos.h, src/rgeos_sp.c: after Oslo
+
+2009-11-15 13:56  rsbivand
+
+	* src/rgeos_sp.c: graphs and relations
+
+2009-11-15 11:08  rsbivand
+
+	* R/rgeos.R, src/rgeos.h, src/rgeos_sp.c: graphs and relations
+
+2009-11-14 12:22  rsbivand
+
+	* R, src, src/rgeos.c, src/rgeos.h, src/rgeos_contains.c,
+	  src/rgeos_distance.c, src/rgeos_length.c, src/rgeos_sp.c: initial
+	  C files
+
+2009-05-28 12:17  stefan7th
+
+	* .: R-Forge: updated repository structure
+
diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100644
index 0000000..f7498ef
--- /dev/null
+++ b/DESCRIPTION
@@ -0,0 +1,33 @@
+Package: rgeos
+Title: Interface to Geometry Engine - Open Source ('GEOS')
+Version: 0.3-26
+Date: 2017-10-30
+Depends: R (>= 3.3.0)
+Imports: methods, sp (>= 1.1-0), utils, stats, graphics
+LinkingTo: sp
+Suggests: maptools (>= 0.8-5), testthat, XML, maps, rgdal
+LazyLoad: yes
+Description: Interface to Geometry Engine - Open Source ('GEOS') using the C 'API' for topology operations on geometries. The 'GEOS' library is external to the package, and, when installing the package from source, must be correctly installed first. Windows and Mac Intel OS X binaries are provided on 'CRAN'.
+Authors at R: c(
+	person("Roger", "Bivand", role = c("cre", "aut"), email = "Roger.Bivand at nhh.no"),
+	person("Colin", "Rundel", role = "aut"),
+	person("Edzer", "Pebesma", role = "ctb"),
+	person("Rainer", "Stuetz", role = "ctb"),
+	person("Karl Ove", "Hufthammer", role = "ctb"))
+License: GPL (>= 2)
+URL: https://r-forge.r-project.org/projects/rgeos/
+        http://trac.osgeo.org/geos/
+SystemRequirements: GEOS (>= 3.2.0); for building from source: GEOS
+        from http://trac.osgeo.org/geos/; GEOS OSX frameworks built by
+        William Kyngesburye at http://www.kyngchaos.com/ may be used
+        for source installs on OSX.
+NeedsCompilation: yes
+Packaged: 2017-10-30 12:15:08 UTC; rsb
+Author: Roger Bivand [cre, aut],
+  Colin Rundel [aut],
+  Edzer Pebesma [ctb],
+  Rainer Stuetz [ctb],
+  Karl Ove Hufthammer [ctb]
+Maintainer: Roger Bivand <Roger.Bivand at nhh.no>
+Repository: CRAN
+Date/Publication: 2017-10-31 13:17:54 UTC
diff --git a/MD5 b/MD5
new file mode 100644
index 0000000..0d0687f
--- /dev/null
+++ b/MD5
@@ -0,0 +1,154 @@
+468be36d97f37dd5cf6a5e78bea95098 *ChangeLog
+69431b4704735ee5fc3aee47c6b5bbc5 *DESCRIPTION
+cfc07ae7edc4272904837709c84a2747 *NAMESPACE
+6e64a784e89f9929510544c06a7e4d8a *R/AAA.R
+437f4edbd6c67d561783af7960575283 *R/Rgpc_funcs.R
+d97a5d4ab563a8c66bfd93dec1449adc *R/gpc_geos.R
+601561f1ad8ff5ebff33a0f4ff7b7c2a *R/labelpt.R
+c27f2fc905f25676fc213d233195cc11 *R/over.R
+5ed94ad254c2dbb32fe47f2b73ff4fbd *R/rgeos_buffer.R
+99fa6584f7894147aeaa10054f43dff7 *R/rgeos_linearref.R
+a3403cf524417af5eb4d0654a596f018 *R/rgeos_misc.R
+22104e5e851b176ed73f2df7a49e54f2 *R/rgeos_predicate_binary.R
+05075c9e2bc204db30af7f741884abd5 *R/rgeos_predicate_unary.R
+96f670127773380ac223dcc5580bd861 *R/rgeos_spExtensions_Classes.R
+fa0bb60e604db6d2c4288c8476e76ce9 *R/rgeos_spExtensions_Methods.R
+81189faf3b743402c05a5856aa655d8e *R/rgeos_topology.R
+da9424ec7cecda9d474e22226c0471a5 *R/rgeos_topology_binary.R
+1ecebecc4c34c067203d5bf91a01e5d0 *R/rgeos_util.R
+6d0eb1653d9c722481408f7ce9d33e3c *R/rgeos_wkt.R
+c3cded853a2388ad53569a7105d1c1e3 *cleanup
+b54692ba395f729fef8b074c81da68eb *configure
+65399e404cf5ea293aa51f4134d0b515 *configure.ac
+468be36d97f37dd5cf6a5e78bea95098 *inst/ChangeLog
+3c570969cc1bcbc2fc4a3753b140a0d1 *inst/README
+93c1029f9b6765de0c7147f2bbd2a3be *inst/SVN_VERSION
+f330d6b1d9127bc82881f33dfe6e18bd *inst/poly-ex-gpc/ex-poly1.txt
+734b9a203116bec1dd173e7f8a50e07a *inst/poly-ex-gpc/ex-poly2.txt
+bd20bfd0827e13fa7ca4a022810e8962 *inst/poly-ex-gpc/hole-poly.txt
+2c254a8dc38537ccd0431dca771f52a1 *inst/test_cases/polys.RData
+0f2b2d0f90111d9403b5fe5c85662146 *inst/wkts/sline1.wkt
+41d7dd100f0ee42d2355c8c81feacfe0 *inst/wkts/sline2.wkt
+4aba44c750973f85620ccbd38813a607 *inst/wkts/sppsp.wkt
+edd0206902db37fe3814a0876db8fa93 *man/class-Ring.Rd
+ebe0caae74361b2ffed802ccead3e473 *man/class-SpatialCollections.Rd
+e1d6338ae1c8959e7d81fe1810cbe6b7 *man/class-SpatialRings.Rd
+0a8ccd4182b1cba52a6c8c87dfbea5dd *man/class-SpatialRingsDataFrame.Rd
+fc596937914e92d353cc72ad3cb53ec4 *man/class-gpc.poly.Rd
+aed22fcecc8afa3757bfd9b4fe50b2a4 *man/class-gpc.poly.nohole.Rd
+82e0eae8d624b6d830cccb5487f8c593 *man/comment-functions.Rd
+8c28c48df99e566a47a72cfca9449edf *man/constructor-SpatialCollections.Rd
+a4f8b6f11e2595120e19822213c04368 *man/constructor-SpatialRings.Rd
+3a242e1954c32e8afc04ec32ba728b11 *man/experimental-functions.Rd
+9b8dad2cab20bd54dd7bf27f1383f7ca *man/gpc-new-generics.Rd
+9daa96192eadb9b1f430ff76cf9b795f *man/gpc-polyfile.Rd
+ffbd1daaa2634b3ac7dd40d101ee7ecb *man/labelpt.Rd
+b2d76d2092995e7972870e082c3170c7 *man/linref-gInterpolate.Rd
+a266bc872ccfb4c1c7f7faf5f116368d *man/linref-gProject.Rd
+fef7af694fc71c476e43cc35f1f2fa5b *man/misc-gArea.Rd
+273d48e54827be3c52346ff46ed5c914 *man/misc-gBuffer.Rd
+263a55b2427e297af210945d94363f1d *man/misc-gDistance.Rd
+9c8503de153718dcc77c6bd80a9e2b4b *man/misc-gLength.Rd
+24ce7da69d4b337442bbe34e59057bd8 *man/misc-gNearestPoints.Rd
+ce5ce9f0e391809912a54812e96f3f89 *man/misc-over.Rd
+03273d4e8ec82269218c3d1f3b377f32 *man/pred-binary-gContains.Rd
+37700662cd67af8ae88f0870c0d41f3e *man/pred-binary-gCrosses.Rd
+fdb49a3cf3ccc518911e95ecaaf4a2f3 *man/pred-binary-gEquals.Rd
+34a32a57b8ed977f52855a6c12849b6c *man/pred-binary-gIntersects.Rd
+5c5a77bcf4b71c7bc6c30e65e67b82f3 *man/pred-binary-gRelate.Rd
+44672cd00f092a5d6ead274004b6ad01 *man/pred-binary-gTouches.Rd
+d56a8bd17039002543dbcc021de23189 *man/pred-unary-gIsEmpty.Rd
+47f95df67ce2465ec0635518f9a5cc6a *man/pred-unary-gIsRing.Rd
+14522b6206db0c56b0bb8f0e61af4fdb *man/pred-unary-gIsSimple.Rd
+c88180a2558016d7a543c52db48522b4 *man/pred-unary-gIsValid.Rd
+2f752b5a292a2224e0a9f8f5e3466cd1 *man/topo-bin-gDifference.Rd
+6685c25b560758b3f4f31ccb9e14364e *man/topo-bin-gIntersection.Rd
+f6389cbe332a986cfefc9e4e5541e152 *man/topo-bin-gSymdifference.Rd
+cfa54e2492061aa9b7522c6100eb869d *man/topo-bin-gUnion.Rd
+b05955696472d44437c45f50812907f0 *man/topo-unary-gBoundary.Rd
+a16d91c0e3066d6f64c0483ac1aac007 *man/topo-unary-gCentroid.Rd
+cd002cddc0b770fe5ad98932de1d6594 *man/topo-unary-gConvexHull.Rd
+8b5f941c77ed367956f288fb8aefe312 *man/topo-unary-gDelaunayTriangulation.Rd
+f5f3ffc0ca63d1f3cff40f59d69ef3f6 *man/topo-unary-gEnvelope.Rd
+f0a13d81ff81d5ac827a757823251922 *man/topo-unary-gNode.Rd
+8f3b6b63cea10321eb3c6e9f5bc275ac *man/topo-unary-gPointOnSurface.Rd
+af69c6b122c56ea7d908307f3a2bcd5f *man/topo-unary-gPolygonize.Rd
+8d36eb44b9dca782ea8c9ac8c9d9c8cf *man/topo-unary-gSimplify.Rd
+c06d61dd3315b64648b74f4df85badab *man/utility-functions.Rd
+d1fcd30b8888bf8cc5f7efdd63abf4ff *man/wkt-functions.Rd
+b9d869d125e18d6f05c1de7ff4e95d9b *src/Makevars.in
+0bd09ef21071443122ff15340542b01b *src/Makevars.win
+d41d8cd98f00b204e9800998ecf8427e *src/dummy.cc
+6a494ae37ab4fb1f260686bfbfa8bc47 *src/init.c
+22487056d51247176401a6afff9f3eba *src/local_stubs.c
+ca569746a0219912bf327fdded1c2e26 *src/rgeos.c
+102bd190068f9851640515ad0bd2ec85 *src/rgeos.h
+d9ff4caf83fabee96983f102be4ede4e *src/rgeos_R2geos.c
+3045f89eab62e6e0d1022c84c9e63ba1 *src/rgeos_R2geosMP.c
+f75b33825e4ad8b1aa64d70d12fb25c4 *src/rgeos_bbox.c
+0bb44be2bcb3ea420540436925aa59ae *src/rgeos_buffer.c
+7b18f2beacfc7843ead46ed50ea04ebb *src/rgeos_coord.c
+fc4e805bbc28b5ef48ca4f71a64096bb *src/rgeos_geos2R.c
+c5233666c4eaf98c49543608928575ea *src/rgeos_linearref.c
+aedf7a4a37315a6fc8f50220832dfa45 *src/rgeos_misc.c
+5f7af3e816def1780f27c16f0de93ca8 *src/rgeos_poly2nb.c
+40de178c41379510080af8da1e0c850f *src/rgeos_predicate_binary.c
+4f39ba7f07b85f29216673dc7d9be3b6 *src/rgeos_predicate_unary.c
+4d2b0095f689b0b7370a6f55735f707e *src/rgeos_topology.c
+56018dab15bce19dd04bad4145637101 *src/rgeos_topology_binary.c
+138e939bb40e8757a7119e9b6d90212b *src/rgeos_validate.c
+7401713afd055d3652fd0d7dbc296637 *src/rgeos_wkt.c
+768a54afc9389fb1b01d6b3973e81f33 *tests/test-all.R
+f28048eb32f3fc4ffdbd2f750b31e535 *tests/testthat/process_testxml.R
+627c975e214e2ff8ec9ff74a7c44a3a7 *tests/testthat/test-jts-xml.R
+88dadbfcd6df147b04bcf31aadf296b2 *tests/testthat/test-linearref.R
+e0d14404278e8ea3080b7ffed7fdae38 *tests/testthat/test-misc.R
+9b8b49132a928c8740b881e6fa234a7f *tests/testthat/test-translate-empty.R
+0d33f089065f673688e69f6218694e91 *tests/testthat/test-translate-lines.R
+a5c6cd10cf0e7cb89e42b9413ee7bcce *tests/testthat/test-translate-points.R
+548ae3b9d90ab90bb13724329f394a52 *tests/testthat/test-translate-polygon-collection.R
+41b87202851e0df48340e8c766ffa522 *tests/testthat/test-translate-polygons.R
+76df903ce8957b59ede16b46f52bd6f2 *tests/testthat/test-translate-rings.R
+85de271a5942086c0d7034b6f23cad16 *tests/testthat/testxml/general/TestBoundary.xml
+238b99796c83b1368cbb468199e31586 *tests/testthat/testxml/general/TestCentroid.xml
+cf4b9d3cdbb673fbe2338b5f1f08231a *tests/testthat/testxml/general/TestConvexHull-big.xml
+02314549a1ccd691b89e6fa62cd2ecec *tests/testthat/testxml/general/TestConvexHull.xml
+4bff009ae3404c63e8fd262960299a2a *tests/testthat/testxml/general/TestFunctionAA.xml
+fc4b823964feb08db0c3f3fbfa397a7f *tests/testthat/testxml/general/TestFunctionAAPrec.xml
+9d1fee1dade6345657310f94201aeca5 *tests/testthat/testxml/general/TestFunctionLA.xml
+fcf1ea9981b5a15323ef594699cd24d8 *tests/testthat/testxml/general/TestFunctionLAPrec.xml
+0316c1549d55821ceabf96b8c3c5d21b *tests/testthat/testxml/general/TestFunctionLL.xml
+d29df13935ad3d08782a08f4d74590f1 *tests/testthat/testxml/general/TestFunctionLLPrec.xml
+017d6a56564624f2c6ae7ff7f67e4a62 *tests/testthat/testxml/general/TestFunctionPA.xml
+88675d6c34cd0ed50981021bbf986f56 *tests/testthat/testxml/general/TestFunctionPL.xml
+954b5cd834d99cf4bd3a1a56f77adb70 *tests/testthat/testxml/general/TestFunctionPLPrec.xml
+b9a7204b5c8925a895480c96306c27de *tests/testthat/testxml/general/TestFunctionPP.xml
+ef7ad411abb64482f9f9467ab34d1b83 *tests/testthat/testxml/general/TestInteriorPoint.xml
+d020d400dacc83946be4071b321e2fa1 *tests/testthat/testxml/general/TestRectanglePredicate.xml
+a603cc5dbc0e476fb7e6ed575f3137e1 *tests/testthat/testxml/general/TestRelateAA.xml
+9c57906c31a570e3d65b58dd434911f0 *tests/testthat/testxml/general/TestRelateAC.xml
+65adcdc2f9d1e43f1ba6e28b3100a78c *tests/testthat/testxml/general/TestRelateLA.xml
+b2426811cd8c4a40d9f4da62fada1432 *tests/testthat/testxml/general/TestRelateLC.xml
+d6483169d875c21525f88efb291b16e0 *tests/testthat/testxml/general/TestRelateLL.xml
+36ed9c771ed716c6d0a7547aff2f3241 *tests/testthat/testxml/general/TestRelatePA.xml
+1cdf6c7444d42166f644b33a72a0929b *tests/testthat/testxml/general/TestRelatePL.xml
+1614e7b3f3ccc50478275386020143ab *tests/testthat/testxml/general/TestRelatePP.xml
+564c51181acf2209e65ac509ae33bd0e *tests/testthat/testxml/general/TestSimple.xml
+20056f0fff77fd490ff2a6bb81fe4421 *tests/testthat/testxml/general/TestValid.xml
+1edf2d54da09378a6a9df5a2bca07d2f *tests/testthat/testxml/general/TestValid2-big.xml
+b68bd7415bf831369786ca812f35020d *tests/testthat/testxml/general/TestValid2.xml
+770eae0ddc4c31f021359ba1c9887b81 *tests/testthat/testxml/general/TestWithinDistance.xml
+a96a20073ad6eca7ec9ccfbadec4b8bf *tests/testthat/testxml/robust/ExternalRobustness.xml
+1c39406b7e17335b496cb06ca20f0398 *tests/testthat/testxml/robust/TestRobustOverlayFixed.xml
+d50e2e9f8163c89143e9fd4a3856a8b5 *tests/testthat/testxml/robust/TestRobustOverlayFloat.xml
+9e3f6bb752ee37cc4ea561d5f519f384 *tests/testthat/testxml/robust/TestRobustRelate.xml
+85eaa6d70a318f5dece551e805d27f8c *tests/testthat/testxml/validate/TestRelateAA-big.xml
+689cdc9247e6ca08b361c614f7e17bd3 *tests/testthat/testxml/validate/TestRelateAA.xml
+2a641ec237a50d71301b8c9725b7b78b *tests/testthat/testxml/validate/TestRelateAC.xml
+49bbed72ecbcb20451fe85286dbfdcf4 *tests/testthat/testxml/validate/TestRelateLA.xml
+99cf031e60310453135aff8e9fcc8f9e *tests/testthat/testxml/validate/TestRelateLC.xml
+9cc1637172535f5e6b1e51c1ab949b9c *tests/testthat/testxml/validate/TestRelateLL.xml
+b9f04df2e44980fc3fab61abef5a1ad3 *tests/testthat/testxml/validate/TestRelatePA.xml
+ec950a450f3334e687d31c54394d9721 *tests/testthat/testxml/validate/TestRelatePL.xml
+6acf466871a08776af9e3fde8b2b7998 *tests/testthat/testxml/validate/TestRelatePP.xml
+86647dbb5cb8d95cbb27010acd325588 *tools/winlibs.R
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100644
index 0000000..4b6148a
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,85 @@
+useDynLib(rgeos)
+
+import(methods)
+import(sp)
+importFrom(utils, packageVersion)
+importFrom(stats, optim)
+importFrom(graphics, par, lines, strwidth, strheight, text)
+
+export(createPolygonsComment, createSPComment, set_do_poly_check, get_do_poly_check)
+export(rgeos_extSoftVersion)
+#export(checkPolygonsGEOS)
+#export(checkHolesGPC)
+export(poly_findInBoxGEOS, gUnarySTRtreeQuery, gBinarySTRtreeQuery)
+
+# sp extension classes
+exportClasses(Ring,SpatialRings, SpatialRingsDataFrame)
+export(Ring,SpatialRings,SpatialRingsDataFrame)
+
+exportClasses(SpatialLinesNULL, SpatialPointsNULL, SpatialPolygonsNULL, SpatialRingsNULL)
+exportClasses(SpatialCollections)
+export(SpatialCollections)
+
+exportMethods(row.names)
+
+# Utility Functions
+export(getScale,setScale,translate,checkP4S) #,groupID)
+export(version_GEOS, version_GEOS0)
+export(set_RGEOS_dropSlivers, get_RGEOS_dropSlivers, set_RGEOS_warnSlivers,
+ get_RGEOS_warnSlivers, set_RGEOS_polyThreshold, get_RGEOS_polyThreshold)
+
+# WKT Functions
+export(readWKT, writeWKT)
+
+
+# GEOS unary predicate functions
+export(RGEOSisEmpty, RGEOSisValid, RGEOSisSimple, RGEOSisRing)#, RGEOSHasZ)
+export(gIsEmpty, gIsValid, gIsSimple, gIsRing)#, gHasZ)
+
+
+# GEOS binary predicate functions
+export( RGEOSRelate, RGEOSDisjoint, RGEOSTouches, RGEOSIntersects, RGEOSCrosses,
+		RGEOSWithin, RGEOSContains, RGEOSOverlaps, RGEOSEquals, RGEOSEqualsExact)
+export( gRelate, gDisjoint, gTouches, gIntersects, gCrosses,
+		gWithin, gContains, gOverlaps, gEquals, gEqualsExact,
+		gContainsProperly, gCovers, gCoveredBy)
+
+# GEOS misc functions
+export( RGEOSArea, RGEOSLength, RGEOSDistance, RGEOSisWithinDistance, 
+		RGEOSHausdorffDistance)
+export( gArea, gLength, gDistance, gWithinDistance, gNearestPoints)
+
+
+# GEOS topology functions
+export( RGEOSEnvelope, RGEOSConvexHull, RGEOSBoundary, RGEOSGetCentroid, 
+		RGEOSPointOnSurface, RGEOSLineMerge, RGEOSUnionCascaded)
+export( gEnvelope, gConvexHull, gBoundary, gCentroid, 
+		gPointOnSurface, gLineMerge, gUnionCascaded, gUnaryUnion)
+
+export(	gSimplify, gPolygonize, gDelaunayTriangulation, gNode)
+		
+# GEOS binary topology functions
+export( gDifference, gSymdifference, gIntersection, gUnion)# RSB FIXME
+
+# GEOS buffer functions
+export( RGEOSBuffer, gBuffer )
+
+# GEOS linearref functions
+export(gProject, gInterpolate)
+
+
+# gpclib shadows
+
+#importFrom(graphics, plot)
+
+exportClasses("gpc.poly", "gpc.poly.nohole")
+exportMethods("show", "get.bbox", "plot", "intersect", "union", "symdiff",
+              "setdiff", "[", "append.poly", "scale.poly", "area.poly",
+              "get.pts", "coerce", "tristrip", "triangulate")
+
+export("read.polyfile", "write.polyfile")
+
+export(polygonsLabel)
+
+export(overGeomGeom) # needed by sp::overMultiPoints
+export(overGeomGeomDF) # needed by sp::overMultiPoints
diff --git a/R/AAA.R b/R/AAA.R
new file mode 100644
index 0000000..11d936f
--- /dev/null
+++ b/R/AAA.R
@@ -0,0 +1,125 @@
+.RGEOS_HANDLE <- new.env(FALSE, parent=globalenv())
+
+set_RGEOS_HANDLE <- function(handle) {
+    assign("GEOSptr", handle, envir=.RGEOS_HANDLE)
+}
+
+set_RGEOS_DENSE <- function(value) {
+    stopifnot(is.logical(value))
+    stopifnot(length(value) == 1)
+    assign("returnDense", value, envir=.RGEOS_HANDLE)
+}
+
+get_RGEOS_DENSE <- function() {
+    get("returnDense", envir=.RGEOS_HANDLE)
+}
+
+set_RGEOS_dropSlivers <- function(value) {
+    stopifnot(is.logical(value))
+    stopifnot(length(value) == 1)
+    assign("dropSlivers", value, envir=.RGEOS_HANDLE)
+}
+
+get_RGEOS_dropSlivers <- function() {
+    get("dropSlivers", envir=.RGEOS_HANDLE)
+}
+
+set_RGEOS_warnSlivers <- function(value) {
+    stopifnot(is.logical(value))
+    stopifnot(length(value) == 1)
+    assign("warnSlivers", value, envir=.RGEOS_HANDLE)
+}
+
+get_RGEOS_warnSlivers <- function() {
+    get("warnSlivers", envir=.RGEOS_HANDLE)
+}
+
+set_RGEOS_polyThreshold <- function(value) {
+    stopifnot(is.numeric(value))
+    stopifnot(length(value) == 1)
+    stopifnot(value >= 0.0)
+    assign("polyThreshold", value, envir=.RGEOS_HANDLE)
+}
+
+get_RGEOS_polyThreshold <- function() {
+    get("polyThreshold", envir=.RGEOS_HANDLE)
+}
+
+set_RGEOS_STR <- function(value) {
+    stopifnot(is.logical(value))
+    stopifnot(length(value) == 1)
+    assign("STRsubset", value, envir=.RGEOS_HANDLE)
+}
+
+get_RGEOS_STR <- function() {
+    get("STRsubset", envir=.RGEOS_HANDLE)
+}
+
+init_RGEOS <- function() {
+    .Call('rgeos_Init', PACKAGE="rgeos")
+}
+
+finish_RGEOS <- function() {
+    .Call('rgeos_finish', .RGEOS_HANDLE, PACKAGE="rgeos")
+}
+
+version_GEOS <- function() {
+    .Call("rgeos_GEOSversion", PACKAGE="rgeos")
+}
+
+version_GEOS0 <- function() {
+    substring(version_GEOS(), 1, 5)
+}
+
+version_sp_linkingTo <- function() {
+    .Call("rgeos_sp_linkingTo_version")
+}
+
+.onLoad <- function(lib, pkg) {
+#  require(methods, quietly = TRUE, warn.conflicts = FALSE)
+#  require("sp")
+#  require("stringr")
+#  library.dynam('rgeos', pkg, lib)
+
+  set_RGEOS_HANDLE(init_RGEOS())
+  assign("scale", 100000000, envir=.RGEOS_HANDLE)
+  assign("do_poly_check", TRUE, envir=.RGEOS_HANDLE)
+#  assign("both_poly", FALSE, envir=.RGEOS_HANDLE)
+#  assign("drop_not_poly", FALSE, envir=.RGEOS_HANDLE)
+  assign("polyThreshold", 0.0, envir=.RGEOS_HANDLE)
+  assign("dropSlivers", FALSE, envir=.RGEOS_HANDLE)
+  assign("warnSlivers", TRUE, envir=.RGEOS_HANDLE)
+  assign("returnDense", TRUE, envir=.RGEOS_HANDLE)
+  assign("STRsubset", FALSE, envir=.RGEOS_HANDLE)
+}
+
+.onAttach <- function(lib, pkg) {
+  fn <- system.file("SVN_VERSION", package="rgeos")
+  if (file.exists(fn)) {
+    svn_version <- scan(fn, what=character(1), sep="\n", quiet=TRUE)
+  } else {
+    svn_version <- "(unknown)"
+  }
+  Smess <- paste("rgeos version: ", utils::packageDescription("rgeos")$Version,
+    ", (SVN revision ", svn_version, ")\n", sep="")
+  Smess <- paste(Smess, "GEOS runtime version:",
+    version_GEOS(), "\n")
+  splVersion <- version_sp_linkingTo()
+  Smess <- paste(Smess, "Linking to sp version:", splVersion, "\n")
+  spVcheck <- NULL
+  if("sp" %in% .packages()) spVcheck <- utils::packageVersion("sp") == splVersion
+  if (!is.null(spVcheck) && !spVcheck) paste(Smess, 
+    "sp version used to install rgeos and loaded sp version differ\n")
+
+  Smess <- paste(Smess, "Polygon checking:", get_do_poly_check(), "\n")
+  packageStartupMessage(Smess, appendLF = TRUE)
+}
+
+.onUnload <- function(libpath) {
+  invisible(finish_RGEOS())
+}
+
+rgeos_extSoftVersion <- function() {
+  res <- c("GEOS"=strsplit(version_GEOS(), "-")[[1]][1], "sp"=version_sp_linkingTo())
+  res
+}
diff --git a/R/Rgpc_funcs.R b/R/Rgpc_funcs.R
new file mode 100644
index 0000000..a77a977
--- /dev/null
+++ b/R/Rgpc_funcs.R
@@ -0,0 +1,358 @@
+## gpclib:  General Polygon Clipping library for R
+## Copyright (C) 2003-2010 Roger D. Peng <rpeng at jhsph.edu>
+
+
+## R functions for using GPC library and manipulating polygons
+
+setClass("gpc.poly", representation(pts = "list"))
+setClass("gpc.poly.nohole", "gpc.poly")
+
+## setValidity("gpc.poly",
+##             function(x) {
+##                 pts <- x at pts
+##                 lens <- sapply(pts, length)
+##                 if(!identical(all(lens == 3), TRUE))
+##                     "Not all contours have correct elements"
+##                 ## correct names (x, y, hole)
+##                 contour.names <- lapply(pts, names)
+##                 correct.names <- c("x", "y", "hole")
+##                 check <- lapply(contour.names, function(n) {
+##                     n %in% correct.names
+##                 })
+##                 if(!identical(all(sapply(check, all)), TRUE))
+##                     "Incorrect list names in contours"
+##                 ## correct types
+##                 ## equal lengths?
+##             })
+
+setMethod("show", "gpc.poly",
+          function(object) {
+              cat("GPC Polygon\n")
+              cat("   Num. Contours: ", length(object at pts), "\n")
+              if(length(object at pts) == 1)
+                  cat("   Num. Vertices: ", length(object at pts[[1]]$x),"\n")
+              bbox <- get.bbox(object)
+              cat("   BBox (X): ", bbox$x[1], "-->", bbox$x[2], "\n")
+              cat("   BBox (Y): ", bbox$y[1], "-->", bbox$y[2], "\n")
+              invisible(object)
+          })
+
+setGeneric("get.bbox", function(x)
+           standardGeneric("get.bbox"))
+
+setMethod("get.bbox", signature(x = "gpc.poly"),
+          function(x) {
+              pts <- x at pts
+              x <- unlist(lapply(pts, "[[", "x"))
+              y <- unlist(lapply(pts, "[[", "y"))
+              
+              if(!is.null(x))
+                  xlim <- range(x)
+              else
+                  xlim <- c(NA, NA)
+              if(!is.null(y))
+                  ylim <- range(y)
+              else
+                  ylim <- c(NA, NA)
+              list(x = xlim, y = ylim)
+          })
+
+setGeneric("plot")
+
+setMethod("plot", "gpc.poly",
+          function(x, y, poly.args = list(), xlab = "X", ylab = "Y",
+                   asp = 1, add = FALSE, ...) {
+              if(!add) {
+                  bbox <- get.bbox(x)
+                  plot(0, 0, ylim = bbox$y, xlim = bbox$x, type="n",
+                       xlab = xlab, ylab = ylab, asp = asp, ...)
+              }
+              invisible(lapply(x at pts, function(p) {
+                  do.call("polygon", append(list(x = p), poly.args))
+              }))
+          })
+
+setGeneric("intersect")
+setGeneric("union")
+setGeneric("setdiff")
+if (!isGeneric("symdiff")) setGeneric("symdiff", function(x, y)
+		standardGeneric("symdiff"))
+
+setMethod("intersect", signature(x = "gpc.poly", y = "gpc.poly"),
+          	function(x, y) {
+		  		spx = as(x,"SpatialPolygons")
+				spy = as(y,"SpatialPolygons")
+				spres = gIntersection(spx, spy, drop_lower_td=TRUE)
+		
+                                if (is.null(spres))
+                                    return(new("gpc.poly"))
+				as(spres,"gpc.poly")
+          	})
+
+
+setMethod("setdiff", signature(x = "gpc.poly", y = "gpc.poly"),
+          	function(x, y) {
+		  		spx = as(x,"SpatialPolygons")
+				spy = as(y,"SpatialPolygons")
+				spres = gDifference(spx,spy, drop_lower_td=TRUE)
+		
+                                if (is.null(spres))
+                                    return(new("gpc.poly"))
+				as(spres,"gpc.poly")
+          	})
+
+setMethod("union", signature(x = "gpc.poly", y = "gpc.poly"),
+          function(x, y) {
+		  		spx = as(x,"SpatialPolygons")
+				spy = as(y,"SpatialPolygons")
+				spres = gUnion(spx,spy, drop_lower_td=TRUE)
+		
+                                if (is.null(spres))
+                                    return(new("gpc.poly"))
+				as(spres,"gpc.poly")
+          })
+
+setMethod("symdiff", signature(x = "gpc.poly", y = "gpc.poly"),
+          function(x, y) {
+		  		spx = as(x,"SpatialPolygons")
+				spy = as(y,"SpatialPolygons")
+				spres = gSymdifference(spx,spy, drop_lower_td=TRUE)
+
+                                if (is.null(spres))
+                                    return(new("gpc.poly"))
+				as(spres,"gpc.poly")
+          })
+
+setGeneric("tristrip", function(x) 
+           standardGeneric("tristrip"))
+           
+setMethod("tristrip", signature(x = "gpc.poly"),
+		function(x) {
+			stop("rgeos does not currently implement this feature of gpclib")
+		
+	      	#poly <- as(x, "numeric")
+	      	#result <- .Call("Rgpc_polygon_to_tristrip", poly, PACKAGE = "gpclib")
+	      	#result <- lapply(result, function(strip) matrix(strip, ncol=2, byrow=TRUE))
+	  	})
+
+setGeneric("triangulate", function(x) 
+           standardGeneric("triangulate"))
+ 
+setMethod("triangulate", signature(x = "gpc.poly"),
+		function(x) {
+			stop("rgeos does not currently implement this feature of gpclib")
+	      	tristrip <- tristrip(x)
+	      	triangles <- lapply(tristrip, 
+	                     function(strip) {
+	                          n <- nrow(strip)
+	                          if (n > 3)
+	                              result <- strip[c(1:3,4:2) + 2*rep(0:(n %/% 2 - 2), each=6), ]
+	                          else
+	                              result <- strip[0,]
+	                          if (n %% 2 && n > 2) result <- rbind(result, strip[1:3 + n - 3,])
+	                          return(result)
+	                          })
+	                          
+	      	do.call(rbind, triangles)
+	  	})
+
+setMethod("[", "gpc.poly",
+          function(x, i, j, ..., drop = FALSE) {
+              new("gpc.poly", pts = x at pts[i])
+          })
+
+setAs("matrix", "gpc.poly",
+      function(from, to) {
+          if(ncol(from) > 2)
+              stop("matrix must have 2 columns")
+          p <- list(x = from[,1], y = from[,2], hole = FALSE)
+          new("gpc.poly", pts = list(p))
+      })
+
+setAs("data.frame", "gpc.poly",
+      function(from, to) {
+          as(as.matrix(from), "gpc.poly")
+      })
+
+## Miscellaneous Utility Functions
+
+setGeneric("append.poly", function(x, y)
+           standardGeneric("append.poly"))
+
+setMethod("append.poly",
+          signature(x = "gpc.poly", y = "gpc.poly"),
+          function(x, y) {
+              newpts <- append(x at pts, y at pts)
+              new("gpc.poly", pts = newpts)
+          })
+
+setGeneric("scale.poly", function(x, ...)
+           standardGeneric("scale.poly"))
+
+setMethod("scale.poly", signature(x = "gpc.poly"), 
+          function(x, xscale, yscale = xscale, ...) {
+              x at pts <- lapply(x at pts, function(p) {
+                  p$x <- p$x / xscale
+                  p$y <- p$y / yscale
+                  p
+              })
+              x
+          })
+
+## Compute the area of each polygon in the polygon set contained in
+## `object'.  
+
+setGeneric("area.poly", function(object, ...)
+           standardGeneric("area.poly"))
+
+setMethod("area.poly", signature(object = "gpc.poly"),
+          function(object, ...) {
+              area <- function(x.mat) {
+                  if(nrow(x.mat) < 3) 
+                      return(0);   
+                  x.segmat <- cbind(x.mat, rbind(x.mat[2:nrow(x.mat), ],
+                                                 x.mat[1, ]));
+                  abs(sum(x.segmat[,1] * x.segmat[,4] - x.segmat[,3]
+                          * x.segmat[,2])) / 2
+              }
+              if(length(object at pts) == 0)
+                  return(0)
+              a <- sapply(object at pts, function(p) area(cbind(p$x, p$y)))
+              holeflags <- sapply(object at pts, "[[", "hole")
+              sum(a[!holeflags]) - sum(a[holeflags])
+          })
+
+## Added 2003/01/07
+setGeneric("get.pts", function(object)
+           standardGeneric("get.pts"))
+
+setMethod("get.pts", signature(object = "gpc.poly"),
+          function(object) {
+              object at pts
+          })
+
+## These two functions are needed for the intersect/union/setdiff
+## methods.  They basically serialize and unserialize the "gpc.poly"
+## object.
+
+## We need separate functions because polygons with holes and polygons
+## without holes have different file formats
+
+setAs("numeric", "gpc.poly.nohole", 
+      function(from) {
+          ## The shortest a vector can be is 8 numbers:  1. Num. Contours;
+          ## 2. Num pts for first contour; and three vertices
+          if(length(from) < 8)
+              stop("numeric vector not long enough")
+          expand.poly <- function(x) {
+              ## `x' is just a long vector of numbers with a special format
+              num.contours <- x[1]; x <- x[-1]
+              polyfile <- x
+              poly <- vector("list", length = num.contours)
+              
+              for(i in 1:num.contours) {
+                  npts <- polyfile[1]; polyfile <- polyfile[-1]
+                  m <- matrix(polyfile[1:(2*npts)], byrow = TRUE, ncol = 2)
+                  poly[[i]] <- list(x = m[,1], y = m[,2], hole = FALSE)
+                  polyfile <- polyfile[-(1:(2*npts))]
+              }
+              poly
+          }
+          new("gpc.poly.nohole", pts = expand.poly(from))
+      })
+
+setAs("numeric", "gpc.poly", 
+      function(from) {
+          ## The shortest a vector can be is 9 numbers:  1. Num. Contours;
+          ## 2. Num pts for first contour; 3. hole flag; and three vertices
+          if(length(from) < 9)
+              stop("numeric vector not long enough")
+          expand.poly <- function(x) {
+              num.contours <- x[1]; x <- x[-1]
+              polyfile <- x
+              poly <- vector("list", length = num.contours)
+              
+              for(i in 1:num.contours) {
+                  npts <- polyfile[1]
+                  polyfile <- polyfile[-1]
+                  hole <- as.logical(polyfile[1])
+                  polyfile <- polyfile[-1]
+                  
+                  m <- matrix(polyfile[1:(2*npts)], byrow = TRUE, ncol = 2)
+                  poly[[i]] <- list(x = m[,1], y = m[,2], hole = hole)
+                  polyfile <- polyfile[-(1:(2*npts))]
+              }
+              poly
+          }
+          new("gpc.poly", pts = expand.poly(from))
+      })
+
+##
+
+setAs("gpc.poly", "numeric",
+      function(from) {
+          flatten.poly <- function(poly) {
+              num.contours <- length(poly at pts)
+              flat <- lapply(poly at pts, function(p)
+                         {
+                             v <- as.vector(t(cbind(p$x, p$y)))
+                             c(length(p$x), as.numeric(p$hole), v)
+                         })
+              c(num.contours, unlist(flat))
+          }
+          flatten.poly(from)
+      })
+
+setAs("gpc.poly", "matrix",
+      function(from) {
+          if(length(from at pts) > 1)
+              stop("can only convert a single contour into a matrix")
+          pts <- from at pts[[1]]
+          m <- cbind(x = pts$x, y = pts$y)
+      })
+
+## 'from' is a list(x = ..., y = ...)
+
+setAs("list", "gpc.poly",
+      function(from) {
+              if(!(all(c("x", "y") %in% names(from))))
+                      stop("list should have names 'x' and 'y'")
+              if(length(from$x) != length(from$y))
+                      stop("'x' and 'y' elements should have the same length")
+              as(cbind(from$x,from$y), "gpc.poly")
+      })
+
+
+## Read a polygon from a file
+
+read.polyfile <- function(filename, nohole = TRUE) {
+        polyfile <- scan(filename, quiet = TRUE)
+        if(nohole) 
+                as(polyfile, "gpc.poly.nohole")
+        else
+                as(polyfile, "gpc.poly")
+}
+
+## Write a "gpc.poly" object to a text file
+
+write.polyfile <- function(poly, filename = "GPCpoly.txt") {    
+    if(!is(poly, "gpc.poly"))
+        stop("'poly' should be of class 'gpc.poly'")
+    outfile <- file(filename, "w")
+    on.exit(close(outfile))
+
+    num.contours <- length(poly at pts)   
+    cat(num.contours, "\n", file = outfile)
+
+    for(i in 1:num.contours) {
+        m <- as(poly[i], "matrix")
+        cat(nrow(m), "\n", file = outfile, append = TRUE)
+
+        if(!is(poly, "gpc.poly.nohole"))
+            cat(as.numeric(poly at pts[[i]]$hole), "\n",
+                file = outfile, append = TRUE)       
+        write(t(m), file = outfile, ncolumns = 2, append = TRUE)
+    }
+}
+
+
diff --git a/R/gpc_geos.R b/R/gpc_geos.R
new file mode 100644
index 0000000..c3e2b38
--- /dev/null
+++ b/R/gpc_geos.R
@@ -0,0 +1,87 @@
+rgeos_SpatialPolygons2gpcpoly <- function(from) {
+    
+    if (!inherits(from,"SpatialPolygons"))
+        stop("sp does not inherit from SpatialPolygons")
+    
+    gpcs = list()
+    for(i in 1:length(from at polygons)) {
+        polys = from at polygons[[i]]
+        
+        pts = list()
+        for(j in 1:length(polys at Polygons)) {
+            coords = polys at Polygons[[j]]@coords
+            hole = polys at Polygons[[j]]@hole
+            l=nrow(coords)
+            
+            pts[[j]] = list(x=coords[-l,1],y=coords[-l,2],hole=hole)
+        }
+        
+        gpc = new("gpc.poly", pts = pts)
+        gpcs[i] = gpc
+    }
+    
+    if (length(gpcs) == 0)
+        gpcs = NULL
+    if (length(gpcs) == 1)
+        gpcs = gpcs[[1]]
+
+    return(gpcs)
+}
+
+rgeos_gpcpoly2SpatialPolygons <- function(from) {
+    
+    if (!is.list(from))
+        from = list(from)
+        
+    res=lapply(from, function(gpc) {
+
+        if (!inherits(gpc,"gpc.poly"))
+            stop("object does not inherit from gpc.poly")
+    
+        if (length(gpc at pts) < 1)
+            stop("must be at least one polygon")
+    
+        polylist = lapply( gpc at pts, function(pt) {
+            x=pt$x
+            y=pt$y
+            l=length(x)
+            
+            if (x[1]!=x[l] | y[1]!=y[l]) {
+                x = c(x,x[1])
+                y = c(y,y[1])
+            }
+            
+			hole = 
+			
+            return( Polygon(cbind(x,y),pt$hole) )
+        })
+
+        
+        p = Polygons(polylist,"0")
+        attr(p,"comment") = createPolygonsComment(p)
+        
+        return(p)
+    })
+    
+    for (m in 1:length(from)) {
+        res[[m]]@ID = as.character(m)
+    }
+    
+    return( SpatialPolygons(res) )
+}
+
+setAs("SpatialPolygons", "gpc.poly", rgeos_SpatialPolygons2gpcpoly)
+setAs("gpc.poly", "SpatialPolygons", rgeos_gpcpoly2SpatialPolygons)
+
+setAs("SpatialPolygons", "gpc.poly.nohole", rgeos_SpatialPolygons2gpcpoly)
+setAs("gpc.poly.nohole", "SpatialPolygons", rgeos_gpcpoly2SpatialPolygons)
+
+
+areaGPC <- function(x.mat) {
+    if(nrow(x.mat) < 3) 
+        return(0);   
+    x.segmat <- cbind(x.mat, rbind(x.mat[2:nrow(x.mat), ],
+         x.mat[1, ]));
+    abs(sum(x.segmat[,1] * x.segmat[,4] - x.segmat[,3]
+        * x.segmat[,2])) / 2
+}
diff --git a/R/labelpt.R b/R/labelpt.R
new file mode 100644
index 0000000..15a4cf1
--- /dev/null
+++ b/R/labelpt.R
@@ -0,0 +1,217 @@
+# Calculate the coordinate inside "pol" where a rectangle 
+# of width "labw" and height "labh" centred on the coordinate
+# has the largest possible distance from the polygon boundary.
+# Uses a grid search with "gridpoints" coordinate pairs for the
+# initial search, and refines the result using numerical 
+# optimisation (the Nelder-Mead algorithm).
+labpos.maxdist = function(pol, labw, labh, gridpoints) {
+
+  # Create a rectangular polygon with a given size, centred at a given position
+  makerect = function(x, y, wd, ht, rectID)
+    Polygons(list(Polygon(cbind(c(x-wd/2, x+wd/2, x+wd/2, x-wd/2, x-wd/2), 
+                                c(y-ht/2, y-ht/2, y+ht/2, y+ht/2, y-ht/2)))), rectID)
+
+  # Calculate the distance from the given coordinates (2-column matrix)
+  # to the polygon boundary. Returns 0 for any coordinates that results
+  # in a rectangle not fully inside the polygon.
+  getDists = function(co) {
+    # Create a candidate label rectangle for each coordinate
+    rects = SpatialPolygons(sapply(seq_len(nrow(co)),
+                            function(i) makerect(co[i,1], co[i,2], labw, labh, i)),
+                            proj4string=CRS(proj4string(pol)))
+
+    # Check each rectangle to see if it"s inside the polygon
+    inside = apply(gContains(pol, rects, byid = TRUE), 1, any)
+
+    # Calculate and return the distance to the polygon boundary for
+    # each rectangle (0 for any rectangle (partially) outside the polygon)
+    di = numeric(nrow(co))
+    if(any(inside))
+      di[inside] = gDistance(pol.l, rects[inside], byid = TRUE)
+    di
+  }
+
+  # Convert the polygon to lines, so that we can easily measure
+  # the distance from the rectangles to the polygon boundary
+  pol.l = as(pol, "SpatialLines")
+  
+  # Sample a regular grid of points inside the polygon
+  co = coordinates(spsample(pol, n = gridpoints, type = "regular"))
+  
+  # Calculate the distances to the polygon boundary
+  di = getDists(co)
+  
+  # Stop if no rectangles were inside the polygon
+  if(all(di == 0))
+    stop("Could not fit label inside polygon (with the given number of grid points)")
+  
+  # Use numerical optimisation to zero in on the optimal position,
+  # with the coordinate found by grid search as initial values.
+  # Unfortunately, the Nelder-Mead algorithm in "optim" has some
+  # strange heuristics for the step size (size of the initial 
+  # simplex) which is not possible to override, so, as a workaround, 
+  # we do our own affine transformation inside a wrapper function.
+  origin = co[which.max(di),]                                          # Initial value
+  stepsize = min(apply(co, 2, function(x) diff(sort(unique(x))[1:2]))) # Distance between grid points
+  
+  getDistsScaled = function(co, origin, stepsize) {
+    -getDists(matrix(co, ncol=2)*stepsize + origin)
+  }
+  optres = optim(c(0,0), getDistsScaled, method = "Nelder-Mead", 
+               control = list(trace = FALSE, reltol = .001),
+               origin = origin, stepsize = stepsize)
+  optval = optres$par*stepsize + origin # "Optimal" label position
+  
+  # Only return the calculated position if the numerical optimisation succeeded
+  if(optres$convergence != 0) {
+    warning("Numerical optimisation did not converge. Returning result of grid search.")
+    optval = origin
+  }
+  
+  # Return the "optimal" label position
+  optval
+}
+
+
+# Shrink the polygon (using a negative buffer) until
+# the convex hull of the shrunken polygon is entirely
+# contained inside the original polygon. Then calculate
+# the label position as the centroid of the shrunken 
+# polygon. (The centroid of the convex hull also gives
+# similar results.)
+labpos.buffer = function(pol, getLargestPolyPart) {
+    init = 0                       # Initial amount to shrink
+    estep = sqrt(gArea(pol)/pi)/10 # Additional amount to shrink for each step
+    
+    # Try repeatedly shrinking the polygon until we"re left
+    # with a polygon whose convex hull fits inside the
+    # original polygon.
+    repeat {
+      repeat {
+        r = init + estep                 # Amount to shrink
+        pol.b = gBuffer(pol, width = -r) # Shrink the polygon
+        if (is.null(pol.b)) {
+          estep = estep/2
+        } else {
+          if( gArea(pol.b) <= 0 )        # If the shrunken polygon is empty ...
+            estep = estep/2 else break   # ... try again with a smaller value
+        }
+      }
+      
+      # If we"re left with more than one polygon, choose the largest one
+      polb = getLargestPolyPart(pol.b)
+      
+      # Calculate the convex hull of the inner polygon.
+      # If this is wholly contained in the original polygon,
+      # break out of the loop and set the label point to
+      # the centroid of the inner polygon.
+      if( gContains(pol, gConvexHull(pol.b)) ) break else init=init+estep
+    }
+    coordinates(pol.b)
+}
+
+
+# Generate a random position inside the polygon
+labpos.random = function(pol) {
+  # Note that the "spsample" function sometimes fail to
+  # find a random point inside the polygon (on the first try),
+  # so we may need repeated sampling. Eventually a point is found.
+  repeat {
+    coord.rand = tryCatch(spsample(pol, n = 1, type = "random"), error = function(x) NULL)
+    if(!is.null(coord.rand)) break
+  }
+  coordinates(coord.rand)
+}
+
+
+# Calculate optimal polygon labels.
+#     pols: SpatialPolygons(DataFrame) object.
+#   labels: The labels to apply to each polygon.
+#           If NULL, the positition is calculated as if the
+#           label is a square with one line long sides
+#           (given the current value of "cex").
+#   method: The method(s) used to calculate label positions.
+#           Possible values: maxdist, buffer, centroid,
+#                            random, pointonsurface
+# polypart: Which parts each multipolygon to use ("all" or "largest").
+#           Note that "largest" also removes any holes before
+#           calculating the label position, so the labels are
+#           no longer guaranteed not to overlap a hole.
+#   doplot: Should the labels be plotted on the current graphics device?
+#      ...: Additional arguments sent to "text"
+polygonsLabel = function(pols, labels = NULL, method = c("maxdist",
+                         "buffer", "centroid", "random", "inpolygon")[1],
+                         gridpoints = 60, polypart = c("all", "largest")[1],
+                         cex = 1, doPlot = TRUE, ...) {
+
+  # Return a SpatialPolygons object containing the
+  # biggest polygon part of a multipolygon
+  getLargestPolyPart = function(multipol) {
+    pols = multipol at polygons[[1]]@Polygons
+    
+    if(length(pols) > 1) {
+      areas = lapply(pols, function(x) x at area) # List of areas of the polygon parts
+      pols = pols[which.max(areas)]            # The largest polygon part
+    
+    # Create new SpatialPolygons object only containing the largest polygon part
+    multipol = SpatialPolygons(list(Polygons(pols, ID="1")),
+                             proj4string=CRS(as.character(proj4string(multipol))))
+    }
+    
+    multipol
+  }
+  
+  # If no labels are given, assume empty labels
+  if(is.null(labels)) labels = ""
+  
+  # If ncessary, convert the labels into character labels
+  # (needed for factor labels)
+  if( !is.character(labels))
+    labels=as.character(labels)
+  
+  # Recycle all arguments so they contain the same
+  # number of elements as there are polygons
+  n = length(pols)
+  labels = rep(labels, length = n)
+  method = rep(method, length = n)
+  polypart = rep(polypart, length = n)
+  
+  # For each polygon, calculate the optimal label position
+  ret = matrix(ncol=2, nrow = n)
+  for (i in seq_along(labels)) {
+      labw = strwidth(labels[i], cex = cex)  # Label width
+      labh = strheight(labels[i], cex = cex) # Label height
+      if(labw == 0) labw = labh # For the empty string, use a one-line high square
+      pol = pols[i,]            # The polygon of interest
+      
+      # Optionally remove smaller polygon parts
+      if(polypart[i] == "largest") pol = getLargestPolyPart(pol)
+          
+      # Calculate the label optimal label position
+      ret[i,] = switch(method[i], "maxdist" = labpos.maxdist(pol, labw, labh, gridpoints),
+                                  "buffer" = labpos.buffer(pol, getLargestPolyPart=getLargestPolyPart),
+                                  "centroid" = coordinates(pol),
+                                  "random" = labpos.random(pol),
+                                  "inpolygon" = coordinates(gPointOnSurface(pol)),
+                                  stop(paste("Unknown method:", method[i])))
+  }
+  
+  # Optionally plot the labels
+  if(doPlot)
+    text(ret, labels, cex=cex, ...)
+  
+  ret
+}
+
+# TODO:
+#
+#   Automatic reprojection for unprojected maps
+#     (simple quirectangular, to match what "plot" does).
+#
+#   Option to auto-rotate labels (default < +/-30 degrees)
+#     to make them fit (better).
+#
+#   Better error handling (option to stop or to use
+#   centroids when no valid label positions are found).
+#
+#   A "removeholes" option?
diff --git a/R/over.R b/R/over.R
new file mode 100644
index 0000000..22e452d
--- /dev/null
+++ b/R/over.R
@@ -0,0 +1,139 @@
+order_relations = function(rel, minDimension) {
+	stopifnot(minDimension %in% 0:2)
+	rel = sapply(rel, function(x)
+			paste0(substring(x, c(1,4),c(2,5)), collapse=""))
+		# our interest is in chars
+		# 1-2 = inner of x with inner/border of y
+		# 4-5 = border of x with inner/border of y
+	ret = vector("numeric", length(rel)) * NA
+	for (d in minDimension:2) {
+		r = regexpr(as.character(d), rel, fixed = TRUE)
+		sel = which(r != -1)
+		if (length(sel) > 0)
+			ret[sel] = 4 - r[sel] + 4 * d
+	}
+	order(ret, decreasing = TRUE, na.last = NA)
+}
+
+listifyMatrix = function(x) { # put columns in list elements
+	if (!is.list(x)) {
+		if (length(x) == 0)
+			return(list(x))
+		if (!is.matrix(x)) { # vector!
+			nm = names(x)
+			x = matrix(x, 1, length(x))
+		} else
+			nm = dimnames(x)[[2]]
+		x = lapply(1:ncol(x), function(i) x[,i])
+		names(x) = nm
+	}
+	x
+}
+
+overGeomGeom = function(x, y, returnList = FALSE, fn = NULL, ..., minDimension = -1) {
+	stopifnot(identicalCRS(x, y))
+	if (gridded(x))
+		x = as(x, "SpatialPolygons")
+	if (gridded(y))
+		y = as(y, "SpatialPolygons")
+
+	if (minDimension %in% 0:2)
+		ret = apply(gRelate(x, y, byid = TRUE), 2, order_relations, minDimension = minDimension)
+	else
+		ret = apply(gIntersects(x, y, byid = TRUE), 2, which)
+	ret = listifyMatrix(ret) # if not already list, create one now
+	if (! returnList) # pick first, or NA if length is 0:
+		sapply(ret, function(x) (x)[1])
+	else 
+		ret
+}
+
+# taken from: overDFGeneric in sp; 
+# if modified here, consider modifying there as well!
+overGeomGeomDF = function(x, y, returnList = FALSE, fn = NULL, ..., minDimension = -1) {
+    r = overGeomGeom(x, y, returnList = TRUE, minDimension = minDimension)
+    #ret = sp:::.overDF(r, y at data, length(x), returnList, fn, ...)
+	#  length(x) differs from length(r) in case of SpatialMultiPoints!!!
+	#  reason to change is sp::overMultiPoints
+    ret = overDF_for_rgeos(r, y at data, length(r), returnList, fn, ...)
+    if (!returnList)
+        row.names(ret) = row.names(r)
+    ret
+}
+
+#setMethod("over",
+#    signature(x = "SpatialPoints", y = "SpatialPolygons"),
+#	        overGeomGeom)
+setMethod("over",
+    signature(x = "SpatialPoints", y = "SpatialLines"),
+	        overGeomGeom)
+#setMethod("over",
+#    signature(x = "SpatialPoints", y = "SpatialPoints"),
+#	        overGeomGeom)
+#setMethod("over",
+#    signature(x = "SpatialPolygons", y = "SpatialPoints"),
+#	        overGeomGeom)
+setMethod("over",
+    signature(x = "SpatialPolygons", y = "SpatialLines"),
+	        overGeomGeom)
+setMethod("over",
+    signature(x = "SpatialPolygons", y = "SpatialPolygons"),
+	        overGeomGeom)
+setMethod("over",
+    signature(x = "SpatialLines", y = "SpatialPoints"),
+	        overGeomGeom)
+setMethod("over",
+    signature(x = "SpatialLines", y = "SpatialPolygons"),
+	        overGeomGeom)
+setMethod("over",
+    signature(x = "SpatialLines", y = "SpatialLines"),
+	        overGeomGeom)
+
+# all with DataFrame:
+#setMethod("over",
+#    signature(x = "SpatialPoints", y = "SpatialPolygonsDataFrame"),
+#	        overGeomGeomDF)
+setMethod("over",
+    signature(x = "SpatialPoints", y = "SpatialLinesDataFrame"),
+	        overGeomGeomDF)
+#setMethod("over",
+#    signature(x = "SpatialPoints", y = "SpatialPointsDataFrame"),
+#	        overGeomGeomDF)
+#setMethod("over",
+#    signature(x = "SpatialPolygons", y = "SpatialPointsDataFrame"),
+#	        overGeomGeomDF)
+setMethod("over",
+    signature(x = "SpatialPolygons", y = "SpatialLinesDataFrame"),
+	        overGeomGeomDF)
+setMethod("over",
+    signature(x = "SpatialPolygons", y = "SpatialPolygonsDataFrame"),
+	        overGeomGeomDF)
+setMethod("over",
+    signature(x = "SpatialLines", y = "SpatialPointsDataFrame"),
+	        overGeomGeomDF)
+setMethod("over",
+    signature(x = "SpatialLines", y = "SpatialPolygonsDataFrame"),
+	        overGeomGeomDF)
+setMethod("over",
+    signature(x = "SpatialLines", y = "SpatialLinesDataFrame"),
+	        overGeomGeomDF)
+
+# lines & grids:
+setMethod("over",
+    signature(x = "SpatialLines", y = "SpatialPixels"),
+	        overGeomGeom)
+setMethod("over",
+    signature(x = "SpatialLines", y = "SpatialGrid"),
+	        overGeomGeom)
+setMethod("over",
+    signature(x = "SpatialLines", y = "SpatialPixelsDataFrame"),
+	        overGeomGeomDF)
+setMethod("over",
+    signature(x = "SpatialLines", y = "SpatialGridDataFrame"),
+	        overGeomGeomDF)
+setMethod("over",
+    signature(x = "SpatialPixels", y = "SpatialLines"),
+	        overGeomGeom)
+setMethod("over",
+    signature(x = "SpatialGrid", y = "SpatialLinesDataFrame"),
+	        overGeomGeomDF)
diff --git a/R/rgeos_buffer.R b/R/rgeos_buffer.R
new file mode 100644
index 0000000..b2f88d8
--- /dev/null
+++ b/R/rgeos_buffer.R
@@ -0,0 +1,88 @@
+
+
+gBuffer = function(spgeom, byid=FALSE, id=NULL, width=1.0, quadsegs=5, 
+                     capStyle="ROUND", joinStyle="ROUND", mitreLimit=1.0) {
+
+    stopifnot(is.logical(byid))
+    if (!is.na(is.projected(spgeom)) && !is.projected(spgeom))
+     warning("Spatial object is not projected; GEOS expects planar coordinates")
+# Josh O'Brien 2016-02-08
+    byid_status <- byid
+    if (byid && length(spgeom) == 1) {
+        id <- row.names(spgeom)[1]
+        byid <- FALSE
+        byid_status <- TRUE
+        #message("byid set to FALSE; single feature detected")
+    }
+    GEOSCapStyles = c("ROUND","FLAT","SQUARE")
+    GEOSJoinStyles = c("ROUND","MITRE","BEVEL")
+
+    
+    curids = unique(row.names(spgeom))
+    if (is.null(id)) {
+        if (byid)   id = curids
+        else        id = "buffer"
+    }
+    
+    if (byid == TRUE  && length(id) != length(curids) )
+        stop("if applying by ids, new ids must be same length as current ids")
+    if (byid == FALSE && length(id) != 1 ) 
+        stop("if applying across ids, new id must be length 1")
+    
+    id = as.character(id)
+    width = as.numeric(width)
+    n <- length(curids)
+    if (byid) {
+        if (length(width) == 1) width <- rep(width, n)
+        stopifnot(length(width) == n)
+    } else {
+        stopifnot(length(width) == 1)
+    }
+    quadsegs = as.integer(quadsegs)
+    byid = as.logical(byid)
+    mitreLimit=as.numeric(mitreLimit)
+    
+    if (is.character(capStyle)) 
+        capStyle = which(match.arg(toupper(capStyle),GEOSCapStyles) == GEOSCapStyles)
+    if (is.character(joinStyle)) 
+        joinStyle = which(match.arg(toupper(joinStyle),GEOSJoinStyles) == GEOSJoinStyles)
+    
+    if ( !(capStyle %in% 1:length(GEOSCapStyles)) ) stop("invalid cap style")
+    if ( !(joinStyle %in% 1:length(GEOSJoinStyles)) ) stop("invalid join style")
+    
+    capStyle= as.integer(capStyle)
+    joinStyle= as.integer(joinStyle)
+    
+    if (mitreLimit <= 0) 
+        stop("mitreLimit must be greater than 0")
+    if (capStyle == 2 && inherits(spgeom,"SpatialPoints")) 
+        stop("Flat capstyle is incompatible with SpatialPoints geometries")
+    if (width < 0 && !inherits(spgeom,"SpatialPolygons")) 
+        stop("Negative width values may only be used with SpatialPolygons geometries")
+
+    ans = .Call("rgeos_buffer", .RGEOS_HANDLE, spgeom, byid, id, width, quadsegs,
+                                capStyle, joinStyle, mitreLimit, PACKAGE="rgeos")
+ 
+	if (!is.null(ans) && byid_status) {
+	    if (.hasSlot(spgeom, 'data')) {
+                m1 <- match(row.names(ans), id)
+                df1 <- spgeom at data[m1, , drop=FALSE]
+                row.names(df1) <- id[m1]
+	        ans <- SpatialPolygonsDataFrame(ans, df1)
+		}	
+	}
+ 
+    return(ans)
+}
+
+RGEOSBuffer = function(spgeom, byid=TRUE, id=NULL, width=1.0, quadsegs=5, 
+                       capStyle="ROUND", joinStyle="ROUND", mitreLimit=1.0) {
+   .Deprecated("gBuffer")
+   return( gBuffer(spgeom, byid, id, width, quadsegs, capStyle, joinStyle, mitreLimit) )
+}
+
+#RGEOSSingleSidedBuffer = function(spgeom, width, quadsegs, joinStyle, mitreLimit) {
+#    
+#    GEOSCapStyles = c("ROUND","FLAT","SQUARE")
+#    GEOSJoinStyles = c("ROUND","MITRE","BEVEL")
+#}
diff --git a/R/rgeos_linearref.R b/R/rgeos_linearref.R
new file mode 100644
index 0000000..9715d66
--- /dev/null
+++ b/R/rgeos_linearref.R
@@ -0,0 +1,68 @@
+#' Project Points to Line Geometry
+#'
+#' Return distances along geometry to points nearest the specified points.
+#'
+#' @param spgeom SpatialLines or SpatialLinesDataFrame object
+#' @param sppoint SpatialPoints or SpatialPointsDataFrame object
+#' @param normalized Logical determining if normalized distances
+#'   should be used
+#' @return a numeric vector containing the distances along the line to
+#'   points nearest to the specified points
+#' @details If \code{normalized=TRUE}, distances normalized to the length
+#'   of the geometry are returned, i.e., values between 0 and 1.
+#' @seealso gInterpolate
+#' @rdname linref-gProject
+#' @author Rainer Stuetz
+#' @keywords spatial
+#' @examples
+#' l <- readWKT("LINESTRING(0 1, 3 4, 5 6)")
+#' p1 <- readWKT("MULTIPOINT(3 2, 3 5)")
+#' frac <- gProject(l, p1)
+#' p2 <- gInterpolate(l, frac)
+#' plot(l, axes=TRUE)
+#' plot(p1, col = "blue", add = TRUE)
+#' plot(p2, col = "red", add = TRUE)
+#' @export
+gProject <- function(spgeom, sppoint, normalized = FALSE) {
+
+  stopifnot(inherits(spgeom, "SpatialLines") ||
+            inherits(spgeom, "SpatialLinesDataFrame"))
+  stopifnot(inherits(sppoint, "SpatialPoints") ||
+            inherits(sppoint, "SpatialPointsDataFrame"))
+  stopifnot(is.finite(normalized))
+
+  x <- .Call("rgeos_project", .RGEOS_HANDLE, spgeom, sppoint, normalized)
+  x
+}
+
+
+#' Interpolate Points along Line Geometry
+#'
+#' Return points at specified distances along a line.
+#'
+#' @param spgeom SpatialLines or SpatialLinesDataFrame object
+#' @param d Numeric vector specifying the distance along the line geometry
+#' @param normalized Logical determining if normalized distances
+#'   should be used
+#' @return SpatialPoints object
+#' @details If \code{normalized=TRUE}, the distances will be interpreted
+#'   as fractions of the line length.
+#' @seealso gInterpolate
+#' @rdname linref-gInterpolate
+#' @author Rainer Stuetz
+#' @keywords spatial
+#' @examples
+#' gInterpolate(readWKT("LINESTRING(25 50, 100 125, 150 190)"),
+#'              d=seq(0, 1, by = 0.2), normalized = TRUE)
+#' @export
+gInterpolate <- function(spgeom, d, normalized = FALSE) {
+
+  stopifnot(inherits(spgeom, "SpatialLines") ||
+            inherits(spgeom, "SpatialLinesDataFrame"))
+  stopifnot(all(is.finite(d)))
+  stopifnot(is.finite(normalized))
+
+  x <- .Call("rgeos_interpolate", .RGEOS_HANDLE, spgeom, d, normalized)
+  rownames(x) <- seq_len(nrow(x))
+  SpatialPoints(x, proj4string=CRS(proj4string(spgeom)))
+}
diff --git a/R/rgeos_misc.R b/R/rgeos_misc.R
new file mode 100644
index 0000000..a8924af
--- /dev/null
+++ b/R/rgeos_misc.R
@@ -0,0 +1,168 @@
+RGEOSMiscFunc = function(spgeom, byid, func) {
+    stopifnot(is.logical(byid))
+    if (!is.na(is.projected(spgeom)) && !is.projected(spgeom))
+     warning("Spatial object is not projected; GEOS expects planar coordinates")
+    byid = as.logical(byid)
+    if (is.na(byid)) stop("Invalid value for byid, must be logical")
+    if (inherits(spgeom, "SpatialPolygons") && get_do_poly_check() && notAllComments(spgeom)) 
+        spgeom <- createSPComment(spgeom)
+    if (func == "rgeos_area")    
+        x <- .Call("rgeos_area", .RGEOS_HANDLE, spgeom, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_length")    
+        x <- .Call("rgeos_length", .RGEOS_HANDLE, spgeom, byid, PACKAGE="rgeos")
+    else stop("no such function:", func)
+
+    if(byid) names(x) <- unique(row.names(spgeom))
+    
+    return(x)
+}
+
+gArea = function(spgeom, byid=FALSE) {
+    return( RGEOSMiscFunc(spgeom,byid,"rgeos_area") )
+}
+
+gLength = function(spgeom, byid=FALSE) {
+    return(RGEOSMiscFunc(spgeom,byid,"rgeos_length"))
+}
+
+
+RGEOSDistanceFunc = function(spgeom1, spgeom2, byid, func, densifyFrac = 1) {
+    stopifnot(is.logical(byid))
+    if (!is.na(is.projected(spgeom1)) && !is.projected(spgeom1))
+     warning("Spatial object 1 is not projected; GEOS expects planar coordinates")
+    if (!is.null(spgeom2) && !is.na(is.projected(spgeom2)) && 
+        !is.projected(spgeom2))
+     warning("Spatial object 2 is not projected; GEOS expects planar coordinates")
+    byid = as.logical(byid)
+    if (any(is.na(byid)) ) stop("Invalid value for byid, must be logical")
+
+    if( length(byid) < 1 || length(byid) > 2 )
+        stop("Invalid length for byid, must be of length 1 or 2")
+
+    if (length(byid) == 1)
+        byid <- rep(byid,2)
+
+    if(!is.null(spgeom1) & !is.null(spgeom2)) {
+        if(!identical(spgeom1 at proj4string,spgeom2 at proj4string))
+            warning("spgeom1 and spgeom2 have different proj4 strings")
+    }
+
+    if (func == "rgeos_hausdorffdistancedensify")
+        x <- .Call("rgeos_hausdorffdistancedensify", .RGEOS_HANDLE, spgeom1, spgeom2, densifyFrac, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_hausdorffdistance")
+        x <- .Call("rgeos_hausdorffdistance", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_distance")
+        x <- .Call("rgeos_distance", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else stop("no such function:", func)
+
+    
+    if(any(byid)) {
+        id1 = row.names(spgeom1) 
+        if (is.null(spgeom2))
+            id2 = id1
+        else 
+            id2 = row.names(spgeom2)
+        
+        if (length(id1) == ncol(x)) colnames(x) = id1
+        if (length(id2) == nrow(x)) rownames(x) = id2
+    }
+
+    return(x)
+} 
+
+gDistance = function(spgeom1, spgeom2=NULL, byid=FALSE, hausdorff=FALSE, densifyFrac = NULL) {
+	if (hausdorff) {
+		if(is.null(densifyFrac)) {
+			return( RGEOSDistanceFunc(spgeom1, spgeom2, byid, "rgeos_hausdorffdistance") )
+		} else {
+			if (!is.numeric(densifyFrac))
+		        stop("densifyFrac must be numeric")
+
+		    if (densifyFrac > 1 | densifyFrac <= 0)
+		        stop("densifyFrac must be in the range (0,1]")
+
+		    return( RGEOSDistanceFunc(spgeom1, spgeom2, byid, "rgeos_hausdorffdistancedensify", densifyFrac) )
+		}
+	} else {
+    	return( RGEOSDistanceFunc(spgeom1, spgeom2, byid, "rgeos_distance") )
+	}
+}
+
+gWithinDistance = function(spgeom1, spgeom2=NULL, dist, byid=FALSE, hausdorff=FALSE, densifyFrac=NULL) {
+    #TODO - include a tolerance?
+    return( gDistance(spgeom1,spgeom2,byid, hausdorff, densifyFrac) <= dist )
+}
+
+
+gTopoDim <- function(obj) {
+    td <- NULL
+    if (inherits(obj, "SpatialPolygons")) td <- 2L
+    if (inherits(obj, "SpatialRings")) td <- 2L
+    if (inherits(obj, "SpatialLines")) td <- 1L
+    if (inherits(obj, "SpatialPoints")) td <- 0L
+    if (is.null(td)) stop("class not supported:", class(obj))
+    td
+}
+
+
+#' Closest Points of two Geometries
+#'
+#' Return closest points of two geometries.
+#'
+#' @param spgeom1,spgeom2 sp objects as defined in package sp.
+#' @return The closest points of the two geometries or NULL on exception.
+#'   The first point comes from spgeom1 geometry and the second point comes
+#'   from spgeom2.
+#' @seealso gDistance
+#' @rdname misc-gNearestPoints
+#' @author Rainer Stuetz
+#' @keywords spatial
+#' @examples
+#' g1 <- readWKT("MULTILINESTRING((34 54, 60 34), (0 10, 50 10, 100 50))")
+#' g2 <- readWKT("MULTIPOINT(30 0, 100 30)")
+#' plot(g1, pch=4, axes=TRUE)
+#' plot(g2, add=TRUE)
+#' plot(gNearestPoints(g1, g2), add=TRUE, col="red", pch=7)
+#' gDistance(g1, g2)
+#' @export
+gNearestPoints <- function(spgeom1, spgeom2) {
+
+
+    if (version_GEOS0() < "3.4.0")
+        stop("No NearestPoints in this version of GEOS")
+
+  stopifnot(identical(proj4string(spgeom1), proj4string(spgeom2)))
+
+  x <- .Call("rgeos_nearestpoints", .RGEOS_HANDLE, spgeom1, spgeom2,
+             PACKAGE="rgeos")
+  if (!is.null(x)) {
+    rownames(x) <- seq_len(nrow(x))
+    SpatialPoints(x, proj4string=CRS(proj4string(spgeom1)))
+  } else {
+    x
+  }
+}
+
+
+#Deprecated function names
+RGEOSArea = function(spgeom, byid=FALSE) {
+    .Deprecated("gArea")
+    return( gArea(spgeom, byid) )
+}
+RGEOSLength = function(spgeom, byid=FALSE) {
+    .Deprecated("gLength")
+    return( gLength(spgeom, byid) )
+}
+RGEOSDistance = function(spgeom1, spgeom2=NULL, byid=FALSE) {
+    .Deprecated("gDistance")
+    return( gDistance(spgeom1, spgeom2, byid) )
+}
+RGEOSisWithinDistance = function(spgeom1, spgeom2=NULL, dist, byid=FALSE) {
+    .Deprecated("gWithinDistance")
+    return( gWithinDistance(spgeom1, spgeom2, dist, byid) )
+}
+RGEOSHausdorffDistance = function(spgeom1, spgeom2=NULL, byid=FALSE) {
+    .Deprecated("gDistance")
+    return( gDistance(spgeom1, spgeom2, byid, TRUE) )
+}
+
diff --git a/R/rgeos_predicate_binary.R b/R/rgeos_predicate_binary.R
new file mode 100644
index 0000000..7326c48
--- /dev/null
+++ b/R/rgeos_predicate_binary.R
@@ -0,0 +1,378 @@
+RGEOSBinPredFunc = function(spgeom1, spgeom2, byid, func, optparam=NULL) {
+    stopifnot(is.logical(byid))
+    byid = as.logical(byid)
+    if (any(is.na(byid)) ) stop("Invalid value for byid, must be logical")
+
+    if( length(byid) < 1 || length(byid) > 2 )
+        stop("Invalid length for byid, must be of length 1 or 2")
+
+    if (length(byid) == 1)
+        byid <- rep(byid,2)
+
+    if (is.null(spgeom2) && inherits(spgeom1, "SpatialPolygons") 
+        && get_do_poly_check() && notAllComments(spgeom1)) 
+        spgeom1 <- createSPComment(spgeom1)
+
+    if(!is.null(spgeom1) & !is.null(spgeom2)) {
+        if(!identical(spgeom1 at proj4string,spgeom2 at proj4string))
+            warning("spgeom1 and spgeom2 have different proj4 strings")
+        if (inherits(spgeom1, "SpatialPolygons") && get_do_poly_check() && notAllComments(spgeom1)) 
+            spgeom1 <- createSPComment(spgeom1)
+        if (inherits(spgeom2, "SpatialPolygons") && get_do_poly_check() && notAllComments(spgeom2)) 
+            spgeom2 <- createSPComment(spgeom2)
+    }
+	
+    if ( func == "rgeos_equalsexact" )         
+        x <- .Call("rgeos_equalsexact", .RGEOS_HANDLE, spgeom1, spgeom2, optparam, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_relatepattern")
+        x <- .Call("rgeos_relatepattern", .RGEOS_HANDLE, spgeom1, spgeom2, optparam, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_contains")
+        x <- .Call("rgeos_contains", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_contains_prepared")
+        x <- .Call("rgeos_contains_prepared", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_intersects")
+        x <- .Call("rgeos_intersects", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_intersects_prepared")
+        x <- .Call("rgeos_intersects_prepared", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_containsproperly_prepared")
+        x <- .Call("rgeos_containsproperly_prepared", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_covers_prepared")
+        x <- .Call("rgeos_covers_prepared", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_disjoint")
+        x <- .Call("rgeos_disjoint", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_touches")
+        x <- .Call("rgeos_touches", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_crosses")
+        x <- .Call("rgeos_crosses", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_within")
+        x <- .Call("rgeos_within", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_overlaps")
+        x <- .Call("rgeos_overlaps", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_equals")
+        x <- .Call("rgeos_equals", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_relate")
+        x <- .Call("rgeos_relate", .RGEOS_HANDLE, spgeom1, spgeom2, byid, PACKAGE="rgeos")
+    else stop("No such function:", func)    
+    if(any(byid)) {
+        id1 = unique(row.names(spgeom1))
+        if (!get_RGEOS_DENSE()) {
+            if (length(id1) == length(x)) names(x) <- id1
+        } else {
+            if (is.null(spgeom2)) id2 = id1
+            else id2 = unique(row.names(spgeom2))
+
+            colnames(x) <- id1
+            rownames(x) <- id2
+        }
+    }
+    
+    return(x)
+}
+
+
+
+gContains = function(spgeom1, spgeom2 = NULL, byid = FALSE, prepared=TRUE, returnDense=TRUE, STRsubset=FALSE, checkValidity=FALSE) {
+    stopifnot(is.logical(STRsubset))
+    stopifnot(length(STRsubset)==1)
+    oSTRsubset <- get_RGEOS_STR()
+    set_RGEOS_STR(STRsubset)
+    if (STRsubset) returnDense=FALSE
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    func = "rgeos_contains"
+    if (prepared)
+		func = paste(func,"_prepared",sep="")
+
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom1,spgeom2,byid,func)
+    set_RGEOS_DENSE(oreturnDense)
+    set_RGEOS_STR(oSTRsubset)
+    res
+}
+gIntersects = function(spgeom1, spgeom2 = NULL, byid = FALSE, prepared=TRUE, returnDense=TRUE, checkValidity=FALSE) {
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    func = "rgeos_intersects"
+    if (prepared)
+		func = paste(func,"_prepared",sep="")
+
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom1,spgeom2,byid,func)
+    set_RGEOS_DENSE(oreturnDense)
+    res
+}
+
+gContainsProperly = function(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE) {
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom1,spgeom2,byid,"rgeos_containsproperly_prepared")
+    set_RGEOS_DENSE(oreturnDense)
+    res
+}
+
+gCovers = function(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE) {
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom1,spgeom2,byid,"rgeos_covers_prepared")
+    set_RGEOS_DENSE(oreturnDense)
+    res
+}
+
+gCoveredBy = function(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE) {
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom2,spgeom1,rev(byid),"rgeos_covers_prepared")
+    set_RGEOS_DENSE(oreturnDense)
+    res
+}
+
+
+gDisjoint = function(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE) {
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom1,spgeom2,byid,"rgeos_disjoint")
+    set_RGEOS_DENSE(oreturnDense)
+    res
+}
+
+gTouches = function(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE) {
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom1,spgeom2,byid,"rgeos_touches")
+    set_RGEOS_DENSE(oreturnDense)
+    res
+}
+
+gCrosses = function(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE) {
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom1,spgeom2,byid,"rgeos_crosses")
+    set_RGEOS_DENSE(oreturnDense)
+    res
+}
+
+gWithin = function(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE) {
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom1,spgeom2,byid,"rgeos_within")
+    set_RGEOS_DENSE(oreturnDense)
+    res
+}
+
+gOverlaps = function(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE) {
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom1,spgeom2,byid,"rgeos_overlaps")
+    set_RGEOS_DENSE(oreturnDense)
+    res
+}
+
+gEquals = function(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE) {
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom1,spgeom2,byid,"rgeos_equals")
+    set_RGEOS_DENSE(oreturnDense)
+    res
+}
+
+gEqualsExact = function(spgeom1, spgeom2 = NULL, tol=0.0, byid = FALSE, returnDense=TRUE, checkValidity=FALSE) {
+    stopifnot(is.logical(returnDense))
+    stopifnot(length(returnDense)==1)
+    oreturnDense <- get_RGEOS_DENSE()
+    set_RGEOS_DENSE(returnDense)
+    tol <- as.numeric(tol)
+    if ( is.na(tol) ) 
+        stop("Invalid value for tolerance, must be numeric")
+
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    res <- RGEOSBinPredFunc(spgeom1,spgeom2,byid,"rgeos_equalsexact", tol)
+    set_RGEOS_DENSE(oreturnDense)
+    res
+}
+
+gRelate = function(spgeom1, spgeom2 = NULL, pattern = NULL, byid = FALSE, checkValidity=FALSE) {
+    
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+	if (is.null(pattern)) {
+		return( RGEOSBinPredFunc(spgeom1,spgeom2,byid,"rgeos_relate") )
+	} else {
+		if ( !is.character(pattern) )
+			stop("Invalid value for pattern, must be character")
+		pattern = toupper(pattern)
+		
+	    if (length(pattern) != 1)
+	        stop("Pattern must have length of 1")
+    
+	    if (nchar(pattern) != 9 || !grepl("[0-2TF\\*]{9}",pattern) )
+	        stop("Invalid pattern, see documentation for proper format")
+    
+		return( RGEOSBinPredFunc(spgeom1,spgeom2,byid,"rgeos_relatepattern",pattern) )
+	}
+}
+
+
+
+
+
+RGEOSDisjoint = function(spgeom1, spgeom2 = NULL, byid = FALSE) {
+    .Deprecated("gDisjoint")
+    return( gDisjoint(spgeom1,spgeom2, byid) )
+}
+RGEOSTouches = function(spgeom1, spgeom2 = NULL, byid = FALSE) {
+    .Deprecated("gTouches")
+    return( gTouches(spgeom1,spgeom2, byid) )
+}
+RGEOSIntersects = function(spgeom1, spgeom2 = NULL, byid = FALSE) {
+    .Deprecated("gIntersects")
+    return( gIntersects(spgeom1,spgeom2, byid) )
+}
+RGEOSCrosses = function(spgeom1, spgeom2 = NULL, byid = FALSE) {
+    .Deprecated("gCrosses")
+    return( gCrosses(spgeom1,spgeom2, byid) )
+}
+RGEOSWithin = function(spgeom1, spgeom2 = NULL, byid = FALSE) {
+    .Deprecated("gWithin")
+    return( gWithin(spgeom1,spgeom2, byid) )
+}
+RGEOSContains = function(spgeom1, spgeom2 = NULL, byid = FALSE) {
+    .Deprecated("gContains")
+    return( gContains(spgeom1,spgeom2, byid) )
+}
+RGEOSOverlaps = function(spgeom1, spgeom2 = NULL, byid = FALSE) {
+    .Deprecated("gOverlaps")
+    return( gOverlaps(spgeom1,spgeom2, byid) )
+}
+RGEOSEquals = function(spgeom1, spgeom2 = NULL, byid = FALSE) {
+    .Deprecated("gEquals")
+    return( gEquals(spgeom1,spgeom2, byid) )
+}
+RGEOSEqualsExact = function(spgeom1, spgeom2 = NULL, tol=0.0, byid = FALSE) {
+    .Deprecated("gEqualsExact")
+    return( gEqualsExact(spgeom1, spgeom2, byid, tol) )
+}
+RGEOSRelate = function(spgeom1, spgeom2 = NULL, pattern = NULL, byid = FALSE) {
+    .Deprecated("gRelate")
+    return( gRelate(spgeom1,spgeom2, byid, pattern) )
+}
diff --git a/R/rgeos_predicate_unary.R b/R/rgeos_predicate_unary.R
new file mode 100644
index 0000000..73c8541
--- /dev/null
+++ b/R/rgeos_predicate_unary.R
@@ -0,0 +1,67 @@
+RGEOSUnaryPredFunc = function(spgeom, byid, func) {
+    stopifnot(is.logical(byid))
+    byid = as.logical(byid)
+    if (is.na(byid)) stop("Invalid value for byid, must be logical")
+    if (inherits(spgeom, "SpatialPolygons") && get_do_poly_check() && notAllComments(spgeom)) 
+        spgeom <- createSPComment(spgeom)
+
+    if (func == "rgeos_isempty")
+        x <- .Call("rgeos_isempty", .RGEOS_HANDLE, spgeom, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_issimple")
+        x <- .Call("rgeos_issimple", .RGEOS_HANDLE, spgeom, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_isring")
+        x <- .Call("rgeos_isring", .RGEOS_HANDLE, spgeom, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_hasz")
+        x <- .Call("rgeos_hasz", .RGEOS_HANDLE, spgeom, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_isvalidreason")
+        x <- .Call("rgeos_isvalidreason", .RGEOS_HANDLE, spgeom, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_isvalid")
+        x <- .Call("rgeos_isvalid", .RGEOS_HANDLE, spgeom, byid, PACKAGE="rgeos")
+    else stop("no such function:", func)
+    
+    if(byid) {
+        id <- unique(row.names(spgeom))
+        names(x) <- id
+    }
+    return(x)
+}
+
+gIsEmpty = function(spgeom, byid = FALSE) { 
+    return( RGEOSUnaryPredFunc(spgeom, byid,"rgeos_isempty") )
+}
+gIsSimple  = function(spgeom, byid = FALSE) { 
+    return( RGEOSUnaryPredFunc(spgeom, byid,"rgeos_issimple") )
+}
+gIsRing  = function(spgeom, byid = FALSE) { 
+    return( RGEOSUnaryPredFunc(spgeom, byid,"rgeos_isring") )
+}
+gHasZ  = function(spgeom, byid = FALSE) { 
+    return( RGEOSUnaryPredFunc(spgeom, byid,"rgeos_hasz") )
+}
+gIsValid  = function(spgeom, byid = FALSE, reason=FALSE) {
+	if (reason) 
+		return( RGEOSUnaryPredFunc(spgeom, byid,"rgeos_isvalidreason") )	    	
+	else
+		return( RGEOSUnaryPredFunc(spgeom, byid,"rgeos_isvalid") )
+}
+
+RGEOSisEmpty = function(spgeom, byid = FALSE) { 
+    .Deprecated("gIsEmpty")
+    return( gIsEmpty(spgeom, byid) )
+}
+RGEOSisSimple  = function(spgeom, byid = FALSE) { 
+    .Deprecated("gIsSimple")
+    return( gIsSimple(spgeom, byid) )
+}
+RGEOSisRing  = function(spgeom, byid = FALSE) { 
+    .Deprecated("gIsRing")
+    return( gIsRing(spgeom, byid) )
+}
+RGEOSHasZ  = function(spgeom, byid = FALSE) { 
+    .Deprecated("gHasZ")
+    return( gHasZ(spgeom, byid) )
+}
+RGEOSisValid  = function(spgeom, byid = FALSE, reason=FALSE) {
+    .Deprecated("gIsValid")
+    return( gIsValid(spgeom, byid, reason) )
+}
diff --git a/R/rgeos_spExtensions_Classes.R b/R/rgeos_spExtensions_Classes.R
new file mode 100644
index 0000000..291bca0
--- /dev/null
+++ b/R/rgeos_spExtensions_Classes.R
@@ -0,0 +1,87 @@
+#########################
+###
+### SpatialRings
+###
+#########################
+
+setClass("Ring", 
+    representation(coords = "matrix",ID = "character"),
+    validity = function(object) {
+        if (any(is.na(object at coords)))
+            stop("coords cannot contain missing values")
+        if (ncol(object at coords) != 2)
+            stop("coords should have 2 columns")
+        if (!all(object at coords[1,] == object at coords[nrow(object at coords),]))
+            stop("invalid ring, start and end coordinates must be equal")
+        return(TRUE)
+    }
+)
+
+
+setClass("SpatialRings",
+    representation("Spatial", rings = "list"),
+    
+    prototype = list(bbox = matrix( rep(NA, 2), 2, 2, dimnames = list(NULL, c("min","max"))),
+                                    proj4string = CRS(as.character(NA)),
+                                    rings = list()),
+    
+    validity = function(object) {
+        if (any(unlist(lapply(object at rings, function(x) !is(x, "Ring"))))) 
+            stop("rings not Ring objects")
+        if (any(duplicated(sapply(slot(object, "rings"), function(i) slot(i, "ID")))))
+            return("non-unique Rings ID slot values")
+        return(TRUE)
+    }
+)
+
+#########################
+###
+### SpatialRingsDataFrame
+###
+#########################
+
+setClass("SpatialRingsDataFrame",
+    representation("SpatialRings", data = "data.frame"),
+    validity = function(object) {
+        if (!inherits(object at data, "data.frame"))
+            stop("data should be of class data.frame")
+        if (nrow(object at data) != length(object at rings))
+            stop("number of rows in data.frame and SpatialRings don't match")
+        return(TRUE)
+    }
+)
+
+#########################
+###
+### SpatialCollections
+###
+#########################
+
+setClassUnion("SpatialPointsNULL", c("SpatialPoints", "NULL")) 
+setClassUnion("SpatialLinesNULL", c("SpatialLines", "NULL")) 
+setClassUnion("SpatialRingsNULL", c("SpatialRings", "NULL")) 
+setClassUnion("SpatialPolygonsNULL", c("SpatialPolygons", "NULL")) 
+
+setClass("SpatialCollections",
+    representation("Spatial", pointobj = "SpatialPointsNULL", 
+							  lineobj = "SpatialLinesNULL",
+							  ringobj = "SpatialRingsNULL",
+							  polyobj = "SpatialPolygonsNULL",
+							  plotOrder = "integer"),
+    
+    prototype = list(bbox = matrix( rep(NA, 2), 2, 2, dimnames = list(c("x","y"), c("min","max"))),
+                     proj4string = CRS(as.character(NA)),
+                     pointobj = NULL,
+					 lineobj = NULL,
+					 ringobj = NULL,
+					 polyobj = NULL ),
+    
+    validity = function(object) {
+		if (!is.null(object at pointobj)) validObject(object at pointobj)
+		if (!is.null(object at lineobj)) validObject(object at lineobj)
+		if (!is.null(object at ringobj)) validObject(object at ringobj)
+		if (!is.null(object at polyobj)) validObject(object at polyobj)
+		
+		return(TRUE)
+    }
+)
diff --git a/R/rgeos_spExtensions_Methods.R b/R/rgeos_spExtensions_Methods.R
new file mode 100644
index 0000000..62576bb
--- /dev/null
+++ b/R/rgeos_spExtensions_Methods.R
@@ -0,0 +1,389 @@
+#########################
+###
+### SpatialRings
+###
+#########################
+
+Ring <- function(coords,ID=as.character(NA)) {
+    if (ncol(coords) != 2) 
+        stop("coords must be a two-column matrix")
+    
+    n = nrow(coords)
+    area2 = sum( (coords[-1,1]-coords[-n,1])*(coords[-1,2]+coords[-n,2]) )
+    if (area2 < 0) {
+        # if area2 is negative coordinates are ccw, reverse them
+        coords[,1] = rev(coords[,1])
+        coords[,2] = rev(coords[,2])
+    }
+    
+    coords <- coordinates(coords)
+    new("Ring", coords = coords, ID = ID)
+}
+
+.bboxSRs <- function(lst) {
+    bb = sapply(lst, bbox)
+    res = matrix(c(min(bb[1,]), min(bb[2,]), max(bb[3,]), max(bb[4,])), 2, 2)
+    dimnames(res) = list(c("x", "y"), c("min", "max"))
+    return(res)
+}
+
+SpatialRings <- function(RingList, proj4string=CRS(as.character(NA))) {
+    if (any(sapply(RingList, function(x) !is(x, "Ring")))) 
+        stop("Ring list not exclusively filled with Ring objects")
+    Sp <- new("Spatial", bbox = .bboxSRs(RingList), proj4string=proj4string)
+    res <- new("SpatialRings", Sp, rings=RingList)
+    return(res)
+}
+
+
+bbox.Ring <- function(obj) {
+    rx <- range(obj at coords[,1])
+    ry <- range(obj at coords[,2])
+    res = rbind(r1 = rx, r2 = ry)
+    dimnames(res)[[2]] <- c("min", "max")
+    return(res)
+}
+setMethod("bbox", "Ring", bbox.Ring)
+
+
+plotSpatialRings <- function(SR, xlim = NULL, ylim = NULL,
+                             col = 1, lwd = 1, lty=1, add = FALSE, axes = FALSE, ..., 
+                             setParUsrBB=FALSE) {
+
+    if (!add) 
+        plot(as(SR, "Spatial"), xlim = xlim, ylim = ylim, axes = axes, ..., setParUsrBB=setParUsrBB)
+    
+
+    lst <- SR at rings
+    if (length(col) != length(lst)) 
+        col <- rep(col[1], length(lst))
+    if (length(lwd) != length(lst)) 
+        lwd <- rep(lwd[1], length(lst))
+    if (length(lty) != length(lst)) 
+        lty <- rep(lty[1], length(lst))
+
+    for (i in seq(along.with=lst)) {
+        crds <- coordinates(lst[[i]])
+        lines(crds, col = col[i], lwd = lwd[i], lty = lty[i], ...)
+    }
+}
+
+setMethod("plot", 
+          signature(x = "SpatialRings", y = "missing"), 
+          function(x, y, ...) plotSpatialRings(x, ...) )
+
+setMethod("coordinates", "Ring", function(obj) obj at coords)
+setMethod("coordinates", "SpatialRings", function(obj) lapply(obj at rings, coordinates))
+
+
+#if (!isGeneric("lines"))
+#    setGeneric("lines", function(x, y, ...)
+#        standardGeneric("lines"))
+
+#setMethod("lines", "Ring", function(x, y = NULL, ...) invisible(lines(coordinates(x), ...)))
+#setMethod("lines", "SpatialRings", function(x, y = NULL, ...) {
+#    f = function(x, ...) lines(x, ...)
+#    invisible(lapply(x at rings, f, ...))
+#})
+
+if (!isGeneric("row.names"))
+	setGeneric("row.names", function(x) standardGeneric("row.names"))
+if (!isGeneric("row.names<-")) 
+	setGeneric("row.names<-", function(x, value) standardGeneric("row.names<-"))
+
+setMethod("row.names", "SpatialRings", function(x) sapply(slot(x, "rings"), slot, "ID"))
+setReplaceMethod("row.names", signature(x = "SpatialRings", value = "character"),
+                 function(x, value) spChFIDs(x, value))
+
+setMethod("[", "SpatialRings", 
+    function(x, i, j, ..., drop = TRUE) {
+        if (any(is.na(i))) stop("NAs not permitted in row index")
+        
+        if (is.logical(i)) {
+            if (length(i) == 1 && i) {
+                i = 1:length(x at rings)
+            } else {
+                i <- which(i)
+            }
+        } else if (is.character(i)) {
+            i <- match(i, row.names(x))
+        }
+        
+        x at rings = x at rings[i]
+        x at bbox = .bboxSRs(x at rings)
+        return(x)
+    }
+)
+
+
+setMethod("coordnames", signature(x = "SpatialRings"), function(x) coordnames(x at rings[[1]]))
+setMethod("coordnames", signature(x = "Ring"), function(x) dimnames(coordinates(x))[[2]])
+
+setReplaceMethod("coordnames", 
+                 signature(x = "SpatialRings", value = "character"),
+                 function(x, value) {
+                     dimnames(x at bbox)[[1]] = value
+                     for (i in seq(along = x at rings))
+                        coordnames(x at rings[[i]]) = value
+                     return(x)
+                 }
+)
+setReplaceMethod("coordnames",signature(x = "Ring", value = "character"),
+                 function(x, value) {
+                     dimnames(x at coords)[[2]] = value
+                     return(x)
+                 }
+)
+
+
+
+chFIDsSpatialRings <- function(obj, x) {
+    nl <- length(slot(obj, "rings"))
+    if (length(x) != nl) stop("lengths differ")
+    if (length(x) > length(unique(x))) stop("duplicate IDs")
+
+    rings <- slot(obj, "rings")
+    for (i in 1:nl) obj at rings[[i]]@ID = x[i]
+    
+    return(obj)
+}
+setMethod("spChFIDs", signature(obj="SpatialRings", x="character"), chFIDsSpatialRings)
+
+setAs("Ring", 
+      "SpatialPoints",
+      function(from) { 
+          SpatialPoints(do.call("rbind", coordinates(from)))
+      }
+)
+
+setAs("SpatialRings", 
+      "SpatialPoints", 
+      function(from) { 
+          SpatialPoints(do.call("rbind", 
+                        lapply(from at rings, function(x) as(x, "SpatialPoints"))),
+                        CRS(proj4string(from)))
+      }
+)
+
+
+#########################
+###
+### SpatialRingsDataFrame
+###
+#########################
+
+SpatialRingsDataFrame = function(sr, data, match.ID = TRUE) {
+    if (match.ID) {
+        sr_IDs <- row.names(sr)
+        data_IDs <- row.names(data)
+        mtch <- match(sr_IDs, data_IDs)
+        if (any(is.na(mtch)))
+            stop("row.names of data and Rings IDs do not match")
+        if (length(unique(mtch)) != length(sr_IDs))
+            stop("row.names of data and Rings IDs do not match")
+        data <- data[mtch, , drop=FALSE]
+    }
+    if (nrow(data) != length(sr at rings))
+        stop("length of data.frame does not match number of Ring elements")
+    
+    return( new("SpatialRingsDataFrame", sr, data = data) )
+}
+
+setAs("SpatialRingsDataFrame","SpatialRings", function(from) SpatialRings(from at rings))
+setAs("SpatialRingsDataFrame", "data.frame", function(from) from at data)
+
+setMethod("names","SpatialRingsDataFrame", function(x) names(x at data))    
+setReplaceMethod("names", signature(x = "SpatialRingsDataFrame", value = "character"),
+                 function(x, value) { names(x at data)<-value; x })
+
+setMethod("row.names","SpatialRingsDataFrame", function(x) sapply(slot(x, "rings"), slot, "ID"))    
+setReplaceMethod("row.names", signature(x = "SpatialRingsDataFrame", value = "character"),
+              function(x, value) spChFIDs(x, value))
+
+
+setMethod("[", c("SpatialRingsDataFrame", "ANY", "ANY"), 
+    function(x, i, j, ... , drop = TRUE) {
+        missing.i = missing(i)
+        missing.j = missing(j)
+        nargs = nargs() # e.g., a[3,] gives 2 for nargs, a[3] gives 1.
+        
+        if (missing.i && missing.j) {
+            i = TRUE
+            j = TRUE
+        } else if (missing.j && !missing.i) {
+            if (nargs == 2) {
+                j = i
+                i = TRUE
+            } else {
+                j = TRUE
+            }
+        } else if (missing.i && !missing.j) {
+            i = TRUE
+        }
+        
+        if (is.matrix(i)) stop("matrix argument not supported in SpatialRingsDataFrame selection")
+        if (is.logical(i)) {
+            if (length(i) == 1 && i)
+                i = 1:length(x at rings)
+            else
+                i = which(i)
+        } else if (is.character(i)) {
+                i = match(i, row.names(x))
+        }
+        
+        if (any(is.na(i))) stop("NAs not permitted in row index")
+        
+        x at rings = x at rings[i]
+        x at data = x at data[i, j, ..., drop = FALSE]
+        x at bbox = .bboxSRs(x at rings)
+        
+        return(x)
+    }
+)
+
+#setMethod("lines","SpatialRingsDataFrame", function(x, y = NULL, ...) lines(as(x, "SpatialRings"), ...))    
+setMethod("dim","SpatialRingsDataFrame", function(x) dim(x at data))
+
+
+chFIDsSpatialRingsDataFrame <- function(obj, x) {
+    SR <- as(obj, "SpatialRings")
+    SRx <- spChFIDs(SR, x)
+    df <- as(obj, "data.frame")
+    row.names(df) <- sapply(slot(SRx, "rings"), function(x) slot(x, "ID"))
+    SpatialRingsDataFrame(SRx, data=df)
+}
+
+setMethod("spChFIDs", signature(obj="SpatialRingsDataFrame", x="character"), chFIDsSpatialRingsDataFrame)
+
+
+
+#########################
+###
+### SpatialCollections
+###
+#########################
+
+
+SpatialCollections <- function( points = NULL, lines = NULL,
+								rings = NULL, polygons = NULL,
+								plotOrder = c(4,3,2,1),
+								proj4string=CRS(as.character(NA))) {
+
+	plotOrder=as.integer(plotOrder)
+	stopifnot(is.integer(plotOrder))
+	stopifnot(length(plotOrder) == 4)
+	
+	stopifnot(inherits(points,"SpatialPoints") | is.null(points))
+	stopifnot(inherits(lines,"SpatialLines") | is.null(lines))
+	stopifnot(inherits(rings,"SpatialRings") | is.null(rings))
+	stopifnot(inherits(polygons,"SpatialPolygons") | is.null(polygons))
+	stopifnot(is(proj4string, "CRS"))
+	
+	bb = c()
+	if (!is.null(points)) bb = rbind(bb,c(bbox(points)))
+	if (!is.null(lines)) bb = rbind(bb,c(bbox(lines)))
+	if (!is.null(rings)) bb = rbind(bb,c(bbox(rings)))
+	if (!is.null(polygons)) bb = rbind(bb,c(bbox(polygons)))
+	
+	if (length(bb) == 0) {
+		bbox = matrix( rep(NA, 2), 2, 2)
+	} else {
+		bbox = matrix(c(min(bb[,1]), min(bb[,2]), max(bb[,3]), max(bb[,4])), 2, 2)
+	}
+	dimnames(bbox) = list(c("x", "y"), c("min", "max"))
+	
+	
+	
+	Sp <- new("Spatial", bbox = bbox, proj4string=proj4string)	
+    res <- new("SpatialCollections", Sp, plotOrder=plotOrder, pointobj=points, 
+				lineobj=lines, ringobj=rings, polyobj=polygons)
+	#validObject(res)
+
+    return(res)
+}
+
+
+plotSpatialCollections <- function(SC, 
+								   pointopt = list(), lineopt = list(),
+								   ringopt = list(), polyopt = list(),
+								   pch = 3, cex = 1, bg = 1,
+								   col = 1, lwd = 1, lty=1,
+								   border = par("fg"), xpd = NULL, 
+								   density = NULL, angle = 45, pbg=NULL,
+								   xlim = NULL, ylim = NULL,
+								   add = FALSE, axes = FALSE, ...,
+	  							   setParUsrBB=FALSE) {
+		
+	if (!add) {
+		plot(as(SC,"Spatial"), xlim=xlim, ylim=ylim, axes=axes, 
+			 ..., setParUsrBB=setParUsrBB)
+	}
+	add=TRUE
+	
+	call = match.call()
+	if (is.null(call$col) & is.null(polyopt[["col"]]))
+		polyopt[["col"]] = NA
+		
+	for (i in order(SC at plotOrder)) {
+		
+		if (i == 1 & !is.null(SC at pointobj)) { # plot points
+			ptcol = col
+			ptlwd = lwd
+			
+			if (!is.null(pointopt[["pch"]])) ptpch = pointopt[["pch"]]
+			if (!is.null(pointopt[["cex"]])) ptcex = pointopt[["cex"]]
+			if (!is.null(pointopt[["col"]])) ptcol = pointopt[["col"]]
+			if (!is.null(pointopt[["lwd"]])) ptlwd = pointopt[["lwd"]]
+			if (!is.null(pointopt[["bg"]]))  ptbg  = pointopt[["bg"]]
+			
+			plot(SC at pointobj, pch=pch, axes=axes, add=add, xlim=xlim, ylim=ylim, 
+				 cex=cex, col=ptcol, lwd=ptlwd, bg=bg, ..., setParUsrBB=setParUsrBB)
+			
+		} else if (i == 2 & !is.null(SC at lineobj)) { #plot lines
+			lcol = col
+			llwd = lwd
+			llty = lty
+			
+			if (!is.null(lineopt[["col"]])) lcol = lineopt[["col"]]
+			if (!is.null(lineopt[["lwd"]])) llwd = lineopt[["lwd"]]
+			if (!is.null(lineopt[["lty"]])) llty = lineopt[["lty"]]
+			
+			plot(SC at lineobj, xlim=xlim, ylim=ylim, col=lcol, lwd=llwd, lty=llty,
+				 add=add, axes=axes, ..., setParUsrBB=setParUsrBB)
+			
+		} else if (i == 3 & !is.null(SC at ringobj)) { #plot rings
+			rcol = col
+			rlwd = lwd
+			rlty = lty
+			
+			if (!is.null(ringopt[["col"]])) rcol = ringopt[["col"]]
+			if (!is.null(ringopt[["lwd"]])) rlwd = ringopt[["lwd"]]
+			if (!is.null(ringopt[["lty"]])) rlty = ringopt[["lty"]]
+			
+			plot(SC at ringobj, xlim=xlim, ylim=ylim, col=rcol, lwd=rlwd, lty=rlty,
+				 add=add, axes=axes, ..., setParUsrBB=setParUsrBB)
+				
+		} else if (i == 4 & !is.null(SC at polyobj)) { #plot polygons
+			pcol = col
+			if (!is.null(polyopt[["col"]])) pcol = polyopt[["col"]]
+			
+			plot(SC at polyobj, col=pcol, border=border, add=add, xlim=xlim, ylim=ylim,
+				 xpd=xpd, density=density, angle=angle, pbg=pbg, axes=axes, ...,
+				 setParUsrBB=setParUsrBB)
+		}
+	}
+}
+		
+setMethod("plot", signature(x = "SpatialCollections", y = "missing"),
+	function(x, y, ...) plotSpatialCollections(x, ...))
+	
+setMethod("row.names", "SpatialCollections", function(x) {
+	
+	ans = list()
+	if (!is.null(x at pointobj)) ans$points = row.names(x at pointobj)
+	if (!is.null(x at lineobj)) ans$lines = row.names(x at lineobj)
+	if (!is.null(x at ringobj)) ans$rings = row.names(x at ringobj)
+	if (!is.null(x at polyobj)) ans$polygons = row.names(x at polyobj)
+	
+	return(ans)
+})
diff --git a/R/rgeos_topology.R b/R/rgeos_topology.R
new file mode 100644
index 0000000..1fcb9f5
--- /dev/null
+++ b/R/rgeos_topology.R
@@ -0,0 +1,242 @@
+gSimplify = function(spgeom, tol, topologyPreserve=FALSE) {
+
+	getCutEdges = as.logical(topologyPreserve)
+	if (is.na(topologyPreserve))
+		stop("Invalid value for topologyPreserve, must be logical")
+	
+    if (inherits(spgeom, "SpatialPolygons") && get_do_poly_check() && notAllComments(spgeom)) 
+        spgeom <- createSPComment(spgeom)
+    id = row.names(spgeom)
+    return( .Call("rgeos_simplify", .RGEOS_HANDLE, spgeom, tol, id, 
+									FALSE, topologyPreserve, PACKAGE="rgeos") )
+}
+
+gPolygonize = function( splist, getCutEdges=FALSE) {
+	
+	if (!is.list(splist))
+		splist = list(splist)
+        if (!all(sapply(splist, inherits, "SpatialLines")))
+            stop("list of SpatialLines object required")
+
+	p4slist = lapply(splist,function(x) x at proj4string)
+#        splist <- lapply(splist, function(s) {
+#            if (inherits(s, "SpatialPolygons") && get_do_poly_check() && notAllComments(s)) {
+#                createSPComment(s)
+#            } else {
+#                s
+#            }
+#        })
+	
+	p4s = p4slist[[1]]
+	if (length(p4slist) != 1) {
+		for(i in 2:length(p4slist)) {
+			if (!identical(p4s, p4slist[[i]]))
+				stop("spgeoms in splist have different proj4strings")
+		}
+	}
+	
+
+	getCutEdges = as.logical(getCutEdges)
+	if (is.na(getCutEdges))
+		stop("Invalid value for getCutEdges, must be logical")
+	
+	nid = sum(sapply(splist, function(x) sapply(slot(x, "lines"),
+            function(y) length(slot(y, "Lines")))))
+#           sum(sapply(splist,function(x) length(unlist(row.names(x)))))
+    id = as.character(1:nid)
+
+    return( .Call("rgeos_polygonize", .RGEOS_HANDLE, splist, id, p4s,
+									getCutEdges, PACKAGE="rgeos") )
+}
+
+
+
+
+
+TopologyFunc = function(spgeom, id, byid, func) {
+    
+    stopifnot(is.logical(byid))
+    byid = as.logical(byid)
+    if (is.na(byid)) 
+        stop("Invalid value for byid, must be logical")
+    
+    curids = unique(row.names(spgeom))
+    if (is.null(id)) {
+        if (byid)   id = curids
+        else        id = "1"
+    }
+    id = as.character(id)
+
+    if (inherits(spgeom, "SpatialPolygons") && get_do_poly_check() && notAllComments(spgeom)) spgeom <- createSPComment(spgeom)
+    
+    if ( length(id) != length(unique(id)) )
+        stop("Non-unique values for id ")
+    
+    if ( !(!byid && length(id) == 1) && !(byid && length(id) == length(curids)) )
+        stop("Invalid number of values in id" ) 
+    if (func == "rgeos_envelope")
+        x <- .Call("rgeos_envelope", .RGEOS_HANDLE, spgeom, id, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_convexhull")
+        x <- .Call("rgeos_convexhull", .RGEOS_HANDLE, spgeom, id, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_boundary")
+        x <- .Call("rgeos_boundary", .RGEOS_HANDLE, spgeom, id, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_getcentroid")
+        x <- .Call("rgeos_getcentroid", .RGEOS_HANDLE, spgeom, id, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_pointonsurface")
+        x <- .Call("rgeos_pointonsurface", .RGEOS_HANDLE, spgeom, id, byid, PACKAGE="rgeos")
+    else if (func == "rgeos_unioncascaded")
+        x <- .Call("rgeos_unioncascaded", .RGEOS_HANDLE, spgeom, id, byid, PACKAGE="rgeos")
+    else stop("no such function:", func)
+
+
+    return( x )
+}
+
+gEnvelope = function(spgeom, byid=FALSE, id = NULL) {
+    return( TopologyFunc(spgeom,id,byid,"rgeos_envelope") ) 
+}
+gConvexHull = function(spgeom, byid=FALSE, id = NULL) {
+    return( TopologyFunc(spgeom,id,byid,"rgeos_convexhull") ) 
+}
+gBoundary = function(spgeom, byid=FALSE, id = NULL) {
+     return( TopologyFunc(spgeom,id,byid,"rgeos_boundary") ) 
+}
+gCentroid = function(spgeom, byid=FALSE, id = NULL) {
+    return( TopologyFunc(spgeom,id,byid,"rgeos_getcentroid") ) 
+}
+gPointOnSurface = function(spgeom, byid=FALSE, id = NULL) {
+    return( TopologyFunc(spgeom,id,byid,"rgeos_pointonsurface") ) 
+}
+gLineMerge = function(spgeom, byid=FALSE, id = NULL) {
+#    return( TopologyFunc(spgeom,id,byid,"rgeos_linemerge") ) 
+    if (!inherits(spgeom,"SpatialLines"))
+        stop("Invalid geometry, may only be applied to lines")
+    spgeom <- as(spgeom, "SpatialLines")
+    if (is.null(id))
+        id = rep("1",length(row.names(spgeom)))
+
+#    if (any(is.na(id))) stop("No NAs permitted in id")
+
+    ids <- split(1:length(id), id)
+    out <- vector(mode="list", length=length(ids))
+    for (i in seq(along.with=ids)) {
+        out[[i]] <- .Call("rgeos_linemerge", .RGEOS_HANDLE,
+        spgeom[ids[[i]]], names(ids)[i], FALSE, PACKAGE="rgeos") 
+    }
+    res <- do.call("rbind.SpatialLines", out)
+    res
+}
+
+gUnionCascaded = function(spgeom, id = NULL) {
+    
+    if (!inherits(spgeom,"SpatialPolygons"))
+        stop("Invalid geometry, may only be applied to polygons")
+    spgeom <- as(spgeom, "SpatialPolygons")
+
+    if (is.null(id))
+        id = rep("1",length(row.names(spgeom)))
+
+#    if (any(is.na(id))) stop("No NAs permitted in id")
+
+    if (get_do_poly_check() && notAllComments(spgeom)) spgeom <- createSPComment(spgeom)
+
+    ids <- split(1:length(id), id)
+    sl <- sapply(ids, length)
+    out <- vector(mode="list", length=length(ids))
+    for (i in seq(along.with=ids)) {
+        out[[i]] <- TopologyFunc(groupID(spgeom[ids[[i]]], id[ids[[i]]]),
+            names(ids)[i], TRUE, "rgeos_unioncascaded")
+    }
+    res <- do.call("rbind.SpatialPolygons", out)
+
+    res
+}
+
+gUnaryUnion = function(spgeom, id = NULL) {
+
+    if (version_GEOS0() < "3.3.0")
+        stop("No UnaryUnion in this version of GEOS")
+    
+    if (!inherits(spgeom,"SpatialPolygons"))
+        stop("Invalid geometry, may only be applied to polygons")
+    spgeom <- as(spgeom, "SpatialPolygons")
+    if (is.null(id))
+        id = rep("1",length(row.names(spgeom)))
+
+#    if (any(is.na(id))) stop("No NAs permitted in id")
+
+    if (get_do_poly_check() && notAllComments(spgeom)) spgeom <- createSPComment(spgeom)
+
+    ids <- split(1:length(id), id)
+    out <- vector(mode="list", length=length(ids))
+    for (i in seq(along.with=ids)) {
+        out[[i]] <- .Call("rgeos_unaryunion", .RGEOS_HANDLE,
+        spgeom[ids[[i]]], names(ids)[i], FALSE, PACKAGE="rgeos") 
+    }
+    res <- do.call("rbind.SpatialPolygons", out)
+    res
+}
+
+gDelaunayTriangulation <- function(spgeom, tolerance=0.0, onlyEdges=FALSE) {
+
+    if (version_GEOS0() < "3.4.0")
+        stop("No DelaunayTriangulation in this version of GEOS")
+
+    if (!inherits(spgeom, "SpatialPoints"))
+        stop("Invalid geometry, may only be applied to points")
+    if (nrow(zerodist(spgeom)) > 0)
+        stop("duplicate points not permitted")
+    stopifnot(is.numeric(tolerance))
+    stopifnot(length(tolerance) == 1)
+    stopifnot(is.logical(onlyEdges))
+    stopifnot(length(onlyEdges) == 1)
+
+    .Call("rgeos_delaunaytriangulation", .RGEOS_HANDLE,
+        spgeom, tolerance, onlyEdges, PACKAGE="rgeos")
+    
+}
+
+gNode <- function(spgeom){
+
+    if (version_GEOS0() < "3.4.0")
+        stop("No noding in this version of GEOS")
+
+    if (!inherits(spgeom, "SpatialLines"))
+        stop("Invalid geometry, may only be applied to lines")
+
+    .Call("rgeos_node", .RGEOS_HANDLE, spgeom, PACKAGE="rgeos")
+
+}
+
+RGEOSEnvelope = function(spgeom, byid=FALSE, id = NULL) {
+    .Deprecated("gEnvelope")
+    return( gEnvelope(spgeom, id, byid) )
+}
+RGEOSConvexHull = function(spgeom, byid=FALSE, id = NULL) {
+    .Deprecated("gConvexHull")
+    return( gConvexHull(spgeom, id, byid) )
+}
+RGEOSBoundary = function(spgeom, byid=FALSE, id = NULL) {
+    .Deprecated("gBoundary")
+    return( gBoundary(spgeom, id, byid) )
+}
+RGEOSGetCentroid = function(spgeom, byid=FALSE, id = NULL) {
+    .Deprecated("gCentroid")
+    return( gCentroid(spgeom, id, byid) )
+}
+RGEOSPointOnSurface = function(spgeom, byid=FALSE, id = NULL) {
+    .Deprecated("gPointOnSurface")
+    return( gPointOnSurface(spgeom, id, byid) )
+}
+RGEOSLineMerge = function(spgeom, byid=FALSE, id = NULL) {
+    .Deprecated("gLineMerge")
+    return( gLineMerge(spgeom, id, byid) )
+}
+RGEOSUnionCascaded = function(spgeom, id = NULL) {
+    .Deprecated("gUnionCascaded")
+    return( gUnionCascaded(spgeom, id) )
+}
+
+
+
+
diff --git a/R/rgeos_topology_binary.R b/R/rgeos_topology_binary.R
new file mode 100644
index 0000000..78d6efb
--- /dev/null
+++ b/R/rgeos_topology_binary.R
@@ -0,0 +1,123 @@
+RGEOSBinTopoFunc = function(spgeom1, spgeom2, byid, ids=NULL, drop_lower_td=FALSE, unaryUnion_if_byid_false=TRUE, func) {
+    stopifnot(is.logical(byid))
+    stopifnot(is.logical(drop_lower_td))
+    stopifnot(length(drop_lower_td) == 1)
+    stopifnot(is.logical(unaryUnion_if_byid_false))
+    stopifnot(length(unaryUnion_if_byid_false) == 1)
+    byid = as.logical(byid)
+    if (any(is.na(byid)) ) 
+        stop("Invalid value for byid, must be logical")
+    if (!length(byid) %in% c(1,2))
+        stop("Invalid length for byid, must be of length 1 or 2")
+    if (length(byid) == 1)
+        byid <- rep(byid,2)
+
+    if (missing(spgeom1) | missing(spgeom2))
+        stop("spgeom1 and spgeom2 must both be specified")
+        
+    if(!identical(spgeom1 at proj4string,spgeom2 at proj4string))
+        warning("spgeom1 and spgeom2 have different proj4 strings")
+
+    if (inherits(spgeom1, "SpatialPolygons") && get_do_poly_check() && notAllComments(spgeom1))
+        spgeom1 <- createSPComment(spgeom1)
+    if (inherits(spgeom2, "SpatialPolygons") && get_do_poly_check() && notAllComments(spgeom2)) 
+        spgeom2 <- createSPComment(spgeom2)
+    id1 = row.names(spgeom1) 
+    id2 = row.names(spgeom2)    
+    if(all(byid)) {
+        if (is.null(ids)) ids = paste(rep(id1,each=length(id2)),rep(id2,length(id1)))
+        idlen = length(id1)*length(id2)
+    } else if (byid[1]) {
+        if (is.null(ids)) ids = id1
+        idlen = length(id1)
+    } else if (byid[2]) {
+        if (is.null(ids)) ids = id2
+        idlen = length(id2)
+    } else {
+        if (is.null(ids)) ids = "1"
+        idlen = 1
+    }
+    
+    if (idlen != length(ids))
+        stop(paste("ids vector has incorrect length of",length(ids),"expected length of",idlen))
+#    oboth_poly <- get("both_poly", envir=.RGEOS_HANDLE)
+#    odrop_not_poly <- get("drop_not_poly", envir=.RGEOS_HANDLE)
+#    both_poly <-(inherits(spgeom1, "SpatialPolygons") &&
+#        inherits(spgeom2, "SpatialPolygons"))
+#    assign("both_poly", (inherits(spgeom1, "SpatialPolygons") &&
+#        inherits(spgeom2, "SpatialPolygons")), envir=.RGEOS_HANDLE)
+#    if (drop_not_poly) assign("drop_not_poly", drop_not_poly, envir=.RGEOS_HANDLE)
+
+    tds <- c(gTopoDim(spgeom1), gTopoDim(spgeom2))
+    min_tds <- as.integer(min(tds))
+    attr(byid, "min_tds") <- min_tds
+    attr(byid, "drop_lower_td") <- drop_lower_td
+    attr(byid, "unaryUnion_if_byid_false") <- unaryUnion_if_byid_false
+    if (func == "rgeos_difference")
+        x <- .Call("rgeos_difference", .RGEOS_HANDLE, spgeom1, spgeom2, byid, ids, PACKAGE="rgeos")
+    else if (func == "rgeos_symdifference")
+        x <- .Call("rgeos_symdifference", .RGEOS_HANDLE, spgeom1, spgeom2, byid, ids, PACKAGE="rgeos")
+    else if (func == "rgeos_intersection")
+        x <- .Call("rgeos_intersection", .RGEOS_HANDLE, spgeom1, spgeom2, byid, ids, PACKAGE="rgeos")
+    else if (func == "rgeos_union")
+        x <- .Call("rgeos_union", .RGEOS_HANDLE, spgeom1, spgeom2, byid, ids, PACKAGE="rgeos")
+    else stop("no such function:", func)
+
+#    assign("both_poly", oboth_poly, envir=.RGEOS_HANDLE)
+#    assign("drop_not_poly", odrop_not_poly, envir=.RGEOS_HANDLE)
+
+    return(x)
+}
+
+gDifference = function(spgeom1, spgeom2, byid=FALSE, id=NULL, drop_lower_td=FALSE, unaryUnion_if_byid_false=TRUE, checkValidity=FALSE) {
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    return( RGEOSBinTopoFunc(spgeom1, spgeom2, byid, id, drop_lower_td,
+        unaryUnion_if_byid_false, "rgeos_difference") )
+}
+gSymdifference = function(spgeom1, spgeom2, byid=FALSE, id=NULL, drop_lower_td=FALSE, unaryUnion_if_byid_false=TRUE, checkValidity=FALSE) {
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    return( RGEOSBinTopoFunc(spgeom1, spgeom2, byid, id, drop_lower_td,
+        unaryUnion_if_byid_false, "rgeos_symdifference") )
+}
+gIntersection = function(spgeom1, spgeom2, byid=FALSE, id=NULL, drop_not_poly, drop_lower_td=FALSE, unaryUnion_if_byid_false=TRUE, checkValidity=FALSE) {
+    if (!missing(drop_not_poly)) {
+        warning("drop_not_poly argument name deprecated, use drop_lower_td")
+        drop_lower_td <- drop_not_poly
+    }
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    return( RGEOSBinTopoFunc(spgeom1, spgeom2, byid, id, drop_lower_td,
+        unaryUnion_if_byid_false, "rgeos_intersection") )
+}
+gUnion = function(spgeom1, spgeom2, byid=FALSE, id=NULL, drop_lower_td=FALSE, unaryUnion_if_byid_false=TRUE, checkValidity=FALSE) {
+    if(checkValidity) {
+        val1 <- gIsValid(spgeom1)
+        val2 <- gIsValid(spgeom2)
+        if (!val1) message(deparse(substitute(spgeom1)), " is invalid")
+        if (!val2) message(deparse(substitute(spgeom2))," is invalid")
+        if (!all(c(val1, val2))) stop("Invalid objects found")
+    }
+    
+    return( RGEOSBinTopoFunc(spgeom1, spgeom2, byid, id, drop_lower_td,
+        unaryUnion_if_byid_false, "rgeos_union") )
+}
diff --git a/R/rgeos_util.R b/R/rgeos_util.R
new file mode 100644
index 0000000..cf4223e
--- /dev/null
+++ b/R/rgeos_util.R
@@ -0,0 +1,226 @@
+poly_findInBoxGEOS <- function(spl, as_points=TRUE) {
+    stopifnot(is(spl, "SpatialPolygons"))
+    stopifnot(is.logical(as_points))
+    stopifnot(!is.na(as_points))
+    pls <- slot(spl, "polygons")
+    res <- .Call("rgeos_poly_findInBox", .RGEOS_HANDLE, pls, as_points,
+       PACKAGE="rgeos")
+    res
+}
+
+gUnarySTRtreeQuery <- function(obj) {
+    if(inherits(obj, "SpatialLines")) type <- "line"
+    else if(inherits(obj, "SpatialPolygons")) type <- "poly"
+    else if(inherits(obj, "Polygons")) type <- "Poly"
+    else stop(paste("unsupported class:", class(obj)))
+    if (type == "line") lst <- slot(obj, "lines")
+    else if (type == "poly") lst <- slot(obj, "polygons")
+    else lst <- slot(obj, "Polygons")
+    res <- .Call("rgeos_unary_STRtree_query", .RGEOS_HANDLE, lst,
+        PACKAGE="rgeos")
+    res
+}
+
+gBinarySTRtreeQuery <- function(obj1, obj2) {
+    if(inherits(obj1, "SpatialLines")) type1 <- "line"
+    else if(inherits(obj1, "SpatialPolygons")) type1 <- "poly"
+    else stop(paste("unsupported class:", class(obj1)))
+    if(inherits(obj2, "SpatialLines")) type2 <- "line"
+    else if(inherits(obj2, "SpatialPoints")) type2 <- "pts"
+    else if(inherits(obj2, "SpatialPolygons")) type2 <- "poly"
+    else stop(paste("unsupported class:", class(obj2)))
+    if (type1 == "line") lst1 <- slot(obj1, "lines")
+    else lst1 <- slot(obj1, "polygons")
+    if (type2 == "line") lst2 <- slot(obj2, "lines")
+    else if (type2 == "pts") lst2 <- as(obj2, "SpatialPoints")
+    else lst2 <- slot(obj2, "polygons")
+    res <- .Call("rgeos_binary_STRtree_query", .RGEOS_HANDLE, lst1, lst2,
+        PACKAGE="rgeos")
+    res
+}
+
+
+set_do_poly_check <- function(value) {
+  stopifnot(is.logical(value))
+  stopifnot(length(value) == 1)
+  assign("do_poly_check", value, envir=.RGEOS_HANDLE)
+}
+
+get_do_poly_check <- function() {
+  get("do_poly_check", envir=.RGEOS_HANDLE)
+}
+
+notAllComments <- function(spgeom) {
+    if (!get_do_poly_check()) return(FALSE)
+    if (!inherits(spgeom, "SpatialPolygons")) return(TRUE)
+    if (is.null(comment(spgeom))) return(TRUE)
+    return(comment(spgeom) != "TRUE")
+}
+
+
+createSPComment = function(sppoly,which=NULL,overwrite=TRUE) {
+    if (!inherits(sppoly, "SpatialPolygons")) 
+        stop("not a SpatialPolygons object")
+    if (get_do_poly_check() && notAllComments(sppoly)) { 
+      if (is.null(which))
+        which = 1:length(sppoly at polygons)
+    
+      sppoly at polygons[which] = lapply(sppoly at polygons[which], function(p) {
+        
+        if (!overwrite && !is.null(attr(p, "comment"))) {
+            return(p)
+        } else if (all(sapply(slot(p, "Polygons"), function(j)
+            is.null(slot(j, "coords"))))) {
+            comment(p) <- paste(rep(0, length(slot(p, "Polygons"))),
+                collapse=" ")
+            return(p)
+        } else {
+            attr(p, "comment") = createPolygonsComment(p)
+            return(p)
+        }
+      })
+      comment(sppoly) <- as.character(any(sapply(slot(sppoly, "polygons"),
+                function(x) !is.null(comment(x))), na.rm=TRUE))
+    }
+
+    return(sppoly)
+}
+
+createPolygonsComment = function(poly) {
+    if (!is(poly, "Polygons")) 
+        stop("not a Polygons object")
+
+    holes = sapply(poly at Polygons, function(x) x at hole)
+    if (!any(holes)) {
+        comm = rep(0,length(poly at Polygons))
+    } else {
+        comm = .Call("rgeos_PolyCreateComment", .RGEOS_HANDLE, poly at Polygons, PACKAGE="rgeos")    
+    }
+    
+    return(paste(comm,collapse=" "))
+}
+
+getScale <- function() {
+    return( mget("scale",.RGEOS_HANDLE)$scale )
+}
+
+setScale <- function(scale=100000000) {
+    
+    maxPreciseValue <- 9007199254740992.0
+    
+    if(scale > maxPreciseValue){
+        stop("Specified scale is larger than maximum allowed")
+    }
+    
+    assign("scale",scale,envir=.RGEOS_HANDLE)
+}
+
+checkP4S = function(p4s) {
+    
+    if ( is.null(p4s) )
+        p4s = CRS(as.character(NA))
+
+    if( is.character(p4s))
+        p4s = CRS(p4s) 
+    
+    if (length(p4s) != 1)
+        stop("proj4string must be of length 1")
+    
+    if ( class(p4s) != "CRS") {
+        stop("proj4string has invalid class")
+    }
+    
+    return( p4s )
+}
+
+translate = function(spgeom) {
+    
+    rn = row.names(spgeom)
+    if (!is.list(rn))
+        rn = list(rn)
+    
+    ids = as.character( unlist( sapply(rn, unique) ) )
+    x = .Call("rgeos_double_translate", .RGEOS_HANDLE, spgeom, ids, 0, PACKAGE="rgeos")
+    return(x)
+}
+
+groupID = function(spgeom, ids) {
+    
+    if (inherits(spgeom,"SpatialCollections"))
+        stop("groupID does not work with SpatialCollections objects")
+        
+    if (length(row.names(spgeom)) != length(ids)) 
+        stop("length of ids does not match number of geometries")
+    if (storage.mode(ids) != "character") ids <- as.character(ids)
+    
+    newids = unique(ids)
+    
+    if (length(row.names(spgeom)) == 1 || length(row.names(spgeom)) == length(newids) || 
+        inherits(spgeom,"SpatialPoints") ) {
+        
+        row.names(spgeom) <- ids
+        return(spgeom)
+    }
+    
+    
+    if ( inherits(spgeom,"SpatialLines")  ) {
+        
+        lineslist = list()
+        k=1
+        for (curid in newids) {
+
+            if (is.na(curid)) next # RSB 101124
+            
+            linelist = list()
+            l = 1
+            for ( i in which(ids == curid) ){
+                    
+                L = length(spgeom at lines[[i]]@Lines)
+                linelist[l:(l+L-1)] = spgeom at lines[[i]]@Lines
+                l=l+L
+            }
+            
+            lineslist[[k]] = Lines(linelist, curid)
+            k=k+1
+        }
+
+        ans = SpatialLines(lineslist,proj4string = spgeom at proj4string)
+        
+    } else if ( inherits(spgeom,"SpatialPolygons") ) {
+        
+        polyslist = list()
+        k=1
+        for (curid in newids) {
+
+            if (is.na(curid)) next # RSB 101124
+
+            comment = c()
+            polylist = list()
+            l = 1
+            for ( i in which(ids == curid) ){
+                
+                L = length(spgeom at polygons[[i]]@Polygons)
+                
+                comm = attr(spgeom at polygons[[i]],"comment")
+                if (is.null(comm)) comm = rep(0,L)
+                else comm = as.integer( strsplit(comm," ")[[1]] )
+                comm[comm!=0] = comm[comm!=0] + l-1 
+                comment = c(comment, comm)
+                    
+                polylist[l:(l+L-1)] = spgeom at polygons[[i]]@Polygons
+                l=l+L
+            }
+            
+            polyslist[[k]] = Polygons(polylist, curid)
+            attr(polyslist[[k]],"comment") = paste(comment, collapse=" ")
+            k=k+1
+        }
+
+        ans = SpatialPolygons(polyslist,proj4string = spgeom at proj4string)
+        
+    } else {
+        stop("Unknown object class")
+    }
+    
+    return(ans)
+}
diff --git a/R/rgeos_wkt.R b/R/rgeos_wkt.R
new file mode 100644
index 0000000..5828b9d
--- /dev/null
+++ b/R/rgeos_wkt.R
@@ -0,0 +1,59 @@
+
+readWKT = function( text, id = NULL, p4s = NULL) {
+    
+    #wkt = str_replace(text,"\n","")
+    wkt = gsub("\n", "", text)
+
+    if (length(wkt) != 1) stop("WKT must have length 1")
+    
+	pat = 
+	"POINT|LINESTRING|LINEARRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON"
+    # m =  str_extract_all(wkt, pat)
+	m = strsplit(wkt, pat)
+    # ngeoms =  length( m[[1]] )
+    ngeoms =  length( m[[1]] ) - 1 # "" before first match is always the first
+    if(is.null(ngeoms)) ngeoms = 0
+    
+    if(is.null(id)) {
+        if (ngeoms == 0) {
+            id = c()
+        } else {
+            id = 1:ngeoms
+        }
+    } 
+    
+    # if the number of ids doesn't take into account sub geometries in geometry collection then create subids
+    if( length(id) == 1 & ngeoms != 1)
+        id = paste(id,1:ngeoms,sep=".")
+    
+    if( length(id) != ngeoms )
+        stop("number of WKT geometries does not match number of ids")        
+
+    p4s = checkP4S(p4s)
+    
+    id = as.character(id)
+        
+    tryCatch(res <- .Call("rgeos_readWKT", .RGEOS_HANDLE, wkt, p4s, 
+                            id, PACKAGE="rgeos"), 
+             error = function(e) { stop( paste( "Unable to parse: ",wkt,"\n",
+                                                "GEOS reported: \"", e$message,"\"",sep=""),call.=FALSE) } )
+    
+	#if (length(unique(row.names(res))) != ngeoms)
+	#if (!is.null(res)) {
+	#	if ( sum(sapply(row.names(res),length)) != ngeoms )
+    #    	warning(paste("Number of geometries does not match between object and text, check WKT validity.",wkt),call.=FALSE)
+    #}
+
+    return( res )
+}
+
+
+writeWKT = function( spgeom, byid = FALSE) {
+
+    stopifnot(is.logical(byid))
+    byid = as.logical(byid)
+    
+    res <- .Call("rgeos_writeWKT", .RGEOS_HANDLE, spgeom, byid)
+    
+    return(res) 
+}
diff --git a/cleanup b/cleanup
new file mode 100755
index 0000000..a199a6a
--- /dev/null
+++ b/cleanup
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+rm -f config.* src/Makevars
diff --git a/configure b/configure
new file mode 100755
index 0000000..09ac761
--- /dev/null
+++ b/configure
@@ -0,0 +1,3122 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for rgeos 0.3-26.
+#
+# Report bugs to <Roger.Bivand at nhh.no>.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf at gnu.org and
+$0: Roger.Bivand at nhh.no about your system, including any
+$0: error possibly output before this message. Then install
+$0: a modern shell, or manually run the script under such a
+$0: shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='rgeos'
+PACKAGE_TARNAME='rgeos'
+PACKAGE_VERSION='0.3-26'
+PACKAGE_STRING='rgeos 0.3-26'
+PACKAGE_BUGREPORT='Roger.Bivand at nhh.no'
+PACKAGE_URL=''
+
+ac_unique_file="src/rgeos.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+PKG_LIBS
+PKG_CPPFLAGS
+GEOS_CONFIG
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_geos_config
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures rgeos 0.3-26 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/rgeos]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of rgeos 0.3-26:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-geos-config=GEOS_CONFIG
+                          the location of geos-config
+
+Report bugs to <Roger.Bivand at nhh.no>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+rgeos configure 0.3-26
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by rgeos $as_me 0.3-26, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+# find R home and set correct compiler + flags
+: ${R_HOME=`R RHOME`}
+if test -z "${R_HOME}"; then
+  as_fn_error $? "cannot determine R_HOME. Make sure you use R CMD INSTALL!" "$LINENO" 5
+fi
+RBIN="${R_HOME}/bin/R"
+
+# pick all flags for testing from R
+: ${CC=`"${RBIN}" CMD config CC`}
+: ${CXX=`"${RBIN}" CMD config CXX`}
+: ${CPP=`"${RBIN}" CMD config CPP`}
+: ${CFLAGS=`"${RBIN}" CMD config CFLAGS`}
+: ${CPPFLAGS=`"${RBIN}" CMD config CPPFLAGS`}
+: ${LDFLAGS=`"${RBIN}" CMD config LDFLAGS`}
+# AC_SUBST([CC],["clang"])
+# AC_SUBST([CXX],["clang++"])
+{ $as_echo "$as_me:${as_lineno-$LINENO}: CC: ${CC}" >&5
+$as_echo "$as_me: CC: ${CC}" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: CXX: ${CXX}" >&5
+$as_echo "$as_me: CXX: ${CXX}" >&6;}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: ${PACKAGE_NAME}: ${PACKAGE_VERSION}" >&5
+$as_echo "$as_me: ${PACKAGE_NAME}: ${PACKAGE_VERSION}" >&6;}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /usr/bin/svnversion" >&5
+$as_echo_n "checking for /usr/bin/svnversion... " >&6; }
+if ${ac_cv_file__usr_bin_svnversion+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  test "$cross_compiling" = yes &&
+  as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
+if test -r "/usr/bin/svnversion"; then
+  ac_cv_file__usr_bin_svnversion=yes
+else
+  ac_cv_file__usr_bin_svnversion=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__usr_bin_svnversion" >&5
+$as_echo "$ac_cv_file__usr_bin_svnversion" >&6; }
+if test "x$ac_cv_file__usr_bin_svnversion" = xyes; then :
+  SVN_VERSION=`svnversion -n '.'`
+else
+  SVN_VERSION=""
+fi
+
+
+if test -n "${SVN_VERSION}" && test "${SVN_VERSION}" != "exported" && test "${SVN_VERSION}" != "Unversioned directory"; then
+  echo "${SVN_VERSION}" > inst/SVN_VERSION
+else
+  SVN_VERSION=`cat inst/SVN_VERSION | tr -d '\n'`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: svn revision: ${SVN_VERSION}" >&5
+$as_echo "$as_me: svn revision: ${SVN_VERSION}" >&6;}
+
+GEOS_CONFIG="geos-config"
+
+GEOS_CONFIG_SET="no"
+
+
+# Check whether --with-geos-config was given.
+if test "${with_geos_config+set}" = set; then :
+  withval=$with_geos_config; geos_config=$withval
+fi
+
+if test  -n "$geos_config"  ; then
+    GEOS_CONFIG_SET="yes"
+    GEOS_CONFIG="${geos_config}"
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: geos-config set to $GEOS_CONFIG" >&5
+$as_echo "$as_me: geos-config set to $GEOS_CONFIG" >&6;}
+fi
+
+if test "$GEOS_CONFIG_SET" = "no" ; then
+  # Extract the first word of ""$GEOS_CONFIG"", so it can be a program name with args.
+set dummy "$GEOS_CONFIG"; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_GEOS_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $GEOS_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_GEOS_CONFIG="$GEOS_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_GEOS_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_GEOS_CONFIG" && ac_cv_path_GEOS_CONFIG=""no""
+  ;;
+esac
+fi
+GEOS_CONFIG=$ac_cv_path_GEOS_CONFIG
+if test -n "$GEOS_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GEOS_CONFIG" >&5
+$as_echo "$GEOS_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  if test "$GEOS_CONFIG" = "no" ; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    as_fn_error $? "geos-config not found or not executable." "$LINENO" 5
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking geos-config exists" >&5
+$as_echo_n "checking geos-config exists... " >&6; }
+  if test -r "${GEOS_CONFIG}"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    as_fn_error $? "geos-config not found - configure argument error." "$LINENO" 5
+  fi
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking geos-config executable" >&5
+$as_echo_n "checking geos-config executable... " >&6; }
+  if test -x "${GEOS_CONFIG}"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    as_fn_error $? "geos-config not executable." "$LINENO" 5
+  fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking geos-config usability" >&5
+$as_echo_n "checking geos-config usability... " >&6; }
+if test `${GEOS_CONFIG} --version`;
+then
+
+        GEOS_VER=`${GEOS_CONFIG} --version`
+        GEOS_VER_DOT=`echo $GEOS_VER | tr -d ".dev"`
+	GEOS_CPPFLAGS=`${GEOS_CONFIG} --cflags`
+	GEOS_LIBS=`${GEOS_CONFIG} --libs`
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+        as_fn_error $? "${GEOS_CONFIG} not usable" "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: GEOS version: ${GEOS_VER}" >&5
+$as_echo "$as_me: GEOS version: ${GEOS_VER}" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking geos version at least 3.2.0" >&5
+$as_echo_n "checking geos version at least 3.2.0... " >&6; }
+if test ${GEOS_VER_DOT} -lt 320 ; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+        as_fn_error $? "Upgrade GEOS to at least 3.2.0" "$LINENO" 5
+else
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking geos-config clibs" >&5
+$as_echo_n "checking geos-config clibs... " >&6; }
+if test ${GEOS_VER_DOT} -lt 332 ; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+        GEOS_CLIBS="-lgeos_c"
+else
+        GEOS_CLIBS=`${GEOS_CONFIG} --clibs`
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+
+
+PKG_CPPFLAGS="${PKG_CPPFLAGS} ${GEOS_CPPFLAGS}"
+
+PKG_LIBS="${PKG_LIBS} ${GEOS_LIBS} ${GEOS_CLIBS}"
+
+
+# honor PKG_xx overrides
+# for CPPFLAGS we will superfluously double R's flags
+# since we'll set PKG_CPPFLAGS with this, but that shouldn't hurt
+CPPFLAGS="${CPPFLAGS} ${PKG_CPPFLAGS}"
+LIBS="${LIBS} ${PKG_LIBS}"
+
+#geosok=yes
+#AC_CHECK_HEADERS(geos_c.h,,geosok=no)
+#if test "${geosok}" = no; then
+#   AC_MSG_ERROR([geos_c.h not found in given locations.])
+#fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking geos_c.h  presence and usability" >&5
+$as_echo_n "checking geos_c.h  presence and usability... " >&6; }
+cat > geos_test.c << _EOCONF
+#include <stdio.h>
+#include <geos_c.h>
+
+int main() {
+    printf("%d\n", GEOS_CAPI_VERSION);
+    exit(0);
+}
+_EOCONF
+
+if test `${CC} ${CPPFLAGS} -o geos_test geos_test.c 2> /dev/null; echo $?` = 0; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  as_fn_error $? "geos_c.h not found in standard or given locations." "$LINENO" 5
+fi
+
+rm -f geos_test geos_test.c
+
+
+#AC_CHECK_LIB(geos_c,initGEOS_r,,geosok=no)
+
+cat > geos_test.cc <<_EOCONF
+#include <geos_c.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+static void __errorHandler(const char *fmt, ...) {
+    return;
+}
+static void __warningHandler(const char *fmt, ...) {
+    return;
+}
+int main() {
+    GEOSContextHandle_t r = initGEOS_r((GEOSMessageHandler) __warningHandler, (GEOSMessageHandler) __errorHandler);
+    finishGEOS_r(r);
+}
+#ifdef __cplusplus
+}
+#endif
+_EOCONF
+
+#echo "${CXX} ${CPPFLAGS} -o geos_test geos_test.cc ${LIBS}"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking geos: linking with libgeos_c" >&5
+$as_echo_n "checking geos: linking with libgeos_c... " >&6; }
+${CXX} ${CPPFLAGS} -o geos_test geos_test.cc ${LIBS} 2> errors.txt
+if test `echo $?` -ne 0 ; then
+geosok=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+else
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+
+if test "${geosok}" = no; then
+   cat errors.txt
+   { $as_echo "$as_me:${as_lineno-$LINENO}: Install failure: compilation and/or linkage problems." >&5
+$as_echo "$as_me: Install failure: compilation and/or linkage problems." >&6;}
+   as_fn_error $? "initGEOS_r not found in libgeos_c." "$LINENO" 5
+fi
+
+rm -f geos_test errors.txt geos_test.cc
+
+
+if test "${geosok}" = no; then
+   as_fn_error $? "libgeos_c not found in given locations." "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: PKG_CPPFLAGS: ${PKG_CPPFLAGS}" >&5
+$as_echo "$as_me: PKG_CPPFLAGS: ${PKG_CPPFLAGS}" >&6;}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: PKG_LIBS: ${PKG_LIBS}" >&5
+$as_echo "$as_me: PKG_LIBS: ${PKG_LIBS}" >&6;}
+
+
+ac_config_files="$ac_config_files src/Makevars"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section.  Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*([^)]*)\)[	 ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[	 `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+	g
+	s/^\n//
+	s/\n/ /g
+	p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by rgeos $as_me 0.3-26, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <Roger.Bivand at nhh.no>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+rgeos config.status 0.3-26
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h |  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "src/Makevars") CONFIG_FILES="$CONFIG_FILES src/Makevars" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X "  :F $CONFIG_FILES      "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+  esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..501a8ae
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,199 @@
+# dnl Process this file with autoconf to produce a configure script.
+define([pkgversion], esyscmd([sh -c "grep Version: DESCRIPTION | cut -d' ' -f2 | tr -d '\n'"]))dnl
+AC_INIT(rgeos, [pkgversion], Roger.Bivand at nhh.no)
+AC_CONFIG_SRCDIR(src/rgeos.c)
+
+# find R home and set correct compiler + flags
+: ${R_HOME=`R RHOME`}
+if test -z "${R_HOME}"; then
+  AC_MSG_ERROR([cannot determine R_HOME. Make sure you use R CMD INSTALL!])
+fi
+RBIN="${R_HOME}/bin/R"
+
+# pick all flags for testing from R
+: ${CC=`"${RBIN}" CMD config CC`}
+: ${CXX=`"${RBIN}" CMD config CXX`}
+: ${CPP=`"${RBIN}" CMD config CPP`}
+: ${CFLAGS=`"${RBIN}" CMD config CFLAGS`}
+: ${CPPFLAGS=`"${RBIN}" CMD config CPPFLAGS`}
+: ${LDFLAGS=`"${RBIN}" CMD config LDFLAGS`}
+# AC_SUBST([CC],["clang"])
+# AC_SUBST([CXX],["clang++"])
+AC_MSG_NOTICE([CC: ${CC}])
+AC_MSG_NOTICE([CXX: ${CXX}])
+
+AC_MSG_NOTICE([${PACKAGE_NAME}: ${PACKAGE_VERSION}])
+
+AC_CHECK_FILE([/usr/bin/svnversion],
+ [SVN_VERSION=`svnversion -n '.'`],
+ [SVN_VERSION=""])
+
+if test -n "${SVN_VERSION}" && test "${SVN_VERSION}" != "exported" && test "${SVN_VERSION}" != "Unversioned directory"; then
+  echo "${SVN_VERSION}" > inst/SVN_VERSION
+else
+  SVN_VERSION=`cat inst/SVN_VERSION | tr -d '\n'`
+fi
+AC_MSG_NOTICE([svn revision: ${SVN_VERSION}])
+
+GEOS_CONFIG="geos-config"
+
+GEOS_CONFIG_SET="no"
+
+AC_ARG_WITH([geos-config],
+    AC_HELP_STRING([--with-geos-config=GEOS_CONFIG],
+           [the location of geos-config]),
+           [geos_config=$withval])
+if test [ -n "$geos_config" ] ; then
+    GEOS_CONFIG_SET="yes"
+    AC_SUBST([GEOS_CONFIG],["${geos_config}"])
+    AC_MSG_NOTICE(geos-config set to $GEOS_CONFIG)
+fi
+
+if test ["$GEOS_CONFIG_SET" = "no"] ; then
+  AC_PATH_PROG([GEOS_CONFIG], ["$GEOS_CONFIG"],["no"])
+  if test ["$GEOS_CONFIG" = "no"] ; then
+    AC_MSG_RESULT(no)
+    AC_MSG_ERROR([geos-config not found or not executable.])
+  fi
+else
+  AC_MSG_CHECKING(geos-config exists)
+  if test -r "${GEOS_CONFIG}"; then
+    AC_MSG_RESULT(yes)
+  else
+    AC_MSG_RESULT(no)
+    AC_MSG_ERROR([geos-config not found - configure argument error.])
+  fi
+  AC_MSG_CHECKING(geos-config executable)
+  if test -x "${GEOS_CONFIG}"; then
+    AC_MSG_RESULT(yes)
+  else
+    AC_MSG_RESULT(no)
+    AC_MSG_ERROR([geos-config not executable.])
+  fi
+fi
+
+
+AC_MSG_CHECKING(geos-config usability)
+if test `${GEOS_CONFIG} --version`;
+then
+
+        GEOS_VER=`${GEOS_CONFIG} --version`
+        GEOS_VER_DOT=`echo $GEOS_VER | tr -d ".dev"`
+	GEOS_CPPFLAGS=`${GEOS_CONFIG} --cflags`
+	GEOS_LIBS=`${GEOS_CONFIG} --libs`
+        AC_MSG_RESULT(yes)
+
+else
+
+        AC_MSG_RESULT(no)
+        AC_MSG_ERROR([${GEOS_CONFIG} not usable])
+fi
+
+AC_MSG_NOTICE([GEOS version: ${GEOS_VER}])
+AC_MSG_CHECKING([geos version at least 3.2.0])
+if test ${GEOS_VER_DOT} -lt 320 ; then
+        AC_MSG_RESULT(no)
+        AC_MSG_ERROR([Upgrade GEOS to at least 3.2.0])
+else
+        AC_MSG_RESULT(yes)
+fi
+
+AC_MSG_CHECKING(geos-config clibs)
+if test ${GEOS_VER_DOT} -lt 332 ; then
+        AC_MSG_RESULT(no)
+        GEOS_CLIBS="-lgeos_c"
+else        
+        GEOS_CLIBS=`${GEOS_CONFIG} --clibs`
+        AC_MSG_RESULT(yes)
+fi
+
+
+AC_SUBST([PKG_CPPFLAGS],["${PKG_CPPFLAGS} ${GEOS_CPPFLAGS}"])
+AC_SUBST([PKG_LIBS],["${PKG_LIBS} ${GEOS_LIBS} ${GEOS_CLIBS}"])
+
+# honor PKG_xx overrides
+# for CPPFLAGS we will superfluously double R's flags
+# since we'll set PKG_CPPFLAGS with this, but that shouldn't hurt
+CPPFLAGS="${CPPFLAGS} ${PKG_CPPFLAGS}"
+LIBS="${LIBS} ${PKG_LIBS}"
+
+#geosok=yes
+#AC_CHECK_HEADERS(geos_c.h,,geosok=no)
+#if test "${geosok}" = no; then
+#   AC_MSG_ERROR([geos_c.h not found in given locations.])
+#fi
+
+AC_MSG_CHECKING(geos_c.h  presence and usability)
+[cat > geos_test.c << _EOCONF
+#include <stdio.h>
+#include <geos_c.h>
+
+int main() {
+    printf("%d\n", GEOS_CAPI_VERSION);
+    exit(0);
+}
+_EOCONF]
+
+if test `${CC} ${CPPFLAGS} -o geos_test geos_test.c 2> /dev/null; echo $?` = 0; then
+  AC_MSG_RESULT(yes)
+else
+  AC_MSG_RESULT(no)
+  AC_MSG_ERROR([geos_c.h not found in standard or given locations.])
+fi
+
+rm -f geos_test geos_test.c
+
+
+#AC_CHECK_LIB(geos_c,initGEOS_r,,geosok=no)
+
+[cat > geos_test.cc <<_EOCONF
+#include <geos_c.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+static void __errorHandler(const char *fmt, ...) {
+    return;
+}
+static void __warningHandler(const char *fmt, ...) {
+    return;
+}
+int main() {
+    GEOSContextHandle_t r = initGEOS_r((GEOSMessageHandler) __warningHandler, (GEOSMessageHandler) __errorHandler);
+    finishGEOS_r(r);
+}
+#ifdef __cplusplus
+}
+#endif
+_EOCONF]
+
+#echo "${CXX} ${CPPFLAGS} -o geos_test geos_test.cc ${LIBS}"
+AC_MSG_CHECKING(geos: linking with libgeos_c)
+${CXX} ${CPPFLAGS} -o geos_test geos_test.cc ${LIBS} 2> errors.txt
+if test `echo $?` -ne 0 ; then
+geosok=no
+AC_MSG_RESULT(no)
+else
+AC_MSG_RESULT(yes)
+fi
+
+if test "${geosok}" = no; then
+   cat errors.txt
+   AC_MSG_NOTICE([Install failure: compilation and/or linkage problems.])
+   AC_MSG_ERROR([initGEOS_r not found in libgeos_c.])
+fi
+
+rm -f geos_test errors.txt geos_test.cc
+
+
+if test "${geosok}" = no; then
+   AC_MSG_ERROR([libgeos_c not found in given locations.])
+fi
+
+AC_MSG_NOTICE([PKG_CPPFLAGS: ${PKG_CPPFLAGS}])
+AC_SUBST(PKG_CPPFLAGS)
+AC_MSG_NOTICE([PKG_LIBS: ${PKG_LIBS}])
+AC_SUBST(PKG_LIBS)
+
+AC_CONFIG_FILES(src/Makevars)
+AC_OUTPUT
+
diff --git a/debian/README.test b/debian/README.test
deleted file mode 100644
index 0fe5d4e..0000000
--- a/debian/README.test
+++ /dev/null
@@ -1,10 +0,0 @@
-Notes on how this package can be tested.
-────────────────────────────────────────
-
-To run the unit tests provided by the package you can do
-
-   sh  run-unit-test
-
-in this directory.
-
- -- Andreas Tille <tille at debian.org>  Fri, 20 Jun 2014 15:25:06 +0200
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index 12e0f43..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,5 +0,0 @@
-r-cran-rgeos (0.3-21-1) unstable; urgency=medium
-
-  * Initial release (closes: #844197)
-
- -- Andreas Tille <tille at debian.org>  Sun, 13 Nov 2016 17:56:16 +0100
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index ec63514..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/debian/control b/debian/control
deleted file mode 100644
index 00b7b20..0000000
--- a/debian/control
+++ /dev/null
@@ -1,25 +0,0 @@
-Source: r-cran-rgeos
-Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Andreas Tille <tille at debian.org>
-Section: gnu-r
-Priority: optional
-Build-Depends: debhelper (>= 9),
-               dh-r,
-               r-base-dev,
-               r-cran-sp,
-               libgeos-dev
-Standards-Version: 3.9.8
-Vcs-Browser: https://anonscm.debian.org/viewvc/debian-med/trunk/packages/R/r-cran-rgeos/trunk/
-Vcs-Svn: svn://anonscm.debian.org/debian-med/trunk/packages/R/r-cran-rgeos/trunk/
-Homepage: https://cran.r-project.org/package=rgeos
-
-Package: r-cran-rgeos
-Architecture: any
-Depends: ${R:Depends},
-         ${shlibs:Depends},
-         ${misc:Depends}
-Recommends: ${R:Recommends}
-Suggests: ${R:Suggests}
-Description: GNU R interface to geometry engine
- This GNU R package provides an Interface to the Geometry Engine - Open Source
- (GEOS) using the C API for topology operations on geometries.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index d606a65..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,74 +0,0 @@
-Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: rgeos
-Upstream-Contact: Roger Bivand <Roger.Bivand at nhh.no>
-Source: https://cran.r-project.org/package=rgeos
-
-Files: *
-Copyright: 2009-2016 Roger Bivand, Colin Rundel, Edzer Pebesma, Rainer Stuetz, Karl Ove Hufthammer
-License: GPL-2+
-
-Files: R/Rgpc_funcs.R
-Copyright: 2003-2010 Roger D. Peng <rpeng at jhsph.edu>
-License: GPL-2+
-Comment: Quoting a mail from Roger Bivand
-   Date: Fri, 3 Feb 2017 10:58:09 +0100
-   From: Roger Bivand <Roger.Bivand at nhh.no>
- .
-   On Fri, 3 Feb 2017, Andreas Tille wrote:
-   >
-   > I intended to package rgeos for Debian since it would enable the test
-   > suite of some other package.  Unfortunately rgeos contains
-   > R/Rgpc_funcs.R which uses gpclib that has a license:
-   >
-   >   Free for non-commercial use; commercial use prohibited (see the files
-   >   `gpc.c' and `gpc.h' for details)
-   >
-   > So how could this be GPL-2?
- .
-   Obviously it is, because rgeos neither suggests, links to, imports or 
-   depends on the R gpclib package, nor does it load or attach that package.
- .
-   The functions in R/gpc_geos.R convert sp objects to R gpclib classes, 
-   defined in R/Rgpc_funcs.R. The examples in man/gpc-new-generics.Rd 
-   expressly show how to use GEOS compiled code instead of gpclib compiled 
-   code to yield the same results. That is, when rgeos was first published in 
-   2011, one of its intentions was to show that nobody needed to use the 
-   R gpclib package with its awkward license, but that the code in 
-   R/Rgpc_funcs.R provided a drop-in replacement - load rgeos instead of 
-   gpclib and get the same output but without the gpclib license issue. The 
-   code copied from gpclib/R/Rgpc.R to rgeos/R is:
- .
-   ## Copyright (C) 2003-2010 Roger D. Peng <rpeng at jhsph.edu>
- .
-   Our understanding of the R gpclib LICENSE is that it only refers to the 
-   code written by Alan Murta and "taken" by this former employer - that is 
-   the files src/gpc.*. This is evidenced by the verbatim text of the package 
-   LICENSE file: Free for non-commercial use; commercial use prohibited (see 
-   the files `gpc.c' and `gpc.h' for details). Obviously C and R code written 
-   by the maintainer or contributed by others is not covered by this 
-   restriction.
- .
- .
- Summarising the content of the last paragraph which is not worth quoting:
- .
- The purposes of rgeos is to provide a substitute for gpclib,  The LICENSE
- file of the R gpclib package should have been drafted to state that only
- src/gpc.* are covered by the conditions stated therein.
-
-Files: debian/*
-Copyright: 2016 Andreas Tille <tille at debian.org>
-License: GPL-2+
-
-License: GPL-2+
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- .
- This program 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 General Public License for more details.
- .
- On Debian systems, the complete text of the GNU General Public
- License version 2 can be found in ‘/usr/share/common-licenses/GPL-2’.
diff --git a/debian/docs b/debian/docs
deleted file mode 100644
index 960011c..0000000
--- a/debian/docs
+++ /dev/null
@@ -1,3 +0,0 @@
-tests
-debian/README.test
-debian/tests/run-unit-test
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index 529c38a..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/make -f
-
-%:
-	dh $@ --buildsystem R
-
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/tests/control b/debian/tests/control
deleted file mode 100644
index b044b0c..0000000
--- a/debian/tests/control
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests: run-unit-test
-Depends: @, r-cran-testthat
-Restrictions: allow-stderr
diff --git a/debian/tests/run-unit-test b/debian/tests/run-unit-test
deleted file mode 100644
index 6a24908..0000000
--- a/debian/tests/run-unit-test
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh -e
-
-oname=rgeos
-pkg=r-cran-`echo $oname | tr '[A-Z]' '[a-z]'`
-
-if [ "$ADTTMP" = "" ] ; then
-  ADTTMP=`mktemp -d /tmp/${pkg}-test.XXXXXX`
-  trap "rm -rf $ADTTMP" 0 INT QUIT ABRT PIPE TERM
-fi
-cd $ADTTMP
-cp -a /usr/share/doc/${pkg}/tests/* $ADTTMP
-LC_ALL=C R --no-save < test-all.R
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index 62600f7..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,2 +0,0 @@
-version=4
-https://cran.r-project.org/src/contrib/rgeos_([-\d.]*)\.tar\.gz
diff --git a/inst/ChangeLog b/inst/ChangeLog
new file mode 100644
index 0000000..1a8ab10
--- /dev/null
+++ b/inst/ChangeLog
@@ -0,0 +1,2904 @@
+2017-09-25 10:51  rsbivand
+
+	* configure: updating for stricter autoconf
+
+2017-09-25 10:50  rsbivand
+
+	* DESCRIPTION: updating for stricter autoconf
+
+2017-09-25 10:49  rsbivand
+
+	* configure, configure.ac: updating for stricter autoconf
+
+2017-09-25 10:46  rsbivand
+
+	* configure, configure.ac: updating for stricter autoconf
+
+2017-09-18 08:59  rsbivand
+
+	* DESCRIPTION: tidy
+
+2017-09-18 08:27  rsbivand
+
+	* ChangeLog, configure, inst/ChangeLog: tidy
+
+2017-09-18 08:26  rsbivand
+
+	* DESCRIPTION, tools, tools/winlibs.R: transition to winlibs
+
+2017-09-15 13:09  rsbivand
+
+	* DESCRIPTION, src/Makevars.win: migrate to winlib/gdal
+
+2017-04-05 12:05  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2017-04-05 12:04  rsbivand
+
+	* configure: tidy
+
+2017-04-05 12:03  rsbivand
+
+	* DESCRIPTION, src/rgeos.c, src/rgeos_validate.c: PROTECT issues
+
+2017-01-08 19:11  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2016-12-10 10:02  rsbivand
+
+	* configure: omitted trap in init.c
+
+2016-12-10 10:00  rsbivand
+
+	* DESCRIPTION, src/init.c: omitted trap in init.c
+
+2016-10-19 11:45  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2016-10-11 03:24  rsbivand
+
+	* ChangeLog, R/rgeos_misc.R, man/misc-gNearestPoints.Rd,
+	  src/rgeos.h, src/rgeos_misc.c: checking NearestPoint dependency
+	  on >= 3.4
+
+2016-10-10 07:28  rcs
+
+	* ChangeLog, DESCRIPTION, NAMESPACE, R/rgeos_misc.R, configure,
+	  inst/ChangeLog, man/misc-gNearestPoints.Rd, src/init.c,
+	  src/rgeos.h, src/rgeos_misc.c, tests/testthat/test-misc.R: add
+	  gNearestPoints
+
+2016-10-08 08:14  rcs
+
+	* tests/testthat/test-linearref.R: fix linearref tests
+
+2016-10-07 21:53  rcs
+
+	* tests/testthat/test-linearref.R: fix linearref tests
+
+2016-09-14 11:18  rcs
+
+	* R/rgeos_spExtensions_Methods.R, R/rgeos_topology.R: fix partial
+	  argument match
+
+2016-09-07 13:10  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2016-09-07 13:09  rsbivand
+
+	* src/rgeos_predicate_binary.c: block list output from gRelate
+
+2016-09-07 10:03  rsbivand
+
+	* inst/ChangeLog: tidy
+
+2016-09-07 09:50  rcs
+
+	* ChangeLog, man/topo-unary-gEnvelope.Rd: fix typo
+
+2016-09-07 09:48  rcs
+
+	* ChangeLog, src/rgeos_geos2R.c: fix stack imbalance in
+	  rgeos_geosring2SpatialRings()
+
+2016-09-06 13:13  rcs
+
+	* ChangeLog, R/rgeos_linearref.R, man/linref-gProject.Rd,
+	  src/rgeos_linearref.c: update Rd; fix typo
+
+2016-09-06 11:41  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2016-09-06 11:40  rsbivand
+
+	* configure: tidy
+
+2016-09-06 11:38  rsbivand
+
+	* inst/tests, tests/test-all.R, tests/testthat: moved tests folder
+
+2016-09-06 10:50  rcs
+
+	* ChangeLog, DESCRIPTION, NAMESPACE, R/rgeos_linearref.R,
+	  inst/tests/test-linearref.R, man/linref-gInterpolate.Rd,
+	  man/linref-gProject.Rd, src/init.c, src/rgeos.h,
+	  src/rgeos_linearref.c: added linear referencing functions
+	  (gInterpolate/gProject)
+
+2016-08-30 17:36  rsbivand
+
+	* DESCRIPTION, src/rgeos_coord.c: protect s in src/rgeos_coord.c
+
+2016-04-04 11:37  rsbivand
+
+	* ChangeLog, configure, inst/ChangeLog: tidy
+
+2016-04-04 11:35  rsbivand
+
+	* DESCRIPTION, src/Makevars.win: update to win-4.9.3
+
+2016-02-15 07:38  rsbivand
+
+	* DESCRIPTION, R/rgeos_buffer.R: gBuffer NULL case
+
+2016-02-13 11:26  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2016-02-12 20:31  rsbivand
+
+	* DESCRIPTION, R/rgeos_buffer.R: buffer byid to FALSE if single
+	  feature
+
+2016-02-12 18:58  rsbivand
+
+	* R/rgeos_buffer.R: buffer byid to FALSE if single feature
+
+2016-02-09 12:53  rsbivand
+
+	* ChangeLog, inst/ChangeLog: buffer byid to FALSE if single feature
+
+2016-02-09 12:52  rsbivand
+
+	* DESCRIPTION, R/rgeos_buffer.R, configure, src/rgeos_buffer.c:
+	  buffer byid to FALSE if single feature
+
+2016-01-23 19:12  rsbivand
+
+	* DESCRIPTION, R/rgeos_misc.R: rev 66 oddity partial workaround
+
+2015-11-04 12:46  rsbivand
+
+	* configure: tidy
+
+2015-11-04 12:43  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-11-04 11:10  rsbivand
+
+	* DESCRIPTION, src/rgeos_buffer.c: rgeos_buffer id overrun bug fix
+
+2015-10-26 14:28  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-10-25 10:38  rsbivand
+
+	* man/topo-bin-gIntersection.Rd: fix td bug
+
+2015-10-25 10:28  rsbivand
+
+	* ChangeLog, DESCRIPTION, inst/ChangeLog,
+	  man/topo-bin-gIntersection.Rd, src/rgeos_topology_binary.c: fix
+	  td bug
+
+2015-09-29 07:07  rsbivand
+
+	* man/topo-bin-gIntersection.Rd: extra intersection example
+
+2015-09-28 15:51  rsbivand
+
+	* ChangeLog, configure,
+	  inst/tests/testxml/general/TestFunctionLLPrec.xml,
+	  inst/tests/testxml/validate/TestRelateLL.xml,
+	  inst/tests/testxml/validate/TestRelatePA.xml,
+	  inst/tests/testxml/validate/TestRelatePL.xml,
+	  inst/tests/testxml/validate/TestRelatePP.xml: tidy
+
+2015-09-28 09:49  rsbivand
+
+	* src/rgeos_geos2R.c: SpatialRings stack unbalance
+
+2015-09-26 17:45  rsbivand
+
+	* man/labelpt.Rd, man/pred-binary-gContains.Rd,
+	  man/pred-binary-gCrosses.Rd, man/pred-binary-gEquals.Rd,
+	  man/pred-binary-gIntersects.Rd, man/pred-binary-gRelate.Rd,
+	  man/pred-binary-gTouches.Rd, man/topo-bin-gDifference.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gSymdifference.Rd,
+	  man/topo-bin-gUnion.Rd: tidy
+
+2015-09-26 17:27  rsbivand
+
+	* DESCRIPTION: adding unaryUnion to topo-bin if FALSE byid
+
+2015-09-26 17:27  rsbivand
+
+	* R/rgeos_topology_binary.R, man/topo-bin-gDifference.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gSymdifference.Rd,
+	  man/topo-bin-gUnion.Rd, src/rgeos_topology_binary.c: adding
+	  unaryUnion to topo-bin if FALSE byid
+
+2015-09-20 21:23  rsbivand
+
+	* man/pred-binary-gContains.Rd, man/pred-binary-gCrosses.Rd,
+	  man/pred-binary-gEquals.Rd, man/pred-binary-gIntersects.Rd,
+	  man/pred-binary-gRelate.Rd, man/pred-binary-gTouches.Rd,
+	  man/topo-bin-gDifference.Rd, man/topo-bin-gIntersection.Rd,
+	  man/topo-bin-gSymdifference.Rd, man/topo-bin-gUnion.Rd: note on
+	  0-based indices
+
+2015-09-18 12:13  rsbivand
+
+	* R/rgeos_predicate_binary.R, R/rgeos_topology_binary.R: add
+	  optional validity checking to binary predicates and operations
+
+2015-09-18 12:09  rsbivand
+
+	* DESCRIPTION, R/rgeos_predicate_binary.R,
+	  R/rgeos_topology_binary.R, man/misc-over.Rd,
+	  man/pred-binary-gContains.Rd, man/pred-binary-gCrosses.Rd,
+	  man/pred-binary-gEquals.Rd, man/pred-binary-gIntersects.Rd,
+	  man/pred-binary-gRelate.Rd, man/pred-binary-gTouches.Rd,
+	  man/topo-bin-gDifference.Rd, man/topo-bin-gIntersection.Rd,
+	  man/topo-bin-gSymdifference.Rd, man/topo-bin-gUnion.Rd: add
+	  optional validity checking to binary predicates and operations
+
+2015-09-10 14:06  edzer
+
+	* DESCRIPTION, R/over.R: version bump; let overGeomGeomDF absorb &
+	  pass on minDimension to overGeomGeom
+
+2015-09-01 10:27  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-08-31 19:59  edzer
+
+	* R/over.R: pass on colnames(x) if x is matrix
+
+2015-08-31 16:49  edzer
+
+	* R/over.R: pass names on to returned list
+
+2015-08-31 16:13  edzer
+
+	* R/over.R, man/misc-over.Rd: complete documentation, clean up
+	  code.
+
+2015-08-31 11:49  rsbivand
+
+	* configure, configure.ac: strip dev from version
+
+2015-08-25 11:48  rsbivand
+
+	* DESCRIPTION, man/pred-binary-gContains.Rd,
+	  man/pred-binary-gCrosses.Rd, man/pred-binary-gEquals.Rd,
+	  man/pred-binary-gIntersects.Rd, man/pred-binary-gTouches.Rd,
+	  src/rgeos_predicate_binary.c: block assigning too large matrix
+
+2015-08-25 09:15  edzer
+
+	* R/over.R: default to gIntersects(), because of the performance
+	  penalty
+
+2015-08-22 13:33  edzer
+
+	* R/over.R: move constant check outside loop
+
+2015-08-21 22:13  edzer
+
+	* R/over.R: increase over sanity
+
+2015-08-21 15:03  edzer
+
+	* R/over.R: catch omission on unrealistic dimension requirements
+
+2015-08-20 20:45  edzer
+
+	* R/over.R: clean up over stuff, order by dimension from gRelate
+
+2015-08-20 09:23  edzer
+
+	* R/over.R: some more tweeks for SpatialMultiPoints
+
+2015-08-19 14:52  edzer
+
+	* man/misc-over.Rd: add overGeomGeom doc
+
+2015-08-19 14:11  edzer
+
+	* NAMESPACE: export overGeomGeomDF and overGeomGeom
+
+2015-08-13 09:22  edzer
+
+	* src/rgeos_R2geos.c: clean up
+
+2015-06-28 20:36  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, man/pred-binary-gRelate.Rd: CRAN
+	  _R_CHECK_CODE_USAGE_WITH_ONLY_BASE_ATTACHED_=true NAMESPACE tidy
+
+2015-06-23 07:56  rsbivand
+
+	* R/AAA.R: add utils:: to packageVersion()
+
+2015-06-05 07:54  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-06-05 07:53  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-06-05 07:52  rsbivand
+
+	* DESCRIPTION: tidy
+
+2015-05-29 13:49  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-05-29 13:47  rsbivand
+
+	* DESCRIPTION: tidy
+
+2015-05-05 17:02  rsbivand
+
+	* DESCRIPTION, man/comment-functions.Rd,
+	  man/experimental-functions.Rd, man/labelpt.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gUnion.Rd,
+	  man/topo-unary-gDelaunayTriangulation.Rd: dontrun require issues
+
+2015-04-23 22:19  edzer
+
+	* man/topo-bin-gIntersection.Rd: typo
+
+2015-04-23 21:45  edzer
+
+	* src/rgeos_validate.c: add const declarations for SEXPs
+
+2015-04-23 21:43  edzer
+
+	* R/over.R: fix bug for SpatialPolygons,SpatialPolygonsDataFrame
+
+2015-04-13 15:59  rsbivand
+
+	* .Rbuildignore, R/labelpt.R, configure.ac, svn2cl.xsl: fix
+	  polygonsLabel
+
+2015-04-09 13:59  rsbivand
+
+	* DESCRIPTION, R/AAA.R, src/init.c, src/rgeos.c, src/rgeos.h: add
+	  linking to version
+
+2015-03-11 13:09  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-03-11 13:08  rsbivand
+
+	* R/labelpt.R, man/pred-unary-gIsSimple.Rd,
+	  man/pred-unary-gIsValid.Rd: tidy
+
+2015-03-11 12:48  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2015-03-10 08:30  rsbivand
+
+	* inst/README, inst/README.windows: OSX install note
+
+2015-03-09 07:37  edzer
+
+	* NAMESPACE, man/class-SpatialCollections.Rd: exportClass
+	  Spatial*NULL classes
+
+2015-03-08 16:04  rsbivand
+
+	* src/rgeos_coord.c, src/rgeos_geos2R.c, src/rgeos_poly2nb.c,
+	  src/rgeos_predicate_binary.c, src/rgeos_topology.c,
+	  src/rgeos_topology_binary.c: added extra geos-config checks
+
+2015-03-08 12:35  rsbivand
+
+	* DESCRIPTION: added extra geos-config checks
+
+2015-03-08 12:34  rsbivand
+
+	* configure, configure.ac: added extra geos-config checks
+
+2015-03-07 17:30  rsbivand
+
+	* configure, configure.ac: added extra geos-config checks
+
+2015-01-29 08:19  edzer
+
+	* R/over.R, man/pred-binary-gIntersects.Rd: improve readability
+	  overGeomGeom
+
+2015-01-28 22:58  edzer
+
+	* R/over.R: fix overGeomGeom for length(x) == 1
+
+2014-09-21 14:09  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-09-21 14:09  rsbivand
+
+	* DESCRIPTION, R/rgeos_topology_binary.R,
+	  man/topo-bin-gIntersection.Rd: deprecate drop_not_poly
+
+2014-09-21 11:19  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-09-21 11:18  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, man/topo-bin-gIntersection.Rd,
+	  man/utility-functions.Rd, src/rgeos_geos2R.c: conditionally drop
+	  slivers
+
+2014-09-20 18:50  rsbivand
+
+	* inst/test_cases, inst/test_cases/polys.RData: drop topological
+	  dimension
+
+2014-09-20 18:35  rsbivand
+
+	* src/rgeos_geos2R.c: drop topological dimension
+
+2014-09-19 20:17  rsbivand
+
+	* R/Rgpc_funcs.R, R/rgeos_misc.R, R/rgeos_topology_binary.R,
+	  man/topo-bin-gDifference.Rd, man/topo-bin-gIntersection.Rd,
+	  man/topo-bin-gSymdifference.Rd, man/topo-bin-gUnion.Rd,
+	  src/rgeos_topology_binary.c: drop topological dimension
+
+2014-09-11 13:08  rsbivand
+
+	* src/rgeos_geos2R.c: slivers
+
+2014-09-06 22:07  rsbivand
+
+	* R/AAA.R, src/rgeos_geos2R.c: drop_not_poly adjustment
+
+2014-09-04 18:30  rsbivand
+
+	* DESCRIPTION, R/AAA.R, R/rgeos_topology_binary.R,
+	  src/rgeos_topology_binary.c: drop_not_poly adjustment
+
+2014-07-08 08:53  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-07-07 22:26  rsbivand
+
+	* DESCRIPTION, R/Rgpc_funcs.R: constrain gpc to polygons
+
+2014-06-05 19:08  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-06-05 19:01  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-06-05 18:59  rsbivand
+
+	* man/pred-binary-gContains.Rd, man/pred-binary-gIntersects.Rd,
+	  src/rgeos_poly2nb.c: tidt
+
+2014-06-05 18:33  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-06-05 18:32  rsbivand
+
+	* DESCRIPTION, R/AAA.R, R/rgeos_predicate_binary.R,
+	  src/rgeos_poly2nb.c, src/rgeos_predicate_binary.c: tidy
+
+2014-03-31 19:58  rsbivand
+
+	* src/rgeos_predicate_binary.c: permit binary predicates to return
+	  lists
+
+2014-03-31 19:46  rsbivand
+
+	* src/rgeos_predicate_binary.c: permit binary predicates to return
+	  lists
+
+2014-03-31 17:15  rsbivand
+
+	* DESCRIPTION, R/AAA.R, R/rgeos_predicate_binary.R, R/rgeos_util.R,
+	  man/experimental-functions.Rd, man/pred-binary-gContains.Rd,
+	  man/pred-binary-gCrosses.Rd, man/pred-binary-gEquals.Rd,
+	  man/pred-binary-gIntersects.Rd, man/pred-binary-gTouches.Rd,
+	  src/rgeos_R2geos.c, src/rgeos_poly2nb.c,
+	  src/rgeos_predicate_binary.c: permit binary predicates to return
+	  lists
+
+2014-03-25 14:00  rsbivand
+
+	* configure: tidy
+
+2014-03-25 13:55  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-03-23 09:22  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/Rgpc_funcs.R, R/rgeos_topology.R,
+	  inst/wkts/sppsp.wkt, man/topo-unary-gDelaunayTriangulation.Rd,
+	  man/topo-unary-gNode.Rd, man/topo-unary-gPolygonize.Rd,
+	  src/init.c, src/rgeos.h, src/rgeos_topology.c: exposing noding
+
+2014-02-13 15:30  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-02-13 15:28  rsbivand
+
+	* src/rgeos_topology_binary.c: cast to remove warnings
+
+2014-02-13 08:52  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2014-02-13 08:51  rsbivand
+
+	* DESCRIPTION, src/rgeos_coord.c, src/rgeos_geos2R.c: changed
+	  PROTECT code for crdMAT
+
+2014-02-08 15:50  rsbivand
+
+	* DESCRIPTION, R/AAA.R, R/rgeos_topology_binary.R,
+	  man/topo-bin-gDifference.Rd, man/topo-bin-gIntersection.Rd,
+	  man/topo-bin-gSymdifference.Rd, man/topo-bin-gUnion.Rd,
+	  src/rgeos_topology_binary.c: drop not poly intersections if both
+	  poly
+
+2014-01-27 19:35  rsbivand
+
+	* src/rgeos_geos2R.c: added id report on GC in GC
+
+2014-01-27 19:06  rsbivand
+
+	* src/rgeos_geos2R.c, src/rgeos_topology_binary.c: added id report
+	  on GC in GC
+
+2014-01-22 12:13  rsbivand
+
+	* src/rgeos_predicate_binary.c: fix over-generous symmetry in binar
+	  predicates
+
+2014-01-22 12:09  rsbivand
+
+	* DESCRIPTION, src/rgeos.h, src/rgeos_predicate_binary.c: fix
+	  over-generous symmetry in binar predicates
+
+2013-12-06 23:34  crundel
+
+	* R/rgeos_predicate_binary.R: Fix for an edge case of predicates
+	  with multipoint geometries
+	  
+	  There is an issue if some points share in a SpatialPoints object
+	  share an ID since there will be a mismatch between the number of
+	  output IDs
+
+2013-10-06 13:29  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-10-06 13:28  rsbivand
+
+	* R/rgeos_buffer.R, man/misc-gBuffer.Rd: blocking EMPTY
+
+2013-10-05 14:46  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-10-05 14:35  rsbivand
+
+	* inst/tests/test-translate-empty.R,
+	  inst/tests/testxml/general/TestBoundary.xml,
+	  inst/tests/testxml/general/TestFunctionLA.xml,
+	  inst/tests/testxml/general/TestFunctionLL.xml,
+	  inst/tests/testxml/general/TestFunctionPP.xml,
+	  inst/tests/testxml/general/TestSimple.xml,
+	  inst/tests/testxml/general/TestValid.xml,
+	  inst/tests/testxml/general/TestValid2.xml,
+	  inst/tests/testxml/robust/ExternalRobustness.xml,
+	  man/misc-gBuffer.Rd, man/pred-unary-gIsEmpty.Rd,
+	  man/wkt-functions.Rd, src/rgeos_geos2R.c: blocking EMPTY
+
+2013-10-04 19:04  rsbivand
+
+	* R/rgeos_buffer.R, man/misc-gBuffer.Rd, src/rgeos_buffer.c: adding
+	  buffer widths either 1 or n
+
+2013-10-04 12:08  rsbivand
+
+	* DESCRIPTION: removing empty polygons
+
+2013-10-04 12:05  rsbivand
+
+	* DESCRIPTION, R/rgeos_buffer.R, src/rgeos_buffer.c,
+	  src/rgeos_geos2R.c: removing empty polygons
+
+2013-09-16 12:23  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-09-16 12:22  rsbivand
+
+	* man/topo-unary-gDelaunayTriangulation.Rd: tidy
+
+2013-09-16 11:15  rsbivand
+
+	* man/topo-unary-gDelaunayTriangulation.Rd: tidy
+
+2013-09-16 11:01  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-09-03 10:17  rsbivand
+
+	* NAMESPACE, R/rgeos_topology.R,
+	  man/topo-unary-gDelaunayTriangulation.Rd, src/rgeos_topology.c:
+	  Delaunay triangulation
+
+2013-09-02 21:14  rsbivand
+
+	* R/rgeos_topology.R: start incorporating triangulation
+
+2013-09-02 19:18  rsbivand
+
+	* DESCRIPTION, R/rgeos_topology.R, src/init.c, src/rgeos.h,
+	  src/rgeos_topology.c: start incorporating triangulation
+
+2013-09-02 12:29  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-09-02 12:28  rsbivand
+
+	* inst/tests/testxml/general/TestInteriorPoint.xml: revert xml
+	  tests to pass GEOS 3.2.0
+
+2013-09-01 17:47  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-09-01 17:22  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-09-01 17:20  rsbivand
+
+	* DESCRIPTION, cleanup, man/topo-unary-gPointOnSurface.Rd: add
+	  cleanup
+
+2013-09-01 16:40  rsbivand
+
+	* inst/tests/testxml/general/TestInteriorPoint.xml: revert two
+	  changes in gPointOnSurface test to match GEOS 3.4.* to suit < 3.4
+
+2013-09-01 10:31  rsbivand
+
+	* inst/tests/testxml/general/TestInteriorPoint.xml,
+	  man/topo-unary-gPointOnSurface.Rd: change gPointOnSurface test to
+	  match GEOS 3.4.*
+
+2013-08-30 16:52  edzer
+
+	* DESCRIPTION, R/over.R, man/comment-functions.Rd, man/labelpt.Rd,
+	  man/topo-unary-gPolygonize.Rd, man/utility-functions.Rd: moved sp
+	  and methods from Depends: to Imports:
+	  added library(sp) to the examples, where needed
+	  removed the ::: using the exported overDF_for_rgeos from sp
+	  1.0-12
+	  increased sp dependency to 1.0-12
+
+2013-07-18 10:30  rsbivand
+
+	* DESCRIPTION, src/rgeos_R2geos.c: check comment length against
+	  Polygons slot
+
+2013-07-17 13:57  rsbivand
+
+	* man/pred-binary-gContains.Rd: tidy
+
+2013-07-02 20:17  rhijmans
+
+	* R/rgeos_buffer.R:
+
+2013-07-02 20:15  rhijmans
+
+	* man/misc-gBuffer.Rd:
+
+2013-07-02 20:12  rhijmans
+
+	* R/rgeos_buffer.R:
+
+2013-06-22 14:17  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-06-22 14:16  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/labelpt.R, man/labelpt.Rd: update
+	  patched to polygonsLabel
+
+2013-06-22 13:40  rsbivand
+
+	* ChangeLog, inst/ChangeLog: more symbol check issues
+
+2013-06-22 13:39  rsbivand
+
+	* R/AAA.R, R/rgeos_misc.R, R/rgeos_predicate_binary.R,
+	  R/rgeos_predicate_unary.R, R/rgeos_topology.R,
+	  R/rgeos_topology_binary.R: tidy
+
+2013-06-22 12:23  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-06-22 12:23  rsbivand
+
+	* man/comment-functions.Rd, man/constructor-SpatialCollections.Rd,
+	  man/misc-gBuffer.Rd, man/misc-gDistance.Rd,
+	  man/pred-binary-gIntersects.Rd, man/pred-binary-gRelate.Rd,
+	  man/pred-unary-gIsValid.Rd, man/topo-bin-gIntersection.Rd,
+	  man/topo-bin-gUnion.Rd, man/topo-unary-gCentroid.Rd,
+	  man/topo-unary-gConvexHull.Rd, man/topo-unary-gEnvelope.Rd,
+	  man/topo-unary-gPointOnSurface.Rd, man/topo-unary-gSimplify.Rd:
+	  more symbol check issues
+
+2013-06-21 11:44  rsbivand
+
+	* DESCRIPTION, R/AAA.R: tidy
+
+2013-05-05 08:03  rsbivand
+
+	* configure, configure.ac: add Unversioned directory to svn
+	  revision
+
+2013-04-26 09:26  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-04-26 09:26  rsbivand
+
+	* DESCRIPTION: Kirill Müller's reversion to GEOS 3.2.0
+
+2013-04-26 09:25  rsbivand
+
+	* DESCRIPTION, configure, configure.ac: Kirill Müller's reversion
+	  to GEOS 3.2.0
+
+2013-04-09 16:47  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-04-09 13:47  rsbivand
+
+	* src/rgeos_geos2R.c: length of IDs guard
+
+2013-04-08 17:30  rsbivand
+
+	* R/rgeos_topology.R, man/topo-unary-gPolygonize.Rd: fix bug in
+	  gPolygonize ids
+
+2013-04-06 08:05  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-04-06 08:04  rsbivand
+
+	* configure, configure.ac: checking with clang++ in configure
+
+2013-04-05 21:05  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-04-05 20:02  rsbivand
+
+	* configure: update configure.ac to force C++ test linking
+
+2013-04-05 19:58  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-04-05 19:53  rsbivand
+
+	* DESCRIPTION, configure, configure.ac: update configure.ac to
+	  force C++ test linking
+
+2013-03-29 11:00  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-03-29 10:59  rsbivand
+
+	* ChangeLog, DESCRIPTION, inst/ChangeLog, src/rgeos_R2geos.c,
+	  src/rgeos_R2geosMP.c, src/rgeos_bbox.c, src/rgeos_buffer.c,
+	  src/rgeos_coord.c, src/rgeos_geos2R.c, src/rgeos_topology.c,
+	  src/rgeos_topology_binary.c: remove clang warnings
+
+2013-03-04 09:53  rsbivand
+
+	* configure: tidy
+
+2013-02-23 11:39  rsbivand
+
+	* DESCRIPTION, R/rgeos_buffer.R, R/rgeos_misc.R,
+	  R/rgeos_predicate_binary.R, R/rgeos_predicate_unary.R,
+	  R/rgeos_topology.R, R/rgeos_topology_binary.R, R/rgeos_wkt.R:
+	  enforce logical byid
+
+2013-02-06 16:58  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-02-06 09:18  rsbivand
+
+	* DESCRIPTION, R/rgeos_topology.R, man/topo-unary-gPolygonize.Rd:
+	  fix bug in gPolygonize for > 2 output objects
+
+2013-01-31 16:46  rsbivand
+
+	* inst/tests/testxml/general,
+	  inst/tests/testxml/general/TestBoundary.xml,
+	  inst/tests/testxml/general/TestCentroid.xml,
+	  inst/tests/testxml/general/TestConvexHull-big.xml,
+	  inst/tests/testxml/general/TestConvexHull.xml,
+	  inst/tests/testxml/general/TestFunctionAA.xml,
+	  inst/tests/testxml/general/TestFunctionAAPrec.xml,
+	  inst/tests/testxml/general/TestFunctionLA.xml,
+	  inst/tests/testxml/general/TestFunctionLAPrec.xml,
+	  inst/tests/testxml/general/TestFunctionLL.xml,
+	  inst/tests/testxml/general/TestFunctionLLPrec.xml,
+	  inst/tests/testxml/general/TestFunctionPA.xml,
+	  inst/tests/testxml/general/TestFunctionPL.xml,
+	  inst/tests/testxml/general/TestFunctionPLPrec.xml,
+	  inst/tests/testxml/general/TestFunctionPP.xml,
+	  inst/tests/testxml/general/TestInteriorPoint.xml,
+	  inst/tests/testxml/general/TestRectanglePredicate.xml,
+	  inst/tests/testxml/general/TestRelateAA.xml,
+	  inst/tests/testxml/general/TestRelateAC.xml,
+	  inst/tests/testxml/general/TestRelateLA.xml,
+	  inst/tests/testxml/general/TestRelateLC.xml,
+	  inst/tests/testxml/general/TestRelateLL.xml,
+	  inst/tests/testxml/general/TestRelatePA.xml,
+	  inst/tests/testxml/general/TestRelatePL.xml,
+	  inst/tests/testxml/general/TestRelatePP.xml,
+	  inst/tests/testxml/general/TestSimple.xml,
+	  inst/tests/testxml/general/TestValid.xml,
+	  inst/tests/testxml/general/TestValid2-big.xml,
+	  inst/tests/testxml/general/TestValid2.xml,
+	  inst/tests/testxml/general/TestWithinDistance.xml: tidy
+
+2013-01-31 16:45  rsbivand
+
+	* inst/tests/testxml/general: tidy
+
+2013-01-16 09:03  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2013-01-16 09:02  rsbivand
+
+	* DESCRIPTION, R/AAA.R: move startup message to .onAttach
+
+2012-12-18 14:10  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-12-18 14:09  rsbivand
+
+	* DESCRIPTION: tidy
+
+2012-12-08 17:29  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-12-08 16:53  rsbivand
+
+	* R/AAA.R: versions in startup messages
+
+2012-12-08 16:50  rsbivand
+
+	* R/AAA.R: versions in startup messages
+
+2012-12-08 16:47  rsbivand
+
+	* configure, configure.ac: versions in configure
+
+2012-12-03 20:27  rsbivand
+
+	* R/AAA.R: tidy
+
+2012-11-20 20:13  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-11-20 20:09  rsbivand
+
+	* DESCRIPTION: cumulation change in rgeos_binarytopologyfunc to
+	  avoid collection in collection error
+
+2012-11-20 19:21  rsbivand
+
+	* src/rgeos_topology_binary.c: cumulation change in
+	  rgeos_binarytopologyfunc to avoid collection in collection error
+
+2012-11-12 09:30  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-11-12 08:00  rsbivand
+
+	* R/gpc_geos.R: adding conversion of a NULL to gpc.poly
+
+2012-11-11 19:01  rsbivand
+
+	* DESCRIPTION, R/Rgpc_funcs.R: adding conversion of a NULL to
+	  gpc.poly
+
+2012-11-05 17:30  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-11-05 17:30  rsbivand
+
+	* man/comment-functions.Rd: dontrun part of check holes example
+
+2012-11-05 08:56  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-11-05 08:55  rsbivand
+
+	* DESCRIPTION: tidy
+
+2012-09-30 18:05  edzer
+
+	* DESCRIPTION, NAMESPACE, R/rgeos_wkt.R: removed dependency on
+	  stringr and plyr, replaced two str_ function
+	  calls with the equivalent ones in base R.
+
+2012-09-06 09:30  rsbivand
+
+	* inst/wkts, inst/wkts/sline1.wkt, inst/wkts/sline2.wkt,
+	  man/utility-functions.Rd: setScale example from Mao-Gui Hu
+
+2012-08-19 13:07  edzer
+
+	* NAMESPACE, R/labelpt.R, man/labelpt.Rd: update function name;
+	  cosmetics.
+
+2012-08-17 20:20  edzer
+
+	* DESCRIPTION, NAMESPACE, R/labelpt.R, man/labelpt.Rd: added first
+	  attempt to label points functions, that evolved from
+	  https://stat.ethz.ch/pipermail/r-sig-geo/2012-July/015693.html ;
+	  edited author at R section to DESCRIPTION.
+
+2012-06-24 14:41  rsbivand
+
+	* DESCRIPTION, src/rgeos.c, src/rgeos.h, src/rgeos_R2geosMP.c,
+	  src/rgeos_coord.c, src/rgeos_poly2nb.c: remove some -Wall
+	  warnings
+
+2012-06-24 13:28  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-06-24 13:27  rsbivand
+
+	* DESCRIPTION, src/dummy.cc, src/local_stubs.c: adding src/dummy.cc
+
+2012-05-07 16:48  rsbivand
+
+	* DESCRIPTION, src/rgeos_misc.c: fixed single geometry bug in
+	  gDistance
+
+2012-05-02 09:58  rsbivand
+
+	* ChangeLog, inst/ChangeLog: more configure updates
+
+2012-05-02 09:58  rsbivand
+
+	* configure, configure.ac: more configure updates
+
+2012-04-24 10:56  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-04-24 10:54  rsbivand
+
+	* configure, configure.ac: tidying configure.ac
+
+2012-04-22 11:42  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-04-22 11:42  rsbivand
+
+	* DESCRIPTION: add plyr dependency
+
+2012-04-20 08:32  rsbivand
+
+	* configure, configure.ac: tidy
+
+2012-04-20 07:06  rsbivand
+
+	* R/AAA.R: tidy
+
+2012-04-20 07:01  rsbivand
+
+	* DESCRIPTION: tidy
+
+2012-04-20 07:01  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-04-20 07:00  rsbivand
+
+	* configure, configure.ac, configure.in, src/Makevars.in: upgrading
+	  configure
+
+2012-04-19 13:20  rsbivand
+
+	* inst/tests/test-translate-polygon-collection.R,
+	  src/rgeos_geos2R.c: fixed broken tests
+
+2012-04-17 13:38  rsbivand
+
+	* DESCRIPTION, inst/tests/test-translate-polygons.R,
+	  src/rgeos_geos2R.c: broken tests
+
+2012-04-16 13:21  rsbivand
+
+	* R/rgeos_util.R: using top-level comment to SpatialPolygons for
+	  all member Polygons commented with OGC SFS kludge
+
+2012-04-16 13:13  rsbivand
+
+	* DESCRIPTION, R/rgeos_misc.R, R/rgeos_predicate_binary.R,
+	  R/rgeos_predicate_unary.R, R/rgeos_topology.R,
+	  R/rgeos_topology_binary.R, R/rgeos_util.R: using top-level
+	  comment to SpatialPolygons for all member Polygons commented with
+	  OGC SFS kludge
+
+2012-03-17 15:08  rsbivand
+
+	* ChangeLog, DESCRIPTION, inst/ChangeLog: tidy
+
+2012-03-16 18:53  crundel
+
+	* src/rgeos_R2geos.c: Fixed crashing bug when ignoring holes with
+	  unknown parent poly
+
+2012-03-16 14:46  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-03-16 11:54  rsbivand
+
+	* DESCRIPTION, R/rgeos_misc.R: added createSPComment to
+	  RGEOSMiscFunc
+
+2012-02-22 17:00  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-02-22 16:59  rsbivand
+
+	* DESCRIPTION: tidy
+
+2012-01-30 10:44  rsbivand
+
+	* DESCRIPTION, R/rgeos_topology.R: revise gLineMerge
+
+2012-01-27 12:31  rsbivand
+
+	* man/topo-bin-gUnion.Rd: fix documentation
+
+2012-01-20 10:12  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-01-19 19:25  rsbivand
+
+	* src/rgeos_poly2nb.c: fixing gBinarySTRtreeQuery
+
+2012-01-19 19:08  rsbivand
+
+	* man/experimental-functions.Rd, src/rgeos_poly2nb.c: fixing
+	  gBinarySTRtreeQuery
+
+2012-01-18 19:11  rsbivand
+
+	* DESCRIPTION, src/rgeos_poly2nb.c: fixing gBinarySTRtreeQuery
+
+2012-01-15 13:12  rsbivand
+
+	* ChangeLog, DESCRIPTION, inst/ChangeLog: tidy
+
+2012-01-15 11:37  edzer
+
+	* DESCRIPTION, src/rgeos_predicate_binary.c: added r-forge URL to
+	  DESCRIPTION
+	  added type casts to remove compilation warnings
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_geos2R.c: Cleanup
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_topology.c, src/rgeos_topology_binary.c: Cleanup and
+	  memory leak
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_R2geos.c: memory leak
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_predicate_binary.c, src/rgeos_predicate_unary.c:
+	  cleanup
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_geos2R.c: Small memory leak
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_bbox.c: Fixing what I broke
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_geos2R.c: Cleanup
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_R2geos.c, src/rgeos_R2geosMP.c: Cleanup and moved
+	  multipoint functions to new source file
+
+2012-01-15 09:58  crundel
+
+	* inst/tests/process_testxml.R, inst/tests/test-jts-xml.R: Break up
+	  XML test runner to allow for separate testing
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_bbox.c: Should function for all geometry types now
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos.h, src/rgeos_coord.c: Fixed const correctness for
+	  coordSequence
+
+2012-01-15 09:58  crundel
+
+	* src/gpc_geos.c, src/init.c, src/rgeos.h: Removed gpc_geos
+	  functions since we arn't using them
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos.h: cleanup
+
+2012-01-15 09:58  crundel
+
+	* src/gpc_geos.c, src/rgeos.h: Lots of cleaning and minor
+	  refactoring, changes have not been tested since we don't
+	  currently use any of this functionality
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_coord.c: cleanup
+
+2012-01-15 09:58  crundel
+
+	* src/rgeos_geos2R.c: cleanup
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_R2geos.c: cleanup
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_R2geos.c: Don't use the handle here
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_R2geos.c: Removed unused scale variable
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_R2geos.c: Cleaned tabs
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_topology.c: More cleanup, removed unused curtype
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_topology.c: Cleanup and switch to use just one call to
+	  GEOSGeomTypeId_r
+
+2012-01-15 09:57  crundel
+
+	* src/rgeos_geos2R.c: Cleaning tabs
+
+2012-01-13 00:02  crundel
+
+	* src/rgeos_geos2R.c: Cleanup and memory leak fix
+
+2012-01-13 00:02  crundel
+
+	* src/rgeos_geos2R.c: Cleanup
+
+2012-01-13 00:02  crundel
+
+	* inst/tests/test-translate-lines.R,
+	  inst/tests/test-translate-points.R,
+	  inst/tests/test-translate-polygon-collection.R,
+	  inst/tests/test-translate-polygons.R,
+	  inst/tests/test-translate-rings.R, inst/tests/test-translate.R:
+	  Break up translate tests into separate files
+
+2012-01-09 07:59  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-01-08 21:42  edzer
+
+	* src/rgeos_geos2R.c: one more memory leak fixed.
+
+2012-01-08 19:46  edzer
+
+	* DESCRIPTION, src/rgeos_bbox.c, src/rgeos_poly2nb.c,
+	  src/rgeos_validate.c: version bump; fixed more memory leaks.
+
+2012-01-07 13:22  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2012-01-06 23:20  edzer
+
+	* src/rgeos_buffer.c, src/rgeos_geos2R.c: further memory release
+	  hunting...
+
+2012-01-06 18:31  edzer
+
+	* DESCRIPTION, src/rgeos_R2geos.c, src/rgeos_buffer.c,
+	  src/rgeos_coord.c, src/rgeos_geos2R.c, src/rgeos_topology.c,
+	  src/rgeos_wkt.c: version bump; hunt for memory leaks.
+
+2012-01-05 22:07  edzer
+
+	* src/rgeos_buffer.c: un-commented the GEOS_destroy_r() commands in
+	  buffer, after adding conditions.
+
+2012-01-02 09:06  rsbivand
+
+	* ChangeLog, inst/ChangeLog: avoid gpclib suggest via maptools
+
+2012-01-02 09:05  rsbivand
+
+	* DESCRIPTION, man/gpc-new-generics.Rd: avoid gpclib suggest via
+	  maptools
+
+2011-12-14 09:11  rsbivand
+
+	* ChangeLog, inst/ChangeLog: revert destroy in R2geos.c
+
+2011-12-14 09:10  rsbivand
+
+	* DESCRIPTION, src/rgeos_R2geos.c: revert destroy in R2geos.c
+
+2011-12-10 11:37  rsbivand
+
+	* ChangeLog, inst/ChangeLog: clear stringr 0.6 mess
+
+2011-12-10 11:36  rsbivand
+
+	* DESCRIPTION, src/rgeos_R2geos.c: clear stringr 0.6 mess
+
+2011-12-10 07:44  crundel
+
+	* R/rgeos_wkt.R: Changed str_match_all to str_extract_all
+
+2011-12-09 22:04  crundel
+
+	* tests/test-all.R: use test_package from testthat instead of
+	  test_file
+
+2011-12-09 22:04  crundel
+
+	* R/rgeos_wkt.R: Fix to address small change in return type from
+	  stringr str_match_all function
+
+2011-11-28 14:55  rsbivand
+
+	* src/rgeos_buffer.c: moved curgeom inside loop
+
+2011-11-18 03:57  crundel
+
+	* src/rgeos_topology_binary.c: Fix returned id for binary topology
+	  operations
+
+2011-11-14 18:39  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-11-14 18:38  rsbivand
+
+	* DESCRIPTION, configure, configure.in, src/init.c, src/rgeos.h,
+	  src/rgeos_topology.c: move HAVE_UNARYUNION to rgeos.h
+
+2011-11-14 10:55  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-11-10 07:43  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-11-09 10:51  rsbivand
+
+	* DESCRIPTION, src/rgeos_topology_binary.c: drop empty objects
+	  before building Geometry Collection in binary topology ops
+
+2011-10-30 18:59  rsbivand
+
+	* DESCRIPTION, man/topo-unary-gSimplify.Rd, src/gpc_geos.c,
+	  src/rgeos_buffer.c, src/rgeos_geos2R.c: tickling destroy
+
+2011-10-25 21:22  crundel
+
+	* DESCRIPTION: Require stringr >= 0.5
+
+2011-10-19 19:20  rsbivand
+
+	* src/gpc_geos.c, src/rgeos_geos2R.c: add space character for
+	  safety in comment
+
+2011-10-19 18:52  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-10-19 18:51  rsbivand
+
+	* DESCRIPTION, src/gpc_geos.c, src/local_stubs.c,
+	  src/rgeos_geos2R.c: fix comment string length
+
+2011-09-16 07:24  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-09-16 07:22  rsbivand
+
+	* DESCRIPTION: tidy
+
+2011-09-05 12:35  rsbivand
+
+	* src/rgeos_poly2nb.c: STRtree loop simplification (strcmp before
+	  loop)
+
+2011-09-05 08:07  rsbivand
+
+	* src/rgeos_poly2nb.c: STRtree loop simplification (strcmp before
+	  loop)
+
+2011-09-04 18:29  rsbivand
+
+	* R/rgeos_util.R, src/rgeos_poly2nb.c: callback corrections
+
+2011-09-03 14:34  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, R/rgeos_spExtensions_Classes.R,
+	  src/rgeos_buffer.c, src/rgeos_wkt.c: changed dependency load
+	  syntax
+
+2011-09-03 03:32  crundel
+
+	* src/rgeos_poly2nb.c: Cleanup of build warnings from using
+	  callback pointer
+
+2011-09-03 03:32  crundel
+
+	* src/rgeos.h, src/rgeos_misc.c, src/rgeos_predicate_binary.c,
+	  src/rgeos_predicate_unary.c, src/rgeos_topology.c,
+	  src/rgeos_topology_binary.c: Cleanup of build warnings from
+	  function pointers
+
+2011-06-11 06:59  rsbivand
+
+	* ChangeLog, inst/ChangeLog: touch local_stubs.c
+
+2011-06-11 06:59  rsbivand
+
+	* src/local_stubs.c: touch local_stubs.c
+
+2011-06-11 05:26  rsbivand
+
+	* ChangeLog, inst/ChangeLog: permit NA IDs in union
+
+2011-06-11 05:25  rsbivand
+
+	* R/rgeos_topology.R: permit NA IDs in union
+
+2011-06-10 22:06  rsbivand
+
+	* DESCRIPTION, R/rgeos_topology.R, configure.in,
+	  man/topo-bin-gUnion.Rd, src/gpc_geos.c, src/rgeos_geos2R.c: sp
+	  comment buffer overflow fix
+
+2011-06-09 14:04  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2011-06-09 13:55  rsbivand
+
+	* DESCRIPTION: update sp version
+
+2011-06-09 08:23  rsbivand
+
+	* R/rgeos_topology.R, man/topo-bin-gUnion.Rd: gUnionCascaded
+	  suggestion
+
+2011-06-09 06:21  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, R/rgeos_topology.R, configure,
+	  configure.in, man/pred-binary-gTouches.Rd,
+	  man/topo-bin-gUnion.Rd, man/utility-functions.Rd, src/init.c,
+	  src/rgeos.h, src/rgeos_topology.c: adding UnaryUnion for GEOS
+	  3.3.0
+
+2011-05-24 16:15  rsbivand
+
+	* DESCRIPTION: added version to GEOS required
+
+2011-05-24 11:27  edzer
+
+	* DESCRIPTION: increased dependency on sp 0.9-73, which has over
+	  defined as generic.
+
+2011-05-18 21:07  rsbivand
+
+	* ChangeLog, inst/ChangeLog: RGEOSBinPredFunc single argument fix
+
+2011-05-18 21:06  rsbivand
+
+	* R/rgeos_predicate_binary.R, R/rgeos_predicate_unary.R,
+	  R/rgeos_topology.R, R/rgeos_topology_binary.R: RGEOSBinPredFunc
+	  single argument fix
+
+2011-05-18 20:53  rsbivand
+
+	* ChangeLog, inst/ChangeLog: RGEOSBinPredFunc single argument fix
+
+2011-05-18 20:49  rsbivand
+
+	* DESCRIPTION, R/rgeos_predicate_binary.R: RGEOSBinPredFunc single
+	  argument fix
+
+2011-05-11 12:49  edzer
+
+	* R/over.R: improved over methods for gridded objects
+
+2011-05-09 20:31  edzer
+
+	* R/over.R: added the lines & (grids / pixels) methods for "over"
+	  overlay.
+
+2011-05-09 16:50  edzer
+
+	* DESCRIPTION, R/over.R: added 18 overlay methods for "over" (from
+	  sp)
+
+2011-03-30 14:42  rsbivand
+
+	* ChangeLog, inst/ChangeLog: attempts to limit memory hunger
+
+2011-03-30 14:40  rsbivand
+
+	* R/AAA.R, R/rgeos_util.R, src/rgeos_poly2nb.c,
+	  src/rgeos_predicate_binary.c, src/rgeos_predicate_unary.c:
+	  attempts to limit memory hunger
+
+2011-03-29 08:25  rsbivand
+
+	* DESCRIPTION, R/rgeos_util.R, man/experimental-functions.Rd,
+	  man/topo-bin-gIntersection.Rd, src/rgeos.h, src/rgeos_R2geos.c,
+	  src/rgeos_poly2nb.c: STRtree for Polygons
+
+2011-03-28 09:40  rsbivand
+
+	* ChangeLog, inst/ChangeLog: documenting hole checking for Polygons
+	  objects
+
+2011-03-28 09:39  rsbivand
+
+	* R/AAA.R: documenting hole checking for Polygons objects
+
+2011-03-28 09:29  rsbivand
+
+	* ChangeLog, inst/ChangeLog: documenting hole checking for Polygons
+	  objects
+
+2011-03-28 09:28  rsbivand
+
+	* DESCRIPTION, configure, configure.in, man/comment-functions.Rd:
+	  documenting hole checking for Polygons objects
+
+2011-03-26 19:41  rsbivand
+
+	* R/rgeos_buffer.R, R/rgeos_misc.R: adding projection check for
+	  buffer and misc
+
+2011-03-26 19:29  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, R/rgeos_buffer.R,
+	  R/rgeos_misc.R, R/rgeos_predicate_binary.R,
+	  R/rgeos_predicate_unary.R, R/rgeos_topology.R,
+	  R/rgeos_topology_binary.R, R/rgeos_util.R,
+	  man/comment-functions.Rd, src/rgeos_geos2R.c, tests/test-all.R:
+	  imposing polygon checking unless option set
+
+2011-03-21 10:13  rsbivand
+
+	* ChangeLog, inst/ChangeLog: prerelease
+
+2011-03-21 09:04  rsbivand
+
+	* ChangeLog, inst/ChangeLog: prerelease
+
+2011-03-21 09:03  rsbivand
+
+	* DESCRIPTION: prerelease
+
+2011-02-26 23:03  rsbivand
+
+	* inst/tests/test-jts-xml.R: xml file reading wrapper for 32-bit
+	  libxml2 on F14 in tests
+
+2011-02-06 14:58  rsbivand
+
+	* R/AAA.R: suppress startup messages
+
+2010-11-30 17:38  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2010-11-24 12:31  rsbivand
+
+	* R/rgeos_topology.R, R/rgeos_util.R, man/topo-bin-gUnion.Rd:
+	  g*STRtreeQuery added to experimental
+
+2010-11-24 10:44  rsbivand
+
+	* man/experimental-functions.Rd: g*STRtreeQuery added to
+	  experimental
+
+2010-11-24 10:39  rsbivand
+
+	* ChangeLog, inst/ChangeLog: g*STRtreeQuery added to experimental
+
+2010-11-24 10:39  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/rgeos_util.R,
+	  man/experimental-functions.Rd, src/rgeos_poly2nb.c:
+	  g*STRtreeQuery added to experimental
+
+2010-11-19 21:56  rsbivand
+
+	* .Rbuildignore: add rgeos_unary_STRtree_query and
+	  rgeos_binary_STRtree_query
+
+2010-11-19 21:54  rsbivand
+
+	* src/init.c, src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_poly2nb.c:
+	  add rgeos_unary_STRtree_query and rgeos_binary_STRtree_query
+
+2010-11-19 13:18  rsbivand
+
+	* src/rgeos_poly2nb.c: STRtree attempts
+
+2010-11-18 23:07  crundel
+
+	* inst/tests/testxml/vivid: Removing empty folder
+
+2010-11-08 20:43  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2010-11-08 20:42  rsbivand
+
+	* DESCRIPTION: tidy
+
+2010-11-08 20:39  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2010-11-08 20:05  crundel
+
+	* inst/poly-ex-gpc, inst/poly-ex-gpc/ex-poly1.txt,
+	  inst/poly-ex-gpc/ex-poly2.txt, inst/poly-ex-gpc/hole-poly.txt:
+	  Added gpc polygon example data files
+
+2010-11-08 20:02  crundel
+
+	* data, man/class-gpc.poly.Rd, man/experimental-functions.Rd: More
+	  clean up
+
+2010-11-08 19:44  crundel
+
+	* DESCRIPTION, inst/tests/test-jts-xml.R, man,
+	  man/class-gpc.poly.Rd, tests, tests/test-all.R: Package clean up
+	  for release
+
+2010-11-07 19:38  rsbivand
+
+	* ChangeLog, inst/ChangeLog: tidy
+
+2010-11-07 19:18  rsbivand
+
+	* configure.win, src/Makevars.win: Windows static build
+
+2010-11-01 18:02  crundel
+
+	* R/rgeos_misc.R, src/rgeos_R2geos.c: Fixed a bug in handling
+	  polygons with holes but no comment.
+
+2010-09-29 17:51  crundel
+
+	* NAMESPACE, R/rgeos_util.R:
+
+2010-09-26 20:29  crundel
+
+	* R/rgeos_util.R, src/rgeos_R2geos.c, tests/test-all.R: Small fixes
+	  to get CHECK to work
+
+2010-09-09 20:47  crundel
+
+	* src/rgeos_R2geos.c: Changed translate functions so that
+	  unassigned holes are ignored and a warning reported.
+
+2010-09-09 19:56  crundel
+
+	* NAMESPACE, R/gpc_geos.R, R/rgeos.R, R/rgeos_util.R,
+	  man/checkHolesGPC.Rd, man/checkPolygonsGEOS.Rd,
+	  man/comment-functions.Rd, src/init.c, src/rgeos.h,
+	  src/rgeos_R2geos.c, src/rgeos_validate.c: Removed
+	  checkPolygonsGEOS and checkHolesGPC functions and replaced then
+	  with createPolygonsComment and createSPComment functions. Similar
+	  functionality, but removes guessing of hole status for polygons
+	  and focuses on assign ownership via comment attributes.
+
+2010-08-16 12:36  crundel
+
+	* src/rgeos_predicate_binary.c: Added const to prepared geometry to
+	  deal with compiler warning
+
+2010-08-16 12:34  crundel
+
+	* man/pred-binary-gEquals.Rd, man/pred-binary-gRelate.Rd: Small
+	  docs typo fix
+
+2010-08-16 12:31  crundel
+
+	* inst/tests/test-jts-xml.R, tests/test-all.R: Small test fixes
+	  
+	  Some of the tests in the JTS xml files are skipped due to
+	  compatibility issues, see descSkip
+
+2010-08-16 12:27  crundel
+
+	* R/rgeos_predicate_binary.R, man/pred-binary-gEquals.Rd,
+	  man/pred-binary-gRelate.Rd, man/pred-unary-gIsSimple.Rd,
+	  man/pred-unary-gIsValid.Rd, man/topo-unary-gSimplify.Rd: Small
+	  documentation fixes
+	  
+	  Put tol and pattern as 3rd arguments in gEquals and gRelate
+
+2010-08-16 11:46  crundel
+
+	* man/misc-gDistance.Rd, man/pred-binary-gContains.Rd,
+	  man/pred-binary-gCrosses.Rd, man/pred-binary-gEquals.Rd,
+	  man/pred-binary-gIntersects.Rd, man/pred-binary-gRelate.Rd,
+	  man/pred-binary-gTouches.Rd, man/pred-unary-gIsSimple.Rd,
+	  man/pred-unary-gIsValid.Rd, man/topo-bin-gDifference.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gSymdifference.Rd,
+	  man/topo-bin-gUnion.Rd, man/topo-unary-gBoundary.Rd,
+	  man/topo-unary-gCentroid.Rd, man/topo-unary-gConvexHull.Rd,
+	  man/topo-unary-gEnvelope.Rd, man/topo-unary-gPointOnSurface.Rd,
+	  man/topo-unary-gPolygonize.Rd, man/topo-unary-gSimplify.Rd:
+	  Documentation update
+
+2010-08-16 11:45  crundel
+
+	* NAMESPACE: Commented out poly_findInBoxGEOS
+
+2010-08-16 10:25  crundel
+
+	* R/rgeos_topology.R: Simplified function arguments for gSimplify
+	  since byid doesnt really matter.
+
+2010-08-16 09:10  crundel
+
+	* R/rgeos_spExtensions_Methods.R: Added isGenerics checks for
+	  row.names and row.names<-
+
+2010-08-16 09:09  crundel
+
+	* NAMESPACE, R/rgeos_predicate_binary.R: Separated Equals and
+	  EqualsExact back into different functions, had misunderstood how
+	  they worked.
+	  
+	  Removed groupID from NAMESPACE for the time being, probably needs
+	  to be reimplemented in C.
+
+2010-08-15 13:46  crundel
+
+	* man/misc-gArea.Rd, man/misc-gBuffer.Rd, man/misc-gDistance.Rd,
+	  man/misc-gLength.Rd, man/pred-unary-gIsEmpty.Rd,
+	  man/pred-unary-gIsRing.Rd, man/pred-unary-gIsSimple.Rd,
+	  man/pred-unary-gIsValid.Rd, man/topo-bin-gUnion.Rd,
+	  man/topo-unary-gBoundary.Rd, man/topo-unary-gCentroid.Rd,
+	  man/topo-unary-gConvexHull.Rd, man/topo-unary-gEnvelope.Rd:
+	  Documentation update
+
+2010-08-15 13:44  crundel
+
+	* NAMESPACE, R/rgeos_buffer.R, R/rgeos_predicate_binary.R,
+	  src/init.c, src/rgeos.h, src/rgeos_predicate_binary.c: Fixed bug
+	  with gRelate when pattern was specified
+	  
+	  Combined gEquals and gEqualsExact functions by adding tol
+	  argument to gEquals
+	  
+	  Changed default of byid in gBuffer to FALSE for consistency
+
+2010-08-15 10:07  crundel
+
+	* R/rgeos_misc.R: Fixed bug, GEOSArea_r was being called by both
+	  gLength and gArea
+
+2010-08-15 10:06  crundel
+
+	* NAMESPACE: Removed reference for gHasZ, no use for the function
+	  currently as 3d geometries are not supported
+
+2010-08-15 10:05  crundel
+
+	* src/rgeos_predicate_unary.c: Cleaned up code / variable
+	  declarations
+
+2010-08-14 11:47  crundel
+
+	* man/pred-unary-gIsValid.Rd: Fixed extra line in example, and
+	  linearring example
+
+2010-08-14 10:51  crundel
+
+	* man/gpc-new-generics.Rd: Added alias to symdiff function
+
+2010-08-14 10:51  crundel
+
+	* NAMESPACE, R/rgeos_predicate_unary.R, inst/tests/test-jts-xml.R:
+	  Unary Predicate functions renamed
+
+2010-08-14 10:50  crundel
+
+	* man/pred-unary-gIsSimple.Rd, man/pred-unary-gIsValid.Rd,
+	  man/topo-unary-gBoundary.Rd, man/topo-unary-gCentroid.Rd,
+	  man/topo-unary-gConvexHull.Rd, man/topo-unary-gEnvelope.Rd,
+	  man/topo-unary-gPointOnSurface.Rd, man/wkt-functions.Rd:
+	  Documentation update
+
+2010-08-11 13:41  crundel
+
+	* R/rgeos_util.R, man/utility-functions.Rd: Small bugfix / typo fix
+
+2010-08-11 12:46  crundel
+
+	* NAMESPACE, R/rgeos_util.R, man/utility-functions.Rd: Utility
+	  function documentation
+	  
+	  Renamed argument in checkP4S to p4s for the sake of brevity
+
+2010-08-11 12:19  crundel
+
+	* NAMESPACE, R/rgeos_util.R, inst/tests/test-translate-empty.R,
+	  inst/tests/test-translate.R: Renamed function doubletranslate to
+	  translate
+
+2010-08-11 12:18  crundel
+
+	* man/checkHolesGPC.Rd: Removed empty documentation sections
+
+2010-08-11 12:14  crundel
+
+	* NAMESPACE, R/rgeos.R: Removed unused intersection functions
+
+2010-08-11 12:14  crundel
+
+	* man/gpc.poly-class.Rd, man/gpc.poly.nohole-class.Rd,
+	  man/new-generics.Rd, man/polyfile.Rd: Files renamed
+
+2010-08-11 12:13  crundel
+
+	* man/class-Ring.Rd, man/class-SpatialCollections.Rd,
+	  man/class-SpatialRings.Rd, man/class-SpatialRingsDataFrame.Rd,
+	  man/class-gpc.poly.Rd, man/class-gpc.poly.nohole.Rd,
+	  man/constructor-SpatialCollections.Rd,
+	  man/constructor-SpatialRings.Rd, man/gpc-new-generics.Rd,
+	  man/gpc-polyfile.Rd, man/topo-bin-gDifference.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gSymdifference.Rd,
+	  man/topo-bin-gUnion.Rd, man/topo-unary-gBoundary.Rd,
+	  man/topo-unary-gCentroid.Rd, man/topo-unary-gConvexHull.Rd,
+	  man/topo-unary-gEnvelope.Rd, man/topo-unary-gPointOnSurface.Rd:
+	  Documentation update, changed naming convention to keep things
+	  clear
+
+2010-08-10 18:04  crundel
+
+	* man/topo-bin-gUnion.Rd: Fixed function argument ordering in
+	  gLineMerge usage.
+
+2010-08-10 18:02  crundel
+
+	* man/topo-unary-gBoundary.Rd, man/topo-unary-gEnvelope.Rd,
+	  man/topo-unary-gPointOnSurface.Rd: Fixed incorrect function names
+	  in usage section
+
+2010-08-10 17:57  crundel
+
+	* tests/test-all.R: Fixed test path
+
+2010-08-10 17:56  crundel
+
+	* man/gpc.poly-class.Rd: Removed triangulate example
+
+2010-08-10 17:49  crundel
+
+	* man/gIntersection.Rd, man/gUnion.Rd, man/topo-bin-gDifference.Rd,
+	  man/topo-bin-gIntersection.Rd, man/topo-bin-gSymdifference.Rd,
+	  man/topo-bin-gUnion.Rd, man/topo-unary-gBoundary.Rd,
+	  man/topo-unary-gCentroid.Rd, man/topo-unary-gConvexHull.Rd,
+	  man/topo-unary-gEnvelope.Rd, man/topo-unary-gPointOnSurface.Rd:
+	  Preliminary documentation for all topology functions along with
+	  examples.
+	  
+	  Changed Rd file naming scheme for clarity
+
+2010-08-10 17:48  crundel
+
+	* R/rgeos_topology.R: Changed argument order for topology functions
+	  for the sake of consistency.
+
+2010-08-10 13:26  crundel
+
+	* R/rgeos_topology.R: Fixed bug in gPolygonizer
+
+2010-08-10 13:24  crundel
+
+	* man/gpc.poly-class.Rd, man/gpc.poly.nohole-class.Rd,
+	  man/new-generics.Rd, man/polyfile.Rd: Updated documentation files
+	  for gpcpoly functions
+
+2010-07-27 06:08  crundel
+
+	* inst/tests/test-jts-xml.R: Fixed (working) version of jts xml
+	  test processing
+
+2010-07-27 05:15  crundel
+
+	* inst/tests/test-translate-empty.R, inst/tests/test-translate.R:
+	  Added setScale() call to begin of each set of tests to reset
+	  scale option (changed by some of the JTS tests)
+
+2010-07-27 05:14  crundel
+
+	* NAMESPACE, R/rgeos_predicate_binary.R, src/init.c, src/rgeos.h,
+	  src/rgeos_predicate_binary.c: Added prepared geometry functions -
+	  gContainsProperly, gCovers, gCoveredBy and prepared variants of
+	  gIntersects and gContains specified by a flag.
+
+2010-07-27 05:04  crundel
+
+	* R/rgeos_util.R: Fixed bug, extra ) in double translate
+
+2010-07-27 03:44  crundel
+
+	* inst/tests/test-empty-geom.R, inst/tests/test-translate-empty.R,
+	  inst/tests/test-translate.R: Changed phrasing of some of the
+	  tests in translate to make it easier to distinguish between
+	  similar tests.
+	  
+	  Renamed test-empty-geom.R to test-translate-empty.R
+
+2010-07-25 09:15  crundel
+
+	* R/rgeos_util.R, R/rgeos_wkt.R, src/rgeos_R2geos.c,
+	  src/rgeos_geos2R.c: Fixed bug in passing ids during translation
+
+2010-07-25 08:08  crundel
+
+	* R/rgeos_predicate_binary.R: Removed more leftover debug messaging
+
+2010-07-25 07:56  crundel
+
+	* R/rgeos_predicate_binary.R: Fixed bug in gRelate, still called
+	  RGEOSRelate and passed byid instead of pattern as 3rd argument
+
+2010-07-25 06:31  crundel
+
+	* src/rgeos_geos2R.c: Removed leftover debug messages
+
+2010-07-25 06:24  crundel
+
+	* inst/tests/test-empty-geom.R: Added test for GEOMETRYCOLLECTION
+	  EMPTY
+
+2010-07-25 06:23  crundel
+
+	* R/rgeos_wkt.R: Fixed bug to handle null geometries
+
+2010-07-25 06:22  crundel
+
+	* src/rgeos_R2geos.c, src/rgeos_geos2R.c: Fixed bugs handling empty
+	  geometries, collections were getting turned into nulls. Now only
+	  GEOMETRYCOLLECTION EMPTY returns null.
+
+2010-07-24 07:03  crundel
+
+	* NAMESPACE, R/rgeos_topology.R, src/init.c, src/rgeos.h,
+	  src/rgeos_topology.c: Added gSimplify and gPolygonize
+	  functionality, no idea how the latter works
+
+2010-07-24 03:19  crundel
+
+	* src/rgeos_R2geos.c: Fixed bug in R2geos translate function for
+	  SpatialPoints object without row names.
+
+2010-07-19 18:17  crundel
+
+	* NAMESPACE, R/rgeos_spExtensions_Methods.R, R/rgeos_util.R,
+	  R/rgeos_wkt.R: Small fixes for handling SpatialCollections
+
+2010-07-19 06:28  crundel
+
+	* src/rgeos_R2geos.c, src/rgeos_geos2R.c: Initial implementation of
+	  translation of SpatialCollections classes to and from geos.
+
+2010-07-19 04:58  crundel
+
+	* R/rgeos_spExtensions_Methods.R: Fixed bug in SpatialCollections
+	  print method to use NA as default polygon color if col is not
+	  specified.
+
+2010-07-19 04:27  crundel
+
+	* R/rgeos_spExtensions_Methods.R: Fixed bug in SpatialCollections
+	  print method to have the proper range
+
+2010-07-19 04:17  crundel
+
+	* NAMESPACE: Export SpatialCollections classes and constructor
+
+2010-07-19 04:16  crundel
+
+	* R/rgeos_SpatialCollections.R, R/rgeos_SpatialRings.R,
+	  R/rgeos_SpatialRingsDataFrame.R, R/rgeos_spExtensions_Classes.R,
+	  R/rgeos_spExtensions_Methods.R: Combined SpatialCollections and
+	  SpatialRings extension classes into the same file
+	  (SpatialCollections depends on SpatialRings this way we can be
+	  sure that the latter is defined first)
+
+2010-07-19 01:46  crundel
+
+	* R/rgeos_SpatialCollections.R: Initial implementation of
+	  SpatialCollections with plot method missing additional helper
+	  methods
+
+2010-07-17 04:56  crundel
+
+	* R/Rgpc_funcs.R, R/gpc_geos.R, src/gpc_geos.c: Updated gpc
+	  replacement functions, added translation functions to and from
+	  gpc and sp
+
+2010-07-17 04:54  crundel
+
+	* man/LinesIntersections.Rd, man/gIntersection.Rd, man/gUnion.Rd,
+	  man/gpc.poly-class.Rd, man/thinnedSpatialPolyGEOS.Rd,
+	  man/unionSpatialPolygonsGEOS.Rd: Documentation update
+	  -removed thinnedSpatialPolyGEOS.Rd
+	  -replaced LinesIntersections.Rd with gIntersections.Rd
+	  -replaced unionSpatialPolygons.Rd with gUnion.Rd
+	  -removed unnecessary example from gpc.poly-class.Rd
+
+2010-07-17 04:51  crundel
+
+	* NAMESPACE, R/rgeos_buffer.R, R/rgeos_linearref.R, R/rgeos_misc.R,
+	  R/rgeos_predicate_binary.R, R/rgeos_predicate_unary.R,
+	  R/rgeos_topology.R, R/rgeos_topology_binary.R, src/init.c,
+	  src/rgeos.h, src/rgeos_coord.c, src/rgeos_misc.c,
+	  src/rgeos_predicate_binary.c, src/rgeos_topology_binary.c: Major
+	  Update
+	  
+	  switched from RGEOS prefix on functions to gFunction style. Old
+	  function names retained but with Deprecated warning. Removed "is"
+	  prefix from relevant functions
+	  
+	  Added binary topology functions (gUnion, gDifference, etc)
+	  
+	  Combined related functions (hausdorffdistance with distance etc)
+
+2010-07-12 19:00  rsbivand
+
+	* R/AAA.R, configure, configure.in: version
+
+2010-07-12 18:55  rsbivand
+
+	* inst/SVN_VERSION: version
+
+2010-07-12 18:32  rsbivand
+
+	* inst/SVN_VERSION: version
+
+2010-07-12 18:32  rsbivand
+
+	* inst/SVN_VERSION: version
+
+2010-07-12 18:29  rsbivand
+
+	* configure, configure.in: version
+
+2010-07-12 18:24  rsbivand
+
+	* R/AAA.R, configure, configure.in: version
+
+2010-07-10 17:57  rsbivand
+
+	* NAMESPACE: fixed NAMESPACE
+
+2010-07-10 07:05  crundel
+
+	* R/rgeos_wkt.R, src/rgeos_geos2R.c: Fixes for handling
+	  GEOMETRYCOLLECTION EMPTY, now
+	  returns NULL
+
+2010-07-08 21:24  crundel
+
+	* inst/tests/test-empty-geom.R: Bug fix - misnamed variabel
+
+2010-07-08 21:19  crundel
+
+	* R/rgeos_buffer.R, R/rgeos_topology.R, R/rgeos_wkt.R, src/init.c,
+	  src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_buffer.c,
+	  src/rgeos_geos2R.c, src/rgeos_topology.c, src/rgeos_wkt.c:
+	  Removed all references to threshold in geos2R translate functions
+	  and calling functions
+
+2010-07-08 21:17  crundel
+
+	* man/LinesIntersections.Rd, man/thinnedSpatialPolyGEOS.Rd:
+	  Commented out current broken function calls
+
+2010-07-08 21:05  crundel
+
+	* R/rgeos_SpatialRingsDataFrame.R: Small bug fix in
+	  chFIDsSpatialRingsDataFrame
+
+2010-07-08 20:52  crundel
+
+	* R/rgeos_simplify.R, R/rgeos_union.R, src/rgeos_sp.c: Removed
+	  files, functionality will be replicated elsewhere
+
+2010-07-08 20:17  crundel
+
+	* inst/tests/test-empty-geom.R: Updated unit tests for handling
+	  empty geometries (added polygons and a few small fixes)
+
+2010-07-08 20:16  crundel
+
+	* src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_coord.c,
+	  src/rgeos_geos2R.c, src/rgeos_sp.c: Renamed functions for parsing
+	  polygons to and from geos and R to be more consistent
+	  
+	  Added handling for empty polygons to translate functions
+	  
+	  Removed thresholding from R2geos polygon translation functions.
+	  Will re-implement as a separate function.
+	  
+	  FIXME - remove threshold parameter from function calls
+	  
+	  Added rgeos_Pt2xy coordinate function for getting x and y
+	  coordinates from a geos point
+	  
+	  Added rgeos_crdMatFixDir which ensures coordinate direction is
+	  correct in a coordinate matrix depending of if it is a hole or
+	  not
+
+2010-07-08 20:10  crundel
+
+	* R/rgeos_SpatialRings.R: Fixed Ring class constructor to check the
+	  direction of points, if not CW then reverses them.
+
+2010-06-27 22:25  crundel
+
+	* inst/tests/test-empty-geom.R: Unit tests for empty geometries and
+	  their translations
+
+2010-06-27 07:49  crundel
+
+	* src/init.c, src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_coord.c:
+	  Separated LinearRing translate functions from Linestring
+	  functions
+	  Fixed R2geos translation of empty geometries
+
+2010-06-26 22:24  crundel
+
+	* NAMESPACE: Export class constructor functions
+
+2010-06-26 22:23  crundel
+
+	* inst/tests/test-translate.R, src/rgeos_R2geos.c,
+	  src/rgeos_geos2R.c: Translate functions for SpatialRings, fixed
+	  translate unit tests to use the proper class.
+
+2010-06-26 22:23  crundel
+
+	* R/rgeos_buffer.R, R/rgeos_misc.R, R/rgeos_predicate_unary.R,
+	  R/rgeos_topology.R, R/rgeos_util.R: Removed extractIDs function,
+	  uses row.names instead
+
+2010-06-26 18:54  crundel
+
+	* src/rgeos_geos2R.c: Initial handling of empty points and empty
+	  linestrings proof of concept (probably doesn't play well with
+	  existing sp methods)
+
+2010-06-26 18:50  crundel
+
+	* src/rgeos_coord.c: Cleaned code
+
+2010-06-26 18:44  crundel
+
+	* src/rgeos_bbox.c: Cleaned code
+
+2010-06-26 18:42  crundel
+
+	* NAMESPACE, R/rgeos_SpatialRings.R,
+	  R/rgeos_SpatialRingsDataFrame.R: Initial implementation of
+	  SpatialRings and SpatialRingsDataFrame classes based on
+	  SpatialLines
+
+2010-06-26 18:41  crundel
+
+	* R/rgeos_wkt.R: changed readWKT, let GEOS do all parsing/checking
+	  of WKTs instead of trying to sort it out in R.
+
+2010-06-26 02:04  crundel
+
+	* src/rgeos_R2geos.c: Cleaned up c code, no changes in
+	  functionality
+
+2010-06-21 02:36  crundel
+
+	* tests/.Rhistory: Removed .Rhistory
+
+2010-06-15 17:13  rsbivand
+
+	* R/AAA.R: keyword on load
+
+2010-06-15 17:10  rsbivand
+
+	* ChangeLog, inst/ChangeLog: keyword on load
+
+2010-06-15 17:09  rsbivand
+
+	* R/AAA.R: keyword on load
+
+2010-06-14 05:30  crundel
+
+	* src/rgeos_bbox.c, src/rgeos_buffer.c, src/rgeos_coord.c,
+	  src/rgeos_misc.c, src/rgeos_wkt.c: Cleaned c code formatting
+
+2010-06-12 20:38  crundel
+
+	* src/rgeos_area.c, src/rgeos_geos2R.c: Cleaned code in
+	  rgeos_LinearRingPolygon removed dependence on rgeos_csArea. Uses
+	  GEOSArea_r now. Should be slightly faster.
+	  
+	  Removed rgeos_area.c (rgeos_csArea only referenced in
+	  rgeos_LinearRingPolygon)
+
+2010-06-12 19:48  crundel
+
+	* src/rgeos.c, src/rgeos.h: Cleaned code in rgeos.c
+
+2010-06-10 00:50  crundel
+
+	* R/rgeos_misc.R, R/rgeos_predicate_binary.R, src/rgeos_misc.c,
+	  src/rgeos_predicate_binary.c: Modified Binary predicate functions
+	  and distance functions to allow byid to be of length 2 to
+	  indicate if one geometry should be processed by id and the other
+	  not.
+
+2010-06-09 23:25  crundel
+
+	* NAMESPACE: Forgot to add groupID to NAMESPACE
+
+2010-06-09 23:22  crundel
+
+	* NAMESPACE, R/rgeos_topology.R, R/rgeos_util.R,
+	  man/unionSpatialPolygonsGEOS.Rd, src/init.c, src/rgeos.h,
+	  src/rgeos_sp.c, src/rgeos_topology.c: Added RGEOSUnionCascaded,
+	  replicates unionSpatialPolygonsGEOS functionality but is
+	  currently slower.
+	  
+	  Added groupID utility function which restructures a SP object
+	  based on newly assigned IDs, subobjects with the same ID are
+	  grouped together. General solution to the need to flatten
+	  SpatialPolygons for use with RGEOSUnionCascaded, but may be too
+	  slow for practical use.
+
+2010-06-07 09:02  rsbivand
+
+	* inst/ChangeLog: update changelog
+
+2010-06-07 08:54  rsbivand
+
+	* ChangeLog: update changelog
+
+2010-06-07 08:28  rsbivand
+
+	* DESCRIPTION, NAMESPACE, src/gpc_geos.c, src/init.c,
+	  src/rgeos_coord.c, src/rgeos_sp.c: tidying up to run CMD check
+
+2010-06-07 05:01  crundel
+
+	* src/rgeos_topology_binary.c:
+
+2010-06-07 04:28  crundel
+
+	* src/rgeos_R2geos.c: Handles Spatial DataFrame classes, currently
+	  just ignores the data frame
+
+2010-06-07 02:51  crundel
+
+	* R/rgeos_topology_binary.R, R/rgeos_topology_relation.R: Renamed
+	  rgeos_topology_relation to rgeos_topology_binary
+
+2010-06-06 05:48  crundel
+
+	* src/rgeos_topology.c: Fixed error message typos (referred to
+	  wrong parent function)
+
+2010-06-06 05:37  crundel
+
+	* R/rgeos_predicate_binary.R, R/rgeos_topology_relation.R,
+	  src/init.c, src/rgeos.h, src/rgeos_predicate_binary.c,
+	  src/rgeos_predicate_unary.c: Fixed issue with argument number
+	  mismatch in binary predicate function.
+	  
+	  Binary predicate functions take into account when the result is
+	  symmetric and perform only the necessary calculations.
+	  
+	  RGEOSRelate and RGEOSRelatePattern moved to rgeos_binary_
+	  predicate
+
+2010-06-05 21:33  crundel
+
+	* R/rgeos_misc.R, R/rgeos_predicate_binary.R,
+	  R/rgeos_predicate_unary.R, R/rgeos_topology.R,
+	  R/rgeos_topology_relation.R, src/init.c, src/rgeos.c,
+	  src/rgeos.h, src/rgeos_predicate_binary.c,
+	  src/rgeos_predicate_unary.c: Fixed issues with binary predicate
+	  issue (temporarily remove rgeos_relatepattern)
+	  
+	  Added Unary Predicate Functions
+
+2010-06-03 22:46  crundel
+
+	* src/rgeos.h, src/rgeos_misc.c, src/rgeos_predicate_binary.c,
+	  src/rgeos_topology.c: Removed the enum for each function and just
+	  passing a function pointer directly now.
+
+2010-06-02 03:44  crundel
+
+	* R/rgeos_misc.R, R/rgeos_predicate_binary.R, src/init.c,
+	  src/rgeos.h, src/rgeos_predicate_binary.c: Added binary predicate
+	  functions: RGEOSDisjoint, RGEOSTouches, RGEOSIntersects,
+	  RGEOSCrosses, RGEOSWithin, RGEOSContains, RGEOSOverlaps,
+	  RGEOSEquals
+	  
+	  Generalized functions in rgeos_misc
+
+2010-06-02 00:35  crundel
+
+	* R/rgeos_topology.R, src/init.c, src/rgeos.h, src/rgeos_coord.c,
+	  src/rgeos_geos2R.c, src/rgeos_misc.c, src/rgeos_topology.c: Added
+	  RGEOSLineMerge
+	  
+	  Generalized function calls in topology and misc, functions with
+	  the same type of parameters and differ only in the GEOS function
+	  used are processed by the same function.
+	  
+	  Small bug fixes in coord and geos2R
+
+2010-05-31 03:05  crundel
+
+	* R/rgeos_misc.R, src/init.c, src/rgeos.h, src/rgeos_misc.c: Added
+	  RGEOSHausdorffDistance, combined underlying C code with
+	  rgeosdistance since everything is the same except for the geos
+	  function call. FIXME - currently uses function pointers which are
+	  causing gcc warnings, but code appears to work.
+
+2010-05-30 21:53  crundel
+
+	* R/rgeos_misc.R, src/init.c, src/rgeos.h, src/rgeos_misc.c: Added
+	  RGEOSDistance and RGEOSisWithinDistance in rgeos_misc
+
+2010-05-30 21:14  crundel
+
+	* R/rgeos_misc.R, src/init.c, src/rgeos.h, src/rgeos_misc.c: Added
+	  RGEOSArea and RGEOSLength in rgeos_misc
+
+2010-05-30 20:40  crundel
+
+	* src/rgeos.h: More cleaning of rgeos.h
+
+2010-05-30 20:38  crundel
+
+	* src/rgeos_contains.c, src/rgeos_distance.c, src/rgeos_length.c:
+	  Removed rgeos_contains.c, rgeos_distance.c, rgeos_length.c
+	  functionality will be covered by rgeos_misc.c
+
+2010-05-30 20:37  crundel
+
+	* src/init.c, src/rgeos.h: Removed rgeos_contains.c,
+	  rgeos_distance.c, rgeos_length.c functionality will be covered by
+	  rgeos_misc.c
+	  
+	  Cleaned up init.c and rgeos.h
+
+2010-05-30 20:15  crundel
+
+	* R/rgeos_buffer.R, src/rgeos_buffer.c: Added RGEOSBuffer
+
+2010-05-30 20:11  crundel
+
+	* R/rgeos_util.R: Added default value for setScale
+
+2010-05-30 20:10  crundel
+
+	* src/rgeos_poly2nb.c, src/rgeos_sp.c, src/rgeos_validate.c:
+	  Updated function names
+
+2010-05-29 09:38  crundel
+
+	* NAMESPACE, R/rgeos_wkt.R, src/init.c, src/rgeos.h,
+	  src/rgeos_R2geos.c, src/rgeos_geos2R.c, src/rgeos_wkt.c: Added
+	  writeWKT, small fixes to translate functions
+
+2010-05-27 19:47  crundel
+
+	* NAMESPACE, R/rgeos_buffer.R, R/rgeos_linearref.R,
+	  R/rgeos_topology.R, src/init.c, src/rgeos.c, src/rgeos.h,
+	  src/rgeos_buffer.c, src/rgeos_predicate_unary.c,
+	  src/rgeos_topology.c: Added RGEOSBoundary, RGEOSGetCentroid,
+	  RGEOSPointOnSurface, RGEOSBuffer which mostly work
+
+2010-05-26 17:59  rsbivand
+
+	* ChangeLog, inst/ChangeLog: changelogs
+
+2010-05-26 06:06  crundel
+
+	* src/init.c:
+
+2010-05-26 06:06  crundel
+
+	* R/rgeos_topology.R, inst/tests/test-translate.R, src/rgeos.h,
+	  src/rgeos_R2geos.c, src/rgeos_geos2R.c, src/rgeos_sp.c,
+	  src/rgeos_topology.c: Small fixes to translation functions,
+	  everything should be working
+	  
+	  Updated test-translate.R with polygon unit tests
+	  
+	  Added RGEOSConvexHull (untested)
+
+2010-05-24 04:40  crundel
+
+	* R/rgeos_topology.R, R/rgeos_util.R, src/rgeos_topology.c: Added
+	  rgeos_envelope and RGEOSEnvelope functions
+
+2010-05-24 04:25  crundel
+
+	* src/init.c, src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_bbox.c,
+	  src/rgeos_geos2R.c: Unified bounding box functions, geom2bbox
+	  should work for all geometry types now
+
+2010-05-23 08:03  crundel
+
+	* NAMESPACE, R/rgeos_util.R, R/rgeos_wkt.R, inst/tests,
+	  inst/tests/test-jts-xml.R, inst/tests/test-translate.R,
+	  src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_coord.c,
+	  src/rgeos_geos2R.c: Added proper ID handling to translation
+	  functions and readWKT. Currently point ids are stored as row
+	  names which is a design decision that should be revisited later
+	  (current implementation works, but probably doesn't integrate
+	  well with existing sp tools)
+	  
+	  Added fixes to test-translate.R, mostly related to IDs
+	  
+	  Removed SP2WKT (which never worked) and WKT2SP in favor of
+	  readWKT - revisit naming convention?
+
+2010-05-21 22:00  crundel
+
+	* NAMESPACE:
+
+2010-05-21 22:00  crundel
+
+	* R/rgeos_util.R, R/rgeos_wkt.R, inst/tests/test-translate.R,
+	  src/init.c, src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_geos2R.c,
+	  src/rgeos_sp.c, tests/test-all.R: Added rgeos_convert_R2geos -
+	  generic function to translate R sp objects to geos geometries
+	  
+	  Moved rgeos_Polygons_i_2Polygon to rgeos_R2geos.c
+	  
+	  Added rgeos_double_translate which translates R->geos->R for
+	  testing purposes
+	  
+	  Added test-translate.R with unit tests for translations -
+	  currently tests Points, Lines, and Rings
+	  
+	  readWKT fix - if the result is only one object return it and not
+	  a list of objects
+
+2010-05-21 00:59  crundel
+
+	* src/rgeos_coord.c: Broke the geospoint2crdMat in the last commit,
+	  fixes POINT and MULTIPOINT cases
+
+2010-05-20 22:46  crundel
+
+	* src/rgeos_coord.c, src/rgeos_geos2R.c: Cleaned up / clarified
+	  point and line handling code
+
+2010-05-20 21:25  crundel
+
+	* src/rgeos_geos2R.c: Added handling of geometry collections of
+	  Lines and Multilines and Linear Rings
+
+2010-05-20 20:40  rsbivand
+
+	* src/rgeos_sp.c: temp FIXME in Line Intersection
+
+2010-05-19 04:37  crundel
+
+	* src/init.c, src/rgeos.h, src/rgeos_coord.c, src/rgeos_geos2R.c,
+	  src/rgeos_sp.c: Updated handling conversion of geos points to R
+	  to handle geometry collections of points and multipoints
+
+2010-05-17 21:51  crundel
+
+	* src/rgeos_geos2R.c: Fix to rgeos_multiline2SpatialLines,
+	  SpatialLines class was being built incorrectly, Lines class is
+	  now added to a list before being attached
+
+2010-05-17 02:33  crundel
+
+	* R/rgeos_util.R, R/rgeos_wkt.R, src/init.c, src/rgeos.h,
+	  src/rgeos_bbox.c, src/rgeos_geos2R.c, src/rgeos_wkt.c: Added
+	  rgeos_multiline2SpatialLines function to covert LINESTRING and
+	  MULTILINESTRING to SpatialLines
+	  
+	  Added rgeos_convert_geos2R function which is geometry type
+	  agnostic and calls other conversion functions based on geometry
+	  type
+	  
+	  Fixed rgeos_crdMat2bbox function to make updates to an existing
+	  bbox, added rgeos_initbbox and rgeos_formatbbox helper functions
+	  
+	  Added checkP4S for basic proj4string checking and initialization,
+	  should now be handled in R and an initialized CRS class passed to
+	  conversion functions
+	  
+	  Other small code cleanups
+
+2010-05-15 05:41  crundel
+
+	* src/init.c, src/rgeos_R2geos.c: More merge fixes
+
+2010-05-15 05:39  crundel
+
+	* src/rgeos.h: Broke rgeos.h somehow while merging.
+
+2010-05-15 05:28  crundel
+
+	* ., NAMESPACE, R, R/AAA.R, R/rgeos_wkt.R, inst/tests,
+	  inst/tests/test-jts-xml.R, inst/tests/testxml,
+	  inst/tests/testxml/general,
+	  inst/tests/testxml/general/TestBoundary.xml,
+	  inst/tests/testxml/general/TestCentroid.xml,
+	  inst/tests/testxml/general/TestConvexHull-big.xml,
+	  inst/tests/testxml/general/TestConvexHull.xml,
+	  inst/tests/testxml/general/TestFunctionAA.xml,
+	  inst/tests/testxml/general/TestFunctionAAPrec.xml,
+	  inst/tests/testxml/general/TestFunctionLA.xml,
+	  inst/tests/testxml/general/TestFunctionLAPrec.xml,
+	  inst/tests/testxml/general/TestFunctionLL.xml,
+	  inst/tests/testxml/general/TestFunctionLLPrec.xml,
+	  inst/tests/testxml/general/TestFunctionPA.xml,
+	  inst/tests/testxml/general/TestFunctionPL.xml,
+	  inst/tests/testxml/general/TestFunctionPLPrec.xml,
+	  inst/tests/testxml/general/TestFunctionPP.xml,
+	  inst/tests/testxml/general/TestInteriorPoint.xml,
+	  inst/tests/testxml/general/TestRectanglePredicate.xml,
+	  inst/tests/testxml/general/TestRelateAA.xml,
+	  inst/tests/testxml/general/TestRelateAC.xml,
+	  inst/tests/testxml/general/TestRelateLA.xml,
+	  inst/tests/testxml/general/TestRelateLC.xml,
+	  inst/tests/testxml/general/TestRelateLL.xml,
+	  inst/tests/testxml/general/TestRelatePA.xml,
+	  inst/tests/testxml/general/TestRelatePL.xml,
+	  inst/tests/testxml/general/TestRelatePP.xml,
+	  inst/tests/testxml/general/TestSimple.xml,
+	  inst/tests/testxml/general/TestValid.xml,
+	  inst/tests/testxml/general/TestValid2-big.xml,
+	  inst/tests/testxml/general/TestValid2.xml,
+	  inst/tests/testxml/general/TestWithinDistance.xml,
+	  inst/tests/testxml/robust,
+	  inst/tests/testxml/robust/ExternalRobustness.xml,
+	  inst/tests/testxml/robust/TestRobustOverlayFixed.xml,
+	  inst/tests/testxml/robust/TestRobustOverlayFloat.xml,
+	  inst/tests/testxml/robust/TestRobustRelate.xml,
+	  inst/tests/testxml/validate,
+	  inst/tests/testxml/validate/TestRelateAA-big.xml,
+	  inst/tests/testxml/validate/TestRelateAA.xml,
+	  inst/tests/testxml/validate/TestRelateAC.xml,
+	  inst/tests/testxml/validate/TestRelateLA.xml,
+	  inst/tests/testxml/validate/TestRelateLC.xml,
+	  inst/tests/testxml/validate/TestRelateLL.xml,
+	  inst/tests/testxml/validate/TestRelatePA.xml,
+	  inst/tests/testxml/validate/TestRelatePL.xml,
+	  inst/tests/testxml/validate/TestRelatePP.xml,
+	  inst/tests/testxml/vivid, src, src/gpc_geos.c, src/init.c,
+	  src/rgeos.h, src/rgeos_R2geos.c, src/rgeos_bbox.c,
+	  src/rgeos_coord.c, src/rgeos_geos2R.c, src/rgeos_length.c,
+	  src/rgeos_sp.c, src/rgeos_wkt.c, tests, tests/.Rhistory,
+	  tests/test-all.R: Fixed issue where CoordSeq were not being
+	  destroyed
+	  
+	  Added some initial work on UnitTests using testthat package,
+	  testxml folder contains xml test files from JTS
+	  
+	  General cleaning and reorganization of C code.
+	  
+	  Added functions to convert point and multipoint geos geometries
+	  
+	  Added readWKT functions that are geometry agnostic
+
+2010-05-13 20:10  crundel
+
+	* R/rgeos_misc.R, R/rgeos_predicate_binary.R,
+	  R/rgeos_predicate_unary.R, R/rgeos_topology.R,
+	  R/rgeos_topology_relation.R: Created new files with basic rgeos
+	  functions organized by task, each file contains empty function
+	  definitions.
+
+2010-05-06 16:19  rsbivand
+
+	* ChangeLog, inst/ChangeLog: use points not polygons for b-box
+	  intersection envelope in poly2nb
+
+2010-05-06 16:19  rsbivand
+
+	* R/rgeos.R, src/init.c, src/rgeos.h, src/rgeos_R2geos.c,
+	  src/rgeos_poly2nb.c: use points not polygons for b-box
+	  intersection envelope in poly2nb
+
+2010-05-05 08:42  rsbivand
+
+	* ChangeLog, inst/ChangeLog: bounding box intersections
+
+2010-05-05 08:41  rsbivand
+
+	* NAMESPACE, R/rgeos.R, src/init.c, src/rgeos.h,
+	  src/rgeos_poly2nb.c: bounding box intersections
+
+2010-05-03 17:19  rsbivand
+
+	* DESCRIPTION: increment DESCRIPTION version #
+
+2010-05-03 16:35  rsbivand
+
+	* DESCRIPTION, R/AAA.R, R/rgeos.R: increment DESCRIPTION version #
+
+2010-05-03 14:04  rsbivand
+
+	* src/rgeos.c, src/rgeos.h, src/rgeos_coord.c, src/rgeos_geos2R.c,
+	  src/rgeos_validate.c, src/rgeos_wkt.c: removing inline
+	  declaration in rgeos.h - see comment
+
+2010-05-03 13:33  rsbivand
+
+	* src/Makevars: removing pkg/src/Makevars - auto-generated from
+	  Makevars.in
+
+2010-05-03 05:24  crundel
+
+	* NAMESPACE, R/AAA.R, R/rgeos.R, R/rgeos_util.R, R/rgeos_wkt.R,
+	  src/Makevars, src/init.c, src/rgeos.c, src/rgeos.h,
+	  src/rgeos_R2geos.c, src/rgeos_area.c, src/rgeos_coord.c,
+	  src/rgeos_geos2R.c, src/rgeos_sp.c, src/rgeos_validate.c,
+	  src/rgeos_wkt.c: Tidying existing functions, roughly grouped into
+	  files by task.
+	  
+	  Added functions for WKT output.
+	  
+	  Fixed precision issue leading to small polygons not being joined.
+	  Added functionality to get, set, and use a scale variable that
+	  determines min precision with appropriate rounding functions from
+	  GEOS.
+
+2010-04-29 14:35  rsbivand
+
+	* R/rgeos.R, man/LinesIntersections.Rd: fix poly2nb framework
+	  (non-operational)
+
+2010-04-28 08:44  rsbivand
+
+	* R/AAA.R, R/rgeos.R, R/rgeos_simplify.R, R/rgeos_union.R,
+	  src/gpc_geos.c, src/rgeos.c, src/rgeos.h, src/rgeos_distance.c,
+	  src/rgeos_length.c, src/rgeos_sp.c: tidy
+
+2010-04-26 08:32  rsbivand
+
+	* R/rgeos.R: starting poly2nb
+
+2010-02-12 12:27  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, R/Rgpc_funcs.R, R/gpc_geos.R,
+	  R/rgeos.R, R/rgeos_simplify.R, R/rgeos_union.R, data,
+	  data/poly_ex.rda, man/checkHolesGPC.Rd, man/gpc.poly-class.Rd,
+	  man/new-generics.Rd, man/unionSpatialPolygonsGEOS.Rd,
+	  src/gpc_geos.c, src/init.c, src/rgeos.c, src/rgeos.h,
+	  src/rgeos_contains.c, src/rgeos_distance.c, src/rgeos_length.c,
+	  src/rgeos_sp.c: adding gpc.poly <-> GEOS interface
+
+2010-02-08 14:55  rsbivand
+
+	* configure.win, src/Makevars.win: Windows DLL to static
+
+2010-02-01 18:01  rsbivand
+
+	* R/Rgpc_funcs.R: Rgpc functions
+
+2010-02-01 12:21  rsbivand
+
+	* configure.win: Win binaries to 320
+
+2010-01-31 19:22  rsbivand
+
+	* ChangeLog, inst/ChangeLog: union buffer scale problem
+
+2010-01-31 19:21  rsbivand
+
+	* man/checkHolesGPC.Rd: union buffer scale problem
+
+2010-01-31 19:19  rsbivand
+
+	* R/gpc_geos.R, R/rgeos.R, R/rgeos_union.R,
+	  man/checkPolygonsGEOS.Rd, man/unionSpatialPolygonsGEOS.Rd,
+	  src/gpc_geos.c, src/init.c, src/rgeos.h, src/rgeos_sp.c: union
+	  buffer scale problem
+
+2010-01-27 10:53  rsbivand
+
+	* R/gpc_geos.R, src/gpc_geos.c: refactoring for gpcpoly objects
+
+2010-01-27 10:20  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/rgeos.R, src/init.c, src/rgeos.h,
+	  src/rgeos_sp.c: refactoring for gpcpoly objects
+
+2010-01-14 07:41  rsbivand
+
+	* ChangeLog, inst/ChangeLog: declaration for Windows binary
+
+2010-01-14 07:41  rsbivand
+
+	* inst/README.windows: declaration for Windows binary
+
+2010-01-13 19:37  rsbivand
+
+	* ChangeLog, inst/ChangeLog: rgeos_finish declaration in init.c
+
+2010-01-13 19:37  rsbivand
+
+	* src/init.c: rgeos_finish declaration in init.c
+
+2010-01-10 19:01  rsbivand
+
+	* ChangeLog, inst/ChangeLog: hole verification fix
+
+2010-01-10 19:00  rsbivand
+
+	* DESCRIPTION, R/rgeos.R, man/checkPolygonsGEOS.Rd: hole
+	  verification fix
+
+2010-01-07 18:50  rsbivand
+
+	* ChangeLog, inst/ChangeLog: union dim fix
+
+2010-01-07 18:49  rsbivand
+
+	* ChangeLog, inst/ChangeLog: union dim fix
+
+2010-01-07 18:49  rsbivand
+
+	* R/rgeos_union.R: union dim fix
+
+2010-01-07 18:14  rsbivand
+
+	* ChangeLog, inst/ChangeLog: missing man file
+
+2010-01-07 18:11  rsbivand
+
+	* man/LinesIntersections.Rd: missing man file
+
+2010-01-07 12:08  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/rgeos.R, src/init.c, src/rgeos.h,
+	  src/rgeos_sp.c: maptools integration
+
+2010-01-04 09:35  rsbivand
+
+	* configure.win: prepare for Windows binary
+
+2010-01-04 07:48  rsbivand
+
+	* configure.win: preparing for Windows build
+
+2010-01-04 07:21  rsbivand
+
+	* configure.win, src/Makevars.win, src/init.c, src/rgeos.h,
+	  src/rgeos_sp.c: preparing for Windows build
+
+2010-01-03 16:41  rsbivand
+
+	* src/init.c: tightening sp dependence
+
+2010-01-03 16:36  rsbivand
+
+	* DESCRIPTION, src/init.c, src/rgeos.c, src/rgeos.h,
+	  src/rgeos_sp.c, src/sp_rgeos.c: tightening sp dependence
+
+2009-12-17 18:46  rsbivand
+
+	* ChangeLog, inst/ChangeLog: C API tidy
+
+2009-12-17 18:44  rsbivand
+
+	* src/init.c, src/local_stubs.c: C API tidy
+
+2009-12-17 18:42  rsbivand
+
+	* DESCRIPTION, R/AAA.R, src/rgeos.h, src/rgeos_sp.c: C API tidy
+
+2009-12-04 09:11  rsbivand
+
+	* ChangeLog, inst/ChangeLog: small fixes from sp transition
+
+2009-12-04 09:10  rsbivand
+
+	* DESCRIPTION: small fixes from sp transition
+
+2009-12-04 09:08  rsbivand
+
+	* src/rgeos_sp.c: small fixes from sp transition
+
+2009-12-03 08:50  rsbivand
+
+	* svn2cl.xsl: first release
+
+2009-12-03 08:47  rsbivand
+
+	* ChangeLog, inst/ChangeLog: first release
+
+2009-12-03 08:47  rsbivand
+
+	* src/sp_rgeos.c: first release
+
+2009-12-03 08:42  rsbivand
+
+	* ChangeLog, inst, inst/ChangeLog: first release
+
+2009-12-03 08:39  rsbivand
+
+	* DESCRIPTION, NAMESPACE, R/AAA.R, R/rgeos_simplify.R,
+	  R/rgeos_union.R, configure, configure.in, man,
+	  man/checkPolygonsGEOS.Rd, man/thinnedSpatialPolyGEOS.Rd,
+	  man/unionSpatialPolygonsGEOS.Rd, src/Makevars.in,
+	  src/rgeos_length.c: first release
+
+2009-12-02 21:03  rsbivand
+
+	* R/rgeos.R, src/rgeos.h, src/rgeos_sp.c: status
+
+2009-11-30 15:55  rsbivand
+
+	* src/rgeos.h, src/rgeos_sp.c: simplify in and out
+
+2009-11-29 20:52  rsbivand
+
+	* src/rgeos.c, src/rgeos.h, src/rgeos_sp.c: simplify in and out
+
+2009-11-28 20:34  rsbivand
+
+	* src/rgeos.c, src/rgeos.h, src/rgeos_sp.c: simplify in and out
+
+2009-11-25 20:52  rsbivand
+
+	* src/rgeos.h, src/rgeos_sp.c: parse comment in C
+
+2009-11-25 17:43  rsbivand
+
+	* R/rgeos.R, src/rgeos.c, src/rgeos.h, src/rgeos_sp.c: parse
+	  comment in C
+
+2009-11-24 20:53  rsbivand
+
+	* R/rgeos.R, src/rgeos.h, src/rgeos_sp.c: contains
+
+2009-11-21 14:52  rsbivand
+
+	* R/rgeos.R, src/rgeos.c, src/rgeos.h, src/rgeos_sp.c: after Oslo
+
+2009-11-15 13:56  rsbivand
+
+	* src/rgeos_sp.c: graphs and relations
+
+2009-11-15 11:08  rsbivand
+
+	* R/rgeos.R, src/rgeos.h, src/rgeos_sp.c: graphs and relations
+
+2009-11-14 12:22  rsbivand
+
+	* R, src, src/rgeos.c, src/rgeos.h, src/rgeos_contains.c,
+	  src/rgeos_distance.c, src/rgeos_length.c, src/rgeos_sp.c: initial
+	  C files
+
+2009-05-28 12:17  stefan7th
+
+	* .: R-Forge: updated repository structure
+
diff --git a/inst/README b/inst/README
new file mode 100644
index 0000000..13b31bf
--- /dev/null
+++ b/inst/README
@@ -0,0 +1,18 @@
+For OSX Mavericks+, Bill Behrman suggests:
+
+https://stat.ethz.ch/pipermail/r-sig-mac/2015-March/011317.html
+
+the comprehensive frameworks provided by William Kyngesburye:
+
+http://www.kyngchaos.com/
+
+Simply install the GEOS framework and all of its dependencies,
+then install the rgdal source package from the command line:
+
+R CMD INSTALL --configure-args="" rgeos_*.tar.gz
+
+with the correct configure-args for your platform. Bill used:
+
+install.packages("rgeos", type = "source", configure.args =
+"--with-geos-config=/Library/Frameworks/GEOS.framework/Versions/Current/unix/bin/geos-config")
+
diff --git a/inst/SVN_VERSION b/inst/SVN_VERSION
new file mode 100644
index 0000000..c7884c0
--- /dev/null
+++ b/inst/SVN_VERSION
@@ -0,0 +1 @@
+560
diff --git a/inst/poly-ex-gpc/ex-poly1.txt b/inst/poly-ex-gpc/ex-poly1.txt
new file mode 100644
index 0000000..1fb3eaf
--- /dev/null
+++ b/inst/poly-ex-gpc/ex-poly1.txt
@@ -0,0 +1,107 @@
+1 
+105 
+317.3501 93.15816
+317.364 93.22914
+317.3727 93.3207
+317.4023 93.38679
+317.4785 93.38882
+317.4871 93.45637
+317.4670 93.52148
+317.5072 93.65698
+317.5528 93.7528
+317.5552 93.84336
+317.6117 93.86206
+317.7282 93.8952
+317.8046 93.81083
+317.8712 93.69503
+317.9629 93.60056
+317.9215 93.43883
+317.9315 93.25885
+317.9963 93.10203
+317.9284 93.04953
+317.8426 92.97986
+317.7969 92.8614
+317.7409 92.89996
+317.7889 92.82841
+317.7360 92.73805
+317.6357 92.69493
+317.6026 92.72543
+317.4844 92.64864
+317.4445 92.54597
+317.4242 92.4933
+317.5481 92.4789
+317.7326 92.37324
+317.8098 92.29678
+317.9795 92.2994
+318.0062 92.15032
+317.9915 92.04499
+318.0591 92.0317
+318.021 91.9497
+317.9251 91.98268
+317.8780 92.01659
+317.815 92.02729
+317.7812 92.05223
+317.7314 92.03021
+317.6697 91.98086
+317.6577 91.9182
+317.6082 91.94144
+317.5317 91.98264
+317.5407 91.90144
+317.5102 91.79038
+317.4726 91.74955
+317.2593 91.74591
+317.2033 91.7915
+317.1228 91.7691
+317.0824 91.7605
+317.0843 91.77104
+316.9512 91.7745
+316.8917 91.7737
+316.8837 91.78889
+316.8023 91.77678
+316.7249 91.78513
+316.6370 91.77823
+316.6003 91.72394
+316.5545 91.73088
+316.5038 91.77402
+316.4809 91.71277
+316.4164 91.72645
+316.3707 91.74367
+316.3026 91.71428
+316.2563 91.702
+316.2013 91.6787
+316.1636 91.66837
+316.2643 91.75067
+316.2361 91.81156
+316.3127 91.9039
+316.3952 91.91097
+316.4209 91.94312
+316.4689 91.96004
+316.4797 91.8893
+316.5173 91.94232
+316.5808 92.00445
+316.6778 91.94444
+316.8321 91.95919
+316.8908 91.94161
+316.8947 92.11817
+316.8469 92.21952
+316.9206 92.27069
+316.8693 92.39573
+316.8574 92.59142
+316.8845 92.61746
+317.0515 92.573
+317.108 92.52248
+317.1798 92.5366
+317.2446 92.56925
+317.3624 92.63748
+317.4015 92.69787
+317.2048 92.78319
+317.1734 92.92751
+317.3021 92.84552
+317.3034 92.91617
+317.3907 92.98261
+317.4786 92.93507
+317.4567 93.04823
+317.5428 93.1414
+317.4708 93.1045
+317.4096 93.08861
+317.3168 93.0415
diff --git a/inst/poly-ex-gpc/ex-poly2.txt b/inst/poly-ex-gpc/ex-poly2.txt
new file mode 100644
index 0000000..6d14895
--- /dev/null
+++ b/inst/poly-ex-gpc/ex-poly2.txt
@@ -0,0 +1,72 @@
+1 
+70 
+317.7923 92.71032
+317.8721 92.81397
+317.8161 92.86238
+317.9423 92.94864
+317.9708 93.06514
+317.9024 93.14354
+317.9944 93.10121
+318.0435 93.05119
+318.0752 93.15552
+318.1362 93.34843
+318.2878 93.38389
+318.5084 93.41663
+318.5511 93.25283
+318.5019 93.18095
+318.5958 93.02759
+318.7896 92.88882
+318.7635 92.77466
+318.8625 92.76704
+318.9 92.6019
+318.8984 92.56074
+318.8406 92.38701
+318.9642 92.42784
+319.0633 92.56795
+319.1674 92.54714
+319.1152 92.4234
+319.0326 92.31596
+319.1695 92.36221
+319.0662 92.23476
+319.0413 92.09074
+319.1166 91.98645
+319.2321 91.98661
+319.2698 91.9251
+319.1771 91.86553
+318.9887 91.8624
+318.7962 91.82497
+318.5386 91.83337
+318.4269 91.85156
+318.2711 91.85401
+318.168 91.87571
+317.9057 91.87077
+317.7538 91.78774
+317.7905 91.94506
+317.7827 91.9935
+317.8094 92.01677
+317.6982 91.97886
+317.6621 91.8611
+317.6485 91.8975
+317.6089 91.939
+317.5289 91.93032
+317.5136 91.8742
+317.3902 91.96788
+317.3164 91.9879
+317.3072 92.021
+317.263 91.88749
+317.2742 91.81092
+317.1592 91.81743
+317.0437 91.82041
+317.0804 92.02054
+317.0768 92.1367
+317.2143 92.15653
+317.3779 92.17453
+317.5140 92.27006
+317.5084 92.335
+317.4464 92.41686
+317.5979 92.42997
+317.7568 92.3773
+317.7674 92.48837
+317.7331 92.54184
+317.7872 92.59388
+317.7876 92.69869
diff --git a/inst/poly-ex-gpc/hole-poly.txt b/inst/poly-ex-gpc/hole-poly.txt
new file mode 100644
index 0000000..c0cc629
--- /dev/null
+++ b/inst/poly-ex-gpc/hole-poly.txt
@@ -0,0 +1,13 @@
+2
+4
+0
+1 1
+4 1
+4 4
+1 4
+4
+1
+2 2
+3 2
+3 3
+2 3
diff --git a/inst/test_cases/polys.RData b/inst/test_cases/polys.RData
new file mode 100644
index 0000000..bfc8dd7
Binary files /dev/null and b/inst/test_cases/polys.RData differ
diff --git a/inst/wkts/sline1.wkt b/inst/wkts/sline1.wkt
new file mode 100644
index 0000000..716f3d7
--- /dev/null
+++ b/inst/wkts/sline1.wkt
@@ -0,0 +1 @@
+LINESTRING (450214.3845795500092208 3138828.4212905000895262, 450799.9114135300042108 3138229.5323124597780406, 451568.6001204299973324 3137954.8021564697846770, 452245.5862279299763031 3138035.9375988701358438, 452892.7827654400025494 3138218.9770908998325467, 453472.4951441399753094 3138810.7618061499670148, 453887.3883077100035734 3139138.2519546700641513, 454662.0303366400185041 3139301.0102413198910654, 455373.6261798799969256 3139177.9487825301475823, 455822.8374310699873604 313870 [...]
diff --git a/inst/wkts/sline2.wkt b/inst/wkts/sline2.wkt
new file mode 100644
index 0000000..a7a2b5e
--- /dev/null
+++ b/inst/wkts/sline2.wkt
@@ -0,0 +1 @@
+LINESTRING (491555.3550056400126778 3158583.0149213098920882, 491948.4376713300007395 3158239.8743964801542461, 492188.8795631899847649 3157941.8343762899748981, 492380.4372084399801679 3157589.9483531098812819, 492723.8962607500143349 3157244.7188935000449419, 492979.0833524200133979 3157179.0318986098282039, 493308.4639162800158374 3157142.1402617702260613, 493661.3285363800241612 3157132.2162676099687815, 494037.2674854599754326 3157174.9268249501474202, 494514.1364549199934117 315724 [...]
diff --git a/inst/wkts/sppsp.wkt b/inst/wkts/sppsp.wkt
new file mode 100644
index 0000000..85d67b3
--- /dev/null
+++ b/inst/wkts/sppsp.wkt
@@ -0,0 +1 @@
+GEOMETRYCOLLECTION (LINESTRING (0.2655086600000000 0.6547239300000000, 0.2675082100000000 0.6737122300000000), LINESTRING (0.3721239000000000 0.3531972700000000, 0.2186452800000000 0.0948578600000000), LINESTRING (0.5728533600000000 0.2702601500000000, 0.5167968400000000 0.4925961200000000), LINESTRING (0.9082077900000000 0.9926840600000000, 0.2689505900000000 0.4615518400000000), LINESTRING (0.2016819300000000 0.6334932599999999, 0.1811683300000000 0.3752165300000000), LINESTRING (0.898 [...]
diff --git a/man/class-Ring.Rd b/man/class-Ring.Rd
new file mode 100644
index 0000000..2a13324
--- /dev/null
+++ b/man/class-Ring.Rd
@@ -0,0 +1,42 @@
+\name{Ring-class}
+\docType{class}
+\alias{Ring-class}
+\alias{bbox,Ring-method}
+\alias{coordinates,Ring-method}
+\alias{coordnames,Ring-method}
+\alias{coordnames<-,Ring,character-method}
+\alias{coerce,Ring,SpatialPoints-method}
+
+
+
+\title{Class "Ring"}
+\description{  class for linear ring }
+\section{Objects from the Class}{
+Objects can be created by calls to the function \link{Ring}
+}
+\section{Slots}{
+  \describe{
+    \item{\code{coords}:}{Object of class \code{"matrix"}; coordinates of the ring;
+	first point should equal the last point }
+    \item{\code{ID}:}{Object of class \code{"character"}; unique identifier string  }
+  }
+}
+
+\section{Methods}{
+Methods defined with class "Ring" in the signature:
+  \describe{
+    \item{bbox}{\code{signature(obj = "Ring")}: retrieves the bbox element }
+	\item{coordinates}{\code{signature(object = "Ring")}: retrieves the coords element from Ring objects in rings slot}
+	\item{coordnames}{\code{signature(object = "Ring")}: retrieves coordinate names}
+	\item{coerce}{\code{signature(from = "Ring", to = "SpatialPoints")}: ... }
+  }
+}
+
+\author{ Colin Rundel }
+\seealso{ \link{Ring} }
+
+\examples{ 
+	#NONE 
+}
+
+\keyword{classes}
diff --git a/man/class-SpatialCollections.Rd b/man/class-SpatialCollections.Rd
new file mode 100644
index 0000000..4115649
--- /dev/null
+++ b/man/class-SpatialCollections.Rd
@@ -0,0 +1,46 @@
+\name{SpatialCollections-class}
+\docType{class}
+\alias{SpatialCollections-class}
+\alias{SpatialLinesNULL-class}
+\alias{SpatialRingsNULL-class}
+\alias{SpatialPolygonsNULL-class}
+\alias{SpatialPointsNULL-class}
+\alias{row.names,SpatialCollections-method}
+\alias{plot,SpatialCollections,missing-method}
+
+
+\title{Class "SpatialCollections"}
+\description{  class to hold SpatialPoints, SpatialLines, SpatialRings, and SpatialPolygons (without attributes) }
+\section{Objects from the Class}{
+Objects can be created by calls to the function \link{SpatialCollections}
+}
+\section{Slots}{
+  \describe{
+	\item{\code{pointobj}:}{Object of class SpatialPoints or NULL}
+    \item{\code{lineobj}:}{Object of class SpatialLines or NULL}
+	\item{\code{ringobj}:}{Object of class SpatialRings or NULL}
+	\item{\code{polyobj}:}{Object of class SpatialPolygons or NULL}
+	\item{\code{plotOrder}:}{Numeric vector of length 4}
+  }
+}
+
+\section{Extends}{
+	Class \code{"Spatial"}, directly.
+}
+
+\section{Methods}{
+Methods defined with class "SpatialCollections" in the signature:
+  \describe{
+	\item{plot}{\code{signature(x = "SpatialCollections", y = "missing")}: plot objects within the SpatialCollections object in the order specified by plotOrder slot}
+	\item{row.names}{\code{signature(object = "SpatialCollections")}: retrieves the ID elements from non-NULL geometry slots}
+  }
+}
+
+\author{ Colin Rundel }
+\seealso{ \link{SpatialCollections} \link{SpatialPoints} \link{SpatialLines} \link{SpatialRings} \link{SpatialPolygons} }
+
+\examples{ 
+	#NONE 
+}
+
+\keyword{classes}
diff --git a/man/class-SpatialRings.Rd b/man/class-SpatialRings.Rd
new file mode 100644
index 0000000..920d259
--- /dev/null
+++ b/man/class-SpatialRings.Rd
@@ -0,0 +1,55 @@
+\name{SpatialRings-class}
+\docType{class}
+\alias{SpatialRings-class}
+\alias{[,SpatialRings-method}
+\alias{plot,SpatialRings,missing-method}
+\alias{coordinates,SpatialRings-method}
+\alias{coordnames,SpatialRings-method}
+\alias{coordnames<-,SpatialRings,character-method}
+\alias{row.names,SpatialRings-method}
+\alias{row.names<-,SpatialRings,character-method}
+\alias{spChFIDs,SpatialRings,character-method}
+\alias{coerce,SpatialRings,SpatialPoints-method}
+
+
+
+\title{Class "SpatialRings"}
+\description{  class to hold linear ring topology (without attributes) }
+\section{Objects from the Class}{
+Objects can be created by calls to the function \link{SpatialRings}
+}
+\section{Slots}{
+  \describe{
+    \item{\code{rings}:}{Object of class \code{"list"}; list elements are
+	all of class \link{Ring-class}}
+    \item{\code{bbox}:}{Object of class \code{"matrix"}; see \link{Spatial-class} }
+    \item{\code{proj4string}:}{Object of class \code{"CRS"}; see \link{CRS-class}}
+  }
+}
+
+\section{Extends}{
+Class \code{"Spatial"}, directly.
+}
+
+\section{Methods}{
+Methods defined with class "SpatialRings" in the signature:
+  \describe{
+    \item{[}{\code{signature(obj = "SpatialRings")}: select subset of (sets of) rings; NAs are not permitted in the row index}
+	\item{plot}{\code{signature(x = "SpatialRings", y = "missing")}: plot rings in SpatialRings object}
+	\item{bbox}{\code{signature(obj = "SpatialRings")}: retrieves the bbox element }
+	\item{coordinates}{\code{signature(object = "SpatialRings")}: retrieves the coords element from Ring objects in rings slot}
+	\item{coordnames}{\code{signature(object = "SpatialRings")}: retrieves coordinate names}
+	\item{row.names}{\code{signature(object = "SpatialRings")}: retrieves the ID element from Ring objects in rings slot}
+	\item{spChFIDs}{\code{signature(obj="SpatialRings", x="character")}: replaces ID element}
+	\item{coerce}{\code{signature(from = "SpatialRings", to = "SpatialPoints")}: ... }
+  }
+}
+
+\author{ Colin Rundel }
+\seealso{ \link{SpatialRings} \link{Ring-class} }
+
+\examples{ 
+	#NONE 
+}
+
+\keyword{classes}
diff --git a/man/class-SpatialRingsDataFrame.Rd b/man/class-SpatialRingsDataFrame.Rd
new file mode 100644
index 0000000..907b795
--- /dev/null
+++ b/man/class-SpatialRingsDataFrame.Rd
@@ -0,0 +1,72 @@
+\name{SpatialRingsDataFrame-class}
+\docType{class}
+\alias{SpatialRingsDataFrame-class}
+\alias{[,SpatialRingsDataFrame-method}
+\alias{plot,SpatialRingsDataFrame-method}
+\alias{bbox,SpatialRingsDataFrame-method}
+\alias{coordinates,SpatialRingsDataFrame-method}
+\alias{coordnames,SpatialRingsDataFrame-method}
+\alias{coordnames<-,SpatialRingsDataFrame,character-method}
+\alias{row.names,SpatialRingsDataFrame-method}
+\alias{row.names<-,SpatialRingsDataFrame,character-method}
+
+\alias{names,SpatialRingsDataFrame-method}
+\alias{names<-,SpatialRingsDataFrame,character-method}
+
+\alias{dim,SpatialRingsDataFrame-method}
+
+\alias{spChFIDs,SpatialRingsDataFrame,character-method}
+\alias{coerce,SpatialRingsDataFrame,SpatialPoints-method}
+
+\alias{coerce,SpatialRingsDataFrame,SpatialRings-method}
+\alias{coerce,SpatialRingsDataFrame,data.frame-method}
+
+
+\title{Class "SpatialRingsDataFrame"}
+\description{  class to hold linear ring topology (without attributes) }
+\section{Objects from the Class}{
+Objects can be created by calls to the function \link{SpatialRingsDataFrame}
+}
+\section{Slots}{
+  \describe{
+	\item{\code{data}:}{Object of class \code{"data.frame"}; attribute table }
+    \item{\code{rings}:}{Object of class \code{"list"}; list elements are
+	all of class \link{Ring-class}}
+    \item{\code{bbox}:}{Object of class \code{"matrix"}; see \link{Spatial-class} }
+    \item{\code{proj4string}:}{Object of class \code{"CRS"}; see \link{CRS-class}}
+  }
+}
+
+\section{Extends}{
+Class \code{"SpatialRings"}, directly.
+Class \code{"Spatial"}, by class \code{"SpatialRings"}.
+}
+
+\section{Methods}{
+Methods defined with class "SpatialRingsDataFrame" in the signature:
+  \describe{
+    \item{[}{\code{signature(obj = "SpatialRingsDataFrame")}: select subset of (sets of) rings; NAs are not permitted in the row index}
+	\item{plot}{\code{signature(x = "SpatialRingsDataFrame", y = "missing")}: plot rings in SpatialRingsDataFrame object}
+	\item{bbox}{\code{signature(obj = "SpatialRingsDataFrame")}: retrieves the bbox element }
+	\item{coordinates}{\code{signature(object = "SpatialRingsDataFrame")}: retrieves the coords element from Ring objects in rings slot}
+	\item{coordnames}{\code{signature(object = "SpatialRingsDataFrame")}: retrieves coordinate names}
+	\item{row.names}{\code{signature(object = "SpatialRingsDataFrame")}: retrieves the ID element from Ring objects in rings slot}
+	\item{spChFIDs}{\code{signature(obj="SpatialRingsDataFrame", x="character")}: replaces ID element}
+	
+	\item{names}{\code{signature(object = "SpatialRingsDataFrame")}: retrieves names from data element}
+	\item{dim}{\code{signature(object = "SpatialRingsDataFrame")}: retrieves dimensions of data element}
+	
+	\item{coerce}{\code{signature(from = "SpatialRingsDataFrame", to = "SpatialPoints")}: ... }
+	\item{coerce}{\code{signature(from = "SpatialRingsDataFrame", to = "SpatialRings")}: ... }
+	\item{coerce}{\code{signature(from = "SpatialRingsDataFrame", to = "data.frame")}: ... }
+  }
+}
+
+\author{ Colin Rundel }
+\seealso{ \link{SpatialRingsDataFrame} \link{Ring-class} \link{SpatialRings-class} }
+
+\examples{ 
+	#NONE 
+}
+
+\keyword{classes}
diff --git a/man/class-gpc.poly.Rd b/man/class-gpc.poly.Rd
new file mode 100644
index 0000000..9b4dccd
--- /dev/null
+++ b/man/class-gpc.poly.Rd
@@ -0,0 +1,152 @@
+\name{gpc.poly-class}
+\docType{class}
+\alias{gpc.poly-class}
+\alias{[,gpc.poly,ANY,ANY-method}
+\alias{[,gpc.poly-method}
+\alias{append.poly,gpc.poly,gpc.poly-method}
+\alias{area.poly,gpc.poly-method}
+\alias{coerce,matrix,gpc.poly-method}
+\alias{coerce,data.frame,gpc.poly-method}
+\alias{coerce,gpc.poly,matrix-method}
+\alias{coerce,gpc.poly,numeric-method}
+\alias{coerce,gpc.poly,SpatialPolygons-method}
+\alias{coerce,SpatialPolygons,gpc.poly-method}
+\alias{coerce,numeric,gpc.poly-method}
+\alias{coerce,list,gpc.poly-method}
+\alias{get.bbox,gpc.poly-method}
+\alias{get.pts,gpc.poly-method}
+\alias{intersect,gpc.poly,gpc.poly-method}
+\alias{plot,gpc.poly-method}
+\alias{plot,gpc.poly,ANY-method}
+\alias{scale.poly,gpc.poly-method}
+\alias{setdiff,gpc.poly,gpc.poly-method}
+\alias{show,gpc.poly-method}
+\alias{symdiff,gpc.poly,gpc.poly-method}
+\alias{union,gpc.poly,gpc.poly-method}
+\alias{tristrip,gpc.poly-method}
+\alias{triangulate,gpc.poly-method}
+
+\title{Class "gpc.poly"}
+\description{
+  A class for representing polygons composed of multiple contours, some
+  of which may be holes.
+}
+\section{Objects from the Class}{
+  Objects can be created by calls of the form \code{new("gpc.poly",
+    ...)} or by reading in from a file using \code{read.polyfile}.
+}
+\section{Slots}{
+  \describe{
+    \item{pts}{Object of class \dQuote{list}.  Actually,
+      \code{pts} is a list of lists with length equal to the number of
+      contours in the \code{"gpc.poly"} object.  Each element of
+      \code{pts} is a list of length 3 with names \code{x}, \code{y},
+      and \code{hole}.  \code{x} and \code{y} are vectors containing the
+      x and y coordinates, respectively, while \code{hole} is a logical
+      indicating whether or not the contour is a hole.}
+  }
+}
+\section{Methods}{
+  \describe{
+    \item{[}{\code{signature(x = "gpc.poly")}: ... }
+    \item{append.poly}{\code{signature(x = "gpc.poly", y = "gpc.poly")}: ... }
+    \item{area.poly}{\code{signature(object = "gpc.poly")}: ... }
+    \item{coerce}{\code{signature(from = "matrix", to = "gpc.poly")}: ... }
+    \item{coerce}{\code{signature(from = "data.frame", to = "gpc.poly")}: ... }
+    \item{coerce}{\code{signature(from = "numeric", to = "gpc.poly")}: ... }
+    \item{coerce}{\code{signature(from = "list", to = "gpc.poly")}: ... }
+	\item{coerce}{\code{signature(from = "SpatialPolygons", to = "gpc.poly")}: ... }
+    \item{coerce}{\code{signature(from = "gpc.poly", to = "matrix")}: ... }
+    \item{coerce}{\code{signature(from = "gpc.poly", to = "numeric")}: ... }
+	\item{coerce}{\code{signature(from = "gpc.poly", to = "SpatialPolygons")}: ... }
+	\item{get.bbox}{\code{signature(x = "gpc.poly")}: ... }
+    \item{get.pts}{\code{signature(object = "gpc.poly")}: ... }
+    \item{intersect}{\code{signature(x = "gpc.poly", y = "gpc.poly")}: ... }
+    \item{plot}{\code{signature(x = "gpc.poly")}: The argument
+      \code{poly.args} can be used to pass a list of additional
+      arguments to be passed to the underlying \code{polygon} call.}
+    \item{scale.poly}{\code{signature(x = "gpc.poly")}: ... }
+    \item{setdiff}{\code{signature(x = "gpc.poly", y = "gpc.poly")}: ... }
+    \item{show}{\code{signature(object = "gpc.poly")}: Scale x and y
+      coordinates by amount \code{xscale} and \code{yscale}.  By default
+      \code{xscale} equals \code{yscale}.}
+    \item{symdiff}{\code{signature(x = "gpc.poly", y = "gpc.poly")}: ... }
+	\item{union}{\code{signature(x = "gpc.poly", y = "gpc.poly")}: ... }
+    \item{tristrip}{\code{signature(x = "gpc.poly")}: ... }
+    \item{triangulate}{\code{signature(x = "gpc.poly")}: ... }
+
+
+  }
+}
+\author{Roger D. Peng}
+
+\note{
+  The class \code{"gpc.poly.nohole"} is identical to
+  \code{"gpc.poly"} except the \code{hole} flag for each contour of a
+  \code{"gpc.poly.nohole"} object is always \code{FALSE}.
+}
+
+\examples{
+## Make some random polygons
+set.seed(100)
+a <- cbind(rnorm(100), rnorm(100))
+a <- a[chull(a), ]
+
+## Convert `a' from matrix to "gpc.poly"
+a <- as(a, "gpc.poly")
+
+b <- cbind(rnorm(100), rnorm(100))
+b <- as(b[chull(b), ], "gpc.poly")
+
+## More complex polygons with an intersection
+p1 <- read.polyfile(system.file("poly-ex-gpc/ex-poly1.txt", package = "rgeos"))
+p2 <- read.polyfile(system.file("poly-ex-gpc/ex-poly2.txt", package = "rgeos"))
+
+## Plot both polygons and highlight their intersection in red
+plot(append.poly(p1, p2))
+plot(intersect(p1, p2), poly.args = list(col = 2), add = TRUE)
+
+## Highlight the difference p1 \ p2 in green
+plot(setdiff(p1, p2), poly.args = list(col = 3), add = TRUE)
+
+## Highlight the difference p2 \ p1 in blue
+plot(setdiff(p2, p1), poly.args = list(col = 4), add = TRUE)
+
+## Plot the union of the two polygons
+plot(union(p1, p2))
+
+## Take the non-intersect portions and create a new polygon
+## combining the two contours
+p.comb <- append.poly(setdiff(p1, p2), setdiff(p2, p1))
+plot(p.comb, poly.args = list(col = 2, border = 0))
+
+## Coerce from a matrix
+x <- 
+structure(c(0.0934073560027759, 0.192713393476752, 0.410062456627342, 
+0.470020818875781, 0.41380985426787, 0.271408743927828, 0.100902151283831, 
+0.0465648854961832, 0.63981588032221, 0.772382048331416,
+0.753739930955121, 0.637744533947066, 0.455466052934407,
+0.335327963176065, 0.399539700805524, 
+0.600460299194476), .Dim = c(8, 2))
+y <- 
+structure(c(0.404441360166551, 0.338861901457321, 0.301387925052047, 
+0.404441360166551, 0.531852879944483, 0.60117973629424, 0.625537820957668, 
+0.179976985040276, 0.341542002301496, 0.445109321058688,
+0.610817031070196, 0.596317606444189, 0.459608745684695,
+0.215189873417722), .Dim = c(7, 2))
+
+x1 <- as(x, "gpc.poly")
+y1 <- as(y, "gpc.poly")
+
+plot(append.poly(x1, y1))
+plot(intersect(x1, y1), poly.args = list(col = 2), add = TRUE)
+
+## Show the triangulation
+#plot(append.poly(x1, y1))
+#triangles <- triangulate(append.poly(x1,y1))
+#for (i in 0:(nrow(triangles)/3 - 1)) 
+#    polygon(triangles[3*i + 1:3,], col="lightblue")
+
+
+}
+\keyword{classes}
diff --git a/man/class-gpc.poly.nohole.Rd b/man/class-gpc.poly.nohole.Rd
new file mode 100644
index 0000000..b3f45b2
--- /dev/null
+++ b/man/class-gpc.poly.nohole.Rd
@@ -0,0 +1,49 @@
+\name{gpc.poly.nohole-class}
+\docType{class}
+\alias{gpc.poly.nohole-class}
+\alias{coerce,numeric,gpc.poly.nohole-method}
+\alias{coerce,gpc.poly.nohole,SpatialPolygons-method}
+\alias{coerce,SpatialPolygons,gpc.poly.nohole-method}
+
+\title{Class "gpc.poly.nohole"}
+\description{
+  A class for representing polygons with multiple contours but without
+  holes.
+}
+\section{Objects from the Class}{
+  Objects can be created by calls of the form
+  \sQuote{new("gpc.poly.nohole", ...) or by calling \code{read.polyfile}}.
+}
+\section{Slots}{
+  \describe{
+    \item{pts}{Object of class \dQuote{list}.  See the help for
+      \dQuote{gpc.poly} for details.}
+  }
+}
+\section{Extends}{
+Class \dQuote{gpc.poly}, directly.
+}
+\section{Methods}{
+  \describe{
+    \item{coerce}{\code{signature(from = "numeric", to = "gpc.poly.nohole")}: ... }
+  }
+}
+\author{Roger D. Peng}
+\note{
+  This class is identical to \dQuote{"gpc.poly"} and is needed because the
+  file formats for polygons without holes is slightly different from the
+  file format for polygons with holes.  For a \dQuote{gpc.poly.nohole}
+  object, the \verb{hole} flag for each contour is always \code{FALSE}.
+
+  Also, \code{write.polyfile} will write the correct file format,
+  depending on whether the object is of class \dQuote{gpc.poly} or
+  \dQuote{gpc.poly.nohole}.
+}
+
+\seealso{
+  \code{\link{gpc.poly-class}}
+}
+\examples{
+## None
+}
+\keyword{classes}
diff --git a/man/comment-functions.Rd b/man/comment-functions.Rd
new file mode 100644
index 0000000..588d9f9
--- /dev/null
+++ b/man/comment-functions.Rd
@@ -0,0 +1,120 @@
+\name{RGEOS Polygon Hole Comment Functions}
+\alias{createSPComment}
+\alias{createPolygonsComment}
+\alias{get_do_poly_check}
+\alias{set_do_poly_check}
+\title{RGEOS Polygon Hole Comment Functions}
+\description{Utility functions for assigning ownership of holes to parent polygons}
+\usage{
+	createSPComment(sppoly,which=NULL,overwrite=TRUE)
+	createPolygonsComment(poly)
+        set_do_poly_check(value)
+        get_do_poly_check()
+}
+
+\arguments{
+  \item{sppoly}{Object that inherits from the \code{SpatialPolygons} class}
+  \item{which}{Vector, which subset of geometries in sppoly should comment attributes be generated}
+  \item{overwrite}{Logical, if a comment attribute already exists should it be overwritten}
+  \item{poly}{Object of class \code{Polygons}}
+  \item{value}{logical value to set \dQuote{do_poly_check} option, default TRUE}
+}
+
+\section{Warning: check polygons}{
+The helper functions get and set the imposition of checking of objects inheriting from \code{SpatialPolygons} for proper assignment of hole \emph{interior rings} to \emph{exterior rings} in \code{Polygons} objects. The internal GEOS representation defines a POLYGON object as a collection of only one exterior ring and from zero to many interior rings, so an \pkg{sp} \code{Polygons} object corresponds to a GEOS MULTIPOLYGON object, but without proper hole assignment. By default \code{do_po [...]
+
+The details below show how hole assignment is handled in the package; here we assume that the hole status slots of all Polygon objects in a given Polygons object are set correctly. In the examples below, we use a data set from \pkg{maptools} which has the holes correctly assigned, and we see that the SpatialPolygons object is geometrically valid both initially and after removing the comment attribute on the only Polygons object in \code{usa} - regenerating internally within \pkg{rgeos} f [...]
+
+If we modify \code{usa} by setting all hole status slots to FALSE, the SpatialPolygons object is geometrically invalid even though a comment attribute can be created - the function \code{createSPComment} is deceived by the incorrect hole status slots. To rectify this, we use \code{\link[maptools]{checkPolygonsHoles}} from \pkg{maptools} on each \code{Polygons} object. This function calls \code{\link{gContains}}, \code{\link{gContainsProperly}}, \code{\link{gEquals}} and \code{\link{creat [...]
+}
+
+\section{Warning: planar geometries}{
+The geometries handled by GEOS are assumed to be planar, so that any \pkg{rgeos} functions making measurements will give incorrect results when used on geographical coordinates measured in decimal degrees. Topological functions may work satisfactorily, but will not understand spherical wrap-around.
+}
+
+\details{In order for rgeos to function properly it is necessary that all holes within a given POLYGON or MULTIPOLYGON geometry must belong to a specific polygon. The \code{SpatialPolygons} class implementation does not currently include this information. To work around this limitation rgeos uses an additional comment attribute on the \code{Polygons} class that indicates which hole belongs to which polygon.
+
+Under the current implementation this comment is a text string of numbers separated by spaces where the order of the numbers corresponds to the order of the \code{Polygon} objects in the \code{Polygons} slot of the \code{Polygons} object. A \code{0} implies the \code{Polygon} object is a polygon, a non-zero number implies that the \code{Polygon} object is a hole with the value indicating the index of the \code{Polygon} that \dQuote{owns} the hole.
+
+\code{createPolygonsComment} attempts to create a valid comment for a \code{Polygons} object by assessing which polygons contain a given hole (using \code{\link{gContains}}). Ownership is assigned to the smallest polygon (by area) that contains the given hole. This is not guaranteed to generate valid polygons, always check the resulting objects for validity.
+
+\code{createSPComment} attempts to create valid comments for all or a subset of polygons within a \code{SpatialPolygons} object.
+}
+
+\author{Roger Bivand & Colin Rundel}
+
+
+\examples{
+	
+library(sp)
+p1 <- Polygon(cbind(x=c(0, 0, 10, 10, 0), y=c(0, 10, 10, 0, 0)), hole=FALSE) # I
+p2 <- Polygon(cbind(x=c(3, 3, 7, 7, 3), y=c(3, 7, 7, 3, 3)), hole=TRUE) # H
+p8 <- Polygon(cbind(x=c(1, 1, 2, 2, 1), y=c(1, 2, 2, 1, 1)), hole=TRUE) # H
+p9 <- Polygon(cbind(x=c(1, 1, 2, 2, 1), y=c(5, 6, 6, 5, 5)), hole=TRUE) # H
+p3 <- Polygon(cbind(x=c(20, 20, 30, 30, 20), y=c(20, 30, 30, 20, 20)),
+ hole=FALSE) # I
+p4 <- Polygon(cbind(x=c(21, 21, 29, 29, 21), y=c(21, 29, 29, 21, 21)),
+ hole=TRUE) # H
+p5 <- Polygon(cbind(x=c(22, 22, 28, 28, 22), y=c(22, 28, 28, 22, 22)),
+ hole=FALSE) # I
+p6 <- Polygon(cbind(x=c(23, 23, 27, 27, 23), y=c(23, 27, 27, 23, 23)),
+ hole=TRUE) # H
+p7 <- Polygon(cbind(x=c(13, 13, 17, 17, 13), y=c(13, 17, 17, 13, 13)),
+ hole=FALSE) # I
+p10 <- Polygon(cbind(x=c(24, 24, 26, 26, 24), y=c(24, 26, 26, 24, 24)),
+ hole=FALSE) # I
+p11 <- Polygon(cbind(x=c(24.25, 24.25, 25.75, 25.75, 24.25),
+ y=c(24.25, 25.75, 25.75, 24.25, 24.25)), hole=TRUE) # H
+p12 <- Polygon(cbind(x=c(24.5, 24.5, 25.5, 25.5, 24.5),
+ y=c(24.5, 25.5, 25.5, 24.5, 24.5)), hole=FALSE) # I
+p13 <- Polygon(cbind(x=c(24.75, 24.75, 25.25, 25.25, 24.75),
+ y=c(24.75, 25.25, 25.25, 24.75, 24.75)), hole=TRUE) # H
+	
+lp <- list(p1, p2, p13, p7, p6, p5, p4, p3, p8, p11, p12, p9, p10)
+#           1   2    3   4   5   6   7   8   9   10   11  12   13
+#           0   1   11   0   6   0   8   0   1   13    0   1    0
+#           I   H    H   I   H   I   H   I   H    H    I   H    I
+pls <- Polygons(lp, ID="1")
+comment(pls)
+	
+comment(pls) = createPolygonsComment(pls)
+comment(pls)
+	
+	
+plot(SpatialPolygons(list(pls)), col="magenta", pbg="cyan")
+ title(xlab="Hole slot values before checking")
+\dontrun{
+# running this illustration may be time-consuming
+if (require(maptools)) {
+data(wrld_simpl)
+usa <- wrld_simpl[wrld_simpl$ISO3=="USA",]
+lapply(slot(usa, "polygons"), comment)
+gIsValid(usa, reason=TRUE)
+comment(slot(usa, "polygons")[[1]]) <- NULL
+lapply(slot(usa, "polygons"), comment)
+gIsValid(usa)
+any(c(sapply(slot(usa, "polygons"),
+ function(x) sapply(slot(x, "Polygons"), slot, "hole"))))
+lapply(slot(createSPComment(usa), "polygons"), comment)
+usa1 <- usa
+Pls <- slot(usa1, "polygons")
+pls <- slot(Pls[[1]], "Polygons")
+pls1 <- lapply(pls, function(p) {slot(p, "hole") <- FALSE; return(p)})
+slot(Pls[[1]], "Polygons") <- pls1
+slot(usa1, "polygons") <- Pls
+any(c(sapply(slot(usa1, "polygons"),
+ function(x) sapply(slot(x, "Polygons"), slot, "hole"))))
+lapply(slot(createSPComment(usa1), "polygons"), comment)
+gIsValid(usa1, reason=TRUE)
+Pls <- slot(usa1, "polygons")
+Pls1 <- lapply(Pls, checkPolygonsHoles)
+slot(usa1, "polygons") <- Pls1
+lapply(slot(usa1, "polygons"), comment)
+gIsValid(usa1, reason=TRUE)
+}
+}
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial}
+
diff --git a/man/constructor-SpatialCollections.Rd b/man/constructor-SpatialCollections.Rd
new file mode 100644
index 0000000..85767a0
--- /dev/null
+++ b/man/constructor-SpatialCollections.Rd
@@ -0,0 +1,28 @@
+\name{SpatialCollections}
+\alias{SpatialCollections}
+
+\title{ create SpatialCollections}
+
+\description{ create object of class \code{SpatialCollections} }
+
+\usage{ 
+SpatialCollections(points=NULL, lines=NULL, rings=NULL, polygons=NULL,
+ plotOrder=c(4,3,2,1), proj4string=CRS(as.character(NA)))
+}
+
+\arguments{
+\item{points}{ list with objects of class \link{SpatialPoints-class}}
+\item{lines}{ list with objects of class \link{SpatialLines-class}}
+\item{rings}{ list with objects of class \link{SpatialRings-class}}
+\item{polygons}{ list with objects of class \link{SpatialPolygons-class}}
+\item{plotOrder}{ numeric vector of length 4 that determines the order in which the geometries will be plotted. By default polygons will be plotted followed by rings, then lines and finally points.}
+\item{proj4string}{Object of class \code{"CRS"} holding a valid proj4 string}
+}
+
+\value{
+\code{SpatialCollections} returns object of class \code{SpatialCollections}
+}
+
+\seealso{ \link{SpatialCollections-class} \link{SpatialPoints-class} \link{SpatialLines-class} \link{SpatialRings-class} \link{SpatialPolygons-class} }
+
+\keyword{manip}
diff --git a/man/constructor-SpatialRings.Rd b/man/constructor-SpatialRings.Rd
new file mode 100644
index 0000000..a1e5e1b
--- /dev/null
+++ b/man/constructor-SpatialRings.Rd
@@ -0,0 +1,35 @@
+\name{SpatialRings}
+\alias{Ring}
+\alias{SpatialRings}
+\alias{SpatialRingsDataFrame}
+
+\title{ create SpatialRings or SpatialRingsDataFrame}
+
+\description{ create objects of class \code{SpatialRings} or \code{SpatialRingsDataFrame} }
+
+\usage{ 
+Ring(coords,ID=as.character(NA))
+SpatialRings(RingList, proj4string=CRS(as.character(NA)))
+SpatialRingsDataFrame(sr, data, match.ID = TRUE)
+}
+
+\arguments{
+\item{coords}{2-column numeric matrix with coordinates; first point (row) should
+equal last coordinates (row); if the hole argument is not given, the status of the polygon as a hole or an island will be taken from the ring direction, with clockwise meaning island, and counter-clockwise meaning hole}
+\item{ID}{character vector of length one with identifier}
+\item{RingList}{ list with objects of class \link{Ring-class}}
+\item{proj4string}{Object of class \code{"CRS"} holding a valid proj4 string}
+\item{sr}{ object of class \link{SpatialRings-class}}
+\item{data}{ object of class \code{data.frame}; the number of rows in \code{data}
+should equal the number of \code{Lines} elements in \code{sl}}
+\item{match.ID}{logical: (default TRUE): match SpatialLines member Lines ID slot values with data frame row names, and re-order the data frame rows if necessary}
+}
+
+\value{
+\code{Ring} returns object of class \code{Ring}
+\code{SpatialRings} returns object of class \code{SpatialRings}
+\code{SpatialRingsDataFrame} returns object of class \code{SpatialRingsDataFrame}
+}
+\seealso{ \link{Ring-class} \link{SpatialRings-class} \link{SpatialRingsDataFrame-class}  }
+
+\keyword{manip}
diff --git a/man/experimental-functions.Rd b/man/experimental-functions.Rd
new file mode 100644
index 0000000..1a3d95e
--- /dev/null
+++ b/man/experimental-functions.Rd
@@ -0,0 +1,56 @@
+\name{RGEOS Experimental Functions}
+\alias{poly_findInBoxGEOS}
+\alias{gUnarySTRtreeQuery}
+\alias{gBinarySTRtreeQuery}
+
+\title{Experimental Functions}
+\description{Functions still under development using the GEOS STRtree structure to find intersecting object component envelopes (bounding boxes).}
+\usage{
+    gUnarySTRtreeQuery(obj)
+    gBinarySTRtreeQuery(obj1, obj2)
+    poly_findInBoxGEOS(spl, as_points=TRUE)
+}
+
+\arguments{
+  \item{obj, obj1, obj2}{Objects inheriting from either \code{SpatialPolygons} or \code{SpatialLines}, obj2 may also inherit from \code{SpatialPoints}}
+  \item{spl}{Object that inherits from the \code{SpatialPolygons} class}
+  \item{as_points}{Logical value indicating if the polygon should be treated as points}
+}
+
+\details{\code{gUnarySTRtreeQuery} and \code{poly_findInBoxGEOS} do the same thing, but \code{poly_findInBoxGEOS} uses the \code{as_points} argument to build the input envelopes from proper geometries. \code{gUnarySTRtreeQuery} and \code{gBinarySTRtreeQuery} build input envelopes by disregarding topology and reducing the coordinates to a multipoint representation. This permits the tree to be built and queried even when some geometries are invalid. \code{gUnarySTRtreeQuery} and \code{poly [...]
+}
+
+\author{Roger Bivand & Colin Rundel}
+
+\keyword{spatial}
+
+\examples{
+if (require(maptools)) {
+xx <- readShapeSpatial(system.file("shapes/fylk-val-ll.shp",
+ package="maptools")[1], proj4string=CRS("+proj=longlat +datum=WGS84"))
+a0 <- gUnarySTRtreeQuery(xx)
+a0
+bbxx <- bbox(xx)
+wdb_lines <- system.file("share/wdb_borders_c.b", package="maptools")
+xxx <- Rgshhs(wdb_lines, xlim=bbxx[1,], ylim=bbxx[2,])$SP
+a1 <- gBinarySTRtreeQuery(xx, xxx)
+a1
+nc1 <- readShapePoly(system.file("shapes/sids.shp", package="maptools")[1],
+ proj4string=CRS("+proj=longlat +datum=NAD27"))
+a2 <- gUnarySTRtreeQuery(nc1)
+a3 <- poly_findInBoxGEOS(nc1)
+all.equal(a2, a3)
+a2
+pl <- slot(nc1, "polygons")[[4]]
+a5 <- gUnarySTRtreeQuery(pl)
+a5
+SG <- Sobj_SpatialGrid(nc1, n=400)$SG
+obj1 <- as(as(SG, "SpatialPixels"), "SpatialPolygons")
+a4 <- gBinarySTRtreeQuery(nc1, obj1)
+plot(nc1, col="orange", border="yellow")
+plot(obj1, angle=sapply(a4, is.null)*45, density=20, lwd=0.5, add=TRUE)
+set.seed(1)
+pts <- spsample(nc1, n=10, type="random")
+res <- gBinarySTRtreeQuery(nc1, pts)
+}
+}
diff --git a/man/gpc-new-generics.Rd b/man/gpc-new-generics.Rd
new file mode 100644
index 0000000..67b4474
--- /dev/null
+++ b/man/gpc-new-generics.Rd
@@ -0,0 +1,96 @@
+\name{new-generics}
+\alias{new-generics}
+\alias{append.poly}
+\alias{append.poly-methods}
+%\alias{append.poly,gpc.poly,gpc.poly-method}
+\alias{get.bbox}
+\alias{get.bbox-methods}
+%\alias{get.bbox,gpc.poly-method}
+\alias{area.poly}
+\alias{area.poly-methods}
+%\alias{area.poly,gpc.poly-method}
+\alias{get.pts}
+\alias{get.pts-methods}
+%\alias{get.pts,gpc.poly-method}
+\alias{scale.poly}
+\alias{scale.poly-methods}
+%\alias{scale.poly,gpc.poly-method}
+%\alias{[-methods}
+%\alias{[,gpc.poly-method}
+\alias{tristrip}
+\alias{tristrip-methods}
+\alias{triangulate}
+\alias{triangulate-methods}
+\alias{symdiff}
+
+\title{Generics/Methods for polygon objects}
+
+\description{
+  Some generic functions and methods for polygon objects
+}
+
+\usage{
+append.poly(x, y)
+area.poly(object, \dots)
+get.pts(object)
+get.bbox(x)
+scale.poly(x, \dots)
+tristrip(x)
+triangulate(x)
+}
+
+\arguments{
+  \item{x,object}{A polygon object}
+  \item{y}{A polygon object}
+  \item{\dots}{Other arguments passed to methods}
+}
+
+\section{Methods}{
+  \describe{
+    \item{append.poly}{\code{signature(x = "gpc.poly", y =
+	"gpc.poly")}:  Combine all contours of two \code{"gpc.poly"}
+      objects and return the combined polygon as a \code{"gpc.poly"}
+      object.}
+    \item{area.poly}{\code{signature(object = "gpc.poly")}:  Compute and
+      return the sum of the areas of all contours in a \code{"gpc.poly"}
+      object.}
+    \item{scale.poly}{\code{signature(x = "gpc.poly")}:  Scale (divide)
+      the x and y coordinates of a \code{"gpc.poly"} object by the
+      amount \code{xscale} and \code{yscale}, respectively.  Return a
+      scaled \code{"gpc.poly"} object.}
+    \item{get.pts}{\code{signature(object = "gpc.poly")}:  Return the
+      list of x and y coordinates of the vertices of a \code{"gpc.poly"}
+      object.}
+    \item{get.bbox}{\code{signature(x = "gpc.poly")}:  Return the
+      bounding box for a \code{"gpc.poly"} object.}
+    \item{tristrip}{\code{signature(x = "gpc.poly")}:  Return a tristrip
+      list for a  \code{"gpc.poly"} object.}
+    \item{triangulate}{\code{signature(x = "gpc.poly")}:  Return a matrix
+      of vertices of a triangulation of a \code{"gpc.poly"} object.}
+  }
+  
+}
+
+\details{
+The result of \code{tristrip(x)} is a list of two-column matrices.  Each
+matrix is a tristrip, i.e. the rows are vertices of triangles, with
+each overlapping triple of rows corresponding to a separate triangle.
+
+The result of \code{triangulate(x)} is a single two-column matrix.  The 
+rows are vertices of triangles, taken in non-overlapping triples.
+  
+}
+
+
+\author{Roger D. Peng; GPC Library by Alan Murta; tristrip additions by
+Duncan Murdoch}
+
+
+\seealso{\code{"gpc.poly"} class documentation.}
+\examples{
+holepoly <- read.polyfile(system.file("poly-ex-gpc/hole-poly.txt",
+ package ="rgeos"), nohole = FALSE)
+area.poly(holepoly)
+stopifnot(area.poly(holepoly) == 8)
+}
+\keyword{methods}
diff --git a/man/gpc-polyfile.Rd b/man/gpc-polyfile.Rd
new file mode 100644
index 0000000..670b98a
--- /dev/null
+++ b/man/gpc-polyfile.Rd
@@ -0,0 +1,102 @@
+\name{polyfile}
+\alias{polyfile}
+\alias{read.polyfile}
+\alias{write.polyfile}
+
+\title{Read/Write polygon data}
+\description{
+  Read/Write polygon and contour information from/to a text file.  
+}
+\usage{
+read.polyfile(filename, nohole = TRUE)
+write.polyfile(poly, filename = "GPCpoly.txt")
+}
+\arguments{
+  \item{filename}{the name of the file (a character string) from/to which
+    data should be read/written.}
+  \item{nohole}{Is this a polygon without holes?}
+  \item{poly}{an object of class \code{"gpc.poly"}}
+}
+\details{
+  The text file representation of a polygon is of the following format:
+ 
+  <number of contours>\cr
+  <number of points in first contour>\cr
+  x1  y1\cr
+  x2  y2\cr
+  ...\cr
+  <number of points in second contour>\cr
+  x1  y1\cr
+  x2  y2\cr
+  ...\cr
+
+  For example, a data file for a polygon with 2 contours (a four-sided
+  object and a triangle) might look like:
+
+  2\cr
+  4\cr
+  1.0 1.0\cr
+  1.0 2.0\cr
+  3.4 3.21\cr
+  10 11.2\cr
+  3\cr
+  21.0 11.2\cr
+  22.3 99.2\cr
+  4.5 5.4\cr
+
+  The vertices of the polygon can be ordered either clockwise or
+  counter-clockwise.
+
+  If a polygon has contours which are holes, then the format is slightly
+  different.  Basically, a flag is set to indicate that a particular
+  contour is a hole.  The format is
+
+  <number of contours>\cr
+  <number of points in first contour>\cr
+  <hole flag>\cr
+  x1  y1\cr
+  x2  y2\cr
+  ...\cr
+  <number of points in second contour>\cr
+  <hole flag>\cr
+  x1  y1\cr
+  x2  y2\cr
+  ...\cr
+
+  The hole flag is either 1 to indicate a hole, or 0 for a regular
+  contour.  For example, a four-sided polygon with a triangular hole
+  would be written as:
+
+  2\cr
+  3\cr
+  1\cr
+  4.0   4.0\cr
+  6.0   5.0\cr
+  5.0   6.0\cr
+  4\cr
+  0\cr
+  2.0   1.0\cr
+  8.0   2.0\cr
+  7.0   9.0\cr
+  1.0   7.0\cr
+}
+
+\value{
+  If \code{nohole} is \code{TRUE} (the default) \code{read.polyfile}
+  returns an  object of class \code{"gpc.poly.nohole"}.  This object has
+  the hole flag set to \code{FALSE} for all contours.  If \code{nohole} is
+  \code{FALSE}, then an object of class \code{"gpc.poly"} is
+  returned.
+  
+  \code{write.polyfile} does not return anything useful.
+}
+\author{Roger D. Peng}
+
+\seealso{
+  \code{\link{gpc.poly-class}}, \code{\link{gpc.poly.nohole-class}}
+}
+
+\examples{
+## None right now.
+}
+\keyword{IO}
diff --git a/man/labelpt.Rd b/man/labelpt.Rd
new file mode 100644
index 0000000..5351344
--- /dev/null
+++ b/man/labelpt.Rd
@@ -0,0 +1,195 @@
+\encoding{UTF-8}
+\name{polygonsLabel}
+\alias{polygonsLabel}
+
+\title{Compute optimal label positions for polygons}
+\description{Compute optimal positions for placing labels inside polygons, and optionally plot the labels.
+Various algorithms for finding the ‘optimal’ label positions are supported.}
+\usage{
+polygonsLabel(pols, labels = NULL, method = c("maxdist",
+              "buffer", "centroid", "random", "inpolygon")[1],
+              gridpoints = 60, polypart = c("all", "largest")[1],
+              cex = 1, doPlot = TRUE, ...)
+}
+
+\arguments{
+  \item{pols}{ Object of class, or deriving from, \code{SpatialPolygons}.}
+  
+  \item{labels}{ Character vector of labels. Will be recycled to have
+  the same number of elements as the number of polygons in \code{pols}.
+  If \code{labels} is \code{NULL} or empty, the label box is taken as a square
+  with sides equal to the current line height (see the \code{cex} argument).}
+  
+  \item{method}{ The method(s) to use when finding label positions.
+  Will be recycled. Valid methods are \code{maxdist} (currently the default),
+  \code{buffer}, \code{centroid}, \code{random} and \code{inpolygon}.}
+  
+  \item{gridpoints}{ Number of grid points to use for the initial grid search
+  in the \code{maxdist} method.}
+  
+  \item{polypart}{ Should \code{all} (default) or only the \code{largest}
+  polygon part of each polygon in \code{pols} be used for the calculations?
+  Will be recycled. Setting this to \code{largest} is very useful when labelling
+  detailed coastlines of a country, consisting of a large polygon (where the
+  label should be placed) and very many tiny islands, as it will greatly
+  speed up the search for an optimal label position. But do note that this
+  also removes any holes (e.g., lakes) before calculating the label position,
+  so the labels are no longer guaranteed not to overlap a hole.}
+  
+  \item{cex}{ Magnification factor for text labels. Is used both when
+  plotting the labels and when calculating the label positions.}
+  
+  \item{doPlot}{ Plot the labels on the current graphics device.
+  Calls the \code{text} function internally.}
+  
+  \item{...}{ Further arguments to be passed to \code{text} (e.g., \code{col}).}
+}
+
+\details{There are no perfect definitions of ‘optimal’ label positions,
+but any such position should at least satisfy a few requirements:
+The label should be positioned wholly inside the polygon. It should also
+be far from any polygon edges. And, though more difficult to quantify,
+it should be positioned in the visual centre (or bulk) of the polygon.
+The algorithms implemented here seems to generally do a very good job
+of finding optimal (or at least ‘good’) label positions.
+
+The \code{maxdist} method is currently the default, and tries to
+find the label position with a maximal distance from the polygon edges.
+More precisely, it finds a position where the minimal distance of
+any point on the (rectangular) label box to the polygon boundary is maximised.
+It does this by first trying a grid search, using \code{gridpoints}
+regular grid points on the polygon, and then doing local optimisation on
+the best grid point. The default grid is quite coarse, but usually gives
+good results in a short amount of time. But for very complicated
+(and narrow) polygons, it may help increasing \code{gridpoints}. Note
+that while this method gives good results for most natural polygons,
+e.g., country outlines, the theoretical optimal position is not 
+necessarily unique, and this is sometimes seen when applying the method
+to regular polygons, like rectangles (see example below), where
+the resulting position may differ much from what one would judge to
+be the visual centre of the polygon.
+
+The \code{buffer} method works by shrinking the polygon (using
+negative buffering) until the convex hull of the shrunken polygon
+can fit wholly inside the original polygon. The label position is
+then taken as the centroid of the shrunken polygon. This method
+usually gives excellent results, is surprisingly fast, and seems
+to capture the ‘visual centre’ idea of an optimal label position well.
+However, it does not guarantee that the label can fit wholly inside the
+polygon. (However, if it does not fit, there are usually no other
+better position either.)
+
+The \code{centroid} method simply returns the centroid of each polygon.
+Note that although this is the geometrical/mathematical centre of 
+the polygon, it may actually be positioned outside the polygon.
+For regular polygons (rectangles, hexagons), it gives perfect results.
+Internally, this method uses the \code{coordinates} function.
+There are three reasons this method is supported:
+To make it easy to find the centroid of the
+largest polygon part of a polygon (using the \code{polypart}
+argument), to make it easy to use the centroid algorithm
+along with other algorithms (using the vector nature of the
+\code{method} argument), and for completeness.
+
+The \code{random} method returns a random position guaranteed
+to be inside the polygon. This will rarely be an optimal label
+position!
+
+The \code{inpolygon} method finds an arbitrary position in the polygon.
+This position is usually quite similar to the centroid, but is
+guaranteed the be inside the polygon. Internally, the method uses
+the \code{gPointOnSurface} function.
+}
+
+\note{
+Note that both the \code{labels}, \code{method} and \code{polypart}
+arguments are vectors, so it’s possible to use different options for each
+polygon in the \code{pols} object.
+}
+
+
+\value{ A two-colum matrix is returned, with each row
+containing the horizontal and vertical coordinates
+for the corresponding polygon. If \code{doPlot} is \code{TRUE}
+(the default), the labels are also plotted on the current
+graphics device, with the given value of \code{cex}
+(font size scaling).}
+
+\author{Karl Ove Hufthammer, \email{karl at huftis.org}.}
+
+\seealso{\code{\link[maptools]{pointLabel}}}
+
+\references{The \code{buffer} method was inspired by
+(but is slightly different from) the algorithm described
+in the paper \cite{Using Shape Analyses for Placement of Polygon Labels}
+by Hoseok Kang and Shoreh Elhami, available at
+\url{http://training.esri.com/bibliography/index.cfm?event=general.recordDetail&ID=13608}
+.}
+
+\examples{
+# Simple example with a single polygon
+x = c(0, 1.8, 1.8, 1, 1, 3, 3, 2.2, 2.2, 4,
+      4, 6, 6, 14, 14, 6, 6,  4, 4, 0, 0)
+y = c(0, 0, -2, -2, -10, -10, -2, -2, 0, 0,
+      1.8, 1.8, 1, 1, 3, 3, 2.2, 2.2, 4, 4, 0)
+xy = data.frame(x,y)
+library(sp)
+xy.sp = SpatialPolygons(list(Polygons(list(Polygon(xy)), ID = "test")))
+plot(xy.sp, col = "khaki")
+polygonsLabel(xy.sp, "Hi!")
+
+
+# Example with multiple polygons, text labels and colours
+x1 = c(0, 4, 4, 0, 0)
+y1 = c(0, 0, 4, 4, 0)
+x2 = c(1, 1, 3, 3, 1)
+y2 = c(-2, -10, -10, -2, -2)
+x3 = c(6, 14, 14, 6, 6)
+y3 = c(1, 1, 3, 3, 1)
+xy.sp = SpatialPolygons(list(
+  Polygons(list(Polygon(cbind(x1,y1))), ID = "test1"), # box
+  Polygons(list(Polygon(cbind(x3,y3))), ID = "test3"), # wide
+  Polygons(list(Polygon(cbind(x2,y2))), ID = "test2")  # high
+))
+plot(xy.sp, col=terrain.colors(3))
+labels=c("Hi!", "A very long text string", "N\na\nr\nr\no\nw")
+
+# Note that the label for the tall and narrow box is
+# not necessarily centred vertically in the box.
+# The reason is that method="maxdist" minimises the 
+# maximum distance from the label box to the surrounding
+# polygon, and this distance is not changed by moving
+# the label vertically, as long the vertical distance
+# to the polygon boundary is less than the horizontal
+# distance. For regular polygons like this, the other
+# label positions (e.g., method="buffer") work better.
+polygonsLabel(xy.sp, labels, cex=.8,
+              col = c('white', 'black', 'maroon'))
+
+
+\dontrun{
+## Example showing how bad the centroid 
+## position can be on real maps.
+
+# Needed libraries
+if (require(maps) && require(maptools) && require(rgdal)) {
+
+# Load map data and convert to spatial object
+nmap = map("world", c("Norway", "Sweden", "Finland"),
+           exact = TRUE, fill = TRUE, col = "transparent", plot = FALSE)
+nmap.pol = map2SpatialPolygons(nmap, IDs = nmap$names,
+                               proj4string = CRS("+init=epsg:4326"))
+nmap.pol = spTransform(nmap.pol, CRS("+init=epsg:3035"))
+
+# Plot map, centroid positions (red dots) and optimal
+# label positions using the ‘buffer’ method.
+plot(nmap.pol, col = "khaki")
+nmap.centroids = polygonsLabel(nmap.pol, names(nmap.pol),
+                               method = "centroid", doPlot = FALSE)
+points(nmap.centroids, col = "red", pch=19)
+polygonsLabel(nmap.pol, names(nmap.pol), method = "buffer", cex=.8)
+}
+}
+}
+
+\keyword{spatial}
diff --git a/man/linref-gInterpolate.Rd b/man/linref-gInterpolate.Rd
new file mode 100644
index 0000000..676b5e5
--- /dev/null
+++ b/man/linref-gInterpolate.Rd
@@ -0,0 +1,38 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rgeos_linearref.R
+\name{gInterpolate}
+\alias{gInterpolate}
+\title{Interpolate Points along Line Geometry}
+\usage{
+gInterpolate(spgeom, d, normalized = FALSE)
+}
+\arguments{
+\item{spgeom}{SpatialLines or SpatialLinesDataFrame object}
+
+\item{d}{Numeric vector specifying the distance along the line geometry}
+
+\item{normalized}{Logical determining if normalized distances
+should be used}
+}
+\value{
+SpatialPoints object
+}
+\description{
+Return points at specified distances along a line.
+}
+\details{
+If \code{normalized=TRUE}, the distances will be interpreted
+  as fractions of the line length.
+}
+\examples{
+gInterpolate(readWKT("LINESTRING(25 50, 100 125, 150 190)"),
+             d=seq(0, 1, by = 0.2), normalized = TRUE)
+}
+\author{
+Rainer Stuetz
+}
+\seealso{
+gInterpolate
+}
+\keyword{spatial}
+
diff --git a/man/linref-gProject.Rd b/man/linref-gProject.Rd
new file mode 100644
index 0000000..7552d1b
--- /dev/null
+++ b/man/linref-gProject.Rd
@@ -0,0 +1,44 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rgeos_linearref.R
+\name{gProject}
+\alias{gProject}
+\title{Project Points to Line Geometry}
+\usage{
+gProject(spgeom, sppoint, normalized = FALSE)
+}
+\arguments{
+\item{spgeom}{SpatialLines or SpatialLinesDataFrame object}
+
+\item{sppoint}{SpatialPoints or SpatialPointsDataFrame object}
+
+\item{normalized}{Logical determining if normalized distances
+should be used}
+}
+\value{
+a numeric vector containing the distances along the line to
+  points nearest to the specified points
+}
+\description{
+Return distances along geometry to points nearest the specified points.
+}
+\details{
+If \code{normalized=TRUE}, distances normalized to the length
+  of the geometry are returned, i.e., values between 0 and 1.
+}
+\examples{
+l <- readWKT("LINESTRING(0 1, 3 4, 5 6)")
+p1 <- readWKT("MULTIPOINT(3 2, 3 5)")
+frac <- gProject(l, p1)
+p2 <- gInterpolate(l, frac)
+plot(l, axes=TRUE)
+plot(p1, col = "blue", add = TRUE)
+plot(p2, col = "red", add = TRUE)
+}
+\author{
+Rainer Stuetz
+}
+\seealso{
+gInterpolate
+}
+\keyword{spatial}
+
diff --git a/man/misc-gArea.Rd b/man/misc-gArea.Rd
new file mode 100644
index 0000000..2e46e22
--- /dev/null
+++ b/man/misc-gArea.Rd
@@ -0,0 +1,41 @@
+\name{gArea}
+\alias{gArea}
+\alias{RGEOSArea}
+
+\title{Area of Geometry}
+\description{Calculates the area of the given geometry.}
+\usage{
+gArea(spgeom, byid=FALSE)
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+}
+
+\value{Returns the area of the geometry in the units of the current projection. By definition non-[MULTI]POLYGON geometries have an area of 0. The area of a POLYGON is the area of its shell less the area of any holes. Note that this value may be different from the \code{area} slot of the \code{Polygons} class as this value does not subtract the area of any holes in the geometry.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gLength}}
+}
+
+\examples{
+	gArea(readWKT("POINT(1 1)"))
+	gArea(readWKT("LINESTRING(0 0,1 1,2 2)"))
+	gArea(readWKT("LINEARRING(0 0,3 0,3 3,0 3,0 0)"))
+	
+	
+	p1 = readWKT("POLYGON((0 0,3 0,3 3,0 3,0 0))")
+	p2 = readWKT("POLYGON((0 0,3 0,3 3,0 3,0 0),(1 1,2 1,2 2,1 2,1 1))")
+	
+	gArea(p1)
+	p1 at polygons[[1]]@area
+	
+	gArea(p2)
+	p2 at polygons[[1]]@area
+}
+
+\keyword{spatial}
+
diff --git a/man/misc-gBuffer.Rd b/man/misc-gBuffer.Rd
new file mode 100644
index 0000000..0d39c59
--- /dev/null
+++ b/man/misc-gBuffer.Rd
@@ -0,0 +1,98 @@
+\name{gBuffer}
+\alias{gBuffer}
+\alias{RGEOSBuffer}
+
+\title{Buffer Geometry}
+\description{Expands the given geometry to include the area within the specified width with specific styling options.}
+\usage{
+gBuffer(spgeom, byid=FALSE, id=NULL, width=1.0, quadsegs=5, capStyle="ROUND",
+ joinStyle="ROUND", mitreLimit=1.0)
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+  \item{id}{Character vector defining id labels for the resulting geometries, if unspecified returned geometries will be labeled based on their parent geometries' labels.}
+  \item{width}{Distance from original geometry to include in the new geometry. Negative values are allowed. Either a numeric vector of length 1 when byid is FALSE; if byid is TRUE: of length 1 replicated to the number of input geometries, or of length equal to the number of input geometries}
+  \item{quadsegs}{Number of line segments to use to approximate a quarter circle.}
+  \item{capStyle}{Style of cap to use at the ends of the geometry. Allowed values: \code{ROUND},\code{FLAT},\code{SQUARE}}
+  \item{joinStyle}{Style to use for joints in the geometry. Allowed values: \code{ROUND},\code{MITRE},\code{BEVEL}}
+  \item{mitreLimit}{Numerical value that specifies how far a joint can extend if a mitre join style is used.}
+}
+
+\value{SpatialPolygons (or a SpatialPolygonsDataFrame if byid=TRUE and spgeom has a data.frame); if negative width(s) lead the object to disappear, NULL is returned for byid FALSE, and component Polygons objects are dropped if empty for byid TRUE; the SpatialPolygonsDataFrame is subsetted by row.names or id if given to retain non-empty geometry rows}
+
+\author{Roger Bivand & Colin Rundel}
+
+
+\examples{
+
+p1 = readWKT("POLYGON((0 1,0.95 0.31,0.59 -0.81,-0.59 -0.81,-0.95 0.31,0 1))")
+p2 = readWKT("POLYGON((2 2,-2 2,-2 -2,2 -2,2 2),(1 1,-1 1,-1 -1,1 -1,1 1))")
+
+par(mfrow=c(2,3))
+plot(gBuffer(p1,width=-0.2),col='black',xlim=c(-1.5,1.5),ylim=c(-1.5,1.5))
+plot(p1,border='blue',lwd=2,add=TRUE);title("width: -0.2")
+plot(gBuffer(p1,width=0),col='black',xlim=c(-1.5,1.5),ylim=c(-1.5,1.5))
+plot(p1,border='blue',lwd=2,add=TRUE);title("width: 0")
+plot(gBuffer(p1,width=0.2),col='black',xlim=c(-1.5,1.5),ylim=c(-1.5,1.5))
+plot(p1,border='blue',lwd=2,add=TRUE);title("width: 0.2")
+
+plot(gBuffer(p2,width=-0.2),col='black',pbg='white',xlim=c(-2.5,2.5),ylim=c(-2.5,2.5))
+plot(p2,border='blue',lwd=2,add=TRUE);title("width: -0.2")
+plot(gBuffer(p2,width=0),col='black',pbg='white',xlim=c(-2.5,2.5),ylim=c(-2.5,2.5))
+plot(p2,border='blue',lwd=2,add=TRUE);title("width: 0")
+plot(gBuffer(p2,width=0.2),col='black',pbg='white',xlim=c(-2.5,2.5),ylim=c(-2.5,2.5))
+plot(p2,border='blue',lwd=2,add=TRUE);title("width: 0.2")
+
+p3 <- readWKT(paste("GEOMETRYCOLLECTION(",
+ "POLYGON((0 1,0.95 0.31,0.59 -0.81,-0.59 -0.81,-0.95 0.31,0 1)),",
+ "POLYGON((2 2,-2 2,-2 -2,2 -2,2 2),(1 1,-1 1,-1 -1,1 -1,1 1)))"))
+
+par(mfrow=c(1,1))
+plot(gBuffer(p3, byid=TRUE, width=c(-0.2, -0.1)),col='black',pbg='white',
+xlim=c(-2.5,2.5),ylim=c(-2.5,2.5))
+plot(p3,border=c('blue', 'red'),lwd=2,add=TRUE);title("width: -0.2, -0.1")
+library(sp)
+p3df <- SpatialPolygonsDataFrame(p3, data=data.frame(i=1:length(p3),
+ row.names=row.names(p3)))
+dim(p3df)
+row.names(p3df)
+dropEmpty = gBuffer(p3df, byid=TRUE, id=letters[1:nrow(p3df)], width=c(-1, 0))
+dim(dropEmpty)
+row.names(dropEmpty)
+row.names(slot(dropEmpty, "data"))
+plot(dropEmpty, col='black', pbg='white', xlim=c(-2.5,2.5),ylim=c(-2.5,2.5))
+plot(p3df,border=c('blue'),lwd=2,add=TRUE);title("width: -1, 0")
+par(mfrow=c(2,3))
+
+
+#Style options
+l1 = readWKT("LINESTRING(0 0,1 5,4 5,5 2,8 2,9 4,4 6.5)")
+par(mfrow=c(2,3))
+plot(gBuffer(l1,capStyle="ROUND"));plot(l1,col='blue',add=TRUE);title("capStyle: ROUND")
+plot(gBuffer(l1,capStyle="FLAT"));plot(l1,col='blue',add=TRUE);title("capStyle: FLAT")
+plot(gBuffer(l1,capStyle="SQUARE"));plot(l1,col='blue',add=TRUE);title("capStyle: SQUARE")
+
+plot(gBuffer(l1,quadsegs=1));plot(l1,col='blue',add=TRUE);title("quadsegs: 1")
+plot(gBuffer(l1,quadsegs=2));plot(l1,col='blue',add=TRUE);title("quadsegs: 2")
+plot(gBuffer(l1,quadsegs=5));plot(l1,col='blue',add=TRUE);title("quadsegs: 5")
+
+
+
+l2 = readWKT("LINESTRING(0 0,1 5,3 2)")
+par(mfrow=c(2,3))
+plot(gBuffer(l2,joinStyle="ROUND"));plot(l2,col='blue',add=TRUE);title("joinStyle: ROUND")
+plot(gBuffer(l2,joinStyle="MITRE"));plot(l2,col='blue',add=TRUE);title("joinStyle: MITRE")
+plot(gBuffer(l2,joinStyle="BEVEL"));plot(l2,col='blue',add=TRUE);title("joinStyle: BEVEL")
+
+plot(gBuffer(l2,joinStyle="MITRE",mitreLimit=0.5));plot(l2,col='blue',add=TRUE)
+ title("mitreLimit: 0.5")
+plot(gBuffer(l2,joinStyle="MITRE",mitreLimit=1));plot(l2,col='blue',add=TRUE)
+ title("mitreLimit: 1")
+plot(gBuffer(l2,joinStyle="MITRE",mitreLimit=3));plot(l2,col='blue',add=TRUE)
+ title("mitreLimit: 3")
+}
+
+\keyword{spatial}
+
diff --git a/man/misc-gDistance.Rd b/man/misc-gDistance.Rd
new file mode 100644
index 0000000..e1e1939
--- /dev/null
+++ b/man/misc-gDistance.Rd
@@ -0,0 +1,75 @@
+\name{gDistance}
+\alias{gDistance}
+\alias{RGEOSDistance}
+\alias{gWithinDistance}
+\alias{RGEOSisWithinDistance}
+\alias{RGEOSHausdorffDistance}
+
+\title{Distance between geometries}
+\description{Calculates the distance between the given geometries}
+\usage{
+gDistance(spgeom1, spgeom2=NULL, byid=FALSE, hausdorff=FALSE, densifyFrac = NULL)
+gWithinDistance(spgeom1, spgeom2=NULL, dist, byid=FALSE,
+ hausdorff=FALSE, densifyFrac=NULL)
+}
+
+\arguments{
+  \item{spgeom1, spgeom2}{sp objects as defined in package sp. If spgeom2 is NULL then spgeom1 is compared to itself.}
+  \item{byid}{Logical vector determining if the function should be applied across ids (TRUE) or the entire object (FALSE) for spgeom1 and spgeom2}
+  \item{hausdorff}{Logical determining if the discrete Hausdorff distance should be calculated}
+  \item{densifyFrac}{Numerical value between 0 and 1 that determines the fraction by which to densify each segment of the geometry.}
+  \item{dist}{Numerical value that determines cutoff distance}
+}
+
+\value{gDistance by default returns the cartesian minimum distance between the two geometries in the units of the current projection. If \code{hausdorff} is TRUE then the Hausdorff distance is returned for the two geometries.
+
+gWithinDistance returns TRUE if returned distance is less than or equal to the specified \code{dist}.
+}
+
+\details{
+Discrete Hausdorff distance is essentially a measure of the similarity or dissimilarity of the two geometries, see references below for more detailed explanations / descriptions.
+
+If \code{hausdorff} is TRUE and \code{densifyFrac} is specified then the geometries' segments are densified by splitting each segment into equal length subsegments whose fraction of the total length is equal to \code{densifyFrac}.
+} 
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gWithinDistance}}
+}
+
+\references{
+Hausdorff Differences:
+\url{http://en.wikipedia.org/wiki/Hausdorff_distance}
+\url{http://lin-ear-th-inking.blogspot.com/2009/01/computing-geometric-similarity.html}
+}
+
+\examples{
+
+pt1 = readWKT("POINT(0.5 0.5)")
+pt2 = readWKT("POINT(2 2)")
+
+p1 = readWKT("POLYGON((0 0,1 0,1 1,0 1,0 0))")
+p2 = readWKT("POLYGON((2 0,3 1,4 0,2 0))")
+
+gDistance(pt1,pt2)
+gDistance(p1,pt1)
+gDistance(p1,pt2)
+gDistance(p1,p2)
+
+
+p3 = readWKT("POLYGON((0 0,2 0,2 2,0 2,0 0))")
+p4 = readWKT("POLYGON((0 0,2 0,2 1.9,1.9 2,0 2,0 0))")
+p5 = readWKT("POLYGON((0 0,2 0,2 1.5,1.5 2,0 2,0 0))")
+p6 = readWKT("POLYGON((0 0,2 0,2 1,1 2,0 2,0 0))")
+p7 = readWKT("POLYGON((0 0,2 0,0 2,0 0))")
+
+gDistance(p3,hausdorff=TRUE)
+gDistance(p3,p4,hausdorff=TRUE)
+gDistance(p3,p5,hausdorff=TRUE)
+gDistance(p3,p6,hausdorff=TRUE)
+gDistance(p3,p7,hausdorff=TRUE)
+}
+
+\keyword{spatial}
+
diff --git a/man/misc-gLength.Rd b/man/misc-gLength.Rd
new file mode 100644
index 0000000..a4d9d67
--- /dev/null
+++ b/man/misc-gLength.Rd
@@ -0,0 +1,35 @@
+\name{gLength}
+\alias{gLength}
+\alias{RGEOSLength}
+
+\title{Length of Geometry}
+\description{Calculates the length of the given geometry.}
+\usage{
+	gLength(spgeom, byid=FALSE)
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+}
+
+\value{Returns the length of the geometry in the units of the current projection. By definition [MULTI]POINTs have a length of 0. The length of POLYGONs is the sum of the length of their shell and their hole(s).}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gArea}}
+}
+
+\examples{
+gLength(readWKT("POINT(1 1)"))
+
+gLength(readWKT("LINESTRING(0 0,1 1,2 2)"))
+gLength(readWKT("LINESTRING(0 0,1 1,2 0,3 1)"))
+
+gLength(readWKT("POLYGON((0 0,3 0,3 3,0 3,0 0))"))
+gLength(readWKT("POLYGON((0 0,3 0,3 3,0 3,0 0),(1 1,2 1,2 2,1 2,1 1))"))
+}
+
+\keyword{spatial}
+
diff --git a/man/misc-gNearestPoints.Rd b/man/misc-gNearestPoints.Rd
new file mode 100644
index 0000000..c2a810a
--- /dev/null
+++ b/man/misc-gNearestPoints.Rd
@@ -0,0 +1,37 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rgeos_misc.R
+\name{gNearestPoints}
+\alias{gNearestPoints}
+\title{Closest Points of two Geometries}
+\usage{
+gNearestPoints(spgeom1, spgeom2)
+}
+\arguments{
+\item{spgeom1, spgeom2}{sp objects as defined in package sp.}
+}
+\value{
+The closest points of the two geometries or NULL on exception.
+  The first point comes from spgeom1 geometry and the second point comes
+  from spgeom2.
+}
+\description{
+Return closest points of two geometries.
+}
+\examples{
+if (version_GEOS0() > "3.4.0") {
+g1 <- readWKT("MULTILINESTRING((34 54, 60 34), (0 10, 50 10, 100 50))")
+g2 <- readWKT("MULTIPOINT(30 0, 100 30)")
+plot(g1, pch=4, axes=TRUE)
+plot(g2, add=TRUE)
+plot(gNearestPoints(g1, g2), add=TRUE, col="red", pch=7)
+gDistance(g1, g2)
+}
+}
+\author{
+Rainer Stuetz
+}
+\seealso{
+\link{gDistance}
+}
+\keyword{spatial}
+
diff --git a/man/misc-over.Rd b/man/misc-over.Rd
new file mode 100644
index 0000000..60f526c
--- /dev/null
+++ b/man/misc-over.Rd
@@ -0,0 +1,36 @@
+\name{over}
+\alias{overGeomGeom}
+\alias{overGeomGeomDF}
+
+\title{Find spatial join or intersections}
+\description{Find spatial join or intersections}
+\usage{
+overGeomGeom(x, y, returnList = FALSE, fn = NULL, ..., minDimension = -1)
+overGeomGeomDF(x, y, returnList = FALSE, fn = NULL, ..., minDimension = -1)
+}
+
+\arguments{
+  \item{x}{see \link[sp]{over}}
+  \item{y}{see \link[sp]{over}}
+  \item{returnList}{see \link[sp]{over}}
+  \item{fn}{see \link[sp]{over}}
+  \item{...}{see \link[sp]{over}}
+  \item{minDimension}{integer; if \code{-1}, \link{gIntersects} is used to find
+  geometry intersections; if \code{0}, \code{1} or \code{2}, \link{gRelate} is used. if
+  \link{gRelate} is used, intersecting geometries are ordered by the dimension of the
+  intersection (2: area overlap; 1: line in common; 0: point in common), and \code{minDimension}
+  determines the mininum dimension of intersection required. }
+}
+
+\value{see \link[sp]{over}}
+\note{\link{gRelate} (\code{minDimension} > -1) is likely to be substantially slower than
+\link{gIntersects}.}
+
+\author{Edzer Pebesma}
+\examples{
+p1 = readWKT("POLYGON((0 1,0.95 0.31,0.59 -0.81,-0.59 -0.81,-0.95 0.31,0 1))")
+p2 = readWKT("POLYGON((2 2,-2 2,-2 -2,2 -2,2 2),(1 1,-1 1,-1 -1,1 -1,1 1))")
+
+overGeomGeom(p1,p2)
+}
+\keyword{spatial}
diff --git a/man/pred-binary-gContains.Rd b/man/pred-binary-gContains.Rd
new file mode 100644
index 0000000..22c9c2c
--- /dev/null
+++ b/man/pred-binary-gContains.Rd
@@ -0,0 +1,110 @@
+\name{gContains}
+\alias{gContains}
+\alias{gContainsProperly}
+\alias{gCovers}
+\alias{gCoveredBy}
+\alias{gWithin}
+\alias{RGEOSContains}
+\alias{RGEOSWithin}
+
+\title{Geometry Relationships - Contains and Within}
+\description{Functions for testing whether one geometry contains or is contained within another geometry}
+\usage{
+gContains(spgeom1, spgeom2 = NULL, byid = FALSE, prepared=TRUE,
+ returnDense=TRUE, STRsubset=FALSE, checkValidity=FALSE)
+gContainsProperly(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE,
+ checkValidity=FALSE)
+gCovers(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE)
+gCoveredBy(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE)
+gWithin(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE, checkValidity=FALSE)
+}
+	
+\arguments{
+  \item{spgeom1, spgeom2}{sp objects as defined in package sp. If spgeom2 is NULL then spgeom1 is compared to itself.}
+  \item{byid}{Logical vector determining if the function should be applied across ids (TRUE) or the entire object (FALSE) for spgeom1 and spgeom2}
+  \item{prepared}{Logical determining if prepared geometry (spatially indexed) version of the GEOS function should be used. In general prepared geometries should be faster than the alternative.}
+  \item{returnDense}{default TRUE, if false returns a list of the length of spgeom1 of integer vectors listing the \code{1:length(spgeom2)} indices which would be TRUE in the dense logical matrix representation; useful when the sizes of the byid=TRUE returned matrix is very large and it is sparse; essential when the returned matrix would be too large}
+  \item{checkValidity}{default FALSE; error meesages from GEOS do not say clearly which object fails if a topology exception is encountered. If this argument is TRUE, \code{gIsValid} is run on each in turn in an environment in which object names are available. If objects are invalid, this is reported and those affected are named}
+  \item{STRsubset}{logical argument for future use}
+}
+
+\value{\code{gContains} returns TRUE if none of the point of \code{spgeom2} is outside of \code{spgeom1} and at least one point of \code{spgeom2} falls within \code{spgeom1}.
+
+\code{gContainsProperly} returns TRUE under the same conditions as \code{gContains} with the additional requirement that \code{spgeom2} does not intersect with the boundary of \code{spgeom1}. As such any given geometry will Contain itself but will not ContainProperly itself. 
+
+\code{gCovers} returns TRUE if no point in \code{spgeom2} is outside of \code{spgeom1}. This is slightly different from \code{gContains} as it does not require a point within \code{spgeom1} which can be an issue as boundaries are not considered to be "within" a geometry, see \code{\link{gBoundary}} for specifics of geometry boundaries.
+
+
+\code{gCoveredBy} is the converse of \code{gCovers} and is equivalent to swapping \code{spgeom1} and \code{spgeom2}. 
+
+\code{gWithin} is the converse of \code{gContains} and is equivalent to swapping \code{spgeom1} and \code{spgeom2}. 
+}
+
+\note{Error messages from GEOS, in particular topology exceptions, report 0-based object order, so geom 0 is spgeom1, and geom 1 is spgeom2.}
+
+\references{
+Helpful information on the subtle differences between these functions:
+\url{http://lin-ear-th-inking.blogspot.com/2007/06/subtleties-of-ogc-covers-spatial.html}}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gCrosses}}
+\code{\link{gDisjoint}}
+\code{\link{gEquals}}
+\code{\link{gEqualsExact}}
+\code{\link{gIntersects}}
+\code{\link{gOverlaps}}
+\code{\link{gRelate}}
+\code{\link{gTouches}}
+}
+
+\examples{
+	l1 = readWKT("LINESTRING(0 3,1 1,2 2,3 0)")
+	l2 = readWKT("LINESTRING(1 3.5,3 3,2 1)")
+	l3 = readWKT("LINESTRING(1 3.5,3 3,4 1)")
+	
+	pt1 = readWKT("MULTIPOINT(1 1,3 0)")
+	pt2 = readWKT("MULTIPOINT(0 3,3 0)")
+	pt3 = readWKT("MULTIPOINT(1 1,2 2,3 1)")
+	
+	p1 = readWKT("POLYGON((0 0,0 2,1 3.5,3 3,4 1,3 0,0 0))")
+	p2 = readWKT("POLYGON((1 1,1 2,2 2,2 1,1 1))")
+
+	
+	par(mfrow=c(2,3))
+	plot(l1,col='blue');plot(pt1,add=TRUE,pch=16)
+	title(paste("Contains:",gContains(l1,pt1),
+				"\nContainsProperly:",gContainsProperly(l1,pt1),
+				"\nCovers:",gCovers(l1,pt1)))
+	
+	plot(l1,col='blue');plot(pt2,add=TRUE,pch=16)
+	title(paste("Contains:",gContains(l1,pt2),
+				"\nContainsProperly:",gContainsProperly(l1,pt2),
+				"\nCovers:",gCovers(l1,pt2)))
+	
+	plot(p1,col='blue',border='blue');plot(pt3,add=TRUE,pch=16)
+	title(paste("Contains:",gContains(p1,pt3),
+				"\nContainsProperly:",gContainsProperly(p1,pt3),
+				"\nCovers:",gCovers(p1,pt3)))
+	
+	plot(p1,col='blue',border='blue');plot(l2,lwd=2,add=TRUE,pch=16)
+	title(paste("Contains:",gContains(p1,l2),
+				"\nContainsProperly:",gContainsProperly(p1,l2),
+				"\nCovers:",gCovers(p1,l2)))
+
+	plot(p1,col='blue',border='blue');plot(l3,lwd=2,add=TRUE,pch=16)
+	title(paste("Contains:",gContains(p1,l3),
+				"\nContainsProperly:",gContainsProperly(p1,l3),
+				"\nCovers:",gCovers(p1,l3)))
+
+	plot(p1,col='blue',border='blue');plot(p2,col='black',add=TRUE,pch=16)
+	title(paste("Contains:",gContains(p1,p2),
+				"\nContainsProperly:",gContainsProperly(p1,p2),
+				"\nCovers:",gCovers(p1,p2)))
+	
+	
+}
+\keyword{spatial}
+
+
diff --git a/man/pred-binary-gCrosses.Rd b/man/pred-binary-gCrosses.Rd
new file mode 100644
index 0000000..7c15ddb
--- /dev/null
+++ b/man/pred-binary-gCrosses.Rd
@@ -0,0 +1,85 @@
+\name{gCrosses}
+\alias{gCrosses}
+\alias{RGEOSCrosses}
+\alias{gOverlaps}
+\alias{RGEOSOverlaps}
+
+\title{Geometry Relationships - Crosses and Overlaps}
+\description{Functions for testing whether geometries share some but not all interior points}
+\usage{
+	gCrosses(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE,
+ checkValidity=FALSE)
+	gOverlaps(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE,
+ checkValidity=FALSE)
+}
+	
+\arguments{
+  \item{spgeom1, spgeom2}{sp objects as defined in package sp. If spgeom2 is NULL then spgeom1 is compared to itself.}
+  \item{byid}{Logical vector determining if the function should be applied across ids (TRUE) or the entire object (FALSE) for spgeom1 and spgeom2}
+  \item{returnDense}{default TRUE, if false returns a list of the length of spgeom1 of integer vectors listing the \code{1:length(spgeom2)} indices which would be TRUE in the dense logical matrix representation; useful when the sizes of the byid=TRUE returned matrix is very large and it is sparse; essential when the returned matrix would be too large}
+  \item{checkValidity}{default FALSE; error meesages from GEOS do not say clearly which object fails if a topology exception is encountered. If this argument is TRUE, \code{gIsValid} is run on each in turn in an environment in which object names are available. If objects are invalid, this is reported and those affected are named}
+}
+
+\value{\code{gCrosses} returns TRUE when the geometries share some but not all interior points, and the dimension of the intersection is less than that of at least one of the geometries.
+
+\code{gOverlaps} returns TRUE when the geometries share some but not all interior points, and the intersection has the same dimension as the geometries themselves.
+}
+
+\note{Error messages from GEOS, in particular topology exceptions, report 0-based object order, so geom 0 is spgeom1, and geom 1 is spgeom2.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gContains}}
+\code{\link{gContainsProperly}}
+\code{\link{gCovers}}
+\code{\link{gCoveredBy}}
+\code{\link{gDisjoint}}
+\code{\link{gEquals}}
+\code{\link{gEqualsExact}}
+\code{\link{gIntersects}}
+\code{\link{gRelate}}
+\code{\link{gTouches}}
+\code{\link{gWithin}}
+}
+
+\examples{
+	l1 = readWKT("LINESTRING(0 3,1 1,2 2,3 0)")
+	l2 = readWKT("LINESTRING(0 0.5,1 1,2 2,3 2.5)")
+	l3 = readWKT("LINESTRING(1 3,1.5 1,2.5 2)")
+	
+	pt1 = readWKT("MULTIPOINT(1 1,3 0)")
+	pt2 = readWKT("MULTIPOINT(1 1,3 0,1 2)")
+
+	p1 = readWKT("POLYGON((0 0,0 2,1 3.5,3 3,4 1,3 0,0 0))")
+	p2 = readWKT("POLYGON((2 2,3 4,4 1,4 0,2 2))")
+	
+	par(mfrow=c(2,3))
+	plot(l1,col='blue');plot(pt1,add=TRUE,pch=16)
+	title(paste("Crosses:",gCrosses(l1,pt1),
+				"\nOverlaps:",gOverlaps(l1,pt1)))
+	
+	plot(l1,col='blue');plot(pt2,add=TRUE,pch=16)
+	title(paste("Crosses:",gCrosses(l1,pt2),
+				"\nOverlaps:",gOverlaps(l1,pt2)))
+				
+	plot(l1,col='blue');plot(l2,add=TRUE)
+	title(paste("Crosses:",gCrosses(l1,l2),
+				"\nOverlaps:",gOverlaps(l1,l2)))
+				
+	plot(l1,col='blue');plot(l3,add=TRUE)
+	title(paste("Crosses:",gCrosses(l1,l3),
+				"\nOverlaps:",gOverlaps(l1,l3)))
+				
+	plot(p1,border='blue',col='blue');plot(l1,add=TRUE)
+	title(paste("Crosses:",gCrosses(p1,l1),
+				"\nOverlaps:",gOverlaps(p1,l1)))
+
+	plot(p1,border='blue',col='blue');plot(p2,add=TRUE)
+	title(paste("Crosses:",gCrosses(p1,p2),
+				"\nOverlaps:",gOverlaps(p1,p2)))
+				
+}
+\keyword{spatial}
+
+
diff --git a/man/pred-binary-gEquals.Rd b/man/pred-binary-gEquals.Rd
new file mode 100644
index 0000000..f6b589c
--- /dev/null
+++ b/man/pred-binary-gEquals.Rd
@@ -0,0 +1,83 @@
+\name{gEquals}
+\alias{gEquals}
+\alias{RGEOSEquals}
+\alias{gEqualsExact}
+\alias{RGEOSEqualsExact}
+
+\title{Geometry Relationships - Equality}
+\description{Function for testing equivalence of the given geometries}
+\usage{
+	gEquals(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE,
+ checkValidity=FALSE)
+	gEqualsExact(spgeom1, spgeom2 = NULL, tol=0.0, byid = FALSE,
+ returnDense=TRUE, checkValidity=FALSE)
+}
+
+\arguments{
+  \item{spgeom1, spgeom2}{sp objects as defined in package sp. If spgeom2 is NULL then spgeom1 is compared to itself.}
+  \item{byid}{Logical vector determining if the function should be applied across ids (TRUE) or the entire object (FALSE) for spgeom1 and spgeom2}
+  \item{tol}{Numerical value of tolerance to use when assessing equivalence}
+  \item{returnDense}{default TRUE, if false returns a list of the length of spgeom1 of integer vectors listing the \code{1:length(spgeom2)} indices which would be TRUE in the dense logical matrix representation; useful when the sizes of the byid=TRUE returned matrix is very large and it is sparse; essential when the returned matrix would be too large}
+  \item{checkValidity}{default FALSE; error meesages from GEOS do not say clearly which object fails if a topology exception is encountered. If this argument is TRUE, \code{gIsValid} is run on each in turn in an environment in which object names are available. If objects are invalid, this is reported and those affected are named}
+}
+
+\value{\code{gEquals} returns TRUE if geometries are "spatially equivalent" which requires that \code{spgeom1} is within \code{spgeom2} and \code{spgeom2} is within \code{spgeom1}, this ignores ordering of points within the geometries. Note that it is possible for geometries with different coordinates to be "spatially equivalent".
+
+\code{gEqualsExact} returns TRUE if geometries are "exactly equivalent" which requires that \code{spgeom1} and \code{spgeom1} are "spatially equivalent" and that their constituent points are in the same order.
+}
+
+\note{Error messages from GEOS, in particular topology exceptions, report 0-based object order, so geom 0 is spgeom1, and geom 1 is spgeom2.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gContains}}
+\code{\link{gContainsProperly}}
+\code{\link{gCovers}}
+\code{\link{gCoveredBy}}
+\code{\link{gCrosses}}
+\code{\link{gDisjoint}}
+\code{\link{gEqualsExact}}
+\code{\link{gIntersects}}
+\code{\link{gOverlaps}}
+\code{\link{gRelate}}
+\code{\link{gTouches}}
+\code{\link{gWithin}}
+}
+
+
+\examples{
+
+# p1 and p2 are spatially identical but not exactly identical due to point ordering
+p1=readWKT("POLYGON((0 0,1 0,1 1,0 1,0 0))")
+p2=readWKT("POLYGON((1 1,0 1,0 0,1 0,1 1))")
+p3=readWKT("POLYGON((0.01 0.01,1.01 0.01,1.01 1.01,0.01 1.01,0.01 0.01))")
+
+gEquals(p1,p2)
+gEquals(p1,p3)
+gEqualsExact(p1,p2)
+gEqualsExact(p1,p3,tol=0)
+gEqualsExact(p1,p3,tol=0.1)
+
+# pt1 and p2t are spatially identical but not exactly identical due to point ordering
+pt1 = readWKT("MULTIPOINT(1 1,2 2,3 3)")
+pt2 = readWKT("MULTIPOINT(3 3,2 2,1 1)")
+pt3 = readWKT("MULTIPOINT(1.01 1.01,2.01 2.01,3.01 3.01)")
+
+gEquals(pt1,pt2)
+gEquals(pt1,pt3)
+gEqualsExact(pt1,pt2)
+gEqualsExact(pt1,pt3,tol=0)
+gEqualsExact(pt1,pt3,tol=0.1)
+
+
+# l2 contains a point that l1 does not
+l1 = readWKT("LINESTRING (10 10, 20 20)")
+l2 = readWKT("LINESTRING (10 10, 15 15,20 20)")
+gEquals(l1,l2)
+gEqualsExact(l1,l2)
+
+}
+\keyword{spatial}
+
+
diff --git a/man/pred-binary-gIntersects.Rd b/man/pred-binary-gIntersects.Rd
new file mode 100644
index 0000000..711382e
--- /dev/null
+++ b/man/pred-binary-gIntersects.Rd
@@ -0,0 +1,92 @@
+\name{gIntersects}
+\alias{gIntersects}
+\alias{RGEOSIntersects}
+\alias{gDisjoint}
+\alias{RGEOSDisjoint}
+
+\title{Geometry Relationships - Intersects and Disjoint}
+\description{Function for testing if the geometries have at least one point in common or no points in common}
+\usage{
+gIntersects(spgeom1, spgeom2 = NULL, byid = FALSE, prepared=TRUE,
+ returnDense=TRUE, checkValidity=FALSE)
+gDisjoint(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE,
+ checkValidity=FALSE)
+}
+	
+\arguments{
+  \item{spgeom1, spgeom2}{sp objects as defined in package sp. If spgeom2 is NULL then spgeom1 is compared to itself.}
+  \item{byid}{Logical vector determining if the function should be applied across ids (TRUE) or the entire object (FALSE) for spgeom1 and spgeom2}
+  \item{prepared}{Logical determining if prepared geometry (spatially indexed) version of the GEOS function should be used. In general prepared geometries should be faster than the alternative.}
+  \item{returnDense}{default TRUE, if false returns a list of the length of spgeom1 of integer vectors listing the \code{1:length(spgeom2)} indices which would be TRUE in the dense logical matrix representation; useful when the sizes of the byid=TRUE returned matrix is very large and it is sparse; essential when the returned matrix would be too large}
+  \item{checkValidity}{default FALSE; error meesages from GEOS do not say clearly which object fails if a topology exception is encountered. If this argument is TRUE, \code{gIsValid} is run on each in turn in an environment in which object names are available. If objects are invalid, this is reported and those affected are named}
+}
+
+\value{\code{gIntersects} returns TRUE if \code{spgeom1} and \code{spgeom2} have at least one point in common.
+
+\code{gDisjoint} returns TRUE if \code{spgeom1} and \code{spgeom2} have no points in common.
+
+Both return a conforming logical matrix if \code{byid = TRUE}.
+}
+
+\note{Error messages from GEOS, in particular topology exceptions, report 0-based object order, so geom 0 is spgeom1, and geom 1 is spgeom2.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gContains}}
+\code{\link{gContainsProperly}}
+\code{\link{gCovers}}
+\code{\link{gCoveredBy}}
+\code{\link{gCrosses}}
+\code{\link{gEquals}}
+\code{\link{gEqualsExact}}
+\code{\link{gOverlaps}}
+\code{\link{gRelate}}
+\code{\link{gTouches}}
+\code{\link{gWithin}}
+}
+
+\examples{
+	p1 = readWKT("POLYGON((0 0,1 0,1 1,0 1,0 0))")
+	p2 = readWKT("POLYGON((0.5 1,0 2,1 2,0.5 1))")
+	p3 = readWKT("POLYGON((0.5 0.5,0 1.5,1 1.5,0.5 0.5))")
+
+	l1 = readWKT("LINESTRING(0 3,1 1,2 2,3 0)")
+	l2 = readWKT("LINESTRING(1 3.5,3 3,2 1)")
+	l3 = readWKT("LINESTRING(-0.1 0,-0.1 1.1,1 1.1)")
+	
+	pt1 = readWKT("MULTIPOINT(1 1,3 0,2 1)")
+	pt2 = readWKT("MULTIPOINT(0 3,3 0,2 1)")
+	pt3 = readWKT("MULTIPOINT(-0.2 0,1 -0.2,1.2 1,0 1.2)")
+
+	
+	par(mfrow=c(3,2))
+	plot(p1,col='blue',border='blue',ylim=c(0,2.5));plot(p2,col='black',add=TRUE,pch=16)
+	title(paste("Intersects:",gIntersects(p1,p2),
+				"\nDisjoint:",gDisjoint(p1,p2)))
+	
+	plot(p1,col='blue',border='blue',ylim=c(0,2.5));plot(p3,col='black',add=TRUE,pch=16)
+	title(paste("Intersects:",gIntersects(p1,p3),
+				"\nDisjoint:",gDisjoint(p1,p3)))
+				
+	plot(l1,col='blue');plot(pt1,add=TRUE,pch=16)
+	title(paste("Intersects:",gIntersects(l1,pt1),
+				"\nDisjoint:",gDisjoint(l1,pt1)))
+	
+	plot(l1,col='blue');plot(pt2,add=TRUE,pch=16)
+	title(paste("Intersects:",gIntersects(l1,pt2),
+				"\nDisjoint:",gDisjoint(l1,pt2)))
+	
+	plot(p1,col='blue',border='blue',xlim=c(-0.5,2),ylim=c(0,2.5))
+	plot(l3,lwd=2,col='black',add=TRUE)
+	title(paste("Intersects:",gIntersects(p1,l3),
+				"\nDisjoint:",gDisjoint(p1,l3)))
+	
+	plot(p1,col='blue',border='blue',xlim=c(-0.5,2),ylim=c(-0.5,2))
+	plot(pt3,pch=16,col='black',add=TRUE)
+	title(paste("Intersects:",gIntersects(p1,pt3),
+				"\nDisjoint:",gDisjoint(p1,pt3)))
+}
+\keyword{spatial}
+
+
diff --git a/man/pred-binary-gRelate.Rd b/man/pred-binary-gRelate.Rd
new file mode 100644
index 0000000..332ce6f
--- /dev/null
+++ b/man/pred-binary-gRelate.Rd
@@ -0,0 +1,120 @@
+\name{gRelate}
+\alias{gRelate}
+\alias{RGEOSRelate}
+
+\title{Geometry Relationships - Intersection Matrix Pattern (DE-9IM)}
+\description{Determines the relationships between two geometries by comparing the intersection of Interior, Boundary and Exterior  of both geometries to each other. The results are summarized by the Dimensionally Extended 9-Intersection Matrix or DE-9IM.}
+\usage{
+	gRelate(spgeom1, spgeom2 = NULL, pattern = NULL, byid = FALSE,
+ checkValidity=FALSE)
+}
+	
+\arguments{
+  \item{spgeom1, spgeom2}{sp objects as defined in package sp. If spgeom2 is NULL then spgeom1 is compared to itself.}
+  \item{byid}{Logical vector determining if the function should be applied across ids (TRUE) or the entire object (FALSE) for spgeom1 and spgeom2}
+  \item{pattern}{Character string containing intersection matrix pattern to match against DE-9IM for given geometries. Wild card \code{*} or \code{*} characters allowed.}
+  \item{checkValidity}{default FALSE; error meesages from GEOS do not say clearly which object fails if a topology exception is encountered. If this argument is TRUE, \code{gIsValid} is run on each in turn in an environment in which object names are available. If objects are invalid, this is reported and those affected are named}
+}
+
+\value{By default returns a 9 character string that represents the DE-9IM.
+
+If \code{pattern} returns TRUE if the pattern matches the DE-9IM.}
+
+\details{Each geometry is decomposed into an interior, a boundary, and an exterior region, all the resulting geometries are then tested by intersection against one another resulting in 9 total comparisons. These comparisons are summarized by the dimensions of the intersection region, as such intersection at point(s) is labeled \code{0}, at linestring(s) is labeled \code{1}, at polygons(s) is labeled \code{2}, and if they do not intersect labeled \code{F}.
+
+If a pattern is specified then limited matching with wildcards is possible, \code{*} matches any character whereas \code{T} matches any non-\code{F} character.
+
+See references for additional details.
+} 
+
+\note{Error messages from GEOS, in particular topology exceptions, report 0-based object order, so geom 0 is spgeom1, and geom 1 is spgeom2.}
+
+\references{
+Documentation of Intersection Matrix Patterns:
+\url{http://docs.geotools.org/stable/userguide/library/jts/dim9.html}
+}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gContains}}
+\code{\link{gContainsProperly}}
+\code{\link{gCovers}}
+\code{\link{gCoveredBy}}
+\code{\link{gCrosses}}
+\code{\link{gDisjoint}}
+\code{\link{gEquals}}
+\code{\link{gEqualsExact}}
+\code{\link{gIntersects}}
+\code{\link{gOverlaps}}
+\code{\link{gTouches}}
+\code{\link{gWithin}}
+}
+
+\examples{
+	x = readWKT("POLYGON((1 0,0 1,1 2,2 1,1 0))")
+	x.inter = x
+	x.bound = gBoundary(x)
+	
+	y = readWKT("POLYGON((2 0,1 1,2 2,3 1,2 0))")
+	y.inter = y
+	y.bound = gBoundary(y)
+	
+	
+	xy.inter = gIntersection(x,y)
+	xy.inter.bound = gBoundary(xy.inter)
+	
+	xy.union = gUnion(x,y)
+	bbox = gBuffer(gEnvelope(xy.union),width=0.5,joinStyle='mitre',mitreLimit=3)
+
+	x.exter = gDifference(bbox,x)
+	y.exter = gDifference(bbox,y)
+
+	# geometry decomposition
+	par(mfrow=c(2,3))
+	plot(bbox,border='grey');plot(x,col="black",add=TRUE);title("Interior",ylab = "Polygon X")
+	plot(bbox,border='grey');plot(x.bound,col="black",add=TRUE);title("Boundary")
+	plot(bbox,border='grey');plot(x.exter,col="black",pbg='white',add=TRUE);title("Exterior")
+	plot(bbox,border='grey');plot(y,col="black",add=TRUE);title(ylab = "Polygon Y")
+	plot(bbox,border='grey');plot(y.bound,col="black",add=TRUE)
+	plot(bbox,border='grey');plot(y.exter,col="black",pbg='white',add=TRUE)
+	
+	
+	
+	defaultplot = function() {
+		plot(bbox,border='grey')
+		plot(x,add=TRUE,col='red1',border="red3")
+		plot(y,add=TRUE,col='blue1',border="blue3")		
+		plot(xy.inter,add=TRUE,col='orange1',border="orange3")
+	}
+	
+	# Dimensionally Extended 9-Intersection Matrix
+	pat = gRelate(x,y)
+	patchars = strsplit(pat,"")[[1]]
+	
+	par(mfrow=c(3,3))
+	defaultplot(); plot(gIntersection(x.inter,y.inter),add=TRUE,col='black')
+	title(paste("dim:",patchars[1]))
+	defaultplot(); plot(gIntersection(x.bound,y.inter),add=TRUE,col='black',lwd=2)
+	title(paste("dim:",patchars[2]))
+	defaultplot(); plot(gIntersection(x.exter,y.inter),add=TRUE,col='black')
+	title(paste("dim:",patchars[3]))
+	
+	defaultplot(); plot(gIntersection(x.inter,y.bound),add=TRUE,col='black',lwd=2)
+	title(paste("dim:",patchars[4]))
+	defaultplot(); plot(gIntersection(x.bound,y.bound),add=TRUE,col='black',pch=16)
+	title(paste("dim:",patchars[5]))
+	defaultplot(); plot(gIntersection(x.exter,y.bound),add=TRUE,col='black',lwd=2)
+	title(paste("dim:",patchars[6]))
+	
+	defaultplot(); plot(gIntersection(x.inter,y.exter),add=TRUE,col='black')
+	title(paste("dim:",patchars[7]))
+	defaultplot(); plot(gIntersection(x.bound,y.exter),add=TRUE,col='black',lwd=2)
+	title(paste("dim:",patchars[8]))
+	defaultplot(); plot(gIntersection(x.exter,y.exter),add=TRUE,col='black')
+	title(paste("dim:",patchars[9]))
+	
+}
+\keyword{spatial}
+
+
diff --git a/man/pred-binary-gTouches.Rd b/man/pred-binary-gTouches.Rd
new file mode 100644
index 0000000..9173fda
--- /dev/null
+++ b/man/pred-binary-gTouches.Rd
@@ -0,0 +1,76 @@
+\name{gTouches}
+\alias{gTouches}
+\alias{RGEOSTouches}
+
+\title{Geometry Relationships - Touches}
+\description{Functions for testing if the geometries have at least one boundary point in common, but no interior points}
+\usage{
+	gTouches(spgeom1, spgeom2 = NULL, byid = FALSE, returnDense=TRUE,
+ checkValidity=FALSE)
+}
+	
+\arguments{
+  \item{spgeom1, spgeom2}{sp objects as defined in package sp. If spgeom2 is NULL then spgeom1 is compared to itself.}
+  \item{byid}{Logical vector determining if the function should be applied across ids (TRUE) or the entire object (FALSE) for spgeom1 and spgeom2}
+  \item{returnDense}{default TRUE, if false returns a list of the length of spgeom1 of integer vectors listing the \code{1:length(spgeom2)} indices which would be TRUE in the dense logical matrix representation; useful when the sizes of the byid=TRUE returned matrix is very large and it is sparse; essential when the returned matrix would be too large}
+  \item{checkValidity}{default FALSE; error meesages from GEOS do not say clearly which object fails if a topology exception is encountered. If this argument is TRUE, \code{gIsValid} is run on each in turn in an environment in which object names are available. If objects are invalid, this is reported and those affected are named}
+}
+
+\value{Returns TRUE if the intersection of the boundaries of the two geometries is not empty.}
+
+\note{Error messages from GEOS, in particular topology exceptions, report 0-based object order, so geom 0 is spgeom1, and geom 1 is spgeom2.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gContains}}
+\code{\link{gContainsProperly}}
+\code{\link{gCovers}}
+\code{\link{gCoveredBy}}
+\code{\link{gCrosses}}
+\code{\link{gDisjoint}}
+\code{\link{gEquals}}
+\code{\link{gEqualsExact}}
+\code{\link{gIntersects}}
+\code{\link{gOverlaps}}
+\code{\link{gRelate}}
+\code{\link{gWithin}}
+}
+
+\examples{
+
+	p1 = readWKT("POLYGON((0 0,1 0,1 1,0 1,0 0))")
+	p2 = readWKT("POLYGON((0 1,0.5 2,1 1,0 1))")
+	p3 = readWKT("POLYGON((0.5 1,0 2,1 2,0.5 1))")
+	p4 = readWKT("POLYGON((0.5 0.5,0 1.5,1 1.5,0.5 0.5))")
+	
+	l0 = readWKT("LINESTRING(0 1,0.5 2,1 1)")
+	
+	l1 = readWKT("LINESTRING(0 0,2 2)")
+	l2 = readWKT("LINESTRING(1 1,2 0)")
+	l3 = readWKT("LINESTRING(0 2,2 0)")
+	
+	
+	par(mfrow=c(2,3))
+	plot(p1,col='blue',border='blue',ylim=c(0,2.5));plot(p2,col='black',add=TRUE,pch=16)
+	title(paste("Touches:",gTouches(p1,p2)))
+	
+	plot(p1,col='blue',border='blue',ylim=c(0,2.5));plot(p3,col='black',add=TRUE,pch=16)
+	title(paste("Touches:",gTouches(p1,p3)))
+	
+	plot(p1,col='blue',border='blue',ylim=c(0,2.5));plot(p4,col='black',add=TRUE,pch=16)
+	title(paste("Touches:",gTouches(p1,p4)))
+	
+	plot(p1,col='blue',border='blue',ylim=c(0,2.5));plot(l0,lwd=2,col='black',add=TRUE,pch=16)
+	title(paste("Touches:",gTouches(p1,l0)))
+	
+	plot(l1,lwd=2,col='blue');plot(l2,lwd=2,col='black',add=TRUE,pch=16)
+	title(paste("Touches:",gTouches(l1,l2)))
+	
+	plot(l1,lwd=2,col='blue');plot(l3,lwd=2,col='black',add=TRUE,pch=16)
+	title(paste("Touches:",gTouches(l1,l3)))
+	
+}
+\keyword{spatial}
+
+
diff --git a/man/pred-unary-gIsEmpty.Rd b/man/pred-unary-gIsEmpty.Rd
new file mode 100644
index 0000000..16d9999
--- /dev/null
+++ b/man/pred-unary-gIsEmpty.Rd
@@ -0,0 +1,38 @@
+\name{gIsEmpty}
+\alias{gIsEmpty}
+\alias{RGEOSisEmpty}
+
+\title{Is Geometry Empty?}
+\description{Tests if the given geometry is empty}
+\usage{
+gIsEmpty(spgeom, byid = FALSE) 
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+}
+
+\details{Because no sp Spatial object may be empty, the function exists but cannot work, as \code{readWKT} is not permitted to create an empty object.}
+
+\value{Returns TRUE if the given geometry is empty, FALSE otherwise.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gIsRing}}
+\code{\link{gIsSimple}}
+\code{\link{gIsValid}}
+}
+
+\examples{
+try(gIsEmpty(readWKT("POINT EMPTY")))
+gIsEmpty(readWKT("POINT(1 1)"))
+try(gIsEmpty(readWKT("LINESTRING EMPTY")))
+gIsEmpty(readWKT("LINESTRING(0 0,1 1)"))
+try(gIsEmpty(readWKT("POLYGON EMPTY")))
+gIsEmpty(readWKT("POLYGON((0 0,1 0,1 1,0 1,0 0))"))
+}
+
+\keyword{spatial}
+
diff --git a/man/pred-unary-gIsRing.Rd b/man/pred-unary-gIsRing.Rd
new file mode 100644
index 0000000..8bedc5c
--- /dev/null
+++ b/man/pred-unary-gIsRing.Rd
@@ -0,0 +1,49 @@
+\name{gIsRing}
+\alias{gIsRing}
+\alias{RGEOSisRing}
+
+\title{Is Geometry a Ring?}
+\description{Tests if the given geometry is a ring}
+\usage{
+gIsRing(spgeom, byid = FALSE) 
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+}
+
+\value{Returns TRUE if the geometry is a LINEARRING.
+
+Returns TRUE if the geometry is a LINESTRING that is both Simple (\link{gIsSimple}) and Closed (end points intersect), FALSE otherwise.
+
+Returns FALSE if the geometry is a [MULTI]POINT, MULTILINESTRING, or [MULTI]POLYGON.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gIsEmpty}}
+\code{\link{gIsSimple}}
+\code{\link{gIsValid}}
+}
+
+\examples{
+
+l1 = readWKT("LINESTRING(0 0, 1 1, 1 0, 0 1, 0 0)")
+l2 = readWKT("LINESTRING(0 0,1 0,1 1,0 1,0 0)")
+r1 = readWKT("LINEARRING(0 0, 1 1, 1 0, 0 1, 0 0)")
+r2 = readWKT("LINEARRING(0 0,1 0,1 1,0 1,0 0)")
+p1 = readWKT("POLYGON((0 0, 1 1, 1 0, 0 1, 0 0))")
+p2 = readWKT("POLYGON((0 0,1 0,1 1,0 1,0 0))")
+
+par(mfrow=c(3,2))
+plot(l1);title(paste("LINESTRING\nRing:",gIsRing(l1)))
+plot(l2);title(paste("LINESTRING\nRing:",gIsRing(l2)))
+plot(r1);title(paste("LINEARRING\nRing:",gIsRing(r1)))
+plot(r2);title(paste("LINEARRING\nRing:",gIsRing(r2)))
+plot(p1);title(paste("POLYGON\nRing:",gIsRing(p1)))
+plot(p2);title(paste("POLYGON\nRing:",gIsRing(p2)))
+}
+
+\keyword{spatial}
+
diff --git a/man/pred-unary-gIsSimple.Rd b/man/pred-unary-gIsSimple.Rd
new file mode 100644
index 0000000..9bea8ee
--- /dev/null
+++ b/man/pred-unary-gIsSimple.Rd
@@ -0,0 +1,78 @@
+\name{gIsSimple}
+\alias{gIsSimple}
+\alias{RGEOSisSimple}
+
+\title{Is Geometry Simple?}
+\description{Function tests if the given geometry is simple}
+\usage{
+gIsSimple(spgeom, byid = FALSE) 
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+}
+
+\value{Returns TRUE if the given geometry does not contain anomalous points, such as self intersection or self tangency.}
+
+\details{Simplicity is used in reference to 0 and 1-dimensional geometries ([MULTI]POINT and [MULTI]LINESTRING) whereas Validity (\code{\link{gIsValid}}) is used in reference to 2-dimensional geometries ([MULTI]POLYGON). 
+
+A POINT is always simple.
+
+A MULTIPOINT is simple if no two points are identical.
+
+A LINESTRING is simple if it does not pass through the same point twice (self intersection) except at the end points, in which case it is a ring (\code{\link{gIsRing}}).
+
+A MULTILINESTRING is simple if all of its subgeometries are simple and none of the subgeometries intersect except at end points.
+
+A [MULTI]POLYGON is simple by definition.
+
+Many of the functions in rgeos expect simple/valid geometries and may exhibit unpredictable behavior if given an invalid geometry. Checking of validity/simplicity can be computationally expensive for complex geometries and so is not done by default, any new geometries should be checked.
+}
+
+
+\references{
+Validity Details:
+\url{http://postgis.net/docs/manual-2.0/using_postgis_dbmanagement.html#OGC_Validity}
+}
+
+
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gIsEmpty}}
+\code{\link{gIsRing}}
+\code{\link{gIsValid}}
+}
+
+\examples{
+# MULTIPOINT examples
+gIsSimple(readWKT("MULTIPOINT(1 1,2 2,3 3)"))
+gIsSimple(readWKT("MULTIPOINT(1 1,2 2,1 1)"))
+
+# LINESTRING examples
+l1 = readWKT("LINESTRING(0 5,3 4,2 3,5 2)")
+l2 = readWKT("LINESTRING(0 5,4 2,5 4,0 1)")
+l3 = readWKT("LINESTRING(3 5,0 4,0 2,2 0,5 1,4 4,4 5,3 5)")
+l4 = readWKT("LINESTRING(3 5,0 4,4 3,5 2,3 0,1 2,4 5,3 5)")
+
+par(mfrow=c(2,2))
+plot(l1);title(paste("Simple:",gIsSimple(l1)))
+plot(l2);title(paste("Simple:",gIsSimple(l2)))
+plot(l3);title(paste("Simple:",gIsSimple(l3)))
+plot(l4);title(paste("Simple:",gIsSimple(l4)))
+
+# MULTILINESTRING examples
+ml1 = readWKT("MULTILINESTRING((0 5,1 2,5 0),(3 5,5 4,4 1))")
+ml2 = readWKT("MULTILINESTRING((0 5,1 2,5 0),(0 5,5 4,4 1))")
+ml3 = readWKT("MULTILINESTRING((0 5,1 2,5 0),(3 5,5 4,2 0))")
+
+par(mfrow=c(1,3))
+plot(ml1);title(paste("Simple:",gIsSimple(ml1)))
+plot(ml2);title(paste("Simple:",gIsSimple(ml2)))
+plot(ml3);title(paste("Simple:",gIsSimple(ml3)))	
+}
+
+\keyword{spatial}
+
diff --git a/man/pred-unary-gIsValid.Rd b/man/pred-unary-gIsValid.Rd
new file mode 100644
index 0000000..aff8b92
--- /dev/null
+++ b/man/pred-unary-gIsValid.Rd
@@ -0,0 +1,88 @@
+\name{gIsValid}
+\alias{gIsValid}
+\alias{RGEOSisValid}
+
+\title{Is Geometry Valid?}
+\description{Function tests if the given geometry is valid}
+\usage{
+gIsValid(spgeom, byid = FALSE, reason=FALSE)
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+  \item{reason}{Logical determining if the function should return a character string describing why the geometry is invalid}
+}
+
+\value{By default will return TRUE if the given geometry is well formed, FALSE otherwise. If reason is set to TRUE then a character string is returned describing the geometry, "Valid Geometry" if it is valid or details of the specific issue. Any given geometry may have multiple issues that make it invalid, gIsValid will only return the first, once it has been corrected additionally checking is necessary to confirm that additional issues do not remain.}
+
+\details{Validity is used in reference to 2-dimensional geometries (LINEARRING and [MULTI]POLYGON) whereas Simplicity (\code{\link{gIsSimple}}) is used in reference to 0 and 1-dimensional geometries ([MULTI]POINT and [MULTI]LINESTRING).
+
+A LINEARRING is valid if it does not intersect itself.
+
+A POLYGON is valid if no two rings in the boundary (made up of an exterior ring and interior rings) cross. The boundary of a POLYGON may intersect at a POINT but only as a tangent (i.e. not on a line). A POLYGON may not have cut lines or spikes and the interior rings must be contained entirely within the exterior ring.
+
+A MULTIPOLYGON is valid if and only if all of its elements are valid and the interiors of no two elements intersect. The boundaries of any two elements may touch, but only at a finite number of POINTs.
+
+Many of the functions in rgeos expect simple/valid geometries and may exhibit unpredictable behavior if given an invalid geometry. Checking of validity/simplicity can be computationally expensive for complex geometries and so is not done by default, any new geometries should be checked.
+}
+
+
+\references{
+Validity Details:
+\url{http://postgis.net/docs/manual-2.0/using_postgis_dbmanagement.html#OGC_Validity}
+}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gIsEmpty}}
+\code{\link{gIsRing}}
+\code{\link{gIsSimple}}
+}
+
+\examples{
+
+#LINEARRING Example
+l = readWKT("LINEARRING(0 0, 100 100, 100 0, 0 100, 0 0)")
+plot(l);title(paste("Valid:",gIsValid(l),"\n",gIsValid(l,reason=TRUE)))
+
+#POLYGON and MULTIPOLYGON Examples
+p1 = readWKT("POLYGON ((0 60, 0 0, 60 0, 60 60, 0 60), (20 40, 20 20, 40 20, 40 40, 20 40))")
+p2 = readWKT("POLYGON ((0 60, 0 0, 60 0, 60 60, 0 60), (20 40, 20 20, 60 20, 20 40))")
+p3 = readWKT(paste("POLYGON ((0 120, 0 0, 140 0, 140 120, 0 120),",
+ "(100 100, 100 20, 120 20, 120 100, 100 100),",
+ "(20 100, 20 40, 100 40, 20 100))"))
+
+p4 = readWKT("POLYGON ((0 40, 0 0, 40 40, 40 0, 0 40))")
+p5 = readWKT("POLYGON ((-10 50, 50 50, 50 -10, -10 -10, -10 50), (0 40, 0 0, 40 40, 40 0, 0 40))")
+p6 = readWKT("POLYGON ((0 60, 0 0, 60 0, 60 20, 100 20, 60 20, 60 60, 0 60))")
+p7 = readWKT(paste("POLYGON ((40 300, 40 20, 280 20, 280 300, 40 300),",
+ "(120 240, 80 180, 160 220, 120 240),",
+ "(220 240, 160 220, 220 160, 220 240),",
+ "(160 100, 80 180, 100 80, 160 100),",
+ "(160 100, 220 160, 240 100, 160 100))"))
+p8 = readWKT(paste("POLYGON ((40 320, 340 320, 340 20, 40 20, 40 320),",
+ "(100 120, 40 20, 180 100, 100 120),",
+ "(200 200, 180 100, 240 160, 200 200),",
+ "(260 260, 240 160, 300 200, 260 260),",
+ "(300 300, 300 200, 340 320, 300 300))"))
+p9 = readWKT(paste("MULTIPOLYGON (((20 380, 420 380, 420 20, 20 20, 20 380),",
+ "(220 340, 180 240, 60 200, 200 180, 340 60, 240 220, 220 340)),",
+ "((60 200, 340 60, 220 340, 60 200)))"))
+
+par(mfrow=c(3,3))
+plot(p1,col='black',pbg='white');title(paste("Valid:",gIsValid(p1),"\n",gIsValid(p1,reason=TRUE)))
+plot(p2,col='black',pbg='white');title(paste("Valid:",gIsValid(p2),"\n",gIsValid(p2,reason=TRUE)))
+plot(p3,col='black',pbg='white');title(paste("Valid:",gIsValid(p3),"\n",gIsValid(p3,reason=TRUE)))
+plot(p4,col='black',pbg='white');title(paste("Valid:",gIsValid(p4),"\n",gIsValid(p4,reason=TRUE)))
+plot(p5,col='black',pbg='white');title(paste("Valid:",gIsValid(p5),"\n",gIsValid(p5,reason=TRUE)))
+plot(p6,col='black',pbg='white');title(paste("Valid:",gIsValid(p6),"\n",gIsValid(p6,reason=TRUE)))
+plot(p7,col='black',pbg='white');title(paste("Valid:",gIsValid(p7),"\n",gIsValid(p7,reason=TRUE)))
+plot(p8,col='black',pbg='white');title(paste("Valid:",gIsValid(p8),"\n",gIsValid(p8,reason=TRUE)))
+plot(p9,col='black',pbg='white')
+title(paste("Valid:",gIsValid(p9),"\n",gIsValid(p9,reason=TRUE)))	
+}
+
+\keyword{spatial}
+
diff --git a/man/topo-bin-gDifference.Rd b/man/topo-bin-gDifference.Rd
new file mode 100644
index 0000000..9f270d1
--- /dev/null
+++ b/man/topo-bin-gDifference.Rd
@@ -0,0 +1,43 @@
+\name{gDifference}
+\alias{gDifference}
+\title{Geometry Difference}
+\description{Function for determining the difference between the two given geometries.}
+\usage{
+gDifference(spgeom1, spgeom2, byid=FALSE, id=NULL, drop_lower_td=FALSE,
+ unaryUnion_if_byid_false=TRUE, checkValidity=FALSE)
+}
+%- maybe also 'usage' for other objects documented here.
+\arguments{
+  \item{spgeom1, spgeom2}{sp objects as defined in package sp}
+  \item{byid}{Logical vector determining if the function should be applied across ids (TRUE) or the entire object (FALSE) for spgeom1 and spgeom2}
+  \item{id}{Character vector defining id labels for the resulting geometries, if unspecified returned geometries will be labeled based on their parent geometries' labels.}
+  \item{drop_lower_td}{default FALSE; if TRUE, objects will be dropped from output GEOMETRYCOLLECTION objects to simplify output if their topological dinension is less than the minimum topological dinension of the input objects.}
+  \item{unaryUnion_if_byid_false}{default TRUE; if \code{byid} takes a FALSE in either position, the subgeometries are combined first to avoid possible topology exceptions (change in 0.3-13, previous behaviour did not combine subgeometries, and may be achieved by setting this argument FALSE}
+  \item{checkValidity}{default FALSE; error meesages from GEOS do not say clearly which object fails if a topology exception is encountered. If this argument is TRUE, \code{gIsValid} is run on each in turn in an environment in which object names are available. If objects are invalid, this is reported and those affected are named}
+}
+
+\details{Returns the regions of spgeom1 that are not within spgeom2. If the geometries do not intersect then the result is just spgeom1. Note that the function is not symmetric for spgeom1 and spgeom2.}
+
+\note{Error messages from GEOS, in particular topology exceptions, report 0-based object order, so geom 0 is spgeom1, and geom 1 is spgeom2.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gIntersection}}
+\code{\link{gSymdifference}}
+\code{\link{gUnion}}
+}
+
+\examples{
+x = readWKT("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))")
+y = readWKT("POLYGON ((3 3, 7 3, 7 7, 3 7, 3 3))")
+
+d = gDifference(x,y)
+plot(d,col='red',pbg='white')
+
+# Empty geometry since y is completely contained with x
+d2 = gDifference(y,x)
+}
+
+\keyword{spatial}
+
diff --git a/man/topo-bin-gIntersection.Rd b/man/topo-bin-gIntersection.Rd
new file mode 100644
index 0000000..5484259
--- /dev/null
+++ b/man/topo-bin-gIntersection.Rd
@@ -0,0 +1,133 @@
+\name{gIntersection}
+\alias{gIntersection}
+\title{Geometry Intersections}
+\description{Function for determining the intersection between the two given geometries}
+\usage{
+gIntersection(spgeom1, spgeom2, byid=FALSE, id=NULL, drop_not_poly,
+ drop_lower_td=FALSE, unaryUnion_if_byid_false=TRUE, checkValidity=FALSE)
+}
+%- maybe also 'usage' for other objects documented here.
+\arguments{
+  \item{spgeom1, spgeom2}{sp objects as defined in package sp}
+  \item{byid}{Logical vector determining if the function should be applied across ids (TRUE) or the entire object (FALSE) for spgeom1 and spgeom2}
+  \item{id}{Character vector defining id labels for the resulting geometries, if unspecified returned geometries will be labeled based on their parent geometries' labels.}
+  \item{drop_not_poly}{deprecated argument, use drop_lower_td}
+  \item{drop_lower_td}{default FALSE; if TRUE, objects will be dropped from output GEOMETRYCOLLECTION objects to simplify output if their topological dimension is less than the minimum topological dinension of the input objects.}
+  \item{unaryUnion_if_byid_false}{default TRUE; if \code{byid} takes a FALSE in either position, the subgeometries are combined first to avoid possible topology exceptions (change in 0.3-13, previous behaviour did not combine subgeometries, and may be achieved by setting this argument FALSE}
+  \item{checkValidity}{default FALSE; error meesages from GEOS do not say clearly which object fails if a topology exception is encountered. If this argument is TRUE, \code{gIsValid} is run on each in turn in an environment in which object names are available. If objects are invalid, this is reported and those affected are named}
+}
+
+\details{Returns all spatial intersections as sp objects of the appropriate class. If the geometries do not intersect then an empty geometry is returned.}
+
+\note{Error messages from GEOS, in particular topology exceptions, report 0-based object order, so geom 0 is spgeom1, and geom 1 is spgeom2.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gDifference}}
+\code{\link{gSymdifference}}
+\code{\link{gUnion}}
+}
+
+\examples{
+if (require(maptools)) {
+xx <- readShapeSpatial(system.file("shapes/fylk-val-ll.shp", package="maptools")[1],
+ proj4string=CRS("+proj=longlat +datum=WGS84"))
+bbxx <- bbox(xx)
+wdb_lines <- system.file("share/wdb_borders_c.b", package="maptools")
+xxx <- Rgshhs(wdb_lines, xlim=bbxx[1,], ylim=bbxx[2,])$SP
+res <-gIntersection(xx, xxx)
+plot(xx, axes=TRUE)
+plot(xxx, lty=2, add=TRUE)
+plot(res, add=TRUE, pch=16,col='red')
+}
+pol <- readWKT(paste("POLYGON((-180 -20, -140 55, 10 0, -140 -60, -180 -20),",
+ "(-150 -20, -100 -10, -110 20, -150 -20))"))
+library(sp)
+GT <- GridTopology(c(-175, -85), c(10, 10), c(36, 18))
+gr <- as(as(SpatialGrid(GT), "SpatialPixels"), "SpatialPolygons")
+try(res <- gIntersection(pol, gr, byid=TRUE))
+res <- gIntersection(pol, gr, byid=TRUE, drop_lower_td=TRUE)
+# Robert Hijmans difficult intersection case
+load(system.file("test_cases/polys.RData", package="rgeos"))
+try(res <- gIntersection(a, b, byid=TRUE))
+res <- gIntersection(a, b, byid=TRUE, drop_lower_td=TRUE)
+unlist(sapply(slot(res, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area")))
+# example from Pius Korner 2015-10-25
+poly1 <- SpatialPolygons(list(Polygons(list(Polygon(coords=matrix(c(0, 0, 2, 2, 0, 1, 1, 0),
+ ncol=2, byrow=FALSE))), ID=c("a")), Polygons(list(Polygon(coords=matrix(c(0, 0, 2, 2, 2, 3, 3, 2),
+ ncol=2, byrow=FALSE))), ID=c("b"))))
+poly2 <- SpatialPolygons(list(Polygons(list(Polygon(coords=matrix(c(0, 0, 2, 2,
+ 1, 1, 1, 3, 3, 0, 0, 2), ncol=2, byrow=FALSE))), ID=c("c"))))
+plot(poly1, border="orange")
+plot(poly2, border="blue", add=TRUE, lty=2, density=8, angle=30, col="blue")
+gI <- gIntersection(poly1, poly2, byid=TRUE, drop_lower_td=TRUE)
+plot(gI, add=TRUE, border="red", lwd=3)
+oT <- get_RGEOS_polyThreshold()
+oW <- get_RGEOS_warnSlivers()
+oD <- get_RGEOS_dropSlivers()
+set_RGEOS_polyThreshold(1e-3)
+set_RGEOS_warnSlivers(TRUE)
+res1 <- gIntersection(a, b, byid=TRUE, drop_lower_td=TRUE)
+unlist(sapply(slot(res1, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area")))
+set_RGEOS_dropSlivers(TRUE)
+res2 <- gIntersection(a, b, byid=TRUE, drop_lower_td=TRUE)
+unlist(sapply(slot(res2, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area")))
+set_RGEOS_dropSlivers(FALSE)
+oo <- gUnaryUnion(res1, c(rep("1", 3), "2", "3", "4"))
+unlist(sapply(slot(oo, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area")))
+ooo <- gIntersection(b, oo, byid=TRUE)
+gArea(ooo, byid=TRUE)
+unlist(sapply(slot(ooo, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area")))
+set_RGEOS_dropSlivers(TRUE)
+ooo <- gIntersection(b, oo, byid=TRUE)
+gArea(ooo, byid=TRUE)
+unlist(sapply(slot(ooo, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area")))
+set_RGEOS_polyThreshold(oT)
+set_RGEOS_warnSlivers(oW)
+set_RGEOS_dropSlivers(oD)
+# see thread https://stat.ethz.ch/pipermail/r-sig-geo/2015-September/023468.html
+Pol1=rbind(c(0,0),c(0,10),c(10,10),c(10,0),c(0,0))
+Pol2=rbind(c(0,0),c(10,0),c(10,-10),c(0,-10),c(0,0))
+library(sp)
+Pols1=Polygons(list(Polygon(Pol1)),"Pols1")
+Pols2=Polygons(list(Polygon(Pol2)),"Pols2")
+MyLay=SpatialPolygons(list(Pols1,Pols2))
+Pol1l=Pol1+0.5
+Pol2l=Pol2+0.5
+Pols1l=Polygons(list(Polygon(Pol1l)),"Pols1l")
+Pols2l=Polygons(list(Polygon(Pol2l)),"Pols2l")
+MyLayl=SpatialPolygons(list(Pols1l,Pols2l))
+inter=gIntersection(MyLay, MyLayl)
+plot(MyLay)
+plot(MyLayl,add=TRUE)
+plot(inter, add=TRUE, border="green")
+try(gIntersection(MyLay, MyLayl, unaryUnion_if_byid_false=FALSE))
+Pol1=rbind(c(0,0),c(0,1),c(1,1),c(1,0),c(0,0))
+Pol2=rbind(c(0,0),c(1,0),c(1,-1),c(0,-1),c(0,0))
+Pols1=Polygons(list(Polygon(Pol1)),"Pols1")
+Pols2=Polygons(list(Polygon(Pol2)),"Pols2")
+MyLay=SpatialPolygons(list(Pols1,Pols2))
+Pol1l=Pol1+0.1
+Pol2l=Pol2+0.1
+Pols1l=Polygons(list(Polygon(Pol1l)),"Pols1l")
+Pols2l=Polygons(list(Polygon(Pol2l)),"Pols2l")
+MyLayl=SpatialPolygons(list(Pols1l,Pols2l))
+inter=gIntersection(MyLay, MyLayl, unaryUnion_if_byid_false=FALSE)
+gEquals(inter, MyLay)
+inter1=gIntersection(MyLay, MyLayl, unaryUnion_if_byid_false=TRUE)
+gEquals(inter1, MyLay)
+gEquals(inter, inter1)
+plot(MyLay, ylim=c(-1, 1.1))
+plot(MyLayl, add=TRUE)
+plot(inter, angle=45, density=10, add=TRUE)
+plot(inter1, angle=135, density=10, add=TRUE)
+inter2=gIntersection(MyLay, MyLayl)
+gEquals(inter2, MyLay)
+gEquals(inter1, inter2)
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial}
+
+
diff --git a/man/topo-bin-gSymdifference.Rd b/man/topo-bin-gSymdifference.Rd
new file mode 100644
index 0000000..0eb1df5
--- /dev/null
+++ b/man/topo-bin-gSymdifference.Rd
@@ -0,0 +1,41 @@
+\name{gSymdifference}
+\alias{gSymdifference}
+\title{Geometry Symmetric Difference}
+\description{Function for determining the symmetric difference between the two given geometries }
+\usage{
+gSymdifference(spgeom1, spgeom2, byid=FALSE, id=NULL, drop_lower_td=FALSE,
+ unaryUnion_if_byid_false=TRUE, checkValidity=FALSE)
+}
+
+\arguments{
+  \item{spgeom1, spgeom2}{sp objects as defined in package sp}
+  \item{byid}{Logical vector determining if the function should be applied across ids (TRUE) or the entire object (FALSE) for spgeom1 and spgeom2}
+  \item{id}{Character vector defining id labels for the resulting geometries, if unspecified returned geometries will be labeled based on their parent geometries' labels.}
+  \item{drop_lower_td}{default FALSE; if TRUE, objects will be dropped from output GEOMETRYCOLLECTION objects to simplify output if their topological dinension is less than the minimum topological dinension of the input objects.}
+  \item{unaryUnion_if_byid_false}{default TRUE; if \code{byid} takes a FALSE in either position, the subgeometries are combined first to avoid possible topology exceptions (change in 0.3-13, previous behaviour did not combine subgeometries, and may be achieved by setting this argument FALSE}
+  \item{checkValidity}{default FALSE; error meesages from GEOS do not say clearly which object fails if a topology exception is encountered. If this argument is TRUE, \code{gIsValid} is run on each in turn in an environment in which object names are available. If objects are invalid, this is reported and those affected are named}
+}
+
+\details{Returns the regions of spgeom1 and spgeom2 that do not intersect. If the geometries do not intersect then spgeom1 and spgeom2 will be returned as separate subgeometries.}
+
+\note{Error messages from GEOS, in particular topology exceptions, report 0-based object order, so geom 0 is spgeom1, and geom 1 is spgeom2.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gDifference}}
+\code{\link{gIntersection}}
+\code{\link{gUnion}}
+}
+
+\examples{
+x = readWKT("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))")
+y = readWKT("POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))")
+
+d = gSymdifference(x,y)
+plot(d,col='red',pbg='white')
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial}
+
diff --git a/man/topo-bin-gUnion.Rd b/man/topo-bin-gUnion.Rd
new file mode 100644
index 0000000..61df5a7
--- /dev/null
+++ b/man/topo-bin-gUnion.Rd
@@ -0,0 +1,84 @@
+\name{gUnion}
+\alias{gUnion}
+\alias{gUnaryUnion}
+\alias{gUnionCascaded}
+\alias{RGEOSUnionCascaded}
+\alias{gLineMerge}
+\alias{RGEOSLineMerge}
+
+\title{Geometry Union}
+\description{Functions for joining intersecting geometries.}
+\usage{
+gUnion(spgeom1, spgeom2, byid=FALSE, id=NULL, drop_lower_td=FALSE,
+ unaryUnion_if_byid_false=TRUE, checkValidity=FALSE)
+gUnionCascaded(spgeom, id = NULL)
+gUnaryUnion(spgeom, id = NULL)
+gLineMerge(spgeom, byid=FALSE, id = NULL)
+}
+%- maybe also 'usage' for other objects documented here.
+\arguments{
+  \item{spgeom1, spgeom2}{sp objects as defined in package sp}
+  \item{byid}{Logical vector determining if the function should be applied across ids (TRUE) or the entire object (FALSE) for spgeom1 and spgeom2}
+  \item{id}{Character vector defining id labels for the resulting geometries, if unspecified returned geometries will be labeled based on their parent geometries' labels; it may contain NA values for input objects not included in the union; it should define the memberships of the output Polygons objects}
+  \item{drop_lower_td}{default FALSE; if TRUE, objects will be dropped from output GEOMETRYCOLLECTION objects to simplify output if their topological dinension is less than the minimum topological dinension of the input objects.}
+  \item{spgeom}{sp Polygon(s) or Line(s) depending on the function used}
+  \item{unaryUnion_if_byid_false}{default TRUE; if \code{byid} takes a FALSE in either position, the subgeometries are combined first to avoid possible topology exceptions (change in 0.3-13, previous behaviour did not combine subgeometries, and may be achieved by setting this argument FALSE}
+  \item{checkValidity}{default FALSE; error meesages from GEOS do not say clearly which object fails if a topology exception is encountered. If this argument is TRUE, \code{gIsValid} is run on each in turn in an environment in which object names are available. If objects are invalid, this is reported and those affected are named}
+}
+
+\details{Returns an sp object with intersecting geometries merged. If geometries do not intersect then both are returned as distinct subgeometries.
+
+gUnionCascaded expects a single sp object of class SpatialPolygons with subgeometries which it unions together. gUnionCascaded can only dissolve MultiPolygon objects, so GeometryCollection objects to be dissolved, here a SpatialPolygons object, must be flattened a Polygons object; if GEOS version 3.3.0 is available, use gUnaryUnion.
+
+gUnaryUnion expects a single sp object of class SpatialPolygons with subgeometries which it unions together; introduced in GEOS version 3.3.0, and handles GeometryCollection objects. If the id argument is used, it should be a character vector defining the memberships of the output Polygons objects, equal in length to the length of the polygons slot of spgeom.
+
+gLineMerge is similar to gUnionCascaded but is written to work with lines, specifically it joins line segments with intersecting end points. 
+}
+
+\note{Error messages from GEOS, in particular topology exceptions, report 0-based object order, so geom 0 is spgeom1, and geom 1 is spgeom2.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gDifference}}
+\code{\link{gIntersection}}
+\code{\link{gSymdifference}}
+}
+
+\examples{
+if (require(maptools)) {
+nc1 <- readShapePoly(system.file("shapes/sids.shp", package="maptools")[1],
+ proj4string=CRS("+proj=longlat +datum=NAD27"))
+lps <- coordinates(nc1)
+ID <- cut(lps[,1], quantile(lps[,1]), include.lowest=TRUE)
+if (version_GEOS0() < "3.3.0") {
+   reg4 <- gUnionCascaded(nc1, ID)
+} else {
+   reg4 <- gUnaryUnion(nc1, ID)
+}
+row.names(reg4)
+par(mfrow=c(2,1))
+plot(nc1)
+plot(reg4)
+par(mfrow=c(1,1))
+}
+gt <- GridTopology(c(0.05,0.05), c(0.1,0.1), c(2,2))
+set.seed(1)
+xv <- rnorm(length(coordinates(gt)[,1]))
+xvs <- ifelse(xv > 0.2,1,0)
+grd <- SpatialGridDataFrame(gt, data.frame(xvs))
+spix <- as(grd, "SpatialPixelsDataFrame")
+spol <- as(spix, "SpatialPolygonsDataFrame")
+image(grd, axes=TRUE)
+if (version_GEOS0() < "3.3.0") {
+  spol1 <- gUnionCascaded(spol, as.character(spol$xvs))
+} else {
+  spol1 <- gUnaryUnion(spol, as.character(spol$xvs))
+}
+plot(spol1, add=TRUE)
+
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial,union}
+
diff --git a/man/topo-unary-gBoundary.Rd b/man/topo-unary-gBoundary.Rd
new file mode 100644
index 0000000..e39576a
--- /dev/null
+++ b/man/topo-unary-gBoundary.Rd
@@ -0,0 +1,73 @@
+\name{gBoundary}
+\alias{gBoundary}
+\alias{RGEOSBoundary}
+
+\title{Boundary of Geometry}
+\description{Function for determinging the Boundary of the given geometry as defined by SFS Section 2.1.13.1}
+\usage{
+gBoundary(spgeom, byid=FALSE, id = NULL)
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+  \item{id}{Character vector defining id labels for the resulting geometries, if unspecified returned geometries will be labeled based on their parent geometries' labels.}
+}
+
+\value{Depending of the class of the spgeom the returned results will differ.
+
+Based on the documentation of JTS (on which GEOS is based) the following outputs are expected:
+\tabular{ll}{
+Point 			\tab 	empty GeometryCollection \cr
+MultiPoint		\tab 	empty GeometryCollection \cr
+LineString		\tab 	if closed: empty MultiPoint
+						if not closed: MultiPoint containing the two endpoints. \cr 
+MultiLineString	\tab 	MultiPoint obtained by applying the Mod-2 rule to the boundaries of the element LineStrings \cr
+LinearRing		\tab 	empty MultiPoint \cr
+Polygon			\tab 	MultiLineString containing the LinearRings of the shell and holes, in that order (SFS 2.1.10) \cr
+MultiPolygon	\tab 	MultiLineString containing the LinearRings for the boundaries of the element polygons, in the same order as they occur in the MultiPolygon (SFS 2.1.12/JTS) \cr
+GeometryCollection	\tab The boundary of an arbitrary collection of geometries whose interiors are disjoint consist of geometries drawn from the boundaries of the element geometries by application of the Mod-2 rule (SFS Section 2.1.13.1)\cr
+}
+
+The mod-2 rule states that for a multiline a point is on the boundary if and only if it on the boundary of an odd number of subgeometries of the multiline (See example below).
+}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gCentroid}}
+\code{\link{gConvexHull}}
+\code{\link{gEnvelope}}
+\code{\link{gPointOnSurface}}
+}
+
+\examples{
+
+x = readWKT("POLYGON((0 0,10 0,10 10,0 10,0 0))")
+b = gBoundary(x)
+
+plot(x,col='black')
+plot(b,col='red',lwd=3,add=TRUE)
+
+# mod-2 rule example
+x1 = readWKT("MULTILINESTRING((2 2,2 0),(2 2,0 2))")
+x2 = readWKT("MULTILINESTRING((2 2,2 0),(2 2,0 2),(2 2,4 2))")
+x3 = readWKT("MULTILINESTRING((2 2,2 0),(2 2,0 2),(2 2,4 2),(2 2,2 4))")
+x4 = readWKT("MULTILINESTRING((2 2,2 0),(2 2,0 2),(2 2,4 2),(2 2,2 4),(2 2,4 4))")
+
+b1 = gBoundary(x1)
+b2 = gBoundary(x2)
+b3 = gBoundary(x3)
+b4 = gBoundary(x4)
+
+par(mfrow=c(2,2))
+plot(x1); plot(b1,pch=16,col='red',add=TRUE)
+plot(x2); plot(b2,pch=16,col='red',add=TRUE)
+plot(x3); plot(b3,pch=16,col='red',add=TRUE)
+plot(x4); plot(b4,pch=16,col='red',add=TRUE)
+
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial}
+
diff --git a/man/topo-unary-gCentroid.Rd b/man/topo-unary-gCentroid.Rd
new file mode 100644
index 0000000..ee2702a
--- /dev/null
+++ b/man/topo-unary-gCentroid.Rd
@@ -0,0 +1,45 @@
+\name{gCentroid}
+\alias{gCentroid}
+\alias{RGEOSGetCentroid}
+
+\title{Centroid of Geometry}
+\description{Function calculates the centroid of the given geometry.}
+\usage{
+gCentroid(spgeom, byid=FALSE, id = NULL)
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+  \item{id}{Character vector defining id labels for the resulting geometries, if unspecified returned geometries will be labeled based on their parent geometries' labels.}
+}
+
+\details{Returns a SpatialPoints object of the centroid(s) for spgeom.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gBoundary}}
+\code{\link{gConvexHull}}
+\code{\link{gEnvelope}}
+\code{\link{gPointOnSurface}}
+}
+
+\examples{
+
+x = readWKT(paste("GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0)),",
+ "POLYGON((15 0,25 15,35 0,15 0)))"))
+
+# Centroids of both the square and circle independently
+c1 = gCentroid(x,byid=TRUE) 
+# Centroid of square and circle together
+c2 = gCentroid(x)
+
+plot(x)
+plot(c1,col='red',add=TRUE)
+plot(c2,col='blue',add=TRUE)
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial}
+
diff --git a/man/topo-unary-gConvexHull.Rd b/man/topo-unary-gConvexHull.Rd
new file mode 100644
index 0000000..a062c90
--- /dev/null
+++ b/man/topo-unary-gConvexHull.Rd
@@ -0,0 +1,40 @@
+\name{gConvexHull}
+\alias{gConvexHull}
+\alias{RGEOSConvexHull}
+
+\title{Convex Hull of Geometry}
+\description{Function produces the Convex Hull of the given geometry, the smallest convex polygon that contains all subgeometries}
+\usage{
+gConvexHull(spgeom, byid=FALSE, id = NULL)
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+  \item{id}{Character vector defining id labels for the resulting geometries, if unspecified returned geometries will be labeled based on their parent geometries' labels.}
+}
+
+\details{Returns the convex hull as a SpatialPolygons object.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gBoundary}}
+\code{\link{gCentroid}}
+\code{\link{gEnvelope}}
+\code{\link{gPointOnSurface}}
+}
+
+\examples{
+x = readWKT(paste("POLYGON((0 40,10 50,0 60,40 60,40 100,50 90,60 100,60",
+ "60,100 60,90 50,100 40,60 40,60 0,50 10,40 0,40 40,0 40))"))
+
+ch = gConvexHull(x)
+
+plot(x,col='blue',border='blue')
+plot(ch,add=TRUE)
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial}
+
diff --git a/man/topo-unary-gDelaunayTriangulation.Rd b/man/topo-unary-gDelaunayTriangulation.Rd
new file mode 100644
index 0000000..2ad1a8f
--- /dev/null
+++ b/man/topo-unary-gDelaunayTriangulation.Rd
@@ -0,0 +1,57 @@
+\name{gDelaunayTriangulation}
+\alias{gDelaunayTriangulation}
+
+\title{Compute Delaunay triangulation between points}
+\description{Function to compute the Delaunay triangulation between points; only available for GEOS >= 3.4.0.}
+\usage{
+	gDelaunayTriangulation(spgeom, tolerance=0.0, onlyEdges=FALSE)
+}
+
+\arguments{
+  \item{spgeom}{sp points object as defined in package sp}
+  \item{tolerance}{Numerical tolerance value to be used in triangulation}
+  \item{onlyEdges}{Logical, default returns triangles as polygons, if TRUE, returns a SpatialLines object with a single MULTILINESTRING}
+}
+
+\value{Either a SpatialPolygons object or a SpatialLines object containing a single Lines object of the undirected edges in the triangulation.}
+
+\details{When onlyEdges is TRUE, the SpatialLines object may be de-merged to identify the input points that are touched by each edge, making it possible to identify spatial neighbours.}
+
+\author{Roger Bivand}
+
+\references{
+\url{http://en.wikipedia.org/wiki/Delaunay_triangulation}
+}
+
+
+\examples{
+if (version_GEOS0() > "3.4.0") {
+library(sp)
+data(meuse)
+coordinates(meuse) <- c("x", "y")
+plot(gDelaunayTriangulation(meuse))
+points(meuse)
+out <- gDelaunayTriangulation(meuse, onlyEdges=TRUE)
+lns <- slot(slot(out, "lines")[[1]], "Lines")
+out1 <- SpatialLines(lapply(seq(along=lns), function(i) Lines(list(lns[[i]]),
+ ID=as.character(i))))
+out2 <- lapply(1:length(out1), function(i) which(gTouches(meuse, out1[i],
+ byid=TRUE)))
+out3 <- do.call("rbind", out2)
+o <- order(out3[,1], out3[,2])
+out4 <- out3[o,]
+out5 <- data.frame(from=out4[,1], to=out4[,2], weight=1)
+head(out5)
+\dontrun{
+if (require(spdep)) {
+class(out5) <- c("spatial.neighbour", class(out5))
+attr(out5, "n") <- length(meuse)
+attr(out5, "region.id") <- as.character(1:length(meuse))
+nb1 <- sn2listw(out5)$neighbours
+nb2 <- make.sym.nb(nb1)
+}
+}
+}
+}
+
+\keyword{spatial}
diff --git a/man/topo-unary-gEnvelope.Rd b/man/topo-unary-gEnvelope.Rd
new file mode 100644
index 0000000..aabe828
--- /dev/null
+++ b/man/topo-unary-gEnvelope.Rd
@@ -0,0 +1,45 @@
+\name{gEnvelope}
+\alias{gEnvelope}
+\alias{RGEOSEnvelope}
+
+\title{Envelope of Geometry}
+\description{Function calculates the rectangular bounding box for the given geometry}
+\usage{
+gEnvelope(spgeom, byid=FALSE, id = NULL)
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+  \item{id}{Character vector defining id labels for the resulting geometries, if unspecified returned geometries will be labeled based on their parent geometries' labels.}
+}
+
+\details{Returns the rectangular bounding box as a SpatialPolygons object. If spgeom is a degenerate case (horizontal/vertical line, single point) then the function may return an object with lower dimension (SpatialLines or SpatialPoints) or an invalid polygon.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gBoundary}}
+\code{\link{gCentroid}}
+\code{\link{gConvexHull}}
+\code{\link{gPointOnSurface}}
+}
+
+\examples{
+x = readWKT(paste("POLYGON((0 40,10 50,0 60,40 60,40 100,50 90,60 100,60",
+ "60,100 60,90 50,100 40,60 40,60 0,50 10,40 0,40 40,0 40))"))
+env = gEnvelope(x)
+
+plot(x,col='blue',border='blue')
+plot(env,add=TRUE)
+
+#Degenerate Cases
+gEnvelope(readWKT("POINT(1 1)")) #returns SpatialPoints
+gEnvelope(readWKT("LINESTRING(1 1,1 2)")) #invalid polygon
+gEnvelope(readWKT("LINESTRING(1 1,2 1)")) #invalid polygon
+
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial}
+
diff --git a/man/topo-unary-gNode.Rd b/man/topo-unary-gNode.Rd
new file mode 100644
index 0000000..447802c
--- /dev/null
+++ b/man/topo-unary-gNode.Rd
@@ -0,0 +1,71 @@
+\name{gNode}
+\alias{gNode}
+
+\title{Linestring Noder}
+\description{Function attempts to node a linestring object, inserting coordinates at intersection points; only available for GEOS >= 3.4.0.}
+\usage{
+	gNode(spgeom);
+}
+
+\arguments{
+  \item{spgeom}{an sp object inheriting from SpatialLines}
+}
+
+\value{Returns a noded linestring object.}
+
+\details{Because \code{\link{gPolygonize}} expects linestrings to be fully noded, as such they must not cross and must touch only at endpoints. \code{gNodee} takes an object inheriting from \code{SpatialLines} and attempts to add omitted nodes. Issue reported by Nicola Farina 21 March 2014.}
+
+
+\author{Roger Bivand}
+
+\seealso{\code{\link{gPolygonize}}}
+
+\examples{
+library(sp)
+pol1 <- readWKT(paste("POLYGON((39.936 43.446, 39.94 43.446, 39.94 43.45,",
+ "39.936 43.45, 39.936 43.446))"))
+pol2 <- readWKT(paste("POLYGON((39.9417 43.45, 39.9395 43.4505,",
+ "39.9385 43.4462, 39.9343 43.4452, 39.9331 43.4469, 39.9417 43.45))"))
+plot(pol2, axes=TRUE)
+plot(pol1, add=TRUE, border="blue")
+gIsValid(pol1)
+gIsValid(pol2)
+try(res <- gUnion(pol1, pol2))
+if (version_GEOS0() > "3.4.0") {
+pol2a <- gPolygonize(gNode(as(pol2, "SpatialLines")))
+try(res <- gUnion(pol1, pol2a))
+plot(res, add=TRUE, border="red", lty=2, lwd=2)
+set.seed(1)
+# rw from Jim Holtman's R-help posting 2010-12-2
+n <- 1000
+rw <- matrix(0, ncol = 2, nrow = n)
+indx <- cbind(seq(n), sample(c(1, 2), n, TRUE))
+rw[indx] <- sample(c(-1, 1), n, TRUE)
+rw[,1] <- cumsum(rw[, 1])
+rw[, 2] <- cumsum(rw[, 2])
+slrw <- SpatialLines(list(Lines(list(Line(rw)), "1")))
+res0 <- gNode(slrw)
+print(length(slrw))
+print(length(res0))
+res <- gPolygonize(res0)
+print(summary(res))
+print(length(res))
+plot(res0, axes=TRUE)
+plot(res, add=TRUE, col=sample(rainbow(length(res))))
+# library(spatstat)
+# set.seed(0)
+# X <- psp(runif(100), runif(100), runif(100), runif(100), window=owin())
+# library(maptools)
+# sppsp <- as(X, "SpatialLines")
+# writeLines(writeWKT(sppsp, byid=FALSE), con="sppsp.wkt")
+sppsp <- readWKT(readLines(system.file("wkts/sppsp.wkt", package="rgeos")))
+plot(sppsp, axes=TRUE)
+res0 <- gNode(sppsp)
+res <- gPolygonize(res0)
+plot(res, add=TRUE, col=sample(rainbow(length(res))))
+}
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial}
+
diff --git a/man/topo-unary-gPointOnSurface.Rd b/man/topo-unary-gPointOnSurface.Rd
new file mode 100644
index 0000000..5738bb3
--- /dev/null
+++ b/man/topo-unary-gPointOnSurface.Rd
@@ -0,0 +1,53 @@
+\name{gPointOnSurface}
+\alias{gPointOnSurface}
+\alias{RGEOSPointOnSurface}
+
+\title{Point on Surface of Geometry}
+\description{Function returns a point on the surface of the given geometry}
+\usage{
+gPointOnSurface(spgeom, byid=FALSE, id = NULL)
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+  \item{id}{Character vector defining id labels for the resulting geometries, if unspecified returned geometries will be labeled based on their parent geometries' labels.}
+}
+
+\details{Returns a SpatialPoints object with a point that intersects with the geometry}
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{
+\code{\link{gBoundary}}
+\code{\link{gCentroid}}
+\code{\link{gConvexHull}}
+\code{\link{gEnvelope}}
+}
+
+\examples{
+# Based on test geometries from JTS
+g1 = readWKT(paste("MULTIPOINT (60 300, 200 200, 240 240, 200 300, 40 140,",
+ "80 240, 140 240, 100 160, 140 200, 60 200)"))
+g2 = readWKT("LINESTRING (0 0, 7 14)")
+g3 = readWKT("LINESTRING (0 0, 3 15, 6 2, 11 14, 16 5, 16 18, 2 22)")
+g4 = readWKT(paste("MULTILINESTRING ((60 240, 140 300, 180 200, 40 140, 100 100, 120 220),",
+ "(240 80, 260 160, 200 240, 180 340, 280 340, 240 180, 180 140, 40 200, 140 260))"))
+g5 = readWKT("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))")
+g6 = readWKT(paste("MULTIPOLYGON (((50 260, 240 340, 260 100, 20 60, 90 140, 50 260),",
+ "(200 280, 140 240, 180 160, 240 140, 200 280)),",
+ "((380 280, 300 260, 340 100, 440 80, 380 280),",
+ "(380 220, 340 200, 400 100, 380 220)))"))
+
+par(mfrow=c(2,3))
+plot(g1); plot(gPointOnSurface(g1),col='red',add=TRUE)
+plot(g2); plot(gPointOnSurface(g2),col='red',add=TRUE)
+plot(g3); plot(gPointOnSurface(g3),col='red',add=TRUE)
+plot(g4); plot(gPointOnSurface(g4),col='red',add=TRUE)
+plot(g5); plot(gPointOnSurface(g5),col='red',add=TRUE)
+plot(g6); plot(gPointOnSurface(g6),col='red',add=TRUE)
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial}
+
diff --git a/man/topo-unary-gPolygonize.Rd b/man/topo-unary-gPolygonize.Rd
new file mode 100644
index 0000000..e4b7185
--- /dev/null
+++ b/man/topo-unary-gPolygonize.Rd
@@ -0,0 +1,78 @@
+\name{gPolygonize}
+\alias{gPolygonize}
+
+\title{Linestring Polygonizer}
+\description{Function attempts to polygonize the given list of linestrings. If the linestrings are not noded (coordinates inserted at intersection points), the function may fail. \code{\link{gNode}} may be tried to insert such missing points}
+\usage{
+	gPolygonize( splist, getCutEdges=FALSE);
+}
+
+\arguments{
+  \item{splist}{a list of sp SpatialLines objects}
+  \item{getCutEdges}{Logical vector indicating if cut edges should be returned}
+}
+
+\value{By default returns polygons generated by polygonizing the given linestrings. If \code{getCutEdges} is TRUE then any cut edges are returned.}
+
+\details{Polygonization is the process of forming polygons from linestrings which enclose an area. Linestrings are expected to be fully noded, as such they must not cross and must touch only at endpoints. \code{gPolygonize} takes a list of fully noded linestrings and forms all the polygons which are enclosed by the lines. Polygonization errors such as dangling lines or cut lines can be identified and reported.}
+
+
+\author{Roger Bivand & Colin Rundel}
+
+\seealso{\code{\link{gNode}}}
+
+\examples{
+library(sp)
+linelist = list(readWKT("LINESTRING (0 0 , 10 10)"),
+				readWKT("LINESTRING (185 221, 100 100)"),
+				readWKT("LINESTRING (185 221, 88 275, 180 316)"),
+				readWKT("LINESTRING (185 221, 292 281, 180 316)"), 
+				readWKT("LINESTRING (189 98, 83 187, 185 221)"), 
+				readWKT("LINESTRING (189 98, 325 168, 185 221)"))
+
+par(mfrow=c(1,2))
+plot(linelist[[1]],xlim=c(0,350),ylim=c(0,350))
+title("Linestrings with nodes")
+plot(as(linelist[[1]],"SpatialPoints"),pch=16,add=TRUE)
+
+for(i in 2:length(linelist)) {
+	plot(linelist[[i]],add=TRUE)
+	plot(as(linelist[[i]],"SpatialPoints"),pch=16,add=TRUE)
+}
+
+plot(gPolygonize(linelist),xlim=c(0,350),ylim=c(0,350))
+title("Polygonized Results")
+
+gPolygonize(linelist,getCutEdges=TRUE) # no cut edges
+
+
+
+linelist2 = list(readWKT("LINESTRING(1 3, 3 3, 3 1, 1 1, 1 3)"),
+				 readWKT("LINESTRING(1 3, 3 3, 3 1, 1 1, 1 3)"))
+
+gPolygonize(linelist2,getCutEdges=FALSE) # NULL
+gPolygonize(linelist2,getCutEdges=TRUE) # Contains LineStrings
+# bug fix 130206
+LS = list(
+readWKT("LINESTRING (425963 576719, 425980 576703)"),
+readWKT("LINESTRING (425963 576719, 425882 577073)"),
+readWKT("LINESTRING (425980 576703, 426082 577072)"),
+readWKT("LINESTRING (425882 577073, 426082 577072)"),
+readWKT("LINESTRING (426138 577068, 426082 577072)"),
+readWKT("LINESTRING (426138 577068, 426420 577039)"),
+readWKT("LINESTRING (426420 577039, 426554 576990)"),
+readWKT("LINESTRING (426751 576924, 426776 576823)"),
+readWKT("LINESTRING (426751 576924, 426783 576919)"),
+readWKT("LINESTRING (426751 576924, 426714 576953)"),
+readWKT("LINESTRING (426776 576823, 426783 576919)"),
+readWKT("LINESTRING (426658 576966, 426554 576990)"),
+readWKT("LINESTRING (426658 576966, 426667 577031)"),
+readWKT("LINESTRING (426658 576966, 426714 576953)"),
+readWKT("LINESTRING (426667 577031, 426714 576953)")
+)
+plot(gPolygonize(LS))
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial}
+
diff --git a/man/topo-unary-gSimplify.Rd b/man/topo-unary-gSimplify.Rd
new file mode 100644
index 0000000..cdd94d7
--- /dev/null
+++ b/man/topo-unary-gSimplify.Rd
@@ -0,0 +1,46 @@
+\name{gSimplify}
+\alias{gSimplify}
+
+\title{Simplify Geometry}
+\description{Function simplifies the given geometry using the Douglas-Peuker algorithm}
+\usage{
+	gSimplify(spgeom, tol, topologyPreserve=FALSE)
+}
+
+\arguments{
+  \item{spgeom}{sp object as defined in package sp}
+  \item{tol}{Numerical tolerance value to be used by the Douglas-Peuker algorithm}
+  \item{topologyPreserve}{Logical determining if the algorithm should attempt to preserve the topology of the original geometry}
+}
+
+\value{Returns a simplified version of the given geometry when applied to [MULTI]LINEs or [MULTI]POLYGONs.}
+
+\details{When applied to lines it is possible for the resulting geometry to lose simplicity (\code{\link{gIsSimple}}). If topologyPreserve is not specified it is also possible that the resulting geometries may no longer be valid (\code{\link{gIsValid}}). Remember to check the resulting geometry as many other functions rely on simplicity and or validity when performing their calculations.}
+
+\author{Roger Bivand & Colin Rundel}
+
+\references{
+Douglas-Peuker Algorithm:
+\url{http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm}
+}
+
+
+\examples{
+p = readWKT(paste("POLYGON((0 40,10 50,0 60,40 60,40 100,50 90,60 100,60",
+ "60,100 60,90 50,100 40,60 40,60 0,50 10,40 0,40 40,0 40))"))
+l = readWKT("LINESTRING(0 7,1 6,2 1,3 4,4 1,5 7,6 6,7 4,8 6,9 4)")
+
+par(mfrow=c(2,4))
+plot(p);title("Original")
+plot(gSimplify(p,tol=10));title("tol: 10")
+plot(gSimplify(p,tol=20));title("tol: 20")
+plot(gSimplify(p,tol=25));title("tol: 25")
+
+plot(l);title("Original")
+plot(gSimplify(l,tol=3));title("tol: 3")
+plot(gSimplify(l,tol=5));title("tol: 5")
+plot(gSimplify(l,tol=7));title("tol: 7")
+par(mfrow=c(1,1))
+}
+
+\keyword{spatial}
diff --git a/man/utility-functions.Rd b/man/utility-functions.Rd
new file mode 100644
index 0000000..edb0fdd
--- /dev/null
+++ b/man/utility-functions.Rd
@@ -0,0 +1,127 @@
+\name{RGEOS Utility Functions}
+\alias{getScale}
+\alias{setScale}
+\alias{translate}
+\alias{checkP4S}
+\alias{version_GEOS}
+\alias{version_GEOS0}
+\alias{set_RGEOS_polyThreshold}
+\alias{get_RGEOS_polyThreshold}
+\alias{set_RGEOS_warnSlivers}
+\alias{get_RGEOS_warnSlivers}
+\alias{set_RGEOS_dropSlivers}
+\alias{get_RGEOS_dropSlivers}
+\alias{rgeos_extSoftVersion}
+
+\title{RGEOS Utility Functions}
+\description{Utility functions for the RGEOS package}
+\usage{
+	getScale()
+	setScale(scale=100000000)
+	translate(spgeom)
+	checkP4S(p4s)
+        version_GEOS()
+        rgeos_extSoftVersion()
+        version_GEOS0()
+        set_RGEOS_polyThreshold(value)
+        get_RGEOS_polyThreshold()
+        set_RGEOS_warnSlivers(value)
+        get_RGEOS_warnSlivers()
+        set_RGEOS_dropSlivers(value)
+        get_RGEOS_dropSlivers()
+}
+
+\arguments{
+  \item{scale}{Numeric value determining the precision of translated geometries}
+  \item{spgeom}{sp object as defined in package sp}
+  \item{p4s}{Either a character string or an object of class \code{CRS}}
+  \item{value}{the value to be passed to an RGEOS option in its environment}
+}
+
+\details{getScale and setScale are used to get and set the scale option in the rgeos environment. This option is used to determine the precision of coordinates when translating to and from GEOS C objects. Precision is defined as 1 / scale. The final example is a use case reported by Mao-Gui Hu, who has also made the objects available, where the default scale defeats an intended line intersection operation; changing the scale temporarily resoves the issue.
+
+In order to permit polygon slivers to be detected, reported and dropped, the user may set a numeric value for polyThreshold and logical values for warnSlivers and dropSlivers. By default, the threshold is 0.0, and warning and dropping are FALSE. To detect slivers, the threshold may be set to a small value and warnSlivers set to TRUE. To drop slivers from returned Polygons and Polygon objects, set dropSlivers to TRUE for a non-zero threshold.
+
+translate is a testing function which translates the sp object into a GEOS C object and then back into an sp object and is used extensively in the translation unit tests. In all cases it is expected that \code{spgeom} and \code{translate(spgeom)} should be identical.
+
+checkP4S is a validation function for proj4strings and is used in testing.
+
+version_GEOS returns the full runtime version string, and version_GEOS0 only the GEOS version number.
+}
+
+\author{Roger Bivand & Colin Rundel}
+
+
+\examples{
+	readWKT("POINT(1.5 1.5)")
+
+	# With scale set to 1, the following point will be rounded
+	setScale(1)
+	readWKT("POINT(1.5 1.5)")
+	
+	setScale(10)
+	readWKT("POINT(1.5 1.5)")
+	
+	getScale()
+	# Set scale option back to default
+	setScale()
+	
+	
+	
+	# scale option only affect objects when they are translated through rgeos
+	setScale(1)
+	library(sp)
+	SpatialPoints(data.frame(x=1.5,y=1.5))
+	translate( SpatialPoints(data.frame(x=1.5,y=1.5)) )
+	
+	setScale()
+
+        # added example of scale impact on intersection 120905
+sline1 <- readWKT(readLines(system.file("wkts/sline1.wkt", package="rgeos")))
+sline2 <- readWKT(readLines(system.file("wkts/sline2.wkt", package="rgeos")))
+rslt <- gIntersection(sline1, sline2)
+class(rslt)
+getScale()
+setScale(1e+6)
+rslt <- gIntersection(sline1, sline2)
+class(rslt)
+sapply(slot(rslt, "lines"), function(x) length(slot(x, "Lines")))
+rslt <- gLineMerge(rslt, byid=TRUE)
+sapply(slot(rslt, "lines"), function(x) length(slot(x, "Lines")))
+setScale()
+get_RGEOS_dropSlivers()
+get_RGEOS_warnSlivers()
+get_RGEOS_polyThreshold()
+# Robert Hijmans difficult intersection case
+load(system.file("test_cases/polys.RData", package="rgeos"))
+try(res <- gIntersection(a, b, byid=TRUE))
+res <- gIntersection(a, b, byid=TRUE, drop_lower_td=TRUE)
+sort(unlist(sapply(slot(res, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area"))))
+oT <- get_RGEOS_polyThreshold()
+oW <- get_RGEOS_warnSlivers()
+oD <- get_RGEOS_dropSlivers()
+set_RGEOS_polyThreshold(1e-3)
+set_RGEOS_warnSlivers(TRUE)
+res1 <- gIntersection(a, b, byid=TRUE, drop_lower_td=TRUE)
+sort(unlist(sapply(slot(res, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area"))))
+set_RGEOS_dropSlivers(TRUE)
+res2 <- gIntersection(a, b, byid=TRUE, drop_lower_td=TRUE)
+sort(unlist(sapply(slot(res, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area"))))
+set_RGEOS_dropSlivers(FALSE)
+oo <- gUnaryUnion(res1, c(rep("1", 3), "2", "3", "4"))
+unlist(sapply(slot(oo, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area")))
+ooo <- gIntersection(b, oo, byid=TRUE)
+gArea(ooo, byid=TRUE)
+unlist(sapply(slot(ooo, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area")))
+set_RGEOS_dropSlivers(TRUE)
+ooo <- gIntersection(b, oo, byid=TRUE)
+gArea(ooo, byid=TRUE)
+unlist(sapply(slot(ooo, "polygons"), function(p) sapply(slot(p, "Polygons"), slot, "area")))
+set_RGEOS_polyThreshold(oT)
+set_RGEOS_warnSlivers(oW)
+set_RGEOS_dropSlivers(oD)
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{spatial}
+
diff --git a/man/wkt-functions.Rd b/man/wkt-functions.Rd
new file mode 100644
index 0000000..55197b0
--- /dev/null
+++ b/man/wkt-functions.Rd
@@ -0,0 +1,58 @@
+\name{RGEOS WKT Functions}
+\alias{readWKT}
+\alias{writeWKT}
+
+\title{RGEOS WKT Functions}
+\description{Functions for reading and writing Well Known Text (WKT)}
+\usage{
+	readWKT(text, id = NULL, p4s = NULL)
+	writeWKT(spgeom, byid = FALSE)
+}
+
+\arguments{
+  \item{text}{character string of WKT}
+  \item{id}{character vector of unique ids to label geometries. Length must match the number of subgeometries in the WKT}
+  \item{p4s}{Either a character string or an object of class \code{CRS}}
+  \item{spgeom}{sp object as defined in package sp}
+  \item{byid}{Logical determining if the function should be applied across subgeometries (TRUE) or the entire object (FALSE)}
+}
+
+\details{readWKT processes the given WKT string and returns an appropriate sp geometry object. If id is not specified then geometries will be labeled by their index position. Because no sp Spatial object may be empty, \code{readWKT} is not permitted to create an empty object.
+
+writeWKT converts an sp geometry object to a GEOS C object which is then written out as a WKT string. If byid is TRUE then each subgeometry is individually converted to a WKT string.}
+
+\references{Additional information on WKT Simple Feature Specification can be found at the following locations:
+
+\url{http://www.opengeospatial.org/standards/sfs}
+
+\url{http://en.wikipedia.org/wiki/Well-known_text}
+
+\url{http://en.wikipedia.org/wiki/Simple_Features}
+}
+
+\author{Colin Rundel}
+
+
+\examples{
+g1=readWKT("POINT(6 10)")
+g2=readWKT("LINESTRING(3 4,10 50,20 25)")
+g3=readWKT("POLYGON((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2))")
+g4=readWKT("MULTIPOINT((3.5 5.6),(4.8 10.5))")
+g5=readWKT("MULTILINESTRING((3 4,10 50,20 25),(-5 -8,-10 -8,-15 -4))")
+g6=readWKT("MULTIPOLYGON(((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2)),((6 3,9 2,9 4,6 3)))")
+try(readWKT("POINT EMPTY"))
+try(readWKT("MULTIPOLYGON EMPTY"))
+g9=readWKT("GEOMETRYCOLLECTION(POINT(4 6),LINESTRING(4 6,7 10))")
+
+writeWKT(g1)
+writeWKT(g2)
+writeWKT(g3)
+writeWKT(g4)
+writeWKT(g5)
+writeWKT(g6)
+writeWKT(g9,byid=FALSE)
+writeWKT(g9,byid=TRUE)
+}
+
+\keyword{spatial}
+
diff --git a/src/Makevars.in b/src/Makevars.in
new file mode 100644
index 0000000..68c8d33
--- /dev/null
+++ b/src/Makevars.in
@@ -0,0 +1,3 @@
+PKG_CPPFLAGS=@PKG_CPPFLAGS@
+PKG_LIBS=@PKG_LIBS@
+
diff --git a/src/Makevars.win b/src/Makevars.win
new file mode 100644
index 0000000..7ac25c4
--- /dev/null
+++ b/src/Makevars.win
@@ -0,0 +1,22 @@
+COMPILED_BY ?= gcc-4.6.3
+RWINLIB = lib${subst gcc,,${COMPILED_BY}}${R_ARCH}
+
+PKG_CPPFLAGS =\
+	-I../windows/gdal2-2.2.0/include/geos \
+
+PKG_LIBS = \
+	-L../windows/gdal2-2.2.0/${RWINLIB} \
+	-lgeos_c -lgeos  
+
+all: clean winlibs
+
+CXX_STD=CXX11
+
+winlibs:
+	mkdir -p ../inst
+	"${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" --vanilla "../tools/winlibs.R"
+
+clean:
+	rm -f $(SHLIB) $(OBJECTS)
+
+.PHONY: all winlibs clean
diff --git a/src/dummy.cc b/src/dummy.cc
new file mode 100644
index 0000000..e69de29
diff --git a/src/init.c b/src/init.c
new file mode 100644
index 0000000..d07d6b9
--- /dev/null
+++ b/src/init.c
@@ -0,0 +1,119 @@
+#include <R.h>
+#include <Rinternals.h>
+#include "rgeos.h"
+
+#include <R_ext/Rdynload.h>
+
+// TODO - do any of these functions need to be called from R?
+
+static const R_CMethodDef CEntries[] = {
+    {NULL, NULL, 0} 
+};
+
+
+static R_CallMethodDef CallEntries[] = {
+    
+    //Utility Functions
+    {"rgeos_Init", (DL_FUNC) &rgeos_Init, 0},
+    {"rgeos_finish", (DL_FUNC) &rgeos_finish, 1},
+    {"rgeos_GEOSversion", (DL_FUNC) &rgeos_GEOSversion, 0},
+    {"rgeos_double_translate", (DL_FUNC) &rgeos_double_translate, 4},
+    {"rgeos_PolyCreateComment", (DL_FUNC) &rgeos_PolyCreateComment, 2},
+    {"rgeos_sp_linkingTo_version", (DL_FUNC) &rgeos_sp_linkingTo_version, 0},
+
+    
+    //WKT Functions
+    {"rgeos_readWKT", (DL_FUNC) &rgeos_readWKT,4}, 
+    {"rgeos_writeWKT", (DL_FUNC) &rgeos_writeWKT, 3}, 
+    
+    //Topology Functions
+    {"rgeos_envelope", (DL_FUNC) &rgeos_envelope, 4},
+    {"rgeos_convexhull", (DL_FUNC) &rgeos_convexhull, 4},
+    {"rgeos_boundary", (DL_FUNC) &rgeos_boundary, 4},
+    {"rgeos_getcentroid", (DL_FUNC) &rgeos_getcentroid, 4},
+    {"rgeos_pointonsurface", (DL_FUNC) &rgeos_pointonsurface, 4},
+    {"rgeos_linemerge", (DL_FUNC) &rgeos_linemerge, 4},
+    {"rgeos_unioncascaded", (DL_FUNC) &rgeos_unioncascaded, 4},
+#ifdef HAVE_UNARYUNION
+    {"rgeos_unaryunion", (DL_FUNC) &rgeos_unaryunion, 4},
+#endif
+#ifdef HAVE_DELAUNAY
+    {"rgeos_delaunaytriangulation", (DL_FUNC) &rgeos_delaunaytriangulation, 4},
+#endif
+
+    {"rgeos_simplify", (DL_FUNC) &rgeos_simplify, 6},
+    {"rgeos_polygonize", (DL_FUNC) &rgeos_polygonize, 5},
+#ifdef HAVE_NODE
+    {"rgeos_node", (DL_FUNC) &rgeos_node, 2},
+#endif
+
+    //Binary Topology Functions
+    {"rgeos_difference", (DL_FUNC) &rgeos_difference, 5},
+    {"rgeos_symdifference", (DL_FUNC) &rgeos_symdifference, 5},
+    {"rgeos_intersection", (DL_FUNC) &rgeos_intersection, 5},
+    {"rgeos_union", (DL_FUNC) &rgeos_union, 5},
+
+    //Binary Predicate Functions
+	{"rgeos_intersects_prepared", (DL_FUNC) &rgeos_intersects_prepared, 4},
+	{"rgeos_contains_prepared", (DL_FUNC) &rgeos_contains_prepared, 4},
+	{"rgeos_containsproperly_prepared", (DL_FUNC) &rgeos_containsproperly_prepared, 4},
+	{"rgeos_covers_prepared", (DL_FUNC) &rgeos_covers_prepared, 4},
+	
+    {"rgeos_disjoint", (DL_FUNC) &rgeos_disjoint, 4},
+    {"rgeos_touches", (DL_FUNC) &rgeos_touches, 4},
+    {"rgeos_intersects", (DL_FUNC) &rgeos_intersects, 4},
+    {"rgeos_crosses", (DL_FUNC) &rgeos_crosses, 4},
+    {"rgeos_within", (DL_FUNC) &rgeos_within, 4},
+    {"rgeos_contains", (DL_FUNC) &rgeos_contains, 4},
+    {"rgeos_overlaps", (DL_FUNC) &rgeos_overlaps, 4},
+    {"rgeos_equals", (DL_FUNC) &rgeos_equals, 4},
+    {"rgeos_relate", (DL_FUNC) &rgeos_relate, 4},
+	{"rgeos_relatepattern", (DL_FUNC) &rgeos_relatepattern, 5},
+    {"rgeos_equalsexact", (DL_FUNC) &rgeos_equalsexact, 5},
+    
+    //Unary Predicate Functions
+    {"rgeos_isvalid", (DL_FUNC) &rgeos_isvalid, 3},
+    {"rgeos_issimple", (DL_FUNC) &rgeos_issimple, 3},
+    {"rgeos_isring", (DL_FUNC) &rgeos_isring, 3},
+    {"rgeos_hasz", (DL_FUNC) &rgeos_hasz, 3},
+    {"rgeos_isempty", (DL_FUNC) &rgeos_isempty, 3},
+    {"rgeos_isvalidreason", (DL_FUNC) &rgeos_isvalidreason, 3},
+    
+    //Buffer Functions
+    {"rgeos_buffer", (DL_FUNC) &rgeos_buffer, 9},
+
+    //Linear referencing functions
+    {"rgeos_interpolate", (DL_FUNC) &rgeos_interpolate, 4},
+    {"rgeos_project", (DL_FUNC) &rgeos_project, 4},
+
+    //Misc functions
+    {"rgeos_area", (DL_FUNC) &rgeos_area, 3},
+    {"rgeos_length", (DL_FUNC) &rgeos_length, 3},
+    {"rgeos_distance", (DL_FUNC) &rgeos_distance, 4},
+    {"rgeos_hausdorffdistance", (DL_FUNC) &rgeos_hausdorffdistance, 4},
+    {"rgeos_hausdorffdistancedensify", (DL_FUNC) &rgeos_hausdorffdistancedensify, 5},
+#ifdef HAVE_NEARESTPOINTS
+    {"rgeos_nearestpoints", (DL_FUNC) &rgeos_nearestpoints, 3},
+#endif
+
+    {"rgeos_PolygonsContain", (DL_FUNC) &rgeos_PolygonsContain, 2},
+    {"rgeos_poly_findInBox", (DL_FUNC) &rgeos_poly_findInBox, 3}, 
+    {"rgeos_binary_STRtree_query", (DL_FUNC) &rgeos_binary_STRtree_query, 3}, 
+    {"rgeos_unary_STRtree_query", (DL_FUNC) &rgeos_unary_STRtree_query, 2}, 
+    {NULL, NULL, 0}
+};
+
+void 
+#ifdef HAVE_VISIBILITY_ATTRIBUTE
+__attribute__ ((visibility ("default")))
+#endif
+R_init_rgeos(DllInfo *dll) {
+
+//    SEXP INIT;
+
+    R_registerRoutines(dll, CEntries, CallEntries, NULL, NULL); // RSB FIXME
+    R_useDynamicSymbols(dll, FALSE);
+
+//    INIT = rgeos_Init();
+
+}
diff --git a/src/local_stubs.c b/src/local_stubs.c
new file mode 100644
index 0000000..f30082b
--- /dev/null
+++ b/src/local_stubs.c
@@ -0,0 +1,7 @@
+/* use same define in package's own header file */
+#define SP_XPORT(x) RGEOS_ ## x
+#include "sp_xports.c"
+
+/* touch 110611 */
+/* touch 111015 */ 
+/* touch 111019 */ 
diff --git a/src/rgeos.c b/src/rgeos.c
new file mode 100644
index 0000000..acdd765
--- /dev/null
+++ b/src/rgeos.c
@@ -0,0 +1,171 @@
+#include <math.h>
+#include "rgeos.h"
+static void rgeos_finish_handle(SEXP ptr);
+
+SEXP rgeos_GEOSversion(void) {
+
+    SEXP ans;
+    PROTECT(ans = NEW_CHARACTER(1));
+    SET_STRING_ELT(ans, 0, COPY_TO_USER_STRING(GEOSversion()));
+    UNPROTECT(1);
+    return(ans);
+}
+
+SEXP rgeos_sp_linkingTo_version(void) {
+    return(SP_PREFIX(sp_linkingTo_version)());
+}
+
+static void __errorHandler(const char *fmt, ...) {
+
+    char buf[BUFSIZ], *p;
+    va_list(ap);
+    va_start(ap, fmt);
+    vsprintf(buf, fmt, ap);
+    va_end(ap);
+    p = buf + strlen(buf) - 1;
+    if(strlen(buf) > 0 && *p == '\n') *p = '\0';
+
+    error(buf);
+
+    return;
+}
+
+static void __warningHandler(const char *fmt, ...) {
+
+    char buf[BUFSIZ], *p;
+    va_list(ap);
+    va_start(ap, fmt);
+    vsprintf(buf, fmt, ap);
+    va_end(ap);
+    p = buf + strlen(buf) - 1;
+    if(strlen(buf) > 0 && *p == '\n') *p = '\0';
+
+    warning(buf);
+    
+    return;
+}
+
+GEOSContextHandle_t getContextHandle(SEXP env) {
+
+    SEXP ptr = findVarInFrame(env, install("GEOSptr"));
+    GEOSContextHandle_t r = R_ExternalPtrAddr(ptr);
+
+    return(r);
+}
+
+SEXP rgeos_Init(void) {
+
+    GEOSContextHandle_t r = initGEOS_r((GEOSMessageHandler) __warningHandler, (GEOSMessageHandler) __errorHandler);
+
+    SEXP sxpHandle = R_MakeExternalPtr((void *) r, mkChar("GEOSContextHandle"), R_NilValue);
+    R_RegisterCFinalizerEx(sxpHandle, rgeos_finish_handle, TRUE);
+ 
+    return(sxpHandle);
+}
+
+static void rgeos_finish_handle(SEXP ptr) {
+
+    if(!R_ExternalPtrAddr(ptr)) return;
+    R_ClearExternalPtr(ptr);
+}
+
+
+SEXP rgeos_finish(SEXP env) {
+
+    GEOSContextHandle_t r = getContextHandle(env);
+    finishGEOS_r(r);
+
+    SEXP sxpHandle = findVarInFrame(env, install("GEOSptr"));
+    rgeos_finish_handle(sxpHandle);
+
+    return(R_NilValue);
+}
+
+
+
+double getScale(SEXP env) {
+
+    return( NUMERIC_POINTER( findVarInFrame(env, install("scale")) )[0] );
+}
+
+double rgeos_round(double val) {
+    
+    return( java_math_round(val) );
+}
+
+
+double makePrecise(double val, double scale) {
+    
+    return( rgeos_round(val*scale)/scale );
+}
+
+// Symmetric Rounding Algorithm  - equivalent to C99 round()
+double sym_round(double val) {
+    double n;
+    double f = fabs(modf(val, &n));
+    if (val >= 0) {
+        if (f < 0.5) {
+            return( floor(val) );
+        } else if (f > 0.5) {
+            return( ceil(val) );
+        } else {
+            return( n + 1.0 );
+        }
+    } else {
+        if (f < 0.5) {
+            return( ceil(val) );
+        } else if (f > 0.5) {
+            return( floor(val) );
+        } else {
+            return( n - 1.0 );
+        }
+    }
+}
+
+
+// Asymmetric Rounding Algorithm  - equivalent to Java Math.round()
+double java_math_round(double val) {
+    double n;
+    double f = fabs(modf(val, &n));
+
+    if (val >= 0) {
+        if (f < 0.5) {
+            return( floor(val) );
+        } else if (f > 0.5) {
+            return( ceil(val) );
+        } else {
+            return( n + 1.0 );
+        }
+    } else {
+        if (f < 0.5) {
+            return( ceil(val) );
+        } else if (f > 0.5) {
+            return( floor(val) );
+        } else {
+            return( n );
+        }
+    }
+} 
+
+// Implementation of rint() 
+double rint_vc(double val) {
+    double n;
+    double f=fabs(modf(val,&n));
+    if (val>=0) {
+        if (f<0.5) {
+            return( floor(val) );
+        } else if (f>0.5) {
+            return( ceil(val) );
+        } else {
+            return( (floor(n/2)==n/2)?n:n+1.0 );
+        }
+    } else {
+        if (f<0.5) {
+            return( ceil(val) );
+        } else if (f>0.5) {
+            return( floor(val) );
+        } else {
+            return(( floor(n/2)==n/2)?n:n-1.0 );
+        }
+    }
+}
diff --git a/src/rgeos.h b/src/rgeos.h
new file mode 100644
index 0000000..d1c4306
--- /dev/null
+++ b/src/rgeos.h
@@ -0,0 +1,222 @@
+#ifndef RGEOS_H
+#define RGEOS_H
+
+#include <R.h>
+#include <Rdefines.h>
+
+#include <geos_c.h>
+
+// suggested BDR 111114
+#if GEOS_VERSION_MAJOR > 3
+#define  HAVE_UNARYUNION 1
+#endif
+#if GEOS_VERSION_MAJOR == 3
+#if GEOS_VERSION_MINOR >= 3
+#define  HAVE_UNARYUNION 1
+#endif
+#endif
+
+#if GEOS_VERSION_MAJOR > 3
+#define  HAVE_DELAUNAY 1
+#define HAVE_NODE 1
+#define HAVE_NEARESTPOINTS 1
+#endif
+#if GEOS_VERSION_MAJOR == 3
+#if GEOS_VERSION_MINOR >= 4
+#define  HAVE_DELAUNAY 1
+#define HAVE_NODE 1
+#define HAVE_NEARESTPOINTS 1
+#endif
+#endif
+
+
+
+/* use same define in package's local_stubs.c file */
+#define SP_XPORT(x) RGEOS_ ## x
+#include "sp.h"
+
+#define R_OFFSET 1
+
+// Utility functions
+SEXP rgeos_GEOSversion(void);
+SEXP rgeos_sp_linkingTo_version(void);
+SEXP rgeos_Init(void);
+SEXP rgeos_finish(SEXP env);
+//static void rgeos_finish_handle(SEXP ptr);
+GEOSContextHandle_t getContextHandle(SEXP env);
+
+double getScale(SEXP env);
+double makePrecise(double val, double scale);
+double sym_round(double val);
+double java_math_round(double val);
+double rint_vc(double val);
+double rgeos_round(double val); // Based on geos rounding methods, use just one global round function
+
+SEXP rgeos_double_translate(SEXP env, SEXP obj, SEXP id);
+SEXP rgeos_PolyCreateComment(SEXP env, SEXP pls);
+
+// Bounding Box functions - rgeos_bbox.c
+SEXP rgeos_geom2bbox(SEXP env, GEOSGeom geom);
+
+
+// Coordinate sequence and matrix functions - rgeos_coord.c
+void     rgeos_Pt2xy(SEXP env, GEOSGeom point, double *x, double *y);
+GEOSGeom rgeos_xy2Pt(SEXP env, double x, double y);
+
+GEOSCoordSeq rgeos_crdMat2CoordSeq(SEXP env, SEXP mat, SEXP dim);
+GEOSGeom rgeos_crdMat2LineString(SEXP env, SEXP mat, SEXP dim);
+GEOSGeom rgeos_crdMat2LinearRing(SEXP env, SEXP mat, SEXP dim);
+GEOSGeom rgeos_crdMat2Polygon(SEXP env, SEXP mat, SEXP dim);
+
+SEXP rgeos_CoordSeq2crdMat(SEXP env, const GEOSCoordSequence *s, int HasZ, int rev);
+SEXP rgeos_geospoint2crdMat(SEXP env, GEOSGeom geom, SEXP idlist, int ntotal, int type);
+
+SEXP rgeos_formatcrdMat(SEXP crdMat, int n );
+SEXP rgeos_crdMatFixDir(SEXP crd, int hole);
+
+
+// Translate functions GEOS to R - rgeos_geos2R.c
+SEXP rgeos_convert_geos2R(SEXP env, GEOSGeom geom, SEXP p4s, SEXP id);
+SEXP rgeos_geospoint2SpatialPoints(SEXP env, GEOSGeom mpt, SEXP p4s, SEXP id, int n);
+SEXP rgeos_geosline2SpatialLines(SEXP env, GEOSGeom geom, SEXP p4s, SEXP id, int ng);
+SEXP rgeos_geosring2SpatialRings(SEXP env, GEOSGeom geom, SEXP p4s, SEXP idlist, int nrings);
+
+SEXP rgeos_geospolygon2SpatialPolygons(SEXP env, GEOSGeom geom, SEXP p4s, SEXP IDs, int ng);
+SEXP rgeos_geospolygon2Polygons(SEXP env, GEOSGeom geom, SEXP id);
+SEXP rgeos_geosring2Polygon(SEXP env, GEOSGeom lr, int hole);
+
+
+//Translate functions R to GEOS - rgeos_R2geos.c
+GEOSGeom rgeos_convert_R2geos(SEXP env, SEXP obj);
+
+GEOSGeom rgeos_SpatialPoints2geospoint(SEXP env, SEXP obj);
+GEOSGeom rgeos_SpatialLines2geosline(SEXP env, SEXP obj);
+GEOSGeom rgeos_Lines2geosline(SEXP env, SEXP obj);
+GEOSGeom rgeos_SpatialRings2geosring(SEXP env, SEXP obj);
+
+GEOSGeom rgeos_SpatialPolygons2geospolygon(SEXP env, SEXP obj);
+GEOSGeom rgeos_Polygons2geospolygon(SEXP env, SEXP obj);
+GEOSGeom rgeos_Polygons2MP(SEXP env, SEXP obj);
+GEOSGeom rgeos_Lines2MP(SEXP env, SEXP obj);
+GEOSGeom rgeos_Polygon2MP(SEXP env, SEXP obj);
+GEOSGeom rgeos_Polygons_i_2Polygon(SEXP env, SEXP pls, SEXP vec);
+
+
+// WKT Functions - rgeos_wkt.c
+SEXP rgeos_readWKT(SEXP env, SEXP obj, SEXP p4s, SEXP id);
+SEXP rgeos_writeWKT(SEXP env, SEXP obj, SEXP byid);
+
+
+// Topology Functions - rgeos_topology.c
+SEXP rgeos_envelope(SEXP env, SEXP obj, SEXP id, SEXP byid);
+SEXP rgeos_convexhull(SEXP env, SEXP obj, SEXP id, SEXP byid);
+SEXP rgeos_boundary(SEXP env, SEXP obj, SEXP id, SEXP byid); 
+SEXP rgeos_getcentroid(SEXP env, SEXP obj, SEXP id, SEXP byid);
+SEXP rgeos_pointonsurface(SEXP env, SEXP obj, SEXP id, SEXP byid);
+SEXP rgeos_linemerge(SEXP env, SEXP obj, SEXP id, SEXP byid);
+SEXP rgeos_unioncascaded(SEXP env, SEXP obj, SEXP id, SEXP byid );
+#ifdef HAVE_UNARYUNION
+SEXP rgeos_unaryunion(SEXP env, SEXP obj, SEXP id, SEXP byid );
+#endif
+#ifdef HAVE_DELAUNAY
+SEXP rgeos_delaunaytriangulation(SEXP env, SEXP obj, SEXP tol,
+ SEXP onlyEdges);
+#endif
+
+typedef GEOSGeometry* (*p_topofunc)(GEOSContextHandle_t, const GEOSGeometry*);
+SEXP rgeos_topologyfunc(SEXP env, SEXP obj, SEXP id, SEXP byid, p_topofunc);
+
+SEXP rgeos_simplify(SEXP env, SEXP obj, SEXP tol, SEXP id, SEXP byid, SEXP topPres);
+SEXP rgeos_polygonize(SEXP env, SEXP obj, SEXP id, SEXP p4s, SEXP cutEdges);
+#ifdef HAVE_NODE
+SEXP rgeos_node(SEXP env, SEXP obj);
+#endif
+
+// Binary Topology Functions - rgeos_topology_binary.c
+SEXP rgeos_difference(SEXP env, SEXP geom1, SEXP geom2, SEXP byid, SEXP ids);
+SEXP rgeos_symdifference(SEXP env, SEXP geom1, SEXP geom2, SEXP byid, SEXP ids);
+SEXP rgeos_intersection(SEXP env, SEXP geom1, SEXP geom2, SEXP byid, SEXP ids);
+SEXP rgeos_union(SEXP env, SEXP geom1, SEXP geom2, SEXP byid, SEXP ids);
+
+typedef GEOSGeometry* (*p_bintopofunc)(GEOSContextHandle_t, const GEOSGeometry*, const GEOSGeometry*);
+SEXP rgeos_binarytopologyfunc(SEXP env, SEXP geom1, SEXP geom2, SEXP byid, SEXP ids, p_bintopofunc);
+
+
+// Binary Predicate Functions - rgeos_predicate_binary.c
+
+SEXP rgeos_intersects_prepared(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_contains_prepared(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_containsproperly_prepared(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_covers_prepared(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+
+typedef char (*p_binpredfunc_prepared)(GEOSContextHandle_t, const GEOSPreparedGeometry*, const GEOSGeometry*);
+SEXP rgeos_binpredfunc_prepared(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, p_binpredfunc_prepared, int canSym);
+
+SEXP rgeos_disjoint(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_touches(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_intersects(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_crosses(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_within(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_contains(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_overlaps(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_equals(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_relate(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+
+typedef char (*p_binpredfunc)(GEOSContextHandle_t, const GEOSGeometry*, const GEOSGeometry*);
+SEXP rgeos_binpredfunc( SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, p_binpredfunc, int canSym);
+
+SEXP rgeos_equalsexact(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP tol, SEXP byid);
+SEXP rgeos_relatepattern(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP pattern, SEXP byid);
+SEXP rgeos_binpredfunc_opt(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP opt, SEXP byid, int relpat, int canSym);
+
+
+// Unary Predicate Functions - rgeos_predicate_unary.c
+
+SEXP rgeos_isvalid(SEXP env, SEXP spgeom, SEXP byid);
+SEXP rgeos_isvalidreason(SEXP env, SEXP spgeom, SEXP byid);
+SEXP rgeos_issimple(SEXP env, SEXP spgeom, SEXP byid);
+SEXP rgeos_isring(SEXP env, SEXP spgeom, SEXP byid);
+SEXP rgeos_hasz(SEXP env, SEXP spgeom, SEXP byid);
+SEXP rgeos_isempty(SEXP env, SEXP spgeom, SEXP byid);
+
+typedef char (*p_unarypredfunc)(GEOSContextHandle_t, const GEOSGeometry*);
+SEXP rgeos_unarypredfunc(SEXP env, SEXP spgeom, SEXP byid, p_unarypredfunc);
+
+
+// Buffer Functions - rgeos_buffer.c
+SEXP rgeos_buffer(SEXP env, SEXP obj, SEXP byid, SEXP id, SEXP width, SEXP quadsegs, 
+                  SEXP capStyle, SEXP joinStyle, SEXP mitreLimit);
+
+// Linear referencing functions
+SEXP rgeos_project(SEXP env, SEXP spgeom, SEXP sppoint, SEXP normalized);
+SEXP rgeos_interpolate(SEXP env, SEXP spgeom, SEXP d, SEXP normalized);
+
+// Miscellaneous functions - rgeos_misc.c
+
+SEXP rgeos_area(SEXP env, SEXP obj, SEXP byid);
+SEXP rgeos_length(SEXP env, SEXP obj, SEXP byid);
+
+typedef int (*p_miscfunc)(GEOSContextHandle_t, const GEOSGeometry*, double *);
+SEXP rgeos_miscfunc(SEXP env, SEXP obj, SEXP byid, p_miscfunc );
+
+SEXP rgeos_distance(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+SEXP rgeos_hausdorffdistance(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid);
+typedef int (*p_distfunc)(GEOSContextHandle_t,const GEOSGeometry*,const GEOSGeometry*, double *);
+SEXP rgeos_distancefunc(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, p_distfunc);
+
+SEXP rgeos_hausdorffdistancedensify(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP densifyFrac, SEXP byid);
+typedef int (*p_distdenfunc)(GEOSContextHandle_t,const GEOSGeometry*,const GEOSGeometry*, double, double *);
+SEXP rgeos_distancedensifyfunc(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP densifyFrac, SEXP byid, p_distdenfunc);
+SEXP rgeos_nearestpoints(SEXP env, SEXP spgeom1, SEXP spgeom2);
+
+// Needs to be classified
+SEXP rgeos_PolygonsContain(SEXP env, SEXP obj);
+SEXP GC_Contains(SEXP env, GEOSGeom GC);
+SEXP rgeos_poly_findInBox(SEXP env, SEXP pls, SEXP as_points);
+
+// STRtree functions
+SEXP rgeos_binary_STRtree_query(SEXP env, SEXP obj1, SEXP obj2);
+SEXP rgeos_unary_STRtree_query(SEXP env, SEXP obj);
+
+#endif
+
diff --git a/src/rgeos_R2geos.c b/src/rgeos_R2geos.c
new file mode 100644
index 0000000..15599a5
--- /dev/null
+++ b/src/rgeos_R2geos.c
@@ -0,0 +1,403 @@
+#include "rgeos.h"
+#include <string.h>
+
+SEXP rgeos_double_translate(SEXP env, SEXP obj, SEXP id) {
+    
+    GEOSGeom geom = rgeos_convert_R2geos( env, obj);
+    SEXP p4s = (obj == R_NilValue) ? R_NilValue : GET_SLOT(obj, install("proj4string"));
+    
+    SEXP ans = rgeos_convert_geos2R(env, geom, p4s, id); 
+    
+    return(ans);
+}
+
+GEOSGeom rgeos_convert_R2geos(SEXP env, SEXP obj) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    if (obj == R_NilValue)
+        return(GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, NULL, 0));
+
+    char classbuf[BUFSIZ];
+    strcpy(classbuf, CHAR( STRING_ELT(GET_CLASS(obj), 0) ));
+    
+    //TODO - handle DataFrame classes gracefully
+    if ( !strcmp( classbuf,"SpatialPoints") || !strcmp(classbuf,"SpatialPointsDataFrame") ) {
+        return( rgeos_SpatialPoints2geospoint( env, obj) );
+    } else if ( !strcmp(classbuf,"SpatialLines") || !strcmp(classbuf,"SpatialLinesDataFrame") ) {
+        return( rgeos_SpatialLines2geosline( env, obj) );
+    } else if ( !strcmp(classbuf,"SpatialRings") || !strcmp(classbuf,"SpatialRingsDataFrame") ) {
+        return( rgeos_SpatialRings2geosring( env, obj) );
+    } else if ( !strcmp(classbuf,"SpatialPolygons") || !strcmp(classbuf,"SpatialPolygonsDataFrame") ) {
+        return( rgeos_SpatialPolygons2geospolygon( env, obj) );
+    } else if ( !strcmp(classbuf,"SpatialCollections") ) {
+
+        SEXP pointobj = GET_SLOT(obj, install("pointobj"));
+        SEXP lineobj = GET_SLOT(obj, install("lineobj"));
+        SEXP ringobj = GET_SLOT(obj, install("ringobj"));
+        SEXP polyobj = GET_SLOT(obj, install("polyobj"));
+        
+        GEOSGeom GCs[] = {NULL,NULL,NULL,NULL};
+        int cnts[] = {0,0,0,0};
+        
+        if (pointobj != R_NilValue) {
+            GCs[0] = rgeos_SpatialPoints2geospoint(env, pointobj);
+            cnts[0] = GEOSGetNumGeometries_r(GEOShandle, GCs[0]);
+            cnts[0] = cnts[0] ? cnts[0] : 1;
+        }
+        if (lineobj != R_NilValue) {
+            GCs[1] = rgeos_SpatialLines2geosline(env, lineobj);
+            cnts[1] = GEOSGetNumGeometries_r(GEOShandle, GCs[1]);
+            cnts[1] = cnts[1] ? cnts[1] : 1;
+        }
+        if (ringobj != R_NilValue) {
+            GCs[2] = rgeos_SpatialRings2geosring(env, ringobj);
+            cnts[2] = GEOSGetNumGeometries_r(GEOShandle, GCs[2]);
+            cnts[2] = cnts[2] ? cnts[2] : 1;
+        }
+        if (polyobj != R_NilValue) {
+            GCs[3] = rgeos_SpatialPolygons2geospolygon(env, polyobj);
+            cnts[3] = GEOSGetNumGeometries_r(GEOShandle, GCs[3]);
+            cnts[3] = cnts[3] ? cnts[3] : 1;        
+        }
+        int ng = cnts[0]+cnts[1]+cnts[2]+cnts[3];
+        
+        GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) ng, sizeof(GEOSGeom));
+        int k=0;
+        for(int i=0;i<4;i++) {
+            
+            if (cnts[i] == 0) continue;
+            
+            int n = GEOSGetNumGeometries_r(GEOShandle, GCs[i]);
+            n = n ? n : 1;
+            
+            if (n == 1) {
+                geoms[k] = GEOSGeom_clone_r(GEOShandle, GCs[i]);
+                k++;
+            } else if (n > 1) {
+                for(int j=0; j<cnts[i]; j++, k++) {
+                    const GEOSGeometry *curgeom = GEOSGetGeometryN_r(GEOShandle, GCs[i],j);
+                    geoms[k] = GEOSGeom_clone_r(GEOShandle, curgeom);
+                }
+            }
+            
+            GEOSGeom_destroy_r(GEOShandle, GCs[i]);
+        }
+        
+        return( GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, geoms, (unsigned int) ng) );
+    }
+    
+    error("rgeos_convert_R2geos: invalid R class, unable to convert");
+    return(NULL); //should never get here, clears up warning
+} 
+
+// Spatial Points to geometry collection (Multipoints)
+GEOSGeom rgeos_SpatialPoints2geospoint(SEXP env, SEXP obj) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc = 0;
+    
+    SEXP crds = GET_SLOT(obj, install("coords")); 
+    SEXP dim = getAttrib(crds, install("dim")); 
+    int n = INTEGER_POINTER(dim)[0];
+    
+    GEOSGeom GC = NULL;
+    if ( n == 1 )
+        GC = rgeos_xy2Pt(env, NUMERIC_POINTER(crds)[0], NUMERIC_POINTER(crds)[1]);
+    else {
+        SEXP ids;
+        PROTECT(ids = VECTOR_ELT( getAttrib(crds, R_DimNamesSymbol), 0 ));pc++;
+        
+        if (ids == R_NilValue) {
+            GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) n, sizeof(GEOSGeom));
+            for (int j=0; j<n; j++) {
+                geoms[j] = rgeos_xy2Pt(env, NUMERIC_POINTER(crds)[j], NUMERIC_POINTER(crds)[j+n]);            
+                if (geoms[j] == NULL) 
+					error("rgeos_SpatialPoints2geospoint: collection not created");
+            }
+        
+            GC = GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, geoms, (unsigned int) n);   
+            //EJP, uncommented; loop now starting at 1; passes check:
+            //for (int j=1; j<n; j++) 
+            //    GEOSGeom_destroy_r(GEOShandle, geoms[j]);
+            if (GC == NULL) 
+				error("rgeos_SpatialPoints2geospoint: collection not created");
+         
+        } else {
+            
+            int *unique  = (int *) R_alloc((size_t) n, sizeof(int));
+            int *unqcnt  = (int *) R_alloc((size_t) n, sizeof(int));
+            int *whichid = (int *) R_alloc((size_t) n, sizeof(int));
+            int nunq = 1;
+
+            unique[0] = 0;
+            unqcnt[0] = 1;
+            whichid[0] = 0;
+        
+            for (int i=1; i<n; i++) {
+            
+                int match = FALSE;
+                int j;
+                for (j=0; j<nunq; j++) {
+                    match = !strcmp( CHAR(STRING_ELT(ids, i)), CHAR(STRING_ELT(ids, unique[j])) );
+                    if (match) break;
+                }
+            
+                if (!match) {
+                    unique[nunq] = i;
+                    unqcnt[nunq] = 0;
+                    nunq++;
+                }
+                unqcnt[j]++;
+                whichid[i] = j;
+            }
+        
+            GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) nunq, sizeof(GEOSGeom));
+            for (int j=0; j<nunq; j++) {
+
+                GEOSGeom *subgeoms = (GEOSGeom *) R_alloc((size_t) unqcnt[j], sizeof(GEOSGeom));
+                for (int i=0; i<unqcnt[j]; i++) subgeoms[i] = NULL;
+
+                int k=0;
+                for (int i=0; i<n; i++) {
+                    if (whichid[i] == j) {
+                        subgeoms[k] = rgeos_xy2Pt(env, NUMERIC_POINTER(crds)[i], NUMERIC_POINTER(crds)[i+n]);
+                        k++;
+                    }
+                }
+                
+                geoms[j] = (k == 1) ? subgeoms[0] : 
+                            GEOSGeom_createCollection_r(GEOShandle, GEOS_MULTIPOINT, subgeoms, (unsigned int) unqcnt[j]);
+                
+                if (geoms[j] == NULL) 
+                    error("rgeos_SpatialPoints2geospoint: collection not created");
+            }
+            
+            GC = (nunq == 1) ? geoms[0] :
+                   GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, geoms, (unsigned int) nunq);
+            
+            if (GC == NULL)
+                error("rgeos_SpatialPoints2geospoint: collection not created");
+        }
+    } 
+// Rprintf("n: %d, GC %s\n", n, GEOSGeomType_r(GEOShandle, GC));
+    
+    UNPROTECT(pc);
+    return(GC);
+}
+
+// SpatialLines class to geometry collection
+GEOSGeom rgeos_SpatialLines2geosline(SEXP env, SEXP obj) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc = 0;
+    
+    SEXP lines;
+    PROTECT(lines = GET_SLOT(obj, install("lines"))); pc++;
+    int nlines = length(lines);
+    
+    GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) nlines, sizeof(GEOSGeom));
+    
+    for (int i=0; i<nlines; i++) {
+        SEXP Lines = VECTOR_ELT(lines, i);
+        geoms[i] = rgeos_Lines2geosline(env, Lines);
+    }
+    
+    // If there is only one line collection return multiline not GC
+    GEOSGeom GC = (nlines == 1) ? geoms[0]
+                    : GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, geoms, (unsigned int) nlines);
+    
+    UNPROTECT(pc);
+    return(GC);
+}
+
+// Lines class to geometry collection (Multilinestring)
+GEOSGeom rgeos_Lines2geosline(SEXP env, SEXP obj) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc=0;
+    
+    SEXP lns;
+    PROTECT(lns = GET_SLOT(obj, install("Lines"))); pc++;
+    int nlns = length(lns);
+
+    GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) nlns, sizeof(GEOSGeom));
+
+    for (int i=0; i<nlns; i++) {
+        SEXP crdMat = GET_SLOT(VECTOR_ELT(lns, i), install("coords"));
+        
+        if (crdMat == R_NilValue) {
+            geoms[i] = GEOSGeom_createLineString_r(GEOShandle, NULL);
+        } else {
+            SEXP dim = getAttrib(crdMat, R_DimSymbol);
+            geoms[i] = rgeos_crdMat2LineString(env, crdMat, dim);
+        }
+    }
+    
+    GEOSGeom GC = (nlns == 1) ? geoms[0]
+                    : GEOSGeom_createCollection_r(GEOShandle, GEOS_MULTILINESTRING, geoms, (unsigned int) nlns);
+    
+    UNPROTECT(pc);
+    return(GC);
+}
+
+
+// Spatial polygons to geometry collection (multipolygon)
+GEOSGeom rgeos_SpatialPolygons2geospolygon(SEXP env, SEXP obj) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc=0;
+    
+    SEXP pls;
+    PROTECT(pls = GET_SLOT(obj, install("polygons"))); pc++;
+    int npls = length(pls);
+    
+    GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) npls, sizeof(GEOSGeom));
+    
+    for (int i=0; i<npls; i++)
+        geoms[i] = rgeos_Polygons2geospolygon(env, VECTOR_ELT(pls, i));
+    
+    GEOSGeom GC = (npls == 1) ? geoms[0]
+                    : GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, geoms, (unsigned int) npls);
+    
+    UNPROTECT(pc);
+    return(GC);
+}
+
+
+GEOSGeom rgeos_Polygons2geospolygon(SEXP env, SEXP obj) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc=0;
+    
+    SEXP pls;
+    PROTECT(pls = GET_SLOT(obj, install("Polygons"))); pc++;
+    int npls = length(pls);
+    
+    SEXP comm;
+    PROTECT(comm = SP_PREFIX(comment2comm)(obj)); pc++;
+
+    GEOSGeom GC;
+    if (comm == R_NilValue) {
+
+        GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) npls, sizeof(GEOSGeom));
+
+        int warned = FALSE;
+        int n = 0;
+        
+        for (int i=0; i<npls; i++) {
+            SEXP crdMat = GET_SLOT(VECTOR_ELT(pls, i), install("coords"));
+            
+            int hole = LOGICAL_POINTER( GET_SLOT(VECTOR_ELT(pls, i), install("hole")) )[0];
+            if (hole) {
+                if (!warned) {
+                    warning("Polygons object missing comment attribute ignoring hole(s). See function createSPComment.");
+                    warned = TRUE;
+                }
+                continue;
+            }
+            
+            geoms[n] = (crdMat == R_NilValue)
+                         ? GEOSGeom_createPolygon_r(GEOShandle, NULL, NULL, (unsigned int) 0)
+                         : rgeos_crdMat2Polygon(env, crdMat, getAttrib(crdMat, R_DimSymbol));
+            n++;
+        }
+        
+        GC = (n == 1) ? geoms[0]
+              : GEOSGeom_createCollection_r(GEOShandle, GEOS_MULTIPOLYGON, geoms, (unsigned int) n);
+        
+    } else {
+
+        int nErings = length(comm);
+        int ncomm = 0;
+        for (int i=0; i<nErings; i++) ncomm += length(VECTOR_ELT(comm, i));
+// Rprintf("npls %d, ncomm %d\n", npls, ncomm);
+        if (npls != ncomm)
+            error("lengths of comment and Polygons slot differ");
+
+        GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) nErings, sizeof(GEOSGeom));
+        
+        for (int i=0; i<nErings; i++)
+            geoms[i] = rgeos_Polygons_i_2Polygon(env, pls, VECTOR_ELT(comm, i));
+        
+        GC = (nErings == 1) ? geoms[0]
+               : GEOSGeom_createCollection_r(GEOShandle, GEOS_MULTIPOLYGON, geoms, (unsigned int) nErings);
+    }
+    
+    UNPROTECT(pc);
+    return(GC);
+}
+
+
+GEOSGeom rgeos_Polygons_i_2Polygon(SEXP env, SEXP pls, SEXP vec) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    int n = length(vec);
+    int i = INTEGER_POINTER(vec)[0]-R_OFFSET;
+    GEOSGeom pol;
+    SEXP mat = GET_SLOT(VECTOR_ELT(pls, i), install("coords"));
+    if (mat == R_NilValue) {
+        if (n != 1) error("Empty polygons should not have holes");
+        pol = GEOSGeom_createLinearRing_r(GEOShandle, NULL);
+    } else {
+        pol = rgeos_crdMat2LinearRing(env, mat, getAttrib(mat, R_DimSymbol));
+    }
+    
+    GEOSGeom res;
+    if (n == 1) {
+        res = GEOSGeom_createPolygon_r(GEOShandle, pol, NULL, (unsigned int) 0);
+    } else {
+        GEOSGeom *holes = (GEOSGeom *) R_alloc((size_t) (n-1), sizeof(GEOSGeom));
+        for (int j=1; j<n; j++) {
+            i = INTEGER_POINTER(vec)[j]-R_OFFSET;
+            mat = GET_SLOT(VECTOR_ELT(pls, i), install("coords"));
+            
+            if (mat == R_NilValue) {
+                holes[j-1] = GEOSGeom_createLinearRing_r(GEOShandle, NULL);
+            } else {
+                holes[j-1] = rgeos_crdMat2LinearRing(env, mat, getAttrib(mat, R_DimSymbol));
+            }
+        }
+        res = GEOSGeom_createPolygon_r(GEOShandle, pol, holes,(unsigned int) (n-1));
+    }
+    
+    if (res == NULL)
+        error("rgeos_Polygons_i_2Polygon: Polygon not created");
+    
+    return(res);
+}
+
+
+// SpatialRings class to geometry collection
+GEOSGeom rgeos_SpatialRings2geosring(SEXP env, SEXP obj) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    int pc = 0;
+    SEXP rings;
+    PROTECT(rings = GET_SLOT(obj, install("rings"))); pc++;
+    int nrings = length(rings);
+
+    GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) nrings, sizeof(GEOSGeom));
+    for (int i=0; i<nrings; i++) {    
+        SEXP crdMat = GET_SLOT(VECTOR_ELT(rings, i), install("coords"));
+        
+        if (crdMat == R_NilValue) {
+            geoms[i] = GEOSGeom_createLinearRing_r(GEOShandle, NULL);
+        } else {
+            SEXP dim = getAttrib(crdMat, R_DimSymbol);
+            geoms[i] = rgeos_crdMat2LinearRing(env, crdMat, dim);
+        }
+    }
+    
+    GEOSGeom GC = (nrings == 1) ? geoms[0]
+                    : GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, geoms, (unsigned int) nrings);
+    
+    if (GC == NULL)
+        error("rgeos_SpatialRings2geosring: collection not created");
+    
+    UNPROTECT(pc);
+    return(GC);
+}
+
diff --git a/src/rgeos_R2geosMP.c b/src/rgeos_R2geosMP.c
new file mode 100644
index 0000000..5b631f6
--- /dev/null
+++ b/src/rgeos_R2geosMP.c
@@ -0,0 +1,94 @@
+#include "rgeos.h"
+
+// sp Polygons to fish soup geometry collection (multipoint) 
+GEOSGeom rgeos_Polygons2MP(SEXP env, SEXP obj) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc=0;
+    
+    SEXP pls;
+    PROTECT(pls = GET_SLOT(obj, install("Polygons"))); pc++;
+    int npls = length(pls);
+    
+    int nn = 0;
+    for (int i=0; i<npls; i++) {
+        SEXP crdMat = GET_SLOT(VECTOR_ELT(pls, i), install("coords"));
+        SEXP dim = getAttrib(crdMat, R_DimSymbol);
+        nn += (INTEGER_POINTER(dim)[0]-1);
+    }
+
+    GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) nn, sizeof(GEOSGeom));
+
+    for (int i=0, ii=0; i<npls; i++) {
+        SEXP crdMat = GET_SLOT(VECTOR_ELT(pls, i), install("coords"));
+        int n = INTEGER_POINTER(getAttrib(crdMat, R_DimSymbol))[0];
+        for (int j=0; j<(n-1); j++,ii++)
+            geoms[ii] = rgeos_xy2Pt(env, NUMERIC_POINTER(crdMat)[j],NUMERIC_POINTER(crdMat)[j+n]);
+    }
+
+    GEOSGeom GC = GEOSGeom_createCollection_r(GEOShandle, GEOS_MULTIPOINT, geoms, (unsigned int) nn);
+    if (GC == NULL)
+        error("rgeos_Polygons2MP: collection not created");
+
+    UNPROTECT(pc);
+    return(GC);
+}
+
+// sp Polygon to fish soup geometry collection (multipoint) 
+GEOSGeom rgeos_Polygon2MP(SEXP env, SEXP obj) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    SEXP crdMat = GET_SLOT(obj, install("coords"));
+    SEXP dim = getAttrib(crdMat, R_DimSymbol);
+    int nn = (INTEGER_POINTER(dim)[0]-1);
+
+    GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) nn, sizeof(GEOSGeom));
+
+    for (int i=0; i<nn; i++)
+        geoms[i] = rgeos_xy2Pt(env, NUMERIC_POINTER(crdMat)[i],NUMERIC_POINTER(crdMat)[i+nn]);
+
+    GEOSGeom GC = GEOSGeom_createCollection_r(GEOShandle, GEOS_MULTIPOINT, geoms, (unsigned int) nn);
+    if (GC == NULL)
+        error("rgeos_Polygon2MP: collection not created");
+
+    return(GC);
+}
+
+
+// sp Lines to fish soup geometry collection (multipoint) 
+GEOSGeom rgeos_Lines2MP(SEXP env, SEXP obj) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc=0;
+    
+    SEXP lines;
+    PROTECT(lines = GET_SLOT(obj, install("Lines"))); pc++;
+    int nlines = length(lines);
+    
+    int nn = 0;
+    for (int i=0; i<nlines; i++) {
+        SEXP crdMat = GET_SLOT(VECTOR_ELT(lines, i), install("coords"));
+        SEXP dim = getAttrib(crdMat, R_DimSymbol);
+        nn += (INTEGER_POINTER(dim)[0]-1);
+    }
+
+    GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) nn, sizeof(GEOSGeom));
+    for (int i=0, ii=0; i<nlines; i++) {
+        SEXP crdMat = GET_SLOT(VECTOR_ELT(lines, i), install("coords"));
+        SEXP dim = getAttrib(crdMat, R_DimSymbol);
+        
+        int n = INTEGER_POINTER(dim)[0];
+        for (int j=0; j<(n-1); j++,ii++)
+            geoms[ii] = rgeos_xy2Pt(env, NUMERIC_POINTER(crdMat)[j],NUMERIC_POINTER(crdMat)[j+n]);
+    }
+
+    GEOSGeom GC = GEOSGeom_createCollection_r(GEOShandle, GEOS_MULTIPOINT, geoms, (unsigned int) nn);
+    if (GC == NULL) {
+        error("rgeos_Lines2MP: collection not created");
+    }
+
+    UNPROTECT(pc);
+    return(GC);
+}
+
diff --git a/src/rgeos_bbox.c b/src/rgeos_bbox.c
new file mode 100644
index 0000000..11f6759
--- /dev/null
+++ b/src/rgeos_bbox.c
@@ -0,0 +1,63 @@
+#include "rgeos.h"
+
+SEXP rgeos_geom2bbox(SEXP env, GEOSGeom geom) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc=0;
+    
+    if (GEOSisEmpty_r(GEOShandle, geom) == 1)
+        return(R_NilValue);
+    
+    GEOSGeom envel = GEOSEnvelope_r(GEOShandle, geom);
+    if (envel == NULL)
+        return(R_NilValue);
+    
+    const GEOSGeometry *ext = (GEOSGeomTypeId_r(GEOShandle, envel) != GEOS_POLYGON)
+                               ? envel : GEOSGetExteriorRing_r(GEOShandle, envel);
+    const GEOSCoordSequence *s = GEOSGeom_getCoordSeq_r(GEOShandle, ext);
+    if (s == NULL)
+        error("rgeos_geom2bbox: envelope has empty coordinate sequence");
+    
+    unsigned int i, n;
+    GEOSCoordSeq_getSize_r(GEOShandle, s, &n);
+    if (n == 0)
+        return(R_NilValue);
+    
+    SEXP bbmat;
+    PROTECT(bbmat = rgeos_CoordSeq2crdMat(env, s, 0, FALSE)); pc++;
+    
+    GEOSGeom_destroy_r(GEOShandle, envel);
+    
+    SEXP ans;    
+    PROTECT(ans = NEW_NUMERIC(4)); pc++;
+    NUMERIC_POINTER(ans)[0] = DBL_MAX;
+    NUMERIC_POINTER(ans)[1] = DBL_MAX;
+    NUMERIC_POINTER(ans)[2] = -DBL_MAX;
+    NUMERIC_POINTER(ans)[3] = -DBL_MAX;
+    
+    for (i=0; i<n; i++) {
+        NUMERIC_POINTER(ans)[0] = MIN(NUMERIC_POINTER(ans)[0], NUMERIC_POINTER(bbmat)[i]);
+        NUMERIC_POINTER(ans)[1] = MIN(NUMERIC_POINTER(ans)[1], NUMERIC_POINTER(bbmat)[i+n]);
+        NUMERIC_POINTER(ans)[2] = MAX(NUMERIC_POINTER(ans)[2], NUMERIC_POINTER(bbmat)[i]);
+        NUMERIC_POINTER(ans)[3] = MAX(NUMERIC_POINTER(ans)[3], NUMERIC_POINTER(bbmat)[i+n]);
+    }
+    
+    SEXP dim;
+    PROTECT(dim = NEW_INTEGER(2)); pc++;
+    INTEGER_POINTER(dim)[0] = 2;
+    INTEGER_POINTER(dim)[1] = 2;
+    setAttrib(ans, R_DimSymbol, dim);
+    
+    SEXP dimnames;
+    PROTECT(dimnames = NEW_LIST(2)); pc++;
+    SET_VECTOR_ELT(dimnames, 0, NEW_CHARACTER(2));
+    SET_STRING_ELT(VECTOR_ELT(dimnames, 0), 0, COPY_TO_USER_STRING("x"));
+    SET_STRING_ELT(VECTOR_ELT(dimnames, 0), 1, COPY_TO_USER_STRING("y"));
+    SET_VECTOR_ELT(dimnames, 1, NEW_CHARACTER(2));
+    SET_STRING_ELT(VECTOR_ELT(dimnames, 1), 0, COPY_TO_USER_STRING("min"));
+    SET_STRING_ELT(VECTOR_ELT(dimnames, 1), 1, COPY_TO_USER_STRING("max"));
+    setAttrib(ans, R_DimNamesSymbol, dimnames);
+    
+    UNPROTECT(pc);
+    return(ans);
+}
diff --git a/src/rgeos_buffer.c b/src/rgeos_buffer.c
new file mode 100644
index 0000000..98fa548
--- /dev/null
+++ b/src/rgeos_buffer.c
@@ -0,0 +1,90 @@
+#include "rgeos.h"
+
+SEXP rgeos_buffer(SEXP env, SEXP obj, SEXP byid, SEXP id, SEXP width,
+    SEXP quadsegs, SEXP capStyle, SEXP joinStyle, SEXP mitreLimit) {
+    int i, pc=0;
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    GEOSGeometry* geom = rgeos_convert_R2geos(env, obj);
+    SEXP p4s = GET_SLOT(obj, install("proj4string"));
+    SEXP n_id;
+    
+//Rprintf("geom is %s; is GC: %d\n", GEOSGeomType_r(GEOShandle, geom), GEOSGeomType_r(GEOShandle, geom) == "GEOS_GEOMETRYCOLLECTION");
+    int n;
+    if (LOGICAL_POINTER(byid)[0]) {
+        n = GEOSGetNumGeometries_r(GEOShandle, geom);
+//Rprintf("n %d, length(id) %d\n", n, length(id));
+// sanity check 151104 RSB
+        if (n > length(id)) {
+            PROTECT(n_id = NEW_CHARACTER(n)); pc++;
+            char str[15];
+            for (i=0; i < n; i++) {
+                sprintf(str, "%d", i+R_OFFSET);
+//Rprintf("i %d, str %s\n", i, str);
+                SET_STRING_ELT(n_id, i, COPY_TO_USER_STRING(str));
+            }
+            warning("rgeos_buffer: geometry count/id count mismatch - id changed");
+        } else {
+            PROTECT(n_id = NEW_CHARACTER(length(id))); pc++;
+            for (i=0; i < length(id); i++)
+                SET_STRING_ELT(n_id, i, STRING_ELT(id, i));
+        }
+    } else {
+        n = 1;
+        PROTECT(n_id = NEW_CHARACTER(length(id))); pc++;
+        for (i=0; i < length(id); i++)
+            SET_STRING_ELT(n_id, i, STRING_ELT(id, i));
+    }
+    
+    GEOSGeometry** geoms = (GEOSGeometry**) R_alloc((size_t) n, sizeof(GEOSGeometry*));
+    SEXP newids;
+    PROTECT(newids = NEW_CHARACTER(n)); pc++;
+    
+    GEOSGeometry* curgeom = geom;
+    GEOSGeometry* thisgeom;
+    int k = 0;
+    for(i=0, k=0; i<n; i++) {
+//Rprintf("i %d, k %d, n %d\n", i, k, n);
+        if ( n > 1) {
+            curgeom = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, i);
+            if (curgeom == NULL) error("rgeos_buffer: unable to get subgeometries");
+        }
+//Rprintf("i %d k %d curgeom is %s\n", i, k, GEOSGeomType_r(GEOShandle, curgeom));
+        
+        thisgeom = GEOSBufferWithStyle_r(GEOShandle, curgeom, 
+                                         NUMERIC_POINTER(width)[i], 
+                                         INTEGER_POINTER(quadsegs)[0], 
+                                         INTEGER_POINTER(capStyle)[0], 
+                                         INTEGER_POINTER(joinStyle)[0],  
+                                         NUMERIC_POINTER(mitreLimit)[0]);
+// modified 131004 RSB 
+// https://stat.ethz.ch/pipermail/r-sig-geo/2013-October/019470.html
+        if (!GEOSisEmpty_r(GEOShandle, thisgeom)) {
+            geoms[k] = thisgeom;
+//Rprintf("i %d k %d thisgeom is %s\n", i, k, GEOSGeomType_r(GEOShandle, thisgeom));
+//Rprintf("n_id %s\n", CHAR(STRING_ELT(n_id, i)));
+            SET_STRING_ELT(newids, k, STRING_ELT(n_id, i));
+            k++;
+        }
+
+    }
+
+    GEOSGeom_destroy_r(GEOShandle, geom);
+
+    if (k == 0) {
+        UNPROTECT(pc);
+        return(R_NilValue);
+    }
+
+    GEOSGeometry* res;
+    if (k == 1)
+        res = geoms[0];
+    else
+        res = GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, geoms, (unsigned int) k);
+//Rprintf("res is %s\n", GEOSGeomType_r(GEOShandle, res));
+
+    SEXP ans;
+    PROTECT(ans = rgeos_convert_geos2R(env, res, p4s, newids)); pc++; // releases res
+    UNPROTECT(pc);
+    return(ans);
+}
diff --git a/src/rgeos_coord.c b/src/rgeos_coord.c
new file mode 100644
index 0000000..21321ac
--- /dev/null
+++ b/src/rgeos_coord.c
@@ -0,0 +1,305 @@
+#include "rgeos.h"
+
+GEOSCoordSeq rgeos_crdMat2CoordSeq(SEXP env, SEXP mat, SEXP dim) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    int n = INTEGER_POINTER(dim)[0];
+    int m = INTEGER_POINTER(dim)[1];
+
+    if (m != 2) error("Only 2D geometries permitted");
+
+    GEOSCoordSeq s = GEOSCoordSeq_create_r(GEOShandle, (unsigned int) n, (unsigned int) m);
+    if (s == NULL) error("rgeos_crdMat2CoordSeq: NULL GEOSCoordSeq");
+
+    double scale = getScale(env);
+    for(int i=0; i<n; i++) {
+        double val;
+        val = makePrecise( NUMERIC_POINTER(mat)[i], scale);
+        if (GEOSCoordSeq_setX_r(GEOShandle, s, (unsigned int) i, val) == 0) {
+            GEOSCoordSeq_destroy_r(GEOShandle, s);
+            error("rgeos_crdMat2CoordSeq: X not set for %d", i);
+        }
+        val = makePrecise( NUMERIC_POINTER(mat)[i+n], scale);
+        if (GEOSCoordSeq_setY_r(GEOShandle, s, (unsigned int) i, val) == 0) {
+            GEOSCoordSeq_destroy_r(GEOShandle, s);
+            error("rgeos_crdMat2CoordSeq: Y not set for %d", i);
+        }
+    }
+
+    return(s);
+}
+
+GEOSGeom rgeos_crdMat2LineString(SEXP env, SEXP mat, SEXP dim) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    GEOSCoordSeq s = rgeos_crdMat2CoordSeq(env, mat, dim);    
+    GEOSGeom gl = GEOSGeom_createLineString_r(GEOShandle, s);
+    
+    if (gl == NULL) {
+        GEOSGeom_destroy_r(GEOShandle, gl);
+        error("rgeos_crdMat2LineString: lineString not created");
+    }
+    return(gl);
+}
+
+
+GEOSGeom rgeos_crdMat2LinearRing(SEXP env, SEXP mat, SEXP dim) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    GEOSCoordSeq s = rgeos_crdMat2CoordSeq(env, mat, dim);
+
+    GEOSGeom gl = GEOSGeom_createLinearRing_r(GEOShandle, s);
+    if (gl == NULL) {
+        GEOSGeom_destroy_r(GEOShandle, gl);
+        error("rgeos_crdMat2LinearRing: linearRing not created");
+    }
+    /*
+	if ((int) GEOSisValid_r(GEOShandle, gl) == 1) {
+        if (GEOSNormalize_r(GEOShandle, gl) == -1)
+            warning("rgeos_crdMat2LinearRing: normalization failure");
+    } else {
+        warning("rgeos_crdMat2LinearRing: validity failure");
+    }*/
+
+    return(gl);
+}
+
+GEOSGeom rgeos_crdMat2Polygon(SEXP env, SEXP mat, SEXP dim) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    GEOSGeom g1 = rgeos_crdMat2LinearRing(env, mat, dim);
+    GEOSGeom p1 = GEOSGeom_createPolygon_r(GEOShandle, g1, NULL, (unsigned int) 0);
+    if (p1 == NULL) {
+        GEOSGeom_destroy_r(GEOShandle, g1);
+        error("rgeos_crdMat2Polygon: Polygon not created");
+    }
+
+    return(p1);
+}
+
+SEXP rgeos_crdMatFixDir(SEXP crd, int hole) {
+    
+    double area = 0.0;
+    int n = length(crd)/2, pc=0;
+    for(int i=1; i<n;i++) {
+        area += (NUMERIC_POINTER(crd)[i] - NUMERIC_POINTER(crd)[i-1])*
+                (NUMERIC_POINTER(crd)[i+n] + NUMERIC_POINTER(crd)[i+n-1]);
+    }
+    
+    int cw = (area > 0) ? TRUE : FALSE;
+    
+    if ( (hole && cw) || (!hole && !cw) ) {
+        SEXP newcrd;
+        PROTECT( newcrd = NEW_NUMERIC(n*2) ); pc++;
+        for(int i=0; i<n;i++) {
+            NUMERIC_POINTER(newcrd)[i] = NUMERIC_POINTER(crd)[n-i-1];
+            NUMERIC_POINTER(newcrd)[n+i] = NUMERIC_POINTER(crd)[n+n-i-1];
+        }
+        
+        PROTECT(crd = rgeos_formatcrdMat(newcrd, n)); pc++;
+    
+        UNPROTECT(pc);
+    }
+    
+    //Rprintf("HERE cw:%d hole:%d\n",cw,hole);
+    return(crd);
+}
+
+SEXP rgeos_CoordSeq2crdMat(SEXP env, const GEOSCoordSequence *s, int HasZ, int rev) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    unsigned int n, m=0;
+    if (GEOSCoordSeq_getSize_r(GEOShandle, s, &n) == 0 ||
+        GEOSCoordSeq_getDimensions_r(GEOShandle, s, &m) == 0) {
+        error("rgeos_CoordSeq2crdMat: unable to get size and or get dimension of Coord Seq");
+    }
+    
+    if (m == 3 && HasZ)
+        warning("rgeos_CoordSeq2crdMat: only 2D coordinates respected");
+    
+    int pc=0;
+    SEXP crd;
+    PROTECT(crd = NEW_NUMERIC(n*2)); pc++;
+    
+    double scale = getScale(env);
+    for (int i=0; i<n; i++){
+        int ii = (rev) ? ((int) (n) -1)-i : i;
+        
+        double x=0.0, y=0.0;
+        if (GEOSCoordSeq_getX_r(GEOShandle, s, (unsigned int) i, &x) == 0 ||
+            GEOSCoordSeq_getY_r(GEOShandle, s, (unsigned int) i, &y) == 0) {
+            error("rgeos_CoordSeq2crdMat: unable to get X and or Y value from Coord Seq");
+        }
+        NUMERIC_POINTER(crd)[ii]    = makePrecise(x, scale);
+        NUMERIC_POINTER(crd)[ii+ (int) n]  = makePrecise(y, scale);
+    }
+
+    SEXP ans;
+    PROTECT(ans = rgeos_formatcrdMat(crd, (int) n));pc++;
+    
+    UNPROTECT(pc);
+    return(ans);
+}
+
+
+SEXP rgeos_geospoint2crdMat(SEXP env, GEOSGeom geom, SEXP idlist, int ntotal, int type) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    int m = (type == GEOS_GEOMETRYCOLLECTION) ? GEOSGetNumGeometries_r(GEOShandle, geom) : 1;
+    if (m == -1) error("rgeos_geospoint2crdMat: invalid number of geometries");
+    
+    int pc=0;
+    SEXP mat;
+    PROTECT(mat = NEW_NUMERIC(ntotal*2)); pc++;
+
+    SEXP ids = R_NilValue;
+    if (idlist != R_NilValue) {/* FIXME RSB */
+        PROTECT(ids = NEW_CHARACTER(ntotal)); pc++;
+    }
+
+    int k=0;
+    double scale=getScale(env);
+    
+/*    int curtype = type; RSB 120624 */
+    
+    for(int j = 0; j<m; j++) {
+        
+        GEOSGeom curgeom = (type == GEOS_GEOMETRYCOLLECTION) ? 
+                                (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, j) :
+                                geom;
+        if (curgeom == NULL) error("rgeos_geospoint2crdMat: unable to get sub geometry");
+        
+        int curtype = GEOSGeomTypeId_r(GEOShandle, curgeom);
+        int n = GEOSGetNumGeometries_r(GEOShandle, curgeom);
+        if (n == -1) error("rgeos_geospoint2crdMat: invalid number of geometries");
+        n = n ? n : 1;
+        
+        char idbuf[BUFSIZ];
+        if (idlist != R_NilValue) /* FIXME RSB */
+            strcpy(idbuf, CHAR(STRING_ELT(idlist, j)));
+        
+        for (int i=0; i<n; i++) {
+            GEOSGeom subgeom = (curtype == GEOS_MULTIPOINT && !GEOSisEmpty_r(GEOShandle, curgeom)) ?
+                                (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, curgeom, i) :
+                                curgeom;
+            if (subgeom == NULL) error("rgeos_geospoint2crdMat: unable to get sub geometry");
+            
+            if (GEOSisEmpty_r(GEOShandle, subgeom) == 1) {
+                NUMERIC_POINTER(mat)[k]        = NA_REAL;
+                NUMERIC_POINTER(mat)[k+ntotal] = NA_REAL;
+            } else {
+                double x,y;
+                rgeos_Pt2xy(env, subgeom, &x, &y);
+                
+                NUMERIC_POINTER(mat)[k]        = makePrecise(x, scale);
+                NUMERIC_POINTER(mat)[k+ntotal] = makePrecise(y, scale);
+            }
+            if (idlist != R_NilValue) /* FIXME RSB */
+                SET_STRING_ELT(ids, k, COPY_TO_USER_STRING(idbuf));
+            
+            k++;
+        }
+    }
+    
+    SEXP ans;
+    PROTECT(ans = rgeos_formatcrdMat(mat,ntotal));pc++;
+    
+    if (idlist != R_NilValue) { /* FIXME RSB */
+        SEXP dimnames;
+        PROTECT(dimnames = getAttrib(ans, R_DimNamesSymbol));pc++;
+        SET_VECTOR_ELT(dimnames, 0, ids);
+        setAttrib(ans, R_DimNamesSymbol, dimnames);
+    }
+    
+    UNPROTECT(pc);
+    return(ans);
+}
+
+
+SEXP rgeos_formatcrdMat( SEXP crdMat, int n ) {
+    int pc = 0;
+    
+    SEXP dims;
+    PROTECT(dims = NEW_INTEGER(2)); pc++;
+    INTEGER_POINTER(dims)[0] = n;
+    INTEGER_POINTER(dims)[1] = 2;
+    
+    SEXP dimnames;
+    PROTECT(dimnames = NEW_LIST(2)); pc++;
+    SET_VECTOR_ELT(dimnames, 1, NEW_CHARACTER(2));
+    SET_STRING_ELT(VECTOR_ELT(dimnames, 1), 0, COPY_TO_USER_STRING("x"));
+    SET_STRING_ELT(VECTOR_ELT(dimnames, 1), 1, COPY_TO_USER_STRING("y"));
+    
+    setAttrib(crdMat, R_DimSymbol, dims);
+    setAttrib(crdMat, R_DimNamesSymbol, dimnames);
+    
+    UNPROTECT(pc);
+    return(crdMat);
+}
+
+
+
+GEOSGeom rgeos_xy2Pt(SEXP env, double x, double y) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    GEOSGeom gl;
+    GEOSCoordSeq s;
+    
+    if (ISNA(x) && ISNA(y)) {
+        gl = GEOSGeom_createPoint_r(GEOShandle, NULL);
+    } else {
+        s = GEOSCoordSeq_create_r(GEOShandle, (unsigned int) 1, (unsigned int) 2);
+        if (s == NULL) error("rgeos_xy2Pt: NULL GEOSCoordSeq");
+
+        if (GEOSCoordSeq_setX_r(GEOShandle, s, 0, x) == 0) {
+            GEOSCoordSeq_destroy_r(GEOShandle, s);
+            error("rgeos_xy2Pt: X not set");
+        }
+        if (GEOSCoordSeq_setY_r(GEOShandle, s, 0, y) == 0) {
+            GEOSCoordSeq_destroy_r(GEOShandle, s);
+            error("rgeos_xy2Pt: Y not set");
+        }
+        
+        gl = GEOSGeom_createPoint_r(GEOShandle, s);
+    }
+    
+    if (gl == NULL) { // EJP: destroy NULL pointer?
+        //GEOSGeom_destroy_r(GEOShandle, gl);
+        error("rgeos_xy2Pt: point not created");
+    }
+    
+    return(gl);
+}
+
+void rgeos_Pt2xy(SEXP env, GEOSGeom point, double *x, double *y) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    if (GEOSisEmpty_r(GEOShandle, point)) {
+        *x = NA_REAL;
+        *y = NA_REAL;
+        return;
+    }
+    
+    int type = GEOSGeomTypeId_r(GEOShandle, point);
+    if (type != GEOS_POINT)
+        error("rgeos_Pt2xy: invalid geometry type, only accepts POINT type");
+    
+    GEOSCoordSeq s = (GEOSCoordSeq) GEOSGeom_getCoordSeq_r(GEOShandle, point);
+    if (s == NULL) error("rgeos_Pt2xy: unable to get coord seq");
+
+    if (GEOSCoordSeq_getX_r(GEOShandle, s, (unsigned int) 0, x) == 0 ||
+        GEOSCoordSeq_getY_r(GEOShandle, s, (unsigned int) 0, y) == 0 ) {
+    
+        error("rgeos_Pt2xy: unable to get X and or Y value from coord seq");
+    }   
+
+}
+
diff --git a/src/rgeos_geos2R.c b/src/rgeos_geos2R.c
new file mode 100644
index 0000000..642f2d0
--- /dev/null
+++ b/src/rgeos_geos2R.c
@@ -0,0 +1,873 @@
+#include "rgeos.h"
+
+SEXP rgeos_convert_geos2R(SEXP env, GEOSGeom geom, SEXP p4s, SEXP id) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    int type = GEOSGeomTypeId_r(GEOShandle, geom);
+    int ng = GEOSGetNumGeometries_r(GEOShandle, geom);
+    if (ng == -1) error("rgeos_convert_geos2R: invalid number of subgeometries"); 
+    
+    if (type == GEOS_GEOMETRYCOLLECTION && ng==0 && GEOSisEmpty_r(GEOShandle,geom)) {
+        GEOSGeom_destroy_r(GEOShandle, geom);
+        return(R_NilValue);
+    }
+    
+    ng = ng ? ng : 1; // Empty MULTI type geometries return size 0
+
+    int pc=0;
+
+    SEXP ans=NULL;
+    switch(type) { // Determine appropriate conversion for the collection
+        case -1:
+            error("rgeos_convert_geos2R: unknown geometry type");
+            break;
+            
+        case GEOS_POINT:
+        case GEOS_MULTIPOINT:
+            PROTECT( ans = rgeos_geospoint2SpatialPoints(env, geom, p4s, id, ng) ); pc++;
+            break;
+    
+        case GEOS_LINEARRING:
+            PROTECT( ans = rgeos_geosring2SpatialRings(env, geom, p4s, id, ng)); pc++;
+            break;
+            
+        case GEOS_LINESTRING:
+        case GEOS_MULTILINESTRING:
+            PROTECT( ans = rgeos_geosline2SpatialLines(env, geom, p4s, id, 1) ); pc++;
+            break;
+    
+        case GEOS_POLYGON:
+        case GEOS_MULTIPOLYGON:
+            PROTECT( ans = rgeos_geospolygon2SpatialPolygons(env, geom,p4s, id, 1) ); pc++;
+            break;
+        
+        case GEOS_GEOMETRYCOLLECTION:
+        {    
+            
+            int gctypes[] = {0,0,0,0,0,0,0,0};
+            int gctypen[] = {0,0,0,0,0,0,0,0};
+            int n=0;
+            
+            int *types = (int *) R_alloc((size_t) ng, sizeof(int));
+            for (int i=0; i<ng; i++) {
+                const GEOSGeometry *subgeom = GEOSGetGeometryN_r(GEOShandle, geom, i);
+                if (subgeom == NULL)
+                    error("rgeos_convert_geos2R: unable to retrieve subgeometry");
+                
+                int ns = GEOSGetNumGeometries_r(GEOShandle, subgeom);
+                if (ns == -1) error("rgeos_convert_geos2R: invalid number of geometries in subgeometry");
+                ns = ns ? ns : 1;
+                n += ns;
+                
+                types[i] = GEOSGeomTypeId_r(GEOShandle, subgeom);
+                if (types[i] == GEOS_GEOMETRYCOLLECTION) {
+                    Rprintf("output subgeometry %d, row.name: %s\n", i,
+                        CHAR(STRING_ELT(id, i)));
+                    for (int ii=0; ii<ns; ii++)
+                        Rprintf("subsubgeometry %d: %s\n", ii,
+                            GEOSGeomType_r(GEOShandle,
+                            GEOSGetGeometryN_r(GEOShandle, subgeom, ii)));
+                    error("Geometry collections may not contain other geometry collections");
+                }
+                
+                gctypes[ types[i] ] += 1; 
+                gctypen[ types[i] ] += ns;
+            }
+            
+            int isPoint = gctypes[GEOS_POINT] + gctypes[GEOS_MULTIPOINT];
+            int isLine  = gctypes[GEOS_LINESTRING] + gctypes[GEOS_MULTILINESTRING];
+            int isPoly  = gctypes[GEOS_POLYGON] + gctypes[GEOS_MULTIPOLYGON];
+            int isRing  = gctypes[GEOS_LINEARRING];
+            int isGC    = gctypes[GEOS_GEOMETRYCOLLECTION];
+            
+            if ( isPoint && !isLine && !isPoly && !isRing && !isGC ) {
+                PROTECT( ans = rgeos_geospoint2SpatialPoints(env, geom, p4s, id, n) ); pc++;
+            } else if ( isLine && !isPoint && !isPoly && !isRing && !isGC ) {
+                PROTECT( ans = rgeos_geosline2SpatialLines(env, geom, p4s, id, ng) ); pc++;
+            } else if ( isPoly && !isPoint && !isLine && !isRing && !isGC ) {
+                PROTECT( ans = rgeos_geospolygon2SpatialPolygons(env, geom, p4s,id, ng) ); pc++;
+            } else if ( isRing && !isPoint && !isLine && !isPoly && !isGC ) {
+                PROTECT( ans = rgeos_geosring2SpatialRings(env, geom, p4s, id, ng) ); pc++;    
+            } else {
+                
+                //Rprintf("isPoint: %d  isLine: %d  isPoly: %d  isRing: %d  isGC: %d\n",isPoint, isLine, isPoly, isRing, isGC);
+                
+                int m = MAX(MAX(MAX(isPoint,isLine),isPoly),isRing);
+                if (length(id) < m) {
+                    char buf[BUFSIZ];
+
+                    PROTECT(id = NEW_CHARACTER(m)); pc++;
+                    for (int i=0;i<m;i++) {
+                        sprintf(buf,"%d",i);
+                        SET_STRING_ELT(id, i, COPY_TO_USER_STRING(buf));
+                    }
+                }
+                
+                GEOSGeom *GCS[4];
+                GCS[0] = (GEOSGeom *) R_alloc((size_t) isPoint, sizeof(GEOSGeom));
+                GCS[1] = (GEOSGeom *) R_alloc((size_t) isLine,  sizeof(GEOSGeom));
+                GCS[2] = (GEOSGeom *) R_alloc((size_t) isRing,  sizeof(GEOSGeom));
+                GCS[3] = (GEOSGeom *) R_alloc((size_t) isPoly,  sizeof(GEOSGeom));
+                
+                SEXP ptID, lID, rID, pID;
+                PROTECT(ptID = NEW_CHARACTER(isPoint)); pc++;
+                PROTECT(lID  = NEW_CHARACTER(isLine)); pc++;
+                PROTECT(rID  = NEW_CHARACTER(isRing)); pc++;
+                PROTECT(pID  = NEW_CHARACTER(isPoly)); pc++;
+                
+                int typei[] = {0,0,0,0};
+                for (int i=0; i<ng; i++) {
+                    const GEOSGeometry *subgeom = GEOSGetGeometryN_r(GEOShandle, geom, i);
+                    if (subgeom == NULL)
+                        error("rgeos_convert_geos2R: unable to retrieve subgeometry");
+                    
+                    int j = -1;
+                    SEXP cur_id=NULL;
+                    
+                    if (types[i]==GEOS_POINT || types[i]==GEOS_MULTIPOINT) {
+                        j=0;
+                        cur_id=ptID;
+                    } else if (types[i]==GEOS_LINESTRING || types[i]==GEOS_MULTILINESTRING) {
+                        j=1;
+                        cur_id=lID;
+                    } else if (types[i]==GEOS_LINEARRING) {
+                        j=2;
+                        cur_id=rID;
+                    } else if (types[i]==GEOS_POLYGON || types[i]==GEOS_MULTIPOLYGON) {
+                        j=3;
+                        cur_id=pID;
+                    }
+                    
+                    if (GCS[j] == NULL)
+                        error("rgeos_convert_geos2R: GCS element is NULL (this should never happen).");
+                    
+                    GCS[j][ typei[j] ] = GEOSGeom_clone_r(GEOShandle, subgeom);
+                    
+                    SET_STRING_ELT(cur_id, typei[j], STRING_ELT(id,typei[j]));
+                    typei[j]++;
+                }         
+                
+                SEXP points = R_NilValue;
+                SEXP lines  = R_NilValue;
+                SEXP rings  = R_NilValue;
+                SEXP polys  = R_NilValue;
+                
+                if (isPoint) {
+                    GEOSGeom ptGC = GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, GCS[0], (unsigned int) isPoint);
+                    PROTECT( points = rgeos_convert_geos2R(env, ptGC, p4s, ptID) ); pc++;
+                }
+                if (isLine) {
+                    GEOSGeom lGC = GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, GCS[1], (unsigned int) isLine);
+                    PROTECT( lines = rgeos_convert_geos2R(env, lGC, p4s, lID) ); pc++;
+                }
+                if (isRing) {
+                    GEOSGeom rGC = GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, GCS[2], (unsigned int) isRing);
+                    PROTECT( rings = rgeos_convert_geos2R(env, rGC, p4s, rID) ); pc++;
+                }
+                if (isPoly) {
+                    GEOSGeom pGC = GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, GCS[3], (unsigned int) isPoly);
+                    PROTECT( polys = rgeos_convert_geos2R(env, pGC, p4s, pID) ); pc++;
+                }
+                
+                PROTECT(ans = NEW_OBJECT(MAKE_CLASS("SpatialCollections"))); pc++;
+                SET_SLOT(ans, install("proj4string"), p4s);
+                
+                SET_SLOT(ans, install("pointobj"), points);
+                SET_SLOT(ans, install("lineobj"), lines);
+                SET_SLOT(ans, install("ringobj"), rings);
+                SET_SLOT(ans, install("polyobj"), polys);
+            
+                SEXP plotOrder;
+                PROTECT(plotOrder = NEW_INTEGER(4)); pc++;
+                INTEGER_POINTER(plotOrder)[0] = 4;
+                INTEGER_POINTER(plotOrder)[1] = 3;
+                INTEGER_POINTER(plotOrder)[2] = 2;
+                INTEGER_POINTER(plotOrder)[3] = 1;
+                SET_SLOT(ans, install("plotOrder"), plotOrder);
+                
+                SEXP bbox;
+                PROTECT(bbox = rgeos_geom2bbox(env, geom)); pc++;
+                SET_SLOT(ans, install("bbox"), bbox);
+            }
+            
+            break;
+        }    
+        default:
+            error("rgeos_convert_geos2R: Unknown geometry type");
+    }
+    
+    GEOSGeom_destroy_r(GEOShandle, geom);
+    UNPROTECT(pc);
+    return(ans);
+}
+
+
+SEXP rgeos_geospolygon2SpatialPolygons(SEXP env, GEOSGeom geom, SEXP p4s, SEXP IDs, int ng) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    int pc=0;
+    int nng = ng;
+    SEXP bbox=R_NilValue, comment;
+    GEOSGeom bb;
+
+    
+    int type = GEOSGeomTypeId_r(GEOShandle, geom);
+    int empty = GEOSisEmpty_r(GEOShandle, geom);
+    if (ng < 1) 
+        error("rgeos_geospolygon2SpatialPolygons: invalid number of geometries");
+    
+    if (ng > length(IDs))
+        error("rgeos_geospolygon2SpatialPolygons: ng > length(IDs)");
+
+    double polyT = NUMERIC_POINTER(findVarInFrame(env,
+        install("polyThreshold")))[0];
+    int dropSlivers = LOGICAL_POINTER(findVarInFrame(env,
+        install("dropSlivers")))[0];
+    int warnSlivers = LOGICAL_POINTER(findVarInFrame(env,
+        install("warnSlivers")))[0];
+    double iarea = 0.0;
+    int *keep = (int *) R_alloc((size_t) ng, sizeof(int));
+    int ing=0;
+    for (int i=0; i<ng; i++) {
+        
+        GEOSGeom GC = (type == GEOS_GEOMETRYCOLLECTION && !empty) ?
+            (GEOSGeometry *) GEOSGetGeometryN_r(GEOShandle, geom, i) :
+            geom;
+        
+        if (GC == NULL) 
+            error("rgeos_geospolygon2SpatialPolygons: unable to get subgeometry");
+        keep[i] = TRUE;
+        GEOSArea_r(GEOShandle, GC, &iarea);
+//Rprintf("%g %g\n", iarea, polyT);
+        if (iarea < polyT) {
+            keep[i] = FALSE;
+            ing++;
+            if (warnSlivers) warning("%d: %s object %s area %g", ing,
+                GEOSGeomType_r(GEOShandle, GC), CHAR(STRING_ELT(IDs, i)),
+                iarea);
+        }
+//Rprintf("keep: %d, type: %s, area: %g, ID: %s\n", keep[i],  GEOSGeomType_r(GEOShandle, GC), iarea, CHAR(STRING_ELT(IDs, i)));
+    }
+
+    GEOSGeom *bbs;
+    if (dropSlivers) {
+        nng = ng - ing;
+        if (nng == 0) {
+            if (warnSlivers)
+                warning("No remaining geometries at threshold %g", polyT);
+            return(R_NilValue);
+        } else if (ng == nng) {
+            dropSlivers = !dropSlivers;
+        } else {
+            bbs = (GEOSGeom *) R_alloc((size_t) nng,
+                sizeof(GEOSGeom));
+        }
+    }
+    if (!dropSlivers) {
+        PROTECT(bbox = rgeos_geom2bbox(env, geom)); pc++;
+    }
+
+
+    SEXP pls;
+    PROTECT(pls = NEW_LIST(nng)); pc++;
+    
+    double *areas = (double *) R_alloc((size_t) nng, sizeof(double));
+    int *po = (int *) R_alloc((size_t) nng, sizeof(int));
+    int ii=0;
+    for (int i=0; i<ng; i++) {
+        if ((dropSlivers && keep[i]) || !dropSlivers) {
+        
+            GEOSGeom GC = (type == GEOS_GEOMETRYCOLLECTION && !empty) ?
+                (GEOSGeometry *) GEOSGetGeometryN_r(GEOShandle, geom, i) :
+                    geom;
+        
+            if (GC == NULL) 
+                error("rgeos_geospolygon2SpatialPolygons: unable to get subgeometry");
+
+
+            SEXP poly, ID;
+            PROTECT( ID = NEW_CHARACTER(1));
+            SET_STRING_ELT(ID,0,STRING_ELT(IDs, i));
+            PROTECT( poly = rgeos_geospolygon2Polygons(env, GC, ID) );
+
+            if (dropSlivers) {
+                if ((bb = GEOSEnvelope_r(GEOShandle,
+                    (GEOSGeom) rgeos_Polygons2MP(env, poly))) == NULL) {
+                    error("rgeos_geospolygon2SpatialPolygons: envelope [%d] not created", i);
+                }
+                bbs[ii] = bb;
+//Rprintf("bb is %s\n", GEOSGeomType_r(GEOShandle, bb));
+            }
+        
+            areas[ii] = NUMERIC_POINTER(GET_SLOT(poly, install("area")))[0];
+            SET_VECTOR_ELT(pls, ii, poly);
+        
+            po[ii] = ii + R_OFFSET;
+
+            UNPROTECT(2); 
+            ii++;
+        }
+    }
+
+    if (dropSlivers) {
+        PROTECT(bbox = rgeos_geom2bbox(env,
+            GEOSGeom_createCollection_r(GEOShandle, GEOS_MULTIPOLYGON,
+                bbs, (unsigned int) nng))); pc++;
+        
+        for (int i=0; i<nng; i++) {
+            GEOSGeom_destroy_r(GEOShandle, bbs[i]);
+        }
+    }
+    
+    revsort(areas, po, nng);
+    
+    SEXP plotOrder;
+    PROTECT(plotOrder = NEW_INTEGER(nng)); pc++;
+    for (int i=0; i<nng; i++) 
+        INTEGER_POINTER(plotOrder)[i] = po[i];
+    
+    SEXP ans;
+    PROTECT(ans = NEW_OBJECT(MAKE_CLASS("SpatialPolygons"))); pc++;
+    SET_SLOT(ans, install("polygons"), pls);
+    SET_SLOT(ans, install("proj4string"), p4s);
+    SET_SLOT(ans, install("plotOrder"), plotOrder);
+    SET_SLOT(ans, install("bbox"), bbox);
+// RSB 120417 add top-level comment that all member Polygons
+// objects have comment set
+    PROTECT(comment = NEW_CHARACTER(1)); pc++;
+    SET_STRING_ELT(comment, 0, mkChar("TRUE"));
+    setAttrib(ans, install("comment"), comment);
+
+    UNPROTECT(pc);
+    return(ans);
+}
+
+
+
+SEXP rgeos_geospolygon2Polygons(SEXP env, GEOSGeom geom, SEXP ID) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc=0;
+    double polyT = NUMERIC_POINTER(findVarInFrame(env,
+        install("polyThreshold")))[0];
+    double totalarea = 0.0;
+    int dropSlivers = LOGICAL_POINTER(findVarInFrame(env,
+        install("dropSlivers")))[0];
+    int warnSlivers = LOGICAL_POINTER(findVarInFrame(env,
+        install("warnSlivers")))[0];
+
+//    GEOSArea_r(GEOShandle, geom, &totalarea);
+//Rprintf("%g %g\n", totalarea, polyT);
+//    if (totalarea < polyT)
+//        warning("Polygons object %s area %g", CHAR(STRING_ELT(ID, 0)),
+//            totalarea);
+
+    
+    int type = GEOSGeomTypeId_r(GEOShandle, geom);    
+    int empty = GEOSisEmpty_r(GEOShandle, geom);
+    int ngeom = GEOSGetNumGeometries_r(GEOShandle, geom);
+    ngeom = ngeom ? ngeom : 1;
+    
+    int npoly = 0;
+    
+    for (int i=0; i<ngeom; i++) {
+        GEOSGeom GC = (type == GEOS_MULTIPOLYGON && !empty) ?
+                        (GEOSGeometry *) GEOSGetGeometryN_r(GEOShandle, geom, i) :
+                        geom;
+        int GCempty = GEOSisEmpty_r(GEOShandle, GC);
+        int GCpolys = (GCempty) ? 1 :
+                        GEOSGetNumInteriorRings_r(GEOShandle, GC) + 1;
+
+
+        npoly += GCpolys;
+    }
+
+    int *keep = (int *) R_alloc((size_t) npoly, sizeof(int));
+    int kk1=npoly;
+    if (polyT > 0.0) {
+        int kk=0;
+        kk1=0;
+        double iiarea, maxiiarea=0.0;
+        int n_maxarea=-1;
+        for (int ii=0; ii<ngeom; ii++) {
+            keep[ii] = TRUE;
+            GEOSGeom GC = (type == GEOS_MULTIPOLYGON && !empty) ?
+                (GEOSGeometry *) GEOSGetGeometryN_r(GEOShandle, geom, ii) :
+                geom;
+        
+            if (GEOSisEmpty_r(GEOShandle, GC)) 
+                error("rgeos_geospolygon2Polygons: empty Polygons object");
+
+            GEOSGeom lr = (GEOSGeometry *) GEOSGetExteriorRing_r(GEOShandle,
+                GC);
+            if (lr == NULL)
+                error("rgeos_geospolygon2Polygons: exterior ring failure");
+            GEOSArea_r(GEOShandle, GEOSGeom_createPolygon_r(GEOShandle, lr, NULL, (unsigned int) 0), &iiarea);
+            if (iiarea < polyT) {
+                keep[kk] = FALSE;
+                if (iiarea > maxiiarea) n_maxarea = kk;
+                if (warnSlivers) 
+                    warning("Exterior ring %d of object %s area %g", ii,
+                    CHAR(STRING_ELT(ID, 0)), iiarea);
+            } else {
+                kk1++;
+            }
+            kk++;
+
+            int nirs = GEOSGetNumInteriorRings_r(GEOShandle, GC);
+            for (int j=0; j<nirs; j++) {
+            
+                lr = (GEOSGeometry *) GEOSGetInteriorRingN_r(GEOShandle, GC, j);
+                if (lr == NULL)
+                    error("rgeos_geospolygon2Polygons: interior ring failure");
+            
+                GEOSArea_r(GEOShandle, GEOSGeom_createPolygon_r(GEOShandle, lr, NULL, (unsigned int) 0), &iiarea);
+                if (iiarea < polyT) {
+                    keep[kk] = FALSE;
+                    if (iiarea > maxiiarea) n_maxarea = kk;
+                    if (warnSlivers) 
+                        warning("Interior ring %d of Polygon %d of object %s area %g", j, ii, CHAR(STRING_ELT(ID, 0)), iiarea);
+                } else {
+                    kk1++;
+                }
+                kk++;
+            }
+        }
+        if (kk1 == 0 && dropSlivers) {
+            if (n_maxarea < 0 || n_maxarea >= npoly)
+                error("n_maxarea %d out of bounds 0:%d", n_maxarea, npoly);
+            keep[n_maxarea] = TRUE;
+            kk1++;
+        }
+    }
+
+    if (polyT > 0.0 && dropSlivers) {
+        npoly = kk1;
+    }
+    
+    SEXP polys;
+    PROTECT(polys = NEW_LIST(npoly)); pc++;
+    int *comm = (int *) R_alloc((size_t) npoly, sizeof(int));
+    int *po = (int *) R_alloc((size_t) npoly, sizeof(int));
+    double *areas = (double *) R_alloc((size_t) npoly, sizeof(double));
+    
+    totalarea = 0.0;
+    int k = 0;
+    int ownerk=0;
+    if (polyT > 0.0 && dropSlivers) {
+        int kk = 0;
+        for (int i=0; i<ngeom; i++) {
+            GEOSGeom GC = (type == GEOS_MULTIPOLYGON && !empty) ?
+                (GEOSGeometry *) GEOSGetGeometryN_r(GEOShandle, geom, i) :
+                 geom;
+        
+            if (GEOSisEmpty_r(GEOShandle, GC)) {
+            
+                error("rgeos_geospolygon2Polygons: empty Polygons object");
+            
+            } else {
+        
+                GEOSGeom lr = (GEOSGeometry *) GEOSGetExteriorRing_r(GEOShandle, GC);
+                if (lr == NULL)
+                    error("rgeos_geospolygon2Polygons: exterior ring failure");
+
+                if (keep[k]) {
+                    SET_VECTOR_ELT(polys, kk, rgeos_geosring2Polygon(env,
+                        lr, FALSE));
+                    comm[kk] = 0;
+        
+                    areas[kk] = NUMERIC_POINTER( GET_SLOT(VECTOR_ELT(polys,
+                        kk), install("area")) )[0];
+                    totalarea += areas[kk];
+                    po[kk] = kk + R_OFFSET;
+        
+                    ownerk = kk + R_OFFSET;
+                    kk++;
+                }
+        
+                k++;
+        
+                int nirs = GEOSGetNumInteriorRings_r(GEOShandle, GC);
+                for (int j=0; j<nirs; j++) {
+                    lr = (GEOSGeometry *) GEOSGetInteriorRingN_r(GEOShandle, GC, j);
+                    if (lr == NULL)
+                        error("rgeos_geospolygon2Polygons: interior ring failure");
+                    if (keep[k]) {
+                        SET_VECTOR_ELT(polys, kk, rgeos_geosring2Polygon(env, lr, TRUE));
+                        comm[kk] = ownerk;
+            
+                        areas[kk] = NUMERIC_POINTER( GET_SLOT(VECTOR_ELT(polys,
+                            kk), install("area")) )[0];
+                        po[kk] = kk + R_OFFSET;
+                        kk++;
+                    }
+                    k++;
+                }
+            }
+        }
+    } else {
+        for (int i=0; i<ngeom; i++) {
+            GEOSGeom GC = (type == GEOS_MULTIPOLYGON && !empty) ?
+                (GEOSGeometry *) GEOSGetGeometryN_r(GEOShandle, geom, i) :
+                 geom;
+        
+            if (GEOSisEmpty_r(GEOShandle, GC)) {
+            
+                error("rgeos_geospolygon2Polygons: empty Polygons object");
+            
+            } else {
+        
+                GEOSGeom lr = (GEOSGeometry *) GEOSGetExteriorRing_r(GEOShandle, GC);
+                if (lr == NULL)
+                    error("rgeos_geospolygon2Polygons: exterior ring failure");
+                SET_VECTOR_ELT(polys, k, rgeos_geosring2Polygon(env,
+                    lr, FALSE));
+                comm[k] = 0;
+        
+                areas[k] = NUMERIC_POINTER( GET_SLOT(VECTOR_ELT(polys, k),
+                    install("area")) )[0];
+                totalarea += areas[k];
+                po[k] = k + R_OFFSET;
+        
+                ownerk = k + R_OFFSET;
+      
+                k++;
+        
+                int nirs = GEOSGetNumInteriorRings_r(GEOShandle, GC);
+                for (int j=0; j<nirs; j++) {
+            
+                    lr = (GEOSGeometry *) GEOSGetInteriorRingN_r(GEOShandle, GC, j);
+                    if (lr == NULL)
+                        error("rgeos_geospolygon2Polygons: interior ring failure");
+            
+                    SET_VECTOR_ELT(polys, k, rgeos_geosring2Polygon(env, lr, TRUE));
+                    comm[k] = ownerk;
+            
+                    areas[k] = NUMERIC_POINTER( GET_SLOT(VECTOR_ELT(polys,
+                        k), install("area")) )[0];
+                    po[k] = k + R_OFFSET;
+            
+                    k++;
+                    
+                }
+            }
+        }
+    } 
+    
+    SEXP plotOrder;
+    PROTECT(plotOrder = NEW_INTEGER(npoly)); pc++;
+    revsort(areas, po, npoly);
+    for (int i=0; i<npoly; i++) 
+        INTEGER_POINTER(plotOrder)[i] = po[i];
+    
+    SEXP labpt = GET_SLOT(VECTOR_ELT(polys,po[0]-1), install("labpt"));
+    
+    SEXP area;
+    PROTECT(area = NEW_NUMERIC(1)); pc++;
+    NUMERIC_POINTER(area)[0] = totalarea;
+    
+    SEXP comment;
+    PROTECT(comment = NEW_CHARACTER(1)); pc++;
+    char *buf;
+    int nc;
+
+    nc = (int) (ceil(log10(npoly)+1.0))+1;
+    buf = (char *) R_alloc((size_t) (npoly*nc)+1, sizeof(char));
+    SP_PREFIX(comm2comment)(buf, (npoly*nc)+1, comm, npoly);
+    SET_STRING_ELT(comment, 0, mkChar((const char*) buf));
+
+    SEXP ans;
+    PROTECT(ans = NEW_OBJECT(MAKE_CLASS("Polygons"))); pc++;    
+    SET_SLOT(ans, install("Polygons"), polys);
+    SET_SLOT(ans, install("plotOrder"), plotOrder);
+    SET_SLOT(ans, install("labpt"), labpt);
+    SET_SLOT(ans, install("ID"), ID);
+    SET_SLOT(ans, install("area"), area);
+    setAttrib(ans, install("comment"), comment);
+
+    UNPROTECT(pc);
+    return(ans);
+}
+
+
+SEXP rgeos_geosring2Polygon(SEXP env, GEOSGeom lr, int hole) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc=0;
+    
+    GEOSCoordSeq s = (GEOSCoordSequence *) GEOSGeom_getCoordSeq_r(GEOShandle, lr);
+    if (s == NULL) 
+        error("rgeos_geosring2Polygon: CoordSeq failure");
+    
+    unsigned int n;
+    if (GEOSCoordSeq_getSize_r(GEOShandle, s, &n) == 0)
+        error("rgeos_geosring2Polygon: CoordSeq failure");
+    
+    // Get coordinates
+    SEXP crd;
+    PROTECT(crd = rgeos_crdMatFixDir(PROTECT(rgeos_CoordSeq2crdMat(env, s, FALSE, hole)), hole)); pc += 2;
+    
+    // Calculate area
+    GEOSGeom p = GEOSGeom_createPolygon_r(GEOShandle,GEOSGeom_clone_r(GEOShandle,lr),NULL,0);
+    if (p == NULL) 
+        error("rgeos_geosring2Polygon: unable to create polygon");
+    
+    SEXP area;
+    PROTECT(area = NEW_NUMERIC(1)); pc++;
+    NUMERIC_POINTER(area)[0] = 0.0;
+    if (!GEOSArea_r(GEOShandle, p, NUMERIC_POINTER(area)))
+        error("rgeos_geosring2Polygon: area calculation failure");
+    
+    
+    // Calculate label position
+    SEXP labpt;
+    PROTECT(labpt = NEW_NUMERIC(2)); pc++;
+    
+    GEOSGeom centroid = GEOSGetCentroid_r(GEOShandle, p);
+    double xc, yc;
+    rgeos_Pt2xy(env, centroid, &xc, &yc);
+    
+    if (!R_FINITE(xc) || !R_FINITE(yc)) {
+        xc = 0.0;
+        yc = 0.0;
+        for(int i=0; i != n; i++) {
+            xc += NUMERIC_POINTER(crd)[i];
+            yc += NUMERIC_POINTER(crd)[(int) (n) +i];
+        }
+        
+        xc /= n;
+        yc /= n;
+    }
+    
+    NUMERIC_POINTER(labpt)[0] = xc;
+    NUMERIC_POINTER(labpt)[1] = yc;
+    
+    GEOSGeom_destroy_r(GEOShandle, centroid);
+    GEOSGeom_destroy_r(GEOShandle, p);
+    
+    // Get ring direction
+    SEXP ringDir;
+    PROTECT(ringDir = NEW_INTEGER(1)); pc++;
+    INTEGER_POINTER(ringDir)[0] = hole ? -1 : 1;
+    
+    // Get hole status
+    SEXP Hole;
+    PROTECT(Hole = NEW_LOGICAL(1)); pc++;
+    LOGICAL_POINTER(Hole)[0] = hole;
+    
+    SEXP ans;
+    PROTECT(ans = NEW_OBJECT(MAKE_CLASS("Polygon"))); pc++;    
+    SET_SLOT(ans, install("ringDir"), ringDir);
+    SET_SLOT(ans, install("labpt"), labpt);
+    SET_SLOT(ans, install("area"), area);
+    SET_SLOT(ans, install("hole"), Hole);
+    SET_SLOT(ans, install("coords"), crd);
+    
+    SEXP valid;
+    PROTECT(valid = SP_PREFIX(Polygon_validate_c)(ans)); pc++;
+    if (!isLogical(valid)) {
+        UNPROTECT(pc);
+        if (isString(valid)) 
+            error(CHAR(STRING_ELT(valid, 0)));
+        else 
+            error("invalid Polygon object");
+    }
+    
+    UNPROTECT(pc);
+    return(ans);
+}
+
+SEXP rgeos_geospoint2SpatialPoints(SEXP env, GEOSGeom geom, SEXP p4s, SEXP id, int n) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+        
+    int type = GEOSGeomTypeId_r(GEOShandle, geom);    
+    if ( type != GEOS_POINT && type != GEOS_MULTIPOINT && type != GEOS_GEOMETRYCOLLECTION )
+        error("rgeos_geospoint2SpatialPoints: invalid geometry type");
+    
+    int pc=0;
+    SEXP bbox, crdmat;
+    if (GEOSisEmpty_r(GEOShandle, geom))
+        error("rgeos_geospoint2SpatialPoints: empty point found");
+    //if (GEOSisEmpty_r(GEOShandle, geom)==0) {
+        PROTECT(bbox = rgeos_geom2bbox(env, geom)); pc++;
+        PROTECT(crdmat = rgeos_geospoint2crdMat(env, geom, id, n, type)); pc++;
+    //} else {
+    //    bbox = R_NilValue;
+    //    crdmat = R_NilValue;
+    //}
+    
+    SEXP ans;
+    PROTECT(ans = NEW_OBJECT(MAKE_CLASS("SpatialPoints"))); pc++;    
+    SET_SLOT(ans, install("coords"), crdmat);
+    SET_SLOT(ans, install("bbox"), bbox);
+    SET_SLOT(ans, install("proj4string"), p4s);
+
+    UNPROTECT(pc);
+    return(ans);
+}
+
+
+SEXP rgeos_geosline2SpatialLines(SEXP env, GEOSGeom geom, SEXP p4s, SEXP idlist, int nlines) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    GEOSGeom curgeom;
+    GEOSGeom subgeom;
+    GEOSCoordSeq s;
+    int type = GEOSGeomTypeId_r(GEOShandle, geom);
+    if (type != GEOS_LINESTRING && type != GEOS_MULTILINESTRING && 
+        type != GEOS_LINEARRING && type != GEOS_GEOMETRYCOLLECTION ) {
+
+        error("rgeos_geosline2SpatialLines: invalid type");
+    }
+    if (nlines < 1) error("rgeos_geosline2SpatialLines: invalid number of geometries");
+    
+    int pc=0;
+
+    if (nlines > length(idlist))
+        error("rgeos_geosline2SpatialLines: nlines > length(idlist)");
+
+    SEXP bbox, lines_list;
+    PROTECT(bbox = rgeos_geom2bbox(env, geom)); pc++;
+    PROTECT(lines_list = NEW_LIST(nlines)); pc++;
+    
+    for(int j = 0; j < nlines; j++) {
+        
+        curgeom = (type == GEOS_GEOMETRYCOLLECTION) ?
+                                (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, j) :
+                                geom;
+        if (curgeom == NULL) 
+            error("rgeos_geosline2SpatialLines: unable to get geometry collection geometry");
+        int curtype = GEOSGeomTypeId_r(GEOShandle, curgeom);
+        
+        int n = GEOSGetNumGeometries_r(GEOShandle, curgeom);
+        if (n == -1) error("rgeos_geosline2SpatialLines: invalid number of geometries in current geometry");
+        n = n ? n : 1;
+        
+        SEXP line_list;
+        PROTECT(line_list = NEW_LIST(n));
+        
+        for(int i = 0; i < n; i++) {
+            subgeom = (curtype == GEOS_MULTILINESTRING && !GEOSisEmpty_r(GEOShandle, curgeom)) ?
+                                    (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, curgeom, i) :
+                                    curgeom;
+            if(subgeom == NULL) error("rgeos_geosline2SpatialLines: unable to get subgeometry");
+            
+            SEXP crdmat;
+            if (GEOSisEmpty_r(GEOShandle, subgeom) == 0) {
+                s = (GEOSCoordSeq) GEOSGeom_getCoordSeq_r(GEOShandle, subgeom);
+                if (s == NULL) 
+                    error("rgeos_geosline2SpatialLines: unable to generate coordinate sequence");
+
+                PROTECT( crdmat = rgeos_CoordSeq2crdMat(env, s, FALSE, FALSE));
+            } else {
+                error("rgeos_geosline2SpatialLines: empty line found");
+//                PROTECT( crdmat = R_NilValue);
+            }
+
+            SEXP line;
+            PROTECT(line = NEW_OBJECT(MAKE_CLASS("Line")));   
+            SET_SLOT(line, install("coords"), crdmat);
+            SET_VECTOR_ELT(line_list, i, line );
+        
+            UNPROTECT(2);
+        }
+
+        SEXP lines;
+        PROTECT( lines = NEW_OBJECT(MAKE_CLASS("Lines")) );
+        SET_SLOT(lines, install("Lines"), line_list);
+        
+        char idbuf[BUFSIZ];
+        strcpy(idbuf, CHAR( STRING_ELT(idlist, j) ));
+        
+        SEXP id;
+        PROTECT( id = NEW_CHARACTER(1) );
+        SET_STRING_ELT(id, 0, COPY_TO_USER_STRING(idbuf));
+        SET_SLOT(lines, install("ID"), id);
+
+        SET_VECTOR_ELT( lines_list, j, lines );
+        
+        UNPROTECT(3);
+    }
+    
+    SEXP ans;    
+    PROTECT(ans = NEW_OBJECT(MAKE_CLASS("SpatialLines"))); pc++;    
+    SET_SLOT(ans, install("lines"), lines_list);
+    SET_SLOT(ans, install("bbox"), bbox);
+    SET_SLOT(ans, install("proj4string"), p4s);
+
+
+    UNPROTECT(pc);
+    return(ans);
+}
+
+
+SEXP rgeos_geosring2SpatialRings(SEXP env, GEOSGeom geom, SEXP p4s, SEXP idlist, int nrings) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    int type = GEOSGeomTypeId_r(GEOShandle, geom);
+    if (type != GEOS_LINEARRING && type != GEOS_GEOMETRYCOLLECTION )
+        error("rgeos_geosring2SpatialRings: invalid type");
+    
+    if (nrings < 1) error("rgeos_geosring2SpatialRings: invalid number of geometries");
+    
+    int pc=0;
+    SEXP bbox, rings_list;
+    PROTECT(bbox = rgeos_geom2bbox(env, geom)); pc++;
+    PROTECT(rings_list = NEW_LIST(nrings)); pc++;
+
+    for(int j = 0; j < nrings; j++) {
+
+        int lpc = 0;
+
+        GEOSGeom curgeom = (type == GEOS_GEOMETRYCOLLECTION) ?
+                                (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, j) :
+                                geom;
+        if (curgeom == NULL) {
+            UNPROTECT(pc);
+            error("rgeos_geosring2SpatialRings: unable to get geometry collection geometry");
+        }
+        
+        SEXP crdmat;
+        if (GEOSisEmpty_r(GEOShandle, curgeom) == 0) {
+            GEOSCoordSeq s = (GEOSCoordSeq) GEOSGeom_getCoordSeq_r(GEOShandle, curgeom);
+            if (s == NULL) {
+                UNPROTECT(pc);
+                error("rgeos_geosring2SpatialRings: unable to generate coordinate sequence");
+            }
+            PROTECT(crdmat = rgeos_crdMatFixDir(PROTECT(rgeos_CoordSeq2crdMat(env, s, FALSE, FALSE)), FALSE)); lpc += 2;
+        } else {
+            PROTECT( crdmat = R_NilValue); lpc++;
+        }
+        
+        SEXP ring;
+        PROTECT(ring = NEW_OBJECT(MAKE_CLASS("Ring"))); lpc++;   
+        SET_SLOT(ring, install("coords"), crdmat);
+        
+        SEXP id;
+        PROTECT( id = NEW_CHARACTER(1) ); lpc++;
+        char idbuf[BUFSIZ];
+        strcpy(idbuf, CHAR( STRING_ELT(idlist, j) ));
+        SET_STRING_ELT(id, 0, COPY_TO_USER_STRING(idbuf));
+        
+        SET_SLOT(ring, install("ID"), id);
+
+        SET_VECTOR_ELT(rings_list, j, ring );
+        
+        
+        UNPROTECT(lpc);
+    }
+    
+    SEXP ans;    
+    PROTECT(ans = NEW_OBJECT(MAKE_CLASS("SpatialRings"))); pc++;    
+    SET_SLOT(ans, install("rings"), rings_list);
+    SET_SLOT(ans, install("bbox"), bbox);
+    SET_SLOT(ans, install("proj4string"), p4s);
+
+    UNPROTECT(pc);
+    return(ans);
+}
diff --git a/src/rgeos_linearref.c b/src/rgeos_linearref.c
new file mode 100644
index 0000000..6dbd21f
--- /dev/null
+++ b/src/rgeos_linearref.c
@@ -0,0 +1,119 @@
+#include "rgeos.h"
+
+// Return distance of points 'spppoints' projected on 'spgeom' from origin
+// of 'spgeom'. Geometry 'spgeom' must be a lineal geometry
+SEXP rgeos_project(SEXP env, SEXP spgeom, SEXP sppoint, SEXP normalized) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    GEOSGeom geom = rgeos_convert_R2geos(env, spgeom);
+
+    SEXP crds = GET_SLOT(sppoint, install("coords"));
+    SEXP dim = getAttrib(crds, install("dim"));
+
+    int nlines = length(GET_SLOT(spgeom, install("lines")));
+    if (nlines < 1) {
+        error("rgeos_project: invalid number of lines");
+    }
+
+    int n = INTEGER_POINTER(dim)[0];
+    if (n < 1) {
+        error("rgeos_project: invalid number of points");
+    }
+
+    int pc = 0;
+    SEXP ans;
+    PROTECT(ans = NEW_NUMERIC(n)); pc++;
+
+    GEOSGeom p;
+
+    // select projection function (normalized/unnormalized)
+    double GEOS_DLL (*proj_fun)(GEOSContextHandle_t,
+                                const GEOSGeometry*,
+                                const GEOSGeometry*);
+
+    if (LOGICAL_POINTER(normalized)[0]) {
+        proj_fun = &GEOSProjectNormalized_r;
+    } else {
+        proj_fun = &GEOSProject_r;
+    }
+
+    // project points to line geometry
+    for (int i = 0; i < n; i++) {
+
+        p = rgeos_xy2Pt(env,
+                        NUMERIC_POINTER(crds)[i],
+                        NUMERIC_POINTER(crds)[i+n]);
+
+        NUMERIC_POINTER(ans)[i] = (*proj_fun)(GEOShandle, geom, p);
+    }
+
+    GEOSGeom_destroy_r(GEOShandle, geom);
+    GEOSGeom_destroy_r(GEOShandle, p);
+
+    UNPROTECT(pc);
+
+    return(ans);
+}
+
+
+// Return closest point to given distance within geometry.
+// 'spgeom' must be a LineString
+SEXP rgeos_interpolate(SEXP env, SEXP spgeom, SEXP d, SEXP normalized) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    GEOSGeom geom = rgeos_convert_R2geos(env, spgeom);
+
+    GEOSGeom res_geos;
+    double dist;
+
+    int nlines = length(GET_SLOT(spgeom, install("lines")));
+    if (nlines < 1) {
+        error("rgeos_project: invalid number of lines");
+    }
+
+    int n = LENGTH(d);
+    if (n < 1) {
+        error("rgeos_interpolate: invalid number of requested points");
+    }
+
+    int pc = 0;
+    SEXP crd;
+    PROTECT(crd = NEW_NUMERIC(n*2)); pc++;
+
+    double x;
+    double y;
+    SEXP ans;
+
+    // select interpolation function (normalized/unnormalized)
+    GEOSGeometry GEOS_DLL *(*interp_fun)(GEOSContextHandle_t,
+                                         const GEOSGeometry*,
+                                         double);
+
+    if (LOGICAL_POINTER(normalized)[0]) {
+        interp_fun = &GEOSInterpolateNormalized_r;
+    } else {
+        interp_fun = &GEOSInterpolate_r;
+    }
+
+    // interpolate points and store result in coord matrix
+    for (int i = 0; i < n; i++) {
+
+        dist = NUMERIC_POINTER(d)[i];
+
+        res_geos = (*interp_fun)(GEOShandle, geom, dist);
+
+        rgeos_Pt2xy(env, res_geos, &x, &y);
+
+        NUMERIC_POINTER(crd)[i] = x;
+        NUMERIC_POINTER(crd)[n+i] = y;
+    }
+
+    GEOSGeom_destroy_r(GEOShandle, geom);
+    GEOSGeom_destroy_r(GEOShandle, res_geos);
+
+    // return coordinates as matrix
+    PROTECT(ans = rgeos_formatcrdMat(crd, n)); pc++;
+
+    UNPROTECT(pc);
+    return(ans);
+}
diff --git a/src/rgeos_misc.c b/src/rgeos_misc.c
new file mode 100644
index 0000000..afa7962
--- /dev/null
+++ b/src/rgeos_misc.c
@@ -0,0 +1,239 @@
+#include "rgeos.h"
+
+
+SEXP rgeos_area(SEXP env, SEXP obj, SEXP byid) {
+    return( rgeos_miscfunc(env, obj, byid, &GEOSArea_r) );
+}
+
+SEXP rgeos_length(SEXP env, SEXP obj, SEXP byid) {
+    return( rgeos_miscfunc(env, obj, byid, &GEOSLength_r) );
+}
+
+
+SEXP rgeos_miscfunc(SEXP env, SEXP obj, SEXP byid, p_miscfunc miscfunc) {
+
+    SEXP ans;
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    GEOSGeom geom = rgeos_convert_R2geos(env, obj);
+    int type = GEOSGeomTypeId_r(GEOShandle, geom);
+    
+    int n = (LOGICAL_POINTER(byid)[0] && type == GEOS_GEOMETRYCOLLECTION) ? 
+                GEOSGetNumGeometries_r(GEOShandle, geom) : 1;
+    
+    int pc=0;
+    PROTECT(ans = NEW_NUMERIC(n)); pc++;
+
+    GEOSGeom curgeom = geom;
+    for(int i=0; i<n; i++) {
+        if ( n > 1) {
+            curgeom = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, i);
+            if (curgeom == NULL) error("rgeos_miscfunc: unable to get subgeometries");
+        }
+        
+        double val;
+        if (!miscfunc(GEOShandle, curgeom, &val))
+            error("rgeos_miscfunc: unable to calculate");
+            
+        NUMERIC_POINTER(ans)[i] = val;
+    }
+
+    GEOSGeom_destroy_r(GEOShandle, geom);
+
+    UNPROTECT(pc);
+    return(ans);
+}
+
+
+
+SEXP rgeos_distance(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_distancefunc(env, spgeom1, spgeom2, byid, &GEOSDistance_r) );
+}
+
+SEXP rgeos_hausdorffdistance(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_distancefunc(env, spgeom1, spgeom2, byid, &GEOSHausdorffDistance_r) );
+}
+
+SEXP rgeos_distancefunc(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, p_distfunc distfunc) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    GEOSGeom geom1 = rgeos_convert_R2geos(env, spgeom1);
+    int type1 = GEOSGeomTypeId_r(GEOShandle, geom1);
+    GEOSGeom geom2;
+    int type2;
+    
+    int sym_ans = FALSE;
+    if (spgeom2 == R_NilValue) {
+        sym_ans = TRUE;
+        geom2 = geom1;
+        type2 = GEOSGeomTypeId_r(GEOShandle, geom2);
+    } else {
+        geom2 = rgeos_convert_R2geos(env, spgeom2);
+        type2 = GEOSGeomTypeId_r(GEOShandle, geom2);
+    }
+
+    int m = (LOGICAL_POINTER(byid)[0] && type1 == GEOS_GEOMETRYCOLLECTION) ?
+                GEOSGetNumGeometries_r(GEOShandle, geom1) : 1;
+    int n = (LOGICAL_POINTER(byid)[1] && type2 == GEOS_GEOMETRYCOLLECTION) ?
+                GEOSGetNumGeometries_r(GEOShandle, geom2) : 1;
+                
+    if (m == -1) error("rgeos_distancefunc: invalid number of subgeometries in geometry 1");
+    if (n == -1) error("rgeos_distancefunc: invalid number of subgeometries in geometry 2");
+
+    int pc=0;
+    SEXP ans;
+    PROTECT(ans = NEW_NUMERIC(m*n)); pc++;
+
+    GEOSGeom curgeom1 = geom1;
+    GEOSGeom curgeom2 = geom2;
+    for(int i=0; i<m; i++) {
+        
+        if ( m > 1) {
+            curgeom1 = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom1, i);
+            if (curgeom1 == NULL) 
+                error("rgeos_binpredfunc: unable to get subgeometries from geometry 1");
+        }
+        for(int j=0; j<n; j++) {
+            if(sym_ans && j > i)
+                break;
+            
+            if ( n > 1) {
+                curgeom2 = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom2, j);
+                if (curgeom2 == NULL) 
+                    error("rgeos_binpredfunc: unable to get subgeometries from geometry 2");
+            }
+            
+            double dist;
+            if (!distfunc(GEOShandle, curgeom1, curgeom2, &dist))
+                error("rgeos_distancefunc: unable to calculate distance");
+
+            NUMERIC_POINTER(ans)[n*i+j] = dist;
+            if (sym_ans) NUMERIC_POINTER(ans)[n*j+i] = dist;
+        }
+    }
+    
+	if (LOGICAL_POINTER(byid)[0] || LOGICAL_POINTER(byid)[1]) {
+        SEXP dims;
+        PROTECT(dims = NEW_INTEGER(2)); pc++;
+        INTEGER_POINTER(dims)[0] = n;
+        INTEGER_POINTER(dims)[1] = m;
+        setAttrib(ans, R_DimSymbol, dims);
+    }
+    
+    GEOSGeom_destroy_r(GEOShandle, geom1);
+    if (!sym_ans)
+        GEOSGeom_destroy_r(GEOShandle, geom2);
+    
+    UNPROTECT(pc);
+    return(ans);
+}
+
+
+SEXP rgeos_hausdorffdistancedensify(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP densifyFrac, SEXP byid) {
+    return( rgeos_distancedensifyfunc(env, spgeom1, spgeom2, densifyFrac, byid, &GEOSHausdorffDistanceDensify_r) );
+}
+
+SEXP rgeos_distancedensifyfunc(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP densifyFrac, SEXP byid, p_distdenfunc distfunc) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    GEOSGeom geom1 = rgeos_convert_R2geos(env, spgeom1);
+    int type1 = GEOSGeomTypeId_r(GEOShandle, geom1);
+    GEOSGeom geom2;
+    int type2;
+    
+    int sym_ans = FALSE;
+    if (spgeom2 == R_NilValue) {
+        sym_ans = TRUE;
+        geom2 = geom1;
+        type2 = GEOSGeomTypeId_r(GEOShandle, geom2);
+    } else {
+        geom2 = rgeos_convert_R2geos(env, spgeom2);
+        type2 = GEOSGeomTypeId_r(GEOShandle, geom2);
+    }
+
+    int m = (LOGICAL_POINTER(byid)[0] && type1 == GEOS_GEOMETRYCOLLECTION) ?
+                GEOSGetNumGeometries_r(GEOShandle, geom1) : 1;
+    int n = (LOGICAL_POINTER(byid)[1] && type2 == GEOS_GEOMETRYCOLLECTION) ?
+                GEOSGetNumGeometries_r(GEOShandle, geom2) : 1;
+                
+    if (m == -1) error("rgeos_distancefunc: invalid number of subgeometries in geometry 1");
+    if (n == -1) error("rgeos_distancefunc: invalid number of subgeometries in geometry 2");
+
+    double frac = NUMERIC_POINTER(densifyFrac)[0];
+
+    int pc=0;
+    SEXP ans;
+    PROTECT(ans = NEW_NUMERIC(m*n)); pc++;
+
+    GEOSGeom curgeom1 = geom1;
+    GEOSGeom curgeom2 = geom2;
+    for(int i=0; i<m; i++) {
+        
+        if ( m > 1) {
+            curgeom1 = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom1, i);
+            if (curgeom1 == NULL) 
+                error("rgeos_binpredfunc: unable to get subgeometries from geometry 1");
+        }
+        for(int j=0; j<n; j++) {
+            if(sym_ans && j > i)
+                break;
+            
+            if ( n > 1) {
+                curgeom2 = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom2, j);
+                if (curgeom2 == NULL) 
+                    error("rgeos_binpredfunc: unable to get subgeometries from geometry 2");
+            }
+            
+            double dist;
+            if (!distfunc(GEOShandle, curgeom1, curgeom2, frac, &dist))
+                error("rgeos_distancefunc: unable to calculate distance");
+
+            NUMERIC_POINTER(ans)[n*i+j] = dist;
+            if (sym_ans) NUMERIC_POINTER(ans)[n*j+i] = dist;
+        }
+    }
+    
+    if (n != 1 && m !=1) {
+        SEXP dims;
+        PROTECT(dims = NEW_INTEGER(2)); pc++;
+        INTEGER_POINTER(dims)[0] = n;
+        INTEGER_POINTER(dims)[1] = m;
+        setAttrib(ans, R_DimSymbol, dims);
+    }
+    
+    GEOSGeom_destroy_r(GEOShandle, geom1);
+    if (!sym_ans)
+        GEOSGeom_destroy_r(GEOShandle, geom2);
+    
+    UNPROTECT(pc);
+    return(ans);
+}
+
+#ifdef HAVE_NEARESTPOINTS
+SEXP rgeos_nearestpoints(SEXP env, SEXP spgeom1, SEXP spgeom2) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    GEOSGeom geom1 = rgeos_convert_R2geos(env, spgeom1);
+    GEOSGeom geom2 = rgeos_convert_R2geos(env, spgeom2);
+
+
+    // Returns the closest points of the two geometries, 0 on exception.
+    // The first point comes from geom1 geometry and
+    // the second point comes from geom2.
+    GEOSCoordSequence* s = GEOSNearestPoints_r(GEOShandle, geom1, geom2);
+
+    SEXP coordmat;
+    if (s == 0) {
+        coordmat = R_NilValue;
+    } else {
+        coordmat = rgeos_CoordSeq2crdMat(env, s, 0, 0);
+    }
+
+    GEOSCoordSeq_destroy_r(GEOShandle, s);
+
+    return(coordmat);
+}
+#endif
diff --git a/src/rgeos_poly2nb.c b/src/rgeos_poly2nb.c
new file mode 100644
index 0000000..bddbda3
--- /dev/null
+++ b/src/rgeos_poly2nb.c
@@ -0,0 +1,300 @@
+#include "rgeos.h"
+
+struct ud {
+    int count;
+    int *ids;
+};
+
+void cb(void *item, void *userdata) {
+    struct ud *my_UD;
+    my_UD = userdata;
+    my_UD->ids[my_UD->count] = *((int *) item);
+// 110904 EJP
+    my_UD->count++;
+}
+
+static struct ud UD;
+
+SEXP rgeos_poly_findInBox(SEXP env, SEXP pls, SEXP as_points) {
+
+    GEOSGeom *bbs;
+    int npls, i, j, jj, pc=0;
+    GEOSGeom GC, bb;
+    SEXP pl, bblist;
+    GEOSSTRtree *str;
+    int *icard, *ids, *oids;
+    int asPTS = LOGICAL_POINTER(as_points)[0];
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    str = (GEOSSTRtree *) GEOSSTRtree_create_r(GEOShandle, (size_t) 10);
+
+    npls = length(pls);
+    bbs = (GEOSGeom *) R_alloc((size_t) npls, sizeof(GEOSGeom));
+    ids = (int *) R_alloc((size_t) npls, sizeof(int));
+    UD.ids = (int *) R_alloc((size_t) npls, sizeof(int));
+    oids = (int *) R_alloc((size_t) npls, sizeof(int));
+
+    for (i=0; i<npls; i++) {
+        ids[i] = i;
+        pl = VECTOR_ELT(pls, i);
+        if (asPTS) {
+              if ((GC = rgeos_Polygons2MP(env, pl)) == NULL) {
+                error("rgeos_poly2nb: MP GC[%d] not created", i);
+            }
+        } else {
+              if ((GC = rgeos_Polygons2geospolygon(env, pl)) == NULL) {
+                error("rgeos_poly2nb: GC[%d] not created", i);
+            }
+        }
+        if ((bb = GEOSEnvelope_r(GEOShandle, GC)) == NULL) {
+            error("rgeos_poly2nb: envelope [%d] not created", i);
+        }
+        bbs[i] = bb;
+        GEOSSTRtree_insert_r(GEOShandle, str, bb, &(ids[i]));
+// 110904 EJP
+        GEOSGeom_destroy_r(GEOShandle, GC);
+    }
+
+    icard = (int *) R_alloc((size_t) npls, sizeof(int));
+    PROTECT(bblist = NEW_LIST(npls-1)); pc++;
+
+    for (i=0; i<(npls-1); i++) {
+        UD.count = 0;
+        GEOSSTRtree_query_r(GEOShandle, str, bbs[i],
+            (GEOSQueryCallback) cb, &UD);
+        for (j=0, jj=0; j<UD.count; j++) if (UD.ids[j] > i) jj++;
+        icard[i] = jj;
+        if (icard[i] > 0) SET_VECTOR_ELT(bblist, i, NEW_INTEGER(icard[i]));
+
+        for (j=0, jj=0; j<UD.count; j++) {
+            if (icard[i] > 0 && UD.ids[j] > i) {
+                oids[jj] = UD.ids[j] + R_OFFSET;
+                jj++;
+            }
+        }
+        R_isort(oids, jj);
+        for (j=0; j<jj; j++) {
+            INTEGER_POINTER(VECTOR_ELT(bblist, i))[j] = oids[j];
+        }
+    }
+
+    for (i=0; i<npls; i++) {
+        GEOSSTRtree_remove_r(GEOShandle, str, bbs[i], &(ids[i]));
+// 110904 EJP
+        GEOSGeom_destroy_r(GEOShandle, bbs[i]);
+    }
+    GEOSSTRtree_destroy_r(GEOShandle, str);
+
+    UNPROTECT(pc);
+    return(bblist);
+}
+
+/*GEOSSTRtree *rgeos_geom2tree(GEOSContextHandle_t GEOShandle, ) {
+}*/
+
+SEXP rgeos_binary_STRtree_query(SEXP env, SEXP obj1, SEXP obj2) {
+
+    GEOSGeom *bbs2;
+    int nobj1, nobj2, i, j, pc=0, isPts=FALSE;
+    GEOSGeom GC, GCpts=NULL, bb;
+    SEXP pl, bblist;
+    GEOSSTRtree *str;
+    int *icard, *ids, *oids;
+    char classbuf1[BUFSIZ], classbuf2[BUFSIZ];
+    GEOSGeom (*rgeos_xx2MP)(SEXP, SEXP);
+
+    strcpy(classbuf1, CHAR(STRING_ELT(GET_CLASS(VECTOR_ELT(obj1, 0)), 0)));
+    if (!strncmp(classbuf1, "Polygons", 8)) 
+        rgeos_xx2MP = rgeos_Polygons2MP;
+    else if (!strncmp(classbuf1, "Lines", 5)) 
+        rgeos_xx2MP = rgeos_Lines2MP;
+    else
+        error("rgeos_binary_STRtree_query: object class %s unknown", classbuf1);
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    str = (GEOSSTRtree *) GEOSSTRtree_create_r(GEOShandle, (size_t) 10);
+
+    nobj1 = length(obj1);
+
+    SEXP cl2 = GET_CLASS(obj2);
+    if (cl2 == R_NilValue) strcpy(classbuf2, "\0");
+    else strcpy(classbuf2, CHAR(STRING_ELT(cl2, 0)));
+    if ( !strcmp( classbuf2, "SpatialPoints") || 
+        !strcmp(classbuf2, "SpatialPointsDataFrame")) {
+        isPts = TRUE;
+        SEXP crds = GET_SLOT(obj2, install("coords")); 
+        SEXP dim = getAttrib(crds, install("dim")); 
+        nobj2 = INTEGER_POINTER(dim)[0];
+    } else {
+        nobj2 = length(obj2);
+    }
+    bbs2 = (GEOSGeom *) R_alloc((size_t) nobj2, sizeof(GEOSGeom));
+    ids = (int *) R_alloc((size_t) nobj1, sizeof(int));
+
+    UD.ids = (int *) R_alloc((size_t) nobj1, sizeof(int));
+    oids = (int *) R_alloc((size_t) nobj1, sizeof(int));
+
+    for (i=0; i<nobj1; i++) {
+        ids[i] = i;
+        pl = VECTOR_ELT(obj1, i);
+        GC = rgeos_xx2MP(env, pl);
+        if (GC == NULL) {
+            error("rgeos_binary_STRtree_query: MP GC[%d] not created", i);
+        }
+        if ((bb = GEOSEnvelope_r(GEOShandle, GC)) == NULL) {
+            error("rgeos_binary_STRtree_query: envelope [%d] not created", i);
+        }
+        GEOSGeom_destroy_r(GEOShandle, GC);
+        GEOSSTRtree_insert_r(GEOShandle, str, bb, &(ids[i]));
+    }
+
+    if (isPts) {
+        GCpts = rgeos_SpatialPoints2geospoint(env, obj2);
+    } else {
+        strcpy(classbuf2, CHAR(STRING_ELT(GET_CLASS(VECTOR_ELT(obj2, 0)), 0)));
+        if (!strncmp(classbuf2, "Polygons", 8)) 
+            rgeos_xx2MP = rgeos_Polygons2MP;
+        else if (!strncmp(classbuf2, "Lines", 5)) 
+            rgeos_xx2MP = rgeos_Lines2MP;
+        else
+            error("rgeos_binary_STRtree_query: object class %s unknown",
+                classbuf2);
+    }
+
+    for (i=0; i<nobj2; i++) {
+        if (isPts) {
+            GC = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, GCpts, i);
+        } else {
+            pl = VECTOR_ELT(obj2, i);
+            GC = rgeos_xx2MP(env, pl);
+        }
+        if (GC == NULL) {
+            error("rgeos_binary_STRtree_query: GC[%d] not created", i);
+        }
+        if ((bb = GEOSEnvelope_r(GEOShandle, GC)) == NULL) {
+            error("rgeos_binary_STRtree_query: envelope [%d] not created", i);
+        }
+        GEOSGeom_destroy_r(GEOShandle, GC);
+// Rprintf("i: %d, bb %s\n", i, GEOSGeomType_r(GEOShandle, bb));
+        bbs2[i] = bb;
+    }
+// 110904 EJP
+    icard = (int *) R_alloc((size_t) nobj2, sizeof(int));
+    PROTECT(bblist = NEW_LIST(nobj2)); pc++;
+
+    for (i=0; i<nobj2; i++) {
+        UD.count = 0;
+        GEOSSTRtree_query_r(GEOShandle, str, bbs2[i],
+            (GEOSQueryCallback) cb, &UD);
+
+        icard[i] = UD.count;
+
+        if (icard[i] > 0) {
+            SET_VECTOR_ELT(bblist, i, NEW_INTEGER(icard[i]));
+
+            for (j=0; j<UD.count; j++) {
+                oids[j] = UD.ids[j] + R_OFFSET;
+            }
+            R_isort(oids, UD.count);
+            for (j=0; j<UD.count; j++) {
+                INTEGER_POINTER(VECTOR_ELT(bblist, i))[j] = oids[j];
+            }
+        }
+    }
+
+    GEOSSTRtree_destroy_r(GEOShandle, str);
+    for (i=0; i<nobj2; i++) {
+        GEOSGeom_destroy_r(GEOShandle, bbs2[i]);
+    }
+
+    UNPROTECT(pc);
+    return(bblist);
+}
+
+SEXP rgeos_unary_STRtree_query(SEXP env, SEXP obj) {
+
+    GEOSGeom *bbs;
+    int nobj, i, j, jj, pc=0;
+    GEOSGeom GC, bb;
+    SEXP pl, bblist;
+    GEOSSTRtree *str;
+    int *icard, *ids, *oids;
+    char classbuf[BUFSIZ];
+    GEOSGeom (*rgeos_xx2MP)(SEXP, SEXP);
+
+    strcpy(classbuf, CHAR(STRING_ELT(GET_CLASS(VECTOR_ELT(obj, 0)), 0)));
+    if (!strncmp(classbuf, "Polygons", 8)) 
+        rgeos_xx2MP = rgeos_Polygons2MP;
+    else if (!strncmp(classbuf, "Lines", 5)) 
+        rgeos_xx2MP = rgeos_Lines2MP;
+    else if (!strncmp(classbuf, "Polygon", 7))
+        rgeos_xx2MP = rgeos_Polygon2MP;
+    else
+    error("rgeos_binary_STRtree_query: object class %s unknown", classbuf);
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    str = (GEOSSTRtree *) GEOSSTRtree_create_r(GEOShandle, (size_t) 10);
+
+    nobj = length(obj);
+    bbs = (GEOSGeom *) R_alloc((size_t) nobj, sizeof(GEOSGeom));
+    ids = (int *) R_alloc((size_t) nobj, sizeof(int));
+    UD.ids = (int *) R_alloc((size_t) nobj, sizeof(int));
+    oids = (int *) R_alloc((size_t) nobj, sizeof(int));
+
+    for (i=0; i<nobj; i++) {
+        ids[i] = i;
+        pl = VECTOR_ELT(obj, i);
+        GC = rgeos_xx2MP(env, pl);
+        if (GC == NULL) {
+            error("rgeos_unary_STRtree_query: MP GC[%d] not created", i);
+        }
+        if ((bb = GEOSEnvelope_r(GEOShandle, GC)) == NULL) {
+            error("rgeos_unary_STRtree_query: envelope [%d] not created", i);
+        }
+        bbs[i] = bb;
+        GEOSSTRtree_insert_r(GEOShandle, str, bb, &(ids[i]));
+        GEOSGeom_destroy_r(GEOShandle, GC);
+// 110904 EJP
+    }
+
+    icard = (int *) R_alloc((size_t) nobj, sizeof(int));
+    PROTECT(bblist = NEW_LIST(nobj-1)); pc++;
+
+    for (i=0; i<(nobj-1); i++) {
+        UD.count = 0;
+        GEOSSTRtree_query_r(GEOShandle, str, bbs[i],
+            (GEOSQueryCallback) cb, &UD);
+        for (j=0, jj=0; j<UD.count; j++) if (UD.ids[j] > i) jj++;
+        icard[i] = jj;
+        if (icard[i] > 0) {
+            SET_VECTOR_ELT(bblist, i, NEW_INTEGER(icard[i]));
+
+            for (j=0, jj=0; j<UD.count; j++) {
+                if (UD.ids[j] > i) {
+                    oids[jj] = UD.ids[j] + R_OFFSET;
+                    jj++;
+                }
+            }
+            R_isort(oids, jj);
+            for (j=0; j<jj; j++) {
+                INTEGER_POINTER(VECTOR_ELT(bblist, i))[j] = oids[j];
+            }
+        }
+    }
+
+    for (i=0; i<nobj; i++) {
+        GEOSSTRtree_remove_r(GEOShandle, str, bbs[i], &(ids[i]));
+// 110904 EJP
+        GEOSGeom_destroy_r(GEOShandle, bbs[i]);
+    }
+    GEOSSTRtree_destroy_r(GEOShandle, str);
+
+    UNPROTECT(pc);
+    return(bblist);
+}
+
+
+
diff --git a/src/rgeos_predicate_binary.c b/src/rgeos_predicate_binary.c
new file mode 100644
index 0000000..6e19826
--- /dev/null
+++ b/src/rgeos_predicate_binary.c
@@ -0,0 +1,340 @@
+#include "rgeos.h"
+// symmetric intersects_prepared 
+// not symmetric contains_prepared containsproperly_prepared covers_prepared
+
+SEXP rgeos_intersects_prepared(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc_prepared(env,spgeom1,spgeom2,byid, &GEOSPreparedIntersects_r, TRUE) );
+}
+SEXP rgeos_contains_prepared(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc_prepared(env,spgeom1,spgeom2,byid, &GEOSPreparedContains_r, FALSE) );
+}
+SEXP rgeos_containsproperly_prepared(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc_prepared(env,spgeom1,spgeom2,byid, &GEOSPreparedContainsProperly_r, FALSE) );
+}
+SEXP rgeos_covers_prepared(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc_prepared(env,spgeom1,spgeom2,byid, &GEOSPreparedCovers_r, FALSE) );
+}
+
+SEXP rgeos_binpredfunc_prepared(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, p_binpredfunc_prepared binpredfunc_prepared, int canSym) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);  
+    SEXP returnDense = findVarInFrame(env, install("returnDense"));
+    int retDen = LOGICAL_POINTER(returnDense)[0];
+//    SEXP STRsubset = findVarInFrame(env, install("STRsubset"));
+//    int STRsub = LOGICAL_POINTER(STRsubset)[0];
+    int *listvec=NULL, vecn=0;
+  
+    
+    GEOSGeom geom1 = rgeos_convert_R2geos(env, spgeom1);
+    int type1 = GEOSGeomTypeId_r(GEOShandle, geom1);
+    
+    GEOSGeom geom2 = (spgeom2 == R_NilValue) ? geom1 : rgeos_convert_R2geos(env, spgeom2);
+    int type2 = GEOSGeomTypeId_r(GEOShandle, geom2);
+    
+    int S1isS2 = (spgeom2 == R_NilValue);
+    
+    int m = (LOGICAL_POINTER(byid)[0] && type1 == GEOS_GEOMETRYCOLLECTION) ? 
+                GEOSGetNumGeometries_r(GEOShandle, geom1) : 1;
+    int n = (LOGICAL_POINTER(byid)[1] && type2 == GEOS_GEOMETRYCOLLECTION) ?
+                GEOSGetNumGeometries_r(GEOShandle, geom2) : 1;
+    
+    if (m == -1) error("rgeos_binpredfunc_prepared: invalid number of subgeometries in geometry 1");
+    if (n == -1) error("rgeos_binpredfunc_prepared: invalid number of subgeometries in geometry 2");
+    
+    int pc = 0;
+    SEXP ans;
+    if (retDen) {
+        if (((double) n * (double) m) >= INT_MAX)
+            error("rgeos_binpredfunc_prepared: maximum returned dense matrix size exceeded");
+        PROTECT(ans = NEW_LOGICAL(m*n)); pc++;
+    } else {
+        PROTECT(ans = NEW_LIST(m)); pc++;
+        listvec = (int *) R_alloc((size_t) n, sizeof(int));
+        vecn = 0;
+    }
+    
+    for(int i=0; i<m; i++) {
+        
+        const GEOSGeometry *curgeom1 = (m > 1) ? GEOSGetGeometryN_r(GEOShandle, geom1, i) : geom1;
+        if (curgeom1 == NULL) 
+            error("rgeos_binpredfunc_prepared: unable to get subgeometries from geometry 1");
+        
+        const GEOSPreparedGeometry *prepgeom = GEOSPrepare_r(GEOShandle, curgeom1);
+
+        for(int j=0; j<n; j++) {
+            if(S1isS2 && j > i && canSym && retDen)
+                break;
+            
+            const GEOSGeometry *curgeom2 = (n > 1) ? GEOSGetGeometryN_r(GEOShandle, geom2, j) : geom2;
+            if (curgeom2 == NULL) 
+                error("rgeos_binpredfunc_prepared: unable to get subgeometries from geometry 2");
+            
+            int val = (int) binpredfunc_prepared(GEOShandle, prepgeom, curgeom2);
+            if (val == 2)
+                error("rgeos_binpredfunc_prepared: comparison failed");
+
+            if (retDen) {
+                LOGICAL_POINTER(ans)[n*i+j] = val;
+                if (S1isS2 && canSym)
+                    LOGICAL_POINTER(ans)[n*j+i] = val;
+            } else {
+                if (val == 1) {
+                    listvec[vecn] = j+R_OFFSET;
+                    vecn++;
+                }
+            }
+        
+        }
+        if (!retDen && vecn > 0) {
+            SET_VECTOR_ELT(ans, i, NEW_INTEGER(vecn));
+            for (int j=0; j<vecn; j++) {
+                INTEGER_POINTER(VECTOR_ELT(ans, i))[j] = listvec[j];
+            }
+            vecn = 0;
+        }
+        
+        GEOSPreparedGeom_destroy_r(GEOShandle, prepgeom);
+    }
+    
+    if ((LOGICAL_POINTER(byid)[0] || LOGICAL_POINTER(byid)[1]) && retDen) {
+        SEXP dims;
+        PROTECT(dims = NEW_INTEGER(2)); pc++;
+        INTEGER_POINTER(dims)[0] = n;
+        INTEGER_POINTER(dims)[1] = m;
+        setAttrib(ans, R_DimSymbol, dims);
+    }
+    
+    GEOSGeom_destroy_r(GEOShandle, geom1);
+    if (!S1isS2)
+        GEOSGeom_destroy_r(GEOShandle, geom2);
+    
+    UNPROTECT(pc);
+    return(ans);
+}
+
+// symmetric intersects disjoint touches crosses overlaps equals
+// not symmetric contains within relate
+
+
+SEXP rgeos_intersects(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc(env,spgeom1,spgeom2,byid, &GEOSIntersects_r, TRUE) );
+}
+SEXP rgeos_contains(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc(env,spgeom1,spgeom2,byid, &GEOSContains_r, FALSE) );
+}
+SEXP rgeos_disjoint(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc(env,spgeom1,spgeom2,byid, &GEOSDisjoint_r, TRUE) );
+}
+SEXP rgeos_touches(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc(env,spgeom1,spgeom2,byid, &GEOSTouches_r, TRUE) );
+}
+SEXP rgeos_crosses(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc(env,spgeom1,spgeom2,byid, &GEOSCrosses_r, TRUE) );
+}
+SEXP rgeos_within(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc(env,spgeom1,spgeom2,byid, &GEOSWithin_r, FALSE) );
+}
+SEXP rgeos_overlaps(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc(env,spgeom1,spgeom2,byid, &GEOSOverlaps_r, TRUE) );
+}
+SEXP rgeos_equals(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc(env,spgeom1,spgeom2,byid, &GEOSEquals_r, TRUE) );
+}
+SEXP rgeos_relate(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid) {
+    return( rgeos_binpredfunc(env,spgeom1,spgeom2,byid, (p_binpredfunc) &GEOSRelate_r, FALSE) );
+}
+
+SEXP rgeos_binpredfunc(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, p_binpredfunc binpredfunc, int canSym) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    SEXP returnDense = findVarInFrame(env, install("returnDense"));
+    int retDen = LOGICAL_POINTER(returnDense)[0];
+    int *listvec=NULL, vecn=0;
+    int pc = 0;
+    
+    GEOSGeom geom1 = rgeos_convert_R2geos(env, spgeom1);
+    int type1 = GEOSGeomTypeId_r(GEOShandle, geom1);
+    
+    GEOSGeom geom2 = (spgeom2 == R_NilValue) ? geom1 : rgeos_convert_R2geos(env, spgeom2);
+    int type2 = GEOSGeomTypeId_r(GEOShandle, geom2);
+    
+    int S1isS2 = (spgeom2 == R_NilValue);
+    
+    int m = (LOGICAL_POINTER(byid)[0] && type1 == GEOS_GEOMETRYCOLLECTION) ? 
+                GEOSGetNumGeometries_r(GEOShandle, geom1) : 1;
+    int n = (LOGICAL_POINTER(byid)[1] && type2 == GEOS_GEOMETRYCOLLECTION) ?
+                GEOSGetNumGeometries_r(GEOShandle, geom2) : 1;
+    if (m == -1) error("rgeos_binpredfunc: invalid number of subgeometries in geometry 1");
+    if (n == -1) error("rgeos_binpredfunc: invalid number of subgeometries in geometry 2");
+
+    SEXP ans;
+    if (!retDen && binpredfunc == (p_binpredfunc) GEOSRelate_r) {
+        retDen = TRUE;
+        warning("rgeos_binpredfunc: gRelate always returns a dense character matrix");
+    }
+    if (retDen) {
+        if (((double) n * (double) m) >= INT_MAX)
+            error("rgeos_binpredfunc: maximum returned dense matrix size exceeded");
+        if (binpredfunc == (p_binpredfunc) GEOSRelate_r) {
+            PROTECT(ans = NEW_CHARACTER(m*n)); pc++;
+        } else {
+            PROTECT(ans = NEW_LOGICAL(m*n)); pc++;
+        }
+    } else {
+        PROTECT(ans = NEW_LIST(m)); pc++;
+        listvec = (int *) R_alloc((size_t) n, sizeof(int));
+        vecn = 0;
+    }
+    
+    for(int i=0; i<m; i++) {
+        
+        const GEOSGeometry *curgeom1 = (m > 1) ? GEOSGetGeometryN_r(GEOShandle, geom1, i) : geom1;
+        if (curgeom1 == NULL) 
+            error("rgeos_binpredfunc: unable to get subgeometries from geometry 1");
+
+        for(int j=0; j<n; j++) {
+            if(S1isS2 && j > i && canSym && retDen)
+                break;
+            
+            const GEOSGeometry *curgeom2 = (n > 1) ? GEOSGetGeometryN_r(GEOShandle, geom2, j) : geom2;
+            if (curgeom2 == NULL) 
+                error("rgeos_binpredfunc: unable to get subgeometries from geometry 2");
+            
+            if (binpredfunc == (p_binpredfunc) GEOSRelate_r) {
+                char *buf = (char *) GEOSRelate_r(GEOShandle, curgeom1, curgeom2);
+                if (buf == NULL)
+                    error("rgeos_isvalidreason: test failed");
+
+                SET_STRING_ELT(ans, n*i+j, COPY_TO_USER_STRING(buf));
+                if (S1isS2 && canSym)
+                    SET_STRING_ELT(ans, n*j+i, COPY_TO_USER_STRING(buf));
+
+                GEOSFree_r(GEOShandle, buf);
+            } else {
+                int val = (int) binpredfunc(GEOShandle, curgeom1, curgeom2);
+                if (val == 2)
+                    error("rgeos_binpredfunc: comparison failed");
+
+                if (retDen) {
+                    LOGICAL_POINTER(ans)[n*i+j] = val;
+                    if (S1isS2 && canSym)
+                        LOGICAL_POINTER(ans)[n*j+i] = val;
+                } else {
+                    if (val == 1) {
+                        listvec[vecn] = j+R_OFFSET;
+                        vecn++;
+                    }
+                }
+            }
+        }
+        if (!retDen && vecn > 0) {
+            SET_VECTOR_ELT(ans, i, NEW_INTEGER(vecn));
+            for (int j=0; j<vecn; j++) {
+                INTEGER_POINTER(VECTOR_ELT(ans, i))[j] = listvec[j];
+            }
+            vecn = 0;
+        }
+
+    }
+    
+    if ((LOGICAL_POINTER(byid)[0] || LOGICAL_POINTER(byid)[1]) && retDen) {
+        SEXP dims;
+        PROTECT(dims = NEW_INTEGER(2)); pc++;
+        INTEGER_POINTER(dims)[0] = n;
+        INTEGER_POINTER(dims)[1] = m;
+        setAttrib(ans, R_DimSymbol, dims);
+    }
+    
+    GEOSGeom_destroy_r(GEOShandle, geom1);
+    if (!S1isS2)
+        GEOSGeom_destroy_r(GEOShandle, geom2);
+    
+    UNPROTECT(pc);
+    return(ans);
+}
+
+// symmetric equalsexact
+// not symmetric relatepattern
+
+SEXP rgeos_equalsexact(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP tol, SEXP byid) {
+    return( rgeos_binpredfunc_opt(env, spgeom1, spgeom2, tol, byid, FALSE, TRUE) );
+}
+
+SEXP rgeos_relatepattern(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP pattern, SEXP byid) {
+    return( rgeos_binpredfunc_opt(env, spgeom1, spgeom2, pattern, byid, 1, FALSE) );
+}
+
+SEXP rgeos_binpredfunc_opt(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP opt, SEXP byid, int relpat, int canSym) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    GEOSGeom geom1 = rgeos_convert_R2geos(env, spgeom1);
+    int type1 = GEOSGeomTypeId_r(GEOShandle, geom1);
+
+    GEOSGeom geom2 = (spgeom2 == R_NilValue) ? geom1 : rgeos_convert_R2geos(env, spgeom2);
+    int type2 = GEOSGeomTypeId_r(GEOShandle, geom2);
+    
+    int m = (LOGICAL_POINTER(byid)[0] && type1 == GEOS_GEOMETRYCOLLECTION) ? 
+                GEOSGetNumGeometries_r(GEOShandle, geom1) : 1;
+    int n = (LOGICAL_POINTER(byid)[1] && type2 == GEOS_GEOMETRYCOLLECTION) ?
+                GEOSGetNumGeometries_r(GEOShandle, geom2) : 1;
+    
+    int S1isS2 = (spgeom2 == R_NilValue);
+         
+    
+    if (m == -1) error("rgeos_equalsexact: invalid number of subgeometries in geometry 1");
+    if (n == -1) error("rgeos_equalsexact: invalid number of subgeometries in geometry 2");
+    
+    SEXP ans;
+    int pc=0;
+    PROTECT(ans = NEW_LOGICAL(m*n)); pc++;
+      
+    for(int i=0; i<m; i++) {
+        
+        const GEOSGeometry *curgeom1 = (m > 1) ? GEOSGetGeometryN_r(GEOShandle, geom1, i) : geom1;
+        if (curgeom1 == NULL) 
+            error("rgeos_equalsexact: unable to get subgeometries from geometry 1");
+        
+        for(int j=0; j<n; j++) {
+            if(S1isS2 && j > i && canSym)
+                break;
+            
+            const GEOSGeometry *curgeom2 = (n > 1) ? (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom2, j) : geom2;
+            if (curgeom2 == NULL) 
+                error("rgeos_equalsexact: unable to get subgeometries from geometry 2");
+            
+            int val;
+            if (relpat) {
+                char patbuf[BUFSIZ];
+                strcpy(patbuf, CHAR( STRING_ELT(opt, 0) ));
+                val = (int) GEOSRelatePattern_r(GEOShandle, curgeom1, curgeom2, patbuf);
+            } else {
+                val = (int) GEOSEqualsExact_r(GEOShandle, curgeom1, curgeom2, NUMERIC_POINTER(opt)[0] );
+            }
+
+            if (val == 2)
+                error("rgeos_equalsexact: comparison failed");
+
+            LOGICAL_POINTER(ans)[n*i+j] = val;
+            if (S1isS2 && canSym)
+                LOGICAL_POINTER(ans)[n*j+i] = val;
+        }
+    }
+    
+    if (LOGICAL_POINTER(byid)[0] || LOGICAL_POINTER(byid)[1]) {
+        SEXP dims;
+        PROTECT(dims = NEW_INTEGER(2)); pc++;
+        INTEGER_POINTER(dims)[0] = n;
+        INTEGER_POINTER(dims)[1] = m;
+        setAttrib(ans, R_DimSymbol, dims);
+    }
+    
+    GEOSGeom_destroy_r(GEOShandle, geom1);
+    if (!S1isS2)
+        GEOSGeom_destroy_r(GEOShandle, geom2);
+    
+    UNPROTECT(pc);
+    return(ans);
+}
+
+
diff --git a/src/rgeos_predicate_unary.c b/src/rgeos_predicate_unary.c
new file mode 100644
index 0000000..f81244e
--- /dev/null
+++ b/src/rgeos_predicate_unary.c
@@ -0,0 +1,96 @@
+#include "rgeos.h"
+
+SEXP rgeos_isvalid(SEXP env, SEXP spgeom, SEXP byid) {
+    return( rgeos_unarypredfunc(env,spgeom,byid, &GEOSisValid_r) );
+}
+
+SEXP rgeos_issimple(SEXP env, SEXP spgeom, SEXP byid) {
+    return( rgeos_unarypredfunc(env,spgeom,byid, &GEOSisSimple_r) );
+}
+
+SEXP rgeos_isring(SEXP env, SEXP spgeom, SEXP byid) {
+    return( rgeos_unarypredfunc(env,spgeom,byid, &GEOSisRing_r) );
+}
+
+SEXP rgeos_hasz(SEXP env, SEXP spgeom, SEXP byid) {
+    return( rgeos_unarypredfunc(env,spgeom,byid, &GEOSHasZ_r) );
+}
+
+SEXP rgeos_isempty(SEXP env, SEXP spgeom, SEXP byid) {
+    return( rgeos_unarypredfunc(env,spgeom,byid, &GEOSisEmpty_r) );
+}
+
+
+SEXP rgeos_unarypredfunc(SEXP env, SEXP spgeom, SEXP byid, p_unarypredfunc unarypredfunc) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc=0;
+    
+    GEOSGeom geom = rgeos_convert_R2geos(env, spgeom);
+    int type = GEOSGeomTypeId_r(GEOShandle, geom);
+    
+    int n = (LOGICAL_POINTER(byid)[0] && type == GEOS_GEOMETRYCOLLECTION) ?
+            GEOSGetNumGeometries_r(GEOShandle, geom) : 1;
+        
+    if (n == -1) error("rgeos_unarypredfunc: invalid number of subgeometries");
+    
+    SEXP ans;
+    PROTECT(ans = NEW_LOGICAL(n)); pc++;
+    
+    for(int i=0; i<n; i++) {
+        
+        const GEOSGeometry *curgeom = (n > 1) ? GEOSGetGeometryN_r(GEOShandle, geom, i) : geom;
+        if (curgeom == NULL) 
+            error("rgeos_unarypredfunc: unable to get subgeometries");
+        
+        int val = (int) unarypredfunc(GEOShandle, curgeom);
+        if (val == 2)
+            error("rgeos_unarypredfunc: test failed");
+        
+        LOGICAL_POINTER(ans)[i] = val;
+    }
+    
+    GEOSGeom_destroy_r(GEOShandle, geom);
+    
+    UNPROTECT(pc);
+    return(ans);
+}
+
+
+SEXP rgeos_isvalidreason(SEXP env, SEXP spgeom, SEXP byid) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int pc=0;
+    
+    GEOSGeom geom = rgeos_convert_R2geos(env, spgeom);
+    int type = GEOSGeomTypeId_r(GEOShandle, geom);
+    
+    int n = (LOGICAL_POINTER(byid)[0] && type == GEOS_GEOMETRYCOLLECTION)
+              ? GEOSGetNumGeometries_r(GEOShandle, geom) : 1;
+    
+    if (n == -1) error("rgeos_isvalidreason: invalid number of subgeometries");
+    
+    SEXP ans;
+    PROTECT(ans = NEW_CHARACTER(n)); pc++;
+    
+    
+    for(int i=0; i<n; i++) {
+        
+        GEOSGeom curgeom = (n > 1) ? curgeom = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, i) : geom;
+        if (curgeom == NULL) 
+            error("rgeos_isvalidreason: unable to get subgeometries");
+        
+        char *buf = (char *) GEOSisValidReason_r(GEOShandle, curgeom);
+        if (buf == NULL)
+            error("rgeos_isvalidreason: test failed");
+
+        SET_STRING_ELT(ans, i, COPY_TO_USER_STRING(buf));
+        
+        GEOSFree_r(GEOShandle, buf);
+    }
+
+    GEOSGeom_destroy_r(GEOShandle, geom);
+    
+    UNPROTECT(pc);
+    return(ans);
+}
diff --git a/src/rgeos_topology.c b/src/rgeos_topology.c
new file mode 100644
index 0000000..b7a3433
--- /dev/null
+++ b/src/rgeos_topology.c
@@ -0,0 +1,219 @@
+#include "rgeos.h"
+
+
+SEXP rgeos_envelope(SEXP env, SEXP obj, SEXP id, SEXP byid) {
+    return( rgeos_topologyfunc(env, obj, id, byid, &GEOSEnvelope_r) );
+}
+
+SEXP rgeos_convexhull(SEXP env, SEXP obj, SEXP id, SEXP byid) {
+    return( rgeos_topologyfunc(env, obj, id, byid, &GEOSConvexHull_r) );
+}
+
+SEXP rgeos_boundary(SEXP env, SEXP obj, SEXP id, SEXP byid) {
+    return( rgeos_topologyfunc(env, obj, id, byid, &GEOSBoundary_r) );
+}
+    
+SEXP rgeos_getcentroid(SEXP env, SEXP obj, SEXP id, SEXP byid) {
+    return( rgeos_topologyfunc(env, obj, id, byid, &GEOSGetCentroid_r) );
+}
+
+SEXP rgeos_pointonsurface(SEXP env, SEXP obj, SEXP id, SEXP byid) {
+    return( rgeos_topologyfunc(env, obj, id, byid, &GEOSPointOnSurface_r) );
+}
+
+SEXP rgeos_linemerge(SEXP env, SEXP obj, SEXP id, SEXP byid) {
+    return( rgeos_topologyfunc(env, obj, id, byid, &GEOSLineMerge_r) );
+}
+
+SEXP rgeos_unioncascaded(SEXP env, SEXP obj, SEXP id, SEXP byid ) {
+    return( rgeos_topologyfunc(env, obj, id, byid, &GEOSUnionCascaded_r) );
+}
+
+#ifdef HAVE_UNARYUNION
+SEXP rgeos_unaryunion(SEXP env, SEXP obj, SEXP id, SEXP byid ) {
+    return( rgeos_topologyfunc(env, obj, id, byid, &GEOSUnaryUnion_r) ); 
+}
+#endif
+
+#ifdef HAVE_DELAUNAY
+SEXP rgeos_delaunaytriangulation(SEXP env, SEXP obj, SEXP tol,
+  SEXP onlyEdges) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    double tolerance = NUMERIC_POINTER(tol)[0];
+    int oE = INTEGER_POINTER(onlyEdges)[0];
+    int pc=0;
+
+    SEXP ans, id;
+    
+    SEXP p4s = GET_SLOT(obj, install("proj4string"));
+
+    GEOSGeom geom = rgeos_convert_R2geos(env, obj);
+
+    GEOSGeom resgeom = GEOSDelaunayTriangulation_r(GEOShandle, geom,
+        tolerance, oE);
+    if (resgeom == NULL)
+            error("rgeos_delaunaytriangulation: unable to compute");
+
+    GEOSGeom_destroy_r(GEOShandle, geom);
+
+//    int type = GEOSGeomTypeId_r(GEOShandle, resgeom);
+
+    int ng = GEOSGetNumGeometries_r(GEOShandle, resgeom);
+
+//Rprintf("ng: %d, type: %d, %s\n", ng, type, GEOSGeomType_r(GEOShandle, resgeom));
+// FIXME convert type 5 to type 7
+
+    char buf[BUFSIZ];
+
+    PROTECT(id = NEW_CHARACTER(ng)); pc++;
+    for (int i=0; i<ng; i++) {
+        sprintf(buf, "%d", i);
+        SET_STRING_ELT(id, i, COPY_TO_USER_STRING(buf));
+    }
+
+    ans = rgeos_convert_geos2R(env, resgeom, p4s, id); 
+
+    UNPROTECT(pc);
+    return(ans);
+
+}
+#endif
+
+SEXP rgeos_topologyfunc(SEXP env, SEXP obj, SEXP id, SEXP byid, p_topofunc topofunc) {
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    SEXP p4s = GET_SLOT(obj, install("proj4string"));
+    GEOSGeom geom = rgeos_convert_R2geos(env, obj);
+    int type = GEOSGeomTypeId_r(GEOShandle, geom);
+    
+    int n = 1;
+    if (LOGICAL_POINTER(byid)[0] && type == GEOS_GEOMETRYCOLLECTION)
+        n = GEOSGetNumGeometries_r(GEOShandle, geom);
+    
+    if (n < 1) error("rgeos_topologyfunc: invalid number of geometries");
+    
+    GEOSGeom *resgeoms = (GEOSGeom *) R_alloc((size_t) n, sizeof(GEOSGeom));
+    
+    for(int i=0; i<n; i++) {
+        const GEOSGeometry *curgeom = (n > 1) ? (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, i)
+                                       : geom;
+        
+        if (curgeom == NULL) 
+            error("rgeos_topologyfunc: unable to get subgeometries");
+        
+        if (    topofunc == GEOSUnionCascaded_r
+             && GEOSGeomTypeId_r(GEOShandle, curgeom) == GEOS_POLYGON) {
+            resgeoms[i] = GEOSGeom_clone_r(GEOShandle, curgeom);
+        } else {
+            resgeoms[i] = topofunc(GEOShandle, curgeom);
+            if (resgeoms[i] == NULL)
+                error("rgeos_topologyfunc: unable to calculate");
+        }
+    }
+    
+    GEOSGeom_destroy_r(GEOShandle, geom);
+    
+    GEOSGeom res = (n == 1) ? resgeoms[0]
+                    : GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, resgeoms, (unsigned int) n);
+    
+    return( rgeos_convert_geos2R(env, res, p4s, id) ); // releases res
+}
+
+
+SEXP rgeos_simplify(SEXP env, SEXP obj, SEXP tol, SEXP id, SEXP byid, SEXP topPres) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    SEXP p4s = GET_SLOT(obj, install("proj4string"));
+    GEOSGeom geom = rgeos_convert_R2geos(env, obj);
+    int type = GEOSGeomTypeId_r(GEOShandle, geom);
+    
+    int preserve = LOGICAL_POINTER(topPres)[0];
+    double tolerance = NUMERIC_POINTER(tol)[0];
+    
+    int n = 1;
+    if (LOGICAL_POINTER(byid)[0] && type == GEOS_GEOMETRYCOLLECTION)
+        n = GEOSGetNumGeometries_r(GEOShandle, geom);
+    
+    if (n < 1) error("rgeos_simplify: invalid number of geometries");
+    
+    GEOSGeom *resgeoms = (GEOSGeom *) R_alloc((size_t) n, sizeof(GEOSGeom));
+    
+    for(int i=0; i<n; i++) {
+        const GEOSGeometry *curgeom = (n > 1) ? (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, i)
+                                       : geom;
+        if (curgeom == NULL)
+            error("rgeos_topologyfunc: unable to get subgeometries");
+        
+        resgeoms[i] = (preserve)
+                        ? GEOSTopologyPreserveSimplify_r(GEOShandle, curgeom, tolerance)
+                        : GEOSSimplify_r(GEOShandle, curgeom, tolerance);
+    }
+    
+    GEOSGeom_destroy_r(GEOShandle, geom);
+    
+    GEOSGeom res = (n == 1) ? resgeoms[0] :
+                    GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, resgeoms, (unsigned int) n);
+    
+    return( rgeos_convert_geos2R(env, res, p4s, id) );
+}
+
+SEXP rgeos_polygonize(SEXP env, SEXP obj, SEXP id, SEXP p4s, SEXP cutEdges) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    int getCutEdges = LOGICAL_POINTER(cutEdges)[0];
+    int n = length(obj);
+    GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) n, sizeof(GEOSGeom));
+    
+    for(int i=0; i<n; i++) {
+        geoms[i] = rgeos_convert_R2geos(env, VECTOR_ELT(obj,i));
+    }
+    
+    GEOSGeom res = (getCutEdges)
+                     ? GEOSPolygonizer_getCutEdges_r(GEOShandle, (const GEOSGeometry *const *) geoms, (unsigned int) n)
+                     : GEOSPolygonize_r(GEOShandle, (const GEOSGeometry *const *) geoms, (unsigned int) n);
+    
+    return( rgeos_convert_geos2R(env, res, p4s, id) );
+}
+
+#ifdef HAVE_NODE
+SEXP rgeos_node(SEXP env, SEXP obj) {
+
+    SEXP ans, id;
+    int pc=0;
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    SEXP p4s = GET_SLOT(obj, install("proj4string"));
+    GEOSGeom geom = rgeos_convert_R2geos(env, obj);
+//    int type = GEOSGeomTypeId_r(GEOShandle, geom);
+//Rprintf("type: %d, %s\n", type, GEOSGeomType_r(GEOShandle, geom));
+    
+    GEOSGeom res = GEOSNode_r(GEOShandle, geom);
+    
+//    type = GEOSGeomTypeId_r(GEOShandle, res);
+
+    int ng = GEOSGetNumGeometries_r(GEOShandle, res);
+
+//Rprintf("ng: %d, type: %d, %s\n", ng, type, GEOSGeomType_r(GEOShandle, res));
+
+    char buf[BUFSIZ];
+
+    PROTECT(id = NEW_CHARACTER(ng)); pc++;
+    for (int i=0; i<ng; i++) {
+        sprintf(buf, "%d", i);
+        SET_STRING_ELT(id, i, COPY_TO_USER_STRING(buf));
+    }
+
+    GEOSGeom_destroy_r(GEOShandle, geom);
+
+    ans = rgeos_convert_geos2R(env, res, p4s, id); 
+
+    UNPROTECT(pc);
+    return(ans);
+
+}
+#endif
+
diff --git a/src/rgeos_topology_binary.c b/src/rgeos_topology_binary.c
new file mode 100644
index 0000000..405d727
--- /dev/null
+++ b/src/rgeos_topology_binary.c
@@ -0,0 +1,171 @@
+#include "rgeos.h"
+
+SEXP rgeos_difference(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, SEXP ids) {
+    return( rgeos_binarytopologyfunc(env, spgeom1, spgeom2, byid, ids, &GEOSDifference_r) );
+}
+SEXP rgeos_symdifference(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, SEXP ids) {
+    return( rgeos_binarytopologyfunc(env, spgeom1, spgeom2, byid, ids, &GEOSSymDifference_r) );
+}
+SEXP rgeos_intersection(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, SEXP ids) {
+    return( rgeos_binarytopologyfunc(env, spgeom1, spgeom2, byid, ids, &GEOSIntersection_r) );
+}
+SEXP rgeos_union(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, SEXP ids) {
+    return( rgeos_binarytopologyfunc(env, spgeom1, spgeom2, byid, ids, &GEOSUnion_r) );
+}
+
+int GEOSTopologicalDimension_r(GEOSContextHandle_t extHandle,
+    const GEOSGeometry* g) {
+    int gType, res=-1;
+    gType = GEOSGeomTypeId_r(extHandle, g);
+    if (gType == GEOS_POINT || gType == GEOS_MULTIPOINT) res = 0;
+    else if (gType == GEOS_LINESTRING || gType == GEOS_MULTILINESTRING) res = 1;
+    else if (gType == GEOS_POLYGON || gType == GEOS_MULTIPOLYGON) res = 2;
+    return(res);
+}
+
+SEXP rgeos_binarytopologyfunc(SEXP env, SEXP spgeom1, SEXP spgeom2, SEXP byid, SEXP ids, p_bintopofunc bintopofunc) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    int min_tds = INTEGER_POINTER(getAttrib(byid,
+        install("min_tds")))[0];
+    int drop_lower_td = LOGICAL_POINTER(getAttrib(byid,
+        install("drop_lower_td")))[0];
+    int uU = LOGICAL_POINTER(getAttrib(byid,
+        install("unaryUnion_if_byid_false")))[0];
+    int drop_me = FALSE,// k_type, 
+        k_empty;
+    int thistd=-1;
+
+    
+    // Default to using spgeom1's proj4string
+    SEXP p4s = GET_SLOT(spgeom1, install("proj4string"));
+    
+    GEOSGeom geom1 = rgeos_convert_R2geos(env, spgeom1);
+#ifdef HAVE_UNARYUNION
+    if (!LOGICAL_POINTER(byid)[0] && uU) {
+        geom1 = GEOSUnaryUnion_r(GEOShandle, geom1);
+    }
+#endif
+    int type1 = GEOSGeomTypeId_r(GEOShandle, geom1);
+
+    GEOSGeom geom2 = rgeos_convert_R2geos(env, spgeom2);
+#ifdef HAVE_UNARYUNION
+    if (!LOGICAL_POINTER(byid)[1] && uU) {
+        geom2 = GEOSUnaryUnion_r(GEOShandle, geom2);
+    }
+#endif
+    int type2 = GEOSGeomTypeId_r(GEOShandle, geom2);
+
+    int m = (LOGICAL_POINTER(byid)[0] && type1 == GEOS_GEOMETRYCOLLECTION) ? 
+            GEOSGetNumGeometries_r(GEOShandle, geom1) : 1;
+
+    int n = (LOGICAL_POINTER(byid)[1] && type2 == GEOS_GEOMETRYCOLLECTION) ?
+            GEOSGetNumGeometries_r(GEOShandle, geom2) : 1;
+    
+    if (m == -1) error("rgeos_bintopofunc: invalid number of subgeometries in geometry 1");
+    if (n == -1) error("rgeos_bintopofunc: invalid number of subgeometries in geometry 2");
+
+    GEOSGeom *geoms = (GEOSGeom *) R_alloc((size_t) (m*n), sizeof(GEOSGeom));
+    GEOSGeom thisgeom;
+    GEOSGeom kgeom;
+//Rprintf("m=%d n=%d\n", m, n);
+//Rprintf("spgeom1 is %s\n", GEOSGeomType_r(GEOShandle, geom1));
+//Rprintf("spgeom2 is %s\n", GEOSGeomType_r(GEOShandle, geom2));
+
+
+    int k=0, k1=0, kk=0;
+    for(int i=0; i<m; i++) {
+
+        const GEOSGeometry *curgeom1 = (m > 1) ? GEOSGetGeometryN_r(GEOShandle, geom1, i) : geom1;
+        if (curgeom1 == NULL) 
+            error("rgeos_bintopofunc: unable to get subgeometries from geometry 1");
+        
+        for(int j=0; j<n; j++) {
+        
+            const GEOSGeometry *curgeom2 = (n > 1) ? GEOSGetGeometryN_r(GEOShandle, geom2, j) : geom2;
+            if (curgeom2 == NULL) 
+                error("rgeos_bintopofunc: unable to get subgeometries from geometry 2");
+            
+            thisgeom = bintopofunc(GEOShandle, curgeom1, curgeom2);
+            if (thisgeom == NULL)
+                error("rgeos_bintopofunc: topology function failed");
+            if (!GEOSisEmpty_r(GEOShandle, thisgeom)) {
+ // conditionally drop returned objects with lower topological dimension
+ // than minimum TD of input objects
+               drop_me = FALSE;
+               if (drop_lower_td) {
+                   thistd = GEOSTopologicalDimension_r(GEOShandle, thisgeom);
+                   if (thistd >= 0) {
+                       if (thistd < min_tds) drop_me = TRUE;
+                   } else {
+                       if (GEOSGeomTypeId_r(GEOShandle, thisgeom)
+                            == GEOS_GEOMETRYCOLLECTION) {
+                            int nsGC = GEOSGetNumGeometries_r(GEOShandle,
+                                thisgeom);
+                            GEOSGeom *kgeoms = (GEOSGeom *) R_alloc(
+                                (size_t) nsGC, sizeof(GEOSGeom));
+                            for (k1=0, kk=0; k1<nsGC; k1++) {
+                              kgeom = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle,
+                                thisgeom, k1);
+                              thistd = GEOSTopologicalDimension_r(GEOShandle,
+                                kgeom);
+                              k_empty = GEOSisEmpty_r(GEOShandle, kgeom);
+                              if (!k_empty && thistd == min_tds) {
+                                kgeoms[kk] = kgeom;
+//Rprintf("%d %d %d %s\n", k1, kk, GEOSGeomTypeId_r(GEOShandle, kgeom), GEOSGeomType_r(GEOShandle, kgeom));
+                                kk++;
+                            }
+                        }
+                        if (kk == 0) {
+                            drop_me = TRUE;
+                       } else {
+                              if (kk > 1) {
+                                  if (min_tds == 0) {
+                                    thisgeom = GEOSGeom_createCollection_r(
+                                      GEOShandle, GEOS_MULTIPOINT, 
+                                      kgeoms, (unsigned int) kk);
+                                } else if (min_tds == 1) {
+                                    thisgeom = GEOSGeom_createCollection_r(
+                                      GEOShandle, GEOS_MULTILINESTRING, 
+                                      kgeoms, (unsigned int) kk);
+                                } else if (min_tds == 2) {
+                                    thisgeom = GEOSGeom_createCollection_r(
+                                      GEOShandle, GEOS_MULTIPOLYGON, 
+                                      kgeoms, (unsigned int) kk);
+                                }
+                            } else {
+                                thisgeom = kgeoms[0];
+                            }
+                        }
+
+                       } else {
+                           drop_me = TRUE;
+                       }
+                   }
+                }
+                if (!drop_me) {
+                    geoms[k] = thisgeom;
+                    SET_STRING_ELT(ids, k, STRING_ELT(ids, i*n+j));
+//Rprintf("%d: %d %d %s %d\n", k, GEOSisEmpty_r(GEOShandle, geoms[k]), GEOSGeomTypeId_r(GEOShandle, geoms[k]), GEOSGeomType_r(GEOShandle, geoms[k]), GEOSGetNumGeometries_r(GEOShandle, geoms[k]));
+                    k++;
+                }
+            }
+            
+            //if (GEOSisEmpty_r(GEOShandle, geomsk)) continue;
+        }
+    }
+    
+    GEOSGeom_destroy_r(GEOShandle, geom1);
+    GEOSGeom_destroy_r(GEOShandle, geom2);
+//Rprintf("m=%d n=%d k=%d\n", m, n, k);
+
+    if (k == 0)
+        return(R_NilValue);
+    GEOSGeom res = (k > 1) ? GEOSGeom_createCollection_r(GEOShandle, GEOS_GEOMETRYCOLLECTION, geoms, (unsigned int) k)
+                             : geoms[0];
+    
+//Rprintf("res is %s\n", GEOSGeomType_r(GEOShandle, res));
+
+    return( rgeos_convert_geos2R(env, res, p4s, ids) );
+}
+
diff --git a/src/rgeos_validate.c b/src/rgeos_validate.c
new file mode 100644
index 0000000..ba6a561
--- /dev/null
+++ b/src/rgeos_validate.c
@@ -0,0 +1,172 @@
+#include "rgeos.h"
+
+SEXP rgeos_PolyCreateComment(const SEXP env, const SEXP pls) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    int npls = length(pls);
+    
+    GEOSGeom *polys = (GEOSGeom *) R_alloc((size_t) npls, sizeof(GEOSGeom));
+    GEOSGeom *holes = (GEOSGeom *) R_alloc((size_t) npls, sizeof(GEOSGeom));
+    
+    int *polyindex = (int *) R_alloc((size_t) npls, sizeof(int));
+    int *holeindex = (int *) R_alloc((size_t) npls, sizeof(int));
+    
+    int nholes = 0;
+    int npolys = 0;
+    
+    for(int i=0; i<npls; i++) {
+        
+        SEXP crdMat = GET_SLOT(VECTOR_ELT(pls, i), install("coords"));
+        GEOSGeom geom;
+        if (crdMat == R_NilValue) {
+            geom = GEOSGeom_createPolygon_r(GEOShandle, NULL, NULL, (unsigned int) 0);
+        } else {
+            geom = rgeos_crdMat2Polygon(env, crdMat, getAttrib(crdMat, R_DimSymbol));
+        }
+        
+        int hole = LOGICAL_POINTER(GET_SLOT(VECTOR_ELT(pls, i), install("hole")))[0];
+        if (hole) {
+            holes[nholes] = geom;
+            holeindex[nholes] = i;
+            nholes++;
+        } else {
+            polys[npolys] = geom;
+            polyindex[npolys] = i;
+            npolys++;
+        }
+    }
+    
+    if (npolys == 0) error("Polygons object contains only holes and no polygons");
+    
+    int pc = 0;
+    SEXP commentvec;
+    PROTECT(commentvec = NEW_INTEGER(npls)); pc++;
+    
+    for(int i=0; i<npls; i++) {
+        INTEGER_POINTER(commentvec)[i] = 0;
+    }
+    
+    if (nholes != 0) {
+    
+        int *containsindex = (int *) R_alloc((size_t) npolys, sizeof(int));
+        for(int i=0; i<nholes; i++) {
+            int total = 0;
+        
+            for(int j=0; j<npolys; j++) {
+                // FIXME - Not sure this is the best predicate to use in all cases
+                int contains = GEOSContains_r(GEOShandle, polys[j], holes[i]);
+            
+                if (contains) {
+                    containsindex[total] = j;
+                    total++;
+                }
+            }
+        
+            if (total == 0) {
+                error("rgeos_PolyCreateComment: orphaned hole, cannot find containing polygon for hole at index %d", 
+                        holeindex[i]+1);
+            } else if (total == 1) { // If only one polygon contains the hole we're done
+                INTEGER_POINTER(commentvec)[ holeindex[i] ] = polyindex[ containsindex[0] ]+1;
+            } else {
+                // If multiple polys contain the hole then our best guess is the smallest
+                // containing polygon 
+            
+                int best = 0;
+                double bestarea, curarea;
+                
+                GEOSArea_r(GEOShandle, polys[containsindex[0]], &bestarea);
+            
+                for(int k=1; k<total; k++) {
+                    GEOSArea_r(GEOShandle, polys[containsindex[k]], &curarea);
+                    if (curarea < bestarea) {
+                        bestarea = curarea;
+                        best = k;
+                    }
+                }
+            
+                INTEGER_POINTER(commentvec)[ holeindex[i] ] = polyindex[ containsindex[best] ]+1;
+            }
+        }
+    }
+	// EJP:
+    for(int i=0; i<nholes; i++)
+    	GEOSGeom_destroy_r(GEOShandle, holes[i]);
+    for(int i=0; i<npolys; i++)
+    	GEOSGeom_destroy_r(GEOShandle, polys[i]);
+    
+    UNPROTECT(pc);
+    return(commentvec);
+}
+
+SEXP GC_Contains(const SEXP env, const GEOSGeom GC) {
+
+    SEXP ans, dim;
+    int pc=0;
+    unsigned int i, j, n;
+    int contains, ident;
+
+    GEOSGeom Pi, Pj;
+
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+
+    if ( GEOSisValid_r(GEOShandle, GC) ) {
+        GEOSGeom_destroy_r(GEOShandle, GC);
+        return(R_NilValue);
+    }
+
+    n = (unsigned int) GEOSGetNumGeometries_r(GEOShandle, GC);
+    PROTECT(ans = NEW_LIST(2)); pc++;
+    SET_VECTOR_ELT(ans, 0, NEW_LOGICAL((int) (n*n)));
+    SET_VECTOR_ELT(ans, 1, NEW_LOGICAL((int) (n*n)));
+    PROTECT(dim = NEW_INTEGER(2)); pc++;
+    INTEGER_POINTER(dim)[0] = (int) n;
+    INTEGER_POINTER(dim)[1] = (int) n;
+    setAttrib(VECTOR_ELT(ans, 0), R_DimSymbol, dim);
+    setAttrib(VECTOR_ELT(ans, 1), R_DimSymbol, dim);
+
+    for (i=0; i<n; i++) {
+        if ((Pi = (GEOSGeometry *) GEOSGetGeometryN_r(GEOShandle, GC, (int) i)) == NULL) {
+            GEOSGeom_destroy_r(GEOShandle, GC);
+            return(R_NilValue);
+        } // Pi invalid
+            for (j=0; j<n; j++) {
+                if ((Pj = (GEOSGeometry *) GEOSGetGeometryN_r(GEOShandle, GC, (int) j)) == NULL) {
+                    GEOSGeom_destroy_r(GEOShandle, GC);
+                    return(R_NilValue);
+                } // Pj invalid
+                if (i == j) {
+                    LOGICAL_POINTER(VECTOR_ELT(ans, 0))[i+(j*n)] = FALSE;
+                    LOGICAL_POINTER(VECTOR_ELT(ans, 1))[i+(j*n)] = FALSE;
+                } else { // i == j
+                    contains = (int) GEOSContains_r(GEOShandle, Pi, Pj);
+                    if (contains == 2) {
+                        LOGICAL_POINTER(VECTOR_ELT(ans, 0))[i+(j*n)] = NA_LOGICAL;
+                        LOGICAL_POINTER(VECTOR_ELT(ans, 1))[i+(j*n)] = NA_LOGICAL;
+                    } else { // contains invalid
+                        ident = (int) GEOSEquals_r(GEOShandle, Pi, Pj);
+                        if (ident == 2) {
+                            LOGICAL_POINTER(VECTOR_ELT(ans, 0))[i+(j*n)] = NA_LOGICAL;
+                            LOGICAL_POINTER(VECTOR_ELT(ans, 1))[i+(j*n)] = NA_LOGICAL;
+                        } else { // ident invalid
+                            LOGICAL_POINTER(VECTOR_ELT(ans, 0))[i+(j*n)] = contains;
+                            LOGICAL_POINTER(VECTOR_ELT(ans, 1))[i+(j*n)] = ident;
+                        } // ident valid
+                    } // contains valid
+                } // i != j
+            } // j
+
+    } // i
+    GEOSGeom_destroy_r(GEOShandle, GC);
+
+    UNPROTECT(pc);
+    return(ans);
+}
+
+SEXP rgeos_PolygonsContain(const SEXP env, const SEXP obj) {
+
+    GEOSGeom GC = rgeos_convert_R2geos(env, obj);
+
+    return(GC_Contains(env, GC));
+}
+
diff --git a/src/rgeos_wkt.c b/src/rgeos_wkt.c
new file mode 100644
index 0000000..3dbed27
--- /dev/null
+++ b/src/rgeos_wkt.c
@@ -0,0 +1,55 @@
+#include "rgeos.h"
+
+
+SEXP rgeos_readWKT(SEXP env, SEXP obj, SEXP p4s, SEXP id) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    GEOSWKTReader *reader = GEOSWKTReader_create_r(GEOShandle);
+    GEOSGeom geom = GEOSWKTReader_read_r(GEOShandle,reader, CHAR(STRING_ELT(obj, 0)));
+    GEOSWKTReader_destroy_r(GEOShandle,reader);
+    
+    if (geom == NULL) error("rgeos_readWKT: unable to read wkt");
+    
+    SEXP ans = rgeos_convert_geos2R(env, geom, p4s, id); // destroys geom
+    
+    return(ans);
+}
+
+
+SEXP rgeos_writeWKT(SEXP env, SEXP obj, SEXP byid) {
+    
+    GEOSContextHandle_t GEOShandle = getContextHandle(env);
+    
+    GEOSGeom geom = rgeos_convert_R2geos(env, obj);
+    
+    int n = (LOGICAL_POINTER(byid)[0]) ? GEOSGetNumGeometries_r(GEOShandle, geom) : 1;
+     
+    int pc=0;
+    SEXP ans;
+    PROTECT(ans = NEW_CHARACTER(n)); pc++;
+    
+    GEOSWKTWriter *writer = GEOSWKTWriter_create_r(GEOShandle);
+    GEOSGeom curgeom = geom;
+    for(int i=0; i<n; i++) {
+        if ( n > 1) {
+            curgeom = (GEOSGeom) GEOSGetGeometryN_r(GEOShandle, geom, i);
+            if (curgeom == NULL) error("rgeos_writeWKT: unable to get subgeometries");
+        }
+        
+        char *buf = GEOSWKTWriter_write_r(GEOShandle, writer, curgeom);
+        if (buf == NULL) error("rgeos_writeWKT: unable to write wkt");
+        
+        SET_STRING_ELT(ans, i, COPY_TO_USER_STRING(buf));
+        
+        GEOSFree_r(GEOShandle, buf);
+    }
+    
+    GEOSWKTWriter_destroy_r(GEOShandle,writer);
+    GEOSGeom_destroy_r(GEOShandle, geom);
+    
+    UNPROTECT(pc);
+    
+    return(ans);
+}
+
diff --git a/tests/test-all.R b/tests/test-all.R
new file mode 100644
index 0000000..da3f278
--- /dev/null
+++ b/tests/test-all.R
@@ -0,0 +1,8 @@
+library(testthat)
+library(rgeos)
+
+set_do_poly_check(FALSE)
+#test_dir(system.file("tests", package = "rgeos"), StopReporter)#SummaryByContextReporter)
+#test_package("rgeos")
+test_check("rgeos")
+set_do_poly_check(TRUE)
diff --git a/tests/testthat/process_testxml.R b/tests/testthat/process_testxml.R
new file mode 100644
index 0000000..7c5ffa0
--- /dev/null
+++ b/tests/testthat/process_testxml.R
@@ -0,0 +1,147 @@
+library(testthat)
+library(XML)
+library(rgeos)
+
+# Some functions have different names between GEOS and JTS
+
+process_testxml = function(xmlfile, n, total, descSkip) {
+    
+    funcTranslate=list( "getboundary"       = list(func=gBoundary,res=readWKT,arg1=readWKT),
+                        "getCentroid"       = list(func=gCentroid,res=readWKT,arg1=readWKT),
+                        "convexhull"        = list(func=gConvexHull,res=readWKT,arg1=readWKT),
+                        "getInteriorPoint"  = list(func=gPointOnSurface,res=readWKT,arg1=readWKT),
+
+                        "isSimple"          = list(func=gIsSimple,res=as.logical,arg1=readWKT),
+                        "isValid"           = list(func=gIsValid,res=as.logical,arg1=readWKT),
+
+                        "isWithinDistance"  = list(func=gWithinDistance,res=as.logical,arg1=readWKT,arg2=readWKT,arg3=as.numeric),
+                        "intersects"        = list(func=gIntersects,res=as.logical,arg1=readWKT,arg2=readWKT),
+                        "contains"          = list(func=gContains,res=as.logical,arg1=readWKT,arg2=readWKT),
+                        "within"            = list(func=gWithin,res=as.logical,arg1=readWKT,arg2=readWKT),
+
+
+                        "intersection"      = list(func=gIntersection,res=readWKT,arg1=readWKT,arg2=readWKT),
+                        "union"             = list(func=gUnion,res=readWKT,arg1=readWKT,arg2=readWKT),
+                        "difference"        = list(func=gDifference,res=readWKT,arg1=readWKT,arg2=readWKT),
+                        "symdifference"     = list(func=gSymdifference,res=readWKT,arg1=readWKT,arg2=readWKT),
+
+                        "relate"            = list(func=gRelate,res=as.logical,arg1=readWKT,arg2=readWKT,arg3=as.character),
+
+                        "covers"            = list(func=gCovers,res=as.logical,arg1=readWKT,arg2=readWKT),
+                        "coveredBy"         = list(func=gCoveredBy,res=as.logical,arg1=readWKT,arg2=readWKT))
+    
+    
+    context(paste('(',n,'/',total,')',basename(xmlfile)))
+    #x = xmlRoot(xmlTreeParse(I(readLines(xmlfile)),ignoreBlanks=TRUE))
+    x = xmlRoot(xmlTreeParse(readLines(xmlfile),ignoreBlanks=TRUE))
+    
+    nodes = xmlSApply(x,xmlName)
+
+    test_that("valid node types",{
+        validNodeTypes = c("precisionModel","case","comment")
+        expect_that( all(nodes %in% validNodeTypes), is_true() )
+    })
+
+
+    #Handle precisionModel nodes - only use the first model
+    pmAttrs =  xmlAttrs( x[[ which(nodes == "precisionModel")[1] ]] )
+
+    test_that("precisionModel attribute tests", {
+        expect_that( length(pmAttrs) == 1 | length(pmAttrs) == 3, is_true() )
+
+        if (length(pmAttrs) == 1) {
+            type = pmAttrs[["type"]]
+        } else if (length(pmAttrs) == 3) {
+            setScale(as.numeric( pmAttrs[["scale"]] ))
+
+            expect_that( pmAttrs[["offsetx"]], equals("0.0") )
+            expect_that( pmAttrs[["offsety"]], equals("0.0") )
+        } 
+    })
+
+    #Handle case nodes
+    for ( i in which(nodes == "case") ) {
+        caseNodes = xmlSApply(x[[i]],xmlName)
+
+        whichDesc = which(caseNodes == "desc")
+        whichTests = which(caseNodes == "test")
+
+        desc = xmlValue( x[[i]][[ whichDesc[1] ]] )
+    
+        if (desc %in% descSkip)
+            next
+
+        whichArgs = which(caseNodes != "desc" & caseNodes != "test")
+    
+        args = rep( NA,length(whichArgs) )
+        # argument nodes can either contain the value or have a file attribute
+        for ( j in whichArgs) {
+            if (is.null( xmlAttrs(x[[i]][[j]]) )) {
+                args[[ xmlName(x[[i]][[j]]) ]] = xmlValue(x[[i]][[j]])
+            } else {
+                file = xmlAttrs(x[[i]][[j]])[["file"]]
+                args[[ xmlName(x[[i]][[j]]) ]] = paste( readLines(file), collapse="" )
+            }
+        }
+    
+        #make sure the arg names are lowercase for the sake of consistency
+        names(args) = tolower(names(args))
+    
+        for ( j in whichTests ) {
+        
+            test_that(paste(desc,'- test nodes in proper format') , {
+                expect_that( xmlSize( x[[i]][[j]] ), equals(1) )
+                expect_that( xmlName( x[[i]][[j]][[1]] ), equals("op") )
+            })
+        
+            if ( xmlSize( x[[i]][[j]] ) == 1 & xmlName( x[[i]][[j]][[1]] ) == "op" ) {
+
+                opAttrs = xmlAttrs( x[[i]][[j]][[1]] )
+                opReturn = xmlValue( x[[i]][[j]][[1]] )
+                opNArgs = length(opAttrs)-1
+
+                # some ops seem to have a pattern argument that is not used
+                if ( 'pattern' %in% names(opAttrs) )
+                    opNArgs = opNArgs-1
+
+                opName = opAttrs[['name']]
+            
+               
+            
+                test_that(paste(desc,'-',opName), {
+                
+                    funcdetails = funcTranslate[[opName]]
+                    expect_that( is.null(funcdetails), is_false() )
+            
+                    if ( !is.null(funcdetails) ) {
+                        funcNArgs = length( funcdetails )-2
+                        expect_that(funcNArgs==opNArgs, is_true())
+                    
+                        funcArgs = list()
+                        for (k in 1:funcNArgs) {
+                            argName = paste("arg",k,sep='')
+
+                            argVal = tolower(opAttrs[[argName]])
+                            if (argVal %in% names(args))
+                                argVal = args[[ argVal ]]
+                            funcArgs[k] =  funcdetails[[argName]](argVal)    
+                        }
+                    
+                        funcReturn = do.call(funcdetails[["func"]], funcArgs)
+                        expectedReturn = funcdetails[["res"]](opReturn)
+                    
+                        if (is.logical(funcReturn)) {
+                            expect_that(funcReturn == expectedReturn, is_true())
+                        } else if (is.null(funcReturn)) {
+                            expect_that(is.null(funcReturn) & is.null(expectedReturn), is_true())
+                        } else if (gIsEmpty(expectedReturn)) {
+                            expect_that(identical(funcReturn,expectedReturn), is_true())
+                        } else { # if it isn't logical or NULL it should be a geometry
+                            expect_that(gEquals(funcReturn,expectedReturn),is_true())
+                        }
+                    }
+                }) 
+            }                
+        } 
+    }
+}
\ No newline at end of file
diff --git a/tests/testthat/test-jts-xml.R b/tests/testthat/test-jts-xml.R
new file mode 100644
index 0000000..d78e495
--- /dev/null
+++ b/tests/testthat/test-jts-xml.R
@@ -0,0 +1,45 @@
+source("process_testxml.R")
+
+# xml files to skip
+fileSkip = c("TestValid2.xml","ExternalRobustness.xml","TestRobustOverlayFloat.xml","TestRobustOverlayFixed.xml")
+
+# tests to skip
+descSkip = c(# TestFunctionLAPrec.xml
+             "LA - line and sliver intersecting, dimensional collapse",
+             # TestFunctionAAPrec.xml
+             "AA - intersecting slivers, dimensional collapse",
+             "AA - sliver triangle with multiple intersecting boxes",
+             "AA - sliver triangles, at angle to each other",
+             "AA - B sliver crossing A triangle in line segment with length < 1",
+             "AA - A hole close to shell, B coincident with A",
+             "AA - hole close to shell, B coincident with A",
+             "AA - sliver triangle, cut by polygon",
+             "AA - polygon with outward sliver, cut by polygon",
+             "AA - hole close to shell",
+             "AA - A sliver triangle cutting all the way across B",
+             "AA - A polygon with sliver cutting all the way across B",
+             "AA - B hole close to shell, A coincident with B",
+             # TestInteriorPoint.xml
+             "L - linestring with single segment")
+
+xmldir = 'tests/testxml'
+testdirs = list.files(system.file(xmldir,package="rgeos"))
+
+for (d in testdirs) {
+    testfiles = list.files(system.file(file.path(xmldir,d),package="rgeos")) 
+    
+    for (f in testfiles)  {
+
+        # files to skip
+        if (f %in% fileSkip)
+            next
+
+        xmlfile =  system.file(file.path(xmldir,d,f),package="rgeos")
+
+        n = which(f==testfiles)
+        total = length(testfiles)
+        
+        process_testxml(xmlfile, n, total, descSkip)
+    }
+}
+
diff --git a/tests/testthat/test-linearref.R b/tests/testthat/test-linearref.R
new file mode 100644
index 0000000..15d3aaa
--- /dev/null
+++ b/tests/testthat/test-linearref.R
@@ -0,0 +1,80 @@
+library("testthat")
+library("rgeos")
+library("sp")
+
+
+context("Linear Referencing")
+
+coord <- function(x) unname(coordinates(x))
+
+
+test_that("zero-length input arguments fail with error", {
+
+  dat <- data.frame(x = 1)
+  p <- SpatialPointsDataFrame(readWKT("POINT(0 0)"), dat)
+  l <- SpatialLinesDataFrame(readWKT("LINESTRING (-1 0, 1 0)"), dat)
+
+  expect_error(gProject(l, subset(p, x > 1)))
+  expect_error(gProject(subset(l, x > 1), p, normalized = TRUE))
+
+  expect_error(gInterpolate(l, numeric(0)))
+  expect_error(gInterpolate(subset(l, x > 1), d = 0.5, normalized = TRUE))
+
+})
+
+
+test_that("interpolation works with zero length line", {
+
+  l <- readWKT("LINESTRING (10 0, 10 0)")
+  expect_identical(coord(gInterpolate(readWKT("LINESTRING (10 0, 10 0)"),
+                                      d = 0.5)),
+                   coord(head(as(l, "SpatialPoints"), 1)))
+})
+
+
+test_that("repeated coordinates work", {
+
+  l <- readWKT("LINESTRING (10 0, 10 0, 20 0)")
+  p <- readWKT("POINT(11 0)")
+
+  d <- gProject(l, p, normalized = TRUE)
+  expect_identical(gInterpolate(l, d, normalized = TRUE), p)
+
+  d <- gProject(l, p, normalized = FALSE)
+  expect_identical(gInterpolate(l, d, normalized = FALSE), p)
+})
+
+
+test_that("functions work with MultiLineStrings", {
+
+  # https://trac.osgeo.org/geos/ticket/323
+  l <- readWKT("MULTILINESTRING ((0 -2, 0 2), (-2 0, 2 0))")
+  p <- readWKT("MULTIPOINT(2 1.9, 2 2.1)")
+  res <- readWKT("MULTIPOINT(2 0, 0 2)")
+
+  expect_identical(coord(gInterpolate(l, gProject(l, p))), coord(res))
+})
+
+
+test_that("normalization works in gInterpolate", {
+
+  l <- readWKT("LINESTRING(25 50, 100 125, 150 190)")
+
+  expect_equal(gInterpolate(l, 0.5*gLength(l), normalized = FALSE),
+               gInterpolate(l, 0.5, normalized = TRUE))
+})
+
+
+test_that("interpolation is correct at endpoints", {
+
+  l <- readWKT("LINESTRING(25 50, 100 125, 150 190)")
+  p <- as(l, "SpatialPoints")
+
+  expect_identical(coord(gInterpolate(l, 0, TRUE)), coord(p[1, ]))
+  expect_identical(coord(gInterpolate(l, 0, FALSE)), coord(p[1, ]))
+
+  expect_identical(coord(gInterpolate(l, 1, TRUE)),
+                   coord(p[length(p), ]))
+  expect_identical(coord(gInterpolate(l, gLength(l), FALSE)),
+                   coord(p[length(p), ]))
+})
diff --git a/tests/testthat/test-misc.R b/tests/testthat/test-misc.R
new file mode 100644
index 0000000..c1afcfd
--- /dev/null
+++ b/tests/testthat/test-misc.R
@@ -0,0 +1,99 @@
+library("testthat")
+library("rgeos")
+library("sp")
+
+
+context("Misc - gNearestPoints")
+
+coord <- function(x) unname(coordinates(x))
+
+
+test_that("gNearestPoints works with different geometries as inputs", {
+
+  g1 <- readWKT("POINT(0 0)")
+  g2 <- readWKT("POINT(10 0)")
+  expect_identical(coord(gNearestPoints(g1, g2)),
+                   coord(readWKT("MULTIPOINT(0 0, 10 0)")))
+  expect_identical(gDistance(g1, g2), 10)
+
+
+  g1 <- readWKT("POINT(0 0)")
+  g2 <- readWKT("MULTIPOINT(10 0, 50 30)")
+  expect_identical(coord(gNearestPoints(g1, g2)),
+                   coord(readWKT("MULTIPOINT(0 0, 10 0)")))
+  expect_identical(gDistance(g1, g2), 10)
+
+
+  g1 <- readWKT("POINT(3 0)")
+  g2 <- readWKT("LINESTRING(0 10, 50 10, 100 50)")
+  expect_identical(coord(gNearestPoints(g1, g2)),
+                   coord(readWKT("MULTIPOINT(3 0, 3 10)")))
+  expect_identical(gDistance(g1, g2), 10)
+
+
+  g1 <- readWKT("POINT(3 0)")
+  g2 <- readWKT("MULTILINESTRING((34 54, 60 34), (0 10, 50 10, 100 50))")
+  expect_identical(coord(gNearestPoints(g1, g2)),
+                   coord(readWKT("MULTIPOINT(3 0, 3 10)")))
+  expect_identical(gDistance(g1, g2), 10)
+
+
+  g1 <- readWKT("POINT(35 60)")
+  g2 <- readWKT("POLYGON((34 54, 60 34, 60 54, 34 54),
+                         (50 50, 52 50, 52 48, 50 48, 50 50))")
+  expect_identical(coord(gNearestPoints(g1, g2)),
+                   coord(readWKT("MULTIPOINT(35 60, 35 54)")))
+  expect_identical(gDistance(g1, g2), 6)
+
+
+  g1 <- readWKT("POINT(35 60)")
+  g2 <- readWKT("MULTIPOLYGON(((34 54, 60 34, 60 54, 34 54),
+                               (50 50, 52 50, 52 48, 50 48, 50 50)),
+                              ((100 100, 150 100, 150 150, 100 150, 100 100),
+                               (120 120, 120 130, 130 130, 130 120, 120 120))))")
+  expect_identical(coord(gNearestPoints(g1, g2)),
+                   coord(readWKT("MULTIPOINT(35 60, 35 54)")))
+  expect_identical(gDistance(g1, g2), 6)
+
+
+  g1 <- readWKT("MULTIPOINT(10 0, 50 30)")
+  g2 <- readWKT("POINT(10 0)")
+  expect_identical(coord(gNearestPoints(g1, g2)),
+                   coord(readWKT("MULTIPOINT(10 0, 10 0)")))
+  expect_identical(gDistance(g1, g2), 0)
+
+
+  g1 <- readWKT("MULTIPOINT(10 0, 50 30)")
+  g2 <- readWKT("MULTIPOINT(0 0, 150 30)")
+  expect_identical(coord(gNearestPoints(g1, g2)),
+                   coord(readWKT("MULTIPOINT(10 0, 0 0)")))
+  expect_identical(gDistance(g1, g2), 10)
+
+
+  g1 <- readWKT("MULTIPOINT(3 0, 200 30)")
+  g2 <- readWKT("LINESTRING(0 10, 50 10, 100 50)")
+  expect_identical(coord(gNearestPoints(g1, g2)),
+                   coord(readWKT("MULTIPOINT(3 0, 3 10)")))
+  expect_identical(gDistance(g1, g2), 10)
+
+
+  g1 <- readWKT("MULTIPOINT(3 0, 200 30)")
+  g2 <- readWKT("LINESTRING(0 10, 50 10, 100 50)")
+  expect_identical(coord(gNearestPoints(g1, g2)),
+                   coord(readWKT("MULTIPOINT(3 0, 3 10)")))
+  expect_identical(gDistance(g1, g2), 10)
+
+
+  g1 <- readWKT("MULTIPOINT(3 0, -50 30)")
+  g2 <- readWKT("MULTILINESTRING((34 54, 60 34), (0 10, 50 10, 100 50))")
+  expect_identical(coord(gNearestPoints(g1, g2)),
+                   coord(readWKT("MULTIPOINT(3 0, 3 10)")))
+  expect_identical(gDistance(g1, g2), 10)
+
+
+  # empty geometry
+  dat <- data.frame(x = 1)
+  g1 <- SpatialPointsDataFrame(rgeos::readWKT("POINT(0 0)"), dat)
+  g2 <- SpatialLinesDataFrame(readWKT("LINESTRING (-1 0, 1 0)"), dat)
+  expect_null(gNearestPoints(subset(g1, x > 1), g2))
+})
diff --git a/tests/testthat/test-translate-empty.R b/tests/testthat/test-translate-empty.R
new file mode 100644
index 0000000..e4ba415
--- /dev/null
+++ b/tests/testthat/test-translate-empty.R
@@ -0,0 +1,222 @@
+#library(testthat)
+#library(rgeos)
+#
+#setScale()
+#context("Translation empty geometries")
+#
+#test_that("empty geometrycollection", {
+#	gc1 = readWKT("GEOMETRYCOLLECTION EMPTY")
+#
+#	expect_that( gc1,  is_identical_to(translate(gc1)) )
+#})
+#
+#
+#test_that("empty points", {
+#    p1 = readWKT("POINT EMPTY")
+#    p2 = readWKT("MULTIPOINT EMPTY")
+#    p3 = readWKT("GEOMETRYCOLLECTION(POINT EMPTY)")
+#    p4 = readWKT("GEOMETRYCOLLECTION(MULTIPOINT EMPTY)")
+#    
+#    expect_that( p1,  is_identical_to(p2) )
+#    expect_that( p2,  is_identical_to(p3) )
+#    expect_that( p3,  is_identical_to(p4) )
+#    
+#    expect_that( p1,  is_identical_to(translate(p1)) )
+#    expect_that( p2,  is_identical_to(translate(p2)) )
+#    expect_that( p3,  is_identical_to(translate(p3)) )
+#    expect_that( p4,  is_identical_to(translate(p4)) )
+#    
+#    pg1 = readWKT("GEOMETRYCOLLECTION(POINT EMPTY,POINT EMPTY)")
+#    pg2 = readWKT("GEOMETRYCOLLECTION(POINT EMPTY,MULTIPOINT EMPTY)")
+#    pg3 = readWKT("GEOMETRYCOLLECTION(MULTIPOINT EMPTY,POINT EMPTY)")
+#    pg4 = readWKT("GEOMETRYCOLLECTION(MULTIPOINT EMPTY,MULTIPOINT EMPTY)")
+#
+#    pg5 = readWKT("GEOMETRYCOLLECTION(POINT (1 1),POINT EMPTY)")
+#    pg6 = readWKT("GEOMETRYCOLLECTION(POINT (1 1),MULTIPOINT EMPTY)")
+#    pg7 = readWKT("GEOMETRYCOLLECTION(MULTIPOINT (1 1),POINT EMPTY)")
+#    pg8 = readWKT("GEOMETRYCOLLECTION(MULTIPOINT (1 1),MULTIPOINT EMPTY)")
+#
+#    pg9 = readWKT("GEOMETRYCOLLECTION(POINT EMPTY,POINT (1 1))")
+#    pg10= readWKT("GEOMETRYCOLLECTION(POINT EMPTY,MULTIPOINT (1 1))")
+#    pg11= readWKT("GEOMETRYCOLLECTION(MULTIPOINT EMPTY,POINT (1 1))")
+#    pg12= readWKT("GEOMETRYCOLLECTION(MULTIPOINT EMPTY,MULTIPOINT (1 1))")
+#
+#    expect_that( pg1,  is_identical_to(pg2) )
+#    expect_that( pg2,  is_identical_to(pg3) )
+#    expect_that( pg3,  is_identical_to(pg4) )
+#
+#    expect_that( pg5,  is_identical_to(pg5) )
+#    expect_that( pg6,  is_identical_to(pg7) )
+#    expect_that( pg7,  is_identical_to(pg8) )
+#    
+#    expect_that( pg9,  is_identical_to(pg10) )
+#    expect_that( pg10, is_identical_to(pg11) )
+#    expect_that( pg11, is_identical_to(pg12) )
+#    
+#    expect_that( pg1,  is_identical_to(translate(pg1)) )
+#    expect_that( pg2,  is_identical_to(translate(pg2)) )
+#    expect_that( pg3,  is_identical_to(translate(pg3)) )
+#    expect_that( pg4,  is_identical_to(translate(pg4)) )
+#    expect_that( pg5,  is_identical_to(translate(pg5)) )
+#    expect_that( pg6,  is_identical_to(translate(pg6)) )
+#    expect_that( pg7,  is_identical_to(translate(pg7)) )
+#    expect_that( pg8,  is_identical_to(translate(pg8)) )
+#    expect_that( pg9,  is_identical_to(translate(pg9)) )
+#    expect_that(pg10,  is_identical_to(translate(pg10)) )
+#    expect_that(pg11,  is_identical_to(translate(pg11)) )
+#    expect_that(pg12,  is_identical_to(translate(pg12)) )
+#    
+#})
+#
+#test_that("empty linestrings", {
+#
+#    l1 = readWKT("LINESTRING EMPTY")
+#    l2 = readWKT("MULTILINESTRING EMPTY")
+#    l3 = readWKT("GEOMETRYCOLLECTION(LINESTRING EMPTY)")
+#    l4 = readWKT("GEOMETRYCOLLECTION(MULTILINESTRING EMPTY)")
+#    
+#    expect_that( l1, is_identical_to(l2) )
+#    expect_that( l2, is_identical_to(l3) )
+#    expect_that( l3, is_identical_to(l4) )
+#    
+#    expect_that( l1, is_identical_to(translate(l1)) )
+#    expect_that( l2, is_identical_to(translate(l2)) )
+#    expect_that( l3, is_identical_to(translate(l3)) )
+#    expect_that( l4, is_identical_to(translate(l4)) )
+#    
+#    
+#    ml1 = readWKT("MULTILINESTRING((1 1,2 2), EMPTY)")
+#    ml2 = readWKT("MULTILINESTRING(EMPTY, (1 1,2 2))")
+#    
+#    expect_that( ml1, is_identical_to(translate(ml1)) )
+#    expect_that( ml2, is_identical_to(translate(ml2)) )
+#    
+#    
+#    lg1 = readWKT("GEOMETRYCOLLECTION(LINESTRING EMPTY,LINESTRING EMPTY)")
+#    lg2 = readWKT("GEOMETRYCOLLECTION(MULTILINESTRING EMPTY,MULTILINESTRING EMPTY)")
+#    lg3 = readWKT("GEOMETRYCOLLECTION(LINESTRING EMPTY,MULTILINESTRING EMPTY)")
+#    lg4 = readWKT("GEOMETRYCOLLECTION(MULTILINESTRING EMPTY,LINESTRING EMPTY)")
+#    
+#    lg5 = readWKT("GEOMETRYCOLLECTION(LINESTRING EMPTY,LINESTRING(1 1,2 2))")
+#    lg6 = readWKT("GEOMETRYCOLLECTION(MULTILINESTRING EMPTY,MULTILINESTRING((1 1,2 2)))")
+#    lg7 = readWKT("GEOMETRYCOLLECTION(LINESTRING EMPTY,MULTILINESTRING((1 1,2 2)))")
+#    lg8 = readWKT("GEOMETRYCOLLECTION(MULTILINESTRING EMPTY,LINESTRING(1 1,2 2))")
+#    
+#    lg9 = readWKT("GEOMETRYCOLLECTION(LINESTRING(1 1,2 2),LINESTRING EMPTY)")
+#    lg10= readWKT("GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2)),MULTILINESTRING EMPTY)")
+#    lg11= readWKT("GEOMETRYCOLLECTION(LINESTRING(1 1,2 2),MULTILINESTRING EMPTY)")
+#    lg12= readWKT("GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2)),LINESTRING EMPTY)")
+#
+#    expect_that( lg1,  is_identical_to(lg2) )
+#    expect_that( lg2,  is_identical_to(lg3) )
+#    expect_that( lg3,  is_identical_to(lg4) )
+#
+#    expect_that( lg5,  is_identical_to(lg5) )
+#    expect_that( lg6,  is_identical_to(lg7) )
+#    expect_that( lg7,  is_identical_to(lg8) )
+#    
+#    expect_that( lg9,  is_identical_to(lg10) )
+#    expect_that( lg10, is_identical_to(lg11) )
+#    expect_that( lg11, is_identical_to(lg12) )
+#    
+#    expect_that( lg1, is_identical_to(translate(lg1)) )
+#    expect_that( lg2, is_identical_to(translate(lg2)) )
+#    expect_that( lg3, is_identical_to(translate(lg3)) )
+#    expect_that( lg4, is_identical_to(translate(lg4)) )
+#    expect_that( lg5, is_identical_to(translate(lg5)) )
+#    expect_that( lg6, is_identical_to(translate(lg6)) )
+#    expect_that( lg7, is_identical_to(translate(lg7)) )
+#    expect_that( lg8, is_identical_to(translate(lg8)) )
+#    expect_that( lg9, is_identical_to(translate(lg9)) )
+#    expect_that( lg10, is_identical_to(translate(lg10)) )
+#    expect_that( lg11, is_identical_to(translate(lg11)) )
+#    expect_that( lg12, is_identical_to(translate(lg12)) )
+#})
+#
+#
+#test_that("empty linearrings", {
+#
+#    lr1 = readWKT("LINEARRING EMPTY")
+#    lr2 = readWKT("GEOMETRYCOLLECTION(LINEARRING EMPTY)")
+#    
+#    expect_that( lr1, is_identical_to(lr2) )
+#    
+#    expect_that( lr1, is_identical_to(translate(lr1)) )
+#    expect_that( lr2, is_identical_to(translate(lr2)) )
+#    
+#    lrg1 = readWKT("GEOMETRYCOLLECTION(LINEARRING EMPTY,LINEARRING EMPTY)")
+#    lrg2 = readWKT("GEOMETRYCOLLECTION(LINEARRING EMPTY,LINEARRING(1 1,2 2,3 1,1 1))")
+#    lrg3 = readWKT("GEOMETRYCOLLECTION(LINEARRING(1 1,2 2,3 1,1 1),LINEARRING EMPTY)")
+#
+#    expect_that( lrg1, is_identical_to(translate(lrg1)) )
+#    expect_that( lrg2, is_identical_to(translate(lrg2)) )
+#    expect_that( lrg3, is_identical_to(translate(lrg3)) )
+#
+#})
+#
+#
+#test_that("empty polygons", {
+#
+#    p1 = readWKT("POLYGON EMPTY")
+#    p2 = readWKT("MULTIPOLYGON EMPTY")
+#    p3 = readWKT("GEOMETRYCOLLECTION(POLYGON EMPTY)")
+#    p4 = readWKT("GEOMETRYCOLLECTION(MULTIPOLYGON EMPTY)")
+#    
+#    expect_that( p1, is_identical_to(p2) )
+#    expect_that( p2, is_identical_to(p3) )
+#    expect_that( p3, is_identical_to(p4) )
+#    
+#    expect_that( p1, is_identical_to(translate(p1)) )
+#    expect_that( p2, is_identical_to(translate(p2)) )
+#    expect_that( p3, is_identical_to(translate(p3)) )
+#    expect_that( p4, is_identical_to(translate(p4)) )
+#    
+#    
+#    mp1 = readWKT("MULTIPOLYGON(((1 1,2 2,3 1,1 1)), EMPTY)")
+#    mp2 = readWKT("MULTIPOLYGON(EMPTY, ((1 1,2 2,3 1,1 1)))")
+#    
+#    expect_that( mp1, is_identical_to(translate(mp1)) )
+#    expect_that( mp2, is_identical_to(translate(mp2)) )
+#    
+#    
+#    pg1 = readWKT("GEOMETRYCOLLECTION(POLYGON EMPTY,POLYGON EMPTY)")
+#    pg2 = readWKT("GEOMETRYCOLLECTION(POLYGON EMPTY,MULTIPOLYGON EMPTY)")
+#    pg3 = readWKT("GEOMETRYCOLLECTION(MULTIPOLYGON EMPTY,POLYGON EMPTY)")
+#    pg4 = readWKT("GEOMETRYCOLLECTION(MULTIPOLYGON EMPTY,MULTIPOLYGON EMPTY)")
+#    
+#    pg5 = readWKT("GEOMETRYCOLLECTION(POLYGON EMPTY, POLYGON((1 1,2 2,3 1,1 1)) )")
+#    pg6 = readWKT("GEOMETRYCOLLECTION(MULTIPOLYGON EMPTY, POLYGON((1 1,2 2,3 1,1 1)) )")
+#    pg7 = readWKT("GEOMETRYCOLLECTION(POLYGON EMPTY, MULTIPOLYGON(((1 1,2 2,3 1,1 1))) )")
+#    pg8 = readWKT("GEOMETRYCOLLECTION(MULTIPOLYGON EMPTY, MULTIPOLYGON(((1 1,2 2,3 1,1 1))) )")
+#
+#    pg9 = readWKT("GEOMETRYCOLLECTION(POLYGON((1 1,2 2,3 1,1 1)), POLYGON EMPTY)")
+#    pg10= readWKT("GEOMETRYCOLLECTION(POLYGON((1 1,2 2,3 1,1 1)), MULTIPOLYGON EMPTY)")
+#    pg11= readWKT("GEOMETRYCOLLECTION(MULTIPOLYGON(((1 1,2 2,3 1,1 1))), POLYGON EMPTY)")
+#    pg12= readWKT("GEOMETRYCOLLECTION(MULTIPOLYGON(((1 1,2 2,3 1,1 1))), MULTIPOLYGON EMPTY)")
+#
+#    expect_that( pg1, is_identical_to(pg2) )
+#    expect_that( pg2, is_identical_to(pg3) )
+#    expect_that( pg3, is_identical_to(pg4) )
+#    
+#    expect_that( pg5, is_identical_to(pg6) )
+#    expect_that( pg6, is_identical_to(pg7) )
+#    expect_that( pg7, is_identical_to(pg8) )
+#
+#    expect_that( pg9, is_identical_to(pg10) )
+#    expect_that(pg10, is_identical_to(pg11) )
+#    expect_that(pg11, is_identical_to(pg12) )
+#
+#    expect_that( pg1, is_identical_to(translate(pg1)) )
+#    expect_that( pg2, is_identical_to(translate(pg2)) )
+#    expect_that( pg3, is_identical_to(translate(pg3)) )
+#    expect_that( pg4, is_identical_to(translate(pg4)) )
+#    expect_that( pg5, is_identical_to(translate(pg5)) )
+#    expect_that( pg6, is_identical_to(translate(pg6)) )
+#    expect_that( pg7, is_identical_to(translate(pg7)) )
+#    expect_that( pg8, is_identical_to(translate(pg8)) )
+#    expect_that( pg9, is_identical_to(translate(pg9)) )
+#    expect_that( pg10,is_identical_to(translate(pg10)))
+#    expect_that( pg11,is_identical_to(translate(pg11)))
+#    expect_that( pg12,is_identical_to(translate(pg12)))
+#
+#})
diff --git a/tests/testthat/test-translate-lines.R b/tests/testthat/test-translate-lines.R
new file mode 100644
index 0000000..f5fe749
--- /dev/null
+++ b/tests/testthat/test-translate-lines.R
@@ -0,0 +1,57 @@
+library(testthat)
+library(rgeos)
+
+setScale()
+
+context("Translate Lines")
+
+test_that("translate lines", {
+
+    l = readWKT("LINESTRING (1 1, 2 2, 3 3, 4 4)")
+
+    ml1 = readWKT("MULTILINESTRING ((1 1, 2 2, 3 3, 4 4),(1 1, 2 2, 3 3, 4 4))")
+    ml2 = readWKT("MULTILINESTRING ((1 1, 2 2, 3 3, 4 4),(4 1, 3 2, 2 3, 1 4))")
+
+    gcl1 = readWKT("GEOMETRYCOLLECTION( LINESTRING (1 1, 2 2, 3 3, 4 4), LINESTRING (1 1, 2 2, 3 3, 4 4) )")
+    gcl2 = readWKT("GEOMETRYCOLLECTION( LINESTRING (1 1, 2 2, 3 3, 4 4), MULTILINESTRING ((1 1, 2 2, 3 3, 4 4),(4 1, 3 2, 2 3, 1 4)), LINESTRING (1 1, 2 2, 3 3, 4 4) )")
+
+
+    Line1 = Line(cbind( x=1:4,y=1:4 ))
+    Line2 = Line(cbind( x=4:1,y=1:4 ))
+    
+    Linesl = Lines( list(Line1), ID = "1" )
+    Linesl2 = Lines( list(Line1), ID = "2" )
+    
+    Linesml1 = Lines( list(Line1, Line1), ID = "1" )
+    Linesml2 = Lines( list(Line1, Line2), ID = "1" )
+    
+    #FIXME - weirdness with rownames in the bbox
+    spl    = SpatialLines( list(Linesl) ); rownames(spl at bbox) = c("x","y")
+    spml1  = SpatialLines( list(Linesml1) ); rownames(spml1 at bbox) = c("x","y")
+    spml2  = SpatialLines( list(Linesml2) ); rownames(spml2 at bbox) = c("x","y")
+    
+    spgcl1 = SpatialLines( list(Linesl,Linesl2) ); rownames(spgcl1 at bbox) = c("x","y")
+    Linesml2 at ID = "2"
+    Linesl2 at ID = "3"
+    spgcl2 = SpatialLines( list(Linesl,Linesml2,Linesl2) ); rownames(spgcl2 at bbox) = c("x","y")
+
+
+    expect_that( l   , is_identical_to(spl) )
+    expect_that( ml1 , is_identical_to(spml1) )
+    expect_that( ml2 , is_identical_to(spml2) )
+    expect_that( gcl1, is_identical_to(spgcl1) )
+    expect_that( gcl2, is_identical_to(spgcl2) )
+    
+    expect_that( spl   , is_identical_to( translate(spl)))
+    expect_that( spml1 , is_identical_to( translate(spml1)))
+    expect_that( spml2 , is_identical_to( translate(spml2)))
+    expect_that( spgcl1, is_identical_to( translate(spgcl1)))
+    expect_that( spgcl2, is_identical_to( translate(spgcl2)))
+    
+    expect_that( l   , is_identical_to( translate(l) ))
+    expect_that( ml1 , is_identical_to( translate(ml1) ))
+    expect_that( ml2 , is_identical_to( translate(ml2) ))
+    expect_that( gcl1, is_identical_to( translate(gcl1) ))
+    expect_that( gcl2, is_identical_to( translate(gcl2) ))
+
+})
\ No newline at end of file
diff --git a/tests/testthat/test-translate-points.R b/tests/testthat/test-translate-points.R
new file mode 100644
index 0000000..498ebd5
--- /dev/null
+++ b/tests/testthat/test-translate-points.R
@@ -0,0 +1,58 @@
+library(testthat)
+library(rgeos)
+
+setScale()
+
+context("Translate Points")
+
+test_that("translate points", {
+    
+    p = readWKT("POINT(1 1)")
+    mp = readWKT("MULTIPOINT(1 1, 2 2, 3 3, 4 4, 5 5)") 
+    gcp1 = readWKT("GEOMETRYCOLLECTION( POINT(1 1), POINT(2 2), POINT(3 3), POINT(4 4), POINT(5 5))")
+    gcp2 = readWKT("GEOMETRYCOLLECTION( POINT(1 1), POINT(2 2), MULTIPOINT(3 3, 4 4, 5 5))")
+    gcp3 = readWKT("GEOMETRYCOLLECTION( POINT(1 1), POINT(2 2), MULTIPOINT(3 3, 4 4),POINT(5 5))")
+    gcp4 = readWKT("GEOMETRYCOLLECTION( MULTIPOINT(1 1, 2 2), MULTIPOINT(3 3, 4 4, 5 5))")
+    gcp5 = readWKT("GEOMETRYCOLLECTION( MULTIPOINT(1 1, 2 2), MULTIPOINT(3 3, 4 4),POINT(5 5))")
+    
+    spp = SpatialPoints(list(x=1,y=1))
+    spmp = SpatialPoints(list(x=1:5,y=1:5))
+    
+    rownames(spp at coords) = c("1")
+    expect_that( identical(p,spp), is_true())
+    expect_that( identical(spp, translate(spp)), is_true())
+    
+    rownames(spmp at coords) = c("1","1","1","1","1")
+    expect_that( identical(mp,spmp), is_true() )
+    expect_that( identical(spmp,translate(spmp)), is_true())
+    
+    rownames(spmp at coords) = c("1","2","3","4","5")
+    expect_that( identical(gcp1,spmp), is_true() )
+	expect_that( identical(spmp,translate(spmp)), is_true())
+    
+    rownames(spmp at coords) = c("1","2","3","3","3")
+    expect_that( identical(gcp2,spmp), is_true() )
+    expect_that( identical(spmp,translate(spmp)), is_true())
+
+    rownames(spmp at coords) = c("1","2","3","3","4")
+    expect_that( identical(gcp3,spmp), is_true() )
+    expect_that( identical(spmp,translate(spmp)), is_true())
+    
+    rownames(spmp at coords) = c("1","1","2","2","2")    
+    expect_that( identical(gcp4,spmp), is_true() )
+    expect_that( identical(spmp,translate(spmp)), is_true())
+    
+    rownames(spmp at coords) = c("1","1","2","2","3")
+    expect_that( identical(gcp5,spmp), is_true() )
+    expect_that( identical(spmp,translate(spmp)), is_true())
+
+    
+    expect_that( identical(p, translate(p) ), is_true())
+    expect_that( identical(mp, translate(mp) ), is_true())
+    expect_that( identical(gcp1, translate(gcp1) ), is_true())
+    expect_that( identical(gcp2, translate(gcp2) ), is_true())
+    expect_that( identical(gcp3, translate(gcp3) ), is_true())
+    expect_that( identical(gcp4, translate(gcp4) ), is_true())
+    expect_that( identical(gcp5, translate(gcp5) ), is_true())
+    
+})
\ No newline at end of file
diff --git a/tests/testthat/test-translate-polygon-collection.R b/tests/testthat/test-translate-polygon-collection.R
new file mode 100644
index 0000000..43e8639
--- /dev/null
+++ b/tests/testthat/test-translate-polygon-collection.R
@@ -0,0 +1,92 @@
+library(testthat)
+library(rgeos)
+
+setScale()
+
+context("Translation Polygon Collections")
+
+test_that("translate polygon collection", {
+
+    gcp1=readWKT("GEOMETRYCOLLECTION( POLYGON((1 1,5 1,5 5,1 5,1 1)), POLYGON((3 5,5 7, 1 7, 3 5)), POLYGON((5 3,7 5,7 1,5 3)) )")
+    gcp2=readWKT("GEOMETRYCOLLECTION( MULTIPOLYGON( ((1 1,5 1,5 5,1 5,1 1)), ((3 5,5 7, 1 7, 3 5)) ), POLYGON((5 3,7 5,7 1,5 3)) )")
+    gcp3=readWKT("GEOMETRYCOLLECTION( POLYGON((1 1,5 1,5 5,1 5,1 1)), MULTIPOLYGON( ((3 5,5 7, 1 7, 3 5)), ((5 3,7 5,7 1,5 3)) ))")
+    gcp4=readWKT("GEOMETRYCOLLECTION( MULTIPOLYGON( ((1 1,5 1,5 5,1 5,1 1)), ((3 5,5 7, 1 7, 3 5)), ((5 3,7 5,7 1,5 3)) ))")
+    
+    gcph1=readWKT("GEOMETRYCOLLECTION( POLYGON((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2)), POLYGON((3 5,5 7, 1 7, 3 5),(3 5.5,4 6.5, 2 6.5, 3 5.5)), POLYGON((5 3,7 5,7 1,5 3)) )")
+    gcph2=readWKT("GEOMETRYCOLLECTION( MULTIPOLYGON( ((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2)), ((3 5,5 7, 1 7, 3 5),(3 5.5,4 6.5, 2 6.5, 3 5.5)) ), POLYGON((5 3,7 5,7 1,5 3)) )")
+    gcph3=readWKT("GEOMETRYCOLLECTION( POLYGON((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2)), MULTIPOLYGON( ((3 5,5 7, 1 7, 3 5),(3 5.5,4 6.5, 2 6.5, 3 5.5)), ((5 3,7 5,7 1,5 3)) ))")
+    
+    
+    Poly1 = Polygon(list(x=c(1,5,5,1,1),y=c(1,1,5,5,1)), hole=FALSE)
+    Poly2 = Polygon(list(x=c(2,2,3,3,2),y=c(2,3,3,2,2)), hole=TRUE)
+    Poly3 = Polygon(list(x=c(3,3,4,4,3),y=c(3,4,4,3,3)), hole=TRUE)
+    Poly4 = Polygon(list(x=c(3,5,1,3),y=c(5,7,7,5)), hole=FALSE)
+    Poly5 = Polygon(list(x=c(3,4,2,3),y=c(5.5,6.5,6.5,5.5)), hole=TRUE)
+    Poly6 = Polygon(list(x=c(5,7,7,5),y=c(3,5,1,3)), hole=FALSE)
+   
+    Polygcp11 = Polygons(list(Poly1), ID="1")
+    Polygcp12 = Polygons(list(Poly4), ID="2")
+    Polygcp13 = Polygons(list(Poly6), ID="3")
+    Polygcp21 = Polygons(list(Poly1,Poly4), ID="1")
+    Polygcp22 = Polygons(list(Poly6), ID="2")
+    Polygcp31 = Polygons(list(Poly1), ID="1")
+    Polygcp32 = Polygons(list(Poly4,Poly6), ID="2")
+    Polygcp4  = Polygons(list(Poly1,Poly4,Poly6), ID="1")
+    
+    Polygcph11 = Polygons(list(Poly1,Poly2), ID="1")
+    Polygcph12 = Polygons(list(Poly4,Poly5), ID="2")
+    Polygcph13 = Polygons(list(Poly6), ID="3")
+    Polygcph21 = Polygons(list(Poly1,Poly2,Poly4,Poly5), ID="1")
+    Polygcph22 = Polygons(list(Poly6), ID="2")
+    Polygcph31 = Polygons(list(Poly1,Poly2), ID="1")
+    Polygcph32 = Polygons(list(Poly4,Poly5,Poly6), ID="2")
+
+    comment(Polygcp11) <- "0"
+    comment(Polygcp12) <- "0"
+    comment(Polygcp13) <- "0"
+    comment(Polygcp21) <- "0 0"
+    comment(Polygcp22) <- "0"
+    comment(Polygcp31) <- "0"
+    comment(Polygcp32) <- "0 0"
+    comment(Polygcp4) <- "0 0 0"
+
+    comment(Polygcph11) <- "0 1"
+    comment(Polygcph12) <- "0 1"
+    comment(Polygcph13) <- "0"
+    comment(Polygcph21) <- "0 1 0 3"
+    comment(Polygcph22) <- "0"
+    comment(Polygcph31) <- "0 1"
+    comment(Polygcph32) <- "0 1 0"
+
+    spgcp1  = SpatialPolygons( list(Polygcp11,Polygcp12,Polygcp13) )
+    spgcp2  = SpatialPolygons( list(Polygcp21,Polygcp22) )
+    spgcp3  = SpatialPolygons( list(Polygcp31,Polygcp32) )
+    spgcp4  = SpatialPolygons( list(Polygcp4) )
+    spgcph1 = SpatialPolygons( list(Polygcph11,Polygcph12,Polygcph13) )
+    spgcph2 = SpatialPolygons( list(Polygcph21,Polygcph22) )
+    spgcph3 = SpatialPolygons( list(Polygcph31,Polygcph32) )
+    
+    expect_that( gcp1 , is_identical_to(spgcp1) )
+    expect_that( gcp2 , is_identical_to(spgcp2) )
+    expect_that( gcp3 , is_identical_to(spgcp3) )
+    expect_that( gcp4 , is_identical_to(spgcp4) )
+    expect_that( gcph1, is_identical_to(spgcph1) )
+    expect_that( gcph2, is_identical_to(spgcph2) )
+    expect_that( gcph3, is_identical_to(spgcph3) )
+    
+    expect_that( spgcp1 , is_identical_to( translate(spgcp1)))
+    expect_that( spgcp2 , is_identical_to( translate(spgcp2)))
+    expect_that( spgcp3 , is_identical_to( translate(spgcp3)))
+    expect_that( spgcp4 , is_identical_to( translate(spgcp4)))
+    expect_that( spgcph1, is_identical_to( translate(spgcph1)))
+    expect_that( spgcph2, is_identical_to( translate(spgcph2)))
+    expect_that( spgcph3, is_identical_to( translate(spgcph3)))
+    
+    expect_that( gcp1 , is_identical_to( translate(gcp1)))
+    expect_that( gcp2 , is_identical_to( translate(gcp2)))
+    expect_that( gcp3 , is_identical_to( translate(gcp3)))
+    expect_that( gcp4 , is_identical_to( translate(gcp4)))
+    expect_that( gcph1, is_identical_to( translate(gcph1)))
+    expect_that( gcph2, is_identical_to( translate(gcph2)))
+    expect_that( gcph3, is_identical_to( translate(gcph3)))
+})
diff --git a/tests/testthat/test-translate-polygons.R b/tests/testthat/test-translate-polygons.R
new file mode 100644
index 0000000..15c9f1c
--- /dev/null
+++ b/tests/testthat/test-translate-polygons.R
@@ -0,0 +1,75 @@
+library(testthat)
+library(rgeos)
+
+setScale()
+
+context("Translate Polygons")
+
+test_that("translate simple polygon", {
+
+    p=readWKT("POLYGON((1 1,5 1,5 5,1 5,1 1))")
+    ph1=readWKT("POLYGON((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2))")
+    ph2=readWKT("POLYGON((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2), (3 3,3 4,4 4,4 3,3 3) ) ")
+    
+    mp=readWKT("MULTIPOLYGON( ((1 1,5 1,5 5,1 5,1 1)),((3 5,5 7, 1 7, 3 5)))")
+    mph1=readWKT("MULTIPOLYGON( ((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2)),((3 5,5 7, 1 7, 3 5)))")
+    mph2=readWKT("MULTIPOLYGON( ((1 1,5 1,5 5,1 5,1 1)),((3 5,5 7, 1 7, 3 5),(3 5.5,4 6.5, 2 6.5, 3 5.5) ))")
+    mph3=readWKT("MULTIPOLYGON( ((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2)),((3 5,5 7, 1 7, 3 5),(3 5.5,4 6.5, 2 6.5, 3 5.5)) )")
+    
+    Poly1 = Polygon(list(x=c(1,5,5,1,1),y=c(1,1,5,5,1)), hole=FALSE)
+    Poly2 = Polygon(list(x=c(2,2,3,3,2),y=c(2,3,3,2,2)), hole=TRUE)
+    Poly3 = Polygon(list(x=c(3,3,4,4,3),y=c(3,4,4,3,3)), hole=TRUE)
+    Poly4 = Polygon(list(x=c(3,5,1,3),y=c(5,7,7,5)), hole=FALSE)
+    Poly5 = Polygon(list(x=c(3,4,2,3),y=c(5.5,6.5,6.5,5.5)), hole=TRUE)
+    Poly6 = Polygon(list(x=c(5,7,7,5),y=c(3,5,1,3)), hole=FALSE)
+    
+    Polysp = Polygons(list(Poly1), ID="1")
+    Polysph1 = Polygons(list(Poly1,Poly2), ID="1")
+    Polysph2 = Polygons(list(Poly1,Poly2,Poly3), ID="1")
+    
+    Polysmp = Polygons(list(Poly1,Poly4), ID="1" )
+    Polysmph1 = Polygons(list(Poly1,Poly2,Poly4), ID="1" )
+    Polysmph2 = Polygons(list(Poly1,Poly4,Poly5), ID="1" )
+    Polysmph3 = Polygons(list(Poly1,Poly2,Poly4,Poly5), ID="1" )
+    
+    comment(Polysp) <- "0"
+    comment(Polysph1) <- "0 1"
+    comment(Polysph2) <- "0 1 1"
+    comment(Polysmp) <- "0 0"
+    comment(Polysmph1) <- "0 1 0"
+    comment(Polysmph2) <- "0 0 2"
+    comment(Polysmph3) <- "0 1 0 3"
+
+    spp     = SpatialPolygons( list(Polysp) )
+    spph1   = SpatialPolygons( list(Polysph1) )
+    spph2   = SpatialPolygons( list(Polysph2) )
+    spmp    = SpatialPolygons( list(Polysmp) )
+    spmph1  = SpatialPolygons( list(Polysmph1) )
+    spmph2  = SpatialPolygons( list(Polysmph2) )
+    spmph3  = SpatialPolygons( list(Polysmph3) )
+    
+    expect_that( identical(p    , spp), is_true())
+    expect_that( identical(ph1  , spph1), is_true())
+    expect_that( identical(ph2  , spph2), is_true())
+    expect_that( identical(mp   , spmp), is_true())
+    expect_that( identical(mph1 , spmph1), is_true())
+    expect_that( identical(mph2 , spmph2), is_true())
+    expect_that( identical(mph3 , spmph3), is_true())
+    
+    expect_that( spp   , is_identical_to( translate(spp)))
+    expect_that( spph1 , is_identical_to( translate(spph1)))
+    expect_that( spph2 , is_identical_to( translate(spph2)))
+    expect_that( spmp  , is_identical_to( translate(spmp)))
+    expect_that( spmph1, is_identical_to( translate(spmph1)))
+    expect_that( spmph2, is_identical_to( translate(spmph2)))
+    expect_that( spmph3, is_identical_to( translate(spmph3)))
+    
+    expect_that( p   , is_identical_to( translate(p)))
+    expect_that( ph1 , is_identical_to( translate(ph1)))
+    expect_that( ph2 , is_identical_to( translate(ph2)))
+    expect_that( mp  , is_identical_to( translate(mp)))
+    expect_that( mph1, is_identical_to( translate(mph1)))
+    expect_that( mph2, is_identical_to( translate(mph2)))
+    expect_that( mph3, is_identical_to( translate(mph3)))
+    
+})
diff --git a/tests/testthat/test-translate-rings.R b/tests/testthat/test-translate-rings.R
new file mode 100644
index 0000000..f2de27e
--- /dev/null
+++ b/tests/testthat/test-translate-rings.R
@@ -0,0 +1,46 @@
+library(testthat)
+library(rgeos)
+
+setScale()
+
+context("Translate Rings")
+
+test_that("translate linear ring", {
+
+    lr1 = readWKT("LINEARRING (1 1, 1 2, 2 2, 2 1, 1 1)")
+    lr2 = readWKT("LINEARRING (1 1, 2 1, 2 2, 1 2, 1 1)")
+    gclr1 = readWKT("GEOMETRYCOLLECTION( LINEARRING (1 1, 1 2, 2 2, 2 1, 1 1), LINEARRING (1 1, 1 2, 2 2, 2 1, 1 1) )")
+    gclr2 = readWKT("GEOMETRYCOLLECTION( LINEARRING (1 1, 1 2, 2 2, 2 1, 1 1), LINEARRING (1 1, 2 1, 2 2, 1 2, 1 1) )")
+    gclr3 = readWKT("GEOMETRYCOLLECTION( LINEARRING (1 1, 2 1, 2 2, 1 2, 1 1), LINEARRING (1 1, 2 1, 2 2, 1 2, 1 1) )")
+    
+    Ring11 = Ring(cbind( x=c(1,1,2,2,1),y=c(1,2,2,1,1) ),ID="1")
+    Ring12 = Ring(cbind( x=c(1,1,2,2,1),y=c(1,2,2,1,1) ),ID="2")
+    Ring21 = Ring(cbind( x=c(1,2,2,1,1),y=c(1,1,2,2,1) ),ID="1")
+    Ring22 = Ring(cbind( x=c(1,2,2,1,1),y=c(1,1,2,2,1) ),ID="2")
+    
+    splr1   = SpatialRings( list(Ring11) ); #rownames(splr1 at bbox) = c("x","y")
+    splr2   = SpatialRings( list(Ring21) ); #rownames(splr2 at bbox) = c("x","y")
+    spgclr1 = SpatialRings( list(Ring11,Ring12) ); #rownames(spgclr1 at bbox) = c("x","y")
+    spgclr2 = SpatialRings( list(Ring11,Ring22) ); #rownames(spgclr2 at bbox) = c("x","y")
+    spgclr3 = SpatialRings( list(Ring21,Ring22) ); #rownames(spgclr3 at bbox) = c("x","y")
+    
+
+    expect_that( lr1  , is_identical_to(splr1) )
+    expect_that( lr2  , is_identical_to(splr2) )
+    expect_that( gclr1, is_identical_to(spgclr1) )
+    expect_that( gclr2, is_identical_to(spgclr2) )
+    expect_that( gclr3, is_identical_to(spgclr3) )
+    
+    expect_that( splr1  , is_identical_to( translate(splr1)))
+    expect_that( splr2  , is_identical_to( translate(splr2)))
+    expect_that( spgclr1, is_identical_to( translate(spgclr1)))
+    expect_that( spgclr2, is_identical_to( translate(spgclr2)))
+    expect_that( spgclr3, is_identical_to( translate(spgclr3)))
+    
+    expect_that( lr1  , is_identical_to( translate(lr1) ))
+    expect_that( lr2  , is_identical_to( translate(lr2) ))
+    expect_that( gclr1, is_identical_to( translate(gclr1) ))
+    expect_that( gclr2, is_identical_to( translate(gclr2) ))
+    expect_that( gclr3, is_identical_to( translate(gclr3) ))
+
+})
\ No newline at end of file
diff --git a/tests/testthat/testxml/general/TestBoundary.xml b/tests/testthat/testxml/general/TestBoundary.xml
new file mode 100644
index 0000000..dd36b45
--- /dev/null
+++ b/tests/testthat/testxml/general/TestBoundary.xml
@@ -0,0 +1,129 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>L - Line</desc>
+  <a>
+    LINESTRING(10 10, 20 20)
+  </a>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(10 10, 20 20)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>L - self-intersecting with boundary</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 180 100, 180 180, 100 180, 100 100)
+  </a>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(40 40, 100 100)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - 2 lines with common endpoint</desc>
+  <a>
+    MULTILINESTRING(
+      (10 10, 20 20), 
+      (20 20, 30 30))
+  </a>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(10 10, 30 30)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - 3 lines with common endpoint</desc>
+  <a>
+    MULTILINESTRING(
+      (10 10, 20 20), 
+      (20 20, 30 20), 
+      (20 20, 30 30))
+  </a>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(10 10, 20 20, 30 20, 30 30)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - 4 lines with common endpoint</desc>
+  <a>
+    MULTILINESTRING(
+      (10 10, 20 20), 
+      (20 20, 30 20), 
+      (20 20, 30 30), 
+      (20 20, 30 40))
+  </a>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(10 10, 30 20, 30 30, 30 40)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - 2 lines, one closed, with common endpoint</desc>
+  <a>
+    MULTILINESTRING(
+      (10 10, 20 20), 
+      (20 20, 20 30, 30 30, 30 20, 20 20))
+  </a>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(10 10, 20 20)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>L - 1 line, self-intersecting, topologically equal to prev case</desc>
+  <a>
+    MULTILINESTRING(
+      (10 10, 20 20, 20 30, 30 30, 30 20, 20 20))
+  </a>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(10 10, 20 20)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>A - polygon with no holes</desc>
+  <a>
+    POLYGON(
+      (40 60, 420 60, 420 320, 40 320, 40 60))
+  </a>
+<test>
+  <op name="getboundary" arg1="A">
+    LINESTRING(40 60, 420 60, 420 320, 40 320, 40 60)
+  </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>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTILINESTRING(
+      (40 60, 420 60, 420 320, 40 320, 40 60), 
+      (200 140, 160 220, 260 200, 200 140))
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestCentroid.xml b/tests/testthat/testxml/general/TestCentroid.xml
new file mode 100644
index 0000000..d5f740d
--- /dev/null
+++ b/tests/testthat/testxml/general/TestCentroid.xml
@@ -0,0 +1,149 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>P - single point</desc>
+  <a>    POINT(10 10)  </a>
+<test><op name="getCentroid" arg1="A" >    POINT(10 10)   </op></test>
+</case>
+
+<case>
+  <desc>mP - two points</desc>
+  <a>    MULTIPOINT(10 10, 20 20 )  </a>
+<test><op name="getCentroid" arg1="A" >    POINT(15 15)   </op></test>
+</case>
+
+<case>
+  <desc>mP - 4 points</desc>
+  <a>    MULTIPOINT(10 10, 20 20, 10 20, 20 10)  </a>
+<test><op name="getCentroid" arg1="A" >    POINT(15 15)   </op></test>
+</case>
+
+<case>
+  <desc>L - single segment</desc>
+  <a>    LINESTRING(10 10, 20 20)  </a>
+<test><op name="getCentroid" arg1="A" >    POINT(15 15)   </op></test>
+</case>
+
+<case>
+  <desc>L - two segments</desc>
+  <a>    LINESTRING (60 180, 120 100, 180 180)  </a>
+<test><op name="getCentroid" arg1="A" >    POINT (120 140)   </op></test>
+</case>
+
+<case>
+  <desc>L - elongated horseshoe</desc>
+  <a>    LINESTRING (80 0, 80 120, 120 120, 120 0))
+	</a>
+<test><op name="getCentroid" arg1="A" >    POINT (100 69)   </op></test>
+</case>
+
+
+<case>
+  <desc>mL - two single-segment lines</desc>
+  <a>    MULTILINESTRING ((0 0, 0 100), (100 0, 100 100))  </a>
+<test><op name="getCentroid" arg1="A" >    POINT (50 50)   </op></test>
+</case>
+
+<case>
+  <desc>mL - two concentric rings, offset</desc>
+  <a>    MULTILINESTRING ((0 0, 0 200, 200 200, 200 0, 0 0), 
+  (60 180, 20 180, 20 140, 60 140, 60 180))  
+</a>
+<test><op name="getCentroid" arg1="A" >    POINT (90 110)   </op></test>
+</case>
+
+<case>
+  <desc>mL - complicated symmetrical collection of lines</desc>
+  <a>    MULTILINESTRING ((20 20, 60 60), 
+  (20 -20, 60 -60), 
+  (-20 -20, -60 -60), 
+  (-20 20, -60 60), 
+  (-80 0, 0 80, 80 0, 0 -80, -80 0), 
+  (-40 20, -40 -20), 
+  (-20 40, 20 40), 
+  (40 20, 40 -20), 
+  (20 -40, -20 -40)) </a>
+<test><op name="getCentroid" arg1="A" >    POINT (0 0)   </op></test>
+</case>
+
+<case>
+  <desc>A - box</desc>
+  <a>    POLYGON ((40 160, 160 160, 160 40, 40 40, 40 160))  </a>
+<test><op name="getCentroid" arg1="A" >    POINT (100 100)   </op></test>
+</case>
+
+<case>
+  <desc>A - box with hole</desc>
+  <a>    POLYGON ((0 200, 200 200, 200 0, 0 0, 0 200), (20 180, 80 180, 80 20, 20 20, 20 180)) </a>
+<test><op name="getCentroid" arg1="A" >    POINT (116 100)   </op></test>
+</case>
+
+<case>
+  <desc>A - box with offset hole (showing difference between area and line centroid)</desc>
+  <a>    POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0), 
+  (60 180, 20 180, 20 140, 60 140, 60 180))
+	 </a>
+<test><op name="getCentroid" arg1="A" >    POINT (103 98)   </op></test>
+</case>
+
+<case>
+  <desc>A - box with 2 symmetric holes </desc>
+  <a>    POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0), 
+  (60 180, 20 180, 20 140, 60 140, 60 180), 
+  (180 60, 140 60, 140 20, 180 20, 180 60))
+	 </a>
+<test><op name="getCentroid" arg1="A" >   POINT (100 100)   </op></test>
+</case>
+
+<case>
+  <desc>mA - symmetric angles</desc>
+  <a>    MULTIPOLYGON (((0 40, 0 140, 140 140, 140 120, 20 120, 20 40, 0 40)), 
+  ((0 0, 0 20, 120 20, 120 100, 140 100, 140 0, 0 0))) 
+	</a>
+<test><op name="getCentroid" arg1="A" >    POINT (70 70)   </op></test>
+</case>
+
+<case>
+  <desc>GC - two adjacent polygons (showing that centroids are additive) </desc>
+  <a>    GEOMETRYCOLLECTION (POLYGON ((0 200, 20 180, 20 140, 60 140, 200 0, 0 0, 0 200)), 
+  POLYGON ((200 200, 0 200, 20 180, 60 180, 60 140, 200 0, 200 200))) 
+	</a>
+<test><op name="getCentroid" arg1="A" >    POINT (103 98)   </op></test>
+</case>
+
+<case>
+  <desc>GC - heterogeneous collection of lines, points</desc>
+  <a>    GEOMETRYCOLLECTION (LINESTRING (80 0, 80 120, 120 120, 120 0), 
+  MULTIPOINT (20 60, 40 80, 60 60))
+	</a>
+<test><op name="getCentroid" arg1="A" >    POINT (100 69)   </op></test>
+</case>
+
+<case>
+  <desc>GC - heterogeneous collection of polygons, line</desc>
+  <a>    GEOMETRYCOLLECTION (POLYGON ((0 40, 40 40, 40 0, 0 0, 0 40)), 
+  LINESTRING (80 0, 80 80, 120 40)) 
+	</a>
+<test><op name="getCentroid" arg1="A" >    POINT (20 20)   </op></test>
+</case>
+
+<case>
+  <desc>GC - heterogeneous collection of polygons, lines, points</desc>
+  <a>    GEOMETRYCOLLECTION (POLYGON ((0 40, 40 40, 40 0, 0 0, 0 40)), 
+  LINESTRING (80 0, 80 80, 120 40), 
+  MULTIPOINT (20 60, 40 80, 60 60))
+	</a>
+<test><op name="getCentroid" arg1="A" >    POINT (20 20)   </op></test>
+</case>
+
+<case>
+  <desc>GC - overlapping polygons </desc>
+  <a>    GEOMETRYCOLLECTION (POLYGON ((20 100, 20 -20, 60 -20, 60 100, 20 100)), 
+  POLYGON ((-20 60, 100 60, 100 20, -20 20, -20 60)))
+	</a>
+<test><op name="getCentroid" arg1="A" >    POINT (40 40)   </op></test>
+</case>
+
+
+</run>
diff --git a/tests/testthat/testxml/general/TestConvexHull-big.xml b/tests/testthat/testxml/general/TestConvexHull-big.xml
new file mode 100644
index 0000000..c6c39b5
--- /dev/null
+++ b/tests/testthat/testxml/general/TestConvexHull-big.xml
@@ -0,0 +1,17 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>Big convex hull</desc>
+  <a>
+    MULTIPOINT(-1000000000000000000000000 -1000000000000000000000000, 1000000000000000000000000 -1000000000000000000000000, 1000000000000000000000000 1000000000000000000000000, -1000000000000000000000000 1000000000000000000000000, 0 0)
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (-1000000000000000000000000 -1000000000000000000000000, -1000000000000000000000000 1000000000000000000000000, 1000000000000000000000000 1000000000000000000000000, 1000000000000000000000000 -1000000000000000000000000, -1000000000000000000000000 -1000000000000000000000000))
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestConvexHull.xml b/tests/testthat/testxml/general/TestConvexHull.xml
new file mode 100644
index 0000000..3dc7028
--- /dev/null
+++ b/tests/testthat/testxml/general/TestConvexHull.xml
@@ -0,0 +1,181 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>Several points collinear and overlapping</desc>
+  <a>
+    MULTIPOINT(130 240, 130 240, 130 240, 570 240, 570 240, 570 240, 650 240)
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    LINESTRING(130 240, 650 240)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Convex hull</desc>
+  <a>
+    POLYGON(
+      (40 60, 420 60, 420 320, 40 320, 40 60), 
+      (200 140, 160 220, 260 200, 200 140))
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (40 60, 40 320, 420 320, 420 60, 40 60))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Convex hull</desc>
+  <a>
+    POLYGON(
+      (10 10, 100 10, 100 100, 10 100, 10 10))
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (10 10, 10 100, 100 100, 100 10, 10 10))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Point</desc>
+  <a>
+    POINT(20 20)
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    POINT(20 20)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Horizontal Line</desc>
+  <a>
+    LINESTRING(30 220, 240 220, 240 220)
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    LINESTRING(30 220, 240 220)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Vertical Line</desc>
+  <a>
+    LINESTRING(110 290, 110 100, 110 100)
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    LINESTRING(110 290, 110 100)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Spiral</desc>
+  <a>
+    LINESTRING(120 230, 120 200, 150 180, 180 220, 160 260, 90 250, 80 190, 140 110, 230 150, 
+    240 230, 180 320, 60 310, 40 160, 140 50, 280 140)
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (140 50, 40 160, 60 310, 180 320, 240 230, 280 140, 140 50))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Starlike Polygon</desc>
+  <a>
+    POLYGON(
+      (200 360, 230 210, 100 190, 270 150, 360 10, 320 200, 490 230, 280 240, 200 360), 
+      (220 300, 250 200, 150 190, 290 150, 330 70, 310 210, 390 230, 280 230, 220 300))
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (360 10, 100 190, 200 360, 490 230, 360 10))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Most of the points in one area</desc>
+  <a>
+    MULTIPOINT(70 340, 70 50, 430 50, 420 340, 340 120, 390 110, 390 70, 350 100, 350 50, 
+    370 90, 320 80, 360 120, 350 80, 390 90, 420 80, 410 60, 410 100, 370 100, 380 60, 
+    370 80, 380 100, 360 80, 370 80, 380 70, 390 80, 390 70, 410 70, 400 60, 410 60, 
+    410 60, 410 60, 370 70, 410 50, 410 50, 410 50, 410 50, 410 50, 410 50, 410 50)
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (70 50, 70 340, 420 340, 430 50, 70 50))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Multipoint</desc>
+  <a>
+    MULTIPOINT(140 350, 510 140, 110 140, 250 290, 250 50, 300 370, 450 310, 440 160, 290 280, 
+    220 160, 100 260, 320 230, 200 280, 360 130, 330 210, 380 80, 220 210, 380 310, 260 150, 
+    260 110, 170 130)
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (250 50, 110 140, 100 260, 140 350, 300 370, 450 310, 510 140, 380 80, 250 50))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>GeometryCollection</desc>
+  <a>
+    GEOMETRYCOLLECTION(
+      POINT(110 300), 
+      POINT(100 110), 
+      POINT(130 210), 
+      POINT(150 210), 
+      POINT(150 180), 
+      POINT(130 170), 
+      POINT(140 190), 
+      POINT(130 200), 
+      LINESTRING(240 50, 210 120, 270 80, 250 140, 330 70, 300 160, 340 130, 340 130), 
+      POLYGON(
+        (210 340, 220 260, 150 270, 230 220, 230 140, 270 210, 360 240, 260 250, 260 280, 
+        240 270, 210 340), 
+        (230 270, 230 250, 200 250, 240 220, 240 190, 260 220, 290 230, 250 230, 230 270)))
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (240 50, 100 110, 110 300, 210 340, 360 240, 330 70, 240 50))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Collinear L</desc>
+  <a>
+    MULTIPOINT(50 320, 50 280, 50 230, 50 160, 50 120, 100 120, 160 120, 210 120, 210 180, 
+    210 150, 180 180, 140 180, 140 210, 140 260, 160 180, 140 300, 140 320, 110 320, 80 320)
+  </a>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (50 120, 50 320, 140 320, 210 180, 210 120, 50 120))
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestFunctionAA.xml b/tests/testthat/testxml/general/TestFunctionAA.xml
new file mode 100644
index 0000000..6e109c0
--- /dev/null
+++ b/tests/testthat/testxml/general/TestFunctionAA.xml
@@ -0,0 +1,633 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>AA - simple polygons</desc>
+  <a>
+    POLYGON(
+      (10 10, 100 10, 100 100, 10 100, 10 10))
+  </a>
+  <b>
+    POLYGON(
+      (50 50, 200 50, 200 200, 50 200, 50 50))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POLYGON(
+      (50 50, 50 100, 100 100, 100 50, 50 50))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (10 10, 10 100, 50 100, 50 200, 200 200, 200 50, 100 50, 100 10, 10 10))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (10 10, 10 100, 50 100, 50 50, 100 50, 100 10, 10 10))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (10 10, 10 100, 50 100, 50 50, 100 50, 100 10, 10 10)), 
+      (
+        (50 100, 50 200, 200 200, 200 50, 100 50, 100 100, 50 100)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - A with hole intersecting B</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 160, 160 160, 160 20, 20 20), 
+      (140 140, 40 140, 40 40, 140 40, 140 140))
+  </a>
+  <b>
+    POLYGON(
+      (80 100, 220 100, 220 240, 80 240, 80 100))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POLYGON(
+      (80 140, 80 160, 160 160, 160 100, 140 100, 140 140, 80 140))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (20 20, 20 160, 80 160, 80 240, 220 240, 220 100, 160 100, 160 20, 20 20), 
+      (80 100, 80 140, 40 140, 40 40, 140 40, 140 100, 80 100))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (20 20, 20 160, 80 160, 80 140, 40 140, 40 40, 140 40, 140 100, 160 100, 
+      160 20, 20 20))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (20 20, 20 160, 80 160, 80 140, 40 140, 40 40, 140 40, 140 100, 160 100, 
+        160 20, 20 20)), 
+      (
+        (80 100, 80 140, 140 140, 140 100, 80 100)), 
+      (
+        (80 160, 80 240, 220 240, 220 100, 160 100, 160 160, 80 160)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - simple polygons #2</desc>
+  <a>
+    POLYGON(
+      (20 340, 330 380, 50 40, 20 340))
+  </a>
+  <b>
+    POLYGON(
+      (210 320, 140 270, 0 270, 140 220, 210 320))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POLYGON(
+      (27 270, 140 270, 210 320, 140 220, 28 260, 27 270))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (20 340, 330 380, 50 40, 28 260, 0 270, 27 270, 20 340))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (20 340, 330 380, 50 40, 28 260, 140 220, 210 320, 140 270, 27 270, 20 340))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (20 340, 330 380, 50 40, 28 260, 140 220, 210 320, 140 270, 27 270, 20 340)), 
+      (
+        (27 270, 28 260, 0 270, 27 270)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - simple polygons intersecting in P, L and A</desc>
+  <a>
+    POLYGON((0 0, 110 0, 110 60, 40 60, 180 140, 40 220, 110 260, 0 260, 0 0))
+  </a>
+  <b>
+    POLYGON((220 0, 110 0, 110 60, 180 60, 40 140, 180 220, 110 260, 220 260, 220 0))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(110 260), 
+      LINESTRING(110 0, 110 60), 
+      POLYGON(
+        (110 100, 40 140, 110 180, 180 140, 110 100)))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (110 0, 0 0, 0 260, 110 260, 220 260, 220 0, 110 0), 
+      (110 260, 40 220, 110 180, 180 220, 110 260), 
+      (110 100, 40 60, 110 60, 180 60, 110 100))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (110 0, 0 0, 0 260, 110 260, 40 220, 110 180, 40 140, 110 100, 40 60, 
+      110 60, 110 0))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    POLYGON(
+      (110 0, 0 0, 0 260, 110 260, 220 260, 220 0, 110 0), 
+      (110 260, 40 220, 110 180, 180 220, 110 260), 
+      (110 180, 40 140, 110 100, 180 140, 110 180), 
+      (110 100, 40 60, 110 60, 180 60, 110 100))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - simple polygons with two touching holes in their symDifference</desc>
+  <a>
+    POLYGON(
+      (0 0, 120 0, 120 50, 50 50, 120 100, 50 150, 120 150, 120 190, 0 190, 
+      0 0))
+  </a>
+  <b>
+    POLYGON(
+      (230 0, 120 0, 120 50, 190 50, 120 100, 190 150, 120 150, 120 190, 230 190, 
+      230 0))
+  </b>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    POLYGON(
+      (120 0, 0 0, 0 190, 120 190, 230 190, 230 0, 120 0), 
+      (120 100, 50 50, 120 50, 190 50, 120 100), 
+      (120 100, 190 150, 120 150, 50 150, 120 100))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AmA - A simple, symDiff contains inversion</desc>
+  <a>
+    POLYGON(
+      (0 0, 210 0, 210 230, 0 230, 0 0))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (40 20, 0 0, 20 40, 60 60, 40 20)), 
+      (
+        (60 90, 60 60, 90 60, 90 90, 60 90)), 
+      (
+        (70 120, 90 90, 100 120, 70 120)), 
+      (
+        (120 70, 90 90, 120 100, 120 70)))
+  </b>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    POLYGON(
+      (0 0, 0 230, 210 230, 210 0, 0 0), 
+      (0 0, 40 20, 60 60, 20 40, 0 0), 
+      (60 60, 90 60, 90 90, 60 90, 60 60), 
+      (90 90, 120 70, 120 100, 90 90), 
+      (90 90, 100 120, 70 120, 90 90))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AmA - A simple, B connected multiPolygon touching A at vertex</desc>
+  <a>
+    POLYGON(
+      (0 0, 340 0, 340 300, 0 300, 0 0))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (40 20, 0 0, 20 40, 60 60, 40 20)), 
+      (
+        (60 100, 60 60, 100 60, 100 100, 60 100)))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (40 20, 0 0, 20 40, 60 60, 40 20)), 
+      (
+        (60 60, 60 100, 100 100, 100 60, 60 60)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    POLYGON(
+      (0 0, 0 300, 340 300, 340 0, 0 0), 
+      (0 0, 40 20, 60 60, 20 40, 0 0), 
+      (60 60, 100 60, 100 100, 60 100, 60 60))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AmA - A simple, B connected multiPolygon touching A at interior of edge</desc>
+  <a>
+    POLYGON(
+      (0 0, 120 0, 120 120, 0 120, 0 0))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (60 20, 0 20, 60 60, 60 20)), 
+      (
+        (60 100, 60 60, 100 60, 100 100, 60 100)))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (60 20, 0 20, 60 60, 60 20)), 
+      (
+        (60 60, 60 100, 100 100, 100 60, 60 60)))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (0 20, 0 120, 120 120, 120 0, 0 0, 0 20))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (0 20, 0 120, 120 120, 120 0, 0 0, 0 20), 
+      (0 20, 60 20, 60 60, 0 20), 
+      (60 60, 100 60, 100 100, 60 100, 60 60))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    POLYGON(
+      (0 20, 0 120, 120 120, 120 0, 0 0, 0 20), 
+      (0 20, 60 20, 60 60, 0 20), 
+      (60 60, 100 60, 100 100, 60 100, 60 60))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - simple polygons with holes</desc>
+  <a>
+    POLYGON(
+      (160 330, 60 260, 20 150, 60 40, 190 20, 270 130, 260 250, 160 330), 
+      (140 240, 80 190, 90 100, 160 70, 210 130, 210 210, 140 240))
+  </a>
+  <b>
+    POLYGON(
+      (300 330, 190 270, 150 170, 150 110, 250 30, 380 50, 380 250, 300 330), 
+      (290 240, 240 200, 240 110, 290 80, 330 170, 290 240))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POLYGON(
+      (251 104, 217 57, 176 89, 210 130, 210 210, 172 226, 190 270, 217 285, 260 250, 
+      263 218, 240 200, 240 110, 251 104))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (217 57, 190 20, 60 40, 20 150, 60 260, 160 330, 217 285, 190 270, 172 226, 
+        140 240, 80 190, 90 100, 160 70, 176 89, 217 57)), 
+      (
+        (217 57, 251 104, 290 80, 330 170, 290 240, 263 218, 260 250, 217 285, 300 330, 
+        380 250, 380 50, 250 30, 217 57)), 
+      (
+        (263 218, 270 130, 251 104, 240 110, 240 200, 263 218)), 
+      (
+        (172 226, 210 210, 210 130, 176 89, 150 110, 150 170, 172 226)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - simple polygons with hole touching shell</desc>
+  <a>
+    POLYGON ((20 0, 20 160, 200 160, 200 0, 20 0))
+  </a>
+  <b>
+    POLYGON ((220 80, 0 80, 0 240, 220 240, 220 80), 
+  	(100 80, 120 120, 80 120, 100 80))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POLYGON ((20 80, 20 160, 200 160, 200 80, 100 80, 20 80), 
+  (100 80, 120 120, 80 120, 100 80))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON ((20 0, 20 80, 0 80, 0 240, 220 240, 220 80, 200 80, 200 0, 20 0))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTIPOLYGON (((20 0, 20 80, 100 80, 200 80, 200 0, 20 0)), 
+  ((100 80, 80 120, 120 120, 100 80)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON (((20 0, 20 80, 100 80, 200 80, 200 0, 20 0)), 
+  ((200 80, 200 160, 20 160, 20 80, 0 80, 0 240, 220 240, 220 80, 200 80)), 
+  ((100 80, 80 120, 120 120, 100 80)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mAmA - complex polygons touching and overlapping</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (120 340, 120 200, 140 200, 140 280, 160 280, 160 200, 180 200, 180 280, 200 280, 
+        200 200, 220 200, 220 340, 120 340)), 
+      (
+        (360 200, 220 200, 220 180, 300 180, 300 160, 220 160, 220 140, 300 140, 300 120, 
+        220 120, 220 100, 360 100, 360 200)))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (100 220, 100 200, 300 200, 300 220, 100 220)), 
+      (
+        (280 180, 280 160, 300 160, 300 180, 280 180)), 
+      (
+        (220 140, 220 120, 240 120, 240 140, 220 140)), 
+      (
+        (180 220, 160 240, 200 240, 180 220)))
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTILINESTRING(
+      (120 340, 120 200, 140 200, 140 280, 160 280, 160 200, 180 200, 180 280, 200 280, 
+      200 200, 220 200, 220 340, 120 340), 
+      (360 200, 220 200, 220 180, 300 180, 300 160, 220 160, 220 140, 300 140, 300 120, 
+      220 120, 220 100, 360 100, 360 200))
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (220 100, 120 200, 120 340, 220 340, 360 200, 360 100, 220 100))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(200 240), 
+      LINESTRING(300 200, 220 200), 
+      LINESTRING(280 180, 300 180), 
+      LINESTRING(300 180, 300 160), 
+      LINESTRING(300 160, 280 160), 
+      LINESTRING(220 140, 240 140), 
+      LINESTRING(240 120, 220 120), 
+      POLYGON(
+        (120 200, 120 220, 140 220, 140 200, 120 200)), 
+      POLYGON(
+        (160 200, 160 220, 180 220, 180 200, 160 200)), 
+      POLYGON(
+        (180 240, 180 220, 160 240, 180 240)), 
+      POLYGON(
+        (200 200, 200 220, 220 220, 220 200, 200 200)))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (120 220, 120 340, 220 340, 220 220, 300 220, 300 200, 360 200, 360 100, 220 100, 
+      220 120, 220 140, 220 160, 280 160, 280 180, 220 180, 220 200, 200 200, 180 200, 160 200, 
+      140 200, 120 200, 100 200, 100 220, 120 220), 
+      (200 240, 200 280, 180 280, 180 240, 200 240), 
+      (200 240, 180 220, 200 220, 200 240), 
+      (160 240, 160 280, 140 280, 140 220, 160 220, 160 240), 
+      (240 120, 300 120, 300 140, 240 140, 240 120))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (120 220, 120 340, 220 340, 220 220, 200 220, 200 240, 200 280, 180 280, 180 240, 
+        160 240, 160 280, 140 280, 140 220, 120 220)), 
+      (
+        (160 220, 160 240, 180 220, 160 220)), 
+      (
+        (300 200, 360 200, 360 100, 220 100, 220 120, 240 120, 300 120, 300 140, 240 140, 
+        220 140, 220 160, 280 160, 300 160, 300 180, 280 180, 220 180, 220 200, 300 200)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (120 220, 120 340, 220 340, 220 220, 200 220, 200 240, 200 280, 180 280, 180 240, 
+        160 240, 160 280, 140 280, 140 220, 120 220)), 
+      (
+        (120 220, 120 200, 100 200, 100 220, 120 220)), 
+      (
+        (140 200, 140 220, 160 220, 160 200, 140 200)), 
+      (
+        (160 220, 160 240, 180 220, 160 220)), 
+      (
+        (180 200, 180 220, 200 220, 200 200, 180 200)), 
+      (
+        (180 220, 180 240, 200 240, 180 220)), 
+      (
+        (220 200, 220 220, 300 220, 300 200, 360 200, 360 100, 220 100, 220 120, 220 140, 
+        220 160, 280 160, 280 180, 220 180, 220 200), 
+        (240 120, 300 120, 300 140, 240 140, 240 120)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mAmA - complex polygons touching</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (100 200, 100 180, 120 180, 120 200, 100 200)), 
+      (
+        (60 240, 60 140, 220 140, 220 160, 160 160, 160 180, 200 180, 200 200, 160 200, 
+        160 220, 220 220, 220 240, 60 240), 
+        (80 220, 80 160, 140 160, 140 220, 80 220)), 
+      (
+        (280 220, 240 180, 260 160, 300 200, 280 220)))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (80 220, 80 160, 140 160, 140 220, 80 220), 
+        (100 200, 100 180, 120 180, 120 200, 100 200)), 
+      (
+        (220 240, 220 220, 160 220, 160 200, 220 200, 220 180, 160 180, 160 160, 220 160, 
+        220 140, 320 140, 320 240, 220 240), 
+        (240 220, 240 160, 300 160, 300 220, 240 220)))
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTILINESTRING(
+      (100 200, 100 180, 120 180, 120 200, 100 200), 
+      (60 240, 60 140, 220 140, 220 160, 160 160, 160 180, 200 180, 200 200, 160 200, 
+      160 220, 220 220, 220 240, 60 240), 
+      (80 220, 80 160, 140 160, 140 220, 80 220), 
+      (280 220, 240 180, 260 160, 300 200, 280 220))
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (60 140, 60 240, 220 240, 280 220, 300 200, 260 160, 220 140, 60 140))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(240 180), 
+      POINT(260 160), 
+      POINT(280 220), 
+      POINT(300 200), 
+      LINESTRING(100 200, 100 180), 
+      LINESTRING(100 180, 120 180), 
+      LINESTRING(120 180, 120 200), 
+      LINESTRING(120 200, 100 200), 
+      LINESTRING(220 140, 220 160), 
+      LINESTRING(220 160, 160 160), 
+      LINESTRING(160 160, 160 180), 
+      LINESTRING(160 180, 200 180), 
+      LINESTRING(200 200, 160 200), 
+      LINESTRING(160 200, 160 220), 
+      LINESTRING(160 220, 220 220), 
+      LINESTRING(220 220, 220 240), 
+      LINESTRING(80 220, 80 160), 
+      LINESTRING(80 160, 140 160), 
+      LINESTRING(140 160, 140 220), 
+      LINESTRING(140 220, 80 220))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (220 140, 60 140, 60 240, 220 240, 320 240, 320 140, 220 140), 
+        (200 200, 200 180, 220 180, 220 200, 200 200), 
+        (240 220, 240 180, 240 160, 260 160, 300 160, 300 200, 300 220, 280 220, 240 220)), 
+      (
+        (240 180, 280 220, 300 200, 260 160, 240 180)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (100 180, 100 200, 120 200, 120 180, 100 180)), 
+      (
+        (220 140, 60 140, 60 240, 220 240, 220 220, 160 220, 160 200, 200 200, 200 180, 
+        160 180, 160 160, 220 160, 220 140), 
+        (80 220, 80 160, 140 160, 140 220, 80 220)), 
+      (
+        (240 180, 280 220, 300 200, 260 160, 240 180)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (220 140, 60 140, 60 240, 220 240, 320 240, 320 140, 220 140), 
+        (200 200, 200 180, 220 180, 220 200, 200 200), 
+        (240 220, 240 180, 240 160, 260 160, 300 160, 300 200, 300 220, 280 220, 240 220)), 
+      (
+        (240 180, 280 220, 300 200, 260 160, 240 180)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - hole intersecting boundary to produce line</desc>
+  <a>
+    POLYGON(
+      (60 160, 140 160, 140 60, 60 60, 60 160))
+  </a>
+  <b>
+    POLYGON(
+      (160 160, 100 160, 100 100, 160 100, 160 160), 
+      (140 140, 120 140, 120 120, 140 120, 140 140))
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    LINESTRING(60 160, 140 160, 140 60, 60 60, 60 160)
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (60 60, 60 160, 140 160, 140 60, 60 60))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(140 140, 140 120), 
+      POLYGON(
+        (100 160, 140 160, 140 140, 120 140, 120 120, 140 120, 140 100, 100 100, 100 160)))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (60 160, 100 160, 140 160, 160 160, 160 100, 140 100, 140 60, 60 60, 60 160))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (60 160, 100 160, 100 100, 140 100, 140 60, 60 60, 60 160)), 
+      (
+        (140 140, 140 120, 120 120, 120 140, 140 140)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (60 160, 100 160, 100 100, 140 100, 140 60, 60 60, 60 160)), 
+      (
+        (140 140, 140 160, 160 160, 160 100, 140 100, 140 120, 120 120, 120 140, 140 140)))
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestFunctionAAPrec.xml b/tests/testthat/testxml/general/TestFunctionAAPrec.xml
new file mode 100644
index 0000000..759cc08
--- /dev/null
+++ b/tests/testthat/testxml/general/TestFunctionAAPrec.xml
@@ -0,0 +1,828 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>AA - sliver triangle, cut by polygon</desc>
+  <a>
+    POLYGON(
+      (10 10, 100 10, 10 11, 10 10))
+  </a>
+  <b>
+    POLYGON(
+      (90 0, 200 0, 200 200, 90 200, 90 0))
+  </b>
+<test>
+  <op name="relate" arg3="212101212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    LINESTRING(90 10, 100 10)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (90 10, 10 10, 10 11, 90 10)), 
+      (
+        (90 10, 90 200, 200 200, 200 0, 90 0, 90 10)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (90 10, 10 10, 10 11, 90 10))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (90 10, 10 10, 10 11, 90 10)), 
+      (
+        (90 10, 90 200, 200 200, 200 0, 90 0, 90 10)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - polygon with outward sliver, cut by polygon</desc>
+  <a>
+    POLYGON(
+      (100 10, 10 10, 90 11, 90 20, 100 20, 100 10))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 0 20, 0 0, 20 0, 20 20))
+  </b>
+<test>
+  <op name="relate" arg3="212101212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    LINESTRING(20 10, 10 10)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - narrow wedge in polygon</desc>
+  <a>
+    POLYGON((10 10, 50 10, 50 50, 10 50, 10 31, 49 30, 10 30, 10 10))
+  </a>
+  <b>
+    POLYGON((60 40, 40 40, 40 20, 60 20, 60 40))
+  </b>
+<test>
+  <op name="relate" arg3="212101212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POLYGON(
+      (50 40, 50 20, 40 20, 40 30, 40 40, 50 40))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (50 20, 50 10, 10 10, 10 30, 40 30, 10 31, 10 50, 50 50, 50 40, 
+      60 40, 60 20, 50 20))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (50 20, 50 10, 10 10, 10 30, 40 30, 40 20, 50 20)), 
+      (
+        (40 30, 10 31, 10 50, 50 50, 50 40, 40 40, 40 30)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (50 20, 50 10, 10 10, 10 30, 40 30, 40 20, 50 20)), 
+      (
+        (50 20, 50 40, 60 40, 60 20, 50 20)), 
+      (
+        (40 30, 10 31, 10 50, 50 50, 50 40, 40 40, 40 30)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - hole close to shell</desc>
+  <a>
+    POLYGON(
+      (10 100, 10 10, 100 10, 100 100, 10 100), 
+      (90 90, 11 90, 10 10, 90 11, 90 90))
+  </a>
+  <b>
+    POLYGON(
+      (0 30, 0 0, 30 0, 30 30, 0 30))
+  </b>
+<test>
+  <op name="relate" arg3="212101212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (10 30, 10 10), 
+      (10 10, 30 10))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (10 30, 10 100, 100 100, 100 10, 30 10, 90 11, 90 90, 11 90, 10 30)), 
+      (
+        (30 10, 30 0, 0 0, 0 30, 10 30, 30 30, 30 10)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (10 30, 10 100, 100 100, 100 10, 30 10, 90 11, 90 90, 11 90, 10 30))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (10 30, 10 100, 100 100, 100 10, 30 10, 90 11, 90 90, 11 90, 10 30)), 
+      (
+        (30 10, 30 0, 0 0, 0 30, 10 30, 30 30, 30 10)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mAA - shells close together</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (0 0, 100 0, 100 20, 0 20, 0 0)), 
+      (
+        (0 40, 0 21, 100 20, 100 40, 0 40)))
+  </a>
+  <b>
+    POLYGON(
+      (110 30, 90 30, 90 10, 110 10, 110 30))
+  </b>
+<test>
+  <op name="relate" arg3="212101212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(100 20, 90 20), 
+      POLYGON(
+        (100 20, 100 10, 90 10, 90 20, 90 30, 100 30, 100 20)))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (100 10, 100 0, 0 0, 0 20, 90 20, 0 21, 0 40, 100 40, 100 30, 
+      110 30, 110 10, 100 10))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (100 10, 100 0, 0 0, 0 20, 90 20, 90 10, 100 10)), 
+      (
+        (90 20, 0 21, 0 40, 100 40, 100 30, 90 30, 90 20)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (100 10, 100 0, 0 0, 0 20, 90 20, 90 10, 100 10)), 
+      (
+        (100 10, 100 20, 100 30, 110 30, 110 10, 100 10)), 
+      (
+        (90 20, 0 21, 0 40, 100 40, 100 30, 90 30, 90 20)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - A sliver triangle cutting all the way across B</desc>
+  <a>
+    POLYGON(
+      (100 10, 0 10, 100 11, 100 10))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 0 20, 0 0, 20 0, 20 20))
+  </b>
+<test>
+  <op name="relate" arg3="212101212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    LINESTRING(20 10, 0 10)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (100 10, 20 10, 100 11, 100 10)), 
+      (
+        (0 10, 0 20, 20 20, 20 10, 20 0, 0 0, 0 10)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (100 10, 20 10, 100 11, 100 10))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (100 10, 20 10, 100 11, 100 10)), 
+      (
+        (0 10, 0 20, 20 20, 20 10, 20 0, 0 0, 0 10)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - A polygon with sliver cutting all the way across B</desc>
+  <a>
+    POLYGON(
+      (100 10, 0 10, 90 11, 90 20, 100 20, 100 10))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 0 20, 0 0, 20 0, 20 20))
+  </b>
+<test>
+  <op name="relate" arg3="212101212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    LINESTRING(20 10, 0 10)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (100 10, 20 10, 90 11, 90 20, 100 20, 100 10)), 
+      (
+        (0 10, 0 20, 20 20, 20 10, 20 0, 0 0, 0 10)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - hole close to shell, B coincident with A</desc>
+  <a>
+    POLYGON(
+      (10 100, 10 10, 100 10, 100 100, 10 100), 
+      (90 90, 11 90, 10 10, 90 11, 90 90))
+  </a>
+  <b>
+    POLYGON(
+      (10 30, 10 0, 30 10, 30 30, 10 30))
+  </b>
+<test>
+  <op name="relate" arg3="212111212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (10 30, 10 10), 
+      (10 10, 30 10))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (10 30, 10 100, 100 100, 100 10, 30 10, 90 11, 90 90, 11 90, 10 30)), 
+      (
+        (10 10, 10 30, 30 30, 30 10, 10 0, 10 10)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (10 30, 10 100, 100 100, 100 10, 30 10, 90 11, 90 90, 11 90, 10 30))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (10 30, 10 100, 100 100, 100 10, 30 10, 90 11, 90 90, 11 90, 10 30)), 
+      (
+        (10 10, 10 30, 30 30, 30 10, 10 0, 10 10)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - A hole close to shell, B coincident with A</desc>
+  <a>
+    POLYGON(
+      (10 100, 10 10, 100 10, 100 100, 10 100), 
+      (90 90, 11 90, 10 10, 90 11, 90 90))
+  </a>
+  <b>
+    POLYGON(
+      (10 30, 10 10, 30 10, 30 30, 10 30))
+  </b>
+<test>
+  <op name="relate" arg3="212111212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (10 30, 10 10), 
+      (10 10, 30 10))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (10 30, 10 100, 100 100, 100 10, 30 10, 90 11, 90 90, 11 90, 10 30)), 
+      (
+        (10 10, 10 30, 30 30, 30 10, 10 10)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (10 30, 10 100, 100 100, 100 10, 30 10, 90 11, 90 90, 11 90, 10 30))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (10 30, 10 100, 100 100, 100 10, 30 10, 90 11, 90 90, 11 90, 10 30)), 
+      (
+        (10 10, 10 30, 30 30, 30 10, 10 10)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - B hole close to shell, A coincident with B</desc>
+  <a>
+    POLYGON(
+      (10 30, 10 10, 30 10, 30 30, 10 30))
+  </a>
+  <b>
+    POLYGON(
+      (10 100, 10 10, 100 10, 100 100, 10 100), 
+      (90 90, 11 90, 10 10, 90 11, 90 90))
+  </b>
+<test>
+  <op name="relate" arg3="212111212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (10 30, 10 10), 
+      (10 10, 30 10))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (10 30, 10 100, 100 100, 100 10, 30 10, 90 11, 90 90, 11 90, 10 30)), 
+      (
+        (10 10, 10 30, 30 30, 30 10, 10 10)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (10 10, 10 30, 30 30, 30 10, 10 10))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (10 30, 10 100, 100 100, 100 10, 30 10, 90 11, 90 90, 11 90, 10 30)), 
+      (
+        (10 10, 10 30, 30 30, 30 10, 10 10)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - B sliver crossing A triangle in line segment with length < 1</desc>
+  <a>
+    POLYGON(
+      (0 0, 200 0, 0 198, 0 0))
+  </a>
+  <b>
+    POLYGON(
+      (280 60, 139 60, 280 70, 280 60))
+  </b>
+<test>
+  <op name="relate" arg3="212101212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POINT(139 60)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (139 60, 200 0, 0 0, 0 198, 139 60)), 
+      (
+        (280 60, 139 60, 280 70, 280 60)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (139 60, 200 0, 0 0, 0 198, 139 60))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (139 60, 200 0, 0 0, 0 198, 139 60)), 
+      (
+        (280 60, 139 60, 280 70, 280 60)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - sliver triangles, at angle to each other</desc>
+  <a>
+    POLYGON(
+      (0 0, 140 10, 0 20, 0 0))
+  </a>
+  <b>
+    POLYGON(
+      (280 0, 139 10, 280 1, 280 0))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    LINESTRING(140 10, 139 10)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - sliver triangle with multiple intersecting boxes</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (1 4, 1 1, 2 1, 2 4, 1 4)), 
+      (
+        (3 4, 3 1, 4 1, 4 4, 3 4)), 
+      (
+        (5 4, 5 1, 6 1, 6 4, 5 4)), 
+      (
+        (7 4, 7 1, 8 1, 8 4, 7 4)), 
+      (
+        (9 4, 9 1, 10 1, 10 4, 9 4)))
+  </a>
+  <b>
+    POLYGON(
+      (0 2, 11 3, 11 2, 0 2))
+  </b>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (1 1, 1 4, 10 4, 10 1, 1 1))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(1 2, 2 2), 
+      LINESTRING(3 2, 4 2), 
+      POLYGON(
+        (6 3, 6 2, 5 2, 6 3)), 
+      POLYGON(
+        (7 2, 7 3, 8 3, 8 2, 7 2)), 
+      POLYGON(
+        (9 2, 9 3, 10 3, 10 2, 9 2)))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+GEOMETRYCOLLECTION(
+  LINESTRING(0 2, 1 2), 
+  LINESTRING(2 2, 3 2), 
+  LINESTRING(4 2, 5 2), 
+  POLYGON(
+    (1 2, 1 4, 2 4, 2 2, 2 1, 1 1, 1 2)), 
+  POLYGON(
+    (3 2, 3 4, 4 4, 4 2, 4 1, 3 1, 3 2)), 
+  POLYGON(
+    (5 2, 5 4, 6 4, 6 3, 7 3, 7 4, 8 4, 8 3, 9 3, 
+    9 4, 10 4, 10 3, 11 3, 11 2, 10 2, 10 1, 9 1, 9 2, 8 2, 
+    8 1, 7 1, 7 2, 6 2, 6 1, 5 1, 5 2)))  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (1 2, 1 4, 2 4, 2 2, 2 1, 1 1, 1 2)), 
+      (
+        (3 2, 3 4, 4 4, 4 2, 4 1, 3 1, 3 2)), 
+      (
+        (5 2, 5 4, 6 4, 6 3, 5 2)), 
+      (
+        (6 2, 6 1, 5 1, 5 2, 6 2)), 
+      (
+        (7 3, 7 4, 8 4, 8 3, 7 3)), 
+      (
+        (8 2, 8 1, 7 1, 7 2, 8 2)), 
+      (
+        (9 3, 9 4, 10 4, 10 3, 9 3)), 
+      (
+        (10 2, 10 1, 9 1, 9 2, 10 2)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+GEOMETRYCOLLECTION(
+  LINESTRING(0 2, 1 2), 
+  LINESTRING(2 2, 3 2), 
+  LINESTRING(4 2, 5 2), 
+  POLYGON(
+    (1 2, 1 4, 2 4, 2 2, 2 1, 1 1, 1 2)), 
+  POLYGON(
+    (3 2, 3 4, 4 4, 4 2, 4 1, 3 1, 3 2)), 
+  POLYGON(
+    (5 2, 5 4, 6 4, 6 3, 5 2)), 
+  POLYGON(
+    (6 2, 6 1, 5 1, 5 2, 6 2)), 
+  POLYGON(
+    (6 2, 6 3, 7 3, 7 2, 6 2)), 
+  POLYGON(
+    (7 3, 7 4, 8 4, 8 3, 7 3)), 
+  POLYGON(
+    (8 2, 8 1, 7 1, 7 2, 8 2)), 
+  POLYGON(
+    (8 2, 8 3, 9 3, 9 2, 8 2)), 
+  POLYGON(
+    (9 3, 9 4, 10 4, 10 3, 9 3)), 
+  POLYGON(
+    (10 2, 10 1, 9 1, 9 2, 10 2)), 
+  POLYGON(
+    (10 2, 10 3, 11 3, 11 2, 10 2)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - Polygon with hole with outward sliver, cut by polygon</desc>
+  <a>
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 40, 20 40), 
+      (180 120, 120 120, 120 160, 60 120, 120 80, 120 119, 180 120))
+  </a>
+  <b>
+    POLYGON(
+      (200 160, 160 160, 160 80, 200 80, 200 160))
+  </b>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 40, 20 40))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(180 120, 160 120), 
+      POLYGON(
+        (180 160, 180 120, 180 80, 160 80, 160 120, 160 160, 180 160)))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 160, 200 160, 200 80, 180 80, 180 40, 20 40), 
+      (160 120, 120 120, 120 160, 60 120, 120 80, 120 119, 160 120))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 160, 160 160, 160 120, 160 80, 180 80, 180 40, 
+      20 40), 
+      (160 120, 120 120, 120 160, 60 120, 120 80, 120 119, 160 120))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (20 40, 20 200, 180 200, 180 160, 160 160, 160 120, 160 80, 180 80, 180 40, 
+        20 40), 
+        (160 120, 120 120, 120 160, 60 120, 120 80, 120 119, 160 120)), 
+      (
+        (180 120, 180 160, 200 160, 200 80, 180 80, 180 120)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - Polygon with hole with outward sliver, cut by line</desc>
+  <a>
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 40, 20 40), 
+      (180 120, 120 120, 120 160, 60 120, 120 80, 120 119, 180 120))
+  </a>
+  <b>
+    LINESTRING(160 140, 160 100)
+  </b>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 40, 20 40))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (160 140, 160 120), 
+      (160 120, 160 100))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 120, 180 40, 20 40), 
+      (160 120, 120 120, 120 160, 60 120, 120 80, 120 119, 160 120))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 120, 180 40, 20 40), 
+      (160 120, 120 120, 120 160, 60 120, 120 80, 120 119, 160 120))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 120, 180 40, 20 40), 
+      (160 120, 120 120, 120 160, 60 120, 120 80, 120 119, 160 120))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - Polygon with inward sliver touching hole, cut by polygon</desc>
+  <a>
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 120, 140 120, 180 119, 180 40, 20 40), 
+      (140 160, 80 120, 140 80, 140 160))
+  </a>
+  <b>
+    POLYGON(
+      (200 160, 150 160, 150 80, 200 80, 200 160))
+  </b>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 40, 20 40))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (180 160, 180 120, 150 120, 150 160, 180 160)), 
+      (
+        (150 120, 180 119, 180 80, 150 80, 150 120)))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 160, 200 160, 200 80, 180 80, 180 40, 20 40), 
+      (140 160, 80 120, 140 80, 140 120, 140 160))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POLYGON(
+      (20 40, 20 200, 180 200, 180 160, 150 160, 150 120, 150 80, 180 80, 180 40, 
+      20 40), 
+      (140 160, 80 120, 140 80, 140 120, 140 160))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (20 40, 20 200, 180 200, 180 160, 150 160, 150 120, 150 80, 180 80, 180 40, 
+        20 40), 
+        (140 160, 80 120, 140 80, 140 120, 140 160)), 
+      (
+        (150 120, 180 120, 180 160, 200 160, 200 80, 180 80, 180 119, 150 120)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - intersecting slivers, dimensional collapse</desc>
+  <a>
+    POLYGON(
+      (83 33, 62 402, 68 402, 83 33))
+  </a>
+  <b>
+    POLYGON(
+      (78 39, 574 76, 576 60, 78 39))
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    LINESTRING(83 33, 62 402, 68 402, 83 33)
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (83 33, 62 402, 68 402, 83 33))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POINT(83 39)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(78 39, 83 39), 
+      LINESTRING(83 33, 83 39), 
+      POLYGON(
+        (83 39, 62 402, 68 402, 83 39)), 
+      POLYGON(
+        (83 39, 574 76, 576 60, 83 39)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(83 33, 83 39), 
+      POLYGON(
+        (83 39, 62 402, 68 402, 83 39)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(78 39, 83 39), 
+      LINESTRING(83 33, 83 39), 
+      POLYGON(
+        (83 39, 62 402, 68 402, 83 39)), 
+      POLYGON(
+        (83 39, 574 76, 576 60, 83 39)))
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestFunctionLA.xml b/tests/testthat/testxml/general/TestFunctionLA.xml
new file mode 100644
index 0000000..1f2422e
--- /dev/null
+++ b/tests/testthat/testxml/general/TestFunctionLA.xml
@@ -0,0 +1,517 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>LA - A and B simple</desc>
+  <a>
+    LINESTRING(240 190, 120 120)
+  </a>
+  <b>
+    POLYGON(
+      (110 240, 50 80, 240 70, 110 240))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    LINESTRING(177 153, 120 120)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(240 190, 177 153), 
+      POLYGON(
+        (177 153, 240 70, 50 80, 110 240, 177 153)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    LINESTRING(240 190, 177 153)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(240 190, 177 153), 
+      POLYGON(
+        (177 153, 240 70, 50 80, 110 240, 177 153)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LA - A intersects B-hole</desc>
+  <a>
+    LINESTRING(0 100, 100 100, 200 200)
+  </a>
+  <b>
+    POLYGON(
+      (30 240, 260 30, 30 30, 30 240), 
+      (80 140, 80 80, 140 80, 80 140))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (30 100, 80 100), 
+      (110 110, 140 140))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(0 100, 30 100), 
+      LINESTRING(80 100, 100 100, 110 110), 
+      LINESTRING(140 140, 200 200), 
+      POLYGON(
+        (30 240, 140 140, 260 30, 30 30, 30 100, 30 240), 
+        (80 140, 80 100, 80 80, 140 80, 110 110, 80 140)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (0 100, 30 100), 
+      (80 100, 100 100, 110 110), 
+      (140 140, 200 200))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(0 100, 30 100), 
+      LINESTRING(80 100, 100 100, 110 110), 
+      LINESTRING(140 140, 200 200), 
+      POLYGON(
+        (30 240, 140 140, 260 30, 30 30, 30 100, 30 240), 
+        (80 140, 80 100, 80 80, 140 80, 110 110, 80 140)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LA - A intersects B-hole #2</desc>
+  <a>
+    LINESTRING(40 340, 200 250, 120 180, 160 110, 270 40)
+  </a>
+  <b>
+    POLYGON(
+      (160 330, 60 260, 20 150, 60 40, 190 20, 270 130, 260 250, 160 330), 
+      (140 240, 80 190, 90 100, 160 70, 210 130, 210 210, 140 240))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (114 298, 200 250, 173 226), 
+      (182 96, 225 68))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(40 340, 114 298), 
+      LINESTRING(173 226, 120 180, 160 110, 182 96), 
+      LINESTRING(225 68, 270 40), 
+      POLYGON(
+        (114 298, 160 330, 260 250, 270 130, 225 68, 190 20, 60 40, 20 150, 60 260, 
+        114 298), 
+        (140 240, 80 190, 90 100, 160 70, 182 96, 210 130, 210 210, 173 226, 140 240)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (40 340, 114 298), 
+      (173 226, 120 180, 160 110, 182 96), 
+      (225 68, 270 40))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(40 340, 114 298), 
+      LINESTRING(173 226, 120 180, 160 110, 182 96), 
+      LINESTRING(225 68, 270 40), 
+      POLYGON(
+        (114 298, 160 330, 260 250, 270 130, 225 68, 190 20, 60 40, 20 150, 60 260, 
+        114 298), 
+        (140 240, 80 190, 90 100, 160 70, 182 96, 210 130, 210 210, 173 226, 140 240)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mLmA - A and B complex, disjoint</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (60 320, 60 80, 300 80, 60 320), 
+        (80 280, 80 100, 260 100, 80 280)), 
+      (
+        (120 160, 140 160, 140 140, 120 160)))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (100 240, 100 180, 160 180, 160 120, 220 120), 
+      (40 360, 40 60, 340 60, 40 360, 40 20), 
+      (120 120, 120 140, 100 140, 100 120, 140 120))
+  </b>
+<test>
+  <op name="convexhull" pattern="FFFFFFFFF" arg1="A">
+    POLYGON(
+      (60 80, 60 320, 300 80, 60 80))
+  </op>
+</test>
+<test>
+  <op name="getboundary" pattern="FFFFFFFFF" arg1="A">
+    MULTILINESTRING(
+      (60 320, 60 80, 300 80, 60 320), 
+      (80 280, 80 100, 260 100, 80 280), 
+      (120 160, 140 160, 140 140, 120 160))
+  </op>
+</test>
+<test>
+  <op name="symdifference" pattern="FFFFFFFFF" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(100 240, 100 180, 160 180, 160 120, 220 120), 
+      LINESTRING(40 360, 40 60), 
+      LINESTRING(40 60, 340 60, 40 360), 
+      LINESTRING(40 60, 40 20), 
+      LINESTRING(120 120, 120 140, 100 140, 100 120, 120 120), 
+      LINESTRING(120 120, 140 120), 
+      POLYGON(
+        (60 320, 300 80, 60 80, 60 320), 
+        (80 280, 80 100, 260 100, 80 280)), 
+      POLYGON(
+        (120 160, 140 160, 140 140, 120 160)))
+  </op>
+</test>
+<test>
+  <op name="difference" pattern="FFFFFFFFF" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (60 320, 300 80, 60 80, 60 320), 
+        (80 280, 80 100, 260 100, 80 280)), 
+      (
+        (120 160, 140 160, 140 140, 120 160)))
+  </op>
+</test>
+<test>
+  <op name="union" pattern="FFFFFFFFF" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(100 240, 100 180, 160 180, 160 120, 220 120), 
+      LINESTRING(40 360, 40 60), 
+      LINESTRING(40 60, 340 60, 40 360), 
+      LINESTRING(40 60, 40 20), 
+      LINESTRING(120 120, 120 140, 100 140, 100 120, 120 120), 
+      LINESTRING(120 120, 140 120), 
+      POLYGON(
+        (60 320, 300 80, 60 80, 60 320), 
+        (80 280, 80 100, 260 100, 80 280)), 
+      POLYGON(
+        (120 160, 140 160, 140 140, 120 160)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mLmA - A and B complex, overlapping and touching #1</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (60 260, 60 120, 220 120, 220 260, 60 260), 
+        (80 240, 80 140, 200 140, 200 240, 80 240)), 
+      (
+        (100 220, 100 160, 180 160, 180 220, 100 220), 
+        (120 200, 120 180, 160 180, 160 200, 120 200)))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (40 260, 240 260, 240 240, 40 240, 40 220, 240 220), 
+      (120 300, 120 80, 140 80, 140 300, 140 80, 120 80, 120 320))
+  </b>
+  <test>
+    <op name="getboundary" arg1="A">
+      MULTILINESTRING(
+        (60 260, 60 120, 220 120, 220 260, 60 260), 
+        (80 240, 80 140, 200 140, 200 240, 80 240), 
+        (100 220, 100 160, 180 160, 180 220, 100 220), 
+        (120 200, 120 180, 160 180, 160 200, 120 200))
+          </op>
+  </test>
+  <test>
+    <op name="convexhull" arg1="A">
+      POLYGON(
+        (60 120, 60 260, 220 260, 220 120, 60 120))
+          </op>
+  </test>
+  <test>
+    <op name="intersection" arg1="A" arg2="B">
+      MULTILINESTRING(
+        (220 260, 140 260), 
+        (140 260, 120 260), 
+        (120 260, 60 260), 
+        (200 240, 140 240), 
+        (140 240, 120 240), 
+        (120 240, 80 240), 
+        (180 220, 140 220), 
+        (140 220, 120 220), 
+        (120 220, 100 220), 
+        (120 200, 120 180), 
+        (220 240, 200 240), 
+        (80 240, 60 240), 
+        (60 220, 80 220), 
+        (200 220, 220 220), 
+        (120 260, 120 240), 
+        (120 220, 120 200), 
+        (120 180, 120 160), 
+        (120 140, 120 120), 
+        (140 120, 140 140), 
+        (140 160, 140 180), 
+        (140 200, 140 220), 
+        (140 240, 140 260))
+          </op>
+  </test>
+  <test>
+    <op name="union" arg1="A" arg2="B">
+      GEOMETRYCOLLECTION(
+        LINESTRING(40 260, 60 260), 
+        LINESTRING(220 260, 240 260, 240 240, 220 240), 
+        LINESTRING(60 240, 40 240, 40 220, 60 220), 
+        LINESTRING(80 220, 100 220), 
+        LINESTRING(180 220, 200 220), 
+        LINESTRING(220 220, 240 220), 
+        LINESTRING(120 300, 120 260), 
+        LINESTRING(120 240, 120 220), 
+        LINESTRING(120 160, 120 140), 
+        LINESTRING(120 120, 120 80), 
+        LINESTRING(120 80, 140 80), 
+        LINESTRING(140 80, 140 120), 
+        LINESTRING(140 140, 140 160), 
+        LINESTRING(140 180, 140 200), 
+        LINESTRING(140 220, 140 240), 
+        LINESTRING(140 260, 140 300), 
+        LINESTRING(120 300, 120 320), 
+        POLYGON(
+          (60 240, 60 260, 120 260, 140 260, 220 260, 220 240, 220 220, 220 120, 140 120, 
+          120 120, 60 120, 60 220, 60 240), 
+          (80 240, 80 220, 80 140, 120 140, 140 140, 200 140, 200 220, 200 240, 140 240, 
+          120 240, 80 240)), 
+        POLYGON(
+          (120 160, 100 160, 100 220, 120 220, 140 220, 180 220, 180 160, 140 160, 120 160), 
+          (120 200, 120 180, 140 180, 160 180, 160 200, 140 200, 120 200)))
+          </op>
+  </test>
+  <test>
+    <op name="difference" arg1="A" arg2="B">
+      MULTIPOLYGON(
+        (
+          (60 240, 60 260, 120 260, 140 260, 220 260, 220 240, 220 220, 220 120, 140 120, 
+          120 120, 60 120, 60 220, 60 240), 
+          (80 240, 80 220, 80 140, 120 140, 140 140, 200 140, 200 220, 200 240, 140 240, 
+          120 240, 80 240)), 
+        (
+          (120 160, 100 160, 100 220, 120 220, 140 220, 180 220, 180 160, 140 160, 120 160), 
+          (120 200, 120 180, 140 180, 160 180, 160 200, 140 200, 120 200)))
+          </op>
+  </test>
+  <test>
+    <op name="symdifference" arg1="A" arg2="B">
+      GEOMETRYCOLLECTION(
+        LINESTRING(40 260, 60 260), 
+        LINESTRING(220 260, 240 260, 240 240, 220 240), 
+        LINESTRING(60 240, 40 240, 40 220, 60 220), 
+        LINESTRING(80 220, 100 220), 
+        LINESTRING(180 220, 200 220), 
+        LINESTRING(220 220, 240 220), 
+        LINESTRING(120 300, 120 260), 
+        LINESTRING(120 240, 120 220), 
+        LINESTRING(120 160, 120 140), 
+        LINESTRING(120 120, 120 80), 
+        LINESTRING(120 80, 140 80), 
+        LINESTRING(140 80, 140 120), 
+        LINESTRING(140 140, 140 160), 
+        LINESTRING(140 180, 140 200), 
+        LINESTRING(140 220, 140 240), 
+        LINESTRING(140 260, 140 300), 
+        LINESTRING(120 300, 120 320), 
+        POLYGON(
+          (60 240, 60 260, 120 260, 140 260, 220 260, 220 240, 220 220, 220 120, 140 120, 
+          120 120, 60 120, 60 220, 60 240), 
+          (80 240, 80 220, 80 140, 120 140, 140 140, 200 140, 200 220, 200 240, 140 240, 
+          120 240, 80 240)), 
+        POLYGON(
+          (120 160, 100 160, 100 220, 120 220, 140 220, 180 220, 180 160, 140 160, 120 160), 
+          (120 200, 120 180, 140 180, 160 180, 160 200, 140 200, 120 200)))
+          </op>
+  </test>
+</case><case>
+  <desc>mLmA - A and B complex, overlapping and touching #2</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (60 320, 60 120, 280 120, 280 320, 60 320), 
+        (120 260, 120 180, 240 180, 240 260, 120 260)), 
+      (
+        (280 400, 320 400, 320 360, 280 360, 280 400)), 
+      (
+        (300 240, 300 220, 320 220, 320 240, 300 240)))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (80 300, 80 160, 260 160, 260 300, 80 300, 80 140), 
+      (220 360, 220 240, 300 240, 300 360))
+  </b>
+<test>
+  <op name="convexhull" pattern="FFFFFFFFF" arg1="A">
+    POLYGON(
+      (60 120, 60 320, 280 400, 320 400, 320 220, 280 120, 60 120))
+  </op>
+</test>
+<test>
+  <op name="getboundary" pattern="FFFFFFFFF" arg1="A">
+    MULTILINESTRING(
+      (60 320, 60 120, 280 120, 280 320, 60 320), 
+      (120 260, 120 180, 240 180, 240 260, 120 260), 
+      (280 400, 320 400, 320 360, 280 360, 280 400), 
+      (300 240, 300 220, 320 220, 320 240, 300 240))
+  </op>
+</test>
+<test>
+  <op name="symdifference" pattern="FFFFFFFFF" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(220 360, 220 320), 
+      LINESTRING(220 260, 220 240, 240 240), 
+      LINESTRING(280 240, 300 240), 
+      LINESTRING(300 240, 300 360), 
+      POLYGON(
+        (280 240, 280 120, 60 120, 60 320, 220 320, 280 320, 280 240), 
+        (120 260, 120 180, 240 180, 240 240, 240 260, 220 260, 120 260)), 
+      POLYGON(
+        (280 400, 320 400, 320 360, 300 360, 280 360, 280 400)), 
+      POLYGON(
+        (300 240, 320 240, 320 220, 300 220, 300 240)))
+  </op>
+</test>
+<test>
+  <op name="difference" pattern="FFFFFFFFF" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (280 240, 280 120, 60 120, 60 320, 220 320, 280 320, 280 240), 
+        (120 260, 120 180, 240 180, 240 240, 240 260, 220 260, 120 260)), 
+      (
+        (280 400, 320 400, 320 360, 300 360, 280 360, 280 400)), 
+      (
+        (300 240, 320 240, 320 220, 300 220, 300 240)))
+  </op>
+</test>
+<test>
+  <op name="union" pattern="FFFFFFFFF" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(220 360, 220 320), 
+      LINESTRING(220 260, 220 240, 240 240), 
+      LINESTRING(280 240, 300 240), 
+      LINESTRING(300 240, 300 360), 
+      POLYGON(
+        (280 240, 280 120, 60 120, 60 320, 220 320, 280 320, 280 240), 
+        (120 260, 120 180, 240 180, 240 240, 240 260, 220 260, 120 260)), 
+      POLYGON(
+        (280 400, 320 400, 320 360, 300 360, 280 360, 280 400)), 
+      POLYGON(
+        (300 240, 320 240, 320 220, 300 220, 300 240)))
+  </op>
+</test>
+<test>
+  <op name="intersection" pattern="FFFFFFFFF" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(300 240), 
+      POINT(300 360), 
+      LINESTRING(80 300, 80 160), 
+      LINESTRING(80 160, 260 160, 260 240), 
+      LINESTRING(260 240, 260 300, 220 300), 
+      LINESTRING(220 300, 80 300), 
+      LINESTRING(80 160, 80 140), 
+      LINESTRING(220 320, 220 300), 
+      LINESTRING(220 300, 220 260), 
+      LINESTRING(240 240, 260 240), 
+      LINESTRING(260 240, 280 240))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mLmA - A and B complex, overlapping and touching #3</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (120 180, 60 80, 180 80, 120 180)), 
+      (
+        (100 240, 140 240, 120 220, 100 240)))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (180 260, 120 180, 60 260, 180 260), 
+      (60 300, 60 40), 
+      (100 100, 140 100))
+  </b>
+<test>
+  <op name="convexhull" pattern="FFFFFFFFF" arg1="A">
+    POLYGON(
+      (60 80, 100 240, 140 240, 180 80, 60 80))
+  </op>
+</test>
+<test>
+  <op name="getboundary" pattern="FFFFFFFFF" arg1="A">
+    MULTILINESTRING(
+      (120 180, 60 80, 180 80, 120 180), 
+      (100 240, 140 240, 120 220, 100 240))
+  </op>
+</test>
+<test>
+  <op name="symdifference" pattern="FFFFFFFFF" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(180 260, 120 180), 
+      LINESTRING(120 180, 60 260), 
+      LINESTRING(60 260, 180 260), 
+      LINESTRING(60 300, 60 260), 
+      LINESTRING(60 260, 60 80), 
+      LINESTRING(60 80, 60 40), 
+      POLYGON(
+        (60 80, 120 180, 180 80, 60 80)), 
+      POLYGON(
+        (100 240, 140 240, 120 220, 100 240)))
+  </op>
+</test>
+<test>
+  <op name="difference" pattern="FFFFFFFFF" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (60 80, 120 180, 180 80, 60 80)), 
+      (
+        (100 240, 140 240, 120 220, 100 240)))
+  </op>
+</test>
+<test>
+  <op name="union" pattern="FFFFFFFFF" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(180 260, 120 180), 
+      LINESTRING(120 180, 60 260), 
+      LINESTRING(60 260, 180 260), 
+      LINESTRING(60 300, 60 260), 
+      LINESTRING(60 260, 60 80), 
+      LINESTRING(60 80, 60 40), 
+      POLYGON(
+        (60 80, 120 180, 180 80, 60 80)), 
+      POLYGON(
+        (100 240, 140 240, 120 220, 100 240)))
+  </op>
+</test>
+<test>
+  <op name="intersection" pattern="FFFFFFFFF" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(60 80), 
+      POINT(120 180), 
+      LINESTRING(100 100, 140 100))
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestFunctionLAPrec.xml b/tests/testthat/testxml/general/TestFunctionLAPrec.xml
new file mode 100644
index 0000000..72e8426
--- /dev/null
+++ b/tests/testthat/testxml/general/TestFunctionLAPrec.xml
@@ -0,0 +1,59 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>LA - line and sliver intersecting, dimensional collapse</desc>
+  <a>
+    POLYGON(
+      (95 9, 81 414, 87 414, 95 9))
+  </a>
+  <b>
+    LINESTRING(93 13, 96 13)
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    LINESTRING(95 9, 81 414, 87 414, 95 9)
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (95 9, 81 414, 87 414, 95 9))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POINT(95 13)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(95 9, 95 13), 
+      POLYGON(
+        (95 13, 81 414, 87 414, 95 13)), 
+      LINESTRING(93 13, 95 13), 
+      LINESTRING(95 13, 96 13))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(95 9, 95 13), 
+      POLYGON(
+        (95 13, 81 414, 87 414, 95 13)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      LINESTRING(95 9, 95 13), 
+      POLYGON(
+        (95 13, 81 414, 87 414, 95 13)), 
+      LINESTRING(93 13, 95 13), 
+      LINESTRING(95 13, 96 13))
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestFunctionLL.xml b/tests/testthat/testxml/general/TestFunctionLL.xml
new file mode 100644
index 0000000..93be6f0
--- /dev/null
+++ b/tests/testthat/testxml/general/TestFunctionLL.xml
@@ -0,0 +1,355 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>LL - A crosses B</desc>
+  <a>
+    LINESTRING(0 0, 100 100)
+  </a>
+  <b>
+    LINESTRING(0 100, 100 0)
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POINT(50 50)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (0 0, 50 50), 
+      (0 100, 50 50), 
+      (50 50, 100 100), 
+      (50 50, 100 0))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (0 0, 50 50), 
+      (50 50, 100 100))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (0 0, 50 50), 
+      (0 100, 50 50), 
+      (50 50, 100 100), 
+      (50 50, 100 0))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - A shares one segment with B</desc>
+  <a>
+    LINESTRING(0 0, 100 100, 200 0)
+  </a>
+  <b>
+    LINESTRING(0 0, 100 100, 200 200)
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    LINESTRING(0 0, 100 100)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (0 0, 100 100), 
+      (100 100, 200 200), 
+      (100 100, 200 0))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    LINESTRING(100 100, 200 0)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (100 100, 200 200), 
+      (100 100, 200 0))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - A and B disjoint</desc>
+  <a>
+    LINESTRING(40 360, 40 220, 120 360)
+  </a>
+  <b>
+    LINESTRING(120 340, 60 220, 140 220, 140 360)
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(40 360, 120 360)
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (40 220, 40 360, 120 360, 40 220))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (40 360, 40 220, 120 360), 
+      (120 340, 60 220, 140 220, 140 360))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    LINESTRING(40 360, 40 220, 120 360)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (40 360, 40 220, 120 360), 
+      (120 340, 60 220, 140 220, 140 360))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - A and B intersect frequently</desc>
+  <a>
+    LINESTRING(220 240, 200 220, 60 320, 40 300, 180 200, 160 180, 20 280)
+  </a>
+  <b>
+    LINESTRING(220 240, 140 160, 120 180, 220 280, 200 300, 100 200)
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(220 240, 20 280)
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (160 180, 20 280, 60 320, 220 240, 160 180))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(113 213), 
+      POINT(133 233), 
+      POINT(137 197), 
+      POINT(153 253), 
+      POINT(157 217), 
+      POINT(177 237), 
+      LINESTRING(180 200, 160 180), 
+      LINESTRING(220 240, 200 220))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (113 213, 20 280), 
+      (133 233, 113 213), 
+      (113 213, 100 200), 
+      (137 197, 113 213), 
+      (153 253, 133 233), 
+      (153 253, 60 320, 40 300, 133 233), 
+      (133 233, 157 217), 
+      (137 197, 157 217), 
+      (160 180, 140 160, 120 180, 137 197), 
+      (160 180, 137 197), 
+      (177 237, 220 280, 200 300, 153 253), 
+      (177 237, 153 253), 
+      (157 217, 177 237), 
+      (157 217, 180 200), 
+      (180 200, 160 180), 
+      (200 220, 177 237), 
+      (200 220, 180 200), 
+      (220 240, 200 220))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (200 220, 177 237), 
+      (177 237, 153 253), 
+      (153 253, 60 320, 40 300, 133 233), 
+      (133 233, 157 217), 
+      (157 217, 180 200), 
+      (160 180, 137 197), 
+      (137 197, 113 213), 
+      (113 213, 20 280))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (200 220, 177 237), 
+      (177 237, 153 253), 
+      (153 253, 60 320, 40 300, 133 233), 
+      (133 233, 157 217), 
+      (157 217, 180 200), 
+      (160 180, 137 197), 
+      (137 197, 113 213), 
+      (113 213, 20 280), 
+      (200 220, 180 200), 
+      (160 180, 140 160, 120 180, 137 197), 
+      (137 197, 157 217), 
+      (157 217, 177 237), 
+      (177 237, 220 280, 200 300, 153 253), 
+      (153 253, 133 233), 
+      (133 233, 113 213), 
+      (113 213, 100 200))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - A and B equal</desc>
+  <a>
+    LINESTRING(80 320, 220 320, 220 160, 80 300)
+  </a>
+  <b>
+    LINESTRING(80 320, 220 320, 220 160, 80 300)
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(80 320, 80 300)
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (220 160, 80 300, 80 320, 220 320, 220 160))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (220 160, 80 300), 
+      (80 320, 220 320), 
+      (220 320, 220 160))
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (220 160, 80 300), 
+      (80 320, 220 320), 
+      (220 320, 220 160))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - A and B touch ends</desc>
+  <a>
+    LINESTRING(60 200, 60 260, 140 200)
+  </a>
+  <b>
+    LINESTRING(60 200, 60 140, 140 200)
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(60 200, 140 200)
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (60 200, 60 260, 140 200, 60 200))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOINT(60 200, 140 200)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (60 200, 60 260, 140 200), 
+      (60 200, 60 140, 140 200))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    LINESTRING(60 200, 60 260, 140 200)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (60 200, 60 260, 140 200), 
+      (60 200, 60 140, 140 200))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - intersecting rings</desc>
+  <a>
+    LINESTRING(180 200, 100 280, 20 200, 100 120, 180 200)
+  </a>
+  <b>
+    LINESTRING(100 200, 220 200, 220 80, 100 80, 100 200)
+  </b>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (100 120, 20 200, 100 280, 180 200, 100 120))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOINT(100 120, 180 200)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (100 120, 180 200), 
+      (100 120, 100 200), 
+      (180 200, 100 280, 20 200, 100 120), 
+      (180 200, 220 200, 220 80, 100 80, 100 120), 
+      (100 200, 180 200))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (100 120, 180 200), 
+      (180 200, 100 280, 20 200, 100 120))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (100 120, 180 200), 
+      (100 120, 100 200), 
+      (180 200, 100 280, 20 200, 100 120), 
+      (180 200, 220 200, 220 80, 100 80, 100 120), 
+      (100 200, 180 200))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LrL - LinearRing bug</desc>
+  <a>
+    LINEARRING(0 0, 0 5, 5 5, 5 0, 0 0)
+  </a>
+  <b>
+    LINESTRING( 2 2, 5 5)
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POINT (5 5)
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestFunctionLLPrec.xml b/tests/testthat/testxml/general/TestFunctionLLPrec.xml
new file mode 100644
index 0000000..94c8c36
--- /dev/null
+++ b/tests/testthat/testxml/general/TestFunctionLLPrec.xml
@@ -0,0 +1,29 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>LL - narrow V</desc>
+  <a>
+    LINESTRING(0 10, 620 10, 0 11)
+  </a>
+  <b>
+    LINESTRING(400 60, 400 10)
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POINT(400 10)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (0 10, 400 10), 
+      (400 10, 620 10, 400 10), 
+      (400 10, 0 11), 
+      (400 60, 400 10))
+  </op>
+</test>
+</case>
+
+</run>
+
diff --git a/tests/testthat/testxml/general/TestFunctionPA.xml b/tests/testthat/testxml/general/TestFunctionPA.xml
new file mode 100644
index 0000000..142ec93
--- /dev/null
+++ b/tests/testthat/testxml/general/TestFunctionPA.xml
@@ -0,0 +1,155 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>PA - point contained in simple polygon</desc>
+  <a>
+    POINT(100 100)
+  </a>
+  <b>
+    POLYGON(
+      (50 50, 200 50, 200 200, 50 200, 50 50))
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POINT(100 100)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPmA - points on I, B and E of touching triangles</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (120 320, 180 200, 240 320, 120 320)), 
+      (
+        (180 200, 240 80, 300 200, 180 200)))
+  </a>
+  <b>
+    MULTIPOINT(120 320, 180 260, 180 320, 180 200, 300 200, 200 220)
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTILINESTRING(
+      (120 320, 180 200, 240 320, 120 320), 
+      (180 200, 240 80, 300 200, 180 200))
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (240 80, 120 320, 240 320, 300 200, 240 80))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOINT(120 320, 180 200, 180 260, 180 320, 300 200)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(200 220), 
+      POLYGON(
+        (180 200, 120 320, 240 320, 180 200)), 
+      POLYGON(
+        (180 200, 300 200, 240 80, 180 200)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (180 200, 120 320, 240 320, 180 200)), 
+      (
+        (180 200, 300 200, 240 80, 180 200)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(200 220), 
+      POLYGON(
+        (180 200, 120 320, 240 320, 180 200)), 
+      POLYGON(
+        (180 200, 300 200, 240 80, 180 200)))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPmA - points on I, B and E of concentric doughnuts</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (120 80, 420 80, 420 340, 120 340, 120 80), 
+        (160 300, 160 120, 380 120, 380 300, 160 300)), 
+      (
+        (200 260, 200 160, 340 160, 340 260, 200 260), 
+        (240 220, 240 200, 300 200, 300 220, 240 220)))
+  </a>
+  <b>
+    MULTIPOINT(200 360, 420 340, 400 100, 340 120, 200 140, 200 160, 220 180, 260 200, 200 360, 
+    420 340, 400 100, 340 120, 200 140, 200 160, 220 180, 260 200)
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTILINESTRING(
+      (120 80, 420 80, 420 340, 120 340, 120 80), 
+      (160 300, 160 120, 380 120, 380 300, 160 300), 
+      (200 260, 200 160, 340 160, 340 260, 200 260), 
+      (240 220, 240 200, 300 200, 300 220, 240 220))
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (120 80, 120 340, 420 340, 420 80, 120 80))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOINT(200 160, 220 180, 260 200, 340 120, 400 100, 420 340)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(200 140), 
+      POINT(200 360), 
+      POLYGON(
+        (120 80, 120 340, 420 340, 420 80, 120 80), 
+        (160 300, 160 120, 380 120, 380 300, 160 300)), 
+      POLYGON(
+        (200 260, 340 260, 340 160, 200 160, 200 260), 
+        (240 220, 240 200, 300 200, 300 220, 240 220)))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTIPOLYGON(
+      (
+        (120 80, 120 340, 420 340, 420 80, 120 80), 
+        (160 300, 160 120, 380 120, 380 300, 160 300)), 
+      (
+        (200 260, 340 260, 340 160, 200 160, 200 260), 
+        (240 220, 240 200, 300 200, 300 220, 240 220)))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(200 140), 
+      POINT(200 360), 
+      POLYGON(
+        (120 80, 120 340, 420 340, 420 80, 120 80), 
+        (160 300, 160 120, 380 120, 380 300, 160 300)), 
+      POLYGON(
+        (200 260, 340 260, 340 160, 200 160, 200 260), 
+        (240 220, 240 200, 300 200, 300 220, 240 220)))
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestFunctionPL.xml b/tests/testthat/testxml/general/TestFunctionPL.xml
new file mode 100644
index 0000000..61c7659
--- /dev/null
+++ b/tests/testthat/testxml/general/TestFunctionPL.xml
@@ -0,0 +1,295 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>mPL - points in I and E of line</desc>
+  <a>
+    MULTIPOINT(40 90, 20 20, 70 70)
+  </a>
+  <b>
+    LINESTRING(20 20, 100 100)
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOINT(20 20, 70 70)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(40 90), 
+      LINESTRING(20 20, 100 100))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POINT(40 90)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(40 90), 
+      LINESTRING(20 20, 100 100))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPL - points in I and E of line, line self-intersecting</desc>
+  <a>
+    MULTIPOINT(40 90, 20 20, 70 70)
+  </a>
+  <b>
+    LINESTRING(20 20, 110 110, 170 50, 130 10, 70 70)
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOINT(20 20, 70 70)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(40 90), 
+      LINESTRING(20 20, 70 70), 
+      LINESTRING(70 70, 110 110, 170 50, 130 10, 70 70))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POINT(40 90)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(40 90), 
+      LINESTRING(20 20, 70 70), 
+      LINESTRING(70 70, 110 110, 170 50, 130 10, 70 70))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPmL - points in I, B and E of lines, lines overlap, points overlap</desc>
+  <a>
+    MULTILINESTRING(
+      (100 320, 100 220), 
+      (100 180, 200 180), 
+      (220 180, 220 320), 
+      (220 320, 160 320), 
+      (100 320, 100 220), 
+      (100 180, 200 180), 
+      (220 180, 220 320), 
+      (220 320, 160 320), 
+      (100 220, 100 320))
+  </a>
+  <b>
+    MULTIPOINT(100 320, 100 260, 100 220, 100 200, 100 180, 120 180, 200 180, 220 180, 220 260, 
+    220 320, 200 320, 160 320, 140 320, 120 320, 100 320, 100 260, 100 220, 100 200, 100 180, 
+    120 180, 200 180, 220 180, 220 260, 220 320, 200 320, 160 320, 140 320, 120 320)
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(100 220, 100 320)
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (100 180, 100 320, 220 320, 220 180, 100 180))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOINT(100 180, 100 220, 100 260, 100 320, 120 180, 160 320, 200 180, 200 320, 220 180, 
+    220 260, 220 320)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(100 200), 
+      POINT(120 320), 
+      POINT(140 320), 
+      LINESTRING(100 320, 100 220), 
+      LINESTRING(100 180, 200 180), 
+      LINESTRING(220 180, 220 320), 
+      LINESTRING(220 320, 160 320))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (100 320, 100 220), 
+      (100 180, 200 180), 
+      (220 180, 220 320), 
+      (220 320, 160 320))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(100 200), 
+      POINT(120 320), 
+      POINT(140 320), 
+      LINESTRING(100 320, 100 220), 
+      LINESTRING(100 180, 200 180), 
+      LINESTRING(220 180, 220 320), 
+      LINESTRING(220 320, 160 320))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPmL - points in I, B and E of lines, lines overlap, points overlap, x <0, y < 0</desc>
+  <a>
+    MULTILINESTRING(
+      (-500 -140, -500 -280, -320 -280, -320 -140, -500 -140, -500 -340), 
+      (-500 -140, -320 -140, -500 -140, -320 -140, -500 -140))
+  </a>
+  <b>
+    MULTIPOINT(-560 -180, -420 -180, -500 -220, -500 -340, -500 -280, -500 -140, -320 -140, -420 -140, -320 -180, 
+    -280 -140, -320 -120, -560 -180, -420 -180, -500 -220, -500 -340, -500 -280, -500 -140, -320 -140, -420 -140, 
+    -320 -180, -280 -140, -320 -120)
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(-500 -340, -500 -140)
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (-500 -340, -500 -140, -320 -140, -320 -280, -500 -340))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOINT(-500 -340, -500 -280, -500 -220, -500 -140, -420 -140, -320 -180, -320 -140)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(-560 -180), 
+      POINT(-420 -180), 
+      POINT(-320 -120), 
+      POINT(-280 -140), 
+      LINESTRING(-500 -140, -500 -280), 
+      LINESTRING(-500 -280, -320 -280, -320 -140), 
+      LINESTRING(-320 -140, -500 -140), 
+      LINESTRING(-500 -280, -500 -340))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (-500 -140, -500 -280), 
+      (-500 -280, -320 -280, -320 -140), 
+      (-320 -140, -500 -140), 
+      (-500 -280, -500 -340))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(-560 -180), 
+      POINT(-420 -180), 
+      POINT(-320 -120), 
+      POINT(-280 -140), 
+      LINESTRING(-500 -140, -500 -280), 
+      LINESTRING(-500 -280, -320 -280, -320 -140), 
+      LINESTRING(-320 -140, -500 -140), 
+      LINESTRING(-500 -280, -500 -340))
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - lines intersect at 1 point</desc>
+  <a>
+    MULTILINESTRING(
+      (180 100, 140 280, 240 140, 220 120, 140 280), 
+      (140 280, 100 400, 80 380, 140 280, 40 380, 20 360, 140 280))
+  </a>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(180 100, 140 280)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPmL - points in I, B and E of lines, lines overlap, points overlap</desc>
+  <a>
+    MULTILINESTRING(
+      (100 320, 100 220), 
+      (100 180, 200 180), 
+      (220 180, 220 320), 
+      (220 320, 160 320), 
+      (100 320, 100 220), 
+      (100 180, 200 180), 
+      (220 180, 220 320), 
+      (220 320, 160 320), 
+      (100 220, 100 320))
+  </a>
+  <b>
+    MULTIPOINT(100 320, 100 260, 100 220, 100 200, 100 180, 120 180, 200 180, 220 180, 220 260, 
+    220 320, 200 320, 160 320, 140 320, 120 320, 100 320, 100 260, 100 220, 100 200, 100 180, 
+    120 180, 200 180, 220 180, 220 260, 220 320, 200 320, 160 320, 140 320, 120 320)
+  </b>
+<test>
+  <op name="getboundary" arg1="A">
+    MULTIPOINT(100 220, 100 320)
+  </op>
+</test>
+<test>
+  <op name="convexhull" arg1="A">
+    POLYGON(
+      (100 180, 100 320, 220 320, 220 180, 100 180))
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOINT(100 180, 100 220, 100 260, 100 320, 120 180, 160 320, 200 180, 200 320, 220 180, 
+    220 260, 220 320)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(100 200), 
+      POINT(120 320), 
+      POINT(140 320), 
+      LINESTRING(100 320, 100 220), 
+      LINESTRING(100 180, 200 180), 
+      LINESTRING(220 180, 220 320), 
+      LINESTRING(220 320, 160 320))
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTILINESTRING(
+      (100 320, 100 220), 
+      (100 180, 200 180), 
+      (220 180, 220 320), 
+      (220 320, 160 320))
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    GEOMETRYCOLLECTION(
+      POINT(100 200), 
+      POINT(120 320), 
+      POINT(140 320), 
+      LINESTRING(100 320, 100 220), 
+      LINESTRING(100 180, 200 180), 
+      LINESTRING(220 180, 220 320), 
+      LINESTRING(220 320, 160 320))
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestFunctionPLPrec.xml b/tests/testthat/testxml/general/TestFunctionPLPrec.xml
new file mode 100644
index 0000000..1477a84
--- /dev/null
+++ b/tests/testthat/testxml/general/TestFunctionPLPrec.xml
@@ -0,0 +1,19 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>PP - Point just off line. Causes non-robust algorithms to fail.</desc>
+  <a>
+    LINESTRING(-123456789 -40, 381039468754763 123456789)
+  </a>
+  <b>
+    POINT(0 0)
+  </b>
+<test>
+  <op name="intersects" arg1="A" arg2="B">
+    false
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestFunctionPP.xml b/tests/testthat/testxml/general/TestFunctionPP.xml
new file mode 100644
index 0000000..80b69b3
--- /dev/null
+++ b/tests/testthat/testxml/general/TestFunctionPP.xml
@@ -0,0 +1,214 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>PP - point contained in both A and B</desc>
+  <a>
+    POINT(100 100)
+  </a>
+  <b>
+    POINT(100 100)
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POINT(100 100)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>PP - A different from B</desc>
+  <a>
+    POINT(100 100)
+  </a>
+  <b>
+    POINT(200 200)
+  </b>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOINT(100 100, 200 200)
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POINT(100 100)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOINT(100 100, 200 200)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>PmP - point in A contained in B</desc>
+  <a>
+    POINT(100 100)
+  </a>
+  <b>
+    MULTIPOINT(100 100, 200 200)
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POINT(100 100)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOINT(100 100, 200 200)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    POINT(200 200)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPmP - points in A only, B only, and in both</desc>
+  <a>
+    MULTIPOINT(100 100, 200 200, 300 300, 500 500)
+  </a>
+  <b>
+    MULTIPOINT(100 100, 200 200, 400 400, 600 600)
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    MULTIPOINT(100 100, 200 200)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOINT(100 100, 200 200, 300 300, 400 400, 500 500, 600 600)
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    MULTIPOINT(300 300, 500 500)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOINT(300 300, 400 400, 500 500, 600 600)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>PP - point contained in both A and B</desc>
+  <a>
+    POINT(80 200)
+  </a>
+  <b>
+    POINT(80 200)
+  </b>
+<test>
+  <op name="convexhull" arg1="A">
+    POINT(80 200)
+  </op>
+</test>
+<test>
+  <op name="intersection" arg1="A" arg2="B">
+    POINT(80 200)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    POINT(80 200)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>PP - A different from B</desc>
+  <a>
+    POINT(80 200)
+  </a>
+  <b>
+    POINT(260 80)
+  </b>
+<test>
+  <op name="convexhull" arg1="A">
+    POINT(80 200)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOINT(80 200, 260 80)
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POINT(80 200)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOINT(80 200, 260 80)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>PP - A different from B, same y</desc>
+  <a>
+    POINT(60 260)
+  </a>
+  <b>
+    POINT(120 260)
+  </b>
+<test>
+  <op name="convexhull" arg1="A">
+    POINT(60 260)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOINT(60 260, 120 260)
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POINT(60 260)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOINT(60 260, 120 260)
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>PP - A different from B, same x</desc>
+  <a>
+    POINT(80 80)
+  </a>
+  <b>
+    POINT(80 280)
+  </b>
+<test>
+  <op name="convexhull" arg1="A">
+    POINT(80 80)
+  </op>
+</test>
+<test>
+  <op name="union" arg1="A" arg2="B">
+    MULTIPOINT(80 80, 80 280)
+  </op>
+</test>
+<test>
+  <op name="difference" arg1="A" arg2="B">
+    POINT(80 80)
+  </op>
+</test>
+<test>
+  <op name="symdifference" arg1="A" arg2="B">
+    MULTIPOINT(80 80, 80 280)
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestInteriorPoint.xml b/tests/testthat/testxml/general/TestInteriorPoint.xml
new file mode 100644
index 0000000..69ec87b
--- /dev/null
+++ b/tests/testthat/testxml/general/TestInteriorPoint.xml
@@ -0,0 +1,56 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>P - single point</desc>
+  <a>    POINT(10 10)  </a>
+<test><op name="getInteriorPoint" arg1="A" >    POINT(10 10)   </op></test>
+</case>
+
+<case>
+  <desc>P - single point</desc>
+  <a>    MULTIPOINT (60 300, 200 200, 240 240, 200 300, 40 140, 80 240, 140 240, 100 160, 140 200, 60 200)
+	</a>
+<test><op name="getInteriorPoint" arg1="A" >    POINT (140 240)   </op></test>
+</case>
+
+<case>
+  <desc>L - linestring with single segment</desc>
+  <a>    LINESTRING (0 0, 7 14)
+	</a>
+<test><op name="getInteriorPoint" arg1="A" >   POINT (7 14)   </op></test>
+</case>
+
+<case>
+  <desc>L - linestring with multiple segments </desc>
+  <a>    LINESTRING (0 0, 3 15, 6 2, 11 14, 16 5, 16 18, 2 22)
+	</a>
+<test><op name="getInteriorPoint" arg1="A" >   POINT (11 14)  </op></test>
+</case>
+
+<case>
+  <desc>mL - complex linestrings</desc>
+  <a>    MULTILINESTRING ((60 240, 140 300, 180 200, 40 140, 100 100, 120 220), 
+  (240 80, 260 160, 200 240, 180 340, 280 340, 240 180, 180 140, 40 200, 140 260))
+	</a>
+<test><op name="getInteriorPoint" arg1="A" >    POINT (180 200)   </op></test>
+</case>
+
+<case>
+  <desc>A - box</desc>
+  <a>    POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))
+	</a>
+<test><op name="getInteriorPoint" arg1="A" >    POINT (5 5)   </op></test>
+</case>
+
+
+<case>
+  <desc>mA - polygons with holes</desc>
+  <a>    MULTIPOLYGON (((50 260, 240 340, 260 100, 20 60, 90 140, 50 260), (200 280, 140 240, 180 160, 240 140, 200 280)), ((380 280, 300 260, 340 100, 440 80, 380 280), (380 220, 340 200, 400 100, 380 220)))
+	</a>
+<test><op name="getInteriorPoint" arg1="A" >    POINT (115 200)  </op></test>
+</case>
+
+
+
+</run>
diff --git a/tests/testthat/testxml/general/TestRectanglePredicate.xml b/tests/testthat/testxml/general/TestRectanglePredicate.xml
new file mode 100644
index 0000000..651dff3
--- /dev/null
+++ b/tests/testthat/testxml/general/TestRectanglePredicate.xml
@@ -0,0 +1,121 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>A disjoint</desc>
+  <a>
+    POLYGON(
+      (0 0, 80 0, 80 80, 0 80, 0 0))
+  </a>
+  <b>
+    POLYGON(
+      (100 200, 100 140, 180 140, 180 200, 100 200))
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   false   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   false   </op> </test>
+</case>
+
+<case>
+  <desc>A contained in rectangle</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    POLYGON((10 10, 10 90, 90 90, 90 10, 10 10))
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   true   </op> </test>
+</case>
+
+<case>
+  <desc>A containing rectangle</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    POLYGON ((60 180, -100 120, -140 60, -40 20, -100 -80, 40 -20, 140 -100, 140 40, 260 160, 80 120, 60 180))
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   false   </op> </test>
+</case>
+
+<case>
+  <desc>mA containing rectangle</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+	MULTIPOLYGON (((-60 180, -60 -60, 40 -20, 140 -100, 180 120, -20 140, -60 180)), 
+  	((20 280, 0 180, 180 160, 200 280, 20 280)))
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   false   </op> </test>
+<test>  <op name="within" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="covers" arg1="A" arg2="B">   false   </op> </test>
+<test>  <op name="coveredBy" arg1="A" arg2="B">   true   </op> </test>
+</case>
+
+<case>
+  <desc>L overlaps thru Y axis side</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    LINESTRING(10 10, 200 10)
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+</case>
+
+<case>
+  <desc>L overlaps thru X axis side</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    LINESTRING(10 10, 10 2000)
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   false   </op> </test>
+<test>  <op name="covers" arg1="A" arg2="B">   false   </op> </test>
+</case>
+
+<case>
+  <desc>L line intersection</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    LINESTRING( 10 10, -10 -20 )
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="covers" arg1="A" arg2="B">   false   </op> </test>
+</case>
+
+<case>
+  <desc>L in polygon boundary</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    LINESTRING( 10 0, 90 0 )
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   false   </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>
+
+<case>
+  <desc>mL with one component contained</desc>
+  <a>
+    POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
+  </a>
+  <b>
+    MULTILINESTRING( (10 10, 10 20), (200 10, 200 20) )
+  </b>
+<test>  <op name="intersects" arg1="A" arg2="B">   true   </op> </test>
+<test>  <op name="contains" arg1="A" arg2="B">   false   </op> </test>
+</case>
+
+
+</run>
diff --git a/tests/testthat/testxml/general/TestRelateAA.xml b/tests/testthat/testxml/general/TestRelateAA.xml
new file mode 100644
index 0000000..5f27e26
--- /dev/null
+++ b/tests/testthat/testxml/general/TestRelateAA.xml
@@ -0,0 +1,221 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>AA disjoint</desc>
+  <a>
+    POLYGON(
+      (0 0, 80 0, 80 80, 0 80, 0 0))
+  </a>
+  <b>
+    POLYGON(
+      (100 200, 100 140, 180 140, 180 200, 100 200))
+  </b>
+<test>
+  <op name="relate" arg3="FF2FF1212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA equal but opposite orientation</desc>
+  <a>
+    POLYGON(
+      (0 0, 140 0, 140 140, 0 140, 0 0))
+  </a>
+  <b>
+    POLYGON(
+      (140 0, 0 0, 0 140, 140 140, 140 0))
+  </b>
+<test>
+  <op name="relate" arg3="2FFF1FFF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA A-shell contains B-shell</desc>
+  <a>
+    POLYGON(
+      (40 60, 360 60, 360 300, 40 300, 40 60))
+  </a>
+  <b>
+    POLYGON(
+      (120 100, 280 100, 280 240, 120 240, 120 100))
+  </b>
+<test>
+  <op name="relate" arg3="212FF1FF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA A-shell contains B-shell contains A-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(
+      (80 100, 360 100, 360 280, 80 280, 80 100))
+  </b>
+<test>
+  <op name="relate" arg3="2121F12F2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA A-shell contains B-shell contains A-hole contains B-hole</desc>
+  <a>
+    POLYGON(
+      (0 280, 0 0, 260 0, 260 280, 0 280), 
+      (220 240, 40 240, 40 40, 220 40, 220 240))
+  </a>
+  <b>
+    POLYGON(
+      (20 260, 240 260, 240 20, 20 20, 20 260), 
+      (160 180, 80 180, 120 120, 160 180))
+  </b>
+<test>
+  <op name="relate" arg3="2121F1212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA A-shell overlapping B-shell</desc>
+  <a>
+    POLYGON(
+      (60 80, 200 80, 200 220, 60 220, 60 80))
+  </a>
+  <b>
+    POLYGON(
+      (120 140, 260 140, 260 260, 120 260, 120 140))
+  </b>
+<test>
+  <op name="relate" arg3="212101212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA A-shell overlapping B-shell at B-vertex</desc>
+  <a>
+    POLYGON(
+      (60 220, 220 220, 140 140, 60 220))
+  </a>
+  <b>
+    POLYGON(
+      (100 180, 180 180, 180 100, 100 100, 100 180))
+  </b>
+<test>
+  <op name="relate" arg3="212101212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA A-shell overlapping B-shell at A & B-vertex</desc>
+  <a>
+    POLYGON(
+      (40 40, 180 40, 180 180, 40 180, 40 40))
+  </a>
+  <b>
+    POLYGON(
+      (180 40, 40 180, 160 280, 300 140, 180 40))
+  </b>
+<test>
+  <op name="relate" arg3="212101212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AmA A-shells overlapping B-shell at A-vertex</desc>
+  <a>
+    POLYGON(
+      (100 60, 140 100, 100 140, 60 100, 100 60))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (80 40, 120 40, 120 80, 80 80, 80 40)), 
+      (
+        (120 80, 160 80, 160 120, 120 120, 120 80)), 
+      (
+        (80 120, 120 120, 120 160, 80 160, 80 120)), 
+      (
+        (40 80, 80 80, 80 120, 40 120, 40 80)))
+  </b>
+<test>
+  <op name="relate" arg3="21210F212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA A-shell touches B-shell, which contains A-hole</desc>
+  <a>
+    POLYGON(
+      (40 280, 200 280, 200 100, 40 100, 40 280), 
+      (100 220, 120 220, 120 200, 100 180, 100 220))
+  </a>
+  <b>
+    POLYGON(
+      (40 280, 180 260, 180 120, 60 120, 40 280))
+  </b>
+<test>
+  <op name="relate" arg3="2121012F2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - A-hole contains B, boundaries touch in line</desc>
+  <a>
+    POLYGON(
+      (0 200, 0 0, 200 0, 200 200, 0 200), 
+      (20 180, 130 180, 130 30, 20 30, 20 180))
+  </a>
+  <b>
+    POLYGON(
+      (60 90, 130 90, 130 30, 60 30, 60 90))
+  </b>
+<test>
+  <op name="relate" arg3="FF2F11212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - A-hole contains B, boundaries touch in points</desc>
+  <a>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </a>
+  <b>
+    POLYGON(
+      (270 90, 200 50, 150 80, 210 120, 270 90))
+  </b>
+<test>
+  <op name="relate" arg3="FF2F01212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestRelateAC.xml b/tests/testthat/testxml/general/TestRelateAC.xml
new file mode 100644
index 0000000..7c8d954
--- /dev/null
+++ b/tests/testthat/testxml/general/TestRelateAC.xml
@@ -0,0 +1,28 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>AC A-shells overlapping B-shell at A-vertex</desc>
+  <a>
+    POLYGON(
+      (100 60, 140 100, 100 140, 60 100, 100 60))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (80 40, 120 40, 120 80, 80 80, 80 40)), 
+      (
+        (120 80, 160 80, 160 120, 120 120, 120 80)), 
+      (
+        (80 120, 120 120, 120 160, 80 160, 80 120)), 
+      (
+        (40 80, 80 80, 80 120, 40 120, 40 80)))
+  </b>
+<test>
+  <op name="relate" arg3="21210F212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestRelateLA.xml b/tests/testthat/testxml/general/TestRelateLA.xml
new file mode 100644
index 0000000..fed9d08
--- /dev/null
+++ b/tests/testthat/testxml/general/TestRelateLA.xml
@@ -0,0 +1,190 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>LA - intersection at NV: {A-Bdy, A-Int} = {B-Bdy, B-Int}</desc>
+  <a>
+    LINESTRING(100 120, 100 240)
+  </a>
+  <b>
+    POLYGON(
+      (40 60, 160 60, 160 180, 40 180, 40 60))
+  </b>
+<test>
+  <op name="relate" arg3="1010F0212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LA - intersection at V: {A-Bdy, A-Int} = {B-Bdy, B-Int}</desc>
+  <a>
+    LINESTRING(80 80, 140 140, 200 200)
+  </a>
+  <b>
+    POLYGON(
+      (40 40, 140 40, 140 140, 40 140, 40 40))
+  </b>
+<test>
+  <op name="relate" arg3="1010F0212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LmA - intersection at NV, L contained in A</desc>
+  <a>
+    LINESTRING(70 50, 70 150)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (0 0, 0 100, 140 100, 140 0, 0 0)), 
+      (
+        (20 170, 70 100, 130 170, 20 170)))
+  </b>
+<test>
+  <op name="relate" arg3="10F0FF212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LA - A crosses B at {shell-NV, hole-V}</desc>
+  <a>
+    LINESTRING(60 160, 150 70)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (110 110, 250 100, 140 30, 110 110))
+  </b>
+<test>
+  <op name="relate" arg3="F01FF0212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LA - A intersects B at {shell-NV}, B-Int, {hole-V}</desc>
+  <a>
+    LINESTRING(60 160, 150 70)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (111 110, 250 100, 140 30, 111 110))
+  </b>
+<test>
+  <op name="relate" arg3="101FF0212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LA - A crosses B hole at {hole1-V, hole2-NV}</desc>
+  <a>
+    LINESTRING(80 110, 170 110)
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 20 20, 240 20, 240 200, 20 200), 
+      (130 110, 60 40, 60 180, 130 110), 
+      (130 180, 130 40, 200 110, 130 180))
+  </b>
+<test>
+  <op name="relate" arg3="F01FF0212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LA - A crosses B hole at {hole1-V}, B-Int, {hole2-NV}</desc>
+  <a>
+    LINESTRING(80 110, 170 110)
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 20 20, 240 20, 240 200, 20 200), 
+      (130 110, 60 40, 60 180, 130 110), 
+      (130 180, 131 40, 200 110, 130 180))
+  </b>
+<test>
+  <op name="relate" arg3="101FF0212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+<desc>LA - Line with endpoints in interior but crossing exterior of multipolygon</desc>
+  <a>
+    LINESTRING(160 70, 320 230)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (140 110, 260 110, 170 20, 50 20, 140 110)), 
+      (
+        (300 270, 420 270, 340 190, 220 190, 300 270)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LA - Line with a very small piece in the exterior between parts of a multipolygon</desc>
+  <a>
+    LINESTRING(100 140, 100 40)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 80, 180 79, 100 0, 20 80)), 
+      (
+        (20 160, 180 160, 100 80, 20 160)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LA - Line contained completely and spanning parts of multipolygon</desc>
+  <a>
+    LINESTRING(100 140, 100 40)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 80, 180 80, 100 0, 20 80)), 
+      (
+        (20 160, 180 160, 100 80, 20 160)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="10F0FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LA - overlapping ring and triangle</desc>
+  <a>
+    LINESTRING(110 60, 20 150, 200 150, 110 60)
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 200 20, 110 110, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FFF212">true</op>
+  </test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestRelateLC.xml b/tests/testthat/testxml/general/TestRelateLC.xml
new file mode 100644
index 0000000..d01c26e
--- /dev/null
+++ b/tests/testthat/testxml/general/TestRelateLC.xml
@@ -0,0 +1,79 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>LC - topographically equal with no boundary</desc>
+  <a>
+    LINESTRING(0 0, 0 50, 50 50, 50 0, 0 0)
+  </a>
+  <b>
+    MULTILINESTRING(
+      (0 0, 0 50), 
+      (0 50, 50 50), 
+      (50 50, 50 0), 
+      (50 0, 0 0))
+  </b>
+<test>
+  <op name="relate" arg3="1FFFFFFF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LC - intersection (containment) along mod-2 A-Int line segment</desc>
+  <a>
+    LINESTRING(40 180, 140 180)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 320, 180 320, 180 180, 20 180, 20 320)), 
+      (
+        (20 180, 20 80, 180 80, 180 180, 20 180)))
+  </b>
+<test>
+  <op name="relate" arg3="1FF0FF212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LC - intersection (overlap) along mod-2 A-Int line segment</desc>
+  <a>
+    LINESTRING(40 180, 140 180)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 320, 180 320, 180 180, 20 180, 20 320)), 
+      (
+        (60 180, 60 80, 180 80, 180 180, 60 180)))
+  </b>
+<test>
+  <op name="relate" arg3="11F00F212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LC - equal with boundary intersection</desc>
+  <a>
+    LINESTRING(0 0, 60 0, 60 60, 60 0, 120 0)
+  </a>
+  <b>
+    MULTILINESTRING(
+      (0 0, 60 0), 
+      (60 0, 120 0), 
+      (60 0, 60 60))
+  </b>
+<test>
+  <op name="relate" arg3="10FF0FFF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestRelateLL.xml b/tests/testthat/testxml/general/TestRelateLL.xml
new file mode 100644
index 0000000..6fe267b
--- /dev/null
+++ b/tests/testthat/testxml/general/TestRelateLL.xml
@@ -0,0 +1,311 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>LL - disjoint, non-overlapping envelopes</desc>
+  <a>
+    LINESTRING(60 0, 20 80, 100 80, 80 120, 40 140)
+  </a>
+  <b>
+    LINESTRING(140 300, 220 160, 260 200, 240 260)
+  </b>
+<test>
+  <op name="relate" arg3="FF1FF0102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - disjoint, overlapping envelopes</desc>
+  <a>
+    LINESTRING(60 0, 20 80, 100 80, 80 120, 40 140)
+  </a>
+  <b>
+    LINESTRING(60 40, 140 40, 140 160, 0 160)
+  </b>
+<test>
+  <op name="relate" arg3="FF1FF0102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - disjoint, non-overlapping envelopes, B closed</desc>
+  <a>
+    LINESTRING(60 0, 20 80, 100 80, 80 120, 40 140)
+  </a>
+  <b>
+    LINESTRING(140 280, 240 280, 240 180, 140 180, 140 280)
+  </b>
+<test>
+  <op name="relate" arg3="FF1FF01F2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - disjoint, overlapping envelopes, B closed</desc>
+  <a>
+    LINESTRING(140 0, 0 0, 40 60, 0 120, 60 200, 220 160, 220 40)
+  </a>
+  <b>
+    LINESTRING(80 140, 180 100, 160 40, 100 40, 60 100, 80 140)
+  </b>
+<test>
+  <op name="relate" arg3="FF1FF01F2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Line vs line - pointwise equal</desc>
+  <a>
+    LINESTRING(20 20, 80 80)
+  </a>
+  <b>
+    LINESTRING(20 20, 80 80)
+  </b>
+<test>
+  <op name="relate" arg3="1FFF0FFF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Line vs line - pointwise equal</desc>
+  <a>
+    LINESTRING(40 40, 160 160, 200 60, 60 140)
+  </a>
+  <b>
+    LINESTRING(40 40, 160 160, 200 60, 60 140)
+  </b>
+<test>
+  <op name="relate" arg3="1FFF0FFF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>Line vs line - topologically equal</desc>
+  <a>
+    LINESTRING(40 40, 200 40)
+  </a>
+  <b>
+    LINESTRING(200 40, 140 40, 40 40)
+  </b>
+<test>
+  <op name="relate" arg3="1FFF0FFF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - topographically equal with self-intersection</desc>
+  <a>
+    LINESTRING(0 0, 110 0, 60 0)
+  </a>
+  <b>
+    LINESTRING(0 0, 110 0)
+  </b>
+<test>
+  <op name="relate" arg3="10F00FFF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LmL - topographically equal with no boundary</desc>
+  <a>
+    LINESTRING(0 0, 0 50, 50 50, 50 0, 0 0)
+  </a>
+  <b>
+    MULTILINESTRING(
+      (0 0, 0 50), 
+      (0 50, 50 50), 
+      (50 50, 50 0), 
+      (50 0, 0 0))
+  </b>
+<test>
+  <op name="relate" arg3="1FFFFFFF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LmL - topographically equal with self intersections</desc>
+  <a>
+    LINESTRING(0 0, 80 0, 80 60, 80 0, 170 0)
+  </a>
+  <b>
+    MULTILINESTRING(
+      (0 0, 170 0), 
+      (80 0, 80 60))
+  </b>
+<test>
+  <op name="relate" arg3="10FF0FFF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - A-IntNV = B-IntNV</desc>
+  <a>
+    LINESTRING(80 100, 180 200)
+  </a>
+  <b>
+    LINESTRING(80 180, 180 120)
+  </b>
+<test>
+  <op name="relate" arg3="0F1FF0102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>intersect in Int NV</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 160 160)
+  </a>
+  <b>
+    LINESTRING(160 60, 100 100, 60 140)
+  </b>
+<test>
+  <op name="relate" arg3="0F1FF0102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - intersection: {A-Bdy, A-IntV} = B-IntNV</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 180 100, 180 180, 100 180, 100 100)
+  </a>
+  <b>
+    LINESTRING(140 60, 60 140)
+  </b>
+<test>
+  <op name="relate" arg3="FF10F0102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - intersection: {A-Bdy, A-IntNV} = B-IntNV</desc>
+  <a>
+    LINESTRING(40 40, 180 180, 100 180, 100 100)
+  </a>
+  <b>
+    LINESTRING(140 60, 60 140)
+  </b>
+<test>
+  <op name="relate" arg3="FF10F0102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - intersection: A-IntNV = {B-Bdy, B-IntNV}</desc>
+  <a>
+    LINESTRING(20 110, 200 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </b>
+<test>
+  <op name="relate" arg3="F01FF0102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - one segment overlapping, one distinct</desc>
+  <a>
+    LINESTRING(80 90, 50 50, 0 0)
+  </a>
+  <b>
+    LINESTRING(0 0, 100 100)
+  </b>
+<test>
+  <op name="relate" arg3="1F1F00102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - A contained in B</desc>
+  <a>
+    LINESTRING(40 140, 240 140)
+  </a>
+  <b>
+    LINESTRING(40 140, 100 140, 80 80, 120 60, 100 140, 160 140, 160 100, 200 100, 160 140, 
+    240 140)
+  </b>
+<test>
+  <op name="relate" arg3="1FFF0F1F2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - simple overlapping lines</desc>
+  <a>
+    LINESTRING(20 20, 100 20, 20 20)
+  </a>
+  <b>
+    LINESTRING(60 20, 200 20)
+  </b>
+<test>
+  <op name="relate" arg3="101FFF102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>LL - A-spiral, B-contained</desc>
+  <a>
+    LINESTRING(40 60, 180 60, 180 140, 100 140, 100 60, 220 60, 220 180, 80 180, 80 60, 
+    280 60)
+  </a>
+  <b>
+    LINESTRING(140 60, 180 60, 220 60, 260 60)
+  </b>
+<test>
+  <op name="relate" arg3="101FF0FF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+<desc>test for LinearRing point location bug</desc>
+  <a>
+    LINEARRING(0 0, 0 5, 5 5, 5 0, 0 0)
+  </a>
+  <b>
+    LINESTRING( 2 2, 4 4)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1FFF102">true</op>
+  </test>
+</case>
+
+
+</run>
diff --git a/tests/testthat/testxml/general/TestRelatePA.xml b/tests/testthat/testxml/general/TestRelatePA.xml
new file mode 100644
index 0000000..e48b63a
--- /dev/null
+++ b/tests/testthat/testxml/general/TestRelatePA.xml
@@ -0,0 +1,103 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>PA - disjoint</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+<test>
+  <op name="relate" arg3="FF0FFF212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPA - points in B: E, I</desc>
+  <a>
+    MULTIPOINT(0 20, 40 20)
+  </a>
+  <b>
+    POLYGON(
+      (20 40, 20 0, 60 0, 60 40, 20 40))
+  </b>
+<test>
+  <op name="relate" arg3="0F0FFF212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPA - points in B: E, B</desc>
+  <a>
+    MULTIPOINT(0 20, 20 20)
+  </a>
+  <b>
+    POLYGON(
+      (20 40, 20 0, 60 0, 60 40, 20 40))
+  </b>
+<test>
+  <op name="relate" arg3="F00FFF212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPA - points in B: B, I</desc>
+  <a>
+    MULTIPOINT(20 20, 40 20)
+  </a>
+  <b>
+    POLYGON(
+      (20 40, 20 0, 60 0, 60 40, 20 40))
+  </b>
+<test>
+  <op name="relate" arg3="00FFFF212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPA - points in B: I, B, E</desc>
+  <a>
+    MULTIPOINT(80 260, 140 260, 180 260)
+  </a>
+  <b>
+    POLYGON(
+      (40 320, 140 320, 140 200, 40 200, 40 320))
+  </b>
+<test>
+  <op name="relate" arg3="000FFF212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>PmA - point in B: mod-2 I</desc>
+  <a>
+    POINT(40 40)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (0 40, 0 0, 40 0, 40 40, 0 40)), 
+      (
+        (40 80, 40 40, 80 40, 80 80, 40 80)))
+  </b>
+<test>
+  <op name="relate" arg3="F0FFFF212" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestRelatePL.xml b/tests/testthat/testxml/general/TestRelatePL.xml
new file mode 100644
index 0000000..17bf4ec
--- /dev/null
+++ b/tests/testthat/testxml/general/TestRelatePL.xml
@@ -0,0 +1,124 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>PL - disjoint</desc>
+  <a>
+    POINT(60 120)
+  </a>
+  <b>
+    LINESTRING(40 40, 120 120, 200 120)
+  </b>
+<test>
+  <op name="relate" arg3="FF0FFF102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>PL - touches Bdy</desc>
+  <a>
+    POINT(40 40)
+  </a>
+  <b>
+    LINESTRING(40 40, 100 100, 160 100)
+  </b>
+<test>
+  <op name="relate" arg3="F0FFFF102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>PL - touches non-vertex</desc>
+  <a>
+    POINT(60 60)
+  </a>
+  <b>
+    LINESTRING(40 40, 100 100)
+  </b>
+<test>
+  <op name="relate" arg3="0FFFFF102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPL - touches Bdy and Ext</desc>
+  <a>
+    MULTIPOINT(40 40, 100 40)
+  </a>
+  <b>
+    LINESTRING(40 40, 80 80)
+  </b>
+<test>
+  <op name="relate" arg3="F00FFF102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPL - touches Int and Bdy</desc>
+  <a>
+    MULTIPOINT(40 40, 60 60)
+  </a>
+  <b>
+    LINESTRING(40 40, 80 80)
+  </b>
+<test>
+  <op name="relate" arg3="00FFFF102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPL - touches Int and Ext</desc>
+  <a>
+    MULTIPOINT(60 60, 100 100)
+  </a>
+  <b>
+    LINESTRING(40 40, 80 80)
+  </b>
+<test>
+  <op name="relate" arg3="0F0FFF102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPL - touches IntNV and Ext</desc>
+  <a>
+    MULTIPOINT(60 60, 100 100)
+  </a>
+  <b>
+    LINESTRING(40 40, 80 80)
+  </b>
+<test>
+  <op name="relate" arg3="0F0FFF102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mPL - touches IntV and Ext</desc>
+  <a>
+    MULTIPOINT(60 60, 100 100)
+  </a>
+  <b>
+    LINESTRING(40 40, 60 60, 80 80)
+  </b>
+<test>
+  <op name="relate" arg3="0F0FFF102" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestRelatePP.xml b/tests/testthat/testxml/general/TestRelatePP.xml
new file mode 100644
index 0000000..5f4e848
--- /dev/null
+++ b/tests/testthat/testxml/general/TestRelatePP.xml
@@ -0,0 +1,64 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>same point</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    POINT(20 20)
+  </b>
+<test>
+  <op name="relate" arg3="0FFFFFFF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>different point</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    POINT(20 30)
+  </b>
+<test>
+  <op name="relate" arg3="FF0FFF0F2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>some same, some different points</desc>
+  <a>
+    MULTIPOINT(40 40, 80 60, 40 100)
+  </a>
+  <b>
+    MULTIPOINT(40 40, 80 60, 120 100)
+  </b>
+<test>
+  <op name="relate" arg3="0F0FFF0F2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>same points</desc>
+  <a>
+    MULTIPOINT(40 40, 80 60, 120 100)
+  </a>
+  <b>
+    MULTIPOINT(40 40, 80 60, 120 100)
+  </b>
+<test>
+  <op name="relate" arg3="0FFFFFFF2" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestSimple.xml b/tests/testthat/testxml/general/TestSimple.xml
new file mode 100644
index 0000000..68b1ded
--- /dev/null
+++ b/tests/testthat/testxml/general/TestSimple.xml
@@ -0,0 +1,259 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>P - point</desc>
+  <a>
+    POINT(10 10)
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mP - multipoint with repeated points</desc>
+  <a>
+    MULTIPOINT (80 280, 80 220, 160 220, 80 220)
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    false
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mP - multipoint with no repeated points</desc>
+  <a>
+    MULTIPOINT (80 280, 80 220, 160 220)
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>L - simple line</desc>
+  <a>
+    LINESTRING(10 10, 20 20)
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>L - non-simple, proper interior intersection</desc>
+  <a>
+    LINESTRING (20 60, 160 60, 80 160, 80 20)
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    false
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>L - non-simple, interior intersection at vertices</desc>
+  <a>
+    LINESTRING (20 80, 80 20, 80 80, 140 60, 80 20, 160 20)
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    false
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>L - non-simple, interior intersection at Bdy/non-vertex</desc>
+  <a>
+    LINESTRING (20 60, 100 60, 60 100, 60 60)
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    false
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>L - non-simple, interior intersection at Bdy/vertex</desc>
+  <a>
+    LINESTRING (20 60, 60 60, 100 60, 60 100, 60 60)
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    false
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>L - simple, intersection at Bdy/Bdy (ring)</desc>
+  <a>
+    LINESTRING (20 20, 80 20, 80 80, 20 20)
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>L - simple, intersection at Bdy/Bdy + non-vertex</desc>
+  <a>
+    LINESTRING (80 80, 20 20, 20 80, 140 80, 140 140, 80 80)
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    false
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - intersection between elements at non-vertex</desc>
+  <a>
+    MULTILINESTRING(
+  (40 140, 160 40), 
+  (160 140, 40 40))
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    false
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - no intersection between elements</desc>
+  <a>
+    MULTILINESTRING(
+  (20 160, 20 20), 
+  (100 160, 100 20))
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - mutual intersection at endpoints only</desc>
+  <a>
+    MULTILINESTRING ((60 140, 20 80, 60 40), 
+  (60 40, 100 80, 60 140))
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - one element is non-simple</desc>
+  <a>
+    MULTILINESTRING ((60 40, 140 40, 100 120, 100 0), 
+  (100 200, 200 120))
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    false
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - proper intersection between elements at vertex</desc>
+  <a>
+    MULTILINESTRING ((40 120, 100 60), 
+  (160 120, 100 60), 
+  (40 60, 160 60))
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    false
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - intersection between closed lines</desc>
+  <a>
+    MULTILINESTRING ((80 160, 40 220, 40 100, 80 160), 
+  (80 160, 120 220, 120 100, 80 160))
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    false
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mL - intersection between closed and open lines</desc>
+  <a>
+    MULTILINESTRING ((80 160, 40 220), 
+  (80 160, 120 220, 120 100, 80 160), 
+  (40 100, 80 160))
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    false
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>A</desc>
+  <a>
+    POLYGON ((180 260, 80 300, 40 180, 160 120, 180 260))
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mA</desc>
+  <a>
+    MULTIPOLYGON (((240 160, 140 220, 80 60, 220 40, 240 160)), 
+  ((160 380, 100 240, 20 380, 160 380), 
+    (120 340, 60 360, 80 320, 120 340)))
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    true
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>mA - with touching elements</desc>
+  <a>
+    MULTIPOLYGON (((240 160, 100 240, 80 60, 220 40, 240 160)), 
+  ((160 380, 100 240, 20 380, 160 380), 
+    (120 340, 60 360, 80 320, 120 340)))
+  </a>
+<test>
+  <op name="isSimple" arg1="A">
+    true
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestValid.xml b/tests/testthat/testxml/general/TestValid.xml
new file mode 100644
index 0000000..d9ac19c
--- /dev/null
+++ b/tests/testthat/testxml/general/TestValid.xml
@@ -0,0 +1,663 @@
+<run>
+   <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+   <case>
+      <desc>L - linear-ring bowtie</desc>
+      <a>LINEARRING(0 0, 100 100, 100 0, 0 100, 0 0)</a>
+      <test>
+         <op name="isValid" arg1="A">false</op>
+      </test>
+   </case>
+
+   <case>
+      <desc>L - linestring bowtie</desc>
+      <a>LINESTRING(0 0, 100 100, 100 0, 0 100, 0 0)</a>
+      <test>
+         <op name="isValid" arg1="A">true</op>
+      </test>
+   </case>
+
+   <case>
+      <desc>P - point</desc>
+      <a>
+    POINT(10 10)
+  </a>
+      <test>
+         <op name="isValid" arg1="A">
+    true
+  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mP - no repeated points</desc>
+      <a>
+    MULTIPOINT(10 10, 20 20, 30 30)
+  </a>
+      <test>
+         <op name="isValid" arg1="A">    true  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>P - repeated points</desc>
+      <a>
+    MULTIPOINT(10 10, 20 20, 30 30, 10 10)
+  </a>
+      <test>
+         <op name="isValid" arg1="A">    true  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>L - no repeated points</desc>
+      <a>
+LINESTRING (40 180, 120 120, 140 200, 200 140, 240 200)
+  </a>
+      <test>
+         <op name="isValid" arg1="A">    true  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>L - repeated points</desc>
+      <a>
+LINESTRING (40 180, 120 120, 140 200, 140 200, 200 140, 240 200)
+  </a>
+      <test>
+         <op name="isValid" arg1="A">    true  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>L - linestring with two identical points </desc>
+      <a>LINESTRING(0 0, 0 0)</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - zero-area polygon </desc>
+      <a>POLYGON ((0 0, 0 0, 0 0, 0 0, 0 0))</a>
+      <test>
+         <op name="isValid" arg1="A"> false </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - polygon with too few points </desc>
+      <a>POLYGON ((0 0, 10 0, 20 0, 0 0, 0 0))</a>
+      <test>
+         <op name="isValid" arg1="A"> false </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - polygon with repeated point </desc>
+      <a>POLYGON ((107 246, 107 246, 250 285, 294 137, 151 90, 15 125, 157 174, 107 246))</a>
+      <test>
+         <op name="isValid" arg1="A"> true </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - polygon with degenerate hole ring (A-B-A) </desc>
+      <a>POLYGON ((0 0, 0 240, 260 240, 260 0, 0 0), 
+  (220 200, 40 200, 40 20, 40 200, 220 200, 220 200))</a>
+      <test>
+         <op name="isValid" arg1="A"> false </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - multipolygon with component with too few points </desc>
+      <a>MULTIPOLYGON ( ((100 20, 180 20, 180 100, 100 100, 100 20)),
+((20 100, 100 100, 100 180, 20 180, 20 100)),
+((100 180, 180 180, 180 260, 100 260, 100 180)),
+((180 100, 180 180, 180 180, 180 100)))</a>
+      <test>
+         <op name="isValid" arg1="A"> false </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - polygon self-intersects at non-vertex</desc>
+      <a>POLYGON ((0 40, 0 0, 40 40, 40 0, 0 40))</a>
+      <test>
+         <op name="isValid" arg1="A"> false </op>
+      </test>
+   </case>
+   <case>
+      <desc>A - polygon self-intersects at vertex</desc>
+      <a>MULTIPOLYGON ( ((0 40, 20 20, 40 0, 40 40, 20 20, 0 0, 0 40)) ) </a>
+      <test>
+         <op name="isValid" arg1="A"> false </op>
+      </test>
+   </case>
+   <case>
+      <desc>A - polygon self-intersects at vertex/non-vertex</desc>
+      <a>POLYGON ((0 40, 20 20, 40 0, 40 40, 0 0, 0 40))</a>
+      <test>
+         <op name="isValid" arg1="A">false</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - hole self-intersects at non-vertex</desc>
+      <a>POLYGON ((-10 50, 50 50, 50 -10, -10 -10, -10 50), (0 40, 0 0, 40 40, 40 0, 0 40))</a>
+      <test>
+         <op name="isValid" arg1="A">false</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - polygon self-intersects at vertex</desc>
+      <a>POLYGON ((-10 50, 50 50, 50 -10, -10 -10, -10 50), (0 40, 20 20, 40 0, 40 40, 20 20, 0 0, 0 40))</a>
+      <test>
+         <op name="isValid" arg1="A">false</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - polygon self-intersects at vertex/non-vertex</desc>
+      <a>POLYGON ((-10 50, 50 50, 50 -10, -10 -10, -10 50), (0 40, 20 20, 40 0, 40 40, 0 0, 0 40))</a>
+      <test>
+         <op name="isValid" arg1="A">false</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - Valid doughnut</desc>
+      <a>POLYGON ((0 60, 0 0, 60 0, 60 60, 0 60), (20 40, 20 20, 40 20, 40 40, 20 40))</a>
+      <test>
+         <op name="isValid" arg1="A">true</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - shell has repeated points</desc>
+      <a>POLYGON ((0 60, 0 0, 0 0, 60 0, 60 60, 0 60), (20 40, 20 20, 40 20, 40 40, 20 40))</a>
+      <test>
+         <op name="isValid" arg1="A">true</op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - shell touches hole without crossing it (valid)</desc>
+      <a>POLYGON ((0 60, 0 0, 60 0, 60 60, 0 60), (20 40, 20 20, 60 20, 20 40))</a>
+      <test>
+         <op name="isValid" arg1="A">true</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - shell touches hole without crossing it, but does so twice (invalid)</desc>
+      <a>POLYGON ((0 60, 0 0, 60 0, 60 60, 0 60), (0 40, 20 20, 60 20, 0 40))</a>
+      <test>
+         <op name="isValid" arg1="A">false</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - hole touches hole without crossing it (valid)</desc>
+      <a>POLYGON ((0 120, 0 0, 140 0, 140 120, 0 120), (100 100, 100 20, 120 20, 120 100, 100 100), (20 100, 20 40, 100 40, 20 100))</a>
+      <test>
+         <op name="isValid" arg1="A">true</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - holel touches hole without crossing it, but does so twice (invalid)</desc>
+      <a>POLYGON ((0 120, 0 0, 140 0, 140 120, 0 120), 
+		(100 100, 100 20, 120 20, 120 100, 100 100), 
+		(20 100, 20 40, 100 40, 80 60, 100 80, 20 100))</a>
+      <test>
+         <op name="isValid" arg1="A">false</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - hole touches hole without crossing it, but does so at an infinite number of points (invalid)</desc>
+      <a>POLYGON ((0 120, 0 0, 140 0, 140 120, 0 120), 
+		(100 100, 100 20, 120 20, 120 100, 100 100), 
+		(20 100, 20 40, 100 40, 100 80, 20 100))</a>
+      <test>
+         <op name="isValid" arg1="A">false</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - spike (invalid)</desc>
+      <a>POLYGON ((0 60, 0 0, 60 0, 60 20, 100 20, 60 20, 60 60, 0 60))</a>
+      <test>
+         <op name="isValid" arg1="A">false</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - puncture (invalid)</desc>
+      <a>POLYGON ((0 60, 0 0, 60 0, 60 20, 20 20, 60 20, 60 60, 0 60))</a>
+      <test>
+         <op name="isValid" arg1="A">false</op>
+      </test>
+   </case>
+   <case>
+      <desc>A - hole within a hole (invalid)</desc>
+      <a>POLYGON ((0 140, 0 0, 180 0, 180 140, 0 140), (20 20, 160 20, 160 120, 20 120, 20 20), (40 100, 40 40, 140 40, 140 100, 40 100))</a>
+      <test>
+         <op name="isValid" arg1="A">false</op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - hole overlapping shell at non-vertex</desc>
+      <a>
+POLYGON ((60 280, 260 180, 60 80, 60 280), 
+  (140 80, 120 180, 200 180, 140 80))
+  </a>
+      <test>
+         <op name="isValid" arg1="A">
+    false
+  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - shell self-overlaps </desc>
+      <a>
+POLYGON ((60 340, 60 100, 340 100, 340 280, 340 200, 340 340, 60 340))
+  </a>
+      <test>
+         <op name="isValid" arg1="A">    false  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - hole with repeated points</desc>
+      <a>
+POLYGON ((40 260, 40 60, 120 60, 180 160, 240 60, 300 60, 300 260, 40 260), 
+  (70 230, 80 230, 80 220, 80 220, 70 230))  </a>
+      <test>
+         <op name="isValid" arg1="A">
+    true
+  </op>
+      </test>
+   </case>
+   <case>
+      <desc>A - hole outside but adjacent to shell</desc>
+      <a>
+POLYGON ((40 260, 40 60, 120 60, 180 160, 240 60, 300 60, 300 260, 40 260), 
+  (180 160, 240 60, 120 60, 180 160))  </a>
+      <test>
+         <op name="isValid" arg1="A">
+    false
+  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - hole touches shell at two points</desc>
+      <a>
+POLYGON ((240 260, 40 260, 40 80, 240 80, 240 260), 
+  (140 180, 40 180, 140 260, 140 180))
+  </a>
+      <test>
+         <op name="isValid" arg1="A">
+    false
+  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - hole touches shell at one non-vertex point</desc>
+      <a>
+POLYGON ((240 260, 40 260, 40 80, 240 80, 240 260), 
+  (140 180, 40 180, 140 240, 140 180))
+  </a>
+      <test>
+         <op name="isValid" arg1="A">    true  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - hole touches shell at one vertex point</desc>
+      <a>
+POLYGON ((240 260, 40 260, 40 80, 240 80, 240 260), 
+  (140 180, 40 260, 140 240, 140 180))
+  </a>
+      <test>
+         <op name="isValid" arg1="A">    true  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - hole outside shell</desc>
+      <a>
+POLYGON ((20 180, 20 20, 140 20, 140 180, 20 180), 
+  (160 120, 180 100, 160 80, 160 120))  
+</a>
+      <test>
+         <op name="isValid" arg1="A">
+    false
+  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - hole identical to shell</desc>
+      <a>
+POLYGON ((20 180, 20 20, 140 20, 140 180, 20 180), 
+  (20 180, 20 20, 140 20, 140 180, 20 180))  
+</a>
+      <test>
+         <op name="isValid" arg1="A">
+    false
+  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - hole identical to shell</desc>
+      <a>
+POLYGON ((20 180, 20 20, 140 20, 140 180, 20 180), 
+  (20 180, 20 20, 140 20, 140 180, 20 180))  
+</a>
+      <test>
+         <op name="isValid" arg1="A">
+    false
+  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - hole self-intersects </desc>
+      <a>
+POLYGON ((380 340, 40 340, 40 20, 380 20, 380 340), 
+  (120 300, 300 280, 320 200, 160 140, 200 80, 320 120, 320 200, 360 60, 120 40, 120 300))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - holes overlap, first point is identical </desc>
+      <a>
+POLYGON ((20 320, 260 320, 260 20, 20 20, 20 320), 
+  (140 280, 80 100, 200 100, 140 280), 
+  (140 280, 40 80, 240 80, 140 280))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - holes do not overlap, first point is identical </desc>
+      <a>
+POLYGON ((20 320, 240 320, 240 40, 20 40, 20 320), 
+  (140 180, 60 120, 60 240, 140 180), 
+  (140 180, 200 120, 200 240, 140 180))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      true      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - shell self-touches at vertex </desc>
+      <a>
+POLYGON ((340 320, 340 200, 200 280, 200 80, 340 200, 340 20, 60 20, 60 340, 340 320))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - shell self-touches at non-vertex </desc>
+      <a>
+POLYGON ((300 320, 300 220, 260 260, 180 220, 360 220, 360 140, 120 140, 120 320, 300 320))	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+    <case>
+      <desc>A - chain of holes surrounds an island inside the polygon </desc>
+      <a>
+POLYGON ((40 300, 40 20, 280 20, 280 300, 40 300), 
+  (120 240, 80 180, 160 220, 120 240), 
+  (220 240, 160 220, 220 160, 220 240), 
+  (160 100, 80 180, 100 80, 160 100), 
+  (160 100, 220 160, 240 100, 160 100))	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - chain of holes splits polygon in two (touching at vertices) </desc>
+      <a>
+POLYGON ((40 320, 340 320, 340 20, 40 20, 40 320), 
+  (100 120, 40 20, 180 100, 100 120), 
+  (200 200, 180 100, 240 160, 200 200), 
+  (260 260, 240 160, 300 200, 260 260), 
+  (300 300, 300 200, 340 320, 300 300))	
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - chain of holes splits polygon in two (touching at non-vertex) </desc>
+      <a>
+POLYGON ((40 320, 340 320, 340 20, 40 20, 40 320), 
+  (100 120, 40 20, 180 100, 100 120), 
+  (200 200, 180 100, 240 160, 200 200), 
+  (260 260, 240 160, 300 200, 260 260), 
+  (300 300, 300 200, 340 260, 300 300))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - holes touch in one point </desc>
+      <a>
+POLYGON ((190 190, 360 20, 20 20, 190 190), 
+  (90 50, 150 110, 190 50, 90 50), 
+  (190 50, 230 110, 290 50, 190 50))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      true      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - holes touch in one point </desc>
+      <a>
+POLYGON ((190 190, 360 20, 20 20, 190 190), 
+  (90 50, 150 110, 190 50, 90 50), 
+  (190 50, 230 110, 290 50, 190 50))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      true      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - hole disconnects interiors </desc>
+      <a>
+POLYGON ((0 0, 10 10, 10 0, 0 0), 
+  (5 5, 5 0, 10 5, 5 5))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>A - touching holes do NOT disconnect (isCCW bug) </desc>
+      <a>
+POLYGON ((60 40, 60 240, 460 240, 460 40, 60 40), 
+  (260 200, 340 60, 400 120, 260 200), 
+  (260 200, 120 100, 200 60, 260 200))
+  	</a>
+      <test>
+         <op name="isValid" arg1="A">      true      </op>
+      </test>
+   </case>
+
+
+  
+  <case>
+      <desc>mA - adjacent shells (shared vertices) </desc>
+      <a>
+MULTIPOLYGON (((40 120, 140 120, 140 40, 40 40, 40 120)), 
+  ((140 120, 40 120, 40 200, 140 200, 140 120)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">
+    false
+  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - adjacent shells (different vertices) </desc>
+      <a>
+MULTIPOLYGON (((40 120, 140 120, 140 40, 40 40, 40 120)), 
+  ((160 120, 60 120, 40 200, 140 200, 160 120)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">
+    false
+  </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - nested overlapping shells </desc>
+      <a>
+MULTIPOLYGON (((80 260, 240 260, 240 100, 80 100, 80 260)), 
+  ((120 240, 220 240, 220 140, 120 140, 120 240)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - nested non-overlapping shells </desc>
+      <a>
+MULTIPOLYGON (((60 320, 60 80, 300 80, 60 320), 
+  (80 280, 80 100, 260 100, 80 280)), 
+  ((120 160, 140 160, 140 140, 120 160)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      true      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - nested non-overlapping shells, all vertices touch </desc>
+      <a>
+MULTIPOLYGON (((20 380, 420 380, 420 20, 20 20, 20 380), 
+  (220 340, 180 240, 60 200, 180 160, 340 60, 240 220, 220 340)), 
+  ((180 240, 180 160, 240 220, 180 240)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      true      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - nested overlapping shells, all vertices touch </desc>
+      <a>
+MULTIPOLYGON (((20 380, 420 380, 420 20, 20 20, 20 380), 
+  (220 340, 180 240, 60 200, 140 100, 340 60, 300 240, 220 340)), 
+  ((60 200, 340 60, 220 340, 60 200)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - nested non-overlapping shells, all vertices touch </desc>
+      <a>
+MULTIPOLYGON (((20 380, 420 380, 420 20, 20 20, 20 380), 
+  (220 340, 80 320, 60 200, 140 100, 340 60, 300 240, 220 340)), 
+  ((60 200, 340 60, 220 340, 60 200)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      true      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - nested overlapping shells, all vertices touch </desc>
+      <a>
+MULTIPOLYGON (((20 380, 420 380, 420 20, 20 20, 20 380), 
+  (220 340, 180 240, 60 200, 200 180, 340 60, 240 220, 220 340)), 
+  ((60 200, 340 60, 220 340, 60 200)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - disconnected exterior </desc>
+      <a>
+MULTIPOLYGON (((100 20, 180 20, 180 100, 100 100, 100 20)), 
+  ((20 100, 100 100, 100 180, 20 180, 20 100)), 
+  ((100 180, 180 180, 180 260, 100 260, 100 180)), 
+  ((180 100, 260 100, 260 180, 180 180, 180 100)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      true      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - shells touch in single point </desc>
+      <a>
+MULTIPOLYGON (((110 110, 70 200, 150 200, 110 110)), 
+  ((110 110, 150 20, 70 20, 110 110)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      true      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - duplicate shells </desc>
+      <a>
+MULTIPOLYGON (((60 300, 320 220, 260 60, 60 100, 60 300)), 
+  ((60 300, 320 220, 260 60, 60 100, 60 300)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      false      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - shells are not nested but share all vertices </desc>
+      <a>
+MULTIPOLYGON (((180 60, 240 160, 300 60, 180 60)), 
+  ((80 80, 180 60, 160 140, 240 160, 360 140, 300 60, 420 100, 320 280, 120 260, 80 80)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      true      </op>
+      </test>
+   </case>
+
+   <case>
+      <desc>mA - shell is nested inside first hole </desc>
+      <a>
+MULTIPOLYGON (((0 0, 0 8, 8 8, 8 0, 0 0), 
+  (3 3, 7 3, 7 7, 3 7, 3 3), 
+  (1 1, 2 1, 2 2, 1 2, 1 1)), 
+  ((4 4, 4 6, 6 6, 6 4, 4 4)))
+	</a>
+      <test>
+         <op name="isValid" arg1="A">      true      </op>
+      </test>
+   </case>
+
+
+</run>
diff --git a/tests/testthat/testxml/general/TestValid2-big.xml b/tests/testthat/testxml/general/TestValid2-big.xml
new file mode 100644
index 0000000..1f1e409
--- /dev/null
+++ b/tests/testthat/testxml/general/TestValid2-big.xml
@@ -0,0 +1,18 @@
+<run>
+   <precisionModel type="FLOATING"/>
+<case>
+  <desc>Test 92</desc>
+  <a>
+    POLYGON ((100 100, 1000000000000000 110, 1000000000000000 100, 100 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 558</desc>
+  <a>
+    MULTIPOINT (-1000000000000000000000000 -1000000000000000000000000, 1000000000000000000000000 -1000000000000000000000000, 1000000000000000000000000 1000000000000000000000000, -1000000000000000000000000 1000000000000000000000000, 0 0)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/general/TestValid2.xml b/tests/testthat/testxml/general/TestValid2.xml
new file mode 100644
index 0000000..a506388
--- /dev/null
+++ b/tests/testthat/testxml/general/TestValid2.xml
@@ -0,0 +1,5225 @@
+<run>
+   <precisionModel type="FLOATING"/>
+<case>
+  <desc>Test 1</desc>
+  <a>
+    LINESTRING (-123456789 -40, 381039468754763 123456789)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 2</desc>
+  <a>
+    POINT (0 0)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 3</desc>
+  <a>
+    POLYGON ((20 20, 20 100, 120 100, 140 20, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 4</desc>
+  <a>
+    POLYGON ((20 20, 140 20, 120 100, 20 100, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 5</desc>
+  <a>
+    POLYGON ((120 100, 140 20, 20 20, 20 100, 120 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 6</desc>
+  <a>
+    POLYGON ((20 100, 60 100, 120 100, 140 20, 80 20, 20 20, 20 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 7</desc>
+  <a>
+    POLYGON ((0 0, 80 0, 80 80, 0 80, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 8</desc>
+  <a>
+    POLYGON ((100 200, 100 140, 180 140, 180 200, 100 200))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 9</desc>
+  <a>
+    POLYGON ((140 120, 160 20, 20 20, 20 120, 140 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 10</desc>
+  <a>
+    POLYGON ((140 120, 140 200, 240 200, 240 120, 140 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 11</desc>
+  <a>
+    POLYGON ((80 180, 140 260, 260 200, 200 60, 80 180))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 12</desc>
+  <a>
+    POLYGON ((240 80, 140 120, 180 240, 280 200, 240 80))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 13</desc>
+  <a>
+    POLYGON ((140 160, 20 20, 270 20, 150 160, 230 40, 60 40, 140 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 14</desc>
+  <a>
+    POLYGON ((140 40, 180 80, 120 100, 140 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 15</desc>
+  <a>
+    POLYGON ((120 100, 180 80, 130 40, 120 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 16</desc>
+  <a>
+    POLYGON ((20 20, 180 20, 140 140, 20 140, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 17</desc>
+  <a>
+    POLYGON ((180 100, 80 200, 180 280, 260 200, 180 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 18</desc>
+  <a>
+    POLYGON ((140 140, 20 120, 0 220, 120 240, 140 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 19</desc>
+  <a>
+    POLYGON ((160 200, 210 70, 120 70, 160 200))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 20</desc>
+  <a>
+    POLYGON ((160 200, 260 40, 70 40, 160 200, 20 20, 310 20, 160 200))
+  </a>
+  <test> <op name="isValid" arg1="A"> false </op> </test>
+</case>
+<case>
+  <desc>Test 21</desc>
+  <a>
+    POLYGON ((110 140, 200 70, 200 160, 110 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 22</desc>
+  <a>
+    POLYGON ((110 140, 110 50, 60 50, 60 90, 160 190, 20 110, 20 20, 200 20, 110 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> false </op> </test>
+</case>
+<case>
+  <desc>Test 23</desc>
+  <a>
+    POLYGON ((20 120, 20 20, 260 20, 260 120, 200 40, 140 120, 80 40, 20 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 24</desc>
+  <a>
+    POLYGON ((20 120, 20 240, 260 240, 260 120, 200 200, 140 120, 80 200, 20 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 25</desc>
+  <a>
+    POLYGON ((20 120, 20 20, 260 20, 260 120, 180 40, 140 120, 100 40, 20 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 26</desc>
+  <a>
+    POLYGON ((20 120, 300 120, 140 240, 20 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 27</desc>
+  <a>
+    POLYGON ((20 20, 20 300, 280 300, 280 260, 220 260, 60 100, 60 60, 280 60, 280 20, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 28</desc>
+  <a>
+    POLYGON ((100 140, 160 80, 280 180, 200 240, 220 160, 160 200, 180 120, 100 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 29</desc>
+  <a>
+    POLYGON ((260 200, 180 80, 120 160, 200 160, 180 220, 260 200))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 30</desc>
+  <a>
+    POLYGON ((20 20, 280 20, 280 140, 220 60, 140 140, 80 60, 20 140, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 31</desc>
+  <a>
+    POLYGON ((0 140, 300 140, 140 240, 0 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 32</desc>
+  <a>
+    POLYGON ((20 240, 20 140, 320 140, 180 240, 20 240))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 33</desc>
+  <a>
+    POLYGON ((20 240, 20 140, 80 180, 140 140, 220 180, 280 140, 280 240, 20 240))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 34</desc>
+  <a>
+    POLYGON ((120 120, 180 60, 20 20, 20 120, 120 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 35</desc>
+  <a>
+    POLYGON ((120 120, 220 20, 280 20, 240 160, 120 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 36</desc>
+  <a>
+    POLYGON ((140 120, 160 20, 260 120, 220 200, 140 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 37</desc>
+  <a>
+    POLYGON ((20 140, 120 40, 20 40, 20 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 38</desc>
+  <a>
+    POLYGON ((190 140, 190 20, 140 20, 20 140, 190 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 39</desc>
+  <a>
+    POLYGON ((300 20, 220 20, 120 120, 260 160, 300 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 40</desc>
+  <a>
+    POLYGON ((140 120, 240 160, 280 60, 160 20, 140 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 41</desc>
+  <a>
+    POLYGON ((280 60, 180 60, 120 120, 260 180, 280 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 42</desc>
+  <a>
+    POLYGON ((120 200, 120 120, 40 120, 40 200, 120 200))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 43</desc>
+  <a>
+    POLYGON ((160 220, 140 120, 60 120, 40 220, 160 220))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 44</desc>
+  <a>
+    POLYGON ((140 120, 20 120, 20 220, 140 220, 140 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 45</desc>
+  <a>
+    POLYGON ((320 20, 220 20, 80 160, 240 140, 320 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 46</desc>
+  <a>
+    POLYGON ((20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 47</desc>
+  <a>
+    POLYGON ((60 40, 60 140, 180 140, 180 40, 60 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 48</desc>
+  <a>
+    POLYGON ((20 20, 80 140, 160 60, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 49</desc>
+  <a>
+    POLYGON ((160 60, 20 20, 100 140, 160 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 50</desc>
+  <a>
+    POLYGON ((20 100, 140 160, 160 40, 20 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 51</desc>
+  <a>
+    POLYGON ((160 40, 20 100, 160 160, 160 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 52</desc>
+  <a>
+    POLYGON ((20 180, 180 120, 80 40, 20 180))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 53</desc>
+  <a>
+    POLYGON ((180 120, 100 40, 20 180, 180 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 54</desc>
+  <a>
+    POLYGON ((20 20, 140 40, 140 120, 20 160, 80 80, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 55</desc>
+  <a>
+    POLYGON ((20 20, 140 40, 140 140, 20 180, 80 100, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 56</desc>
+  <a>
+    POLYGON ((40 180, 60 100, 180 100, 200 180, 120 120, 40 180))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 57</desc>
+  <a>
+    POLYGON ((20 180, 60 80, 180 80, 220 180, 120 120, 20 180))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 58</desc>
+  <a>
+    POLYGON ((40 60, 20 180, 100 100, 140 180, 160 120, 220 100, 140 40, 40 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 59</desc>
+  <a>
+    POLYGON ((60 100, 180 100, 220 180, 120 140, 20 180, 60 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 60</desc>
+  <a>
+    POLYGON ((20 20, 20 140, 120 120, 120 40, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 61</desc>
+  <a>
+    POLYGON ((20 20, 20 180, 140 140, 140 60, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 62</desc>
+  <a>
+    POLYGON ((20 20, 120 40, 120 120, 20 140, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 63</desc>
+  <a>
+    POLYGON ((120 40, 20 20, 20 140, 120 120, 120 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 64</desc>
+  <a>
+    POLYGON ((20 20, 140 60, 140 140, 20 180, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 65</desc>
+  <a>
+    POLYGON ((140 60, 20 20, 20 180, 140 140, 140 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 66</desc>
+  <a>
+    POLYGON ((20 20, 60 120, 140 120, 180 20, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 67</desc>
+  <a>
+    POLYGON ((20 40, 120 40, 120 120, 20 140, 20 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 68</desc>
+  <a>
+    POLYGON ((20 20, 20 180, 60 120, 100 180, 140 120, 220 180, 200 120, 140 60, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 69</desc>
+  <a>
+    POLYGON ((150 150, 330 150, 250 70, 70 70, 150 150))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 70</desc>
+  <a>
+    POLYGON ((150 150, 270 150, 140 20, 20 20, 150 150))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 71</desc>
+  <a>
+    POLYGON ((150 150, 270 150, 330 150, 250 70, 190 70, 70 70, 150 150))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 72</desc>
+  <a>
+    POLYGON ((150 150, 270 150, 190 70, 140 20, 20 20, 70 70, 150 150))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 73</desc>
+  <a>
+    POLYGON ((20 20, 60 50, 20 40, 60 70, 20 60, 60 90, 20 90, 70 110, 20 130, 80 130, 20 150, 80 160, 20 170, 80 180, 20 200, 80 200, 30 240, 80 220, 50 260, 100 220, 100 260, 120 220, 130 260, 140 220, 150 280, 150 190, 160 280, 170 190, 180 280, 190 190, 200 280, 210 190, 220 280, 230 190, 240 260, 250 230, 260 260, 260 220, 290 270, 290 220, 330 260, 300 210, 340 240, 290 180, 340 210, 290 170, 350 170, 240 150, 350 150, 240 140, 350 130, 240 120, 350 120, 240 110, 350 110, 240 100,  [...]
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 74</desc>
+  <a>
+    POLYGON ((190 140, 140 130, 200 160, 130 150, 210 170, 130 170, 210 180, 120 190, 220 200, 120 200, 250 210, 120 210, 250 220, 120 220, 250 230, 120 240, 230 240, 120 250, 240 260, 120 260, 240 270, 120 270, 270 290, 120 290, 230 300, 150 310, 250 310, 180 320, 250 320, 200 360, 260 330, 240 360, 280 320, 290 370, 290 320, 320 360, 310 320, 360 360, 310 310, 380 340, 310 290, 390 330, 310 280, 410 310, 310 270, 420 280, 310 260, 430 250, 300 250, 440 240, 300 240, 450 230, 280 220, 4 [...]
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 75</desc>
+  <a>
+    POLYGON ((70 150, 20 160, 110 160, 20 180, 100 200, 20 200, 190 210, 20 210, 160 220, 20 220, 150 230, 60 240, 180 250, 20 260, 170 260, 60 270, 160 270, 100 310, 170 280, 200 260, 180 230, 210 260, 130 330, 230 250, 210 290, 240 250, 230 210, 260 300, 250 230, 270 300, 270 240, 300 340, 280 250, 320 330, 290 250, 340 350, 290 240, 350 360, 270 190, 350 340, 290 200, 350 330, 300 190, 360 320, 310 190, 360 300, 320 200, 360 280, 330 200, 360 260, 340 200, 370 260, 340 180, 390 290, 3 [...]
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 76</desc>
+  <a>
+    POLYGON ((60 160, 220 160, 220 20, 60 20, 60 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 77</desc>
+  <a>
+    POLYGON ((60 160, 20 200, 260 200, 220 160, 140 80, 60 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 78</desc>
+  <a>
+    POLYGON ((60 160, 20 200, 260 200, 140 80, 60 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 79</desc>
+  <a>
+    POLYGON ((20 200, 140 80, 260 200, 20 200))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 80</desc>
+  <a>
+    POLYGON ((20 200, 60 160, 140 80, 220 160, 260 200, 20 200))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 81</desc>
+  <a>
+    POLYGON ((20 200, 60 160, 140 80, 260 200, 20 200))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 82</desc>
+  <a>
+    POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 83</desc>
+  <a>
+    POLYGON ((100 100, 1000000 110, 10000000 100, 100 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 84</desc>
+  <a>
+    POLYGON ((100 0, 100 200, 200 200, 200 0, 100 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 85</desc>
+  <a>
+    POLYGON ((120 0, 120 200, 200 200, 200 0, 120 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 86</desc>
+  <a>
+    POLYGON ((0 0, 0 200, 110 200, 110 0, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 87</desc>
+  <a>
+    POLYGON ((100 100, 100 200, 200 200, 200 100, 100 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 88</desc>
+  <a>
+    POLYGON ((100 100, 2100 110, 2100 100, 100 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 89</desc>
+  <a>
+    POLYGON ((100 100, 2101 110, 2101 100, 100 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 90</desc>
+  <a>
+    POLYGON ((100 100, 200 200, 200 100, 100 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 91</desc>
+  <a>
+    POLYGON ((100 100, 1000000 110, 1000000 100, 100 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 93</desc>
+  <a>
+    POLYGON ((120 100, 120 200, 200 200, 200 100, 120 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 94</desc>
+  <a>
+    POLYGON ((100 100, 500 110, 500 100, 100 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 95</desc>
+  <a>
+    POLYGON ((100 100, 501 110, 501 100, 100 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 96</desc>
+  <a>
+    POLYGON ((120 100, 130 200, 200 200, 200 100, 120 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 97</desc>
+  <a>
+    POLYGON ((120 100, 17 200, 200 200, 200 100, 120 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 98</desc>
+  <a>
+    POLYGON ((101 99, 101 1000000, 102 1000000, 101 99))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 99</desc>
+  <a>
+    POLYGON ((100 100, 200 101, 200 100, 100 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 100</desc>
+  <a>
+    POLYGON ((16 319, 150 39, 25 302, 160 20, 265 20, 127 317, 16 319))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 101</desc>
+  <a>
+    POLYGON ((10 307, 22 307, 153 34, 22 34, 10 307))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 102</desc>
+  <a>
+    POLYGON ((160 200, 310 20, 20 20, 160 200), (160 200, 260 40, 70 40, 160 200))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 103</desc>
+  <a>
+    POLYGON ((170 120, 240 100, 260 50, 190 70, 170 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 104</desc>
+  <a>
+    POLYGON ((150 150, 410 150, 280 20, 20 20, 150 150), (170 120, 330 120, 260 50, 100 50, 170 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 105</desc>
+  <a>
+    POLYGON ((270 90, 200 50, 150 80, 210 120, 270 90))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 106</desc>
+  <a>
+    POLYGON ((170 120, 260 100, 240 60, 150 80, 170 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 107</desc>
+  <a>
+    POLYGON ((220 120, 270 80, 200 60, 160 100, 220 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 108</desc>
+  <a>
+    POLYGON ((260 50, 180 70, 180 110, 260 90, 260 50))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 109</desc>
+  <a>
+    POLYGON ((230 110, 290 80, 190 60, 140 90, 230 110))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 110</desc>
+  <a>
+    POLYGON ((170 120, 330 120, 260 50, 100 50, 170 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 111</desc>
+  <a>
+    POLYGON ((170 120, 330 120, 280 70, 120 70, 170 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 112</desc>
+  <a>
+    POLYGON ((170 120, 300 120, 250 70, 120 70, 170 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 113</desc>
+  <a>
+    POLYGON ((190 100, 310 100, 260 50, 140 50, 190 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 114</desc>
+  <a>
+    POLYGON ((280 130, 360 130, 270 40, 190 40, 280 130))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 115</desc>
+  <a>
+    POLYGON ((150 150, 410 150, 280 20, 20 20, 150 150), (170 120, 250 120, 180 50, 100 50, 170 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 116</desc>
+  <a>
+    POLYGON ((220 80, 180 40, 80 40, 170 130, 270 130, 230 90, 300 90, 250 30, 280 30, 390 140, 150 140, 40 30, 230 30, 280 80, 220 80))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 117</desc>
+  <a>
+    POLYGON ((260 130, 360 130, 280 40, 170 40, 260 130))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 118</desc>
+  <a>
+    POLYGON ((240 110, 340 110, 290 60, 190 60, 240 110))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 119</desc>
+  <a>
+    POLYGON ((250 120, 350 120, 280 50, 180 50, 250 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 120</desc>
+  <a>
+    POLYGON ((230 210, 230 20, 20 20, 20 210, 230 210), (120 180, 50 50, 200 50, 120 180))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 121</desc>
+  <a>
+    POLYGON ((230 210, 230 20, 20 20, 20 210, 230 210), (140 40, 40 40, 40 170, 140 40), (110 190, 210 190, 210 50, 110 190))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 122</desc>
+  <a>
+    POLYGON ((280 190, 330 150, 200 110, 150 150, 280 190))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 123</desc>
+  <a>
+    MULTIPOLYGON (((140 110, 260 110, 170 20, 50 20, 140 110)), ((300 270, 420 270, 340 190, 220 190, 300 270)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 124</desc>
+  <a>
+    POLYGON ((80 190, 220 190, 140 110, 0 110, 80 190))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 125</desc>
+  <a>
+    POLYGON ((330 150, 200 110, 150 150, 280 190, 330 150))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 126</desc>
+  <a>
+    POLYGON ((290 190, 340 150, 220 120, 170 170, 290 190))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 127</desc>
+  <a>
+    POLYGON ((220 190, 340 190, 260 110, 140 110, 220 190))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 128</desc>
+  <a>
+    POLYGON ((140 190, 220 190, 100 70, 20 70, 140 190))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 129</desc>
+  <a>
+    POLYGON ((140 220, 60 140, 140 60, 220 140, 140 220))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 130</desc>
+  <a>
+    MULTIPOLYGON (((100 20, 180 20, 180 100, 100 100, 100 20)), ((20 100, 100 100, 100 180, 20 180, 20 100)), ((100 180, 180 180, 180 260, 100 260, 100 180)), ((180 100, 260 100, 260 180, 180 180, 180 100)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 131</desc>
+  <a>
+    MULTIPOLYGON (((110 110, 70 200, 150 200, 110 110)), ((110 110, 150 20, 70 20, 110 110)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 132</desc>
+  <a>
+    MULTIPOLYGON (((110 110, 160 160, 210 110, 160 60, 110 110)), ((110 110, 60 60, 10 110, 60 160, 110 110)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 133</desc>
+  <a>
+    MULTIPOLYGON (((110 110, 70 200, 150 200, 110 110), (110 110, 100 180, 120 180, 110 110)), ((110 110, 150 20, 70 20, 110 110), (110 110, 120 40, 100 40, 110 110)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 134</desc>
+  <a>
+    MULTIPOLYGON (((110 110, 160 160, 210 110, 160 60, 110 110), (110 110, 160 130, 160 90, 110 110)), ((110 110, 60 60, 10 110, 60 160, 110 110), (110 110, 60 90, 60 130, 110 110)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 135</desc>
+  <a>
+    MULTIPOLYGON (((110 110, 70 200, 200 200, 110 110), (110 110, 100 180, 120 180, 110 110)), ((110 110, 200 20, 70 20, 110 110), (110 110, 120 40, 100 40, 110 110)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 136</desc>
+  <a>
+    MULTIPOLYGON (((110 110, 20 200, 200 200, 110 110), (110 110, 100 180, 120 180, 110 110)), ((110 110, 200 20, 20 20, 110 110), (110 110, 120 40, 100 40, 110 110)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 137</desc>
+  <a>
+    MULTIPOLYGON (((110 110, 70 200, 210 110, 70 20, 110 110), (110 110, 110 140, 150 110, 110 80, 110 110)), ((110 110, 60 60, 10 110, 60 160, 110 110), (110 110, 60 90, 60 130, 110 110)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 138</desc>
+  <a>
+    POLYGON ((100 60, 140 100, 100 140, 60 100, 100 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 139</desc>
+  <a>
+    MULTIPOLYGON (((80 40, 120 40, 120 80, 80 80, 80 40)), ((120 80, 160 80, 160 120, 120 120, 120 80)), ((80 120, 120 120, 120 160, 80 160, 80 120)), ((40 80, 80 80, 80 120, 40 120, 40 80)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 140</desc>
+  <a>
+    LINESTRING (150 150, 40 230)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 141</desc>
+  <a>
+    POLYGON ((150 150, 410 150, 280 20, 20 20, 150 150))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 142</desc>
+  <a>
+    LINESTRING (40 40, 50 130, 130 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 143</desc>
+  <a>
+    LINESTRING (40 230, 150 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 144</desc>
+  <a>
+    LINESTRING (210 150, 330 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 145</desc>
+  <a>
+    LINESTRING (200 150, 310 150, 360 220)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 146</desc>
+  <a>
+    LINESTRING (180 150, 250 150, 230 250, 370 250, 410 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 147</desc>
+  <a>
+    LINESTRING (210 210, 220 150, 320 150, 370 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 148</desc>
+  <a>
+    LINESTRING (20 60, 150 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 149</desc>
+  <a>
+    LINESTRING (60 90, 310 180)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 150</desc>
+  <a>
+    LINESTRING (90 210, 210 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 151</desc>
+  <a>
+    LINESTRING (290 10, 130 170)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 152</desc>
+  <a>
+    LINESTRING (30 100, 100 100, 180 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 153</desc>
+  <a>
+    LINESTRING (20 100, 100 100, 360 100, 410 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 154</desc>
+  <a>
+    LINESTRING (90 210, 150 150, 210 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 155</desc>
+  <a>
+    LINESTRING (180 90, 280 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 156</desc>
+  <a>
+    LINESTRING (70 70, 80 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 157</desc>
+  <a>
+    LINESTRING (130 20, 150 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 158</desc>
+  <a>
+    LINESTRING (70 70, 80 20, 140 20, 150 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 159</desc>
+  <a>
+    LINESTRING (170 50, 170 20, 240 20, 260 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 160</desc>
+  <a>
+    LINESTRING (50 100, 140 190, 280 190)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 161</desc>
+  <a>
+    LINESTRING (140 60, 180 100, 290 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 162</desc>
+  <a>
+    LINESTRING (170 120, 210 80, 270 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 163</desc>
+  <a>
+    LINESTRING (170 120, 260 50)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 164</desc>
+  <a>
+    LINESTRING (190 90, 190 270)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 165</desc>
+  <a>
+    POLYGON ((190 190, 360 20, 20 20, 190 190), (190 190, 280 50, 100 50, 190 190))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 166</desc>
+  <a>
+    LINESTRING (60 160, 150 70)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 167</desc>
+  <a>
+    POLYGON ((190 190, 360 20, 20 20, 190 190), (110 110, 250 100, 140 30, 110 110))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 168</desc>
+  <a>
+    POLYGON ((190 190, 20 20, 360 20, 190 190), (250 100, 110 110, 140 30, 250 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 169</desc>
+  <a>
+    LINESTRING (190 90, 190 190, 190 270)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 170</desc>
+  <a>
+    LINESTRING (60 160, 110 110, 150 70)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 171</desc>
+  <a>
+    POLYGON ((190 190, 110 110, 20 20, 360 20, 190 190), (250 100, 110 110, 140 30, 250 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 172</desc>
+  <a>
+    LINESTRING (130 110, 180 110, 190 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 173</desc>
+  <a>
+    POLYGON ((20 200, 240 200, 240 20, 20 20, 20 200), (130 110, 60 180, 60 40, 130 110), (130 110, 200 40, 200 180, 130 110))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 174</desc>
+  <a>
+    LINESTRING (80 110, 180 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 175</desc>
+  <a>
+    POLYGON ((20 200, 20 20, 240 20, 240 200, 20 200), (60 180, 130 110, 60 40, 60 180), (130 110, 200 40, 200 180, 130 110))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 176</desc>
+  <a>
+    LINESTRING (80 110, 170 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 177</desc>
+  <a>
+    POLYGON ((20 200, 20 20, 240 20, 240 200, 20 200), (130 110, 60 40, 60 180, 130 110), (130 180, 130 40, 200 110, 130 180))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 178</desc>
+  <a>
+    LINESTRING (80 110, 130 110, 170 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 179</desc>
+  <a>
+    LINESTRING (80 110, 130 110, 180 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 180</desc>
+  <a>
+    LINESTRING (160 70, 320 230)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 181</desc>
+  <a>
+    LINESTRING (160 70, 200 110, 280 190, 320 230)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 182</desc>
+  <a>
+    LINESTRING (70 50, 70 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 183</desc>
+  <a>
+    MULTIPOLYGON (((0 0, 0 100, 140 100, 140 0, 0 0)), ((20 170, 70 100, 130 170, 20 170)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 184</desc>
+  <a>
+    LINESTRING (110 110, 20 200, 200 200, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 185</desc>
+  <a>
+    POLYGON ((20 20, 200 20, 110 110, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 186</desc>
+  <a>
+    LINESTRING (150 70, 160 110, 200 60, 150 70)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 187</desc>
+  <a>
+    LINESTRING (80 60, 120 40, 120 70, 80 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 188</desc>
+  <a>
+    POLYGON ((110 110, 200 20, 20 20, 110 110), (110 90, 50 30, 170 30, 110 90))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 189</desc>
+  <a>
+    LINESTRING (20 20, 200 20, 110 110, 20 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 190</desc>
+  <a>
+    LINESTRING (110 90, 170 30, 50 30, 110 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 191</desc>
+  <a>
+    LINESTRING (110 110, 170 50, 170 110, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 192</desc>
+  <a>
+    LINESTRING (110 90, 70 50, 130 50, 110 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 193</desc>
+  <a>
+    LINESTRING (110 60, 20 150, 200 150, 110 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 194</desc>
+  <a>
+    LINESTRING (110 130, 110 70, 200 100, 110 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 195</desc>
+  <a>
+    LINESTRING (110 90, 160 40, 60 40, 110 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 196</desc>
+  <a>
+    LINESTRING (110 100, 40 30, 180 30, 110 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 197</desc>
+  <a>
+    POLYGON ((110 110, 200 20, 20 20, 110 110), (110 90, 60 40, 160 40, 110 90))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 198</desc>
+  <a>
+    LINESTRING (110 110, 180 30, 40 30, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 199</desc>
+  <a>
+    LINESTRING (110 90, 180 30, 40 30, 110 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 200</desc>
+  <a>
+    LINESTRING (110 90, 50 30, 180 30, 110 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 201</desc>
+  <a>
+    LINESTRING (110 110, 200 200, 200 110, 110 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 202</desc>
+  <a>
+    POLYGON ((110 110, 200 20, 20 20, 110 110))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 203</desc>
+  <a>
+    LINESTRING (110 110, 200 200, 110 110, 20 200, 20 110, 200 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 204</desc>
+  <a>
+    LINESTRING (110 110, 20 110, 200 110, 50 110, 110 170)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 205</desc>
+  <a>
+    LINESTRING (110 110, 20 200, 110 200, 110 110, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 206</desc>
+  <a>
+    LINESTRING (110 110, 170 50, 20 200, 20 110, 200 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 207</desc>
+  <a>
+    LINESTRING (110 110, 180 40, 110 40, 110 180)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 208</desc>
+  <a>
+    LINESTRING (110 60, 50 30, 170 30, 90 70)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 209</desc>
+  <a>
+    LINESTRING (110 110, 180 40, 110 40, 110 110, 70 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 210</desc>
+  <a>
+    LINESTRING (230 70, 170 120, 190 60, 140 60, 170 120, 270 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 211</desc>
+  <a>
+    MULTILINESTRING ((20 110, 200 110), (200 200, 110 110, 20 210, 110 110))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 212</desc>
+  <a>
+    MULTILINESTRING ((20 110, 200 110), (60 180, 60 110, 160 110, 110 110))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 213</desc>
+  <a>
+    MULTILINESTRING ((20 110, 200 110), (200 200, 110 110, 20 200, 110 200, 110 110))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 214</desc>
+  <a>
+    MULTILINESTRING ((20 110, 200 110), (110 50, 110 170, 110 70, 110 150, 200 150))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 215</desc>
+  <a>
+    MULTILINESTRING ((20 110, 200 110), (50 110, 170 110, 110 170, 110 50, 110 170, 110 50))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 216</desc>
+  <a>
+    MULTILINESTRING ((20 110, 200 110), (110 60, 110 160, 200 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 217</desc>
+  <a>
+    MULTILINESTRING ((110 100, 40 30, 180 30), (170 30, 110 90, 50 30))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 218</desc>
+  <a>
+    MULTILINESTRING ((110 110, 60 40, 70 20, 150 20, 170 40), (180 30, 40 30, 110 80))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 219</desc>
+  <a>
+    MULTILINESTRING ((20 110, 200 110, 200 160), (110 110, 200 110, 200 70, 20 150))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 220</desc>
+  <a>
+    MULTIPOLYGON (((110 110, 20 20, 200 20, 110 110)), ((110 110, 20 200, 200 200, 110 110)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 221</desc>
+  <a>
+    MULTILINESTRING ((20 160, 70 110, 150 110, 200 160), (110 110, 20 110, 50 80, 70 110, 200 110))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 222</desc>
+  <a>
+    MULTILINESTRING ((20 110, 200 110), (110 110, 20 170, 20 130, 200 90))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 223</desc>
+  <a>
+    LINESTRING (0 0, 0 50, 50 50, 50 0, 0 0)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 224</desc>
+  <a>
+    MULTILINESTRING ((0 0, 0 50), (0 50, 50 50), (50 50, 50 0), (50 0, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 225</desc>
+  <a>
+    LINESTRING (40 180, 140 180)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 226</desc>
+  <a>
+    MULTIPOLYGON (((20 320, 180 320, 180 180, 20 180, 20 320)), ((20 180, 20 80, 180 80, 180 180, 20 180)))
+  </a>
+  <test> <op name="isValid" arg1="A"> false </op> </test>
+</case>
+<case>
+  <desc>Test 227</desc>
+  <a>
+    MULTIPOLYGON (((20 320, 180 320, 180 180, 20 180, 20 320)), ((60 180, 60 80, 180 80, 180 180, 60 180)))
+  </a>
+  <test> <op name="isValid" arg1="A"> false </op> </test>
+</case>
+<case>
+  <desc>Test 228</desc>
+  <a>
+    LINESTRING (0 0, 60 0, 60 60, 60 0, 120 0)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 229</desc>
+  <a>
+    MULTILINESTRING ((0 0, 60 0), (60 0, 120 0), (60 0, 60 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 230</desc>
+  <a>
+    LINESTRING (40 40, 120 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 231</desc>
+  <a>
+    LINESTRING (40 40, 60 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 232</desc>
+  <a>
+    LINESTRING (60 240, 40 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 233</desc>
+  <a>
+    LINESTRING (40 40, 180 180)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 234</desc>
+  <a>
+    LINESTRING (120 120, 20 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 235</desc>
+  <a>
+    LINESTRING (60 240, 120 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 236</desc>
+  <a>
+    LINESTRING (20 180, 140 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 237</desc>
+  <a>
+    LINESTRING (40 120, 120 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 238</desc>
+  <a>
+    LINESTRING (40 40, 100 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 239</desc>
+  <a>
+    LINESTRING (100 100, 40 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 240</desc>
+  <a>
+    LINESTRING (40 120, 120 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 241</desc>
+  <a>
+    LINESTRING (20 20, 180 180)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 242</desc>
+  <a>
+    LINESTRING (20 20, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 243</desc>
+  <a>
+    LINESTRING (50 50, 140 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 244</desc>
+  <a>
+    LINESTRING (180 180, 40 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 245</desc>
+  <a>
+    LINESTRING (120 120, 260 260)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 246</desc>
+  <a>
+    LINESTRING (260 260, 120 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 247</desc>
+  <a>
+    LINESTRING (40 40, 100 100, 200 120, 80 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 248</desc>
+  <a>
+    LINESTRING (40 40, 20 100, 40 160, 20 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 249</desc>
+  <a>
+    LINESTRING (20 200, 40 160, 20 100, 40 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 250</desc>
+  <a>
+    LINESTRING (80 240, 200 120, 100 100, 40 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 251</desc>
+  <a>
+    LINESTRING (60 60, 60 230, 140 230, 250 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 252</desc>
+  <a>
+    LINESTRING (20 20, 60 60, 250 160, 310 230)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 253</desc>
+  <a>
+    LINESTRING (20 20, 110 110, 200 110, 320 230)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 254</desc>
+  <a>
+    LINESTRING (60 110, 60 250, 360 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 255</desc>
+  <a>
+    LINESTRING (60 110, 110 160, 250 160, 310 160, 360 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 256</desc>
+  <a>
+    LINESTRING (360 210, 310 160, 110 160, 60 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 257</desc>
+  <a>
+    LINESTRING (160 160, 240 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 258</desc>
+  <a>
+    LINESTRING (240 240, 160 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 259</desc>
+  <a>
+    LINESTRING (60 150, 110 100, 170 100, 110 230)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 260</desc>
+  <a>
+    LINESTRING (200 120, 200 190, 150 240, 200 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 261</desc>
+  <a>
+    LINESTRING (200 240, 150 240, 200 200, 200 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 262</desc>
+  <a>
+    LINESTRING (60 230, 80 140, 120 140, 140 230)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 263</desc>
+  <a>
+    LINESTRING (60 110, 200 110, 250 160, 300 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 264</desc>
+  <a>
+    LINESTRING (60 110, 200 110, 250 160, 300 210, 360 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 265</desc>
+  <a>
+    LINESTRING (60 110, 220 110, 250 160, 280 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 266</desc>
+  <a>
+    LINESTRING (60 110, 150 110, 200 160, 250 110, 360 110, 360 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 267</desc>
+  <a>
+    LINESTRING (130 160, 160 110, 220 110, 250 160, 250 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 268</desc>
+  <a>
+    LINESTRING (130 160, 160 110, 190 110, 230 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 269</desc>
+  <a>
+    LINESTRING (130 160, 160 110, 200 110, 230 160, 260 210, 360 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 270</desc>
+  <a>
+    LINESTRING (130 160, 160 110, 200 110, 230 160, 260 210, 360 210, 380 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 271</desc>
+  <a>
+    LINESTRING (130 160, 160 110, 200 110, 230 160, 260 210, 380 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 272</desc>
+  <a>
+    LINESTRING (110 160, 160 110, 200 110, 250 160, 250 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 273</desc>
+  <a>
+    LINESTRING (110 160, 180 110, 250 160, 320 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 274</desc>
+  <a>
+    LINESTRING (140 160, 180 80, 220 160, 250 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 275</desc>
+  <a>
+    LINESTRING (40 40, 100 100, 200 120, 130 190)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 276</desc>
+  <a>
+    LINESTRING (20 130, 70 130, 160 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 277</desc>
+  <a>
+    LINESTRING (40 160, 40 100, 110 40, 170 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 278</desc>
+  <a>
+    LINESTRING (130 110, 180 160, 230 110, 280 160, 330 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 279</desc>
+  <a>
+    LINESTRING (30 140, 80 140, 100 100, 200 30)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 280</desc>
+  <a>
+    LINESTRING (110 110, 110 160, 180 110, 250 160, 250 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 281</desc>
+  <a>
+    LINESTRING (20 20, 80 80, 160 80, 240 80, 300 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 282</desc>
+  <a>
+    LINESTRING (20 60, 60 60, 60 140, 80 80, 100 20, 140 140, 180 20, 200 80, 220 20, 240 80, 300 80, 270 110, 200 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 283</desc>
+  <a>
+    LINESTRING (20 20, 230 20, 20 30, 170 30, 20 40, 230 40, 20 50, 230 60, 60 60, 230 70, 20 70, 180 80, 60 80, 230 90, 20 90, 230 100, 30 100, 210 110, 20 110, 80 120, 20 130, 170 130, 90 120, 230 130, 170 140, 230 140, 80 150, 160 140, 20 140, 70 150, 20 150, 230 160, 80 160, 230 170, 20 160, 180 170, 20 170, 230 180, 20 180, 40 190, 230 190, 20 200, 230 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 284</desc>
+  <a>
+    LINESTRING (30 210, 30 60, 40 210, 40 30, 50 190, 50 20, 60 160, 60 50, 70 220, 70 50, 80 20, 80 210, 90 50, 90 150, 100 30, 100 210, 110 20, 110 190, 120 50, 120 180, 130 210, 120 20, 140 210, 130 50, 150 210, 130 20, 160 210, 140 30, 170 210, 150 20, 180 210, 160 20, 190 210, 180 80, 170 50, 170 20, 180 70, 180 20, 190 190, 190 30, 200 210, 200 30, 210 210, 210 20, 220 150, 220 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 285</desc>
+  <a>
+    LINESTRING (80 240, 120 200, 200 120, 100 100, 80 80, 40 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 286</desc>
+  <a>
+    LINESTRING (260 210, 240 130, 280 120, 260 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 287</desc>
+  <a>
+    LINESTRING (100 20, 20 20, 20 160, 210 160, 210 20, 110 20, 50 120, 120 150, 200 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 288</desc>
+  <a>
+    LINESTRING (140 130, 100 110, 120 60, 170 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 289</desc>
+  <a>
+    LINESTRING (60 110, 110 160, 310 160, 360 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 290</desc>
+  <a>
+    LINESTRING (60 110, 110 160, 250 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 291</desc>
+  <a>
+    LINESTRING (110 160, 310 160, 340 190)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 292</desc>
+  <a>
+    LINESTRING (140 160, 250 160, 310 160, 340 190)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 293</desc>
+  <a>
+    LINESTRING (110 160, 250 160, 310 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 294</desc>
+  <a>
+    LINESTRING (200 120, 100 100, 40 40, 140 80, 200 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 295</desc>
+  <a>
+    LINESTRING (280 240, 240 140, 200 120, 100 100, 40 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 296</desc>
+  <a>
+    LINESTRING (80 190, 140 140, 40 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 297</desc>
+  <a>
+    LINESTRING (240 200, 200 260, 80 240, 140 180)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 298</desc>
+  <a>
+    LINESTRING (140 180, 80 240, 200 260, 240 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 299</desc>
+  <a>
+    LINESTRING (280 240, 240 140, 200 120, 80 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 300</desc>
+  <a>
+    LINESTRING (20 80, 120 80, 200 80, 260 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 301</desc>
+  <a>
+    LINESTRING (100 100, 200 120, 240 140, 280 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 302</desc>
+  <a>
+    LINESTRING (280 240, 240 140, 200 120, 100 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 303</desc>
+  <a>
+    LINESTRING (80 20, 80 80, 240 80, 300 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 304</desc>
+  <a>
+    LINESTRING (20 80, 80 80, 120 80, 140 140, 160 80, 200 80, 220 20, 240 80, 270 110, 300 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 305</desc>
+  <a>
+    LINESTRING (100 100, 20 180, 180 180)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 306</desc>
+  <a>
+    LINESTRING (100 100, 180 20, 20 20, 100 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 307</desc>
+  <a>
+    LINESTRING (20 100, 180 100, 100 180)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 308</desc>
+  <a>
+    LINESTRING (100 40, 100 160, 180 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 309</desc>
+  <a>
+    LINESTRING (20 100, 100 100, 180 100, 100 180)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 310</desc>
+  <a>
+    LINESTRING (100 100, 160 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 311</desc>
+  <a>
+    LINESTRING (100 100, 180 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 312</desc>
+  <a>
+    LINESTRING (60 60, 100 100, 140 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 313</desc>
+  <a>
+    LINESTRING (100 100, 190 10, 190 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 314</desc>
+  <a>
+    LINESTRING (100 100, 160 40, 160 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 315</desc>
+  <a>
+    LINESTRING (60 140, 160 40, 160 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 316</desc>
+  <a>
+    LINESTRING (20 20, 140 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 317</desc>
+  <a>
+    LINESTRING (80 80, 20 80, 140 80, 80 20, 80 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 318</desc>
+  <a>
+    LINESTRING (80 80, 20 80, 140 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 319</desc>
+  <a>
+    LINESTRING (80 80, 140 80, 80 20, 80 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 320</desc>
+  <a>
+    LINESTRING (80 80, 20 80, 140 80, 80 20, 80 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 321</desc>
+  <a>
+    LINESTRING (80 80, 20 80, 140 80, 80 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 322</desc>
+  <a>
+    LINESTRING (80 80, 20 80, 20 140, 140 20, 80 20, 80 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 323</desc>
+  <a>
+    LINESTRING (20 140, 140 20, 100 20, 100 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 324</desc>
+  <a>
+    LINESTRING (140 80, 20 80, 120 80, 80 20, 80 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 325</desc>
+  <a>
+    LINESTRING (140 80, 20 80, 140 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 326</desc>
+  <a>
+    LINESTRING (140 80, 20 80, 80 140, 80 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 327</desc>
+  <a>
+    LINESTRING (140 80, 80 80, 20 80, 50 140, 50 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 328</desc>
+  <a>
+    LINESTRING (140 80, 20 80, 120 80, 80 20, 80 80, 80 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 329</desc>
+  <a>
+    LINESTRING (140 80, 20 80, 80 80, 140 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 330</desc>
+  <a>
+    LINESTRING (140 80, 20 80, 80 140, 80 80, 80 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 331</desc>
+  <a>
+    LINESTRING (130 150, 220 150, 220 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 332</desc>
+  <a>
+    LINESTRING (130 240, 130 150, 220 20, 50 20, 130 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 333</desc>
+  <a>
+    LINESTRING (30 150, 130 150, 250 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 334</desc>
+  <a>
+    LINESTRING (30 150, 250 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 335</desc>
+  <a>
+    LINESTRING (130 240, 130 20, 30 20, 130 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 336</desc>
+  <a>
+    LINESTRING (120 240, 120 20, 20 20, 120 170)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 337</desc>
+  <a>
+    LINESTRING (200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 338</desc>
+  <a>
+    LINESTRING (110 110, 200 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 339</desc>
+  <a>
+    LINESTRING (20 110, 200 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 340</desc>
+  <a>
+    LINESTRING (90 200, 90 130, 110 110, 150 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 341</desc>
+  <a>
+    LINESTRING (200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 342</desc>
+  <a>
+    LINESTRING (200 110, 110 110, 90 130, 90 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 343</desc>
+  <a>
+    LINESTRING (80 80, 150 80, 210 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 344</desc>
+  <a>
+    MULTILINESTRING ((20 20, 140 140), (20 140, 140 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 345</desc>
+  <a>
+    LINESTRING (40 80, 160 200, 260 20, 40 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 346</desc>
+  <a>
+    LINESTRING (40 80, 260 20, 160 200, 40 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 347</desc>
+  <a>
+    LINESTRING (260 20, 40 80, 160 200, 260 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 348</desc>
+  <a>
+    LINESTRING (100 140, 160 200, 260 20, 40 80, 100 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 349</desc>
+  <a>
+    LINESTRING (100 100, 180 180, 20 180, 100 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 350</desc>
+  <a>
+    LINESTRING (40 150, 40 40, 150 40, 150 150, 40 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 351</desc>
+  <a>
+    LINESTRING (40 150, 150 40, 170 20, 170 190, 40 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 352</desc>
+  <a>
+    LINESTRING (180 100, 20 100, 100 180, 180 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 353</desc>
+  <a>
+    LINESTRING (180 180, 100 100, 20 180, 180 180)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 354</desc>
+  <a>
+    LINESTRING (20 180, 100 100, 20 20, 20 180)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 355</desc>
+  <a>
+    LINESTRING (100 20, 100 180, 180 100, 100 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 356</desc>
+  <a>
+    LINESTRING (170 20, 20 170, 170 170, 170 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 357</desc>
+  <a>
+    LINESTRING (40 150, 150 150, 90 210, 40 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 358</desc>
+  <a>
+    LINESTRING (20 150, 170 150, 90 230, 20 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 359</desc>
+  <a>
+    LINESTRING (40 150, 150 150, 150 40, 20 40, 20 150, 40 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 360</desc>
+  <a>
+    LINESTRING (110 110, 200 20, 20 20, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 361</desc>
+  <a>
+    LINESTRING (200 20, 20 200, 200 200, 110 110, 110 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 362</desc>
+  <a>
+    LINESTRING (200 20, 20 200, 200 200, 20 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 363</desc>
+  <a>
+    LINESTRING (110 110, 20 110, 110 20, 20 20, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 364</desc>
+  <a>
+    LINESTRING (110 110, 200 200, 110 200, 200 110, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 365</desc>
+  <a>
+    LINESTRING (20 120, 120 120, 20 20, 120 20, 20 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 366</desc>
+  <a>
+    LINESTRING (170 100, 70 100, 170 170, 70 170, 170 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 367</desc>
+  <a>
+    LINESTRING (20 110, 110 110, 20 20, 110 20, 20 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 368</desc>
+  <a>
+    LINESTRING (110 160, 70 110, 60 160, 20 130, 110 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 369</desc>
+  <a>
+    LINESTRING (20 200, 200 200, 20 20, 200 20, 20 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 370</desc>
+  <a>
+    LINESTRING (20 110, 200 110, 200 160, 20 60, 20 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 371</desc>
+  <a>
+    LINESTRING (200 200, 110 110, 200 110, 110 200, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 372</desc>
+  <a>
+    LINESTRING (220 120, 120 20, 220 20, 120 120, 220 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 373</desc>
+  <a>
+    MULTILINESTRING ((70 20, 20 90, 70 170), (70 170, 120 90, 70 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 374</desc>
+  <a>
+    MULTILINESTRING ((20 20, 90 20, 170 20), (90 20, 90 80, 90 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 375</desc>
+  <a>
+    MULTILINESTRING ((90 140, 90 60, 90 20), (170 20, 130 20, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 376</desc>
+  <a>
+    MULTILINESTRING ((90 20, 170 100, 170 140), (170 60, 90 20, 20 60), (130 100, 130 60, 90 20, 50 90))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 377</desc>
+  <a>
+    MULTILINESTRING ((90 20, 170 100, 170 140), (130 140, 130 60, 90 20, 20 90, 90 20, 130 60, 170 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 378</desc>
+  <a>
+    MULTILINESTRING ((90 20, 170 100, 170 140), (170 60, 90 20, 20 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 379</desc>
+  <a>
+    MULTILINESTRING ((90 20, 170 100, 170 140), (170 60, 90 20, 20 60), (130 100, 90 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 380</desc>
+  <a>
+    MULTILINESTRING ((90 20, 170 100, 170 140), (170 60, 90 20, 20 60), (120 100, 170 100, 90 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 381</desc>
+  <a>
+    MULTILINESTRING ((90 20, 170 100, 170 140), (130 140, 130 60, 90 20, 20 90, 90 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 382</desc>
+  <a>
+    MULTILINESTRING ((90 20, 170 100, 170 140), (170 60, 90 20, 20 60, 20 140, 90 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 383</desc>
+  <a>
+    MULTILINESTRING ((20 20, 90 90, 20 160), (90 160, 90 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 384</desc>
+  <a>
+    MULTILINESTRING ((160 160, 90 90, 160 20), (160 120, 120 120, 90 90, 160 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 385</desc>
+  <a>
+    MULTILINESTRING ((160 160, 90 90, 160 20), (160 120, 120 120, 90 90, 120 60, 160 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 386</desc>
+  <a>
+    MULTILINESTRING ((160 160, 90 90, 160 20), (160 120, 90 90, 160 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 387</desc>
+  <a>
+    POINT (20 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 388</desc>
+  <a>
+    POLYGON ((60 120, 60 40, 160 40, 160 120, 60 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 389</desc>
+  <a>
+    POINT (70 170)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 390</desc>
+  <a>
+    POLYGON ((110 230, 80 160, 20 160, 20 20, 200 20, 200 160, 140 160, 110 230))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 391</desc>
+  <a>
+    POINT (110 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 392</desc>
+  <a>
+    POLYGON ((20 160, 80 160, 110 100, 140 160, 200 160, 200 20, 20 20, 20 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 393</desc>
+  <a>
+    POINT (100 70)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 394</desc>
+  <a>
+    POLYGON ((20 150, 100 150, 40 50, 170 50, 110 150, 190 150, 190 20, 20 20, 20 150))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 395</desc>
+  <a>
+    POLYGON ((20 150, 100 150, 40 50, 160 50, 100 150, 180 150, 180 20, 20 20, 20 150))
+  </a>
+  <test> <op name="isValid" arg1="A"> false </op> </test>
+</case>
+<case>
+  <desc>Test 396</desc>
+  <a>
+    POINT (60 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 397</desc>
+  <a>
+    POINT (110 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 398</desc>
+  <a>
+    POINT (160 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 399</desc>
+  <a>
+    POINT (100 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 400</desc>
+  <a>
+    POINT (100 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 401</desc>
+  <a>
+    POINT (60 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 402</desc>
+  <a>
+    POLYGON ((190 190, 360 20, 20 20, 190 190), (280 50, 100 50, 190 140, 280 50))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 403</desc>
+  <a>
+    POINT (190 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 404</desc>
+  <a>
+    POINT (190 190)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 405</desc>
+  <a>
+    POINT (360 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 406</desc>
+  <a>
+    POINT (130 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 407</desc>
+  <a>
+    POINT (280 50)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 408</desc>
+  <a>
+    POINT (150 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 409</desc>
+  <a>
+    POINT (100 50)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 410</desc>
+  <a>
+    POINT (140 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 411</desc>
+  <a>
+    POINT (190 50)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 412</desc>
+  <a>
+    POLYGON ((190 190, 360 20, 20 20, 190 190), (90 50, 150 110, 190 50, 90 50), (190 50, 230 110, 290 50, 190 50))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 413</desc>
+  <a>
+    POINT (180 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 414</desc>
+  <a>
+    POLYGON ((190 190, 360 20, 20 20, 190 190), (180 140, 180 40, 80 40, 180 140), (180 90, 210 140, 310 40, 230 40, 180 90))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 415</desc>
+  <a>
+    MULTIPOINT (20 80, 110 160, 20 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 416</desc>
+  <a>
+    MULTIPOINT (20 80, 60 120, 20 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 417</desc>
+  <a>
+    MULTIPOINT (10 80, 110 170, 110 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 418</desc>
+  <a>
+    MULTIPOINT (10 80, 110 170, 160 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 419</desc>
+  <a>
+    MULTIPOINT (20 120, 60 120, 110 120, 160 120, 200 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 420</desc>
+  <a>
+    MULTIPOINT (60 120, 110 120, 160 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 421</desc>
+  <a>
+    MULTIPOINT (60 120, 160 120, 160 40, 60 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 422</desc>
+  <a>
+    MULTIPOINT (20 150, 60 120, 110 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 423</desc>
+  <a>
+    MULTIPOINT (110 80, 160 120, 200 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 424</desc>
+  <a>
+    MULTIPOINT (110 80, 110 120, 110 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 425</desc>
+  <a>
+    MULTIPOINT (110 170, 110 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 426</desc>
+  <a>
+    MULTIPOINT (60 120, 160 120, 110 80, 110 170)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 427</desc>
+  <a>
+    MULTIPOINT (90 80, 130 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 428</desc>
+  <a>
+    MULTIPOINT (60 120, 160 120, 110 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 429</desc>
+  <a>
+    MULTIPOINT (40 170, 40 90, 130 170)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 430</desc>
+  <a>
+    MULTIPOINT (90 170, 280 170, 190 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 431</desc>
+  <a>
+    MULTIPOINT (190 110, 150 70, 230 70)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 432</desc>
+  <a>
+    POINT (100 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 433</desc>
+  <a>
+    MULTIPOLYGON (((20 100, 20 20, 100 20, 100 100, 20 100)), ((100 180, 100 100, 180 100, 180 180, 100 180)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 434</desc>
+  <a>
+    POINT (20 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 435</desc>
+  <a>
+    POINT (60 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 436</desc>
+  <a>
+    POINT (110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 437</desc>
+  <a>
+    MULTIPOLYGON (((110 110, 20 200, 200 200, 110 110), (110 110, 80 180, 140 180, 110 110)), ((110 110, 20 20, 200 20, 110 110), (110 110, 80 40, 140 40, 110 110)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 438</desc>
+  <a>
+    POINT (110 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 439</desc>
+  <a>
+    LINESTRING (90 80, 160 150, 300 150, 340 150, 340 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 440</desc>
+  <a>
+    POINT (90 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 441</desc>
+  <a>
+    POINT (340 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 442</desc>
+  <a>
+    POINT (230 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 443</desc>
+  <a>
+    POINT (160 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 444</desc>
+  <a>
+    POINT (90 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 445</desc>
+  <a>
+    LINESTRING (150 150, 20 20, 280 20, 150 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 446</desc>
+  <a>
+    POINT (150 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 447</desc>
+  <a>
+    POINT (150 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 448</desc>
+  <a>
+    POINT (100 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 449</desc>
+  <a>
+    POINT (220 220)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 450</desc>
+  <a>
+    LINESTRING (110 110, 220 20, 20 20, 110 110, 220 220)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 451</desc>
+  <a>
+    LINESTRING (110 110, 220 20, 20 20, 220 220)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 452</desc>
+  <a>
+    POINT (110 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 453</desc>
+  <a>
+    POINT (220 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 454</desc>
+  <a>
+    LINESTRING (220 220, 20 20, 220 20, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 455</desc>
+  <a>
+    POINT (20 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 456</desc>
+  <a>
+    LINESTRING (20 200, 20 20, 110 20, 20 110, 110 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 457</desc>
+  <a>
+    POINT (20 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 458</desc>
+  <a>
+    LINESTRING (20 200, 200 20, 20 20, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 459</desc>
+  <a>
+    LINESTRING (20 200, 200 20, 140 20, 140 80, 80 140, 20 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 460</desc>
+  <a>
+    POINT (80 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 461</desc>
+  <a>
+    LINESTRING (20 200, 110 110, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 462</desc>
+  <a>
+    LINESTRING (20 200, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 463</desc>
+  <a>
+    LINESTRING (20 200, 110 110, 200 20, 20 20, 110 110, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 464</desc>
+  <a>
+    LINESTRING (20 200, 200 20, 20 20, 110 110, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 465</desc>
+  <a>
+    LINESTRING (20 200, 110 110, 20 20, 200 20, 110 110, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 466</desc>
+  <a>
+    LINESTRING (110 110, 110 200, 20 200, 110 110, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 467</desc>
+  <a>
+    LINESTRING (110 110, 110 200, 20 200, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 468</desc>
+  <a>
+    LINESTRING (110 110, 110 200, 20 200, 200 20, 140 20, 140 80, 80 140, 20 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 469</desc>
+  <a>
+    LINESTRING (110 110, 110 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 470</desc>
+  <a>
+    LINESTRING (110 110, 110 200, 20 200, 200 20, 20 20, 110 110, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 471</desc>
+  <a>
+    LINESTRING (110 110, 110 200, 20 200, 200 20, 20 20, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 472</desc>
+  <a>
+    LINESTRING (110 110, 110 200, 20 200, 110 110, 20 20, 200 20, 110 110, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 473</desc>
+  <a>
+    LINESTRING (110 110, 110 200, 20 200, 200 20, 200 110, 110 110, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 474</desc>
+  <a>
+    LINESTRING (200 200, 110 110, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 475</desc>
+  <a>
+    LINESTRING (200 200, 20 20, 200 20, 20 200, 110 200, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 476</desc>
+  <a>
+    LINESTRING (200 200, 110 110, 200 20, 20 20, 110 110, 20 200, 110 200, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 477</desc>
+  <a>
+    LINESTRING (200 200, 20 20, 20 110, 110 110, 20 200, 110 200, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 478</desc>
+  <a>
+    POINT (110 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 479</desc>
+  <a>
+    LINESTRING (110 160, 200 250, 110 250, 110 160, 110 110, 110 20, 20 20, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 480</desc>
+  <a>
+    LINESTRING (110 160, 200 250, 110 250, 110 110, 110 20, 20 20, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 481</desc>
+  <a>
+    LINESTRING (110 160, 200 250, 110 250, 110 160, 110 20, 20 20, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 482</desc>
+  <a>
+    LINESTRING (110 110, 200 200, 110 200, 110 110, 110 20, 20 20, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 483</desc>
+  <a>
+    LINESTRING (110 110, 200 200, 110 200, 110 20, 20 20, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 484</desc>
+  <a>
+    POINT (140 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 485</desc>
+  <a>
+    LINESTRING (110 110, 200 200, 110 200, 110 110, 110 20, 200 20, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 486</desc>
+  <a>
+    POINT (90 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 487</desc>
+  <a>
+    LINESTRING (90 130, 20 130, 20 200, 90 130, 200 20, 20 20, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 488</desc>
+  <a>
+    LINESTRING (90 130, 20 130, 20 200, 200 20, 20 20, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 489</desc>
+  <a>
+    LINESTRING (200 200, 20 20, 200 20, 90 130, 20 200, 20 130, 90 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 490</desc>
+  <a>
+    LINESTRING (110 110, 20 130, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 200 130, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 491</desc>
+  <a>
+    LINESTRING (110 110, 20 130, 20 200, 200 20, 20 20, 200 200, 200 130, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 492</desc>
+  <a>
+    LINESTRING (110 110, 80 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 140 200, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 493</desc>
+  <a>
+    LINESTRING (110 110, 80 200, 20 200, 200 20, 20 20, 200 200, 140 200, 110 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 494</desc>
+  <a>
+    LINESTRING (200 200, 20 20, 200 20, 20 200, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 495</desc>
+  <a>
+    LINESTRING (200 200, 110 110, 20 20, 200 20, 110 110, 20 200, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 496</desc>
+  <a>
+    LINESTRING (200 200, 110 110, 200 20, 20 20, 110 110, 20 200, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 497</desc>
+  <a>
+    LINESTRING (90 130, 20 130, 20 200, 90 130, 110 110, 200 20, 20 20, 110 110, 200 200, 90 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 498</desc>
+  <a>
+    LINESTRING (90 130, 20 130, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 90 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 499</desc>
+  <a>
+    LINESTRING (90 130, 90 200, 20 200, 90 130, 110 110, 200 20, 20 20, 110 110, 200 200, 90 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 500</desc>
+  <a>
+    LINESTRING (90 130, 90 200, 20 200, 200 20, 20 20, 200 200, 90 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 501</desc>
+  <a>
+    LINESTRING (90 130, 90 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 90 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 502</desc>
+  <a>
+    LINESTRING (110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 503</desc>
+  <a>
+    POINT (110 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 504</desc>
+  <a>
+    LINESTRING (110 200, 110 110, 20 20, 200 20, 110 110, 110 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 505</desc>
+  <a>
+    LINESTRING (20 200, 110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 506</desc>
+  <a>
+    MULTIPOINT (50 250, 90 220, 130 190)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 507</desc>
+  <a>
+    MULTIPOINT (180 180, 230 130, 280 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 508</desc>
+  <a>
+    MULTIPOINT (50 120, 90 80, 130 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 509</desc>
+  <a>
+    MULTIPOINT (300 280, 340 240, 380 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 510</desc>
+  <a>
+    MULTIPOINT (230 150, 260 120, 290 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 511</desc>
+  <a>
+    MULTIPOINT (200 190, 240 150, 270 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 512</desc>
+  <a>
+    MULTIPOINT (160 150, 190 120, 220 90)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 513</desc>
+  <a>
+    MULTIPOINT (120 190, 160 150, 200 110)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 514</desc>
+  <a>
+    MULTIPOINT (90 80, 160 150, 340 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 515</desc>
+  <a>
+    MULTIPOINT (90 80, 160 150, 300 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 516</desc>
+  <a>
+    MULTIPOINT (90 80, 160 150, 240 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 517</desc>
+  <a>
+    MULTIPOINT (90 80, 130 120, 210 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 518</desc>
+  <a>
+    MULTIPOINT (130 120, 210 150, 340 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 519</desc>
+  <a>
+    MULTIPOINT (160 150, 240 150, 340 210)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 520</desc>
+  <a>
+    MULTIPOINT (160 150, 300 150, 340 150)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 521</desc>
+  <a>
+    MULTIPOINT (160 150, 240 150, 340 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 522</desc>
+  <a>
+    POINT (40 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 523</desc>
+  <a>
+    POINT (40 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 524</desc>
+  <a>
+    MULTIPOINT (20 20, 80 80, 20 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 525</desc>
+  <a>
+    MULTIPOINT (40 40, 80 60, 120 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 526</desc>
+  <a>
+    MULTIPOINT (40 40, 120 100, 80 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 527</desc>
+  <a>
+    MULTIPOINT (40 40, 60 100, 100 60, 120 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 528</desc>
+  <a>
+    MULTIPOINT (20 120, 60 60, 100 100, 140 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 529</desc>
+  <a>
+    MULTIPOINT (20 20, 80 70, 140 120, 200 170)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 530</desc>
+  <a>
+    MULTIPOINT (20 20, 140 120, 80 70, 200 170)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 531</desc>
+  <a>
+    MULTIPOINT (80 70, 20 20, 200 170, 140 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 532</desc>
+  <a>
+    MULTIPOINT (80 70, 140 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 533</desc>
+  <a>
+    MULTIPOINT (140 120, 80 70)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 534</desc>
+  <a>
+    MULTIPOINT (80 170, 140 120, 200 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 535</desc>
+  <a>
+    MULTIPOINT (80 170, 140 120, 200 80, 80 70)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 536</desc>
+  <a>
+    POINT (10 10)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 537</desc>
+  <a>
+    MULTIPOINT (10 10, 20 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 538</desc>
+  <a>
+    LINESTRING (10 10, 20 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 539</desc>
+  <a>
+    LINESTRING (10 10, 20 20, 20 10, 10 10)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 540</desc>
+  <a>
+    LINESTRING (40 40, 100 100, 180 100, 180 180, 100 180, 100 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 541</desc>
+  <a>
+    MULTILINESTRING ((10 10, 20 20), (20 20, 30 30))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 542</desc>
+  <a>
+    MULTILINESTRING ((10 10, 20 20), (20 20, 30 20), (20 20, 30 30))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 543</desc>
+  <a>
+    MULTILINESTRING ((10 10, 20 20), (20 20, 30 20), (20 20, 30 30), (20 20, 30 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 544</desc>
+  <a>
+    MULTILINESTRING ((10 10, 20 20), (20 20, 20 30, 30 30, 30 20, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 545</desc>
+  <a>
+    MULTILINESTRING ((10 10, 20 20, 20 30, 30 30, 30 20, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 546</desc>
+  <a>
+    POLYGON ((40 60, 420 60, 420 320, 40 320, 40 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 547</desc>
+  <a>
+    POLYGON ((40 60, 420 60, 420 320, 40 320, 40 60), (200 140, 160 220, 260 200, 200 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 548</desc>
+  <a>
+    MULTIPOINT (130 240, 130 240, 130 240, 570 240, 570 240, 570 240, 650 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 549</desc>
+  <a>
+    POLYGON ((10 10, 100 10, 100 100, 10 100, 10 10))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 550</desc>
+  <a>
+    LINESTRING (30 220, 240 220, 240 220)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 551</desc>
+  <a>
+    LINESTRING (110 290, 110 100, 110 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 552</desc>
+  <a>
+    LINESTRING (120 230, 120 200, 150 180, 180 220, 160 260, 90 250, 80 190, 140 110, 230 150, 240 230, 180 320, 60 310, 40 160, 140 50, 280 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 553</desc>
+  <a>
+    POLYGON ((200 360, 230 210, 100 190, 270 150, 360 10, 320 200, 490 230, 280 240, 200 360), (220 300, 250 200, 150 190, 290 150, 330 70, 310 210, 390 230, 280 230, 220 300))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 554</desc>
+  <a>
+    MULTIPOINT (70 340, 70 50, 430 50, 420 340, 340 120, 390 110, 390 70, 350 100, 350 50, 370 90, 320 80, 360 120, 350 80, 390 90, 420 80, 410 60, 410 100, 370 100, 380 60, 370 80, 380 100, 360 80, 370 80, 380 70, 390 80, 390 70, 410 70, 400 60, 410 60, 410 60, 410 60, 370 70, 410 50, 410 50, 410 50, 410 50, 410 50, 410 50, 410 50)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 555</desc>
+  <a>
+    MULTIPOINT (140 350, 510 140, 110 140, 250 290, 250 50, 300 370, 450 310, 440 160, 290 280, 220 160, 100 260, 320 230, 200 280, 360 130, 330 210, 380 80, 220 210, 380 310, 260 150, 260 110, 170 130)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 556</desc>
+  <a>
+    GEOMETRYCOLLECTION (POINT (110 300), POINT (100 110), POINT (130 210), POINT (150 210), POINT (150 180), POINT (130 170), POINT (140 190), POINT (130 200), LINESTRING (240 50, 210 120, 270 80, 250 140, 330 70, 300 160, 340 130, 340 130), POLYGON ((210 340, 220 260, 150 270, 230 220, 230 140, 270 210, 360 240, 260 250, 260 280, 240 270, 210 340), (230 270, 230 250, 200 250, 240 220, 240 190, 260 220, 290 230, 250 230, 230 270)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 557</desc>
+  <a>
+    MULTIPOINT (50 320, 50 280, 50 230, 50 160, 50 120, 100 120, 160 120, 210 120, 210 180, 210 150, 180 180, 140 180, 140 210, 140 260, 160 180, 140 300, 140 320, 110 320, 80 320)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 559</desc>
+  <a>
+    POLYGON ((50 50, 200 50, 200 200, 50 200, 50 50))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 560</desc>
+  <a>
+    POLYGON ((20 20, 20 160, 160 160, 160 20, 20 20), (140 140, 40 140, 40 40, 140 40, 140 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 561</desc>
+  <a>
+    POLYGON ((80 100, 220 100, 220 240, 80 240, 80 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 562</desc>
+  <a>
+    POLYGON ((20 340, 330 380, 50 40, 20 340))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 563</desc>
+  <a>
+    POLYGON ((210 320, 140 270, 0 270, 140 220, 210 320))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 564</desc>
+  <a>
+    POLYGON ((0 0, 110 0, 110 60, 40 60, 180 140, 40 220, 110 260, 0 260, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 565</desc>
+  <a>
+    POLYGON ((220 0, 110 0, 110 60, 180 60, 40 140, 180 220, 110 260, 220 260, 220 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 566</desc>
+  <a>
+    POLYGON ((0 0, 120 0, 120 50, 50 50, 120 100, 50 150, 120 150, 120 190, 0 190, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 567</desc>
+  <a>
+    POLYGON ((230 0, 120 0, 120 50, 190 50, 120 100, 190 150, 120 150, 120 190, 230 190, 230 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 568</desc>
+  <a>
+    POLYGON ((0 0, 210 0, 210 230, 0 230, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 569</desc>
+  <a>
+    MULTIPOLYGON (((40 20, 0 0, 20 40, 60 60, 40 20)), ((60 90, 60 60, 90 60, 90 90, 60 90)), ((70 120, 90 90, 100 120, 70 120)), ((120 70, 90 90, 120 100, 120 70)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 570</desc>
+  <a>
+    POLYGON ((0 0, 340 0, 340 300, 0 300, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 571</desc>
+  <a>
+    MULTIPOLYGON (((40 20, 0 0, 20 40, 60 60, 40 20)), ((60 100, 60 60, 100 60, 100 100, 60 100)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 572</desc>
+  <a>
+    POLYGON ((0 0, 120 0, 120 120, 0 120, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 573</desc>
+  <a>
+    MULTIPOLYGON (((60 20, 0 20, 60 60, 60 20)), ((60 100, 60 60, 100 60, 100 100, 60 100)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 574</desc>
+  <a>
+    POLYGON ((160 330, 60 260, 20 150, 60 40, 190 20, 270 130, 260 250, 160 330), (140 240, 80 190, 90 100, 160 70, 210 130, 210 210, 140 240))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 575</desc>
+  <a>
+    POLYGON ((300 330, 190 270, 150 170, 150 110, 250 30, 380 50, 380 250, 300 330), (290 240, 240 200, 240 110, 290 80, 330 170, 290 240))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 576</desc>
+  <a>
+    MULTIPOLYGON (((120 340, 120 200, 140 200, 140 280, 160 280, 160 200, 180 200, 180 280, 200 280, 200 200, 220 200, 220 340, 120 340)), ((360 200, 220 200, 220 180, 300 180, 300 160, 220 160, 220 140, 300 140, 300 120, 220 120, 220 100, 360 100, 360 200)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 577</desc>
+  <a>
+    MULTIPOLYGON (((100 220, 100 200, 300 200, 300 220, 100 220)), ((280 180, 280 160, 300 160, 300 180, 280 180)), ((220 140, 220 120, 240 120, 240 140, 220 140)), ((180 220, 160 240, 200 240, 180 220)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 578</desc>
+  <a>
+    MULTIPOLYGON (((100 200, 100 180, 120 180, 120 200, 100 200)), ((60 240, 60 140, 220 140, 220 160, 160 160, 160 180, 200 180, 200 200, 160 200, 160 220, 220 220, 220 240, 60 240), (80 220, 80 160, 140 160, 140 220, 80 220)), ((280 220, 240 180, 260 160, 300 200, 280 220)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 579</desc>
+  <a>
+    MULTIPOLYGON (((80 220, 80 160, 140 160, 140 220, 80 220), (100 200, 100 180, 120 180, 120 200, 100 200)), ((220 240, 220 220, 160 220, 160 200, 220 200, 220 180, 160 180, 160 160, 220 160, 220 140, 320 140, 320 240, 220 240), (240 220, 240 160, 300 160, 300 220, 240 220)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 580</desc>
+  <a>
+    POLYGON ((60 160, 140 160, 140 60, 60 60, 60 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 581</desc>
+  <a>
+    POLYGON ((160 160, 100 160, 100 100, 160 100, 160 160), (140 140, 120 140, 120 120, 140 120, 140 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 582</desc>
+  <a>
+    POLYGON ((10 10, 100 10, 10 11, 10 10))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 583</desc>
+  <a>
+    POLYGON ((90 0, 200 0, 200 200, 90 200, 90 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 584</desc>
+  <a>
+    POLYGON ((100 10, 10 10, 90 11, 90 20, 100 20, 100 10))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 585</desc>
+  <a>
+    POLYGON ((20 20, 0 20, 0 0, 20 0, 20 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 586</desc>
+  <a>
+    POLYGON ((10 10, 50 10, 50 50, 10 50, 10 31, 49 30, 10 30, 10 10))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 587</desc>
+  <a>
+    POLYGON ((60 40, 40 40, 40 20, 60 20, 60 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 588</desc>
+  <a>
+    POLYGON ((10 100, 10 10, 100 10, 100 100, 10 100), (90 90, 11 90, 10 10, 90 11, 90 90))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 589</desc>
+  <a>
+    POLYGON ((0 30, 0 0, 30 0, 30 30, 0 30))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 590</desc>
+  <a>
+    MULTIPOLYGON (((0 0, 100 0, 100 20, 0 20, 0 0)), ((0 40, 0 21, 100 20, 100 40, 0 40)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 591</desc>
+  <a>
+    POLYGON ((110 30, 90 30, 90 10, 110 10, 110 30))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 592</desc>
+  <a>
+    POLYGON ((100 10, 0 10, 100 11, 100 10))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 593</desc>
+  <a>
+    POLYGON ((100 10, 0 10, 90 11, 90 20, 100 20, 100 10))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 594</desc>
+  <a>
+    POLYGON ((10 30, 10 0, 30 10, 30 30, 10 30))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 595</desc>
+  <a>
+    POLYGON ((10 30, 10 10, 30 10, 30 30, 10 30))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 596</desc>
+  <a>
+    POLYGON ((0 0, 200 0, 0 198, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 597</desc>
+  <a>
+    POLYGON ((280 60, 139 60, 280 70, 280 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 598</desc>
+  <a>
+    POLYGON ((0 0, 140 10, 0 20, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 599</desc>
+  <a>
+    POLYGON ((280 0, 139 10, 280 1, 280 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 600</desc>
+  <a>
+    MULTIPOLYGON (((1 4, 1 1, 2 1, 2 4, 1 4)), ((3 4, 3 1, 4 1, 4 4, 3 4)), ((5 4, 5 1, 6 1, 6 4, 5 4)), ((7 4, 7 1, 8 1, 8 4, 7 4)), ((9 4, 9 1, 10 1, 10 4, 9 4)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 601</desc>
+  <a>
+    POLYGON ((0 2, 11 3, 11 2, 0 2))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 602</desc>
+  <a>
+    POLYGON ((20 40, 20 200, 180 200, 180 40, 20 40), (180 120, 120 120, 120 160, 60 120, 120 80, 120 119, 180 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 603</desc>
+  <a>
+    POLYGON ((200 160, 160 160, 160 80, 200 80, 200 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 604</desc>
+  <a>
+    LINESTRING (160 140, 160 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 605</desc>
+  <a>
+    POLYGON ((20 40, 20 200, 180 200, 180 120, 140 120, 180 119, 180 40, 20 40), (140 160, 80 120, 140 80, 140 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 606</desc>
+  <a>
+    POLYGON ((200 160, 150 160, 150 80, 200 80, 200 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 607</desc>
+  <a>
+    POLYGON ((83 33, 62 402, 68 402, 83 33))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 608</desc>
+  <a>
+    POLYGON ((78 39, 574 76, 576 60, 78 39))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 609</desc>
+  <a>
+    LINESTRING (240 190, 120 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 610</desc>
+  <a>
+    POLYGON ((110 240, 50 80, 240 70, 110 240))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 611</desc>
+  <a>
+    LINESTRING (0 100, 100 100, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 612</desc>
+  <a>
+    POLYGON ((30 240, 260 30, 30 30, 30 240), (80 140, 80 80, 140 80, 80 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 613</desc>
+  <a>
+    LINESTRING (40 340, 200 250, 120 180, 160 110, 270 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 614</desc>
+  <a>
+    MULTIPOLYGON (((60 320, 60 80, 300 80, 60 320), (80 280, 80 100, 260 100, 80 280)), ((120 160, 140 160, 140 140, 120 160)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 615</desc>
+  <a>
+    MULTILINESTRING ((100 240, 100 180, 160 180, 160 120, 220 120), (40 360, 40 60, 340 60, 40 360, 40 20), (120 120, 120 140, 100 140, 100 120, 140 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 616</desc>
+  <a>
+    MULTIPOLYGON (((60 260, 60 120, 220 120, 220 260, 60 260), (80 240, 80 140, 200 140, 200 240, 80 240)), ((100 220, 100 160, 180 160, 180 220, 100 220), (120 200, 120 180, 160 180, 160 200, 120 200)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 617</desc>
+  <a>
+    MULTILINESTRING ((40 260, 240 260, 240 240, 40 240, 40 220, 240 220), (120 300, 120 80, 140 80, 140 300, 140 80, 120 80, 120 320))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 618</desc>
+  <a>
+    MULTIPOLYGON (((60 320, 60 120, 280 120, 280 320, 60 320), (120 260, 120 180, 240 180, 240 260, 120 260)), ((280 400, 320 400, 320 360, 280 360, 280 400)), ((300 240, 300 220, 320 220, 320 240, 300 240)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 619</desc>
+  <a>
+    MULTILINESTRING ((80 300, 80 160, 260 160, 260 300, 80 300, 80 140), (220 360, 220 240, 300 240, 300 360))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 620</desc>
+  <a>
+    MULTIPOLYGON (((120 180, 60 80, 180 80, 120 180)), ((100 240, 140 240, 120 220, 100 240)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 621</desc>
+  <a>
+    MULTILINESTRING ((180 260, 120 180, 60 260, 180 260), (60 300, 60 40), (100 100, 140 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 622</desc>
+  <a>
+    POLYGON ((95 9, 81 414, 87 414, 95 9))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 623</desc>
+  <a>
+    LINESTRING (93 13, 96 13)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 624</desc>
+  <a>
+    LINESTRING (0 0, 100 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 625</desc>
+  <a>
+    LINESTRING (0 100, 100 0)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 626</desc>
+  <a>
+    LINESTRING (0 0, 100 100, 200 0)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 627</desc>
+  <a>
+    LINESTRING (0 0, 100 100, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 628</desc>
+  <a>
+    LINESTRING (40 360, 40 220, 120 360)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 629</desc>
+  <a>
+    LINESTRING (120 340, 60 220, 140 220, 140 360)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 630</desc>
+  <a>
+    LINESTRING (220 240, 200 220, 60 320, 40 300, 180 200, 160 180, 20 280)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 631</desc>
+  <a>
+    LINESTRING (220 240, 140 160, 120 180, 220 280, 200 300, 100 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 632</desc>
+  <a>
+    LINESTRING (80 320, 220 320, 220 160, 80 300)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 633</desc>
+  <a>
+    LINESTRING (60 200, 60 260, 140 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 634</desc>
+  <a>
+    LINESTRING (60 200, 60 140, 140 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 635</desc>
+  <a>
+    LINESTRING (180 200, 100 280, 20 200, 100 120, 180 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 636</desc>
+  <a>
+    LINESTRING (100 200, 220 200, 220 80, 100 80, 100 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 637</desc>
+  <a>
+    LINESTRING (0 10, 620 10, 0 11)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 638</desc>
+  <a>
+    LINESTRING (400 60, 400 10)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 639</desc>
+  <a>
+    MULTIPOLYGON (((120 320, 180 200, 240 320, 120 320)), ((180 200, 240 80, 300 200, 180 200)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 640</desc>
+  <a>
+    MULTIPOINT (120 320, 180 260, 180 320, 180 200, 300 200, 200 220)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 641</desc>
+  <a>
+    MULTIPOLYGON (((120 80, 420 80, 420 340, 120 340, 120 80), (160 300, 160 120, 380 120, 380 300, 160 300)), ((200 260, 200 160, 340 160, 340 260, 200 260), (240 220, 240 200, 300 200, 300 220, 240 220)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 642</desc>
+  <a>
+    MULTIPOINT (200 360, 420 340, 400 100, 340 120, 200 140, 200 160, 220 180, 260 200, 200 360, 420 340, 400 100, 340 120, 200 140, 200 160, 220 180, 260 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 643</desc>
+  <a>
+    MULTIPOINT (40 90, 20 20, 70 70)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 644</desc>
+  <a>
+    LINESTRING (20 20, 100 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 645</desc>
+  <a>
+    LINESTRING (20 20, 110 110, 170 50, 130 10, 70 70)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 646</desc>
+  <a>
+    MULTILINESTRING ((100 320, 100 220), (100 180, 200 180), (220 180, 220 320), (220 320, 160 320), (100 320, 100 220), (100 180, 200 180), (220 180, 220 320), (220 320, 160 320), (100 220, 100 320))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 647</desc>
+  <a>
+    MULTIPOINT (100 320, 100 260, 100 220, 100 200, 100 180, 120 180, 200 180, 220 180, 220 260, 220 320, 200 320, 160 320, 140 320, 120 320, 100 320, 100 260, 100 220, 100 200, 100 180, 120 180, 200 180, 220 180, 220 260, 220 320, 200 320, 160 320, 140 320, 120 320)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 648</desc>
+  <a>
+    MULTILINESTRING ((-500 -140, -500 -280, -320 -280, -320 -140, -500 -140, -500 -340), (-500 -140, -320 -140, -500 -140, -320 -140, -500 -140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 649</desc>
+  <a>
+    MULTIPOINT (-560 -180, -420 -180, -500 -220, -500 -340, -500 -280, -500 -140, -320 -140, -420 -140, -320 -180, -280 -140, -320 -120, -560 -180, -420 -180, -500 -220, -500 -340, -500 -280, -500 -140, -320 -140, -420 -140, -320 -180, -280 -140, -320 -120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 650</desc>
+  <a>
+    MULTILINESTRING ((180 100, 140 280, 240 140, 220 120, 140 280), (140 280, 100 400, 80 380, 140 280, 40 380, 20 360, 140 280))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 651</desc>
+  <a>
+    POINT (200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 652</desc>
+  <a>
+    MULTIPOINT (100 100, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 653</desc>
+  <a>
+    MULTIPOINT (100 100, 200 200, 300 300, 500 500)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 654</desc>
+  <a>
+    MULTIPOINT (100 100, 200 200, 400 400, 600 600)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 655</desc>
+  <a>
+    POINT (80 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 656</desc>
+  <a>
+    POINT (260 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 657</desc>
+  <a>
+    POINT (60 260)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 658</desc>
+  <a>
+    POINT (120 260)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 659</desc>
+  <a>
+    POINT (80 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 660</desc>
+  <a>
+    POINT (80 280)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 661</desc>
+  <a>
+    POLYGON ((0 0, 140 0, 140 140, 0 140, 0 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 662</desc>
+  <a>
+    POLYGON ((140 0, 0 0, 0 140, 140 140, 140 0))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 663</desc>
+  <a>
+    POLYGON ((40 60, 360 60, 360 300, 40 300, 40 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 664</desc>
+  <a>
+    POLYGON ((120 100, 280 100, 280 240, 120 240, 120 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 665</desc>
+  <a>
+    POLYGON ((80 100, 360 100, 360 280, 80 280, 80 100))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 666</desc>
+  <a>
+    POLYGON ((0 280, 0 0, 260 0, 260 280, 0 280), (220 240, 40 240, 40 40, 220 40, 220 240))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 667</desc>
+  <a>
+    POLYGON ((20 260, 240 260, 240 20, 20 20, 20 260), (160 180, 80 180, 120 120, 160 180))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 668</desc>
+  <a>
+    POLYGON ((60 80, 200 80, 200 220, 60 220, 60 80))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 669</desc>
+  <a>
+    POLYGON ((120 140, 260 140, 260 260, 120 260, 120 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 670</desc>
+  <a>
+    POLYGON ((60 220, 220 220, 140 140, 60 220))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 671</desc>
+  <a>
+    POLYGON ((100 180, 180 180, 180 100, 100 100, 100 180))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 672</desc>
+  <a>
+    POLYGON ((40 40, 180 40, 180 180, 40 180, 40 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 673</desc>
+  <a>
+    POLYGON ((180 40, 40 180, 160 280, 300 140, 180 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 674</desc>
+  <a>
+    POLYGON ((40 280, 200 280, 200 100, 40 100, 40 280), (100 220, 120 220, 120 200, 100 180, 100 220))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 675</desc>
+  <a>
+    POLYGON ((40 280, 180 260, 180 120, 60 120, 40 280))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 676</desc>
+  <a>
+    POLYGON ((0 200, 0 0, 200 0, 200 200, 0 200), (20 180, 130 180, 130 30, 20 30, 20 180))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 677</desc>
+  <a>
+    POLYGON ((60 90, 130 90, 130 30, 60 30, 60 90))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 678</desc>
+  <a>
+    LINESTRING (100 120, 100 240)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 679</desc>
+  <a>
+    POLYGON ((40 60, 160 60, 160 180, 40 180, 40 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 680</desc>
+  <a>
+    LINESTRING (80 80, 140 140, 200 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 681</desc>
+  <a>
+    POLYGON ((40 40, 140 40, 140 140, 40 140, 40 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 682</desc>
+  <a>
+    POLYGON ((190 190, 360 20, 20 20, 190 190), (111 110, 250 100, 140 30, 111 110))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 683</desc>
+  <a>
+    POLYGON ((20 200, 20 20, 240 20, 240 200, 20 200), (130 110, 60 40, 60 180, 130 110), (130 180, 131 40, 200 110, 130 180))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 684</desc>
+  <a>
+    LINESTRING (100 140, 100 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 685</desc>
+  <a>
+    MULTIPOLYGON (((20 80, 180 79, 100 0, 20 80)), ((20 160, 180 160, 100 80, 20 160)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 686</desc>
+  <a>
+    MULTIPOLYGON (((20 80, 180 80, 100 0, 20 80)), ((20 160, 180 160, 100 80, 20 160)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 687</desc>
+  <a>
+    LINESTRING (60 0, 20 80, 100 80, 80 120, 40 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 688</desc>
+  <a>
+    LINESTRING (140 300, 220 160, 260 200, 240 260)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 689</desc>
+  <a>
+    LINESTRING (60 40, 140 40, 140 160, 0 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 690</desc>
+  <a>
+    LINESTRING (140 280, 240 280, 240 180, 140 180, 140 280)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 691</desc>
+  <a>
+    LINESTRING (140 0, 0 0, 40 60, 0 120, 60 200, 220 160, 220 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 692</desc>
+  <a>
+    LINESTRING (80 140, 180 100, 160 40, 100 40, 60 100, 80 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 693</desc>
+  <a>
+    LINESTRING (20 20, 80 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 694</desc>
+  <a>
+    LINESTRING (40 40, 160 160, 200 60, 60 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 695</desc>
+  <a>
+    LINESTRING (40 40, 200 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 696</desc>
+  <a>
+    LINESTRING (200 40, 140 40, 40 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 697</desc>
+  <a>
+    LINESTRING (0 0, 110 0, 60 0)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 698</desc>
+  <a>
+    LINESTRING (0 0, 110 0)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 699</desc>
+  <a>
+    LINESTRING (0 0, 80 0, 80 60, 80 0, 170 0)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 700</desc>
+  <a>
+    MULTILINESTRING ((0 0, 170 0), (80 0, 80 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 701</desc>
+  <a>
+    LINESTRING (80 100, 180 200)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 702</desc>
+  <a>
+    LINESTRING (80 180, 180 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 703</desc>
+  <a>
+    LINESTRING (40 40, 100 100, 160 160)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 704</desc>
+  <a>
+    LINESTRING (160 60, 100 100, 60 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 705</desc>
+  <a>
+    LINESTRING (140 60, 60 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 706</desc>
+  <a>
+    LINESTRING (40 40, 180 180, 100 180, 100 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 707</desc>
+  <a>
+    LINESTRING (80 90, 50 50, 0 0)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 708</desc>
+  <a>
+    LINESTRING (40 140, 240 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 709</desc>
+  <a>
+    LINESTRING (40 140, 100 140, 80 80, 120 60, 100 140, 160 140, 160 100, 200 100, 160 140, 240 140)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 710</desc>
+  <a>
+    LINESTRING (20 20, 100 20, 20 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 711</desc>
+  <a>
+    LINESTRING (60 20, 200 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 712</desc>
+  <a>
+    LINESTRING (40 60, 180 60, 180 140, 100 140, 100 60, 220 60, 220 180, 80 180, 80 60, 280 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 713</desc>
+  <a>
+    LINESTRING (140 60, 180 60, 220 60, 260 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 714</desc>
+  <a>
+    MULTIPOINT (0 20, 40 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 715</desc>
+  <a>
+    POLYGON ((20 40, 20 0, 60 0, 60 40, 20 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 716</desc>
+  <a>
+    MULTIPOINT (0 20, 20 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 717</desc>
+  <a>
+    MULTIPOINT (20 20, 40 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 718</desc>
+  <a>
+    MULTIPOINT (80 260, 140 260, 180 260)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 719</desc>
+  <a>
+    POLYGON ((40 320, 140 320, 140 200, 40 200, 40 320))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 720</desc>
+  <a>
+    MULTIPOLYGON (((0 40, 0 0, 40 0, 40 40, 0 40)), ((40 80, 40 40, 80 40, 80 80, 40 80)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 721</desc>
+  <a>
+    LINESTRING (40 40, 120 120, 200 120)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 722</desc>
+  <a>
+    LINESTRING (40 40, 100 100, 160 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 723</desc>
+  <a>
+    POINT (60 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 724</desc>
+  <a>
+    MULTIPOINT (40 40, 100 40)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 725</desc>
+  <a>
+    LINESTRING (40 40, 80 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 726</desc>
+  <a>
+    MULTIPOINT (40 40, 60 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 727</desc>
+  <a>
+    MULTIPOINT (60 60, 100 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 728</desc>
+  <a>
+    LINESTRING (40 40, 60 60, 80 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 729</desc>
+  <a>
+    POINT (20 30)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 730</desc>
+  <a>
+    MULTIPOINT (40 40, 80 60, 40 100)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 731</desc>
+  <a>
+    MULTIPOINT (80 280, 80 220, 160 220, 80 220)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 732</desc>
+  <a>
+    MULTIPOINT (80 280, 80 220, 160 220)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 734</desc>
+  <a>
+    LINESTRING (20 60, 160 60, 80 160, 80 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 735</desc>
+  <a>
+    LINESTRING (20 80, 80 20, 80 80, 140 60, 80 20, 160 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 736</desc>
+  <a>
+    LINESTRING (20 60, 100 60, 60 100, 60 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 737</desc>
+  <a>
+    LINESTRING (20 60, 60 60, 100 60, 60 100, 60 60)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 738</desc>
+  <a>
+    LINESTRING (20 20, 80 20, 80 80, 20 20)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 739</desc>
+  <a>
+    LINESTRING (80 80, 20 20, 20 80, 140 80, 140 140, 80 80)
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 741</desc>
+  <a>
+    MULTILINESTRING ((40 140, 160 40), (160 140, 40 40))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 742</desc>
+  <a>
+    MULTILINESTRING ((20 160, 20 20), (100 160, 100 20))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 743</desc>
+  <a>
+    MULTILINESTRING ((60 140, 20 80, 60 40), (60 40, 100 80, 60 140))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 744</desc>
+  <a>
+    MULTILINESTRING ((60 40, 140 40, 100 120, 100 0), (100 200, 200 120))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 745</desc>
+  <a>
+    MULTILINESTRING ((40 120, 100 60), (160 120, 100 60), (40 60, 160 60))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 746</desc>
+  <a>
+    MULTILINESTRING ((80 160, 40 220, 40 100, 80 160), (80 160, 120 220, 120 100, 80 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 747</desc>
+  <a>
+    MULTILINESTRING ((80 160, 40 220), (80 160, 120 220, 120 100, 80 160), (40 100, 80 160))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 748</desc>
+  <a>
+    POLYGON ((180 260, 80 300, 40 180, 160 120, 180 260))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 750</desc>
+  <a>
+    MULTIPOLYGON (((240 160, 140 220, 80 60, 220 40, 240 160)), ((160 380, 100 240, 20 380, 160 380), (120 340, 60 360, 80 320, 120 340)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+<case>
+  <desc>Test 751</desc>
+  <a>
+    MULTIPOLYGON (((240 160, 100 240, 80 60, 220 40, 240 160)), ((160 380, 100 240, 20 380, 160 380), (120 340, 60 360, 80 320, 120 340)))
+  </a>
+  <test> <op name="isValid" arg1="A"> true </op> </test>
+</case>
+</run>
diff --git a/tests/testthat/testxml/general/TestWithinDistance.xml b/tests/testthat/testxml/general/TestWithinDistance.xml
new file mode 100644
index 0000000..4daa340
--- /dev/null
+++ b/tests/testthat/testxml/general/TestWithinDistance.xml
@@ -0,0 +1,92 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>PP - disjoint points</desc>
+  <a>    POINT(10 10)  </a>
+  <b>    POINT(100 100)  </b>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="200">    true   </op></test>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="100">    false  </op></test>
+</case>
+
+<case>
+  <desc>PP - overlapping points</desc>
+  <a>    POINT(10 10)  </a>
+  <b>    POINT(10 10)  </b>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="200">  true   </op></test>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="0">    true  </op></test>
+</case>
+
+<case>
+  <desc>PL - point on linestring</desc>
+  <a>    POINT (340 200)  </a>
+  <b>    LINESTRING (80 280, 340 200, 80 80)  </b>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="0">    true   </op></test>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="10">   true  </op></test>
+</case>
+
+<case>
+  <desc>PL - point not on linestring</desc>
+  <a>    LINESTRING (100 100, 200 100, 200 200, 100 200, 100 100)  </a>
+  <b>    POINT (10 10)  </b>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="128">    true   </op></test>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="127">    false  </op></test>
+</case>
+
+<case>
+  <desc>PA - point inside polygon</desc>
+  <a>    POINT (240 160)  </a>
+  <b>    POLYGON ((100 260, 340 180, 100 60, 180 160, 100 260))  </b>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="0">    true   </op></test>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="10">   true  </op></test>
+</case>
+
+<case>
+  <desc>mPA - points outside polygon</desc>
+  <a>    POLYGON ((200 180, 60 140, 60 260, 200 180))  </a>
+  <b>    MULTIPOINT (140 280, 140 320)  </b>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="60">    true   </op></test>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="57">    false  </op></test>
+</case>
+
+<case>
+  <desc>LL - disjoint linestrings</desc>
+  <a>    LINESTRING (40 300, 240 260, 60 160, 140 60)  </a>
+  <b>    LINESTRING (140 360, 260 280, 240 120, 120 160)  </b>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="18">    true   </op></test>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="17">    false  </op></test>
+</case>
+
+<case>
+  <desc>LL - crossing linestrings</desc>
+  <a>    LINESTRING (40 300, 280 220, 60 160, 140 60)  </a>
+  <b>    LINESTRING (140 360, 260 280, 240 120, 120 160)  </b>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="0">     true   </op></test>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="10">    true  </op></test>
+</case>
+
+<case>
+  <desc>AA - overlapping polygons</desc>
+  <a>    POLYGON ((60 260, 260 180, 100 60, 60 160, 60 260))  </a>
+  <b>    POLYGON ((220 280, 120 160, 300 60, 360 220, 220 280))  </b>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="0">     true   </op></test>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="10">    true  </op></test>
+</case>
+
+<case>
+  <desc>AA - disjoint polygons</desc>
+  <a>    POLYGON ((100 320, 60 120, 240 180, 200 260, 100 320))  </a>
+  <b>    POLYGON ((420 320, 280 260, 400 100, 420 320))  </b>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="72">    true   </op></test>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="71">    false  </op></test>
+</case>
+
+<case>
+  <desc>mAmA - overlapping multipolygons</desc>
+  <a>    MULTIPOLYGON (((40 240, 160 320, 40 380, 40 240)),   ((100 240, 240 60, 40 40, 100 240)))  </a>
+  <b>    MULTIPOLYGON (((220 280, 120 160, 300 60, 360 220, 220 280)),   ((240 380, 280 300, 420 340, 240 380)))  </b>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="0">    true   </op></test>
+<test><op name="isWithinDistance" arg1="A" arg2="B" arg3="10">    true  </op></test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/robust/ExternalRobustness.xml b/tests/testthat/testxml/robust/ExternalRobustness.xml
new file mode 100644
index 0000000..6d30717
--- /dev/null
+++ b/tests/testthat/testxml/robust/ExternalRobustness.xml
@@ -0,0 +1,190 @@
+<run>
+  <!-- first occurrence is used -->
+  <precisionModel type="FLOATING"/>
+  <precisionModel type="FLOATING_SINGLE"/>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+<desc>http://geos.refractions.net/pipermail/geos-devel/2005-May/001441.html</desc>
+
+ <a>
+ 0103000020E80A00000100000069010000ECA2396C13BBFF40E8BA3424319F2541DEFB1D49DFB8FF40E73660ADA07F2541FAD6C80B43B2FF407033A9AC12602541E43630383FA7FF401F0EFC9789402541470638AAD497FF408AE2E2E40721254133F2A0950484FF40D372540890012541776AF085D06BFF40B21B837624E22441E2C9515E3A4FFF40DBD7ABA2C7C22441CDA87059442EFF407956E5FE7BA32441DF5C4C09F108FF40A728EFFB4384244184A9045743DFFE40A40901092265244116A59F823EB1FE4096459A931846244141D7C822E67EFE40AD4251072A272441B29589243E48FE405630A3CD58082441A6A4FACA4 [...]
+</a>
+<b>
+ 0103000020E80A0000010000001B0000003731C25DB7A40AC123BABA3D2F2E1541482DDA6520AE15C150176B846E0E04419D9BAD51D2DD20C188B238C6A20F1341C93BA6B63EF616C1773C690356B72041AFE718BD3DE01AC1363F67295618224104666722A81614C128DF2B476DE92641E3BF74CA1BBCF1C0D43292B68C652141BDD1D74AAFA6CCC01D27263DE8A122418FF95A96AD86C240BA1AA7079685274134285EE6E81EF9C040F2AA56B1AF2C4117B1B91CDC81FA40E8363289617C3041DF296F1F14800941806416C77A5C2C4143DE3E9BAE901A41E5DD836A7C8E2E413E4390CBBBDE1E41DCBAED0B9BC82741489E9ED93 [...]
+</b>
+
+</case>
+
+<case>
+
+<desc>http://postgis.refractions.net/pipermail/postgis-users/2006-March/011316.html</desc>
+<a>
+POLYGON((742605.987032656 5087763.72510381,742599.903121688 
+5087760.56016809,742598.666141033
+5087762.50894352,742591.100910753
+5087758.50480931,742586.861672536
+5087766.63211263,742591.417801844
+5087769.04526206,742592.428792606
+5087767.35034731,742601.541294342
+5087772.18101105,742605.987032656 5087763.72510381))
+</a>
+<b>
+POLYGON((742601.541294537 5087772.18101068,742592.428792606
+5087767.35034731,742589.944404072
+5087771.51539701,742583.880455986 5087782.54873438,742582.81550675
+5087784.27809355,742583.216887765 5087784.43459684,742582.99081514
+5087785.0349637,742592.341351823 5087789.67654,742593.375823205
+5087787.7060691,742599.28794443 5087776.4640487,742601.541294537
+5087772.18101068))
+</b>
+
+</case>
+
+<case>
+<desc>http://postgis.refractions.net/pipermail/postgis-users/2006-March/011332.html</desc>
+
+<a>
+POLYGON ((613697.0000000041909516 2369267.9999981997534633, 613797.0000000043073669 2368322.9999981978908181, 613643.0000000041909516 2367807.9999981969594955, 613674.0000000041909516 2367405.9999981969594955, 613400.0000000041909516 2367299.9999981955625117, 613200.0000000040745363 2366813.9999981950968504, 613252.0000000040745363 2366474.9999981927685440, 613094.0000000040745363 2366400.9999981927685440, 612695.0000000039581209 2365506.9999981909058988, 612326.0000000038417056 2365402. [...]
+</a>
+
+<b>
+POLYGON ((607216.0000000019790605 2370623.9999982002191246, 608128.0000000019790605 2370312.9999982002191246, 608317.0000000030267984 2370101.9999982002191246, 608328.0000000030267984 2369868.9999982002191246, 608644.0000000030267984 2369847.9999982002191246, 608801.0000000030267984 2369192.9999982002191246, 608919.0000000030267984 2368811.9999982002191246, 609151.0000000030267984 2368684.9999982002191246, 609061.0000000030267984 2368332.9999982002191246, 608602.0000000030267984 2368124. [...]
+</b>
+
+</case>
+
+<case>
+<desc>http://postgis.refractions.net/pipermail/postgis-users/2006-March/011332.html (2)</desc>
+
+<a>
+ 0103000020BE6B0000010000002A000000FBFFFFFF0BB81A41D3FFFFFF12C63E41FBFFFFFF4FBD1A41D6FFFFFF66C63E41FCFFFFFF1BC11A41D7FFFFFF14C53E41FBFFFFFF93C31A41D3FFFFFFC4C23E41FCFFFFFF87C71A41D8FFFFFFC4C23E41FBFFFFFF8BD41A41D5FFFFFFBEC03E41FBFFFFFF2BD81A41D3FFFFFFDEC03E41FCFFFFFF63DA1A41DBFFFFFFB9BF3E41FCFFFFFF43D91A41D7FFFFFF5BBE3E41FBFFFFFFD7D81A41D1FFFFFFA8BC3E41FCFFFFFF37D61A41D3FFFFFF60BB3E41FCFFFFFFF3DD1A41D6FFFFFFFDB73E41FCFFFFFF6BE11A41D8FFFFFFBCB33E41FCFFFFFF4BDE1A41D8FFFFFFEBB13E41FCFFFFFF7 [...]
+</a>
+
+<b>
+ 0103000020BE6B00000100000038000000000000009C801A41D5FFFFFF33D83E41000000006C821A41D5FFFFFFE0D63E410000000038861A41D5FFFFFFE3D53E4100000000E4851A41D5FFFFFFB0D43E4100000000C0821A41D5FFFFFFF2D33E4100000000B4691A41D5FFFFFFC6CF3E410000000038681A41D5FFFFFFBDCE3E410000000038751A41D5FFFFFF76CD3E410000000068731A41D5FFFFFF30CB3E4100000000787C1A41D5FFFFFFDCCA3E4100000000B4851A41D5FFFFFFDCCA3E4100000000788B1A41D5FFFFFF23CC3E41000000004C8C1A41D5FFFFFF10CB3E4100000000A48A1A41D5FFFFFFDEC93E41000000007 [...]
+</b>
+
+</case>
+
+ <case>
+<desc>
+postgis-users/2006-November/013743.html
+Fails due to 'gore' with apex extremely close to other segment (in B)
+</desc>
+<a>
+POLYGON((5417148.108 5658342.603,5417139.016
+5658338.009,5417126.791 5658331.833,5417116.292 5658327.518,5417112.871
+5658325.598,5417110.25 5658324.127,5417106.071 5658321.781,5417104.226
+5658320.745,5417093.266 5658315.008,5417091.265 5658313.961,5417085.335
+5658310.857,5417060.44 5658326.26,5417064.68 5658327.52,5417088.83
+5658336.46,5417088.52 5658337.31,5417102.92 5658342.65,5417103.26
+5658341.83,5417111.76 5658345.51,5417121.662 5658349.583,5417121.878
+5658349.672,5417125.217 5658351.119,5417131.761 5658353.388,5417137.589
+5658356.276,5417142.166 5658359.67,5417146.599 5658364.988,5417151.395
+5658370.641,5417150.853 5658371.392,5417152.59741167
+5658373.52811061,5417154.92 5658376.37,5417155.18955743
+5658376.89699992,5417154.919 5658376.371,5417155.814
+5658378.111,5417157.051 5658380.297,5417158.004 5658382.304,5417159.014
+5658384.47,5417159.775 5658386.619,5417160.629 5658389.278,5417161.5
+5658399.49,5417160.773 5658404.194,5417159.41 5658413.02,5417158.853
+5658414.442,5417153.671 5658427.659,5417153.67051161
+5658427.6586943,5417153.67 5658427.66,5417152.73 5658427.07,5417149.993
+5658436.599,5417148.81 5658439.42,5417149.233 5658439.67,5417148.36
+5658440.81,5417146.41 5658446.6,5417144.321 5658453.127,5417144.32092232
+5658453.13043826,5417154.59 5658458.01,5417154.99551047
+5658455.8409905,5417155.446 5658453.413,5417157.23981414
+5658448.75748237,5417157.22660892 5658448.57861162,5417157.22660849
+5658448.57860592,5417157.22660865 5658448.57860812,5417157.128
+5658447.265,5417157.64950997 5658446.06368023,5417157.64950961
+5658446.06368108,5417158.314 5658444.533,5417172.322
+5658417.957,5417174.99 5658418.57,5417175.23 5658417.74,5417176.696
+5658412.61,5417177.875 5658408.488,5417178.76 5658405.39,5417178.1
+5658393.55,5417178.08 5658393.36,5417177.11 5658384.95,5417178.151
+5658384.915,5417178.14836289 5658384.91508866,5417178.12
+5658384.83,5417177.91415246 5658383.81114117,5417176.927
+5658378.944,5417176.603 5658377.341,5417176.73975922
+5658378.01762048,5417176.6 5658377.34,5417176.51210558
+5658376.89535766,5417176.428 5658376.483,5417175.235
+5658370.602,5417171.577 5658362.886,5417170.762 5658360.107,5417168.522
+5658357.989,5417166.042 5658355.047,5417164.137 5658352.264,5417162.642
+5658351.593,5417160.702 5658350.843,5417160.05417889
+5658350.5823586,5417158.82 5658350.09,5417158.82103105
+5658350.0862195,5417159.50373263 5658350.36089455,5417158.818
+5658350.085,5417159.055 5658349.214,5417155.754
+5658347.679,5417156.78066321 5658348.15640928,5417155.7525011
+5658347.6811561,5417155.161 5658348.532,5417149.028
+5658343.237,5417152.26877967 5658346.03496647,5417149.03
+5658343.24,5417148.78133339 5658343.06701453,5417148.108
+5658342.603))
+</a>
+
+<b>
+POLYGON((5417148.36 5658440.81,5417149.233
+5658439.67,5417148.81 5658439.42,5417149.993 5658436.599,5417152.73
+5658427.07,5417153.67 5658427.66,5417153.67051161
+5658427.6586943,5417153.671 5658427.659,5417158.853
+5658414.442,5417159.41 5658413.02,5417160.773 5658404.194,5417161.5
+5658399.49,5417160.63 5658389.28,5417159.78 5658386.62,5417159.366239
+5658385.46469333,5417159.014 5658384.47,5417158.004
+5658382.304,5417157.051 5658380.297,5417155.814
+5658378.111,5417155.18955747 5658376.897,5417154.92
+5658376.37,5417152.59740379 5658373.52810095,5417150.853
+5658371.392,5417151.13020611 5658371.00790076,5417151.4
+5658370.64,5417147.11100598 5658365.59149663,5417146.599
+5658364.988,5417145.96673439 5658364.22950947,5417142.17
+5658359.67,5417139.98754716 5658358.05460369,5417137.589
+5658356.276,5417131.761 5658353.388,5417125.33011568
+5658351.15822058,5417125.22 5658351.12,5417121.88 5658349.67,5417121.66
+5658349.58,5417111.76 5658345.51,5417103.26 5658341.83,5417102.92
+5658342.65,5417088.52 5658337.31,5417088.83 5658336.46,5417064.68
+5658327.52,5417060.44 5658326.26,5417085.34 5658310.86,5417085.90750076
+5658311.15666987,5417091.265 5658313.961,5417093.266
+5658315.008,5417093.61266829 5658315.18946314,5417104.23
+5658320.75,5417105.81727304 5658321.63852784,5417106.071
+5658321.781,5417106.60319005 5658322.07975996,5417110.25
+5658324.13,5417112.87 5658325.6,5417116.29 5658327.52,5417121.76604303
+5658329.76778528,5417126.791 5658331.833,5417139.016
+5658338.009,5417148.108 5658342.603,5417148.78133333
+5658343.06701449,5417149.03 5658343.24,5417152.26878253
+5658346.03496893,5417155.161 5658348.532,5417155.7525011
+5658347.6811561,5417156.78066337 5658348.15640935,5417159.055
+5658349.214,5417158.818 5658350.085,5417158.82103105
+5658350.0862195,5417158.82 5658350.09,5417160.0541792
+5658350.58235872,5417160.702 5658350.843,5417162.642
+5658351.593,5417164.137 5658352.264,5417165.25343486
+5658353.89499119,5417166.04 5658355.05,5417168.52 5658357.99,5417170.76
+5658360.11,5417171.26171711 5658361.81094338,5417171.577
+5658362.886,5417175.235 5658370.602,5417176.428
+5658376.483,5417176.51210558 5658376.89535766,5417176.6
+5658377.34,5417176.73975924 5658378.01762057,5417176.927
+5658378.944,5417177.91415134 5658383.81113564,5417178.12
+5658384.83,5417178.14836289 5658384.91508866,5417177.11
+5658384.95,5417178.08 5658393.36,5417178.1 5658393.55,5417178.76
+5658405.39,5417177.875 5658408.488,5417176.696 5658412.61,5417175.23
+5658417.74,5417174.99 5658418.57,5417172.322
+5658417.957,5417172.32037372 5658417.96008538,5417172.32
+5658417.96,5417158.31 5658444.53,5417157.64951003
+5658446.06368011,5417157.128 5658447.265,5417157.22660867
+5658448.5786084,5417157.23981414 5658448.75748238,5417155.446
+5658453.413,5417154.99551072 5658455.84098918,5417154.59
+5658458.01,5417144.32092232 5658453.13043826,5417144.321
+5658453.127,5417146.41 5658446.6,5417148.36 5658440.81))
+</b>
+
+<test>
+<op name="isValid" arg1="A">
+true
+</op>
+</test>
+
+<test>
+<op name="isValid" arg1="B">
+true
+</op>
+</test>
+
+</case>
+
+
+</run>
diff --git a/tests/testthat/testxml/robust/TestRobustOverlayFixed.xml b/tests/testthat/testxml/robust/TestRobustOverlayFixed.xml
new file mode 100644
index 0000000..2dc4917
--- /dev/null
+++ b/tests/testthat/testxml/robust/TestRobustOverlayFixed.xml
@@ -0,0 +1,18 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>AA</desc>
+  <a>
+POLYGON ((545 317, 617 379, 581 321, 545 317))
+	  </a>
+  <b>
+POLYGON ((484 290, 558 359, 543 309, 484 290))
+
+  	</b>
+<test>
+  <op name="intersection" arg1="A" arg2="B"> POINT (545 317) </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/robust/TestRobustOverlayFloat.xml b/tests/testthat/testxml/robust/TestRobustOverlayFloat.xml
new file mode 100644
index 0000000..14f9550
--- /dev/null
+++ b/tests/testthat/testxml/robust/TestRobustOverlayFloat.xml
@@ -0,0 +1,104 @@
+<run>
+  <precisionModel type="FLOATING" />
+<case>
+  <desc>AA - OLD robustness failure (works with snapping)</desc>
+  <a>
+POLYGON ((301949.68 2767249.16, 301936.52 2767241.28, 301938.87 
+2767237.43, 301952.47 2767245.59, 301950.74 2767247.81, 301949.68 
+2767249.16))
+  </a>
+  <b>
+POLYGON ((302041.321 2767264.675, 301938.823 2767237.507, 301941.21 2767233.59, 301943.821 2767229.304, 
+302048.886 2767243.046, 302041.321 2767264.675))  
+  </b>
+<test>
+  <op name="intersection" arg1="A" arg2="B"> 
+  POLYGON ((301939.1370850084 2767237.5902510053, 301938.87 2767237.43, 301938.823 2767237.507, 301939.1370850084 2767237.5902510053)) 
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - OLD robustness failure (works with snapping)</desc>
+  <a>
+POLYGON ((301936.52 2767241.28, 301933.22 2767239.3, 301934.9 
+2767236.51, 301935.54 2767235.44, 301938.87 2767237.43, 301936.52 
+2767241.28))
+  </a>
+  <b>
+POLYGON ((302041.321 2767264.675, 301938.823 2767237.507, 301941.21 2767233.59, 301943.821 2767229.304, 
+302048.886 2767243.046, 302041.321 2767264.675))  
+</b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">    
+  POLYGON ((301938.823 2767237.507, 301938.87 2767237.43, 301938.86994385667 2767237.4299664493, 301938.823 2767237.507))  
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - OLD robustness failure  (works with snapping)</desc>
+  <a>
+POLYGON ((464664.782646596 5362148.87380619, 464664.713299 5362148.758128, 464686.806220838 5362136.92416521, 
+464713.650216607 5362122.5453135, 464711.113332785 5362117.30158834, 464707.408813375 5362110.21553566, 
+464703.323866879 5362103.23305736, 464698.945488413 5362096.31213576, 464694.461274991 5362089.42505804, 
+464625.876674576 5361951.92914952, 464622.430583893 5361944.69388208, 464535.3572 5361970.739, 
+464648.194399372 5362157.89548451, 464664.782646596 5362148.87380619))  </a>
+  <b>
+POLYGON ((464769.977147523 5362187.88829332, 464765.146147008 5362180.84587461, 464754.387021019 5362169.93629911, 
+464747.786455245 5362160.11104076, 464734.810564627 5362148.45253107, 464725.386626381 5362135.71065214, 
+464712.646269 5362123.083073, 464727.794520848 5362149.37983229, 464738.165719397 5362165.72994593, 
+464746.257208116 5362179.45514151, 464752.378040379 5362191.80978275, 464769.977147523 5362187.88829332))  
+</b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">    
+  POINT (464712.646269 5362123.083073)  
+  </op>
+</test>
+</case>
+
+<case>
+  <desc>AA - OLD robustness failure  (works with snapping)</desc>
+  <a>
+POLYGON ((698400.5682737827 2388494.3828697307, 698402.3209180075 
+2388497.0819257903, 698415.3598714538 2388498.764371397, 
+698413.5003455497 2388495.90071853, 698400.5682737827 
+2388494.3828697307))
+	</a>
+  <b>
+POLYGON ((698231.847335025 2388474.57994264, 698440.416211779 
+2388499.05985776, 698432.582638943 2388300.28294705, 698386.666515791 
+2388303.40346027, 698328.29462841 2388312.88889197, 698231.847335025 
+2388474.57994264))
+	</b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">    
+  LINESTRING (698413.5003455497 2388495.90071853, 698400.5682737827 2388494.3828697307)  
+  </op>
+</test>
+</case>
+
+
+<case>
+  <desc>AA - OLD robustness failure (works with snapping)</desc>
+  <a>
+POLYGON ((698265.5760207245 2388415.007869463, 698266.5171698363 
+2388416.456984281, 698272.2367250263 2388406.868318228, 
+698271.2748419731 2388405.3872787533, 698265.5760207245 
+2388415.007869463))
+	</a>
+  <b>
+POLYGON ((698230.86813842 2388473.60074604, 698104.551776442 
+2388363.93072634, 698321.933422637 2388319.86687914, 698230.86813842 
+2388473.60074604))
+	</b>
+<test>
+  <op name="intersection" arg1="A" arg2="B">    
+  POLYGON ((698265.5760207245 2388415.007869463, 698265.5760207246 2388415.007869463, 698271.2748419731 2388405.3872787533, 698265.5760207245 2388415.007869463))  
+  </op>
+</test>
+</case>
+
+
+
+</run>
diff --git a/tests/testthat/testxml/robust/TestRobustRelate.xml b/tests/testthat/testxml/robust/TestRobustRelate.xml
new file mode 100644
index 0000000..a02be8a
--- /dev/null
+++ b/tests/testthat/testxml/robust/TestRobustRelate.xml
@@ -0,0 +1,19 @@
+<run>
+  <precisionModel scale="1.0" offsetx="0.0" offsety="0.0"/>
+
+<case>
+  <desc>PP - Point is not on line. Non-robust algorithms fail by erroneously reporting intersects=true.</desc>
+  <a>
+    LINESTRING(-123456789 -40, 381039468754763 123456789)
+  </a>
+  <b>
+    POINT(0 0)
+  </b>
+<test>
+  <op name="intersects" arg1="A" arg2="B">
+    false
+  </op>
+</test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/validate/TestRelateAA-big.xml b/tests/testthat/testxml/validate/TestRelateAA-big.xml
new file mode 100644
index 0000000..d2fb775
--- /dev/null
+++ b/tests/testthat/testxml/validate/TestRelateAA-big.xml
@@ -0,0 +1,34 @@
+<run>
+<precisionModel type="FLOATING"/>
+
+<case>
+<desc>A/A-6-18: a polygon overlapping a very skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-EP}, dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (100 100, 100 200, 200 200, 200 100, 100 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 1000000000000000 110, 1000000000000000 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-24: a polygon overlapping a very skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-NV}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (120 100, 120 200, 200 200, 200 100, 120 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 1000000000000000 110, 1000000000000000 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/validate/TestRelateAA.xml b/tests/testthat/testxml/validate/TestRelateAA.xml
new file mode 100644
index 0000000..4e6a3f1
--- /dev/null
+++ b/tests/testthat/testxml/validate/TestRelateAA.xml
@@ -0,0 +1,1793 @@
+<run>
+<precisionModel type="FLOATING"/>
+
+<case>
+<desc>A/A-1-1: same polygons [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-EP = B.A.Bdy.SP-EP}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 100, 120 100, 140 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 20 100, 120 100, 140 20, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="2FFF1FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-1-2: same polygons with reverse sequence of points [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-EP = B.A.Bdy.EP-SP}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 100, 120 100, 140 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 140 20, 120 100, 20 100, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="2FFF1FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-1-3: same polygons with different sequence of points [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-EP = B.A.Bdy.SP-EP}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 100, 120 100, 140 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (120 100, 140 20, 20 20, 20 100, 120 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="2FFF1FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-1-4: same polygons with different number of points [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-EP = B.A.Bdy.SP-EP}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 100, 120 100, 140 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 100, 60 100, 120 100, 140 20, 80 20, 20 20, 20 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="2FFF1FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-2: different polygons [dim(2){A.A.Int = B.A.Ext}]</desc>
+  <a>
+    POLYGON(
+      (0 0, 80 0, 80 80, 0 80, 0 0))
+  </a>
+  <b>
+    POLYGON(
+      (100 200, 100 140, 180 140, 180 200, 100 200))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2FF1212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-1-1: the closing point of a polygon touching the closing point of another polygon [dim(0){A.A.Bdy.CP = B.A.Bdy.CP}]</desc>
+  <a>
+    POLYGON(
+      (140 120, 160 20, 20 20, 20 120, 140 120))
+  </a>
+  <b>
+    POLYGON(
+      (140 120, 140 200, 240 200, 240 120, 140 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-1-2: the closing point of a polygon touching the boundary (at a non-vertex) of another polygon [dim(0){A.A.Bdy.CP = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (140 120, 160 20, 20 20, 20 120, 140 120))
+  </a>
+  <b>
+    POLYGON(
+      (80 180, 140 260, 260 200, 200 60, 80 180))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-1-3: the closing point of a polygon touching the boundary (at a vertex) of another polygon [dim(0){A.A.Bdy.CP = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (140 120, 160 20, 20 20, 20 120, 140 120))
+  </a>
+  <b>
+    POLYGON(
+      (240 80, 140 120, 180 240, 280 200, 240 80))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-1-4: the boundary (at a non-vertex) of a polygon touching the closing point of another polygon [dim(0){A.A.Bdy.NV = B.A.Bdy.CP}]</desc>
+  <a>
+    POLYGON(
+      (140 160, 20 20, 270 20, 150 160, 230 40, 60 40, 140 160))
+  </a>
+  <b>
+    POLYGON(
+      (140 40, 180 80, 120 100, 140 40))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-1-5: the boundary (at a non-vertex) of a polygon touching the boundary (at a vertex) of another polygon [dim(0){A.A.Bdy.NV = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (140 160, 20 20, 270 20, 150 160, 230 40, 60 40, 140 160))
+  </a>
+  <b>
+    POLYGON(
+      (120 100, 180 80, 130 40, 120 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-1-6: the boundary (at a vertex) of a polygon touching the boundary (at a non-vertex) of another polygon [dim(0){A.A.Bdy.V = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 180 20, 140 140, 20 140, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (180 100, 80 200, 180 280, 260 200, 180 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-1-7: the boundary (at a vertex) of a polygon touching the boundary (at a vertex) of another polygon [dim(0){A.A.Bdy.V = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (140 120, 160 20, 20 20, 20 120, 140 120))
+  </a>
+  <b>
+    POLYGON(
+      (140 140, 20 120, 0 220, 120 240, 140 140))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-1-8: the closing point of a polygon touching the boundary of another polygon where the closing point touching the boundary at a vertex [dim(0){A.A.Bdy.CP = B.A.Bdy.TP}]</desc>
+  <a>
+    POLYGON(
+      (160 200, 210 70, 120 70, 160 200))
+  </a>
+  <b>
+    POLYGON(
+      (160 200, 260 40, 70 40, 160 200, 20 20, 310 20, 160 200))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-1-9: the closing point of a polygon touching the boundary of another polygon where the closing point intersecting the boundary at a non-vertex [dim(0){A.A.Bdy.CP = B.A.Bdy.TP}]</desc>
+  <a>
+    POLYGON(
+      (110 140, 200 70, 200 160, 110 140))
+  </a>
+  <b>
+    POLYGON(
+      (110 140, 110 50, 60 50, 60 90, 160 190, 20 110, 20 20, 200 20, 110 140))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-2-1: two polygons touching at multiple points [dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.V = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (20 120, 20 20, 260 20, 260 120, 200 40, 140 120, 80 40, 20 120))
+  </a>
+  <b>
+    POLYGON(
+      (20 120, 20 240, 260 240, 260 120, 200 200, 140 120, 80 200, 20 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-2-2: two polygons touching at multiple points [dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.V = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (20 120, 20 20, 260 20, 260 120, 180 40, 140 120, 100 40, 20 120))
+  </a>
+  <b>
+    POLYGON(
+      (20 120, 300 120, 140 240, 20 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-2-3: two polygons touching at multiple points [dim(0){A.A.Bdy.CP = B.A.Bdy.NV}, dim(0){A.A.Bdy.V = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 300, 280 300, 280 260, 220 260, 60 100, 60 60, 280 60, 280 20, 
+      20 20))
+  </a>
+  <b>
+    POLYGON(
+      (100 140, 160 80, 280 180, 200 240, 220 160, 160 200, 180 120, 100 140))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-2-4: two polygons touching at multiple points [dim(0){A.A.Bdy.V = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 300, 280 300, 280 260, 220 260, 60 100, 60 60, 280 60, 280 20, 
+      20 20))
+  </a>
+  <b>
+    POLYGON(
+      (260 200, 180 80, 120 160, 200 160, 180 220, 260 200))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-2-5: two polygons touching at multiple points [dim(0){A.A.Bdy.V = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 280 20, 280 140, 220 60, 140 140, 80 60, 20 140, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (0 140, 300 140, 140 240, 0 140))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-2-6: two polygons touching at multiple points [dim(0){A.A.Bdy.V = B.A.Bdy.V}, dim(0){A.A.Bdy.V = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 280 20, 280 140, 220 60, 140 140, 80 60, 20 140, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 240, 20 140, 320 140, 180 240, 20 240))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-2-7: two polygons touching at multiple points [dim(0){A.A.Bdy.V = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 280 20, 280 140, 220 60, 140 140, 80 60, 20 140, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 240, 20 140, 80 180, 140 140, 220 180, 280 140, 280 240, 20 240))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-3-1: two polygons touching along a boundary [dim(1){A.A.Bdy.SP-V = B.A.Bdy.SP-NV}]</desc>
+  <a>
+    POLYGON(
+      (120 120, 180 60, 20 20, 20 120, 120 120))
+  </a>
+  <b>
+    POLYGON(
+      (120 120, 220 20, 280 20, 240 160, 120 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-3-2: two polygons touching along a boundary [dim(1){A.A.Bdy.SP-V = B.A.Bdy.SP-V}]</desc>
+  <a>
+    POLYGON(
+      (140 120, 160 20, 20 20, 20 120, 140 120))
+  </a>
+  <b>
+    POLYGON(
+      (140 120, 160 20, 260 120, 220 200, 140 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-3-3: two polygons touching along a boundary [dim(1){A.A.Bdy.SP-V = B.A.Bdy.NV-V}]</desc>
+  <a>
+    POLYGON(
+      (20 140, 120 40, 20 40, 20 140))
+  </a>
+  <b>
+    POLYGON(
+      (190 140, 190 20, 140 20, 20 140, 190 140))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-3-4: two polygons touching along a boundary [dim(1){A.A.Bdy.SP-V = B.A.Bdy.NV-V}]</desc>
+  <a>
+    POLYGON(
+      (120 120, 180 60, 20 20, 20 120, 120 120))
+  </a>
+  <b>
+    POLYGON(
+      (300 20, 220 20, 120 120, 260 160, 300 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-3-5: two polygons touching along a boundary [dim(1){A.A.Bdy.SP-V = B.A.Bdy.V-EP}]</desc>
+  <a>
+    POLYGON(
+      (140 120, 160 20, 20 20, 20 120, 140 120))
+  </a>
+  <b>
+    POLYGON(
+      (140 120, 240 160, 280 60, 160 20, 140 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-3-6: two polygons touching along a boundary [dim(1){A.A.Bdy.SP-V = B.A.Bdy.V-V}]</desc>
+  <a>
+    POLYGON(
+      (120 120, 180 60, 20 20, 20 120, 120 120))
+  </a>
+  <b>
+    POLYGON(
+      (280 60, 180 60, 120 120, 260 180, 280 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-3-7: two polygons touching along a boundary [dim(1){A.A.Bdy.NV-NV = B.A.Bdy.V-V}]</desc>
+  <a>
+    POLYGON(
+      (140 120, 160 20, 20 20, 20 120, 140 120))
+  </a>
+  <b>
+    POLYGON(
+      (120 200, 120 120, 40 120, 40 200, 120 200))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-3-8: two polygons touching along a boundary [dim(1){A.A.Bdy.NV-EP = B.A.Bdy.V-V}]</desc>
+  <a>
+    POLYGON(
+      (140 120, 160 20, 20 20, 20 120, 140 120))
+  </a>
+  <b>
+    POLYGON(
+      (160 220, 140 120, 60 120, 40 220, 160 220))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-3-9: two polygons touching along a boundary [dim(1){A.A.Bdy.V-EP = B.A.Bdy.V-SP}]</desc>
+  <a>
+    POLYGON(
+      (140 120, 160 20, 20 20, 20 120, 140 120))
+  </a>
+  <b>
+    POLYGON(
+      (140 120, 20 120, 20 220, 140 220, 140 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-3-3-10: two polygons touching along a boundary [dim(1){A.A.Bdy.V-V = B.A.Bdy.NV-NV}]</desc>
+  <a>
+    POLYGON(
+      (120 120, 180 60, 20 20, 20 120, 120 120))
+  </a>
+  <b>
+    POLYGON(
+      (320 20, 220 20, 80 160, 240 140, 320 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-1: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-EP = B.A.Int}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (60 40, 60 140, 180 140, 180 40, 60 40))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212FF1FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-2-1: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.CP = B.A.Bdy.CP}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 80 140, 160 60, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-2-2: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.CP = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (160 60, 20 20, 100 140, 160 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-2-3: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.NV = B.A.Bdy.CP}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 100, 140 160, 160 40, 20 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-2-4: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.NV = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (160 40, 20 100, 160 160, 160 40))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-2-5: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.V = B.A.Bdy.CP}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 180, 180 120, 80 40, 20 180))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-2-6: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.V = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (180 120, 100 40, 20 180, 180 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-3-1: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.NV = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 140 40, 140 120, 20 160, 80 80, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-3-2: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.V = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 140 40, 140 140, 20 180, 80 100, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-3-3: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.NV = B.A.Bdy.V}, dim(0){A.A.Bdy.NV = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (40 180, 60 100, 180 100, 200 180, 120 120, 40 180))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-3-4: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.V = B.A.Bdy.CP}, dim(0){A.A.Bdy.V = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 180, 60 80, 180 80, 220 180, 120 120, 20 180))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-3-5: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.V = B.A.Bdy.V}, dim(0){A.A.Bdy.NV = B.A.Bdy.V}, dim(0){A.A.Bdy.NV = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (40 60, 20 180, 100 100, 140 180, 160 120, 220 100, 140 40, 40 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-3-6: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.V = B.A.Bdy.V}, dim(0){A.A.Bdy.V = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (60 100, 180 100, 220 180, 120 140, 20 180, 60 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F01FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-4-1: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-NV = B.A.Bdy.SP-V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 20 140, 120 120, 120 40, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F11FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-4-2: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-V = B.A.Bdy.SP-V)}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 20 180, 140 140, 140 60, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F11FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-4-3: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-NV = B.A.Bdy.V-EP}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 120 40, 120 120, 20 140, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F11FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-4-4: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-NV = B.A.Bdy.V-V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (120 40, 20 20, 20 140, 120 120, 120 40))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F11FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-4-5: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-V = B.A.Bdy.V-EP}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 140 60, 140 140, 20 180, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F11FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-4-6: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-V = B.A.Bdy.V-V}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (140 60, 20 20, 20 180, 140 140, 140 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F11FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-4-7: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.NV-EP = B.A.Bdy.V-EP}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 60 120, 140 120, 180 20, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F11FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-4-8: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.NV-NV = B.A.Bdy.V-EP}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 40, 120 40, 120 120, 20 140, 20 40))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F11FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-5-5-1: a polygon containing another polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.SP-V = B.A.Bdy.SP-V},  dim(1){A.A.Bdy.(NV, V) = B.A.Bdy.(V, V)}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 20 180, 220 180, 220 20, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 20 180, 60 120, 100 180, 140 120, 220 180, 200 120, 140 60, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212F11FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-1: a polygon overlapping another polygon [dim(2){A.A.Int = B.A.Int}]</desc>
+  <a>
+    POLYGON(
+      (150 150, 330 150, 250 70, 70 70, 150 150))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 270 150, 140 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-2: a polygon overlapping another polygon [dim(2){A.A.Int = B.A.Int}]</desc>
+  <a>
+    POLYGON(
+      (150 150, 270 150, 330 150, 250 70, 190 70, 70 70, 150 150))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 270 150, 190 70, 140 20, 20 20, 70 70, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-3: spiky polygons overlapping; boundary <-> boundary intersecting at 0 dimension [dim(2){A.A.Int = B.A.Int}]</desc>
+  <a>
+    POLYGON(
+      (20 20, 60 50, 20 40, 60 70, 20 60, 60 90, 20 90, 70 110, 20 130, 
+      80 130, 20 150, 80 160, 20 170, 80 180, 20 200, 80 200, 30 240, 80 220, 50 260, 
+      100 220, 100 260, 120 220, 130 260, 140 220, 150 280, 150 190, 160 280, 170 190, 180 280, 
+      190 190, 200 280, 210 190, 220 280, 230 190, 240 260, 250 230, 260 260, 260 220, 290 270, 
+      290 220, 330 260, 300 210, 340 240, 290 180, 340 210, 290 170, 350 170, 240 150, 350 150, 
+      240 140, 350 130, 240 120, 350 120, 240 110, 350 110, 240 100, 350 100, 240 90, 350 90, 
+      240 80, 350 80, 300 70, 340 60, 290 60, 340 40, 300 50, 340 20, 270 60, 310 20, 
+      250 60, 270 20, 230 60, 240 20, 210 60, 210 20, 190 70, 190 20, 180 90, 170 20, 
+      160 90, 150 20, 140 90, 130 20, 120 90, 110 20, 100 90, 100 20, 90 60, 80 20, 
+      70 40, 20 20))
+  </a>
+  <b>
+    POLYGON(
+      (190 140, 140 130, 200 160, 130 150, 210 170, 130 170, 210 180, 120 190, 220 200, 
+      120 200, 250 210, 120 210, 250 220, 120 220, 250 230, 120 240, 230 240, 120 250, 240 260, 
+      120 260, 240 270, 120 270, 270 290, 120 290, 230 300, 150 310, 250 310, 180 320, 250 320, 
+      200 360, 260 330, 240 360, 280 320, 290 370, 290 320, 320 360, 310 320, 360 360, 310 310, 
+      380 340, 310 290, 390 330, 310 280, 410 310, 310 270, 420 280, 310 260, 430 250, 300 250, 
+      440 240, 300 240, 450 230, 280 220, 440 220, 280 210, 440 210, 300 200, 430 190, 300 190, 
+      440 180, 330 180, 430 150, 320 180, 420 130, 300 180, 410 120, 280 180, 400 110, 280 170, 
+      390 90, 280 160, 400 70, 270 160, 450 30, 260 160, 420 30, 250 160, 390 30, 240 160, 
+      370 30, 230 160, 360 30, 230 150, 330 50, 240 130, 330 30, 230 130, 310 30, 220 130, 
+      280 30, 230 100, 270 40, 220 110, 250 30, 210 130, 240 30, 210 100, 220 40, 200 90, 
+      200 20, 190 100, 180 30, 20 20, 180 40, 20 30, 180 50, 20 50, 180 60, 30 60, 
+      180 70, 20 70, 170 80, 80 80, 170 90, 20 80, 180 100, 40 100, 200 110, 60 110, 
+      200 120, 120 120, 190 140))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-4: spiky polygons overlapping; boundary <-> boundary intersecting at 1 dimension at a few locations [dim(2){A.A.Int = B.A.Int}]</desc>
+  <a>
+    POLYGON(
+      (70 150, 20 160, 110 160, 20 180, 100 200, 20 200, 190 210, 20 210, 160 220, 
+      20 220, 150 230, 60 240, 180 250, 20 260, 170 260, 60 270, 160 270, 100 310, 170 280, 
+      200 260, 180 230, 210 260, 130 330, 230 250, 210 290, 240 250, 230 210, 260 300, 250 230, 
+      270 300, 270 240, 300 340, 280 250, 320 330, 290 250, 340 350, 290 240, 350 360, 270 190, 
+      350 340, 290 200, 350 330, 300 190, 360 320, 310 190, 360 300, 320 200, 360 280, 330 200, 
+      360 260, 340 200, 370 260, 340 180, 390 290, 340 170, 400 260, 350 170, 400 250, 350 160, 
+      410 240, 350 150, 400 170, 350 140, 310 170, 340 140, 270 180, 330 140, 260 170, 310 140, 
+      240 170, 290 140, 200 190, 270 140, 180 190, 260 140, 170 190, 260 130, 170 180, 250 130, 
+      170 170, 240 120, 170 160, 210 120, 170 150, 210 110, 340 130, 230 110, 420 140, 220 100, 
+      410 130, 220 90, 400 120, 220 80, 390 110, 220 70, 420 110, 240 70, 420 100, 260 70, 
+      420 90, 280 70, 430 80, 230 60, 430 60, 270 50, 450 40, 210 50, 370 40, 260 40, 
+      460 30, 160 40, 210 60, 200 110, 190 60, 190 120, 170 50, 180 130, 150 30, 170 130, 
+      140 20, 160 120, 130 20, 160 150, 120 20, 160 170, 110 20, 160 190, 100 20, 150 190, 
+      90 20, 140 180, 80 20, 120 140, 70 20, 120 150, 60 20, 110 150, 50 20, 100 140, 
+      50 30, 90 130, 40 30, 80 120, 30 30, 80 130, 30 40, 80 140, 20 40, 70 140, 
+      40 90, 60 130, 20 90, 60 140, 20 130, 70 150))
+  </a>
+  <b>
+    POLYGON(
+      (190 140, 140 130, 200 160, 130 150, 210 170, 130 170, 210 180, 120 190, 220 200, 
+      120 200, 250 210, 120 210, 250 220, 120 220, 250 230, 120 240, 230 240, 120 250, 240 260, 
+      120 260, 240 270, 120 270, 270 290, 120 290, 230 300, 150 310, 250 310, 180 320, 250 320, 
+      200 360, 260 330, 240 360, 280 320, 290 370, 290 320, 320 360, 310 320, 360 360, 310 310, 
+      380 340, 310 290, 390 330, 310 280, 410 310, 310 270, 420 280, 310 260, 430 250, 300 250, 
+      440 240, 300 240, 450 230, 280 220, 440 220, 280 210, 440 210, 300 200, 430 190, 300 190, 
+      440 180, 330 180, 430 150, 320 180, 420 130, 300 180, 410 120, 280 180, 400 110, 280 170, 
+      390 90, 280 160, 400 70, 270 160, 450 30, 260 160, 420 30, 250 160, 390 30, 240 160, 
+      370 30, 230 160, 360 30, 230 150, 330 50, 240 130, 330 30, 230 130, 310 30, 220 130, 
+      280 30, 230 100, 270 40, 220 110, 250 30, 210 130, 240 30, 210 100, 220 40, 200 90, 
+      200 20, 190 100, 180 30, 20 20, 180 40, 20 30, 180 50, 20 50, 180 60, 30 60, 
+      180 70, 20 70, 170 80, 80 80, 170 90, 20 80, 180 100, 40 100, 200 110, 60 110, 
+      200 120, 120 120, 190 140))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-5: a polygon overlapping another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.V = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (60 160, 220 160, 220 20, 60 20, 60 160))
+  </a>
+  <b>
+    POLYGON(
+      (60 160, 20 200, 260 200, 220 160, 140 80, 60 160))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-6: a polygon overlapping another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.V = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (60 160, 220 160, 220 20, 60 20, 60 160))
+  </a>
+  <b>
+    POLYGON(
+      (60 160, 20 200, 260 200, 140 80, 60 160))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-7: a polygon overlapping another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.CP = B.A.Bdy.NV}, dim(0){A.A.Bdy.V = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (60 160, 220 160, 220 20, 60 20, 60 160))
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 140 80, 260 200, 20 200))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-8: a polygon overlapping another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.CP = B.A.Bdy.V}, dim(0){A.A.Bdy.V = B.A.Bdy.V}]</desc>
+  <a>
+    POLYGON(
+      (60 160, 220 160, 220 20, 60 20, 60 160))
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 60 160, 140 80, 220 160, 260 200, 20 200))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-9: a polygon overlapping another polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.CP = B.A.Bdy.V}, dim(0){A.A.Bdy.V = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (60 160, 220 160, 220 20, 60 20, 60 160))
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 60 160, 140 80, 260 200, 20 200))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-10: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (0 0, 0 200, 200 200, 200 0, 0 0))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 1000000 110, 10000000 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-11: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.NV = B.A.Bdy.CP}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (100 0, 100 200, 200 200, 200 0, 100 0))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 1000000 110, 10000000 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-12: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int},  dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (120 0, 120 200, 200 200, 200 0, 120 0))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 1000000 110, 10000000 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-13: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (0 0, 0 200, 110 200, 110 0, 0 0))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 1000000 110, 10000000 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-14: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-EP}, dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (100 100, 100 200, 200 200, 200 100, 100 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 2100 110, 2100 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-15: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-EP}, dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (100 100, 100 200, 200 200, 200 100, 100 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 2101 110, 2101 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-16: two skinny polygons overlapping [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-EP}, dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (100 100, 200 200, 200 100, 100 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 2101 110, 2101 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-17: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-EP}, dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (100 100, 100 200, 200 200, 200 100, 100 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 1000000 110, 1000000 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-19: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-NV}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (120 100, 120 200, 200 200, 200 100, 120 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 500 110, 500 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-20: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-NV}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (120 100, 120 200, 200 200, 200 100, 120 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 501 110, 501 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-21: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-NV}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (120 100, 130 200, 200 200, 200 100, 120 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 501 110, 501 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-22: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-NV}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (120 100, 17 200, 200 200, 200 100, 120 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 501 110, 501 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-23: a polygon overlapping a skinny polygon [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-NV}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (120 100, 120 200, 200 200, 200 100, 120 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 1000000 110, 1000000 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-25: two skinny polygons overlapping [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (101 99, 101 1000000, 102 1000000, 101 99))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 1000000 110, 1000000 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-26: two skinny polygons overlapping [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.Bdy.V-EP = B.A.Bdy.NV-EP}, dim(0){A.A.Bdy.CP = B.A.Bdy.CP}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (100 100, 200 101, 200 100, 100 100))
+  </a>
+  <b>
+    POLYGON(
+      (100 100, 2101 110, 2101 100, 100 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/A-6-26: two polygons overlapping [dim(2){A.A.Int = B.A.Int}, dim(0){A.A.Bdy.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (16 319, 150 39, 25 302, 160 20, 265 20, 127 317, 16 319))
+  </a>
+  <b>
+    POLYGON(
+      (10 307, 22 307, 153 34, 22 34, 10 307))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212101212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-3-1: the closing point of a polygon touching the closing points of another polygon and its hole [dim(0){A.A.Bdy.CP = B.A.oBdy.CP}, dim(0){A.A.Bdy.CP = B.A.iBdy.CP}]</desc>
+  <a>
+    POLYGON(
+      (160 200, 210 70, 120 70, 160 200))
+  </a>
+  <b>
+    POLYGON(
+      (160 200, 310 20, 20 20, 160 200), 
+      (160 200, 260 40, 70 40, 160 200))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-3-2: the boundary of a polygon touching the inner boundary of another polygon at two spots [dim(2){A.A.Int = B.A.Ext.h}, dim(0){A.A.oBdy.SP = B.A.iBdy.SP}, dim(0){A.A.oBdy.V = B.A.iBdy.V}]</desc>
+  <a>
+    POLYGON(
+      (170 120, 240 100, 260 50, 190 70, 170 120))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-3-3: the boundary of a polygon touching the inner boundary of another polygon at two spots [dim(2){A.A.Int = B.A.Ext.h}, dim(0){A.A.oBdy.SP = B.A.iBdy.SP}, dim(0){A.A.oBdy.V = B.A.iBdy.V}]</desc>
+  <a>
+    POLYGON(
+      (270 90, 200 50, 150 80, 210 120, 270 90))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-3-4: the boundary of a polygon touching the inner boundary of another polygon at one spot [dim(2){A.A.Int = B.A.Ext.h}, dim(0){A.A.oBdy.SP = B.A.iBdy.SP}]</desc>
+  <a>
+    POLYGON(
+      (170 120, 260 100, 240 60, 150 80, 170 120))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-3-5: the boundary of a polygon touching the inner boundary of another polygon at one spot [dim(2){A.A.Int = B.A.Ext.h}, dim(0){A.A.oBdy.SP = B.A.iBdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (220 120, 270 80, 200 60, 160 100, 220 120))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-3-6: the boundary of a polygon touching the inner boundary of another polygon at one spot [dim(2){A.A.Int = B.A.Ext.h}, dim(0){A.A.oBdy.SP = B.A.iBdy.V}]</desc>
+  <a>
+    POLYGON(
+      (260 50, 180 70, 180 110, 260 90, 260 50))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-3-7: the boundary of a polygon touching the inner boundary of another polygon at two spots [dim(2){A.A.Int = B.A.Ext.h}, dim(0){A.A.oBdy.V = B.A.iBdy.NV}, dim(0){A.A.oBdy.V = B.A.iBdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (230 110, 290 80, 190 60, 140 90, 230 110))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-3-8: the boundary of a polygon touching the inner boundary of another polygon [dim(2){A.A.Int = B.A.Ext.h}, dim(1){A.A.oBdy.SP-EP = B.A.iBdy.SP-EP}]</desc>
+  <a>
+    POLYGON(
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F1F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-3-9: part of the boundary of a polygon touching part of the inner boundary of another polygon [dim(2){A.A.Int = B.A.Ext.h}, dim(1){A.A.oBdy.SP-V = B.A.iBdy.SP-NV}, dim(1){A.A.oBdy.V-EP = B.A.iBdy.NV-EP}]</desc>
+  <a>
+    POLYGON(
+      (170 120, 330 120, 280 70, 120 70, 170 120))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-3-10: part of the boundary of a polygon touching part of the inner boundary of another polygon [dim(2){A.A.Int = B.A.Ext.h}, dim(1){A.A.oBdy.SP-V = B.A.iBdy.SP-NV}, dim(1){A.A.oBdy.V-EP = B.A.iBdy.NV-EP}]</desc>
+  <a>
+    POLYGON(
+      (170 120, 300 120, 250 70, 120 70, 170 120))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-3-11: part of the boundary of a polygon touching part of the inner boundary of another polygon [dim(2){A.A.Int = B.A.Ext.h}, dim(1){A.A.oBdy.V-V-V = B.A.iBdy.NV-V-NV}]</desc>
+  <a>
+    POLYGON(
+      (190 100, 310 100, 260 50, 140 50, 190 100))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-5-1: an entire polygon within another polygon which has a hole [dim(2){A.A.Ext = B.A.Int}, dim(2){A.A.Int = B.A.Int}]</desc>
+  <a>
+    POLYGON(
+      (280 130, 360 130, 270 40, 190 40, 280 130))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 250 120, 180 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="2FF1FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-5-2: an entire polygon within another polygon which has a hole [dim(2){A.A.Int = B.A.Int}, dim(2){A.A.Ext = B.A.Int}]</desc>
+  <a>
+    POLYGON(
+      (220 80, 180 40, 80 40, 170 130, 270 130, 230 90, 300 90, 250 30, 280 30, 
+      390 140, 150 140, 40 30, 230 30, 280 80, 220 80))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 250 120, 180 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="2FF1FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-5-3: polygon A within polygon B, the boundary of A touching the inner boundary of B [dim(2){A.A.Int = B.A.Int}, dim(2){A.A.Ext = B.A.Int}, dim(1){A.A.Bdy.NV-NV = B.A.iBdy.V-V}]</desc>
+  <a>
+    POLYGON(
+      (260 130, 360 130, 280 40, 170 40, 260 130))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 250 120, 180 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="2FF11F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-5-4: polygon A within polygon B, the boundary of A touching the inner boundary of B [dim(2){A.A.Int = B.A.Int}, dim(2){A.A.Ext = B.A.Int}, dim(1){A.A.Bdy.V-V = B.A.iBdy.NV-NV}]</desc>
+  <a>
+    POLYGON(
+      (240 110, 340 110, 290 60, 190 60, 240 110))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 250 120, 180 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="2FF11F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/Ah-5-5: polygon A within polygon B, the boundary of A touching the inner boundary of B [dim(2){A.A.Int = B.A.Int}, dim(2){A.A.Ext = B.A.Int}, dim(1){A.A.Bdy.V-V = B.A.iBdy.V-V}]</desc>
+  <a>
+    POLYGON(
+      (250 120, 350 120, 280 50, 180 50, 250 120))
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 250 120, 180 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="2FF11F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>Ah/Ah-1-1: same polygons (with a hole) [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.oBdy.SP-EP = B.A.oBdy.SP-EP}, dim(1){A.A.iBdy.SP-EP = B.A.iBdy.SP-EP}]</desc>
+  <a>
+    POLYGON(
+      (230 210, 230 20, 20 20, 20 210, 230 210), 
+      (120 180, 50 50, 200 50, 120 180))
+  </a>
+  <b>
+    POLYGON(
+      (230 210, 230 20, 20 20, 20 210, 230 210), 
+      (120 180, 50 50, 200 50, 120 180))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="2FFF1FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A2h/A2h-1-1: same polygons (with two holes) [dim(2){A.A.Int = B.A.Int}, dim(1){A.A.oBdy.SP-EP = B.A.oBdy.SP-EP}, dim(1){A.A.iBdy.SP-EP = B.A.iBdy.SP-EP}]</desc>
+  <a>
+    POLYGON(
+      (230 210, 230 20, 20 20, 20 210, 230 210), 
+      (140 40, 40 40, 40 170, 140 40), 
+      (110 190, 210 190, 210 50, 110 190))
+  </a>
+  <b>
+    POLYGON(
+      (230 210, 230 20, 20 20, 20 210, 230 210), 
+      (140 40, 40 40, 40 170, 140 40), 
+      (110 190, 210 190, 210 50, 110 190))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="2FFF1FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/mA-3-1: a polygon touching multipolygon at two points [dim(2){A.A.Int = B.2A.Ext}, dim(0){A.A.oBdy.CP = B.2A2.oBdy.NV}, dim(0){A.A.oBdy.V = B.2A1.oBdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (280 190, 330 150, 200 110, 150 150, 280 190))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (140 110, 260 110, 170 20, 50 20, 140 110)), 
+      (
+        (300 270, 420 270, 340 190, 220 190, 300 270)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/mA-3-2: a polygon touching multipolygon at two points [dim(2){A.A.Int = B.2A.Ext}, dim(0){A.A.oBdy.V = B.2A1.oBdy.CP}, dim(0){A.A.oBdy.V = B.2A2.oBdy.V}]</desc>
+  <a>
+    POLYGON(
+      (80 190, 220 190, 140 110, 0 110, 80 190))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (140 110, 260 110, 170 20, 50 20, 140 110)), 
+      (
+        (300 270, 420 270, 340 190, 220 190, 300 270)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/mA-3-3: a polygon touching multipolygon at two points [dim(2){A.A.Int = B.2A.Ext}, dim(0){A.A.oBdy.V = B.2A2.oBdy.NV}, dim(0){A.A.oBdy.V = B.2A1.oBdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (330 150, 200 110, 150 150, 280 190, 330 150))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (140 110, 260 110, 170 20, 50 20, 140 110)), 
+      (
+        (300 270, 420 270, 340 190, 220 190, 300 270)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/mA-3-4: a polygon touching multipolygon at one spoint [dim(2){A.A.Int = B.2A.Ext}, dim(0){A.A.oBdy.V = B.2A2.oBdy.NV}]</desc>
+  <a>
+    POLYGON(
+      (290 190, 340 150, 220 120, 170 170, 290 190))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (140 110, 260 110, 170 20, 50 20, 140 110)), 
+      (
+        (300 270, 420 270, 340 190, 220 190, 300 270)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/mA-3-5: a polygon touching multipolygon along boundaries [dim(2){A.A.Int = B.2A.Ext}, dim(1){A.A.oBdy.SP-V = B.2A2.oBdy.V-V}, dim(1){A.A.oBdy.V-V = B.2A1.oBdy.V-SP}]</desc>
+  <a>
+    POLYGON(
+      (220 190, 340 190, 260 110, 140 110, 220 190))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (140 110, 260 110, 170 20, 50 20, 140 110)), 
+      (
+        (300 270, 420 270, 340 190, 220 190, 300 270)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/mA-3-6: a polygon touching multipolygon along boundaries and at a point [dim(2){A.A.Int = B.2A.Ext}, dim(1){A.A.oBdy.V-NV = B.2A1.oBdy.NV-SP}, dim(0){A.A.oBdy.V = B.2A2.oBdy.V}]</desc>
+  <a>
+    POLYGON(
+      (140 190, 220 190, 100 70, 20 70, 140 190))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (140 110, 260 110, 170 20, 50 20, 140 110)), 
+      (
+        (300 270, 420 270, 340 190, 220 190, 300 270)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>A/mA-6-1: a polygon overlapping multipolygon [dim(2){A.A.Int = B.4A.Int}, dim(0){A.A.Bdy.NV = B.A.Bdy.V}, dim(0){A.A.Bdy.NV = B.A.Bdy.CP}, dim(0){A.A.Bdy.NV = B.A.Bdy.V}, dim(0){A.A.Bdy.NV = B.A.Bdy.CP}]</desc>
+  <a>
+    POLYGON(
+      (140 220, 60 140, 140 60, 220 140, 140 220))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (100 20, 180 20, 180 100, 100 100, 100 20)), 
+      (
+        (20 100, 100 100, 100 180, 20 180, 20 100)), 
+      (
+        (100 180, 180 180, 180 260, 100 260, 100 180)), 
+      (
+        (180 100, 260 100, 260 180, 180 180, 180 100)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="21210F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mA/mA-3-1: MultiPolygon touching MultiPolygon [dim(0){A.mA.Bdy.TP = B.mA.Bdy.TP}]</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (110 110, 70 200, 150 200, 110 110)), 
+      (
+        (110 110, 150 20, 70 20, 110 110)))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (110 110, 160 160, 210 110, 160 60, 110 110)), 
+      (
+        (110 110, 60 60, 10 110, 60 160, 110 110)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mAh/mAh-3-1: MultiPolygon touching MultiPolygon [dim(0){A.mA.Bdy.TP = B.mA.Bdy.TP}]</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (110 110, 70 200, 150 200, 110 110), 
+        (110 110, 100 180, 120 180, 110 110)), 
+      (
+        (110 110, 150 20, 70 20, 110 110), 
+        (110 110, 120 40, 100 40, 110 110)))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (110 110, 160 160, 210 110, 160 60, 110 110), 
+        (110 110, 160 130, 160 90, 110 110)), 
+      (
+        (110 110, 60 60, 10 110, 60 160, 110 110), 
+        (110 110, 60 90, 60 130, 110 110)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F01212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mAh/mAh-3-2: MultiPolygon touching MultiPolygon [dim(1){A.mA.Bdy.NV-EP = B.mA.Bdy.V-SP}, dim(1){A.mA.Bdy.SP-NV = B.mA.Bdy.EP-V}]</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (110 110, 70 200, 200 200, 110 110), 
+        (110 110, 100 180, 120 180, 110 110)), 
+      (
+        (110 110, 200 20, 70 20, 110 110), 
+        (110 110, 120 40, 100 40, 110 110)))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (110 110, 160 160, 210 110, 160 60, 110 110), 
+        (110 110, 160 130, 160 90, 110 110)), 
+      (
+        (110 110, 60 60, 10 110, 60 160, 110 110), 
+        (110 110, 60 90, 60 130, 110 110)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mAh/mAh-3-3: MultiPolygon touching MultiPolygon [dim(1){A.mA.Bdy.SP-NV = B.mA.Bdy.EP-V}, dim(1){A.mA.Bdy.NV-EP = B.mA.Bdy.V-SP},   dim(1){A.mA.Bdy.NV-EP = B.mA.Bdy.V-SP}, dim(1){A.mA.Bdy.SP-NV = B.mA.Bdy.EP-V}]</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (110 110, 20 200, 200 200, 110 110), 
+        (110 110, 100 180, 120 180, 110 110)), 
+      (
+        (110 110, 200 20, 20 20, 110 110), 
+        (110 110, 120 40, 100 40, 110 110)))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (110 110, 160 160, 210 110, 160 60, 110 110), 
+        (110 110, 160 130, 160 90, 110 110)), 
+      (
+        (110 110, 60 60, 10 110, 60 160, 110 110), 
+        (110 110, 60 90, 60 130, 110 110)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mAh/mAh-6-1: MultiPolygon touching MultiPolygon [dim(2){A.mA.Int = B.mA.Int}]</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (110 110, 70 200, 200 200, 110 110), 
+        (110 110, 100 180, 120 180, 110 110)), 
+      (
+        (110 110, 200 20, 70 20, 110 110), 
+        (110 110, 120 40, 100 40, 110 110)))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (110 110, 160 160, 210 110, 160 60, 110 110), 
+        (110 110, 160 130, 160 90, 110 110)), 
+      (
+        (110 110, 60 60, 10 110, 60 160, 110 110), 
+        (110 110, 60 90, 60 130, 110 110)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF2F11212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mAh/mAh-6-2: MultiPolygon touching MultiPolygon [dim(2){A.mA.Int = B.mA.Int}]</desc>
+  <a>
+    MULTIPOLYGON(
+      (
+        (110 110, 70 200, 200 200, 110 110), 
+        (110 110, 100 180, 120 180, 110 110)), 
+      (
+        (110 110, 200 20, 70 20, 110 110), 
+        (110 110, 120 40, 100 40, 110 110)))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (110 110, 70 200, 210 110, 70 20, 110 110), 
+        (110 110, 110 140, 150 110, 110 80, 110 110)), 
+      (
+        (110 110, 60 60, 10 110, 60 160, 110 110), 
+        (110 110, 60 90, 60 130, 110 110)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="212111212">true</op>
+  </test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/validate/TestRelateAC.xml b/tests/testthat/testxml/validate/TestRelateAC.xml
new file mode 100644
index 0000000..4bbafcb
--- /dev/null
+++ b/tests/testthat/testxml/validate/TestRelateAC.xml
@@ -0,0 +1,26 @@
+<run>
+<precisionModel type="FLOATING"/>
+
+<case>
+<desc>AC A-shells overlapping B-shell at A-vertex</desc>
+  <a>
+    POLYGON(
+      (100 60, 140 100, 100 140, 60 100, 100 60))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (80 40, 120 40, 120 80, 80 80, 80 40)), 
+      (
+        (120 80, 160 80, 160 120, 120 120, 120 80)), 
+      (
+        (80 120, 120 120, 120 160, 80 160, 80 120)), 
+      (
+        (40 80, 80 80, 80 120, 40 120, 40 80)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="21210F212">true</op>
+  </test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/validate/TestRelateLA.xml b/tests/testthat/testxml/validate/TestRelateLA.xml
new file mode 100644
index 0000000..ca1e2b1
--- /dev/null
+++ b/tests/testthat/testxml/validate/TestRelateLA.xml
@@ -0,0 +1,1162 @@
+<run>
+<precisionModel type="FLOATING"/>
+
+<case>
+<desc>L/A-3-1: a line touching the closing point of a polygon [dim(0){A.L.Bdy.SP = B.oBdy.CP}]</desc>
+  <a>
+    LINESTRING(150 150, 40 230)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-3-2: the start and end points of a LineString touching the boundary (at non-vertices) of a polygon [dim(0){A.L.Bdy.SP = B.oBdy.NV}, dim(0){A.L.Bdy.EP = B.oBdy.NV}]</desc>
+  <a>
+    LINESTRING(40 40, 50 130, 130 130)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F0F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-3-3: the end point of a line touching the closing point of a polygon [dim(0){A.L.Bdy.EP = B.oBdy.CP}]</desc>
+  <a>
+    LINESTRING(40 230, 150 150)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-3-4: an entire LineString touching the boundary (at non-vertices) of a polygon [dim(1){A.L.Int.SP-EP = B.oBdy.NV-NV}]</desc>
+  <a>
+    LINESTRING(210 150, 330 150)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F1FF0F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-3-5: the start portion of a LineString touching the boundary (at non-vertices) of a polygon [dim(1){A.L.Int.SP-V = B.oBdy.NV-NV}]</desc>
+  <a>
+    LINESTRING(200 150, 310 150, 360 220)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F11F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-3-6: the start portion and the end point of a LineString touching the boundary of a polygon [dim(1){A.L.Int.SP-V = B.oBdy.NV-NV}, dim(0){A.L.Bdy.EP = B.A.oBdy.V}]</desc>
+  <a>
+    LINESTRING(180 150, 250 150, 230 250, 370 250, 410 150)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F11F0F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-3-7: the middle portion of a LineString touching the boundary (at non-vertices) of a polygon [dim(1){A.L.Int.V-V = B.oBdy.NV-NV}]</desc>
+  <a>
+    LINESTRING(210 210, 220 150, 320 150, 370 210)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F11FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-4-1: a line at non-vertex crossing non-vertex boundary of polygon [dim(0){A.L.Int.NV = B.A.oBdy.NV}, dim(1){A.L.Int.NV-EP = B.A.Int}]</desc>
+  <a>
+    LINESTRING(20 60, 150 60)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-4-2: a line at non-vertex crossing non-vertex boundaries of polygon twice [dim(0){A.L.Int.NV = B.A.oBdy.NV}, dim(1){A.L.Int.NV-NV = B.A.Int}]</desc>
+  <a>
+    LINESTRING(60 90, 310 180)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-4-3: a line at non-vertex crossing vertex boundary of polygon [dim(0){A.L.Int.NV = B.A.oBdy.V}, dim(1){A.L.Int.NV-EP = B.A.Int}]</desc>
+  <a>
+    LINESTRING(90 210, 210 90)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-4-4: a line at non-vertex crossing vertex boundaries of polygon twice [dim(0){A.L.Int.NV = B.A.oBdy.V}, dim(1){A.L.Int.NV-NV = B.A.Int}, dim(0){A.L.Int.NV = B.A.oBdy.CP}]</desc>
+  <a>
+    LINESTRING(290 10, 130 170)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-4-5: a line at vertex crossing non-vertex boundary of polygon [dim(0){A.L.Int.V = B.A.oBdy.NV}, dim(1){A.L.Int.V-EP = B.A.Int}]</desc>
+  <a>
+    LINESTRING(30 100, 100 100, 180 100)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-4-6: a line at vertex crossing non-vertex boundaries of polygon twice [dim(0){A.L.Int.V = B.A.oBdy.NV}, dim(1){A.L.Int.V-V = B.A.Int}]</desc>
+  <a>
+    LINESTRING(20 100, 100 100, 360 100, 410 100)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-4-7: a line at vertex crossing vertex boundary of polygon [dim(0){A.L.Int.V = B.A.oBdy.V}, dim(1){A.L.Int.V-EP = B.A.Int}]</desc>
+  <a>
+    LINESTRING(90 210, 150 150, 210 90)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-5-1: an entire line within a polygon [dim(1){A.L.Int.SP-EP = B.A.Int}]</desc>
+  <a>
+    LINESTRING(180 90, 280 120)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-5-2: a line within a polygon but the line's both ends touching the boundary of the polygon [dim(1){A.L.Int.SP-EP = B.A.Int}, dim(0){A.L.Bdy.SP = B.oBdy.NV}, dim(0){A.L.Bdy.EP = B.oBdy.NV}]</desc>
+  <a>
+    LINESTRING(70 70, 80 20)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-5-3: a line within a polygon but the line's start point touching the boundary of the polygon [dim(1){A.L.Int.SP-EP = B.A.Int}, dim(0){A.L.Bdy.SP = B.oBdy.NV}]</desc>
+  <a>
+    LINESTRING(130 20, 150 60)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FF00F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-5-4: a line within a polygon but the line's start point and middle portion touching the boundary of the polygon [dim(1){A.L.Int.SP-V = B.A.Int}, dim(1){A.L.Int.V-V = B.oBdy.NV-NV}, dim(1){A.L.Int.V-EP = B.A.Int}, dim(0){A.L.Bdy.SP = B.A.oBdy.NV}]</desc>
+  <a>
+    LINESTRING(70 70, 80 20, 140 20, 150 60)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="11F00F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A-5-5: a line within a polygon but the line's middle portion touching the boundary of the polygon [dim(1){A.L.Int.SP-V = B.A.Int}, dim(1){A.L.Int.V-V = B.A.oBdy.NV-NV}, dim(1){A.L.Int.V-EP = B.A.Int}]</desc>
+  <a>
+    LINESTRING(170 50, 170 20, 240 20, 260 60)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="11F0FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-2-1: a line outside a polygon [dim(1){A.L.Int.SP-EP = B.A.Ext}]</desc>
+  <a>
+    LINESTRING(50 100, 140 190, 280 190)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-2-2: a line inside a polygon's hole [dim(1){A.L.Int.SP-EP = B.A.Ext.h}]</desc>
+  <a>
+    LINESTRING(140 60, 180 100, 290 100)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-3-1: the start point of a line touching the inner boundary of a polygon [dim(0){A.L.Bdy.SP = B.A.iBdy.CP}, dim(1){A.L.Int.SP-EP = B.A.Ext.h}]</desc>
+  <a>
+    LINESTRING(170 120, 210 80, 270 80)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-3-2: both ends of a line touching the inner boundary of a polygon [dim(0){A.L.Bdy.SP = B.A.iBdy.CP}, dim(1){A.L.Int.SP-EP = B.A.Ext.h}, dim(0){A.L.Bdy.SP = B.A.iBdy.CP}]</desc>
+  <a>
+    LINESTRING(170 120, 260 50)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F0F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-3-1: both ends of a line touching the inner boundary of a polygon [dim(0){A.L.Int.NV = B.A.Bdy.TP}]</desc>
+  <a>
+    LINESTRING(190 90, 190 270)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (190 190, 280 50, 100 50, 190 190))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-3-2: a line at a non-vertex crossing the boundary of a polygon where the closing point of the hole touches the shell at a non-vertex [dim(0){A.L.Int.NV = B.A.Bdy.TP}]</desc>
+  <a>
+    LINESTRING(60 160, 150 70)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (110 110, 250 100, 140 30, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-3-3: a line at a non-vertex crossing the boundary of a polygon where the hole at a vertex touches the shell at a non-vertex [dim(0){A.L.Int.NV = B.A.Bdy.TP}]</desc>
+  <a>
+    LINESTRING(60 160, 150 70)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 20 20, 360 20, 190 190), 
+      (250 100, 110 110, 140 30, 250 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-3-4: a line at a non-vertex crossing the boundary of a polygon where the hole at a vertex touches the shell at a vertex [dim(0){A.L.Int.NV = B.A.Bdy.TP}]</desc>
+  <a>
+    LINESTRING(60 160, 150 70)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 20 20, 360 20, 190 190), 
+      (250 100, 110 110, 140 30, 250 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-3-5: a line crossing polygon boundary where the closing point of the hole touches the shell at a vertex [dim(0){A.L.Int.V = B.A.Bdy.TP}]</desc>
+  <a>
+    LINESTRING(190 90, 190 190, 190 270)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (190 190, 280 50, 100 50, 190 190))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-3-6: a line at a vertex crossing the boundary of a polygon where closing point of the hole touches the shell at a non-vertex [dim(0){A.L.Int.V = B.A.Bdy.TP}]</desc>
+  <a>
+    LINESTRING(60 160, 110 110, 150 70)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (110 110, 250 100, 140 30, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-3-7: a line at a vertex crossing the boundary of a polygon where the hole at a vertex touches the shell at a non-vertex [dim(0){A.L.Int.V = B.A.Bdy.TP}]</desc>
+  <a>
+    LINESTRING(60 160, 110 110, 150 70)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 20 20, 360 20, 190 190), 
+      (250 100, 110 110, 140 30, 250 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/Ah-3-8: a line at a non-vertex crossing the boundary of a polygon where the hole at a vertex touches the shell at a vertex [dim(0){A.L.Int.V = B.A.Bdy.TP}]</desc>
+  <a>
+    LINESTRING(60 160, 110 110, 150 70)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 110 110, 20 20, 360 20, 190 190), 
+      (250 100, 110 110, 140 30, 250 100))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A2h-3-1: the start point a line touching the closing points of two connected holes in a polygon [dim(0){A.L.Int.SP = B.A.iBdy.TP}]</desc>
+  <a>
+    LINESTRING(130 110, 180 110, 190 60)
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 240 200, 240 20, 20 20, 20 200), 
+      (130 110, 60 180, 60 40, 130 110), 
+      (130 110, 200 40, 200 180, 130 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A2h-3-2: the interior (at a non-vertex) of a line touching the closing points of two connected holes in a polygon [dim(0){A.L.Int.NV = B.A.iBdy.TP}]</desc>
+  <a>
+    LINESTRING(80 110, 180 110)
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 240 200, 240 20, 20 20, 20 200), 
+      (130 110, 60 180, 60 40, 130 110), 
+      (130 110, 200 40, 200 180, 130 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A2h-3-3: the interior (at a non-vertex) of a line touching the closing point and at a vertex of two connected holes in a polygon [dim(0){A.L.Int.NV = B.A.iBdy1.TP}]</desc>
+  <a>
+    LINESTRING(80 110, 180 110)
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 20 20, 240 20, 240 200, 20 200), 
+      (60 180, 130 110, 60 40, 60 180), 
+      (130 110, 200 40, 200 180, 130 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A2h-3-4: the interior (at a non-vertex) of a line touching the closing point and at a non-vertex of two connected holes in a polygon [dim(0){A.L.Int.NV = B.A.iBdy.TP}]</desc>
+  <a>
+    LINESTRING(80 110, 170 110)
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 20 20, 240 20, 240 200, 20 200), 
+      (130 110, 60 40, 60 180, 130 110), 
+      (130 180, 130 40, 200 110, 130 180))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A2h-3-5: the start point a line touching the closing point and a non-vertex of two connected holes in a polygon [dim(0){A.L.Int.V = B.A.iBdy.TP}]</desc>
+  <a>
+    LINESTRING(80 110, 130 110, 170 110)
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 20 20, 240 20, 240 200, 20 200), 
+      (130 110, 60 40, 60 180, 130 110), 
+      (130 180, 130 40, 200 110, 130 180))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A2h-3-6: the interior (at a vertex) of a line touching the closing points of two connected holes in a polygon [dim(0){A.L.Int.V = B.A.iBdy.TP}]</desc>
+  <a>
+    LINESTRING(80 110, 130 110, 180 110)
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 240 200, 240 20, 20 20, 20 200), 
+      (130 110, 60 180, 60 40, 130 110), 
+      (130 110, 200 40, 200 180, 130 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A2h-3-7: the interior (at a vertex) of a line touching the closing point and at a vertex of two connected holes in a polygon [dim(0){A.L.Int.V = B.A.iBdy1.TP}]</desc>
+  <a>
+    LINESTRING(80 110, 130 110, 180 110)
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 20 20, 240 20, 240 200, 20 200), 
+      (60 180, 130 110, 60 40, 60 180), 
+      (130 110, 200 40, 200 180, 130 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/A2h-3-8: the interior (at a vertex) of a line touching the closing point and at a non-vertex of two connected holes in a polygon [dim(0){A.L.Int.V = B.A.iBdy.TP}]</desc>
+  <a>
+    LINESTRING(80 110, 130 110, 170 110)
+  </a>
+  <b>
+    POLYGON(
+      (20 200, 20 20, 240 20, 240 200, 20 200), 
+      (130 110, 60 40, 60 180, 130 110), 
+      (130 180, 130 40, 200 110, 130 180))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/mA-4-1: a line intersecting the interior and exterior of MultiPolygon [dim(1){A.L.Int.SP-NV = B.2A1.Int}, dim (1){A.L.Int.NV-EP = B.2A2.Int}]</desc>
+  <a>
+    LINESTRING(160 70, 320 230)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (140 110, 260 110, 170 20, 50 20, 140 110)), 
+      (
+        (300 270, 420 270, 340 190, 220 190, 300 270)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/mA-4-2: a line intersecting the interior and exterior of MultiPolygon [dim(1){A.L.Int.SP-V = B.2A1.Int}, dim (1){A.L.Int.V-EP = B.2A2.Int}]</desc>
+  <a>
+    LINESTRING(160 70, 200 110, 280 190, 320 230)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (140 110, 260 110, 170 20, 50 20, 140 110)), 
+      (
+        (300 270, 420 270, 340 190, 220 190, 300 270)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/mA-5-1: a line within two connected polygons [dim(1){A.L.Int = B.2A.Int}, dim(0){A.L.Int.NV = B.2A.Bdy.TP]</desc>
+  <a>
+    LINESTRING(70 50, 70 150)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (0 0, 0 100, 140 100, 140 0, 0 0)), 
+      (
+        (20 170, 70 100, 130 170, 20 170)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="10F0FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-3-1: a LinearRing touching a polygon's closing point [dim(0){A.RL.Int.CP = B.A.Bdy.CP}]</desc>
+  <a>
+    LINESTRING(110 110, 20 200, 200 200, 110 110)
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 200 20, 110 110, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-3-2: a LinearRing touching a polygon's boundary at a non-vertex [dim(0){A.RL.Int.CP = B.A.Bdy.NV}]</desc>
+  <a>
+    LINESTRING(150 70, 160 110, 200 60, 150 70)
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 200 20, 110 110, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-3-3: a LinearRing touching a polygon's boundary at a non-vertex [dim(0){A.RL.Int.CP = B.A.iBdy.NV}]</desc>
+  <a>
+    LINESTRING(80 60, 120 40, 120 70, 80 60)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110), 
+      (110 90, 50 30, 170 30, 110 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-3-4: a LinearRing on the boundary of a polygon [dim(1){A.RL.Int.SP-EP = B.A.Bdy.SP-EP}]</desc>
+  <a>
+    LINESTRING(20 20, 200 20, 110 110, 20 20)
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 200 20, 110 110, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F1FFFF2F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-3-5: a LinearRing on the inner boundary of a polygon [dim(1){A.RL.Int.SP-EP = B.A.iBdy.SP-EP}]</desc>
+  <a>
+    LINESTRING(110 90, 170 30, 50 30, 110 90)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110), 
+      (110 90, 50 30, 170 30, 110 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F1FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-3-6: a LinearRing on the inner boundary of a polygon [dim(1){A.RL.Int.SP-V = B.A.oBdy.SP-NV}]</desc>
+  <a>
+    LINESTRING(110 110, 170 50, 170 110, 110 110)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110), 
+      (110 90, 50 30, 170 30, 110 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F11FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-3-7: a LinearRing on the inner boundary of a polygon [dim(1){A.RL.Int.SP-V = B.A.iBdy.SP-NV}]</desc>
+  <a>
+    LINESTRING(110 90, 70 50, 130 50, 110 90)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110), 
+      (110 90, 50 30, 170 30, 110 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F11FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-4-1: a LinearRing crossing a polygon [dim(1){A.RL.Int.CP-NV = B.A.Int}, dim(0){A.L.Int.NV = B.A.Bdy.NV}]</desc>
+  <a>
+    LINESTRING(110 60, 20 150, 200 150, 110 60)
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 200 20, 110 110, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-4-2: a LinearRing crossing a polygon with a hole [dim(1){A.RL.Int.NV-NV = B.A.Int}, dim(0){A.RL.Int.NV = B.A.oBdy.CP}, dim(0){A.RL.Int.NV = B.A.iBdy.CP}, dim(0){A.RL.Int.NV = B.A.oBdy.NV}, dim(0){A.RL.Int.NV = B.A.iBdy.NV}]</desc>
+  <a>
+    LINESTRING(110 130, 110 70, 200 100, 110 130)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110), 
+      (110 90, 50 30, 170 30, 110 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-5-1: a LinearRing within a polygon [dim(1){A.RL.Int.SP-EP = B.A.Int}]</desc>
+  <a>
+    LINESTRING(110 90, 160 40, 60 40, 110 90)
+  </a>
+  <b>
+    POLYGON(
+      (20 20, 200 20, 110 110, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-5-2: a LinearRing within a polygon with a hole [dim(1){A.RL.Int.SP-EP = B.A.Int}]</desc>
+  <a>
+    LINESTRING(110 100, 40 30, 180 30, 110 100)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110), 
+      (110 90, 60 40, 160 40, 110 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-5-3: a LinearRing within a polygon with a hole [dim(1){A.RL.Int.SP-EP = B.A.Int}, dim(0){A.L.Int.CP = B.A.oBdy.CP}]</desc>
+  <a>
+    LINESTRING(110 110, 180 30, 40 30, 110 110)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110), 
+      (110 90, 60 40, 160 40, 110 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="10FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-5-4: a LinearRing within a polygon with a hole [dim(1){A.RL.Int.SP-EP = B.A.Int}, dim(0){A.RL.Int.CP = B.A.iBdy.CP}]</desc>
+  <a>
+    LINESTRING(110 90, 180 30, 40 30, 110 90)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110), 
+      (110 90, 60 40, 160 40, 110 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="10FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>RL/A-5-5: a LinearRing within a polygon with a hole [dim(1){A.RL.Int.SP-EP = B.A.Int}, dim(1){A.RL.Int.SP-NV = B.A.Bdy.iBdy.SP-V}]</desc>
+  <a>
+    LINESTRING(110 90, 50 30, 180 30, 110 90)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110), 
+      (110 90, 60 40, 160 40, 110 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="11FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/A-3-1: a non-simple LineString touching a polygon [dim(0){A.nsL.Bdy.SP = B.A.Bdy.CP}]</desc>
+  <a>
+    LINESTRING(110 110, 200 200, 200 110, 110 200)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/A-3-2: a non-simple LineString touching a polygon [dim(0){A.nsL.Bdy.SPb = B.A.Bdy.CP}]</desc>
+  <a>
+    LINESTRING(110 110, 200 200, 110 110, 20 200, 20 110, 200 110)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/A-3-3: a non-simple LineString touching a polygon [dim(0){A.nsL.Bdy.SPo = B.A.Bdy.CP}]</desc>
+  <a>
+    LINESTRING(110 110, 20 110, 200 110, 50 110, 110 170)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/A-3-4: a non-simple LineString touching a polygon [dim(0){A.nsL.Bdy.SPx = B.A.Bdy.CP}]</desc>
+  <a>
+    LINESTRING(110 110, 20 200, 110 200, 110 110, 200 200)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/A-3-5: a non-simple LineString touching a polygon [dim(1){A.nsL.Int.SPb-Vo = B.A.Bdy.SP-NV}]</desc>
+  <a>
+    LINESTRING(110 110, 170 50, 20 200, 20 110, 200 110)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F11F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/A-4-1: a non-simple LineString crossing a polygon [dim(1){A.nsL.Int.V-V-NV = B.A.Int}, dim(1){A.nsL.SPx-V = B.A.Bdy.SP-NV}]</desc>
+  <a>
+    LINESTRING(110 110, 180 40, 110 40, 110 180)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="111F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/A-5-1: a non-simple LineString within a polygon [dim(1){A.nsL.Int.SPx-EP = B.A.Int}]</desc>
+  <a>
+    LINESTRING(110 60, 50 30, 170 30, 90 70)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/A-5-2: a non-simple LineString within a polygon [dim(1){A.nsL.Int.SPx-EP = B.A.Int}, dim(1){A.nsL.Int.SPx-V = B.A.Bdy.SP-NV}]</desc>
+  <a>
+    LINESTRING(110 110, 180 40, 110 40, 110 110, 70 40)
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="11F00F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/Ah: the self-crossing point of a non-simple LineString touching the closing point of the inner boundary of a polygon [dim(0){A.nsL.Int.V = B.A.iBdy.CP}]</desc>
+  <a>
+    LINESTRING(230 70, 170 120, 190 60, 140 60, 170 120, 270 90)
+  </a>
+  <b>
+    POLYGON(
+      (150 150, 410 150, 280 20, 20 20, 150 150), 
+      (170 120, 330 120, 260 50, 100 50, 170 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/A-3-1: MultiLineString touching a polygon's closing point [dim(0){A.mL.Bdy.SPb = B.A.Bdy.CP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 110, 200 110), 
+      (200 200, 110 110, 20 210, 110 110))
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/A-3-2: MultiLineString touching a polygon's closing point [dim(0){A.mL.Bdy.SPo = B.A.Bdy.CP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 110, 200 110), 
+      (60 180, 60 110, 160 110, 110 110))
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/A-3-3: MultiLineString touching a polygon's closing point [dim(0){A.mL.Bdy.SPx = B.A.Bdy.CP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 110, 200 110), 
+      (200 200, 110 110, 20 200, 110 200, 110 110))
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/A-4-1: MultiLineString crossing a polygon [dim(1){A.mL.Int.SP-NVb = B.A.Int}, dim(0){A.mL.Int.NVb = B.A.Bdy.CP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 110, 200 110), 
+      (110 50, 110 170, 110 70, 110 150, 200 150))
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/A-4-2: MultiLineString crossing a polygon [dim(1){A.mL.Int.SP-NVo = B.A.Int}, dim(0){A.mL.Int.NVo = B.A.Bdy.CP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 110, 200 110), 
+      (50 110, 170 110, 110 170, 110 50, 110 170, 110 50))
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/A-4-3: MultiLineString crossing a polygon [dim(1){A.mL.Int.SP-NVx = B.A.Int}, dim(0){A.mL.Int.NVx = B.A.Bdy.CP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 110, 200 110), 
+      (110 60, 110 160, 200 160))
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/A-4-4: MultiLineString crossing a polygon [dim(1){A.mL.Int.Vb-Vb = B.A.Int}, dim(0){A.mL.Int.Vb = B.A.oBdy.CP}, dim(0){A.mL.Int.Vb = B.A.iBdy.CP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 110, 200 110), 
+      (110 60, 110 160, 200 160))
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/A-5-1: MultiLineString within a polygon [dim(1){A.mL.Int.SP-EP = B.A.Int}]</desc>
+  <a>
+    MULTILINESTRING(
+      (110 100, 40 30, 180 30), 
+      (170 30, 110 90, 50 30))
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/A-5-2: MultiLineString within a polygon [dim(1){A.mL.Int.SP-EP = B.A.Int}]</desc>
+  <a>
+    MULTILINESTRING(
+      (110 110, 60 40, 70 20, 150 20, 170 40), 
+      (180 30, 40 30, 110 80))
+  </a>
+  <b>
+    POLYGON(
+      (110 110, 200 20, 20 20, 110 110))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="11F00F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mA-3-1: MultiLineString within a MultiPolygon [dim(0){A.mL.Bdy.SPb = B.mA.Bdy.TP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 110, 200 110, 200 160), 
+      (110 110, 200 110, 200 70, 20 150))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (110 110, 20 20, 200 20, 110 110)), 
+      (
+        (110 110, 20 200, 200 200, 110 110)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mA-3-2: MultiLineString within a MultiPolygon [dim(0){A.mL.Bdy.SPo = B.mA.Bdy.TP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 160, 70 110, 150 110, 200 160), 
+      (110 110, 20 110, 50 80, 70 110, 200 110))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (110 110, 20 20, 200 20, 110 110)), 
+      (
+        (110 110, 20 200, 200 200, 110 110)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mA-3-3: MultiLineString within a MultiPolygon [dim(0){A.mL.Bdy.SPx = B.mA.Bdy.TP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 110, 200 110), 
+      (110 110, 20 170, 20 130, 200 90))
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (110 110, 20 20, 200 20, 110 110)), 
+      (
+        (110 110, 20 200, 200 200, 110 110)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00212">true</op>
+  </test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/validate/TestRelateLC.xml b/tests/testthat/testxml/validate/TestRelateLC.xml
new file mode 100644
index 0000000..d27f616
--- /dev/null
+++ b/tests/testthat/testxml/validate/TestRelateLC.xml
@@ -0,0 +1,71 @@
+<run>
+<precisionModel type="FLOATING"/>
+
+<case>
+<desc>LC - topographically equal with no boundary</desc>
+  <a>
+    LINESTRING(0 0, 0 50, 50 50, 50 0, 0 0)
+  </a>
+  <b>
+    MULTILINESTRING(
+      (0 0, 0 50), 
+      (0 50, 50 50), 
+      (50 50, 50 0), 
+      (50 0, 0 0))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LC - intersection (containment) along mod-2 A-Int line segment</desc>
+  <a>
+    LINESTRING(40 180, 140 180)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 320, 180 320, 180 180, 20 180, 20 320)), 
+      (
+        (20 180, 20 80, 180 80, 180 180, 20 180)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LC - intersection (overlap) along mod-2 A-Int line segment</desc>
+  <a>
+    LINESTRING(40 180, 140 180)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 320, 180 320, 180 180, 20 180, 20 320)), 
+      (
+        (60 180, 60 80, 180 80, 180 180, 60 180)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="11F00F212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LC - equal with boundary intersection</desc>
+  <a>
+    LINESTRING(0 0, 60 0, 60 60, 60 0, 120 0)
+  </a>
+  <b>
+    MULTILINESTRING(
+      (0 0, 60 0), 
+      (60 0, 120 0), 
+      (60 0, 60 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="10FF0FFF2">true</op>
+  </test>
+</case>
+
+</run>
diff --git a/tests/testthat/testxml/validate/TestRelateLL.xml b/tests/testthat/testxml/validate/TestRelateLL.xml
new file mode 100644
index 0000000..c446326
--- /dev/null
+++ b/tests/testthat/testxml/validate/TestRelateLL.xml
@@ -0,0 +1,1949 @@
+<run>
+<precisionModel type="FLOATING"/>
+
+<case>
+<desc>L/L.1-3-1: touching at the start points of two lines [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(40 40, 120 120)
+  </a>
+  <b>
+    LINESTRING(40 40, 60 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-3-2: start point of one line touching end point of another line [dim(0){A.L.Bdy.SP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(40 40, 120 120)
+  </a>
+  <b>
+    LINESTRING(60 240, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-3-3: start point of a line touching the interior of another line at a non-vertex [dim(0){A.L.Bdy.SP = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(40 40, 180 180)
+  </a>
+  <b>
+    LINESTRING(120 120, 20 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-3-4: touching at the end points of two lines [dim(0){A.L.Bdy.EP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(40 40, 120 120)
+  </a>
+  <b>
+    LINESTRING(60 240, 120 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-3-5: end point of a line touching the interior of another line at a non-vertex [dim(0){A.L.Bdy.EP = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(40 40, 180 180)
+  </a>
+  <b>
+    LINESTRING(20 180, 140 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-4-1: two lines crossing at non-vertex [dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(40 40, 120 120)
+  </a>
+  <b>
+    LINESTRING(40 120, 120 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-1-1: equal pointwise [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100)
+  </a>
+  <b>
+    LINESTRING(40 40, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-1-2: equal lines but points in reverse sequence [dim(1){A.L.Int.SP-EP = B.L.Int.EP-SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100)
+  </a>
+  <b>
+    LINESTRING(100 100, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-2-1: dim(1){A.L.Int.SP-EP = B.L.Ext}</desc>
+  <a>
+    LINESTRING(40 40, 120 120)
+  </a>
+  <b>
+    LINESTRING(40 120, 120 160)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-5-1: line A containing line B [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(20 20, 180 180)
+  </a>
+  <b>
+    LINESTRING(20 20, 180 180)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-5-2: line B is part of line A [dim(1){A.L.Int.SP-NV) = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(20 20, 180 180)
+  </a>
+  <b>
+    LINESTRING(20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101F00FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-5-3: Line B is part of line A (in the middle portion) [dim(1){A.L.Int.NV-NV = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(20 20, 180 180)
+  </a>
+  <b>
+    LINESTRING(50 50, 140 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-6-1: start portions of two lines overlapping [dim(1){A.L.Int.SP-NV = B.L.Int.SP-NV]</desc>
+  <a>
+    LINESTRING(180 180, 40 40)
+  </a>
+  <b>
+    LINESTRING(120 120, 260 260)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-6-2: end portions of two lines overlapping [dim(1){A.L.Int.NV-EP = B.L.Int.NV-EP]</desc>
+  <a>
+    LINESTRING(40 40, 180 180)
+  </a>
+  <b>
+    LINESTRING(260 260, 120 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.1-6-3: end portion of line A overlapping the start portion of line B [dim(1){A.L.Int.NV-EP = B.L.Int.SP-NV]</desc>
+  <a>
+    LINESTRING(40 40, 180 180)
+  </a>
+  <b>
+    LINESTRING(120 120, 260 260)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-1: two LineStrings touching at start points [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(40 40, 20 100, 40 160, 20 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-2: start point of LineStrings A touching the end point of LineString B [dim(0){A.L.Bdy.SP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(20 200, 40 160, 20 100, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-3: two LineStrings touching at end points [dim(0){A.L.Bdy.EP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(80 240, 200 120, 100 100, 40 40)
+  </a>
+  <b>
+    LINESTRING(20 200, 40 160, 20 100, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-4: both the start and end points of LineString A touching the interior of LineString B at two vertices  [dim(0){A.L.Bdy.SP = B.L.Int.V}, dim(0){A.L.Bdy.EP = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(60 60, 60 230, 140 230, 250 160)
+  </a>
+  <b>
+    LINESTRING(20 20, 60 60, 250 160, 310 230)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10FF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-5: both the start and end points of LineString A touching the interior of LineString B at two non-vertices  [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Bdy.EP = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(60 60, 60 230, 140 230, 250 160)
+  </a>
+  <b>
+    LINESTRING(20 20, 110 110, 200 110, 320 230)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10FF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-6: the start and end points of two LineStrings touching each other [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}, dim(0){A.L.Bdy.EP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(60 110, 60 250, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F0F1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-7: the start and end points of two LineStrings touching each other [dim(0){A.L.Bdy.SP = B.L.Bdy.EP}, dim(0){A.L.Bdy.EP = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(60 110, 60 250, 360 210)
+  </a>
+  <b>
+    LINESTRING(360 210, 310 160, 110 160, 60 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F0F1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-8: start point of LineString B touching LineString A at a non-vertex [dim(0){A.L.Int.NV = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(160 160, 240 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-9: end point of LineString B touching LineString A at a non-vertex [dim(0){A.L.Int.NV = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(240 240, 160 160)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-10: both the start and end points of LineString B touching the interior of LineString A at two non-vertices  [dim(0){A.L.Int.NV = B.L.Bdy.SP}, dim(0){A.L.Int.NV = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(60 60, 60 230, 140 230, 250 160)
+  </a>
+  <b>
+    LINESTRING(60 150, 110 100, 170 100, 110 230)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-11: the start point of LineString B touching the interior of LineString A at a non-vertex and the end point of LineString A touching the interior of LineString B at a vertex  [dim(0){A.L.Int.NV = B.L.Bdy.SP}, dim(0){A.L.Bdy.EP = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(60 60, 60 230, 140 230, 250 160)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-12: start point of LineString B touching LineString A at a vertex [dim(0){A.L.Int.V = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(200 120, 200 190, 150 240, 200 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-13: end point of LineString B touching LineString A at a vertex [dim(0){A.L.Int.V = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(200 240, 150 240, 200 200, 200 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-3-14: both the start and end points of LineString B touching the interior of LineString A at two vertices  [dim(0){A.L.Int.V = B.L.Bdy.SP}, dim(0){A.L.Int.V = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(60 60, 60 230, 140 230, 250 160)
+  </a>
+  <b>
+    LINESTRING(60 230, 80 140, 120 140, 140 230)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-1: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(60 110, 200 110, 250 160, 300 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-2: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.SP}, dim(0){A.L.Int.V = B.L.Int.V}, dim(0){A.L.Bdy.EP = B.L.Int.EP}]</desc>
+  <a>
+    LINESTRING(60 110, 200 110, 250 160, 300 210, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1F0F1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-3: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Bdy.SP}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(60 110, 220 110, 250 160, 280 110)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-4: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Int.SP}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Bdy.EP = B.L.Int.EP}]</desc>
+  <a>
+    LINESTRING(60 110, 150 110, 200 160, 250 110, 360 110, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1F0F1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-5: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(130 160, 160 110, 220 110, 250 160, 250 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-6: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(130 160, 160 110, 190 110, 230 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-7: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Bdy.SP = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(130 160, 160 110, 200 110, 230 160, 260 210, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F100F102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-8: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(130 160, 160 110, 200 110, 230 160, 260 210, 360 210, 380 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-9: two LineStrings crossing at three points [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Int.NV = B.L.Bdy.EP}]</desc>
+  <a>
+    LINESTRING(130 160, 160 110, 200 110, 230 160, 260 210, 380 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-10: two LineStrings crossing at two points [dim(0){A.L.Bdy.SP = B.L.Int.V}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(110 160, 160 110, 200 110, 250 160, 250 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-11: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Int.V}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(110 160, 180 110, 250 160, 320 110)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-12: two LineStrings crossing on one side [dim(0){A.L.Bdy.SP = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(140 160, 180 80, 220 160, 250 80)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-13: two LineStrings crossing at a vertex for one of the LineStrings [dim(0){A.L.Int.V = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 130 190)
+  </a>
+  <b>
+    LINESTRING(20 130, 70 130, 160 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-14: two LineStrings crossing at non-vertices for both of the LineStrings [dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 130 190)
+  </a>
+  <b>
+    LINESTRING(40 160, 40 100, 110 40, 170 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-15: two LineStrings crossing on one side [dim(0){A.L.Int.V = B.L.Int.NV}, dim(0){A.L.Int.V = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(130 110, 180 160, 230 110, 280 160, 330 110)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-16: two LineStrings crossing at vertices for both LineString  [dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 130 190)
+  </a>
+  <b>
+    LINESTRING(30 140, 80 140, 100 100, 200 30)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-17: two LineStrings crossing on one side [dim(0){A.L.Int.V = B.L.Int.V}, dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(110 110, 110 160, 180 110, 250 160, 250 110)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-18: multiple crossings [dim(0){A.L.Int.V = B.L.Int.V}, dim(0){A.L.Int.NV = B.L.Int.NV}]</desc>
+  <a>
+    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
+  </a>
+  <b>
+    LINESTRING(20 60, 60 60, 60 140, 80 80, 100 20, 140 140, 180 20, 200 80, 220 20, 
+    240 80, 300 80, 270 110, 200 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-4-19: spiky LineStrings with multiple crossing [dim(0){A.L.Int.V = B.L.Int.V}]</desc>
+  <a>
+    LINESTRING(20 20, 230 20, 20 30, 170 30, 20 40, 230 40, 20 50, 230 60, 60 60, 
+    230 70, 20 70, 180 80, 60 80, 230 90, 20 90, 230 100, 30 100, 210 110, 20 110, 
+    80 120, 20 130, 170 130, 90 120, 230 130, 170 140, 230 140, 80 150, 160 140, 20 140, 
+    70 150, 20 150, 230 160, 80 160, 230 170, 20 160, 180 170, 20 170, 230 180, 20 180, 
+    40 190, 230 190, 20 200, 230 200)
+  </a>
+  <b>
+    LINESTRING(30 210, 30 60, 40 210, 40 30, 50 190, 50 20, 60 160, 60 50, 70 220, 
+    70 50, 80 20, 80 210, 90 50, 90 150, 100 30, 100 210, 110 20, 110 190, 120 50, 
+    120 180, 130 210, 120 20, 140 210, 130 50, 150 210, 130 20, 160 210, 140 30, 170 210, 
+    150 20, 180 210, 160 20, 190 210, 180 80, 170 50, 170 20, 180 70, 180 20, 190 190, 
+    190 30, 200 210, 200 30, 210 210, 210 20, 220 150, 220 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="001FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-1-1: two equal LineStrings with equal pointwise [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-1-2: two equal LineStrings with points in reverse sequence [dim(1){A.L.Int.SP-EP = B.L.Int.EP-SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(80 240, 200 120, 100 100, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-1-3: two equal LineStrings with different number of points [dim(1){A.L.Int.SP-EP = B.L.Int.EP-SP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(80 240, 120 200, 200 120, 100 100, 80 80, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-2-1: disjoint [dim(1){A.L.Int.SP-EP = B.L.Ext}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(260 210, 240 130, 280 120, 260 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-2-2: wrapping around but still disjoint [dim(1){A.L.Int.SP-EP = B.L.Ext}]</desc>
+  <a>
+    LINESTRING(100 20, 20 20, 20 160, 210 160, 210 20, 110 20, 50 120, 120 150, 200 150)
+  </a>
+  <b>
+    LINESTRING(140 130, 100 110, 120 60, 170 60)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-1: LineString A containing LineString B, same pointwise [dim(1){A.L.Int.SP-EP = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-2: LineString A containing LineString B, LineString A with less points [dim(1){A.L.Int.SP-V = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-3: LineString A containing LineString B [dim(1){A.L.Int.SP-V = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(60 110, 110 160, 250 160)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101F00FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-4: LineString A containing LineString B [dim(1){A.L.Int.NV-NV = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(110 160, 310 160, 340 190)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-5: LineString A containing LineString B [dim(1){A.L.Int.V-NV = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(140 160, 250 160, 310 160, 340 190)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-5-6: LineString A containing LineString B [dim(1){A.L.Int.V-V = B.L.Int.SP-EP}]</desc>
+  <a>
+    LINESTRING(60 110, 110 160, 250 160, 310 160, 360 210)
+  </a>
+  <b>
+    LINESTRING(110 160, 250 160, 310 160)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0FF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-1: start portions of two LineStrings overlapping [dim(1){A.L.Int.SP-V = B.L.Int.SP-V}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(200 120, 100 100, 40 40, 140 80, 200 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-2: start portion of LineString A overlapping end portion of LineString B, intersecting at the middle of LineString A [dim(1){A.L.Int.SP-V = B.L.Int.V-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(280 240, 240 140, 200 120, 100 100, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-3: start portion of LineString A overlapping end portion of LineString B, intersecting at the middle of LineString A [dim(1){A.L.Int.SP-V = B.L.Int.NV-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(80 190, 140 140, 40 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-4: end portions of two LineStrings overlapping [dim(1){A.L.Int.NV-EP = B.L.Int.V-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(240 200, 200 260, 80 240, 140 180)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-5: end portion of LineString A overlapping start portion of LineString B [dim(1){A.L.Int.NV-EP = B.L.Int.SP-V}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(140 180, 80 240, 200 260, 240 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1010F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-6: end portion of LineString A overlapping end portion of LineString B, intersecting at the middle of LineString A [dim(1){A.L.Int.V-EP = B.L.Int.V-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(280 240, 240 140, 200 120, 80 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-7: middle portions of two LineStrings overlapping [dim(1){A.L.Int.V-NV = B.L.Int.NV-V}]</desc>
+  <a>
+    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
+  </a>
+  <b>
+    LINESTRING(20 80, 120 80, 200 80, 260 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-8: middle portion of LineString A overlapping start portion of LineString B [dim(1){A.L.Int.V-V = B.L.Int.SP-V}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(100 100, 200 120, 240 140, 280 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-9: middle portion of LineString A overlapping end portion of LineString B [dim(1){A.L.Int.V-V = B.L.Int.V-EP}]</desc>
+  <a>
+    LINESTRING(40 40, 100 100, 200 120, 80 240)
+  </a>
+  <b>
+    LINESTRING(280 240, 240 140, 200 120, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-10: middle portions of two LineStrings overlapping [dim(1){A.L.Int.V-V = B.L.Int.V-V}]</desc>
+  <a>
+    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
+  </a>
+  <b>
+    LINESTRING(80 20, 80 80, 240 80, 300 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/L.2-6-11: middle portions of two LineStrings overlapping, multiple intersects [dim(1){A.L.Int.V-V = B.L.Int.V-NV}, dim(1){A.L.Int.V-V = B.L.Int.V-NV}, dim(1){A.L.Int.V-V = B.L.Int.V-NV}]</desc>
+  <a>
+    LINESTRING(20 20, 80 80, 160 80, 240 80, 300 140)
+  </a>
+  <b>
+    LINESTRING(20 80, 80 80, 120 80, 140 140, 160 80, 200 80, 220 20, 240 80, 270 110, 
+    300 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-3-1: a LineString touching a LinearRing [dim(0){A.L.Bdy.SP = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(100 100, 20 180, 180 180)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-4-1: a LineString crossing a LinearRing [dim(0){A.L.Int.NV = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(20 100, 180 100, 100 180)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-4-2: a LineString crossing a LinearRing [dim(0){A.L.Int.NV = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(100 40, 100 160, 180 160)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-4-3: a LineString crossing a LinearRing [dim(0){A.L.Int.V = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(20 100, 100 100, 180 100, 100 180)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-5-1: a LineString within a LinearRing [dim(1){A.L.Int.SP-EP = B.LR.Int.SP-NV}]</desc>
+  <a>
+    LINESTRING(100 100, 160 40)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-5-2: a LineString within a LinearRing [dim(1){A.L.Int.SP-EP = B.LR.Int.SP-NV}]</desc>
+  <a>
+    LINESTRING(100 100, 180 20)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-5-3: a LineString within a LinearRing [dim(1){A.L.Int.SP-V-EP = B.LR.Int.NV-CP-NV}]</desc>
+  <a>
+    LINESTRING(60 60, 100 100, 140 60)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FF0FF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-6-1: a LineString crossing a LinearRing [dim(1){A.L.Int.SP-NV = B.LR.Int.SP-V}]</desc>
+  <a>
+    LINESTRING(100 100, 190 10, 190 100)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F10F01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-6-2: a LineString crossing a LinearRing [dim(1){A.L.Int.SP-V = B.LR.Int.SP-NV}]</desc>
+  <a>
+    LINESTRING(100 100, 160 40, 160 100)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F10F01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/LR-6-3: a LineString crossing a LinearRing [dim(1){A.L.Int.NV-V = B.LR.Int.SP-NV}]</desc>
+  <a>
+    LINESTRING(60 140, 160 40, 160 140)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's end point with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Bdy.EPb}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 20 80, 140 80, 80 20, 80 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's end point with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Bdy.EPo}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 20 80, 140 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's end point with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 140 80, 80 20, 80 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's closing point with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.CPb}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 20 80, 140 80, 80 20, 80 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's closing point with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.CPo}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 20 80, 140 80, 80 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's closing point with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Int.CPx}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(80 80, 20 80, 20 140, 140 20, 80 20, 80 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex [dim(0){A.L.Int.NV = B.nsL.Int.NV}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(20 140, 140 20, 100 20, 100 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.NVb}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 120 80, 80 20, 80 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.NVo}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 140 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a non-vertex with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Int.NVx}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 80 140, 80 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex [dim(0){A.L.Int.NV = B.nsL.Int.V}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 80 80, 20 80, 50 140, 50 60)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex with both crossing and overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.Vb}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 120 80, 80 20, 80 80, 80 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex with overlapping line segments [dim(0){A.L.Int.NV = B.nsL.Int.Vo}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 80 80, 140 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF01F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL: A line's interior at a non-vertex intersecting a non-simple linestring's interior at a vertex with crossing line segments [dim(0){A.L.Int.NV = B.nsL.Int.Vx}]</desc>
+  <a>
+    LINESTRING(20 20, 140 140)
+  </a>
+  <b>
+    LINESTRING(140 80, 20 80, 80 140, 80 80, 80 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.1-3-1: start point of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Bdy.SP = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(130 150, 220 150, 220 240)
+  </a>
+  <b>
+    LINESTRING(130 240, 130 150, 220 20, 50 20, 130 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.1-3-2: the interior of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Int.V = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(30 150, 130 150, 250 150)
+  </a>
+  <b>
+    LINESTRING(130 240, 130 150, 220 20, 50 20, 130 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.1-3-3: the interior of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Int.NV = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(30 150, 250 150)
+  </a>
+  <b>
+    LINESTRING(130 240, 130 150, 220 20, 50 20, 130 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.1-3-4: the interior of a LineString touching the self-intersecting point of a non-simple LineString [dim(0){A.L.Int.V = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(30 150, 130 150, 250 150)
+  </a>
+  <b>
+    LINESTRING(130 240, 130 20, 30 20, 130 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.1-4: a Line crossing a non-simple LineString at non-vertices [dim(0){A.L.Int.NV = B.nsL.Int.NV}]</desc>
+  <a>
+    LINESTRING(30 150, 250 150)
+  </a>
+  <b>
+    LINESTRING(120 240, 120 20, 20 20, 120 170)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL.5/L-3-1: switching the geometries for case L/nsL.5-3-1 [dim(0){A.nsL.Bdy.EPx = B.L.Bdy.SP}]</desc>
+  <a>
+    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.5-3-2: the start point of a line touching the self-intersecting and self-crossing point of a non-simple LineString [dim(0){A.L.Bdy.SP = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(110 110, 200 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.5-3-3: the interior of a line touching the self-intersecting and self-crossing point of a non-simple LineString [dim(0){A.L.Int.NV = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    LINESTRING(20 110, 200 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL.5/L-3-4 touches dim(0){A.nsL.Bdy.EPx = B.L.Int.NV}</desc>
+  <a>
+    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </a>
+  <b>
+    LINESTRING(20 110, 200 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.10-6-1: the middle portion of a line overlapping from the self-intersecting to the self-crossing a non-simple LineString [dim(1){A.L.Int.V-V = B.nsL.Int.EPx-NVx}]</desc>
+  <a>
+    LINESTRING(90 200, 90 130, 110 110, 150 200)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/nsL.10-6-2: the middle portion of a line overlapping from the self-intersecting to the self-crossing a non-simple LineString [dim(1){A.L.Int.V-V = B.nsL.Int.NVx-EPx}]</desc>
+  <a>
+    LINESTRING(200 110, 110 110, 90 130, 90 200)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>L/mL-3-1: a line's end point touching a non-vertex with crossing line segments of a MultiLineString [dim(0){A.L.Bdy.SP = B.mL.Int.NVx]</desc>
+  <a>
+    LINESTRING(80 80, 150 80, 210 80)
+  </a>
+  <b>
+    MULTILINESTRING(
+      (20 20, 140 140), 
+      (20 140, 140 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-1-1: two equal LinearRings, pointwise [dim(1){A.LR.Int.SP-EP = B.LR.Int.SP-EP}, dim(0){A.LR.Int.CP = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(40 80, 160 200, 260 20, 40 80)
+  </a>
+  <b>
+    LINESTRING(40 80, 160 200, 260 20, 40 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-1-2: two equal LinearRings with points in reverse sequence [dim(1){A.LR.Int.SP-EP = B.LR.Int.EP-SP}, dim(0){A.LR.Int.CP = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(40 80, 160 200, 260 20, 40 80)
+  </a>
+  <b>
+    LINESTRING(40 80, 260 20, 160 200, 40 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-1-3: two equal LinearRings with points in different sequence [dim(1){A.LR.Int.SP-EP = B.LR.Int.SP-EP}, dim(0){A.LR.Int.CP = B.LR.Int.V}, dim(0){A.LR.Int.V = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(40 80, 160 200, 260 20, 40 80)
+  </a>
+  <b>
+    LINESTRING(260 20, 40 80, 160 200, 260 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-1-4: two equal LinearRings with different number of points [dim(1){A.LR.Int.SP-EP = B.LR.Int.SP-EP}, dim(0){A.LR.Int.CP = B.LR.Int.V}, dim(0){A.LR.Int.NV = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(40 80, 160 200, 260 20, 40 80)
+  </a>
+  <b>
+    LINESTRING(100 140, 160 200, 260 20, 40 80, 100 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-1: two LinearRings crossing at closing points [dim(0){A.LR.Int.CP = B.LR.Int.CP}]</desc>
+  <a>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </a>
+  <b>
+    LINESTRING(100 100, 180 180, 20 180, 100 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-2: two LinearRings crossing at two points [dim(0){A.LR.Int.CP = B.LR.Int.CP}, dim(0){A.LR.Int.V = B.LR.Int.V},]</desc>
+  <a>
+    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
+  </a>
+  <b>
+    LINESTRING(40 150, 150 40, 170 20, 170 190, 40 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-3: two LinearRings crossing at the closing and a non-vertex [dim(0){A.LR.Int.CP = B.LR.Int.NV}]</desc>
+  <a>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </a>
+  <b>
+    LINESTRING(180 100, 20 100, 100 180, 180 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-4: two LinearRings crossing at the closing and a vertex [dim(0){A.LR.Int.CP = B.LR.Int.V}]</desc>
+  <a>
+    LINESTRING(100 100, 180 20, 20 20, 100 100)
+  </a>
+  <b>
+    LINESTRING(180 180, 100 100, 20 180, 180 180)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-5: two LinearRings crossing at a vertex and a non-vertex [dim(0){A.LR.Int.V = B.LR.Int.NV}]</desc>
+  <a>
+    LINESTRING(20 180, 100 100, 20 20, 20 180)
+  </a>
+  <b>
+    LINESTRING(100 20, 100 180, 180 100, 100 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-4-6: two LinearRings crossing at two points [dim(0){A.LR.Int.V = B.LR.Int.NV}, dim(0){A.LR.Int.V = B.LR.Int.NV},]</desc>
+  <a>
+    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
+  </a>
+  <b>
+    LINESTRING(170 20, 20 170, 170 170, 170 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-6-1: two LinearRings overlapping [dim(1){A.LR.Int.CP-V = B.LR.Int.CP-V}]</desc>
+  <a>
+    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
+  </a>
+  <b>
+    LINESTRING(40 150, 150 150, 90 210, 40 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-6-2: two LinearRings overlapping [dim(1){A.LR.Int.CP-V = B.LR.Int.NV-NV}]</desc>
+  <a>
+    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
+  </a>
+  <b>
+    LINESTRING(20 150, 170 150, 90 230, 20 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/LR-6-3: two LinearRings overlapping [dim(1){A.LR.Int.(V-V-V-EP) = B.LR.Int.(NV-V-V-SP)}]</desc>
+  <a>
+    LINESTRING(40 150, 40 40, 150 40, 150 150, 40 150)
+  </a>
+  <b>
+    LINESTRING(40 150, 150 150, 150 40, 20 40, 20 150, 40 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/nsL-3-1: a LinearRing touching a non-simple LineString [dim(0){A.nsL.Int.CP = B.nsL.Bdy.SPb}]</desc>
+  <a>
+    LINESTRING(110 110, 200 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 110, 20 200, 20 110, 200 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/nsL-3-1: a LinearRing touching a non-simple LineString [dim(0){A.nsL.Int.CP = B.nsL.Bdy.SPo}]</desc>
+  <a>
+    LINESTRING(110 110, 200 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 20 110, 200 110, 50 110, 110 170)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/nsL-3-1: a LinearRing touching a non-simple LineString [dim(0){A.nsL.Int.CP = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    LINESTRING(110 110, 200 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 20 200, 110 200, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F01FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/nsL-6-1: a LinearRing and a non-simple LineString overlapping [dim(1){A.nsL.Int.SP-V = B.nsL.Int.NVx-SP}]</desc>
+  <a>
+    LINESTRING(110 110, 200 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(200 20, 20 200, 200 200, 110 110, 110 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>LR/nsL-6-2: a LinearRing and a non-simple LineString overlapping [dim(1){A.nsL.Int.SP-V = B.nsL.Int.NVx-SP}, dim(1){A.nsL.Int.V-EP = B.nsL.Int.EP-NVx}]</desc>
+  <a>
+    LINESTRING(110 110, 200 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(200 20, 20 200, 200 200, 20 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="101FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-1: non-simple LineStrings crossing at closing points [dim(0){A.nsL.Int.CP = B.nsL.Int.CP}]</desc>
+  <a>
+    LINESTRING(110 110, 20 110, 110 20, 20 20, 110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 200 110, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-2: non-simple LineStrings crossing at two points without vertices [dim(0){A.nsL.Int.NV = B.nsL.Int.NV}]</desc>
+  <a>
+    LINESTRING(20 120, 120 120, 20 20, 120 20, 20 120)
+  </a>
+  <b>
+    LINESTRING(170 100, 70 100, 170 170, 70 170, 170 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-3: non-simple LineStrings crossing at a point [dim(0){A.nsL.Int.NV = B.nsL.Int.V}]</desc>
+  <a>
+    LINESTRING(20 110, 110 110, 20 20, 110 20, 20 110)
+  </a>
+  <b>
+    LINESTRING(110 160, 70 110, 60 160, 20 130, 110 160)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-4: non-simple LineStrings crossing at self-crossing points [dim(0){A.nsL.Int.NVx = B.nsL.Int.NVx}]</desc>
+  <a>
+    LINESTRING(20 200, 200 200, 20 20, 200 20, 20 200)
+  </a>
+  <b>
+    LINESTRING(20 110, 200 110, 200 160, 20 60, 20 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-5: non-simple LineStrings crossing at vertices [dim(0){A.nsL.Int.V = B.nsL.Int.V}]</desc>
+  <a>
+    LINESTRING(20 110, 110 110, 20 20, 110 20, 20 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 110 110, 200 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>nsL/nsL-4-6: non-simple LineStrings crossing at two points with vertices [dim(0){A.nsL.Int.V = B.nsL.Int.V}]</desc>
+  <a>
+    LINESTRING(20 120, 120 120, 20 20, 120 20, 20 120)
+  </a>
+  <b>
+    LINESTRING(220 120, 120 20, 220 20, 120 120, 220 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-1: MultiLineString [dim(1){A.mL.Int.SP-EP = B.mL.Int.SP-EP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (70 20, 20 90, 70 170), 
+      (70 170, 120 90, 70 20))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (70 20, 20 90, 70 170), 
+      (70 170, 120 90, 70 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-1-1: non-simple MultiLineString  [dim(1){A.mL.Int.SP-EP = B.mL.Int.SP-EP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-1-2: equal non-simple MultiLineString with different sequence of lines and points [dim(1){A.mL.Int.SP-EP = B.mL.Int.EP-SP}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 140, 90 60, 90 20), 
+      (170 20, 130 20, 20 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="1FFF0FFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-1: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPb}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60), 
+      (130 100, 130 60, 90 20, 50 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-2: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPo}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (130 140, 130 60, 90 20, 20 90, 90 20, 130 60, 170 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-3: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPx}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF1F00102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-4: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPx}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60), 
+      (130 100, 90 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-5: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Bdy.SPx}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60), 
+      (120 100, 170 100, 90 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-6: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Int.SPb}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60), 
+      (120 100, 170 100, 90 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-7: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Int.SPo}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (130 140, 130 60, 90 20, 20 90, 90 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-3-8: non-simple MultiLineStrings touching at boundaries [dim(0){A.mL.Bdy.SPx = B.mL.Int.SPx}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 20, 170 20), 
+      (90 20, 90 80, 90 140))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (90 20, 170 100, 170 140), 
+      (170 60, 90 20, 20 60, 20 140, 90 20))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF10F0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-4-1: non-simple MultiLineStrings crossing [dim(0){A.mL.Int.Vx = B.mL.Int.Vb}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 90, 20 160), 
+      (90 160, 90 20))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (160 160, 90 90, 160 20), 
+      (160 120, 120 120, 90 90, 160 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-4-2: non-simple MultiLineStrings crossing [dim(0){A.mL.Int.Vx = B.mL.Int.Vo}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 90, 20 160), 
+      (90 160, 90 20))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (160 160, 90 90, 160 20), 
+      (160 120, 120 120, 90 90, 120 60, 160 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mL/mL-4-3: non-simple MultiLineStrings crossing [dim(0){A.mL.Int.Vx = B.mL.Int.Vx}]</desc>
+  <a>
+    MULTILINESTRING(
+      (20 20, 90 90, 20 160), 
+      (90 160, 90 20))
+  </a>
+  <b>
+    MULTILINESTRING(
+      (160 160, 90 90, 160 20), 
+      (160 120, 90 90, 160 60))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F1FF0102">true</op>
+  </test>
+</case>
+
+</run>
+
diff --git a/tests/testthat/testxml/validate/TestRelatePA.xml b/tests/testthat/testxml/validate/TestRelatePA.xml
new file mode 100644
index 0000000..e10ac8b
--- /dev/null
+++ b/tests/testthat/testxml/validate/TestRelatePA.xml
@@ -0,0 +1,623 @@
+<run>
+<precisionModel type="FLOATING"/>
+
+<case>
+<desc>P/A-2-1: a point outside a polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-2-2: a point outside a converx polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
+  <a>
+    POINT(70 170)
+  </a>
+  <b>
+    POLYGON(
+      (110 230, 80 160, 20 160, 20 20, 200 20, 200 160, 140 160, 110 230))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-2-3: a point outside a concave polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
+  <a>
+    POINT(110 130)
+  </a>
+  <b>
+    POLYGON(
+      (20 160, 80 160, 110 100, 140 160, 200 160, 200 20, 20 20, 20 160))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-2-4: dim(0){A.P.Int = B.A.Ext}</desc>
+  <a>
+    POINT(100 70)
+  </a>
+  <b>
+    POLYGON(
+      (20 150, 100 150, 40 50, 170 50, 110 150, 190 150, 190 20, 20 20, 20 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-2-5: a point outside a concave polygon [dim(0){A.P.Int = B.A.Ext}]</desc>
+  <a>
+    POINT(100 70)
+  </a>
+  <b>
+    POLYGON(
+      (20 150, 100 150, 40 50, 160 50, 100 150, 180 150, 180 20, 20 20, 20 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-3-1: a point on the closing point of a polygon [dim(0){A.P.Int = B.A.Bdy.CP}]</desc>
+  <a>
+    POINT(60 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-3-2: a point on the boudary of a polygon at a non-vertex [dim(0){A.P.Int = B.A.Bdy.NV}]</desc>
+  <a>
+    POINT(110 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-3-3: a point on the boundary of a polygon at a vertex [dim(0){A.P.Int = B.A.Bdy.V]</desc>
+  <a>
+    POINT(160 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-3-4: a point on the touching point of boudary [dim(0){A.P.Int = B.A.Bdy.TP}]</desc>
+  <a>
+    POINT(100 150)
+  </a>
+  <b>
+    POLYGON(
+      (20 150, 100 150, 40 50, 160 50, 100 150, 180 150, 180 20, 20 20, 20 150))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A-5: a point on the interior of a polygon [dim(0){A.P.Int = B.A.Int}]</desc>
+  <a>
+    POINT(100 80)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-2-1: a point outside of polygon with a hole [dim(0){A.P.Int = B.A.Ext}]</desc>
+  <a>
+    POINT(60 160)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-2-2: a point inside the hole of the polygon [dim(0){A.P.Int = B.A.Ext.h}]</desc>
+  <a>
+    POINT(190 90)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-1: a point on the closing point of the outer boundary of a polygon with a hole [dim(0){A.P.Int = B.A.oBdy.CP}]</desc>
+  <a>
+    POINT(190 190)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-2: a point on the outer boundary of a polygon at a vertex [dim(0){A.P.Int = B.A.oBdy.V}]</desc>
+  <a>
+    POINT(360 20)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-3: a point on the outer boundary of a polygon at a non-vertex [dim(0){A.P.Int = B.A.oBdy.NV}]</desc>
+  <a>
+    POINT(130 130)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-4: a point on the closing point of the inner boundary of a polygon [dim(0){A.P.Int = B.A.iBdy.CP}]</desc>
+  <a>
+    POINT(280 50)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-5: a point on the inner boundary of a polygon at a non-vertex [dim(0){A.P.Int = B.A.iBdy.NV}]</desc>
+  <a>
+    POINT(150 100)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-3-6: a point on the inner boundary of a polygon at a vertex [dim(0){A.P.Int = B.A.iBdy.V}]</desc>
+  <a>
+    POINT(100 50)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/Ah-5: a point inside the interior of a polygon with a hole [dim(0){A.P.Int = B.A.Int}]</desc>
+  <a>
+    POINT(140 120)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A2h-3-1: a point on the touching point of two holes in a polygon [dim(0){A.P.Int = B.A.iBdy.TP}]</desc>
+  <a>
+    POINT(190 50)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (90 50, 150 110, 190 50, 90 50), 
+      (190 50, 230 110, 290 50, 190 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/A2h-3-2: a point on the touching point of two holes in a polygon [dim(0){A.P.Int = B.A.iBdy.TP}]</desc>
+  <a>
+    POINT(180 90)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (180 140, 180 40, 80 40, 180 140), 
+      (180 90, 210 140, 310 40, 230 40, 180 90))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-2: 3 points outside a polygon [dim(0){A.2P.Int = B.A.Ext}]</desc>
+  <a>
+    MULTIPOINT(20 80, 110 160, 20 160)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-1: one of 3 points on the closing point of the boundary of a polygon [dim(0){A.3P1.Int = B.A.Bdy.CP}]</desc>
+  <a>
+    MULTIPOINT(20 80, 60 120, 20 160)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-2: one of 3 points on the boundary of a polygon at a non-vertex [dim(0){A.3P3 = B.A.Bdy.NV}]</desc>
+  <a>
+    MULTIPOINT(10 80, 110 170, 110 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-3: one of 3 points on the boundary of a polygon at a vertex [dim(0){A.3P1.Int = B.A.Bdy.V}]</desc>
+  <a>
+    MULTIPOINT(10 80, 110 170, 160 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-4: 3 of the 5 points on the boundary of a polygon [dim(0){A.5P2.Int = B.A.Bdy.CP}, dim(0){A.5P3.Int = B.A.Bdy.NV}, dim(0){A.5P4.Int = B.A.Bdy.V}]</desc>
+  <a>
+    MULTIPOINT(20 120, 60 120, 110 120, 160 120, 200 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-5: all 3 points on the boundary of a polygon [dim(0){A.3P1.Int = B.A.Bdy.CP}, dim(0){A.3P2.Int = B.A.Bdy.NV}, dim(0){A.3P3.Int = B.A.Bdy.V}]</desc>
+  <a>
+    MULTIPOINT(60 120, 110 120, 160 120)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-3-6: all 4 points on the boundary of a polygon [dim(0){A.4P = B.A.Bdy}]</desc>
+  <a>
+    MULTIPOINT(60 120, 160 120, 160 40, 60 40)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-4-1: 1 point outside a polygon, 1 point on the boundary and 1 point inside [dim(0){A.3P1.Int = B.A.Ext}, dim(0){A.3P2.Int = B.A.Bdy.CP}, dim(0){A.3P3.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(20 150, 60 120, 110 80)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-4-2: 1 point outside a polygon, 1 point on the boundary and 1 point inside [dim(0){A.3P1.Int = B.A.Ext}, dim(0){A.3P2.Int = B.A.Bdy.V}, dim(0){A.3P3.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(110 80, 160 120, 200 160)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-4-3: 1 point outside a polygon, 1 point on the boundary and 1 point inside [dim(0){A.3P1.Int = B.A.Ext}, dim(0){A.3P2.Int = B.A.Bdy.NV}, dim(0){A.3P3.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(110 80, 110 120, 110 160)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-4-4: 1 point outside a polygon, 1 point inside [dim(0){A.2P1.Int = B.A.Ext}, dim(0){A.2P2.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(110 170, 110 80)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-4-5: 1 point outside a polygon, 2 points on the boundary and 1 point inside [dim(0){A.4P1.Int = B.A.Ext}, dim(0){A.4P2.Int = B.A.Bdy.CP}, dim(0){A.4P3.Int = B.A.Bdy.V}, dim(0){A.4P4.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(60 120, 160 120, 110 80, 110 170)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="000FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-5-1: 2 points within a polygon [dim(0){A.2P.Int = B.A.Int]</desc>
+  <a>
+    MULTIPOINT(90 80, 130 80)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/A-5-2: 1 point on the boundary and 1 point inside a polygon [dim(0){A.2P1.Int = B.A.Bdy.CP}, dim(0){A.2P2.Int = B.A.Int}]</desc>
+  <a>
+    MULTIPOINT(60 120, 160 120, 110 80)
+  </a>
+  <b>
+    POLYGON(
+      (60 120, 60 40, 160 40, 160 120, 60 120))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/Ah-2-1: 3 points outside a polygon [dim(0){A.3P.Int = B.Ah.Ext}]</desc>
+  <a>
+    MULTIPOINT(40 170, 40 90, 130 170)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/Ah-2-2: 2 points outside a polygon and 1 point inside the hole of the polygon [dim(0){A.3P1.Int = B.Ah.Ext}, dim(0){A.3P2.Int = B.Ah.Ext}, dim(0){A.3P3.Int = B.Ah.Ext.h}]</desc>
+  <a>
+    MULTIPOINT(90 170, 280 170, 190 90)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/Ah-2-3: all 3 points in polygon's hole [dim(0){A.3P.Int = B.Ah.Ext.h}]</desc>
+  <a>
+    MULTIPOINT(190 110, 150 70, 230 70)
+  </a>
+  <b>
+    POLYGON(
+      (190 190, 360 20, 20 20, 190 190), 
+      (280 50, 100 50, 190 140, 280 50))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mA-3-1: a point on the touching point of two polygons [dim(0){A.P.Int = B.2A.Bdy}]</desc>
+  <a>
+    POINT(100 100)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 100, 20 20, 100 20, 100 100, 20 100)), 
+      (
+        (100 180, 100 100, 180 100, 180 180, 100 180)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mA-3-2: a point on the boundary of one of the 2 polygons [dim(0){A.P.Int = B.2A1.Bdy.CP}]</desc>
+  <a>
+    POINT(20 100)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 100, 20 20, 100 20, 100 100, 20 100)), 
+      (
+        (100 180, 100 100, 180 100, 180 180, 100 180)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mA-3-3: a point on the boundary of one of the 2 polygons [dim(0){A.P.Int = B.2A1.Bdy.V}]</desc>
+  <a>
+    POINT(60 100)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (20 100, 20 20, 100 20, 100 100, 20 100)), 
+      (
+        (100 180, 100 100, 180 100, 180 180, 100 180)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mA-3-4: a point touching a polygon's boundary where the boundaries touch at a point [dim(0){A.P.Int = B.2A.Bdy.TP}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    MULTIPOLYGON(
+      (
+        (110 110, 20 200, 200 200, 110 110), 
+        (110 110, 80 180, 140 180, 110 110)), 
+      (
+        (110 110, 20 20, 200 20, 110 110), 
+        (110 110, 80 40, 140 40, 110 110)))
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF212">true</op>
+  </test>
+</case>
+
+</run>
+
diff --git a/tests/testthat/testxml/validate/TestRelatePL.xml b/tests/testthat/testxml/validate/TestRelatePL.xml
new file mode 100644
index 0000000..525b30b
--- /dev/null
+++ b/tests/testthat/testxml/validate/TestRelatePL.xml
@@ -0,0 +1,1284 @@
+<run>
+<precisionModel type="FLOATING"/>
+
+<case>
+<desc>P/L-2: a point and a line disjoint [dim(0){A.P.Int = B.L.Ext}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/L-3-1: a point touching the start point of a line  [dim(0){A.P.Int = B.L.Bdy.SP}]</desc>
+  <a>
+    POINT(90 80)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/L-3-2: a point touching the end point of a line [dim(0){A.P.Int = B.L.Bdy.EP}]</desc>
+  <a>
+    POINT(340 240)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/L-5-1: a point on the line at a non-vertex [dim(0){A.P.Int = B.L.Int.NV}]</desc>
+  <a>
+    POINT(230 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/L-5-2: a point on the line at a vertex [dim(0){A.P.Int = B.L.Int.V}]</desc>
+  <a>
+    POINT(160 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/LR-2-1: a point outside a LinearRing [dim(0){A.P.Int = B.LR.Ext}]</desc>
+  <a>
+    POINT(90 150)
+  </a>
+  <b>
+    LINESTRING(150 150, 20 20, 280 20, 150 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/LR-2-2: a point inside a LinearRing  [dim(0){A.P.Int = B.LR.Ext}]</desc>
+  <a>
+    POINT(150 80)
+  </a>
+  <b>
+    LINESTRING(150 150, 20 20, 280 20, 150 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/LR-5-1: a point on the closing point of a LinearRing [dim(0){A.P.Int = B.LR.Int.CP}]</desc>
+  <a>
+    POINT(150 150)
+  </a>
+  <b>
+    LINESTRING(150 150, 20 20, 280 20, 150 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/LR-5-2: a point on a LinearRing at a non-vertex [dim(0){A.P.Int = B.L.Int.NV}]</desc>
+  <a>
+    POINT(100 20)
+  </a>
+  <b>
+    LINESTRING(150 150, 20 20, 280 20, 150 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/LR-5-3: a point on a LinearRing at a vertex [dim(0){A.P.Int = B.L.Int.V}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    LINESTRING(150 150, 20 20, 280 20, 150 150)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.1-3-1: a point on a non-simple LineString's end point [dim(0){A.P.Int = B.nsL.Bdy.EP}]</desc>
+  <a>
+    POINT(220 220)
+  </a>
+  <b>
+    LINESTRING(110 110, 220 20, 20 20, 110 110, 220 220)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.1-5-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 220 20, 20 20, 110 110, 220 220)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.1-5-2: a point a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 220 20, 20 20, 220 220)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.1-5-3: a point on a non-simple LineString's interior at a non-vertex [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
+  <a>
+    POINT(110 20)
+  </a>
+  <b>
+    LINESTRING(110 110, 220 20, 20 20, 220 220)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.1-5-4: a point on a non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
+  <a>
+    POINT(220 20)
+  </a>
+  <b>
+    LINESTRING(110 110, 220 20, 20 20, 220 220)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.2-5-2: a point on a non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
+  <a>
+    POINT(110 20)
+  </a>
+  <b>
+    LINESTRING(220 220, 20 20, 220 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.2-5-3: a point on a non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    LINESTRING(220 220, 20 20, 220 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.2-5-4: a point on a non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(20 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 20 20, 110 20, 20 110, 110 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-3-1: a point on a non-simple LineString's start point [dim(0){A.P.Int = B.nsL.Bdy.SP}]</desc>
+  <a>
+    POINT(20 200)
+  </a>
+  <b>
+    LINESTRING(20 200, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-1: a point on a non-simple LineString's interior at a non-vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 200 20, 140 20, 140 80, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-2: a point on a non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-3: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
+  <a>
+    POINT(80 140)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 110, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-4: a point on a non-simple LineString's interior at a two-vertex point with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vo}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 110, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-5: a point on a non-simple LineString's interior at a vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vo}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-6: a point on a non-simple LineString's interior at a two-vertex point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 110, 200 20, 20 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-7: a point on a non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 200 20, 20 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.3-5-8: a point on a non-simple LineString's interior at a two-vertex point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 110, 20 20, 200 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-1: a point on a non-simple LineString's start point with crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 110 110, 200 20, 140 20, 140 80, 110 110, 80 140, 
+    20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-2: a point on a non-simple LineString's start point with crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 200 20, 140 20, 140 80, 110 110, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-3:a point on a non-simple LineString's start point with crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 200 20, 140 20, 140 80, 80 140, 20 140)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-4: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-5: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 200 20, 20 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-6: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-7: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 110 110, 20 20, 200 20, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.4-3-8: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 110 200, 20 200, 200 20, 200 110, 110 110, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.5-3-1: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 110 110, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.5-3-2: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.5-3-3: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.5-3-4: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 110 110, 200 20, 20 20, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.5-3-5: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 20 110, 110 110, 20 200, 110 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.6-3-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 160)
+  </a>
+  <b>
+    LINESTRING(110 160, 200 250, 110 250, 110 160, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.6-3-2: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(110 160)
+  </a>
+  <b>
+    LINESTRING(110 160, 200 250, 110 250, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.6-3-3: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 160, 200 250, 110 250, 110 160, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.6-3-4: a point on a non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 160, 200 250, 110 250, 110 160, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.7-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.7-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.7-5-3: a point on a closed non-simple LineString's interior at a non-vertex [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
+  <a>
+    POINT(140 200)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.7-5-4: a point on a closed non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 20 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.8-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 200 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.8-5-2: a point on the interior (at a non-vertex) of a closed non-simple LineString [dim(0){A.P.Int = B.nsL.Int.NV}]</desc>
+  <a>
+    POINT(140 200)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 200 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.8-5-3: a point on a closed non-simple LineString's interior at a vertex [dim(0){A.P.Int = B.nsL.Int.V}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(110 110, 200 200, 110 200, 110 110, 110 20, 200 20, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.9-3-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 90 130, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.9-5-1: a point on a non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 90 130, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.10-3-1: a point on a non-simple LineString's start point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.10-5-1: a point on a non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 200 20, 20 20, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.11-3-1: a point on a closed non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.EPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 90 130, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.11-5-1: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 90 130, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.12-3-1: a point on a closed non-simple LineString's end point with crossing line segments [dim(0){A.P.Int = B.nsL.Bdy.SPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.12-5-1: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 20 130, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.13-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 20 130, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 200 130, 
+    110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.13-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 20 130, 20 200, 200 20, 20 20, 200 200, 200 130, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.14-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 80 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 140 200, 
+    110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.14-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 110, 80 200, 20 200, 200 20, 20 20, 200 200, 140 200, 110 110)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.15-5-1: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 20 20, 200 20, 20 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.15-5-2: a point on a closed non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 110 110, 20 20, 200 20, 110 110, 20 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.15-5-3: a point on a closed non-simple LineString's interior at a vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.Vx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(200 200, 110 110, 200 20, 20 20, 110 110, 20 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.16-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 90 130, 110 110, 200 20, 20 20, 110 110, 200 200, 
+    90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.16-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 20 130, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.17-5-1: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 90 200, 20 200, 90 130, 110 110, 200 20, 20 20, 110 110, 200 200, 
+    90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.17-5-2: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 90 200, 20 200, 200 20, 20 20, 200 200, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.17-5-3: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 90 200, 20 200, 110 110, 200 20, 20 20, 110 110, 200 200, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.17-5-4: a point on a closed non-simple LineString's closing point with crossing line segments [dim(0){A.P.Int = B.nsL.Int.CPx}]</desc>
+  <a>
+    POINT(90 130)
+  </a>
+  <b>
+    LINESTRING(90 130, 90 200, 20 200, 200 20, 20 20, 200 200, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.17-5-5: a point on a closed non-simple LineString's interior at a non-vertex with crossing line segments [dim(0){A.P.Int = B.nsL.Int.NVx}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(90 130, 90 200, 20 200, 200 20, 20 20, 200 200, 90 130)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.18-5-1: a point on a non-simple LineString's start point with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Bdy.SPb)}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F0FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.18-5-2: a point on a non-simple LineString's interior at a non-vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
+  <a>
+    POINT(110 150)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.18-5-3: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.19-5-1: a point on a non-simple LineString's closing point with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.CPo}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.19-5-2: a point on a non-simple LineString's interior at a non-vertex overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
+  <a>
+    POINT(110 150)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.19-5-3: a point on a non-simple LineString interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(110 200, 110 110, 20 20, 200 20, 110 110, 110 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.20-5-1: a point on a non-simple LineString's interior at a non-vertex with overlapping line segments [dim(0){A.P.Int = B.nsL.Int.NVo}]</desc>
+  <a>
+    POINT(110 150)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsL.20-5-2: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
+  <a>
+    POINT(110 110)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/nsl.20-5-3: a point on a non-simple LineString's interior at a vertex with both crossing and overlapping line segments [dim(0){A.P.Int = B.nsL.Int.Vb}]</desc>
+  <a>
+    POINT(110 200)
+  </a>
+  <b>
+    LINESTRING(20 200, 110 200, 110 110, 20 20, 200 20, 110 110, 110 200, 200 200)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-2-1: MultiPoint and a line disjoint (points on one side of the line) [dim(0){A.3P.Int = B.L.Ext}]</desc>
+  <a>
+    MULTIPOINT(50 250, 90 220, 130 190)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-2-2: MultiPoint and a line disjoint (points over the line but no intersection) [dim(0){A.3P.Int = B.L.Ext}]</desc>
+  <a>
+    MULTIPOINT(180 180, 230 130, 280 80)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-3-1: one of the points intersecting the start point of a line [dim(0){A.3P2.Int = B.L.Bdy.SP}]</desc>
+  <a>
+    MULTIPOINT(50 120, 90 80, 130 40)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-3-2: one of the points intersecting the end point of a line [dim(0){A.3P2 = B.L.Bdy.EP}]</desc>
+  <a>
+    MULTIPOINT(300 280, 340 240, 380 200)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="F00FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-4-1: one of the points intersecting the interior of a line at a non-vertex (points on one side of the line) [dim(0){A.3P1.Int = B.L.Int.NV]</desc>
+  <a>
+    MULTIPOINT(230 150, 260 120, 290 90)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-4-2: one of the points intersecting the interior of a line at a non-vertex (points over the line) [dim(0){A.3P2.Int = B.L.Int.NV]</desc>
+  <a>
+    MULTIPOINT(200 190, 240 150, 270 110)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-4-3: one of the points intersecting the interior of a line at a vertex (points on one side of the line) [dim(0){A.3P1.Int = B.L.Int.V]</desc>
+  <a>
+    MULTIPOINT(160 150, 190 120, 220 90)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-4-4: one of the points intersecting the interior of a line at a vertex (points over the line) [dim(0){A.3P2.Int = B.L.Int.V]</desc>
+  <a>
+    MULTIPOINT(120 190, 160 150, 200 110)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-1: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Bdy.EP}]</desc>
+  <a>
+    MULTIPOINT(90 80, 160 150, 340 240)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF1F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-2: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.V}]</desc>
+  <a>
+    MULTIPOINT(90 80, 160 150, 300 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-3: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
+  <a>
+    MULTIPOINT(90 80, 160 150, 240 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-4: all the points on a line [dim(0){A.3P1.Int = B.L.Bdy.SP}, dim(0){A.3P2.Int = B.L.Int.NV}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
+  <a>
+    MULTIPOINT(90 80, 130 120, 210 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-5: all the points on a line [dim(0){A.3P1.Int = B.L.Int.NV}, dim(0){A.3P2.Int = B.L.Int.NV}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
+  <a>
+    MULTIPOINT(130 120, 210 150, 340 200)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-6: all the points on a line [dim(0){A.3P1.Int = B.L.Int.V}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.NV}]</desc>
+  <a>
+    MULTIPOINT(160 150, 240 150, 340 210)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-7: all the points on a line [dim(0){A.3P1.Int = B.L.Int.V}, dim(0){A.3P2.Int = B.L.Int.V}, dim(0){A.3P3.Int = B.Int.V}]</desc>
+  <a>
+    MULTIPOINT(160 150, 300 150, 340 150)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF102">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/L-5-8: all the points on a line [dim(0){A.3P1.Int = B.L.Int.V}, dim(0){A.3P2.Int = B.L.Int.NV}, dim(0){A.3P3.Int = B.Bdy.EP}]</desc>
+  <a>
+    MULTIPOINT(160 150, 240 150, 340 240)
+  </a>
+  <b>
+    LINESTRING(90 80, 160 150, 300 150, 340 150, 340 240)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="00FFFF102">true</op>
+  </test>
+</case>
+
+</run>
+
diff --git a/tests/testthat/testxml/validate/TestRelatePP.xml b/tests/testthat/testxml/validate/TestRelatePP.xml
new file mode 100644
index 0000000..7798173
--- /dev/null
+++ b/tests/testthat/testxml/validate/TestRelatePP.xml
@@ -0,0 +1,174 @@
+<run>
+<precisionModel type="FLOATING"/>
+
+<case>
+<desc>P/P: same point [dim(0){A.P.Int = B.P.Int}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    POINT(20 20)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/P: different point [dim(0){A.P.Int = B.P.Ext}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    POINT(40 60)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF0F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mP: different points [dim(0){A.P.Int = B.3P.Ext}]</desc>
+  <a>
+    POINT(40 40)
+  </a>
+  <b>
+    MULTIPOINT(20 20, 80 80, 20 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF0F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>P/mP: point A within one of B points [dim(0){A.P.Int = B.3P1.Int}]</desc>
+  <a>
+    POINT(20 20)
+  </a>
+  <b>
+    MULTIPOINT(20 20, 80 80, 20 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFF0F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-1-1: same points [dim(0){A.3P1.Int = B.3P1.Int}, dim(0){A.3P2.Int = B.3P2.Int}, dim(0){A.3P3.Int = B.3P3.Int}]</desc>
+  <a>
+    MULTIPOINT(40 40, 80 60, 120 100)
+  </a>
+  <b>
+    MULTIPOINT(40 40, 80 60, 120 100)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-1-2: same but different sequence of points [dim(0){A.3P1.Int = B.3P1.Int}, dim(0){A.3P1.Int = B.3P3.Int}, dim(0){A.3P3.Int = B.3P2.Int}]</desc>
+  <a>
+    MULTIPOINT(40 40, 80 60, 120 100)
+  </a>
+  <b>
+    MULTIPOINT(40 40, 120 100, 80 60)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-2: different points [dim(0){A.4P.Int = B.4P.Ext}]</desc>
+  <a>
+    MULTIPOINT(40 40, 60 100, 100 60, 120 120)
+  </a>
+  <b>
+    MULTIPOINT(20 120, 60 60, 100 100, 140 40)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="FF0FFF0F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-5-1: same points [dim(0){A.4P.Int = B.4P.Int}]</desc>
+  <a>
+    MULTIPOINT(20 20, 80 70, 140 120, 200 170)
+  </a>
+  <b>
+    MULTIPOINT(20 20, 80 70, 140 120, 200 170)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-5-2: same points but different sequence [dim(0){A.4P.Int = B.4P.Int}]</desc>
+  <a>
+    MULTIPOINT(20 20, 140 120, 80 70, 200 170)
+  </a>
+  <b>
+    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0FFFFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-5-3: some points same [dim(0){A.4P2.Int = B.2P1.Int}, dim(0){A.4P3.Int = B.2P2.Int}]</desc>
+  <a>
+    MULTIPOINT(20 20, 80 70, 140 120, 200 170)
+  </a>
+  <b>
+    MULTIPOINT(80 70, 140 120)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-5-4: some points same, in a different sequence [dim(0){A.4P1.Int = B.2P2.Int}, dim(0){A.4P4.Int = B.2P1.Int}]</desc>
+  <a>
+    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
+  </a>
+  <b>
+    MULTIPOINT(140 120, 80 70)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFFFF2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-6-1: some points same, some different [dim(0){A.4P4.Int = B.3P2.Int}]</desc>
+  <a>
+    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
+  </a>
+  <b>
+    MULTIPOINT(80 170, 140 120, 200 80)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF0F2">true</op>
+  </test>
+</case>
+
+<case>
+<desc>mP/mP-6-2: dim(0){A.4P1.Int = B.4P4.Int}, dim(0){A.4P4.Int = B.4P2.Int}</desc>
+  <a>
+    MULTIPOINT(80 70, 20 20, 200 170, 140 120)
+  </a>
+  <b>
+    MULTIPOINT(80 170, 140 120, 200 80, 80 70)
+  </b>
+  <test>
+    <op name="relate" arg1="A" arg2="B" arg3="0F0FFF0F2">true</op>
+  </test>
+</case>
+
+</run>
+
diff --git a/tools/winlibs.R b/tools/winlibs.R
new file mode 100644
index 0000000..00ac191
--- /dev/null
+++ b/tools/winlibs.R
@@ -0,0 +1,11 @@
+if(getRversion() < "3.3.0") {
+  stop("Your version of R is too old. This package requires R-3.3.0 or newer on Windows.")
+}
+
+# Download gdal-2.2.0 from rwinlib
+if(!file.exists("../windows/gdal2-2.2.0/include/geos/geos_c.h")){
+  download.file("https://github.com/rwinlib/gdal2/archive/v2.2.0.zip", "lib.zip", quiet = TRUE)
+  dir.create("../windows", showWarnings = FALSE)
+  unzip("lib.zip", exdir = "../windows")
+  unlink("lib.zip")
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-rgeos.git



More information about the debian-med-commit mailing list