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

Sandro Santilli strk at kbt.io
Mon Dec 5 05:09:17 PST 2016


Author: strk
Date: 2016-12-05 05:09:16 -0800 (Mon, 05 Dec 2016)
New Revision: 4314

Added:
   trunk/include/geos/algorithm/distance/DiscreteFrechetDistance.h
   trunk/src/algorithm/distance/DiscreteFrechetDistance.cpp
   trunk/tests/unit/algorithm/distance/DiscreteFrechetDistanceTest.cpp
   trunk/tests/unit/capi/GEOSFrechetDistanceTest.cpp
   trunk/tests/unit/capi/GEOSHausdorffDistanceTest.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/distance/Makefile.am
   trunk/include/geos/algorithm/distance/PointPairDistance.h
   trunk/src/Makefile.vc
   trunk/src/algorithm/distance/Makefile.am
   trunk/tests/geostest/geostest.c
   trunk/tests/geostest/test.expected
   trunk/tests/unit/Makefile.am
Log:
Add DiscreteFrechetDistance

Patch by Shinichi SUGIYAMA <shin.sugi at gmail.com>
Closes #797

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2016-12-02 14:01:48 UTC (rev 4313)
+++ trunk/NEWS	2016-12-05 13:09:16 UTC (rev 4314)
@@ -3,6 +3,7 @@
 
 - New things:
   - CAPI: GEOSDistanceIndexed (#795, Dan Baston)
+  - CAPI: GEOSFrechetDistance (#797, Shinichi SUGIYAMA)
 
 Changes in 3.6.0
 2016-10-25

Modified: trunk/capi/geos_c.cpp
===================================================================
--- trunk/capi/geos_c.cpp	2016-12-02 14:01:48 UTC (rev 4313)
+++ trunk/capi/geos_c.cpp	2016-12-05 13:09:16 UTC (rev 4314)
@@ -25,6 +25,7 @@
 #include <geos/operation/overlay/OverlayOp.h>
 #include <geos/operation/union/CascadedPolygonUnion.h>
 #include <geos/algorithm/distance/DiscreteHausdorffDistance.h>
+#include <geos/algorithm/distance/DiscreteFrechetDistance.h>
 #include <geos/util/Interrupt.h>
 
 #include <stdexcept>
@@ -297,6 +298,18 @@
 }
 
 int
+GEOSFrechetDistance(const Geometry *g1, const Geometry *g2, double *dist)
+{
+    return GEOSFrechetDistance_r( handle, g1, g2, dist );
+}
+
+int
+GEOSFrechetDistanceDensify(const Geometry *g1, const Geometry *g2, double densifyFrac, double *dist)
+{
+    return GEOSFrechetDistanceDensify_r( handle, g1, g2, densifyFrac, dist );
+}
+
+int
 GEOSArea(const Geometry *g, double *area)
 {
     return GEOSArea_r( handle, g, area );

Modified: trunk/capi/geos_c.h.in
===================================================================
--- trunk/capi/geos_c.h.in	2016-12-02 14:01:48 UTC (rev 4313)
+++ trunk/capi/geos_c.h.in	2016-12-05 13:09:16 UTC (rev 4314)
@@ -1111,6 +1111,14 @@
                                    const GEOSGeometry *g1,
                                    const GEOSGeometry *g2,
                                    double densifyFrac, double *dist);
+extern int GEOS_DLL GEOSFrechetDistance_r(GEOSContextHandle_t handle,
+                                   const GEOSGeometry *g1,
+                                   const GEOSGeometry *g2,
+                                   double *dist);
+extern int GEOS_DLL GEOSFrechetDistanceDensify_r(GEOSContextHandle_t handle,
+                                   const GEOSGeometry *g1,
+                                   const GEOSGeometry *g2,
+                                   double densifyFrac, double *dist);
 extern int GEOS_DLL GEOSGeomGetLength_r(GEOSContextHandle_t handle,
                                    const GEOSGeometry *g, double *length);
 
@@ -1972,6 +1980,10 @@
         const GEOSGeometry *g2, double *dist);
 extern int GEOS_DLL GEOSHausdorffDistanceDensify(const GEOSGeometry *g1,
         const GEOSGeometry *g2, double densifyFrac, double *dist);
