Path.Area: Welcome, to the new era!

Here's the place for discussion related to CAM/CNC and the development of the Path module.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
User avatar
sliptonic
Veteran
Posts: 3457
Joined: Tue Oct 25, 2011 10:46 pm
Location: Columbia, Missouri
Contact:

Re: Path.Area: Welcome, to the new era!

Post by sliptonic »

I'm still getting my head around this new PathArea tool. I'm still not there yet but I'm starting to understand Realthunder's way of thinking. There are definitely some interesting possibilities here.

One thing that I'm wondering about though is this:

In the old way, we basically figured out some collection of wires to represent a shape. The collection might be nested to represent islands, but it was a 2D representation. Then we called libarea to calculate a profile or pocket by offsetting those wires in or out. We then converted the result to path commands and duplicated it for each step-down value. The last part is important because the step downs might represent 90% of the path but they're just cheap copies.

This works fine for 2.5D objects and it's very fast but it obviously has serious limitations for more complex shapes (things with sloped walls for instance).

In the examples Realthunder showed, the 3D shape is sectioned for each step-down. Each of those shapes is then fed to libarea and offset separately. The resulting wires are then converted to commands.

Without actually benchmarking it, I think the new is faster at offsetting a single section because everything is in c++. However, it calls libarea many many more times depending on the number of sections and these are pretty expensive operations.. What comes back is much more useful -- We can do things like sloped walls -- but the user might wait.....a long time.

For 2.5D stuff, full-step sectioning doesn't make sense. Every step down is identical. The trick is figuring out when to do a single section and copy the result going down and when to actually section at each step. One option is to have different kinds of operations or have a setting that the user chooses but I would prefer for the system to be smart enough to know when it needs to do full-section.
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: Path.Area: Welcome, to the new era!

Post by realthunder »

sliptonic wrote:Without actually benchmarking it, I think the new is faster at offsetting a single section because everything is in c++. However, it calls libarea many many more times depending on the number of sections and these are pretty expensive operations.. What comes back is much more useful -- We can do things like sloped walls -- but the user might wait.....a long time.
Path.Area can effectively replace all current python code using libarea, quite trivially actually. For the section thing you mentioned, you simply need to do one section only and getShape(), duplicate the wires and stepdown like the old way. You can, of course, manually add face to Area and do pocketing and profiling without section at all, But it is just easier to work with solid directly with the one section technique. No need for face selection in most cases, since Path.Area defaults to use top Z face if there is one. It also comes in handy when you need some boolean operation, like use a work piece and cut it with your object to get the pocket shape. Simply add two objects, set operation to 'difference', set SectouCount=1, getShape and call it a day.

In fact, most of the lengthy libarea python code can be replaced by simple one liners. For example, one section cut and pocket,

Code: Select all

section = Path.Area(Operation=1,PocketMode=1,SectionCount=1).add([Workpiece.Shape, myObj.Shape]).getShape()
I made Path.Area python code this way so that you don't really need to keep a Path.Area object around, just use it it in transit, like a toolbox. You'll need some more code to catch possible errors of course.

You are right, sectioning is potentially expensive, and really not necessary for many 2.5D objects. But it is crucial for other use cases, such as 3D printing. I am actually thinking of adding parallel support for sectioning, although that may have to wait for while.
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
chrisb
Veteran
Posts: 53941
Joined: Tue Mar 17, 2015 9:14 am

Re: Path.Area: Welcome, to the new era!

Post by chrisb »

sliptonic wrote:In the old way, we basically figured out some collection of wires to represent a shape. The collection might be nested to represent islands, but it was a 2D representation. Then we called libarea to calculate a profile or pocket by offsetting those wires in or out. We then converted the result to path commands and duplicated it for each step-down value. The last part is important because the step downs might represent 90% of the path but they're just cheap copies.

This works fine for 2.5D objects and it's very fast but it obviously has serious limitations for more complex shapes (things with sloped walls for instance).
I think these could well be different operations, like pad/pocket are different from lofts. The question to me is if the user should be left alone with this decision or if it could be at least verified that the wall might be sloped with a possible warning. I am pretty sure that it is very hard to check the slope in all possible cases. As soon as lofts are involved FreeCAD cannot recognize them as plane even if they are.
A Sketcher Lecture with in-depth information is available in English, auf Deutsch, en français, en español.
User avatar
sliptonic
Veteran
Posts: 3457
Joined: Tue Oct 25, 2011 10:46 pm
Location: Columbia, Missouri
Contact:

