Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
58bc22e
feat(core): add QgsNurbsCurve class for NURBS curve support
lbartoletti Dec 17, 2025
8748ac1
test(core): add C++ unit tests for QgsNurbsCurve
lbartoletti Dec 17, 2025
febe82c
test(core): add Python tests for QgsNurbsCurve
lbartoletti Dec 17, 2025
3e7395c
feat(geometry): add interpolatePointOnCubicBezier
lbartoletti Dec 24, 2025
0a85903
refactor(qgslinestring): use QgsGeometryUtils::interpolatePointOnCubi…
lbartoletti Dec 24, 2025
b03f273
feat(core): add ControlPoint snapping support
lbartoletti Dec 24, 2025
1a83782
fix(nurbs): add todo for oracle provider
lbartoletti Dec 19, 2025
e94441e
refactor(nurbs): Add a dedicated generateUniformKnots method
lbartoletti Jan 13, 2026
9331405
chore(style): fixup revert code formatting + SIP
lbartoletti Jan 13, 2026
db5565b
docs(geometryutils): move cubic bézier formula inside a code bloc
lbartoletti Jan 13, 2026
dae39d1
refactor(nurbs): replace const QVector<QgsPoint> & by QVector<QgsPoint>
lbartoletti Jan 13, 2026
5f2c524
refactor(nurbs): rename findNurbsCurveForVertex and SIP_SKIP the cons…
lbartoletti Jan 13, 2026
c5c46c0
fix(nurbs): enforce wkb endianess
lbartoletti Jan 13, 2026
e2e600e
fix(geometryutils): derive wkbType from all points in Bézier interpol…
lbartoletti Jan 13, 2026
5fe5990
test(core): complete test(core): add Python tests for QgsNurbsCurve
lbartoletti Jan 13, 2026
45dff76
fix(qgsgeometry): fix roundwaves test after use of QgsGeometryUtils::…
lbartoletti Jan 13, 2026
bb0a27f
chore(spell): add spellok for 'normalY'
lbartoletti Jan 13, 2026
9fd1b35
fix(qgsgeometrypaintdevice): fix tests
lbartoletti Jan 14, 2026
9599a26
refactor(qgsgeoemtryutils): move interpolatePointOnCubicBezier to Qgs…
lbartoletti Jan 14, 2026
a2002f4
perf(qgslinestring): rewrite fromBezierCurve using QgsGeometryUtilsBase
lbartoletti Jan 14, 2026
e4d4820
test(qgsgeometryutils): add tests for interpolatePointOnCubicBezier
lbartoletti Jan 14, 2026
c7a48bb
chore(nurbs): add a TODO for sumUpArea
lbartoletti Jan 14, 2026
cb584ff
temporary commit, placeholder for nurbs app/gui part
lbartoletti Jan 12, 2026
6d70287
fixup! fix(selectivemasking): fix due to numericalstability
lbartoletti Jan 15, 2026
1662a63
Revert "temporary commit, placeholder for nurbs app/gui part"
lbartoletti Jan 18, 2026
ad05a7a
Revert "feat(core): add ControlPoint snapping support"
lbartoletti Jan 18, 2026
141805e
revert(core): remove enum class NurbsMode, CaptureTechnique::NurbsCu…
lbartoletti Jan 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions python/PyQt6/core/auto_additions/qgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@
QgsWkbTypes.TIN = Qgis.WkbType.TIN
QgsWkbTypes.TIN.is_monkey_patched = True
QgsWkbTypes.TIN.__doc__ = "TIN \n.. versionadded:: 3.40"
QgsWkbTypes.NurbsCurve = Qgis.WkbType.NurbsCurve
QgsWkbTypes.NurbsCurve.is_monkey_patched = True
QgsWkbTypes.NurbsCurve.__doc__ = "NurbsCurve \n.. versionadded:: 4.0"
QgsWkbTypes.NoGeometry = Qgis.WkbType.NoGeometry
QgsWkbTypes.NoGeometry.is_monkey_patched = True
QgsWkbTypes.NoGeometry.__doc__ = "No geometry"
Expand Down Expand Up @@ -373,6 +376,9 @@
QgsWkbTypes.TINZ = Qgis.WkbType.TINZ
QgsWkbTypes.TINZ.is_monkey_patched = True
QgsWkbTypes.TINZ.__doc__ = "TINZ"
QgsWkbTypes.NurbsCurveZ = Qgis.WkbType.NurbsCurveZ
QgsWkbTypes.NurbsCurveZ.is_monkey_patched = True
QgsWkbTypes.NurbsCurveZ.__doc__ = "NurbsCurveZ \n.. versionadded:: 4.0"
QgsWkbTypes.PointM = Qgis.WkbType.PointM
QgsWkbTypes.PointM.is_monkey_patched = True
QgsWkbTypes.PointM.__doc__ = "PointM"
Expand Down Expand Up @@ -418,6 +424,9 @@
QgsWkbTypes.TINM = Qgis.WkbType.TINM
QgsWkbTypes.TINM.is_monkey_patched = True
QgsWkbTypes.TINM.__doc__ = "TINM"
QgsWkbTypes.NurbsCurveM = Qgis.WkbType.NurbsCurveM
QgsWkbTypes.NurbsCurveM.is_monkey_patched = True
QgsWkbTypes.NurbsCurveM.__doc__ = "NurbsCurveM \n.. versionadded:: 4.0"
QgsWkbTypes.PointZM = Qgis.WkbType.PointZM
QgsWkbTypes.PointZM.is_monkey_patched = True
QgsWkbTypes.PointZM.__doc__ = "PointZM"
Expand Down Expand Up @@ -463,6 +472,9 @@
QgsWkbTypes.TriangleZM = Qgis.WkbType.TriangleZM
QgsWkbTypes.TriangleZM.is_monkey_patched = True
QgsWkbTypes.TriangleZM.__doc__ = "TriangleZM"
QgsWkbTypes.NurbsCurveZM = Qgis.WkbType.NurbsCurveZM
QgsWkbTypes.NurbsCurveZM.is_monkey_patched = True
QgsWkbTypes.NurbsCurveZM.__doc__ = "NurbsCurveZM \n.. versionadded:: 4.0"
QgsWkbTypes.Point25D = Qgis.WkbType.Point25D
QgsWkbTypes.Point25D.is_monkey_patched = True
QgsWkbTypes.Point25D.__doc__ = "Point25D"
Expand Down Expand Up @@ -531,6 +543,10 @@

