View Issue Details

IDProjectCategoryView StatusLast Update
0002786PathBugpublic2018-01-12 22:53
Reportersliptonic Assigned Toyorik  
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionwon't fix 
PlatformallOSallOS Versionall
Product Version0.17 
Target Version0.17 
Summary0002786: Path.fromShape() doesn't produce correct path
DescriptionPath.fromShape() takes a wire and should produce a path directly from the edges. However the resulting path does not meet expectations.

Steps To Reproducetest macro:

import Part
import Path

FreeCAD.ActiveDocument.addObject("Part::Box","Box")
FreeCAD.ActiveDocument.ActiveObject.Label = "Cube"
FreeCAD.ActiveDocument.getObject("Box").Length = '100 mm'
FreeCAD.ActiveDocument.getObject("Box").Width = '100 mm'

#top face
face = getattr(FreeCAD.ActiveDocument.Box.Shape, "Face6")

mywire = face.OuterWire
print("unsorted edges")
for e in mywire.Edges:
    print (e.Vertexes[0].X, e.Vertexes[0].Y,  ":",  e.Vertexes[1].X, e.Vertexes[1].Y)

#mywire = Part.Wire(Part.__sortEdges__(mywire.Edges))
#print ("sorted edges")
#for e in mywire.Edges:
#    print (e.Vertexes[0].X, e.Vertexes[0].Y,  ":",  e.Vertexes[1].X, e.Vertexes[1].Y)

thepath = Path.fromShape(mywire)
Path.show(thepath)
Part.show(mywire)
print(thepath.toGCode())
Additional InformationThe edges in the wires unsorted are in a reasonable order but are not correctly oriented start to finish. Given the unsorted output below, here's the expected output (with explanation) and the actual output.

EXPECTED
unsorted edges
(0.0, 100.0, ':', 0.0, 0.0)
(100.0, 100.0, ':', 0.0, 100.0)
(100.0, 100.0, ':', 100.0, 0.0)
(100.0, 0.0, ':', 0.0, 0.0)

G0 X0 Y0 Z10 (Rapid move to first position)
G1 Z10 (feed move to first depth)
G1 X0 Y100 Z10 (feed move along first edge)
G1 X100 Y100 Z10
G1 X100 Y0 Z10
G1 X0 Y0 Z10 (feed move along last edge)
G0 Z10 (rapid back to original depth)

ACTUAL

unsorted edges
(0.0, 100.0, ':', 0.0, 0.0)
(100.0, 100.0, ':', 0.0, 100.0)
(100.0, 100.0, ':', 100.0, 0.0)
(100.0, 0.0, ':', 0.0, 0.0)
G0 X0 Y100 Z10
G1 Z10
G1 Y100 Z10
G1 X100 Z10
G1 Z10
TagsNo tags attached.
FreeCAD Information

Relationships

related to 0003276 closedsliptonic Path-Workbench Has redundant Shape-From-Area menu items. 

Activities

mlampert

2016-11-23 07:22

developer  

cylinder.png (2,864 bytes)   
cylinder.png (2,864 bytes)   

mlampert

2016-11-23 07:43

developer   ~0007485

I played around with this a bit and I think there are 2 problems here.

1) As you discovered (and the commented out code indicates), Path.fromShape() does not modify the given Wire/Edges in any form. It takes each Edge as it is and translates that to a Command. In order to make a valid Path, or something you expected, the given Edges would need to be sorted /and/ re-oriented.

which brings us to the harder problem here

2) If Path.fromShape starts re-ordering and re-orienting Edges, then the given example above has 8 valid resulting Paths it could generate. It has 4 possible entry points and it could process the loop CW or CCW.

Obviously it gets more interesting with more complex wires. I've attached the resulting Path of a Contour of a cylinder, 5 circles and 8 lines. 2 loose ends either one can be used as a starting point ..... if I'm not mistaken there are 20 valid Paths possible ....

What I'm getting at is that for any decently shaped wire the result is not predictable (and therefore of little value) iff we let Path.fromShape() modify the input wire. It's probably OK to re-orient an Edge (except for the first one) but everything else should be processed as is. The onus of placing the entry point as Vertex[0] of the first Edge in the wire and sorting the rest of the edges properly should be on the caller.

There is still the question of which way to traverse a full circle though.

Kunda1

2017-05-13 12:55

administrator   ~0008992

@realthunder do you mind weighing in?

realthunder

2017-05-13 16:58

developer   ~0008993

Last edited: 2017-05-13 17:00

