* Draft: make move, rotate and scale commands link-aware
Fixes#12836.
Fixes#15681.
These changes are presented as a single ('big') PR because the mentioned commands have several similarities. Working on them seperately would have made less sense.
The commands have been made 'link-aware' meaning they can now handle Links and objects in linked containers.
This required several changes in the following main files. For each command all options are handled by a single function now (the `move`, `rotate` and `scale` functions). This was the only reasonable solution to correctly handle nested placements. As a result there is no longer a need to build very complex 'cmd' strings in the gui_*.py files (which is a good thing IMO).
Main files:
* move.py
* rotate.py
* scale.py
* gui_move.py
* gui_rotate.py
* gui_scale.py
* gui_trackers.py
The following files have also been updated:
* Draft.py: Imports updated.
* DraftGui.py: If `CopyMode` is changed the ghosts have to be updated. The move and rotate commands now also show previews of movable children. But since those are not copied they should be removed from the ghosts if `CopyMode` is changed to `True`.
* utils.py: Some helper functions have been added. An existing helper function (only used internally) has been renamed.
* gui_utils.py: The `select` function has been updated to accept a list of tuples to allow the reselection of nested objects.
* clone.py: A new property `ForceCompound`, necessary for non-uniform scaling, has been added.
* join.py: The `join_wires` function now returns the resultant wire objects.
* task_scale.py: Updated to allow negative scale factors. Support for `SubelementMode` preference added.
* dimension.py: `transform` methods added.
* layer.py: `get_layer` function added.
* svg.py: Updated to use `get_layer`.
* view_text.py: Instead of two added `coin.SoTransform()` nodes the main transform node is used instead. This was done so that ghosts of Draft Texts can be handled properly without requiring dedicated code in gui_trackers.py.
Notes:
* Support for "App::Annotation" is limited. Only their `Position` is handled (by the move and rotate commands).
* Support for "Image::ImagePlane" has been removed from the scale command. The object has its own calibrate feature (see https://wiki.freecad.org/Std_Import).
* Copies and clones are always created in the global space.
* Fix several unit test issues.
* Reset value that was changed while testing
* Rebase and update test_modification.py
* Reintroduce scaling of image planes
Forum topic:
https://forum.freecad.org/viewtopic.php?t=92476
For LinkGroups and Links to Std_Groups that do not have a default placement, a temporary hidden document is used to handle the placement of their children. This is a bit of a hack of course.
The fix in #16212 only checks the LayerContainer for layers. Since we do not stop users from moving layers out of that container, we should search the whole document instead.
Fixes: #16201.
TextAlignment is the vertical alignment, while Justification is the
horizontal alignment. here, get_text was passed the vertical, while it
expected the horizontal. This caused the alignment of a Label to be
wrong in the resulting SVG (e.g. in a TechDraw draft view).
This seems to have been broken since SVG support for Labels was first
introduced in commit d6f8ded4ca (Initial work, only text (no lines)).
Label objects would produce invalid SVG XML, because the stroke-linecap
property was added as if it was a style (with : and ;), but it was
inserted in the XML tag directly, rather than inside the style attribute
value. The invalid SVG prevented for example a TechDraw draft view from
rendering when it contained a label.
This was added in commit 6a7912d399 (Draft: Using square endcaps for
lines in SVG output).
This stroke-linecap is supported both as a presentation attribute inside
the style or a XML attribute, so for consistency with the surrounding
attributes, it is made a normal attribute, rather than putting it inside
the style.
See also https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap
An AttributeError is raised when `direction=Vector(0,0,0)` and obj is
an Arch::Space on line: a3fb3cc804/src/Mod/Draft/draftfunctions/svg.py (L799)
This patch checks if early on if the direction vector and raises a
ValueError with a description of what has gone wrong.
A caveat with this solution is that this new behaviour might break old
code which depends on that invalid directions can be used.
If it's not a circle nor ellipse nor straight line
convert the curve to BSpline. Move into a subfunction.
Improve a few varible names to be more verbose, like `vertex`
and `edge`.
The angle between the curve and plane is tested for being coplanar,
0 or 180 degrees. The negative test is done earlier so that the
return is done earlier, and the rest of the code is not indented.
For the try-except blocks we should trap a specific `Exception`,
not just any type. It seems string handling was an issue
with Python 2, so the string needed UTF8 decoding.
When the software no longer supports Python 2, these
blocks can be removed.
Small fixes where the `get_svg` function is used, for example,
in the (obsolete) `DrawingView` class and `Arch_SectionPlane`.
Also update the unit tests accordingly.