[FIXED] Ticket #6407 - python API access to 2d fillet OCC functionality

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
User avatar
looo
Veteran
Posts: 3941
Joined: Mon Nov 11, 2013 5:29 pm

[FIXED] Ticket #6407 - python API access to 2d fillet OCC functionality

Post by looo »

Opencascade provides the algorythm ChFi2d_FilletAlgo which allows to create 2d fillets between two wires with numerical methods. Do we have access to this functionality from python? If not would it make sense to add it to the Part module?
Last edited by Kunda1 on Sat May 28, 2022 11:30 am, edited 2 times in total.
Reason: Solved by wmayer
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: 2d fillet

Post by DeepSOIC »

looo wrote: Tue Aug 18, 2020 7:10 pm If not would it make sense to add it to the Part module?
YES, absolutely!
User avatar
looo
Veteran
Posts: 3941
Joined: Mon Nov 11, 2013 5:29 pm

Re: 2d fillet

Post by looo »

DeepSOIC wrote: Tue Aug 18, 2020 7:53 pm YES, absolutely!
And who wants to do it?

With pythonocc it's possible to use this functionality, but not sure how to retrieve the resulting arc...

Code: Select all

radius = 1
from OCC import Core
api = Core.ChFi2d.ChFi2d_FilletAPI()
# w = ... wire in xy-plane
w_1 = Part.__toPythonOCC__(w)
w_2 = Core.TopoDS.topods_Wire(w_1)
pln = Core.gp.gp_Pln(Core.gp.gp_Pnt(0, 0, 0), Core.gp.gp_Dir(0, 0, 1))
api.Init(w_2, pln)
api.Perform(radius)
api.Result(????)
User avatar
Gift
Posts: 769
Joined: Tue Aug 18, 2015 10:08 am
Location: Germany, Sauerland

Re: 2d fillet

Post by Gift »