+extern int GEOS_DLL GEOSFrechetDistance(const GEOSGeometry *g1,
+        const GEOSGeometry *g2, double *dist);
+extern int GEOS_DLL GEOSFrechetDistanceDensify(const GEOSGeometry *g1,
+        const GEOSGeometry *g2, double densifyFrac, double *dist);
 extern int GEOS_DLL GEOSGeomGetLength(const GEOSGeometry *g, double *length);
 
 /* Return 0 on exception, the closest points of the two geometries otherwise.

Modified: trunk/capi/geos_ts_c.cpp
===================================================================
--- trunk/capi/geos_ts_c.cpp	2016-12-02 14:01:48 UTC (rev 4313)
+++ trunk/capi/geos_ts_c.cpp	2016-12-05 13:09:16 UTC (rev 4314)
@@ -42,6 +42,7 @@
 #include <geos/io/WKTWriter.h>
 #include <geos/io/WKBWriter.h>
 #include <geos/algorithm/distance/DiscreteHausdorffDistance.h>
+#include <geos/algorithm/distance/DiscreteFrechetDistance.h>
 #include <geos/algorithm/CGAlgorithms.h>
 #include <geos/algorithm/BoundaryNodeRule.h>
 #include <geos/algorithm/MinimumDiameter.h>
@@ -141,6 +142,7 @@
 using geos::precision::GeometryPrecisionReducer;
 using geos::util::IllegalArgumentException;
 using geos::algorithm::distance::DiscreteHausdorffDistance;
+using geos::algorithm::distance::DiscreteFrechetDistance;
 
 typedef std::auto_ptr<Geometry> GeomAutoPtr;
 
@@ -1262,6 +1264,74 @@
 }
 
 int
+GEOSFrechetDistance_r(GEOSContextHandle_t extHandle, const Geometry *g1, const Geometry *g2, double *dist)
+{
+    assert(0 != dist);
+
+    if ( 0 == extHandle )
+    {
+        return 0;
+    }
+
+    GEOSContextHandleInternal_t *handle = 0;
+    handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
+    if ( 0 == handle->initialized )
+    {
+        return 0;
+    }
+
+    try
+    {
+        *dist = DiscreteFrechetDistance::distance(*g1, *g2);
+        return 1;
+    }
+    catch (const std::exception &e)
+    {
+        handle->ERROR_MESSAGE("%s", e.what());
+    }
+    catch (...)
+    {
+        handle->ERROR_MESSAGE("Unknown exception thrown");
+    }
+
+    return 0;
+}
+
+int
+GEOSFrechetDistanceDensify_r(GEOSContextHandle_t extHandle, const Geometry *g1, const Geometry *g2, double densifyFrac, double *dist)
+{
+    assert(0 != dist);
+
+    if ( 0 == extHandle )
+    {
+        return 0;
+    }
+
+    GEOSContextHandleInternal_t *handle = 0;
+    handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
+    if ( 0 == handle->initialized )
+    {
+        return 0;
+    }
+
+    try
+    {
+        *dist = DiscreteFrechetDistance::distance(*g1, *g2, densifyFrac);
+        return 1;
+    }
+    catch (const std::exception &e)
+    {
+        handle->ERROR_MESSAGE("%s", e.what());
+    }
+    catch (...)
+    {
+        handle->ERROR_MESSAGE("Unknown exception thrown");
+    }
+
+    return 0;
+}
+
+int
 GEOSArea_r(GEOSContextHandle_t extHandle, const Geometry *g, double *area)
 {
     assert(0 != area);

Added: trunk/include/geos/algorithm/distance/DiscreteFrechetDistance.h
===================================================================
--- trunk/include/geos/algorithm/distance/DiscreteFrechetDistance.h	                        (rev 0)
+++ trunk/include/geos/algorithm/distance/DiscreteFrechetDistance.h	2016-12-05 13:09:16 UTC (rev 4314)
@@ -0,0 +1,184 @@
+/**********************************************************************
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.osgeo.org
+ *
+ * Copyright (C) 2016 Shinichi SUGIYAMA (shin.sugi at gmail.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.
+ *
+ **********************************************************************
+ *
+ * Last port: original work
+ *
+ * Developed by Shinichi SUGIYAMA (shin.sugi at gmail.com)
+ * based on http://www.kr.tuwien.ac.at/staff/eiter/et-archive/cdtr9464.pdf
+ *
+ **********************************************************************/
+
+#ifndef GEOS_ALGORITHM_DISTANCE_DISCRETEFRECHETDISTANCE_H
+#define GEOS_ALGORITHM_DISTANCE_DISCRETEFRECHETDISTANCE_H
+
+#include <geos/export.h>
+#include <geos/algorithm/distance/PointPairDistance.h> // for composition
+#include <geos/algorithm/distance/DistanceToPoint.h> // for composition
+#include <geos/util/IllegalArgumentException.h> // for inlines
+#include <geos/geom/Geometry.h> // for inlines
+#include <geos/util/math.h> // for inlines
+#include <geos/geom/CoordinateFilter.h> // for inheritance
+#include <geos/geom/CoordinateSequence.h> // for inheritance
+
+#include <cstddef>
+#include <vector>
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4251) // warning C4251: needs to have dll-interface to be used by clients of class
+#endif
+
+namespace geos {
+	namespace algorithm {
+		//class RayCrossingCounter;
+	}
+	namespace geom {
+		class Geometry;
+		class Coordinate;
+		//class CoordinateSequence;
+	}
+	namespace index {
+		namespace intervalrtree {
+			//class SortedPackedIntervalRTree;
+		}
+	}
+}
+
+namespace geos {
+namespace algorithm { // geos::algorithm
+namespace distance { // geos::algorithm::distance
+
+/** \brief
+ * An algorithm for computing a distance metric
+ * which is an approximation to the Frechet Distance
+ * based on a discretization of the input {@link Geometry}.
+ *
+ * The algorithm computes the Frechet distance restricted to discrete points
+ * for one of the geometries.
+ * The points can be either the vertices of the geometries (the default),
+ * or the geometries with line segments densified by a given fraction.
+ * Also determines two points of the Geometries which are separated by the
+ * computed distance.
+ *
+ * This algorithm is an approximation to the standard Frechet distance.
+ * Specifically,
+ * <pre>
+ *    for all geometries a, b:    DFD(a, b) >= FD(a, b)
+ * </pre>
+ * The approximation can be made as close as needed by densifying the
+ * input geometries.
+ * In the limit, this value will approach the true Frechet distance:
+ * <pre>
+ *    DFD(A, B, densifyFactor) -> FD(A, B) as densifyFactor -> 0.0
+ * </pre>
+ * The default approximation is exact or close enough for a large subset of
+ * useful cases.
+ *
+ * The difference between DFD and FD is bounded
+ * by the length of the longest edge of the polygonal curves.
+ *
+ * Fréchet distance sweep continuously along their respective curves
+ * and the direction of curves is significant.
+ * This makes a better measure of similarity than Hausdorff distance.
+ *
+ * An example showing how different DHD and DFD are:
+ * <pre>
+ *   A  = LINESTRING (0 0, 50 200, 100 0, 150 200, 200 0)
+ *   B  = LINESTRING (0 200, 200 150, 0 100, 200 50, 0 0)
+ *   B' = LINESTRING (0 0, 200 50, 0 100, 200 150, 0 200)
+ *
+ *   DHD(A, B)  = DHD(A, B') = 48.5071250072666
+ *   DFD(A, B)  = 200
+ *   DFD(A, B') = 282.842712474619
+ * </pre>
+ */
+class GEOS_DLL DiscreteFrechetDistance
+{
+public:
+
+	static double distance(const geom::Geometry& g0,
+			       const geom::Geometry& g1);
+
+	static double distance(const geom::Geometry& g0,
+			       const geom::Geometry& g1, double densifyFrac);
+
+	DiscreteFrechetDistance(const geom::Geometry& g0,
+				const geom::Geometry& g1)
+		:
+		g0(g0),
+		g1(g1),
+		ptDist(),
+		densifyFrac(0.0)
+	{}
+
+	/**
+	 * Sets the fraction by which to densify each segment.
+	 * Each segment will be (virtually) split into a number of equal-length
+	 * subsegments, whose fraction of the total length is closest
+	 * to the given fraction.
+	 *
+	 * @param dFrac
+	 */
+	void setDensifyFraction(double dFrac)
+	{
+		if ( dFrac > 1.0 || dFrac <= 0.0 )
+		{
+			throw util::IllegalArgumentException(
+				"Fraction is not in range (0.0 - 1.0]");
+		}
+
+		densifyFrac = dFrac;
+	}
+
+	double distance()
+	{
+		compute(g0, g1);
+		return ptDist.getDistance();
+	}
+
+	const std::vector<geom::Coordinate> getCoordinates() const
+	{
+		return ptDist.getCoordinates();
+	}
+
+private:
+	geom::Coordinate getSegementAt(const geom::CoordinateSequence& seq, size_t index);
+
+	PointPairDistance& getFrecheDistance(std::vector< std::vector<PointPairDistance> >& ca, size_t i, size_t j, const geom::CoordinateSequence& p, const geom::CoordinateSequence& q);
+
+	void compute(const geom::Geometry& discreteGeom, const geom::Geometry& geom);
+
+	const geom::Geometry& g0;
+
+	const geom::Geometry& g1;
+
+	PointPairDistance ptDist;
+
+	/// Value of 0.0 indicates that no densification should take place
+    double densifyFrac; // = 0.0;
+
+    // Declare type as noncopyable
+    DiscreteFrechetDistance(const DiscreteFrechetDistance& other);
+    DiscreteFrechetDistance& operator=(const DiscreteFrechetDistance& rhs);
+};
+
+} // geos::algorithm::distance
+} // geos::algorithm
+} // geos
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif // GEOS_ALGORITHM_DISTANCE_DISCRETEFRECHETDISTANCE_H