My contribution is in Path.fromShapes(). For the code in Additional Information, to get the path you want
thepath = Path.fromShapes(mywire,orientation=1,start=App.Vector(0,0,20))
The 'start' parameter specifies the starting position. If not set, defaults to (0,0,0), which will cause the algorithm to use (xMax,yMax,zMax) of the bounding box of the shape as the start position. The GCode produced,
G90
G17
G0 X0.000000 Y0.000000 Z10.000000
G1 X0.000000 Y100.000000 Z10.000000
G1 X100.000000 Y100.000000 Z10.000000
G1 X100.000000 Y0.000000 Z10.000000
G1 X0.000000 Y0.000000 Z10.000000
Because of the complex nature of CAM, Path.fromShapes has quite a few parameters for you to play with. It can handle very complex raw wires (such as PCB milling path) and can sort the wires to minimize travel. You can use PathShapeFeature to explore the parameters using Gui. Simply select the shape and click 'Create path from selected shape' in Path workbench. Hover the mouse in each parameter for explanation.

sliptonic

2017-07-08 16:57

manager   ~0009689

Last edited: 2017-07-08 17:13

Path.fromShape is a python implementation. It's very old and was meant to be a reference implementation to build more complex things from. I think it should be deprecated and removed.

Path.fromShapes is realthunder's implementation of a similar general tool and much more powerful. The only issue I see with it is that the user can't get it into a Job so it can be postprocessed. It's a c++ implementation so I've got no clue. If someone can weigh in on how we modify fromShapes, I think this ticket can be closed pretty quick.

Kunda1

2017-09-25 13:11

administrator   ~0010190

@wmayer do you mind weighing in?

Kunda1

2017-11-06 13:03

administrator   ~0010387

@mlampert what say you in regards to 0002786:0009689 ?

yorik

2018-01-11 16:11

administrator   ~0010739

The only issue I see with it is that the user can't get it into a Job so it can be postprocessed.

sliptonic

Is the result of fromShapes a valid Path object? If yes, then I suppose the problem lies within the job object itself?

yorik

2018-01-12 17:32

administrator   ~0010746

@sliptonic can you explain how path are added to jobs? Couldn't find that in the code...

sliptonic

2018-01-12 18:18

manager   ~0010747

this is @mlampert's code so he knows it better than I. I believe it's done in the base class PathOp. in _setBaseAndStock() All the operations retain a reference to their job.

@mlampert, can you clarify how the Job tree gets built on the GUI side?

mlampert

2018-01-12 18:42

developer   ~0010748

Job uses a Path::FeatureCompoundPython as the Operations property, and whatever gets added to that is part of the job. I've never looked at the internals of Path::Compound that code predates my involvement.

yorik

2018-01-12 19:05

administrator   ~0010749

Okay, Part.fromShapes() seems to do the job much better than the old fromShape, which could be deprecated. Indeed I see now that it is easy to add the generated object to the Group property of the Operations subobject. So I guess @sliptonic's question is solved too.

I suggest then to simply change the docstring of Part.fromShape to indicate that it is deprecated?

yorik

2018-01-12 19:07

administrator   ~0010750

https://github.com/FreeCAD/FreeCAD/commit/fb8875df08146c520d8ce8cd351da624360ba5d5

wmayer

2018-01-12 22:53

administrator   ~0010751

https://github.com/FreeCAD/FreeCAD/commit/fb8875df08146c520d8ce8cd351da624360ba5d5

Issue History

Date Modified Username Field Change
2016-11-19 19:33 sliptonic New Issue
2016-11-19 19:33 sliptonic Status new => assigned
2016-11-19 19:33 sliptonic Assigned To => yorik
2016-11-23 07:22 mlampert File Added: cylinder.png
2016-11-23 07:43 mlampert Note Added: 0007485
2017-05-11 03:20 Kunda1 Steps to Reproduce Updated
2017-05-13 12:55 Kunda1 Note Added: 0008992
2017-05-13 16:58 realthunder Note Added: 0008993
2017-05-13 17:00 realthunder Note Edited: 0008993
2017-07-08 16:57 sliptonic Note Added: 0009689
2017-07-08 17:13 Kunda1 Note Edited: 0009689
2017-09-25 13:11 Kunda1 Note Added: 0010190
2017-11-06 13:03 Kunda1 Note Added: 0010387
2017-11-28 03:48 mlampert Relationship added related to 0003276
2018-01-11 16:11 yorik Note Added: 0010739
2018-01-12 17:32 yorik Note Added: 0010746
2018-01-12 18:18 sliptonic Note Added: 0010747
2018-01-12 18:42 mlampert Note Added: 0010748
2018-01-12 19:05 yorik Note Added: 0010749
2018-01-12 19:07 yorik Note Added: 0010750
2018-01-12 22:53 wmayer Status assigned => closed
2018-01-12 22:53 wmayer Resolution open => won't fix
2018-01-12 22:53 wmayer Note Added: 0010751