Weird behaviour of CadQuery when subtracting cylinders to sphere

168 views Asked by At

I want to subtract 4 cylinders from a hemisphere. The four cylinders are aligned to (1,0,0), (-1,0,0), (0,1,0), (0,-1,0) and do intersect.

When intersecting one part won't be subtracted! Problematic behaviour (cones intersect)

Whit non-intersecting cones i get the following as expected! enter image description here

In case I use cylinders instead of cones everything works fine.
Here is my code:


import math
import cadquery as cq
from ocp_vscode import show_object, reset_show, set_defaults

def align(obj, dir):
    l = math.sqrt(dir[0]**2+dir[1]**2+dir[2]**2); ## radial distance
    b = math.degrees(math.acos(dir[2]/l));        ## inclination angle
    c = math.degrees(math.atan2(dir[1],dir[0]));  ## azimuthal angle
    return obj.rotate((0,0,0),(1,0,0),0).rotate((0,0,0),(0,1,0),b).rotate((0,0,0),(0,0,1),c)

def cone(height, angle):
    radius = height*math.tan(math.radians(angle))
    cone = cq.Solid.makeCone(0, radius, height)
    return cone

def cylinder(height, angle):
    radius = height*math.tan(math.radians(angle))
    cylinder = cq.Solid.makeCylinder(radius, height)
    return cylinder

# BUILD
# ----------------------------------------------------------------
reset_show()
angle = 30

def piece(listCone):
    ## construct general parts
    shellOuter  = cq.Solid.makeSphere(10).cut(cq.Solid.makeSphere(8))
    pieceOuter = shellOuter
    ## generate the piece
    for element in listCone:
        ## outer shell
        obj = cone(10.01,angle)
        obj = align(obj, element)
        pieceOuter = pieceOuter.cut(obj)
    return pieceOuter

center = piece([
    (0,1,0),
    (0,-1,0),
    (1,0,0),
    (-1,0,0)
    ])
show_object(center, options=dict(alpha=0.5,color='red'))

Maybe you can help me out :)

1

There are 1 answers

0
Pa Dalton On

The solution I came up with has the following fixes:

  • the align function performs only 1 rotation instead of 2
  • the cones need to have all the tips intersecting, this can be achieved by making the top radius greater than zero.

Many thanks to Jeremy Wright, who helped me in the CadQuery Discussion Group.

import math
import cadquery as cq
from ocp_vscode import show_object, reset_show, set_defaults

# First modification
def align(obj, dir):
    if dir[0] == 0 and dir[1] == 0:
        return obj
    l = math.sqrt(dir[0]**2+dir[1]**2+dir[2]**2); ## radial distance
    a = math.degrees(math.acos(dir[2]/l))         ## rotation angle
    dir = (-dir[1], dir[0], 0)                    ## (0,0,1)x(a,b,c) = (-b,a,c)
    return obj.rotate((0,0,0),dir, a)

def cone(height, angle):
    radius = height*math.tan(math.radians(angle))
    # Second modification
    cone = cq.Solid.makeCone(0.1, radius, height)
    return cone

# BUILD
# ----------------------------------------------------------------
reset_show()
angle = 60

def piece(listCone):
    ## construct general parts
    shellOuter  = cq.Solid.makeSphere(10).cut(cq.Solid.makeSphere(8))
    pieceOuter = shellOuter
    ## generate the piece
    for element in listCone:
        ## outer shell
        obj = cone(10.01,angle)
        obj = align(obj, element)
        pieceOuter = pieceOuter.cut(obj)
    return pieceOuter

center = piece([
    (0,1,0),
    (0,-1,0),
    (1,0,0),
    (-1,0,0)
    ])
show_object(center, options=dict(alpha=0.5,color='red'))