question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Discussion: Parts, Assemblies and Instances

See original GitHub issue

Right now we have two kinds of components Parts and Assemblies. A part is an atomic component and an Assembly is a non-atomic component consisting of Parts and other assemblies.

This is inconvenient since if I am creating a table with four legs I need create four leg parts and enter the same dimensions four times for each leg and create four separate objects that should be identical. Not very DRY and not very memory efficient. This is also true when exporting for example GLTF.

To solve this I would like to introduce “Instances” to cqparts.

The four legs in the table assembly should be four instances of the same part. I want to enter the dimensions and create the part only once. The part should define the dimensions, shape, and color of the part. The instance of the part should just define the position of each part-instance in the world and a reference to the defining part.

This means that an assembly should always consist of only Instances and not Parts and Assemblies. Parts are instantiated when added to the assembly and assemblies are also instantiated when added to an assembly.

Some pseudo code for how this could look in practice for a four legged table. The interesting part is in the class Table() make_components() definition

import cadquery
import cqparts
from cqparts.component import Mate

class Leg(cqparts.Part):
    def make(self):
        return cadquery.Workplane('XY').box(1, 1, 10, centered=(True, True, False))

    @property
    def mate_top(self):
        return Mate(self, CoordSystem((0, 0, 10)))

class Tabletop(cqparts.Part):
    def make(self):
        return cadquery.Workplane('XY').box(10, 10, 1, centered=(True, True, False))
    
    @property
    def mate_leg_0(self):
        return Mate(self, CoordSystem((5, 5, 10)))

    @property
    def mate_leg_1(self):
        return Mate(self, CoordSystem((5, -5, 10)))

    @property
    def mate_leg_2(self):
        return Mate(self, CoordSystem((-5, -5, 10)))
    
    @property
    def mate_leg_3(self):
        return Mate(self, CoordSystem((-5, 5, 10)))

class Table(cqparts.Assembly):
    def make_components(self):
        # Only create the individual parts once
        leg = Leg()
        tabletop = Tabletop()

        # The components are instances of the parts, this would be the same for sub-assemblies as well
        components = dict()
        components["tabletop_instance_0"] = cqparts.Instance(tabletop)
        components["leg_instance_0"] = cqparts.Instance(leg)
        components["leg_instance_1"] = cqparts.Instance(leg)
        components["leg_instance_2"] = cqparts.Instance(leg)
        components["leg_instance_3"] = cqparts.Instance(leg)

        return components

    def make_constraints(self):
            constraints = [
                Fixed(self.components['tabletop_instance_0'].mate_origin,
                    CoordSystem((0,0,10), (1,0,0), (0,0,1))),
                Coincident(
                    self.components['leg_instance_0'].mate_top,
                    self.components['tabletop_instance_0'].mate_leg_0
                ),
                Coincident(
                    self.components['leg_instance_1'].mate_top,
                    self.components['tabletop_instance_0'].mate_leg_1
                ),
                Coincident(
                    self.components['leg_instance_2'].mate_top,
                    self.components['tabletop_instance_0'].mate_leg_2
                ),
                Coincident(
                    self.components['leg_instance_3'].mate_top,
                    self.components['tabletop_instance_0'].mate_leg_3
                ),
            ]

            return constraints

table = Table()

A sub-assembly is also always instantiated when inserted into an assembly.

Take for example your car-assembly example in the documentation. With this notion of Parts, Assemblies and Instances the structure would look something like this.

Parts

  • Chassis
  • Axle
  • Wheel

Assemblies

  • Wheel-axle
    • Wheel-instance-1
    • Wheel-instance-2
    • Axle-instance-1
  • Car
    • Chassis-instance-1
    • Wheel-axle-instance-1
    • Wheel-axle-instance-2

This has the added benefit as well that I can compare two instances to see if they are identical. Identical in this context is “based on the same part”.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:2
  • Comments:44 (27 by maintainers)

github_iconTop GitHub Comments

1reaction
fragmuffincommented, Jun 2, 2018

I’d like to make a table of all these terms at some point. It makes transitioning from one language/CAD-tool to another much easier.

1reaction
zwncommented, May 24, 2018

@dcowden I think this is a smaller issue for cqparts than it is for cadquery. In cqparts one explicitly creates a Part instance and all subsequent methods called on that instance just modify this one instance (as one would expect in OO I presume).

In cadquery one implicitly creates (or modifies?) shapes and I think that is where the confusion came from. And since cqparts does not use method chaining, the return value c1.cut_a_hole_out_of_it() can be really anything. I think that for cadquery it is the best to always return the new geometry/shape to allow both - saving the return value for future reference and chaining the operations. I don’t see any disadvantage to returning the new shape for each call (but I don’t have that much experience so I might be easily missing something).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Forums : Instances of Parts and Assemblies? - COE.org
Simple question: how do we create instances (or configurations) of parts and assemblies in CATIA? e.g.: I would like to create a plate...
Read more >
Is there a way to create a different instance of a part in ...
Hi I am using On-shape and wanted to ask this question about creating assemblies.
Read more >
Accessing Assembly Components - Mod the Machine - TypePad
(For this discussion I'm going to focus only on the parts and subassemblies within an assembly and not anything else that can be...
Read more >
Configuring application parts from multiple assemblies #7287
I want to be able to have a base grain class in one assembly and subclass it in another. For example, let's say...
Read more >
Assembly 4 - Multiple instances of one part - Expectations?
One file for assembly with three inserted parts; one base-part, and two cube-parts. My goal is to get these two cubes to be...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found