Modified: trunk/include/geos/algorithm/distance/Makefile.am
===================================================================
--- trunk/include/geos/algorithm/distance/Makefile.am	2016-12-02 14:01:48 UTC (rev 4313)
+++ trunk/include/geos/algorithm/distance/Makefile.am	2016-12-05 13:09:16 UTC (rev 4314)
@@ -9,5 +9,6 @@
 
 geos_HEADERS = \
     DiscreteHausdorffDistance.h \
+    DiscreteFrechetDistance.h \
     DistanceToPoint.h \
     PointPairDistance.h

Modified: trunk/include/geos/algorithm/distance/PointPairDistance.h
===================================================================
--- trunk/include/geos/algorithm/distance/PointPairDistance.h	2016-12-02 14:01:48 UTC (rev 4313)
+++ trunk/include/geos/algorithm/distance/PointPairDistance.h	2016-12-05 13:09:16 UTC (rev 4314)
@@ -7,7 +7,7 @@
  *
  * 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. 
+ * by the Free Software Foundation.
  * See the COPYING file for more information.
  *
  **********************************************************************
@@ -108,6 +108,11 @@
 			initialize(p0, p1, dist);
 	}
 
+	bool getIsNull()
+	{
+		return isNull;
+	}
+
 private:
 
 	/**

Modified: trunk/src/Makefile.vc
===================================================================
--- trunk/src/Makefile.vc	2016-12-02 14:01:48 UTC (rev 4313)
+++ trunk/src/Makefile.vc	2016-12-05 13:09:16 UTC (rev 4314)
@@ -52,6 +52,7 @@
 	algorithm\SimplePointInRing.$(EXT) \
 	algorithm\SIRtreePointInRing.$(EXT) \
 	algorithm\distance\DiscreteHausdorffDistance.$(EXT) \
+	algorithm\distance\DiscreteFrechetDistance.$(EXT) \
 	algorithm\distance\DistanceToPoint.$(EXT) \
 	algorithm\locate\IndexedPointInAreaLocator.$(EXT) \
 	algorithm\locate\PointOnGeometryLocator.$(EXT) \

Added: trunk/src/algorithm/distance/DiscreteFrechetDistance.cpp
===================================================================
--- trunk/src/algorithm/distance/DiscreteFrechetDistance.cpp	                        (rev 0)
+++ trunk/src/algorithm/distance/DiscreteFrechetDistance.cpp	2016-12-05 13:09:16 UTC (rev 4314)
@@ -0,0 +1,156 @@
+/**********************************************************************
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.osgeo.org
+ *
+ * Copyright (C) 2016  Shinichi SUGIYAMA <shin.sugi at gmail.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.
+ *
+ **********************************************************************
+ *
+ * Last port: original work
+ *
+ **********************************************************************/
+
+#include <geos/algorithm/distance/DiscreteFrechetDistance.h>
+#include <geos/geom/CoordinateSequence.h>
+
+#include <geos/geom/Geometry.h>
+#include <geos/geom/LineString.h>
+
+#include <typeinfo>
+#include <cassert>
+#include <vector>
+#include <algorithm>
+#include <iostream>
+using namespace geos::geom;
+
+namespace geos {
+namespace algorithm { // geos.algorithm
+namespace distance { // geos.algorithm.distance
+
+/* static public */
+double
+DiscreteFrechetDistance::distance(const geom::Geometry& g0,
+			       const geom::Geometry& g1)
+{
+	DiscreteFrechetDistance dist(g0, g1);
+	return dist.distance();
+}
+
+/* static public */
+double
+DiscreteFrechetDistance::distance(const geom::Geometry& g0,
+			       const geom::Geometry& g1,
+			       double densifyFrac)
+{
+	DiscreteFrechetDistance dist(g0, g1);
+	dist.setDensifyFraction(densifyFrac);
+	return dist.distance();
+}
+
+/* private */
+
+geom::Coordinate
+DiscreteFrechetDistance::getSegementAt(const CoordinateSequence& seq, size_t index)
+{
+	if (densifyFrac > 0.0)
+	{
+		size_t numSubSegs =  std::size_t(util::round(1.0/densifyFrac));
+		size_t i = index / numSubSegs;
+		size_t j = index % numSubSegs;
+		if (i >= seq.size()-1) {
+			return seq.getAt(seq.size()-1);
+		}
+		const geom::Coordinate& p0 = seq.getAt(i);
+		const geom::Coordinate& p1 = seq.getAt(i+1);
+
+		double delx = (p1.x - p0.x)/numSubSegs;
+		double dely = (p1.y - p0.y)/numSubSegs;
+
+		double x = p0.x + j*delx;
+		double y = p0.y + j*dely;
+		Coordinate pt(x, y);
+		return pt;
+	}
+	else
+	{
+		return seq.getAt(index);
+	}
+}
+
+PointPairDistance&
+DiscreteFrechetDistance::getFrecheDistance(std::vector< std::vector<PointPairDistance> >& ca, size_t i, size_t j, const CoordinateSequence& p, const CoordinateSequence& q)
+{
+	PointPairDistance ptDist;
+	if (! ca[i][j].getIsNull())
+	{
+		return ca[i][j];
+	}
+	ptDist.initialize(getSegementAt(p, i), getSegementAt(q, j));
+	if (i == 0 && j == 0)
+	{
+		ca[i][j] = ptDist;
+	}
+	else if (i > 0 && j == 0)
+	{
+		PointPairDistance nextDist = getFrecheDistance(ca,i-1,0,p,q);
+		ca[i][j] =  (nextDist.getDistance() > ptDist.getDistance()) ? nextDist : ptDist;
+	}
+	else if (i == 0 && j > 0)
+	{
+		PointPairDistance nextDist = getFrecheDistance(ca,0,j-1,p,q);
+		ca[i][j] =  (nextDist.getDistance() > ptDist.getDistance()) ? nextDist : ptDist;
+	}
+	else
+	{
+		PointPairDistance d1 = getFrecheDistance(ca,i-1,j,p,q),
+				  d2 = getFrecheDistance(ca,i-1,j-1,p,q),
+				  d3 = getFrecheDistance(ca,i,j-1,p,q);
+		PointPairDistance& minDist = (d1.getDistance() < d2.getDistance()) ? d1 : d2;
+		if (d3.getDistance() < minDist.getDistance()) minDist = d3;
+		ca[i][j] =  (minDist.getDistance() > ptDist.getDistance()) ? minDist : ptDist;
+	}
+
+	return ca[i][j];
+}
+
+void
+DiscreteFrechetDistance::compute(
+		const geom::Geometry& discreteGeom,
+		const geom::Geometry& geom)
+{
+	const CoordinateSequence* lp = discreteGeom.getCoordinates();
+	const CoordinateSequence* lq = geom.getCoordinates();
+	size_t pSize, qSize;
+	if (densifyFrac > 0)
+	{
+		size_t numSubSegs =  std::size_t(util::round(1.0/densifyFrac));
+		pSize = numSubSegs * (lp->size() - 1) + 1;
+		qSize = numSubSegs * (lq->size() - 1) + 1;
+	}
+	else
+	{
+		pSize = lp->size();
+		qSize = lq->size();
+	}
+	std::vector< std::vector<PointPairDistance> > ca(pSize, std::vector<PointPairDistance>(qSize));
+	for (size_t i = 0; i < pSize; i++)
+	{
+		for (size_t j = 0; j < qSize; j++)
+		{
+			ca[i][j].initialize();
+		}
+	}
+	ptDist = getFrecheDistance(ca, pSize-1, qSize-1, *lp, *lq);
+	delete lp;
+	delete lq;
+}
+
+} // namespace geos.algorithm.distance
+} // namespace geos.algorithm
+} // namespace geos

