diff --git a/src/geos_types.jl b/src/geos_types.jl index b2506e2..ed24b85 100644 --- a/src/geos_types.jl +++ b/src/geos_types.jl @@ -12,6 +12,7 @@ and that shared context is returned. If contexts of some geometries differ, an error is thrown. """ function get_context end + function get_context(gs::AbstractVector)::GEOSContext if isempty(gs) get_global_context() # is this a good idea? @@ -304,6 +305,18 @@ const Geometry = Union{ GeometryCollection, } +""" + clone(obj::Geometry, context=get_context(obj)) + +Create a deep copy of obj, optionally also moving it to a new context. +""" +function clone(obj::Geometry, context=get_context(obj)) + G = typeof(obj) + # Note that all Geometry constructors + # implicitly clone the pointer, in the following line + GC.@preserve obj G(obj.ptr, context)::G +end + get_context(obj::Geometry) = obj.context function destroyGeom(obj::Geometry) context = get_context(obj) diff --git a/test/test_geos_types.jl b/test/test_geos_types.jl index 04cff68..f1bafc7 100644 --- a/test/test_geos_types.jl +++ b/test/test_geos_types.jl @@ -369,4 +369,39 @@ end return nothing end f91(91) + @testset "clone" begin + function f(n) + # adapted from https://github.com/JuliaGeo/LibGEOS.jl/issues/91#issuecomment-1267732709 + contexts = [LibGEOS.GEOSContext() for i=1:Threads.nthreads()] + p = LibGEOS.Polygon([[[-1.,-1],[+1,-1],[+1,+1],[-1,+1],[-1,-1]]]) + Threads.@threads :static for i=1:n + ctx = contexts[Threads.threadid()] + g1 = LibGEOS.clone(p,ctx) + g2 = LibGEOS.clone(p,ctx) + for j=1:n + intersects(g1,g2) + end + end + GC.gc(true) + return nothing + end + f(91) + end +end + +@testset "clone" begin + geos = [ + readgeom("POINT(0 0)") + readgeom("MULTIPOINT(0 0, 5 0, 10 0)") + readgeom("LINESTRING (130 240, 650 240)") + readgeom("POLYGON EMPTY") + readgeom("POLYGON ((10 10, 20 40, 90 90, 90 10, 10 10))") + readgeom("MULTILINESTRING ((5 0, 10 0), (0 0, 5 0))") + readgeom("GEOMETRYCOLLECTION (LINESTRING (1 2, 2 2), LINESTRING (2 1, 1 1), POLYGON ((0.5 1, 1 2, 1 1, 0.5 1)), POLYGON ((9 2, 9.5 1, 2 1, 2 2, 9 2)))") + ] + for g1 in geos + g2 = LibGEOS.clone(g1) + @test g1 !== g2 + @test LibGEOS.equals(g1,g2) + end end diff --git a/test/test_misc.jl b/test/test_misc.jl index 34cd1a5..9c56950 100644 --- a/test/test_misc.jl +++ b/test/test_misc.jl @@ -36,4 +36,3 @@ end @test_throws ArgumentError LibGEOS.intersects(p1, q2) @test_throws ArgumentError LibGEOS.intersects(p2, q1) end -