QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
Loading...
Searching...
No Matches
qgssfcgalgeometry.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgssfcgalGeometry.cpp
3 ----------------
4 begin : May 2025
5 copyright : (C) 2025 by Oslandia
6 email : benoit dot de dot mezzo at oslandia dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#ifdef WITH_SFCGAL
19
20#include "qgssfcgalgeometry.h"
21
22#include "qgsvector3d.h"
23#include "qgswkbptr.h"
24
25#include <QByteArray>
26#include <QString>
27
28using namespace Qt::StringLiterals;
29
30QgsSfcgalGeometry::QgsSfcgalGeometry()
31 : mIsPrimitive( false )
32{}
33
34QgsSfcgalGeometry::QgsSfcgalGeometry( const QgsAbstractGeometry *qgsGeom )
35 : mIsPrimitive( false )
36{
37 if ( qgsGeom )
38 {
39 QString errorMsg;
40 sfcgal::errorHandler()->clearText( &errorMsg );
41 mSfcgalGeom = QgsSfcgalEngine::fromAbstractGeometry( qgsGeom, &errorMsg );
42 THROW_ON_ERROR( &errorMsg );
43 }
44}
45
46QgsSfcgalGeometry::QgsSfcgalGeometry( const QgsAbstractGeometry &qgsGeom )
47 : mIsPrimitive( false )
48{
49 QString errorMsg;
50 sfcgal::errorHandler()->clearText( &errorMsg );
51 mSfcgalGeom = QgsSfcgalEngine::fromAbstractGeometry( &qgsGeom, &errorMsg );
52 THROW_ON_ERROR( &errorMsg );
53}
54
55QgsSfcgalGeometry::QgsSfcgalGeometry( sfcgal::shared_geom sfcgalGeom )
56 : mSfcgalGeom( sfcgalGeom )
57 , mIsPrimitive( false )
58{}
59
60QgsSfcgalGeometry::QgsSfcgalGeometry( sfcgal::shared_prim sfcgalPrim, sfcgal::primitiveType type )
61 : mIsPrimitive( true )
62{
63#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
64 mSfcgalPrim = sfcgalPrim;
65 mPrimType = type;
66#else
67 ( void ) sfcgalPrim;
68 ( void ) type;
69 throw QgsNotSupportedException( QObject::tr( "This operation requires a QGIS build based on SFCGAL 2.3 or later" ) );
70#endif
71}
72
73QgsSfcgalGeometry::QgsSfcgalGeometry( const QgsGeometry &qgsGeom )
74{
75 QString errorMsg;
76 sfcgal::errorHandler()->clearText( &errorMsg );
77 mSfcgalGeom = QgsSfcgalEngine::fromAbstractGeometry( qgsGeom.constGet(), &errorMsg );
78 THROW_ON_ERROR( &errorMsg );
79}
80
81QgsSfcgalGeometry::QgsSfcgalGeometry( const QgsSfcgalGeometry &otherGeom )
82{
83 QString errorMsg;
84 sfcgal::errorHandler()->clearText( &errorMsg );
85 mIsPrimitive = otherGeom.mIsPrimitive;
86#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
87 mPrimType = otherGeom.mPrimType;
88 if ( mIsPrimitive )
89 mSfcgalPrim = QgsSfcgalEngine::primitiveClone( otherGeom.mSfcgalPrim.get(), &errorMsg );
90 else
91#endif
92 mSfcgalGeom = QgsSfcgalEngine::cloneGeometry( otherGeom.mSfcgalGeom.get(), &errorMsg );
93 THROW_ON_ERROR( &errorMsg );
94}
95
96QgsSfcgalGeometry::QgsSfcgalGeometry( const QString &wkt )
97{
98 QString errorMsg;
99 sfcgal::errorHandler()->clearText( &errorMsg );
100 mSfcgalGeom = QgsSfcgalEngine::fromWkt( wkt, &errorMsg );
101 THROW_ON_ERROR( &errorMsg );
102}
103
104sfcgal::shared_geom QgsSfcgalGeometry::workingGeom() const
105{
106 sfcgal::shared_geom geom;
107
108#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
109 if ( mIsPrimitive )
110 {
111 QString errorMsg;
112 geom = QgsSfcgalEngine::primitiveAsPolyhedral( mSfcgalPrim.get(), mPrimTransform, &errorMsg );
113 THROW_ON_ERROR( &errorMsg );
114 }
115 else
116#endif
117 geom = mSfcgalGeom;
118
119 return geom;
120}
121
122
123Qgis::WkbType QgsSfcgalGeometry::wkbType() const
124{
125 QString errorMsg;
126 sfcgal::errorHandler()->clearText( &errorMsg );
127
128#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
129 if ( mIsPrimitive )
131#endif
132
133 Qgis::WkbType out = QgsSfcgalEngine::wkbType( mSfcgalGeom.get(), &errorMsg );
134 THROW_ON_ERROR( &errorMsg );
135 return out;
136}
137
138QString QgsSfcgalGeometry::geometryType() const
139{
140 QString errorMsg;
141 sfcgal::errorHandler()->clearText( &errorMsg );
142
143 QString out;
144#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
145 if ( mIsPrimitive )
146 {
147 switch ( mPrimType )
148 {
149 case sfcgal::primitiveType::SFCGAL_TYPE_CYLINDER:
150 out = "cylinder";
151 break;
152 case sfcgal::primitiveType::SFCGAL_TYPE_SPHERE:
153 out = "sphere";
154 break;
155 case sfcgal::primitiveType::SFCGAL_TYPE_TORUS:
156 out = "torus";
157 break;
158 case sfcgal::primitiveType::SFCGAL_TYPE_BOX:
159 out = "box";
160 break;
161 case sfcgal::primitiveType::SFCGAL_TYPE_CUBE:
162 out = "cube";
163 break;
164 case sfcgal::primitiveType::SFCGAL_TYPE_CONE:
165 out = "cone";
166 break;
167 default:
168 sfcgal::errorHandler()->addText( u"Type '%1' is unknown."_s.arg( mPrimType ) );
169 }
170 }
171 else
172#endif
173 {
174 out = QgsSfcgalEngine::geometryType( mSfcgalGeom.get(), &errorMsg );
175 THROW_ON_ERROR( &errorMsg );
176 }
177 return out;
178}
179
180std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::clone() const
181{
182 return std::make_unique<QgsSfcgalGeometry>( *this );
183}
184
185std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::fromWkb( const QgsConstWkbPtr &wkbPtr )
186{
187 if ( !wkbPtr )
188 {
189 return nullptr;
190 }
191
192 QString errorMsg;
193 sfcgal::shared_geom sfcgalGeom = QgsSfcgalEngine::fromWkb( wkbPtr, &errorMsg );
194 THROW_ON_ERROR( &errorMsg );
195
196 return std::make_unique<QgsSfcgalGeometry>( sfcgalGeom );
197}
198
199
200QByteArray QgsSfcgalGeometry::asWkb( QgsAbstractGeometry::WkbFlags ) const
201{
202 QString errorMsg;
203 sfcgal::errorHandler()->clearText( &errorMsg );
204
205 sfcgal::shared_geom geom = workingGeom();
206 QByteArray wkbArray = QgsSfcgalEngine::toWkb( geom.get(), &errorMsg );
207 THROW_ON_ERROR( &errorMsg );
208
209 return wkbArray;
210}
211
212QString QgsSfcgalGeometry::asWkt( int precision ) const
213{
214 QString errorMsg;
215 sfcgal::errorHandler()->clearText( &errorMsg );
216
217 sfcgal::shared_geom geom = workingGeom();
218 QString out = QgsSfcgalEngine::toWkt( geom.get(), precision, &errorMsg );
219 THROW_ON_ERROR( &errorMsg );
220
221 return out;
222}
223
224std::unique_ptr<QgsAbstractGeometry> QgsSfcgalGeometry::asQgisGeometry() const
225{
226 QString errorMsg;
227 sfcgal::errorHandler()->clearText( &errorMsg );
228
229 sfcgal::shared_geom geom = workingGeom();
230 std::unique_ptr<QgsAbstractGeometry> out = QgsSfcgalEngine::toAbstractGeometry( geom.get(), &errorMsg );
231 THROW_ON_ERROR( &errorMsg );
232 return out;
233}
234
235std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::boundary() const
236{
237 QString errorMsg;
238 sfcgal::errorHandler()->clearText( &errorMsg );
239
240 sfcgal::shared_geom geom = workingGeom();
241 sfcgal::shared_geom boundary = QgsSfcgalEngine::boundary( geom.get(), &errorMsg );
242 THROW_ON_ERROR( &errorMsg );
243
244 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( boundary, &errorMsg );
245 THROW_ON_ERROR( &errorMsg );
246 return resultGeom;
247}
248
249bool QgsSfcgalGeometry::operator==( const QgsSfcgalGeometry &other ) const
250{
251#if SFCGAL_VERSION_NUM < SFCGAL_MAKE_VERSION( 2, 1, 0 )
252 ( void ) other;
253 throw QgsNotSupportedException( QObject::tr( "This operation requires a QGIS build based on SFCGAL 2.1 or later" ) );
254#else
255 QString errorMsg;
256 bool out;
257
258#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
259 if ( mIsPrimitive != other.mIsPrimitive )
260 return false;
261
262 if ( mIsPrimitive )
263 {
264 out = QgsSfcgalEngine::primitiveIsEqual( mSfcgalPrim.get(), other.mSfcgalPrim.get(), -1.0, &errorMsg );
265 }
266 else
267#endif
268 {
269 out = QgsSfcgalEngine::isEqual( mSfcgalGeom.get(), other.mSfcgalGeom.get(), -1.0, &errorMsg );
270 }
271 THROW_ON_ERROR( &errorMsg );
272 return out;
273#endif
274}
275
276bool QgsSfcgalGeometry::operator!=( const QgsSfcgalGeometry &other ) const
277{
278 return !( *this == other );
279}
280
281bool QgsSfcgalGeometry::fuzzyEqual( const QgsSfcgalGeometry &other, double epsilon ) const
282{
283 QString errorMsg;
284 sfcgal::errorHandler()->clearText( &errorMsg );
285
286 bool out;
287
288#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
289 if ( mIsPrimitive != other.mIsPrimitive )
290 return false;
291
292 if ( mIsPrimitive )
293 {
294 out = QgsSfcgalEngine::primitiveIsEqual( mSfcgalPrim.get(), other.mSfcgalPrim.get(), epsilon, &errorMsg );
295 }
296 else
297#endif
298 {
299 out = QgsSfcgalEngine::isEqual( mSfcgalGeom.get(), other.mSfcgalGeom.get(), epsilon, &errorMsg );
300 }
301
302 THROW_ON_ERROR( &errorMsg );
303 return out;
304}
305
306int QgsSfcgalGeometry::dimension() const
307{
308 QString errorMsg;
309 sfcgal::errorHandler()->clearText( &errorMsg );
310
311 if ( mIsPrimitive )
312 return 3;
313
314 int result = QgsSfcgalEngine::dimension( mSfcgalGeom.get(), &errorMsg );
315 THROW_ON_ERROR( &errorMsg );
316
317 return result;
318}
319
320std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::fromWkt( const QString &wkt )
321{
322 QString errorMsg;
323
324 sfcgal::shared_geom sfcgalGeom = QgsSfcgalEngine::fromWkt( wkt, &errorMsg );
325 THROW_ON_ERROR( &errorMsg );
326
327 return std::make_unique<QgsSfcgalGeometry>( sfcgalGeom );
328}
329
330int QgsSfcgalGeometry::partCount() const
331{
332 QString errorMsg;
333 sfcgal::errorHandler()->clearText( &errorMsg );
334
335 if ( mIsPrimitive )
336 return 1;
337
338 int out = QgsSfcgalEngine::partCount( mSfcgalGeom.get(), &errorMsg );
339 THROW_ON_ERROR( &errorMsg );
340
341 return out;
342}
343
344bool QgsSfcgalGeometry::addZValue( double zValue )
345{
346 QString errorMsg;
347 sfcgal::errorHandler()->clearText( &errorMsg );
348
349 if ( mIsPrimitive )
350 throw QgsNotSupportedException( QObject::tr( "Operation '%1' does not apply to primitive." ).arg( "addZValue" ) );
351
352 const bool added = QgsSfcgalEngine::addZValue( mSfcgalGeom.get(), zValue, &errorMsg );
353 THROW_ON_ERROR( &errorMsg );
354
355 clearCache();
356
357 return added;
358}
359
360bool QgsSfcgalGeometry::addMValue( double mValue )
361{
362 QString errorMsg;
363 sfcgal::errorHandler()->clearText( &errorMsg );
364
365 if ( mIsPrimitive )
366 throw QgsNotSupportedException( QObject::tr( "Operation '%1' does not apply to primitive." ).arg( "addMValue" ) );
367
368 const bool added = QgsSfcgalEngine::addMValue( mSfcgalGeom.get(), mValue, &errorMsg );
369 THROW_ON_ERROR( &errorMsg );
370
371 clearCache();
372
373 return added;
374}
375
376bool QgsSfcgalGeometry::dropZValue()
377{
378 QString errorMsg;
379 sfcgal::errorHandler()->clearText( &errorMsg );
380
381 if ( mIsPrimitive )
382 throw QgsNotSupportedException( QObject::tr( "Operation '%1' does not apply to primitive." ).arg( "dropZValue" ) );
383
384 const bool dropped = QgsSfcgalEngine::dropZValue( mSfcgalGeom.get(), &errorMsg );
385 THROW_ON_ERROR( &errorMsg );
386
387 clearCache();
388
389 return dropped;
390}
391
392bool QgsSfcgalGeometry::dropMValue()
393{
394 QString errorMsg;
395 sfcgal::errorHandler()->clearText( &errorMsg );
396
397 if ( mIsPrimitive )
398 throw QgsNotSupportedException( QObject::tr( "Operation '%1' does not apply to primitive." ).arg( "dropMValue" ) );
399
400 const bool dropped = QgsSfcgalEngine::dropMValue( mSfcgalGeom.get(), &errorMsg );
401 THROW_ON_ERROR( &errorMsg );
402
403 clearCache();
404
405 return dropped;
406}
407
408void QgsSfcgalGeometry::swapXy()
409{
410 QString errorMsg;
411 sfcgal::errorHandler()->clearText( &errorMsg );
412
413 if ( mIsPrimitive )
414 throw QgsNotSupportedException( QObject::tr( "Operation '%1' does not apply to primitive." ).arg( "swapXy" ) );
415
416 QgsSfcgalEngine::swapXy( mSfcgalGeom.get(), &errorMsg );
417 THROW_ON_ERROR( &errorMsg );
418
419 clearCache();
420}
421
422bool QgsSfcgalGeometry::isValid() const
423{
424 QString errorMsg;
425 sfcgal::errorHandler()->clearText( &errorMsg );
426
427 if ( mIsPrimitive )
428 return true;
429
430 const bool valid = QgsSfcgalEngine::isValid( mSfcgalGeom.get(), &errorMsg, nullptr );
431 THROW_ON_ERROR( &errorMsg );
432 return valid;
433}
434
435void QgsSfcgalGeometry::clearCache() const
436{}
437
438bool QgsSfcgalGeometry::isSimple() const
439{
440 QString errorMsg;
441 sfcgal::errorHandler()->clearText( &errorMsg );
442
443 if ( mIsPrimitive )
444 return true;
445
446 bool result = QgsSfcgalEngine::isSimple( mSfcgalGeom.get(), &errorMsg );
447 THROW_ON_ERROR( &errorMsg );
448 return result;
449}
450
451QgsPoint QgsSfcgalGeometry::centroid() const
452{
453 QString errorMsg;
454 sfcgal::errorHandler()->clearText( &errorMsg );
455
456 sfcgal::shared_geom geom = workingGeom();
457 return QgsSfcgalEngine::centroid( geom.get(), &errorMsg );
458}
459
460bool QgsSfcgalGeometry::isEmpty() const
461{
462 QString errorMsg;
463 sfcgal::errorHandler()->clearText( &errorMsg );
464
465 if ( mIsPrimitive )
466 return false;
467
468 bool result = QgsSfcgalEngine::isEmpty( mSfcgalGeom.get(), &errorMsg );
469 THROW_ON_ERROR( &errorMsg );
470
471 return result;
472}
473
474std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::translate( const QgsVector3D &translation ) const
475{
476 QString errorMsg;
477 sfcgal::errorHandler()->clearText( &errorMsg );
478
479 std::unique_ptr<QgsSfcgalGeometry> resultGeom;
480#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
481 if ( mIsPrimitive )
482 {
483 sfcgal::shared_prim prim = QgsSfcgalEngine::primitiveClone( mSfcgalPrim.get(), &errorMsg );
484 resultGeom = QgsSfcgalEngine::toSfcgalGeometry( prim, mPrimType, &errorMsg );
485 resultGeom->setPrimitiveTranslate( translation );
486 }
487 else
488#endif
489 {
490 sfcgal::shared_geom result = QgsSfcgalEngine::translate( mSfcgalGeom.get(), translation, &errorMsg );
491 THROW_ON_ERROR( &errorMsg );
492 resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
493 }
494
495 THROW_ON_ERROR( &errorMsg );
496 return resultGeom;
497}
498
499std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::scale( const QgsVector3D &scaleFactor, const QgsPoint &center ) const
500{
501 QString errorMsg;
502 sfcgal::errorHandler()->clearText( &errorMsg );
503
504 std::unique_ptr<QgsSfcgalGeometry> resultGeom;
505#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
506 if ( mIsPrimitive )
507 {
508 sfcgal::shared_prim prim = QgsSfcgalEngine::primitiveClone( mSfcgalPrim.get(), &errorMsg );
509 resultGeom = QgsSfcgalEngine::toSfcgalGeometry( prim, mPrimType, &errorMsg );
510 resultGeom->setPrimitiveScale( scaleFactor, center );
511 }
512 else
513#endif
514 {
515 sfcgal::shared_geom result = QgsSfcgalEngine::scale( mSfcgalGeom.get(), scaleFactor, center, &errorMsg );
516 THROW_ON_ERROR( &errorMsg );
517 resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
518 }
519
520 THROW_ON_ERROR( &errorMsg );
521 return resultGeom;
522}
523
524std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::rotate2D( double angle, const QgsPoint &center ) const
525{
526 QString errorMsg;
527 sfcgal::errorHandler()->clearText( &errorMsg );
528
529 std::unique_ptr<QgsSfcgalGeometry> resultGeom;
530#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
531 if ( mIsPrimitive )
532 {
533 sfcgal::shared_prim prim = QgsSfcgalEngine::primitiveClone( mSfcgalPrim.get(), &errorMsg );
534 resultGeom = QgsSfcgalEngine::toSfcgalGeometry( prim, mPrimType, &errorMsg );
535 resultGeom->setPrimitiveRotation( angle, { 0.0, 0.0, 1.0 }, center );
536 }
537 else
538#endif
539 {
540 sfcgal::shared_geom result = QgsSfcgalEngine::rotate2D( mSfcgalGeom.get(), angle, center, &errorMsg );
541 THROW_ON_ERROR( &errorMsg );
542
543 resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
544 }
545
546 THROW_ON_ERROR( &errorMsg );
547 return resultGeom;
548}
549
550std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::transform( const QMatrix4x4 &mat ) const
551{
552 QString errorMsg;
553 sfcgal::errorHandler()->clearText( &errorMsg );
554
555#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
556 sfcgal::shared_geom geom = workingGeom();
557
558 sfcgal::shared_geom result = QgsSfcgalEngine::transform( geom.get(), mat );
559 THROW_ON_ERROR( &errorMsg );
560
561 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
562 THROW_ON_ERROR( &errorMsg );
563 return resultGeom;
564#else
565 ( void ) mat;
566 throw QgsNotSupportedException( QObject::tr( "This operation requires a QGIS build based on SFCGAL 2.3 or later" ) );
567#endif
568}
569
570std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::rotate3D( double angle, const QgsVector3D &axisVector, const QgsPoint &center ) const
571{
572 QString errorMsg;
573 sfcgal::errorHandler()->clearText( &errorMsg );
574
575 std::unique_ptr<QgsSfcgalGeometry> resultGeom;
576#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
577 if ( mIsPrimitive )
578 {
579 sfcgal::shared_prim prim = QgsSfcgalEngine::primitiveClone( mSfcgalPrim.get(), &errorMsg );
580 resultGeom = QgsSfcgalEngine::toSfcgalGeometry( prim, mPrimType, &errorMsg );
581 resultGeom->setPrimitiveRotation( angle, axisVector, center );
582 }
583 else
584#endif
585 {
586 sfcgal::shared_geom result = QgsSfcgalEngine::rotate3D( mSfcgalGeom.get(), angle, axisVector, center, &errorMsg );
587 THROW_ON_ERROR( &errorMsg );
588
589 resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
590 }
591
592 THROW_ON_ERROR( &errorMsg );
593 return resultGeom;
594}
595
596double QgsSfcgalGeometry::area( bool withDiscretization ) const
597{
598 QString errorMsg;
599 sfcgal::errorHandler()->clearText( &errorMsg );
600
601 double result;
602#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
603 if ( mIsPrimitive )
604 {
605 result = QgsSfcgalEngine::primitiveArea( mSfcgalPrim.get(), withDiscretization, &errorMsg );
606 }
607 else
608#endif
609 {
610 ( void ) withDiscretization;
611 result = QgsSfcgalEngine::area( mSfcgalGeom.get(), &errorMsg );
612 }
613
614 THROW_ON_ERROR( &errorMsg );
615 return result;
616}
617
618double QgsSfcgalGeometry::length() const
619{
620 QString errorMsg;
621 sfcgal::errorHandler()->clearText( &errorMsg );
622
623 if ( mIsPrimitive )
624 throw QgsNotSupportedException( QObject::tr( "Operation '%1' does not apply to primitive." ).arg( "length" ) );
625
626 double result = QgsSfcgalEngine::length( mSfcgalGeom.get(), &errorMsg );
627 THROW_ON_ERROR( &errorMsg );
628
629 return result;
630}
631
632double QgsSfcgalGeometry::volume( bool withDiscretization ) const
633{
634 QString errorMsg;
635 sfcgal::errorHandler()->clearText( &errorMsg );
636
637 if ( !mIsPrimitive )
638 throw QgsNotSupportedException( QObject::tr( "Operation '%1' does not apply to geometry." ).arg( "volume" ) );
639
640 double result;
641#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
642 result = QgsSfcgalEngine::primitiveVolume( mSfcgalPrim.get(), withDiscretization, &errorMsg );
643#else
644 ( void ) withDiscretization;
645 throw QgsNotSupportedException( QObject::tr( "This operation requires a QGIS build based on SFCGAL 2.3 or later" ) );
646#endif
647
648 THROW_ON_ERROR( &errorMsg );
649 return result;
650}
651
652bool QgsSfcgalGeometry::intersects( const QgsAbstractGeometry *otherGeom ) const
653{
654 QString errorMsg;
655 sfcgal::errorHandler()->clearText( &errorMsg );
656 sfcgal::shared_geom otherShared = QgsSfcgalEngine::fromAbstractGeometry( otherGeom, &errorMsg );
657 THROW_ON_ERROR( &errorMsg );
658
659 sfcgal::shared_geom geom = workingGeom();
660 bool out = QgsSfcgalEngine::intersects( geom.get(), otherShared.get(), &errorMsg );
661 THROW_ON_ERROR( &errorMsg );
662 return out;
663}
664
665bool QgsSfcgalGeometry::intersects( const QgsSfcgalGeometry &otherGeom ) const
666{
667 QString errorMsg;
668 sfcgal::errorHandler()->clearText( &errorMsg );
669
670 sfcgal::shared_geom geom = workingGeom();
671 bool out = QgsSfcgalEngine::intersects( geom.get(), otherGeom.workingGeom().get(), &errorMsg );
672 THROW_ON_ERROR( &errorMsg );
673 return out;
674}
675
676std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::intersection( const QgsAbstractGeometry *otherGeom ) const
677{
678 QString errorMsg;
679 sfcgal::errorHandler()->clearText( &errorMsg );
680 sfcgal::shared_geom otherShared = QgsSfcgalEngine::fromAbstractGeometry( otherGeom, &errorMsg );
681 THROW_ON_ERROR( &errorMsg );
682
683 sfcgal::shared_geom geom = workingGeom();
684 sfcgal::shared_geom result = QgsSfcgalEngine::intersection( geom.get(), otherShared.get(), &errorMsg );
685 THROW_ON_ERROR( &errorMsg );
686
687 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
688 THROW_ON_ERROR( &errorMsg );
689 return resultGeom;
690}
691
692std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::intersection( const QgsSfcgalGeometry &otherGeom ) const
693{
694 QString errorMsg;
695 sfcgal::errorHandler()->clearText( &errorMsg );
696
697 sfcgal::shared_geom geom = workingGeom();
698 sfcgal::shared_geom result = QgsSfcgalEngine::intersection( geom.get(), otherGeom.workingGeom().get(), &errorMsg );
699 THROW_ON_ERROR( &errorMsg );
700
701 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
702 THROW_ON_ERROR( &errorMsg );
703 return resultGeom;
704}
705
706std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::combine( const QVector<QgsAbstractGeometry *> &geomList ) const
707{
708 QString errorMsg;
709 sfcgal::errorHandler()->clearText( &errorMsg );
710 QVector<sfcgal::shared_geom> sfcgalGeomList;
711
712 sfcgal::shared_geom geom = workingGeom();
713 sfcgalGeomList.append( geom );
714 for ( QVector<QgsAbstractGeometry *>::const_iterator ite = geomList.constBegin(); ite != geomList.constEnd(); ++ite )
715 {
716 sfcgal::shared_geom otherShared = QgsSfcgalEngine::fromAbstractGeometry( *ite, &errorMsg );
717 THROW_ON_ERROR( &errorMsg );
718 sfcgalGeomList.append( otherShared );
719 }
720
721 sfcgal::shared_geom result = QgsSfcgalEngine::combine( sfcgalGeomList, &errorMsg );
722 THROW_ON_ERROR( &errorMsg );
723
724 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
725 THROW_ON_ERROR( &errorMsg );
726 return resultGeom;
727}
728
729std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::difference( const QgsAbstractGeometry *otherGeom ) const
730{
731 QString errorMsg;
732 sfcgal::errorHandler()->clearText( &errorMsg );
733 sfcgal::shared_geom otherSharedr = QgsSfcgalEngine::fromAbstractGeometry( otherGeom, &errorMsg );
734 THROW_ON_ERROR( &errorMsg );
735
736 sfcgal::shared_geom geom = workingGeom();
737 sfcgal::shared_geom result = QgsSfcgalEngine::difference( geom.get(), otherSharedr.get(), &errorMsg );
738 THROW_ON_ERROR( &errorMsg );
739
740 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
741 THROW_ON_ERROR( &errorMsg );
742 return resultGeom;
743}
744
745std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::difference( const QgsSfcgalGeometry &otherGeom ) const
746{
747 QString errorMsg;
748 sfcgal::errorHandler()->clearText( &errorMsg );
749
750 sfcgal::shared_geom geom = workingGeom();
751 sfcgal::shared_geom result = QgsSfcgalEngine::difference( geom.get(), otherGeom.workingGeom().get(), &errorMsg );
752 THROW_ON_ERROR( &errorMsg );
753
754 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
755 THROW_ON_ERROR( &errorMsg );
756 return resultGeom;
757}
758
759std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::triangulate() const
760{
761 QString errorMsg;
762 sfcgal::errorHandler()->clearText( &errorMsg );
763
764 sfcgal::shared_geom geom = workingGeom();
765 sfcgal::shared_geom result = QgsSfcgalEngine::triangulate( geom.get(), &errorMsg );
766 THROW_ON_ERROR( &errorMsg );
767
768 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
769 THROW_ON_ERROR( &errorMsg );
770 return resultGeom;
771}
772
773std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::convexHull() const
774{
775 QString errorMsg;
776 sfcgal::errorHandler()->clearText( &errorMsg );
777
778 sfcgal::shared_geom geom = workingGeom();
779 sfcgal::shared_geom result = QgsSfcgalEngine::convexHull( geom.get(), &errorMsg );
780 THROW_ON_ERROR( &errorMsg );
781
782 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
783 THROW_ON_ERROR( &errorMsg );
784 return resultGeom;
785}
786
787std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::envelope() const
788{
789 QString errorMsg;
790 sfcgal::errorHandler()->clearText( &errorMsg );
791
792 sfcgal::shared_geom geom = workingGeom();
793 sfcgal::shared_geom result = QgsSfcgalEngine::envelope( geom.get(), &errorMsg );
794 THROW_ON_ERROR( &errorMsg );
795
796 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
797 THROW_ON_ERROR( &errorMsg );
798 return resultGeom;
799}
800
801bool QgsSfcgalGeometry::covers( const QgsSfcgalGeometry &otherGeom ) const
802{
803 QString errorMsg;
804 sfcgal::errorHandler()->clearText( &errorMsg );
805
806 sfcgal::shared_geom geom = workingGeom();
807 bool out = QgsSfcgalEngine::covers( geom.get(), otherGeom.workingGeom().get(), &errorMsg );
808 THROW_ON_ERROR( &errorMsg );
809 return out;
810}
811
812std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::buffer3D( double radius, int segments, Qgis::JoinStyle3D joinStyle3D ) const
813{
814 QString errorMsg;
815 sfcgal::errorHandler()->clearText( &errorMsg );
816
817 sfcgal::shared_geom geom = workingGeom();
818 sfcgal::shared_geom result = QgsSfcgalEngine::buffer3D( geom.get(), radius, segments, joinStyle3D, &errorMsg );
819 THROW_ON_ERROR( &errorMsg );
820
821 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
822 THROW_ON_ERROR( &errorMsg );
823 return resultGeom;
824}
825
826std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::buffer2D( double radius, int segments, Qgis::JoinStyle joinStyle ) const
827{
828 QString errorMsg;
829 sfcgal::errorHandler()->clearText( &errorMsg );
830
831 sfcgal::shared_geom geom = workingGeom();
832 sfcgal::shared_geom result = QgsSfcgalEngine::buffer2D( geom.get(), radius, segments, joinStyle, &errorMsg );
833 THROW_ON_ERROR( &errorMsg );
834
835 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
836 THROW_ON_ERROR( &errorMsg );
837 return resultGeom;
838}
839
840std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::simplify( double tolerance, bool preserveTopology ) const
841{
842 QString errorMsg;
843 sfcgal::errorHandler()->clearText( &errorMsg );
844
845 sfcgal::shared_geom geom = workingGeom();
846 sfcgal::shared_geom result = QgsSfcgalEngine::simplify( geom.get(), tolerance, preserveTopology, &errorMsg );
847 THROW_ON_ERROR( &errorMsg );
848
849 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
850 THROW_ON_ERROR( &errorMsg );
851 return resultGeom;
852}
853
854std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::extrude( const QgsVector3D &extrusion ) const
855{
856 QString errorMsg;
857 sfcgal::errorHandler()->clearText( &errorMsg );
858
859 sfcgal::shared_geom geom = workingGeom();
860 sfcgal::shared_geom result = QgsSfcgalEngine::extrude( geom.get(), extrusion, &errorMsg );
861 THROW_ON_ERROR( &errorMsg );
862
863 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
864 THROW_ON_ERROR( &errorMsg );
865 return resultGeom;
866}
867
868std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::approximateMedialAxis() const
869{
870 QString errorMsg;
871 sfcgal::errorHandler()->clearText( &errorMsg );
872
873 sfcgal::shared_geom geom = workingGeom();
874 sfcgal::shared_geom result = QgsSfcgalEngine::approximateMedialAxis( geom.get(), &errorMsg );
875 THROW_ON_ERROR( &errorMsg );
876
877 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
878 THROW_ON_ERROR( &errorMsg );
879 return resultGeom;
880}
881
882std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::createCube( double size )
883{
884#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
885 QString errorMsg;
886 sfcgal::errorHandler()->clearText( &errorMsg );
887 sfcgal::shared_prim result = QgsSfcgalEngine::createCube( size, &errorMsg );
888 THROW_ON_ERROR( &errorMsg );
889
890 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, sfcgal::primitiveType::SFCGAL_TYPE_CUBE, &errorMsg );
891 THROW_ON_ERROR( &errorMsg );
892 return resultGeom;
893#else
894 ( void ) size;
895 throw QgsNotSupportedException( QObject::tr( "This operation requires a QGIS build based on SFCGAL 2.3 or later" ) );
896#endif
897}
898
899std::unique_ptr<QgsSfcgalGeometry> QgsSfcgalGeometry::primitiveAsPolyhedralSurface() const
900{
901#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
902 if ( !mIsPrimitive )
903 throw QgsSfcgalException( "Need primitive geometry to operate." );
904
905 QString errorMsg;
906 sfcgal::errorHandler()->clearText( &errorMsg );
907 sfcgal::shared_prim result = QgsSfcgalEngine::primitiveAsPolyhedral( mSfcgalPrim.get(), mPrimTransform, &errorMsg );
908 THROW_ON_ERROR( &errorMsg );
909
910 auto resultGeom = QgsSfcgalEngine::toSfcgalGeometry( result, &errorMsg );
911 THROW_ON_ERROR( &errorMsg );
912 return resultGeom;
913#else
914 throw QgsNotSupportedException( QObject::tr( "This operation requires a QGIS build based on SFCGAL 2.3 or later" ) );
915#endif
916}
917
918QMatrix4x4 QgsSfcgalGeometry::primitiveTransform() const
919{
920#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
921 if ( !mIsPrimitive )
922 throw QgsSfcgalException( "Need primitive geometry to operate." );
923
924 return mPrimTransform;
925#else
926 throw QgsNotSupportedException( QObject::tr( "This operation requires a QGIS build based on SFCGAL 2.3 or later" ) );
927#endif
928}
929
930QList<std::pair<QString, QString>> QgsSfcgalGeometry::primitiveParameters() const
931{
932#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
933 if ( !mIsPrimitive )
934 throw QgsSfcgalException( "Need primitive geometry to operate." );
935
936 QString errorMsg;
937 sfcgal::errorHandler()->clearText( &errorMsg );
938 QVector<sfcgal::PrimitiveParameterDesc> result = QgsSfcgalEngine::primitiveParameters( mSfcgalPrim.get(), &errorMsg );
939 THROW_ON_ERROR( &errorMsg );
940
941 QList<QPair<QString, QString>> out;
942 for ( const auto &param : result )
943 {
944 out.append( std::pair<QString, QString>( QString::fromStdString( param.name ), QString::fromStdString( param.type ) ) );
945 }
946
947 return out;
948#else
949 throw QgsNotSupportedException( QObject::tr( "This operation requires a QGIS build based on SFCGAL 2.3 or later" ) );
950#endif
951}
952
953QVariant QgsSfcgalGeometry::primitiveParameter( const QString &name ) const
954{
955#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
956 if ( !mIsPrimitive )
957 throw QgsSfcgalException( "Need primitive geometry to operate." );
958
959 QString errorMsg;
960 sfcgal::errorHandler()->clearText( &errorMsg );
961 QVariant result = QgsSfcgalEngine::primitiveParameter( mSfcgalPrim.get(), name, &errorMsg );
962 THROW_ON_ERROR( &errorMsg );
963
964 return result;
965#else
966 ( void ) name;
967 throw QgsNotSupportedException( QObject::tr( "This operation requires a QGIS build based on SFCGAL 2.3 or later" ) );
968#endif
969}
970
971void QgsSfcgalGeometry::primitiveSetParameter( const QString &name, const QVariant &value )
972{
973#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
974 if ( !mIsPrimitive )
975 throw QgsSfcgalException( "Need primitive geometry to operate." );
976
977 QString errorMsg;
978 sfcgal::errorHandler()->clearText( &errorMsg );
979 QgsSfcgalEngine::primitiveSetParameter( mSfcgalPrim.get(), name, value, &errorMsg );
980 THROW_ON_ERROR( &errorMsg );
981
982#else
983 ( void ) name;
984 ( void ) value;
985 throw QgsNotSupportedException( QObject::tr( "This operation requires a QGIS build based on SFCGAL 2.3 or later" ) );
986#endif
987}
988
989
990#if SFCGAL_VERSION_NUM >= SFCGAL_MAKE_VERSION( 2, 3, 0 )
991void QgsSfcgalGeometry::setPrimitiveTranslate( const QgsVector3D &translation )
992{
993 mPrimTransform.translate( mPrimTransform.column( 3 ).toVector3D() + translation.toVector3D() );
994}
995
996void QgsSfcgalGeometry::setPrimitiveScale( const QgsVector3D &scaleFactor, const QgsPoint &center )
997{
998 QVector3D qCenter( center.x(), center.y(), center.z() );
999 QVector3D prevTrans = mPrimTransform.column( 3 ).toVector3D();
1000 mPrimTransform.translate( prevTrans - qCenter );
1001 mPrimTransform.scale( scaleFactor.toVector3D() );
1002 mPrimTransform.translate( prevTrans + qCenter );
1003}
1004
1005void QgsSfcgalGeometry::setPrimitiveRotation( double angle, const QgsVector3D &axisVector, const QgsPoint &center )
1006{
1007 QVector3D qCenter( center.x(), center.y(), center.z() );
1008 QVector3D prevTrans = mPrimTransform.column( 3 ).toVector3D();
1009 mPrimTransform.translate( prevTrans - qCenter );
1010 // TODO: need to merge previous rotation values with the new ones
1011 mPrimTransform.rotate( QQuaternion::fromAxisAndAngle( axisVector.toVector3D(), angle ) );
1012 mPrimTransform.translate( prevTrans + qCenter );
1013}
1014
1015#endif
1016
1017#endif
JoinStyle3D
Join styles for 3D buffers.
Definition qgis.h:2214
JoinStyle
Join styles for buffers.
Definition qgis.h:2201
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:294
@ PolyhedralSurfaceZ
PolyhedralSurfaceZ.
Definition qgis.h:326
Abstract base class for all geometries.
QFlags< WkbFlag > WkbFlags
A const WKB pointer.
Definition qgswkbptr.h:211
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Custom exception class which is raised when an operation is not supported.
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
double z
Definition qgspoint.h:58
double x
Definition qgspoint.h:56
double y
Definition qgspoint.h:57
Custom exception class for SfCGAL related operations.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
Definition qgsvector3d.h:33
QVector3D toVector3D() const
Converts the current object to QVector3D.