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
|
emphasis of Assembly3 is on full support of nested and multi-document
|
||||||
assemblies.
|
assemblies.
|
||||||
|
|
||||||
|
You can find more details at Assembly3 [wiki](/wiki).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
If you don't want to build everything yourself, please checkout the release
|
Although Assembly3 workbench is written in Python, it relies on quite a few
|
||||||
page for pre-built images.
|
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
|
||||||
At the moment of this writing, Assembly3 only works with a forked FreeCAD
|
branch. Pre-built images are available at the
|
||||||
[branch](https://github.com/realthunder/FreeCAD/tree/LinkStage3). You need to
|
[release page](https://github.com/realthunder/FreeCAD_assembly3/releases).
|
||||||
first checkout this branch and build it yourself.
|
Or, if you want to build everything yourself, please check out the build
|
||||||
|
instruction [[here|BuildInstruction]]
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
|
||||||
The design of Assembly3 (and the fork of FreeCAD) partially follows the
|
The design of Assembly3 (and the fork of FreeCAD) partially follows the
|
||||||
unfinished FreeCAD Assembly [project plan](https://www.freecadweb.org/wiki/Assembly_project),
|
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)
|
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),
|
and [Object model](https://www.freecadweb.org/wiki/Assembly_project#Object_model).
|
||||||
which are summarized below,
|
You can find more details at [[wiki|Design]].
|
||||||
|
|
||||||
### Multi model
|
## Usage
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
Before starting to use the Assembly3 workbench, it is necessary for the user to
|
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
|
be familiar with a few new [[concepts|Concepts]] introduced by the forked
|
||||||
read [this tutorial](https://www.freecadweb.org/wiki/Assembly_Basic_Tutorial)
|
FreeCAD.
|
||||||
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.
|
|
||||||
|
|
||||||
There is an existing container, `App::Part`, in upstream FreeCAD, which is
|
You can find instructions on common operations along with some tutorials at
|
||||||
a group type object that provides local coordinate system. The difference,
|
[[here|Usage]].
|
||||||
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.
|
|
||||||
|
|
||||||
## Comparing with Assembly2
|
## 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
|
allow you to interactively drag any part of the assembly under constraint in
|
||||||
real time.
|
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