[geos-commits] r4123 - in trunk: . capi include/geos/algorithm src/algorithm tests/unit tests/unit/algorithm tests/unit/capi

svn_geos at osgeo.org svn_geos at osgeo.org
Mon Nov 30 04:01:42 PST 2015


Author: strk
Date: 2015-11-30 04:01:42 -0800 (Mon, 30 Nov 2015)
New Revision: 4123

Added:
   trunk/tests/unit/algorithm/MinimumDiameterTest.cpp
   trunk/tests/unit/capi/GEOSMinimumDiameterTest.cpp
   trunk/tests/unit/capi/GEOSMinimumRectangleTest.cpp
Modified:
   trunk/NEWS
   trunk/capi/geos_c.cpp
   trunk/capi/geos_c.h.in
   trunk/capi/geos_ts_c.cpp
   trunk/include/geos/algorithm/MinimumDiameter.h
   trunk/src/algorithm/MinimumDiameter.cpp
   trunk/tests/unit/Makefile.am
Log:
Port MinimumDiameter::getMinimumRectangle algorithm from JTS

Also add GEOSMinimumRotatedRectangle and GEOSMinimumDiameter
to C API, and re-sync MinimumDiameter with JTS r966.

Includes testcases.

Fixes #729.

Patch by: Nyall Dawson <nyall.dawson at gmail.com>
Signed-off-by: Sandro Santilli <strk at keybit.net>

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2015-11-30 10:06:15 UTC (rev 4122)
+++ trunk/NEWS	2015-11-30 12:01:42 UTC (rev 4123)
@@ -4,6 +4,8 @@
 - New things:
   - CAPI: GEOSGeom_setPrecision (#713) - PHP: Geometry->setPrecision
   - CAPI: GEOSGeom_getPrecision - PHP: Geometry->getPrecision
+  - CAPI: GEOSMinimumRotatedRectangle and GEOSMinimumDiameter
+    (#729, Nyall Dawson)
 - Improvements:
   - ...
 - C++ API changes:

Modified: trunk/capi/geos_c.cpp
===================================================================
--- trunk/capi/geos_c.cpp	2015-11-30 10:06:15 UTC (rev 4122)
+++ trunk/capi/geos_c.cpp	2015-11-30 12:01:42 UTC (rev 4123)
@@ -437,6 +437,18 @@
 }
 
 Geometry *
+GEOSMinimumRotatedRectangle(const Geometry *g)
+{
+    return GEOSMinimumRotatedRectangle_r( handle, g );
+}
+
+Geometry *
+GEOSMinimumDiameter(const Geometry *g)
+{
+    return GEOSMinimumDiameter_r( handle, g );
+}
+
+Geometry *
 GEOSDifference(const Geometry *g1, const Geometry *g2)
 {
     return GEOSDifference_r( handle, g1, g2 );

Modified: trunk/capi/geos_c.h.in
===================================================================
--- trunk/capi/geos_c.h.in	2015-11-30 10:06:15 UTC (rev 4122)
+++ trunk/capi/geos_c.h.in	2015-11-30 12:01:42 UTC (rev 4123)
@@ -538,6 +538,10 @@
                                                  const GEOSGeometry* g2);
 extern GEOSGeometry GEOS_DLL *GEOSConvexHull_r(GEOSContextHandle_t handle,
                                                const GEOSGeometry* g);
+extern GEOSGeometry GEOS_DLL *GEOSMinimumRotatedRectangle_r(GEOSContextHandle_t handle,
+                                               const GEOSGeometry* g);
+extern GEOSGeometry GEOS_DLL *GEOSMinimumDiameter_r(GEOSContextHandle_t handle,
+                                               const GEOSGeometry* g);
 extern GEOSGeometry GEOS_DLL *GEOSDifference_r(GEOSContextHandle_t handle,
                                                const GEOSGeometry* g1,
                                                const GEOSGeometry* g2);
@@ -1448,6 +1452,8 @@
 extern GEOSGeometry GEOS_DLL *GEOSEnvelope(const GEOSGeometry* g);
 extern GEOSGeometry GEOS_DLL *GEOSIntersection(const GEOSGeometry* g1, const GEOSGeometry* g2);
 extern GEOSGeometry GEOS_DLL *GEOSConvexHull(const GEOSGeometry* g);
+extern GEOSGeometry GEOS_DLL *GEOSMinimumRotatedRectangle(const GEOSGeometry* g);
+extern GEOSGeometry GEOS_DLL *GEOSMinimumDiameter(const GEOSGeometry* g);
 extern GEOSGeometry GEOS_DLL *GEOSDifference(const GEOSGeometry* g1, const GEOSGeometry* g2);
 extern GEOSGeometry GEOS_DLL *GEOSSymDifference(const GEOSGeometry* g1, const GEOSGeometry* g2);
 extern GEOSGeometry GEOS_DLL *GEOSBoundary(const GEOSGeometry* g);

Modified: trunk/capi/geos_ts_c.cpp
===================================================================
--- trunk/capi/geos_ts_c.cpp	2015-11-30 10:06:15 UTC (rev 4122)
+++ trunk/capi/geos_ts_c.cpp	2015-11-30 12:01:42 UTC (rev 4123)
@@ -43,6 +43,7 @@
 #include <geos/algorithm/distance/DiscreteHausdorffDistance.h>
 #include <geos/algorithm/CGAlgorithms.h>
 #include <geos/algorithm/BoundaryNodeRule.h>
+#include <geos/algorithm/MinimumDiameter.h>
 #include <geos/simplify/DouglasPeuckerSimplifier.h>
 #include <geos/simplify/TopologyPreservingSimplifier.h>
 #include <geos/noding/GeometryNoder.h>
@@ -2007,7 +2008,77 @@
     return NULL;
 }
 
+
 Geometry *
+GEOSMinimumRotatedRectangle_r(GEOSContextHandle_t extHandle, const Geometry *g)
+{
+    if ( 0 == extHandle )
+    {
+        return NULL;
+    }
+
+    GEOSContextHandleInternal_t *handle = 0;
+    handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
+    if ( 0 == handle->initialized )
+    {
+        return NULL;
+    }
+
+    try
+    {
+        geos::algorithm::MinimumDiameter m(g);
+
+        Geometry *g3 = m.getMinimumRectangle();
+        return g3;
+    }
+    catch (const std::exception &e)
+    {
+        handle->ERROR_MESSAGE("%s", e.what());
+    }
+    catch (...)
+    {
+        handle->ERROR_MESSAGE("Unknown exception thrown");
+    }
+
+    return NULL;
+}
+
+Geometry *
+GEOSMinimumDiameter_r(GEOSContextHandle_t extHandle, const Geometry *g)
+{
+    if ( 0 == extHandle )
+    {
+        return NULL;
+    }
+
+    GEOSContextHandleInternal_t *handle = 0;
+    handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
+    if ( 0 == handle->initialized )
+    {
+        return NULL;
+    }
+
+    try
+    {
+        geos::algorithm::MinimumDiameter m(g);
+
+        Geometry *g3 = m.getDiameter();
+        return g3;
+    }
+    catch (const std::exception &e)
+    {
+        handle->ERROR_MESSAGE("%s", e.what());
+    }
+    catch (...)
+    {
+        handle->ERROR_MESSAGE("Unknown exception thrown");
+    }
+
+    return NULL;
+}
+
+
+Geometry *
 GEOSDifference_r(GEOSContextHandle_t extHandle, const Geometry *g1, const Geometry *g2)
 {
     if ( 0 == extHandle )

Modified: trunk/include/geos/algorithm/MinimumDiameter.h
===================================================================
--- trunk/include/geos/algorithm/MinimumDiameter.h	2015-11-30 10:06:15 UTC (rev 4122)
+++ trunk/include/geos/algorithm/MinimumDiameter.h	2015-11-30 12:01:42 UTC (rev 4123)
@@ -11,6 +11,10 @@
  * by the Free Software Foundation. 
  * See the COPYING file for more information.
  *
+ **********************************************************************
+ *
+ * Last port: algorithm/MinimumDiameter.java r966
+ *
  **********************************************************************/
 
 #ifndef GEOS_ALGORITHM_MINIMUMDIAMETER_H
@@ -47,6 +51,13 @@
  * The first step in the algorithm is computing the convex hull of the Geometry.
  * If the input Geometry is known to be convex, a hint can be supplied to
  * avoid this computation.
+ * <p>
+ * This class can also be used to compute a line segment representing
+ * the minimum diameter, the supporting line segment of the minimum diameter,
+ * and a minimum rectangle enclosing the input geometry.
+ * This rectangle will
+ * have width equal to the minimum diameter, and have one side
+ * parallel to the supporting segment.
  *
  * @see ConvexHull
  *
@@ -55,6 +66,9 @@
 private:
 	const geom::Geometry* inputGeom;
 	bool isConvex;
+
+	geom::CoordinateSequence* convexHullPts;
+
 	geom::LineSegment* minBaseSeg;
 	geom::Coordinate* minWidthPt;
 	int minPtIndex;
@@ -77,6 +91,10 @@
 	static unsigned int getNextIndex(const geom::CoordinateSequence* pts,
 		unsigned int index);
 
+	static double computeC(double a, double b, const geom::Coordinate &p);
+
+	static geom::LineSegment computeSegmentForLine(double a, double b, double c);
+
 public:
 	~MinimumDiameter();
 
@@ -126,6 +144,33 @@
 	 * @return a LineString which is a minimum diameter
 	 */
 	geom::LineString* getDiameter();
+
+	/**
+	 * Gets the minimum rectangular Polygon which encloses the input geometry. The rectangle has width
+	 * equal to the minimum diameter, and a longer length. If the convex hill of the input is degenerate
+	 * (a line or point) a LineString or Point is returned.
+	 * The minimum rectangle can be used as an extremely generalized representation for the given
+	 * geometry.
+	 *
+	 * @return the minimum rectangle enclosing the input (or a line or point if degenerate)
+	 */
+	geom::Geometry* getMinimumRectangle();
+
+	/**
+	 * Gets the minimum rectangle enclosing a geometry.
+	 *
+	 * @param geom the geometry
+	 * @return the minimum rectangle enclosing the geometry
+	*/
+	static geom::Geometry* getMinimumRectangle(geom::Geometry* geom);
+
+	/**
+	 * Gets the length of the minimum diameter enclosing a geometry
+	 * @param geom the geometry
+	 * @return the length of the minimum diameter of the geometry
+	 */
+	static geom::Geometry* getMinimumDiameter(geom::Geometry* geom);
+
 };
 
 } // namespace geos::algorithm

