Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get the absolute location of a tag? #1635

Open
lenianiva opened this issue Jul 21, 2024 · 7 comments
Open

How to get the absolute location of a tag? #1635

lenianiva opened this issue Jul 21, 2024 · 7 comments
Labels
question Further information is requested

Comments

@lenianiva
Copy link
Contributor

Consider this example:

import cadquery as cq

def makeBoxWithTag():
    result = (
        cq.Workplane('XY')
        .box(1, 1, 1, centered=False)
    )
    result.vertices(">X and >Y and >Z").tag("v")
    return result
assembly = (
    cq.Assembly()
    .add(cq.Solid.makeBox(1, 1, 1), name="b1")
    .constrain("b1", "Fixed")
    .add(makeBoxWithTag(), name="b2", loc=cq.Location((0,0,1)))
    .constrain("b2", "Fixed")
    .add(cq.Solid.makeBox(1, 1, 1), name="b3", loc=cq.Location((0,0,2)))
    .constrain("b3", "Fixed")
    .add(cq.Solid.makeSphere(0.2, angleDegrees1=-90), name="m")
    .constrain("m", "b2@faces@>Y", "Point")
    .solve()
)

def print_loc(self: cq.Assembly, tag: str) -> cq.Location:
    name, shape = self._query(tag)
    loc_shape = shape.location()
    loc_centre = cq.Location(shape.Center())
    loc_parent, top = self._subloc(name)
    print(f"[{tag}] {name}: {shape}")
    print(f"    Shape: {loc_shape.toTuple()} ({type(loc_shape)})")
    print(f"    Centre: {loc_centre.toTuple()} ({type(loc_centre)})")
    print(f"    Parent: {loc_parent.toTuple()} ({type(loc_parent)})")
    _, top_shape = self._query(top)
    loc_top_shape = top_shape.location()
    print(f"    Top: {loc_top_shape.toTuple()}")
    print(f"    Top.loc: {top_shape.location().toTuple()}")
    loc_self = self.loc
    print(f"    Self: {loc_self.toTuple()}")
    loc = loc_parent * loc_centre
    print(f"    Total: {loc.toTuple()}")
print_loc(assembly, "b2@faces@>Y")
print_loc(assembly, "b2?v")

result = assembly

The location of the middle face has z = 1.5, but none of the functions I've tried in print_loc outputs a location of z = 1.5. How can I get its location?

absloc

@lorenzncode
Copy link
Member

One method to access the locations might be with the assembly iterator:

import cadquery as cq


def makeBoxWithTag():
    result = cq.Workplane("XY").box(1, 1, 1, centered=False)
    result.vertices(">X and >Y and >Z").tag("v")
    return result


assembly = (
    cq.Assembly(name="myassy", loc=cq.Location((5, 0, 0)))  # added a name and top level location for testing
    .add(cq.Solid.makeBox(1, 1, 1), name="b1")
    .constrain("b1", "Fixed")
    .add(makeBoxWithTag(), name="b2", loc=cq.Location((0, 0, 1)))
    .constrain("b2", "Fixed")
    .add(cq.Solid.makeBox(1, 1, 1), name="b3", loc=cq.Location((0, 0, 2)))
    .constrain("b3", "Fixed")
    .add(cq.Solid.makeSphere(0.2, angleDegrees1=-90), name="m")
    .constrain("m", "b2@faces@>Y", "Point")
    .solve(0)
)


def toDict(assy):
    rv = {}
    for shape, name, loc, _ in assy:
        val = {}
        val["shape"] = shape
        val["loc"] = loc
        rv[name] = val
    return rv


b2loc = toDict(assembly)["myassy/b2"]["loc"]  # get the b2 location

b2 = assembly.objects["b2"].obj  # the Workplane box object b2
b2face = b2.faces(">Y")  # select the face
b2face = b2face.val().locate(b2loc)  # apply the location

print(b2face.Center())

@lenianiva
Copy link
Contributor Author

One method to access the locations might be with the assembly iterator:

import cadquery as cq


def makeBoxWithTag():
    result = cq.Workplane("XY").box(1, 1, 1, centered=False)
    result.vertices(">X and >Y and >Z").tag("v")
    return result


assembly = (
    cq.Assembly(name="myassy", loc=cq.Location((5, 0, 0)))  # added a name and top level location for testing
    .add(cq.Solid.makeBox(1, 1, 1), name="b1")
    .constrain("b1", "Fixed")
    .add(makeBoxWithTag(), name="b2", loc=cq.Location((0, 0, 1)))
    .constrain("b2", "Fixed")
    .add(cq.Solid.makeBox(1, 1, 1), name="b3", loc=cq.Location((0, 0, 2)))
    .constrain("b3", "Fixed")
    .add(cq.Solid.makeSphere(0.2, angleDegrees1=-90), name="m")
    .constrain("m", "b2@faces@>Y", "Point")
    .solve(0)
)


def toDict(assy):
    rv = {}
    for shape, name, loc, _ in assy:
        val = {}
        val["shape"] = shape
        val["loc"] = loc
        rv[name] = val
    return rv


b2loc = toDict(assembly)["myassy/b2"]["loc"]  # get the b2 location

b2 = assembly.objects["b2"].obj  # the Workplane box object b2
b2face = b2.faces(">Y")  # select the face
b2face = b2face.val().locate(b2loc)  # apply the location

print(b2face.Center())

but this requires a traversal through the entire assembly tree. is there no way to get it directly?

@adam-urbanczyk adam-urbanczyk added the question Further information is requested label Aug 4, 2024
@adam-urbanczyk
Copy link
Member

Is that what you want: result.objects['m'].loc ?

@lenianiva
Copy link
Contributor Author

Is that what you want: result.objects['m'].loc ?

you can't do that with a tag inside the object, e.g. b2?v

@adam-urbanczyk
Copy link
Member

adam-urbanczyk commented Sep 5, 2024

AFAICT there is no well defined location of the tagged object. You'd need to construct it yourself from its center and some prior knowledge or assumptions and then multiply with the loc and possibly locs of the parent assy objects.

Aren't we hitting the xy problem here? What are you trying to achieve in the end?

@lenianiva
Copy link
Contributor Author

lenianiva commented Sep 5, 2024

AFAICT there is no well defined location of the tagged object. You'd need to construct it yourself from its center and some prior knowledge or assumptions and then multiply with the loc and possibly locs of the parent assy objects.

Aren't we hitting the xy problem here? What are you trying to achieve in the end?

The use case is this: I have two tags on my (joint) assembly, child?mount and parent?mount, and a linear actuator is supposed to connect these. I want to ensure via a unit test that when the joint is closed, the two distance between the two mounts is some number, and when the joint is open, the distance between the two mounts is equal to the actuator's maximal length. I don't think this is an XY problem.

There's existing function in Assembly.solve that generates the location of a tag, so I think this is definitely doable.

@adam-urbanczyk
Copy link
Member

I guess you want something like this then?

name = 'b2'
tag = 'v'

loc = result.objects['b2'].loc
tagged = result.objects['b2'].obj._getTagged('v').val()

result: Vector = tagged.moved(loc).Center()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants