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