Constraining Concave and Convex Geometries

28 views
Skip to first unread message

Patrick Dees

unread,
May 31, 2024, 10:06:00 AMMay 31
to CadQuery
Hello all;

I am attempting to constrain two simple geometries together, one which has a concave shape and the other convex. Specifically, these are two tanks, with cylindrical portions and elliptical domes. One, the forward tank, has its aft dome reversed (concave). Second, the aft tank, has no reversed domes (convex). In rocketry this is called a "common bulkhead" design. I am able to get close to properly aligning the objects, but am having difficulty properly tagging and constraining the two. Any advice would be appreciated!

python Version: 3.12.2
CadQuery Version: 2.4.0

Code:
---------------------------------------------------------------
import cadquery as cq

# dimensions of the tank
thickness = 0.1
dt = 10 - 2*thickness    # diameter of tank less thickness of the shell
rt = dt/2                # radius of tank
ht = 20                  # total height of tank cylindrical section
hht = ht / 2             # half the tank height
hd = 3 - thickness       # height of dome

# colors
green = cq.Color("Green")
red = cq.Color("Red")

def make_tank(reverse_aft_dome: bool = False) -> cq.Workplane:
    # create the starting plane from which to work
    wp = cq.Workplane("XZ")

    # trace one half of the perimeter then rotate
    # start at lower-left corner above aft dome
    tank = wp.move(xDist=rt, yDist=-hht)

    # create the vertical wall of the cylinder
    tank = tank.line(xDist=0, yDist=ht)

    # create the forward dome. this ends at the center
    # line of the tank
    tank = tank.ellipseArc(
        x_radius=rt,
        y_radius=hd,
        angle1=0.,
        angle2=90.,
        sense=1, #  clockwise (-1) or counter clockwise (1)
    )

    # create a vertical line at center of the tank
    tank = tank.line(xDist=0, yDist=-(ht+2*hd))

    # create the aft dome, starting from the center line
    if reverse_aft_dome:
        tank = tank.ellipseArc(
            x_radius=rt,
            y_radius=hd,
            angle1=0,
            angle2=90.,
            sense=-1 #  clockwise (-1) or counter clockwise (1)
        )
    else:
        tank = tank.ellipseArc(
            x_radius=rt,
            y_radius=hd,
            angle1=-90,
            angle2=0.,
            sense=1, #  clockwise (-1) or counter clockwise (1)
        )

    # mark the 2D shape as complete
    tank = tank.close()

    # revolve the shape 360 degrees to create the 3D geometry
    tank = tank.revolve(360)

    # finally, apply a thin shell
    tank = tank.shell(thickness=thickness)

    # tag EVERYTHING
    tank.edges(">Z").tag("topedge")
    tank.faces(">Z").tag("topface")
    tank.vertices(">Z").tag("topvert")

    tank.edges("<Z").tag("bottomedge")
    tank.faces("<Z").tag("bottomface")
    tank.vertices("<Z").tag("bottomvert")

    return tank

# create the forward tank with a reversed aft dome
fwd_tank = make_tank(reverse_aft_dome=True)
# create the aft tank with no reversed domes
aft_tank = make_tank()

# create the assembly to house both tanks
assy = cq.Assembly()
# create a center line to align along Z axis
center_line = cq.Workplane("XZ").vLine(0.1, forConstruction=True)
assy.add(center_line, name="CenterLine")
assy.constrain("CenterLine", "Fixed")

# add the forward tank
assy.add(fwd_tank, name='Forward_Tank', color=red)

# add the aft tank
assy.add(aft_tank, name='Aft_Tank', color=green)

# constrain the forward tank to be fixed
assy.constrain('Forward_Tank', "Fixed")

# constrain the aft tank to the center line
assy.constrain('Aft_Tank?topvert', 'CenterLine', 'PointOnLine')
assy.constrain('Aft_Tank?bottomvert', 'CenterLine', 'PointOnLine')

# constrain the two tanks to overlap at the
# forward_tank:aft_dome - aft_tank:forward_dome
# interface
assy.constrain('Forward_Tank?bottomvert', 'Aft_Tank?topface', 'PointInPlane')
assy.solve()

# visualize
display(assy)


The tagging of the tanks within make_tank and the final constraint are my issues. 

If you have any advice on how to 
1) Tag the vertex at the center of a concave dome
2) Properly constrain the items

I would be most appreciative!

Thanks,
Patrick

Adam Urbanczyk

unread,
May 31, 2024, 3:57:14 PMMay 31
to CadQuery
You tagged the wrong vertices. I also simplified your constraints. You might want to take a look this section https://cadquery.readthedocs.io/en/latest/assy.html#constraints

    if reverse_aft_dome:
        tank.faces("<<Z[-2]").tag("bottomface")
        tank.vertices(">Z", tag="bottomface").tag("bottomvert")
    else:

        tank.faces("<Z").tag("bottomface")
        tank.vertices("<Z", tag="bottomface").tag("bottomvert")


    return tank

# create the forward tank with a reversed aft dome
fwd_tank = make_tank(reverse_aft_dome=True)
# create the aft tank with no reversed domes
aft_tank = make_tank()

assy = cq.Assembly()


assy.add(fwd_tank, name='Forward_Tank', color=red)
assy.add(aft_tank, name='Aft_Tank', color=green)

assy.constrain('Aft_Tank','FixedRotation',(0,0,0))
assy.constrain('Forward_Tank?bottomvert', 'Aft_Tank?topvert', 'Point')

assy.solve()

# visualize
show_object(assy)

Patrick Dees

unread,
Jun 3, 2024, 9:43:06 AMJun 3
to CadQuery
Thanks for that, works perfectly!

I am confused by the lines such as
" tank.vertices("<Z", tag="bottomface").tag("bottomvert")"

Do these tag the vertices as both "bottomface" and "bottomvert"?

Adam Urbanczyk

unread,
Jun 3, 2024, 1:57:37 PMJun 3
to CadQuery
That selects "<Z" vertices from the "bottomface" tag and tags them as "bottomvert". See also: https://cadquery.readthedocs.io/en/latest/classreference.html#cadquery.Workplane.vertices

Patrick Dees

unread,
Jun 6, 2024, 12:59:48 PMJun 6
to CadQuery
Thank you very much for the clarification!
Reply all
Reply to author
Forward
0 new messages