Modified: trunk/src/algorithm/distance/Makefile.am
===================================================================
--- trunk/src/algorithm/distance/Makefile.am	2016-12-02 14:01:48 UTC (rev 4313)
+++ trunk/src/algorithm/distance/Makefile.am	2016-12-05 13:09:16 UTC (rev 4314)
@@ -9,6 +9,7 @@
 
 libdistance_la_SOURCES = \
     DiscreteHausdorffDistance.cpp \
+    DiscreteFrechetDistance.cpp \
     DistanceToPoint.cpp 
 
 libdistance_la_LIBADD = 

Modified: trunk/tests/geostest/geostest.c
===================================================================
--- trunk/tests/geostest/geostest.c	2016-12-02 14:01:48 UTC (rev 4313)
+++ trunk/tests/geostest/geostest.c	2016-12-05 13:09:16 UTC (rev 4314)
@@ -337,6 +337,12 @@
 	/* Hausdorff Distance with densification */
 	if ( GEOSHausdorffDistanceDensify(g1, g2, 0.001, &dist) ) printf("HausdorffDistanceDensify: %g\n", dist);
 
+	/* Frechet Distance */
+	if ( GEOSFrechetDistance(g1, g2, &dist) ) printf("FrechetDistance: %g\n", dist);
+
+	/* Frechet Distance with densification */
+	if ( GEOSFrechetDistanceDensify(g1, g2, 0.1, &dist) ) printf("FrechetDistanceDensify: %g\n", dist);
+
 	/* Area */
 	if ( GEOSArea(g1, &area) ) printf("Area 1: %g\n", area);
 	if ( GEOSArea(g2, &area) ) printf("Area 2: %g\n", area);

