I start with a Bspline, obtained approximating a cruve present in a FreeCAD file, so to use for scripting I have no other way to manually discretize and copy an paste the "point list" obtained from the code I manually input in the FreeCAD console:
Code: Select all
import FreeCAD
from FreeCAD import Base, Rotation, Vector
import Part
import Draft
import DraftVecUtils
from draftgeoutils.edges import findMidpoint
from draftgeoutils.intersections import findIntersection
from math import degrees
DOC_NAME = "test"
DOC = FreeCAD.activeDocument()
# CMPN_NAME = "Components"
# DOC.addObject("App::DocumentObjectGroup",CMPN_NAME)
def clear_doc():
"""
Clear the active document deleting all the objects
"""
for obj in DOC.Objects:
DOC.removeObject(obj.Name)
if DOC is None:
FreeCAD.newDocument(DOC_NAME)
FreeCAD.setActiveDocument(DOC_NAME)
DOC = FreeCAD.activeDocument()
VIEW = FreeCAD.Gui.ActiveDocument.ActiveView
else:
clear_doc()
VIEW = FreeCAD.Gui.ActiveDocument.ActiveView
def setview():
"""Rearrange View"""
DOC.recompute()
VIEW.viewAxometric()
VIEW.setAxisCross(True)
VIEW.fitAll()
def bsp2arcs(spline, prec):
edges = []
arcs = spline.toBiArcs(prec)
for i in arcs:
edges.append(Part.Edge(i))
return Part.Wire(edges)
def bilinear_surface(pts):
"""Create a degree 1 bspline surface from array(2D) for points
code made by chrisb on FreeCAD forum
"""
ny = len(pts)
nx = len(pts[0])
umults = [1]*ny
umults[0] = 2
umults[-1] = 2
vmults = [1]*nx
vmults[0] = 2
vmults[-1] = 2
uknots = [v for v in range(ny)]
vknots = [v for v in range(nx)]
bs = Part.BSplineSurface()
# 1 x 1 are the last numbers
bs.buildFromPolesMultsKnots(array, umults, vmults, uknots, vknots, False, False, 1, 1)
return bs
def find_intersection(wire, line):
pts = []
for edge in wire.Edges:
f_pts = findIntersection(line, edge)
if len(f_pts) > 1:
pts.extend(f_pts)
else:
if len(f_pts) != 0:
pts.append(f_pts[0])
return pts
# some vars
ROT0 = Rotation(0,0,0)
EPS = 1e-5
cm_pts = (
(-56.64199999999988, -108.52651511673002, 0.0),
(5.045714702451431, -89.33237066431363, 0.0),
(68.53266394469387, -77.37432303177049, 0.0),
(132.97648568219708, -72.83764291497576, 0.0),
(197.51261011152948, -75.78319379570682, 0.0),
(260.7847439701756, -88.14580249881409, 0.0),
(323.6040807225694, -79.3788987372448, 0.0),
(367.2823694583445, -33.3861228817963, 0.0),
(372.79691119601375, 29.801837430421966, 0.0),
(337.74602605414333, 82.66546820752089, 0.0),
(277.3950206667093, 102.18170352239254, 0.0),
(214.92488372007435, 86.599090089876, 0.0),
(150.92898644445887, 78.65194260507964, 0.0),
(86.93383045440443, 86.30428420472582, 0.0),
(32.35737605886684, 119.93166381983781, 0.0),
(-29.46640748383976, 133.54417536624192, 0.0),
(-93.13416360635159, 129.88433443137143, 0.0),
(-153.07012316309192, 153.86273378994565, 0.0),
(-216.6511630988794, 164.47375642110174, 0.0),
(-280.4777089025564, 156.68787584496482, 0.0),
(-336.6023312195406, 125.4766614340001, 0.0),
(-376.3754965874899, 75.05634269866019, 0.0),
(-393.6601152739239, 13.206886332309258, 0.0),
(-385.78913055704123, -50.52819728232701, 0.0),
(-353.9770547168756, -106.31444138277075, 0.0),
(-303.132563410529, -145.54390506584397, 0.0),
(-241.10107460845313, -162.1633961111713, 0.0),
(-177.15670396003594, -154.8026278244786, 0.0),
(-116.09033910107355, -133.8670902129459, 0.0),
(-56.641999999999854, -108.52651511673002, 0.0)
)
a_tol = 0.002
# interpolation points of the recostructed bspline (y dir)
dis_fac= 25
cus_incr = 40
incr = 18
f_incr = cus_incr * 0.25
off_dim = 1.0
c_off = 0
c_height = 41
bsf = (0.05, 0.22)
# this is holding the height as factor of c_height in the "central section"
# same progression is done for start and end section, but c_height is calculated
# using a formula that increase from start and decrease to end of surface
bsh = (0.45, 0.90, 1, 0.90, 0.45)
# cut h must be more high than bsh[2] *c_height as the surface is extruded in negative z-height
cut_h = c_height * 1.25
# body height the heigh of the base, using base_spline
body_h = 1.5 * 25.4
newpoints = []
for point in cm_pts:
newpoints.append(Vector(*point))
base_spline = Part.BSplineCurve()
base_spline.buildFromPoles(newpoints)
Part.show(base_spline.toShape(), "spline")
base_curve = bsp2arcs(base_spline, a_tol)
Part.show(base_curve, "curve")
DOC.recompute()
off_curve = base_curve.makeOffset2D(off_dim)
DOC.recompute()
# calculations
# select the offset spline
sp_dims = off_curve.BoundBox
xmax = sp_dims.XMax
xmin = sp_dims.XMin
ymin = sp_dims.YMin
ymax = sp_dims.YMax
lax = sp_dims.XLength * 1.1
lay = sp_dims.YLength * 1.1
# Create lines to find intersection points:
lines = []
idx = 0
xpos = xmin
while xpos < (xmin + cus_incr):
line = Part.LineSegment(Vector(xpos, ymin - incr), Vector(xpos, ymax + incr, 0))
lines.append(line)
xpos += f_incr
idx +=1
idx1 = idx - 1
xpos = xmin + cus_incr + 0.05
while xpos < xmax - cus_incr:
line = Part.LineSegment(Vector(xpos, ymin - incr), Vector(xpos, ymax + incr, 0))
lines.append(line)
last_xpos = xpos
xpos += incr
idx +=1
idx2 = idx
xpos = last_xpos + 0.05
while xpos < xmax:
line = Part.LineSegment(Vector(xpos, ymin - incr), Vector(xpos, ymax + incr, 0))
lines.append(line)
xpos += f_incr
idx +=1
idx_max = idx - 1
#print("number of lines", len(lines))
yint = []
idx = 0
for line in lines:
pts = find_intersection(off_curve, line.toShape())
yint.append((idx, pts))
idx +=1
#print("yint = ", yint)
splines = []
idx = 0
for apts in yint:
poles = []
print(apts)
if len(apts[1]) == 2:
pt_s = apts[1][0]
pt_e = apts[1][1]
if pt_s.y > pt_e.y:
pta = pt_s
ptb = pt_e
else:
pta = pt_e
ptb = pt_s
poles.append(pta)
pt1 = Vector.add(pta, (ptb.sub(pta)).multiply(bsf[0]))
pt2 = Vector.add(pta, (ptb.sub(pta)).multiply(bsf[1]))
pt3 = Vector.add(pta, (ptb.sub(pta)).multiply(1 - bsf[1]))
pt4 = Vector.add(pta, (ptb.sub(pta)).multiply(1 - bsf[0]))
if apts[0] < idx1:
mul_f = c_height / idx1
fact = [mul_f * idx * x for x in bsh]
elif apts[0] >= idx1 and apts[0] <= idx2:
fact = [c_height * x for x in bsh]
else:
mul_f = c_height / (idx_max - idx2)
el_h = c_height - (idx - idx2) * mul_f
fact = [el_h * x for x in bsh]
poles.extend(
[Vector(pt1.x, pt1.y, fact[0]),
Vector(pt2.x, pt2.y, fact[1]),
Vector(pt2.x, c_off, fact[2]),
Vector(pt3.x, pt3.y, fact[3]),
Vector(pt3.x, pt3.y, fact[4]),
ptb
])
skspline = Part.BSplineCurve()
skspline.buildFromPoles(poles)
skcurve = bsp2arcs(skspline, a_tol)
vrtxs = skcurve.OrderedVertexes
stpt = Part.LineSegment(vrtxs[-1].Point, vrtxs[0].Point)
edges = skcurve.OrderedEdges
edges.append(stpt.toShape())
new_wire = Part.Wire(edges)
profile = DOC.addObject('Part::Feature','Profile_{0:03d}'.format(idx))
profile.Shape = new_wire
splines.append(skcurve)
idx +=1
end_idx = idx
array = []
for spl in splines:
pts = spl.discretize(dis_fac)
array.append(pts)
surf = bilinear_surface(array)
int_shape = surf.toShape()
Part.show(int_shape, "surf")
path = DOC.addObject('Part::Feature','Length')
path.Shape = Part.Wire(Part.LineSegment(Vector(xmin, 0, 5), Vector(xmax, 0,5)).toShape())
DOC.recompute()
setview()
I want to obtain a solid, but I can't find a way to correctly close the solid:
1) the faces of the surface seems to be created in the "wrong way" with the surface internal to the solid, the gray color is in the "bottom" side of the created surface.
2) I can't close the solid as the "base face" is not matching the "curve" (that is the bspline transfomed in biarcs)
3) i cant to model the edges, the two parts at the begging and at the end of the shape, that has to be a cruved surface between the portion of the "generating curve" and the first an last spline of the approximating "vertical" splines.
TIA and Regards
Carlo D.