40 : mGeometry( geometry.constGet() )
67 double dx = p2.
x() - p1.
x();
68 double dy = p2.
y() - p1.
y();
69 if ( ( dx == 0.0 ) && ( dy == 0.0 ) )
71 if ( fabs( dx ) >= fabs( dy ) )
73 double dev = fabs( dy ) / fabs( dx );
80 double dev = fabs( dx ) / fabs( dy );
98 std::array<Direction, 5> dirs;
105 while ( current != end )
115 else if ( dir != dirs[idx - 1] )
125 ret.first = ( idx == 5 ) ? ( dirs[0] == dirs[4] ) : ( idx == 4 );
126 std::copy( dirs.begin(), dirs.begin() + 4, ret.second.begin() );
132 int idx = std::find( oriented.begin(), oriented.end(), dirs[0] ) - oriented.begin();
133 for (
int i = 1; i < 4; ++i )
135 if ( dirs[i] != oriented[( idx + i ) % 4] )
166 const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( mGeometry );
171 if ( vertexCount < 4 )
173 else if ( simpleRectanglesOnly && ( vertexCount != 5 || !polygon->
exteriorRing()->
isClosed() ) )
177 std::array<Direction, 4> dirs;
178 std::tie( found4Dirs, dirs ) =
getEdgeDirections( polygon, std::tan( maximumDeviation * M_PI / 180 ) );
192 QVector<QgsLineString *> linesToProcess;
194 const QgsMultiCurve *multiCurve = qgsgeometry_cast< const QgsMultiCurve * >( mGeometry );
197 linesToProcess.reserve( multiCurve->
partCount() );
198 for (
int i = 0; i < multiCurve->
partCount(); ++i )
200 linesToProcess << static_cast<QgsLineString *>( multiCurve->
geometryN( i )->
clone() );
204 const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( mGeometry );
207 linesToProcess << static_cast<QgsLineString *>( curve->
segmentize() );
210 std::unique_ptr<QgsMultiPolygon> multipolygon( linesToProcess.size() > 1 ?
new QgsMultiPolygon() :
nullptr );
213 if ( !linesToProcess.empty() )
215 std::unique_ptr< QgsLineString > secondline;
216 for (
QgsLineString *line : std::as_const( linesToProcess ) )
218 QTransform transform = QTransform::fromTranslate( x, y );
220 secondline.reset( line->reversed() );
221 secondline->transform( transform );
223 line->append( secondline.get() );
224 line->addVertex( line->pointN( 0 ) );
230 multipolygon->addGeometry( polygon );
252 Cell(
double x,
double y,
double h,
const QgsPolygon *polygon )
256 , d( polygon->pointDistanceToBoundary( x, y ) )
257 , max( d + h * M_SQRT2 )
272 struct GreaterThanByMax
274 bool operator()(
const Cell *lhs,
const Cell *rhs )
const
276 return rhs->max > lhs->max;
280 Cell *getCentroidCell(
const QgsPolygon *polygon )
288 for (
int i = 0, j = len - 1; i < len; j = i++ )
290 double aX = exterior->
xAt( i );
291 double aY = exterior->
yAt( i );
292 double bX = exterior->
xAt( j );
293 double bY = exterior->
yAt( j );
294 double f = aX * bY - bX * aY;
295 x += ( aX + bX ) * f;
296 y += ( aY + bY ) * f;
300 return new Cell( exterior->
xAt( 0 ), exterior->
yAt( 0 ), 0, polygon );
302 return new Cell( x / area, y / area, 0.0, polygon );
307 std::unique_ptr< QgsPolygon > segmentizedPoly;
308 const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( surface );
312 polygon = segmentizedPoly.get();
319 double cellSize = std::min( bounds.
width(), bounds.
height() );
324 double h = cellSize / 2.0;
325 std::priority_queue< Cell *, std::vector<Cell *>, GreaterThanByMax > cellQueue;
332 cellQueue.push(
new Cell( x + h, y + h, h, polygon ) );
337 std::unique_ptr< Cell > bestCell( getCentroidCell( polygon ) );
340 std::unique_ptr< Cell > bboxCell(
new Cell( bounds.
xMinimum() + bounds.
width() / 2.0,
343 if ( bboxCell->d > bestCell->d )
345 bestCell = std::move( bboxCell );
348 while ( !cellQueue.empty() )
351 std::unique_ptr< Cell > cell( cellQueue.top() );
353 Cell *currentCell = cell.get();
356 if ( currentCell->d > bestCell->d )
358 bestCell = std::move( cell );
362 if ( currentCell->max - bestCell->d <=
precision )
366 h = currentCell->h / 2.0;
367 cellQueue.push(
new Cell( currentCell->x - h, currentCell->y - h, h, polygon ) );
368 cellQueue.push(
new Cell( currentCell->x + h, currentCell->y - h, h, polygon ) );
369 cellQueue.push(
new Cell( currentCell->x - h, currentCell->y + h, h, polygon ) );
370 cellQueue.push(
new Cell( currentCell->x + h, currentCell->y + h, h, polygon ) );
373 distanceFromBoundary = bestCell->d;
375 return QgsPoint( bestCell->x, bestCell->y );
383 if ( distanceFromBoundary )
384 *distanceFromBoundary = std::numeric_limits<double>::max();
386 if ( !mGeometry || mGeometry->
isEmpty() )
392 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
394 int numGeom = gc->numGeometries();
397 for (
int i = 0; i < numGeom; ++i )
399 const QgsSurface *surface = qgsgeometry_cast< const QgsSurface * >( gc->geometryN( i ) );
403 double dist = std::numeric_limits<double>::max();
405 if ( dist > maxDist )
415 if ( distanceFromBoundary )
416 *distanceFromBoundary = maxDist;
421 const QgsSurface *surface = qgsgeometry_cast< const QgsSurface * >( mGeometry );
425 double dist = std::numeric_limits<double>::max();
430 if ( distanceFromBoundary )
431 *distanceFromBoundary = dist;
442 return lowerThreshold > std::fabs( dotProduct ) || std::fabs( dotProduct ) > upperThreshold;
468 for (
int i = 0; i < numPoints; ++i )
470 if ( !isClosed && i == numPoints - 1 )
472 else if ( !isClosed && i == 0 )
481 a = ring->
pointN( numPoints - 1 );
484 if ( i == numPoints - 1 )
493 sum += 2.0 * std::min( std::fabs( dotProduct - 1.0 ), std::min( std::fabs( dotProduct ), std::fabs( dotProduct + 1 ) ) );
503 double lowerThreshold,
double upperThreshold )
512 double scale = 2.0 * std::min( p.
length(), q.
length() );
516 double dotProduct = p * q;
525 if ( dotProduct < -M_SQRT1_2 )
534 return new_v.
normalized() * ( 0.1 * dotProduct * scale );
539 double minScore = std::numeric_limits<double>::max();
544 std::unique_ptr< QgsLineString > best( ring->
clone() );
546 QVector< QgsVector > motions;
547 motions.reserve( numPoints );
549 for (
int it = 0; it < iterations; ++it )
557 for (
int i = 0; i < numPoints; ++i )
559 if ( isClosed && i == numPoints - 1 )
560 motions << motions.at( 0 );
561 else if ( !isClosed && ( i == 0 || i == numPoints - 1 ) )
571 a = ring->
pointN( numPoints - 1 );
574 if ( i == numPoints - 1 )
579 motions <<
calcMotion( a, b,
c, lowerThreshold, upperThreshold );
586 for (
int i = 0; i < numPoints; ++i )
588 ring->
setXAt( i, ring->
xAt( i ) + motions.at( i ).x() );
589 ring->
setYAt( i, ring->
yAt( i ) + motions.at( i ).y() );
592 double newScore =
squareness( ring, lowerThreshold, upperThreshold );
593 if ( newScore < minScore )
595 best.reset( ring->
clone() );
599 if ( minScore < tolerance )
605 return best.release();
611 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
615 geom = segmentizedCopy.get();
621 maxIterations, tolerance, lowerThreshold, upperThreshold );
630 maxIterations, tolerance, lowerThreshold, upperThreshold ) );
634 maxIterations, tolerance, lowerThreshold, upperThreshold ) );
650 double lowerThreshold = std::cos( ( 90 - angleThreshold ) * M_PI / 180.00 );
651 double upperThreshold = std::cos( angleThreshold * M_PI / 180.0 );
653 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
655 int numGeom = gc->numGeometries();
656 QVector< QgsAbstractGeometry * > geometryList;
657 geometryList.reserve( numGeom );
658 for (
int i = 0; i < numGeom; ++i )
660 geometryList <<
orthogonalizeGeom( gc->geometryN( i ), maxIterations, tolerance, lowerThreshold, upperThreshold );
679 QVector< double > outX;
680 QVector< double > outY;
681 QVector< double > outZ;
682 QVector< double > outM;
683 double multiplier = 1.0 / double( extraNodesPerSegment + 1 );
686 outX.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
687 outY.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
688 bool withZ = ring->
is3D();
690 outZ.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
693 outM.reserve( ( extraNodesPerSegment + 1 ) * nPoints );
706 int extraNodesThisSegment = extraNodesPerSegment;
707 for (
int i = 0; i < nPoints - 1; ++i )
710 x2 = ring->
xAt( i + 1 );
712 y2 = ring->
yAt( i + 1 );
716 z2 = ring->
zAt( i + 1 );
721 m2 = ring->
mAt( i + 1 );
731 if ( extraNodesPerSegment < 0 )
734 extraNodesThisSegment = std::floor( std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) ) / distance );
735 if ( extraNodesThisSegment >= 1 )
736 multiplier = 1.0 / ( extraNodesThisSegment + 1 );
739 for (
int j = 0; j < extraNodesThisSegment; ++j )
741 double delta = multiplier * ( j + 1 );
742 xOut = x1 + delta * ( x2 - x1 );
743 yOut = y1 + delta * ( y2 - y1 );
745 zOut = z1 + delta * ( z2 - z1 );
747 mOut = m1 + delta * ( m2 - m1 );
757 outX << ring->
xAt( nPoints - 1 );
758 outY << ring->
yAt( nPoints - 1 );
760 outZ << ring->
zAt( nPoints - 1 );
762 outM << ring->
mAt( nPoints - 1 );
770 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
774 geom = segmentizedCopy.get();
788 extraNodesPerSegment, distance ) );
792 extraNodesPerSegment, distance ) );
812 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
814 int numGeom = gc->numGeometries();
815 QVector< QgsAbstractGeometry * > geometryList;
816 geometryList.reserve( numGeom );
817 for (
int i = 0; i < numGeom; ++i )
819 geometryList <<
densifyGeometry( gc->geometryN( i ), extraNodesPerSegment );
848 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
850 int numGeom = gc->numGeometries();
851 QVector< QgsAbstractGeometry * > geometryList;
852 geometryList.reserve( numGeom );
853 for (
int i = 0; i < numGeom; ++i )
880 "line_segment_dist_comparer",
881 "AB must not be collinear with the origin." );
883 "line_segment_dist_comparer",
884 "CD must not be collinear with the origin." );
898 if ( ab.
end() == cd.
end() || oad != oab )
908 if ( cdb == 0 && cda == 0 )
910 return mOrigin.sqrDist( ab.
start() ) < mOrigin.sqrDist( cd.
start() );
912 else if ( cda == cdb || cda == 0 || cdb == 0 )
915 return cdo == cda || cdo == cdb;
931 const bool aIsLeft = a.
x() < mVertex.x();
932 const bool bIsLeft = b.
x() < mVertex.x();
933 if ( aIsLeft != bIsLeft )
938 if ( a.
y() >= mVertex.y() || b.
y() >= mVertex.y() )
940 return b.
y() < a.
y();
944 return a.
y() < b.
y();
976 const int abo =
segment.pointLeftOfLine( origin );
983 const double distA = ao * direction;
984 const double distB = ( origin -
segment.end() ) * direction;
986 if ( distA > 0 && distB > 0 )
992 if ( ( distA > 0 ) != ( distB > 0 ) )
993 intersectPoint = origin;
994 else if ( distA > distB )
995 intersectPoint =
segment.start();
997 intersectPoint =
segment.end();
1005 if ( u < 0.0 || 1.0 < u )
1012 intersectPoint = origin + direction * t;
1021 if ( radius1 > radius2 )
1028 QVector<QgsPointXY> points;
1050 std::vector< std::unique_ptr<QgsLineString > > linesToProcess;
1052 const QgsMultiCurve *multiCurve = qgsgeometry_cast< const QgsMultiCurve * >( mGeometry );
1055 for (
int i = 0; i < multiCurve->
partCount(); ++i )
1064 const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( mGeometry );
1071 if ( linesToProcess.empty() )
1074 g.mLastError = QStringLiteral(
"Input geometry was not a curve type geometry" );
1078 QVector<QgsGeometry> bufferedLines;
1079 bufferedLines.reserve( linesToProcess.size() );
1081 for ( std::unique_ptr< QgsLineString > &line : linesToProcess )
1083 QVector<QgsGeometry> parts;
1085 double prevRadius = 0;
1088 std::unique_ptr< double[] > widths = widthFunction( line.get() ) ;
1093 double thisRadius = widths[ i ] / 2.0;
1094 if ( thisRadius > 0 )
1098 QgsCircle circ( thisPoint, thisRadius );
1100 parts << thisCircle;
1109 if ( prevRadius > 0 || thisRadius > 0 )
1111 QVector< QgsPointXY > points =
generateSegmentCurve( prevPoint, prevRadius, thisPoint, thisRadius );
1112 if ( !points.empty() )
1117 int beforeVertex = 0;
1118 int afterVertex = 0;
1120 double sqrDistPrev = 0;
1121 for (
int j = 0; j < points.count(); ++j )
1125 points[j] = sqrDistPrev < sqrDist ? pA : pB;
1128 points.append( points.at( 0 ) );
1130 std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
1132 if ( poly->area() > 0 )
1137 prevPoint = thisPoint;
1138 prevRadius = thisRadius;
1139 prevCircle = thisCircle;
1154 start = std::fabs( start );
1155 end = std::fabs( end );
1161 std::unique_ptr< double [] > widths(
new double[ line->nCoordinates() ] );
1163 widths[line->nCoordinates() - 1] = end;
1165 double lineLength = line->length();
1166 double currentLength = 0;
1167 QgsPoint prevPoint = line->pointN( 0 );
1168 for (
int i = 1; i < line->nCoordinates() - 1; ++i )
1170 QgsPoint point = line->pointN( i );
1171 double segmentLength = point.
distance( prevPoint );
1172 currentLength += segmentLength;
1173 double lengthFraction = lineLength > 0 ? currentLength / lineLength : 1;
1174 double delta = lengthFraction * ( end - start );
1175 widths[i] = start + delta;
1189 std::unique_ptr< double [] > widths(
new double[ line->nCoordinates() ] );
1190 for (
int i = 0; i < line->nCoordinates(); ++i )
1192 widths[ i ] = line->mAt( i );
1201 const std::function<
bool(
const QgsPointXY & ) > &acceptPoint,
unsigned long seed,
QgsFeedback *feedback,
int maxTriesPerPoint )
1204 return QVector< QgsPointXY >();
1216 return QVector< QgsPointXY >();
1224 std::unique_ptr< QgsPolygon > p( qgsgeometry_cast< QgsPolygon * >( ms->
geometryN( i )->
segmentize() ) );
1231 if (
const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( polygon.
constGet() ) )
1237 std::unique_ptr< QgsPolygon > p( qgsgeometry_cast< QgsPolygon * >( polygon.
constGet()->
segmentize() ) );
1243 return QVector< QgsPointXY >();
1245 const QVector<float> triangleData = t.
data();
1246 if ( triangleData.empty() )
1247 return QVector< QgsPointXY >();
1250 std::vector< double > cumulativeAreas;
1252 double totalArea = 0;
1253 for (
auto it = triangleData.constBegin(); it != triangleData.constEnd(); )
1256 return QVector< QgsPointXY >();
1258 const float aX = *it++;
1260 const float aY = -( *it++ );
1261 const float bX = *it++;
1263 const float bY = -( *it++ );
1264 const float cX = *it++;
1266 const float cY = -( *it++ );
1270 cumulativeAreas.emplace_back( totalArea );
1273 std::random_device rd;
1274 std::mt19937 mt( seed == 0 ? rd() : seed );
1275 std::uniform_real_distribution<> uniformDist( 0, 1 );
1278 auto selectRandomTriangle = [&cumulativeAreas, totalArea](
double random )->
int
1281 const double target = random * totalArea;
1282 for (
auto it = cumulativeAreas.begin(); it != cumulativeAreas.end(); ++it, triangle++ )
1287 Q_ASSERT_X(
false,
"QgsInternalGeometryEngine::randomPointsInPolygon",
"Invalid random triangle index" );
1292 QVector<QgsPointXY> result;
1293 result.reserve( count );
1295 for (
int i = 0; i < count; )
1298 return QVector< QgsPointXY >();
1300 const double triangleIndexRnd = uniformDist( mt );
1302 const int triangleIndex = selectRandomTriangle( triangleIndexRnd );
1305 const double weightB = uniformDist( mt );
1306 const double weightC = uniformDist( mt );
1311 const double aX = triangleData.at( triangleIndex * 9 ) + bounds.
xMinimum();
1312 const double aY = -triangleData.at( triangleIndex * 9 + 2 ) + bounds.
yMinimum();
1313 const double bX = triangleData.at( triangleIndex * 9 + 3 ) + bounds.
xMinimum();
1314 const double bY = -triangleData.at( triangleIndex * 9 + 5 ) + bounds.
yMinimum();
1315 const double cX = triangleData.at( triangleIndex * 9 + 6 ) + bounds.
xMinimum();
1316 const double cY = -triangleData.at( triangleIndex * 9 + 8 ) + bounds.
yMinimum();
1320 if ( acceptPoint( candidate ) )
1326 else if ( maxTriesPerPoint != 0 )
1330 if ( tries == maxTriesPerPoint )
1343 double pointSpacingAngleTolerance )
1349 std::unique_ptr< QgsCircularString > out;
1350 out.reset( qgsgeometry_cast< QgsCircularString * >( curve )->clone() );
1355 std::unique_ptr< QgsCompoundCurve > out = std::make_unique< QgsCompoundCurve >();
1356 const QgsCompoundCurve *in = qgsgeometry_cast< const QgsCompoundCurve * >( curve );
1357 for (
int i = 0; i < in->
nCurves(); i ++ )
1359 std::unique_ptr< QgsCurve > processed =
lineToCurve( in->
curveAt( i ), distanceTolerance, pointSpacingAngleTolerance );
1367 out->addCurve( qgsgeometry_cast< const QgsLineString * >( processed->simplifiedTypeRef() )->clone() );
1371 out->addCurve( processed.release() );
1379 const QgsLineString *lineString = qgsgeometry_cast< QgsLineString * >( curve );
1381 std::unique_ptr< QgsCompoundCurve > out = std::make_unique< QgsCompoundCurve >();
1384 const unsigned int minQuadEdges = 2;
1397 out->addCurve( lineString->
clone() );
1403 QVector< int > edgesInArcs( numEdges + 1, 0 );
1407 double abX = b.x() - a.
x();
1408 double abY = b.y() - a.
y();
1410 double cbX = b.x() -
c.x();
1411 double cbY = b.y() -
c.y();
1413 double dot = ( abX * cbX + abY * cbY );
1414 double cross = ( abX * cbY - abY * cbX );
1416 double alpha = std::atan2( cross, dot );
1431 double centerX = 0.0;
1432 double centerY = 0.0;
1435 while ( i < numEdges - 2 )
1437 unsigned int arcEdges = 0;
1438 double numQuadrants = 0;
1441 bool foundArc =
false;
1443 a1 = lineString->
pointN( i );
1444 a2 = lineString->
pointN( i + 1 );
1445 a3 = lineString->
pointN( i + 2 );
1448 for ( j = i + 3; j < numEdges + 1; j++ )
1450 b = lineString->
pointN( j );
1457 for ( k = j - 1; k > j - 4; k-- )
1458 edgesInArcs[k] = currentArc;
1478 arcEdges = j - 1 - i;
1479 if ( first.
x() == b.
x() && first.
y() == b.
y() )
1494 numQuadrants = ( 4 *
angle ) / ( 2 * M_PI );
1497 if ( arcEdges < minQuadEdges * numQuadrants )
1500 for ( k = j - 1; k >= i; k-- )
1517 int edgeType = edgesInArcs[0];
1519 auto addPointsToCurve = [ lineString, &out ](
int start,
int end,
int type )
1524 QVector< QgsPoint > points;
1525 for (
int j = start; j < end + 2; ++ j )
1527 points.append( lineString->
pointN( j ) );
1529 std::unique_ptr< QgsCurve > straightSegment = std::make_unique< QgsLineString >( points );
1530 out->addCurve( straightSegment.release() );
1535 QVector< QgsPoint > points;
1536 points.append( lineString->
pointN( start ) );
1537 points.append( lineString->
pointN( ( start + end + 1 ) / 2 ) );
1538 points.append( lineString->
pointN( end + 1 ) );
1539 std::unique_ptr< QgsCircularString > curvedSegment = std::make_unique< QgsCircularString >();
1540 curvedSegment->setPoints( points );
1541 out->addCurve( curvedSegment.release() );
1545 for (
int i = 1; i < numEdges; i++ )
1547 if ( edgeType != edgesInArcs[i] )
1550 addPointsToCurve( start, end, edgeType );
1552 edgeType = edgesInArcs[i];
1558 addPointsToCurve( start, end, edgeType );
1563 std::unique_ptr< QgsCircularString > res;
1564 res.reset( qgsgeometry_cast< const QgsCircularString * >( out->simplifiedTypeRef() )->clone() );
1578 return lineToCurve( qgsgeometry_cast< const QgsCurve * >( geom ), distanceTolerance, angleTolerance );
1583 const QgsCurvePolygon *polygon = qgsgeometry_cast< const QgsCurvePolygon * >( geom );
1584 std::unique_ptr< QgsCurvePolygon > result = std::make_unique< QgsCurvePolygon>();
1587 distanceTolerance, angleTolerance ).release() );
1591 distanceTolerance, angleTolerance ).release() );
1611 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
1613 int numGeom = gc->numGeometries();
1614 QVector< QgsAbstractGeometry * > geometryList;
1615 geometryList.reserve( numGeom );
1616 for (
int i = 0; i < numGeom; ++i )
1639 area = std::numeric_limits<double>::max();
1641 width = std::numeric_limits<double>::max();
1642 height = std::numeric_limits<double>::max();
1648 std::unique_ptr< QgsAbstractGeometry > hull( engine->convexHull( &mLastError ) );
1659 double totalRotation = 0;
1660 while ( hull->nextVertex( vertexId, pt2 ) )
1663 double rotateAngle = 180.0 / M_PI * currentAngle;
1664 totalRotation += rotateAngle;
1666 QTransform t = QTransform::fromTranslate( pt0.
x(), pt0.
y() );
1667 t.rotate( rotateAngle );
1668 t.translate( -pt0.
x(), -pt0.
y() );
1670 hull->transform( t );
1673 double currentArea = bounds.
width() * bounds.
height();
1674 if ( currentArea < area )
1678 angle = totalRotation;
1679 width = bounds.
width();
1680 height = bounds.
height();
1689 if ( width > height )
1691 width = minRect.
height();
1692 height = minRect.
width();
1697 if (
angle > 180.0 )
1705 const int totalPoints = line->
numPoints();
1706 if ( totalPoints < 2 )
1709 const double *x = line->
xData();
1710 const double *y = line->
yData();
1712 double prevX = *x++;
1713 double prevY = *y++;
1715 QVector< double > outX;
1716 QVector< double > outY;
1717 const double totalLength = line->
length();
1719 const int maxRepetitions = std::ceil( totalLength / wavelength );
1720 if ( !strictWavelength )
1721 wavelength = totalLength / maxRepetitions;
1723 const int estimatedPoints = maxRepetitions * 2 + 2;
1724 outX.reserve( estimatedPoints );
1725 outY.reserve( estimatedPoints );
1726 outX.append( prevX );
1727 outY.append( prevY );
1729 double distanceToNextPointFromStartOfSegment = wavelength / 4;
1731 for (
int i = 1; i < totalPoints; ++i )
1733 double thisX = *x++;
1734 double thisY = *y++;
1737 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1738 while ( distanceToNextPointFromStartOfSegment < segmentLength ||
qgsDoubleNear( distanceToNextPointFromStartOfSegment, segmentLength ) )
1741 const double distanceToPoint = std::min( distanceToNextPointFromStartOfSegment, segmentLength );
1746 const double outPointX = pX + side * amplitude * std::sin( segmentAngleRadians + M_PI_2 );
1747 const double outPointY = pY + side * amplitude * std::cos( segmentAngleRadians + M_PI_2 );
1749 outX.append( outPointX );
1750 outY.append( outPointY );
1752 distanceToNextPointFromStartOfSegment += wavelength / 2;
1758 distanceToNextPointFromStartOfSegment -= segmentLength;
1761 outX.append( prevX );
1762 outY.append( prevY );
1764 return std::make_unique< QgsLineString >( outX, outY );
1768 const double minimumWavelength,
const double maximumWavelength,
1769 const double minimumAmplitude,
const double maximumAmplitude,
1770 std::uniform_real_distribution<> &uniformDist, std::mt19937 &mt )
1772 const int totalPoints = line->
numPoints();
1773 if ( totalPoints < 2 )
1776 const double *x = line->
xData();
1777 const double *y = line->
yData();
1779 double prevX = *x++;
1780 double prevY = *y++;
1782 QVector< double > outX;
1783 QVector< double > outY;
1784 const double totalLength = line->
length();
1786 const int maxRepetitions = std::ceil( totalLength / minimumWavelength );
1788 const int estimatedPoints = maxRepetitions * 2 + 2;
1789 outX.reserve( estimatedPoints );
1790 outY.reserve( estimatedPoints );
1791 outX.append( prevX );
1792 outY.append( prevY );
1794 double wavelength = uniformDist( mt ) * ( maximumWavelength - minimumWavelength ) + minimumWavelength;
1795 double distanceToNextPointFromStartOfSegment = wavelength / 4;
1796 double amplitude = uniformDist( mt ) * ( maximumAmplitude - minimumAmplitude ) + minimumAmplitude;
1799 for (
int i = 1; i < totalPoints; ++i )
1801 double thisX = *x++;
1802 double thisY = *y++;
1805 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1806 while ( distanceToNextPointFromStartOfSegment < segmentLength ||
qgsDoubleNear( distanceToNextPointFromStartOfSegment, segmentLength ) )
1809 const double distanceToPoint = std::min( distanceToNextPointFromStartOfSegment, segmentLength );
1814 const double outPointX = pX + side * amplitude * std::sin( segmentAngleRadians + M_PI_2 );
1815 const double outPointY = pY + side * amplitude * std::cos( segmentAngleRadians + M_PI_2 );
1816 outX.append( outPointX );
1817 outY.append( outPointY );
1819 wavelength = uniformDist( mt ) * ( maximumWavelength - minimumWavelength ) + minimumWavelength;
1820 amplitude = uniformDist( mt ) * ( maximumAmplitude - minimumAmplitude ) + minimumAmplitude;
1822 distanceToNextPointFromStartOfSegment += wavelength / 2;
1828 distanceToNextPointFromStartOfSegment -= segmentLength;
1831 outX.append( prevX );
1832 outY.append( prevY );
1834 return std::make_unique< QgsLineString >( outX, outY );
1839 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
1843 geom = segmentizedCopy.get();
1854 std::unique_ptr< QgsPolygon > result = std::make_unique< QgsPolygon >();
1857 wavelength, amplitude, strictWavelength ).release() );
1861 wavelength, amplitude, strictWavelength ).release() );
1868 std::unique_ptr< QgsAbstractGeometry >
triangularWavesRandomizedPrivate(
const QgsAbstractGeometry *geom,
double minimumWavelength,
double maximumWavelength,
double minimumAmplitude,
double maximumAmplitude, std::uniform_real_distribution<> &uniformDist, std::mt19937 &mt )
1870 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
1874 geom = segmentizedCopy.get();
1885 std::unique_ptr< QgsPolygon > result = std::make_unique< QgsPolygon >();
1888 minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, uniformDist, mt ).release() );
1892 minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, uniformDist, mt ).release() );
1915 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
1917 int numGeom = gc->numGeometries();
1918 QVector< QgsAbstractGeometry * > geometryList;
1919 geometryList.reserve( numGeom );
1920 for (
int i = 0; i < numGeom; ++i )
1922 geometryList <<
triangularWavesPrivate( gc->geometryN( i ), wavelength, amplitude, strictWavelength ).release();
1940 if ( minimumWavelength < 0 ||
qgsDoubleNear( minimumWavelength, 0 ) || maximumWavelength < 0 ||
qgsDoubleNear( maximumWavelength, 0 ) || maximumWavelength < minimumWavelength )
1949 std::random_device rd;
1950 std::mt19937 mt( seed == 0 ? rd() : seed );
1951 std::uniform_real_distribution<> uniformDist( 0, 1 );
1958 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
1960 int numGeom = gc->numGeometries();
1961 QVector< QgsAbstractGeometry * > geometryList;
1962 geometryList.reserve( numGeom );
1963 for (
int i = 0; i < numGeom; ++i )
1965 geometryList <<
triangularWavesRandomizedPrivate( gc->geometryN( i ), minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, uniformDist, mt ).release();
1983 const int totalPoints = line->
numPoints();
1984 if ( totalPoints < 2 )
1987 const double *x = line->
xData();
1988 const double *y = line->
yData();
1990 double prevX = *x++;
1991 double prevY = *y++;
1993 QVector< double > outX;
1994 QVector< double > outY;
1995 const double totalLength = line->
length();
1997 const int maxRepetitions = std::ceil( totalLength / wavelength );
1998 if ( !strictWavelength )
1999 wavelength = totalLength / maxRepetitions;
2001 const int estimatedPoints = maxRepetitions * 4 + 2;
2002 outX.reserve( estimatedPoints );
2003 outY.reserve( estimatedPoints );
2004 outX.append( prevX );
2005 outY.append( prevY );
2008 outX.append( prevX - amplitude * std::sin( startSegmentAngleRadians + M_PI_2 ) );
2009 outY.append( prevY - amplitude * std::cos( startSegmentAngleRadians + M_PI_2 ) );
2011 double distanceToNextPointFromStartOfSegment = wavelength / 2;
2014 for (
int i = 1; i < totalPoints; ++i )
2016 double thisX = *x++;
2017 double thisY = *y++;
2020 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
2021 while ( distanceToNextPointFromStartOfSegment < segmentLength ||
qgsDoubleNear( distanceToNextPointFromStartOfSegment, segmentLength ) )
2024 const double distanceToPoint = std::min( distanceToNextPointFromStartOfSegment, segmentLength );
2029 const double sinAngle = std::sin( segmentAngleRadians + M_PI_2 );
2030 const double cosAngle = std::cos( segmentAngleRadians + M_PI_2 );
2031 outX.append( pX + side * amplitude * sinAngle );
2032 outY.append( pY + side * amplitude * cosAngle );
2033 outX.append( pX - side * amplitude * sinAngle );
2034 outY.append( pY - side * amplitude * cosAngle );
2036 distanceToNextPointFromStartOfSegment += wavelength / 2;
2042 distanceToNextPointFromStartOfSegment -= segmentLength;
2048 outX.append( prevX );
2049 outY.append( prevY );
2051 return std::make_unique< QgsLineString >( outX, outY );
2055 const double minimumWavelength,
const double maximumWavelength,
2056 const double minimumAmplitude,
const double maximumAmplitude,
2057 std::uniform_real_distribution<> &uniformDist, std::mt19937 &mt )
2059 const int totalPoints = line->
numPoints();
2060 if ( totalPoints < 2 )
2063 const double *x = line->
xData();
2064 const double *y = line->
yData();
2066 double prevX = *x++;
2067 double prevY = *y++;
2069 QVector< double > outX;
2070 QVector< double > outY;
2071 const double totalLength = line->
length();
2073 const int maxRepetitions = std::ceil( totalLength / minimumWavelength );
2075 const int estimatedPoints = maxRepetitions * 4 + 2;
2076 outX.reserve( estimatedPoints );
2077 outY.reserve( estimatedPoints );
2078 outX.append( prevX );
2079 outY.append( prevY );
2081 double amplitude = uniformDist( mt ) * ( maximumAmplitude - minimumAmplitude ) + minimumAmplitude;
2084 outX.append( prevX - amplitude * std::sin( segmentAngleRadians + M_PI_2 ) );
2085 outY.append( prevY - amplitude * std::cos( segmentAngleRadians + M_PI_2 ) );
2087 double wavelength = uniformDist( mt ) * ( maximumWavelength - minimumWavelength ) + minimumWavelength;
2088 double distanceToNextPointFromStartOfSegment = wavelength / 2;
2091 for (
int i = 1; i < totalPoints; ++i )
2093 double thisX = *x++;
2094 double thisY = *y++;
2097 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
2098 while ( distanceToNextPointFromStartOfSegment < segmentLength ||
qgsDoubleNear( distanceToNextPointFromStartOfSegment, segmentLength ) )
2101 const double distanceToPoint = std::min( distanceToNextPointFromStartOfSegment, segmentLength );
2106 const double sinAngle = std::sin( segmentAngleRadians + M_PI_2 );
2107 const double cosAngle = std::cos( segmentAngleRadians + M_PI_2 );
2108 outX.append( pX + side * amplitude * sinAngle );
2109 outY.append( pY + side * amplitude * cosAngle );
2111 amplitude = uniformDist( mt ) * ( maximumAmplitude - minimumAmplitude ) + minimumAmplitude;
2112 outX.append( pX - side * amplitude * sinAngle );
2113 outY.append( pY - side * amplitude * cosAngle );
2115 wavelength = uniformDist( mt ) * ( maximumWavelength - minimumWavelength ) + minimumWavelength;
2116 distanceToNextPointFromStartOfSegment += wavelength / 2;
2122 distanceToNextPointFromStartOfSegment -= segmentLength;
2125 outX.append( prevX + side * amplitude * std::sin( segmentAngleRadians + M_PI_2 ) );
2126 outY.append( prevY + side * amplitude * std::cos( segmentAngleRadians + M_PI_2 ) );
2127 outX.append( prevX );
2128 outY.append( prevY );
2130 return std::make_unique< QgsLineString >( outX, outY );
2135 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2139 geom = segmentizedCopy.get();
2150 std::unique_ptr< QgsPolygon > result = std::make_unique< QgsPolygon >();
2153 wavelength, amplitude, strictWavelength ).release() );
2157 wavelength, amplitude, strictWavelength ).release() );
2164 std::unique_ptr< QgsAbstractGeometry >
squareWavesRandomizedPrivate(
const QgsAbstractGeometry *geom,
double minimumWavelength,
double maximumWavelength,
double minimumAmplitude,
double maximumAmplitude, std::uniform_real_distribution<> &uniformDist, std::mt19937 &mt )
2166 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2170 geom = segmentizedCopy.get();
2181 std::unique_ptr< QgsPolygon > result = std::make_unique< QgsPolygon >();
2184 minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, uniformDist, mt ).release() );
2188 minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, uniformDist, mt ).release() );
2211 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
2213 int numGeom = gc->numGeometries();
2214 QVector< QgsAbstractGeometry * > geometryList;
2215 geometryList.reserve( numGeom );
2216 for (
int i = 0; i < numGeom; ++i )
2218 geometryList <<
squareWavesPrivate( gc->geometryN( i ), wavelength, amplitude, strictWavelength ).release();
2236 if ( minimumWavelength < 0 ||
qgsDoubleNear( minimumWavelength, 0 ) || maximumWavelength < 0 ||
qgsDoubleNear( maximumWavelength, 0 ) || maximumWavelength < minimumWavelength )
2245 std::random_device rd;
2246 std::mt19937 mt( seed == 0 ? rd() : seed );
2247 std::uniform_real_distribution<> uniformDist( 0, 1 );
2254 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
2256 int numGeom = gc->numGeometries();
2257 QVector< QgsAbstractGeometry * > geometryList;
2258 geometryList.reserve( numGeom );
2259 for (
int i = 0; i < numGeom; ++i )
2261 geometryList <<
squareWavesRandomizedPrivate( gc->geometryN( i ), minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, uniformDist, mt ).release();
2279 const int totalPoints = line->
numPoints();
2280 if ( totalPoints < 2 )
2283 const double *x = line->
xData();
2284 const double *y = line->
yData();
2286 double prevX = *x++;
2287 double prevY = *y++;
2289 const double totalLength = line->
length();
2291 const int maxRepetitions = std::ceil( totalLength / wavelength );
2292 if ( !strictWavelength )
2293 wavelength = totalLength / maxRepetitions;
2295 const int segments = 10;
2299 double xOutBuffer[4] { prevX, prevX, prevX, prevX };
2300 double yOutBuffer[4] { prevY, prevY, prevY, prevY };
2301 bool isFirstPart =
true;
2303 double distanceToNextPointFromStartOfSegment = wavelength / 8;
2304 int bufferIndex = 1;
2305 std::unique_ptr< QgsLineString > out = std::make_unique< QgsLineString >();
2307 double segmentAngleRadians = 0;
2308 double remainingDistance = totalLength;
2309 double totalCoveredDistance = 0;
2311 for (
int i = 1; i < totalPoints; ++i )
2313 double thisX = *x++;
2314 double thisY = *y++;
2317 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
2318 while ( distanceToNextPointFromStartOfSegment < segmentLength ||
qgsDoubleNear( distanceToNextPointFromStartOfSegment, segmentLength ) )
2321 const double distanceToPoint = std::min( distanceToNextPointFromStartOfSegment, segmentLength );
2324 remainingDistance = totalLength - totalCoveredDistance - distanceToPoint;
2326 const double sinAngle = std::sin( segmentAngleRadians + M_PI_2 );
2327 const double cosAngle = std::cos( segmentAngleRadians + M_PI_2 );
2329 if ( bufferIndex == 0 )
2331 xOutBuffer[0] = pX + side * amplitude * sinAngle;
2332 yOutBuffer[0] = pY + side * amplitude * cosAngle;
2334 distanceToNextPointFromStartOfSegment += wavelength / 4;
2336 else if ( bufferIndex == 1 && isFirstPart )
2338 xOutBuffer[1] = ( xOutBuffer[0] + pX - side * amplitude * sinAngle ) * 0.5;
2339 yOutBuffer[1] = ( yOutBuffer[0] + pY - side * amplitude * cosAngle ) * 0.5;
2340 xOutBuffer[2] = pX - side * amplitude * sinAngle;
2341 yOutBuffer[2] = pY - side * amplitude * cosAngle;
2343 distanceToNextPointFromStartOfSegment += wavelength / 8;
2345 else if ( bufferIndex == 1 )
2347 xOutBuffer[1] = pX + side * amplitude * sinAngle;
2348 yOutBuffer[1] = pY + side * amplitude * cosAngle;
2349 xOutBuffer[2] = pX - side * amplitude * sinAngle;
2350 yOutBuffer[2] = pY - side * amplitude * cosAngle;
2352 distanceToNextPointFromStartOfSegment += wavelength / 4;
2354 else if ( bufferIndex == 2 )
2356 xOutBuffer[3] = pX - side * amplitude * sinAngle;
2357 yOutBuffer[3] = pY - side * amplitude * cosAngle;
2361 xOutBuffer[2] = ( xOutBuffer[2] + xOutBuffer[3] ) * 0.5;
2362 yOutBuffer[2] = ( yOutBuffer[2] + yOutBuffer[3] ) * 0.5;
2363 isFirstPart =
false;
2368 QgsPoint( xOutBuffer[1], yOutBuffer[1] ),
2369 QgsPoint( xOutBuffer[2], yOutBuffer[2] ),
2370 QgsPoint( xOutBuffer[3], yOutBuffer[3] ),
2372 out->append( bezier.get() );
2375 xOutBuffer[0] = xOutBuffer[3];
2376 yOutBuffer[0] = yOutBuffer[3];
2379 distanceToNextPointFromStartOfSegment += wavelength / 4;
2382 totalCoveredDistance += segmentLength;
2385 distanceToNextPointFromStartOfSegment -= segmentLength;
2388 const double midX = prevX - remainingDistance / 2 * std::sin( segmentAngleRadians );
2389 const double midY = prevY - remainingDistance / 2 * std::cos( segmentAngleRadians );
2390 const double pX = midX + side * amplitude * std::sin( segmentAngleRadians + M_PI_2 );
2391 const double pY = midY + side * amplitude * std::cos( segmentAngleRadians + M_PI_2 );
2394 QgsPoint( ( out->endPoint().x() + pX ) * 0.5, ( out->endPoint().y() + pY ) * 0.5 ),
2395 QgsPoint( ( prevX + pX ) * 0.5, ( prevY + pY ) * 0.5 ),
2398 out->append( bezier.get() );
2404 const double minimumWavelength,
const double maximumWavelength,
2405 const double minimumAmplitude,
const double maximumAmplitude,
2406 std::uniform_real_distribution<> &uniformDist, std::mt19937 &mt )
2408 const int totalPoints = line->
numPoints();
2409 if ( totalPoints < 2 )
2412 const double *x = line->
xData();
2413 const double *y = line->
yData();
2415 double prevX = *x++;
2416 double prevY = *y++;
2418 const double totalLength = line->
length();
2420 const int segments = 10;
2424 double xOutBuffer[4] { prevX, prevX, prevX, prevX };
2425 double yOutBuffer[4] { prevY, prevY, prevY, prevY };
2426 bool isFirstPart =
true;
2428 double amplitude = uniformDist( mt ) * ( maximumAmplitude - minimumAmplitude ) + minimumAmplitude;
2429 double wavelength = uniformDist( mt ) * ( maximumWavelength - minimumWavelength ) + minimumWavelength;
2431 double distanceToNextPointFromStartOfSegment = wavelength / 8;
2432 int bufferIndex = 1;
2433 std::unique_ptr< QgsLineString > out = std::make_unique< QgsLineString >();
2435 double segmentAngleRadians = 0;
2437 double remainingDistance = totalLength;
2438 double totalCoveredDistance = 0;
2440 for (
int i = 1; i < totalPoints; ++i )
2442 double thisX = *x++;
2443 double thisY = *y++;
2446 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
2447 while ( distanceToNextPointFromStartOfSegment < segmentLength ||
qgsDoubleNear( distanceToNextPointFromStartOfSegment, segmentLength ) )
2450 const double distanceToPoint = std::min( distanceToNextPointFromStartOfSegment, segmentLength );
2453 remainingDistance = totalLength - totalCoveredDistance - distanceToPoint;
2455 const double sinAngle = std::sin( segmentAngleRadians + M_PI_2 );
2456 const double cosAngle = std::cos( segmentAngleRadians + M_PI_2 );
2458 if ( bufferIndex == 0 )
2460 xOutBuffer[0] = pX + side * amplitude * sinAngle;
2461 yOutBuffer[0] = pY + side * amplitude * cosAngle;
2463 distanceToNextPointFromStartOfSegment += wavelength / 4;
2465 else if ( bufferIndex == 1 && isFirstPart )
2467 xOutBuffer[1] = ( xOutBuffer[0] + pX - side * amplitude * sinAngle ) * 0.5;
2468 yOutBuffer[1] = ( yOutBuffer[0] + pY - side * amplitude * cosAngle ) * 0.5;
2469 xOutBuffer[2] = pX - side * amplitude * sinAngle;
2470 yOutBuffer[2] = pY - side * amplitude * cosAngle;
2472 distanceToNextPointFromStartOfSegment += wavelength / 8;
2474 else if ( bufferIndex == 1 )
2476 xOutBuffer[1] = pX + side * amplitude * sinAngle;
2477 yOutBuffer[1] = pY + side * amplitude * cosAngle;
2478 amplitude = uniformDist( mt ) * ( maximumAmplitude - minimumAmplitude ) + minimumAmplitude;
2479 xOutBuffer[2] = pX - side * amplitude * sinAngle;
2481 yOutBuffer[2] = pY - side * amplitude * cosAngle;
2482 distanceToNextPointFromStartOfSegment += wavelength / 4;
2484 else if ( bufferIndex == 2 )
2486 xOutBuffer[3] = pX - side * amplitude * sinAngle;
2487 yOutBuffer[3] = pY - side * amplitude * cosAngle;
2491 xOutBuffer[2] = ( xOutBuffer[2] + xOutBuffer[3] ) * 0.5;
2492 yOutBuffer[2] = ( yOutBuffer[2] + yOutBuffer[3] ) * 0.5;
2493 isFirstPart =
false;
2498 QgsPoint( xOutBuffer[1], yOutBuffer[1] ),
2499 QgsPoint( xOutBuffer[2], yOutBuffer[2] ),
2500 QgsPoint( xOutBuffer[3], yOutBuffer[3] ),
2502 out->append( bezier.get() );
2505 xOutBuffer[0] = xOutBuffer[3];
2506 yOutBuffer[0] = yOutBuffer[3];
2510 wavelength = uniformDist( mt ) * ( maximumWavelength - minimumWavelength ) + minimumWavelength;
2512 distanceToNextPointFromStartOfSegment += wavelength / 4;
2515 totalCoveredDistance += segmentLength;
2519 distanceToNextPointFromStartOfSegment -= segmentLength;
2522 const double midX = prevX - remainingDistance / 2 * std::sin( segmentAngleRadians );
2523 const double midY = prevY - remainingDistance / 2 * std::cos( segmentAngleRadians );
2524 const double pX = midX + side * amplitude * std::sin( segmentAngleRadians + M_PI_2 );
2525 const double pY = midY + side * amplitude * std::cos( segmentAngleRadians + M_PI_2 );
2527 if ( out->isEmpty() )
2531 QgsPoint( ( prevX + pX ) * 0.5, ( prevY + pY ) * 0.5 ),
2534 out->append( bezier.get() );
2539 QgsPoint( ( out->endPoint().x() + pX ) * 0.5, ( out->endPoint().y() + pY ) * 0.5 ),
2540 QgsPoint( ( prevX + pX ) * 0.5, ( prevY + pY ) * 0.5 ),
2543 out->append( bezier.get() );
2551 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2555 geom = segmentizedCopy.get();
2566 std::unique_ptr< QgsPolygon > result = std::make_unique< QgsPolygon >();
2569 wavelength, amplitude, strictWavelength ).release() );
2573 wavelength, amplitude, strictWavelength ).release() );
2580 std::unique_ptr< QgsAbstractGeometry >
roundWavesRandomizedPrivate(
const QgsAbstractGeometry *geom,
double minimumWavelength,
double maximumWavelength,
double minimumAmplitude,
double maximumAmplitude, std::uniform_real_distribution<> &uniformDist, std::mt19937 &mt )
2582 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2586 geom = segmentizedCopy.get();
2597 std::unique_ptr< QgsPolygon > result = std::make_unique< QgsPolygon >();
2600 minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, uniformDist, mt ).release() );
2604 minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, uniformDist, mt ).release() );
2627 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
2629 int numGeom = gc->numGeometries();
2630 QVector< QgsAbstractGeometry * > geometryList;
2631 geometryList.reserve( numGeom );
2632 for (
int i = 0; i < numGeom; ++i )
2634 geometryList <<
roundWavesPrivate( gc->geometryN( i ), wavelength, amplitude, strictWavelength ).release();
2652 if ( minimumWavelength < 0 ||
qgsDoubleNear( minimumWavelength, 0 ) || maximumWavelength < 0 ||
qgsDoubleNear( maximumWavelength, 0 ) || maximumWavelength < minimumWavelength )
2661 std::random_device rd;
2662 std::mt19937 mt( seed == 0 ? rd() : seed );
2663 std::uniform_real_distribution<> uniformDist( 0, 1 );
2670 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
2672 int numGeom = gc->numGeometries();
2673 QVector< QgsAbstractGeometry * > geometryList;
2674 geometryList.reserve( numGeom );
2675 for (
int i = 0; i < numGeom; ++i )
2677 geometryList <<
roundWavesRandomizedPrivate( gc->geometryN( i ), minimumWavelength, maximumWavelength, minimumAmplitude, maximumAmplitude, uniformDist, mt ).release();
2694 const QVector< double> &pattern,
2698 double patternOffset )
2700 const int totalPoints = line->
numPoints();
2701 if ( totalPoints < 2 )
2704 const int patternSize = pattern.size();
2706 const double *x = line->
xData();
2707 const double *y = line->
yData();
2709 double prevX = *x++;
2710 double prevY = *y++;
2712 std::unique_ptr< QgsMultiLineString > result = std::make_unique< QgsMultiLineString >();
2714 QVector< double > outX;
2715 QVector< double > outY;
2716 const double totalLength = line->
length();
2718 double patternLength = 0;
2719 double patternDashLength = 0;
2720 double patternGapLength = 0;
2721 for (
int i = 0; i < pattern.size(); ++i )
2723 patternLength += pattern.at( i );
2725 patternDashLength += pattern.at( i );
2727 patternGapLength += pattern.at( i );
2730 double firstPatternLength = 0;
2731 double firstPatternDashLength = 0;
2732 double firstPatternGapLength = 0;
2733 switch ( startRule )
2737 firstPatternLength = patternLength;
2738 firstPatternDashLength = patternDashLength;
2739 firstPatternGapLength = patternGapLength;
2742 firstPatternLength = patternLength - pattern.at( 0 ) * 0.5;
2743 firstPatternDashLength = patternDashLength - pattern.at( 0 ) * 0.5;
2744 firstPatternGapLength = patternGapLength;
2747 firstPatternLength = pattern.at( patternSize - 1 );
2748 firstPatternDashLength = 0;
2749 firstPatternGapLength = pattern.at( patternSize - 1 );
2752 firstPatternLength = pattern.at( patternSize - 1 ) * 0.5;
2753 firstPatternDashLength = 0;
2754 firstPatternGapLength = pattern.at( patternSize - 1 ) * 0.5;
2758 const bool isSmallEnoughForSinglePattern = ( totalLength - firstPatternLength ) < patternLength * 0.5;
2760 double lastPatternLength = isSmallEnoughForSinglePattern ? firstPatternLength : patternLength;
2761 double lastPatternDashLength = isSmallEnoughForSinglePattern ? firstPatternDashLength : patternDashLength;
2762 double lastPatternGapLength = isSmallEnoughForSinglePattern ? firstPatternGapLength : patternGapLength;
2766 lastPatternLength = 0;
2767 lastPatternDashLength = 0;
2768 lastPatternGapLength = 0;
2771 lastPatternLength -= pattern.at( patternSize - 1 );
2772 lastPatternGapLength -= pattern.at( patternSize - 1 );
2775 lastPatternLength -= pattern.at( patternSize - 1 ) + pattern.at( patternSize - 2 ) * 0.5;
2776 lastPatternDashLength -= pattern.at( patternSize - 2 ) * 0.5;
2777 lastPatternGapLength -= pattern.at( patternSize - 1 );
2780 lastPatternGapLength = patternGapLength;
2783 lastPatternLength -= pattern.at( patternSize - 1 ) * 0.5;
2784 lastPatternGapLength -= pattern.at( patternSize - 1 ) * 0.5;
2788 const double remainingLengthForCompletePatterns = totalLength - ( !isSmallEnoughForSinglePattern ? firstPatternLength : 0 ) - lastPatternLength;
2789 const int middlePatternRepetitions = std::max(
static_cast< int >( std::round( remainingLengthForCompletePatterns / patternLength ) ), 0 );
2791 const double totalUnscaledLengthOfPatterns = ( !isSmallEnoughForSinglePattern ? firstPatternLength : 0 ) + middlePatternRepetitions * patternLength + lastPatternLength;
2792 const double totalUnscaledLengthOfDashes = ( !isSmallEnoughForSinglePattern ? firstPatternDashLength : 0 ) + middlePatternRepetitions * patternDashLength + lastPatternDashLength;
2793 const double totalUnscaledLengthOfGaps = ( !isSmallEnoughForSinglePattern ? firstPatternGapLength : 0 ) + middlePatternRepetitions * patternGapLength + lastPatternGapLength;
2795 double dashLengthScalingFactor = 1;
2796 double gapLengthScalingFactor = 1;
2800 const double lengthToShrinkBy = totalUnscaledLengthOfPatterns - totalLength;
2802 switch ( adjustment )
2805 dashLengthScalingFactor = totalLength / totalUnscaledLengthOfPatterns;
2806 gapLengthScalingFactor = dashLengthScalingFactor;
2809 dashLengthScalingFactor = ( totalUnscaledLengthOfDashes - lengthToShrinkBy ) / totalUnscaledLengthOfDashes;
2812 gapLengthScalingFactor = ( totalUnscaledLengthOfGaps - lengthToShrinkBy ) / totalUnscaledLengthOfGaps;
2817 dashLengthScalingFactor = std::max( dashLengthScalingFactor, 0.0 );
2818 gapLengthScalingFactor = std::max( gapLengthScalingFactor, 0.0 );
2820 const int maxPatterns = middlePatternRepetitions + 2;
2821 result->reserve( maxPatterns );
2823 int patternIndex = 0;
2824 double distanceToNextPointFromStartOfSegment = pattern.at( 0 ) * dashLengthScalingFactor;
2826 switch ( startRule )
2832 distanceToNextPointFromStartOfSegment *= 0.5;
2835 patternIndex = patternSize - 1;
2837 distanceToNextPointFromStartOfSegment = pattern.at( patternSize - 1 ) * gapLengthScalingFactor;
2840 patternIndex = patternSize - 1;
2842 distanceToNextPointFromStartOfSegment = 0.5 * pattern.at( patternSize - 1 ) * gapLengthScalingFactor;
2846 const double adjustedOffset = fmod( patternOffset, patternLength );
2847 const double scaledOffset = ( adjustedOffset < 0 ? ( adjustedOffset + patternLength ) : adjustedOffset ) * ( gapLengthScalingFactor + dashLengthScalingFactor ) / 2;
2851 double remainingOffset = scaledOffset;
2852 while ( remainingOffset > 0 )
2854 if ( distanceToNextPointFromStartOfSegment > remainingOffset )
2856 distanceToNextPointFromStartOfSegment -= remainingOffset;
2860 remainingOffset -= distanceToNextPointFromStartOfSegment;
2863 if ( patternIndex == patternSize )
2866 distanceToNextPointFromStartOfSegment = pattern.at( patternIndex ) * ( isDash ? dashLengthScalingFactor : gapLengthScalingFactor );
2872 outX.append( prevX );
2873 outY.append( prevY );
2876 for (
int i = 1; i < totalPoints; ++i )
2878 double thisX = *x++;
2879 double thisY = *y++;
2881 const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
2882 while ( distanceToNextPointFromStartOfSegment < segmentLength ||
qgsDoubleNear( distanceToNextPointFromStartOfSegment, segmentLength ) )
2885 const double distanceToPoint = std::min( distanceToNextPointFromStartOfSegment, segmentLength );
2900 if ( patternIndex >= patternSize )
2903 distanceToNextPointFromStartOfSegment += pattern.at( patternIndex ) * ( isDash ? dashLengthScalingFactor : gapLengthScalingFactor );
2908 outX.append( thisX );
2909 outY.append( thisY );
2914 distanceToNextPointFromStartOfSegment -= segmentLength;
2919 outX.append( prevX );
2920 outY.append( prevY );
2928 const QVector<double> &pattern,
2932 double patternOffset )
2934 std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
2938 geom = segmentizedCopy.get();
2949 std::unique_ptr< QgsMultiLineString > result = std::make_unique< QgsMultiLineString >();
2952 for (
int i = 0; i < exteriorParts->numGeometries(); ++i )
2953 result->addGeometry( exteriorParts->geometryN( i )->clone() );
2958 for (
int j = 0; j < ringParts->numGeometries(); ++j )
2959 result->addGeometry( ringParts->geometryN( j )->clone() );
2968 if ( pattern.size() < 2 )
2972 if ( !mGeometry || mGeometry->
isEmpty() )
2982 if (
const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) )
2984 int numGeom = gc->numGeometries();
2985 QVector< QgsAbstractGeometry * > geometryList;
2986 geometryList.reserve( numGeom );
2987 for (
int i = 0; i < numGeom; ++i )
2989 geometryList <<
applyDashPatternPrivate( gc->geometryN( i ), pattern, startRule, endRule, adjustment, patternOffset ).release();
2997 for (
int j = 0; j < collection->numGeometries(); ++j )
2999 first.
addPart( collection->geometryN( j )->clone() );