Open marcocecchiscmgroup opened 1 year ago
By fixing all the data format issues and continuing, another error shows up:
'SurfaceSpline' object has no attribute 'entity' in:
def getSurface(self): return None if (self._surface is None) else self._surface.entity
maybe more defensive checks are needed?
Thanks.
For the record: building nubs/nurbs is quite straightforward with NURBS-python or splipy (I'd discourage scipy/numpy as being too big only for that task). With those, you can as well interopolate b-splines from points, in the same way as you already do with Part (which we don't want to kick in in Acis2Step.py).
@HolographicPrince : this is the reason why numpy was banned a "long time" ago. @marcocecchiscmgroup : mea culpa - but is there a way to build a helical curve/surface in STEP without using Part.BSpline?
For the record: building nubs/nurbs is quite straightforward with NURBS-python or splipy (...). With those, you can as well interopolate b-splines from points, in the same way as you already do with Part (...). As long splines have a nubs/nurbs information no problem. It's all about parametric splines (like helical surfaces) for those I have to create a model based on Part.
As long splines have a nubs/nurbs information no problem. It's all about parametric splines (like helical surfaces) for those I have to create a model based on Part.
I see. Let's start with the helix. Here you have written a Helix class of your own, without using the Part.Helix (that would have been available, in case). So you're using Part only to do this:
self.rotateShape(helix, DIR_X, VEC(self.dirMajor.x, self.dirMajor.y, 0), DIR_Z)
self.rotateShape(helix, DIR_Z, self.vecAxis, DIR_X)
helix.translate(self.posCenter)
So this can be dealt with quite easily: just transform each single point before creating the spline. Or else, you can transform the control points, as the knots are invariant for rigid transformations.
Please check out this version that, by merging new and old approach, provides what follows:
bug fixes in STEP transformation
** Online Autodesk dxf viewer didn't show the transformed elements at all (while FreeCAD, Rhino and ShareCAD did)
** Translations only sometimes result in a (0, 0, 0) rotation axis, which cannot be normalized
Demo-Status-0.4.2.ipt works with native Part (no stubs)
Demo-Status-0.6.ipt works with native Part (no stubs)
Fixed syntax errors found compiling with Cython
From the -dbg version, implement this snippet below in Part.py, class BSplineCurve(Curve). Then, in Acis.py you transform the single points before interpolating, instead of rotating the whole spline once built. Let me know how it works.
from geomdl import fitting, BSpline as NURBSBSpline
[...]
class BSplineCurve(Curve):
def __init__(self, points = [], weights = None, knots = None, periodic = False, degree = 3, multiplicities = None, checkrational = False):
super(BSplineCurve, self).__init__('BSplineCurve')
self._poles = points
self._weights = weights
self.KnotSequence = knots
self._closed = periodic
self._mults = multiplicities
self._knotsExploded = []
if not knots is None:
for i in range(0, len(knots)):
for m in range(0, multiplicities[i]):
self._knotsExploded.append(knots[i])
self.Degree = degree
self.bSplineCurve = None
def getPoles(self):
return self._poles
def getMultiplicities(self):
nb_knots = len(self._knotsExploded)
if (nb_knots == 0):
return []
elif (nb_knots == 1):
return [1]
else:
ret = []
mult = 1
i = 1
while i < nb_knots:
while (i < nb_knots and isclose(self._knotsExploded[i - 1], self._knotsExploded[i])):
mult += 1
i += 1
ret.append(mult)
mult = 1
i += 1
return ret
def getKnots(self):
return self.KnotSequence
def getWeights(self):
return self._weights
def isRational(self):
if (not self.bSplineCurve is None):
return self.bSplineCurve.rational
else:
return (self._weights is not None) and (len(self._weights) > 0)
def isClosed(self): return self._closed
def value(self, u):
#evaluate
if (not self.bSplineCurve is None):
value = self.bSplineCurve.evaluate_single(u)
return Vector(value.x, value.y, value.z)
def interpolate(self, points, periodicFlag=False, tolerance=1e-6, initialTangent=None, finalTangent=None, tangents=None, tangentFlags=False, parameters=None, scale=1.0):
pointsV = []
for p in points:
pointsV.append((p.x, p.y, p.z))
self.bSplineCurve = fitting.interpolate_curve(pointsV, self.Degree)
self._poles = []
for p in self.bSplineCurve.ctrlpts:
self._poles.append(Vector(p[0], p[1], p[2])) # lo stesso formato atteso
self._knotsExploded = self.bSplineCurve.knotvector
self.KnotSequence = []
nbKnots = len(self._knotsExploded)
if nbKnots > 0:
if nbKnots == 1:
self.KnotSequence = self._knotsExploded
else:
self.KnotSequence.append(self._knotsExploded[0])
i = 1
while i < nbKnots:
while (i < nbKnots and isclose(self._knotsExploded[i - 1], self._knotsExploded[i])):
i += 1
if (i < nbKnots):
self.KnotSequence.append(self._knotsExploded[i])
i += 1
startp = self.bSplineCurve.evaluate_single(self.KnotSequence[0])
startpV = Vector(startp[0], startp[1], startp[2])
endp = self.bSplineCurve.evaluate_single(self.KnotSequence[-1])
endpV = Vector(endp[0], endp[1], endp[2])
self._closed = startpV.distanceToPoint(endpV) < EPS
self._weights = parameters
def buildFromPolesMultsKnots(self, poles, mults=(), knots=(), periodic=False, degree=1, weights=None, CheckRational = True):
lu = len(poles)
sum_of_mults = sum(mults)
if (PyObject_IsTrue(periodic) and (sum_of_mults - degree - 1 != lu)): raise Exception("number of poles and sum of mults mismatch")
if (PyObject_Not(periodic) and (sum_of_mults - degree - 1 != lu)): raise Exception("number of poles and sum of mults mismatch")
if ((weights is not None) and (lu != len(weights))): raise Exception("number of poles and weights mismatch")
self._poles = poles
self._mults = mults
self.KnotSequence = knots
self._knotsExploded = []
for i in range(0, len(knots)):
for _ in range(0, mults[i]):
self._knotsExploded.append(knots[i])
self._closed = periodic
self.Degree = degree
self._weights = weights
self.bSplineCurve = NURBSBSpline.Curve()
self.bSplineCurve.degree = degree
self.bSplineCurve.weights = weights
self.bSplineCurve.ctrlpoints = poles
self.bSplineCurve.knotvector = self._knotsExploded
return self
class BSplineSurface(GeometrySurface):
def __init__(self):
super(BSplineSurface, self).__init__('BSplineSurface')
self._poles = []
self.UKnotSequence = []
self.VKnotSequence = []
self.UDegree = 3
self.VDegree = 3
self._weights = []
#MC
self._uknotsExploded = []
self._vknotsExploded = []
self.bSplineSurface = None
def getPoles(self): return self._poles
def getUMultiplicities(self):
nb_uknots = len(self._uknotsExploded)
if (nb_uknots == 0):
return []
elif (nb_uknots == 1):
return [1]
else:
ret = []
mult = 1
i = 1
while i < nb_uknots:
while (i < nb_uknots and isclose(self._uknotsExploded[i - 1], self._uknotsExploded[i])):
mult += 1
i += 1
ret.append(mult)
mult = 1
i += 1
return ret
def getVMultiplicities(self):
nb_vknots = len(self._vknotsExploded)
if (nb_vknots == 0):
return []
elif (nb_vknots == 1):
return [1]
else:
ret = []
mult = 1
i = 1
while i < nb_vknots:
while (i < nb_vknots and isclose(self._vknotsExploded[i - 1], self._vknotsExploded[i])):
mult += 1
i += 1
ret.append(mult)
mult = 1
i += 1
return ret
def getUKnots(self):
return self.UKnotSequence
def getVKnots(self):
return self.VKnotSequence
def isURational(self):
if (self.bSplineSurface is not None):
return self.bSplineSurface.rational
else:
return self._weights is not None and len(self._weights) > 0
def isVRational(self):
if (self.bSplineSurface is not None):
return self.bSplineSurface.rational
else:
return self._weights is not None and len(self._weights) > 0
def NbUKnots(self):
return len(self.UKnotSequence)
def NbVKnots(self):
return len(self.VKnotSequence)
def NbUPoles(self):
return len(self._poles)
def NbVPoles(self):
if (self.NbUPoles() > 0):
return len(self._poles[0])
else:
return 0
def NbPoles(self):
return len(self._poles)
def isUClosed(self):
isClosed = True
j = 0
while (isClosed and j < self.NbVPoles()):
isClosed = self._poles[0][j].distance(self._poles[-1][j]) <= EPS
j += 1
return isClosed
def isVClosed(self):
isClosed = True
i = 0
while (isClosed and i < self.NbUPoles()):
isClosed = self._poles[i][0].distance(self._poles[i][-1]) <= EPS
i += 1
return isClosed
def getWeights(self):
return self._weights
def buildFromPolesMultsKnots(self, poles, umults=(), vmults=(), uknots=(), vknots=(), uperiodic=False, vperiodic=False, udegree=1, vdegree=1, weights=None):
lu = len(poles)
sum_of_umults = sum(umults)
lv = len(poles[0])
sum_of_vmults = sum(vmults)
for i in umults:
for j in range(0, i):
self._uknotsExploded.append(uknots[i])
for i in vmults:
for j in range(0, i):
self._vknotsExploded.append(vknots[i])
if ((weights is not None) and (lu != len(weights))): raise Exception("weights and poles rows-mismatch")
if ((weights is not None) and (lv != len(weights[0]))): raise Exception("weights and poles cols-mismatch")
if (len(uknots) != len(umults)): raise Exception("number of u-knots and u-mults mismatch")
if (len(vknots) != len(vmults)): raise Exception("number of v-knots and v-mults mismatch")
#if (PyObject_IsTrue(uperiodic) and (sum_of_umults - udegree - 1 != lu)): raise Exception("number of poles (%d) and sum of u-mults (%d) mismatch for uPeriodic = True" %(lu, sum_of_umults))
#if (PyObject_IsTrue(vperiodic) and (sum_of_umults - udegree - 1 != lu)): raise Exception("number of poles (%d) and sum of v-mults (%d) mismatch for vPeriodic = True" %(lv, sum_of_vmults))
if (PyObject_Not(uperiodic) and (sum_of_umults - udegree - 1 != lu)): raise Exception("number of poles (%d) and sum of u-mults (%d) mismatch for uPeriodic = False" %(lu, sum_of_umults))
if (PyObject_Not(vperiodic) and (sum_of_vmults - vdegree - 1 != lv)): raise Exception("number of poles (%d) and sum of v-mults (%d) mismatch for vPeriodic = False" %(lv, sum_of_vmults))
self._poles = poles
self.UKnotSequence = uknots
self.VKnotSequence = vknots
self.UDegree = udegree
self.VDegree = vdegree
self._weights = weights
self.bSplineSurface = NURBSBSpline.Surface()
self.bSplineCurve.weights = weights
self.bSplineSurface.ctrlpoints = poles
self.bSplineSurface.degree_u = udegree
self.bSplineSurface.degree_v = vdegree
self.bSplineSurface.knotvector_u = self._uknotsExploded
self.bSplineSurface.knotvector_v = self._vknotsExploded
return self
def value(self, u, v):
if (self.bSplineSurface):
return Vector(self.bSplineSurface.evaluate(u, v))
else:
return None
def interpolate(self, points, periodic=False):
knotvector_u_len = len(points)
knotvector_v_len =len(points[0])
pointsConv = []
for row in points:
for col in row:
pointsConv.append((col.x, col.y, col.z))
self.bSplineSurface = fitting.interpolate_surface(pointsConv, knotvector_u_len, knotvector_v_len, self.UDegree, self.VDegree)
if (self.bSplineSurface.rational):
self._weights = self.bSplineSurface.weights
poles_tmp = reshape(self.bSplineSurface.ctrlpts, knotvector_v_len)
self._poles = []
for pole_row in poles_tmp:
self._poles.append([])
for pole_col in pole_row:
self._poles[-1].append(Vector(pole_col[0], pole_col[1], pole_col[2]))
self._uknotsExploded = self.bSplineSurface.knotvector_u
self.UKnotSequence = []
nbUKnots = len(self._uknotsExploded)
if nbUKnots > 0:
if nbUKnots == 1:
self.UKnotSequence = self._uknotsExploded
else:
self.UKnotSequence.append(self._uknotsExploded[0])
i = 1
while i < nbUKnots:
while (i < nbUKnots and isclose(self._uknotsExploded[i - 1], self._uknotsExploded[i])):
i += 1
if (i < nbUKnots):
self.UKnotSequence.append(self._uknotsExploded[i])
i += 1
self._vknotsExploded = self.bSplineSurface.knotvector_v
self.VKnotSequence = []
nbVKnots = len(self._vknotsExploded)
if nbVKnots > 0:
if nbVKnots == 1:
self.VKnotSequence = self._vknotsExploded
else:
self.VKnotSequence.append(self._vknotsExploded[0])
i = 1
while i < nbVKnots:
while (i < nbVKnots and isclose(self._vknotsExploded[i - 1], self._vknotsExploded[i])):
i += 1
if (i < nbVKnots):
self.VKnotSequence.append(self._vknotsExploded[i])
i += 1
#self._closed = periodic
# non si sa mai
self.UDegree = self.bSplineSurface.degree_u
self.VDegree = self.bSplineSurface.degree_v
@marcocecchiscmgroup : poles_tmp = reshape(self.bSplineSurface.ctrlpts, knotvector_v_len)
<- Is reshape from numpy?
A couple of years ago I gave you this to remove the numpy dependency, maybe you wiped it out completely:
def reshape(v, size):
if size == 1: return v
return [[v[size * i + j] for j in range(size)] for i in range(len(v) // size)]
I was only too long away from this project.
The helicoidal spline curve/surfaces from Demo-Status-0.6.ipt raise exceptions. There are various issues into play:
Acis.py/class SurfaceSpline(Surface)/build(self, face = None): 'helix_spl_circ' is not contemplated in the if .. elif .. elif
Then, returning a Shape fails the if .. elif... in Acis2Step.py/createSurfaceSpline(acisFace)(acisFace), which in turn returns None instead of a pair None, None, that raises a 'cannot unpack non-iterable NoneType object' exception, because of this:
surface, sense = _createSurfaceFaceShape(acisFace)
This used to work before, because the Helix was at least built correctly and now it is not used anymore. Jens, these are your very examples, why don't you at least run them all before committing?