Repository: JuliaGeo/LibGEOS.jl
Pull request #156 (2023-01-28 12:51:54)

Geointerface conversions
This PR adds the new `geointerface_geomtype` local methods, updates `convert` to not use `coordinates`, and adds methods to all functions that will work on any compatible geometries.

There are some extra methods needed for some constructors to make `convert` more consistent.

Its not really practical to test this without wrapper types, the test objects are too limited: 

So also waiting on https://github.com/JuliaGeo/GeoInterface.jl/pull/78

We may as well review this now as its basically ready to go, just needs 78 to work. @jw3126 if you would also like to review this that would be helpful.

rafaqz: This should be good to go. It's a breaking change because I have renamed `Base.contains` to `LibGEOS.contains`, otherwise we can't accept other geometries in it without piracy.

We can lump it with #155 



Patch:
diff --git a/src/LibGEOS.jl b/src/LibGEOS.jl
index 872bd95..521c253 100644
--- a/src/LibGEOS.jl
+++ b/src/LibGEOS.jl
@@ -6,6 +6,8 @@ using GeoInterfaceRecipes
 using Extents
 using CEnum
 
+const GI = GeoInterface
+
 export Point,
     MultiPoint,
     LineString,
diff --git a/src/geo_interface.jl b/src/geo_interface.jl
index 3b8c5a4..80c85e6 100644
--- a/src/geo_interface.jl
+++ b/src/geo_interface.jl
@@ -1,5 +1,14 @@
 GeoInterface.isgeometry(::Type{<:AbstractGeometry}) = true
 
+geointerface_geomtype(::PointTrait) = Point
+geointerface_geomtype(::MultiPointTrait) = MultiPoint
+geointerface_geomtype(::LineStringTrait) = LineString
+geointerface_geomtype(::MultiLineStringTrait) = MultiLineString
+geointerface_geomtype(::LinearRingTrait) = LinearRing
+geointerface_geomtype(::PolygonTrait) = Polygon
+geointerface_geomtype(::MultiPolygonTrait) = MultiPolygon
+geointerface_geomtype(::GeometryCollectionTrait) = GeometryCollection
+
 GeoInterface.geomtrait(::Point) = PointTrait()
 GeoInterface.geomtrait(::MultiPoint) = MultiPointTrait()
 GeoInterface.geomtrait(::LineString) = LineStringTrait()
@@ -44,6 +53,10 @@ GeoInterface.getgeom(t::AbstractGeometryTrait, geom::PreparedGeometry, i) =
     GeoInterface.getgeom(t, geom.ownedby, i)
 GeoInterface.getgeom(t::AbstractPointTrait, geom::PreparedGeometry, i) = 0
 
+GeoInterface.x(::AbstractPointTrait, geom::AbstractGeometry) = getX(geom.ptr, 1, get_context(geom))
+GeoInterface.y(::AbstractPointTrait, geom::AbstractGeometry) = getY(geom.ptr, 1, get_context(geom))
+GeoInterface.z(::AbstractPointTrait, geom::AbstractGeometry) = getZ(geom.ptr, 1, get_context(geom))
+
 GeoInterface.ncoord(::AbstractGeometryTrait, geom::AbstractGeometry) =
     isEmpty(geom) ? 0 : getCoordinateDimension(geom)
 GeoInterface.getcoord(::AbstractGeometryTrait, geom::AbstractGeometry, i) =
@@ -60,40 +73,69 @@ function GeoInterface.extent(::AbstractGeometryTrait, geom::AbstractGeometry)
     return Extent(X = (getXMin(env), getXMax(env)), Y = (getYMin(env), getYMax(env)))
 end
 
-function Base.convert(::Type{T}, geom::T) where {T<:AbstractGeometry}
-    return geom
-end
-
-function Base.convert(::Type{T}, geom::X) where {T<:AbstractGeometry,X}
-    return Base.convert(T, GeoInterface.geomtrait(geom), geom)
+GI.convert(::Type{Point}, ::PointTrait, geom::Point; context=nothing) = geom
+function GI.convert(::Type{Point}, ::PointTrait, geom; context=get_global_context())
+    if GI.is3d(geom)
+        return Point(GI.x(geom), GI.y(geom), GI.z(geom), context)
+    else
+        return Point(GI.x(geom), GI.y(geom), context)
+    end
 end