Re: Path.Area: Welcome, to the new era!

Post by sliptonic »

realthunder wrote: Path.Area can effectively replace all current python code using libarea, quite trivially actually.
I hope that's true. My first priority is to eliminate as much of the old Heeks PathKurveUtils stuff as I can. But I'm skeptical. That Python code accumulated over the years to deal with a lot of border cases. The only way to know is to try.
For the section thing you mentioned, you simply need to do one section only and getShape(), duplicate the wires and stepdown like the old way.
That's what I was assuming and what I'm working at now. But I'm having a hard time getting consistent results. There are many settings and options to explore and it's not clear what they all do. Trying to play with it with FeatureArea doesn't really help since when problems happen, I don't know if it's FeatureArea or the underlying Path.Area. Here's an example. I drew this sketch on XZ plane and revolved it. I want to generate a section at an arbitrary height along Z axis. No matter what I select for workplane, it always sections on the XZ plane and not the XY. (file attached)
snapshot-11.png
snapshot-11.png (59.22 KiB) Viewed 2357 times
In fact, most of the lengthy libarea python code can be replaced by simple one liners. For example, one section cut and pocket,

Code: Select all

section = Path.Area(Operation=1,PocketMode=1,SectionCount=1).add([Workpiece.Shape, myObj.Shape]).getShape()
That command gives me an error that Operation is an invalid keyword. Did you mean Offset=1?
You are right, sectioning is potentially expensive, and really not necessary for many 2.5D objects. But it is crucial for other use cases, such as 3D printing. I am actually thinking of adding parallel support for sectioning, although that may have to wait for while.
Agreed. My question here was really about how to determine whether or not section is needed. I think chrisb is right and we'll need to leave it to the user to decide for now by having different operation types.
Attachments
turnedpart.fcstd
(63.71 KiB) Downloaded 39 times
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: Path.Area: Welcome, to the new era!

Post by realthunder »

sliptonic wrote:There are many settings and options to explore and it's not clear what they all do. Trying to play with it with FeatureArea doesn't really help since when problems happen, I don't know if it's FeatureArea or the underlying Path.Area
That's fine. Just send me the model when you got any problem. I'll post the code.
sliptonic wrote:Here's an example. I drew this sketch on XZ plane and revolved it. I want to generate a section at an arbitrary height along Z axis. No matter what I select for workplane, it always sections on the XZ plane and not the XY.
That's strange. Are you using my latest PathArea branch? Because, when I tried, there is no need to select workplane at all. Just create a FeatureArea, and you got the top Z face. Like I said, Area uses top Z face as default work plane if there is one. Set SectionCount=1, and SectionOffset to some thing, you'll get what you want. Or use the following code,

Code: Select all

section = Path.Area(SectionCount=1,SectionOffset=5.0).add(App.ActiveDocument.Revolution.Shape).getShape()
Part.show(section)
# if you want offset
Part.show(Path.Area(Offset=1.0).add(section).getShape())
# pocket?
Part.show(Path.Area(PocketMode=1).add(section).getShape())
If you are using the latest branch, and the above code is not working. Then maybe I've introduced some new bugs, but have already been fixed in my local branch. I'll push some commits soon. Stay tuned. There is a dramatic performance improvement on wire sorting, which is achieved by using boost::geometry::rtree spatial index.
sliptonic wrote:That command gives me an error that Operation is an invalid keyword. Did you mean Offset=1?
Oops, should be more careful. It should be

Code: Select all

section = Path.Area(PocketMode=1,SectionCount=1).add([Workpiece.Shape, myObj.Shape],op=1).getShape()
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
User avatar
sliptonic
Veteran
Posts: 3457
Joined: Tue Oct 25, 2011 10:46 pm
Location: Columbia, Missouri
Contact:

Re: Path.Area: Welcome, to the new era!

Post by sliptonic »

