Move contents of readme to wiki

This commit is contained in:
Zheng, Lei 2018-02-01 10:14:25 +08:00
parent d4992a4706
commit 96cc841033

737
Readme.md
View File

@ -8,569 +8,34 @@ inspiration of this workbench, and with some code borrowed as well. The
emphasis of Assembly3 is on full support of nested and multi-document
assemblies.
You can find more details at Assembly3 [wiki](/wiki).
## Installation
If you don't want to build everything yourself, please checkout the release
page for pre-built images.
At the moment of this writing, Assembly3 only works with a forked FreeCAD
[branch](https://github.com/realthunder/FreeCAD/tree/LinkStage3). You need to
first checkout this branch and build it yourself.
After that, checkout this repository directly inside the `Ext/freecad/`
directory of your FreeCAD installation or build directory. Be sure to name the
directory as **asm3**. The Assembly3 workbench supports multiple constraint
solver backends. Currently, there are two backends available, `SolveSpace` and
`SymPy + SciPy`, both of which have external dependency. The current focus is
to get SolveSpace backend fully working first, with SymPy + SciPy serving as
a reference implementation for future exploration. All backends are optional.
But, you'll need at least one installed to be able to do constraint based
assembling, unless you are fine with manually movement, which is actually
doable because Assembly3 provides a powerful mouse dragger.
### SolveSpace
[SolveSpace](http://solvespace.com/) is by itself a standalone CAD software
with excellent assembly support. IMO, it has the opposite design principle of
FreeCAD, which is big, modular, and fully extensible. SolveSpace, on the other
hand is lean and compact, and does extremely well for what it offers. But, you
most likely will find something you want that's missing, and have to seek out
other software for help. The constraint solver of SolveSpace is available as
a small library for integration by third party software, which gives us the
opportunity to bring the best from both worlds.
There is no official python binding of SolveSpace at the moment. Besides, some
small modification is required to bring out the SolveSpace assembly
functionality into the solver library. You can find my fork at `asm3/slvs`
subdirectory. To checkout,
```
cd asm3
git submodule update --init slvs
```
If you are using Ubuntu 16.04 or Windows 64-bit, then you can check out the
pre-built python binding at `asm3/py_slvs` subdirectory.
```
cd asm3
git submodule update --init py_slvs
```
#### Build for Ubuntu
To build for Ubuntu, run
```
apt-get install libpng12-dev libjson-c-dev libfreetype6-dev \
libfontconfig1-dev libgtkmm-2.4-dev libpangomm-1.4-dev \
libgl-dev libglu-dev libglew-dev libspnav-dev cmake
```
Make sure to checkout one of the necessary sub module before building.
```
cd asm3/slvs
git submodule update --init extlib/libdxfrw
```
To build the python binding only
```
cd asm3/slvs
mkdir build
cd build
cmake -DBUILD_PYTHON=1 ..
make _slvs
```
After compilation is done, copy `slvs.py` and `_slvs.so` from
`asm3/slvs/build/src/swig/python/CMakeFiles` to `asm3/py_slvs`. Overwrite
existing files if you've checked out the `py_slvs` sub module. If not, then be
sure to create an empty file named `__init__.py` at `asm3/py_slvs`.
#### Cross Compile for Windows
To build for Windows 64-bit, you have two options. This section shows how to
cross compile for Windows on Ubuntu
```
apt-get install cmake mingw-w64
cd asm3/slvs
git submodule update --init --recursive
mkdir build_mingw
cd build_mingw
cmake -DBUILD_PYTHON=1 -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw64.cmake ..
make _slvs
```
After finish, copy `slvs.py` and `_slvs.pyd` from
`asm3/slvs/build/src/swig/python/CMakeFiles` to `asm3/py_slvs`. Overwrite
existing files if you've checked out the `py_slvs` sub module. If not, then be
sure to create an empty file named `__init__.py` at `asm3/py_slvs`.
#### Build on Windows
To build on Windows, you should use Visual Studio 2013, the same one FreeCAD
uses. Install CMake and Python. If you are building the 64-bit version, make
sure you install the Python 64-bit version. I have only tested the build with
Python 2.7.14 64-bit. You probably can use the python lib included in FreeCAD
libpack by adding the libpack path to `PATH` environment variable. But it
doesn't work for me somehow. CMake only found the debug version python lib in
the libpack.
Download and extract the latest [swig](http://www.swig.org/download.html) to
some where, and add the path to `PATH` environment variable. I haven't tested
to build with the old version swig that's bundled with FreeCAD libpack.
Be sure to checkout all the submodules of slvs before building. None of them
is actually used, but is still needed to satisfy CMake dependency checking,
```
cd asm3/slvs
git submodule update --init --recursive
```
Run CMake-gui, select a build directory. Add a `BOOL` type entry named
`BUILD_PYTHON`, and set it to `true`. Then click `configure` and select Visual
Studio 2013 Win64, which is what FreeCAD used. If done without error, click
`generate`.
Finally, open the `solvespace.sln` file in the build directory. You only need to
build two projects, first `slvs_static_excp`, and then `_slvs`. Once finished,
copy the output at the following location to `asm/py_slvs`
```
asm/slvs/<your_build_directory>/src/swig/python/slvs.py
asm/slvs/<your_build_directory>/src/swig/python/Release/_slvs.pyd
```
If you want to build the Debug version, you should put FreeCAD libpack directory
in `PATH` environment variable before configuring CMake, so that CMake can find
the debug version Python library. Once built, you must rename `_slvs.pyd` to
`_slvs_d.pyd` before copying to `asm/py_slvs`
### SymPy + SciPy
The other constraint solver backend uses [SymPy](http://www.sympy.org/) and
[SciPy](https://www.scipy.org/). They are mostly Python based, with some native
acceleration in certain critical parts. The backend implementation models after
SolveSpace's solver design, that is, symbolic algebraic + non-linear least
square minimization. It can be considered as a python implementation of the
SolveSpace's solver.
SciPy offers a dozen of different [minimization](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html)
algorithms, but most of which cannot compete with SolveSpace performance wise.
The following list shows some non-formal testing result using default
parameters with the sample [assembly](#create-a-super-assembly-with-external-link-array)
described later
| Algorithm | Time |
| --------- | ---- |
| SolveSpace (as reference) | 0.006s |
| Nelder-Mead | Not converge |
| Powell | 7.8s |
| CG | 10+37s <sup>[1](#f1)</sup> |
| BFGS | 10+0.8 <sup>[1](#f1)</sup> |
| Newton-CG | 10+61+0.5s <sup>[2](#f2),</sup><sup>[3](#f3)</sup> |
| L-BFGS-B | 10+1.5s <sup>[1](#f1),</sup><sup>[3](#f3)</sup> |
| TNC | 10+0.8s <sup>[1](#f1)</sup> |
| COBYLA | 0.2s <sup>[3](#f3)</sup> |
| SLSQP | 10+0.3 <sup>[1](#f1),</sup><sup>[3](#f3)</sup> |
| dogleg | 10+61+?s <sup>[2](#f2)</sup> Failed to solve, linalg error |
| trust-ncg | 10+61+1.5s <sup>[2](#f2)</sup> |
<b name="f1">[1]</b> Including Jacobian matrix calculation (10s in this test
case), which is implemented using sympy lambdify with numpy.
<b name="f2">[2]</b> Including Hessian matrix calculation (61s in this test
case), in addition to Jacobian matrix.
<b name="f3">[3]</b> The obtained solution contains small gaps in some of
the coincedence constrained points. Incorrect use of the algorithm?
The reasons for writing this backend are,
* SolveSpace is under GPL, which is incompatible with FreeCAD's LGPL,
* To gain more insight of the solver system, and easy experimentation with new
ideas due to its python based nature,
* For future extension, physics based simulation, maybe?
You'll need to install SymPy and SciPy for your platform.
```
pip install --upgrade sympy scipy
```
Although Assembly3 workbench is written in Python, it relies on quite a few
FreeCAD core changes to work properly. At the moment of this writing, these
changes has not been merged into upstream yet, and only exists as a forked
branch. Pre-built images are available at the
[release page](https://github.com/realthunder/FreeCAD_assembly3/releases).
Or, if you want to build everything yourself, please check out the build
instruction [[here|BuildInstruction]]
## Design
The design of Assembly3 (and the fork of FreeCAD) partially follows the
unfinished FreeCAD Assembly [project plan](https://www.freecadweb.org/wiki/Assembly_project),
in particularly, the section [Infrustracture](https://www.freecadweb.org/wiki/Assembly_project#Infrastructure)
and [Object model](https://www.freecadweb.org/wiki/Assembly_project#Object_model),
which are summarized below,
and [Object model](https://www.freecadweb.org/wiki/Assembly_project#Object_model).
You can find more details at [[wiki|Design]].
### Multi model
The forked FreeCAD core supports external object linking (with a new type of
property, `PropertyXLink`, as a drop-in replacement of PropertyLink),
displaying, editing, importing/exporting, and cross-document undo/redo.
### Part-tree
Assembly3 provides the `Assembly` container for holding its child features (or
sub-assembly), and their constraints. It also introduce a new concept of
`Elements` for declaring geometry elements used by constraints inside parent
assembly. The purpose of the `Element` is to minimize the problem caused by
geometry topological name changing, and make the assembly easier to maintain.
See the following section for more details. A single object (e.g. Part object,
sketch, or another assembly), can be added to multiple parent assemblies,
either within the same or located outside of the current document. Each of its
appearance inside the parent assembly has independent visibility control, but
shares the same placement, meaning that if you move one instance of the object,
all other instances moves relative to their parent assembly container. You can
have independent placement by converting a child object into a link type object
(See the following section for details). Simply right click the child object in
the tree view and select `Link actions -> Replace with link`.
### Unified Drag/Drop/Copy/Paste interface
The drag and drop API has been extended to let the target object know where the
dropped object located in the object hierarchy, which is taken full advantage
by Assembly3. The copy and paste is extended as well to be aware of external
objects, and let the user decide whether to do a shallow or deep copy.
### Object model
The `SubName` field in `Gui::SelectionObject` is for holding the selected
geometry sub-element, such as face, edge or vertex. The forked FreeCAD extended
usage of `SubName` to hold the path of selected object within the object
hierarchy, e.g. a selection object with `Object = Assembly1` and `SubName
= Parts.Assembly2.Constraints002.Constraint.` means the user selected the
`Constraint` object of `Assembly2`, which is a child feature of the part group
(`Parts`) in `Assembly1`. Notice the ending `.` in `SubName`. This is for
backward compatibility purpose, so that the `SubName` can still be used to
refer to a geometry sub-element of some sub-object without any ambiguity. The
rule is that, any sub-object references must end with a `.`, and those names
without an ending `.` are sub-element references. The aforementioned
`PropertyXLink` has an optional `subname` field (assign/return as a `tuple(obj,
subname)` in Python) for linking into a sub-object/element.
`Gui.Selection` is extended with backward compatibility to provide full object
path information on each selection, which makes it possible for the same object
to be included in more than one group like objects without ambiguity on
selection. Several new APIs have been added to FreeCAD core to provide nested
child object placement and geometry information.
## Concepts
### Coordinate System
## Usage
Before starting to use the Assembly3 workbench, it is necessary for the user to
be familiar with a few new concepts in FreeCAD. The user is encouraged to first
read [this tutorial](https://www.freecadweb.org/wiki/Assembly_Basic_Tutorial)
to get some idea about the new concept of _local coordinate systems_. The
tutorial is for the original unfinished Assembly workbench, but gives a pretty
comprehensive overview of what Assembly3 is providing as well. The `Part` or
`Product` container mentioned in the tutorial are equivalent to the `Assembly`
container in Assembly3, which of course can be treated just as a _part_ and
added to other assemblies. There is one thing I disagree with this tutorial.
The concept of _global coordinate system_ is still useful, and necessary to
interoperate with objects from other legacy (i.e. non-local-CS-aware)
workbench. Let's just define the _global coordinate system_ as the 3D view
coordinate system, in other word, the location where you actually see the
object in the 3D view, or, the coordinates displayed in the status bar when you
move your mouse over some object.
be familiar with a few new [[concepts|Concepts]] introduced by the forked
FreeCAD.
There is an existing container, `App::Part`, in upstream FreeCAD, which is
a group type object that provides local coordinate system. The difference,
comparing to Assembly3 container, is that one object is allowed to be added to
one and only one `App::Part` container. The owner container can be added to
other `App::Part` container, but must still obey the one direct parent
container rule. The reason behind this is that when any object is added to
`App::Part`, it is physically removed from its original parent coordinate
system, and added to the owner `App::Part's` coordinate system, so the object
cannot appear in more than one coordinate system. By _physically removed_,
I mean the 3D visual representation data is physically moved to a different
coordinate system inside the 3D scene graph (See
[here](https://www.freecadweb.org/wiki/Scenegraph) for more details).
Assembly3 container has no such restriction. When added to a Assembly3
container, the object's visual data is simply reused and inserted multiple
times into the scene graph, meaning that the object actually exists
simultaneously in multiple coordinate systems. This has a somewhat unexpected
side effect. When an object is added to an assembly with some placement, the
object is seemingly jumping into a new place. This is excepted, because the
object enters a new coordinate system, and it seems to have the same behavior
as `App::Part`. But what actually happened is that the original object inside
the global coordinate system is simply made invisible before adding to the
assembly container. You can verify this by manually toggle the `Visibility`
property to reveal the object in its original placement. Every object's
`Visibility` property controls its own visibility in the global coordinate
system only. Each assembly container has the `VisibilityList` property to
control the visibilities of its children.
### Link
The forked FreeCAD core introduced a new type of object, called _Link_.
A _Link_ type object (not to be confused with a _link property_) often does not
have geometry data of its own, but instead, link to other objects (using link
property) for geometry data sharing. Its companion view provider,
`Gui::ViewProviderLink`, links to the linked object's view provider for visual
data sharing. It is the most efficient way of duplicating the same object in
different places, with optional scale/mirror and material override. The core
provides an extension, `App::LinkBaseExtension`, as a flexible way to help
users extend their own object into a link type object. The extension utilize
a so called _property design pattern_, meaning that the extension itself does
not define any property, but has a bunch of pre-defined property place holders.
The extension activates part of its function depending on what properties are
defined in the object. This design pattern allows the object to choose their
own property names and types.
The core provides two ready-to-use link type objects, `App::Link` and
`App::LinkGroup`, which expose different parts of `LinkBaseExtension's`
functionality. `App::Link` supports linking to an object, either in the same or
external document, and has built-in support of array (through property
`ElementCount`) for efficient duplicating of the same object. `LinkGroup` acts
like a group type object with local coordinate system. It relies on
`LinkBaseExtension` and `ViewProviderLink` to provide advanced features like,
adding external child object, adding the same object multiple times, etc. All
of the Assembly3 containers are in fact customized `LinkGroup`.
### Element
`Element` is a brand new concept introduced by Assembly3. It is used to
minimize the dreadful consequences of geometry topological name changing, and
also brings the object-oriented concept in the programming world into CAD
assembling. `Element` can be considered as a declaration of connection
interface of the owner assembly, so that other parent assembly can know which
part of this assembly can be joined with others.
For a geometry constraint based system, each constraint defines some
relationship among geometry elements of some features. Conventionally, the
constraint refers to those geometry elements by their topological names, such
as `Fusion001.Face1`, `Cut002.Edge2`, etc. The problem with this simple
approach is that the topological name is volatile. Faces or edges may be
added/removed after the geometry model is modified. More sophisticated
algorithm can be applied to reduce the topological name changing, but there
will never be guarantee of fixed topological names. Imagine a simple but yet
extreme case where the user simply wants to replace an entire child feature,
say, changing the type of some screw. The two features are totally different
geometry objects with different topological naming. The user has to manually
find and amend geometry element references to the original child feature in
multiple constraints, which may exists in multiple assembly hierarchies, across
multiple documents.
The solution, presented by Assembly3, is to use abstraction by adding multiple
levels of indirections to geometry references. Each `Assembly` container has an
element group that contains a list of `Elements`, which are a link type of
object that links to some geometry element of some child feature of this
assembly. In case the feature is also an `Assembly`, then the `Element` in
upper hierarchy will instead point to the `Element` inside lower hierarchy
assembly. In this way, each `Element` acts as an abstraction to which geometry
element can be used by other parent assemblies. Any constraint involving some
assembly will only indirectly link to the geometry element through an `Element`
of some child assembly. If the geometry element's topological name changes due
to whatever reason, the user only needs to change the deepest nested (i.e.
nearest to the actual geometry object) `Element`'s link reference, and all
upper hierarchy `Elements` and related constraints stays the same.
The `Element` is a specialized `App::Link` that links into a sub-object, using
a `PropertyXLink` that accepts a `tuple(object, subname)` reference. In
addition, `Element` allows to be linked by its label, instead of the immutable
internal FreeCAD object name. `Element` specifically allows its label to be
duplicated (but still enforces uniqueness among its siblings). This enables the
user to define inter-changeable parts with the same set of elements as
interface.
Let's take a look at the following assembly hierarchy for an example,
```
Assembly001
|--Constraints001
| |--Constraint001
| |--ElementLink -> (Elements001, "$Element.")
| |--ElementLink001 -> (Parts001, "Assembly002.Elements002.$Element001.")
|--Elements001
| |--Element -> (Parts001, "Cut.Face3")
|--Parts001
|--Cut
|--Assembly002
|--Constraints002
|--Elements002
| |--Element001 -> (Parts002, "Assembly003.Elements003.$Element002.")
|--Parts002
|--Assembly003
|--Constraints003
|--Elements003
| |--Element002 -> (Parts003, "Fusion.Face1")
|--Parts003
|--Fusion
```
The `Assembly001` has two child features, a `Cut` object and a child
`Assembly002`, which in turn has its own child `Assembly003`. `Assembly001`
contains a constraint `Constraint001` that defines the relationship of its two
child features. `Constraint001` refers to two geometry element through two
links, `ElementLink`, which point to a second level link, `Element`.
`ElementLink001` points to `Element001`, And, because the first child feature
`Cut` is not defined as an assembly, its geometry element reference is directly
stored inside the parent assembly element group. `Element001`, however, links
to the lower hierarchy `Element002` in its child assembly, which again links to
`Element003` in its child `Assembly003`. Notice the `$` inside the subname
references. It marks the followed text to be a label instead of an object name
reference. If you re-label the object, all `PropertyXLink` of all opened
documents containing that label reference will be automatically updated.
The grand idea is that, after the author modified an assembly, whether its
a modification to the geometry model, or replacing some child feature. He needs
to check all element references inside that and only that assembly, and make
proper adjustment to correct any undesired changes. Other assemblies with
elements or constraints referring to this assembly will stay the same (although
recomputation is still required), even if those assemblies reside in different
documents, or come from different authors.
Let's say, we have modified `Fusion`, and the original `Fusion.Face1` is now
changed to `Face10`. All we need to do is to simply modify `Element002` inside
the same owner assembly of `Fusion`. Everything else stays the same.
Again, say, we want to replace `Assembly003` with some other assembly. Now this
is a bit involving, because, we added `Aseembly003` directly to `Assembly002`,
instead of using a link, which can be changed dynamically. The FreeCAD core has
a general command to simplify this task. Right click `Assembly003` in the tree
view, and select `Link actions -> Replace with link`. `Assembly003` inside
`Parts002` will now be replaced with a link that links to `Assembly003`. Every
relative link that involving `Parts002.Assembly003` will be updated to
`Parts002.Link_Assembly003` automatically. In our case, that will be
`Element001`. You can then simply change the link to point to another assembly
containing an element object with the same label `Element001` (remember element
object allows duplicated labels). If you still insist on adding the new
assembly directly and get rid of the link, you can use `Link actions ->
unlink`, and delete the link object afterward.
It may seem intimidating to maintain all these complex hierarchies of
`Elements`, but the truth is that it is not mandatory for the user to manually
create any element, at all. Simply select any two geometry elements in the 3D
view, and you can create a constraint, regardless how many levels of
hierarchies in-between. All intermediate `Elements` and `ElementLinks` will be
created automatically. Although, for the sake of re-usability, it is best for
the user as an assembly author to explicitly create `Element` as interfaces,
and give them proper names for easy (re)assembling. Check the [section](#replace-sub-assembly)
below for a demonstration of part replacement.
Last but not the least, `Element`, as well as the `ElementLink` inside
a constraint, make use of a new core feature, `OnTopWhenSelected`, to
forcefully show highlight of its referring geometry sub-element (Face, Edge,
Vertex) when selected, regardless of any obscuring objects. The property
`OnTopWhenSelected` is available to all view object, but default to `False`,
while `Element` and `ElementLink` make it active by default. The on-top feature
makes it even easier for the user to check any anomaly due to topological name
changing.
### Selection
There are two types of selection in FreeCAD, geometry element selection by
clicking in the 3D view, and whole object selection by clicking in the tree
view. When using Assembly3, it is important to distinguish between these two
types of selection, because there are now lots of objects with just one
geometry element. While you are getting used to these, it is helpful to bring
out the selection view (FreeCAD menu bar, `View -> Panels -> Selection view`).
You select a geometry element by clicking any unselected element (Face, Edge or
Vertex) in the 3D view. If you click an already selected element, the selection
will go one hierarchy up. For example, for a `LinkGroup` shown below,
```
LinkGroup
|--LinkGroup001
| |--Fusion
| |--Cut
|--Cut001
```
Suppose you have already selected `Fusion.Face1`. If you click that face again,
the selection will go one hierarchy up, and select the whole `Fusion` object.
If you click any where inside `Fusion` object again, the selection goes to
`LinkGroup001`, and you'll see both `Fusion` and `Cut` being highlighted. If
you again click anywhere inside `LinkGroup001`, `Cut001` will be highlighted,
too, because the entire `LinkGroup` is selected. Click again in `LinkGroup`,
the selection goes back to the geometry element you just clicked.
There is a new feature in the forked FreeCAD selection view. Check the `Enable
pick list` option in selection view. You can now pick any overlapping geometry
elements that intersect with your mouse click in the selection view.
You may find it helpful to turn on tree view selection synchronization (right
click in tree view, select `Sync selection`), so that the tree view will
automatically scroll to the object you just selected in the 3D view. When you
select an originally unselected object in the tree view, the whole object will
be selected. And if you start dragging the object item in the tree view, you
are dragging the whole object. If you select a geometry element in the 3D view,
its owner object will also be selected in tree view. But if you then initiate
dragging of that particular object item, you are in fact dragging the selected
geometry element. This is an important distinction, because some containers,
such as the `Constraint` object, only accept dropping of geometry element, and
refuse whole object dropping.
## Constraints and Solvers
As mentioned in previous section, Assembly3 supports multiple constraint solver
backend. The user can choose different solver for each `Assembly`. The type of
constraints available may be different for each solver. At the time of this
writing, two backend are supported, one based on the solver from SolveSpace,
while the other uses SymPy and SciPy, but is modeled after SolveSpace. In other
word, the current two available solvers supports practically the same set of
constraints and should have very similar behavior, except some difference in
performance.
Assembly3 exposed most of SolveSpace's constraints. If you want to know more
about the internals, please read
[this document](https://github.com/realthunder/solvespace/blob/python/exposed/DOC.txt)
from SolveSpace first. The way Assembly3 uses the solver is that, for a given
`Assembly`,
* Create free parameters corresponding to the placement of each movable child
feature, that is, three parameters for position, and four parameters for its
orientation (quaternion).
* For each constraint, create SolveSpace `Entities` (i.e. points, normals,
rotations, etc) for each geometry element as a transformation of its owner
feature's placement parameters.
* Create SolveSpace `Constraints` with the `Entities` created in the previous
step.
* Ask SolveSpace to solve the constraints. SolveSpace formulate the constraint
problems as a non-linear least square minimization problem, generates
equations symbolically, and then tries to numerically find a solution for the
free parameters.
* The child features placements are then updated with the found solution.
For nested assemblies, Assembly3 will always solve all the child assemblies
first before the parent.
One thing to take note is that, SolveSpace is a numerical solver, which means
it is sensitive to initial conditions. In other word, you must first roughly
align two features according to their constraints, or else the solver may not
be able to find an answer. Assembly3 has extensive support of easy manual
placement of child feature. See the following section for more details.
Assembly3 provides several new constraints that are more useful for assembly
purposes. Most of these constraints are in fact composite of the original
constraints from SolveSpace, except for the `Lock` constraint. Some more common
constraints are available as toolbar buttons for easy access, while all
constraint types are accessible in property editor. Each `Constraint` object
has a `Type` property, which allows the user to change the type of an existing
constraint. Not all constraints require the same types of geometry elements,
which means that changing the type may invalidate a constraint. The tree view
will mark those invalid constraints with a red exclamation mark. Hover the
mouse over those invalid items to see the explanation. Just follow the
instruction to manually correct the element links.
Special mention about the `Lock` constraint, which is used to lock the
placement of a related child feature. Like all other constraints, `Lock`
constraint, as a container, only accepts geometry element drag and drop. If you
drop in a `Vertex` or linear `Edge`, then the owner feature is allowed to be
rotated around the geometry element. If you drop in a non-linear `Edge` or
`Face`, then the feature is completely fixed within the owner assembly with
this constraint. If no `Lock` constraint is found in an `Assembly`, then the
feature that owns the first element of the first constraint is fixed.
You can find instructions on common operations along with some tutorials at
[[here|Usage]].
## Comparing with Assembly2
@ -613,173 +78,3 @@ a brief list of comparison between Assembly2 to Assembly3.
allow you to interactively drag any part of the assembly under constraint in
real time.
## Common Operations
We are going to build a simple assembly through this section to showcase some
of the main features of Assembly3
### Create a Simple Assembly with a Constraint
* Start FreeCAD, and create a new document
* Switch to `Part` workbench, and create a `Cube` and a `Cylinder`
* Switch to `Assembly3` workbench, click ![Add assembly](/Gui/Resources/icons/Assembly_New_Assembly.svg) to create a new assembly
* Select both the `Cube` and `Cylinder`, and drag them into the new assembly
* Select any face of the `Cylinder` or `Cube`, and click ![Move](/Gui/Resources/icons/Assembly_Move.svg) to activate part manual movement. Click any arrow to drag the `Cylinder` on top of the `Cube`
* Select the top face of `Cut` and (while holding `CTRL` key) select the bottom face or edge of the `Cylinder`, and then click ![Add Coincidence](/Gui/Resources/icons/constraints/Assembly_ConstraintCoincidence.svg) to create a plane coincidence constraint.
* Finally, click ![Solve](/Gui/Resources/icons/AssemblyWorkbench.svg) to solve the constraint system.
![Screencast1](https://github.com/realthunder/files/blob/master/screencast/asm3/asm1.gif)
You can click ![Auto recompute](/Gui/Resources/icons/Assembly_AutoRecompute.svg)
to enable auto-solving with any changes in constraint.
Now, save this document with whatever name you like.
### Create a Super Assembly with External Link Array
We are going to build a multi-joint _thing_ using the above assembly as the
base part.
* Create a new document, and save it to whatever name you like. Yes, you need
to save both the link and linked document at least once for external linking
to work, because `PropertyXLink` need the file path information of both
document to calculate relative path.
* Make sure the current active 3D view is the new empty document. Now, in the
tree view, select the assembly we just created previously, and then hold on
`CTRL` key and right click the new document item in the tree view, and select
`Link actions -> Make link`. A `Link` will be created that brings the
assembly into the new document. You probably need to click `Fit content`
button (or press `V,F` in 3D view) to see the assembly.
* Select the link in the tree view, and change the `ElementCount` property to
four. Now you have four identical assemblies.
* Create a new assembly, and then drag the link object into it.
* Select any face of any `Cube`, click
![Move](/Gui/Resources/icons/Assembly_Move.svg) and drag to spread out the
parts.
* Select any face of the left most `Cube` in 3D view, and click
![Lock](/Gui/Resources/icons/constraints/Assembly_ConstraintLock.svg) to lock
the left most sub assembly.
* Orient the parts whatever you like. Select two face from any two assembly,
and create a plane coincidence constraint. If you've enabled _auto
recompute_, then the two assembly will now be snapped together
* Do the same for the rest of the parts.
![Screencast2](https://github.com/realthunder/files/blob/master/screencast/asm3/asm2.gif)
Now that we've made this multi-joint thingy, try to save this document, and
FreeCAD will ask if you want to save the external document, too. If you answer
yes, then FreeCAD will take care of ordering, and save the external document
first before linking document.
Close both documents. Open the multi-joint assembly document, FreeCAD will
automatically open any externally referenced documents, too. If you close the
external document while leaving the linking document open, all externally
linked object will vanish from 3D view. Open external document again and the
objects will re-appear. This allows you to easily swap in a replacement
document for whatever reason. But, it demands the replacement document having
an object of the same internal name as the original linked one. You can of
course, easily re-assign the link to any other object in the opened documents.
Just use the property editor, click the edit button of `LinkedObject` property.
In the editor window, select the desired document in the drop list, and then
select the desired object. But now, you need to make sure the new linked object
has the same element interface, or else the constraints will be broken.
A few more words about link array. Assembly3 normally treats any object added
to its part group as a stand alone entity that can be moved as a whole.
However, it has special treatment for a link array object. Each array element
will be treated as separate entities, that can be constrained and moved
individually. If you actually want to add the array as an integral part, simply
wrap the array inside a dummy assembly without any constraint, and add that
assembly instead into the parent assembly.
By the way, the `Draft` workbench now has two variation of link array, the
`LinkArray` and `LinkPathArray`, which provide the same functionality as
`Draft` `Array` and `PathArray`, but use link to provide duplicates. Those link
arrays, by default, do not show individual element in tree view. You can still
access each element through `subname` reference as usual. Having less
objects can improve document saving and loading performance. It is particularly
noticeable if you have large amount of array elements. You can, however, show
the array element at any time by toggle property `ShowElement`. Once the
elements are visible, they can be moved independently by change their
placements.
### Add/Modify Element and ElementLink
It is quite easy to directly create a new constraint as shown above, with all
involved `Element` and `ElementLink` being taken care of for you by Assembly3.
It is also straightforward to manually add new or modify existing `Elements`
and `ElementLink`. Simply select a geometry element in 3D view, and its
corresponding owner object will be selected in the tree view (Remember to turn
on `Sync selection` option in tree view as mentioned before). You can then drag
the selected item to the `ElementGroup` of an `Assembly` to create a new
`Element`, or to a `Constraint` to add an `ElementLink`. You can modify an
existing `Element` or `ElementLink` by simply dragging the item onto an
existing item of `Element` or `ElementLink`.
### Part Move
Assembly3 has extensive support of manual movement of nested assembly. In 3D
view, select any geometry element (Face, Edge) that belongs to some assembly,
and click ![Move](/Gui/Resources/icons/Assembly_Move.svg) to activate part
dragging. The dragger will be centered around the selected geometry element. In
case of multi-hierarchy assemblies, you will be dragging the first level
sub-assembly of the top-level assembly. If you want to drag intermediate
sub-assembly instead, add that assembly as the second selection (`CTRL` select)
before activating part move.
If you have enabled ![Auto recompute](/Gui/Resources/icons/Assembly_AutoRecompute.svg),
any movement of the sub-assembly will cause the parent assembly to auto
re-solve its constraints, as shown below. Because there are too many degree of
freedom left, hence many possible solutions of the constraint system, the
movement of the multi-joint assembly is jerky. Besides, the part move command
is very complicated, and probably need a lot more work to make it perfect. In
case when the parts are moved such that they stuck in some invalid position, as
you can see from the screen cast below, simply `CTRL+Z` to undo the movement.
Every time you release the mouse button, a transaction will be committed, so
that you can undo/redo the previous mouse drag. You can also temporary bypass
recomputation by holding `CTRL` key while dragging.
![Screencast3](https://github.com/realthunder/files/blob/master/screencast/asm3/asm3.gif)
### Replace Sub-Assembly
Continue from the Multi-join assembly we created in previous section. Suppose
we want to change the sub-assembly with another part. The screencast below
shows how to do it.
![Screencast3](https://github.com/realthunder/files/blob/master/screencast/asm3/asm-replace-part.gif)
All geometry element references used in any constraints will be referenced
through some auto created `Element` object. Find out those elements, and give
them some meaningful name. When you rename some `Element` object that are
referenced by some constraint, or high level `Element` objects, all involved
subname references will be automatically updated. Be careful, though. If you are
editing an external assembly that are referenced in some other super assembly
file that are not currently opened in FreeCAD, you will obviously break the link
reference.
Now, to replace the sub-assembly, manually create the corresponding elements
with selection, drag and drop, and give them the same names. Because the
original sub-assembly is brought in by a `Link` object, simply re-point the
`Link` to the replacement part, and re-solve the constraint system. Done!
Note that, in the screencast, we didn't rename the first two elements. It is
because that those elements are used internally by the original sub-assembly. It
is not involved in the parent assembly. If you modified the geometry model of
the sub-assembly, then you should double check all the elements for any geometry
topological name changes.
### Import External Assembly
In some cases, it will be easier to distribute your multi-hierarchy assembly as
a single self-contained document. FreeCAD core provides a convenient command to
help with this otherwise not so trivial task. Simply right-click any item in
the document you want to distribute, and select `Link actions -> Import all
links`, and that's all. Click ![Solve](/Gui/Resources/icons/AssemblyWorkbench.svg)
to see if every thing is okay. You can of course selectively import any object
you want. Simply right click that item and select `Link actions -> Import
link`.