1 /************************************************************************
2  *
3  *
4  * C-Wrapper for GEOS library
5  *
6  * Copyright (C) 2005-2006 Refractions Research Inc.
7  * Copyright (C) 2010-2012 Sandro Santilli <strk@kbt.io>
8  * Copyright (C) 2016-2019 Daniel Baston <dbaston@gmail.com>
9  *
10  * This is free software; you can redistribute and/or modify it under
11  * the terms of the GNU Lesser General Public Licence as published
12  * by the Free Software Foundation.
13  * See the COPYING file for more information.
14  *
15  * Author: Sandro Santilli <strk@kbt.io>
16  * Thread Safety modifications: Chuck Thibert <charles.thibert@ingres.com>
17  *
18  ***********************************************************************/
19 
20 #include <geos/geom/Coordinate.h>
21 #include <geos/geom/Geometry.h>
22 #include <geos/geom/prep/PreparedGeometry.h>
23 #include <geos/geom/prep/PreparedGeometryFactory.h>
24 #include <geos/geom/GeometryCollection.h>
25 #include <geos/geom/Polygon.h>
26 #include <geos/geom/Point.h>
27 #include <geos/geom/MultiPoint.h>
28 #include <geos/geom/MultiLineString.h>
29 #include <geos/geom/MultiPolygon.h>
30 #include <geos/geom/LinearRing.h>
31 #include <geos/geom/LineSegment.h>
32 #include <geos/geom/LineString.h>
33 #include <geos/geom/PrecisionModel.h>
34 #include <geos/geom/GeometryFactory.h>
35 #include <geos/geom/CoordinateSequenceFactory.h>
36 #include <geos/geom/FixedSizeCoordinateSequence.h>
37 #include <geos/geom/Coordinate.h>
38 #include <geos/geom/IntersectionMatrix.h>
39 #include <geos/geom/Envelope.h>
40 #include <geos/index/strtree/SimpleSTRtree.h>
41 #include <geos/index/strtree/GeometryItemDistance.h>
42 #include <geos/index/ItemVisitor.h>
43 #include <geos/io/WKTReader.h>
44 #include <geos/io/WKBReader.h>
45 #include <geos/io/WKTWriter.h>
46 #include <geos/io/WKBWriter.h>
47 #include <geos/algorithm/BoundaryNodeRule.h>
48 #include <geos/algorithm/MinimumBoundingCircle.h>
49 #include <geos/algorithm/MinimumDiameter.h>
50 #include <geos/algorithm/Orientation.h>
51 #include <geos/algorithm/construct/MaximumInscribedCircle.h>
52 #include <geos/algorithm/construct/LargestEmptyCircle.h>
53 #include <geos/algorithm/distance/DiscreteHausdorffDistance.h>
54 #include <geos/algorithm/distance/DiscreteFrechetDistance.h>
55 #include <geos/simplify/DouglasPeuckerSimplifier.h>
56 #include <geos/simplify/TopologyPreservingSimplifier.h>
57 #include <geos/noding/GeometryNoder.h>
58 #include <geos/noding/Noder.h>
59 #include <geos/operation/buffer/BufferBuilder.h>
60 #include <geos/operation/buffer/BufferOp.h>
61 #include <geos/operation/buffer/BufferParameters.h>
62 #include <geos/operation/distance/DistanceOp.h>
63 #include <geos/operation/distance/IndexedFacetDistance.h>
64 #include <geos/operation/linemerge/LineMerger.h>
65 #include <geos/operation/overlay/OverlayOp.h>
66 #include <geos/operation/overlay/snap/GeometrySnapper.h>
67 #include <geos/operation/overlayng/PrecisionReducer.h>
68 #include <geos/operation/overlayng/OverlayNG.h>
69 #include <geos/operation/overlayng/OverlayNGRobust.h>
70 #include <geos/operation/overlayng/UnaryUnionNG.h>
71 #include <geos/operation/intersection/Rectangle.h>
72 #include <geos/operation/intersection/RectangleIntersection.h>
73 #include <geos/operation/polygonize/Polygonizer.h>
74 #include <geos/operation/polygonize/BuildArea.h>
75 #include <geos/operation/relate/RelateOp.h>
76 #include <geos/operation/sharedpaths/SharedPathsOp.h>
77 #include <geos/operation/union/CascadedPolygonUnion.h>
78 #include <geos/operation/union/CoverageUnion.h>
79 #include <geos/operation/valid/IsValidOp.h>
80 #include <geos/operation/valid/MakeValid.h>
81 #include <geos/precision/GeometryPrecisionReducer.h>
82 #include <geos/linearref/LengthIndexedLine.h>
83 #include <geos/triangulate/DelaunayTriangulationBuilder.h>
84 #include <geos/triangulate/VoronoiDiagramBuilder.h>
85 #include <geos/util.h>
86 #include <geos/util/IllegalArgumentException.h>
87 #include <geos/util/Interrupt.h>
88 #include <geos/util/UniqueCoordinateArrayFilter.h>
89 #include <geos/util/Machine.h>
90 #include <geos/version.h>
91 
92 // This should go away
93 #include <cmath> // finite
94 #include <cstdarg>
95 #include <cstddef>
96 #include <cstdio>
97 #include <cstdlib>
98 #include <cstring>
99 #include <fstream>
100 #include <iostream>
101 #include <sstream>
102 #include <string>
103 #include <memory>
104 
105 #ifdef _MSC_VER
106 #pragma warning(disable : 4099)
107 #endif
108 
109 // Some extra magic to make type declarations in geos_c.h work -
110 // for cross-checking of types in header.
111 #define GEOSGeometry geos::geom::Geometry
112 #define GEOSPreparedGeometry geos::geom::prep::PreparedGeometry
113 #define GEOSCoordSequence geos::geom::CoordinateSequence
114 #define GEOSBufferParams geos::operation::buffer::BufferParameters
115 #define GEOSSTRtree geos::index::strtree::SimpleSTRtree
116 #define GEOSWKTReader geos::io::WKTReader
117 #define GEOSWKTWriter geos::io::WKTWriter
118 #define GEOSWKBReader geos::io::WKBReader
119 #define GEOSWKBWriter geos::io::WKBWriter
120 
121 #include "geos_c.h"
122 
123 // Intentional, to allow non-standard C elements like C99 functions to be
124 // imported through C++ headers of C library, like <cmath>.
125 using namespace std;
126 
127 /// Define this if you want operations triggering Exceptions to
128 /// be printed.
129 /// (will use the NOTIFY channel - only implemented for GEOSUnion so far)
130 ///
131 #undef VERBOSE_EXCEPTIONS
132 
133 #include <geos/export.h>
134 #include <geos/precision/MinimumClearance.h>
135 
136 
137 // import the most frequently used definitions globally
138 using geos::geom::Geometry;
139 using geos::geom::LineString;
140 using geos::geom::LinearRing;
141 using geos::geom::MultiLineString;
142 using geos::geom::MultiPolygon;
143 using geos::geom::Polygon;
144 using geos::geom::PrecisionModel;
145 using geos::geom::CoordinateSequence;
146 using geos::geom::GeometryCollection;
147 using geos::geom::GeometryFactory;
148 
149 using geos::io::WKTReader;
150 using geos::io::WKTWriter;
151 using geos::io::WKBReader;
152 using geos::io::WKBWriter;
153 
154 using geos::algorithm::distance::DiscreteFrechetDistance;
155 using geos::algorithm::distance::DiscreteHausdorffDistance;
156 
157 using geos::operation::buffer::BufferBuilder;
158 using geos::operation::buffer::BufferParameters;
159 using geos::operation::distance::IndexedFacetDistance;
160 using geos::operation::geounion::CascadedPolygonUnion;
161 using geos::operation::overlayng::OverlayNG;
162 using geos::operation::overlayng::UnaryUnionNG;
163 using geos::operation::overlayng::OverlayNGRobust;
164 
165 using geos::precision::GeometryPrecisionReducer;
166 
167 using geos::util::IllegalArgumentException;
168 
169 typedef std::unique_ptr<Geometry> GeomPtr;
170 
171 typedef struct GEOSContextHandle_HS {
172     const GeometryFactory* geomFactory;
173     char msgBuffer[1024];
174     GEOSMessageHandler noticeMessageOld;
175     GEOSMessageHandler_r noticeMessageNew;
176     void* noticeData;
177     GEOSMessageHandler errorMessageOld;
178     GEOSMessageHandler_r errorMessageNew;
179     void* errorData;
180     int WKBOutputDims;
181     int WKBByteOrder;
182     int initialized;
183 
GEOSContextHandle_HSGEOSContextHandle_HS184     GEOSContextHandle_HS()
185         :
186         geomFactory(nullptr),
187         noticeMessageOld(nullptr),
188         noticeMessageNew(nullptr),
189         noticeData(nullptr),
190         errorMessageOld(nullptr),
191         errorMessageNew(nullptr),
192         errorData(nullptr)
193     {
194         memset(msgBuffer, 0, sizeof(msgBuffer));
195         geomFactory = GeometryFactory::getDefaultInstance();
196         WKBOutputDims = 2;
197         WKBByteOrder = getMachineByteOrder();
198         setNoticeHandler(nullptr);
199         setErrorHandler(nullptr);
200         initialized = 1;
201     }
202 
203     GEOSMessageHandler
setNoticeHandlerGEOSContextHandle_HS204     setNoticeHandler(GEOSMessageHandler nf)
205     {
206         GEOSMessageHandler f = noticeMessageOld;
207         noticeMessageOld = nf;
208         noticeMessageNew = nullptr;
209         noticeData = nullptr;
210 
211         return f;
212     }
213 
214     GEOSMessageHandler
setErrorHandlerGEOSContextHandle_HS215     setErrorHandler(GEOSMessageHandler nf)
216     {
217         GEOSMessageHandler f = errorMessageOld;
218         errorMessageOld = nf;
219         errorMessageNew = nullptr;
220         errorData = nullptr;
221 
222         return f;
223     }
224 
225     GEOSMessageHandler_r
setNoticeHandlerGEOSContextHandle_HS226     setNoticeHandler(GEOSMessageHandler_r nf, void* userData)
227     {
228         GEOSMessageHandler_r f = noticeMessageNew;
229         noticeMessageOld = nullptr;
230         noticeMessageNew = nf;
231         noticeData = userData;
232 
233         return f;
234     }
235 
236     GEOSMessageHandler_r
setErrorHandlerGEOSContextHandle_HS237     setErrorHandler(GEOSMessageHandler_r ef, void* userData)
238     {
239         GEOSMessageHandler_r f = errorMessageNew;
240         errorMessageOld = nullptr;
241         errorMessageNew = ef;
242         errorData = userData;
243 
244         return f;
245     }
246 
247     void
NOTICE_MESSAGEGEOSContextHandle_HS248     NOTICE_MESSAGE(const char *fmt, ...)
249     {
250         if(nullptr == noticeMessageOld && nullptr == noticeMessageNew) {
251             return;
252         }
253 
254         va_list args;
255         va_start(args, fmt);
256         int result = vsnprintf(msgBuffer, sizeof(msgBuffer) - 1, fmt, args);
257         va_end(args);
258 
259         if(result > 0) {
260             if(noticeMessageOld) {
261                 noticeMessageOld("%s", msgBuffer);
262             }
263             else {
264                 noticeMessageNew(msgBuffer, noticeData);
265             }
266         }
267     }
268 
269     void
ERROR_MESSAGEGEOSContextHandle_HS270     ERROR_MESSAGE(const char *fmt, ...)
271     {
272         if(nullptr == errorMessageOld && nullptr == errorMessageNew) {
273             return;
274         }
275 
276         va_list args;
277         va_start(args, fmt);
278         int result = vsnprintf(msgBuffer, sizeof(msgBuffer) - 1, fmt, args);
279         va_end(args);
280 
281         if(result > 0) {
282             if(errorMessageOld) {
283                 errorMessageOld("%s", msgBuffer);
284             }
285             else {
286                 errorMessageNew(msgBuffer, errorData);
287             }
288         }
289     }
290 } GEOSContextHandleInternal_t;
291 
292 // CAPI_ItemVisitor is used internally by the CAPI STRtree
293 // wrappers. It's defined here just to keep it out of the
294 // extern "C" block.
295 class CAPI_ItemVisitor : public geos::index::ItemVisitor {
296     GEOSQueryCallback callback;
297     void* userdata;
298 public:
CAPI_ItemVisitor(GEOSQueryCallback cb,void * ud)299     CAPI_ItemVisitor(GEOSQueryCallback cb, void* ud)
300         : ItemVisitor(), callback(cb), userdata(ud) {}
301     void
visitItem(void * item)302     visitItem(void* item) override
303     {
304         callback(item, userdata);
305     }
306 };
307 
308 
309 //## PROTOTYPES #############################################
310 
311 extern "C" const char GEOS_DLL* GEOSjtsport();
312 extern "C" char GEOS_DLL* GEOSasText(Geometry* g1);
313 
314 
315 namespace { // anonymous
316 
317 char*
gstrdup_s(const char * str,const std::size_t size)318 gstrdup_s(const char* str, const std::size_t size)
319 {
320     char* out = static_cast<char*>(malloc(size + 1));
321     if(nullptr != out) {
322         // as no strlen call necessary, memcpy may be faster than strcpy
323         std::memcpy(out, str, size + 1);
324     }
325 
326     assert(nullptr != out);
327 
328     // we haven't been checking allocation before ticket #371
329     if(nullptr == out) {
330         throw(std::runtime_error("Failed to allocate memory for duplicate string"));
331     }
332 
333     return out;
334 }
335 
336 char*
gstrdup(std::string const & str)337 gstrdup(std::string const& str)
338 {
339     return gstrdup_s(str.c_str(), str.size());
340 }
341 
342 } // namespace anonymous
343 
344 // Execute a lambda, using the given context handle to process errors.
345 // Return errval on error.
346 // Errval should be of the type returned by f, unless f returns a bool in which case we promote to char.
347 template<typename F>
execute(GEOSContextHandle_t extHandle,typename std::conditional<std::is_same<decltype(std::declval<F> ()()),bool>::value,char,decltype(std::declval<F> ()())>::type errval,F && f)348 inline auto execute(
349         GEOSContextHandle_t extHandle,
350         typename std::conditional<std::is_same<decltype(std::declval<F>()()),bool>::value,
351                                   char,
352                                   decltype(std::declval<F>()())>::type errval,
353         F&& f) -> decltype(errval) {
354     if (extHandle == nullptr) {
355         return errval;
356     }
357 
358     GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
359     if (!handle->initialized) {
360         return errval;
361     }
362 
363     try {
364         return f();
365     } catch (const std::exception& e) {
366         handle->ERROR_MESSAGE("%s", e.what());
367     } catch (...) {
368         handle->ERROR_MESSAGE("Unknown exception thrown");
369     }
370 
371     return errval;
372 }
373 
374 // Execute a lambda, using the given context handle to process errors.
375 // Return nullptr on error.
376 template<typename F, typename std::enable_if<!std::is_void<decltype(std::declval<F>()())>::value, std::nullptr_t>::type = nullptr>
execute(GEOSContextHandle_t extHandle,F && f)377 inline auto execute(GEOSContextHandle_t extHandle, F&& f) -> decltype(f()) {
378     if (extHandle == nullptr) {
379         return nullptr;
380     }
381 
382     GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
383     if (!handle->initialized) {
384         return nullptr;
385     }
386 
387     try {
388         return f();
389     } catch (const std::exception& e) {
390         handle->ERROR_MESSAGE("%s", e.what());
391     } catch (...) {
392         handle->ERROR_MESSAGE("Unknown exception thrown");
393     }
394 
395     return nullptr;
396 }
397 
398 // Execute a lambda, using the given context handle to process errors.
399 // No return value.
400 template<typename F, typename std::enable_if<std::is_void<decltype(std::declval<F>()())>::value, std::nullptr_t>::type = nullptr>
execute(GEOSContextHandle_t extHandle,F && f)401 inline void execute(GEOSContextHandle_t extHandle, F&& f) {
402     GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
403     try {
404         f();
405     } catch (const std::exception& e) {
406         handle->ERROR_MESSAGE("%s", e.what());
407     } catch (...) {
408         handle->ERROR_MESSAGE("Unknown exception thrown");
409     }
410 }
411 
412 extern "C" {
413 
414     GEOSContextHandle_t
initGEOS_r(GEOSMessageHandler nf,GEOSMessageHandler ef)415     initGEOS_r(GEOSMessageHandler nf, GEOSMessageHandler ef)
416     {
417         GEOSContextHandle_t handle = GEOS_init_r();
418 
419         if(nullptr != handle) {
420             GEOSContext_setNoticeHandler_r(handle, nf);
421             GEOSContext_setErrorHandler_r(handle, ef);
422         }
423 
424         return handle;
425     }
426 
427     GEOSContextHandle_t
GEOS_init_r()428     GEOS_init_r()
429     {
430         GEOSContextHandleInternal_t* handle = new GEOSContextHandleInternal_t();
431 
432         geos::util::Interrupt::cancel();
433 
434         return static_cast<GEOSContextHandle_t>(handle);
435     }
436 
437     GEOSMessageHandler
GEOSContext_setNoticeHandler_r(GEOSContextHandle_t extHandle,GEOSMessageHandler nf)438     GEOSContext_setNoticeHandler_r(GEOSContextHandle_t extHandle, GEOSMessageHandler nf)
439     {
440         GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
441         if(0 == handle->initialized) {
442             return nullptr;
443         }
444 
445         return handle->setNoticeHandler(nf);
446     }
447 
448     GEOSMessageHandler
GEOSContext_setErrorHandler_r(GEOSContextHandle_t extHandle,GEOSMessageHandler nf)449     GEOSContext_setErrorHandler_r(GEOSContextHandle_t extHandle, GEOSMessageHandler nf)
450     {
451         GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
452         if(0 == handle->initialized) {
453             return nullptr;
454         }
455 
456         return handle->setErrorHandler(nf);
457     }
458 
459     GEOSMessageHandler_r
GEOSContext_setNoticeMessageHandler_r(GEOSContextHandle_t extHandle,GEOSMessageHandler_r nf,void * userData)460     GEOSContext_setNoticeMessageHandler_r(GEOSContextHandle_t extHandle, GEOSMessageHandler_r nf, void* userData)
461     {
462         GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
463         if(0 == handle->initialized) {
464             return nullptr;
465         }
466 
467         return handle->setNoticeHandler(nf, userData);
468     }
469 
470     GEOSMessageHandler_r
GEOSContext_setErrorMessageHandler_r(GEOSContextHandle_t extHandle,GEOSMessageHandler_r ef,void * userData)471     GEOSContext_setErrorMessageHandler_r(GEOSContextHandle_t extHandle, GEOSMessageHandler_r ef, void* userData)
472     {
473         GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
474         if(0 == handle->initialized) {
475             return nullptr;
476         }
477 
478         return handle->setErrorHandler(ef, userData);
479     }
480 
481     void
finishGEOS_r(GEOSContextHandle_t extHandle)482     finishGEOS_r(GEOSContextHandle_t extHandle)
483     {
484         // Fix up freeing handle w.r.t. malloc above
485         delete extHandle;
486         extHandle = nullptr;
487     }
488 
489     void
GEOS_finish_r(GEOSContextHandle_t extHandle)490     GEOS_finish_r(GEOSContextHandle_t extHandle)
491     {
492         finishGEOS_r(extHandle);
493     }
494 
495     void
GEOSFree_r(GEOSContextHandle_t extHandle,void * buffer)496     GEOSFree_r(GEOSContextHandle_t extHandle, void* buffer)
497     {
498         assert(nullptr != extHandle);
499         geos::ignore_unused_variable_warning(extHandle);
500 
501         free(buffer);
502     }
503 
504 //-----------------------------------------------------------
505 // relate()-related functions
506 //  return 0 = false, 1 = true, 2 = error occurred
507 //-----------------------------------------------------------
508 
509     char
GEOSDisjoint_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)510     GEOSDisjoint_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
511     {
512         return execute(extHandle, 2, [&]() {
513             return g1->disjoint(g2);
514         });
515     }
516 
517     char
GEOSTouches_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)518     GEOSTouches_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
519     {
520         return execute(extHandle, 2, [&]() {
521             return g1->touches(g2);
522         });
523     }
524 
525     char
GEOSIntersects_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)526     GEOSIntersects_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
527     {
528         return execute(extHandle, 2, [&]() {
529             return g1->intersects(g2);
530         });
531     }
532 
533     char
GEOSCrosses_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)534     GEOSCrosses_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
535     {
536         return execute(extHandle, 2, [&]() {
537             return g1->crosses(g2);
538         });
539     }
540 
541     char
GEOSWithin_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)542     GEOSWithin_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
543     {
544         return execute(extHandle, 2, [&]() {
545             return g1->within(g2);
546         });
547     }
548 
549     char
GEOSContains_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)550     GEOSContains_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
551     {
552         return execute(extHandle, 2, [&]() {
553             return g1->contains(g2);
554         });
555     }
556 
557     char
GEOSOverlaps_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)558     GEOSOverlaps_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
559     {
560         return execute(extHandle, 2, [&]() {
561             return g1->overlaps(g2);
562         });
563     }
564 
565     char
GEOSCovers_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)566     GEOSCovers_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
567     {
568         return execute(extHandle, 2, [&]() {
569             return g1->covers(g2);
570         });
571     }
572 
573     char
GEOSCoveredBy_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)574     GEOSCoveredBy_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
575     {
576         return execute(extHandle, 2, [&]() {
577             return g1->coveredBy(g2);
578         });
579     }
580 
581 
582 //-------------------------------------------------------------------
583 // low-level relate functions
584 //------------------------------------------------------------------
585 
586     char
GEOSRelatePattern_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,const char * pat)587     GEOSRelatePattern_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, const char* pat)
588     {
589         return execute(extHandle, 2, [&]() {
590             std::string s(pat);
591             return g1->relate(g2, s);
592         });
593     }
594 
595     char
GEOSRelatePatternMatch_r(GEOSContextHandle_t extHandle,const char * mat,const char * pat)596     GEOSRelatePatternMatch_r(GEOSContextHandle_t extHandle, const char* mat,
597                              const char* pat)
598     {
599         return execute(extHandle, 2, [&]() {
600             using geos::geom::IntersectionMatrix;
601 
602             std::string m(mat);
603             std::string p(pat);
604             IntersectionMatrix im(m);
605 
606             return im.matches(p);
607         });
608     }
609 
610     char*
GEOSRelate_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)611     GEOSRelate_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
612     {
613         return execute(extHandle, [&]() {
614             using geos::geom::IntersectionMatrix;
615 
616             auto im = g1->relate(g2);
617             if(im == nullptr) {
618                 return (char*) nullptr;
619             }
620 
621             return gstrdup(im->toString());
622         });
623     }
624 
625     char*
GEOSRelateBoundaryNodeRule_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,int bnr)626     GEOSRelateBoundaryNodeRule_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, int bnr)
627     {
628         using geos::operation::relate::RelateOp;
629         using geos::geom::IntersectionMatrix;
630         using geos::algorithm::BoundaryNodeRule;
631 
632         return execute(extHandle, [&]() -> char* {
633             std::unique_ptr<IntersectionMatrix> im;
634 
635             switch (bnr) {
636                 case GEOSRELATE_BNR_MOD2: /* same as OGC */
637                     im = RelateOp::relate(g1, g2,
638                                           BoundaryNodeRule::getBoundaryRuleMod2());
639                     break;
640                 case GEOSRELATE_BNR_ENDPOINT:
641                     im = RelateOp::relate(g1, g2,
642                                           BoundaryNodeRule::getBoundaryEndPoint());
643                     break;
644                 case GEOSRELATE_BNR_MULTIVALENT_ENDPOINT:
645                     im = RelateOp::relate(g1, g2,
646                                           BoundaryNodeRule::getBoundaryMultivalentEndPoint());
647                     break;
648                 case GEOSRELATE_BNR_MONOVALENT_ENDPOINT:
649                     im = RelateOp::relate(g1, g2,
650                                           BoundaryNodeRule::getBoundaryMonovalentEndPoint());
651                     break;
652                 default:
653                     std::ostringstream ss;
654                     ss << "Invalid boundary node rule " << bnr;
655                     throw std::runtime_error(ss.str());
656             }
657 
658             if(!im) {
659                 return nullptr;
660             }
661 
662             char* result = gstrdup(im->toString());
663 
664             return result;
665         });
666     }
667 
668 
669 
670 //-----------------------------------------------------------------
671 // isValid
672 //-----------------------------------------------------------------
673 
674 
675     char
GEOSisValid_r(GEOSContextHandle_t extHandle,const Geometry * g1)676     GEOSisValid_r(GEOSContextHandle_t extHandle, const Geometry* g1)
677     {
678         return execute(extHandle, 2, [&]() {
679             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
680 
681             using geos::operation::valid::IsValidOp;
682             using geos::operation::valid::TopologyValidationError;
683 
684             IsValidOp ivo(g1);
685             TopologyValidationError* err = ivo.getValidationError();
686 
687             if(err) {
688                 handle->NOTICE_MESSAGE("%s", err->toString().c_str());
689                 return false;
690             }
691             else {
692                 return true;
693             }
694         });
695     }
696 
697     char*
GEOSisValidReason_r(GEOSContextHandle_t extHandle,const Geometry * g1)698     GEOSisValidReason_r(GEOSContextHandle_t extHandle, const Geometry* g1)
699     {
700         return execute(extHandle, [&]() {
701             using geos::operation::valid::IsValidOp;
702             using geos::operation::valid::TopologyValidationError;
703 
704             char* result = nullptr;
705             char const* const validstr = "Valid Geometry";
706 
707             IsValidOp ivo(g1);
708             TopologyValidationError* err = ivo.getValidationError();
709 
710             if(err) {
711                 std::ostringstream ss;
712                 ss.precision(15);
713                 ss << err->getCoordinate();
714                 const std::string errloc = ss.str();
715                 std::string errmsg(err->getMessage());
716                 errmsg += "[" + errloc + "]";
717                 result = gstrdup(errmsg);
718             }
719             else {
720                 result = gstrdup(std::string(validstr));
721             }
722 
723             return result;
724         });
725     }
726 
727     char
GEOSisValidDetail_r(GEOSContextHandle_t extHandle,const Geometry * g,int flags,char ** reason,Geometry ** location)728     GEOSisValidDetail_r(GEOSContextHandle_t extHandle, const Geometry* g,
729                         int flags, char** reason, Geometry** location)
730     {
731         using geos::operation::valid::IsValidOp;
732         using geos::operation::valid::TopologyValidationError;
733 
734         return execute(extHandle, 2, [&]() {
735             IsValidOp ivo(g);
736             if(flags & GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE) {
737                 ivo.setSelfTouchingRingFormingHoleValid(true);
738             }
739             TopologyValidationError* err = ivo.getValidationError();
740             if(err != nullptr) {
741                 if(location) {
742                     *location = g->getFactory()->createPoint(err->getCoordinate());
743                 }
744                 if(reason) {
745                     std::string errmsg(err->getMessage());
746                     *reason = gstrdup(errmsg);
747                 }
748                 return false;
749             }
750 
751             if(location) {
752                 *location = nullptr;
753             }
754             if(reason) {
755                 *reason = nullptr;
756             }
757             return true; /* valid */
758 
759         });
760     }
761 
762 //-----------------------------------------------------------------
763 // general purpose
764 //-----------------------------------------------------------------
765 
766     char
GEOSEquals_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)767     GEOSEquals_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
768     {
769         return execute(extHandle, 2, [&]() {
770             return g1->equals(g2);
771         });
772     }
773 
774     char
GEOSEqualsExact_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,double tolerance)775     GEOSEqualsExact_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double tolerance)
776     {
777         return execute(extHandle, 2, [&]() {
778             return g1->equalsExact(g2, tolerance);
779         });
780     }
781 
782     int
GEOSDistance_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,double * dist)783     GEOSDistance_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double* dist)
784     {
785         return execute(extHandle, 0, [&]() {
786             *dist = g1->distance(g2);
787             return 1;
788         });
789     }
790 
791     int
GEOSDistanceIndexed_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,double * dist)792     GEOSDistanceIndexed_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double* dist)
793     {
794         return execute(extHandle, 0, [&]() {
795             *dist = IndexedFacetDistance::distance(g1, g2);
796             return 1;
797         });
798     }
799 
800     int
GEOSHausdorffDistance_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,double * dist)801     GEOSHausdorffDistance_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double* dist)
802     {
803         return execute(extHandle, 0, [&]() {
804             *dist = DiscreteHausdorffDistance::distance(*g1, *g2);
805             return 1;
806         });
807     }
808 
809     int
GEOSHausdorffDistanceDensify_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,double densifyFrac,double * dist)810     GEOSHausdorffDistanceDensify_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2,
811                                    double densifyFrac, double* dist)
812     {
813         return execute(extHandle, 0, [&]() {
814             *dist = DiscreteHausdorffDistance::distance(*g1, *g2, densifyFrac);
815             return 1;
816         });
817     }
818 
819     int
GEOSFrechetDistance_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,double * dist)820     GEOSFrechetDistance_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double* dist)
821     {
822         return execute(extHandle, 0, [&]() {
823             *dist = DiscreteFrechetDistance::distance(*g1, *g2);
824             return 1;
825         });
826     }
827 
828     int
GEOSFrechetDistanceDensify_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,double densifyFrac,double * dist)829     GEOSFrechetDistanceDensify_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double densifyFrac,
830                                  double* dist)
831     {
832         return execute(extHandle, 0, [&]() {
833             *dist = DiscreteFrechetDistance::distance(*g1, *g2, densifyFrac);
834             return 1;
835         });
836     }
837 
838     int
GEOSArea_r(GEOSContextHandle_t extHandle,const Geometry * g,double * area)839     GEOSArea_r(GEOSContextHandle_t extHandle, const Geometry* g, double* area)
840     {
841         return execute(extHandle, 0, [&]() {
842             *area = g->getArea();
843             return 1;
844         });
845     }
846 
847     int
GEOSLength_r(GEOSContextHandle_t extHandle,const Geometry * g,double * length)848     GEOSLength_r(GEOSContextHandle_t extHandle, const Geometry* g, double* length)
849     {
850         return execute(extHandle, 0, [&]() {
851             *length = g->getLength();
852             return 1;
853         });
854     }
855 
856     CoordinateSequence*
GEOSNearestPoints_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)857     GEOSNearestPoints_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
858     {
859         return execute(extHandle, [&]() -> CoordinateSequence* {
860             if(g1->isEmpty() || g2->isEmpty()) {
861                 return nullptr;
862             }
863             return geos::operation::distance::DistanceOp::nearestPoints(g1, g2).release();
864         });
865     }
866 
867 
868     Geometry*
GEOSGeomFromWKT_r(GEOSContextHandle_t extHandle,const char * wkt)869     GEOSGeomFromWKT_r(GEOSContextHandle_t extHandle, const char* wkt)
870     {
871         return execute(extHandle, [&]() {
872             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
873 
874             const std::string wktstring(wkt);
875             WKTReader r(static_cast<GeometryFactory const*>(handle->geomFactory));
876 
877             auto g = r.read(wktstring);
878             return g.release();
879         });
880     }
881 
882     char*
GEOSGeomToWKT_r(GEOSContextHandle_t extHandle,const Geometry * g1)883     GEOSGeomToWKT_r(GEOSContextHandle_t extHandle, const Geometry* g1)
884     {
885         return execute(extHandle, [&]() {
886             char* result = gstrdup(g1->toString());
887             return result;
888         });
889     }
890 
891     // Remember to free the result!
892     unsigned char*
GEOSGeomToWKB_buf_r(GEOSContextHandle_t extHandle,const Geometry * g,size_t * size)893     GEOSGeomToWKB_buf_r(GEOSContextHandle_t extHandle, const Geometry* g, size_t* size)
894     {
895         using geos::io::WKBWriter;
896 
897         return execute(extHandle, [&]() {
898             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
899 
900             int byteOrder = handle->WKBByteOrder;
901             WKBWriter w(handle->WKBOutputDims, byteOrder);
902             std::ostringstream os(std::ios_base::binary);
903             w.write(*g, os);
904             std::string wkbstring(os.str());
905             const std::size_t len = wkbstring.length();
906 
907             unsigned char* result = static_cast<unsigned char*>(malloc(len));
908             if(result) {
909                 std::memcpy(result, wkbstring.c_str(), len);
910                 *size = len;
911             }
912             return result;
913         });
914     }
915 
916     Geometry*
GEOSGeomFromWKB_buf_r(GEOSContextHandle_t extHandle,const unsigned char * wkb,size_t size)917     GEOSGeomFromWKB_buf_r(GEOSContextHandle_t extHandle, const unsigned char* wkb, size_t size)
918     {
919         using geos::io::WKBReader;
920 
921         return execute(extHandle, [&]() {
922             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
923 
924             std::string wkbstring(reinterpret_cast<const char*>(wkb), size); // make it binary !
925             WKBReader r(*(static_cast<GeometryFactory const*>(handle->geomFactory)));
926             std::istringstream is(std::ios_base::binary);
927             is.str(wkbstring);
928             is.seekg(0, std::ios::beg); // rewind reader pointer
929             auto g = r.read(is);
930             return g.release();
931         });
932     }
933 
934     /* Read/write wkb hex values.  Returned geometries are
935        owned by the caller.*/
936     unsigned char*
GEOSGeomToHEX_buf_r(GEOSContextHandle_t extHandle,const Geometry * g,size_t * size)937     GEOSGeomToHEX_buf_r(GEOSContextHandle_t extHandle, const Geometry* g, size_t* size)
938     {
939         using geos::io::WKBWriter;
940 
941         return execute(extHandle, [&]() {
942             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
943 
944             int byteOrder = handle->WKBByteOrder;
945             WKBWriter w(handle->WKBOutputDims, byteOrder);
946             std::ostringstream os(std::ios_base::binary);
947             w.writeHEX(*g, os);
948             std::string hexstring(os.str());
949 
950             char* result = gstrdup(hexstring);
951             if(result) {
952                 *size = hexstring.length();
953             }
954 
955             return reinterpret_cast<unsigned char*>(result);
956         });
957     }
958 
959     Geometry*
GEOSGeomFromHEX_buf_r(GEOSContextHandle_t extHandle,const unsigned char * hex,size_t size)960     GEOSGeomFromHEX_buf_r(GEOSContextHandle_t extHandle, const unsigned char* hex, size_t size)
961     {
962         using geos::io::WKBReader;
963 
964         return execute(extHandle, [&]() {
965             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
966             std::string hexstring(reinterpret_cast<const char*>(hex), size);
967             WKBReader r(*(static_cast<GeometryFactory const*>(handle->geomFactory)));
968             std::istringstream is(std::ios_base::binary);
969             is.str(hexstring);
970             is.seekg(0, std::ios::beg); // rewind reader pointer
971 
972             auto g = r.readHEX(is);
973             return g.release();
974         });
975     }
976 
977     char
GEOSisEmpty_r(GEOSContextHandle_t extHandle,const Geometry * g1)978     GEOSisEmpty_r(GEOSContextHandle_t extHandle, const Geometry* g1)
979     {
980         return execute(extHandle, 2, [&]() {
981             return g1->isEmpty();
982         });
983     }
984 
985     char
GEOSisSimple_r(GEOSContextHandle_t extHandle,const Geometry * g1)986     GEOSisSimple_r(GEOSContextHandle_t extHandle, const Geometry* g1)
987     {
988         return execute(extHandle, 2, [&]() {
989             return g1->isSimple();
990         });
991     }
992 
993     char
GEOSisRing_r(GEOSContextHandle_t extHandle,const Geometry * g)994     GEOSisRing_r(GEOSContextHandle_t extHandle, const Geometry* g)
995     {
996         return execute(extHandle, 2, [&]() {
997             const LineString* ls = dynamic_cast<const LineString*>(g);
998             if(ls) {
999                 return ls->isRing();
1000             }
1001             else {
1002                 return false;
1003             }
1004         });
1005     }
1006 
1007     //free the result of this
1008     char*
GEOSGeomType_r(GEOSContextHandle_t extHandle,const Geometry * g1)1009     GEOSGeomType_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1010     {
1011         return execute(extHandle, [&]() {
1012             std::string s = g1->getGeometryType();
1013 
1014             char* result = gstrdup(s);
1015             return result;
1016         });
1017     }
1018 
1019     // Return postgis geometry type index
1020     int
GEOSGeomTypeId_r(GEOSContextHandle_t extHandle,const Geometry * g1)1021     GEOSGeomTypeId_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1022     {
1023         return execute(extHandle, -1, [&]() {
1024             return static_cast<int>(g1->getGeometryTypeId());
1025         });
1026     }
1027 
1028 //-------------------------------------------------------------------
1029 // GEOS functions that return geometries
1030 //-------------------------------------------------------------------
1031 
1032     Geometry*
GEOSEnvelope_r(GEOSContextHandle_t extHandle,const Geometry * g1)1033     GEOSEnvelope_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1034     {
1035         return execute(extHandle, [&]() {
1036             Geometry* g3 = g1->getEnvelope().release();
1037             g3->setSRID(g1->getSRID());
1038             return g3;
1039         });
1040     }
1041 
1042     Geometry*
GEOSIntersection_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)1043     GEOSIntersection_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
1044     {
1045         return execute(extHandle, [&]() {
1046             auto g3 = g1->intersection(g2);
1047             g3->setSRID(g1->getSRID());
1048             return g3.release();
1049         });
1050     }
1051 
1052     Geometry*
GEOSIntersectionPrec_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,double gridSize)1053     GEOSIntersectionPrec_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double gridSize)
1054     {
1055         return execute(extHandle, [&]() {
1056             using geos::geom::PrecisionModel;
1057 
1058             std::unique_ptr<PrecisionModel> pm;
1059             if(gridSize != 0) {
1060                 pm.reset(new PrecisionModel(1.0 / gridSize));
1061             }
1062             else {
1063                 pm.reset(new PrecisionModel());
1064             }
1065             auto g3 = gridSize != 0 ?
1066               OverlayNG::overlay(g1, g2, OverlayNG::INTERSECTION, pm.get())
1067               :
1068               OverlayNGRobust::Overlay(g1, g2, OverlayNG::INTERSECTION);
1069             g3->setSRID(g1->getSRID());
1070             return g3.release();
1071         });
1072     }
1073 
1074     Geometry*
GEOSBuffer_r(GEOSContextHandle_t extHandle,const Geometry * g1,double width,int quadrantsegments)1075     GEOSBuffer_r(GEOSContextHandle_t extHandle, const Geometry* g1, double width, int quadrantsegments)
1076     {
1077         return execute(extHandle, [&]() {
1078             auto g3 = g1->buffer(width, quadrantsegments);
1079             g3->setSRID(g1->getSRID());
1080             return g3.release();
1081         });
1082     }
1083 
1084     Geometry*
GEOSBufferWithStyle_r(GEOSContextHandle_t extHandle,const Geometry * g1,double width,int quadsegs,int endCapStyle,int joinStyle,double mitreLimit)1085     GEOSBufferWithStyle_r(GEOSContextHandle_t extHandle, const Geometry* g1, double width, int quadsegs, int endCapStyle,
1086                           int joinStyle, double mitreLimit)
1087     {
1088         using geos::operation::buffer::BufferParameters;
1089         using geos::operation::buffer::BufferOp;
1090         using geos::util::IllegalArgumentException;
1091 
1092         return execute(extHandle, [&]() {
1093             BufferParameters bp;
1094             bp.setQuadrantSegments(quadsegs);
1095 
1096             if(endCapStyle > BufferParameters::CAP_SQUARE) {
1097                 throw IllegalArgumentException("Invalid buffer endCap style");
1098             }
1099             bp.setEndCapStyle(
1100                 static_cast<BufferParameters::EndCapStyle>(endCapStyle)
1101             );
1102 
1103             if(joinStyle > BufferParameters::JOIN_BEVEL) {
1104                 throw IllegalArgumentException("Invalid buffer join style");
1105             }
1106             bp.setJoinStyle(
1107                 static_cast<BufferParameters::JoinStyle>(joinStyle)
1108             );
1109             bp.setMitreLimit(mitreLimit);
1110             BufferOp op(g1, bp);
1111             Geometry* g3 = op.getResultGeometry(width);
1112             g3->setSRID(g1->getSRID());
1113             return g3;
1114         });
1115     }
1116 
1117     Geometry*
GEOSOffsetCurve_r(GEOSContextHandle_t extHandle,const Geometry * g1,double width,int quadsegs,int joinStyle,double mitreLimit)1118     GEOSOffsetCurve_r(GEOSContextHandle_t extHandle, const Geometry* g1, double width, int quadsegs, int joinStyle,
1119                       double mitreLimit)
1120     {
1121         return execute(extHandle, [&]() {
1122             BufferParameters bp;
1123             bp.setEndCapStyle(BufferParameters::CAP_FLAT);
1124             bp.setQuadrantSegments(quadsegs);
1125 
1126             if(joinStyle > BufferParameters::JOIN_BEVEL) {
1127                 throw IllegalArgumentException("Invalid buffer join style");
1128             }
1129             bp.setJoinStyle(
1130                 static_cast<BufferParameters::JoinStyle>(joinStyle)
1131             );
1132             bp.setMitreLimit(mitreLimit);
1133 
1134             bool isLeftSide = true;
1135             if(width < 0) {
1136                 isLeftSide = false;
1137                 width = -width;
1138             }
1139             BufferBuilder bufBuilder(bp);
1140             Geometry* g3 = bufBuilder.bufferLineSingleSided(g1, width, isLeftSide);
1141             g3->setSRID(g1->getSRID());
1142             return g3;
1143         });
1144     }
1145 
1146     /* @deprecated in 3.3.0 */
1147     Geometry*
GEOSSingleSidedBuffer_r(GEOSContextHandle_t extHandle,const Geometry * g1,double width,int quadsegs,int joinStyle,double mitreLimit,int leftSide)1148     GEOSSingleSidedBuffer_r(GEOSContextHandle_t extHandle, const Geometry* g1, double width, int quadsegs, int joinStyle,
1149                             double mitreLimit, int leftSide)
1150     {
1151         return execute(extHandle, [&]() {
1152             BufferParameters bp;
1153             bp.setEndCapStyle(BufferParameters::CAP_FLAT);
1154             bp.setQuadrantSegments(quadsegs);
1155 
1156             if(joinStyle > BufferParameters::JOIN_BEVEL) {
1157                 throw IllegalArgumentException("Invalid buffer join style");
1158             }
1159             bp.setJoinStyle(
1160                 static_cast<BufferParameters::JoinStyle>(joinStyle)
1161             );
1162             bp.setMitreLimit(mitreLimit);
1163 
1164             bool isLeftSide = leftSide == 0 ? false : true;
1165             BufferBuilder bufBuilder(bp);
1166             Geometry* g3 = bufBuilder.bufferLineSingleSided(g1, width, isLeftSide);
1167             g3->setSRID(g1->getSRID());
1168             return g3;
1169         });
1170     }
1171 
1172     Geometry*
GEOSConvexHull_r(GEOSContextHandle_t extHandle,const Geometry * g1)1173     GEOSConvexHull_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1174     {
1175         return execute(extHandle, [&]() {
1176             auto g3 = g1->convexHull();
1177             g3->setSRID(g1->getSRID());
1178             return g3.release();
1179         });
1180     }
1181 
1182 
1183     Geometry*
GEOSMinimumRotatedRectangle_r(GEOSContextHandle_t extHandle,const Geometry * g)1184     GEOSMinimumRotatedRectangle_r(GEOSContextHandle_t extHandle, const Geometry* g)
1185     {
1186         return execute(extHandle, [&]() {
1187             geos::algorithm::MinimumDiameter m(g);
1188             auto g3 = m.getMinimumRectangle();
1189             g3->setSRID(g->getSRID());
1190             return g3.release();
1191         });
1192     }
1193 
1194     Geometry*
GEOSMaximumInscribedCircle_r(GEOSContextHandle_t extHandle,const Geometry * g,double tolerance)1195     GEOSMaximumInscribedCircle_r(GEOSContextHandle_t extHandle, const Geometry* g, double tolerance)
1196     {
1197         return execute(extHandle, [&]() {
1198             geos::algorithm::construct::MaximumInscribedCircle mic(g, tolerance);
1199             auto g3 = mic.getRadiusLine();
1200             g3->setSRID(g->getSRID());
1201             return g3.release();
1202         });
1203     }
1204 
1205     Geometry*
GEOSLargestEmptyCircle_r(GEOSContextHandle_t extHandle,const Geometry * g,const GEOSGeometry * boundary,double tolerance)1206     GEOSLargestEmptyCircle_r(GEOSContextHandle_t extHandle, const Geometry* g, const GEOSGeometry* boundary, double tolerance)
1207     {
1208         return execute(extHandle, [&]() {
1209             geos::algorithm::construct::LargestEmptyCircle lec(g, boundary, tolerance);
1210             auto g3 = lec.getRadiusLine();
1211             g3->setSRID(g->getSRID());
1212             return g3.release();
1213         });
1214     }
1215 
1216     Geometry*
GEOSMinimumWidth_r(GEOSContextHandle_t extHandle,const Geometry * g)1217     GEOSMinimumWidth_r(GEOSContextHandle_t extHandle, const Geometry* g)
1218     {
1219         return execute(extHandle, [&]() {
1220             geos::algorithm::MinimumDiameter m(g);
1221             auto g3 = m.getDiameter();
1222             g3->setSRID(g->getSRID());
1223             return g3.release();
1224         });
1225     }
1226 
1227     Geometry*
GEOSMinimumClearanceLine_r(GEOSContextHandle_t extHandle,const Geometry * g)1228     GEOSMinimumClearanceLine_r(GEOSContextHandle_t extHandle, const Geometry* g)
1229     {
1230         return execute(extHandle, [&]() {
1231             geos::precision::MinimumClearance mc(g);
1232             auto g3 = mc.getLine();
1233             g3->setSRID(g->getSRID());
1234             return g3.release();
1235         });
1236     }
1237 
1238     int
GEOSMinimumClearance_r(GEOSContextHandle_t extHandle,const Geometry * g,double * d)1239     GEOSMinimumClearance_r(GEOSContextHandle_t extHandle, const Geometry* g, double* d)
1240     {
1241         return execute(extHandle, 2, [&]() {
1242             geos::precision::MinimumClearance mc(g);
1243             double res = mc.getDistance();
1244             *d = res;
1245             return 0;
1246         });
1247     }
1248 
1249 
1250     Geometry*
GEOSDifference_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)1251     GEOSDifference_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
1252     {
1253         return execute(extHandle, [&]() {
1254             auto g3 = g1->difference(g2);
1255             g3->setSRID(g1->getSRID());
1256             return g3.release();
1257         });
1258     }
1259 
1260     Geometry*
GEOSDifferencePrec_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,double gridSize)1261     GEOSDifferencePrec_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double gridSize)
1262     {
1263         return execute(extHandle, [&]() {
1264 
1265             std::unique_ptr<PrecisionModel> pm;
1266             if(gridSize != 0) {
1267                 pm.reset(new PrecisionModel(1.0 / gridSize));
1268             }
1269             else {
1270                 pm.reset(new PrecisionModel());
1271             }
1272             auto g3 = gridSize != 0 ?
1273                 OverlayNG::overlay(g1, g2, OverlayNG::DIFFERENCE, pm.get())
1274                 :
1275                 OverlayNGRobust::Overlay(g1, g2, OverlayNG::DIFFERENCE);
1276             g3->setSRID(g1->getSRID());
1277             return g3.release();
1278         });
1279     }
1280 
1281     Geometry*
GEOSBoundary_r(GEOSContextHandle_t extHandle,const Geometry * g1)1282     GEOSBoundary_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1283     {
1284         return execute(extHandle, [&]() {
1285             auto g3 = g1->getBoundary();
1286             g3->setSRID(g1->getSRID());
1287             return g3.release();
1288         });
1289     }
1290 
1291     Geometry*
GEOSSymDifference_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)1292     GEOSSymDifference_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
1293     {
1294         return execute(extHandle, [&]() {
1295             auto g3 = g1->symDifference(g2);
1296             g3->setSRID(g1->getSRID());
1297             return g3.release();
1298         });
1299     }
1300 
1301     Geometry*
GEOSSymDifferencePrec_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,double gridSize)1302     GEOSSymDifferencePrec_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double gridSize)
1303     {
1304         return execute(extHandle, [&]() {
1305 
1306             std::unique_ptr<PrecisionModel> pm;
1307             if(gridSize != 0) {
1308                 pm.reset(new PrecisionModel(1.0 / gridSize));
1309             }
1310             else {
1311                 pm.reset(new PrecisionModel());
1312             }
1313             auto g3 = gridSize != 0 ?
1314               OverlayNG::overlay(g1, g2, OverlayNG::SYMDIFFERENCE, pm.get())
1315               :
1316               OverlayNGRobust::Overlay(g1, g2, OverlayNG::SYMDIFFERENCE);
1317             g3->setSRID(g1->getSRID());
1318             return g3.release();
1319         });
1320     }
1321 
1322     Geometry*
GEOSUnion_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2)1323     GEOSUnion_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
1324     {
1325         return execute(extHandle, [&]() {
1326             auto g3 = g1->Union(g2);
1327             g3->setSRID(g1->getSRID());
1328             return g3.release();
1329         });
1330     }
1331 
1332     Geometry*
GEOSUnionPrec_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * g2,double gridSize)1333     GEOSUnionPrec_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double gridSize)
1334     {
1335         return execute(extHandle, [&]() {
1336 
1337             std::unique_ptr<PrecisionModel> pm;
1338             if(gridSize != 0) {
1339                 pm.reset(new PrecisionModel(1.0 / gridSize));
1340             }
1341             else {
1342                 pm.reset(new PrecisionModel());
1343             }
1344             auto g3 = gridSize != 0 ?
1345               OverlayNG::overlay(g1, g2, OverlayNG::UNION, pm.get())
1346               :
1347               OverlayNGRobust::Overlay(g1, g2, OverlayNG::UNION);
1348             g3->setSRID(g1->getSRID());
1349             return g3.release();
1350         });
1351     }
1352 
1353     Geometry*
GEOSCoverageUnion_r(GEOSContextHandle_t extHandle,const Geometry * g)1354     GEOSCoverageUnion_r(GEOSContextHandle_t extHandle, const Geometry* g)
1355     {
1356         return execute(extHandle, [&]() {
1357             auto g3 = geos::operation::geounion::CoverageUnion::Union(g);
1358             g3->setSRID(g->getSRID());
1359             return g3.release();
1360         });
1361     }
1362 
1363     Geometry*
GEOSUnaryUnion_r(GEOSContextHandle_t extHandle,const Geometry * g)1364     GEOSUnaryUnion_r(GEOSContextHandle_t extHandle, const Geometry* g)
1365     {
1366         return execute(extHandle, [&]() {
1367             GeomPtr g3(g->Union());
1368             g3->setSRID(g->getSRID());
1369             return g3.release();
1370         });
1371     }
1372 
1373     Geometry*
GEOSUnaryUnionPrec_r(GEOSContextHandle_t extHandle,const Geometry * g1,double gridSize)1374     GEOSUnaryUnionPrec_r(GEOSContextHandle_t extHandle, const Geometry* g1, double gridSize)
1375     {
1376         return execute(extHandle, [&]() {
1377 
1378             std::unique_ptr<PrecisionModel> pm;
1379             if(gridSize != 0) {
1380                 pm.reset(new PrecisionModel(1.0 / gridSize));
1381             }
1382             else {
1383                 pm.reset(new PrecisionModel());
1384             }
1385             auto g3 = gridSize != 0 ?
1386               UnaryUnionNG::Union(g1, *pm)
1387               :
1388               OverlayNGRobust::Union(g1);
1389             g3->setSRID(g1->getSRID());
1390             return g3.release();
1391         });
1392     }
1393 
1394     Geometry*
GEOSNode_r(GEOSContextHandle_t extHandle,const Geometry * g)1395     GEOSNode_r(GEOSContextHandle_t extHandle, const Geometry* g)
1396     {
1397         return execute(extHandle, [&]() {
1398             auto g3 = geos::noding::GeometryNoder::node(*g);
1399             g3->setSRID(g->getSRID());
1400             return g3.release();
1401         });
1402     }
1403 
1404     Geometry*
GEOSUnionCascaded_r(GEOSContextHandle_t extHandle,const Geometry * g1)1405     GEOSUnionCascaded_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1406     {
1407         using geos::operation::geounion::CascadedPolygonUnion;
1408 
1409         return execute(extHandle, [&]() {
1410             const geos::geom::MultiPolygon *p = dynamic_cast<const geos::geom::MultiPolygon *>(g1);
1411 
1412             if (!p) {
1413                 throw IllegalArgumentException("Invalid argument (must be a MultiPolygon)");
1414             }
1415 
1416             Geometry* g3 = CascadedPolygonUnion::Union(p);
1417             g3->setSRID(g1->getSRID());
1418             return g3;
1419         });
1420     }
1421 
1422     Geometry*
GEOSPointOnSurface_r(GEOSContextHandle_t extHandle,const Geometry * g1)1423     GEOSPointOnSurface_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1424     {
1425         return execute(extHandle, [&]() {
1426             auto ret = g1->getInteriorPoint();
1427             if(ret == nullptr) {
1428                 const GeometryFactory* gf = g1->getFactory();
1429                 // return an empty point
1430                 ret = gf->createPoint();
1431             }
1432             ret->setSRID(g1->getSRID());
1433             return ret.release();
1434         });
1435     }
1436 
1437     Geometry*
GEOSClipByRect_r(GEOSContextHandle_t extHandle,const Geometry * g,double xmin,double ymin,double xmax,double ymax)1438     GEOSClipByRect_r(GEOSContextHandle_t extHandle, const Geometry* g, double xmin, double ymin, double xmax, double ymax)
1439     {
1440         return execute(extHandle, [&]() {
1441             using geos::operation::intersection::Rectangle;
1442             using geos::operation::intersection::RectangleIntersection;
1443             Rectangle rect(xmin, ymin, xmax, ymax);
1444             std::unique_ptr<Geometry> g3 = RectangleIntersection::clip(*g, rect);
1445             g3->setSRID(g->getSRID());
1446             return g3.release();
1447         });
1448     }
1449 
1450 //-------------------------------------------------------------------
1451 // memory management functions
1452 //------------------------------------------------------------------
1453 
1454     void
GEOSGeom_destroy_r(GEOSContextHandle_t extHandle,Geometry * a)1455     GEOSGeom_destroy_r(GEOSContextHandle_t extHandle, Geometry* a)
1456     {
1457         execute(extHandle, [&]() {
1458             // FIXME: mloskot: Does this try-catch around delete means that
1459             // destructors in GEOS may throw? If it does, this is a serious
1460             // violation of "never throw an exception from a destructor" principle
1461             delete a;
1462         });
1463     }
1464 
1465     void
GEOSGeom_setUserData_r(GEOSContextHandle_t extHandle,Geometry * g,void * userData)1466     GEOSGeom_setUserData_r(GEOSContextHandle_t extHandle, Geometry* g, void* userData)
1467     {
1468         execute(extHandle, [&]() {
1469             g->setUserData(userData);
1470         });
1471     }
1472 
1473     void
GEOSSetSRID_r(GEOSContextHandle_t extHandle,Geometry * g,int srid)1474     GEOSSetSRID_r(GEOSContextHandle_t extHandle, Geometry* g, int srid)
1475     {
1476         execute(extHandle, [&]() {
1477             g->setSRID(srid);
1478         });
1479     }
1480 
1481 
1482     int
GEOSGetNumCoordinates_r(GEOSContextHandle_t extHandle,const Geometry * g)1483     GEOSGetNumCoordinates_r(GEOSContextHandle_t extHandle, const Geometry* g)
1484     {
1485         return execute(extHandle, -1, [&]() {
1486             return static_cast<int>(g->getNumPoints());
1487         });
1488     }
1489 
1490     /*
1491      * Return -1 on exception, 0 otherwise.
1492      * Converts Geometry to normal form (or canonical form).
1493      */
1494     int
GEOSNormalize_r(GEOSContextHandle_t extHandle,Geometry * g)1495     GEOSNormalize_r(GEOSContextHandle_t extHandle, Geometry* g)
1496     {
1497         return execute(extHandle, -1, [&]() {
1498             g->normalize();
1499             return 0; // SUCCESS
1500         });
1501     }
1502 
1503     int
GEOSGetNumInteriorRings_r(GEOSContextHandle_t extHandle,const Geometry * g1)1504     GEOSGetNumInteriorRings_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1505     {
1506         return execute(extHandle, -1, [&]() {
1507             const Polygon* p = dynamic_cast<const Polygon*>(g1);
1508             if(!p) {
1509                 throw IllegalArgumentException("Argument is not a Polygon");
1510             }
1511             return static_cast<int>(p->getNumInteriorRing());
1512         });
1513     }
1514 
1515 
1516     // returns -1 on error and 1 for non-multi geometries
1517     int
GEOSGetNumGeometries_r(GEOSContextHandle_t extHandle,const Geometry * g1)1518     GEOSGetNumGeometries_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1519     {
1520         return execute(extHandle, -1, [&]() {
1521             return static_cast<int>(g1->getNumGeometries());
1522         });
1523     }
1524 
1525 
1526     /*
1527      * Call only on GEOMETRYCOLLECTION or MULTI*.
1528      * Return a pointer to the internal Geometry.
1529      */
1530     const Geometry*
GEOSGetGeometryN_r(GEOSContextHandle_t extHandle,const Geometry * g1,int n)1531     GEOSGetGeometryN_r(GEOSContextHandle_t extHandle, const Geometry* g1, int n)
1532     {
1533         return execute(extHandle, [&]() {
1534             if(n < 0) {
1535                 throw IllegalArgumentException("Index must be non-negative.");
1536             }
1537             return g1->getGeometryN(static_cast<size_t>(n));
1538         });
1539     }
1540 
1541     /*
1542      * Call only on LINESTRING
1543      * Returns NULL on exception
1544      */
1545     Geometry*
GEOSGeomGetPointN_r(GEOSContextHandle_t extHandle,const Geometry * g1,int n)1546     GEOSGeomGetPointN_r(GEOSContextHandle_t extHandle, const Geometry* g1, int n)
1547     {
1548         using geos::geom::LineString;
1549 
1550         return execute(extHandle, [&]() {
1551             const LineString* ls = dynamic_cast<const LineString*>(g1);
1552             if(!ls) {
1553                 throw IllegalArgumentException("Argument is not a LineString");
1554             }
1555             if(n < 0) {
1556                 throw IllegalArgumentException("Index must be non-negative.");
1557             }
1558             return ls->getPointN(static_cast<size_t>(n)).release();
1559         });
1560     }
1561 
1562     /*
1563      * Call only on LINESTRING
1564      */
1565     Geometry*
GEOSGeomGetStartPoint_r(GEOSContextHandle_t extHandle,const Geometry * g1)1566     GEOSGeomGetStartPoint_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1567     {
1568         using geos::geom::LineString;
1569 
1570         return execute(extHandle, [&]() {
1571             const LineString* ls = dynamic_cast<const LineString*>(g1);
1572             if(!ls) {
1573                 throw IllegalArgumentException("Argument is not a LineString");
1574             }
1575 
1576             return ls->getStartPoint().release();
1577         });
1578     }
1579 
1580     /*
1581      * Call only on LINESTRING
1582      */
1583     Geometry*
GEOSGeomGetEndPoint_r(GEOSContextHandle_t extHandle,const Geometry * g1)1584     GEOSGeomGetEndPoint_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1585     {
1586         using geos::geom::LineString;
1587 
1588         return execute(extHandle, [&]() {
1589             const LineString* ls = dynamic_cast<const LineString*>(g1);
1590             if(!ls) {
1591                 throw IllegalArgumentException("Argument is not a LineString");
1592             }
1593             return ls->getEndPoint().release();
1594         });
1595     }
1596 
1597     /*
1598      * Call only on LINESTRING or MULTILINESTRING
1599      * return 2 on exception, 1 on true, 0 on false
1600      */
1601     char
GEOSisClosed_r(GEOSContextHandle_t extHandle,const Geometry * g1)1602     GEOSisClosed_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1603     {
1604         using geos::geom::LineString;
1605         using geos::geom::MultiLineString;
1606 
1607         return execute(extHandle, 2, [&]() {
1608             const LineString* ls = dynamic_cast<const LineString*>(g1);
1609             if(ls) {
1610                 return ls->isClosed();
1611             }
1612 
1613             const MultiLineString* mls = dynamic_cast<const MultiLineString*>(g1);
1614             if(mls) {
1615                 return mls->isClosed();
1616             }
1617 
1618             throw IllegalArgumentException("Argument is not a LineString or MultiLineString");
1619         });
1620     }
1621 
1622     /*
1623      * Call only on LINESTRING
1624      * return 0 on exception, otherwise 1
1625      */
1626     int
GEOSGeomGetLength_r(GEOSContextHandle_t extHandle,const Geometry * g1,double * length)1627     GEOSGeomGetLength_r(GEOSContextHandle_t extHandle, const Geometry* g1, double* length)
1628     {
1629         using geos::geom::LineString;
1630 
1631         return execute(extHandle, 0, [&]() {
1632             const LineString* ls = dynamic_cast<const LineString*>(g1);
1633             if(!ls) {
1634                 throw IllegalArgumentException("Argument is not a LineString");
1635             }
1636             *length = ls->getLength();
1637             return 1;
1638         });
1639     }
1640 
1641     /*
1642      * Call only on LINESTRING
1643      */
1644     int
GEOSGeomGetNumPoints_r(GEOSContextHandle_t extHandle,const Geometry * g1)1645     GEOSGeomGetNumPoints_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1646     {
1647         using geos::geom::LineString;
1648 
1649         return execute(extHandle, -1, [&]() {
1650             const LineString* ls = dynamic_cast<const LineString*>(g1);
1651             if(!ls) {
1652                 throw IllegalArgumentException("Argument is not a LineString");
1653             }
1654             return static_cast<int>(ls->getNumPoints());
1655         });
1656     }
1657 
1658     /*
1659      * For POINT
1660      * returns 0 on exception, otherwise 1
1661      */
1662     int
GEOSGeomGetX_r(GEOSContextHandle_t extHandle,const Geometry * g1,double * x)1663     GEOSGeomGetX_r(GEOSContextHandle_t extHandle, const Geometry* g1, double* x)
1664     {
1665         using geos::geom::Point;
1666 
1667         return execute(extHandle, 0, [&]() {
1668             const Point* po = dynamic_cast<const Point*>(g1);
1669             if(!po) {
1670                 throw IllegalArgumentException("Argument is not a Point");
1671             }
1672             *x = po->getX();
1673             return 1;
1674         });
1675     }
1676 
1677     /*
1678      * For POINT
1679      * returns 0 on exception, otherwise 1
1680      */
1681     int
GEOSGeomGetY_r(GEOSContextHandle_t extHandle,const Geometry * g1,double * y)1682     GEOSGeomGetY_r(GEOSContextHandle_t extHandle, const Geometry* g1, double* y)
1683     {
1684         using geos::geom::Point;
1685 
1686         return execute(extHandle, 0, [&]() {
1687             const Point* po = dynamic_cast<const Point*>(g1);
1688             if(!po) {
1689                 throw IllegalArgumentException("Argument is not a Point");
1690             }
1691             *y = po->getY();
1692             return 1;
1693         });
1694     }
1695 
1696     /*
1697      * For POINT
1698      * returns 0 on exception, otherwise 1
1699      */
1700     int
GEOSGeomGetZ_r(GEOSContextHandle_t extHandle,const Geometry * g1,double * z)1701     GEOSGeomGetZ_r(GEOSContextHandle_t extHandle, const Geometry* g1, double* z)
1702     {
1703         using geos::geom::Point;
1704 
1705         return execute(extHandle, 0, [&]() {
1706             const Point* po = dynamic_cast<const Point*>(g1);
1707             if(!po) {
1708                 throw IllegalArgumentException("Argument is not a Point");
1709             }
1710             *z = po->getZ();
1711             return 1;
1712         });
1713     }
1714 
1715     /*
1716      * Call only on polygon
1717      * Return a pointer to the internal Geometry.
1718      */
1719     const Geometry*
GEOSGetExteriorRing_r(GEOSContextHandle_t extHandle,const Geometry * g1)1720     GEOSGetExteriorRing_r(GEOSContextHandle_t extHandle, const Geometry* g1)
1721     {
1722         return execute(extHandle, [&]() {
1723             const Polygon* p = dynamic_cast<const Polygon*>(g1);
1724             if(!p) {
1725                 throw IllegalArgumentException("Invalid argument (must be a Polygon)");
1726             }
1727             return p->getExteriorRing();
1728         });
1729     }
1730 
1731     /*
1732      * Call only on polygon
1733      * Return a pointer to internal storage, do not destroy it.
1734      */
1735     const Geometry*
GEOSGetInteriorRingN_r(GEOSContextHandle_t extHandle,const Geometry * g1,int n)1736     GEOSGetInteriorRingN_r(GEOSContextHandle_t extHandle, const Geometry* g1, int n)
1737     {
1738         return execute(extHandle, [&]() {
1739             const Polygon* p = dynamic_cast<const Polygon*>(g1);
1740             if(!p) {
1741                 throw IllegalArgumentException("Invalid argument (must be a Polygon)");
1742             }
1743             if(n < 0) {
1744                 throw IllegalArgumentException("Index must be non-negative.");
1745             }
1746             return p->getInteriorRingN(static_cast<size_t>(n));
1747         });
1748     }
1749 
1750     Geometry*
GEOSGetCentroid_r(GEOSContextHandle_t extHandle,const Geometry * g)1751     GEOSGetCentroid_r(GEOSContextHandle_t extHandle, const Geometry* g)
1752     {
1753         return execute(extHandle, [&]() -> Geometry* {
1754             auto ret = g->getCentroid();
1755 
1756             if(ret == nullptr) {
1757                 // TODO check if getCentroid() can really return null
1758                 const GeometryFactory* gf = g->getFactory();
1759                 ret =  gf->createPoint();
1760             }
1761             ret->setSRID(g->getSRID());
1762             return ret.release();
1763         });
1764     }
1765 
1766     Geometry*
GEOSMinimumBoundingCircle_r(GEOSContextHandle_t extHandle,const Geometry * g,double * radius,Geometry ** center)1767     GEOSMinimumBoundingCircle_r(GEOSContextHandle_t extHandle, const Geometry* g,
1768         double* radius, Geometry** center)
1769     {
1770         return execute(extHandle, [&]() -> Geometry* {
1771             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
1772 
1773             geos::algorithm::MinimumBoundingCircle mc(g);
1774             std::unique_ptr<Geometry> ret = mc.getCircle();
1775             const GeometryFactory* gf = handle->geomFactory;
1776             if(!ret) {
1777                 if (center) *center = NULL;
1778                 if (radius) *radius = 0.0;
1779                 return gf->createPolygon().release();
1780             }
1781             if (center) *center = static_cast<Geometry*>(gf->createPoint(mc.getCentre()));
1782             if (radius) *radius = mc.getRadius();
1783             ret->setSRID(g->getSRID());
1784             return ret.release();
1785         });
1786     }
1787 
1788     Geometry*
GEOSGeom_createEmptyCollection_r(GEOSContextHandle_t extHandle,int type)1789     GEOSGeom_createEmptyCollection_r(GEOSContextHandle_t extHandle, int type)
1790     {
1791         return execute(extHandle, [&]() {
1792             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
1793             const GeometryFactory* gf = handle->geomFactory;
1794 
1795             std::unique_ptr<Geometry> g = 0;
1796             switch(type) {
1797             case GEOS_GEOMETRYCOLLECTION:
1798                 g = gf->createGeometryCollection();
1799                 break;
1800             case GEOS_MULTIPOINT:
1801                 g = gf->createMultiPoint();
1802                 break;
1803             case GEOS_MULTILINESTRING:
1804                 g = gf->createMultiLineString();
1805                 break;
1806             case GEOS_MULTIPOLYGON:
1807                 g = gf->createMultiPolygon();
1808                 break;
1809             default:
1810                 throw IllegalArgumentException("Unsupported type request for GEOSGeom_createEmptyCollection_r");
1811             }
1812 
1813             return g.release();
1814         });
1815     }
1816 
1817     Geometry*
GEOSGeom_createCollection_r(GEOSContextHandle_t extHandle,int type,Geometry ** geoms,unsigned int ngeoms)1818     GEOSGeom_createCollection_r(GEOSContextHandle_t extHandle, int type, Geometry** geoms, unsigned int ngeoms)
1819     {
1820         return execute(extHandle, [&]() {
1821             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
1822 
1823             const GeometryFactory* gf = handle->geomFactory;
1824 
1825             std::vector<std::unique_ptr<Geometry>> vgeoms(ngeoms);
1826             for (size_t i = 0; i < ngeoms; i++) {
1827                 vgeoms[i].reset(geoms[i]);
1828             }
1829 
1830             std::unique_ptr<Geometry> g;
1831             switch(type) {
1832             case GEOS_GEOMETRYCOLLECTION:
1833                 g = gf->createGeometryCollection(std::move(vgeoms));
1834                 break;
1835             case GEOS_MULTIPOINT:
1836                 g = gf->createMultiPoint(std::move(vgeoms));
1837                 break;
1838             case GEOS_MULTILINESTRING:
1839                 g = gf->createMultiLineString(std::move(vgeoms));
1840                 break;
1841             case GEOS_MULTIPOLYGON:
1842                 g = gf->createMultiPolygon(std::move(vgeoms));
1843                 break;
1844             default:
1845                 handle->ERROR_MESSAGE("Unsupported type request for PostGIS2GEOS_collection");
1846             }
1847 
1848             return g.release();
1849         });
1850     }
1851 
1852     Geometry*
GEOSPolygonize_r(GEOSContextHandle_t extHandle,const Geometry * const * g,unsigned int ngeoms)1853     GEOSPolygonize_r(GEOSContextHandle_t extHandle, const Geometry* const* g, unsigned int ngeoms)
1854     {
1855         using geos::operation::polygonize::Polygonizer;
1856 
1857         return execute(extHandle, [&]() {
1858             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
1859 
1860             // Polygonize
1861             Polygonizer plgnzr;
1862             for(std::size_t i = 0; i < ngeoms; ++i) {
1863                 plgnzr.add(g[i]);
1864             }
1865 
1866             auto polys = plgnzr.getPolygons();
1867             const GeometryFactory* gf = handle->geomFactory;
1868             return gf->createGeometryCollection(std::move(polys)).release();
1869         });
1870     }
1871 
1872     Geometry*
GEOSPolygonize_valid_r(GEOSContextHandle_t extHandle,const Geometry * const * g,unsigned int ngeoms)1873     GEOSPolygonize_valid_r(GEOSContextHandle_t extHandle, const Geometry* const* g, unsigned int ngeoms)
1874     {
1875         using geos::operation::polygonize::Polygonizer;
1876 
1877         return execute(extHandle, [&]() -> Geometry* {
1878             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
1879             Geometry* out;
1880 
1881             // Polygonize
1882             Polygonizer plgnzr(true);
1883             int srid = 0;
1884             for(std::size_t i = 0; i < ngeoms; ++i) {
1885                 plgnzr.add(g[i]);
1886                 srid = g[i]->getSRID();
1887             }
1888 
1889             auto polys = plgnzr.getPolygons();
1890             if (polys.empty()) {
1891                 out = handle->geomFactory->createGeometryCollection().release();
1892             } else if (polys.size() == 1) {
1893                 return polys[0].release();
1894             } else {
1895                 return handle->geomFactory->createMultiPolygon(std::move(polys)).release();
1896             }
1897 
1898             out->setSRID(srid);
1899             return out;
1900         });
1901     }
1902 
1903     Geometry*
GEOSBuildArea_r(GEOSContextHandle_t extHandle,const Geometry * g)1904     GEOSBuildArea_r(GEOSContextHandle_t extHandle, const Geometry* g)
1905     {
1906         using geos::operation::polygonize::BuildArea;
1907 
1908         return execute(extHandle, [&]() {
1909             BuildArea builder;
1910             auto out = builder.build(g);
1911             out->setSRID(g->getSRID());
1912             return out.release();
1913         });
1914     }
1915 
1916     Geometry*
GEOSMakeValid_r(GEOSContextHandle_t extHandle,const Geometry * g)1917     GEOSMakeValid_r(GEOSContextHandle_t extHandle, const Geometry* g)
1918     {
1919         using geos::operation::valid::MakeValid;
1920 
1921         return execute(extHandle, [&]() {
1922             MakeValid makeValid;
1923             auto out = makeValid.build(g);
1924             out->setSRID(g->getSRID());
1925             return out.release();
1926         });
1927     }
1928 
1929     Geometry*
GEOSPolygonizer_getCutEdges_r(GEOSContextHandle_t extHandle,const Geometry * const * g,unsigned int ngeoms)1930     GEOSPolygonizer_getCutEdges_r(GEOSContextHandle_t extHandle, const Geometry* const* g, unsigned int ngeoms)
1931     {
1932         using geos::operation::polygonize::Polygonizer;
1933 
1934         return execute(extHandle, [&]() {
1935             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
1936             const GeometryFactory* gf = handle->geomFactory;
1937             Geometry* out;
1938 
1939             // Polygonize
1940             Polygonizer plgnzr;
1941             int srid = 0;
1942             for(std::size_t i = 0; i < ngeoms; ++i) {
1943                 plgnzr.add(g[i]);
1944                 srid = g[i]->getSRID();
1945             }
1946 
1947             const std::vector<const LineString*>& lines = plgnzr.getCutEdges();
1948 
1949             // We need a vector of Geometry pointers, not Polygon pointers.
1950             // STL vector doesn't allow transparent upcast of this
1951             // nature, so we explicitly convert.
1952             // (it's just a waste of processor and memory, btw)
1953             // XXX mloskot: See comment for GEOSPolygonize_r
1954 
1955             // TODO avoid "new" here
1956             std::vector<Geometry*>* linevec = new std::vector<Geometry*>(lines.size());
1957 
1958             for(std::size_t i = 0, n = lines.size(); i < n; ++i) {
1959                 (*linevec)[i] = lines[i]->clone().release();
1960             }
1961 
1962             // The below takes ownership of the passed vector,
1963             // so we must *not* delete it
1964 
1965             out = gf->createGeometryCollection(linevec);
1966             out->setSRID(srid);
1967 
1968             return out;
1969         });
1970     }
1971 
1972     Geometry*
GEOSPolygonize_full_r(GEOSContextHandle_t extHandle,const Geometry * g,Geometry ** cuts,Geometry ** dangles,Geometry ** invalid)1973     GEOSPolygonize_full_r(GEOSContextHandle_t extHandle, const Geometry* g,
1974                           Geometry** cuts, Geometry** dangles, Geometry** invalid)
1975     {
1976         using geos::operation::polygonize::Polygonizer;
1977 
1978         return execute(extHandle, [&]() {
1979             // Polygonize
1980             Polygonizer plgnzr;
1981             for(std::size_t i = 0; i < g->getNumGeometries(); ++i) {
1982                 plgnzr.add(g->getGeometryN(i));
1983             }
1984 
1985             const GeometryFactory* gf = g->getFactory();
1986 
1987             if(cuts) {
1988                 const std::vector<const LineString*>& lines = plgnzr.getCutEdges();
1989                 std::vector<std::unique_ptr<Geometry>> linevec(lines.size());
1990                 for(std::size_t i = 0, n = lines.size(); i < n; ++i) {
1991                     linevec[i] = lines[i]->clone();
1992                 }
1993 
1994                 *cuts = gf->createGeometryCollection(std::move(linevec)).release();
1995             }
1996 
1997             if(dangles) {
1998                 const std::vector<const LineString*>& lines = plgnzr.getDangles();
1999                 std::vector<std::unique_ptr<Geometry>> linevec(lines.size());
2000                 for(std::size_t i = 0, n = lines.size(); i < n; ++i) {
2001                     linevec[i] = lines[i]->clone();
2002                 }
2003 
2004                 *dangles = gf->createGeometryCollection(std::move(linevec)).release();
2005             }
2006 
2007             if(invalid) {
2008                 const std::vector<std::unique_ptr<LineString>>& lines = plgnzr.getInvalidRingLines();
2009                 std::vector<std::unique_ptr<Geometry>> linevec(lines.size());
2010                 for(std::size_t i = 0, n = lines.size(); i < n; ++i) {
2011                     linevec[i] = lines[i]->clone();
2012                 }
2013 
2014                 *invalid = gf->createGeometryCollection(std::move(linevec)).release();
2015             }
2016 
2017             auto polys = plgnzr.getPolygons();
2018             Geometry* out = gf->createGeometryCollection(std::move(polys)).release();
2019             out->setSRID(g->getSRID());
2020             return out;
2021         });
2022     }
2023 
2024     Geometry*
GEOSLineMerge_r(GEOSContextHandle_t extHandle,const Geometry * g)2025     GEOSLineMerge_r(GEOSContextHandle_t extHandle, const Geometry* g)
2026     {
2027         using geos::operation::linemerge::LineMerger;
2028 
2029         return execute(extHandle, [&]() {
2030             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2031             const GeometryFactory* gf = handle->geomFactory;
2032             LineMerger lmrgr;
2033             lmrgr.add(g);
2034 
2035             auto lines = lmrgr.getMergedLineStrings();
2036 
2037             auto out = gf->buildGeometry(std::move(lines));
2038             out->setSRID(g->getSRID());
2039 
2040             return out.release();
2041         });
2042     }
2043 
2044     Geometry*
GEOSReverse_r(GEOSContextHandle_t extHandle,const Geometry * g)2045     GEOSReverse_r(GEOSContextHandle_t extHandle, const Geometry* g)
2046     {
2047         return execute(extHandle, [&]() {
2048             auto g3 = g->reverse();
2049             g3->setSRID(g->getSRID());
2050             return g3.release();
2051         });
2052     }
2053 
2054     void*
GEOSGeom_getUserData_r(GEOSContextHandle_t extHandle,const Geometry * g)2055     GEOSGeom_getUserData_r(GEOSContextHandle_t extHandle, const Geometry* g)
2056     {
2057         return execute(extHandle, [&]() {
2058             return g->getUserData();
2059         });
2060     }
2061 
2062     int
GEOSGetSRID_r(GEOSContextHandle_t extHandle,const Geometry * g)2063     GEOSGetSRID_r(GEOSContextHandle_t extHandle, const Geometry* g)
2064     {
2065         return execute(extHandle, 0, [&]() {
2066             return g->getSRID();
2067         });
2068     }
2069 
GEOSversion()2070     const char* GEOSversion()
2071     {
2072         static char version[256];
2073         sprintf(version, "%s", GEOS_CAPI_VERSION);
2074         return version;
2075     }
2076 
GEOSjtsport()2077     const char* GEOSjtsport()
2078     {
2079         return GEOS_JTS_PORT;
2080     }
2081 
2082     char
GEOSHasZ_r(GEOSContextHandle_t extHandle,const Geometry * g)2083     GEOSHasZ_r(GEOSContextHandle_t extHandle, const Geometry* g)
2084     {
2085         return execute(extHandle, -1, [&]() {
2086             if(g->isEmpty()) {
2087                 return false;
2088             }
2089 
2090             double az = g->getCoordinate()->z;
2091 
2092             return std::isfinite(az);
2093         });
2094     }
2095 
2096     int
GEOS_getWKBOutputDims_r(GEOSContextHandle_t extHandle)2097     GEOS_getWKBOutputDims_r(GEOSContextHandle_t extHandle)
2098     {
2099         return execute(extHandle, -1, [&]() {
2100             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2101             return handle->WKBOutputDims;
2102         });
2103     }
2104 
2105     int
GEOS_setWKBOutputDims_r(GEOSContextHandle_t extHandle,int newdims)2106     GEOS_setWKBOutputDims_r(GEOSContextHandle_t extHandle, int newdims)
2107     {
2108         return execute(extHandle, -1, [&]() {
2109             GEOSContextHandleInternal_t *handle = reinterpret_cast<GEOSContextHandleInternal_t *>(extHandle);
2110 
2111             if (newdims < 2 || newdims > 3) {
2112                 handle->ERROR_MESSAGE("WKB output dimensions out of range 2..3");
2113             }
2114 
2115             const int olddims = handle->WKBOutputDims;
2116             handle->WKBOutputDims = newdims;
2117 
2118             return olddims;
2119         });
2120     }
2121 
2122     int
GEOS_getWKBByteOrder_r(GEOSContextHandle_t extHandle)2123     GEOS_getWKBByteOrder_r(GEOSContextHandle_t extHandle)
2124     {
2125         return execute(extHandle, -1, [&]() {
2126             GEOSContextHandleInternal_t *handle = reinterpret_cast<GEOSContextHandleInternal_t *>(extHandle);
2127             return handle->WKBByteOrder;
2128         });
2129     }
2130 
2131     int
GEOS_setWKBByteOrder_r(GEOSContextHandle_t extHandle,int byteOrder)2132     GEOS_setWKBByteOrder_r(GEOSContextHandle_t extHandle, int byteOrder)
2133     {
2134         return execute(extHandle, -1, [&]() {
2135             GEOSContextHandleInternal_t *handle = reinterpret_cast<GEOSContextHandleInternal_t *>(extHandle);
2136             const int oldByteOrder = handle->WKBByteOrder;
2137             handle->WKBByteOrder = byteOrder;
2138 
2139             return oldByteOrder;
2140         });
2141     }
2142 
2143 
2144     CoordinateSequence*
GEOSCoordSeq_create_r(GEOSContextHandle_t extHandle,unsigned int size,unsigned int dims)2145     GEOSCoordSeq_create_r(GEOSContextHandle_t extHandle, unsigned int size, unsigned int dims)
2146     {
2147         return execute(extHandle, [&]() {
2148             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2149 
2150             switch (size) {
2151                 case 1:
2152                     return static_cast<CoordinateSequence*>(new geos::geom::FixedSizeCoordinateSequence<1>(dims));
2153                 case 2:
2154                     return static_cast<CoordinateSequence*>(new geos::geom::FixedSizeCoordinateSequence<2>(dims));
2155                 default: {
2156                     const GeometryFactory *gf = handle->geomFactory;
2157                     return gf->getCoordinateSequenceFactory()->create(size, dims).release();
2158                 }
2159             }
2160         });
2161     }
2162 
2163     int
GEOSCoordSeq_setOrdinate_r(GEOSContextHandle_t extHandle,CoordinateSequence * cs,unsigned int idx,unsigned int dim,double val)2164     GEOSCoordSeq_setOrdinate_r(GEOSContextHandle_t extHandle, CoordinateSequence* cs,
2165                                unsigned int idx, unsigned int dim, double val)
2166     {
2167         return execute(extHandle, 0, [&]() {
2168             cs->setOrdinate(idx, dim, val);
2169             return 1;
2170         });
2171     }
2172 
2173     int
GEOSCoordSeq_setX_r(GEOSContextHandle_t extHandle,CoordinateSequence * s,unsigned int idx,double val)2174     GEOSCoordSeq_setX_r(GEOSContextHandle_t extHandle, CoordinateSequence* s, unsigned int idx, double val)
2175     {
2176         return GEOSCoordSeq_setOrdinate_r(extHandle, s, idx, 0, val);
2177     }
2178 
2179     int
GEOSCoordSeq_setY_r(GEOSContextHandle_t extHandle,CoordinateSequence * s,unsigned int idx,double val)2180     GEOSCoordSeq_setY_r(GEOSContextHandle_t extHandle, CoordinateSequence* s, unsigned int idx, double val)
2181     {
2182         return GEOSCoordSeq_setOrdinate_r(extHandle, s, idx, 1, val);
2183     }
2184 
2185     int
GEOSCoordSeq_setZ_r(GEOSContextHandle_t extHandle,CoordinateSequence * s,unsigned int idx,double val)2186     GEOSCoordSeq_setZ_r(GEOSContextHandle_t extHandle, CoordinateSequence* s, unsigned int idx, double val)
2187     {
2188         return GEOSCoordSeq_setOrdinate_r(extHandle, s, idx, 2, val);
2189     }
2190 
2191     int
GEOSCoordSeq_setXY_r(GEOSContextHandle_t extHandle,CoordinateSequence * cs,unsigned int idx,double x,double y)2192     GEOSCoordSeq_setXY_r(GEOSContextHandle_t extHandle, CoordinateSequence* cs, unsigned int idx, double x, double y)
2193     {
2194         return execute(extHandle, 0, [&]() {
2195             cs->setAt({x, y}, idx);
2196             return 1;
2197         });
2198     }
2199 
2200     int
GEOSCoordSeq_setXYZ_r(GEOSContextHandle_t extHandle,CoordinateSequence * cs,unsigned int idx,double x,double y,double z)2201     GEOSCoordSeq_setXYZ_r(GEOSContextHandle_t extHandle, CoordinateSequence* cs, unsigned int idx, double x, double y, double z)
2202     {
2203         return execute(extHandle, 0, [&]() {
2204             cs->setAt({x, y, z}, idx);
2205             return 1;
2206         });
2207     }
2208 
2209     CoordinateSequence*
GEOSCoordSeq_clone_r(GEOSContextHandle_t extHandle,const CoordinateSequence * cs)2210     GEOSCoordSeq_clone_r(GEOSContextHandle_t extHandle, const CoordinateSequence* cs)
2211     {
2212         return execute(extHandle, [&]() {
2213             return cs->clone().release();
2214         });
2215     }
2216 
2217     int
GEOSCoordSeq_getOrdinate_r(GEOSContextHandle_t extHandle,const CoordinateSequence * cs,unsigned int idx,unsigned int dim,double * val)2218     GEOSCoordSeq_getOrdinate_r(GEOSContextHandle_t extHandle, const CoordinateSequence* cs,
2219                                unsigned int idx, unsigned int dim, double* val)
2220     {
2221         return execute(extHandle, 0, [&]() {
2222             *val = cs->getOrdinate(idx, dim);
2223             return 1;
2224         });
2225     }
2226 
2227     int
GEOSCoordSeq_getX_r(GEOSContextHandle_t extHandle,const CoordinateSequence * s,unsigned int idx,double * val)2228     GEOSCoordSeq_getX_r(GEOSContextHandle_t extHandle, const CoordinateSequence* s, unsigned int idx, double* val)
2229     {
2230         return GEOSCoordSeq_getOrdinate_r(extHandle, s, idx, 0, val);
2231     }
2232 
2233     int
GEOSCoordSeq_getY_r(GEOSContextHandle_t extHandle,const CoordinateSequence * s,unsigned int idx,double * val)2234     GEOSCoordSeq_getY_r(GEOSContextHandle_t extHandle, const CoordinateSequence* s, unsigned int idx, double* val)
2235     {
2236         return GEOSCoordSeq_getOrdinate_r(extHandle, s, idx, 1, val);
2237     }
2238 
2239     int
GEOSCoordSeq_getZ_r(GEOSContextHandle_t extHandle,const CoordinateSequence * s,unsigned int idx,double * val)2240     GEOSCoordSeq_getZ_r(GEOSContextHandle_t extHandle, const CoordinateSequence* s, unsigned int idx, double* val)
2241     {
2242         return GEOSCoordSeq_getOrdinate_r(extHandle, s, idx, 2, val);
2243     }
2244 
2245     int
GEOSCoordSeq_getXY_r(GEOSContextHandle_t extHandle,const CoordinateSequence * cs,unsigned int idx,double * x,double * y)2246     GEOSCoordSeq_getXY_r(GEOSContextHandle_t extHandle, const CoordinateSequence* cs, unsigned int idx, double* x, double* y)
2247     {
2248         return execute(extHandle, 0, [&]() {
2249             auto& c = cs->getAt(idx);
2250             *x = c.x;
2251             *y = c.y;
2252             return 1;
2253         });
2254     }
2255 
2256     int
GEOSCoordSeq_getXYZ_r(GEOSContextHandle_t extHandle,const CoordinateSequence * cs,unsigned int idx,double * x,double * y,double * z)2257     GEOSCoordSeq_getXYZ_r(GEOSContextHandle_t extHandle, const CoordinateSequence* cs, unsigned int idx, double* x, double* y, double* z)
2258     {
2259         return execute(extHandle, 0, [&]() {
2260             auto& c = cs->getAt(idx);
2261             *x = c.x;
2262             *y = c.y;
2263             *z = c.z;
2264             return 1;
2265         });
2266     }
2267 
2268     int
GEOSCoordSeq_getSize_r(GEOSContextHandle_t extHandle,const CoordinateSequence * cs,unsigned int * size)2269     GEOSCoordSeq_getSize_r(GEOSContextHandle_t extHandle, const CoordinateSequence* cs, unsigned int* size)
2270     {
2271         return execute(extHandle, 0, [&]() {
2272             const std::size_t sz = cs->getSize();
2273             *size = static_cast<unsigned int>(sz);
2274             return 1;
2275         });
2276     }
2277 
2278     int
GEOSCoordSeq_getDimensions_r(GEOSContextHandle_t extHandle,const CoordinateSequence * cs,unsigned int * dims)2279     GEOSCoordSeq_getDimensions_r(GEOSContextHandle_t extHandle, const CoordinateSequence* cs, unsigned int* dims)
2280     {
2281         return execute(extHandle, 0, [&]() {
2282             const std::size_t dim = cs->getDimension();
2283             *dims = static_cast<unsigned int>(dim);
2284 
2285             return 1;
2286         });
2287     }
2288 
2289     int
GEOSCoordSeq_isCCW_r(GEOSContextHandle_t extHandle,const CoordinateSequence * cs,char * val)2290     GEOSCoordSeq_isCCW_r(GEOSContextHandle_t extHandle, const CoordinateSequence* cs, char* val)
2291     {
2292         return execute(extHandle, 0, [&]() {
2293             *val = geos::algorithm::Orientation::isCCW(cs);
2294             return 1;
2295         });
2296     }
2297 
2298     void
GEOSCoordSeq_destroy_r(GEOSContextHandle_t extHandle,CoordinateSequence * s)2299     GEOSCoordSeq_destroy_r(GEOSContextHandle_t extHandle, CoordinateSequence* s)
2300     {
2301         return execute(extHandle, [&]() {
2302             delete s;
2303         });
2304     }
2305 
2306     const CoordinateSequence*
GEOSGeom_getCoordSeq_r(GEOSContextHandle_t extHandle,const Geometry * g)2307     GEOSGeom_getCoordSeq_r(GEOSContextHandle_t extHandle, const Geometry* g)
2308     {
2309         using geos::geom::Point;
2310 
2311         return execute(extHandle, [&]() {
2312             const LineString* ls = dynamic_cast<const LineString*>(g);
2313             if(ls) {
2314                 return ls->getCoordinatesRO();
2315             }
2316 
2317             const Point* p = dynamic_cast<const Point*>(g);
2318             if(p) {
2319                 return p->getCoordinatesRO();
2320             }
2321 
2322             throw IllegalArgumentException("Geometry must be a Point or LineString");
2323         });
2324     }
2325 
2326     Geometry*
GEOSGeom_createEmptyPoint_r(GEOSContextHandle_t extHandle)2327     GEOSGeom_createEmptyPoint_r(GEOSContextHandle_t extHandle)
2328     {
2329         return execute(extHandle, [&]() {
2330             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2331             const GeometryFactory* gf = handle->geomFactory;
2332             return gf->createPoint().release();
2333         });
2334     }
2335 
2336     Geometry*
GEOSGeom_createPoint_r(GEOSContextHandle_t extHandle,CoordinateSequence * cs)2337     GEOSGeom_createPoint_r(GEOSContextHandle_t extHandle, CoordinateSequence* cs)
2338     {
2339         return execute(extHandle, [&]() {
2340             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2341             const GeometryFactory* gf = handle->geomFactory;
2342 
2343             return gf->createPoint(cs);
2344         });
2345     }
2346 
2347     Geometry*
GEOSGeom_createPointFromXY_r(GEOSContextHandle_t extHandle,double x,double y)2348     GEOSGeom_createPointFromXY_r(GEOSContextHandle_t extHandle, double x, double y)
2349     {
2350         return execute(extHandle, [&]() {
2351             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2352             const GeometryFactory* gf = handle->geomFactory;
2353 
2354             geos::geom::Coordinate c(x, y);
2355             return gf->createPoint(c);
2356         });
2357     }
2358 
2359     Geometry*
GEOSGeom_createLinearRing_r(GEOSContextHandle_t extHandle,CoordinateSequence * cs)2360     GEOSGeom_createLinearRing_r(GEOSContextHandle_t extHandle, CoordinateSequence* cs)
2361     {
2362         return execute(extHandle, [&]() {
2363             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2364             const GeometryFactory* gf = handle->geomFactory;
2365 
2366             return gf->createLinearRing(cs);
2367         });
2368     }
2369 
2370     Geometry*
GEOSGeom_createEmptyLineString_r(GEOSContextHandle_t extHandle)2371     GEOSGeom_createEmptyLineString_r(GEOSContextHandle_t extHandle)
2372     {
2373         return execute(extHandle, [&]() {
2374             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2375             const GeometryFactory* gf = handle->geomFactory;
2376 
2377             return gf->createLineString().release();
2378         });
2379     }
2380 
2381     Geometry*
GEOSGeom_createLineString_r(GEOSContextHandle_t extHandle,CoordinateSequence * cs)2382     GEOSGeom_createLineString_r(GEOSContextHandle_t extHandle, CoordinateSequence* cs)
2383     {
2384         return execute(extHandle, [&]() {
2385             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2386             const GeometryFactory* gf = handle->geomFactory;
2387 
2388             return gf->createLineString(cs);
2389         });
2390     }
2391 
2392     Geometry*
GEOSGeom_createEmptyPolygon_r(GEOSContextHandle_t extHandle)2393     GEOSGeom_createEmptyPolygon_r(GEOSContextHandle_t extHandle)
2394     {
2395         return execute(extHandle, [&]() {
2396             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2397             const GeometryFactory* gf = handle->geomFactory;
2398             return gf->createPolygon().release();
2399         });
2400     }
2401 
2402     Geometry*
GEOSGeom_createPolygon_r(GEOSContextHandle_t extHandle,Geometry * shell,Geometry ** holes,unsigned int nholes)2403     GEOSGeom_createPolygon_r(GEOSContextHandle_t extHandle, Geometry* shell, Geometry** holes, unsigned int nholes)
2404     {
2405         using geos::geom::LinearRing;
2406 
2407         // FIXME: holes must be non-nullptr or may be nullptr?
2408         //assert(0 != holes);
2409 
2410         return execute(extHandle, [&]() {
2411 
2412             std::vector<LinearRing*> tmpholes(nholes);
2413             for (size_t i = 0; i < nholes; i++) {
2414                 LinearRing* lr = dynamic_cast<LinearRing*>(holes[i]);
2415                 if (! lr) {
2416                     throw IllegalArgumentException("Hole is not a LinearRing");
2417                 }
2418                 tmpholes[i] = lr;
2419             }
2420             LinearRing* nshell = dynamic_cast<LinearRing*>(shell);
2421             if(! nshell) {
2422                 throw IllegalArgumentException("Shell is not a LinearRing");
2423             }
2424             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2425             const GeometryFactory* gf = handle->geomFactory;
2426 
2427             /* Create unique_ptr version for constructor */
2428             std::vector<std::unique_ptr<LinearRing>> vholes;
2429             vholes.reserve(nholes);
2430             for (LinearRing* lr: tmpholes) {
2431                 vholes.emplace_back(lr);
2432             }
2433             std::unique_ptr<LinearRing> shell(nshell);
2434 
2435             return gf->createPolygon(std::move(shell), std::move(vholes)).release();
2436         });
2437     }
2438 
2439     Geometry*
GEOSGeom_clone_r(GEOSContextHandle_t extHandle,const Geometry * g)2440     GEOSGeom_clone_r(GEOSContextHandle_t extHandle, const Geometry* g)
2441     {
2442         return execute(extHandle, [&]() {
2443             return g->clone().release();
2444         });
2445     }
2446 
2447     Geometry*
GEOSGeom_setPrecision_r(GEOSContextHandle_t extHandle,const GEOSGeometry * g,double gridSize,int flags)2448     GEOSGeom_setPrecision_r(GEOSContextHandle_t extHandle, const GEOSGeometry* g,
2449                             double gridSize, int flags)
2450     {
2451         using namespace geos::geom;
2452 
2453         return execute(extHandle, [&]() {
2454             const PrecisionModel* pm = g->getPrecisionModel();
2455             double cursize = pm->isFloating() ? 0 : 1.0 / pm->getScale();
2456             std::unique_ptr<PrecisionModel> newpm;
2457             if(gridSize != 0) {
2458                 newpm.reset(new PrecisionModel(1.0 / std::abs(gridSize)));
2459             }
2460             else {
2461                 newpm.reset(new PrecisionModel());
2462             }
2463             Geometry* ret;
2464             GeometryFactory::Ptr gf =
2465                 GeometryFactory::create(newpm.get(), g->getSRID());
2466             if(gridSize != 0 && cursize != gridSize) {
2467                 GeometryPrecisionReducer reducer(*gf);
2468                 reducer.setChangePrecisionModel(true);
2469                 reducer.setUseAreaReducer(!(flags & GEOS_PREC_NO_TOPO));
2470                 reducer.setPointwise(flags & GEOS_PREC_NO_TOPO);
2471                 reducer.setRemoveCollapsedComponents(!(flags & GEOS_PREC_KEEP_COLLAPSED));
2472                 ret = reducer.reduce(*g).release();
2473             }
2474             else {
2475                 // No need or willing to snap, just change the factory
2476                 ret = gf->createGeometry(g);
2477             }
2478             return ret;
2479         });
2480     }
2481 
2482     double
GEOSGeom_getPrecision_r(GEOSContextHandle_t extHandle,const GEOSGeometry * g)2483     GEOSGeom_getPrecision_r(GEOSContextHandle_t extHandle, const GEOSGeometry* g)
2484     {
2485         using namespace geos::geom;
2486 
2487         return execute(extHandle, -1.0, [&]() {
2488             const PrecisionModel* pm = g->getPrecisionModel();
2489             double cursize = pm->isFloating() ? 0 : 1.0 / pm->getScale();
2490             return cursize;
2491         });
2492     }
2493 
2494     int
GEOSGeom_getDimensions_r(GEOSContextHandle_t extHandle,const Geometry * g)2495     GEOSGeom_getDimensions_r(GEOSContextHandle_t extHandle, const Geometry* g)
2496     {
2497         return execute(extHandle, 0, [&]() {
2498             return (int) g->getDimension();
2499         });
2500     }
2501 
2502     int
GEOSGeom_getCoordinateDimension_r(GEOSContextHandle_t extHandle,const Geometry * g)2503     GEOSGeom_getCoordinateDimension_r(GEOSContextHandle_t extHandle, const Geometry* g)
2504     {
2505         return execute(extHandle, 0, [&]() {
2506             return (int)(g->getCoordinateDimension());
2507         });
2508     }
2509 
2510     int
GEOSGeom_getXMin_r(GEOSContextHandle_t extHandle,const Geometry * g,double * value)2511     GEOSGeom_getXMin_r(GEOSContextHandle_t extHandle, const Geometry* g, double* value)
2512     {
2513         return execute(extHandle, 0, [&]() {
2514             if(g->isEmpty()) {
2515                 return 0;
2516             }
2517 
2518             *value = g->getEnvelopeInternal()->getMinX();
2519             return 1;
2520         });
2521     }
2522 
2523     int
GEOSGeom_getXMax_r(GEOSContextHandle_t extHandle,const Geometry * g,double * value)2524     GEOSGeom_getXMax_r(GEOSContextHandle_t extHandle, const Geometry* g, double* value)
2525     {
2526         return execute(extHandle, 0, [&]() {
2527             if(g->isEmpty()) {
2528                 return 0;
2529             }
2530 
2531             *value = g->getEnvelopeInternal()->getMaxX();
2532             return 1;
2533         });
2534     }
2535 
2536     int
GEOSGeom_getYMin_r(GEOSContextHandle_t extHandle,const Geometry * g,double * value)2537     GEOSGeom_getYMin_r(GEOSContextHandle_t extHandle, const Geometry* g, double* value)
2538     {
2539         return execute(extHandle, 0, [&]() {
2540             if(g->isEmpty()) {
2541                 return 0;
2542             }
2543 
2544             *value = g->getEnvelopeInternal()->getMinY();
2545             return 1;
2546         });
2547     }
2548 
2549     int
GEOSGeom_getYMax_r(GEOSContextHandle_t extHandle,const Geometry * g,double * value)2550     GEOSGeom_getYMax_r(GEOSContextHandle_t extHandle, const Geometry* g, double* value)
2551     {
2552         return execute(extHandle, 0, [&]() {
2553             if(g->isEmpty()) {
2554                 return 0;
2555             }
2556 
2557             *value = g->getEnvelopeInternal()->getMaxY();
2558             return 1;
2559         });
2560     }
2561 
2562     Geometry*
GEOSSimplify_r(GEOSContextHandle_t extHandle,const Geometry * g1,double tolerance)2563     GEOSSimplify_r(GEOSContextHandle_t extHandle, const Geometry* g1, double tolerance)
2564     {
2565         using namespace geos::simplify;
2566 
2567         return execute(extHandle, [&]() {
2568             Geometry::Ptr g3(DouglasPeuckerSimplifier::simplify(g1, tolerance));
2569             g3->setSRID(g1->getSRID());
2570             return g3.release();
2571         });
2572     }
2573 
2574     Geometry*
GEOSTopologyPreserveSimplify_r(GEOSContextHandle_t extHandle,const Geometry * g1,double tolerance)2575     GEOSTopologyPreserveSimplify_r(GEOSContextHandle_t extHandle, const Geometry* g1, double tolerance)
2576     {
2577         using namespace geos::simplify;
2578 
2579         return execute(extHandle, [&]() {
2580             Geometry::Ptr g3(TopologyPreservingSimplifier::simplify(g1, tolerance));
2581             g3->setSRID(g1->getSRID());
2582             return g3.release();
2583         });
2584     }
2585 
2586 
2587     /* WKT Reader */
2588     WKTReader*
GEOSWKTReader_create_r(GEOSContextHandle_t extHandle)2589     GEOSWKTReader_create_r(GEOSContextHandle_t extHandle)
2590     {
2591         using geos::io::WKTReader;
2592 
2593         return execute(extHandle, [&]() {
2594             GEOSContextHandleInternal_t *handle = reinterpret_cast<GEOSContextHandleInternal_t *>(extHandle);
2595             return new WKTReader((GeometryFactory *) handle->geomFactory);
2596         });
2597     }
2598 
2599     void
GEOSWKTReader_destroy_r(GEOSContextHandle_t extHandle,WKTReader * reader)2600     GEOSWKTReader_destroy_r(GEOSContextHandle_t extHandle, WKTReader* reader)
2601     {
2602         return execute(extHandle, [&]() {
2603             delete reader;
2604         });
2605     }
2606 
2607     Geometry*
GEOSWKTReader_read_r(GEOSContextHandle_t extHandle,WKTReader * reader,const char * wkt)2608     GEOSWKTReader_read_r(GEOSContextHandle_t extHandle, WKTReader* reader, const char* wkt)
2609     {
2610         return execute(extHandle, [&]() {
2611             const std::string wktstring(wkt);
2612             return reader->read(wktstring).release();
2613         });
2614     }
2615 
2616     /* WKT Writer */
2617     WKTWriter*
GEOSWKTWriter_create_r(GEOSContextHandle_t extHandle)2618     GEOSWKTWriter_create_r(GEOSContextHandle_t extHandle)
2619     {
2620         using geos::io::WKTWriter;
2621 
2622         return execute(extHandle, [&]() {
2623             return new WKTWriter();
2624         });
2625     }
2626 
2627     void
GEOSWKTWriter_destroy_r(GEOSContextHandle_t extHandle,WKTWriter * Writer)2628     GEOSWKTWriter_destroy_r(GEOSContextHandle_t extHandle, WKTWriter* Writer)
2629     {
2630         execute(extHandle, [&]() {
2631             delete Writer;
2632         });
2633     }
2634 
2635 
2636     char*
GEOSWKTWriter_write_r(GEOSContextHandle_t extHandle,WKTWriter * writer,const Geometry * geom)2637     GEOSWKTWriter_write_r(GEOSContextHandle_t extHandle, WKTWriter* writer, const Geometry* geom)
2638     {
2639         return execute(extHandle, [&]() {
2640             std::string sgeom(writer->write(geom));
2641             char* result = gstrdup(sgeom);
2642             return result;
2643         });
2644     }
2645 
2646     void
GEOSWKTWriter_setTrim_r(GEOSContextHandle_t extHandle,WKTWriter * writer,char trim)2647     GEOSWKTWriter_setTrim_r(GEOSContextHandle_t extHandle, WKTWriter* writer, char trim)
2648     {
2649         execute(extHandle, [&]() {
2650             writer->setTrim(0 != trim);
2651         });
2652     }
2653 
2654     void
GEOSWKTWriter_setRoundingPrecision_r(GEOSContextHandle_t extHandle,WKTWriter * writer,int precision)2655     GEOSWKTWriter_setRoundingPrecision_r(GEOSContextHandle_t extHandle, WKTWriter* writer, int precision)
2656     {
2657         execute(extHandle, [&]() {
2658             writer->setRoundingPrecision(precision);
2659         });
2660     }
2661 
2662     void
GEOSWKTWriter_setOutputDimension_r(GEOSContextHandle_t extHandle,WKTWriter * writer,int dim)2663     GEOSWKTWriter_setOutputDimension_r(GEOSContextHandle_t extHandle, WKTWriter* writer, int dim)
2664     {
2665         execute(extHandle, [&]() {
2666             writer->setOutputDimension(dim);
2667         });
2668     }
2669 
2670     int
GEOSWKTWriter_getOutputDimension_r(GEOSContextHandle_t extHandle,WKTWriter * writer)2671     GEOSWKTWriter_getOutputDimension_r(GEOSContextHandle_t extHandle, WKTWriter* writer)
2672     {
2673         return execute(extHandle, -1, [&]() {
2674             return writer->getOutputDimension();
2675         });
2676     }
2677 
2678     void
GEOSWKTWriter_setOld3D_r(GEOSContextHandle_t extHandle,WKTWriter * writer,int useOld3D)2679     GEOSWKTWriter_setOld3D_r(GEOSContextHandle_t extHandle, WKTWriter* writer, int useOld3D)
2680     {
2681         execute(extHandle, [&]() {
2682             writer->setOld3D(0 != useOld3D);
2683         });
2684     }
2685 
2686     /* WKB Reader */
2687     WKBReader*
GEOSWKBReader_create_r(GEOSContextHandle_t extHandle)2688     GEOSWKBReader_create_r(GEOSContextHandle_t extHandle)
2689     {
2690         using geos::io::WKBReader;
2691 
2692         return execute(extHandle, [&]() {
2693             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
2694             return new WKBReader(*(GeometryFactory*)handle->geomFactory);
2695         });
2696     }
2697 
2698     void
GEOSWKBReader_destroy_r(GEOSContextHandle_t extHandle,WKBReader * reader)2699     GEOSWKBReader_destroy_r(GEOSContextHandle_t extHandle, WKBReader* reader)
2700     {
2701         execute(extHandle, [&]() {
2702             delete reader;
2703         });
2704     }
2705 
2706     struct membuf : public std::streambuf {
membufmembuf2707         membuf(char* s, std::size_t n)
2708         {
2709             setg(s, s, s + n);
2710         }
2711     };
2712 
2713     Geometry*
GEOSWKBReader_read_r(GEOSContextHandle_t extHandle,WKBReader * reader,const unsigned char * wkb,size_t size)2714     GEOSWKBReader_read_r(GEOSContextHandle_t extHandle, WKBReader* reader, const unsigned char* wkb, size_t size)
2715     {
2716         return execute(extHandle, [&]() {
2717             // http://stackoverflow.com/questions/2079912/simpler-way-to-create-a-c-memorystream-from-char-size-t-without-copying-t
2718             membuf mb((char*)wkb, size);
2719             istream is(&mb);
2720 
2721             return reader->read(is).release();
2722         });
2723     }
2724 
2725     Geometry*
GEOSWKBReader_readHEX_r(GEOSContextHandle_t extHandle,WKBReader * reader,const unsigned char * hex,size_t size)2726     GEOSWKBReader_readHEX_r(GEOSContextHandle_t extHandle, WKBReader* reader, const unsigned char* hex, size_t size)
2727     {
2728         return execute(extHandle, [&]() {
2729             std::string hexstring(reinterpret_cast<const char*>(hex), size);
2730             std::istringstream is(std::ios_base::binary);
2731             is.str(hexstring);
2732             is.seekg(0, std::ios::beg); // rewind reader pointer
2733 
2734             return reader->readHEX(is).release();
2735         });
2736     }
2737 
2738     /* WKB Writer */
2739     WKBWriter*
GEOSWKBWriter_create_r(GEOSContextHandle_t extHandle)2740     GEOSWKBWriter_create_r(GEOSContextHandle_t extHandle)
2741     {
2742         using geos::io::WKBWriter;
2743 
2744         return execute(extHandle, [&]() {
2745             return new WKBWriter();
2746         });
2747     }
2748 
2749     void
GEOSWKBWriter_destroy_r(GEOSContextHandle_t extHandle,WKBWriter * Writer)2750     GEOSWKBWriter_destroy_r(GEOSContextHandle_t extHandle, WKBWriter* Writer)
2751     {
2752         execute(extHandle, [&]() {
2753             delete Writer;
2754         });
2755     }
2756 
2757 
2758     /* The caller owns the result */
2759     unsigned char*
GEOSWKBWriter_write_r(GEOSContextHandle_t extHandle,WKBWriter * writer,const Geometry * geom,size_t * size)2760     GEOSWKBWriter_write_r(GEOSContextHandle_t extHandle, WKBWriter* writer, const Geometry* geom, size_t* size)
2761     {
2762         return execute(extHandle, [&]() {
2763             std::ostringstream os(std::ios_base::binary);
2764             writer->write(*geom, os);
2765 
2766             const std::string& wkbstring = os.str();
2767             const std::size_t len = wkbstring.length();
2768 
2769             unsigned char* result = (unsigned char*) malloc(len);
2770             std::memcpy(result, wkbstring.c_str(), len);
2771             *size = len;
2772             return result;
2773         });
2774     }
2775 
2776     /* The caller owns the result */
2777     unsigned char*
GEOSWKBWriter_writeHEX_r(GEOSContextHandle_t extHandle,WKBWriter * writer,const Geometry * geom,size_t * size)2778     GEOSWKBWriter_writeHEX_r(GEOSContextHandle_t extHandle, WKBWriter* writer, const Geometry* geom, size_t* size)
2779     {
2780         return execute(extHandle, [&]() {
2781             std::ostringstream os(std::ios_base::binary);
2782             writer->writeHEX(*geom, os);
2783             std::string wkbstring(os.str());
2784             const std::size_t len = wkbstring.length();
2785 
2786             unsigned char* result = (unsigned char*) malloc(len);
2787             std::memcpy(result, wkbstring.c_str(), len);
2788             *size = len;
2789             return result;
2790         });
2791     }
2792 
2793     int
GEOSWKBWriter_getOutputDimension_r(GEOSContextHandle_t extHandle,const GEOSWKBWriter * writer)2794     GEOSWKBWriter_getOutputDimension_r(GEOSContextHandle_t extHandle, const GEOSWKBWriter* writer)
2795     {
2796         return execute(extHandle, 0, [&]() {
2797             return writer->getOutputDimension();
2798         });
2799     }
2800 
2801     void
GEOSWKBWriter_setOutputDimension_r(GEOSContextHandle_t extHandle,GEOSWKBWriter * writer,int newDimension)2802     GEOSWKBWriter_setOutputDimension_r(GEOSContextHandle_t extHandle, GEOSWKBWriter* writer, int newDimension)
2803     {
2804         execute(extHandle, [&]() {
2805             writer->setOutputDimension(newDimension);
2806         });
2807     }
2808 
2809     int
GEOSWKBWriter_getByteOrder_r(GEOSContextHandle_t extHandle,const GEOSWKBWriter * writer)2810     GEOSWKBWriter_getByteOrder_r(GEOSContextHandle_t extHandle, const GEOSWKBWriter* writer)
2811     {
2812         return execute(extHandle, 0, [&]() {
2813             return writer->getByteOrder();
2814         });
2815     }
2816 
2817     void
GEOSWKBWriter_setByteOrder_r(GEOSContextHandle_t extHandle,GEOSWKBWriter * writer,int newByteOrder)2818     GEOSWKBWriter_setByteOrder_r(GEOSContextHandle_t extHandle, GEOSWKBWriter* writer, int newByteOrder)
2819     {
2820         execute(extHandle, [&]() {
2821             writer->setByteOrder(newByteOrder);
2822         });
2823     }
2824 
2825     char
GEOSWKBWriter_getIncludeSRID_r(GEOSContextHandle_t extHandle,const GEOSWKBWriter * writer)2826     GEOSWKBWriter_getIncludeSRID_r(GEOSContextHandle_t extHandle, const GEOSWKBWriter* writer)
2827     {
2828         return execute(extHandle, -1, [&]{
2829             return writer->getIncludeSRID();
2830         });
2831     }
2832 
2833     void
GEOSWKBWriter_setIncludeSRID_r(GEOSContextHandle_t extHandle,GEOSWKBWriter * writer,const char newIncludeSRID)2834     GEOSWKBWriter_setIncludeSRID_r(GEOSContextHandle_t extHandle, GEOSWKBWriter* writer, const char newIncludeSRID)
2835     {
2836         execute(extHandle, [&]{
2837             writer->setIncludeSRID(newIncludeSRID);
2838         });
2839     }
2840 
2841 
2842 //-----------------------------------------------------------------
2843 // Prepared Geometry
2844 //-----------------------------------------------------------------
2845 
2846     const geos::geom::prep::PreparedGeometry*
GEOSPrepare_r(GEOSContextHandle_t extHandle,const Geometry * g)2847     GEOSPrepare_r(GEOSContextHandle_t extHandle, const Geometry* g)
2848     {
2849         return execute(extHandle, [&]() {
2850             return geos::geom::prep::PreparedGeometryFactory::prepare(g).release();
2851         });
2852     }
2853 
2854     void
GEOSPreparedGeom_destroy_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * a)2855     GEOSPreparedGeom_destroy_r(GEOSContextHandle_t extHandle, const geos::geom::prep::PreparedGeometry* a)
2856     {
2857         execute(extHandle, [&]() {
2858             delete a;
2859         });
2860     }
2861 
2862     char
GEOSPreparedContains_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g)2863     GEOSPreparedContains_r(GEOSContextHandle_t extHandle,
2864                            const geos::geom::prep::PreparedGeometry* pg, const Geometry* g)
2865     {
2866         return execute(extHandle, 2, [&]() {
2867             return pg->contains(g);
2868         });
2869     }
2870 
2871     char
GEOSPreparedContainsProperly_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g)2872     GEOSPreparedContainsProperly_r(GEOSContextHandle_t extHandle,
2873                                    const geos::geom::prep::PreparedGeometry* pg, const Geometry* g)
2874     {
2875         return execute(extHandle, 2, [&]() {
2876             return pg->containsProperly(g);
2877         });
2878     }
2879 
2880     char
GEOSPreparedCoveredBy_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g)2881     GEOSPreparedCoveredBy_r(GEOSContextHandle_t extHandle,
2882                             const geos::geom::prep::PreparedGeometry* pg, const Geometry* g)
2883     {
2884         return execute(extHandle, 2, [&]() {
2885             return pg->coveredBy(g);
2886         });
2887     }
2888 
2889     char
GEOSPreparedCovers_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g)2890     GEOSPreparedCovers_r(GEOSContextHandle_t extHandle,
2891                          const geos::geom::prep::PreparedGeometry* pg, const Geometry* g)
2892     {
2893         return execute(extHandle, 2, [&]() {
2894             return pg->covers(g);
2895         });
2896     }
2897 
2898     char
GEOSPreparedCrosses_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g)2899     GEOSPreparedCrosses_r(GEOSContextHandle_t extHandle,
2900                           const geos::geom::prep::PreparedGeometry* pg, const Geometry* g)
2901     {
2902         return execute(extHandle, 2, [&]() {
2903             return pg->crosses(g);
2904         });
2905     }
2906 
2907     char
GEOSPreparedDisjoint_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g)2908     GEOSPreparedDisjoint_r(GEOSContextHandle_t extHandle,
2909                            const geos::geom::prep::PreparedGeometry* pg, const Geometry* g)
2910     {
2911         return execute(extHandle, 2, [&]() {
2912             return pg->disjoint(g);
2913         });
2914     }
2915 
2916     char
GEOSPreparedIntersects_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g)2917     GEOSPreparedIntersects_r(GEOSContextHandle_t extHandle,
2918                              const geos::geom::prep::PreparedGeometry* pg, const Geometry* g)
2919     {
2920         return execute(extHandle, 2, [&]() {
2921             return pg->intersects(g);
2922         });
2923     }
2924 
2925     char
GEOSPreparedOverlaps_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g)2926     GEOSPreparedOverlaps_r(GEOSContextHandle_t extHandle,
2927                            const geos::geom::prep::PreparedGeometry* pg, const Geometry* g)
2928     {
2929         return execute(extHandle, 2, [&]() {
2930             return pg->overlaps(g);
2931         });
2932     }
2933 
2934     char
GEOSPreparedTouches_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g)2935     GEOSPreparedTouches_r(GEOSContextHandle_t extHandle,
2936                           const geos::geom::prep::PreparedGeometry* pg, const Geometry* g)
2937     {
2938         return execute(extHandle, 2, [&]() {
2939             return pg->touches(g);
2940         });
2941     }
2942 
2943     char
GEOSPreparedWithin_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g)2944     GEOSPreparedWithin_r(GEOSContextHandle_t extHandle,
2945                          const geos::geom::prep::PreparedGeometry* pg, const Geometry* g)
2946     {
2947         return execute(extHandle, 2, [&]() {
2948             return pg->within(g);
2949         });
2950     }
2951 
2952     CoordinateSequence*
GEOSPreparedNearestPoints_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g)2953     GEOSPreparedNearestPoints_r(GEOSContextHandle_t extHandle,
2954                          const geos::geom::prep::PreparedGeometry* pg, const Geometry* g)
2955     {
2956         using namespace geos::geom;
2957 
2958         return execute(extHandle, [&]() -> CoordinateSequence* {
2959             return pg->nearestPoints(g).release();
2960         });
2961     }
2962 
2963     int
GEOSPreparedDistance_r(GEOSContextHandle_t extHandle,const geos::geom::prep::PreparedGeometry * pg,const Geometry * g,double * dist)2964     GEOSPreparedDistance_r(GEOSContextHandle_t extHandle,
2965                          const geos::geom::prep::PreparedGeometry* pg,
2966                          const Geometry* g, double* dist)
2967     {
2968         return execute(extHandle, 0, [&]() {
2969             *dist = pg->distance(g);
2970             return 1;
2971         });
2972     }
2973 
2974 //-----------------------------------------------------------------
2975 // STRtree
2976 //-----------------------------------------------------------------
2977 
2978     GEOSSTRtree*
GEOSSTRtree_create_r(GEOSContextHandle_t extHandle,size_t nodeCapacity)2979     GEOSSTRtree_create_r(GEOSContextHandle_t extHandle,
2980                          size_t nodeCapacity)
2981     {
2982         return execute(extHandle, [&]() {
2983             return new GEOSSTRtree(nodeCapacity);
2984         });
2985     }
2986 
2987     void
GEOSSTRtree_insert_r(GEOSContextHandle_t extHandle,GEOSSTRtree * tree,const geos::geom::Geometry * g,void * item)2988     GEOSSTRtree_insert_r(GEOSContextHandle_t extHandle,
2989                          GEOSSTRtree* tree,
2990                          const geos::geom::Geometry* g,
2991                          void* item)
2992     {
2993         execute(extHandle, [&]() {
2994             tree->insert(g->getEnvelopeInternal(), item);
2995         });
2996     }
2997 
2998     void
GEOSSTRtree_query_r(GEOSContextHandle_t extHandle,GEOSSTRtree * tree,const geos::geom::Geometry * g,GEOSQueryCallback callback,void * userdata)2999     GEOSSTRtree_query_r(GEOSContextHandle_t extHandle,
3000                         GEOSSTRtree* tree,
3001                         const geos::geom::Geometry* g,
3002                         GEOSQueryCallback callback,
3003                         void* userdata)
3004     {
3005         execute(extHandle, [&]() {
3006             CAPI_ItemVisitor visitor(callback, userdata);
3007             tree->query(g->getEnvelopeInternal(), visitor);
3008         });
3009     }
3010 
3011     const GEOSGeometry*
GEOSSTRtree_nearest_r(GEOSContextHandle_t extHandle,GEOSSTRtree * tree,const geos::geom::Geometry * geom)3012     GEOSSTRtree_nearest_r(GEOSContextHandle_t extHandle,
3013                           GEOSSTRtree* tree,
3014                           const geos::geom::Geometry* geom)
3015     {
3016         return (const GEOSGeometry*) GEOSSTRtree_nearest_generic_r(extHandle, tree, geom, geom, nullptr, nullptr);
3017     }
3018 
3019     const void*
GEOSSTRtree_nearest_generic_r(GEOSContextHandle_t extHandle,GEOSSTRtree * tree,const void * item,const geos::geom::Geometry * itemEnvelope,GEOSDistanceCallback distancefn,void * userdata)3020     GEOSSTRtree_nearest_generic_r(GEOSContextHandle_t extHandle,
3021                                   GEOSSTRtree* tree,
3022                                   const void* item,
3023                                   const geos::geom::Geometry* itemEnvelope,
3024                                   GEOSDistanceCallback distancefn,
3025                                   void* userdata)
3026     {
3027         using namespace geos::index::strtree;
3028 
3029         struct CustomItemDistance : public ItemDistance {
3030             CustomItemDistance(GEOSDistanceCallback p_distancefn, void* p_userdata)
3031                 : m_distancefn(p_distancefn), m_userdata(p_userdata) {}
3032 
3033             GEOSDistanceCallback m_distancefn;
3034             void* m_userdata;
3035 
3036             double
3037             distance(const ItemBoundable* item1, const ItemBoundable* item2) override
3038             {
3039                 const void* a = item1->getItem();
3040                 const void* b = item2->getItem();
3041                 double d;
3042 
3043                 if(!m_distancefn(a, b, &d, m_userdata)) {
3044                     throw std::runtime_error(std::string("Failed to compute distance."));
3045                 }
3046 
3047                 return d;
3048             }
3049         };
3050 
3051         return execute(extHandle, [&]() {
3052             if(distancefn) {
3053                 CustomItemDistance itemDistance(distancefn, userdata);
3054                 return tree->nearestNeighbour(itemEnvelope->getEnvelopeInternal(), item, &itemDistance);
3055             }
3056             else {
3057                 GeometryItemDistance itemDistance = GeometryItemDistance();
3058                 return tree->nearestNeighbour(itemEnvelope->getEnvelopeInternal(), item, &itemDistance);
3059             }
3060         });
3061     }
3062 
3063     void
GEOSSTRtree_iterate_r(GEOSContextHandle_t extHandle,GEOSSTRtree * tree,GEOSQueryCallback callback,void * userdata)3064     GEOSSTRtree_iterate_r(GEOSContextHandle_t extHandle,
3065                           GEOSSTRtree* tree,
3066                           GEOSQueryCallback callback,
3067                           void* userdata)
3068     {
3069         return execute(extHandle, [&]() {
3070             CAPI_ItemVisitor visitor(callback, userdata);
3071             tree->iterate(visitor);
3072         });
3073     }
3074 
3075     char
GEOSSTRtree_remove_r(GEOSContextHandle_t extHandle,GEOSSTRtree * tree,const geos::geom::Geometry * g,void * item)3076     GEOSSTRtree_remove_r(GEOSContextHandle_t extHandle,
3077                          GEOSSTRtree* tree,
3078                          const geos::geom::Geometry* g,
3079                          void* item) {
3080         return execute(extHandle, 2, [&]() {
3081             return tree->remove(g->getEnvelopeInternal(), item);
3082         });
3083     }
3084 
3085     void
GEOSSTRtree_destroy_r(GEOSContextHandle_t extHandle,GEOSSTRtree * tree)3086     GEOSSTRtree_destroy_r(GEOSContextHandle_t extHandle,
3087                           GEOSSTRtree* tree)
3088     {
3089         return execute(extHandle, [&]() {
3090             delete tree;
3091         });
3092     }
3093 
3094     double
GEOSProject_r(GEOSContextHandle_t extHandle,const Geometry * g,const Geometry * p)3095     GEOSProject_r(GEOSContextHandle_t extHandle,
3096                   const Geometry* g,
3097                   const Geometry* p)
3098     {
3099         return execute(extHandle, -1.0, [&]() {
3100             const geos::geom::Point* point = dynamic_cast<const geos::geom::Point*>(p);
3101             if(!point) {
3102                 throw std::runtime_error("third argument of GEOSProject_r must be Point");
3103             }
3104             const geos::geom::Coordinate* inputPt = p->getCoordinate();
3105             return geos::linearref::LengthIndexedLine(g).project(*inputPt);
3106         });
3107     }
3108 
3109 
3110     Geometry*
GEOSInterpolate_r(GEOSContextHandle_t extHandle,const Geometry * g,double d)3111     GEOSInterpolate_r(GEOSContextHandle_t extHandle, const Geometry* g, double d)
3112     {
3113         return execute(extHandle, [&]() {
3114             GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
3115 
3116             geos::linearref::LengthIndexedLine lil(g);
3117             geos::geom::Coordinate coord = lil.extractPoint(d);
3118             const GeometryFactory* gf = handle->geomFactory;
3119             Geometry* point = gf->createPoint(coord);
3120             point->setSRID(g->getSRID());
3121             return point;
3122         });
3123     }
3124 
3125 
3126     double
GEOSProjectNormalized_r(GEOSContextHandle_t extHandle,const Geometry * g,const Geometry * p)3127     GEOSProjectNormalized_r(GEOSContextHandle_t extHandle, const Geometry* g,
3128                             const Geometry* p)
3129     {
3130 
3131         double length;
3132         double distance;
3133         if(GEOSLength_r(extHandle, g, &length) != 1) {
3134             return -1.0;
3135         };
3136         distance = GEOSProject_r(extHandle, g, p);
3137         if (distance == -1.0) {
3138             return -1.0;
3139         } else {
3140             return distance / length;
3141         }
3142     }
3143 
3144 
3145     Geometry*
GEOSInterpolateNormalized_r(GEOSContextHandle_t extHandle,const Geometry * g,double d)3146     GEOSInterpolateNormalized_r(GEOSContextHandle_t extHandle, const Geometry* g,
3147                                 double d)
3148     {
3149         double length;
3150         if (GEOSLength_r(extHandle, g, &length) != 1) {
3151             return 0;
3152         }
3153         return GEOSInterpolate_r(extHandle, g, d * length);
3154     }
3155 
3156     GEOSGeometry*
GEOSGeom_extractUniquePoints_r(GEOSContextHandle_t extHandle,const GEOSGeometry * g)3157     GEOSGeom_extractUniquePoints_r(GEOSContextHandle_t extHandle,
3158                                    const GEOSGeometry* g)
3159     {
3160         using namespace geos::geom;
3161         using namespace geos::util;
3162 
3163         return execute(extHandle, [&]() {
3164             /* 1: extract points */
3165             std::vector<const Coordinate*> coords;
3166             UniqueCoordinateArrayFilter filter(coords);
3167             g->apply_ro(&filter);
3168 
3169             /* 2: for each point, create a geometry and put into a vector */
3170             std::vector<Geometry*>* points = new std::vector<Geometry*>();
3171             points->reserve(coords.size());
3172             const GeometryFactory* factory = g->getFactory();
3173             for(std::vector<const Coordinate*>::iterator it = coords.begin(),
3174                     itE = coords.end();
3175                     it != itE; ++it) {
3176                 Geometry* point = factory->createPoint(*(*it));
3177                 points->push_back(point);
3178             }
3179 
3180             /* 3: create a multipoint */
3181             Geometry* out = factory->createMultiPoint(points);
3182             out->setSRID(g->getSRID());
3183             return out;
3184 
3185         });
3186     }
3187 
GEOSOrientationIndex_r(GEOSContextHandle_t extHandle,double Ax,double Ay,double Bx,double By,double Px,double Py)3188     int GEOSOrientationIndex_r(GEOSContextHandle_t extHandle,
3189                                double Ax, double Ay, double Bx, double By, double Px, double Py)
3190     {
3191         using geos::geom::Coordinate;
3192         using geos::algorithm::Orientation;
3193 
3194         return execute(extHandle, 2, [&]() {
3195             Coordinate A(Ax, Ay);
3196             Coordinate B(Bx, By);
3197             Coordinate P(Px, Py);
3198             return Orientation::index(A, B, P);
3199         });
3200     }
3201 
3202     GEOSGeometry*
GEOSSharedPaths_r(GEOSContextHandle_t extHandle,const GEOSGeometry * g1,const GEOSGeometry * g2)3203     GEOSSharedPaths_r(GEOSContextHandle_t extHandle, const GEOSGeometry* g1, const GEOSGeometry* g2)
3204     {
3205         using namespace geos::operation::sharedpaths;
3206 
3207         if(nullptr == extHandle) {
3208             return nullptr;
3209         }
3210         GEOSContextHandleInternal_t* handle =
3211             reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
3212         if(handle->initialized == 0) {
3213             return nullptr;
3214         }
3215 
3216         SharedPathsOp::PathList forw, back;
3217         try {
3218             SharedPathsOp::sharedPathsOp(*g1, *g2, forw, back);
3219         }
3220         catch(const std::exception& e) {
3221             SharedPathsOp::clearEdges(forw);
3222             SharedPathsOp::clearEdges(back);
3223             handle->ERROR_MESSAGE("%s", e.what());
3224             return nullptr;
3225         }
3226         catch(...) {
3227             SharedPathsOp::clearEdges(forw);
3228             SharedPathsOp::clearEdges(back);
3229             handle->ERROR_MESSAGE("Unknown exception thrown");
3230             return nullptr;
3231         }
3232 
3233         // Now forw and back have the geoms we want to use to construct
3234         // our output GeometryCollections...
3235 
3236         const GeometryFactory* factory = g1->getFactory();
3237         size_t count;
3238 
3239         std::unique_ptr< std::vector<Geometry*> > out1(
3240             new std::vector<Geometry*>()
3241         );
3242         count = forw.size();
3243         out1->reserve(count);
3244         for(size_t i = 0; i < count; ++i) {
3245             out1->push_back(forw[i]);
3246         }
3247         std::unique_ptr<Geometry> out1g(
3248             factory->createMultiLineString(out1.release())
3249         );
3250 
3251         std::unique_ptr< std::vector<Geometry*> > out2(
3252             new std::vector<Geometry*>()
3253         );
3254         count = back.size();
3255         out2->reserve(count);
3256         for(size_t i = 0; i < count; ++i) {
3257             out2->push_back(back[i]);
3258         }
3259         std::unique_ptr<Geometry> out2g(
3260             factory->createMultiLineString(out2.release())
3261         );
3262 
3263         std::unique_ptr< std::vector<Geometry*> > out(
3264             new std::vector<Geometry*>()
3265         );
3266         out->reserve(2);
3267         out->push_back(out1g.release());
3268         out->push_back(out2g.release());
3269 
3270         std::unique_ptr<Geometry> outg(
3271             factory->createGeometryCollection(out.release())
3272         );
3273 
3274         outg->setSRID(g1->getSRID());
3275         return outg.release();
3276     }
3277 
3278     GEOSGeometry*
GEOSSnap_r(GEOSContextHandle_t extHandle,const GEOSGeometry * g1,const GEOSGeometry * g2,double tolerance)3279     GEOSSnap_r(GEOSContextHandle_t extHandle, const GEOSGeometry* g1,
3280                const GEOSGeometry* g2, double tolerance)
3281     {
3282         using namespace geos::operation::overlay::snap;
3283 
3284         return execute(extHandle, [&]() {
3285             GeometrySnapper snapper(*g1);
3286             std::unique_ptr<Geometry> ret = snapper.snapTo(*g2, tolerance);
3287             ret->setSRID(g1->getSRID());
3288             return ret.release();
3289         });
3290     }
3291 
3292     BufferParameters*
GEOSBufferParams_create_r(GEOSContextHandle_t extHandle)3293     GEOSBufferParams_create_r(GEOSContextHandle_t extHandle)
3294     {
3295         return execute(extHandle, [&]() {
3296             return new BufferParameters();
3297         });
3298     }
3299 
3300     void
GEOSBufferParams_destroy_r(GEOSContextHandle_t extHandle,BufferParameters * p)3301     GEOSBufferParams_destroy_r(GEOSContextHandle_t extHandle, BufferParameters* p)
3302     {
3303         (void)extHandle;
3304         delete p;
3305     }
3306 
3307     int
GEOSBufferParams_setEndCapStyle_r(GEOSContextHandle_t extHandle,GEOSBufferParams * p,int style)3308     GEOSBufferParams_setEndCapStyle_r(GEOSContextHandle_t extHandle,
3309                                       GEOSBufferParams* p, int style)
3310     {
3311         return execute(extHandle, 0, [&]() {
3312             if(style > BufferParameters::CAP_SQUARE) {
3313                 throw IllegalArgumentException("Invalid buffer endCap style");
3314             }
3315             p->setEndCapStyle(static_cast<BufferParameters::EndCapStyle>(style));
3316             return 1;
3317         });
3318     }
3319 
3320     int
GEOSBufferParams_setJoinStyle_r(GEOSContextHandle_t extHandle,GEOSBufferParams * p,int style)3321     GEOSBufferParams_setJoinStyle_r(GEOSContextHandle_t extHandle,
3322                                     GEOSBufferParams* p, int style)
3323     {
3324         return execute(extHandle, 0, [&]() {
3325             if(style > BufferParameters::JOIN_BEVEL) {
3326                 throw IllegalArgumentException("Invalid buffer join style");
3327             }
3328             p->setJoinStyle(static_cast<BufferParameters::JoinStyle>(style));
3329 
3330             return 1;
3331         });
3332     }
3333 
3334     int
GEOSBufferParams_setMitreLimit_r(GEOSContextHandle_t extHandle,GEOSBufferParams * p,double limit)3335     GEOSBufferParams_setMitreLimit_r(GEOSContextHandle_t extHandle,
3336                                      GEOSBufferParams* p, double limit)
3337     {
3338         return execute(extHandle, 0, [&]() {
3339             p->setMitreLimit(limit);
3340             return 1;
3341         });
3342     }
3343 
3344     int
GEOSBufferParams_setQuadrantSegments_r(GEOSContextHandle_t extHandle,GEOSBufferParams * p,int segs)3345     GEOSBufferParams_setQuadrantSegments_r(GEOSContextHandle_t extHandle,
3346                                            GEOSBufferParams* p, int segs)
3347     {
3348         return execute(extHandle, 0, [&]() {
3349             p->setQuadrantSegments(segs);
3350             return 1;
3351         });
3352     }
3353 
3354     int
GEOSBufferParams_setSingleSided_r(GEOSContextHandle_t extHandle,GEOSBufferParams * p,int ss)3355     GEOSBufferParams_setSingleSided_r(GEOSContextHandle_t extHandle,
3356                                       GEOSBufferParams* p, int ss)
3357     {
3358         return execute(extHandle, 0, [&]() {
3359             p->setSingleSided((ss != 0));
3360             return 1;
3361         });
3362     }
3363 
3364     Geometry*
GEOSBufferWithParams_r(GEOSContextHandle_t extHandle,const Geometry * g1,const BufferParameters * bp,double width)3365     GEOSBufferWithParams_r(GEOSContextHandle_t extHandle, const Geometry* g1, const BufferParameters* bp, double width)
3366     {
3367         using geos::operation::buffer::BufferOp;
3368 
3369         return execute(extHandle, [&]() {
3370             BufferOp op(g1, *bp);
3371             Geometry* g3 = op.getResultGeometry(width);
3372             g3->setSRID(g1->getSRID());
3373             return g3;
3374         });
3375     }
3376 
3377     Geometry*
GEOSDelaunayTriangulation_r(GEOSContextHandle_t extHandle,const Geometry * g1,double tolerance,int onlyEdges)3378     GEOSDelaunayTriangulation_r(GEOSContextHandle_t extHandle, const Geometry* g1, double tolerance, int onlyEdges)
3379     {
3380         using geos::triangulate::DelaunayTriangulationBuilder;
3381 
3382         return execute(extHandle, [&]() -> Geometry* {
3383             DelaunayTriangulationBuilder builder;
3384             builder.setTolerance(tolerance);
3385             builder.setSites(*g1);
3386 
3387             if(onlyEdges) {
3388                 Geometry* out = builder.getEdges(*g1->getFactory()).release();
3389                 out->setSRID(g1->getSRID());
3390                 return out;
3391             }
3392             else {
3393                 Geometry* out = builder.getTriangles(*g1->getFactory()).release();
3394                 out->setSRID(g1->getSRID());
3395                 return out;
3396             }
3397         });
3398     }
3399 
3400     Geometry*
GEOSVoronoiDiagram_r(GEOSContextHandle_t extHandle,const Geometry * g1,const Geometry * env,double tolerance,int onlyEdges)3401     GEOSVoronoiDiagram_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* env, double tolerance,
3402                          int onlyEdges)
3403     {
3404         using geos::triangulate::VoronoiDiagramBuilder;
3405 
3406         return execute(extHandle, [&]() -> Geometry* {
3407             VoronoiDiagramBuilder builder;
3408             builder.setSites(*g1);
3409             builder.setTolerance(tolerance);
3410             if(env) {
3411                 builder.setClipEnvelope(env->getEnvelopeInternal());
3412             }
3413             if(onlyEdges) {
3414                 Geometry* out = builder.getDiagramEdges(*g1->getFactory()).release();
3415                 out->setSRID(g1->getSRID());
3416                 return out;
3417             }
3418             else {
3419                 Geometry* out = builder.getDiagram(*g1->getFactory()).release();
3420                 out->setSRID(g1->getSRID());
3421                 return out;
3422             }
3423         });
3424     }
3425 
3426     int
GEOSSegmentIntersection_r(GEOSContextHandle_t extHandle,double ax0,double ay0,double ax1,double ay1,double bx0,double by0,double bx1,double by1,double * cx,double * cy)3427     GEOSSegmentIntersection_r(GEOSContextHandle_t extHandle,
3428                               double ax0, double ay0, double ax1, double ay1,
3429                               double bx0, double by0, double bx1, double by1,
3430                               double* cx, double* cy)
3431     {
3432         return execute(extHandle, 0, [&]() {
3433             geos::geom::LineSegment a(ax0, ay0, ax1, ay1);
3434             geos::geom::LineSegment b(bx0, by0, bx1, by1);
3435             geos::geom::Coordinate isect = a.intersection(b);
3436 
3437             if(isect.isNull()) {
3438                 return -1;
3439             }
3440 
3441             *cx = isect.x;
3442             *cy = isect.y;
3443 
3444             return 1;
3445         });
3446     }
3447 
3448 } /* extern "C" */
3449 
3450