1 /**
2  *   SFCGAL
3  *
4  *   Copyright (C) 2012-2013 Oslandia <infos@oslandia.com>
5  *   Copyright (C) 2012-2013 IGN (http://www.ign.fr)
6  *
7  *   This library is free software; you can redistribute it and/or
8  *   modify it under the terms of the GNU Library General Public
9  *   License as published by the Free Software Foundation; either
10  *   version 2 of the License, or (at your option) any later version.
11  *
12  *   This library is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *   Library General Public License for more details.
16 
17  *   You should have received a copy of the GNU Library General Public
18  *   License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 
22 #include <SFCGAL/Geometry.h>
23 #include <SFCGAL/version.h>
24 #include <SFCGAL/Point.h>
25 #include <SFCGAL/LineString.h>
26 #include <SFCGAL/Triangle.h>
27 #include <SFCGAL/Polygon.h>
28 #include <SFCGAL/Solid.h>
29 #include <SFCGAL/MultiPoint.h>
30 #include <SFCGAL/MultiLineString.h>
31 #include <SFCGAL/MultiPolygon.h>
32 #include <SFCGAL/GeometryCollection.h>
33 #include <SFCGAL/PolyhedralSurface.h>
34 #include <SFCGAL/TriangulatedSurface.h>
35 #include <SFCGAL/PreparedGeometry.h>
36 
37 #include <SFCGAL/capi/sfcgal_c.h>
38 
39 #include <SFCGAL/io/wkt.h>
40 #include <SFCGAL/io/ewkt.h>
41 #include <SFCGAL/detail/io/Serialization.h>
42 
43 #include <SFCGAL/algorithm/isValid.h>
44 #include <SFCGAL/algorithm/intersects.h>
45 #include <SFCGAL/algorithm/covers.h>
46 #include <SFCGAL/algorithm/intersection.h>
47 #include <SFCGAL/algorithm/difference.h>
48 #include <SFCGAL/algorithm/union.h>
49 #include <SFCGAL/algorithm/convexHull.h>
50 #include <SFCGAL/algorithm/distance.h>
51 #include <SFCGAL/algorithm/distance3d.h>
52 #include <SFCGAL/algorithm/lineSubstring.h>
53 #include <SFCGAL/algorithm/plane.h>
54 #include <SFCGAL/algorithm/volume.h>
55 #include <SFCGAL/algorithm/area.h>
56 #include <SFCGAL/algorithm/extrude.h>
57 #include <SFCGAL/algorithm/tesselate.h>
58 #include <SFCGAL/triangulate/triangulate2DZ.h>
59 #include <SFCGAL/algorithm/minkowskiSum.h>
60 #include <SFCGAL/algorithm/offset.h>
61 #include <SFCGAL/algorithm/straightSkeleton.h>
62 
63 #include <SFCGAL/detail/transform/ForceZOrderPoints.h>
64 #include <SFCGAL/detail/transform/ForceOrderPoints.h>
65 #include <SFCGAL/detail/transform/RoundTransform.h>
66 
67 //
68 // Note about sfcgal_geometry_t pointers: they are basically void* pointers that represent
69 // pointers to a SFCGAL::Geometry.
70 // In order to support multiple inheritance:
71 // every input or output sfcgal_geometry_t* is a pointer to the *base class* SFCGAL::Geometry.
72 // If a function wants to return a sub-class, it must be up casted before returned (static_cast)
73 // If a function wants to use a sub-class from a parameter, it must also be down casted.
74 // For instance, static_cast<SFCGAL::Point*>(reinterpret_cast<SFCGAL::Geometry*>(p))
75 //
76 // SFCGAL::PreparedGeometry has no vtable and can thus be manipuled through reinterpret_cast without
77 // problem
78 
79 static sfcgal_error_handler_t __sfcgal_warning_handler = printf;
80 static sfcgal_error_handler_t __sfcgal_error_handler = printf;
81 
82 #define SFCGAL_WARNING __sfcgal_warning_handler
83 #define SFCGAL_ERROR __sfcgal_error_handler
84 
85 #define SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR( call ) \
86     try {call}\
87     catch( std::exception& e ) { SFCGAL_ERROR( "%s", e.what() ); return 0; }
88 
89 #define SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET( call ) \
90     try {call}\
91     catch( std::exception& e ) { SFCGAL_ERROR( "%s", e.what() ); }
92 
93 template <class T>
down_cast(sfcgal_geometry_t * p)94 inline T* down_cast( sfcgal_geometry_t* p )
95 {
96     T* q = dynamic_cast<T*>( reinterpret_cast<SFCGAL::Geometry*>( p ) );
97 
98     if ( !q ) {
99         BOOST_THROW_EXCEPTION( SFCGAL::Exception( "wrong geometry type" ) );
100     }
101 
102     return q;
103 }
104 
105 template <class T>
down_const_cast(const sfcgal_geometry_t * p)106 inline const T* down_const_cast( const sfcgal_geometry_t* p )
107 {
108     const T* q = dynamic_cast<const T*>( reinterpret_cast<const SFCGAL::Geometry*>( p ) );
109 
110     if ( !q ) {
111         BOOST_THROW_EXCEPTION( SFCGAL::Exception( "wrong geometry type" ) );
112     }
113 
114     return q;
115 }
116 
sfcgal_set_error_handlers(sfcgal_error_handler_t warning_handler,sfcgal_error_handler_t error_handler)117 extern "C" void sfcgal_set_error_handlers( sfcgal_error_handler_t warning_handler, sfcgal_error_handler_t error_handler )
118 {
119     __sfcgal_warning_handler = warning_handler;
120     __sfcgal_error_handler = error_handler;
121 }
122 
123 static sfcgal_alloc_handler_t __sfcgal_alloc_handler = malloc;
124 static sfcgal_free_handler_t __sfcgal_free_handler = free;
125 
sfcgal_set_alloc_handlers(sfcgal_alloc_handler_t alloc_handler,sfcgal_free_handler_t free_handler)126 extern "C" void sfcgal_set_alloc_handlers( sfcgal_alloc_handler_t alloc_handler, sfcgal_free_handler_t free_handler )
127 {
128     __sfcgal_alloc_handler = alloc_handler;
129     __sfcgal_free_handler = free_handler;
130 }
131 
sfcgal_init()132 extern "C" void sfcgal_init()
133 {
134     // Empty for now
135 }
136 
sfcgal_version()137 extern "C" const char* sfcgal_version()
138 {
139     return SFCGAL::Version();
140 }
141 
sfcgal_full_version()142 extern "C" const char* sfcgal_full_version()
143 {
144     return SFCGAL::Full_Version();
145 }
146 
sfcgal_set_geometry_validation(int)147 extern "C" void sfcgal_set_geometry_validation( int /*enabled*/ )
148 {
149 }
150 
sfcgal_geometry_type_id(const sfcgal_geometry_t * geom)151 extern "C" sfcgal_geometry_type_t sfcgal_geometry_type_id( const sfcgal_geometry_t* geom )
152 {
153 
154     try {
155         return ( sfcgal_geometry_type_t )reinterpret_cast<const SFCGAL::Geometry*>( geom )->geometryTypeId();
156     }
157     catch( std::exception& e ) {
158         SFCGAL_ERROR( "%s", e.what() );
159         return SFCGAL_TYPE_POINT; // to avoid warning
160     }
161 }
162 
sfcgal_geometry_is_valid(const sfcgal_geometry_t * geom)163 extern "C" int sfcgal_geometry_is_valid( const sfcgal_geometry_t* geom )
164 {
165     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
166         return ( int )bool( SFCGAL::algorithm::isValid( *reinterpret_cast<const SFCGAL::Geometry*>( geom ) ) );
167     )
168 }
169 
sfcgal_geometry_is_valid_detail(const sfcgal_geometry_t * geom,char ** invalidity_reason,sfcgal_geometry_t ** invalidity_location)170 extern "C" int sfcgal_geometry_is_valid_detail( const sfcgal_geometry_t* geom, char** invalidity_reason, sfcgal_geometry_t** invalidity_location )
171 {
172     // invalidity location is not supported for now
173     if ( invalidity_location )
174         *invalidity_location = 0;
175     // set to null for now
176     if ( invalidity_reason )
177         *invalidity_reason = 0;
178 
179     const SFCGAL::Geometry* g = reinterpret_cast<const SFCGAL::Geometry*>( geom );
180     if ( g->hasValidityFlag() )
181         return true;
182     bool is_valid = false;
183     try
184     {
185         SFCGAL::Validity validity = SFCGAL::algorithm::isValid( *g );
186         is_valid = validity;
187         if ( !is_valid && invalidity_reason ) {
188             *invalidity_reason = strdup( validity.reason().c_str() );
189         }
190     }
191     catch ( SFCGAL::Exception& e )
192     {
193         if ( invalidity_reason ) {
194             *invalidity_reason = strdup( e.what() );
195         }
196     }
197     return is_valid;
198 }
199 
sfcgal_geometry_is_3d(const sfcgal_geometry_t * geom)200 extern "C" int sfcgal_geometry_is_3d( const sfcgal_geometry_t* geom )
201 {
202     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
203         return ( int )reinterpret_cast<const SFCGAL::Geometry*>( geom )->is3D();
204     )
205 }
206 
sfcgal_geometry_is_measured(const sfcgal_geometry_t * geom)207 extern "C" int sfcgal_geometry_is_measured( const sfcgal_geometry_t* geom )
208 {
209     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
210         return ( int )reinterpret_cast<const SFCGAL::Geometry*>( geom )->isMeasured();
211     )
212 }
213 
sfcgal_geometry_is_empty(const sfcgal_geometry_t * geom)214 extern "C" int sfcgal_geometry_is_empty( const sfcgal_geometry_t* geom )
215 {
216     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
217         return ( int )reinterpret_cast<const SFCGAL::Geometry*>( geom )->isEmpty();
218     )
219 }
220 
sfcgal_geometry_clone(const sfcgal_geometry_t * geom)221 extern "C" sfcgal_geometry_t* sfcgal_geometry_clone( const sfcgal_geometry_t* geom )
222 {
223     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
224         return reinterpret_cast<const SFCGAL::Geometry*>( geom )->clone();
225     )
226 }
227 
sfcgal_geometry_delete(sfcgal_geometry_t * geom)228 extern "C" void sfcgal_geometry_delete( sfcgal_geometry_t* geom )
229 {
230     delete reinterpret_cast<SFCGAL::Geometry*>( geom );
231 }
232 
sfcgal_geometry_as_text(const sfcgal_geometry_t * pgeom,char ** buffer,size_t * len)233 extern "C" void sfcgal_geometry_as_text( const sfcgal_geometry_t* pgeom, char** buffer, size_t* len )
234 {
235     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
236         std::string wkt = reinterpret_cast<const SFCGAL::Geometry*>( pgeom )->asText();
237         *buffer = ( char* )__sfcgal_alloc_handler( wkt.size() + 1 );
238         *len = wkt.size();
239         strncpy( *buffer, wkt.c_str(), *len );
240     )
241 }
242 
sfcgal_geometry_as_text_decim(const sfcgal_geometry_t * pgeom,int numDecimals,char ** buffer,size_t * len)243 extern "C" void sfcgal_geometry_as_text_decim( const sfcgal_geometry_t* pgeom, int numDecimals, char** buffer, size_t* len )
244 {
245     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
246         std::string wkt = reinterpret_cast<const SFCGAL::Geometry*>( pgeom )->asText( numDecimals );
247         *buffer = ( char* )__sfcgal_alloc_handler( wkt.size() + 1 );
248         *len = wkt.size();
249         strncpy( *buffer, wkt.c_str(), *len );
250     )
251 }
252 
253 /**
254  * Point
255  */
sfcgal_point_create()256 extern "C" sfcgal_geometry_t* sfcgal_point_create()
257 {
258     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
259         return static_cast<SFCGAL::Geometry*>( new SFCGAL::Point() );
260     )
261 }
262 
sfcgal_point_create_from_xy(double x,double y)263 extern "C" sfcgal_geometry_t* sfcgal_point_create_from_xy( double x, double y )
264 {
265     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
266         return static_cast<SFCGAL::Geometry*>( new SFCGAL::Point( x, y ) );
267     )
268 }
sfcgal_point_create_from_xyz(double x,double y,double z)269 extern "C" sfcgal_geometry_t* sfcgal_point_create_from_xyz( double x, double y, double z )
270 {
271     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
272         return static_cast<SFCGAL::Geometry*>( new SFCGAL::Point( x, y, z ) );
273     )
274 }
275 
sfcgal_point_x(const sfcgal_geometry_t * geom)276 extern "C" double sfcgal_point_x( const sfcgal_geometry_t* geom )
277 {
278     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
279         return CGAL::to_double( down_const_cast<SFCGAL::Point>( geom )->x() );
280     )
281 }
282 
sfcgal_point_y(const sfcgal_geometry_t * geom)283 extern "C" double sfcgal_point_y( const sfcgal_geometry_t* geom )
284 {
285     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
286         return CGAL::to_double( down_const_cast<SFCGAL::Point>( geom )->y() );
287     )
288 }
289 
sfcgal_point_z(const sfcgal_geometry_t * geom)290 extern "C" double sfcgal_point_z( const sfcgal_geometry_t* geom )
291 {
292     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
293         return CGAL::to_double( down_const_cast<SFCGAL::Point>( geom )->z() );
294     )
295 }
296 
sfcgal_point_m(const sfcgal_geometry_t * geom)297 extern "C" double sfcgal_point_m( const sfcgal_geometry_t* geom )
298 {
299     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
300         return CGAL::to_double( down_const_cast<SFCGAL::Point>( geom )->m() );
301     )
302 }
303 
304 /**
305  * LineString
306  */
sfcgal_linestring_create()307 extern "C" sfcgal_geometry_t* sfcgal_linestring_create()
308 {
309     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
310         return static_cast<SFCGAL::Geometry*>( new SFCGAL::LineString() );
311     )
312 }
313 
sfcgal_linestring_num_points(const sfcgal_geometry_t * geom)314 extern "C" size_t sfcgal_linestring_num_points( const sfcgal_geometry_t* geom )
315 {
316     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
317         return down_const_cast<SFCGAL::LineString>( geom )->numPoints();
318     )
319 }
320 
sfcgal_linestring_point_n(const sfcgal_geometry_t * geom,size_t i)321 extern "C" const sfcgal_geometry_t* sfcgal_linestring_point_n( const sfcgal_geometry_t* geom, size_t i )
322 {
323     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
324         return static_cast<const SFCGAL::Geometry*>( &( down_const_cast<SFCGAL::LineString>( geom )->pointN( i ) ) );
325     )
326 }
327 
sfcgal_linestring_add_point(sfcgal_geometry_t * geom,sfcgal_geometry_t * point)328 extern "C" void sfcgal_linestring_add_point( sfcgal_geometry_t* geom, sfcgal_geometry_t* point )
329 {
330     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
331         down_cast<SFCGAL::LineString>( geom )->addPoint( down_cast<SFCGAL::Point>( point ) );
332     )
333 }
334 
335 /**
336  * Triangle
337  */
sfcgal_triangle_create()338 extern "C" sfcgal_geometry_t* sfcgal_triangle_create()
339 {
340     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
341         return static_cast<SFCGAL::Geometry*>( new SFCGAL::Triangle() );
342     )
343 }
344 
sfcgal_triangle_create_from_points(const sfcgal_geometry_t * pa,const sfcgal_geometry_t * pb,const sfcgal_geometry_t * pc)345 extern "C" sfcgal_geometry_t* sfcgal_triangle_create_from_points( const sfcgal_geometry_t* pa,
346         const sfcgal_geometry_t* pb,
347         const sfcgal_geometry_t* pc )
348 {
349     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
350         return static_cast<SFCGAL::Geometry*>( new SFCGAL::Triangle( *down_const_cast<SFCGAL::Point>( pa ),
351                 *down_const_cast<SFCGAL::Point>( pb ),
352                 *down_const_cast<SFCGAL::Point>( pc ) ) );
353     )
354 }
355 
356 
sfcgal_triangle_vertex(const sfcgal_geometry_t * geom,int i)357 extern "C" const sfcgal_geometry_t* sfcgal_triangle_vertex( const sfcgal_geometry_t* geom, int i )
358 {
359     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
360         return static_cast<const SFCGAL::Geometry*>( &down_const_cast<SFCGAL::Triangle>( geom )->vertex( i ) );
361     )
362 }
363 
sfcgal_triangle_set_vertex(sfcgal_geometry_t * geom,int i,const sfcgal_geometry_t * point)364 extern "C" void sfcgal_triangle_set_vertex( sfcgal_geometry_t* geom, int i, const sfcgal_geometry_t* point )
365 {
366     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
367         down_cast<SFCGAL::Triangle>( geom )->vertex( i ) = *down_const_cast<const SFCGAL::Point>( point );
368     )
369 }
370 
sfcgal_triangle_set_vertex_from_xy(sfcgal_geometry_t * geom,int i,double x,double y)371 extern "C" void sfcgal_triangle_set_vertex_from_xy( sfcgal_geometry_t* geom, int i, double x, double y )
372 {
373     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
374         down_cast<SFCGAL::Triangle>( geom )->vertex( i ) = SFCGAL::Point( x, y );
375     )
376 }
377 
sfcgal_triangle_set_vertex_from_xyz(sfcgal_geometry_t * geom,int i,double x,double y,double z)378 extern "C" void sfcgal_triangle_set_vertex_from_xyz( sfcgal_geometry_t* geom, int i, double x, double y, double z )
379 {
380     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
381         down_cast<SFCGAL::Triangle>( geom )->vertex( i ) = SFCGAL::Point( x, y, z );
382     )
383 }
384 
385 /**
386  * Polygon
387  */
sfcgal_polygon_create()388 extern "C" sfcgal_geometry_t* sfcgal_polygon_create()
389 {
390     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
391         return static_cast<SFCGAL::Geometry*>( new SFCGAL::Polygon() );
392     )
393 }
394 
sfcgal_polygon_create_from_exterior_ring(sfcgal_geometry_t * ring)395 extern "C" sfcgal_geometry_t* sfcgal_polygon_create_from_exterior_ring( sfcgal_geometry_t* ring )
396 {
397     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
398         return static_cast<SFCGAL::Geometry*>( new SFCGAL::Polygon( down_cast<SFCGAL::LineString>( ring ) ) );
399     )
400 }
401 
sfcgal_polygon_exterior_ring(const sfcgal_geometry_t * geom)402 extern "C" const sfcgal_geometry_t* sfcgal_polygon_exterior_ring( const sfcgal_geometry_t* geom )
403 {
404     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
405         return static_cast<const SFCGAL::Geometry*>( &down_const_cast<SFCGAL::Polygon>( geom )->exteriorRing() );
406     )
407 }
408 
sfcgal_polygon_num_interior_rings(const sfcgal_geometry_t * geom)409 extern "C" size_t sfcgal_polygon_num_interior_rings( const sfcgal_geometry_t* geom )
410 {
411     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
412         return down_const_cast<SFCGAL::Polygon>( geom )->numInteriorRings();
413     )
414 }
415 
sfcgal_polygon_interior_ring_n(const sfcgal_geometry_t * geom,size_t i)416 extern "C" const sfcgal_geometry_t* sfcgal_polygon_interior_ring_n( const sfcgal_geometry_t* geom, size_t i )
417 {
418     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
419         return static_cast<const SFCGAL::Geometry*>( &down_const_cast<SFCGAL::Polygon>( geom )->interiorRingN( i ) );
420     )
421 }
422 
sfcgal_polygon_add_interior_ring(sfcgal_geometry_t * geom,sfcgal_geometry_t * ring)423 extern "C" void sfcgal_polygon_add_interior_ring( sfcgal_geometry_t* geom, sfcgal_geometry_t* ring )
424 {
425     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
426         down_cast<SFCGAL::Polygon>( geom )->addRing( down_cast<SFCGAL::LineString>( ring ) );
427     )
428 }
429 
430 /**
431  * Geometry collection
432  */
433 
sfcgal_geometry_collection_create()434 extern "C" sfcgal_geometry_t* sfcgal_geometry_collection_create()
435 {
436     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
437         return static_cast<SFCGAL::Geometry*>( new SFCGAL::GeometryCollection() );
438     )
439 }
440 
sfcgal_geometry_collection_num_geometries(const sfcgal_geometry_t * geom)441 extern "C" size_t sfcgal_geometry_collection_num_geometries( const sfcgal_geometry_t* geom )
442 {
443     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
444         return down_const_cast<SFCGAL::GeometryCollection>( geom )->numGeometries();
445     )
446 }
447 
sfcgal_geometry_collection_geometry_n(const sfcgal_geometry_t * geom,size_t i)448 extern "C" const sfcgal_geometry_t* sfcgal_geometry_collection_geometry_n( const sfcgal_geometry_t* geom, size_t i )
449 {
450     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
451         const SFCGAL::GeometryCollection* g = down_const_cast<SFCGAL::GeometryCollection>( geom );
452         return static_cast<const SFCGAL::Geometry*>( &g->geometryN( i ) );
453     )
454 }
455 
sfcgal_geometry_collection_add_geometry(sfcgal_geometry_t * geom,sfcgal_geometry_t * ngeom)456 extern "C" void sfcgal_geometry_collection_add_geometry( sfcgal_geometry_t* geom, sfcgal_geometry_t* ngeom )
457 {
458     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
459         down_cast<SFCGAL::GeometryCollection>( geom )->addGeometry( reinterpret_cast<SFCGAL::Geometry*>( ngeom ) );
460     )
461 }
462 
463 /**
464  * Multi-*
465  */
sfcgal_multi_point_create()466 extern "C" sfcgal_geometry_t* sfcgal_multi_point_create()
467 {
468     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
469         return static_cast<SFCGAL::Geometry*>( new SFCGAL::MultiPoint() );
470     )
471 }
472 
sfcgal_multi_linestring_create()473 extern "C" sfcgal_geometry_t* sfcgal_multi_linestring_create()
474 {
475     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
476         return static_cast<SFCGAL::Geometry*>( new SFCGAL::MultiLineString() );
477     )
478 }
479 
sfcgal_multi_polygon_create()480 extern "C" sfcgal_geometry_t* sfcgal_multi_polygon_create()
481 {
482     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
483         return static_cast<SFCGAL::Geometry*>( new SFCGAL::MultiPolygon() );
484     )
485 }
486 
487 /**
488  * Polyhedral surface
489  */
490 
sfcgal_polyhedral_surface_create()491 extern "C" sfcgal_geometry_t* sfcgal_polyhedral_surface_create()
492 {
493     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
494         return static_cast<SFCGAL::Geometry*>( new SFCGAL::PolyhedralSurface() );
495     )
496 }
497 
sfcgal_polyhedral_surface_num_polygons(const sfcgal_geometry_t * geom)498 extern "C" size_t sfcgal_polyhedral_surface_num_polygons( const sfcgal_geometry_t* geom )
499 {
500     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
501         return down_const_cast<SFCGAL::PolyhedralSurface>( geom )->numPolygons();
502     )
503 }
504 
sfcgal_polyhedral_surface_polygon_n(const sfcgal_geometry_t * geom,size_t i)505 extern "C" const sfcgal_geometry_t* sfcgal_polyhedral_surface_polygon_n( const sfcgal_geometry_t* geom, size_t i )
506 {
507     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
508         return static_cast<const SFCGAL::Geometry*>( &down_const_cast<SFCGAL::PolyhedralSurface>( geom )->polygonN( i ) );
509     )
510 }
511 
sfcgal_polyhedral_surface_add_polygon(sfcgal_geometry_t * geom,sfcgal_geometry_t * poly)512 extern "C" void sfcgal_polyhedral_surface_add_polygon( sfcgal_geometry_t* geom, sfcgal_geometry_t* poly )
513 {
514     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
515         return down_cast<SFCGAL::PolyhedralSurface>( geom )->addPolygon( down_cast<SFCGAL::Polygon>( poly ) );
516     )
517 }
518 
519 /**
520  * Triangulated surface
521  */
522 
sfcgal_triangulated_surface_create()523 extern "C" sfcgal_geometry_t* sfcgal_triangulated_surface_create()
524 {
525     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
526         return static_cast<SFCGAL::Geometry*>( new SFCGAL::TriangulatedSurface() );
527     )
528 }
529 
sfcgal_triangulated_surface_num_triangles(const sfcgal_geometry_t * geom)530 extern "C" size_t sfcgal_triangulated_surface_num_triangles( const sfcgal_geometry_t* geom )
531 {
532     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
533         return down_const_cast<SFCGAL::TriangulatedSurface>( geom )->numTriangles();
534     )
535 }
536 
sfcgal_triangulated_surface_triangle_n(const sfcgal_geometry_t * geom,size_t i)537 extern "C" const sfcgal_geometry_t* sfcgal_triangulated_surface_triangle_n( const sfcgal_geometry_t* geom, size_t i )
538 {
539     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
540         return static_cast<const SFCGAL::Geometry*>( &down_const_cast<SFCGAL::TriangulatedSurface>( geom )->triangleN( i ) );
541     )
542 }
543 
sfcgal_triangulated_surface_add_triangle(sfcgal_geometry_t * geom,sfcgal_geometry_t * triangle)544 extern "C" void sfcgal_triangulated_surface_add_triangle( sfcgal_geometry_t* geom, sfcgal_geometry_t* triangle )
545 {
546     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
547         down_cast<SFCGAL::TriangulatedSurface>( geom )->addTriangle( down_cast<SFCGAL::Triangle>( triangle ) );
548     )
549 }
550 
551 /**
552  * Solid
553  */
554 
sfcgal_solid_create()555 extern "C" sfcgal_geometry_t* sfcgal_solid_create()
556 {
557     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
558         return static_cast<SFCGAL::Geometry*>( new SFCGAL::Solid() );
559     )
560 }
561 
sfcgal_solid_create_from_exterior_shell(sfcgal_geometry_t * shell)562 extern "C" sfcgal_geometry_t* sfcgal_solid_create_from_exterior_shell( sfcgal_geometry_t* shell )
563 {
564     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
565         return static_cast<SFCGAL::Geometry*>( new SFCGAL::Solid( down_cast<SFCGAL::PolyhedralSurface>( shell ) ) );
566     )
567 }
568 
sfcgal_solid_num_shells(const sfcgal_geometry_t * geom)569 extern "C" size_t sfcgal_solid_num_shells( const sfcgal_geometry_t* geom )
570 {
571     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
572         return down_const_cast<SFCGAL::Solid>( geom )->numShells();
573     )
574 }
575 
sfcgal_solid_shell_n(const sfcgal_geometry_t * geom,size_t i)576 extern "C" const sfcgal_geometry_t* sfcgal_solid_shell_n( const sfcgal_geometry_t* geom, size_t i )
577 {
578     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
579         return static_cast<const SFCGAL::Geometry*>( &down_const_cast<SFCGAL::Solid>( geom )->shellN( i ) );
580     )
581 }
582 
sfcgal_solid_add_interior_shell(sfcgal_geometry_t * geom,sfcgal_geometry_t * shell)583 extern "C" void sfcgal_solid_add_interior_shell( sfcgal_geometry_t* geom , sfcgal_geometry_t* shell )
584 {
585     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
586         down_cast<SFCGAL::Solid>( geom )->addInteriorShell( down_cast<SFCGAL::PolyhedralSurface>( shell ) );
587     )
588 }
589 
sfcgal_prepared_geometry_create()590 extern "C" sfcgal_prepared_geometry_t* sfcgal_prepared_geometry_create()
591 {
592     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
593         return new SFCGAL::PreparedGeometry();
594     )
595 }
596 
sfcgal_prepared_geometry_create_from_geometry(sfcgal_geometry_t * geom,srid_t srid)597 extern "C" sfcgal_prepared_geometry_t* sfcgal_prepared_geometry_create_from_geometry( sfcgal_geometry_t* geom, srid_t srid )
598 {
599     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
600         return new SFCGAL::PreparedGeometry( reinterpret_cast<SFCGAL::Geometry*>( geom ), srid );
601     )
602 }
603 
sfcgal_prepared_geometry_delete(sfcgal_prepared_geometry_t * pgeom)604 extern "C" void sfcgal_prepared_geometry_delete( sfcgal_prepared_geometry_t* pgeom )
605 {
606     delete reinterpret_cast<SFCGAL::PreparedGeometry*>( pgeom );
607 }
608 
sfcgal_prepared_geometry_geometry(const sfcgal_prepared_geometry_t * pgeom)609 extern "C" const sfcgal_geometry_t* sfcgal_prepared_geometry_geometry( const sfcgal_prepared_geometry_t* pgeom )
610 {
611     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
612         return &reinterpret_cast<const SFCGAL::PreparedGeometry*>( pgeom )->geometry();
613     )
614 }
615 
sfcgal_prepared_geometry_set_geometry(sfcgal_prepared_geometry_t * pgeom,sfcgal_geometry_t * geom)616 extern "C" void sfcgal_prepared_geometry_set_geometry( sfcgal_prepared_geometry_t* pgeom, sfcgal_geometry_t* geom )
617 {
618     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
619         reinterpret_cast<SFCGAL::PreparedGeometry*>( pgeom )->resetGeometry( reinterpret_cast<SFCGAL::Geometry*>( geom ) );
620     )
621 }
622 
sfcgal_prepared_geometry_srid(const sfcgal_prepared_geometry_t * pgeom)623 extern "C" srid_t sfcgal_prepared_geometry_srid( const sfcgal_prepared_geometry_t* pgeom )
624 {
625     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
626         return reinterpret_cast<const SFCGAL::PreparedGeometry*>( pgeom )->SRID();
627     )
628 }
629 
sfcgal_prepared_geometry_set_srid(sfcgal_prepared_geometry_t * pgeom,srid_t srid)630 extern "C" void sfcgal_prepared_geometry_set_srid( sfcgal_prepared_geometry_t* pgeom, srid_t srid )
631 {
632     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
633         reinterpret_cast<SFCGAL::PreparedGeometry*>( pgeom )->SRID() = srid;
634     )
635 }
636 
sfcgal_prepared_geometry_as_ewkt(const sfcgal_prepared_geometry_t * pgeom,int num_decimals,char ** buffer,size_t * len)637 extern "C" void sfcgal_prepared_geometry_as_ewkt( const sfcgal_prepared_geometry_t* pgeom, int num_decimals, char** buffer, size_t* len )
638 {
639     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
640         std::string ewkt = reinterpret_cast<const SFCGAL::PreparedGeometry*>( pgeom )->asEWKT( num_decimals );
641         *buffer = ( char* )__sfcgal_alloc_handler( ewkt.size() + 1 );
642         *len = ewkt.size();
643         strncpy( *buffer, ewkt.c_str(), *len );
644     )
645 }
646 
sfcgal_io_read_wkt(const char * str,size_t len)647 extern "C" sfcgal_geometry_t* sfcgal_io_read_wkt( const char* str, size_t len )
648 {
649     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR(
650         return SFCGAL::io::readWkt( str, len ).release();
651     )
652 }
653 
sfcgal_io_write_binary_prepared(const sfcgal_prepared_geometry_t * geom,char ** buffer,size_t * len)654 extern "C" void sfcgal_io_write_binary_prepared( const sfcgal_prepared_geometry_t* geom, char** buffer, size_t* len )
655 {
656     SFCGAL_GEOMETRY_CONVERT_CATCH_TO_ERROR_NO_RET(
657         const SFCGAL::PreparedGeometry* g = reinterpret_cast<const SFCGAL::PreparedGeometry*>( geom );
658         std::string str = SFCGAL::io::writeBinaryPrepared( *g );
659         *buffer = ( char* )__sfcgal_alloc_handler( str.size() + 1 );
660         *len = str.size();
661         memcpy( *buffer, str.c_str(), *len );
662     )
663 }
664 
sfcgal_io_read_binary_prepared(const char * str,size_t len)665 extern "C" sfcgal_prepared_geometry_t* sfcgal_io_read_binary_prepared( const char* str, size_t len )
666 {
667     std::string sstr( str, len );
668     std::unique_ptr<SFCGAL::PreparedGeometry> g;
669 
670     try {
671         g = SFCGAL::io::readBinaryPrepared( sstr );
672     }
673     catch ( std::exception& e ) {
674         SFCGAL_WARNING( "During read_binary_prepared" );
675         SFCGAL_ERROR( "%s", e.what() );
676         return 0;
677     }
678 
679     return g.release();
680 }
681 
sfcgal_io_read_ewkt(const char * str,size_t len)682 extern "C" sfcgal_prepared_geometry_t* sfcgal_io_read_ewkt( const char* str, size_t len )
683 {
684     std::unique_ptr<SFCGAL::PreparedGeometry> g;
685 
686     try {
687         g = SFCGAL::io::readEwkt( str, len );
688     }
689     catch ( std::exception& e ) {
690         SFCGAL_ERROR( "%s", e.what() );
691         return 0;
692     }
693 
694     SFCGAL::PreparedGeometry* pg = g.release();
695     return pg;
696 }
697 
698 // Functions that take two geometries and return a scalar
699 //
700 // name: C function name
701 // ret_type: C function return type
702 // sfcgal_function: C++ SFCGAL method to call
703 // cpp_type: C++ return type (might be different than ret_type)
704 // fail_value: returned value on failure
705 #define SFCGAL_GEOMETRY_FUNCTION_BINARY_SCALAR( name, sfcgal_function, ret_type, cpp_type, fail_value ) \
706 	extern "C" ret_type sfcgal_geometry_##name( const sfcgal_geometry_t* ga, const sfcgal_geometry_t* gb ) \
707 	{								\
708 		cpp_type r;							\
709 		try							\
710 		{							\
711 			r = sfcgal_function( *(const SFCGAL::Geometry*)(ga), *(const SFCGAL::Geometry*)(gb) ); \
712 		}							\
713 		catch ( std::exception& e )				\
714 		{							\
715 			SFCGAL_WARNING( "During " #name "(A,B) :" ); \
716 			SFCGAL_WARNING( "  with A: %s", ((const SFCGAL::Geometry*)(ga))->asText().c_str() ); \
717 			SFCGAL_WARNING( "   and B: %s", ((const SFCGAL::Geometry*)(gb))->asText().c_str() ); \
718 			SFCGAL_ERROR( "%s", e.what() );	\
719 			return fail_value;					\
720 		}							\
721 		return r;					\
722 	}
723 
724 #define SFCGAL_GEOMETRY_FUNCTION_BINARY_PREDICATE( name, sfcgal_function ) \
725 	SFCGAL_GEOMETRY_FUNCTION_BINARY_SCALAR( name, sfcgal_function, int, bool, -1 )
726 
SFCGAL_GEOMETRY_FUNCTION_BINARY_PREDICATE(covers,SFCGAL::algorithm::covers)727 SFCGAL_GEOMETRY_FUNCTION_BINARY_PREDICATE( covers, SFCGAL::algorithm::covers )
728 SFCGAL_GEOMETRY_FUNCTION_BINARY_PREDICATE( covers_3d, SFCGAL::algorithm::covers3D )
729 
730 SFCGAL_GEOMETRY_FUNCTION_BINARY_PREDICATE( intersects, SFCGAL::algorithm::intersects )
731 SFCGAL_GEOMETRY_FUNCTION_BINARY_PREDICATE( intersects_3d, SFCGAL::algorithm::intersects3D )
732 
733 #define SFCGAL_GEOMETRY_FUNCTION_BINARY_MEASURE( name, sfcgal_function ) \
734 	SFCGAL_GEOMETRY_FUNCTION_BINARY_SCALAR( name, sfcgal_function, double, double, -1.0 )
735 
736 SFCGAL_GEOMETRY_FUNCTION_BINARY_MEASURE( distance, SFCGAL::algorithm::distance )
737 SFCGAL_GEOMETRY_FUNCTION_BINARY_MEASURE( distance_3d, SFCGAL::algorithm::distance3D )
738 
739 
740 #define SFCGAL_GEOMETRY_FUNCTION_BINARY_CONSTRUCTION( name, sfcgal_function ) \
741 	extern "C" sfcgal_geometry_t* sfcgal_geometry_##name( const sfcgal_geometry_t* ga, const sfcgal_geometry_t* gb ) \
742 	{								\
743 		std::unique_ptr<SFCGAL::Geometry> result;			\
744 		try							\
745 		{							\
746 			result = sfcgal_function( *(const SFCGAL::Geometry*)(ga), *(const SFCGAL::Geometry*)(gb) ); \
747 		}							\
748 		catch ( std::exception& e )				\
749 		{							\
750 			SFCGAL_WARNING( "During " #name "(A,B) :" ); \
751 			SFCGAL_WARNING( "  with A: %s", ((const SFCGAL::Geometry*)(ga))->asText().c_str() ); \
752 			SFCGAL_WARNING( "   and B: %s", ((const SFCGAL::Geometry*)(gb))->asText().c_str() ); \
753 			SFCGAL_ERROR( "%s", e.what() );	\
754 			return 0;					\
755 		}							\
756 		return result.release();				\
757 	}
758 
759 SFCGAL_GEOMETRY_FUNCTION_BINARY_CONSTRUCTION( intersection, SFCGAL::algorithm::intersection )
760 SFCGAL_GEOMETRY_FUNCTION_BINARY_CONSTRUCTION( intersection_3d, SFCGAL::algorithm::intersection3D )
761 SFCGAL_GEOMETRY_FUNCTION_BINARY_CONSTRUCTION( difference, SFCGAL::algorithm::difference )
762 SFCGAL_GEOMETRY_FUNCTION_BINARY_CONSTRUCTION( difference_3d, SFCGAL::algorithm::difference3D )
763 SFCGAL_GEOMETRY_FUNCTION_BINARY_CONSTRUCTION( union, SFCGAL::algorithm::union_ )
764 SFCGAL_GEOMETRY_FUNCTION_BINARY_CONSTRUCTION( union_3d, SFCGAL::algorithm::union3D )
765 
766 #define SFCGAL_GEOMETRY_FUNCTION_UNARY_CONSTRUCTION( name, sfcgal_function ) \
767 	extern "C" sfcgal_geometry_t* sfcgal_geometry_##name( const sfcgal_geometry_t* ga ) \
768 	{								\
769 		std::unique_ptr<SFCGAL::Geometry> result;			\
770 		try							\
771 		{							\
772 			result = sfcgal_function( *(const SFCGAL::Geometry*)(ga) ); \
773 		}							\
774 		catch ( std::exception& e )				\
775 		{							\
776 			SFCGAL_WARNING( "During " #name "(A) :" ); \
777 			SFCGAL_WARNING( "  with A: %s", ((const SFCGAL::Geometry*)(ga))->asText().c_str() ); \
778 			SFCGAL_ERROR( "%s", e.what() );	\
779 			return 0;					\
780 		}							\
781 		return result.release();				\
782 	}
783 
784 SFCGAL_GEOMETRY_FUNCTION_UNARY_CONSTRUCTION( convexhull, SFCGAL::algorithm::convexHull )
785 SFCGAL_GEOMETRY_FUNCTION_UNARY_CONSTRUCTION( convexhull_3d, SFCGAL::algorithm::convexHull3D )
786 SFCGAL_GEOMETRY_FUNCTION_UNARY_CONSTRUCTION( straight_skeleton, SFCGAL::algorithm::straightSkeleton )
787 SFCGAL_GEOMETRY_FUNCTION_UNARY_CONSTRUCTION( approximate_medial_axis, SFCGAL::algorithm::approximateMedialAxis )
788 SFCGAL_GEOMETRY_FUNCTION_UNARY_CONSTRUCTION( tesselate, SFCGAL::algorithm::tesselate )
789 
790 #define SFCGAL_GEOMETRY_FUNCTION_UNARY_MEASURE( name, sfcgal_function ) \
791 	extern "C" double sfcgal_geometry_##name( const sfcgal_geometry_t* ga ) \
792 	{								\
793 		double r;						\
794 		try							\
795 		{							\
796 			r = sfcgal_function( *(const SFCGAL::Geometry*)(ga) ); \
797 		}							\
798 		catch ( std::exception& e )				\
799 		{							\
800 			SFCGAL_WARNING( "During " #name "(A) :" ); \
801 			SFCGAL_WARNING( "  with A: %s", ((const SFCGAL::Geometry*)(ga))->asText().c_str() ); \
802 			SFCGAL_ERROR( "%s", e.what() );	\
803 			return -1.0;					\
804 		}							\
805 		return r;						\
806 	}
807 
808 extern "C" double sfcgal_geometry_volume( const sfcgal_geometry_t* ga )
809 {
810     double r;
811 
812     try {
813         r = CGAL::to_double( SFCGAL::algorithm::volume( *( const SFCGAL::Geometry* )( ga ) ) );
814     }
815     catch ( std::exception& e ) {
816         SFCGAL_WARNING( "During volume(A) :" );
817         SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( ga ) )->asText().c_str() );
818         SFCGAL_ERROR( "%s", e.what() );
819         return -1.0;
820     }
821 
822     return r;
823 }
824 
SFCGAL_GEOMETRY_FUNCTION_UNARY_MEASURE(area,SFCGAL::algorithm::area)825 SFCGAL_GEOMETRY_FUNCTION_UNARY_MEASURE( area, SFCGAL::algorithm::area )
826 SFCGAL_GEOMETRY_FUNCTION_UNARY_MEASURE( area_3d, SFCGAL::algorithm::area3D )
827 
828 extern "C" int sfcgal_geometry_is_planar( const sfcgal_geometry_t* ga )
829 {
830     const SFCGAL::Geometry* g = reinterpret_cast<const SFCGAL::Geometry*>( ga );
831 
832     if ( g->geometryTypeId() != SFCGAL::TYPE_POLYGON ) {
833         SFCGAL_ERROR( "is_planar() only applies to polygons" );
834         return -1;
835     }
836 
837     bool r;
838 
839     try {
840         r = SFCGAL::algorithm::isPlane3D< SFCGAL::Kernel >( g->as<const SFCGAL::Polygon >(), 1e-9 );
841     }
842     catch ( std::exception& e ) {
843         SFCGAL_WARNING( "During is_planar(A) :" );
844         SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( ga ) )->asText().c_str() );
845         SFCGAL_ERROR( "%s", e.what() );
846         return -1.0;
847     }
848 
849     return r ? 1 : 0;
850 }
851 
852 /**
853  * Get geometry orientation.
854  * Returns:
855  * -1 for a counter clock wise orientation,
856  * 1 for a clock wise orientation,
857  * 0 for invalid or undetermined orientation
858  */
sfcgal_geometry_orientation(const sfcgal_geometry_t * ga)859 extern "C" int sfcgal_geometry_orientation( const sfcgal_geometry_t* ga )
860 {
861     const SFCGAL::Geometry* g = reinterpret_cast<const SFCGAL::Geometry*>( ga );
862 
863     if ( g->geometryTypeId() != SFCGAL::TYPE_POLYGON ) {
864         SFCGAL_ERROR( "orientation() only applies to polygons" );
865         return 0;
866     }
867 
868     bool r;
869 
870     try {
871         r = g->as<const SFCGAL::Polygon>().isCounterClockWiseOriented();
872     }
873     catch ( std::exception& e ) {
874         SFCGAL_WARNING( "During orientation(A) :" );
875         SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( ga ) )->asText().c_str() );
876         SFCGAL_ERROR( "%s", e.what() );
877         return -1.0;
878     }
879 
880     return r ? -1 : 1;
881 }
882 
sfcgal_geometry_make_solid(const sfcgal_geometry_t * ga)883 extern "C" sfcgal_geometry_t* sfcgal_geometry_make_solid( const sfcgal_geometry_t* ga )
884 {
885     const SFCGAL::Geometry* g = reinterpret_cast<const SFCGAL::Geometry*>( ga );
886 
887     if ( g->geometryTypeId() != SFCGAL::TYPE_POLYHEDRALSURFACE ) {
888         SFCGAL_ERROR( "make_solid() only applies to polyhedral surfaces" );
889         return 0;
890     }
891 
892     return static_cast<SFCGAL::Geometry*>( new SFCGAL::Solid( g->as<const SFCGAL::PolyhedralSurface>() ) );
893 }
894 
sfcgal_geometry_force_lhr(const sfcgal_geometry_t * ga)895 extern "C" sfcgal_geometry_t* sfcgal_geometry_force_lhr( const sfcgal_geometry_t* ga )
896 {
897     const SFCGAL::Geometry* g = reinterpret_cast<const SFCGAL::Geometry*>( ga );
898     SFCGAL::Geometry* gb = g->clone();
899     SFCGAL::transform::ForceOrderPoints force( /* ccw */ true );
900 
901     try {
902         gb->accept( force );
903     }
904     catch ( std::exception& e ) {
905         SFCGAL_WARNING( "During force_lhr(A) :" );
906         SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( ga ) )->asText().c_str() );
907         SFCGAL_ERROR( "%s", e.what() );
908         return 0;
909     }
910 
911     return gb;
912 }
913 
sfcgal_geometry_force_rhr(const sfcgal_geometry_t * ga)914 extern "C" sfcgal_geometry_t* sfcgal_geometry_force_rhr( const sfcgal_geometry_t* ga )
915 {
916     const SFCGAL::Geometry* g = reinterpret_cast<const SFCGAL::Geometry*>( ga );
917     SFCGAL::Geometry* gb = g->clone();
918     SFCGAL::transform::ForceOrderPoints force( /* ccw */ false );
919 
920     try {
921         gb->accept( force );
922     }
923     catch ( std::exception& e ) {
924         SFCGAL_WARNING( "During force_rhr(A) :" );
925         SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( ga ) )->asText().c_str() );
926         SFCGAL_ERROR( "%s", e.what() );
927         return 0;
928     }
929 
930     return gb;
931 }
932 
sfcgal_geometry_triangulate_2dz(const sfcgal_geometry_t * ga)933 extern "C" sfcgal_geometry_t* sfcgal_geometry_triangulate_2dz( const sfcgal_geometry_t* ga )
934 {
935     const SFCGAL::Geometry* g = reinterpret_cast<const SFCGAL::Geometry*>( ga );
936     SFCGAL::TriangulatedSurface* surf = new SFCGAL::TriangulatedSurface;
937 
938     try {
939         SFCGAL::triangulate::ConstraintDelaunayTriangulation cdt;
940         SFCGAL::triangulate::triangulate2DZ( *g, cdt );
941         cdt.getTriangles( *surf );
942     }
943     catch ( std::exception& e ) {
944         SFCGAL_WARNING( "During triangulate_2d(A) :" );
945         SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( ga ) )->asText().c_str() );
946         SFCGAL_ERROR( "%s", e.what() );
947         return 0;
948     }
949 
950     return static_cast<SFCGAL::Geometry*>( surf );
951 }
952 
sfcgal_geometry_extrude(const sfcgal_geometry_t * ga,double x,double y,double z)953 extern "C" sfcgal_geometry_t* sfcgal_geometry_extrude( const sfcgal_geometry_t* ga, double x, double y, double z )
954 {
955     const SFCGAL::Geometry* g = reinterpret_cast<const SFCGAL::Geometry*>( ga );
956     std::unique_ptr<SFCGAL::Geometry> gb( g->clone() );
957     SFCGAL::transform::ForceZOrderPoints forceZ;
958     std::unique_ptr<SFCGAL::Geometry> result;
959 
960     try {
961         gb->accept( forceZ );
962         result = SFCGAL::algorithm::extrude( *gb, x, y, z );
963     }
964     catch ( std::exception& e ) {
965         SFCGAL_WARNING( "During extrude(A, %g, %g, %g) :", x, y, z );
966         SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( ga ) )->asText().c_str() );
967         SFCGAL_ERROR( "%s", e.what() );
968         return 0;
969     }
970 
971     return result.release();
972 }
973 
sfcgal_geometry_round(const sfcgal_geometry_t * ga,int scale)974 extern "C" sfcgal_geometry_t* sfcgal_geometry_round( const sfcgal_geometry_t* ga, int scale )
975 {
976     const SFCGAL::Geometry* g = reinterpret_cast<const SFCGAL::Geometry*>( ga );
977     SFCGAL::Geometry* gb = g->clone();
978     //	SFCGAL_WARNING( "geom: %s %s", gb->asText().c_str(), typeid(g).name() );
979 
980     SFCGAL::transform::RoundTransform roundT( scale );
981 
982     try {
983         gb->accept( roundT );
984     }
985     catch ( std::exception& e ) {
986         SFCGAL_WARNING( "During round(A):" );
987         SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( ga ) )->asText().c_str() );
988         SFCGAL_ERROR( "%s", e.what() );
989         return 0;
990     }
991 
992     //	SFCGAL_WARNING( "processed geom: %s", gb->asText().c_str() );
993     return gb;
994 }
995 
sfcgal_geometry_minkowski_sum(const sfcgal_geometry_t * ga,const sfcgal_geometry_t * gb)996 extern "C" sfcgal_geometry_t* sfcgal_geometry_minkowski_sum( const sfcgal_geometry_t* ga, const sfcgal_geometry_t* gb )
997 {
998     const SFCGAL::Geometry* g1 = reinterpret_cast<const SFCGAL::Geometry*>( ga );
999     const SFCGAL::Geometry* g2 = reinterpret_cast<const SFCGAL::Geometry*>( gb );
1000 
1001     if ( g2->geometryTypeId() != SFCGAL::TYPE_POLYGON ) {
1002         SFCGAL_ERROR( "minkowski_sum(): the second argument must be a polygon" );
1003         return 0;
1004     }
1005 
1006     std::unique_ptr<SFCGAL::Geometry> sum;
1007 
1008     try {
1009         sum = SFCGAL::algorithm::minkowskiSum( *g1, g2->as<const SFCGAL::Polygon>() );
1010     }
1011     catch ( std::exception& e ) {
1012         SFCGAL_WARNING( "During minkowski_sum(A,B):" );
1013         SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( ga ) )->asText().c_str() );
1014         SFCGAL_WARNING( "   and B: %s", ( ( const SFCGAL::Geometry* )( gb ) )->asText().c_str() );
1015         SFCGAL_ERROR( "%s", e.what() );
1016         return 0;
1017     }
1018 
1019     return sum.release();
1020 }
1021 
sfcgal_geometry_offset_polygon(const sfcgal_geometry_t * ga,double offset)1022 extern "C" sfcgal_geometry_t* sfcgal_geometry_offset_polygon( const sfcgal_geometry_t* ga, double offset )
1023 {
1024     const SFCGAL::Geometry* g1 = reinterpret_cast<const SFCGAL::Geometry*>( ga );
1025     std::unique_ptr<SFCGAL::MultiPolygon> mp;
1026 
1027     try {
1028         mp = SFCGAL::algorithm::offset( *g1, offset );
1029     }
1030     catch ( std::exception& e ) {
1031         SFCGAL_WARNING( "During offset(A,%g):", offset );
1032         SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( ga ) )->asText().c_str() );
1033         SFCGAL_ERROR( "%s", e.what() );
1034         return 0;
1035     }
1036 
1037     return mp.release();
1038 }
1039 
sfcgal_geometry_force_valid(sfcgal_geometry_t * geom,int valid)1040 extern "C" void sfcgal_geometry_force_valid( sfcgal_geometry_t* geom, int valid )
1041 {
1042     SFCGAL::Geometry* g1 = reinterpret_cast<SFCGAL::Geometry*>( geom );
1043     SFCGAL::algorithm::propagateValidityFlag( *g1, valid != 0 );
1044 }
1045 
sfcgal_geometry_has_validity_flag(const sfcgal_geometry_t * geom)1046 extern "C" int sfcgal_geometry_has_validity_flag( const sfcgal_geometry_t* geom )
1047 {
1048     const SFCGAL::Geometry* g1 = reinterpret_cast<const SFCGAL::Geometry*>( geom );
1049     return g1->hasValidityFlag() ? 1 : 0;
1050 }
1051 
sfcgal_geometry_straight_skeleton_distance_in_m(const sfcgal_geometry_t * geom)1052 extern "C" sfcgal_geometry_t* sfcgal_geometry_straight_skeleton_distance_in_m( const sfcgal_geometry_t* geom )
1053 {
1054     const SFCGAL::Geometry* g1 = reinterpret_cast<const SFCGAL::Geometry*>( geom );
1055     std::unique_ptr<SFCGAL::MultiLineString> mls;
1056 
1057     try {
1058         mls = SFCGAL::algorithm::straightSkeleton( *g1, /*autoOrientation*/ true, /*innerOnly*/ false, /*outputDistanceInM*/ true );
1059     }
1060     catch ( std::exception& e ) {
1061         SFCGAL_WARNING( "During straight_skeleton_distance_in_m(A):" );
1062         SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( geom ) )->asText().c_str() );
1063         SFCGAL_ERROR( "%s", e.what() );
1064         return 0;
1065     }
1066 
1067     return mls.release();
1068 }
1069 
sfcgal_geometry_line_sub_string(const sfcgal_geometry_t * geom,double start,double end)1070 extern "C" sfcgal_geometry_t* sfcgal_geometry_line_sub_string( const sfcgal_geometry_t* geom, double start, double end )
1071 {
1072     const SFCGAL::Geometry* g1 = reinterpret_cast<const SFCGAL::Geometry*>( geom );
1073     if ( g1->geometryTypeId() != SFCGAL::TYPE_LINESTRING ) {
1074         SFCGAL_ERROR( "line_sub_string(): the first argument must be a lineString" );
1075         return 0;
1076     }
1077     std::unique_ptr<SFCGAL::LineString> ls;
1078     try {
1079       ls = SFCGAL::algorithm::lineSubstring( g1->as<const SFCGAL::LineString>(), start, end );
1080     }
1081     catch ( std::exception& e ) {
1082       SFCGAL_WARNING( "During line_sub_string(A, %g, %g):", start, end );
1083       SFCGAL_WARNING( "  with A: %s", ( ( const SFCGAL::Geometry* )( geom ) )->asText().c_str() );
1084       SFCGAL_ERROR( "%s", e.what() );
1085       return 0;
1086     }
1087 
1088     return ls.release();
1089 }
1090