Modified: trunk/src/algorithm/MinimumDiameter.cpp
===================================================================
--- trunk/src/algorithm/MinimumDiameter.cpp	2015-11-30 10:06:15 UTC (rev 4122)
+++ trunk/src/algorithm/MinimumDiameter.cpp	2015-11-30 12:01:42 UTC (rev 4123)
@@ -12,6 +12,10 @@
  * See the COPYING file for more information.
  *
  **********************************************************************
+ *
+ * Last port: algorithm/MinimumDiameter.java r966
+ *
+ **********************************************************************
  * 
  * TODO:
  * 	- avoid heap allocation for LineSegment and Coordinate
@@ -23,6 +27,7 @@
 #include <geos/geom/Geometry.h>
 #include <geos/geom/LineSegment.h>
 #include <geos/geom/Polygon.h>
+#include <geos/geom/Point.h>
 #include <geos/geom/LineString.h>
 #include <geos/geom/CoordinateSequenceFactory.h>
 #include <geos/geom/GeometryFactory.h>
@@ -67,6 +72,7 @@
 	minWidth=0.0;
 	inputGeom=newInputGeom;
 	isConvex=false;
+	convexHullPts=NULL;
 }
 
 /**
@@ -86,12 +92,14 @@
 	minWidth=0.0;
 	inputGeom=newInputGeom;
 	isConvex=newIsConvex;
+	convexHullPts=NULL;
 }
 
 MinimumDiameter::~MinimumDiameter()
 {
 	delete minBaseSeg;
 	delete minWidthPt;
+	delete convexHullPts;
 }
 
 /**
@@ -177,42 +185,45 @@
 MinimumDiameter::computeWidthConvex(const Geometry *geom)
 {
 	//System.out.println("Input = " + geom);
-	CoordinateSequence* pts=NULL;
+	delete convexHullPts;
 	if (typeid(*geom)==typeid(Polygon))
 	{
 		const Polygon* p = dynamic_cast<const Polygon*>(geom);
-		pts=p->getExteriorRing()->getCoordinates();
+		convexHullPts=p->getExteriorRing()->getCoordinates();
 	}
 	else
 	{
-		pts=geom->getCoordinates();
+		convexHullPts=geom->getCoordinates();
 	}
 
 	// special cases for lines or points or degenerate rings
-	switch(pts->getSize())
+	switch(convexHullPts->getSize())
 	{
 		case 0:
 			minWidth=0.0;
+			delete minWidthPt;
 			minWidthPt=NULL;
+			delete minBaseSeg;
 			minBaseSeg=NULL;
 			break;
 		case 1:
 			minWidth = 0.0;
-			minWidthPt=new Coordinate(pts->getAt(0));
-			minBaseSeg->p0=pts->getAt(0);
-			minBaseSeg->p1=pts->getAt(0);
+			delete minWidthPt;
+			minWidthPt=new Coordinate(convexHullPts->getAt(0));
+			minBaseSeg->p0=convexHullPts->getAt(0);
+			minBaseSeg->p1=convexHullPts->getAt(0);
 			break;
 		case 2:
 		case 3:
 			minWidth = 0.0;
-			minWidthPt=new Coordinate(pts->getAt(0));
-			minBaseSeg->p0=pts->getAt(0);
-			minBaseSeg->p1=pts->getAt(1);
+			delete minWidthPt;
+			minWidthPt=new Coordinate(convexHullPts->getAt(0));
+			minBaseSeg->p0=convexHullPts->getAt(0);
+			minBaseSeg->p1=convexHullPts->getAt(1);
 			break;
 		default:
-			computeConvexRingMinDiameter(pts);
+			computeConvexRingMinDiameter(convexHullPts);
 	}
-	delete pts; 
 }
 
 /**
@@ -275,6 +286,111 @@
 	return index;
 }
 
+Geometry* MinimumDiameter::getMinimumRectangle()
+{
+	computeMinimumDiameter();
+
+	if ( !minBaseSeg || !convexHullPts )
+	{
+		//return empty polygon
+		return inputGeom->getFactory()->createPolygon();
+	}
+
+	// check if minimum rectangle is degenerate (a point or line segment)
+	if (minWidth == 0.0) {
+		if (minBaseSeg->p0.equals2D(minBaseSeg->p1)) {
+			return inputGeom->getFactory()->createPoint(minBaseSeg->p0);
+		}
+		return minBaseSeg->toGeometry(*inputGeom->getFactory()).release();
+	}
+
+	// deltas for the base segment of the minimum diameter
+	double dx = minBaseSeg->p1.x - minBaseSeg->p0.x;
+	double dy = minBaseSeg->p1.y - minBaseSeg->p0.y;
+
+	double minPara = DoubleMax;
+	double maxPara = -DoubleMax;
+	double minPerp = DoubleMax;
+	double maxPerp = -DoubleMax;
+
+	// compute maxima and minima of lines parallel and perpendicular to base segment
+	std::size_t const n=convexHullPts->getSize();
+	for (std::size_t i = 0; i < n; ++i) {
+
+		double paraC = computeC(dx, dy, convexHullPts->getAt(i));
+		if (paraC > maxPara) maxPara = paraC;
+		if (paraC < minPara) minPara = paraC;
+
+		double perpC = computeC(-dy, dx, convexHullPts->getAt(i));
+		if (perpC > maxPerp) maxPerp = perpC;
+		if (perpC < minPerp) minPerp = perpC;
+	}
+
+	// compute lines along edges of minimum rectangle
+	LineSegment maxPerpLine = computeSegmentForLine(-dx, -dy, maxPerp);
+	LineSegment minPerpLine = computeSegmentForLine(-dx, -dy, minPerp);
+	LineSegment maxParaLine = computeSegmentForLine(-dy, dx, maxPara);
+	LineSegment minParaLine = computeSegmentForLine(-dy, dx, minPara);
+
+	// compute vertices of rectangle (where the para/perp max & min lines intersect)
+	Coordinate p0, p1, p2, p3;
+	maxParaLine.lineIntersection(maxPerpLine, p0);
+	minParaLine.lineIntersection(maxPerpLine, p1);
+	minParaLine.lineIntersection(minPerpLine, p2);
+	maxParaLine.lineIntersection(minPerpLine, p3);
+
+	const CoordinateSequenceFactory *csf =
+	inputGeom->getFactory()->getCoordinateSequenceFactory();
+
+	geom::CoordinateSequence *seq = csf->create(5, 2);
+	seq->setAt(p0, 0);
+	seq->setAt(p1, 1);
+	seq->setAt(p2, 2);
+	seq->setAt(p3, 3);
+	seq->setAt(p0, 4); // close
+
+	LinearRing* shell = inputGeom->getFactory()->createLinearRing( seq );
+	return inputGeom->getFactory()->createPolygon( shell, NULL );
+}
+
+double MinimumDiameter::computeC(double a, double b, const Coordinate& p)
+{
+	return a * p.y - b * p.x;
+}
+
+LineSegment MinimumDiameter::computeSegmentForLine(double a, double b, double c)
+{
+	Coordinate p0;
+	Coordinate p1;
+	/*
+	* Line eqn is ax + by = c
+	* Slope is a/b.
+	* If slope is steep, use y values as the inputs
+	*/
+	if (fabs(b) > fabs(a) ) {
+		p0 = Coordinate(0.0, c/b);
+		p1 = Coordinate(1.0, c/b - a/b);
+	}
+	else {
+		p0 = Coordinate(c/a, 0.0);
+		p1 = Coordinate(c/a - b/a, 1.0);
+	}
+	return LineSegment(p0, p1);
+}
+
+
+Geometry *MinimumDiameter::getMinimumRectangle(Geometry *geom)
+{
+	MinimumDiameter md( geom );
+	return md.getMinimumRectangle();
+}
+
+Geometry *MinimumDiameter::getMinimumDiameter(Geometry *geom)
+{
+	MinimumDiameter md( geom );
+	return md.getDiameter();
+}
+
 } // namespace geos.algorithm
 } // namespace geos
 

