diff --git a/python/core/auto_generated/geometry/qgsgeometryutils.sip.in b/python/core/auto_generated/geometry/qgsgeometryutils.sip.in index 6e077fc17f8..9ee9a139f30 100644 --- a/python/core/auto_generated/geometry/qgsgeometryutils.sip.in +++ b/python/core/auto_generated/geometry/qgsgeometryutils.sip.in @@ -632,6 +632,25 @@ An algorithm to calculate an (approximate) intersection of two lines in 3D. Returns the area of the triangle denoted by the points (``aX``, ``aY``), (``bX``, ``bY``) and (``cX``, ``cY``). +.. versionadded:: 3.10 +%End + + static void weightedPointInTriangle( double aX, double aY, double bX, double bY, double cX, double cY, + double weightB, double weightC, double &pointX /Out/, double &pointY /Out/ ); +%Docstring +Returns a weighted point inside the triangle denoted by the points (``aX``, ``aY``), (``bX``, ``bY``) and +(``cX``, ``cY``). + +:param aX: x-coordinate of first vertex in triangle +:param aY: y-coordinate of first vertex in triangle +:param bX: x-coordinate of second vertex in triangle +:param bY: y-coordinate of second vertex in triangle +:param cX: x-coordinate of third vertex in triangle +:param cY: y-coordinate of third vertex in triangle +:param weightB: weighting factor along axis A-B (between 0 and 1) +:param weightC: weighting factor along axis A-C (between 0 and 1) +:param pointY: y-coordinate of generated point + .. versionadded:: 3.10 %End diff --git a/src/core/geometry/qgsgeometryutils.cpp b/src/core/geometry/qgsgeometryutils.cpp index d56c9625e03..0f6c77b4b85 100644 --- a/src/core/geometry/qgsgeometryutils.cpp +++ b/src/core/geometry/qgsgeometryutils.cpp @@ -1603,6 +1603,25 @@ double QgsGeometryUtils::triangleArea( double aX, double aY, double bX, double b return 0.5 * std::abs( ( aX - cX ) * ( bY - aY ) - ( aX - bX ) * ( cY - aY ) ); } +void QgsGeometryUtils::weightedPointInTriangle( const double aX, const double aY, const double bX, const double bY, const double cX, const double cY, + double weightB, double weightC, double &pointX, double &pointY ) +{ + // if point will be outside of the triangle, invert weights + if ( weightB + weightC > 1 ) + { + weightB = 1 - weightB; + weightC = 1 - weightC; + } + + const double rBx = weightB * ( bX - aX ); + const double rBy = weightB * ( bY - aY ); + const double rCx = weightC * ( cX - aX ); + const double rCy = weightC * ( cY - aY ); + + pointX = rBx + rCx + aX; + pointY = rBy + rCy + aY; +} + bool QgsGeometryUtils::setZValueFromPoints( const QgsPointSequence &points, QgsPoint &point ) { bool rc = false; diff --git a/src/core/geometry/qgsgeometryutils.h b/src/core/geometry/qgsgeometryutils.h index dd41cd72c76..57757b99f11 100644 --- a/src/core/geometry/qgsgeometryutils.h +++ b/src/core/geometry/qgsgeometryutils.h @@ -671,6 +671,26 @@ class CORE_EXPORT QgsGeometryUtils */ static double triangleArea( double aX, double aY, double bX, double bY, double cX, double cY ); + /** + * Returns a weighted point inside the triangle denoted by the points (\a aX, \a aY), (\a bX, \a bY) and + * (\a cX, \a cY). + * + * \param aX x-coordinate of first vertex in triangle + * \param aY y-coordinate of first vertex in triangle + * \param bX x-coordinate of second vertex in triangle + * \param bY y-coordinate of second vertex in triangle + * \param cX x-coordinate of third vertex in triangle + * \param cY y-coordinate of third vertex in triangle + * \param weightB weighting factor along axis A-B (between 0 and 1) + * \param weightC weighting factor along axis A-C (between 0 and 1) + * \param pointX x-coordinate of generated point + * \param pointY y-coordinate of generated point + * + * \since QGIS 3.10 + */ + static void weightedPointInTriangle( double aX, double aY, double bX, double bY, double cX, double cY, + double weightB, double weightC, double &pointX SIP_OUT, double &pointY SIP_OUT ); + /** * A Z dimension is added to \a point if one of the point in the list * \a points is in 3D. Moreover, the Z value of \a point is updated with. diff --git a/tests/src/core/testqgsgeometryutils.cpp b/tests/src/core/testqgsgeometryutils.cpp index 8bd84305b53..9a426802f42 100644 --- a/tests/src/core/testqgsgeometryutils.cpp +++ b/tests/src/core/testqgsgeometryutils.cpp @@ -78,6 +78,8 @@ class TestQgsGeometryUtils: public QObject void testSegmentizeArcFullCircle(); void testTriangleArea_data(); void testTriangleArea(); + void testWeightedPointInTriangle_data(); + void testWeightedPointInTriangle(); }; @@ -1380,5 +1382,51 @@ void TestQgsGeometryUtils::testTriangleArea() QGSCOMPARENEAR( QgsGeometryUtils::triangleArea( aX, aY, bX, bY, cX, cY ), expectedResult, 0.0000001 ); } +void TestQgsGeometryUtils::testWeightedPointInTriangle_data() +{ + QTest::addColumn( "aX" ); + QTest::addColumn( "aY" ); + QTest::addColumn( "bX" ); + QTest::addColumn( "bY" ); + QTest::addColumn( "cX" ); + QTest::addColumn( "cY" ); + QTest::addColumn( "weightB" ); + QTest::addColumn( "weightC" ); + QTest::addColumn( "expectedX" ); + QTest::addColumn( "expectedY" ); + + QTest::newRow( "weighted 1" ) << 15.0 << 15.0 << 23.0 << 30.0 << 50.0 << 25.0 << 0.0 << 0.0 << 15.0 << 15.0; + QTest::newRow( "weighted 2" ) << 15.0 << 15.0 << 23.0 << 30.0 << 50.0 << 25.0 << 0.5 << 0.0 << 19.0 << 22.5; + QTest::newRow( "weighted 3" ) << 15.0 << 15.0 << 23.0 << 30.0 << 50.0 << 25.0 << 1.0 << 0.0 << 23.0 << 30.0; + QTest::newRow( "weighted 4" ) << 15.0 << 15.0 << 23.0 << 30.0 << 50.0 << 25.0 << 0.0 << 0.5 << 32.5 << 20.0; + QTest::newRow( "weighted 5" ) << 15.0 << 15.0 << 23.0 << 30.0 << 50.0 << 25.0 << 0.0 << 1.0 << 50.0 << 25.0; + QTest::newRow( "weighted 6" ) << 15.0 << 15.0 << 23.0 << 30.0 << 50.0 << 25.0 << 0.5 << 0.5 << 36.5 << 27.5; + QTest::newRow( "weighted 7" ) << 15.0 << 15.0 << 23.0 << 30.0 << 50.0 << 25.0 << 1.0 << 1.0 << 15.0 << 15.0; + QTest::newRow( "weighted 8" ) << 15.0 << 16.0 << 15.0 << 16.0 << 15.0 << 25.0 << 0.0 << 0.0 << 15.0 << 16.0; + QTest::newRow( "weighted 9" ) << 15.0 << 16.0 << 15.0 << 16.0 << 15.0 << 25.0 << 1.0 << 0.0 << 15.0 << 16.0; + QTest::newRow( "weighted 10" ) << 15.0 << 16.0 << 15.0 << 16.0 << 15.0 << 16.0 << 0.0 << 1.0 << 15.0 << 16.0; + QTest::newRow( "weighted 11" ) << 15.0 << 16.0 << 15.0 << 16.0 << 15.0 << 16.0 << 1.0 << 1.0 << 15.0 << 16.0; + QTest::newRow( "weighted 12" ) << -15.0 << -15.0 << -23.0 << -30.0 << -50.0 << -25.0 << 0.5 << 0.5 << -36.5 << -27.5; +} + +void TestQgsGeometryUtils::testWeightedPointInTriangle() +{ + QFETCH( double, aX ); + QFETCH( double, aY ); + QFETCH( double, bX ); + QFETCH( double, bY ); + QFETCH( double, cX ); + QFETCH( double, cY ); + QFETCH( double, weightB ); + QFETCH( double, weightC ); + QFETCH( double, expectedX ); + QFETCH( double, expectedY ); + + double x, y; + QgsGeometryUtils::weightedPointInTriangle( aX, aY, bX, bY, cX, cY, weightB, weightC, x, y ); + QGSCOMPARENEAR( x, expectedX, 0.0000001 ); + QGSCOMPARENEAR( y, expectedY, 0.0000001 ); +} + QGSTEST_MAIN( TestQgsGeometryUtils ) #include "testqgsgeometryutils.moc"