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 frameCmd.edges()] try: P = frameCmd.intersectionCLines(*frameCmd.edges()) except: pass if hasattr(c, 'PType') and hasattr(c, 'BendAngle') and v1 and v2: v1.normalize() v2.normalize() ortho = rounded(frameCmd.ortho(v1, v2)) bisect = rounded(v2 - v1) cBisect = rounded(c.Ports[1] + c.Ports[0]) # math cZ = c.Ports[0].cross(c.Ports[1]) # more math ang = degrees(v1.getAngle(v2)) c.BendAngle = ang rot1 = FreeCAD.Rotation(rounded(frameCmd.beamAx(c, cZ)), ortho) c.Placement.Rotation = rot1.multiply(c.Placement.Rotation) rot2 = FreeCAD.Rotation(rounded(frameCmd.beamAx(c, cBisect)), bisect) c.Placement.Rotation = rot2.multiply(c.Placement.Rotation) if not P: P = c.Placement.Base c.Placement.Base = P
def portsDir(o): ''' portsDir(o) Returns the orientation of Ports of the pype-object o ''' dirs = list() two_ways = ['Pipe', 'Reduct', 'Flange'] if hasattr(o, 'PType'): if o.PType in two_ways: dirs = [ o.Placement.Rotation.multVec(p) for p in [FreeCAD.Vector(0, 0, -1), FreeCAD.Vector(0, 0, 1)] ] elif hasattr(o, 'Ports') and hasattr(o, 'Placement'): dirs = list() for p in o.Ports: if p.Length: dirs.append( rounded(o.Placement.Rotation.multVec(p).normalize())) else: dirs.append( rounded( o.Placement.Rotation.multVec( FreeCAD.Vector(0, 0, -1)).normalize())) return dirs
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 frameCmd.edges()] try: P = frameCmd.intersectionCLines(*frameCmd.edges()) except: pass if hasattr(c, 'PType') and hasattr(c, 'BendAngle') and v1 and v2: v1.normalize() v2.normalize() ortho = rounded(frameCmd.ortho(v1, v2)) bisect = rounded(v2 - v1) ang = degrees(v1.getAngle(v2)) c.BendAngle = ang rot1 = FreeCAD.Rotation( rounded(frameCmd.beamAx(c, FreeCAD.Vector(0, 0, 1))), ortho) c.Placement.Rotation = rot1.multiply(c.Placement.Rotation) rot2 = FreeCAD.Rotation( rounded(frameCmd.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 = frameCmd.edges()[:2] P = frameCmd.intersectionCLines(thing1, thing2) directions = list() try: for thing in [thing1, thing2]: if frameCmd.beams([thing]): directions.append( rounded( (frameCmd.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 = frameCmd.bisect(directions[0], directions[1]) elbBisect = rounded(frameCmd.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 frameCmd.beams([t])]: vectA = tube.Shape.Solids[0].CenterOfMass - portA vectB = tube.Shape.Solids[0].CenterOfMass - portB if frameCmd.isParallel(vectA, frameCmd.beamAx(tube)): frameCmd.extendTheBeam(tube, portA) else: frameCmd.extendTheBeam(tube, portB) return elb
def portsPos(o): ''' portsPos(o) Returns the position of Ports of the pype-object o ''' if hasattr(o, 'Ports') and hasattr(o, 'Placement'): return [rounded(o.Placement.multVec(p)) for p in o.Ports]
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 frameCmd.faces() if type(f.Surface) == Part.Plane ][0] pipe = [p for p in frameCmd.beams() if hasattr(p, 'OD')][0] try: if type(refFace.Surface) == Part.Plane and frameCmd.isOrtho( refFace, frameCmd.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 intersectionCLines(thing1=None, thing2=None): ''' intersectionCLines(thing1=None, thing2=None) Returns the intersection (vector) of the center lines of thing1 and thing2. Things can be any combination of intersecting beams, pipes or edges. If less than 2 arguments are given, thing1 and thing2 are the first 2 beams or pipes found in the selection set. ''' if not (thing1 and thing2): try: thing1,thing2=beams()[:2] except: FreeCAD.Console.PrintError('Insufficient arguments for intersectionCLines\n') return None edges=[] for thing in [thing1,thing2]: if beams([thing]): edges.append(vec2edge(thing.Placement.Base,beamAx(thing))) elif hasattr(thing,'ShapeType') and thing.ShapeType=='Edge': edges.append(thing) intersections=dgu.findIntersection(*edges, infinite1=True, infinite2=True) if len(intersections): return rounded(intersections[0]) else: FreeCAD.Console.PrintError('No intersection found\n') return None
def intersectionCLines(thing1=None, thing2=None): ''' intersectionCLines(thing1=None, thing2=None) Returns the intersection (vector) of the center lines of thing1 and thing2. Things can be any combination of intersecting beams, pipes or edges. If less than 2 arguments are given, thing1 and thing2 are the first 2 beams or pipes found in the selection set. ''' if not (thing1 and thing2): try: thing1, thing2 = beams()[:2] except: FreeCAD.Console.PrintError( 'Insufficient arguments for intersectionCLines\n') return None edges = [] for thing in [thing1, thing2]: if beams([thing]): edges.append(vec2edge(thing.Placement.Base, beamAx(thing))) elif hasattr(thing, 'ShapeType') and thing.ShapeType == 'Edge': edges.append(thing) intersections = dgu.findIntersection(*edges, infinite1=True, infinite2=True) if len(intersections): return rounded(intersections[0]) else: FreeCAD.Console.PrintError('No intersection found\n') return None
def intersectionPlane(base=None, v=None, face=None): ''' intersectionPlane(base,v,face) Returns the point (vector) at the intersection of a line and a plane. base (vector): the base point to be projected v (vector): the direction of the line that intersect the plane face (Face): the face that defines the plane to be intersect ''' # only for quick testing: if base == v == face == None: face = faces()[0] beam = beams()[0] base = beam.Placement.Base v = beamAx(beam) if isOrtho(v, face): FreeCAD.Console.PrintError( 'Direction of projection and Face are parallel.\n') return None else: # equation of plane: ax+by+cz+d=0 a, b, c = list(face.normalAt(0, 0)) d = -face.CenterOfMass.dot(face.normalAt(0, 0)) #FreeCAD.Console.PrintMessage('a=%.2f b=%.2f c=%.2f d=%.2f\n' %(a,b,c,d)) ## definition of line #FreeCAD.Console.PrintMessage('base=(%.2f,%.2f,%.2f)\n' %(base.x,base.y,base.z)) #FreeCAD.Console.PrintMessage('v=(%.2f,%.2f,%.2f)\n' %(v.x,v.y,v.z)) ##intersection k = -1 * (a * base.x + b * base.y + c * base.z + d) / (a * v.x + b * v.y + c * v.z) #FreeCAD.Console.PrintMessage('k=%f\n' %float(k)) P = base + v * k return rounded(P)
def intersectionPlane(base=None,v=None,face=None): ''' intersectionPlane(base,v,face) Returns the point (vector) at the intersection of a line and a plane. base (vector): the base point to be projected v (vector): the direction of the line that intersect the plane face (Face): the face that defines the plane to be intersect ''' # only for quick testing: if base==v==face==None: face = faces()[0] beam=beams()[0] base=beam.Placement.Base v=beamAx(beam) if isOrtho(v,face): FreeCAD.Console.PrintError('Direction of projection and Face are parallel.\n') return None else: # equation of plane: ax+by+cz+d=0 a,b,c=list(face.normalAt(0,0)) d=-face.CenterOfMass.dot(face.normalAt(0,0)) #FreeCAD.Console.PrintMessage('a=%.2f b=%.2f c=%.2f d=%.2f\n' %(a,b,c,d)) ## definition of line #FreeCAD.Console.PrintMessage('base=(%.2f,%.2f,%.2f)\n' %(base.x,base.y,base.z)) #FreeCAD.Console.PrintMessage('v=(%.2f,%.2f,%.2f)\n' %(v.x,v.y,v.z)) ##intersection k=-1*(a*base.x+b*base.y+c*base.z+d)/(a*v.x+b*v.y+c*v.z) #FreeCAD.Console.PrintMessage('k=%f\n' %float(k)) P=base+v*k return rounded(P)
def getReference(self): selex=FreeCADGui.Selection.getSelectionEx() for sx in selex: if sx.SubObjects: planes=[f for f in frameCmd.faces([sx]) if type(f.Surface)==Part.Plane] if len(planes)>0: self.refNorm=rounded(planes[0].normalAt(0,0)) self.lab1.setText("ref. Face on "+sx.Object.Label)
def rotjoinTheBeam(beam=None, e1=None, e2=None): if not (beam and e1 and e2): beam = beams()[1] e1, e2 = edges() rot = FreeCAD.Rotation(e2.tangentAt(0), e1.tangentAt(0)) dist = dgu.findDistance(beam.Placement.Base, e1) delta = beam.Placement.Base - e2.CenterOfMass beam.Placement.Rotation = rot.multiply(beam.Placement.Rotation) beam.Placement.move(rounded(dist + rot.multVec(delta)))
def rotjoinTheBeam(beam=None,e1=None,e2=None): if not (beam and e1 and e2): beam=beams()[1] e1,e2=edges() rot=FreeCAD.Rotation(e2.tangentAt(0),e1.tangentAt(0)) dist=dgu.findDistance(beam.Placement.Base,e1) delta=beam.Placement.Base-e2.CenterOfMass beam.Placement.Rotation=rot.multiply(beam.Placement.Rotation) beam.Placement.move(rounded(dist+rot.multVec(delta)))
def intersectionLines(p1=None, v1=None, p2=None, v2=None): # OBSOLETE: replaced with intersectionCLines ''' intersectionLines(p1,v1,p2,v2) If exist, returns the intersection (vector) between two lines p1,v1: the reference point and direction of first line p2,v2: the reference point and direction of second line ''' if None in [p1, p2, v1, v2]: eds = edges()[:2] p1, p2 = [e.valueAt(0) for e in eds] v1, v2 = [e.tangentAt(0) for e in eds] if not isParallel(v1, v2): dist = p1 - p2 import numpy #M=numpy.matrix([list(v1),list(v2),list(dist)]) # does not work: it seems for lack of accuracy of FreeCAD.Base.Vector operations! rowM1 = [round(x, 2) for x in v1] rowM2 = [round(x, 2) for x in v2] rowM3 = [round(x, 2) for x in dist] M = numpy.matrix([rowM1, rowM2, rowM3]) if numpy.linalg.det(M) == 0: #3 equations, 2 unknowns => 1 eq. must be dependent a11, a21, a31 = list(v1) a12, a22, a32 = list(v2 * -1) M1 = numpy.matrix([[a11, a12], [a21, a22]]) M2 = numpy.matrix([[a21, a22], [a31, a32]]) M3 = numpy.matrix([[a31, a32], [a11, a12]]) pl1 = list(p1) pl2 = list(p2) if numpy.linalg.det(M1) != 0: k = numpy.linalg.inv(M1) * numpy.matrix([[pl2[0] - pl1[0]], [pl2[1] - pl1[1]]]) elif numpy.linalg.det(M2) != 0: k = numpy.linalg.inv(M2) * numpy.matrix([[pl2[1] - pl1[1]], [pl2[2] - pl1[2]]]) else: k = numpy.linalg.inv(M3) * numpy.matrix([[pl2[2] - pl1[2]], [pl2[0] - pl1[0]]]) P = p1 + v1 * float(k[0]) # ..=p2+v2*float(k[1]) #FreeCAD.Console.PrintWarning("k1 = "+str(float(k[0]))+"\nk2 = "+str(float(k[1]))+"\n") return rounded(P) else: #se i vettori non sono complanari <=> intersezione nulla FreeCAD.Console.PrintError('Lines are not in the same plane.\n') return None else: #se i vettori sono paralleli <=> intersezione nulla FreeCAD.Console.PrintError('Lines are parallel.\n') return None
def intersectionLines(p1=None,v1=None,p2=None,v2=None): # OBSOLETE: replaced with intersectionCLines ''' intersectionLines(p1,v1,p2,v2) If exist, returns the intersection (vector) between two lines p1,v1: the reference point and direction of first line p2,v2: the reference point and direction of second line ''' if None in [p1,p2,v1,v2]: eds=edges()[:2] p1,p2=[e.valueAt(0) for e in eds] v1,v2=[e.tangentAt(0) for e in eds] if not isParallel(v1,v2): dist=p1-p2 import numpy #M=numpy.matrix([list(v1),list(v2),list(dist)]) # does not work: it seems for lack of accuracy of FreeCAD.Base.Vector operations! rowM1=[round(x,2) for x in v1] rowM2=[round(x,2) for x in v2] rowM3=[round(x,2) for x in dist] M=numpy.matrix([rowM1,rowM2,rowM3]) if numpy.linalg.det(M)==0: #3 equations, 2 unknowns => 1 eq. must be dependent a11,a21,a31=list(v1) a12,a22,a32=list(v2*-1) M1=numpy.matrix([[a11,a12],[a21,a22]]) M2=numpy.matrix([[a21,a22],[a31,a32]]) M3=numpy.matrix([[a31,a32],[a11,a12]]) pl1=list(p1) pl2=list(p2) if numpy.linalg.det(M1)!=0: k=numpy.linalg.inv(M1)*numpy.matrix([[pl2[0]-pl1[0]],[pl2[1]-pl1[1]]]) elif numpy.linalg.det(M2)!=0: k=numpy.linalg.inv(M2)*numpy.matrix([[pl2[1]-pl1[1]],[pl2[2]-pl1[2]]]) else: k=numpy.linalg.inv(M3)*numpy.matrix([[pl2[2]-pl1[2]],[pl2[0]-pl1[0]]]) P=p1+v1*float(k[0]) # ..=p2+v2*float(k[1]) #FreeCAD.Console.PrintWarning("k1 = "+str(float(k[0]))+"\nk2 = "+str(float(k[1]))+"\n") return rounded(P) else: #se i vettori non sono complanari <=> intersezione nulla FreeCAD.Console.PrintError('Lines are not in the same plane.\n') return None else: #se i vettori sono paralleli <=> intersezione nulla FreeCAD.Console.PrintError('Lines are parallel.\n') return None