Skip to content

Commit

Permalink
Merge #51446 #51461
Browse files Browse the repository at this point in the history
51446: builtins: implement ST_ConvexHull r=rytaft a=otan

Resolves #48909.

Release note (sql change): Implement the ST_ConvexHull function on
geometry types.

51461: builtins: implement ST_DistanceSphere and ST_DistanceSpheroid r=rytaft a=otan

Resolves #48921
Resolves #48922

Release note (sql change): Implement the ST_DistanceSphere and
ST_DistanceSpheroid operators for geometry types.

Co-authored-by: Oliver Tan <[email protected]>
  • Loading branch information
craig[bot] and otan committed Jul 15, 2020
3 parents 69a2551 + abe114e + 0a69e11 commit 3428a4a
Show file tree
Hide file tree
Showing 8 changed files with 313 additions and 13 deletions.
10 changes: 10 additions & 0 deletions docs/generated/sql/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,9 @@ given Geometry.</p>
<p>This function utilizes the GEOS module.</p>
<p>This function variant will attempt to utilize any available geospatial index.</p>
</span></td></tr>
<tr><td><a name="st_convexhull"></a><code>st_convexhull(geometry: geometry) &rarr; geometry</code></td><td><span class="funcdesc"><p>Returns a geometry that represents the Convex Hull of the given geometry.</p>
<p>This function utilizes the GEOS module.</p>
</span></td></tr>
<tr><td><a name="st_coveredby"></a><code>st_coveredby(geography_a: geography, geography_b: geography) &rarr; <a href="bool.html">bool</a></code></td><td><span class="funcdesc"><p>Returns true if no point in geography_a is outside geography_b.</p>
<p>The calculations performed are have a precision of 1cm.</p>
<p>This function utilizes the S2 library for spherical calculations.</p>
Expand Down Expand Up @@ -1007,6 +1010,13 @@ given Geometry.</p>
</span></td></tr>
<tr><td><a name="st_distance"></a><code>st_distance(geometry_a: geometry, geometry_b: geometry) &rarr; <a href="float.html">float</a></code></td><td><span class="funcdesc"><p>Returns the distance between the given geometries.</p>
</span></td></tr>
<tr><td><a name="st_distancesphere"></a><code>st_distancesphere(geometry_a: geometry, geometry_b: geometry) &rarr; <a href="float.html">float</a></code></td><td><span class="funcdesc"><p>Returns the distance in meters between geometry_a and geometry_b assuming the coordinates represent lng/lat points on a sphere.</p>
<p>This function utilizes the S2 library for spherical calculations.</p>
</span></td></tr>
<tr><td><a name="st_distancespheroid"></a><code>st_distancespheroid(geometry_a: geometry, geometry_b: geometry) &rarr; <a href="float.html">float</a></code></td><td><span class="funcdesc"><p>Returns the distance in meters between geometry_a and geometry_b assuming the coordinates represent lng/lat points on a spheroid.&quot;\n\nWhen operating on a spheroid, this function will use the sphere to calculate the closest two points using S2. The spheroid distance between these two points is calculated using GeographicLib. This follows observed PostGIS behavior.</p>
<p>This function utilizes the S2 library for spherical calculations.</p>
<p>This function utilizes the GeographicLib library for spheroid calculations.</p>
</span></td></tr>
<tr><td><a name="st_dwithin"></a><code>st_dwithin(geography_a: geography, geography_b: geography, distance: <a href="float.html">float</a>) &rarr; <a href="bool.html">bool</a></code></td><td><span class="funcdesc"><p>Returns true if any of geography_a is within distance meters of geography_b. Uses a spheroid to perform the operation.&quot;\n\nWhen operating on a spheroid, this function will use the sphere to calculate the closest two points using S2. The spheroid distance between these two points is calculated using GeographicLib. This follows observed PostGIS behavior.</p>
<p>The calculations performed are have a precision of 1cm.</p>
<p>This function utilizes the GeographicLib library for spheroid calculations.</p>
Expand Down
9 changes: 9 additions & 0 deletions pkg/geo/geomfn/topology_operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ func Centroid(g *geo.Geometry) (*geo.Geometry, error) {
return geo.ParseGeometryFromEWKB(centroidEWKB)
}

// ConvexHull returns the convex hull of a given Geometry.
func ConvexHull(g *geo.Geometry) (*geo.Geometry, error) {
convexHullEWKB, err := geos.ConvexHull(g.EWKB())
if err != nil {
return nil, err
}
return geo.ParseGeometryFromEWKB(convexHullEWKB)
}

// PointOnSurface returns the PointOnSurface of a given Geometry.
func PointOnSurface(g *geo.Geometry) (*geo.Geometry, error) {
pointOnSurfaceEWKB, err := geos.PointOnSurface(g.EWKB())
Expand Down
34 changes: 34 additions & 0 deletions pkg/geo/geomfn/topology_operations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,40 @@ func TestCentroid(t *testing.T) {
}
}

