Open lalebarde opened 4 years ago
I have tried wp = cq.copyWorkplane(wp2)
instead of wp = wp2
, but I get the following error:
AttributeError: module 'cadquery' has no attribute 'copyWorkplane'
I have supposed it is right from the documentation here:
class cadquery.CQ(obj) copyWorkplane(obj)[source] Copies the workplane from obj. Parameters obj (a CQ object) – an object to copy the workplane from Returns a CQ object with obj’s workplane
Why do you want to actually loft? There is a sweep
function that can even take different sections.
I need control on the section orientation: yaw, roll and pitch
Here is an example with sweep:
import cadquery as cq
from math import sin, cos, pi
SEGMENTS = 48
def sinusoidal_ring(rad=25, segments=SEGMENTS):
outline = []
for i in range(segments):
angle = i * 2 * pi / segments
x = rad * (cos(angle) + i/segments)
y = rad * sin(angle)
z = 2 * rad * (sin(angle) / 5 + i / segments)
outline.append((x, y, z))
return outline
def triangle(base = 15, ratio = 2):
return [(-base/2, 0), (base/2, 0), (0, base*ratio)]
def extrude_example():
shape = triangle()
path = sinusoidal_ring(rad=50)
p= cq.Workplane("XY").spline(path,includeCurrent=True)
s = cq.Workplane("YZ").polyline(shape).close().sweep(p)
return s
result = extrude_example()
show_object(result)
The section starts with a triangle oriented towards the Z axes, and does not stay as this along the path.
Is this what you want to get?
I used raw OCC features, in the end it will be implemented in CQ in relation to #97
import cadquery as cq
from math import sin, cos, pi
SEGMENTS = 148
def sinusoidal_ring(rad=250, segments=SEGMENTS, N = 1):
outline = []
for i in range(segments):
angle = N*i * 2 * pi / segments
x = rad * (cos(angle) + i/segments)
y = rad * sin(angle)
z = 2 * rad * (sin(angle) / 5 + i / segments)
outline.append((x, y, z))
return outline
def triangle(base = 15, ratio = 2):
return [(-base/2, 0), (base/2, 0), (0, base*ratio)]
def extrude_example():
shape = triangle()
p= cq.Workplane("XY",origin=(0,0,30)).spline(path,includeCurrent=True)
s = cq.Workplane("YZ").polyline(shape).close().sweep(p,isFrenet=True)
return s,p
path = sinusoidal_ring(rad=50)
p1 = cq.Workplane("XY",origin=(0,0,30)).spline(path,includeCurrent=True)
p2 = cq.Workplane("XY",origin=(0,0,0)).spline(path,includeCurrent=True)
t = cq.Workplane("YZ").polyline(triangle()).close()
result,p = extrude_example()
import OCC
ps = OCC.Core.BRepOffsetAPI.BRepOffsetAPI_MakePipeShell(p1.wire().val().wrapped)
ps.Add(t.val().wrapped)
ps.SetMode(p2.wire().val().wrapped,True)
ps.Build()
ps.MakeSolid()
res = cq.Shape(ps.Shape())
show_object(res)
show_object(p1)
show_object(p2)
Oh yes, thank you very much Adam! I cannot use OCC directly at this time, so, you have saved me. Very nice to ear from you it will be in CQ.
Adam, there is something strange: I understand the spline starts at the origin because of includeCurrent=True
in the spline
command. If I put false, I obtain this:
I would like also to explore the different OCC options:
ps.SetMode(p2.wire().val().wrapped,True,OCC.Core.BRepOffsetAPI.BRepFill_ContactOnBorder)
raises the error:
AttributeError: module 'OCC.Core.BRepOffsetAPI' has no attribute 'BRepFill_ContactOnBorder'
Adam, I have made a more realistic test and unfortunatly, what brings ps.SetMode(p2.wire().val().wrapped,True)
is not what I am looking for.
import cadquery as cq
from math import sin, cos, pi
SEGMENTS = 10
def test(l=20):
return[(0,0,0),(l,0,0),(2*l,0,l/2),(3*l,0,4*l),(4*l,l,5*l),(4*l,2*l,6*l),(3*l,4*l,6*l)]
def triangle(base = 15, ratio = 2):
return [(-base/2, 0), (base/2, 0), (0, base*ratio)]
path = test()
p1 = cq.Workplane("XY",origin=(0,0,40)).polyline(path)
p2 = cq.Workplane("XY",origin=(0,0,0)).polyline(path)
t = cq.Workplane("YZ").polyline(triangle()).close()
import OCC
ps = OCC.Core.BRepOffsetAPI.BRepOffsetAPI_MakePipeShell(p1.wire().val().wrapped)
ps.Add(t.val().wrapped)
ps.SetMode(p2.wire().val().wrapped,True)
ps.Build()
ps.MakeSolid()
res = cq.Shape(ps.Shape())
show_object(res)
show_object(p1)
show_object(p2)
As you can see from the bottom view, the pattern don't rotate and the section of the volume becomes a line. Think of my need as a stair handrail. In my post here, my use case is (1, 1, 0) no yaw, but the section can roll when the handrail turns right or left, and can pitch when it climbs.
OCC is very hard to learn because the documentation is light and one has to test thoroughly to figure out what it can perform, or review the code if possible - and testing is hard because it lacks examples. Probably there is a way to use BRepOffsetAPI_MakePipeShell
to fit ma case, but I cannot figure it out. So, maybe the best solution for me would be to going on with loft
, where I can master what I want. loft
enables to control precisely the location of every sections and I can calculate them. But I have failed above to perform it cf ValueError: More than one wire is required
Here is the working code:
import cadquery as cq
wp = cq.Workplane("XY").rect(1,2).workplane()
result = None
for i in range(0,5):
wp2 = wp.transformed(offset=cq.Vector(0, -0.5, 1.0),rotate=cq.Vector(10, 0, 0)).rect(1,2).workplane()
if result == None:
result = wp2.loft(combine=True)
else:
nextpart = wp2.loft(combine=True)
result = result.union(nextpart)
wp = wp.transformed(offset=cq.Vector(0, -0.5, 1.0),rotate=cq.Vector(10, 0, 0)).rect(1,2).workplane()
show_object(result, options=dict(alpha=0.5,color='red'))
The point is to push back the last wire in the CQ stack, what a simple python assigment could not do (wp = wp2
). So I changed it to wp = wp.transformed(offset=cq.Vector(0, -0.5, 1.0),rotate=cq.Vector(10, 0, 0)).rect(1,2).workplane()
to make work the CQ kernel.
Same post as here. I can loft a 2D shape from one plane to another like this:
image
I would like to repeat the operation several times like this:
I have the following error:
At least, If I suppress the for loop and keep the same variable decomposition, it works:
I think I am close to the result, but I cannot find where I mistake myself. The problem occurs when I come in the loop the second time. I think I have accumulated already two wires in wp2. I should keep only the last one before adding a new one, but I don't know how to do it.