Locating Parts in Assembly

436 views
Skip to first unread message

Anthony Sokolowski

unread,
Jun 16, 2021, 7:59:57 AM6/16/21
to CadQuery

I am trying to add parts into an assembly and locate them manually rather than using constraints.
I would like to make a tray with separate plates that are welded together. See image.
tray.png
Positioning the red plates is easy using a Location object with translations and 90 degree rotations about the X axis.
The green plates require a translation and two 90 degree rotations about the X and Y axis. How can this be done using a Location object in Cadquery?

Roger Maitland

unread,
Jun 16, 2021, 11:22:51 AM6/16/21
to Anthony Sokolowski, CadQuery
Hi Anthony,

I've used some of the methods from numpy and scipy for this.  Here is an example of combined rotations for a human model assembly:
import numpy as np
from scipy.spatial.transform import Rotation as R
def rot2Loc(rotationVector: cq.Vector):
rx = R.from_euler('x', rotationVector.x, degrees=True)
ry = R.from_euler('y', rotationVector.y, degrees=True)
rz = R.from_euler('z', rotationVector.z, degrees=True)
r = (rz*ry*rx).as_rotvec() # Combine the three and translate to a numpy.ndarray
m = degrees(np.linalg.norm(r)) # The magnitude of the rotation is the norm of the result
if m==0:
r[0]=1
return (Vector(r[0],r[1],r[2]),m)
...
neckHeadAngle = Vector(0,-20,0)
backNeckAngle = Vector(0,+32,0)
...
human = cq.Assembly(None,name="human")
human.add(head,loc=Location(neckPos,*rot2Loc(neckHeadAngle+backNeckAngle)),name="head")
Note the * in front of the rot2Loc method call, this flattens the tuple that is returned so the Location class sees a location, rotation axis and rotation magnitude.

Having rotate() and translate() methods in the Assembly class would help with this as rotate() could be used multiple times. The above should at least allow you to proceed.

Cheers,
Roger

--
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/395e2c46-ca51-44df-adbe-5a3d2aeae7fan%40googlegroups.com.

Adam Urbanczyk

unread,
Jun 17, 2021, 2:27:01 AM6/17/21
to CadQuery
You can compose Location objects by multiplication:

L =  Ltrans*Lrot1 * Lrto2

Anthony Sokolowski

unread,
Jun 17, 2021, 4:42:25 AM6/17/21
to CadQuery
Both solutions work well. Thank you.

Roger Maitland

unread,
Jun 21, 2021, 1:16:22 PM6/21/21
to CadQuery
Would the following Assembly methods be helpful (based on Adam's response)?
    def translate(self, vec: VectorLike):
        """
        Moves the current assembly (without making a copy) by the specified translation vector
        :param vec: The translation vector
        """
        self.loc = self.loc*Location(Vector(vec))
        return self

    def rotate(self, axis: VectorLike, angle: float):
        """
        Rotates the current assembly (without making a copy) around the axis of rotation by the specified angle

        :param axis: The axis of rotation (starting at the origin)
        :type axis: a 3-tuple of floats
        :param angle: the rotation angle, in degrees
        :type angle: float
        """
        self.loc = self.loc*Location(Vector(0,0,0),Vector(axis),angle)
        return self

The location of parts in an assembly are relative to the parent if I understand assemblies correctly so one has to keep this in mind when applying transformations. These methods do allow stacking as follows:
a = Assembly(None,name="test")
a = a.add(Solid.makeCylinder(radius=2,height=20,pnt=Vector(0,0,0),dir=Vector(0,0,1)))
a.translate((1,1,1))
a.rotate((1,0,0),60).rotate((0,1,0),30)

Cheers,
Roger

Adam Urbanczyk

unread,
Jun 22, 2021, 2:45:36 AM6/22/21
to CadQuery
Thanks, I'm curious regarding what does it add to the original API from your point of view? Not having to write Vector in the Location constructor?

Roger Maitland

unread,
Jun 22, 2021, 4:38:35 PM6/22/21
to CadQuery
As far as I know, most (if not all) objects in cadquery have rotate and translate methods except for the Assembly class. This is confusing for new users as it appears that one can rotate a Solid but not an Assembly. I may have missed it but I don't recall ever seeing the composition of Location via multiplication in the documentation thus making this usage of multiplication available to only those who know or have exhaustively searched these conversations.

I understand that the Assembly class supports the location of assemblies via tagging and use of the solver but clearly there are users who would like to directly place assemblies and sub-assemblies. Both solutions to locating assemblies are valuable.

Adam Urbanczyk

unread,
Jun 22, 2021, 5:44:54 PM6/22/21
to CadQuery
You can specify the location when adding objects - there is an example in the docs here: https://cadquery.readthedocs.io/en/latest/primer.html#assemblies. Indeed multiplication is not mentioned - we need to add an example showing it.
Reply all
Reply to author
Forward
0 new messages