Modified: trunk/tests/unit/Makefile.am
===================================================================
--- trunk/tests/unit/Makefile.am	2015-11-30 10:06:15 UTC (rev 4122)
+++ trunk/tests/unit/Makefile.am	2015-11-30 12:01:42 UTC (rev 4123)
@@ -41,6 +41,7 @@
 	algorithm/CGAlgorithms/signedAreaTest.cpp \
 	algorithm/ConvexHullTest.cpp \
 	algorithm/distance/DiscreteHausdorffDistanceTest.cpp \
+	algorithm/MinimumDiameterTest.cpp \
 	algorithm/PointLocatorTest.cpp \
 	algorithm/RobustLineIntersectionTest.cpp \
 	algorithm/RobustLineIntersectorTest.cpp \
@@ -130,6 +131,8 @@
 	capi/GEOSInterruptTest.cpp \
 	capi/GEOSIntersectsTest.cpp \
 	capi/GEOSIntersectionTest.cpp \
+	capi/GEOSMinimumRectangleTest.cpp \
+	capi/GEOSMinimumDiameterTest.cpp \
 	capi/GEOSNearestPointsTest.cpp \
 	capi/GEOSWithinTest.cpp \
 	capi/GEOSSimplifyTest.cpp \

Added: trunk/tests/unit/algorithm/MinimumDiameterTest.cpp
===================================================================
--- trunk/tests/unit/algorithm/MinimumDiameterTest.cpp	                        (rev 0)
+++ trunk/tests/unit/algorithm/MinimumDiameterTest.cpp	2015-11-30 12:01:42 UTC (rev 4123)
@@ -0,0 +1,236 @@
+/**********************************************************************
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.osgeo.org
+ *
+ * Copyright (C) 2015      Nyall Dawson <nyall dot dawson at gmail dot com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU Lesser General Public Licence as published
+ * by the Free Software Foundation.
+ * See the COPYING file for more information.
+ *
+ **********************************************************************/
+
+//
+// Test Suite for geos::algorithm::MinimumDiameter
+
+#include <tut.hpp>
+// geos
+#include <geos/geom/Coordinate.h>
+#include <geos/algorithm/MinimumDiameter.h>
+#include <geos/io/WKTReader.h>
+#include <geos/io/WKTWriter.h>
+#include <geos/geom/Geometry.h>
+// std
+#include <sstream>
+#include <string>
+#include <memory>
+
+namespace tut
+{
+    //
+    // Test Group
+    //
+
+    // dummy data, not used
+    struct test_minimumdiameter_data {
+      typedef geos::geom::Geometry Geometry;
+      typedef std::auto_ptr<geos::geom::Geometry> GeomPtr;
+
+      typedef geos::geom::Coordinate Coordinate;
+      typedef geos::algorithm::MinimumDiameter MinimumDiameter;
+
+      geos::io::WKTReader reader;
+      std::auto_ptr<Geometry> geom;
+
+      test_minimumdiameter_data()
+      {}
+
+    };
+
+    typedef test_group<test_minimumdiameter_data> group;
+    typedef group::object object;
+
+    group test_minimumdiameter_data_group("geos::algorithm::MinimumDiameter");
+
+    //
+    // Test Cases
+    //
+
+    // Test of getMinimumRectangle
+    template<>
+    template<>
+    void object::test<1>()
+    {
+        GeomPtr geom(reader.read("POLYGON ((0 0, 0 20, 20 20, 20 0, 0 0))"));
+        ensure(0 != geom.get());
+
+        geos::algorithm::MinimumDiameter m(geom.get());
+        GeomPtr minRect( m.getMinimumRectangle() );
+        ensure(0 != minRect.get());
+
+        GeomPtr expectedGeom(reader.read("POLYGON ((0 0, 20 0, 20 20, 0 20, 0 0))"));
+        ensure(0 != expectedGeom.get());
+
+        ensure( minRect.get()->equalsExact(expectedGeom.get()) );
+    }
+
+    // Test with expected rotated rectangle
+    template<>
+    template<>
+    void object::test<2>()
+    {
+        GeomPtr geom(reader.read("POLYGON ((0 5, 5 10, 10 5, 5 0, 0 5))"));
+        ensure(0 != geom.get());
+
+        geos::algorithm::MinimumDiameter m(geom.get());
+        GeomPtr minRect( m.getMinimumRectangle() );
+        ensure(0 != minRect.get());
+
+        GeomPtr expectedGeom(reader.read("POLYGON ((5 0, 10 5, 5 10, 0 5, 5 0))"));
+        ensure(0 != expectedGeom.get());
+
+        ensure( minRect.get()->equalsExact(expectedGeom.get()) );
+    }
+
+    // Test with EMPTY input
+    template<>
+    template<>
+    void object::test<3>()
+    {
+        GeomPtr geom(reader.read("POLYGON EMPTY"));
+        ensure(0 != geom.get());
+
+        geos::algorithm::MinimumDiameter m(geom.get());
+        GeomPtr minRect( m.getMinimumRectangle() );
+        ensure(0 != minRect.get());
+
+        GeomPtr expectedGeom(reader.read("POLYGON EMPTY"));
+        ensure(0 != expectedGeom.get());
+
+        ensure( minRect.get()->equalsExact(expectedGeom.get()) );
+    }
+
+    // Test with Point input
+    template<>
+    template<>
+    void object::test<4>()
+    {
+        GeomPtr geom(reader.read("Point(1 2)"));
+        ensure(0 != geom.get());
+
+        geos::algorithm::MinimumDiameter m(geom.get());
+        GeomPtr minRect( m.getMinimumRectangle() );
+        ensure(0 != minRect.get());
+
+        GeomPtr expectedGeom(reader.read("Point(1 2)"));
+        ensure(0 != expectedGeom.get());
+
+        ensure( minRect.get()->equalsExact(expectedGeom.get()) );
+    }
+
+    // Test with LineString input
+    template<>
+    template<>
+    void object::test<5>()
+    {
+        GeomPtr geom(reader.read("LineString(1 2, 2 4)"));
+        ensure(0 != geom.get());
+
+        geos::algorithm::MinimumDiameter m(geom.get());
+        GeomPtr minRect( m.getMinimumRectangle() );
+        ensure(0 != minRect.get());
+
+        GeomPtr expectedGeom(reader.read("LineString(1 2, 2 4)"));
+        ensure(0 != expectedGeom.get());
+
+        ensure( minRect.get()->equalsExact(expectedGeom.get()) );
+    }
+
+    // Test minimumDiameter with Point input
+    template<>
+    template<>
+    void object::test<6>()
+    {
+        GeomPtr geom(reader.read("POINT (0 240)"));
+        ensure(0 != geom.get());
+
+        GeomPtr minDiameter( geos::algorithm::MinimumDiameter::getMinimumDiameter( geom.get() ) );
+        ensure(0 != minDiameter.get());
+
+        GeomPtr expectedGeom(reader.read("LineString (0 240, 0 240)"));
+        ensure(0 != expectedGeom.get());
+
+        ensure( minDiameter.get()->equalsExact(expectedGeom.get()) );
+    }
+
+    // Test minimumDiameter with LineString input
+    template<>
+    template<>
+    void object::test<7>()
+    {
+        GeomPtr geom(reader.read("LINESTRING (0 240, 220 240)"));
+        ensure(0 != geom.get());
+
+        GeomPtr minDiameter( geos::algorithm::MinimumDiameter::getMinimumDiameter( geom.get() ) );
+        ensure(0 != minDiameter.get());
+
+        GeomPtr expectedGeom(reader.read("LINESTRING (0 240, 0 240)"));
+        ensure(0 != expectedGeom.get());
+
+        ensure( minDiameter.get()->equalsExact(expectedGeom.get()) );
+    }
+
+    // Test minimumDiameter with Polygon input
+    template<>
+    template<>
+    void object::test<8>()
+    {
+        GeomPtr geom(reader.read("POLYGON ((0 240, 220 240, 220 0, 0 0, 0 240))"));
+        ensure(0 != geom.get());
+
+        GeomPtr minDiameter( geos::algorithm::MinimumDiameter::getMinimumDiameter( geom.get() ) );
+        ensure(0 != minDiameter.get());
+
+        GeomPtr expectedGeom(reader.read("LINESTRING (0 0, 220 0)"));
+        ensure(0 != expectedGeom.get());
+
+        ensure( minDiameter.get()->equalsExact(expectedGeom.get()) );
+    }
+
+    // Test minimumDiameter with Polygon input
+    template<>
+    template<>
+    void object::test<9>()
+    {
+        GeomPtr geom(reader.read("POLYGON ((0 240, 160 140, 220 0, 0 0, 0 240))"));
+        ensure(0 != geom.get());
+
+        GeomPtr minDiameter( geos::algorithm::MinimumDiameter::getMinimumDiameter( geom.get() ) );
+        ensure(0 != minDiameter.get());
+
+        GeomPtr expectedGeom(reader.read("LINESTRING (185.86206896551724 79.65517241379311, 0 0)"));
+        ensure(0 != expectedGeom.get());
+
+        ensure( minDiameter.get()->equalsExact(expectedGeom.get(), 0.00000000001) );
+    }
+
+    // Test minimumDiameter with complex LineString
+    template<>
+    template<>
+    void object::test<10>()
+    {
+        GeomPtr geom(reader.read("LINESTRING ( 39 119, 162 197, 135 70, 95 35, 33 66, 111 82, 97 131, 48 160, -4 182, 57 195, 94 202, 90 174, 75 134, 47 114, 0 100, 59 81, 123 60, 136 43, 163 75, 145 114, 93 136, 92 159, 105 175 )"));
+        ensure(0 != geom.get());
+
+        GeomPtr minDiameter( geos::algorithm::MinimumDiameter::getMinimumDiameter( geom.get() ) );
+        ensure(0 != minDiameter.get());
+
+        GeomPtr expectedGeom(reader.read("LINESTRING (64.46262341325811 196.41184767277855, 95 35)"));
+        ensure(0 != expectedGeom.get());
+
+        ensure( minDiameter.get()->equalsExact(expectedGeom.get(), 0.00000000001) );
+    }
+
+} // namespace tut

