39 : mGeometry( geometry.constGet() )
58 QVector<QgsLineString *> linesToProcess;
60 const QgsMultiCurve *multiCurve = qgsgeometry_cast< const QgsMultiCurve * >( mGeometry );
63 linesToProcess.reserve( multiCurve->
partCount() );
64 for (
int i = 0; i < multiCurve->
partCount(); ++i )
66 linesToProcess << static_cast<QgsLineString *>( multiCurve->
geometryN( i )->
clone() );
70 const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( mGeometry );
73 linesToProcess << static_cast<QgsLineString *>( curve->
segmentize() );
76 std::unique_ptr<QgsMultiPolygon> multipolygon( linesToProcess.size() > 1 ?
new QgsMultiPolygon() :
nullptr );
79 if ( !linesToProcess.empty() )
81 std::unique_ptr< QgsLineString > secondline;
82 for (
QgsLineString *line : qgis::as_const( linesToProcess ) )
84 QTransform transform = QTransform::fromTranslate( x, y );
86 secondline.reset( line->reversed() );
87 secondline->transform( transform );
89 line->append( secondline.get() );
90 line->addVertex( line->pointN( 0 ) );
96 multipolygon->addGeometry( polygon );
118 Cell(
double x,
double y,
double h,
const QgsPolygon *polygon )
122 , d( polygon->pointDistanceToBoundary( x, y ) )
123 , max( d + h * M_SQRT2 )
138 struct GreaterThanByMax
140 bool operator()(
const Cell *lhs,
const Cell *rhs )
142 return rhs->max > lhs->max;
146 Cell *getCentroidCell(
const QgsPolygon *polygon )
154 for (
int i = 0, j = len - 1; i < len; j = i++ )
156 double aX = exterior->
xAt( i );
157 double aY = exterior->
yAt( i );
158 double bX = exterior->
xAt( j );
159 double bY = exterior->
yAt( j );
160 double f = aX * bY - bX * aY;
161 x += ( aX + bX ) * f;
162 y += ( aY + bY ) * f;
166 return new Cell( exterior->
xAt( 0 ), exterior->
yAt( 0 ), 0, polygon );
168 return new Cell( x / area, y / area, 0.0, polygon );
173 std::unique_ptr< QgsPolygon > segmentizedPoly;
174 const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( surface );
178 polygon = segmentizedPoly.get();
185 double cellSize = std::min( bounds.
width(), bounds.
height() );
190 double h = cellSize / 2.0;
191 std::priority_queue< Cell *, std::vector<Cell *>, GreaterThanByMax > cellQueue;
198 cellQueue.push(
new Cell( x + h, y + h, h, polygon ) );
203 std::unique_ptr< Cell > bestCell( getCentroidCell( polygon ) );
206 std::unique_ptr< Cell > bboxCell(
new Cell( bounds.
xMinimum() + bounds.
width() / 2.0,
209 if ( bboxCell->d > bestCell->d )
211 bestCell = std::move( bboxCell );
214 while ( !cellQueue.empty() )
217 std::unique_ptr< Cell > cell( cellQueue.top() );
219 Cell *currentCell = cell.get();
222 if ( currentCell->d > bestCell->d )
224 bestCell = std::move( cell );
228 if ( currentCell->max - bestCell->d <=
precision )
232 h = currentCell->h / 2.0;
233 cellQueue.push(
new Cell( currentCell->x - h, currentCell->y - h, h, polygon ) );
234 cellQueue.push(
new Cell( currentCell->x + h, currentCell->y - h, h, polygon ) );
235 cellQueue.push(
new Cell( currentCell->x - h, currentCell->y + h, h, polygon ) );
236 cellQueue.push(
new Cell( currentCell->x + h, currentCell->y + h, h, polygon ) );
239 distanceFromBoundary = bestCell->d;
241 return QgsPoint( bestCell->x, bestCell->y );
249 if ( distanceFromBoundary )
250 *distanceFromBoundary = std::numeric_limits<double>::max();
252 if ( !mGeometry || mGeometry->
isEmpty() )
258 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
260 int numGeom = gc->numGeometries();
264 for (
int i = 0; i < numGeom; ++i )
266 const QgsSurface *surface = qgsgeometry_cast< const QgsSurface * >( gc->geometryN( i ) );
271 double dist = std::numeric_limits<double>::max();
273 if ( dist > maxDist )
283 if ( distanceFromBoundary )
284 *distanceFromBoundary = maxDist;
289 const QgsSurface *surface = qgsgeometry_cast< const QgsSurface * >( mGeometry );
293 double dist = std::numeric_limits<double>::max();
295 if ( distanceFromBoundary )
296 *distanceFromBoundary = dist;
307 return lowerThreshold > std::fabs( dotProduct ) || std::fabs( dotProduct ) > upperThreshold;
333 for (
int i = 0; i < numPoints; ++i )
335 if ( !isClosed && i == numPoints - 1 )
337 else if ( !isClosed && i == 0 )
346 a = ring->
pointN( numPoints - 1 );
349 if ( i == numPoints - 1 )
358 sum += 2.0 * std::min( std::fabs( dotProduct - 1.0 ), std::min( std::fabs( dotProduct ), std::fabs( dotProduct + 1 ) ) );
368 double lowerThreshold,
double upperThreshold )
377 double scale = 2.0 * std::min( p.
length(), q.
length() );
381 double dotProduct = p * q;
390 if ( dotProduct < -M_SQRT1_2 )
395 return new_v.
normalized() * ( 0.1 * dotProduct * scale );
400 double minScore = std::numeric_limits<double>::max();
405 std::unique_ptr< QgsLineString > best( ring->
clone() );
407 QVector< QgsVector > motions;
408 motions.reserve( numPoints );
410 for (
int it = 0; it < iterations; ++it )
418 for (
int i = 0; i < numPoints; ++i )
420 if ( isClosed && i == numPoints - 1 )
421 motions << motions.at( 0 );
422 else if ( !isClosed && ( i == 0 || i == numPoints - 1 ) )
432 a = ring->
pointN( numPoints - 1 );
435 if ( i == numPoints - 1 )
440 motions <<
calcMotion( a, b,
c, lowerThreshold, upperThreshold );
447 for (
int i = 0; i < numPoints; ++i )
449 ring->
setXAt( i, ring->
xAt( i ) + motions.at( i ).x() );
450 ring->
setYAt( i, ring->
yAt( i ) + motions.at( i ).y() );
453 double newScore =
squareness( ring, lowerThreshold, upperThreshold );
454 if ( newScore < minScore )
456 best.reset( ring->
clone() );
460 if ( minScore < tolerance )
466 return best.release();
472 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
476 geom = segmentizedCopy.get();
482 maxIterations, tolerance, lowerThreshold, upperThreshold );
491 maxIterations, tolerance, lowerThreshold, upperThreshold ) );
495 maxIterations, tolerance, lowerThreshold, upperThreshold ) );
511 double lowerThreshold = std::cos( ( 90 - angleThreshold ) * M_PI / 180.00 );
512 double upperThreshold = std::cos( angleThreshold * M_PI / 180.0 );
514 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
516 int numGeom = gc->numGeometries();
517 QVector< QgsAbstractGeometry * > geometryList;
518 geometryList.reserve( numGeom );
519 for (
int i = 0; i < numGeom; ++i )
521 geometryList <<
orthogonalizeGeom( gc->geometryN( i ), maxIterations, tolerance, lowerThreshold, upperThreshold );
540 QVector< double > outX;
541 QVector< double > outY;
542 QVector< double > outZ;
543 QVector< double > outM;
544 double multiplier = 1.0 / double( extraNodesPerSegment + 1 );
547 outX.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
548 outY.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
549 bool withZ = ring->
is3D();
551 outZ.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
554 outM.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
567 int extraNodesThisSegment = extraNodesPerSegment;
568 for (
int i = 0; i < nPoints - 1; ++i )
571 x2 = ring->
xAt( i + 1 );
573 y2 = ring->
yAt( i + 1 );
577 z2 = ring->
zAt( i + 1 );
582 m2 = ring->
mAt( i + 1 );
592 if ( extraNodesPerSegment < 0 )
595 extraNodesThisSegment = std::floor( std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) ) / distance );
596 if ( extraNodesThisSegment >= 1 )
597 multiplier = 1.0 / ( extraNodesThisSegment + 1 );
600 for (
int j = 0; j < extraNodesThisSegment; ++j )
602 double delta = multiplier * ( j + 1 );
603 xOut = x1 + delta * ( x2 - x1 );
604 yOut = y1 + delta * ( y2 - y1 );
606 zOut = z1 + delta * ( z2 - z1 );
608 mOut = m1 + delta * ( m2 - m1 );
618 outX << ring->
xAt( nPoints - 1 );
619 outY << ring->
yAt( nPoints - 1 );
621 outZ << ring->
zAt( nPoints - 1 );
623 outM << ring->
mAt( nPoints - 1 );
631 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
635 geom = segmentizedCopy.get();
649 extraNodesPerSegment, distance ) );
653 extraNodesPerSegment, distance ) );
673 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
675 int numGeom = gc->numGeometries();
676 QVector< QgsAbstractGeometry * > geometryList;
677 geometryList.reserve( numGeom );
678 for (
int i = 0; i < numGeom; ++i )
680 geometryList <<
densifyGeometry( gc->geometryN( i ), extraNodesPerSegment );
709 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
711 int numGeom = gc->numGeometries();
712 QVector< QgsAbstractGeometry * > geometryList;
713 geometryList.reserve( numGeom );
714 for (
int i = 0; i < numGeom; ++i )
741 "line_segment_dist_comparer",
742 "AB must not be collinear with the origin." );
744 "line_segment_dist_comparer",
745 "CD must not be collinear with the origin." );
759 if ( ab.
end() == cd.
end() || oad != oab )
769 if ( cdb == 0 && cda == 0 )
771 return mOrigin.sqrDist( ab.
start() ) < mOrigin.sqrDist( cd.
start() );
773 else if ( cda == cdb || cda == 0 || cdb == 0 )
776 return cdo == cda || cdo == cdb;
792 const bool aIsLeft = a.
x() < mVertex.x();
793 const bool bIsLeft = b.
x() < mVertex.x();
794 if ( aIsLeft != bIsLeft )
799 if ( a.
y() >= mVertex.y() || b.
y() >= mVertex.y() )
801 return b.
y() < a.
y();
805 return a.
y() < b.
y();
844 const double distA = ao * direction;
845 const double distB = ( origin - segment.
end() ) * direction;
847 if ( distA > 0 && distB > 0 )
853 if ( ( distA > 0 ) != ( distB > 0 ) )
854 intersectPoint = origin;
855 else if ( distA > distB )
856 intersectPoint = segment.
start();
858 intersectPoint = segment.
end();
866 if ( u < 0.0 || 1.0 < u )
873 intersectPoint = origin + direction * t;
882 if ( radius1 > radius2 )
889 QVector<QgsPointXY> points;
911 std::vector< std::unique_ptr<QgsLineString > > linesToProcess;
913 const QgsMultiCurve *multiCurve = qgsgeometry_cast< const QgsMultiCurve * >( mGeometry );
916 for (
int i = 0; i < multiCurve->
partCount(); ++i )
925 const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( mGeometry );
932 if ( linesToProcess.empty() )
935 g.mLastError = QStringLiteral(
"Input geometry was not a curve type geometry" );
939 QVector<QgsGeometry> bufferedLines;
940 bufferedLines.reserve( linesToProcess.size() );
942 for ( std::unique_ptr< QgsLineString > &line : linesToProcess )
944 QVector<QgsGeometry> parts;
946 double prevRadius = 0;
949 std::unique_ptr< double[] > widths = widthFunction( line.get() ) ;
954 double thisRadius = widths[ i ] / 2.0;
955 if ( thisRadius > 0 )
970 if ( prevRadius > 0 || thisRadius > 0 )
972 QVector< QgsPointXY > points =
generateSegmentCurve( prevPoint, prevRadius, thisPoint, thisRadius );
973 if ( !points.empty() )
978 int beforeVertex = 0;
981 double sqrDistPrev = 0;
982 for (
int j = 0; j < points.count(); ++j )
986 points[j] = sqrDistPrev < sqrDist ? pA : pB;
989 points.append( points.at( 0 ) );
991 std::unique_ptr< QgsPolygon > poly = qgis::make_unique< QgsPolygon >();
993 if ( poly->area() > 0 )
998 prevPoint = thisPoint;
999 prevRadius = thisRadius;
1000 prevCircle = thisCircle;
1012 start = std::fabs( start );
1013 end = std::fabs( end );
1019 std::unique_ptr< double [] > widths(
new double[ line->nCoordinates() ] );
1021 widths[line->nCoordinates() - 1] = end;
1023 double lineLength = line->length();
1024 double currentLength = 0;
1025 QgsPoint prevPoint = line->pointN( 0 );
1026 for (
int i = 1; i < line->nCoordinates() - 1; ++i )
1028 QgsPoint point = line->pointN( i );
1029 double segmentLength = point.
distance( prevPoint );
1030 currentLength += segmentLength;
1031 double lengthFraction = lineLength > 0 ? currentLength / lineLength : 1;
1032 double delta = lengthFraction * ( end - start );
1033 widths[i] = start + delta;
1047 std::unique_ptr< double [] > widths(
new double[ line->nCoordinates() ] );
1048 for (
int i = 0; i < line->nCoordinates(); ++i )
1050 widths[ i ] = line->mAt( i );
1059 const std::function<
bool(
const QgsPointXY & ) > &acceptPoint,
unsigned long seed,
QgsFeedback *feedback,
int maxTriesPerPoint )
1062 return QVector< QgsPointXY >();
1074 return QVector< QgsPointXY >();
1082 std::unique_ptr< QgsPolygon > p( qgsgeometry_cast< QgsPolygon * >( ms->
geometryN( i )->
segmentize() ) );
1089 if (
const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( polygon.
constGet() ) )
1095 std::unique_ptr< QgsPolygon > p( qgsgeometry_cast< QgsPolygon * >( polygon.
constGet()->
segmentize() ) );
1101 return QVector< QgsPointXY >();
1103 const QVector<float> triangleData = t.
data();
1104 if ( triangleData.empty() )
1105 return QVector< QgsPointXY >();
1108 std::vector< double > cumulativeAreas;
1110 double totalArea = 0;
1111 for (
auto it = triangleData.constBegin(); it != triangleData.constEnd(); )
1114 return QVector< QgsPointXY >();
1116 const float aX = *it++;
1118 const float aY = -( *it++ );
1119 const float bX = *it++;
1121 const float bY = -( *it++ );
1122 const float cX = *it++;
1124 const float cY = -( *it++ );
1128 cumulativeAreas.emplace_back( totalArea );
1131 std::random_device rd;
1132 std::mt19937 mt( seed == 0 ? rd() : seed );
1133 std::uniform_real_distribution<> uniformDist( 0, 1 );
1136 auto selectRandomTriangle = [&cumulativeAreas, totalArea](
double random )->
int
1139 const double target = random * totalArea;
1140 for (
auto it = cumulativeAreas.begin(); it != cumulativeAreas.end(); ++it, triangle++ )
1145 Q_ASSERT_X(
false,
"QgsInternalGeometryEngine::randomPointsInPolygon",
"Invalid random triangle index" );
1150 QVector<QgsPointXY> result;
1151 result.reserve( count );
1153 for (
int i = 0; i < count; )
1156 return QVector< QgsPointXY >();
1158 const double triangleIndexRnd = uniformDist( mt );
1160 const int triangleIndex = selectRandomTriangle( triangleIndexRnd );
1163 const double weightB = uniformDist( mt );
1164 const double weightC = uniformDist( mt );
1169 const double aX = triangleData.at( triangleIndex * 9 ) + bounds.
xMinimum();
1170 const double aY = -triangleData.at( triangleIndex * 9 + 2 ) + bounds.
yMinimum();
1171 const double bX = triangleData.at( triangleIndex * 9 + 3 ) + bounds.
xMinimum();
1172 const double bY = -triangleData.at( triangleIndex * 9 + 5 ) + bounds.
yMinimum();
1173 const double cX = triangleData.at( triangleIndex * 9 + 6 ) + bounds.
xMinimum();
1174 const double cY = -triangleData.at( triangleIndex * 9 + 8 ) + bounds.
yMinimum();
1178 if ( acceptPoint( candidate ) )
1184 else if ( maxTriesPerPoint != 0 )
1188 if ( tries == maxTriesPerPoint )
1201 double pointSpacingAngleTolerance )
1203 std::unique_ptr< QgsCompoundCurve > out = qgis::make_unique< QgsCompoundCurve >();
1206 const unsigned int minQuadEdges = 2;
1219 out->addCurve( lineString->
clone() );
1225 QVector< int > edgesInArcs( numEdges + 1, 0 );
1229 double abX = b.x() - a.
x();
1230 double abY = b.y() - a.
y();
1232 double cbX = b.x() -
c.x();
1233 double cbY = b.y() -
c.y();
1235 double dot = ( abX * cbX + abY * cbY );
1236 double cross = ( abX * cbY - abY * cbX );
1238 double alpha = std::atan2( cross, dot );
1253 double centerX = 0.0;
1254 double centerY = 0.0;
1257 while ( i < numEdges - 2 )
1259 unsigned int arcEdges = 0;
1260 double numQuadrants = 0;
1263 bool foundArc =
false;
1265 a1 = lineString->
pointN( i );
1266 a2 = lineString->
pointN( i + 1 );
1267 a3 = lineString->
pointN( i + 2 );
1270 for ( j = i + 3; j < numEdges + 1; j++ )
1272 b = lineString->
pointN( j );
1279 for ( k = j - 1; k > j - 4; k-- )
1280 edgesInArcs[k] = currentArc;
1300 arcEdges = j - 1 - i;
1301 if ( first.
x() == b.
x() && first.
y() == b.
y() )
1316 numQuadrants = ( 4 *
angle ) / ( 2 * M_PI );
1319 if ( arcEdges < minQuadEdges * numQuadrants )
1322 for ( k = j - 1; k >= i; k-- )
1339 int edgeType = edgesInArcs[0];
1341 auto addPointsToCurve = [ lineString, &out ](
int start,
int end,
int type )
1346 QVector< QgsPoint > points;
1347 for (
int j = start; j < end + 2; ++ j )
1349 points.append( lineString->
pointN( j ) );
1351 std::unique_ptr< QgsCurve > straightSegment = qgis::make_unique< QgsLineString >( points );
1352 out->addCurve( straightSegment.release() );
1357 QVector< QgsPoint > points;
1358 points.append( lineString->
pointN( start ) );
1359 points.append( lineString->
pointN( ( start + end + 1 ) / 2 ) );
1360 points.append( lineString->
pointN( end + 1 ) );
1361 std::unique_ptr< QgsCircularString > curvedSegment = qgis::make_unique< QgsCircularString >();
1362 curvedSegment->setPoints( points );
1363 out->addCurve( curvedSegment.release() );
1367 for (
int i = 1; i < numEdges; i++ )
1369 if ( edgeType != edgesInArcs[i] )
1372 addPointsToCurve( start, end, edgeType );
1374 edgeType = edgesInArcs[i];
1380 addPointsToCurve( start, end, edgeType );
1395 std::unique_ptr< QgsCurvePolygon > result = qgis::make_unique< QgsCurvePolygon>();
1398 distanceTolerance, angleTolerance ).release() );
1402 distanceTolerance, angleTolerance ).release() );
1429 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
1431 int numGeom = gc->numGeometries();
1432 QVector< QgsAbstractGeometry * > geometryList;
1433 geometryList.reserve( numGeom );
1434 for (
int i = 0; i < numGeom; ++i )
1457 area = std::numeric_limits<double>::max();
1459 width = std::numeric_limits<double>::max();
1460 height = std::numeric_limits<double>::max();
1467 std::unique_ptr< QgsAbstractGeometry > hull( engine->convexHull( &mLastError ) );
1478 double totalRotation = 0;
1479 while ( hull->nextVertex( vertexId, pt2 ) )
1482 double rotateAngle = 180.0 / M_PI * currentAngle;
1483 totalRotation += rotateAngle;
1485 QTransform t = QTransform::fromTranslate( pt0.
x(), pt0.
y() );
1486 t.rotate( rotateAngle );
1487 t.translate( -pt0.
x(), -pt0.
y() );
1489 hull->transform( t );
1492 double currentArea = bounds.
width() * bounds.
height();
1493 if ( currentArea < area )
1497 angle = totalRotation;
1498 width = bounds.
width();
1499 height = bounds.
height();
1509 if (
angle > 180.0 )