Modified: trunk/tests/geostest/test.expected
===================================================================
--- trunk/tests/geostest/test.expected	2016-12-02 14:01:48 UTC (rev 4313)
+++ trunk/tests/geostest/test.expected	2016-12-05 13:09:16 UTC (rev 4314)
@@ -21,6 +21,8 @@
 Distance: 0
 HausdorffDistance: 100
 HausdorffDistanceDensify: 100
+FrechetDistance: 100
+FrechetDistanceDensify: 100
 Area 1: 2.67588e+09
 Area 2: 2.65405e+09
 Simplify: POLYGON ((335215.0239261208334938 167537.5377202073286753, 335205.1267784655792639 167536.2307696900388692, 335190.1602671957225539 167536.1341839407396037, 329275.7395326890982687 167942.1145713863952551, 329261.2026209282921627 167945.7238237099954858, 326746.7026209282921627 168774.3238237039768137, 326614.4661321343737654 168829.7659389766049571, 326483.0105803586193360 168904.0626540626399219, 326415.8285449087852612 168952.2921427348919678, 314706.9285449027665891 178006.3921427289023995, 314699.2775538869318552 178012.9502176995156333, 314692.3254273570491932 178020.2450067681784276, 314686.1427613845444284 178028.2024342618533410, 314680.7923384761670604 178036.7416956787055824, 314230.7465425680857152 178947.3026234415883664, 314226.6719709816970862 178956.7423383510031272, 314223.5882016817340627 178966.5505348258011509, 303859.9882016727351584 219020.0505348258011509, 303310.6373324339510873 221276.7480226673360448, 303244.5555483103962615 221575.223136145708849
 7, 303207.9014352059457451 221755.5931846564926673, 303174.1926699578762054 222016.0467631698702462, 303147.8926699608564377 222311.9467631608713418, 303145.8096594382659532 222441.7101097303093411, 303148.4957166555686854 222489.2534012109390460, 303150.6692645543371327 222504.6388423194293864, 303153.4334335363237187 222514.6280661432247143, 303157.2167087217676453 222524.2775247619138099, 303161.9784481927636079 222533.4835586513218004, 303167.6674988568993285 222542.1472717873693909, 303174.2227459607529454 222550.1755940386210568, 303181.5737696161959320 222557.4822809745091945, 303189.6416012879926711 222563.9888403478544205, 303198.3395721145207062 222569.6253752996271942, 303212.3620380503707565 222576.3191453621548135, 303222.2142427377984859 222579.5377297651721165, 303232.3466742536984384 222581.7192554557113908, 340240.9466742626973428 228562.4192554587207269, 371903.0451431074179709 233449.6295974932727404, 373488.5732348550227471 233688.9796828530670609, 373535.2659228
 414413519 233694.0060347228136379, 373625.1659228474600241 233697.9060347288323101, 373642.9873771221027710 233697.8969001443183515, 373658.5972774084657431 233696.5464864801033400, 373668.8035941756097600 233694.2963110199489165, 373678.7193140533054247 233690.9931775288132485, 373692.8122531549306586 233684.1461583603522740, 373705.6626988743664697 233675.1818597918318119, 373713.3821066011441872 233668.1360854624363128, 373723.4792837048298679 233656.1552833794266917, 373731.5811145076295361 233642.7443571751064155, 373737.4887050554389134 233628.2325351690815296, 373741.0570283696870320 233612.9760718587203883, 373742.1984847519779578 233597.3495021346316207, 373741.5948758341837674 233586.9155264864384662, 373738.6590603159856983 233571.5248282807588112, 373733.3552462080260739 233556.7816210339078680, 373652.5153630711138248 233377.7256075733166654, 365392.9153630621149205 216697.2256075733166654, 365330.2477527938899584 216577.1791839415382128, 339880.6477527848910540 171569.
 1791839415382128, 338822.4769281532499008 169840.9383075150544755, 337870.8334730038768612 168543.3540531243779697, 337827.5742276740493253 168491.7532505890121683, 337753.4899077645386569 168423.4924162378301844, 337717.4185027767089196 168392.1531549684004858, 337663.9758644747198559 168349.0786549655895215, 337651.0045043539139442 168340.2275259852758609, 337530.7915914550540037 168279.3433566540188622, 337516.7246118161710910 168273.5343728628649842, 335388.0246118131908588 167578.8343728748441208, 335310.1989645521389320 167555.1487824073119555, 335215.0239261208334938 167537.5377202073286753))

