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