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