From 94e32a2c16fa20262ce5ee1bfb629bd16fe4c001 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Sun, 4 Oct 2009 00:51:00 +0000 Subject: [PATCH] Some fixes to the ST_DWithin code. git-svn-id: http://svn.osgeo.org/postgis/trunk@4585 b70326c6-7e19-0410-871a-916f4a2858ee --- install-sh | 560 +++++++++++++++++++++++----------- liblwgeom/cunit/cu_geodetic.c | 32 +- liblwgeom/lwgeodetic.c | 59 +++- postgis/geography.sql.in.c | 6 +- postgis/geography_distance.c | 2 + postgis/geography_estimate.c | 25 ++ postgis/geography_gist.c | 2 +- 7 files changed, 487 insertions(+), 199 deletions(-) diff --git a/install-sh b/install-sh index e4160c991..a5897de6e 100755 --- a/install-sh +++ b/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2004-04-01.17 +scriptversion=2006-12-25.00 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -39,120 +39,157 @@ scriptversion=2004-04-01.17 # when there is no Makefile. # # This script is compatible with the BSD install script, but was written -# from scratch. It can only install one file at a time, a restriction -# shared with many OS's install programs. +# from scratch. + +nl=' +' +IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. -doit="${DOITPROG-}" - -# put in absolute paths if you don't have them in your path; or use env. vars. - -mvprog="${MVPROG-mv}" -cpprog="${CPPROG-cp}" -chmodprog="${CHMODPROG-chmod}" -chownprog="${CHOWNPROG-chown}" -chgrpprog="${CHGRPPROG-chgrp}" -stripprog="${STRIPPROG-strip}" -rmprog="${RMPROG-rm}" -mkdirprog="${MKDIRPROG-mkdir}" - -transformbasename= -transform_arg= -instcmd="$mvprog" -chmodcmd="$chmodprog 0755" -chowncmd= +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + chgrpcmd= -stripcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog rmcmd="$rmprog -f" -mvcmd="$mvprog" +stripcmd= + src= dst= dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= -usage="Usage: $0 [OPTION]... SRCFILE DSTFILE +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 -d DIRECTORIES... + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... -In the first form, install SRCFILE to DSTFILE, removing SRCFILE by default. -In the second, create the directory path DIR. +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. Options: --b=TRANSFORMBASENAME --c copy source (using $cpprog) instead of moving (using $mvprog). --d create directories instead of installing files. --g GROUP $chgrp installed files to GROUP. --m MODE $chmod installed files to MODE. --o USER $chown installed files to USER. --s strip installed files (using $stripprog). --t=TRANSFORM ---help display this help and exit. ---version display version info and exit. + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG " -while test -n "$1"; do +while test $# -ne 0; do case $1 in - -b=*) transformbasename=`echo $1 | sed 's/-b=//'` - shift - continue;; + -c) ;; - -c) instcmd=$cpprog - shift - continue;; + -C) copy_on_change=true;; - -d) dir_arg=true - shift - continue;; + -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" - shift - shift - continue;; + shift;; - --help) echo "$usage"; exit 0;; + --help) echo "$usage"; exit $?;; - -m) chmodcmd="$chmodprog $2" - shift - shift - continue;; + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; -o) chowncmd="$chownprog $2" - shift - shift - continue;; - - -s) stripcmd=$stripprog - shift - continue;; - - -t=*) transformarg=`echo $1 | sed 's/-t=//'` - shift - continue;; - - --version) echo "$0 $scriptversion"; exit 0;; - - *) # When -d is used, all remaining arguments are directories to create. - test -n "$dir_arg" && break - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dstarg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dstarg" - shift # fnord - fi - shift # arg - dstarg=$arg - done + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; esac + shift done -if test -z "$1"; then +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 @@ -162,25 +199,48 @@ if test -z "$1"; then exit 0 fi +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + for src do # Protect names starting with `-'. case $src in - -*) src=./$src ;; + -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src - src= - - if test -d "$dst"; then - instcmd=: - chmodcmd= - else - instcmd=$mkdirprog - fi + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? else - # Waiting for this to be detected by the "$instcmd $src $dsttmp" command + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then @@ -188,135 +248,269 @@ do exit 1 fi - if test -z "$dstarg"; then + if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi - dst=$dstarg + dst=$dst_arg # Protect names starting with `-'. case $dst in - -*) dst=./$dst ;; + -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then - dst=$dst/`basename "$src"` + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? fi fi - # This sed command emulates the dirname command. - dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac - # Make sure that the destination directory exists. + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else - # Skip lots of stat calls in the usual case. - if test ! -d "$dstdir"; then - defaultIFS=' - ' - IFS="${IFS-$defaultIFS}" + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. - oIFS=$IFS - # Some sh's can't handle IFS=/ for some reason. - IFS='%' - set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` - IFS=$oIFS + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac - pathcomp= + eval "$initialize_posix_glob" - while test $# -ne 0 ; do - pathcomp=$pathcomp$1 + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir shift - if test ! -d "$pathcomp"; then - $mkdirprog "$pathcomp" || lasterr=$? - # mkdir can fail with a `File exist' error in case several - # install-sh are creating the directory concurrently. This - # is OK. - test ! -d "$pathcomp" && { (exit ${lasterr-1}); exit; } + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true fi - pathcomp=$pathcomp/ - done + fi fi if test -n "$dir_arg"; then - $doit $instcmd "$dst" \ - && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ - && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ - && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ - && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } - + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else - # If we're going to rename the final executable, determine the name now. - if test -z "$transformarg"; then - dstfile=`basename "$dst"` - else - dstfile=`basename "$dst" $transformbasename \ - | sed $transformarg`$transformbasename - fi - - # don't allow the sed command to completely eliminate the filename. - test -z "$dstfile" && dstfile=`basename "$dst"` # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. - trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 - trap '(exit $?); exit' 1 2 13 15 + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - # Move or copy the file name to the temp name - $doit $instcmd "$src" "$dsttmp" && + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $instcmd $src $dsttmp" command. + # errors from the above "$doit $cpprog $src $dsttmp" command. # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ - && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ - && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ - && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && - - # Now rename the file to the real destination. - { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ - || { - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - if test -f "$dstdir/$dstfile"; then - $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ - || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ - || { - echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 - (exit 1); exit - } - else - : - fi - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" - } - } - fi || { (exit 1); exit; } + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi done -# The final little trick to "correctly" pass the exit status to the exit trap. -{ - (exit 0); exit -} - # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" diff --git a/liblwgeom/cunit/cu_geodetic.c b/liblwgeom/cunit/cu_geodetic.c index f33151c7c..589ffe289 100644 --- a/liblwgeom/cunit/cu_geodetic.c +++ b/liblwgeom/cunit/cu_geodetic.c @@ -32,9 +32,9 @@ CU_pSuite register_geodetic_suite(void) (NULL == CU_add_test(pSuite, "test_gbox_from_spherical_coordinates()", test_gbox_from_spherical_coordinates)) || (NULL == CU_add_test(pSuite, "test_gserialized_get_gbox_geocentric()", test_gserialized_get_gbox_geocentric)) || (NULL == CU_add_test(pSuite, "test_clairaut()", test_clairaut)) || - (NULL == CU_add_test(pSuite, "test_edge_intersection()", test_edge_intersection)) || + (NULL == CU_add_test(pSuite, "test_edge_intersection()", test_edge_intersection)) || (NULL == CU_add_test(pSuite, "test_edge_distance_to_point()", test_edge_distance_to_point)) || - (NULL == CU_add_test(pSuite, "test_edge_distance_to_edge()", test_edge_distance_to_edge)) || + (NULL == CU_add_test(pSuite, "test_edge_distance_to_edge()", test_edge_distance_to_edge)) || (NULL == CU_add_test(pSuite, "test_lwgeom_distance_sphere()", test_lwgeom_distance_sphere)) @@ -265,8 +265,22 @@ void test_edge_intersection(void) GEOGRAPHIC_POINT g; int rv; - edge_set(-1.0, 0.0, 1.0, 0.0, &e1); - edge_set(0.0, -1.0, 0.0, 1.0, &e2); + /* Medford case, very short segment vs very long one */ + e1.start.lat = 0.74123572595649878103; + e1.start.lon = -2.1496353191142714145; + e1.end.lat = 0.74123631950116664058; + e1.end.lon = -2.1496353248304860273; + e2.start.lat = 0.73856343764436815924; + e2.start.lon = -2.1461493501950630325; + e2.end.lat = 0.70971354024834598651; + e2.end.lon = 2.1082194552519770703; + rv = edge_intersection(e1, e2, &g); + CU_ASSERT_EQUAL(rv, LW_FALSE); + + /* Again, this time with a less exact input edge. */ + edge_set(-123.165031277506, 42.4696787216231, -123.165031605021, 42.4697127292275, &e1); + rv = edge_intersection(e1, e2, &g); + CU_ASSERT_EQUAL(rv, LW_FALSE); /* Intersection at (0 0) */ edge_set(-1.0, 0.0, 1.0, 0.0, &e1); @@ -482,6 +496,16 @@ void test_lwgeom_distance_sphere(void) lwgeom_free(lwg1); lwgeom_free(lwg2); + /* Medford test case #1 */ + lwg1 = lwgeom_from_ewkt("0105000020E610000001000000010200000002000000EF7B8779C7BD5EC0FD20D94B852845400E539C62B9BD5EC0F0A5BE767C284540", PARSER_CHECK_NONE); + lwg2 = lwgeom_from_ewkt("0106000020E61000000100000001030000000100000007000000280EC3FB8CCA5EC0A5CDC747233C45402787C8F58CCA5EC0659EA2761E3C45400CED58DF8FCA5EC0C37FAE6E1E3C4540AE97B8E08FCA5EC00346F58B1F3C4540250359FD8ECA5EC05460628E1F3C45403738F4018FCA5EC05DC84042233C4540280EC3FB8CCA5EC0A5CDC747233C4540", PARSER_CHECK_NONE); + lwgeom_calculate_gbox_geodetic(lwg1, &gbox1); + lwgeom_calculate_gbox_geodetic(lwg2, &gbox2); + d = lwgeom_distance_sphere(lwg1, lwg2, &gbox1, &gbox2, 0.0); + CU_ASSERT_DOUBLE_EQUAL(d * 6371009.0, 23630.8003, 0.1); + lwgeom_free(lwg1); + lwgeom_free(lwg2); + } diff --git a/liblwgeom/lwgeodetic.c b/liblwgeom/lwgeodetic.c index 6e84c84c8..89869ede7 100644 --- a/liblwgeom/lwgeodetic.c +++ b/liblwgeom/lwgeodetic.c @@ -397,12 +397,12 @@ int edge_point_in_cone(GEOGRAPHIC_EDGE e, GEOGRAPHIC_POINT p) normalize(&vcp); /* The projection of start onto the center defines the minimum similarity */ vs_dot_vcp = dot_product(vs, vcp); - LWDEBUGF(4,"vs_dot_vcp %.9g",vs_dot_vcp); + LWDEBUGF(4,"vs_dot_vcp %.19g",vs_dot_vcp); /* The projection of candidate p onto the center */ vp_dot_vcp = dot_product(vp, vcp); - LWDEBUGF(4,"vp_dot_vcp %.9g",vp_dot_vcp); + LWDEBUGF(4,"vp_dot_vcp %.19g",vp_dot_vcp); /* If p is more similar than start then p is inside the cone */ - if ( FP_GTEQ(vp_dot_vcp, vs_dot_vcp) ) + if ( vp_dot_vcp >= vs_dot_vcp ) { LWDEBUG(4, "point is in cone"); return LW_TRUE; @@ -575,12 +575,21 @@ int clairaut_geographic(GEOGRAPHIC_POINT start, GEOGRAPHIC_POINT end, GEOGRAPHIC int edge_intersection(GEOGRAPHIC_EDGE e1, GEOGRAPHIC_EDGE e2, GEOGRAPHIC_POINT *g) { POINT3D ea, eb, v; + LWDEBUGF(4, "e1 start(%.20g %.20g) end(%.20g %.20g)", e1.start.lat, e1.start.lon, e1.end.lat, e1.end.lon); + LWDEBUGF(4, "e2 start(%.20g %.20g) end(%.20g %.20g)", e2.start.lat, e2.start.lon, e2.end.lat, e2.end.lon); + + LWDEBUGF(4, "e1 start(%.20g %.20g) end(%.20g %.20g)", rad2deg(e1.start.lon), rad2deg(e1.start.lat), rad2deg(e1.end.lon), rad2deg(e1.end.lat)); + LWDEBUGF(4, "e2 start(%.20g %.20g) end(%.20g %.20g)", rad2deg(e2.start.lon), rad2deg(e2.start.lat), rad2deg(e2.end.lon), rad2deg(e2.end.lat)); + robust_cross_product(e1.start, e1.end, &ea); normalize(&ea); robust_cross_product(e2.start, e2.end, &eb); normalize(&eb); + LWDEBUGF(4, "e1 cross product == POINT(%.8g %.8g %.8g)", ea.x, ea.y, ea.z); + LWDEBUGF(4, "e2 cross product == POINT(%.8g %.8g %.8g)", eb.x, eb.y, eb.z); if( FP_EQUALS(fabs(dot_product(ea, eb)), 1.0) ) { + LWDEBUGF(4, "parallel edges found! dot_product = %.12g", dot_product(ea, eb)); /* Parallel (maybe equal) edges! */ /* Hack alert, only returning ONE end of the edge right now, most do better later. */ if ( edge_contains_point(e1, e2.start) ) @@ -604,13 +613,12 @@ int edge_intersection(GEOGRAPHIC_EDGE e1, GEOGRAPHIC_EDGE e2, GEOGRAPHIC_POINT * return LW_TRUE; } } - LWDEBUGF(4, "e1 cross product == POINT(%.8g %.8g %.8g)", ea.x, ea.y, ea.z); - LWDEBUGF(4, "e2 cross product == POINT(%.8g %.8g %.8g)", eb.x, eb.y, eb.z); unit_normal(ea, eb, &v); LWDEBUGF(4, "v == POINT(%.8g %.8g %.8g)", v.x, v.y, v.z); g->lat = atan2(v.z, sqrt(v.x * v.x + v.y * v.y)); g->lon = atan2(v.y, v.x); LWDEBUGF(4, "g == GPOINT(%.6g %.6g)", g->lat, g->lon); + LWDEBUGF(4, "g == POINT(%.12g %.12g)", rad2deg(g->lon), rad2deg(g->lat)); if ( edge_contains_point(e1, *g) && edge_contains_point(e2, *g) ) { return LW_TRUE; @@ -1146,8 +1154,10 @@ static int ptarray_point_in_ring(POINTARRAY *pa, POINT2D pt_outside, POINT2D pt_ /* Does stab line cross, and if so, not on the first point. We except the first point to avoid double counting crossings at vertices. */ + LWDEBUG(4,"testing edge crossing"); if( edge_intersection(edge, crossing_edge, &g) && ! geographic_point_equals(g, edge.start) ) { + LWDEBUG(4,"edge crossing found!"); count++; } } @@ -1242,17 +1252,26 @@ static double ptarray_distance_sphere(POINTARRAY *pa1, POINTARRAY *pa2, double t getPoint2d_p(pa2, j, &p); geographic_point_init(p.x, p.y, &(e2.end)); + LWDEBUGF(4, "e1.start == GPOINT(%.6g %.6g) ", e1.start.lat, e1.start.lon); + LWDEBUGF(4, "e1.end == GPOINT(%.6g %.6g) ", e1.end.lat, e1.end.lon); + LWDEBUGF(4, "e2.start == GPOINT(%.6g %.6g) ", e2.start.lat, e2.start.lon); + LWDEBUGF(4, "e2.end == GPOINT(%.6g %.6g) ", e2.end.lat, e2.end.lon); + if ( edge_intersection(e1, e2, &g) ) { + LWDEBUG(4,"edge intersection! returning 0.0"); return 0.0; } d = edge_distance_to_edge(e1, e2, 0, 0); + LWDEBUGF(4,"got edge_distance_to_edge %.8g", d); if( d < distance ) distance = d; if( d < tolerance ) return distance; } } + LWDEBUGF(4,"finished all loops, returning %.8g", distance); + return distance; } @@ -1269,6 +1288,8 @@ double lwgeom_distance_sphere(LWGEOM *lwgeom1, LWGEOM *lwgeom2, GBOX *gbox1, GBO assert(lwgeom1); assert(lwgeom2); + LWDEBUGF(4, "entered function, tolerance %.8g", tolerance); + /* What's the distance to an empty geometry? We don't know. */ if( lwgeom_is_empty(lwgeom1) || lwgeom_is_empty(lwgeom2) ) { @@ -1369,19 +1390,25 @@ double lwgeom_distance_sphere(LWGEOM *lwgeom1, LWGEOM *lwgeom2, GBOX *gbox1, GBO } getPoint2d_p(lwline->points, 0, &p); + LWDEBUG(4, "checking if a point of line is in polygon"); + /* Point in polygon implies zero distance */ if( lwpoly_covers_point2d(lwpoly, gbox, p) ) return 0.0; - + + LWDEBUG(4, "checking ring distances"); + /* Not contained, so what's the actual distance? */ for( i = 0; i < lwpoly->nrings; i++ ) { double ring_distance = ptarray_distance_sphere(lwpoly->rings[i], lwline->points, tolerance); + LWDEBUGF(4, "ring[%d] ring_distance = %.8g", i, ring_distance); if( ring_distance < distance ) distance = ring_distance; if( distance < tolerance ) return distance; } + LWDEBUGF(4, "all rings checked, returning distance = %.8g", distance); return distance; } @@ -1485,6 +1512,7 @@ int lwpoly_covers_point2d(const LWPOLY *poly, GBOX *gbox, POINT2D pt_to_test) /* Nulls and empties don't contain anything! */ if( ! poly || lwgeom_is_empty((LWGEOM*)poly) ) { + LWDEBUG(4,"returning false, geometry is empty or null"); return LW_FALSE; } @@ -1494,23 +1522,38 @@ int lwpoly_covers_point2d(const LWPOLY *poly, GBOX *gbox, POINT2D pt_to_test) pt_outside.x = rad2deg(g.lon); pt_outside.y = rad2deg(g.lat); + LWDEBUGF(4, "pt_outside POINT(%.8g %.8g)", pt_outside.x, pt_outside.y); + LWDEBUGF(4, "pt_to_test POINT(%.8g %.8g)", pt_to_test.x, pt_to_test.y); + LWDEBUGF(4, "polygon %s", lwgeom_to_ewkt((LWGEOM*)poly, PARSER_CHECK_NONE)); + LWDEBUGF(4, "gbox %s", gbox_to_string(gbox)); + /* Not in outer ring? We're done! */ if( ! ptarray_point_in_ring(poly->rings[0], pt_outside, pt_to_test) ) { + LWDEBUG(4,"returning false, point is outside ring"); return LW_FALSE; } + + LWDEBUGF(4, "testing %d rings", poly->nrings); /* But maybe point is in a hole... */ for( i = 1; i < poly->nrings; i++ ) { + LWDEBUGF(4, "ring test loop %d", i); /* Count up hole containment. Odd => outside boundary. */ if( ptarray_point_in_ring(poly->rings[i], pt_outside, pt_to_test) ) in_hole_count++; } + + LWDEBUGF(4, "in_hole_count == %d", in_hole_count); - if( in_hole_count % 2 ) + if( in_hole_count % 2 ) + { + LWDEBUG(4,"returning false, inner ring containment count is odd"); return LW_FALSE; - + } + + LWDEBUG(4,"returning true, inner ring containment count is even"); return LW_TRUE; } diff --git a/postgis/geography.sql.in.c b/postgis/geography.sql.in.c index 774d61549..b00f3e1ee 100644 --- a/postgis/geography.sql.in.c +++ b/postgis/geography.sql.in.c @@ -228,9 +228,9 @@ CREATE OR REPLACE FUNCTION geography_overlaps(geography, geography) -- Availability: 1.5.0 CREATE OPERATOR && ( LEFTARG = geography, RIGHTARG = geography, PROCEDURE = geography_overlaps, - COMMUTATOR = '&&' --- ,RESTRICT = geography_gist_selectivity, --- JOIN = geography_gist_join_selectivity + COMMUTATOR = '&&', + RESTRICT = geography_gist_selectivity, + JOIN = geography_gist_join_selectivity ); diff --git a/postgis/geography_distance.c b/postgis/geography_distance.c index 5a81cecfd..6e07e8faa 100644 --- a/postgis/geography_distance.c +++ b/postgis/geography_distance.c @@ -51,6 +51,8 @@ Datum geography_distance_sphere(PG_FUNCTION_ARGS) geography_datum_gidx(PG_GETARG_DATUM(0), gidx2); gbox_from_gidx(gidx1, &gbox1); gbox_from_gidx(gidx2, &gbox2); + gbox1.flags = FLAGS_SET_GEODETIC(gbox1.flags,1); + gbox2.flags = FLAGS_SET_GEODETIC(gbox2.flags,1); pfree(gidx1); pfree(gidx2); diff --git a/postgis/geography_estimate.c b/postgis/geography_estimate.c index 3ba1da714..206a54f35 100644 --- a/postgis/geography_estimate.c +++ b/postgis/geography_estimate.c @@ -16,6 +16,31 @@ #include "lwgeom_pg.h" +/* Prototypes */ +Datum geography_gist_selectivity(PG_FUNCTION_ARGS); +Datum geography_gist_join_selectivity(PG_FUNCTION_ARGS); +Datum geography_analyze(PG_FUNCTION_ARGS); + + +/** +* Place holder selectivity calculations to make the index work in +* the absence of real selectivity calculations. +*/ + +#define DEFAULT_GEOGRAPHY_SEL 0.000005 + +PG_FUNCTION_INFO_V1(geography_gist_selectivity); +Datum geography_gist_selectivity(PG_FUNCTION_ARGS) +{ + PG_RETURN_FLOAT8(DEFAULT_GEOGRAPHY_SEL); +} + +PG_FUNCTION_INFO_V1(geography_gist_join_selectivity); +Datum geography_gist_join_selectivity(PG_FUNCTION_ARGS) +{ + PG_RETURN_FLOAT8(DEFAULT_GEOGRAPHY_SEL); +} + /** * This function is called by the analyze function iff diff --git a/postgis/geography_gist.c b/postgis/geography_gist.c index c11e72dc9..16283e156 100644 --- a/postgis/geography_gist.c +++ b/postgis/geography_gist.c @@ -196,7 +196,7 @@ static float gidx_volume(GIDX *a) int i; if ( a == NULL ) { - elog(ERROR, "gidx_volume received a null argument"); +/* elog(ERROR, "gidx_volume received a null argument"); */ return 0.0; } result = GIDX_GET_MAX(a,0) - GIDX_GET_MIN(a,0); -- 2.50.1