pyslm icon indicating copy to clipboard operation
pyslm copied to clipboard

Using the pyslm.hatching.*Hatcher with shapely object as input

Open jkur opened this issue 2 years ago • 4 comments

Hi, i'm trying to use some of the pySLM methods to do some basic hatching for robot tool path generation (there are not so many hatching implementation out there).

The idea is to create a shapely.Polygon oder shapely.LineString from a set of arbitrary points (x,y). Then i like to feed this polygon into one of the Hatchers from pySLM.

The examples use getVectorSlice() for generating input for the .hatch() method.

Can i generate the input for hatching from shapely Objects? Or would it be possible to generate input directly based on some list of points that describe a polygon?

The whole point is to generate paths for some laser cladding application, where the surface boundaries are extracted from some CAD document via FreeCAD.

jkur avatar Sep 06 '22 15:09 jkur

HI,

Sounds an interesting application.

That is fine and definitely possible. As you suggested you can directly export the path segments as a series of coordinates from the shapely objects. There's an internal function for extracting segment/path coordinates from shapely polygons into a format (list of coordinates) used internally by the clipper library in PySLM. This function iterates through the paths within a Shapely polygon list and extracts the coordinates into a compatible list of coordinates.

 def path2DToPathList shapes) -> List[np.ndarray]:

    paths = []

    for poly in shapes:
        coords = np.array(poly.exterior.coords)
        paths.append(coords)

        for path in poly.interiors:
            coords = np.array(path.coords)
            paths.append(coords)

    return paths

coordList = path2DToPathList(shapelyPaths)

From here you create a Hatcher object (or sub-class) and use the hatching functionality directly.

myHatcher = hatching.Hatcher()
layer = myHatcher.hatch(coordList)

drlukeparry avatar Sep 06 '22 19:09 drlukeparry

That actually works so far. Thanks a lot!

But now i'm actually struggling with interpreting the result of this hatching.

The resulting Layer has LaserGeometry objects. I have a very basic shape (rectangle with circular/rect hole).

Depending on parameters for the hatcher:

myHatcher.numInnerContours = 0
myHatcher.numOuterContours = 1
myHatcher.hatchSortMethod = hatching.AlternateSort()

i get some HatchGeometry and some ContourGeometry via getGeometry()

When setting the parameters for contours to zero, the hole is ignored completly. When setting inner or outer contours to 1, i get a ContourGeometry, which kind of has the holes in it, but i don't really know how to interpret these, because they are just arrays of x,y coordinates.

I doing something along these lines in my FreeCAD-Macro, where Draft.make_wire does what you would think. With two coordinates it generates a line.

poly = Polygon(outerpoly, holes=inner_polys)
coordList = path2DToPathList([poly])

layer = myHatcher.hatch(coordList)

for geom in layer.getGeometry():
    if geom.type() == LayerGeometryType.Hatch:
        hatches = np.vstack([geom.coords.reshape(-1, 2, 2)])
        for line in hatches:
            p0 = line[0]
            p1 = line[1]
            wire = Draft.make_wire([App.Vector(p0[0], p0[1],0), App.Vector(p1[0],p1[1],0)], closed=False, face=False)
    elif geom.type() == LayerGeometryType.Polygon:
        wire = Draft.make_wire([ App.Vector(x,y,0) for (x,y) in geom.coords], closed=True, face=False)
    else:
        print("Unhandled Geometry")

It looks to me, that the Hatcher does not actually clip the hatching lines. From looking at the code i cannot figure out, what makes the difference, since all examples e.g. from the blog obviously have holes and the hatching works. I attached some figures to show the result i get in FreeCAD.

The model with some rect as hole. The green highlighted lines are the result from the hatching process. The code is basically from above. fc_screen03

Here is another interesting detail of the hole fc_screen02

The Shapely Polygon extracted from the FreeCAD Selection is correct as plotted with matplot: fc_polygon

With some contours the clipping works, somewhat.... fc_screen04

There is something i'm missing i guess. Could you give a hint?

jkur avatar Sep 08 '22 11:09 jkur

Sorry, but the problem is probably not with the hatching code from PySLM but somewhere in my code. With certain geometries everything looks actually quite nice.

fc_screen05 The tool path is projected to the XY-Plane for now. Therefore is looks a bit off.

I think i need to dig a bit further.

jkur avatar Sep 08 '22 12:09 jkur

That looks a nice result already within FreeCAD and integrating it with PySLM.

Likely, you have to be careful with the projection of coordinates into the OpenCascade wire (path) structure used in FreeCAD and ensure that they full connected and in the correct orientation (winding order, for the contour paths. If in doubt, extract the polygons, hatch and plot with pyslm.visualise.plotPolygon, or pyslm.visualise.plot()

The default Hatcher assumes that there is one offset for the outer contour, but this behavior can be changed in the future, if there are occurance of issues.

Let me know if you find any further issues.

drlukeparry avatar Sep 09 '22 09:09 drlukeparry

No further questions, so marked as resolved.

drlukeparry avatar Jan 03 '23 13:01 drlukeparry