-
Notifications
You must be signed in to change notification settings - Fork 9
Curve functionalities #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7a2ccea
01444c8
94994fa
d76ebba
2843656
f0b2319
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| from compas.geometry import Point, Polyline | ||
| from compas_occ.geometry import NurbsCurve | ||
|
|
||
| from compas_view2.app import App | ||
|
|
||
| points = [Point(0, 0, 0), Point(3, 0, 2), Point(6, 0, -3), Point(8, 0, 0)] | ||
| curve = NurbsCurve.from_interpolation(points) | ||
|
|
||
| projection_point = Point(2, -1, 0) | ||
|
|
||
| closest_point, t = curve.closest_point(projection_point, parameter=True) | ||
|
|
||
| print(curve.point_at(t) == closest_point) | ||
|
|
||
| # ============================================================================== | ||
| # Visualisation | ||
| # ============================================================================== | ||
|
|
||
| view = App() | ||
|
|
||
| view.add(Polyline(curve.locus()), linewidth=3) | ||
| view.add(projection_point, pointcolor = (0, 0, 1)) | ||
| view.add(closest_point, pointcolor = (1, 0, 0)) | ||
|
|
||
| view.run() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| ******************************************************************************** | ||
| Curve Closest Point | ||
| ******************************************************************************** | ||
|
|
||
| .. figure:: /_images/example_curve_closest_point.png | ||
| :figclass: figure | ||
| :class: figure-img img-fluid | ||
|
|
||
| .. literalinclude:: curve_closest_point.py | ||
| :language: python | ||
|
|
||
| .. code-block:: text | ||
|
|
||
| True |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| from compas.geometry import Point, Polyline | ||
| from compas_occ.geometry import NurbsCurve | ||
|
|
||
| from compas_view2.app import App | ||
|
|
||
|
|
||
| pointsA = [Point(0, 0, 0), Point(3, 6, 0), Point(6, -3, 3), Point(10, 0, 0)] | ||
| curveA = NurbsCurve.from_points(pointsA) | ||
|
|
||
| curveA.segment(u=0.2, v=0.5) | ||
|
|
||
| print(curveA.domain) | ||
|
|
||
|
|
||
| pointsB = [Point(0, -1, 0), Point(3, 5, 0), Point(6, -4, 3), Point(10, -1, 0)] | ||
| curveB = NurbsCurve.from_points(pointsB) | ||
|
|
||
| segment = curveB.segmented(u=0.2, v=0.5) | ||
|
|
||
| print(curveB.domain) | ||
| print(segment.domain) | ||
|
|
||
| # ============================================================================== | ||
| # Visualisation | ||
| # ============================================================================== | ||
|
|
||
| view = App() | ||
|
|
||
| view.add(Polyline(curveA.locus()), linewidth=4, linecolor=(1, 0, 0)) | ||
|
|
||
| view.add(Polyline(curveB.locus()), linewidth=1, linecolor=(0, 0, 0)) | ||
| view.add(Polyline(segment.locus()), linewidth=4, linecolor=(0, 1, 0)) | ||
|
|
||
| view.run() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| ******************************************************************************** | ||
| Curve Segmentation | ||
| ******************************************************************************** | ||
|
|
||
| .. figure:: /_images/example_segmentation.png | ||
| :figclass: figure | ||
| :class: figure-img img-fluid | ||
|
|
||
| .. literalinclude:: curve_segmentation.py | ||
| :language: python | ||
|
|
||
| .. code-block:: text | ||
|
|
||
| (0.2, 0.5) | ||
|
|
||
| (0.0, 1.0) | ||
| (0.2, 0.5) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
| from OCC.Core.gp import gp_Trsf | ||
| from OCC.Core.Geom import Geom_BSplineCurve | ||
| from OCC.Core.GeomAPI import GeomAPI_Interpolate | ||
| from OCC.Core.GeomAPI import GeomAPI_ProjectPointOnCurve | ||
| from OCC.Core.GeomAdaptor import GeomAdaptor_Curve | ||
| from OCC.Core.GCPnts import GCPnts_AbscissaPoint_Length | ||
| from OCC.Core.Bnd import Bnd_Box | ||
|
|
@@ -601,9 +602,27 @@ def frame_at(self, t): | |
| """ | ||
| pass | ||
|
|
||
| def closest_point(self, point, distance=None): | ||
| """Compute the closest point on the curve to a given point.""" | ||
| pass | ||
| def closest_point(self, point: Point, parameter: bool = False) -> Point: | ||
| """Compute the closest point on the curve to a given point. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| point : Point | ||
| The point to project orthogonally to the curve. | ||
| parameter : bool, optional | ||
| Return the projected point as well as the curve parameter. | ||
|
|
||
| Returns | ||
| ------- | ||
| Point or tuple | ||
| The nearest point on the curve, if ``parameter`` is false. | ||
| The nearest as (point, parameter) tuple, if ``parameter`` is true. | ||
| """ | ||
| projector = GeomAPI_ProjectPointOnCurve(point.to_occ(), self.occ_curve) | ||
| point = Point.from_occ(projector.NearestPoint()) | ||
| if not parameter: | ||
| return point | ||
| return point, projector.LowerDistanceParameter() | ||
|
|
||
| def divide_by_count(self, count): | ||
| """Divide the curve into a specific number of equal length segments.""" | ||
|
|
@@ -631,3 +650,46 @@ def obb(self, precision: float = 0.0) -> Box: | |
| def length(self, precision: float = 1e-3) -> float: | ||
| """Compute the length of the curve.""" | ||
| return GCPnts_AbscissaPoint_Length(GeomAdaptor_Curve(self.occ_curve)) | ||
|
|
||
| def segment(self, u: float, v: float, precision: float = 1e-3) -> None: | ||
| """Modifies this curve by segmenting it between the parameters u and v. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| u: float | ||
| v: float | ||
| tol: float, optional | ||
| default value is 1e-3 | ||
|
|
||
| Returns | ||
| ------- | ||
| None | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return value should be updated to the type of the returned object.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in the segment (vs. segmented) nothing is returned actually (using the same convention as in compas, e.g transform vs. transformed). -> in that case, should there then be no Return section at all? (in compas this appears inconsistent, sometimes it returns None, sometimes there is no return at all...)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. returning nothing or returning |
||
|
|
||
| """ | ||
| if u > v: | ||
| u, v = v, u | ||
| s, e = self.domain | ||
| if u < s or v > e: | ||
| raise ValueError('At least one of the given parameters is outside the curve domain.') | ||
|
Comment on lines
+672
to
+673
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as far as i understand the OCC docs, is this requirement not necessary
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in the case of e.g. u<v, Occ gives this error:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes just leave it as is... |
||
| if u == v: | ||
| raise ValueError('The given domain is zero length.') | ||
| self.occ_curve.Segment(u, v, precision) | ||
|
|
||
| def segmented(self, u: float, v: float, precision: float = 1e-3) -> 'NurbsCurve': | ||
| """Returns a copy of this curve by segmenting it between the parameters u and v. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| u: float | ||
| v: float | ||
| tol: float,optional | ||
| default value is 1e-3 | ||
|
|
||
| Returns | ||
| ------- | ||
| NurbsCurve | ||
|
|
||
| """ | ||
| copy = self.copy() | ||
| copy.occ_curve.Segment(u, v, precision) | ||
| return copy | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you add a comment about what segmenting actually is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you mean...
Maybe something like " a segment is a portion of the curve bounded by the points of two curve parameters u and v." ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to something like "Reduces the curve to the segment between parameters u and v." is a lot more descriptive of what actually happens