def placeoTherElbow(c,v1=None,v2=None,P=None): ''' Like placeTheElbow() but with more math. ''' if not (v1 and v2): v1,v2=[e.tangentAt(0) for e in fCmd.edges()] try: P=fCmd.intersectionCLines(*fCmd.edges()) except: pass if hasattr(c,'PType') and hasattr(c,'BendAngle') and v1 and v2: v1.normalize() v2.normalize() ortho=rounded(fCmd.ortho(v1,v2)) bisect=rounded(v2-v1) cBisect=rounded(c.Ports[1].normalize()+c.Ports[0].normalize()) # math cZ=c.Ports[0].cross(c.Ports[1]) # more math ang=degrees(v1.getAngle(v2)) c.BendAngle=ang rot1=FreeCAD.Rotation(rounded(fCmd.beamAx(c,cZ)),ortho) c.Placement.Rotation=rot1.multiply(c.Placement.Rotation) rot2=FreeCAD.Rotation(rounded(fCmd.beamAx(c,cBisect)),bisect) c.Placement.Rotation=rot2.multiply(c.Placement.Rotation) if not P: P=c.Placement.Base c.Placement.Base=P
def update(self,fp,edges=None): from DraftVecUtils import rounded from math import degrees if not edges and hasattr(fp.Base,'Shape'): edges=fp.Base.Shape.Edges if not edges: FreeCAD.Console.PrintError('Base has not valid edges\n') return pipes=list() for e in edges: #---Create the tube--- p=pCmd.makePipe([fp.PSize,fp.OD,fp.thk,e.Length],pos=e.valueAt(0),Z=e.tangentAt(0)) p.PRating=fp.PRating p.PSize=fp.PSize pCmd.moveToPyLi(p,fp.Label) pipes.append(p) n=len(pipes)-1 if n and not fCmd.isParallel(fCmd.beamAx(pipes[n]),fCmd.beamAx(pipes[n-1])): #---Create the curve--- propList=[fp.PSize,fp.OD,fp.thk,90,fp.BendRadius] c=pCmd.makeElbowBetweenThings(edges[n],edges[n-1],propList) if c: portA,portB=[c.Placement.multVec(port) for port in c.Ports] #---Trim the tube--- p1,p2=pipes[-2:] fCmd.extendTheBeam(p1,portA) fCmd.extendTheBeam(p2,portB) pCmd.moveToPyLi(c,fp.Label)
def placeTheElbow(c,v1=None,v2=None,P=None): ''' placeTheElbow(c,v1,v2,P=None) Puts the curve C between vectors v1 and v2. If point P is given, translates it in there. NOTE: v1 and v2 oriented in the same direction along the path! ''' if not (v1 and v2): v1,v2=[e.tangentAt(0) for e in fCmd.edges()] try: P=fCmd.intersectionCLines(*fCmd.edges()) except: pass if hasattr(c,'PType') and hasattr(c,'BendAngle') and v1 and v2: v1.normalize() v2.normalize() ortho=rounded(fCmd.ortho(v1,v2)) bisect=rounded(v2-v1) ang=degrees(v1.getAngle(v2)) c.BendAngle=ang rot1=FreeCAD.Rotation(rounded(fCmd.beamAx(c,FreeCAD.Vector(0,0,1))),ortho) c.Placement.Rotation=rot1.multiply(c.Placement.Rotation) rot2=FreeCAD.Rotation(rounded(fCmd.beamAx(c,FreeCAD.Vector(1,1,0))),bisect) c.Placement.Rotation=rot2.multiply(c.Placement.Rotation) if not P: P=c.Placement.Base c.Placement.Base=P
def makeElbowBetweenThings(thing1=None, thing2=None, propList=None): ''' makeElbowBetweenThings(thing1, thing2, propList=None): Place one elbow at the intersection of thing1 and thing2. Things can be any combination of intersecting beams, pipes or edges. If nothing is passed as argument, the function attempts to take the first two edges selected in the view. propList is one optional list with 5 elements: DN (string): nominal diameter OD (float): outside diameter thk (float): shell thickness BA (float): bend angle - that will be recalculated! - BR (float): bend radius Default is "DN50 (SCH-STD)" Remember: property PRating must be defined afterwards ''' if not (thing1 and thing2): thing1,thing2=fCmd.edges()[:2] P=fCmd.intersectionCLines(thing1,thing2) directions=list() try: for thing in [thing1,thing2]: if fCmd.beams([thing]): directions.append(rounded((fCmd.beamAx(thing).multiply(thing.Height/2)+thing.Placement.Base)-P)) elif hasattr(thing,'ShapeType') and thing.ShapeType=='Edge': directions.append(rounded(thing.CenterOfMass-P)) except: return None ang=180-degrees(directions[0].getAngle(directions[1])) if ang==0 or ang==180: return None if not propList: propList=["DN50",60.3,3.91,ang,45.24] else: propList[3]=ang elb=makeElbow(propList,P,directions[0].negative().cross(directions[1].negative())) # mate the elbow ends with the pipes or edges b=fCmd.bisect(directions[0],directions[1]) elbBisect=rounded(fCmd.beamAx(elb,FreeCAD.Vector(1,1,0))) #if not rounded, fail in plane xz rot=FreeCAD.Rotation(elbBisect,b) elb.Placement.Rotation=rot.multiply(elb.Placement.Rotation) # trim the adjacent tubes #FreeCAD.activeDocument().recompute() # may delete this row? portA=elb.Placement.multVec(elb.Ports[0]) portB=elb.Placement.multVec(elb.Ports[1]) for tube in [t for t in [thing1,thing2] if fCmd.beams([t])]: vectA=tube.Shape.Solids[0].CenterOfMass-portA vectB=tube.Shape.Solids[0].CenterOfMass-portB if fCmd.isParallel(vectA,fCmd.beamAx(tube)): fCmd.extendTheBeam(tube,portA) else: fCmd.extendTheBeam(tube,portB) return elb
def accept(self): if self.labTail: self.labTail.removeLabel() self.labTail=None self.L=fCmd.getDistance() if self.form.edit1.text(): length=float(self.form.edit1.text()) FreeCAD.activeDocument().openTransaction('Stretch beam') for beam in fCmd.beams(): delta=float(beam.Height)-length fCmd.stretchTheBeam(beam,length) if self.form.tail.isChecked(): disp=fCmd.beamAx(beam).multiply(delta) beam.Placement.move(disp) elif self.form.both.isChecked(): disp=fCmd.beamAx(beam).multiply(delta/2.0) beam.Placement.move(disp) FreeCAD.activeDocument().recompute() FreeCAD.activeDocument().commitTransaction()
def rotateTheTubeAx(obj=None,vShapeRef=None, angle=45): ''' rotateTheTubeAx(obj=None,vShapeRef=None,angle=45) Rotates obj around the vShapeRef axis of its Shape by an angle. obj: if not defined, the first in the selection set vShapeRef: if not defined, the Z axis of the Shape angle: default=45 deg ''' if obj==None: obj=FreeCADGui.Selection.getSelection()[0] if vShapeRef==None: vShapeRef=FreeCAD.Vector(0,0,1) rot=FreeCAD.Rotation(fCmd.beamAx(obj,vShapeRef),angle) obj.Placement.Rotation=rot.multiply(obj.Placement.Rotation)
def execute(self,obj): X=FreeCAD.Vector(1,0,0) Z=FreeCAD.Vector(0,0,1) if hasattr(obj,'Base') and obj.Base and hasattr(obj,'Beams'): n=obj.Base.Placement.Rotation.multVec(Z) for i in range(len(obj.Beams)): if obj.Beams[i]: edge=obj.Base.Shape.Edges[i] beam=FreeCAD.ActiveDocument.getObject(obj.Beams[i]) beam.Height=float(obj.Base.Shape.Edges[i].Length)+beam.tailOffset+beam.headOffset offset=FreeCAD.Vector(0,0,beam.tailOffset).negative() spin=FreeCAD.Rotation() beam.AttachmentOffset = FreeCAD.Placement(offset, spin) angle=degrees(fCmd.beamAx(beam,X).getAngle(n)) beam.AttachmentOffset.Rotation=FreeCAD.Rotation(Z,angle+beam.spin)
def breakTheTubes(point,pipes=[],gap=0): ''' breakTheTube(point,pipes=[],gap=0) Breaks the "pipes" at "point" leaving a "gap". ''' pipes2nd=list() if not pipes: pipes=[p for p in fCmd.beams() if isPipe(p)] if pipes: for pipe in pipes: if point<float(pipe.Height) and gap<(float(pipe.Height)-point): propList=[pipe.PSize,float(pipe.OD),float(pipe.thk),float(pipe.Height)-point-gap] pipe.Height=point Z=fCmd.beamAx(pipe) pos=pipe.Placement.Base+Z*(float(pipe.Height)+gap) pipe2nd=makePipe(propList,pos,Z) pipes2nd.append(pipe2nd) #FreeCAD.activeDocument().recompute() return pipes2nd
def laydownTheTube(pipe=None, refFace=None, support=None): ''' laydownTheTube(pipe=None, refFace=None, support=None) Makes one pipe touch one face if the center-line is parallel to it. If support is not None, support is moved towards pipe. ''' if not(pipe and refFace): # without argument take from selection set refFace=[f for f in fCmd.faces() if type(f.Surface)==Part.Plane][0] pipe=[p for p in fCmd.beams() if hasattr(p,'OD')] [0] try: if type(refFace.Surface)==Part.Plane and fCmd.isOrtho(refFace,fCmd.beamAx(pipe)) and hasattr(pipe,'OD'): dist=rounded(refFace.normalAt(0,0).multiply(refFace.normalAt(0,0).dot(pipe.Placement.Base-refFace.CenterOfMass)-float(pipe.OD)/2)) if support: support.Placement.move(dist) else: pipe.Placement.move(dist.multiply(-1)) else: FreeCAD.Console.PrintError('Face is not flat or not parallel to axis of pipe\n') except: FreeCAD.Console.PrintError('Wrong selection\n')
def reverseTheTube(objEx): ''' reverseTheTube(objEx) Reverse the orientation of objEx spinning it 180 degrees around the x-axis of its shape. If an edge is selected, it's used as pivot. ''' disp=None selectedEdges=[e for e in objEx.SubObjects if e.ShapeType=='Edge'] if selectedEdges: for edge in fCmd.edges([objEx]): if edge.curvatureAt(0): disp=edge.centerOfCurvatureAt(0)-objEx.Object.Placement.Base break elif fCmd.beams([objEx.Object]): ax=fCmd.beamAx(objEx.Object) disp=ax*((edge.CenterOfMass-objEx.Object.Placement.Base).dot(ax)) rotateTheTubeAx(objEx.Object,FreeCAD.Vector(1,0,0),180) if disp: objEx.Object.Placement.move(disp*2)
def onPushButton1(self): from math import pi, degrees import fCmd try: obj=self.Selection.getSelection()[0] self.labName.setText(obj.Label) self.labBaseVal.setText(str("P = %.1f,%.1f,%.1f"%tuple(obj.Placement.Base))) self.labRotAng.setText(str("%.2f " %(degrees(obj.Placement.Rotation.Angle)))) ax=obj.Placement.Rotation.Axis self.labRotAx.setText(str("v = (%(x).2f,%(y).2f,%(z).2f)" %{'x':ax.x,'y':ax.y,'z':ax.z})) shapes=[y for x in self.Selection.getSelectionEx() for y in x.SubObjects if hasattr(y,'ShapeType')] if len(shapes)==1: sub=shapes[0] if sub.ShapeType=='Edge': if sub.curvatureAt(0)==0: self.labSubObj.setText(sub.ShapeType+':\tL = %.1f mm' %sub.Length) else: x,y,z=sub.centerOfCurvatureAt(0) d=2/sub.curvatureAt(0) self.labSubObj.setText(sub.ShapeType+':\tD = %.1f mm\n\tC = %.1f,%.1f,%.1f' %(d,x,y,z)) elif sub.ShapeType=='Face': self.labSubObj.setText(sub.ShapeType+':\tA = %.1f mm2' %sub.Area) elif sub.ShapeType=='Vertex': self.labSubObj.setText(sub.ShapeType+': pos = (%(x).1f,%(y).1f,%(z).1f)' %{'x':sub.X,'y':sub.Y,'z':sub.Z}) elif len(shapes)>1: self.labSubObj.setText(shapes[0].ShapeType+' to '+shapes[1].ShapeType+': distance = %.1f mm' %(shapes[0].distToShape(shapes[1])[0])) else: self.labSubObj.setText(' ') if len(fCmd.beams())==1: b=fCmd.beams()[0] self.labBeam.setText(b.Label+":\tL=%.2f"%(b.Height)) self.labProfile.setText("Profile: "+b.Profile) elif len(fCmd.beams())>1: b1,b2=fCmd.beams()[:2] self.labBeam.setText(b1.Label+"^"+b2.Label+": %.2f"%(degrees(fCmd.beamAx(b1).getAngle(fCmd.beamAx(b2))))) self.labProfile.setText("") else: self.labBeam.setText("") self.labProfile.setText("") except: pass