Modified: trunk/tests/unit/Makefile.am
===================================================================
--- trunk/tests/unit/Makefile.am	2016-12-02 14:01:48 UTC (rev 4313)
+++ trunk/tests/unit/Makefile.am	2016-12-05 13:09:16 UTC (rev 4314)
@@ -1,5 +1,5 @@
 #
-# This file is part of project GEOS (http://trac.osgeo.org/geos/) 
+# This file is part of project GEOS (http://trac.osgeo.org/geos/)
 #
 
 AUTOMAKE_OPTIONS = subdir-objects
@@ -41,6 +41,7 @@
 	algorithm/CGAlgorithms/signedAreaTest.cpp \
 	algorithm/ConvexHullTest.cpp \
 	algorithm/distance/DiscreteHausdorffDistanceTest.cpp \
+	algorithm/distance/DiscreteFrechetDistanceTest.cpp \
 	algorithm/MinimumDiameterTest.cpp \
 	algorithm/PointLocatorTest.cpp \
 	algorithm/RobustLineIntersectionTest.cpp \
@@ -128,6 +129,8 @@
 	capi/GEOSContainsTest.cpp \
 	capi/GEOSConvexHullTest.cpp \
 	capi/GEOSDistanceTest.cpp \
+	capi/GEOSHausdorffDistanceTest.cpp \
+	capi/GEOSFrechetDistanceTest.cpp \
 	capi/GEOSEqualsTest.cpp \
 	capi/GEOSInterruptTest.cpp \
 	capi/GEOSIntersectsTest.cpp \