.. versionadded:: 3.40

* ``NurbsCurve``: NurbsCurve

.. versionadded:: 4.0

* ``NoGeometry``: No geometry
* ``PointZ``: PointZ
* ``LineStringZ``: LineStringZ
Expand All @@ -547,6 +563,10 @@
* ``MultiSurfaceZ``: MultiSurfaceZ
* ``PolyhedralSurfaceZ``: PolyhedralSurfaceZ
* ``TINZ``: TINZ
* ``NurbsCurveZ``: NurbsCurveZ

.. versionadded:: 4.0

* ``PointM``: PointM
* ``LineStringM``: LineStringM
* ``PolygonM``: PolygonM
Expand All @@ -562,6 +582,10 @@
* ``MultiSurfaceM``: MultiSurfaceM
* ``PolyhedralSurfaceM``: PolyhedralSurfaceM
* ``TINM``: TINM
* ``NurbsCurveM``: NurbsCurveM

.. versionadded:: 4.0

* ``PointZM``: PointZM
* ``LineStringZM``: LineStringZM
* ``PolygonZM``: PolygonZM
Expand All @@ -577,6 +601,10 @@
* ``PolyhedralSurfaceZM``: PolyhedralSurfaceM
* ``TINZM``: TINZM
* ``TriangleZM``: TriangleZM
* ``NurbsCurveZM``: NurbsCurveZM

.. versionadded:: 4.0

