# -*- coding: utf-8 -*- __title__ = "Oriented sketch" __author__ = "Christophe Grellier (Chris_G)" __license__ = "LGPL 2.1" __doc__ = """Sketch normal to an edge, with up vector normal to a face""" import sys if sys.version_info.major >= 3: from importlib import reload import os import FreeCAD import FreeCADGui import Part import Sketcher from freecad.Curves import _utils from freecad.Curves import ICONPATH TOOL_ICON = os.path.join( ICONPATH, 'oriented_sketch.svg') #debug = _utils.debug #debug = _utils.doNothing props = """ App::PropertyBool App::PropertyBoolList App::PropertyFloat App::PropertyFloatList App::PropertyFloatConstraint App::PropertyQuantity App::PropertyQuantityConstraint App::PropertyAngle App::PropertyDistance App::PropertyLength App::PropertySpeed App::PropertyAcceleration App::PropertyForce App::PropertyPressure App::PropertyInteger App::PropertyIntegerConstraint App::PropertyPercent App::PropertyEnumeration App::PropertyIntegerList App::PropertyIntegerSet App::PropertyMap App::PropertyString App::PropertyUUID App::PropertyFont App::PropertyStringList App::PropertyLink App::PropertyLinkSub App::PropertyLinkList App::PropertyLinkSubList App::PropertyMatrix App::PropertyVector App::PropertyVectorList App::PropertyPlacement App::PropertyPlacementLink App::PropertyColor App::PropertyColorList App::PropertyMaterial App::PropertyPath App::PropertyFile App::PropertyFileIncluded App::PropertyPythonObject Part::PropertyPartShape Part::PropertyGeometryList Part::PropertyShapeHistory Part::PropertyFilletEdges Sketcher::PropertyConstraintList """ class orientedSketchFP: """Creates a Oriented sketch""" def __init__(self, obj, edge, face): """Add the properties""" obj.addProperty("App::PropertyLinkSub", "Edge", "OrientedSketch", "Edge support") obj.addProperty("App::PropertyLinkSub", "Face", "OrientedSketch", "Face support") obj.addProperty("App::PropertyFloatConstraint", "Parameter", "OrientedSketch", "Parameter on edge") obj.Proxy = self obj.Edge = edge obj.Face = face obj.Parameter = (0.0, 0.0, 1.0, 0.05) def execute(self, obj): edges = [] for g in obj.Geometry: if hasattr(g, 'Construction') and not g.Construction: #try: edges.append(g.toShape()) #except AttributeError: #debug("Failed to convert %s to BSpline"%str(g)) if edges: c = Part.Compound([]) se = Part.sortEdges(edges) for l in se: c.add(Part.Wire(l)) obj.Shape = c def onChanged(self, obj, prop): if prop == "Parameter": e = _utils.getShape(obj, "Edge", "Edge") f = _utils.getShape(obj, "Face", "Face") p = e.FirstParameter + (e.LastParameter - e.FirstParameter) * obj.Parameter loc = e.valueAt(p) u, v = f.Surface.parameter(loc) norm = f.normalAt(u, v) #print("{0!s} - {1!s}".format(p, loc)) x = norm.cross(e.tangentAt(p)) rot = FreeCAD.Rotation(x, norm, e.tangentAt(p)) obj.Placement.Base = loc obj.Placement.Rotation = rot class orientedSketchVP: def __init__(self, vobj): vobj.Proxy = self def getIcon(self): return TOOL_ICON def attach(self, vobj): self.Object = vobj.Object def __getstate__(self): return {"name": self.Object.Name} def __setstate__(self, state): self.Object = FreeCAD.ActiveDocument.getObject(state["name"]) return None class oriented_sketch_cmd: """Creates a Oriented sketch""" def makeFeature(self, e, f): fp = FreeCAD.ActiveDocument.addObject("Sketcher::SketchObjectPython", "Oriented sketch") orientedSketchFP(fp, e, f) orientedSketchVP(fp.ViewObject) FreeCAD.ActiveDocument.recompute() def Activated(self): sel = FreeCADGui.Selection.getSelectionEx() e = None f = None for s in sel: for sen in s.SubElementNames: if "Edge" in sen: e = (s.Object, sen) elif "Face" in sen: f = (s.Object, sen) if e and f: self.makeFeature(e, f) else: FreeCAD.Console.PrintError("Select 1 edge and 1 face first !\n") def IsActive(self): if FreeCAD.ActiveDocument: return True else: return False def GetResources(self): return {'Pixmap' : TOOL_ICON, 'MenuText': __title__, 'ToolTip': __doc__} FreeCADGui.addCommand('oriented_sketch', oriented_sketch_cmd())