OCC is not part of condo.dmg (OS X). :( Did you see this example?
User avatar
looo
Veteran
Posts: 3941
Joined: Mon Nov 11, 2013 5:29 pm

Re: 2d fillet

Post by looo »

Gift wrote: Thu Aug 20, 2020 3:47 pm OCC is not part of condo.dmg (OS X). :( Did you see this example?
thx. that is what I needed.

regarding python-occ for osx: I will work on this in the next weeks.
User avatar
looo
Veteran
Posts: 3941
Joined: Mon Nov 11, 2013 5:29 pm

Re: 2d fillet

Post by looo »

The example uses the analytic algorithm which doesn't work for all edges. As far as I understand the numeric method should also work on more complex edges like bsplines. So here is a working example. But I am not yet sure why the point is needed for the result.

Code: Select all

import numpy as np
import FreeCAD as App
import Part
from OCC.Core import ChFi2d
from OCC import Core

api = ChFi2d.ChFi2d_FilletAPI()


def pyocc_2d_fillet(e1, e2):
    # asuming edges are in a plane
    # extracting vertices
    p1 = np.array([*e1.valueAt(e1.FirstParameter)])
    p2 = np.array([*e1.valueAt(e1.LastParameter)])
    p3 = np.array([*e2.valueAt(e2.FirstParameter)])
    p4 = np.array([*e2.valueAt(e2.LastParameter)])
    t1 = p2 - p1
    t2 = p4 - p3
    n = np.cross(t1, t2)
    pln = Core.gp.gp_Pln(Core.gp.gp_Pnt(*p1), Core.gp.gp_Dir(*n))
    occ_e1 = Core.TopoDS.topods_Edge(Part.__toPythonOCC__(e1))
    occ_e2 = Core.TopoDS.topods_Edge(Part.__toPythonOCC__(e2))
    api.Init(occ_e1, occ_e2, pln)
    api.Perform(radius)
    occ_p0 = Core.gp.gp_Pnt(0,0,0)
    occ_arc = api.Result(occ_p0, occ_e1, occ_e2)
    return Part.Wire([Part.__fromPythonOCC__(occ_e1),
                      Part.__fromPythonOCC__(occ_arc),
                      Part.__fromPythonOCC__(occ_e2)])


def test():
    App.newDocument()
    radius = 0.1
    p0 = App.Vector(0,0,0)
    p1 = App.Vector(1,0,0)
    p2 = App.Vector(0,1,0)
    e1 = Part.LineSegment(p1, p0).toShape()
    e2 = Part.LineSegment(p0, p2).toShape()
    Part.show(e1)
    Part.show(e2)
    Part.show(pyocc_2d_fillet(e1, e2))

test()

Last edited by looo on Fri Aug 21, 2020 8:57 am, edited 1 time in total.
User avatar
Chris_G
Veteran
Posts: 2601
Joined: Tue Dec 31, 2013 4:10 pm
Location: France
Contact:

Re: 2d fillet

Post by Chris_G »

looo wrote: Fri Aug 21, 2020 7:38 am But I am not yet sure why the point is needed for the result.
It seems to be needed for choosing a solution, in case of multiple solutions :
https://www.opencascade.com/doc/occt-7. ... 3fd2e88967
User avatar
looo
Veteran
Posts: 3941
Joined: Mon Nov 11, 2013 5:29 pm

Re: 2d fillet

Post by looo »

Chris_G wrote: Fri Aug 21, 2020 8:40 am
looo wrote: Fri Aug 21, 2020 7:38 am But I am not yet sure why the point is needed for the result.
It seems to be needed for choosing a solution, in case of multiple solutions :
https://www.opencascade.com/doc/occt-7. ... 3fd2e88967
But what is the point reffering to. Is it the center of the arc?

Also pythonocc-core is already available from conda-forge. But I am not sure if we should include it in the bundle. I guess this will add another ~100mb...
User avatar
Gift
Posts: 769
Joined: Tue Aug 18, 2015 10:08 am
Location: Germany, Sauerland

Re: 2d fillet

Post by Gift »

looo wrote: Fri Aug 21, 2020 8:59 am
Chris_G wrote: Fri Aug 21, 2020 8:40 am
looo wrote: Fri Aug 21, 2020 7:38 am But I am not yet sure why the point is needed for the result.
It seems to be needed for choosing a solution, in case of multiple solutions :
https://www.opencascade.com/doc/occt-7. ... 3fd2e88967
But what is the point reffering to. Is it the center of the arc?

Also pythonocc-core is already available from conda-forge. But I am not sure if we should include it in the bundle. I guess this will add another ~100mb...
In your example is small mistake. The method pyocc_2d_fillet(e1, e2, r) missing the last parameter. In my testing the coords of occ_p0 has never changed. Maybe is really need complex example (e.g. 2x arcs) with two connection points.

Thx, pythonocc-core works fine. I think to add it in the bundle need other topic in the discussion forum.

Code: Select all

import numpy as np
import FreeCAD as App
import Part
from OCC.Core import ChFi2d
from OCC import Core

api = ChFi2d.ChFi2d_FilletAPI()

npt = None

def pyocc_2d_fillet(e1, e2, r):
    # asuming edges are in a plane
    # extracting vertices
    p1 = np.array([*e1.valueAt(e1.FirstParameter)])
    p2 = np.array([*e1.valueAt(e1.LastParameter)])
    p3 = np.array([*e2.valueAt(e2.FirstParameter)])
    p4 = np.array([*e2.valueAt(e2.LastParameter)])
    t1 = p2 - p1
    t2 = p4 - p3
    n = np.cross(t1, t2)
    pln = Core.gp.gp_Pln(Core.gp.gp_Pnt(*p1), Core.gp.gp_Dir(*n))
    occ_e1 = Core.TopoDS.topods_Edge(Part.__toPythonOCC__(e1))
    occ_e2 = Core.TopoDS.topods_Edge(Part.__toPythonOCC__(e2))
    api.Init(occ_e1, occ_e2, pln)
    if api.Perform(r) > 0:
    	occ_p0 = Core.gp.gp_Pnt(0,0,0)
    	occ_arc = api.Result(occ_p0, occ_e1, occ_e2)
    	global npt
    	npt = occ_p0
    	return Part.Wire([Part.__fromPythonOCC__(occ_e1),
                      Part.__fromPythonOCC__(occ_arc),
                      Part.__fromPythonOCC__(occ_e2)])
    else:
    	return Part.Shape

def test():
    App.newDocument()
    radius = 0.1
    p0 = App.Vector(1,0,0)
    p1 = App.Vector(2,0.5,0)
    p2 = App.Vector(1,1,0)
    p3 = App.Vector(1,0,0)
    e1 = Part.LineSegment(p1, p0).toShape()
    e2 = Part.LineSegment(p3, p2).toShape()
    Part.show(e1)
    Part.show(e2)
    Part.show(pyocc_2d_fillet(e1, e2, radius))

test()
FreeCAD.Console.PrintMessage(npt.Coord())
User avatar
looo
Veteran
Posts: 3941
Joined: Mon Nov 11, 2013 5:29 pm

Re: 2d fillet

Post by looo »

Gift wrote: Fri Aug 21, 2020 3:34 pm In your example is small mistake. The method pyocc_2d_fillet(e1, e2, r) missing the last parameter. In my testing the coords of occ_p0 has never changed. Maybe is really need complex example (e.g. 2x arcs) with two connection points.
Ah I see, thanks for fixing this.
Gift wrote: Fri Aug 21, 2020 3:34 pm Thx, pythonocc-core works fine. I think to add it in the bundle need other topic in the discussion forum.
I have included it now. In my eyes it's good if people can have direct access to occ from python. This will further help to gather knowledge about occ. For example the minimal bounding box algorythm you found here: https://forum.freecadweb.org/viewtopic. ... 08#p425370

I tried to implement something like this for the unwrapping algorythm some time ago: https://github.com/FreeCAD/FreeCAD/blob ... x.cpp#L642 Actually this never worked properly so it is not used at all, but with the possibility to do this with occ it shouldn't be a big problem to align the patterns and later nest the bounding boxes...
Post Reply