Added: trunk/tests/unit/algorithm/distance/DiscreteFrechetDistanceTest.cpp
===================================================================
--- trunk/tests/unit/algorithm/distance/DiscreteFrechetDistanceTest.cpp	                        (rev 0)
+++ trunk/tests/unit/algorithm/distance/DiscreteFrechetDistanceTest.cpp	2016-12-05 13:09:16 UTC (rev 4314)
@@ -0,0 +1,130 @@
+//
+// Test Suite for geos::algorithm::distance::DiscreteFrechetDistance
+//
+
+#include <tut.hpp>
+// geos
+#include <geos/platform.h>
+#include <geos/io/WKTReader.h>
+#include <geos/algorithm/distance/DiscreteFrechetDistance.h>
+#include <geos/geom/PrecisionModel.h>
+#include <geos/geom/GeometryFactory.h>
+#include <geos/geom/Geometry.h> // required for use in auto_ptr
+#include <geos/geom/Coordinate.h>
+// std
+#include <cmath>
+#include <sstream>
+#include <string>
+#include <memory>
+
+namespace geos {
+	namespace geom {
+		class Geometry;
+	}
+}
+
+using namespace geos::geom;
+using namespace geos::algorithm::distance; // for Location
+
+namespace tut
+{
+	//
+	// Test Group
+	//
+
+	// Test data, not used
+	struct test_DiscreteFrechetDistance_data {
+
+	typedef std::auto_ptr<Geometry> GeomPtr;
+
+	test_DiscreteFrechetDistance_data()
+		:
+		pm(),
+		gf(GeometryFactory::create(&pm)),
+		reader(gf.get())
+	{}
+
+	static const double TOLERANCE;
+
+	void runTest(const std::string& wkt1, const std::string& wkt2,
+		     double expectedDistance)
+	{
+		GeomPtr g1 ( reader.read(wkt1) );
+		GeomPtr g2 ( reader.read(wkt2) );
+
+		double distance = DiscreteFrechetDistance::distance(*g1, *g2);
+		double diff = std::fabs(distance-expectedDistance);
+		//std::cerr << "expectedDistance:" << expectedDistance << " actual distance:" << distance << std::endl;
+		ensure( diff <= TOLERANCE );
+	}
+
+	void runTest(const std::string& wkt1, const std::string& wkt2,
+		     double densifyFactor, double expectedDistance)
+	{
+		GeomPtr g1 ( reader.read(wkt1) );
+		GeomPtr g2 ( reader.read(wkt2) );
+
+		double distance = DiscreteFrechetDistance::distance(*g1,
+			*g2, densifyFactor);
+		double diff = std::fabs(distance-expectedDistance);
+		//std::cerr << "expectedDistance:" << expectedDistance << " actual distance:" << distance << std::endl;
+		ensure( diff <= TOLERANCE );
+	}
+
+	PrecisionModel pm;
+	GeometryFactory::unique_ptr gf;
+	geos::io::WKTReader reader;
+
+	};
+	const double test_DiscreteFrechetDistance_data::TOLERANCE = 0.00001;
+
+	typedef test_group<test_DiscreteFrechetDistance_data> group;
+	typedef group::object object;
+
+	group test_DiscreteFrechetDistance_group("geos::algorithm::distace::DiscreteFrechetDistance");
+
+
+
+	//
+	// Test Cases
+	//
+
+	// 1 - testLineSegments
+	template<>
+	template<>
+	void object::test<1>()
+	{
+runTest("LINESTRING (0 0, 2 1)", "LINESTRING (0 0, 2 0)", 1.0);
+	}
+
+	// 2 - testLineSegments2
+	template<>
+	template<>
+	void object::test<2>()
+	{
+runTest("LINESTRING (0 0, 2 0)", "LINESTRING (0 1, 1 2, 2 1)", 2.23606797749979);
+	}
+
+	// 3 - testLinePoints
+	template<>
+	template<>
+	void object::test<3>()
+	{
+runTest("LINESTRING (0 0, 2 0)", "MULTIPOINT (0 1, 1 0, 2 1)", 1.0);
+	}
+
+	// 4 - testLinesShowingDiscretenessEffect
+	//
+	// Shows effects of limiting FD to vertices
+	// Answer is not true Frechet distance.
+	//
+	template<>
+	template<>
+	void object::test<4>()
+	{
+runTest("LINESTRING (0 0, 100 0)", "LINESTRING (0 0, 50 50, 100 0)", 70.7106781186548);
+// densifying provides accurate HD
+runTest("LINESTRING (0 0, 100 0)", "LINESTRING (0 0, 50 50, 100 0)", 0.5, 50.0);
+	}
+
+} // namespace tut