-
-function Base.convert(::Type{Point}, type::PointTrait, geom)
-    return Point(GeoInterface.coordinates(geom))
+GI.convert(::Type{MultiPoint}, ::MultiPointTrait, geom::MultiPoint; context=nothing) = geom
+function GI.convert(::Type{MultiPoint}, t::MultiPointTrait, geom; context=get_global_context())
+    points = Point[GI.convert(Point, PointTrait(), p) for p in GI.getpoint(t, geom)]
+    return MultiPoint(points, context)
 end
-function Base.convert(::Type{MultiPoint}, type::MultiPointTrait, geom)
-    return MultiPoint(GeoInterface.coordinates(geom))
+GI.convert(::Type{LineString}, ::LineStringTrait, geom::LineString; context=nothing) = geom
+function GI.convert(::Type{LineString}, ::LineStringTrait, geom; context=get_global_context())
+    # Faster to make a CoordSeq directly here
+    seq = _geom_to_coord_seq(geom, context)
+    return LineString(createLineString(seq, context), context)
 end
-function Base.convert(::Type{LineString}, type::LineStringTrait, geom)
-    return LineString(GeoInterface.coordinates(geom))
+GI.convert(::Type{LinearRing}, ::LinearRingTrait, geom::LinearRing; context=nothing) = geom
+function GI.convert(::Type{LinearRing}, ::LinearRingTrait, geom; context=get_global_context())
+    # Faster to make a CoordSeq directly here
+    seq = _geom_to_coord_seq(geom, context)
+    return LinearRing(createLinearRing(seq, context), context)
 end
-function Base.convert(::Type{MultiLineString}, type::MultiLineStringTrait, geom)
-    return MultiLineString(GeoInterface.coordinates(geom))
+GI.convert(::Type{MultiLineString}, ::MultiLineStringTrait, geom::MultiLineString; context=nothing) = geom
+function GI.convert(::Type{MultiLineString}, ::MultiLineStringTrait, geom; context=get_global_context())
+    linestrings = LineString[GI.convert(LineString, LineStringTrait(), g; context) for g in getgeom(geom)]
+    return MultiLineString(linestrings)
 end
-function Base.convert(::Type{Polygon}, type::PolygonTrait, geom)
-    return Polygon(GeoInterface.coordinates(geom))
+GI.convert(::Type{Polygon}, ::PolygonTrait, geom::Polygon; context=nothing) = geom
+function GI.convert(::Type{Polygon}, ::PolygonTrait, geom; context=get_global_context())
+    exterior = GI.convert(LinearRing, GI.LinearRingTrait(), GI.getexterior(geom); context)
+    holes = LinearRing[GI.convert(LinearRing, GI.LinearRingTrait(), g; context) for g in GI.gethole(geom)]
+    return Polygon(exterior, holes)
 end
-function Base.convert(::Type{MultiPolygon}, type::MultiPolygonTrait, geom)
-    return MultiPolygon(GeoInterface.coordinates(geom))
+GI.convert(::Type{MultiPolygon}, ::MultiPolygonTrait, geom::MultiPolygon; context=nothing) = geom
+function GI.convert(::Type{MultiPolygon}, ::MultiPolygonTrait, geom; context=get_global_context())
+    polygons = Polygon[GI.convert(Polygon, PolygonTrait(), g; context) for g in GI.getgeom(geom)]
+    return MultiPolygon(polygons)
 end
 
-function Base.convert(t::Type{<:AbstractGeometry}, type::AbstractGeometryTrait, geom)
+function GI.convert(t::Type{<:AbstractGeometry}, ::AbstractGeometryTrait, geom; context=nothing)
     error(
-        "Cannot convert an object of $(typeof(geom)) with the $(typeof(type)) trait to a $t (yet). Please report an issue.",
+        "Cannot convert an object of $(of(geom)) with the $(of()) trait to a $t (yet). Please report an issue.",
     )
-    return f(GeoInterface.coordinates(geom))
 end
 