func TestConvexHull(t *testing.T) {
testCases := []struct {
wkt string
expected string
}{
{
"GEOMETRYCOLLECTION (POINT (40 10),LINESTRING (10 10, 20 20, 10 40),POLYGON ((40 40, 20 45, 45 30, 40 40)))",
"POLYGON((10 10,10 40,20 45,40 40,45 30,40 10,10 10))",
},
{
"SRID=4326;GEOMETRYCOLLECTION (POINT (40 10),LINESTRING (10 10, 20 20, 10 40),POLYGON ((40 40, 20 45, 45 30, 40 40)))",
"SRID=4326;POLYGON((10 10,10 40,20 45,40 40,45 30,40 10,10 10))",
},
{
"MULTILINESTRING((100 190,10 8),(150 10, 20 30))",
"POLYGON((10 8,20 30,100 190,150 10,10 8))",
},
}

for _, tc := range testCases {
t.Run(tc.wkt, func(t *testing.T) {
g, err := geo.ParseGeometry(tc.wkt)
require.NoError(t, err)
ret, err := ConvexHull(g)
require.NoError(t, err)

expected, err := geo.ParseGeometry(tc.expected)
require.NoError(t, err)

require.Equal(t, expected, ret)
})
}
}

func TestPointOnSurface(t *testing.T) {
testCases := []struct {
wkt string
Expand Down
21 changes: 21 additions & 0 deletions pkg/geo/geos/geos.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ typedef int (*CR_GEOS_Area_r)(CR_GEOS_Handle, CR_GEOS_Geometry, double*);
typedef int (*CR_GEOS_Length_r)(CR_GEOS_Handle, CR_GEOS_Geometry, double*);

typedef CR_GEOS_Geometry (*CR_GEOS_Centroid_r)(CR_GEOS_Handle, CR_GEOS_Geometry);
typedef CR_GEOS_Geometry (*CR_GEOS_ConvexHull_r)(CR_GEOS_Handle, CR_GEOS_Geometry);
typedef CR_GEOS_Geometry (*CR_GEOS_Union_r)(CR_GEOS_Handle, CR_GEOS_Geometry, CR_GEOS_Geometry);
typedef CR_GEOS_Geometry (*CR_GEOS_Intersection_r)(CR_GEOS_Handle, CR_GEOS_Geometry,
CR_GEOS_Geometry);
Expand Down Expand Up @@ -162,6 +163,7 @@ struct CR_GEOS {
CR_GEOS_Length_r GEOSLength_r;

CR_GEOS_Centroid_r GEOSGetCentroid_r;
CR_GEOS_ConvexHull_r GEOSConvexHull_r;
CR_GEOS_Union_r GEOSUnion_r;
CR_GEOS_PointOnSurface_r GEOSPointOnSurface_r;
CR_GEOS_Intersection_r GEOSIntersection_r;
Expand Down Expand Up @@ -232,6 +234,7 @@ struct CR_GEOS {
INIT(GEOSArea_r);
INIT(GEOSLength_r);
INIT(GEOSGetCentroid_r);
INIT(GEOSConvexHull_r);
INIT(GEOSUnion_r);
INIT(GEOSPointOnSurface_r);
INIT(GEOSIntersection_r);
Expand Down Expand Up @@ -535,6 +538,24 @@ CR_GEOS_Status CR_GEOS_Centroid(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String* c
return toGEOSString(error.data(), error.length());
}

CR_GEOS_Status CR_GEOS_ConvexHull(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String* convexHullEWKB) {
std::string error;
auto handle = initHandleWithErrorBuffer(lib, &error);
auto geom = CR_GEOS_GeometryFromSlice(lib, handle, a);
*convexHullEWKB = {.data = NULL, .len = 0};
if (geom != nullptr) {
auto convexHullGeom = lib->GEOSConvexHull_r(handle, geom);
if (convexHullGeom != nullptr) {
auto srid = lib->GEOSGetSRID_r(handle, geom);
CR_GEOS_writeGeomToEWKB(lib, handle, convexHullGeom, convexHullEWKB, srid);
lib->GEOSGeom_destroy_r(handle, convexHullGeom);
}
lib->GEOSGeom_destroy_r(handle, geom);
}
lib->GEOS_finish_r(handle);
return toGEOSString(error.data(), error.length());
}

CR_GEOS_Status CR_GEOS_Union(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_Slice b,
CR_GEOS_String* unionEWKB) {
std::string error;
Expand Down
13 changes: 13 additions & 0 deletions pkg/geo/geos/geos.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,19 @@ func Centroid(ewkb geopb.EWKB) (geopb.EWKB, error) {
return cStringToSafeGoBytes(cEWKB), nil
}

// ConvexHull returns an EWKB which returns the convex hull of the given EWKB.
func ConvexHull(ewkb geopb.EWKB) (geopb.EWKB, error) {
g, err := ensureInitInternal()
if err != nil {
return nil, err
}
var cEWKB C.CR_GEOS_String
if err := statusToError(C.CR_GEOS_ConvexHull(g, goToCSlice(ewkb), &cEWKB)); err != nil {
return nil, err
}
return cStringToSafeGoBytes(cEWKB), nil
}

// PointOnSurface returns an EWKB with a point that is on the surface of the given EWKB.
func PointOnSurface(ewkb geopb.EWKB) (geopb.EWKB, error) {
g, err := ensureInitInternal()
Expand Down
1 change: 1 addition & 0 deletions pkg/geo/geos/geos.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ CR_GEOS_Status CR_GEOS_Length(CR_GEOS* lib, CR_GEOS_Slice a, double* ret);
//

CR_GEOS_Status CR_GEOS_Centroid(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String* centroidEWKB);
CR_GEOS_Status CR_GEOS_ConvexHull(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_String* convexHullEWKB);
CR_GEOS_Status CR_GEOS_Union(CR_GEOS* lib, CR_GEOS_Slice a, CR_GEOS_Slice b,
CR_GEOS_String* unionEWKB);
CR_GEOS_Status CR_GEOS_PointOnSurface(CR_GEOS* lib, CR_GEOS_Slice a,
Expand Down
Loading

0 comments on commit 3428a4a

Please sign in to comment.