cadquery
cadquery copied to clipboard
2D Sweep Along Line
Hello,
Is there a way to perform a 2D sweep along a path in CQ ? The resulting geometry should be a shell with zero thickness. Attached is a sample geometry created in FreeCAD and that's what I'm trying to do in CQ. The code below works when the profile geometry is a rectangle or circle but it doesn't work for line (ValueError: No pending wires present).
Thanks,
`import cadquery as cq
plane_path = "XY" pts_path = [(0,0), (100, 100), (100, 200), (200, 400)] path = cq.Workplane(plane_path, origin=pts_path[0]).polyline(pts_path) show_object(path)
plane_profile = "XZ" pts_profile = [(-5,0), (5, 0)] profile = cq.Workplane(plane_profile).polyline(pts_profile)
show_object(profile)
SweepShell = profile.sweep(path, makeSolid=False, isFrenet=True) show_object(SweepShell)`
The resulting geometry you would get is not a shell but a face (or a set of faces) and as far as I know you cannot do that in CQ.
Thanks for the answer Jojain, sorry for the naming, I'm from CAE world, so that a shell for us :)
@utkuunlu Have a look at the makeSolid
argument of sweep. https://cadquery.readthedocs.io/en/latest/classreference.html?highlight=sweep#cadquery.Solid.sweep
@utkuunlu Have a look at the
makeSolid
argument of sweep. https://cadquery.readthedocs.io/en/latest/classreference.html?highlight=sweep#cadquery.Solid.sweep
Yes, I tried both makeSolid=False and True. Result is the same (error).
Is your profile closed before the sweep? I only had time to take a glance, but with the polyline and two points you might be ending up with a 1D profile. You can set includeCurrent=True
on polyline
and try calling close
afterwards. You could also try replacing the polyline
call with rect
temporarily as a baseline test to force the profile to be closed.
@jmwright The problem here is that @utkuunlu wants to sweep a 1d profile which is not possible with the sweep method of CQ. I cannot test here but trying to create a rectangle with 0 height will surely result in an error.
To achieve this another algorithm than than the one used in the sweep
method of CQ must be used.
A starting point could be to look there : BRepPrimAPI_MakeSweep Class Reference - Open CASCADE Technology Documentation - https://dev.opencascade.org/doc/refman/html/class_b_rep_prim_a_p_i___make_sweep.html
Ok, thanks @Jojain . I was in a hurry to answer and didn't properly understand the intent.
I think OCCT allows this, but it is not exposed [in CQ]. @Jojain https://dev.opencascade.org/doc/refman/html/class_b_rep_offset_a_p_i___make_pipe_shell.html suggests that the profile wire does not need to be closed.
Thanks for the answers @adam-urbanczyk , @jmwright , @Jojain. The profile is not closed, the points on the path are generated automatically by another python subroutine.
I just come up with another idea, I'll try to generate the sweep with a thin rectangular profile and will delete unnecessary faces. I'll let you know if that works.
If that idea doesn't work, I guess I have to continue with FreeCAD scripting since I'm not familiar with C++ and OCCT. Thanks anyway.
This solution will work but you'll have to take in account that your faces will have an offset compare to the neutral fiber of your solid.
As you may not be aware all the c++ functions are available through python via importing OCP.
So it might be a solution for you (you still need to refer to c++ doc however)
I was solving this some time ago, because I needed to sweep a lot of complex sufraces with varying cross-section.
In principle, you can create an individual profile for each cross-section, as long as the number of points in the profile polyline stays the same. In gen_list you specify coordinates and plane rotation angle. also you can extend 3D coordinates and 3D rotation if you want. The only problem is that you need to adjust stretching factor of the profile every time you bend it. In this case I used cos(radians(halfangle) multiplier, which should be actually only applied to one axis, not all three as I did, but I am too lazy to fix it.
With minor adjustments you can do the same with closed polylines, then you will make solids with varying cross-sections.
You can also use splines or combination of polylines and splines, but this will be quite computationally intensive.
Hope this helps.
import cadquery as cq
import numpy as np
from math import sin, cos,radians,degrees
def sweep_flat(body_list):
#this one concentrates edges to wires and then creates a ruled surface
united=cq.Workplane("XZ")
for j in range(0,int(len(body_list))):
wires1=cq.Workplane('XZ').tag('body')
wires2=cq.Workplane('XZ').tag('body')
for i in range(0,int(len(body_list[j]))-1):
wires1 = wires1.workplaneFromTagged('body').transformed(offset=cq.Vector((body_list[j][i][0],0,body_list[j][i][1])),rotate=cq.Vector(0,(body_list[j][i][2]),0)).polyline(body_list[j][i][3])
wires2 = wires2.workplaneFromTagged('body').transformed(offset=cq.Vector((body_list[j][i+1][0],0,body_list[j][i+1][1])),rotate=cq.Vector(0,(body_list[j][i+1][2]),0)).polyline(body_list[j][i+1][3])
WIRES1=cq.Wire.assembleEdges(wires1.vals())
WIRES2=cq.Wire.assembleEdges(wires2.vals())
swept=cq.Face.makeRuledSurface(WIRES1,WIRES2)
united=united.add(swept)
united=united.combine()
return united
profile=np.array([[-1,0],[1,0],[1,1]])
gen_list=[]
gen_list.append([[0,0,90,profile],\
[5,0,45,profile/cos(radians(45))],\
[10,10,0,profile]])
result=sweep_flat(gen_list)