38 : mGeometry( geometry.constGet() )
51 QVector<QgsLineString *> linesToProcess;
53 const QgsMultiCurve *multiCurve = qgsgeometry_cast< const QgsMultiCurve * >( mGeometry );
56 linesToProcess.reserve( multiCurve->
partCount() );
57 for (
int i = 0; i < multiCurve->
partCount(); ++i )
59 linesToProcess << static_cast<QgsLineString *>( multiCurve->
geometryN( i )->
clone() );
63 const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( mGeometry );
66 linesToProcess << static_cast<QgsLineString *>( curve->
segmentize() );
69 std::unique_ptr<QgsMultiPolygon> multipolygon( linesToProcess.size() > 1 ?
new QgsMultiPolygon() :
nullptr );
72 if ( !linesToProcess.empty() )
74 std::unique_ptr< QgsLineString > secondline;
75 for (
QgsLineString *line : qgis::as_const( linesToProcess ) )
77 QTransform transform = QTransform::fromTranslate( x, y );
79 secondline.reset( line->reversed() );
80 secondline->transform( transform );
82 line->append( secondline.get() );
83 line->addVertex( line->pointN( 0 ) );
89 multipolygon->addGeometry( polygon );
111 Cell(
double x,
double y,
double h,
const QgsPolygon *polygon )
115 , d( polygon->pointDistanceToBoundary( x, y ) )
116 , max( d + h * M_SQRT2 )
131 struct GreaterThanByMax
133 bool operator()(
const Cell *lhs,
const Cell *rhs )
135 return rhs->max > lhs->max;
139 Cell *getCentroidCell(
const QgsPolygon *polygon )
147 for (
int i = 0, j = len - 1; i < len; j = i++ )
149 double aX = exterior->
xAt( i );
150 double aY = exterior->
yAt( i );
151 double bX = exterior->
xAt( j );
152 double bY = exterior->
yAt( j );
153 double f = aX * bY - bX * aY;
154 x += ( aX + bX ) * f;
155 y += ( aY + bY ) * f;
159 return new Cell( exterior->
xAt( 0 ), exterior->
yAt( 0 ), 0, polygon );
161 return new Cell( x / area, y / area, 0.0, polygon );
166 std::unique_ptr< QgsPolygon > segmentizedPoly;
167 const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( surface );
171 polygon = segmentizedPoly.get();
178 double cellSize = std::min( bounds.
width(), bounds.
height() );
183 double h = cellSize / 2.0;
184 std::priority_queue< Cell *, std::vector<Cell *>, GreaterThanByMax > cellQueue;
191 cellQueue.push(
new Cell( x + h, y + h, h, polygon ) );
196 std::unique_ptr< Cell > bestCell( getCentroidCell( polygon ) );
199 std::unique_ptr< Cell > bboxCell(
new Cell( bounds.
xMinimum() + bounds.
width() / 2.0,
202 if ( bboxCell->d > bestCell->d )
204 bestCell = std::move( bboxCell );
207 while ( !cellQueue.empty() )
210 std::unique_ptr< Cell > cell( cellQueue.top() );
212 Cell *currentCell = cell.get();
215 if ( currentCell->d > bestCell->d )
217 bestCell = std::move( cell );
221 if ( currentCell->max - bestCell->d <=
precision )
225 h = currentCell->h / 2.0;
226 cellQueue.push(
new Cell( currentCell->x - h, currentCell->y - h, h, polygon ) );
227 cellQueue.push(
new Cell( currentCell->x + h, currentCell->y - h, h, polygon ) );
228 cellQueue.push(
new Cell( currentCell->x - h, currentCell->y + h, h, polygon ) );
229 cellQueue.push(
new Cell( currentCell->x + h, currentCell->y + h, h, polygon ) );
232 distanceFromBoundary = bestCell->d;
234 return QgsPoint( bestCell->x, bestCell->y );
241 if ( distanceFromBoundary )
242 *distanceFromBoundary = std::numeric_limits<double>::max();
244 if ( !mGeometry || mGeometry->
isEmpty() )
250 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
252 int numGeom = gc->numGeometries();
256 for (
int i = 0; i < numGeom; ++i )
258 const QgsSurface *surface = qgsgeometry_cast< const QgsSurface * >( gc->geometryN( i ) );
263 double dist = std::numeric_limits<double>::max();
265 if ( dist > maxDist )
275 if ( distanceFromBoundary )
276 *distanceFromBoundary = maxDist;
281 const QgsSurface *surface = qgsgeometry_cast< const QgsSurface * >( mGeometry );
285 double dist = std::numeric_limits<double>::max();
287 if ( distanceFromBoundary )
288 *distanceFromBoundary = dist;
299 return lowerThreshold > std::fabs( dotProduct ) || std::fabs( dotProduct ) > upperThreshold;
325 for (
int i = 0; i < numPoints; ++i )
327 if ( !isClosed && i == numPoints - 1 )
329 else if ( !isClosed && i == 0 )
338 a = ring->
pointN( numPoints - 1 );
341 if ( i == numPoints - 1 )
350 sum += 2.0 * std::min( std::fabs( dotProduct - 1.0 ), std::min( std::fabs( dotProduct ), std::fabs( dotProduct + 1 ) ) );
360 double lowerThreshold,
double upperThreshold )
369 double scale = 2.0 * std::min( p.
length(), q.
length() );
373 double dotProduct = p * q;
382 if ( dotProduct < -M_SQRT1_2 )
387 return new_v.
normalized() * ( 0.1 * dotProduct * scale );
392 double minScore = std::numeric_limits<double>::max();
397 std::unique_ptr< QgsLineString > best( ring->
clone() );
399 QVector< QgsVector > motions;
400 motions.reserve( numPoints );
402 for (
int it = 0; it < iterations; ++it )
410 for (
int i = 0; i < numPoints; ++i )
412 if ( isClosed && i == numPoints - 1 )
413 motions << motions.at( 0 );
414 else if ( !isClosed && ( i == 0 || i == numPoints - 1 ) )
424 a = ring->
pointN( numPoints - 1 );
427 if ( i == numPoints - 1 )
432 motions <<
calcMotion( a, b,
c, lowerThreshold, upperThreshold );
439 for (
int i = 0; i < numPoints; ++i )
441 ring->
setXAt( i, ring->
xAt( i ) + motions.at( i ).x() );
442 ring->
setYAt( i, ring->
yAt( i ) + motions.at( i ).y() );
445 double newScore =
squareness( ring, lowerThreshold, upperThreshold );
446 if ( newScore < minScore )
448 best.reset( ring->
clone() );
452 if ( minScore < tolerance )
458 return best.release();
464 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
468 geom = segmentizedCopy.get();
474 maxIterations, tolerance, lowerThreshold, upperThreshold );
483 maxIterations, tolerance, lowerThreshold, upperThreshold ) );
487 maxIterations, tolerance, lowerThreshold, upperThreshold ) );
502 double lowerThreshold = std::cos( ( 90 - angleThreshold ) * M_PI / 180.00 );
503 double upperThreshold = std::cos( angleThreshold * M_PI / 180.0 );
505 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
507 int numGeom = gc->numGeometries();
508 QVector< QgsAbstractGeometry * > geometryList;
509 geometryList.reserve( numGeom );
510 for (
int i = 0; i < numGeom; ++i )
512 geometryList <<
orthogonalizeGeom( gc->geometryN( i ), maxIterations, tolerance, lowerThreshold, upperThreshold );
531 QVector< double > outX;
532 QVector< double > outY;
533 QVector< double > outZ;
534 QVector< double > outM;
535 double multiplier = 1.0 / double( extraNodesPerSegment + 1 );
538 outX.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
539 outY.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
540 bool withZ = ring->
is3D();
542 outZ.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
545 outM.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
558 int extraNodesThisSegment = extraNodesPerSegment;
559 for (
int i = 0; i < nPoints - 1; ++i )
562 x2 = ring->
xAt( i + 1 );
564 y2 = ring->
yAt( i + 1 );
568 z2 = ring->
zAt( i + 1 );
573 m2 = ring->
mAt( i + 1 );
583 if ( extraNodesPerSegment < 0 )
586 extraNodesThisSegment = std::floor( std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) ) / distance );
587 if ( extraNodesThisSegment >= 1 )
588 multiplier = 1.0 / ( extraNodesThisSegment + 1 );
591 for (
int j = 0; j < extraNodesThisSegment; ++j )
593 double delta = multiplier * ( j + 1 );
594 xOut = x1 + delta * ( x2 - x1 );
595 yOut = y1 + delta * ( y2 - y1 );
597 zOut = z1 + delta * ( z2 - z1 );
599 mOut = m1 + delta * ( m2 - m1 );
609 outX << ring->
xAt( nPoints - 1 );
610 outY << ring->
yAt( nPoints - 1 );
612 outZ << ring->
zAt( nPoints - 1 );
614 outM << ring->
mAt( nPoints - 1 );
622 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
626 geom = segmentizedCopy.get();
640 extraNodesPerSegment, distance ) );
644 extraNodesPerSegment, distance ) );
663 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
665 int numGeom = gc->numGeometries();
666 QVector< QgsAbstractGeometry * > geometryList;
667 geometryList.reserve( numGeom );
668 for (
int i = 0; i < numGeom; ++i )
670 geometryList <<
densifyGeometry( gc->geometryN( i ), extraNodesPerSegment );
698 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
700 int numGeom = gc->numGeometries();
701 QVector< QgsAbstractGeometry * > geometryList;
702 geometryList.reserve( numGeom );
703 for (
int i = 0; i < numGeom; ++i )
730 "line_segment_dist_comparer",
731 "AB must not be collinear with the origin." );
733 "line_segment_dist_comparer",
734 "CD must not be collinear with the origin." );
748 if ( ab.
end() == cd.
end() || oad != oab )
758 if ( cdb == 0 && cda == 0 )
760 return mOrigin.sqrDist( ab.
start() ) < mOrigin.sqrDist( cd.
start() );
762 else if ( cda == cdb || cda == 0 || cdb == 0 )
765 return cdo == cda || cdo == cdb;
781 const bool aIsLeft = a.
x() < mVertex.x();
782 const bool bIsLeft = b.
x() < mVertex.x();
783 if ( aIsLeft != bIsLeft )
788 if ( a.
y() >= mVertex.y() || b.
y() >= mVertex.y() )
790 return b.
y() < a.
y();
794 return a.
y() < b.
y();
833 const double distA = ao * direction;
834 const double distB = ( origin - segment.
end() ) * direction;
836 if ( distA > 0 && distB > 0 )
842 if ( ( distA > 0 ) != ( distB > 0 ) )
843 intersectPoint = origin;
844 else if ( distA > distB )
845 intersectPoint = segment.
start();
847 intersectPoint = segment.
end();
855 if ( u < 0.0 || 1.0 < u )
862 intersectPoint = origin + direction * t;
871 if ( radius1 > radius2 )
878 QVector<QgsPointXY> points;
899 std::vector< std::unique_ptr<QgsLineString > > linesToProcess;
901 const QgsMultiCurve *multiCurve = qgsgeometry_cast< const QgsMultiCurve * >( mGeometry );
904 for (
int i = 0; i < multiCurve->
partCount(); ++i )
913 const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( mGeometry );
920 if ( linesToProcess.empty() )
923 g.mLastError = QStringLiteral(
"Input geometry was not a curve type geometry" );
927 QVector<QgsGeometry> bufferedLines;
928 bufferedLines.reserve( linesToProcess.size() );
930 for ( std::unique_ptr< QgsLineString > &line : linesToProcess )
932 QVector<QgsGeometry> parts;
934 double prevRadius = 0;
937 std::unique_ptr< double[] > widths = widthFunction( line.get() ) ;
942 double thisRadius = widths[ i ] / 2.0;
943 if ( thisRadius > 0 )
958 if ( prevRadius > 0 || thisRadius > 0 )
960 QVector< QgsPointXY > points =
generateSegmentCurve( prevPoint, prevRadius, thisPoint, thisRadius );
961 if ( !points.empty() )
966 int beforeVertex = 0;
969 double sqrDistPrev = 0;
970 for (
int j = 0; j < points.count(); ++j )
974 points[j] = sqrDistPrev < sqrDist ? pA : pB;
977 points.append( points.at( 0 ) );
979 std::unique_ptr< QgsPolygon > poly = qgis::make_unique< QgsPolygon >();
981 if ( poly->area() > 0 )
986 prevPoint = thisPoint;
987 prevRadius = thisRadius;
988 prevCircle = thisCircle;
999 start = std::fabs( start );
1000 end = std::fabs( end );
1006 std::unique_ptr< double [] > widths(
new double[ line->nCoordinates() ] );
1008 widths[line->nCoordinates() - 1] = end;
1010 double lineLength = line->length();
1011 double currentLength = 0;
1012 QgsPoint prevPoint = line->pointN( 0 );
1013 for (
int i = 1; i < line->nCoordinates() - 1; ++i )
1015 QgsPoint point = line->pointN( i );
1016 double segmentLength = point.
distance( prevPoint );
1017 currentLength += segmentLength;
1018 double lengthFraction = lineLength > 0 ? currentLength / lineLength : 1;
1019 double delta = lengthFraction * ( end - start );
1020 widths[i] = start + delta;
1033 std::unique_ptr< double [] > widths(
new double[ line->nCoordinates() ] );
1034 for (
int i = 0; i < line->nCoordinates(); ++i )
1036 widths[ i ] = line->mAt( i );
1045 const std::function<
bool(
const QgsPointXY & ) > &acceptPoint,
unsigned long seed,
QgsFeedback *feedback )
1048 return QVector< QgsPointXY >();
1060 return QVector< QgsPointXY >();
1068 std::unique_ptr< QgsPolygon > p( qgsgeometry_cast< QgsPolygon * >( ms->
geometryN( i )->
segmentize() ) );
1075 if (
const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( polygon.
constGet() ) )
1081 std::unique_ptr< QgsPolygon > p( qgsgeometry_cast< QgsPolygon * >( polygon.
constGet()->
segmentize() ) );
1087 return QVector< QgsPointXY >();
1089 const QVector<float> triangleData = t.
data();
1090 if ( triangleData.empty() )
1091 return QVector< QgsPointXY >();
1094 std::vector< double > cumulativeAreas;
1096 double totalArea = 0;
1097 for (
auto it = triangleData.constBegin(); it != triangleData.constEnd(); )
1100 return QVector< QgsPointXY >();
1102 const float aX = *it++;
1104 const float aY = -( *it++ );
1105 const float bX = *it++;
1107 const float bY = -( *it++ );
1108 const float cX = *it++;
1110 const float cY = -( *it++ );
1114 cumulativeAreas.emplace_back( totalArea );
1117 std::random_device rd;
1118 std::mt19937 mt( seed == 0 ? rd() : seed );
1119 std::uniform_real_distribution<> uniformDist( 0, 1 );
1122 auto selectRandomTriangle = [&cumulativeAreas, totalArea](
double random )->
int
1125 const double target = random * totalArea;
1126 for (
auto it = cumulativeAreas.begin(); it != cumulativeAreas.end(); ++it, triangle++ )
1131 Q_ASSERT_X(
false,
"QgsInternalGeometryEngine::randomPointsInPolygon",
"Invalid random triangle index" );
1136 QVector<QgsPointXY> result;
1137 result.reserve( count );
1138 for (
int i = 0; i < count; )
1141 return QVector< QgsPointXY >();
1143 const double triangleIndexRnd = uniformDist( mt );
1145 const int triangleIndex = selectRandomTriangle( triangleIndexRnd );
1148 const double weightB = uniformDist( mt );
1149 const double weightC = uniformDist( mt );
1154 const double aX = triangleData.at( triangleIndex * 9 ) + bounds.
xMinimum();
1155 const double aY = -triangleData.at( triangleIndex * 9 + 2 ) + bounds.
yMinimum();
1156 const double bX = triangleData.at( triangleIndex * 9 + 3 ) + bounds.
xMinimum();
1157 const double bY = -triangleData.at( triangleIndex * 9 + 5 ) + bounds.
yMinimum();
1158 const double cX = triangleData.at( triangleIndex * 9 + 6 ) + bounds.
xMinimum();
1159 const double cY = -triangleData.at( triangleIndex * 9 + 8 ) + bounds.
yMinimum();
1163 if ( acceptPoint( candidate ) )
1175 double pointSpacingAngleTolerance )
1177 std::unique_ptr< QgsCompoundCurve > out = qgis::make_unique< QgsCompoundCurve >();
1180 const unsigned int minQuadEdges = 2;
1193 out->addCurve( lineString->
clone() );
1199 QVector< int > edgesInArcs( numEdges + 1, 0 );
1203 double abX = b.x() - a.
x();
1204 double abY = b.y() - a.
y();
1206 double cbX = b.x() -
c.x();
1207 double cbY = b.y() -
c.y();
1209 double dot = ( abX * cbX + abY * cbY );
1210 double cross = ( abX * cbY - abY * cbX );
1212 double alpha = std::atan2( cross, dot );
1227 double centerX = 0.0;
1228 double centerY = 0.0;
1231 while ( i < numEdges - 2 )
1233 unsigned int arcEdges = 0;
1234 double numQuadrants = 0;
1237 bool foundArc =
false;
1239 a1 = lineString->
pointN( i );
1240 a2 = lineString->
pointN( i + 1 );
1241 a3 = lineString->
pointN( i + 2 );
1244 for ( j = i + 3; j < numEdges + 1; j++ )
1246 b = lineString->
pointN( j );
1253 for ( k = j - 1; k > j - 4; k-- )
1254 edgesInArcs[k] = currentArc;
1274 arcEdges = j - 1 - i;
1275 if ( first.
x() == b.
x() && first.
y() == b.
y() )
1290 numQuadrants = ( 4 *
angle ) / ( 2 * M_PI );
1293 if ( arcEdges < minQuadEdges * numQuadrants )
1296 for ( k = j - 1; k >= i; k-- )
1313 int edgeType = edgesInArcs[0];
1315 auto addPointsToCurve = [ lineString, &out ](
int start,
int end,
int type )
1320 QVector< QgsPoint > points;
1321 for (
int j = start; j < end + 2; ++ j )
1323 points.append( lineString->
pointN( j ) );
1325 std::unique_ptr< QgsCurve > straightSegment = qgis::make_unique< QgsLineString >( points );
1326 out->addCurve( straightSegment.release() );
1331 QVector< QgsPoint > points;
1332 points.append( lineString->
pointN( start ) );
1333 points.append( lineString->
pointN( ( start + end + 1 ) / 2 ) );
1334 points.append( lineString->
pointN( end + 1 ) );
1335 std::unique_ptr< QgsCircularString > curvedSegment = qgis::make_unique< QgsCircularString >();
1336 curvedSegment->setPoints( points );
1337 out->addCurve( curvedSegment.release() );
1341 for (
int i = 1; i < numEdges; i++ )
1343 if ( edgeType != edgesInArcs[i] )
1346 addPointsToCurve( start, end, edgeType );
1348 edgeType = edgesInArcs[i];
1354 addPointsToCurve( start, end, edgeType );
1369 std::unique_ptr< QgsCurvePolygon > result = qgis::make_unique< QgsCurvePolygon>();
1372 distanceTolerance, angleTolerance ).release() );
1376 distanceTolerance, angleTolerance ).release() );
1402 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
1404 int numGeom = gc->numGeometries();
1405 QVector< QgsAbstractGeometry * > geometryList;
1406 geometryList.reserve( numGeom );
1407 for (
int i = 0; i < numGeom; ++i )