Move contents of readme to wiki
This commit is contained in:
parent
d4992a4706
commit
96cc841033
737
Readme.md
737
Readme.md
|
@ -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  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  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  to create a plane coincidence constraint.
|
||||
* Finally, click  to solve the constraint system.
|
||||
|
||||

|
||||
|
||||
You can click 
|
||||
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
|
||||
 and drag to spread out the
|
||||
parts.
|
||||
* Select any face of the left most `Cube` in 3D view, and click
|
||||
 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.
|
||||
|
||||

|
||||
|
||||
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  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 ,
|
||||
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.
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
### 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.
|
||||
|
||||

|
||||
|
||||
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 
|
||||
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`.
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user