[solved] Part WB "Failed to create loft face"

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
jsusarean
Posts: 11
Joined: Thu Nov 12, 2020 4:22 pm

[solved] Part WB "Failed to create loft face"

Post by jsusarean »

Hello. I've done my best looking for a solution for this error in the forum. Although there are similar issues, I have not found a solution for this apparently common lofting case. I didn't have in previously released 0.2 beta version.

Version

Code: Select all

OS: Windows 10 (10.0)
Word size of FreeCAD: 64-bit
Version: 0.20.29126 (Git)
Build type: Release
Branch: master
Hash: 6c1c63cffebe6a9d55bd9b1d8ca6b741a4d16548
Python 3.8.13, Qt 5.12.9, Coin 4.0.0, Vtk 9.1.0, OCC 7.5.3
Locale: Spanish/Spain (es_ES)
Installed mods: 
  * BIM 2021.12.0
  * dodo
  * fcgear 1.0.0
  * P3System
  * Render 2022.2.0
THE PROBLEM

Below macro creates two lofts. Both are made in the same way, using two triangle wires as Sections. The difference is that in the FirstLoft, two edges of the triangles are coincidental, while in the SecondLoft both triangle wires are apart from each other. FirstLoft returns "Recompute failed! Please check report view" log, showing "Failed to create loft face" comment when hovering over the objet's icon.

Code: Select all

import FreeCAD as App
import Draft

doc = FreeCAD.ActiveDocument

# First loft try. Returns "Recompute failed! Please check report view." --> Failed to create loft face
p11 = App.Vector(0, 0, 0)
p12 = App.Vector(1000, 0, 0)
p13 = App.Vector(0, 1000, 0)
p14 =  App.Vector(0, 0, 1000)

wire11 = Draft.make_wire([p11, p12, p14], closed=True)
wire12 = Draft.make_wire([p11, p13, p14], closed=True)

loft = doc.addObject('Part::Loft', 'FirstLoft')
loft.Sections = [wire11, wire12]
loft.Solid = True

# Second loft try. No error.
p21 = App.Vector(2000, 0, 0)
p22 = App.Vector(3000, 0, 0)
p23= App.Vector(2000, 0, 1000)

p24 = App.Vector(2000, 50, 0)
p25 = App.Vector(2000, 1000, 0)
p26 =  App.Vector(2000, 50, 1000)

wire21 = Draft.make_wire([p21, p22, p23], closed=True)
wire22 = Draft.make_wire([p24, p25, p26], closed=True)

loft = doc.addObject('Part::Loft', 'SecondLoft')
loft.Sections = [wire21, wire22]
loft.Solid = True

doc.recompute()
Could somebody help me with this?

Thanks!
Last edited by jsusarean on Sun Jul 31, 2022 9:19 am, edited 1 time in total.
User avatar
onekk
Veteran
Posts: 6222
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Part WB "Failed to create loft face"

Post by onekk »

Probably loft is not working if an edge is coincident, as it could not create faces from coincident wires.

Or the order of faces is different and loft should twist faces and the operation fail.

