Ticket #209: hausdorff.patch
| File hausdorff.patch, 9.7 KB (added by vincentp, 3 years ago) |
|---|
-
postgis/lwgeom_geos.c
62 62 */ 63 63 Datum linemerge(PG_FUNCTION_ARGS); 64 64 Datum coveredby(PG_FUNCTION_ARGS); 65 Datum hausdorffdistance(PG_FUNCTION_ARGS); 66 Datum hausdorffdistancedensify(PG_FUNCTION_ARGS); 65 67 66 68 Datum pgis_union_geometry_array_old(PG_FUNCTION_ARGS); 67 69 Datum pgis_union_geometry_array(PG_FUNCTION_ARGS); … … 91 93 } 92 94 93 95 /** 96 * @brief Compute the Hausdorff distance thanks to the corresponding GEOS function 97 * @example hausdorffdistance {@link #hausdorffdistance} - SELECT st_hausdorffdistance( 98 * 'POLYGON((0 0, 0 2, 1 2, 2 2, 2 0, 0 0))'::geometry, 99 * 'POLYGON((0.5 0.5, 0.5 2.5, 1.5 2.5, 2.5 2.5, 2.5 0.5, 0.5 0.5))'::geometry); 100 */ 101 102 PG_FUNCTION_INFO_V1(hausdorffdistance); 103 Datum hausdorffdistance(PG_FUNCTION_ARGS) 104 { 105 PG_LWGEOM *geom1; 106 PG_LWGEOM *geom2; 107 GEOSGeometry *g1; 108 GEOSGeometry *g2; 109 double result; 110 int retcode; 111 112 POSTGIS_DEBUG(2, "hausdorff_distance called"); 113 114 geom1 = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 115 geom2 = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 116 117 initGEOS(lwnotice, lwnotice); 118 119 g1 = (GEOSGeometry *)POSTGIS2GEOS(geom1); 120 g2 = (GEOSGeometry *)POSTGIS2GEOS(geom2); 121 retcode = GEOSHausdorffDistance(g1, g2, &result); 122 GEOSGeom_destroy(g1); 123 GEOSGeom_destroy(g2); 124 125 if (retcode == 0) 126 { 127 elog(ERROR,"GEOS HausdorffDistance() threw an error!"); 128 PG_RETURN_NULL(); /*never get here */ 129 } 130 131 PG_FREE_IF_COPY(geom1, 0); 132 PG_FREE_IF_COPY(geom2, 0); 133 134 PG_RETURN_FLOAT8(result); 135 } 136 137 /** 138 * @brief Compute the Hausdorff distance with densification thanks to the corresponding GEOS function 139 * @example hausdorffdistancedensify {@link #hausdorffdistancedensify} - SELECT st_hausdorffdistancedensify( 140 * 'POLYGON((0 0, 0 2, 1 2, 2 2, 2 0, 0 0))'::geometry, 141 * 'POLYGON((0.5 0.5, 0.5 2.5, 1.5 2.5, 2.5 2.5, 2.5 0.5, 0.5 0.5))'::geometry, 0.5); 142 */ 143 144 PG_FUNCTION_INFO_V1(hausdorffdistancedensify); 145 Datum hausdorffdistancedensify(PG_FUNCTION_ARGS) 146 { 147 PG_LWGEOM *geom1; 148 PG_LWGEOM *geom2; 149 GEOSGeometry *g1; 150 GEOSGeometry *g2; 151 double densifyFrac; 152 double result; 153 int retcode; 154 155 156 geom1 = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 157 geom2 = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); 158 densifyFrac = *(double *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2)); 159 160 initGEOS(lwnotice, lwnotice); 161 162 g1 = (GEOSGeometry *)POSTGIS2GEOS(geom1); 163 g2 = (GEOSGeometry *)POSTGIS2GEOS(geom2); 164 retcode = GEOSHausdorffDistanceDensify(g1, g2, densifyFrac, &result); 165 GEOSGeom_destroy(g1); 166 GEOSGeom_destroy(g2); 167 168 if (retcode == 0) 169 { 170 elog(ERROR,"GEOS HausdorffDistanceDensify() threw an error!"); 171 PG_RETURN_NULL(); /*never get here */ 172 } 173 174 PG_FREE_IF_COPY(geom1, 0); 175 PG_FREE_IF_COPY(geom2, 0); 176 177 PG_RETURN_FLOAT8(result); 178 } 179 180 /** 94 181 * @brief This is the final function for GeomUnion 95 182 * aggregate. Will have as input an array of Geometries. 96 183 * Will iteratively call GEOSUnion on the GEOS-converted -
postgis/uninstall_postgis.sql.in.c
397 397 DROP FUNCTION buffer(geometry,float8); 398 398 DROP FUNCTION ST_Intersection(geometry,geometry); 399 399 DROP FUNCTION intersection(geometry,geometry); 400 #if POSTGIS_GEOS_VERSION >= 32 401 DROP FUNCTION ST_HausdorffDistance(geometry, geometry) 402 #endif 403 #if POSTGIS_GEOS_VERSION >= 32 404 DROP FUNCTION ST_HausdorffDistance(geometry, geometry, float8) 405 #endif 400 406 401 407 402 408 --------------------------------------------------------------- -
postgis/postgis.sql.in.c
3918 3918 LANGUAGE 'C' IMMUTABLE STRICT; 3919 3919 #endif 3920 3920 3921 #if POSTGIS_GEOS_VERSION >= 32 3922 -- Requires GEOS >= 3.2.0 3923 -- Availability: 1.5.0 3924 CREATE OR REPLACE FUNCTION ST_HausdorffDistance(geometry, geometry) 3925 RETURNS FLOAT8 3926 AS 'MODULE_PATHNAME', 'hausdorffdistance' 3927 LANGUAGE 'C' IMMUTABLE STRICT; 3928 #endif 3929 3930 #if POSTGIS_GEOS_VERSION >= 32 3931 -- Requires GEOS >= 3.2.0 3932 -- Availability: 1.5.0 3933 CREATE OR REPLACE FUNCTION ST_HausdorffDistance(geometry, geometry, float8) 3934 RETURNS FLOAT8 3935 AS 'MODULE_PATHNAME', 'hausdorffdistancedensify' 3936 LANGUAGE 'C' IMMUTABLE STRICT; 3937 #endif 3938 3921 3939 -- Deprecation in 1.2.3 3922 3940 CREATE OR REPLACE FUNCTION difference(geometry,geometry) 3923 3941 RETURNS geometry -
doc/reference.xml
9818 9818 </refsection> 9819 9819 </refentry> 9820 9820 9821 <refentry id="ST_HausdorffDistance"> 9822 <refnamediv> 9823 <refname>ST_HausdorffDistance</refname> 9824 9825 <refpurpose>Returns the Hausdorff distance between two geometries.</refpurpose> 9826 </refnamediv> 9827 9828 <refsynopsisdiv> 9829 <funcsynopsis> 9830 <funcprototype> 9831 <funcdef>float <function>ST_HausdorffDistance</function></funcdef> 9832 9833 <paramdef><type>geometry </type> 9834 <parameter>g1</parameter></paramdef> 9835 9836 <paramdef><type>geometry </type> 9837 <parameter>g2</parameter></paramdef> 9838 </funcprototype> 9839 <funcprototype> 9840 <funcdef>float <function>ST_HausdorffDistance</function></funcdef> 9841 9842 <paramdef><type>geometry </type> 9843 <parameter>g1</parameter></paramdef> 9844 9845 <paramdef><type>geometry </type> 9846 <parameter>g2</parameter></paramdef> 9847 9848 <paramdef><type>float</type> 9849 <parameter>densifyFrac</parameter></paramdef> 9850 </funcprototype> 9851 </funcsynopsis> 9852 </refsynopsisdiv> 9853 9854 <refsection> 9855 <title>Description</title> 9856 9857 <para>Implements algorithm for computing a distance metric which can be thought of as the "Discrete Hausdorff Distance". 9858 This is the Hausdorff distance restricted to discrete points for one of the geometries.</para> 9859 <para> 9860 When densifyFrac is specified, this function performs a segment densification before computing the discrete hausdorff distance. The densifyFrac parameter sets the fraction by which to densify each segment. Each segment will be split into a number of equal-length subsegments, whose fraction of the total length is closest to the given fraction. 9861 </para> 9862 9863 <note> 9864 <para> 9865 The current implementation supports only vertices as the discrete locations. This could be extended to allow an arbitrary density of points to be used. 9866 </para> 9867 </note> 9868 <note> 9869 <para> 9870 This algorithm is NOT equivalent to the standard Hausdorff distance. However, it computes an approximation that is correct for a large subset of useful cases. 9871 One important part of this subset is Linestrings that are roughly parallel to each other, and roughly equal in length. This is a useful metric for line matching. 9872 </para> 9873 </note> 9874 9875 </refsection> 9876 9877 <refsection> 9878 <title>Examples</title> 9879 9880 <programlisting>postgis=# SELECT st_HausdorffDistance( 9881 'LINESTRING (0 0, 2 0)'::geometry, 9882 'MULTIPOINT (0 1, 1 0, 2 1)'::geometry); 9883 st_hausdorffdistance 9884 ---------------------- 9885 1 9886 (1 row) 9887 </programlisting> 9888 <programlisting>postgis=# SELECT st_hausdorffdistance('LINESTRING (130 0, 0 0, 0 150)'::geometry, 'LINESTRING (10 10, 10 150, 130 10)'::geometry, 0.5); 9889 st_hausdorffdistance 9890 ---------------------- 9891 70 9892 (1 row) 9893 </programlisting> 9894 9895 </refsection> 9896 </refentry> 9897 9821 9898 <refentry id="ST_Distance_Sphere"> 9822 9899 <refnamediv> 9823 9900 <refname>ST_Distance_Sphere</refname> -
regress/Makefile.in
52 52 kml \ 53 53 regress_ogc \ 54 54 regress_bdpoly \ 55 regress_proj 55 regress_proj \ 56 hausdorff 56 57 57 58 # Covers/CoveredBy only if GEOS >= 3.0 58 59 ifeq ($(shell expr $(POSTGIS_GEOS_VERSION) ">=" 30),1) -
regress/hausdorff_expected
1 hausdorff_poly_poly|0.707106781186548 2 hausdorff_ls_ls|1 3 hausdorff_ls_ls_2|2 4 hausdorff_ls_mp|1 5 hausdorff_ls_ls_3|14.142135623731 6 hausdorffdensify_ls_ls|70 -
regress/hausdorff.sql
1 -- tests for Hausdorff distances 2 3 -- polygon and polygon 4 SELECT 'hausdorff_poly_poly', st_hausdorffdistance( 5 'POLYGON((0 0, 0 2, 1 2, 2 2, 2 0, 0 0))'::geometry, 6 'POLYGON((0.5 0.5, 0.5 2.5, 1.5 2.5, 2.5 2.5, 2.5 0.5, 0.5 0.5))'::geometry); 7 -- 0.707106781186548 8 9 -- linestring and linestring 10 SELECT 'hausdorff_ls_ls', st_hausdorffdistance( 11 'LINESTRING (0 0, 2 1)'::geometry 12 , 'LINESTRING (0 0, 2 0)'::geometry); 13 -- 1.0 14 15 -- other linestrings 16 SELECT 'hausdorff_ls_ls_2', st_hausdorffdistance( 17 'LINESTRING (0 0, 2 0)'::geometry, 18 'LINESTRING (0 1, 1 2, 2 1)'::geometry); 19 -- 2.0 20 21 -- linestring and multipoint 22 SELECT 'hausdorff_ls_mp', st_hausdorffdistance( 23 'LINESTRING (0 0, 2 0)'::geometry, 24 'MULTIPOINT (0 1, 1 0, 2 1)'::geometry); 25 -- 1.0 26 27 -- another linestring and linestring 28 SELECT 'hausdorff_ls_ls_3', st_hausdorffdistance( 29 'LINESTRING (130 0, 0 0, 0 150)'::geometry, 30 'LINESTRING (10 10, 10 150, 130 10)'::geometry); 31 -- 14.142135623730951 32 33 -- hausdorf with densification 34 SELECT 'hausdorffdensify_ls_ls', st_hausdorffdistance( 35 'LINESTRING (130 0, 0 0, 0 150)'::geometry 36 , 'LINESTRING (10 10, 10 150, 130 10)'::geometry, 0.5); 37 -- 70.0