Added: trunk/tests/unit/capi/GEOSMinimumDiameterTest.cpp
===================================================================
--- trunk/tests/unit/capi/GEOSMinimumDiameterTest.cpp	                        (rev 0)
+++ trunk/tests/unit/capi/GEOSMinimumDiameterTest.cpp	2015-11-30 12:01:42 UTC (rev 4123)
@@ -0,0 +1,83 @@
+//
+// Test Suite for C-API GEOSMinimumDiameter
+#include <tut.hpp>
+// geos
+#include <geos_c.h>
+// std
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+namespace tut
+{
+    //
+    // Test Group
+    //
+
+    // Common data used in test cases.
+    struct test_capigeosminimumdiameter_data
+    {
+        GEOSGeometry* input_;
+        GEOSWKTWriter* wktw_;
+        char* wkt_;
+
+        static void notice(const char *fmt, ...)
+        {
+            std::fprintf( stdout, "NOTICE: ");
+
+            va_list ap;
+            va_start(ap, fmt);
+            std::vfprintf(stdout, fmt, ap);
+            va_end(ap);
+
+            std::fprintf(stdout, "\n");
+        }
+
+        test_capigeosminimumdiameter_data()
+            : input_(0), wkt_(0)
+        {
+            initGEOS(notice, notice);
+            wktw_ = GEOSWKTWriter_create();
+            GEOSWKTWriter_setTrim(wktw_, 1);
+            GEOSWKTWriter_setRoundingPrecision(wktw_, 8);
+        }
+
+        ~test_capigeosminimumdiameter_data()
+        {
+            GEOSGeom_destroy(input_);
+            input_ = 0;
+            GEOSWKTWriter_destroy(wktw_);
+            GEOSFree(wkt_);
+            wkt_ = 0;
+            finishGEOS();
+        }
+
+    };
+
+    typedef test_group<test_capigeosminimumdiameter_data> group;
+    typedef group::object object;
+
+    group test_capigeosminimumdiameter_group("capi::GEOSMinimumDiameter");
+
+    //
+    // Test Cases
+    //
+
+    template<>
+    template<>
+    void object::test<1>()
+    {
+        input_ = GEOSGeomFromWKT("POLYGON ((0 0, 0 15, 5 10, 5 0, 0 0))");
+        ensure( 0 != input_ );
+
+        GEOSGeometry* output = GEOSMinimumDiameter(input_);
+        ensure( 0 != output );
+        ensure( 0 == GEOSisEmpty(output) );
+
+        wkt_ = GEOSWKTWriter_write(wktw_, output);
+        ensure_equals(std::string(wkt_), std::string( "LINESTRING (0 0, 5 0)"));
+
+        GEOSGeom_destroy(output);
+    }
+
+} // namespace tut

