cadquery icon indicating copy to clipboard operation
cadquery copied to clipboard

Center assemblies

Open chaffra opened this issue 1 year ago • 6 comments

The code below allows me to stack 2 assemblies but I don't know how to center them, so that they have the same center in the XY plane.

rows = 5
cols = 5
pitch = 8

dx = cols*pitch
dy = rows*pitch
dz = 3*pitch
roic = cq.Workplane('XY').box(dx,dy,dz, centered=True)

r = pitch/2/2
h = (2*r)*2
bumps = cq.Workplane('XY').rarray(pitch,pitch,cols,rows, center=True).cylinder(h,r)

assy = cq.Assembly()
assy.add(roic, name='roic', color=cq.Color('pink'))
assy.add(bumps, name='bumps', color=cq.Color('gray'))
assy.constrain("roic@faces@>Z", "bumps@faces@<Z", "Plane")
assy.solve()
display(assy)

chaffra avatar Apr 09 '24 22:04 chaffra

The "Plane" constraint is stronger than "Axis" plus "PointInPlane", and it can make the first part's center meet the second part's center as close as possible. In your case, there are 25 faces for bumps.faces("<Z"), and CQ's assembly takes the first one (-16.0, -16.0)[the one enclosed by the green circle] as the object of "bumps@faces@<Z". So the constraint assy.constrain("roic@faces@>Z", "bumps@faces@<Z", "Plane") makes the bottom face center of enclosed cylinder by the green circle and the top face center of the box coincidence. demo

Using the following constraints can do the job. assy.constrain("roic@faces@>Z", "bumps@faces@<Z", "Axis") assy.constrain("roic@faces@>Z", "bumps@faces@<Z", "PointInPlane") assy.constrain("roic@faces@<Y", "bumps@faces@>Y", "Axis") assy.constrain("roic@faces@>Z", "bumps", "Point", param=(h/2))

Or the following constraints can also do the job. assy.constrain("roic@faces@>Z", "bumps@faces@<Z", "Axis") assy.constrain("roic@faces@>Z", "bumps@faces@<Z", "PointInPlane") assy.constrain("roic", "FixedRotation", (0, 0, 0)) assy.constrain("bumps", "FixedRotation", (0, 0, 0)) assy.constrain("roic@faces@>Z", "bumps", "Point", param=(h/2))

huskier avatar Apr 10 '24 14:04 huskier

Change this: https://github.com/CadQuery/cadquery/blob/3451007f8eeb9d78e784ec8047ef69a5359ecb5e/cadquery/assembly.py#L271

to something like?:

        if len(res.vals()) > 1:
            if shapes:= _selectShapes(res.objects):
                center = Shape.CombinedCenter(shapes)
                res = getattr(res, query.selector_kind)(NearestToPointSelector(center.toTuple()))

        val = res.val()

Then the original example posted here works as expected.

Otherwise can select and tag single object:

bumps.faces("<Z").faces(cq.selectors.NearestToPointSelector((0, 0, 0))).tag("centerface")
#...
assy.constrain("roic", "Fixed")
assy.constrain("roic@faces@>Z", "bumps?centerface", "Plane")

lorenzncode avatar Apr 12 '24 02:04 lorenzncode

Thanks! Both solutions work. Maybe a deeper issue I was after is that you have to use assemblies to get colors. A simpler implementation would be like below but it's missing colors. It would be nice if the primitives could have colors when displaying. Should I file a feature request for that? Something like box(..., color=cq.Color('pink')) would be useful.

rows = 8
cols = 8
pitch = 8

dx = cols*pitch
dy = rows*pitch
dz = 3*pitch

#roic
assy = cq.Workplane('XY').center(0,0).box(dx,dy,dz, centered=True)

#bumps
r = pitch/2/2
h = (2*r)*2
assy = assy.faces('>Z').workplane().rarray(pitch,pitch,cols,rows).cylinder(h,r)
display(assy)

chaffra avatar Apr 12 '24 13:04 chaffra

Plus I think the aspect ratios are different between using assemblies and using the stack directly. The bumps look taller when using assemblies.

image image

chaffra avatar Apr 12 '24 13:04 chaffra

No need to use constraints, or modify cq:

rows = 8
cols = 8
pitch = 8

dx = cols*pitch
dy = rows*pitch
dz = 3*pitch

#roic
base = cq.Workplane('XY').center(0,0).box(dx,dy,dz, centered=True)

#bumps
r = pitch/2/2
h = (2*r)*2
top = base.faces('>Z').workplane().rarray(pitch,pitch,cols,rows).circle(r).extrude(h/2,combine=False)

assy = cq.Assembly().add(base, color=cq.Color('pink')).add(top, color=cq.Color('gray'))
show_object(assy)

adam-urbanczyk avatar Apr 12 '24 16:04 adam-urbanczyk

Plus I think the aspect ratios are different between using assemblies and using the stack directly. The bumps look taller when using assemblies.

@chaffra The difference is expected. When using assembly, there are two individual objects, and the bumps are on the top of the face of the roic box. When using the stack directly, I remember there is an implicit concept that the object is symmetrical with respect to the workplane except for some operations, such as extrude.

If you want to get the same results, the code should be written as following (NB: offset=h/2). assy.faces('>Z').workplane(offset=h/2).rarray(pitch,pitch,cols,rows).cylinder(h,r)

huskier avatar Apr 15 '24 13:04 huskier