-
Notifications
You must be signed in to change notification settings - Fork 291
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
Implement ability to construct B-Splines from Poles, Knots, Multiplicities, and Degree parameters. #1448
Comments
First take a look at |
I see no way how these methods are related to the proposed functionality. SplineApprox is supposed to be used for fitting data points. The proposed method is about enabling the construction of B-Splines based on control points, knot vector, and degree (ideally weights too). |
You mentioned external approximation libraries and airfoils yourself. I'd use the functions above in those contexts. |
Due to the Moreover - the requested method will enable users to write custom methods for spline construction. Imagine a pipeline connector or other similar cases when you need to define spline by control points without any data points to approximate/interpolate. |
Can you describe your actual use case precisely? BTW you can always use OCCT methods directly. |
I do use OCCT methods right now: However, I think it should be implemented as a CadQuery method. My use case: I'm trying to build smooth airfoil shapes using data points in this format: I can not use splineApprox due to:
Here is how I find the best fit with SciPy: And Then I reconstruct the spline with the OCCT methods as mentioned before. |
This is what I get with What you say you need is more or less implemented here
but with the dxf import use case in mind. You could refactor it into e.g. occ_impl.importers.utils and enable it to accept nurbs control points knots and weights as e.g. iterators or sequences. You wrote some code already, so PRs are welcome. There will be some review process though.
import numpy as np
import cadquery as cq
data = np.loadtxt(r'naca23015_Subset_1.csv',skiprows=1,delimiter=',')
w = cq.Workplane().splineApprox(data[:,[1,2]]).close()
pts = [cq.Vertex.makeVertex(*d,0) for d in data[:,[1,2]]]
show_object(w)
show_object(pts) |
Wow, thanks for digging deep into my problem! Must confess now, that the CQ spline fitting methods do work with airfoil data (do not know why I got the exception last time). However, since we have this discussion, let me explain the drawbacks of these methods in more detail. I've been into spline fitting for quite some time and even created a dedicated platform for spline fitting (SplineCloud). As with many other fitting methods, two issues hurt the most: overfitting and underfitting. And this is also the case for airfoil shape approximation. There are a bunch of research papers dedicated to this problem, here are just a few of them: Universal Airfoil Parametrization Using B-Splines A Comparison of Airfoil Shape Parameterization Techniques Smoothing of the airfoil section having curvature graph As I mentioned before, the CQ methods ( I deed some analysis to show the obvious issues of overfitting and underfitting that are induced by blindly using default interpolation and approximation with CadQuery. The airfoil from your example show no visible signs of these issues, so I picked another one from the database that is more susceptible.
Setting bug or it's meaning differs form
As you can see, by diving deep and trying to optimize airfoil shape one can find out the need to use some external libraries. And this is what I did with SciPy after trying out different other options. It's method You can find code with my analyses here: |
OK, your use case is clear and very specific. I can see how having this import functionality would be beneficial for some users. As I mentioned the code is there: degree = el.dxf.degree
periodic = el.closed
rational = False
knots_unique = OrderedDict()
for k in el.knots:
if k in knots_unique:
knots_unique[k] += 1
else:
knots_unique[k] = 1
# assmble knots
knots = TColStd_Array1OfReal(1, len(knots_unique))
multiplicities = TColStd_Array1OfInteger(1, len(knots_unique))
for i, (k, m) in enumerate(knots_unique.items()):
knots.SetValue(i + 1, k)
multiplicities.SetValue(i + 1, m)
# assemble weights if present:
if el.weights:
rational = True
weights = TColStd_Array1OfReal(1, len(el.weights))
for i, w in enumerate(el.weights):
weights.SetValue(i + 1, w)
# assemble control points
pts = TColgp_Array1OfPnt(1, len(el.control_points))
for i, p in enumerate(el.control_points):
pts.SetValue(i + 1, gp_Pnt(*p))
if rational:
spline = Geom_BSplineCurve(
pts, weights, knots, multiplicities, degree, periodic
)
else:
spline = Geom_BSplineCurve(pts, knots, multiplicities, degree, periodic)
return (Edge(BRepBuilderAPI_MakeEdge(spline).Edge()),) It just needs to be refactored into a separate function along the lines of |
I can take this on in a week or two. |
In the meantime, can you please confirm if there is a bug in the smoothing parameter of the |
I don't think it is a bug. AFAICT the parameters are relative weights of certain penalty terms, try e.g |
Existing spline construction methods assume that the user passes an array of points to interpolate/approximate. This approach, however, does not provide control over interpolation methods, and in some cases fails to satisfy expected smoothness.
Example. For the airfoil geometry, I often obtain wavy shapes due to overfitting (I use Selig format for the profile points). A possible solution would be to construct the desired shape using external spline approx libraries or services (SciPy, NurbsPython, SplineCloud) and pass spline-supporting data (control points, knots, degree) directly into CadQuery to end up with the shape of desired smoothness.
OCC supports this type of the spline creation via
OCC.Geom.Geom_BSplineCurve
class.Links to OCCT documentation:
https://liuxinwin_admin.gitee.io/pythonocc-docs/OCC.Geom.html#OCC.Geom.Geom_BSplineCurve
https://dev.opencascade.org/doc/refman/html/class_geom___b_spline_curve.html#a00d969dca532b7cd71594f805608fc7d
The text was updated successfully, but these errors were encountered: