Skip to content

Commit 6c857e2

Browse files
authored
Update Constructors with new functionality and test memory safety (#136)
* Add createPolygon with single argument and update Polygon constructor New createPolygon function allows creation of polygons without user specified holes. Polygon constructor added to convert a LinearRing to Polygon. Polygon constructor that takes a pointer limited by type. * Add tests for Polygon constructors - ERROR thrown Create a test file for GEOSGeom constructors found in geos_types.jl. Tests pass for Polygon constructed from vectors, but an "illegal instruction" error is thrown when one is constructed from a pointer. The error messages mentions destroyGeom. There are more tests below for constructing from a linear ring but these depend on the pointer constructor and thus cause a seg fault. * Add cloneGeom around pointers in Polygon constructor and finish tests Adding cloneGeom around pointers sent to Polygon constructor that takes in a pointer has stopped the tests from seg faulting. All desired Polygon constructors and createPolygon functionality added and tested. * Fix requested pull request changes Typo in comments, remove magic numbers, change variable name * Update Point constructror and add tests Added cloneGeom to Point constructor to stop seg fault and tested each method to construct a point. * Update MultiPoint constructors and add tests Update existing multipoint constructors to clone pointers and add constructors to take in a vector of points and a point pointer. * Update LineString and MultiLineString constructors and add tests Update LineString and MultiLineString constructors so that they use cloneGeom when needed and only accept appropriate type pointers. Added tests for all constructor functionality. * Update LinearRing constructor and add tests Add cloneGeom to LinearRing constructor and add tests for all functionality. Also refactor names and add comments. * Update MultiPolygon and GeometryCollection constructors and add tests Add cloneGeom to constructors, add MultiPolygon constructor from list of polygons, and test all functionality.
1 parent c21a0a7 commit 6c857e2

File tree

2 files changed

+340
-47
lines changed

2 files changed

+340
-47
lines changed

src/geos_types.jl

Lines changed: 96 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,55 +2,93 @@ abstract type AbstractGeometry end
22

33
mutable struct Point <: AbstractGeometry
44
ptr::GEOSGeom
5-
5+
# create a point from a pointer - only makese sense if it is a pointer to a point, otherwise error
66
function Point(ptr::GEOSGeom)
7-
point = new(ptr)
8-
finalizer(destroyGeom, point)
9-
point
7+
id = LibGEOS.geomTypeId(ptr)
8+
if id == GEOS_POINT
9+
point = new(cloneGeom(ptr))
10+
finalizer(destroyGeom, point)
11+
point
12+
else
13+
error("LibGEOS: Can't convert a pointer to an element with a GeomType ID of $id to a point (yet). Please open an issue if you think this conversion makes sense.")
14+
end
1015
end
16+
# create a point from a vector of floats
1117
Point(coords::Vector{Float64}) = Point(createPoint(coords))
1218
Point(x::Real, y::Real) = Point(createPoint(x, y))
1319
Point(x::Real, y::Real, z::Real) = Point(createPoint(x, y, z))
14-
1520
end
1621

1722
mutable struct MultiPoint <: AbstractGeometry
1823
ptr::GEOSGeom
19-
24+
# create a multipoint from a pointer - only makes sense if it is a pointer to a multipoint or to a point, otherwise error
2025
function MultiPoint(ptr::GEOSGeom)
21-
multipoint = new(ptr)
26+
id = LibGEOS.geomTypeId(ptr)
27+
if id == GEOS_MULTIPOINT
28+
multipoint = new(cloneGeom(ptr))
29+
elseif id == GEOS_POINT
30+
multipoint = new(createCollection(GEOS_MULTIPOINT,
31+
GEOSGeom[cloneGeom(ptr)]))
32+
else
33+
error("LibGEOS: Can't convert a pointer to an element with a GeomType ID of $id to a multipoint (yet). Please open an issue if you think this conversion makes sense.")
34+
end
2235
finalizer(destroyGeom, multipoint)
2336
multipoint
2437
end
38+
# create a multipoint frome a vector of vector coordinates
2539
MultiPoint(multipoint::Vector{Vector{Float64}}) = MultiPoint(
2640
createCollection(
2741
GEOS_MULTIPOINT,
2842
GEOSGeom[createPoint(coords) for coords in multipoint],
2943
),
3044
)
31-
45+
# create a multipoint from a list of points
46+
MultiPoint(points::Vector{LibGEOS.Point}) = MultiPoint(
47+
createCollection(
48+
GEOS_MULTIPOINT,
49+
GEOSGeom[point.ptr for point in points],
50+
),
51+
)
3252
end
3353

3454
mutable struct LineString <: AbstractGeometry
3555
ptr::GEOSGeom
36-
56+
# create a linestring from a linestring pointer, otherwise error
3757
function LineString(ptr::GEOSGeom)
38-
line = new(ptr)
58+
id = LibGEOS.geomTypeId(ptr)
59+
if id == GEOS_LINESTRING
60+
line = new(cloneGeom(ptr))
61+
finalizer(destroyGeom, line)
62+
line
63+
else
64+
error("LibGEOS: Can't convert a pointer to an element with a GeomType ID of $id to a linestring (yet). Please open an issue if you think this conversion makes sense.")
65+
end
66+
end
67+
#create a linestring from a list of coordiantes
68+
function LineString(coords::Vector{Vector{Float64}})
69+
line = new(createLineString(coords))
3970
finalizer(destroyGeom, line)
4071
line
4172
end
42-
LineString(line::Vector{Vector{Float64}}) = LineString(createLineString(line))
43-
4473
end
4574

4675
mutable struct MultiLineString <: AbstractGeometry
4776
ptr::GEOSGeom
48-
77+
# create a multiline string from a multilinestring or a linestring pointer, else error
4978
function MultiLineString(ptr::GEOSGeom)
50-
multiline = new(ptr)
79+
id = LibGEOS.geomTypeId(ptr)
80+
if id == GEOS_MULTILINESTRING
81+
multiline = new(cloneGeom(ptr))
82+
elseif id == GEOS_LINESTRING
83+
multiline = new(createCollection(GEOS_MULTILINESTRING,
84+
GEOSGeom[cloneGeom(ptr)]))
85+
else
86+
error("LibGEOS: Can't convert a pointer to an element with a GeomType ID of $id to a multi-linestring (yet). Please open an issue if you think this conversion makes sense.")
87+
end
5188
finalizer(destroyGeom, multiline)
5289
multiline
5390
end
91+
# create a multilinestring from a list of linestring coordiantes
5492
MultiLineString(multiline::Vector{Vector{Vector{Float64}}}) = MultiLineString(
5593
createCollection(
5694
GEOS_MULTILINESTRING,
@@ -62,13 +100,24 @@ end
62100

63101
mutable struct LinearRing <: AbstractGeometry
64102
ptr::GEOSGeom
65-
103+
# create a linear ring from a linear ring pointer, otherwise error
66104
function LinearRing(ptr::GEOSGeom)
67-
ring = new(ptr)
105+
id = LibGEOS.geomTypeId(ptr)
106+
if id == GEOS_LINEARRING
107+
ring = new(cloneGeom(ptr))
108+
finalizer(destroyGeom, ring)
109+
ring
110+
else
111+
error("LibGEOS: Can't convert a pointer to an element with a GeomType ID of $id to a linear ring (yet). Please open an issue if you think this conversion makes sense.")
112+
end
113+
end
114+
# create linear ring from a list of coordinates -
115+
# first and last coordinates must be the same
116+
function LinearRing(coords::Vector{Vector{Float64}})
117+
ring = new(createLinearRing(coords))
68118
finalizer(destroyGeom, ring)
69119
ring
70120
end
71-
LinearRing(ring::Vector{Vector{Float64}}) = LinearRing(createLinearRing(ring))
72121

73122
end
74123

@@ -82,7 +131,7 @@ mutable struct Polygon <: AbstractGeometry
82131
elseif id == GEOS_LINEARRING
83132
polygon = new(cloneGeom(createPolygon(ptr)))
84133
else
85-
error("LibGEOS: Can't convert a pointer to an element with a GeomType ID of $id to a polygon (yet). Please open an issue if you think this conversion makes sense. ")
134+
error("LibGEOS: Can't convert a pointer to an element with a GeomType ID of $id to a polygon (yet). Please open an issue if you think this conversion makes sense.")
86135
end
87136
finalizer(destroyGeom, polygon)
88137
polygon
@@ -106,12 +155,29 @@ end
106155

107156
mutable struct MultiPolygon <: AbstractGeometry
108157
ptr::GEOSGeom
109-
158+
# create multipolygon using a multipolygon or polygon pointer, else error
110159
function MultiPolygon(ptr::GEOSGeom)
111-
multipolygon = new(ptr)
160+
id = LibGEOS.geomTypeId(ptr)
161+
if id == GEOS_MULTIPOLYGON
162+
multipolygon = new(cloneGeom(ptr))
163+
elseif id == GEOS_POLYGON
164+
multipolygon = new(createCollection(
165+
GEOS_MULTIPOLYGON,
166+
GEOSGeom[cloneGeom(ptr)]))
167+
else
168+
error("LibGEOS: Can't convert a pointer to an element with a GeomType ID of $id to a multi-polygon (yet). Please open an issue if you think this conversion makes sense.")
169+
end
112170
finalizer(destroyGeom, multipolygon)
113171
multipolygon
114172
end
173+
174+
# create multipolygon from list of Polygon objects
175+
MultiPolygon(polygons::Vector{Polygon}) = MultiPolygon(
176+
createCollection(
177+
GEOS_MULTIPOLYGON,
178+
GEOSGeom[poly.ptr for poly in polygons],))
179+
180+
# create multipolygon using list of polygon coordinates - note that each polygon can have holes as explained above in Polygon comments
115181
MultiPolygon(multipolygon::Vector{Vector{Vector{Vector{Float64}}}}) = MultiPolygon(
116182
createCollection(
117183
GEOS_MULTIPOLYGON,
@@ -123,17 +189,22 @@ mutable struct MultiPolygon <: AbstractGeometry
123189
],
124190
),
125191
)
126-
127192
end
128193

129194
mutable struct GeometryCollection <: AbstractGeometry
130195
ptr::GEOSGeom
131-
196+
# create a geometric collection from a pointer to a geometric collection, else error
132197
function GeometryCollection(ptr::GEOSGeom)
133-
geometrycollection = new(ptr)
134-
finalizer(destroyGeom, geometrycollection)
135-
geometrycollection
198+
id = LibGEOS.geomTypeId(ptr)
199+
if id == GEOS_GEOMETRYCOLLECTION
200+
geometrycollection = new(cloneGeom(ptr))
201+
finalizer(destroyGeom, geometrycollection)
202+
geometrycollection
203+
else
204+
error("LibGEOS: Can't convert a pointer to an element with a GeomType ID of $id to a geometry collection (yet). Please open an issue if you think this conversion makes sense.")
205+
end
136206
end
207+
# create a geometric collection from a list of pointers to geometric objects
137208
GeometryCollection(collection::Vector{GEOSGeom}) =
138209
GeometryCollection(createCollection(GEOS_GEOMETRYCOLLECTION, collection))
139210
end

0 commit comments

Comments
 (0)