import math import os import dummy import FreeCAD import FreeCADGui import Part from pivy import coin path_curvesWB = os.path.dirname(dummy.__file__) path_curvesWB_icons = os.path.join( path_curvesWB, 'Resources', 'icons') class birail: def __init__(self, obj): obj.Proxy = self obj.addProperty("App::PropertyLinkSub", "Edge1", "Base", "Edge1") obj.addProperty("App::PropertyLinkSub", "Edge2", "Base", "Edge2") obj.addProperty("App::PropertyBool", "Untwist", "Base", "Untwist surface" ).Untwist = False obj.addProperty("App::PropertyBool", "NormalizeTangent", "Normalize", "Normalize tangent" ).NormalizeTangent = False obj.addProperty("App::PropertyBool", "NormalizeNormal", "Normalize", "Normalize normal" ).NormalizeNormal = True obj.addProperty("App::PropertyBool", "NormalizeBinormal", "Normalize", "Normalize binormal").NormalizeBinormal = False self.edge1 = None self.edge2 = None self.normTan = False self.normNor = True self.normBin = False def execute(self, obj): self.ruledSurface() obj.Shape = self.ruled def onChanged(self, fp, prop): FreeCAD.Console.PrintMessage('%s changed\n'%prop) if prop == "Edge1": self.edge1 = self.getEdge(fp.Edge1) self.ruledSurface() if prop == "Edge2": self.edge2 = self.getEdge(fp.Edge2) self.ruledSurface() if prop == "Untwist": self.edge2.reverse() self.ruledSurface() if prop == "NormalizeTangent": self.normTan = fp.NormalizeTangent if prop == "NormalizeNormal": self.normNor = fp.NormalizeNormal if prop == "NormalizeBinormal": self.normBin = fp.NormalizeBinormal def getEdge(self, prop): o = prop[0] e = prop[1][0] n = eval(e.lstrip('Edge')) try: edge = o.Shape.Edges[n-1] return edge except: return None def ruledSurface(self): if isinstance(self.edge1,Part.Edge) and isinstance(self.edge2,Part.Edge): self.ruled = Part.makeRuledSurface(self.edge1, self.edge2) self.rail1 = self.ruled.Edges[0] self.rail2 = self.ruled.Edges[2] self.u0 = self.ruled.ParameterRange[0] self.u1 = self.ruled.ParameterRange[1] def tangentsAt(self, p): if self.normTan: return (self.rail1.tangentAt(p), self.rail2.tangentAt(p)) else: return (self.rail1.derivative1At(p), self.rail2.derivative1At(p)) def normalsAt(self, p): n1 = self.ruled.normalAt(p,0).negative() n2 = self.ruled.normalAt(p,1).negative() if self.normNor: n1.normalize() n2.normalize() return (n1, n2) def binormalsAt(self, p): # TODO check for 0-length vector v1 = self.rail1.valueAt(p) v2 = self.rail2.valueAt(p) v = v2.sub(v1) if self.normBin: v.normalize() return (v, v.negative()) def frame1At(self, p): t = self.tangentsAt(p)[0] b = self.binormalsAt(p)[0] n = self.normalsAt(p)[0] return (b, t, n) def frame2At(self, p): t = self.tangentsAt(p)[1] b = self.binormalsAt(p)[1] n = self.normalsAt(p)[1] return (b, t, n) def matrix1At(self, p): t = self.rail1.valueAt(p) u,v,w = self.frame1At(p) m=FreeCAD.Matrix( u.x,v.x,w.x,t.x, u.y,v.y,w.y,t.y, u.z,v.z,w.z,t.z, 0.0,0.0,0.0,1.0) return m def matrix2At(self, p): t = self.rail2.valueAt(p) u,v,w = self.frame2At(p) m=FreeCAD.Matrix( u.x,v.x,w.x,t.x, u.y,v.y,w.y,t.y, u.z,v.z,w.z,t.z, 0.0,0.0,0.0,1.0) return m class birailVP: def __init__(self, obj): obj.Proxy = self def getIcon(self): return (path_curvesWB_icons+'/birail.svg') def attach(self, vobj): self.ViewObject = vobj self.Object = vobj.Object def setEdit(self,vobj,mode): return False def unsetEdit(self,vobj,mode): return def __getstate__(self): return None def __setstate__(self,state): return None def claimChildren(self): #return [self.Object.Edge1[0], self.Object.Edge2[0]] return def onDelete(self, feature, subelements): # subelements is a tuple of strings try: self.Object.Edge1[0].ViewObject.show() self.Object.Edge2[0].ViewObject.show() except Exception as err: FreeCAD.Console.PrintError("Error in onDelete: {0} \n".format(err)) return True class birailcommand: def parseSel(self, selectionObject): res = [] for obj in selectionObject: if obj.HasSubObjects: for i,sobj in enumerate(obj.SubObjects): if issubclass(type(sobj),Part.Edge): res.append((obj.Object,[obj.SubElementNames[i]])) else: res.append((obj.Object,["Edge1"])) return res def Activated(self): myBirail = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Birail") birail(myBirail) birailVP(myBirail.ViewObject) s = FreeCADGui.Selection.getSelectionEx() myBirail.Edge1 = self.parseSel(s)[0] myBirail.Edge2 = self.parseSel(s)[1] myBirail.Edge1[0].ViewObject.Visibility = False myBirail.Edge2[0].ViewObject.Visibility = False FreeCAD.ActiveDocument.recompute() def GetResources(self): return {'Pixmap' : path_curvesWB_icons+'/birail.svg', 'MenuText': 'Birail', 'ToolTip': 'Birail object to use with Sweep on 2 rails tool'} FreeCADGui.addCommand('Birail', birailcommand())