/********************************************************************** * * GEOS - Geometry Engine Open Source * http://geos.osgeo.org * * Copyright (C) 2016 Shinichi SUGIYAMA (shin.sugi@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@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 geom::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& p_g0, const geom::Geometry& p_g1) : g0(p_g0), g1(p_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::array<geom::Coordinate, 2> 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) = delete; DiscreteFrechetDistance& operator=(const DiscreteFrechetDistance& rhs) = delete; }; } // geos::algorithm::distance } // geos::algorithm } // geos #ifdef _MSC_VER #pragma warning(pop) #endif #endif // GEOS_ALGORITHM_DISTANCE_DISCRETEFRECHETDISTANCE_H