+function _geom_to_coord_seq(geom, context)
+    npoint = GI.npoint(geom)
+    ndim = GI.is3d(geom) ? 3 : 2
+    seq = createCoordSeq(npoint, context; ndim)
+    for (i, p) in enumerate(GI.getpoint(geom))
+        if ndim == 2
+            setCoordSeq!(seq, i, (GI.x(p), GI.y(p)), context)
+        else
+            setCoordSeq!(seq, i, (GI.x(p), GI.y(p), GI.z(p)), context)
+        end
+    end
+    return seq
+end
+
+
 GeoInterface.distance(
     ::AbstractGeometryTrait,
     ::AbstractGeometryTrait,
@@ -180,3 +222,42 @@ GeoInterface.union(
 ) = union(a, b)
 
 GeoInterfaceRecipes.@enable_geo_plots AbstractGeometry
+
+
+# -----
+# LibGeos operations for any GeoInterface.jl compatible geometries
+# -----
+
+# Internal convert method that avoids the overhead of `convert(LibGEOS, geom)`
+to_geos(geom) = to_geos(GI.geomtrait(geom), geom)
+to_geos(trait, geom) = GI.convert(geointerface_geomtype(trait), trait, geom)
+
+# These methods are all the same with 1 or two geometries, some arguments, and maybe keywords.
+# We define them with `@eval` to avoid all the boilerplate code.
+
+buffer(obj, dist::Real, args...; kw...) = buffer(to_geos(obj), dist::Real, args...; kw...)
+bufferWithStyle(obj, dist::Real; kw...) = bufferWithStyle(to_geos(obj), dist; kw...)
+
+# 1 geom methods
+for f in (
+    :area, :geomLength, :envelope, :minimumRotatedRectangle, :convexhull, :boundary,
+    :unaryUnion, :pointOnSurface, :centroid, :node, :simplify, :topologyPreserveSimplify, :uniquePoints,
+    :delaunayTriangulationEdges, :delaunayTriangulation, :constrainedDelaunayTriangulation,
+)
+    # We convert the geometry to a GEOS geometry and forward it to the geos method
+    @eval $f(geom, args...; kw...) = $f(to_geos(geom), args...; kw...)
+    @eval $f(geom::AbstractGeometry, args...; kw...) =
+        throw(MethodError($f, (geom, args...)))
+end
+
+# 2 geom methods
+for f in (
+    :project, :projectNormalized, :intersection, :difference, :symmetricDifference, :union, :sharedPaths,
+    :snap, :distance, :hausdorffdistance, :nearestPoints, :disjoint, :touches, :intersects, :crosses,
+    :within, :contains, :overlaps, :equalsexact, :covers, :coveredby, :equals,
+)
+    # We convert the geometries to GEOS geometries and forward them to the geos method
+    @eval $f(geom1, geom2, args...; kw...) = $f(to_geos(geom1), to_geos(geom2), args...; kw...)
+    @eval $f(geom1::AbstractGeometry, geom2::AbstractGeometry, args...; kw...) =
+        throw(MethodError($f, (geom1, geom2, args...)))
+end
diff --git a/src/geos_functions.jl b/src/geos_functions.jl
index b2ed83a..887e471 100644
--- a/src/geos_functions.jl
+++ b/src/geos_functions.jl
@@ -145,10 +145,11 @@ function getDimensions(ptr::GEOSCoordSeq, context::GEOSContext = get_global_cont
 end
 
 # convenience functions
+# Use Tuple where possible
 function setCoordSeq!(
     ptr::GEOSCoordSeq,
     i::Integer,
-    coords::Vector{Float64},
+    coords::Union{Vector{<:Real},Tuple},
     context::GEOSContext = get_global_context(),
 )
     ndim = length(coords)
@@ -158,9 +159,9 @@ function setCoordSeq!(
             "LibGEOS: i=$i is out of bounds for CoordSeq with size=$(getSize(ptr, context))",
         )
     end
-    setX!(ptr, i, coords[1], context)
-    setY!(ptr, i, coords[2], context)
-    ndim >= 3 && setZ!(ptr, i, coords[3], context)
+    setX!(ptr, i, Float64(coords[1]), context)
+    setY!(ptr, i, Float64(coords[2]), context)
+    ndim >= 3 && setZ!(ptr, i, Float64(coords[3]), context)
     ptr
 end
 
@@ -233,7 +234,7 @@ end
 
 function getX(ptr::GEOSCoordSeq, context::GEOSContext = get_global_context())
     ncoords = getSize(ptr, context)
-    xcoords = Array{Float64}(undef, ncoords)
+    xcoords = Vector{Float64}(undef, ncoords)
     start = pointer(xcoords)
     floatsize = sizeof(Float64)
     for i = 0:ncoords-1
@@ -258,7 +259,7 @@ end
 
 function getY(ptr::GEOSCoordSeq, context::GEOSContext = get_global_context())
     ncoords = getSize(ptr, context)
-    ycoords = Array{Float64}(undef, ncoords)
+    ycoords = Vector{Float64}(undef, ncoords)
     start = pointer(ycoords)
     floatsize = sizeof(Float64)
     for i = 0:ncoords-1
@@ -777,7 +778,10 @@ function within(obj1::Geometry, obj2::Geometry, context::GEOSContext = get_conte
     result != 0x00
 end
 
-function Base.contains(obj1::Geometry, obj2::Geometry, context::GEOSContext = get_context(obj1))
+Base.contains(obj1::Geometry, obj2::Geometry, context::GEOSContext = get_context(obj1)) =
+    contains(obj1, obj2, context)
+
+function contains(obj1::Geometry, obj2::Geometry, context::GEOSContext = get_context(obj1))
     result = GEOSContains_r(context, obj1, obj2)
     if result == 0x02
         error("LibGEOS: Error in GEOSContains")
@@ -842,7 +846,10 @@ function destroyPreparedGeom(obj::PreparedGeometry, context::GEOSContext = get_g
     GEOSPreparedGeom_destroy_r(context, obj)
 end
 
-function Base.contains(
+Base.contains(obj1::PreparedGeometry, obj2::Geometry, context::GEOSContext = get_context(obj1)) =
+    contains(obj1, obj2, context)
+
+function contains(
     obj1::PreparedGeometry,
     obj2::Geometry,
     context::GEOSContext = get_context(obj1)
diff --git a/src/geos_types.jl b/src/geos_types.jl
index c38520a..4f527c0 100644
--- a/src/geos_types.jl
+++ b/src/geos_types.jl
@@ -89,12 +89,17 @@ mutable struct LineString <: AbstractGeometry
         finalizer(destroyGeom, line)
         line
     end
-    #create a linestring from a list of coordinates
+    # create a linestring from a vector of points
     function LineString(coords::Vector{Vector{Float64}}, context::GEOSContext = get_global_context())
         line = new(createLineString(coords, context), context)
         finalizer(destroyGeom, line)
         line
     end
+    function LineString(coords::Vector{Point}, context::GEOSContext = get_global_context())
+        line = new(createLineString(coords, context), context)
+        finalizer(destroyGeom, line)
+        line
+    end
 end
 
 mutable struct MultiLineString <: AbstractGeometry
@@ -124,6 +129,13 @@ mutable struct MultiLineString <: AbstractGeometry
                 GEOSGeom[createLineString(coords, context) for coords in multiline],
                 context),
             context)
+    MultiLineString(multiline::Vector{LineString}, context::GEOSContext = get_global_context()) =
+        MultiLineString(
+            createCollection(
+                GEOS_MULTILINESTRING,
+                GEOSGeom[ls.ptr for ls in multiline],
+                context),
+            context)
 end
 
 mutable struct LinearRing <: AbstractGeometry
@@ -256,6 +268,13 @@ mutable struct GeometryCollection <: AbstractGeometry
                 collection,
                 context),
             context)
+    GeometryCollection(collection::Vector{<:AbstractGeometry}, context::GEOSContext = get_global_context()) =
+        GeometryCollection(
+            createCollection(
+                GEOS_GEOMETRYCOLLECTION,
+                GEOSGeom[geom.ptr for geom in collection],
+                context),
+            context)
 end
 
 const Geometry = Union{
@@ -434,7 +453,7 @@ typesalt(::Type{Polygon}            ) = 0xa5c895d62ef56723
 
 function Base.hash(geo::AbstractGeometry, h::UInt)::UInt
     h = hash(typesalt(typeof(geo)), h)
-    if has_coord_seq(geo) 
+    if has_coord_seq(geo)
         return hash_coord_seq(geo, h)
     else
         for i in 1:ngeom(geo)


Test patch:
diff --git a/test/test_geo_interface.jl b/test/test_geo_interface.jl
index dcc3fa7..5d23f91 100644
--- a/test/test_geo_interface.jl
+++ b/test/test_geo_interface.jl
@@ -1,4 +1,6 @@
-using Plots
+using Test, Plots, GeoInterface, LibGEOS, Extents
+const GI = GeoInterface
+const LG = LibGEOS
 
 @testset "Geo interface" begin
     pt = LibGEOS.Point(1.0, 2.0)
@@ -207,71 +209,103 @@ using Plots
     @test GeoInterface.testgeometry(geomcollection)
 
     @testset "Conversion" begin
+        one_arg_functions = (
+            LG.area, LG.geomLength, LG.envelope, LG.minimumRotatedRectangle, LG.convexhull, LG.boundary,
+            LG.uniquePoints, LG.unaryUnion, LG.pointOnSurface, LG.centroid, LG.node,
+            LG.delaunayTriangulationEdges, LG.delaunayTriangulation, LG.constrainedDelaunayTriangulation,
+            # these have different signatures
+            # LG.simplify, LG.topologyPreserveSimplify,
+        )
+        two_arg_functions = (
+            LG.intersection, LG.difference, LG.symmetricDifference, LG.union,
+            LG.distance, LG.hausdorffdistance, LG.nearestPoints, LG.disjoint, LG.touches, LG.intersects, LG.crosses,
+            LG.within, LG.overlaps, LG.covers, LG.coveredby, LG.equals,
+            # these have different signatures
+            # LG.project, LG.projectNormalized, LG.sharedPaths, LG.snap, LG.contains, LG.equalsexact,
+        )
+
         mp = LibGEOS.readgeom("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))")
-        @test_throws Exception convert(Polygon, mp)
-        mp2 = convert(MultiPolygon, mp)
+        @test_throws Exception GeoInterface.convert(Polygon, mp)
+        mp2 = GeoInterface.convert(MultiPolygon, mp)
         @test mp2 isa MultiPolygon
         @test mp === mp2
 
-        struct XPoint end
-        coords = [0.0, 0]
-        GeoInterface.geomtrait(::XPoint) = GeoInterface.PointTrait()
-        GeoInterface.coordinates(::XPoint) = coords
-        geom = convert(Point, XPoint())
+        coords = [0.0, 1.0]
+        geom = GeoInterface.convert(Point, GeoInterface.Point(coords))
         @test geom isa Point
         @test GeoInterface.coordinates(geom) == coords
 
-        struct XMultiPoint end
-        coords = [[0.0, 0], [0.0, 10]]
-        GeoInterface.geomtrait(::XMultiPoint) = GeoInterface.MultiPointTrait()
-        GeoInterface.coordinates(::XMultiPoint) = coords
-        geom = convert(MultiPoint, XMultiPoint())
+        coords = [[0.0, 0.0], [0.0, 10.0]]
+        geom = GeoInterface.convert(MultiPoint, GeoInterface.MultiPoint(coords))
         @test geom isa MultiPoint
         @test GeoInterface.coordinates(geom) == coords
+        for f in one_arg_functions
+            @test f(LibGEOS.MultiPoint(coords)) == f(GeoInterface.MultiPoint(coords))
+        end
+        coords2 = [[0.0, 10], [0.5, 10], [20.0, 20], [10.0, 10], [0.0, 10]]
+        for f in two_arg_functions
+            @test f(LibGEOS.LineString(coords), LibGEOS.LineString(coords)) ==
+                  f(GeoInterface.LineString(coords), GeoInterface.LineString(coords))
+        end
 
-        struct XLineString end
         coords = [[0.0, 0], [0.0, 10], [10.0, 10], [10.0, 0], [0.0, 0]]
-        GeoInterface.geomtrait(::XLineString) = GeoInterface.LineStringTrait()
-        GeoInterface.coordinates(::XLineString) = coords
-        geom = convert(LineString, XLineString())
+        geom = GeoInterface.convert(LineString, GeoInterface.LineString(coords))
         @test geom isa LineString
         @test GeoInterface.coordinates(geom) == coords
+        for f in one_arg_functions
+            @test f(LibGEOS.LineString(coords)) == f(GeoInterface.LineString(coords))
+        end
+        coords2 = [[0.0, 10], [0.5, 10], [20.0, 20], [10.0, 10], [0.0, 10]]
+        for f in two_arg_functions
+            @test f(LibGEOS.LineString(coords), LibGEOS.LineString(coords)) ==
+                  f(GeoInterface.LineString(coords), GeoInterface.LineString(coords))
+        end
 
-        struct XMultiLineString end
         coords = [[[0.0, 0], [0.0, 10], [10.0, 10], [10.0, 0], [0.0, 0]]]
-        GeoInterface.geomtrait(::XMultiLineString) = GeoInterface.MultiLineStringTrait()
-        GeoInterface.coordinates(::XMultiLineString) = coords
-        geom = convert(MultiLineString, XMultiLineString())
+        geom = GeoInterface.convert(MultiLineString, GeoInterface.MultiLineString(coords))
         @test geom isa MultiLineString
         @test GeoInterface.coordinates(geom) == coords
+        for f in one_arg_functions
+            @test f(LibGEOS.MultiLineString(coords)) == f(GeoInterface.MultiLineString(coords))
+        end
+        coords2 = [[[0.0, 10], [0.5, 10], [20.0, 20], [10.0, 10], [0.0, 10]]]
+        for f in two_arg_functions
+            @test f(LibGEOS.MultiLineString(coords), LibGEOS.MultiLineString(coords2)) ==
+                  f(GeoInterface.MultiLineString(coords), LibGEOS.MultiLineString(coords2))
+        end
 
-        struct XPolygon end
         coords = [[[0.0, 0], [0.0, 10], [10.0, 10], [10.0, 0], [0.0, 0]]]
-        GeoInterface.geomtrait(::XPolygon) = GeoInterface.PolygonTrait()
-        GeoInterface.coordinates(::XPolygon) = coords
-        geom = convert(Polygon, XPolygon())
+        geom = GeoInterface.convert(Polygon, Polygon(coords))
         @test geom isa Polygon
         @test GeoInterface.ngeom(geom) == 1
         @test GeoInterface.nring(geom) == 1
         @test GeoInterface.nhole(geom) == 0
         @test GeoInterface.coordinates(geom) == coords
+        for f in one_arg_functions
+            @test f(LibGEOS.Polygon(coords)) == f(GeoInterface.Polygon(coords))
+        end
+        coords2 = [[[0.0, 10], [0.5, 10], [20.0, 20], [10.0, 10], [0.0, 10]]]
+        for f in two_arg_functions
+            @test f(LibGEOS.Polygon(coords), LibGEOS.Polygon(coords2)) ==
+            f(GeoInterface.Polygon(coords), LibGEOS.Polygon(coords2))
+        end
 
         pgeom = LibGEOS.prepareGeom(geom)
         @test GeoInterface.coordinates(pgeom) == coords
         LibGEOS.destroyGeom(pgeom)
 
-        struct XMultiPolygon end
         coords = [[[[0.0, 0], [0.0, 10], [10.0, 10], [10.0, 0], [0.0, 0]]]]
-        GeoInterface.geomtrait(::XMultiPolygon) = GeoInterface.MultiPolygonTrait()
-        GeoInterface.coordinates(::XMultiPolygon) = coords
-        geom = convert(MultiPolygon, XMultiPolygon())
+        geom = GeoInterface.convert(MultiPolygon, GeoInterface.MultiPolygon(coords))
         @test geom isa MultiPolygon
         @test GeoInterface.coordinates(geom) == coords
-
-        struct XMesh end
-        GeoInterface.geomtrait(::XMesh) = GeoInterface.PolyhedralSurfaceTrait()
-        @test_throws Exception convert(MultiPolygon, XMesh())
-
+        for f in one_arg_functions
+            @test f(LibGEOS.MultiPolygon(coords)) == f(GeoInterface.MultiPolygon(coords))
+        end
+        coords2 = [[[[0.0, 10], [0.5, 10], [20.0, 20], [10.0, 10], [0.0, 10]]]]
+        for f in two_arg_functions
+            @test f(LibGEOS.MultiPolygon(coords), LibGEOS.MultiPolygon(coords2)) ==
+                  f(GeoInterface.MultiPolygon(coords), LibGEOS.MultiPolygon(coords2))
+        end
     end
 
     @testset "Operations" begin
diff --git a/test/test_geos_functions.jl b/test/test_geos_functions.jl
index 3763d91..f94b74e 100644
--- a/test/test_geos_functions.jl
+++ b/test/test_geos_functions.jl
@@ -123,22 +123,28 @@ end
     # GEOSContainsTest
     geom1_ = LibGEOS.readgeom("POLYGON EMPTY")
     geom2_ = LibGEOS.readgeom("POLYGON EMPTY")
-    @test !contains(geom1_, geom2_)
-    @test !contains(geom2_, geom1_)
+    @test !Base.contains(geom1_, geom2_)
+    @test !Base.contains(geom2_, geom1_)
+    @test !LibGEOS.contains(geom1_, geom2_)
+    @test !LibGEOS.contains(geom2_, geom1_)
     LibGEOS.destroyGeom(geom1_)
     LibGEOS.destroyGeom(geom2_)
 
     geom1_ = LibGEOS.readgeom("POLYGON((1 1,1 5,5 5,5 1,1 1))")
     geom2_ = LibGEOS.readgeom("POINT(2 2)")
-    @test contains(geom1_, geom2_)
-    @test !contains(geom2_, geom1_)
+    @test Base.contains(geom1_, geom2_)
+    @test !Base.contains(geom2_, geom1_)
+    @test LibGEOS.contains(geom1_, geom2_)
+    @test !LibGEOS.contains(geom2_, geom1_)
     LibGEOS.destroyGeom(geom1_)
     LibGEOS.destroyGeom(geom2_)
 
     geom1_ = LibGEOS.readgeom("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))")
     geom2_ = LibGEOS.readgeom("POLYGON((1 1,1 2,2 2,2 1,1 1))")
-    @test contains(geom1_, geom2_)
-    @test !contains(geom2_, geom1_)
+    @test Base.contains(geom1_, geom2_)
+    @test !Base.contains(geom2_, geom1_)
+    @test LibGEOS.contains(geom1_, geom2_)
+    @test !LibGEOS.contains(geom2_, geom1_)
     LibGEOS.destroyGeom(geom1_)
     LibGEOS.destroyGeom(geom2_)
 
diff --git a/test/test_geos_operations.jl b/test/test_geos_operations.jl
index 2df624b..8d408e3 100644
--- a/test/test_geos_operations.jl
+++ b/test/test_geos_operations.jl
@@ -314,7 +314,7 @@ end
         for f in (within, coveredby)
             factcheck(f, g1, g2, testvalue)
         end
-        for f in (contains, covers)
+        for f in (LibGEOS.contains, covers)
             factcheck(f, g2, g1, testvalue)
         end
     end
diff --git a/test/test_misc.jl b/test/test_misc.jl
index 071b963..1744e0a 100644
--- a/test/test_misc.jl
+++ b/test/test_misc.jl
@@ -145,7 +145,7 @@ end
     @test !(lr1 == lr2)
     @test !isequal(lr1, lr2)
     @test !isapprox(lr1, lr2)
-    
+
     @test 300 > @allocated lr1 == lr2
     @test 300 > @allocated isequal(lr1, lr2)
     @test 300 > @allocated isapprox(lr1, lr2)
@@ -160,7 +160,7 @@ end
     @test !(poly1 == poly2)
     @test !isequal(poly1, poly2)
     @test !isapprox(poly1, poly2)
-    
+
     @test 300 > @allocated poly1 == poly2
     @test 300 > @allocated isequal(poly1, poly2)
     @test 300 > @allocated isapprox(poly1, poly2)