CadQuery / cadquery

A python parametric CAD scripting framework based on OCCT
https://cadquery.readthedocs.io
Other
3.18k stars 289 forks source link

Cut operation doesn't work #529

Open RubenRubens opened 3 years ago

RubenRubens commented 3 years ago

Tested with the latest CQ version provided on conda

I'm working on a nut and the last cut operation fails, this is, there is no thread. The thing is that when using union instead of cut the operation is successfully performed. I cannot tell if it's my fault or a bug.

The code

import cadquery as cq
from math import sin, cos, tan, pi

# Parameters
d = 10
p = 1.50
da = 10.40
dw = 14.60
e = 17.77
m = 8.10
s = 16
angle = 30 * pi / 180

# Constant
H = 0.866 * p

# Gemetry
def cutting_hexagon():
    points = [
        (s/2, 0),
        (e, 0),
        (e, e * sin(angle))
    ]

    a = (
        cq.Workplane('YZ')
        .polyline(points).close()
        .revolve()
    )

    b = a.mirror('XY', (0, 0, m/2))

    return a.union(b)

def internal_iso_thread():
    # Helix
    helix = cq.Workplane('XY').parametricCurve(
    lambda t : (
            d/2 * cos(t * 2 * pi),
            d/2 * sin(t * 2 * pi),
            p * t
        ),
        start = 0,
        stop = m/p
    )

    # Face
    A = H/8 / tan(pi/3)
    B = A * tan(pi/6)
    C = A / cos(pi/6)
    face = (
        cq.Workplane('XZ')
        .center(d/2, 0)
        .moveTo(0, A)
        .threePointArc((C-B, 0), (0, -A))
        .lineTo(-7/8 * H, -H/2)
        .lineTo(-7/8 * H, H/2)
        .lineTo(0, A)
        .close()
    )

    return face.sweep(helix, isFrenet=True)

def core():
    def circumscribed(nSides, inscribedDiameter):
        angle = 1/(nSides * 2) * 2 * pi
        return inscribedDiameter / cos(angle)

    return (
        cq.Workplane('XY')
        .polygon(6, circumscribed(6, s))
        .circle(d / 2 - 3/8 * H)
        .extrude(m)
    )

result = (
    core()
    .cut(cutting_hexagon())
    .cut(internal_iso_thread())
)

result.val().exportStep('bug.step')

The result

result

The issue

cq_nut

jmwright commented 3 years ago

We have run into kernel bugs fairly often with threads. For example: #407

I can confirm that the thread isn't cut in CQ-editor, so it's not an export issue. You could try a couple of things to see if they help, and then we can try to figure out how to work around whatever is going on.

  1. Increase the diameter of the thread coil so that more (or all) of the thread solid intersects with the nut core.
  2. Shorten the height of the coil so that it does not extend above (or below) the nut core.
dcowden commented 3 years ago

For what it's worth, boundary conditions with cutting and more generally with coincident faces are common with all BREP kernels, even professional ones like Parasolid. It feels dirty, but the old 'make one part slightly bigger by some trivial amount' trick works wonders.

On Thu, Dec 3, 2020 at 9:05 AM Jeremy Wright notifications@github.com wrote:

We have run into kernel bugs fairly often with threads. For example: #407 https://github.com/CadQuery/cadquery/issues/407

I can confirm that the thread isn't cut in CQ-editor, so it's not an export issue. You could try a couple of things to see if they help, and then we can try to figure out how to work around whatever is going on.

  1. Increase the diameter of the thread coil so that more (or all) of the thread solid intersects with the nut core.
  2. Shorten the height of the coil so that it does not extend above (or below) the nut core.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/CadQuery/cadquery/issues/529#issuecomment-738014719, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAJ44AYNLUSGQYSJYKVYBVDSS6LK3ANCNFSM4ULC576A .

adam-urbanczyk commented 3 years ago

Here is how you can make it work: image

import cadquery as cq
from math import sin, cos, tan, pi

# Parameters
d = 10
p = 1.50
da = 10.40
dw = 14.60
e = 17.77
m = 8.10
s = 16
angle = 30 * pi / 180

# Constant
H = 0.866 * p

# Gemetry
def cutting_hexagon():
    points = [
        (s/2, 0),
        (e, 0),
        (e, e * sin(angle))
    ]

    a = (
        cq.Workplane('YZ')
        .polyline(points).close()
        .revolve()
    )

    b = a.mirror('XY', (0, 0, m/2))

    return a.union(b)

def internal_iso_thread():
    # Helix
    helix = cq.Workplane('XY',origin=(0,0,-1)).parametricCurve(
    lambda t : (
            d/2 * cos(t * 2 * pi),
            d/2 * sin(t * 2 * pi),
            p * t
        ),
        start = 0,
        stop = 2*m/p
    )

    # Face
    A = H/8 / tan(pi/3)
    B = A * tan(pi/6)
    C = A / cos(pi/6)
    face = (
        cq.Workplane('XZ')
        .center(d/2, 0)
        .moveTo(0, A)
        .threePointArc((C-B, 0), (0, -A))
        .lineTo(-7/8 * H, -H/2)
        .lineTo(-7/8 * H, H/2)
        .lineTo(0, A)
        .close()
    )

    return face.sweep(helix, isFrenet=True)

def core():
    def circumscribed(nSides, inscribedDiameter):
        angle = 1/(nSides * 2) * 2 * pi
        return inscribedDiameter / cos(angle)

    return (
        cq.Workplane('XY')
        .polygon(6, circumscribed(6, s))
        .circle(d / 2 - 3/8 * H)
        .extrude(m)
    )

thread = (
    internal_iso_thread()
    .transformed((-90,0,0))
    .split(True)
    .transformed((0,0,0),(0,0,m))
    .split(False, True)
    )

result = (
    core()
    .cut(cutting_hexagon())
    .cut(thread,clean=False)
)
dcowden commented 3 years ago

wow @adam-urbanczyk nice!

@RubenRubens would you consider the idea of promoting this code to a core operation available as a convenience operation, similar to counterbores?

It wouldn't take much at all to convert the code above to automatically apply this code to a selected cylindrical face to create an internal or external thread, which would be immensely helpful when you need threads!

RubenRubens commented 3 years ago

Cool! @dcowden you can do whatever makes you happy with the code above. I might consider to do a PR myself...

jpoles1 commented 2 years ago

Getting some very strange results using this with the latest version to try and make internal threads. Had similar results with twisted threads when using another example I found (when using specific sets of params for height and pitch in particular). Not sure what might be causing this:

image

lorenzncode commented 2 years ago

It looks like there were changes to parametricCurve since these examples were created, see issue #682.

lorenzncode commented 2 years ago

Had similar results with twisted threads when using another example I found (when using specific sets of params for height and pitch in particular).

@jpoles1 In my testing, specifying parametricCurve(..., smoothing=None) resolves the problem.