You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
7.4 KiB
195 lines
7.4 KiB
import FreeCAD |
|
import FreeCAD as App |
|
import FreeCADGui as Gui |
|
import numpy as np |
|
import math |
|
import Part |
|
from shapely.geometry import Polygon, Point |
|
from pyslm import hatching as hatching |
|
from pyslm.geometry.geometry import LayerGeometryType |
|
from typing import List |
|
import rdp |
|
from .utils import * |
|
from freecad.LaserCladdingWorkbench.path import LaserPath |
|
|
|
|
|
|
|
class LaserPad: |
|
def __init__(self, obj, face): |
|
obj.addProperty("App::PropertyFloatConstraint", "tool_width", "Parameters", "Width of the circular effect area of Laser in mm") |
|
obj.tool_width = (2.3, 0.01, 20.0, 0.1) |
|
|
|
obj.addProperty("App::PropertyFloatConstraint", "hatch_angle", "Hatching Parameters", "Hatch Angle") |
|
obj.hatch_angle = (0.0, 0.0, 180.0, 1.0) |
|
|
|
obj.addProperty("App::PropertyFloat", "hatch_volume_offset", "Parameters", "Offset between internal and external boundary") |
|
obj.hatch_volume_offset = 2.3*0.5 |
|
|
|
obj.addProperty("App::PropertyFloat", "hatch_spot_compensation", "Parameters", "Additional offset to account for laser spot size") |
|
obj.hatch_spot_compensation = 2.3*0.5 |
|
|
|
obj.addProperty("App::PropertyInteger", "hatch_inner_contours", "Parameters", "Inner Contours") |
|
obj.hatch_inner_contours = 1 |
|
|
|
obj.addProperty("App::PropertyInteger", "hatch_outer_contours", "Parameters", "Outer Contours") |
|
obj.hatch_outer_contours = 0 |
|
|
|
obj.addProperty("App::PropertyFloat", "hatch_contour_offset", "Parameters", "Contour Offset") |
|
obj.hatch_contour_offset = 2.3 |
|
|
|
obj.addProperty("App::PropertyLinkGlobal","ref_body","Reference","body") |
|
obj.ref_body = face[0] |
|
|
|
obj.addProperty("App::PropertyString","ref_surface","Reference","face") |
|
obj.ref_surface = face[1] |
|
|
|
obj.addExtension("App::GroupExtensionPython") |
|
obj.Proxy = self |
|
self._create_path(obj) |
|
|
|
def _create_path(self, obj): |
|
print("Create_path") |
|
print("obj.ref_surface", obj.ref_surface) |
|
# if len(obj.Group): |
|
# obj.removeObjectsFromDocument() |
|
face = obj.ref_body.getSubObject(obj.ref_surface) |
|
myHatcher = hatching.Hatcher() |
|
myHatcher.hatchDistance = obj.tool_width |
|
myHatcher.hatchAngle = obj.hatch_angle |
|
myHatcher.volumeOffsetHatch = obj.hatch_volume_offset |
|
myHatcher.spotCompensation = obj.hatch_spot_compensation |
|
myHatcher.numInnerContours = obj.hatch_inner_contours |
|
myHatcher.numOuterContours = obj.hatch_outer_contours |
|
myHatcher.contourOffset = obj.hatch_contour_offset |
|
myHatcher.hatchSortMethod = hatching.AlternateSort() |
|
|
|
polygon_coords = get_coords_from_shape(face) |
|
layer = myHatcher.hatch(polygon_coords) |
|
|
|
contours_geoms = layer.getContourGeometry() |
|
hatch_geoms = layer.getHatchGeometry() |
|
|
|
contours = create_contour_lines(contours_geoms) |
|
hatchlines = create_hatch_lines(hatch_geoms) |
|
|
|
proj_contours = project_to_face(contours, face) |
|
proj_hatchlines = project_to_face(hatchlines, face) |
|
# DEBUG Part.show(Part.makeCompound(hatchlines)) |
|
obj.purgeTouched() |
|
|
|
for pc in proj_contours: |
|
p = Part.makeCompound(pc) |
|
contours_comp = obj.newObject("Part::Feature", "Contours") |
|
LaserPath(contours_comp) |
|
contours_comp.Shape = p |
|
contours_comp.ViewObject.LineColor = (0.5, 0.8, 0.9) |
|
|
|
print("Creating Hatch Part") |
|
hatches_comp = obj.newObject("Part::Feature", "Hatchlines") |
|
p = Part.makeCompound([]) |
|
for pc in proj_hatchlines: |
|
p.add(Part.makeCompound(pc)) |
|
|
|
LaserPath(hatches_comp) |
|
hatches_comp.Shape = p |
|
hatches_comp.ViewObject.LineColor = (0.9, 0.2, 0.2) |
|
print("Group: ", obj.Group) |
|
|
|
def onChanged(self, fp, prop): |
|
'''Do something when a property has changed''' |
|
App.Console.PrintMessage("Change property: " + str(prop) + "\n") |
|
|
|
def execute(self, fp): |
|
App.Console.PrintMessage("Recompute LaserPad\n") |
|
# self._create_path(fp) |
|
|
|
|
|
class ViewProviderLaserPad: |
|
def __init__(self, obj): |
|
'''Set this object to the proxy object of the actual view provider''' |
|
obj.addProperty("App::PropertyColor", "Color", "Box", "Color of the box").Color=(1.0, 0.0, 0.0) |
|
obj.addExtension("Gui::ViewProviderGroupExtensionPython") |
|
self.Object = obj.Object |
|
obj.Proxy = self |
|
|
|
def claimChildren(self): |
|
"""Return objects that will be placed under it in the tree view.""" |
|
App.Console.PrintMessage("Reclaim children\n") |
|
|
|
claimed = [] |
|
App.Console.PrintMessage(self.__dict__) |
|
for o in self.Object.OutList: |
|
if o.TypeId == 'Part::Feature': |
|
claimed.append(o) |
|
return claimed |
|
|
|
def attach(self, vobj): |
|
self.Object = vobj.Object |
|
self.ViewObject = vobj |
|
|
|
def getDisplayModes(self, obj): |
|
"'''Return a list of display modes.'''" |
|
return ["Standard"] |
|
|
|
def getDefaultDisplayMode(self): |
|
"'''Return the name of the default display mode. It must be defined in getDisplayModes.'''" |
|
return "Standard" |
|
|
|
def updateData(self, fp, prop): |
|
'''If a property of the handled feature has changed we have the chance to handle this here''' |
|
# fp is the handled feature, prop is the name of the property that has changed |
|
pass |
|
|
|
def setDisplayMode(self, mode): |
|
'''Map the display mode defined in attach with those defined in getDisplayModes.\ |
|
Since they have the same names nothing needs to be done. This method is optional''' |
|
return mode |
|
|
|
def onChanged(self, vp, prop): |
|
'''Here we can do something when a single property got changed''' |
|
App.Console.PrintMessage("Change property: " + str(prop) + "\n") |
|
# if prop == "Color": |
|
# c = vp.getPropertyByName("Color") |
|
# self.color.rgb.setValue(c[0],c[1],c[2]) |
|
|
|
def getIcon(self): |
|
'''Return the icon in XPM format which will appear in the tree view. This method is\ |
|
optional and if not defined a default icon is shown.''' |
|
return """ |
|
/* XPM */ |
|
static const char * ViewProviderBox_xpm[] = { |
|
"16 16 6 1", |
|
" c None", |
|
". c #141010", |
|
"+ c #615BD2", |
|
"@ c #C39D55", |
|
"# c #000000", |
|
"$ c #57C355", |
|
" ........", |
|
" ......++..+..", |
|
" .@@@@.++..++.", |
|
" .@@@@.++..++.", |
|
" .@@ .++++++.", |
|
" ..@@ .++..++.", |
|
"###@@@@ .++..++.", |
|
"##$.@@$#.++++++.", |
|
"#$#$.$$$........", |
|
"#$$####### ", |
|
"#$$#$$$$$# ", |
|
"#$$#$$$$$# ", |
|
"#$$#$$$$$# ", |
|
" #$#$$$$$# ", |
|
" ##$$$$$# ", |
|
" ####### "}; |
|
""" |
|
|
|
def __getstate__(self): |
|
'''When saving the document this object gets stored using Python's json module.\ |
|
Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\ |
|
to return a tuple of all serializable objects or None.''' |
|
return None |
|
|
|
def __setstate__(self, state): |
|
'''When restoring the serialized object from document we have the chance to set some internals here.\ |
|
Since no data were serialized nothing needs to be done here.''' |
|
return None
|
|
|