Path.Area: Welcome, to the new era!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Be nice to others! Respect the FreeCAD code of conduct!
- sliptonic
- Veteran
- Posts: 3459
- Joined: Tue Oct 25, 2011 10:46 pm
- Location: Columbia, Missouri
- Contact:
Re: Path.Area: Welcome, to the new era!
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.
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.
-
- Veteran
- Posts: 2190
- Joined: Tue Jan 03, 2017 10:55 am
Re: Path.Area: Welcome, to the new era!
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.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.
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()
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.
Re: Path.Area: Welcome, to the new era!
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.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).
A Sketcher Lecture with in-depth information is available in English, auf Deutsch, en français, en español.
- sliptonic
- Veteran
- Posts: 3459
- Joined: Tue Oct 25, 2011 10:46 pm
- Location: Columbia, Missouri
- Contact:
Re: Path.Area: Welcome, to the new era!
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.realthunder wrote: Path.Area can effectively replace all current python code using libarea, quite trivially actually.
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)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 command gives me an error that Operation is an invalid keyword. Did you mean Offset=1?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()
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.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.
- Attachments
-
- turnedpart.fcstd
- (63.71 KiB) Downloaded 39 times
-
- Veteran
- Posts: 2190
- Joined: Tue Jan 03, 2017 10:55 am
Re: Path.Area: Welcome, to the new era!
That's fine. Just send me the model when you got any problem. I'll post the code.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 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,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.
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())
Oops, should be more careful. It should besliptonic wrote:That command gives me an error that Operation is an invalid keyword. Did you mean Offset=1?
Code: Select all
section = Path.Area(PocketMode=1,SectionCount=1).add([Workpiece.Shape, myObj.Shape],op=1).getShape()
- sliptonic
- Veteran
- Posts: 3459
- Joined: Tue Oct 25, 2011 10:46 pm
- Location: Columbia, Missouri
- Contact:
Re: Path.Area: Welcome, to the new era!
Thanks! I'll take you up on that.realthunder wrote: That's fine. Just send me the model when you got any problem. I'll post the code.
No. I'm using the latest master. So it's your latest which has been merged. I can try rebasing from your branch.That's strange. Are you using my latest PathArea branch?
Awesome!Stay tuned. There is a dramatic performance improvement on wire sorting, which is achieved by using boost::geometry::rtree spatial index.
-
- Veteran
- Posts: 2190
- Joined: Tue Jan 03, 2017 10:55 am
Re: Path.Area: Welcome, to the new era!
Please try my PathArea branch at github first. I haven't submit it as PR yet.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.
- sliptonic
- Veteran
- Posts: 3459
- Joined: Tue Oct 25, 2011 10:46 pm
- Location: Columbia, Missouri
- Contact:
Re: Path.Area: Welcome, to the new era!
Yes! Much improved.realthunder wrote:Please try my PathArea branch at github first. I haven't submit it as PR yet.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.
- sliptonic
- Veteran
- Posts: 3459
- Joined: Tue Oct 25, 2011 10:46 pm
- Location: Columbia, Missouri
- Contact:
Re: Path.Area: Welcome, to the new era!
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?
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
-
- Veteran
- Posts: 2190
- Joined: Tue Jan 03, 2017 10:55 am
Re: Path.Area: Welcome, to the new era!
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.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?
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())