Added: trunk/tests/unit/capi/GEOSFrechetDistanceTest.cpp
===================================================================
--- trunk/tests/unit/capi/GEOSFrechetDistanceTest.cpp	                        (rev 0)
+++ trunk/tests/unit/capi/GEOSFrechetDistanceTest.cpp	2016-12-05 13:09:16 UTC (rev 4314)
@@ -0,0 +1,99 @@
+//
+// Test Suite for C-API GEOSFrechetDistance
+
+#include <tut.hpp>
+// geos
+#include <geos_c.h>
+// std
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+#include <math.h>
+
+namespace tut
+{
+    //
+    // Test Group
+    //
+
+    // Common data used in test cases.
+    struct test_capigeosfrechetdistance_data
+    {
+        GEOSGeometry* geom1_;
+        GEOSGeometry* geom2_;
+        GEOSGeometry* geom3_;
+        GEOSWKTWriter* w_;
+
+        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_capigeosfrechetdistance_data()
+            : geom1_(0), geom2_(0), geom3_(0), w_(0)
+        {
+            initGEOS(notice, notice);
+            w_ = GEOSWKTWriter_create();
+            GEOSWKTWriter_setTrim(w_, 1);
+        }
+
+        ~test_capigeosfrechetdistance_data()
+        {
+            GEOSGeom_destroy(geom1_);
+            GEOSGeom_destroy(geom2_);
+            GEOSGeom_destroy(geom3_);
+            GEOSWKTWriter_destroy(w_);
+            geom1_ = 0;
+            geom2_ = 0;
+            geom3_ = 0;
+            finishGEOS();
+        }
+
+    };
+
+    typedef test_group<test_capigeosfrechetdistance_data> group;
+    typedef group::object object;
+
+    group test_capigeosfrechetdistance_group("capi::GEOSFrechetDistance");
+
+    //
+    // Test Cases
+    //
+
+    template<>
+    template<>
+    void object::test<1>()
+    {
+        geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 100 0)");
+        geom2_ = GEOSGeomFromWKT("LINESTRING (0 0, 50 50, 100 0)");
+
+        double dist;
+        int ret = GEOSFrechetDistance(geom1_, geom2_, &dist);
+
+        ensure_equals(ret, 1);
+        ensure_distance(dist, 70.7106781186548, 1e-12);
+    }
+
+    template<>
+    template<>
+    void object::test<2>()
+    {
+        geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 100 0)");
+        geom2_ = GEOSGeomFromWKT("LINESTRING (0 0, 50 50, 100 0)");
+
+        double dist;
+        int ret = GEOSFrechetDistanceDensify(geom1_, geom2_, 0.5, &dist);
+
+        ensure_equals(ret, 1);
+        ensure_distance(dist, 50., 1e-12);
+    }
+
+} // namespace tut

Added: trunk/tests/unit/capi/GEOSHausdorffDistanceTest.cpp
===================================================================
--- trunk/tests/unit/capi/GEOSHausdorffDistanceTest.cpp	                        (rev 0)
+++ trunk/tests/unit/capi/GEOSHausdorffDistanceTest.cpp	2016-12-05 13:09:16 UTC (rev 4314)
@@ -0,0 +1,99 @@
+//
+// Test Suite for C-API GEOSHausdorffDistance
+
+#include <tut.hpp>
+// geos
+#include <geos_c.h>
+// std
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+#include <math.h>
+
+namespace tut
+{
+    //
+    // Test Group
+    //
+
+    // Common data used in test cases.
+    struct test_capigeoshausdorffdistance_data
+    {
+        GEOSGeometry* geom1_;
+        GEOSGeometry* geom2_;
+        GEOSGeometry* geom3_;
+        GEOSWKTWriter* w_;
+
+        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_capigeoshausdorffdistance_data()
+            : geom1_(0), geom2_(0), geom3_(0), w_(0)
+        {
+            initGEOS(notice, notice);
+            w_ = GEOSWKTWriter_create();
+            GEOSWKTWriter_setTrim(w_, 1);
+        }
+
+        ~test_capigeoshausdorffdistance_data()
+        {
+            GEOSGeom_destroy(geom1_);
+            GEOSGeom_destroy(geom2_);
+            GEOSGeom_destroy(geom3_);
+            GEOSWKTWriter_destroy(w_);
+            geom1_ = 0;
+            geom2_ = 0;
+            geom3_ = 0;
+            finishGEOS();
+        }
+
+    };
+
+    typedef test_group<test_capigeoshausdorffdistance_data> group;
+    typedef group::object object;
+
+    group test_capigeoshausdorffdistance_group("capi::GEOSHausdorffDistance");
+
+    //
+    // Test Cases
+    //
+
+    template<>
+    template<>
+    void object::test<1>()
+    {
+        geom1_ = GEOSGeomFromWKT("LINESTRING (130 0, 0 0, 0 150)");
+        geom2_ = GEOSGeomFromWKT("LINESTRING (10 10, 10 150, 130 10)");
+
+        double dist;
+        int ret = GEOSHausdorffDistance(geom1_, geom2_, &dist);
+
+        ensure_equals(ret, 1);
+        ensure_distance(dist, 14.142135623730951, 1e-12);
+    }
+
+    template<>
+    template<>
+    void object::test<2>()
+    {
+        geom1_ = GEOSGeomFromWKT("LINESTRING (130 0, 0 0, 0 150)");
+        geom2_ = GEOSGeomFromWKT("LINESTRING (10 10, 10 150, 130 10)");
+
+        double dist;
+        int ret = GEOSHausdorffDistanceDensify(geom1_, geom2_, 0.5, &dist);
+
+        ensure_equals(ret, 1);
+        ensure_distance(dist, 70., 1e-12);
+    }
+
+} // namespace tut



More information about the geos-commits mailing list