realthunder wrote: That's fine. Just send me the model when you got any problem. I'll post the code.
Thanks! I'll take you up on that.
That's strange. Are you using my latest PathArea branch?
No. I'm using the latest master. So it's your latest which has been merged. I can try rebasing from your branch.
Stay tuned. There is a dramatic performance improvement on wire sorting, which is achieved by using boost::geometry::rtree spatial index.
Awesome!
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: Path.Area: Welcome, to the new era!

Post by realthunder »

sliptonic wrote:No. I'm using the latest master. So it's your latest which has been merged. I can try rebasing from your branch.
Please try my PathArea branch at github first. I haven't submit it as PR yet.
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
User avatar
sliptonic
Veteran
Posts: 3457
Joined: Tue Oct 25, 2011 10:46 pm
Location: Columbia, Missouri
Contact:

Re: Path.Area: Welcome, to the new era!

Post by sliptonic »

realthunder wrote:
sliptonic wrote:No. I'm using the latest master. So it's your latest which has been merged. I can try rebasing from your branch.
Please try my PathArea branch at github first. I haven't submit it as PR yet.
Yes! Much improved.
User avatar
sliptonic
Veteran
Posts: 3457
Joined: Tue Oct 25, 2011 10:46 pm
Location: Columbia, Missouri
Contact:

Re: Path.Area: Welcome, to the new era!

Post by sliptonic »

I've attached a file with my chess pawn part.

I select the pawn and run this macro. It gets the 2D projection and then builds the step-downs for a 2.5D contour. While the shapes are all at the correct heights, the path calculated from the list of shapes has all moves at z=0. Do I need to add the vertical feed moves down between steps?


Code: Select all

snippet = '''
import Path
import TechDraw
import DraftGeomUtils as dgu
import PathScripts.PathUtils as PU

sel = Gui.Selection.getSelectionEx()[0]
obj = sel.Object
h = obj.Shape.BoundBox.ZLength

shadow = TechDraw.findShapeOutline(obj.Shape, 1, FreeCAD.Vector(0,0,1))
e = Part.__sortEdges__(shadow.Edges)
c = Part.Wire(e)
f = Part.makeFace([c], 'Part::FaceMakerSimple')
#s = f.extrude(FreeCAD.Vector(0,0,h))

#Part.show(s)

d = PU.depth_params(clearance_height = 5.0, rapid_safety_space = 3.0, start_depth =h, step_down=1.0,z_finish_step=0.0,final_depth=0.0)

profile = Path.Area(Offset=0.15,SectionCount=1)
profile.setPlane(Part.makeCircle(10))
profile.add(f)
#profile.setPlane(s)

#profile.makeSections(heights=d.get_depths())
#profile.makeSections()
#Part.show(profile.getShape())

lshapes = [profile.getShape()]
for l in d.get_depths():
	c = lshapes[0].copy()
	c.Placement.Base.z = l
	Part.show(c)
	lshapes.append(c)

pp = Path.fromShapes(lshapes, start=FreeCAD.Vector(0,0,0))
Path.show(pp)
#print profile.Workplane
for c in pp.Commands:
	print c
'''
FreeCADGui.doCommand(snippet)

Attachments
lathepart1.fcstd
(110.52 KiB) Downloaded 42 times
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: Path.Area: Welcome, to the new era!

Post by realthunder »

sliptonic wrote:I've attached a file with my chess pawn part.

I select the pawn and run this macro. It gets the 2D projection and then builds the step-downs for a 2.5D contour. While the shapes are all at the correct heights, the path calculated from the list of shapes has all moves at z=0. Do I need to add the vertical feed moves down between steps?
You code works without modification with my latest PathArea branch. Please sync it. You may have some problem pulling, because I rebase the branch with upstream master and force update it. If you have any error, just checkout a fresh copy. I have submit the PR already, it should be in the master soon.

By the way, in your code. If you are adding a face, there is really no need to use section. It's only for solid. You can do away with TechDraw, and simply use Area to makeSection at absolute position

Code: Select all

shape=App.ActiveDocument.Revolution.Shape

# no need to setPlane if all planar faces are parallel to your desired work plane

# makeSection with absolute height
sections=Path.Area().add(shape).makeSections(mode=0,heights=[0.0])

# get the section with offset. You can of course set the offset when creating the first area. This just shows another alternative.
Part.show(sections[0].setParams(Offset=0.15).getShape())
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
Post Reply