Changeset 4208

Show
Ignore:
Timestamp:
06/24/09 15:08:33 (3 years ago)
Author:
pramsey
Message:

Add support for hausdorff distance calculations. Requires GEOS 3.2+. (#209) From Vincent Picavet.
If you are working off of GEOS trunk, svn up, compile and install!

Location:
trunk
Files:
2 added
5 modified

Legend:

Unmodified
Added
Removed
  • trunk/doc/reference.xml

    r4205 r4208  
    98199819        </refentry> 
    98209820 
     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". 
     9858This is the Hausdorff distance restricted to discrete points for one of the geometries.</para> 
     9859                <para> 
     9860When 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> 
     9865The 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 
    98219898        <refentry id="ST_Distance_Sphere"> 
    98229899          <refnamediv> 
  • trunk/postgis/lwgeom_geos.c

    r4198 r4208  
    6363Datum linemerge(PG_FUNCTION_ARGS); 
    6464Datum coveredby(PG_FUNCTION_ARGS); 
     65Datum hausdorffdistance(PG_FUNCTION_ARGS); 
     66Datum hausdorffdistancedensify(PG_FUNCTION_ARGS); 
    6567 
    6668Datum pgis_union_geometry_array_old(PG_FUNCTION_ARGS); 
     
    8991        memcpy(VARDATA(result), ver, strlen(ver)); 
    9092        PG_RETURN_POINTER(result); 
     93} 
     94 
     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 
     102PG_FUNCTION_INFO_V1(hausdorffdistance); 
     103Datum 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 
     144PG_FUNCTION_INFO_V1(hausdorffdistancedensify); 
     145Datum 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); 
    91178} 
    92179 
  • trunk/postgis/postgis.sql.in.c

    r4200 r4208  
    39193919#endif 
    39203920 
     3921#if POSTGIS_GEOS_VERSION >= 32 
     3922-- Requires GEOS >= 3.2.0 
     3923-- Availability: 1.5.0  
     3924CREATE 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  
     3933CREATE OR REPLACE FUNCTION ST_HausdorffDistance(geometry, geometry, float8) 
     3934        RETURNS FLOAT8 
     3935        AS 'MODULE_PATHNAME', 'hausdorffdistancedensify' 
     3936        LANGUAGE 'C' IMMUTABLE STRICT; 
     3937#endif 
     3938 
    39213939-- Deprecation in 1.2.3 
    39223940CREATE OR REPLACE FUNCTION difference(geometry,geometry) 
  • trunk/postgis/uninstall_postgis.sql.in.c

    r4207 r4208  
    400400DROP FUNCTION ST_Intersection(geometry,geometry); 
    401401DROP FUNCTION intersection(geometry,geometry); 
     402#if POSTGIS_GEOS_VERSION >= 32 
     403DROP FUNCTION ST_HausdorffDistance(geometry, geometry) 
     404#endif 
     405#if POSTGIS_GEOS_VERSION >= 32 
     406DROP FUNCTION ST_HausdorffDistance(geometry, geometry, float8) 
     407#endif 
    402408 
    403409 
  • trunk/regress/Makefile.in

    r4206 r4208  
    5353        regress_ogc \ 
    5454        regress_bdpoly \ 
    55         regress_proj 
     55        regress_proj \ 
     56        hausdorff 
    5657 
    5758# Covers/CoveredBy only if GEOS >= 3.0