Varying line thickness for different parts in TechDraw

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
youen
Posts: 62
Joined: Sun May 19, 2019 7:32 pm

Varying line thickness for different parts in TechDraw

Post by youen »

I would like to export SVG images looking like the attached image. I think I can handle everything semi-automatically with a custom python script (which parts are displayed, callout of parts, etc), in the TechDraw workbench. The only thing I don't know is possible or not is to display some parts in fat lines, others in thin lines. I can change individual lines thickness in TechDraw, probably also possible to do that from a python script (?), but the problem is I don't think TechDraw remembers which line comes from which part? For example if I want the L00 part to be displayed with fat lines, how can I know which lines I should change thickness?

A neat feature would be for TechDraw to use the display thickness from each part when the view is rendered, but I don't think such a feature exists at this time?

Any idea how I could do that?

Thanks for any hints!
test-line-width.png
test-line-width.png (12.44 KiB) Viewed 1076 times
User avatar
wandererfan
Veteran
Posts: 6268
Joined: Tue Nov 06, 2012 5:42 pm
Contact:

Re: Varying line thickness for different parts in TechDraw

Post by wandererfan »

youen wrote: Wed Oct 05, 2022 7:34 pm but the problem is I don't think TechDraw remembers which line comes from which part? For example if I want the L00 part to be displayed with fat lines, how can I know which lines I should change thickness?
Are the "parts"(L00) all in the same View? If so, then there is no easy way for the program to know what lines belong to which part. All the lines from all the source shapes are delivered in one big pile. If they are in different Views, then this is easy.

Off the top of my head, the only way to do this would be to take every edge in the source shape, project it onto the paper plane, then try to find a matching projected edge in the View. This would be very slow on a big model, and difficult to do since the lines in the view might be clipped if they are occluded by a face.
youen
Posts: 62
Joined: Sun May 19, 2019 7:32 pm

Re: Varying line thickness for different parts in TechDraw

Post by youen »

wandererfan wrote: Thu Oct 06, 2022 1:21 pm Are the "parts"(L00) all in the same View? If so, then there is no easy way for the program to know what lines belong to which part. All the lines from all the source shapes are delivered in one big pile. If they are in different Views, then this is easy.
All the parts are in the same view
wandererfan wrote: Thu Oct 06, 2022 1:21 pm Off the top of my head, the only way to do this would be to take every edge in the source shape, project it onto the paper plane, then try to find a matching projected edge in the View. This would be very slow on a big model, and difficult to do since the lines in the view might be clipped if they are occluded by a face.
Yes, some parts may occlude others, so I'm on the "difficult" side of things ;)

Thanks for your suggesion though! A variant of your technique would be to project the "fat" parts in one view, then project all the parts (thin and fat) in the final view. Then lines of the final view that are contained within a line of the "fat" view (colinear and within the extremities) should be rendered as fat lines. However, this would assume the "depth" of lines is retained in the 2D view (as a Z value?) otherwise this technique could not discriminate between two lines from different parts that end up superposed in the 2D view. Also, while it may be "easy" for straight lines, it becomes more complicated for curves (especially when they are partially occluded).

I also wonder if the feature could be properly (i.e. not like the hack described above) implemented in TechDraw. I guess it's OCCT that performs the projection and hidden line removal? Is there a place in FreeCAD code where it's still possible to know which projected line came from what part, or is it already lost when OCCT gives its result?
User avatar
wandererfan
Veteran
Posts: 6268
Joined: Tue Nov 06, 2012 5:42 pm
Contact:

Re: Varying line thickness for different parts in TechDraw

Post by wandererfan »

youen wrote: Thu Oct 06, 2022 2:33 pm Is there a place in FreeCAD code where it's still possible to know which projected line came from what part, or is it already lost when OCCT gives its result?
The way the code works is shape->OCCT-HLR->unorganized pile of edges.

If shape is a compound of many subshapes, according to the documentation, there might be a way to ask OCCT which edges in the pile came from which subshape. This is a bit of a special case though.
youen
Posts: 62
Joined: Sun May 19, 2019 7:32 pm

Re: Varying line thickness for different parts in TechDraw

Post by youen »

OK, interesting. Sadly, I don't think I'll find the time to look at the code any time soon, but I'll keep that in mind. Thanks for the info!
youen
Posts: 62
Joined: Sun May 19, 2019 7:32 pm

Re: Varying line thickness for different parts in TechDraw

Post by youen »

@wandererfan FYI, I've implemented the technique of matching lines with a drawing of the same part (rendered in a separate view that I delete afterwards). It kind of works, but as expected this is slow. I cache the result of each part rendering in a separate view, but it has to be rendered once for each part for each projection direction. Comparing lines is actually pretty fast, and can be further accelerated by partitioning the space (maybe in Hough space, by direction and distance from origin of each line). Also, curves are not handled by my implementation (yet). While this may be sufficient for my current needs, I'll consider exploring other options (like finding a way to get lines associated to each part from the OCCT projection).

For anyone interested, source code is here: https://gitea.youb.fr/youen/assembly_handbook (work in progress of course). It's an additional workbench, I'll try to make a small tutorial to explain how to use it (it has other features, like creating balloons for each part automatically, updating the arrows when parts are moved, and allowing to select parts to add/remove to the drawing from the 3D view)
step04.png
step04.png (26.53 KiB) Viewed 762 times
youen
Posts: 62
Joined: Sun May 19, 2019 7:32 pm

Re: Varying line thickness for different parts in TechDraw

Post by youen »

