Sweep and twist

22 views
Skip to first unread message

Dov Grobgeld

unread,
Jun 18, 2024, 4:39:13 PMJun 18
to CadQuery
Hello,

I'd like to sweep a profile over a wire, while parameterizing the x-dir along the wire.

As an example, sweeping a thin rectangle over a circular path yields a torus with a rectangular cross section.

But I'd like to twist the rectangle's x-direction during the sweep.

Currently it seems like you have to choose between either sweep() in which you have no control (except by setting the isFrenet option) of the changing of the xdir.

Or twistExtrude() in which case the sweep is linear, i.e. an extrusion.

I'd like to combine them. Is this even supported by OpenCascade?

I suppose that I can linearize the sweep path and do tiny lofts between subsequent rotated profiles, but this seems very inefficient.

Any ideas?

Regards,


Adam Urbanczyk

unread,
Jun 19, 2024, 2:05:25 AMJun 19
to CadQuery
cq.Workplane.sweep has auxSpine argument that allows you to achieve what want.

Dov Grobgeld

unread,
Jun 19, 2024, 2:59:14 AMJun 19
to Adam Urbanczyk, CadQuery
Thanks Adam.

How exactly is the auxSpine wire turned into the binormal direction? My guess was that the path and the auxSpine are parameterized by t between 0 and 1 and the binormal is the vector between auxSpine(t)-path(t). But the following example shows that this is not the case. In the example my path is a circle, and my auxSpine is a larger circle in the same plane. I assumed this would mean that the binormal would be in the radial direction over the circle, and the sweep would be unaffected and essentially a torus with a rectangular cross section. However this is what I got:


fs.png
Here is my example:

#!/usr/bin/env python

import cadquery as cq
from cadquery import exporters

def sweep_wire(wire,
               profile,
               binormal=None,
               up = cq.Vector(0,0,1),
               isFrenet=True):
  '''Sweep the (plane) profile along the open or closed wire'''
  first_edge = next(iter(wire))
  plane_normal = first_edge.tangentAt(0)
  plane_point = first_edge.positionAt(0)

  x_dir = plane_normal.cross(up)
  plane = cq.Plane(origin=plane_point,
                   xDir = x_dir,
                   normal = plane_normal)

  auxSpine = cq.Workplane(plane).eachpoint(binormal) if binormal is not None else None
  return (cq.Workplane(plane)
          .eachpoint(profile) 
          .sweep(wire, isFrenet=isFrenet, auxSpine=auxSpine)
  )

aux = cq.Wire.makeCircle(11,(0,0,0),(0,0,1))
path = cq.Wire.makeCircle(10,(0,0,0),(0,0,1))
w,h = (1,2)
profile = cq.Wire.makePolygon([(0,0),
                               (w,0),
                               (w,h),
                               (0,h)]).close()

res = sweep_wire(path,profile,binormal=aux)

exporters.export(res, 'sweep-aux-spine.stl')   
Once I understand how this works, I'll create a PR with an example.

Thanks!

--
cadquery home: https://github.com/CadQuery/cadquery
post issues at https://github.com/CadQuery/cadquery/issues
run it at home at : https://github.com/CadQuery/CQ-editor
---
You received this message because you are subscribed to the Google Groups "CadQuery" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cadquery+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cadquery/a6e13a2c-5b03-41aa-8b45-b4c984ea75b7n%40googlegroups.com.

Adam Urbanczyk

unread,
Jun 19, 2024, 4:42:34 PMJun 19
to CadQuery
You did something weird (not sure what yet) with eachpoint. Try using add instead:

import cadquery as cq
from cadquery import exporters

def sweep_wire(wire,
               profile,
               binormal=None,
               up = cq.Vector(0,0,1),
               isFrenet=False):

  '''Sweep the (plane) profile along the open or closed wire'''
  first_edge = next(iter(wire))
  plane_normal = first_edge.tangentAt(0)
  plane_point = first_edge.positionAt(0)

  x_dir = plane_normal.cross(up)
  plane = cq.Plane(origin=plane_point,
                   xDir = x_dir,
                   normal = plane_normal)

  auxSpine = cq.Workplane(plane).add(binormal)
  return (cq.Workplane(plane)
          .eachpoint(profile)
          .sweep(wire, auxSpine=auxSpine)
  )

aux = cq.Wire.makeCircle(12,(0,0,0),(0,0,1))
path = cq.Wire.makeCircle(11,(0,0,0),(0,0,1))

w,h = (1,2)
profile = cq.Wire.makePolygon([(0,0),
                               (w,0),
                               (w,h),
                               (0,h)]).close()

res = sweep_wire(path,profile,binormal=aux)

Dov Grobgeld

unread,
Jun 20, 2024, 1:56:39 AMJun 20
to Adam Urbanczyk, CadQuery
Thanks Adam. Interesting find! Indeed using add() gets rid of the strange warping. However, it still doesn't seem to work as intended.

I tried a couple of different auxSpines to try to rotate the cross section, but the result was a no-op, as if I hadn't given the auxSpine parameter:

Tried turning the cross section 90 degrees by making the aux spine offset in the +Z direction:

aux = cq.Wire.makeCircle(10,(0,0,1),(0,0,1))

Tried turning the cross section 45 degrees by offsetting the spine in the radial and the +Z direction:

aux = cq.Wire.makeCircle(11,(0,0,1),(0,0,1))

So using eachpoint() does something weird (currently unexplainable), while add() causes auxSpine not to affect the sweep at all.

Any ideas?


Regards,
Dov


Adam Urbanczyk

unread,
Jun 20, 2024, 5:38:39 AMJun 20
to CadQuery

You might have misunderstood how aux spine works. To get a twisted square torus you'll need an aux spine that coils around the main spine.
Reply all
Reply to author
Forward
0 new messages