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) 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)