realthunder / FreeCAD_assembly3

Experimental attempt for the next generation assembly workbench for FreeCAD
GNU General Public License v3.0
884 stars 74 forks source link

Copying Assembly container causes exception #130

Open ceremcem opened 6 years ago

ceremcem commented 6 years ago

Reproduction

  1. Create a new document
  2. Define an assembly container in the root
  3. Place some objects
  4. Create some constraints
  5. Copy the container
  6. Create a group (we need somewhere to paste into)
  7. Paste into the group
  8. Following error is thrown:
Traceback (most recent call last):
  File "/opt/FreeCAD/Ext/freecad/asm3/assembly.py", line 93, in onDocumentRestored
    self.linkSetup(obj)
  File "/opt/FreeCAD/Ext/freecad/asm3/assembly.py", line 2780, in linkSetup
    partGroup = self.getPartGroup(True)
  File "/opt/FreeCAD/Ext/freecad/asm3/assembly.py", line 2895, in getPartGroup
    self.getElementGroup(True)
  File "/opt/FreeCAD/Ext/freecad/asm3/assembly.py", line 2873, in getElementGroup
    self.getConstraintGroup(True)
  File "/opt/FreeCAD/Ext/freecad/asm3/assembly.py", line 2836, in getConstraintGroup
    '{}'.format(objName(ret)))
<type 'exceptions.RuntimeError'>: invalid parent of constraint group "Constraints"
Traceback (most recent call last):
  File "/opt/FreeCAD/Ext/freecad/asm3/assembly.py", line 3223, in onFinishRestoring
    self.showParts()
  File "/opt/FreeCAD/Ext/freecad/asm3/assembly.py", line 3205, in showParts
    proxy.getPartGroup().ViewObject.Proxy.showParts()
  File "/opt/FreeCAD/Ext/freecad/asm3/assembly.py", line 2905, in getPartGroup
    'invalid parent of part group {}'.format(objName(ret)))
<type 'exceptions.RuntimeError'>: invalid parent of part group "Parts"

Version

OS: Debian GNU/Linux 9.5 (stretch)
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.18.15546 (Git)
Build type: Release
Branch: LinkStage3
Hash: 169aeb74d470d376011ac2309546ec57813cdc16
Python version: 2.7.13
Qt version: 4.8.7
Coin version: 4.0.0a
OCC version: 7.1.0
Locale: English/UnitedStates (en_US)
realthunder commented 6 years ago

Copying object is a very complex operation. Especially so for assembly. May I ask what is your intention when copying the assembly? I am having a hard time to find a way to capture all possibilities. Do you intend to copy all parts inside, or do you want to share the parts? I notice that you sometimes directly include the part object instead of adding it as Link. In this case, do you want the new assembly to auto create link in order to share the parts? Sharing through Link means two parts has independent Placement, hence no interference between the new and the original assembly. Although it is rare, but sometimes it also make sense to direct share the part, i.e. with synchronized Placement between the two parts. For this kind of use case, usually one and only assembly will use constraint to place the parts, all other assembly sharing the part will use it as a locked base part.

ceremcem commented 6 years ago

what is your intention when copying the assembly?

Of course. For example, I draw a bolt, that has thread cylinder, hole cylinder (a virtual cylinder around thread), head (also a cylinder). There are also a few constraints. Moreover, there are a few Elements defined for interfacing, like hole-start, thread-tip, head-start. Dimensions are defined in a spreadsheet.

Now I want to create a variant, which has a cone head, instead of cylinder head. I want to copy and paste the Assembly container as if it was a standard part (like a fuse), rename, replace that cylinder with a cone, change one of the constraints (cylinder head bolt length starts from bottom surface of head but cone head bolt length is measured between upper surface and the thread tip) and go on.

In this case, do you want the new assembly to auto create link in order to share the parts?

I would expect copying exactly as is. If they are objects, objects should be copied. If they are links, links are copied to point the same source.

realthunder commented 6 years ago

I just submitted a partial fix of this. It is a complex fix, may have a few problems. Please test it.

When copying assembly, do not select anything inside the assembly. When asked whether you want to copy dependency, click Yes.

ceremcem commented 6 years ago

Interesting. I thought when I clicked "Yes", it would also duplicate "the" Spreadsheet unnecessarily for the below configuration:

+Assembly
  + Parts 
     + Cube: height = Spreadsheet.aaa
+ Spreadsheet 
+ Group <- is being pasted here

But it seems it's not the case. The Spreadsheet was a dependency, but deduplicated correctly.

Nicely working the first case.

realthunder commented 6 years ago

Unfortunately, that was a mistake. And I have fixed it. The Spreadsheet will be copied in this case. Maybe I can add an option to let use select the auto included dependencies.

realthunder commented 6 years ago

Right now, if you don't want to duplicate the spreadsheet, you can replace any part using spreadsheet in an assembly with a link. Use treeview context menu Link actions -> Replace with a link. Link act as a barrier when copy with dependencies.

ceremcem commented 3 years ago

I needed this "copy, paste, diverge" approach again. Here is what I needed to do:

I created the following drawing:

image

I need to create another leaf unit that will be just a little bit different from the hot_leaf. So I

image

File

exchanger2.FCStd.zip

Expected

At this point, I expect every pointer to "params" spreadsheet to be stay intact (will still point to params spreadsheet, not params001 spreadsheet) within the copy.

Observed

There is an exception occurs instead when I deselect (or not) the params and paste it into the same document:

image

There is an Unnamed# prefix added in front of every variable. This might be the error indication.

Version

OS: Debian GNU/Linux 9.5 (stretch)
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.19.24494 (Git)
Build type: Release
Branch: LinkDev
Hash: 5c756018210aede00673c0559933f072bbbadb40
Python version: 2.7.13
Qt version: 4.8.7
Coin version: 4.0.0a
OCC version: 7.3.0
Locale: English/UnitedStates (en_US)
ceremcem commented 3 years ago

Proposal

While it's up to you to support this kind of workflow, if this will be supported, my proposal would be as follows:

In order to create a copy of an Assembly and "override" some "features";

  1. Create a link (Link actions -> Make link)
  2. Navigate to the object that you want to make "unique", right click, Link actions -> Make Unique

Expectation

The Make Unique action will:

Let's think our original assembly (hot_leaf) as a JSON object so I could define my intention better:

document:
  hot_leaf (Assembly): 
    Constraints:
      * foo_constraint:
        * element1
        * element2
      * bar_constraint:
        * element3 (related to ./hot_spacing)
        * element4 (related to ./hot_spacing)
    Parts:
      * hot_spacing001 (Link): <<< ./hot_spacing
      * hot_spacing (Body):
        * Pad002:
            * Sketch002
      * leaf_unit (Assembly):
        * ...
        * Parts:
          * leaf (Body)
          * middle_spacer (Body)

This is what's added to the document when we create a Link to hot_leaf:

  hot_leaf001 (Link): ./hot_leaf

When we Make unique the hot_spacing part, the hot_leaf001 (Link) will be replaced by the following hot_leaf001 (Assembly):

  hot_leaf001 (Assembly): 
    Constraints:
      * foo_constraint (Link): <<< ../hot_leaf/Constraints/foo_constraint
      * bar_constraint:
        * element1 (related to ./hot_spacing)
        * element2 (related to ./hot_spacing)
    Parts:
      * hot_spacing001 (Link): <<< ./hot_spacing
      * hot_spacing (Body):
        * Pad003:
            * Sketch003
      * leaf_unit (Link): <<< ../hot_leaf/Parts/leaf_unit

This is nearly the same request in https://stackoverflow.com/questions/14184971/more-complex-inheritance-in-yaml and this is the "proof of concept".

What do you think?

realthunder commented 3 years ago

I think it is already somewhat possible. Please checkout the description here. In short, what the post describes is a way for a container, like App::Part, PartDesign::Body, or the assembly container to define some properties that are marked as 'CopyOnChange'. The child object can bind to these properties using href() function (to bypass cyclic dependency checking) for parametric modeling, like pad length, sketch angles, etc. Then use either link or binder to point to the container, and turn on the its Link/BinderCopyOnChange property. The link/binder will pull the marked properties from the container into itself. Any time you change these properties, the link/binder will make a deep copy of the container with the new configuration. This is how you can have a variant link or binder.

Regarding the assembly copy exception, please try again after you have sync my branch.