* ``Point25D``: Point25D
* ``LineString25D``: LineString25D
* ``Polygon25D``: Polygon25D
Expand Down Expand Up @@ -5689,6 +5717,10 @@
QgsVertexId.VertexType.CurveVertex = Qgis.VertexType.Curve
QgsVertexId.CurveVertex.is_monkey_patched = True
QgsVertexId.CurveVertex.__doc__ = "An intermediate point on a segment defining the curvature of the segment"
QgsVertexId.ControlPointVertex = Qgis.VertexType.ControlPoint
QgsVertexId.VertexType.ControlPointVertex = Qgis.VertexType.ControlPoint
QgsVertexId.ControlPointVertex.is_monkey_patched = True
QgsVertexId.ControlPointVertex.__doc__ = "A NURBS control point (does not lie on the curve) \n.. versionadded:: 4.0"
Qgis.VertexType.__doc__ = """Types of vertex.

.. versionadded:: 3.22
Expand All @@ -5701,6 +5733,13 @@

Available as ``QgsVertexId.CurveVertex`` in older QGIS releases.

* ``ControlPoint``: A NURBS control point (does not lie on the curve)

.. versionadded:: 4.0


Available as ``QgsVertexId.ControlPointVertex`` in older QGIS releases.


"""
# --
Expand Down
1 change: 1 addition & 0 deletions python/PyQt6/core/auto_additions/qgsgeometryutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
QgsGeometryUtils.projectPointOnSegment = staticmethod(QgsGeometryUtils.projectPointOnSegment)
QgsGeometryUtils.leftOfLine = staticmethod(QgsGeometryUtils.leftOfLine)
QgsGeometryUtils.interpolatePointOnArc = staticmethod(QgsGeometryUtils.interpolatePointOnArc)
QgsGeometryUtils.interpolatePointOnCubicBezier = staticmethod(QgsGeometryUtils.interpolatePointOnCubicBezier)
QgsGeometryUtils.segmentMidPoint = staticmethod(QgsGeometryUtils.segmentMidPoint)
QgsGeometryUtils.segmentMidPointFromCenter = staticmethod(QgsGeometryUtils.segmentMidPointFromCenter)
QgsGeometryUtils.circleTangentDirection = staticmethod(QgsGeometryUtils.circleTangentDirection)
Expand Down
6 changes: 6 additions & 0 deletions python/PyQt6/core/auto_additions/qgsnurbscurve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# The following has been generated automatically from src/core/geometry/qgsnurbscurve.h
try:
QgsNurbsCurve.__overridden_methods__ = ['clone', 'isClosed', 'isClosed2D', 'curveToLine', 'draw', 'drawAsPolygon', 'endPoint', 'equals', 'indexOf', 'interpolatePoint', 'numPoints', 'pointAt', 'points', 'reversed', 'scroll', 'startPoint', 'sumUpArea', 'sumUpArea3D', 'xAt', 'yAt', 'zAt', 'mAt', 'asQPolygonF', 'addToPainterPath', 'curveSubstring', 'length', 'segmentLength', 'distanceBetweenVertices', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'vertexAngle', 'swapXy', 'transform', 'createEmptyWithSameType', 'closestSegment', 'boundingBox', 'boundingBox3D', 'moveVertex', 'insertVertex', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'dimension', 'isEmpty', 'clear', 'boundingBoxIntersects', 'centroid', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'deleteVertex', 'fromWkb', 'fromWkt', 'fuzzyEqual', 'fuzzyDistanceEqual', 'geometryType', 'hasCurvedSegments', 'partCount', 'toCurveType', 'vertexAt', 'vertexCount', 'vertexNumberFromVertexId', 'isValid', 'clearCache', 'compareToSameClass', 'calculateBoundingBox3D']
QgsNurbsCurve.__group__ = ['geometry']
except (NameError, AttributeError):
pass
7 changes: 7 additions & 0 deletions python/PyQt6/core/auto_additions/qgsnurbsutils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# The following has been generated automatically from src/core/geometry/qgsnurbsutils.h
try:
QgsNurbsUtils.containsNurbsCurve = staticmethod(QgsNurbsUtils.containsNurbsCurve)
QgsNurbsUtils.findNurbsCurveForVertex = staticmethod(QgsNurbsUtils.findNurbsCurveForVertex)
QgsNurbsUtils.__group__ = ['geometry']
except (NameError, AttributeError):
pass
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ Abstract base class for all geometries.
sipType = sipType_QgsCircularString;
else if ( qgsgeometry_cast<QgsCompoundCurve *>( sipCpp ) != nullptr )
sipType = sipType_QgsCompoundCurve;
else if ( qgsgeometry_cast<QgsNurbsCurve *>( sipCpp ) != nullptr )
sipType = sipType_QgsNurbsCurve;
else if ( qgsgeometry_cast<QgsTriangle *>( sipCpp ) != nullptr )
sipType = sipType_QgsTriangle;
else if ( qgsgeometry_cast<QgsPolygon *>( sipCpp ) != nullptr )
Expand Down
24 changes: 24 additions & 0 deletions python/PyQt6/core/auto_generated/geometry/qgsgeometryutils.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,30 @@ Any z or m values present in the points will also be linearly
interpolated in the output.

.. versionadded:: 3.4
%End

static QgsPoint interpolatePointOnCubicBezier( const QgsPoint &p0, const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, double t ) /HoldGIL/;
%Docstring
Evaluates a point on a cubic Bézier curve defined by four control
points.

:param p0: start point (the curve passes through this point)
:param p1: first control point
:param p2: second control point
:param p3: end point (the curve passes through this point)
:param t: parameter value between 0 and 1

:return: the point on the Bézier curve at parameter ``t``

Any Z or M values present in the input points will also be interpolated.

The cubic Bézier formula is:

.. code-block:: text

B(t) = (1-t)³P₀ + 3(1-t)²tP₁ + 3(1-t)t²P₂ + t³P₃

.. versionadded:: 4.0
%End

static bool segmentMidPoint( const QgsPoint &p1, const QgsPoint &p2, QgsPoint &result /Out/, double radius, const QgsPoint &mousePos ) /HoldGIL/;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ segment) and the result is undefined.
%End



static void perpendicularOffsetPointAlongSegment( double x1, double y1, double x2, double y2, double proportion, double offset, double *x /Out/, double *y /Out/ );
%Docstring
Calculates a point a certain ``proportion`` of the way along the segment
Expand Down
Loading