A trick that works to some extent to avoid false positive (line detected from a part while it's not) is to not use an exact projection direction. A very small offset from the principal directions or from isometric direction avoids to have perfect match from lines that are at a different depth.

Also, I found no way to project a 3D point to 2D view coordinates. So what I do is I use makeCosmeticVertex3d to create a vertex at the 3D position, and then read back the 2D coordinates of that vertex. However it's an additional performance hit, because it triggers a repaint of the view for each additional vertex created, and also when deleting it.

Another thing I'm not too sure about is how to convert 2D view coordinates to Qt coordinates (I use a custom QGraphicsItem as handle to drag/drop the balloon arrow end). It seems I just need to multiply by the view scale multiplied by 10, is this correct in all cases?

I've also noticed bugs with balloons: when reloading the document, visible balloons are not displayed until I select them. And hidden balloons have the text displayed until I set them hidden again. Not a big problem though.
User avatar
wandererfan
Veteran
Posts: 6268
Joined: Tue Nov 06, 2012 5:42 pm
Contact:

Re: Varying line thickness for different parts in TechDraw

Post by wandererfan »

youen wrote: Wed Oct 19, 2022 9:28 am Also, I found no way to project a 3D point to 2D view coordinates. So what I do is I use makeCosmeticVertex3d to create a vertex at the 3D position, and then read back the 2D coordinates of that vertex.
I've just merged a PR that exposes the C++ method DrawViewPart::projectPoint to Python.

Code: Select all

>>> dvp = App.ActiveDocument.View
>>> vec3d = App.Vector(10.0, 10.0, 10.0)
>>> dvp.projectPoint(vec3d)
Vector (10.0, 10.0, 0.0)
>>> dvp.projectPoint(vec3d, True)
Vector (10.0, -10.0, 0.0)
>>> 
youen wrote: Wed Oct 19, 2022 9:28 am Another thing I'm not too sure about is how to convert 2D view coordinates to Qt coordinates (I use a custom QGraphicsItem as handle to drag/drop the balloon arrow end). It seems I just need to multiply by the view scale multiplied by 10, is this correct in all cases?
If you are working within a View's coordinate system, this will work. If you are moving Views on the page, then you have to worry about +Y being down in Qt (and don't forget clockwise angles!). We deal with this by drawing in the (X, -Y) quadrant and flipping the y coordinate. This is why you'll see various "invert" and "mirror" methods in the code.
youen wrote: Wed Oct 19, 2022 9:28 am I've also noticed bugs with balloons: when reloading the document, visible balloons are not displayed until I select them. And hidden balloons have the text displayed until I set them hidden again. Not a big problem though.
I haven't seen this one. Do you have step by step instructions for me?
youen
Posts: 62
Joined: Sun May 19, 2019 7:32 pm

Re: Varying line thickness for different parts in TechDraw

Post by youen »

wandererfan wrote: Thu Oct 20, 2022 12:13 am I've just merged a PR that exposes the C++ method DrawViewPart::projectPoint to Python.
Great, thanks :-)

wandererfan wrote: Thu Oct 20, 2022 12:13 am If you are working within a View's coordinate system, this will work. If you are moving Views on the page, then you have to worry about +Y being down in Qt (and don't forget clockwise angles!). We deal with this by drawing in the (X, -Y) quadrant and flipping the y coordinate. This is why you'll see various "invert" and "mirror" methods in the code.
OK, good, thanks for the details!

wandererfan wrote: Thu Oct 20, 2022 12:13 am
youen wrote: Wed Oct 19, 2022 9:28 am I've also noticed bugs with balloons: when reloading the document, visible balloons are not displayed until I select them. And hidden balloons have the text displayed until I set them hidden again. Not a big problem though.
I haven't seen this one. Do you have step by step instructions for me?
I've made more tests, and the bugs need two conditions to happen: the view must have KeepUpdated = False, and the bug only happens on my Linux installation. It does not happen on Windows. Of course it may also be related to some settings I've changed, but at least it works on one of my installations.

I've attached the example file. On Linux, I start FreeCAD, open the file, double click on the TechDraw page, click the "Redraw Page" button, and then the cube appears but not the balloon. When I select the balloon in the document tree, it instantly appears on the TechDraw page.

Here are the details on the version I have on Linux :

Code: Select all

OS: Debian GNU/Linux 11 (bullseye) (MATE/lightdm-xsession)
Word size of FreeCAD: 64-bit
Version: 0.20.29177 (Git) AppImage
Build type: Release
Branch: (HEAD detached at 0.20)
Hash: 68e337670e227889217652ddac593c93b5e8dc94
Python 3.9.13, Qt 5.12.9, Coin 4.0.0, Vtk 9.1.0, OCC 7.5.3
Locale: French/France (fr_FR)
Installed mods: 
  * assembly_handbook
  * sheetmetal 0.2.56
  * fasteners 0.4.3
  * Assembly4 0.12.3
Attachments
test.FCStd
(17.97 KiB) Downloaded 7 times
User avatar
wandererfan
Veteran
Posts: 6268
Joined: Tue Nov 06, 2012 5:42 pm
Contact:

Re: Varying line thickness for different parts in TechDraw

Post by wandererfan »

youen wrote: Thu Oct 20, 2022 7:41 am I've made more tests, and the bugs need two conditions to happen: the view must have KeepUpdated = False, and the bug only happens on my Linux installation.
If KeepUpdated on the Page is False, then the expected behaviour on load is that Views will not be drawn and only the frame will appear. If the frames are toggled off, then you won't see anything other than the template.
When I select the balloon in the document tree, it instantly appears on the TechDraw page.
I don't get this behaviour, but maybe I didn't follow instructions correctly. It could be that selecting the Balloon triggers a recompute which triggers a redraw.
Post Reply