Let me try the code when I will have a computer. (I'm on mobile).

Try in the meanwhile to check the wiki page of Loft and see "technical consideration" or similar description. that is linked on the page.

There are some technical explanation about how to check when doing a loft.

Regards.

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
jsusarean
Posts: 11
Joined: Thu Nov 12, 2020 4:22 pm

Re: Part WB "Failed to create loft face"

Post by jsusarean »

Thanks Carlo!

As you suggest, I've cheked the wiki (https://wiki.freecadweb.org/Part_Loft_Technical_Details) and in the additional remarks it says:
"For Loft, it is not required that the profiles are separated (see a picture below). They can be coplanar, but they should not intersect."

I understand there is no intersection. Could it be related to the precision of the document's units?

Regards.

Jon.
User avatar
onekk
Veteran
Posts: 6222
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Part WB "Failed to create loft face"

Post by onekk »

Coplanar is different from intersecting.

I think that there is an angle between faces it is considered an intersection.

When Lofting you have to create planes between profiles and this "plane creation" could have problem.

Later this day I could gave an eye to the code and try to find a way, probably loft is not right tool
Have you tought to investigate if using "ruled surfaces" will made an acceptable solid for you?

DONE: see post below

Regards.

Carlo D.
Last edited by onekk on Fri Jul 29, 2022 9:38 am, edited 2 times in total.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
User avatar
onekk
Veteran
Posts: 6222
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Part WB "Failed to create loft face"

Post by onekk »

jsusarean wrote: Fri Jul 29, 2022 6:24 am ...

I found a solution, using topology, as you have common edges:
20220729-loft_coinc.py
(3.98 KiB) Downloaded 25 times
The point is to use the BREP paaradigm, although many thinks wrong that part is only CSG (see Wikipedia for difference between them), Part WB have all the machinery to make BREP surfaces.

Following topology:
  • A wire is made of egdes
  • A face is made "filling" closed wires
  • A shell is made of faces
  • A solid is a "portion of 3d space" include in a closed shell, read may "watertight" or "manifold" as terminology is shared between meshed sometimes
So you have already two wires, not difficult to obtain, using "only" Part WB:

Code: Select all

wire11 = Part.makePolygon([p11, p12, p14, p11])
# Part.show(wire11, "wire11")

wire12 = Part.makePolygon([p11, p13, p14, p11])
# Part.show(wire12, "wire12")
Not too difficult, note the repetition of the starting point to obtain a closed polygon

To obtain faces is not very difficult:

Code: Select all

face11 = Part.Face(wire11)
face12 = Part.Face(wire12)

Now you have to create the two "missing" faces, so following again topology:

Code: Select all

edge11 = Part.LineSegment(p11, p12).toShape()
edge12 = Part.LineSegment(p11, p13).toShape()
edge13 = Part.LineSegment(p13, p12).toShape()

surf1 = Part.makeFilledFace([edge11, edge12,edge13])
# Part.show(surf1, "surface1")


This will supply a list of edges and if they are closed the method Part.makeFilledFace will do the job.


Same for the other face.

Now the Shell and the solid:

Code: Select all

shell1 = Part.Shell([face11, face12, surf1, surf2])
Part.show(shell1, "shell1")

solid1 = Part.Solid(shell1)
Part.show(solid1, "solid1")
Not very difficult, and usually it works, but if you create some "non closed", "non manifold" or "non watertight" shells, the solid could not be created.

The code is left as an educational code, as it shows a couple of techniques to make faces, you could have created all the edges and compose individually faces using Part.makeFilledFace as example, or used the Part.makePolygon and then transform the wire in a Face.

You could use:

Code: Select all

help(Part.makePolygon)
to obtain info about methods in the "python Console" fairly easily, probably doing:

Code: Select all

import Part
could solve some problems that may arise as not everytime Part is imported in FC explicitly.

Code is more verbose as it uses some "helper methods" to make thing easier, as at every run it "empty the document" and fill it with new objects.

Plus some imports in the code:

Code: Select all

from FreeCAD import Placement, Rotation, Vector # noqa
Will explicitly expose many construct that will short writing.

note that:

Code: Select all

Part.LineSegment(p11, p12).toShape()
could create some conceptual problems, if you have not cacth the inner working of FC:

Code: Select all

Part.LineSegment(p11, p12)
Alone will return a "Curve" i.e a "Geometry object" that have not a Shape so the .toShape() to obtain a Shape that could be used as an Edge


more on:

Document Objects
https://wiki.freecadweb.org/App_DocumentObject

TopoShapes
https://wiki.freecadweb.org/Part_TopoShape

Some geometry and topology consideration (with some code):
https://forum.freecadweb.org/viewtopic. ... 55#p484455
https://forum.freecadweb.org/viewtopic. ... 89#p500989
https://forum.freecadweb.org/viewtopic. ... 11#p463511

Tested on:

Code: Select all

OS: Artix Linux (openbox)
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: Italian/Italy (it_IT)
Installed mods: 
  * Curves 0.5.2

Hope it helps

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
jsusarean
Posts: 11
Joined: Thu Nov 12, 2020 4:22 pm

Re: Part WB "Failed to create loft face"

Post by jsusarean »

Hi Carlo! Thanks for the suggested solution. It has helped me to approach the problem from a different point of view and it has worked. Also thanks for the educational tips.

Regards.

Jon.
User avatar
onekk
Veteran
Posts: 6222
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Part WB "Failed to create loft face"

Post by onekk »

jsusarean wrote: Sun Jul 31, 2022 9:19 am Hi Carlo! Thanks for the suggested solution. It has helped me to approach the problem from a different point of view and it has worked. Also thanks for the educational tips.

Regards.

Jon.
You are welcome, if I could be useful to other users, it's my delight (probably a wrong translation of a phrase taken from "Seven Pillars of Wisdom").

They are note very "educational", as my explanations are not very good, but are the sum of many things I've learned.

Despite my tone, I'm still learning as you could see from:

https://forum.freecadweb.org/viewtopic.php?f=22&t=70530

So don't discourage, and "keep scripting" it is a good way to discover "internals of FC", and also some "internals of OCCT" (That is very near to Part WB, as Part is the more "direct" interface to OCCT).

Scripting using Part will permit you to make many things in a more quick way that fiddling with interface. (Not 100% true, as you have to learn how to do something) and permit to reuse many code portions.

To be more educational, I have some other advices (sorry for bothering!)

From my code you could have seen my "infrastructure" that is the portion of code till "CODE STARTS HERE" if you like you could reuse it as a "HEADER" for your code as it permits to:

1) Make a new document (there is a field on which you can enter a name) if there is nothing opened
2) Reuse an existing document with same name when you relaunch the script (deleting all the object from the "old run")
3) Make coding more compact as it import Vector, Placement and Rotation to be accessed without prepending FreeCAD to them (I don't like App as it is an alias for FreeCAD, but it is clearly only a matter of taste
4) Some other things like EPS and EPS_C that are useful when you have to make fusions or other things to have some "overlapping solids that fuse in a better ways as having coplanar faces, not everytime result in a clean fusion", so the trick is as example make a cylinder 1 * EPS more long and position it EPS *-1 lower than the upper face where it will go, (EPS is usually very small 0.01 or even less). But this is also a personal habits.

During time I have keep an "arsenal" of Python methods that I could reuse when coding, so it is easy to make even a complex model, if you have right methods noted somewhere.

One more thing is the fact that a script could be relaunched and produce a very complex design that could be maybe some MB with a 4 or 5 KB script, so even for archive purpose, if you don't want to keep several MB used only for archive purpose (as FCStd file is a Zipped file, reZipping will not lead to a much lower disk occupation) you could simply keep the scripts and delete the FCStd files, It is very handy as example if you want to make STL files that if are detailed will occupy several MB even for simple pieces.

Hope it helps.

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
Post Reply