Added: trunk/tests/unit/capi/GEOSMinimumRectangleTest.cpp
===================================================================
--- trunk/tests/unit/capi/GEOSMinimumRectangleTest.cpp	                        (rev 0)
+++ trunk/tests/unit/capi/GEOSMinimumRectangleTest.cpp	2015-11-30 12:01:42 UTC (rev 4123)
@@ -0,0 +1,84 @@
+//
+// Test Suite for C-API GEOSMinimumRotatedRectangle
+
+#include <tut.hpp>
+// geos
+#include <geos_c.h>
+// std
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+namespace tut
+{
+    //
+    // Test Group
+    //
+
+    // Common data used in test cases.
+    struct test_capigeosminimumrectangle_data
+    {
+        GEOSGeometry* input_;
+        GEOSWKTWriter* wktw_;
+        char* wkt_;
+
+        static void notice(const char *fmt, ...)
+        {
+            std::fprintf( stdout, "NOTICE: ");
+
+            va_list ap;
+            va_start(ap, fmt);
+            std::vfprintf(stdout, fmt, ap);
+            va_end(ap);
+
+            std::fprintf(stdout, "\n");
+        }
+
+        test_capigeosminimumrectangle_data()
+            : input_(0), wkt_(0)
+        {
+            initGEOS(notice, notice);
+            wktw_ = GEOSWKTWriter_create();
+            GEOSWKTWriter_setTrim(wktw_, 1);
+            GEOSWKTWriter_setRoundingPrecision(wktw_, 8);
+        }
+
+        ~test_capigeosminimumrectangle_data()
+        {
+            GEOSGeom_destroy(input_);
+            input_ = 0;
+            GEOSWKTWriter_destroy(wktw_);
+            GEOSFree(wkt_);
+            wkt_ = 0;
+            finishGEOS();
+        }
+
+    };
+
+    typedef test_group<test_capigeosminimumrectangle_data> group;
+    typedef group::object object;
+
+    group test_capigeosminimumrectangle_group("capi::GEOSMinimumRotatedRectangle");
+
+    //
+    // Test Cases
+    //
+
+    template<>
+    template<>
+    void object::test<1>()
+    {
+        input_ = GEOSGeomFromWKT("POLYGON ((1 6, 6 11, 11 6, 6 1, 1 6))");
+        ensure( 0 != input_ );
+
+        GEOSGeometry* output = GEOSMinimumRotatedRectangle(input_);
+        ensure( 0 != output );
+        ensure( 0 == GEOSisEmpty(output) );
+
+        wkt_ = GEOSWKTWriter_write(wktw_, output);
+        ensure_equals(std::string(wkt_), std::string( "POLYGON ((6 1, 11 6, 6 11, 1 6, 6 1))"));
+
+        GEOSGeom_destroy(output);
+    }
+
+} // namespace tut



More information about the geos-commits mailing list