def getGlobalRot(self,point): "Same as getGlobalCoords, but discards the WP position" vx = Vector(self.u).multiply(point.x) vy = Vector(self.v).multiply(point.y) vz = Vector(self.axis).multiply(point.z) pt = (vx.add(vy)).add(vz) return pt
def getGlobalCoords(self,point): "returns the global coordinates of the given point, taken relatively to this working plane" vx = Vector(self.u).multiply(point.x) vy = Vector(self.v).multiply(point.y) vz = Vector(self.axis).multiply(point.z) pt = (vx.add(vy)).add(vz) return pt.add(self.position)
def makeStraightStairsWithLanding(self,obj,edge): "builds a straight staircase with a landing in the middle" if obj.NumberOfSteps < 3: return import Part,DraftGeomUtils v = DraftGeomUtils.vec(edge) reslength = edge.Length - obj.Width.Value vLength = DraftVecUtils.scaleTo(v,float(reslength)/(obj.NumberOfSteps-2)) vLength = Vector(vLength.x,vLength.y,0) vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0,0,1)),obj.Width.Value) p1 = edge.Vertexes[0].Point if round(v.z,Draft.precision()) != 0: h = v.z else: h = obj.Height.Value hstep = h/obj.NumberOfSteps landing = obj.NumberOfSteps/2 p2 = p1.add(DraftVecUtils.scale(vLength,landing-1).add(Vector(0,0,landing*hstep))) p3 = p2.add(DraftVecUtils.scaleTo(vLength,obj.Width.Value)) p4 = p3.add(DraftVecUtils.scale(vLength,obj.NumberOfSteps-(landing+1)).add(Vector(0,0,(obj.NumberOfSteps-landing)*hstep))) self.makeStraightStairs(obj,Part.Line(p1,p2).toShape(),landing) self.makeStraightLanding(obj,Part.Line(p2,p3).toShape()) self.makeStraightStairs(obj,Part.Line(p3,p4).toShape(),obj.NumberOfSteps-landing)
def removeShape(objs, mark=True): """takes an arch object (wall or structure) built on a cubic shape, and removes the inner shape, keeping its length, width and height as parameters.""" import DraftGeomUtils if not isinstance(objs, list): objs = [objs] for obj in objs: if DraftGeomUtils.isCubic(obj.Shape): dims = DraftGeomUtils.getCubicDimensions(obj.Shape) if dims: name = obj.Name tp = Draft.getType(obj) print tp if tp == "Structure": FreeCAD.ActiveDocument.removeObject(name) import ArchStructure str = ArchStructure.makeStructure(length=dims[1], width=dims[2], height=dims[3], name=name) str.Placement = dims[0] elif tp == "Wall": FreeCAD.ActiveDocument.removeObject(name) import ArchWall length = dims[1] width = dims[2] v1 = Vector(length / 2, 0, 0) v2 = v1.negative() v1 = dims[0].multVec(v1) v2 = dims[0].multVec(v2) line = Draft.makeLine(v1, v2) wal = ArchWall.makeWall(line, width=width, height=dims[3], name=name) else: if mark: obj.ViewObject.ShapeColor = (1.0, 0.0, 0.0, 1.0)
def constrain(self,point,basepoint=None,axis=None): '''constrain(point,basepoint=None,axis=None: Returns a constrained point. Axis can be "x","y" or "z" or a custom vector. If None, the closest working plane axis will be picked. Basepoint is the base point used to figure out from where the point must be constrained. If no basepoint is given, the current point is used as basepoint.''' # without the Draft module fully loaded, no axes system!" if not hasattr(FreeCAD,"DraftWorkingPlane"): return point point = Vector(point) # setup trackers if needed if not self.constrainLine: self.constrainLine = DraftTrackers.lineTracker(dotted=True) # setting basepoint if not basepoint: if not self.basepoint: self.basepoint = point else: self.basepoint = basepoint delta = point.sub(self.basepoint) # setting constraint axis if not self.affinity: self.affinity = FreeCAD.DraftWorkingPlane.getClosestAxis(delta) if isinstance(axis,FreeCAD.Vector): self.constraintAxis = axis elif axis == "x": self.constraintAxis = FreeCAD.DraftWorkingPlane.u elif axis == "y": self.constraintAxis = FreeCAD.DraftWorkingPlane.v elif axis == "z": self.constraintAxis = FreeCAD.DraftWorkingPlane.axis else: if self.affinity == "x": self.constraintAxis = FreeCAD.DraftWorkingPlane.u elif self.affinity == "y": self.constraintAxis = FreeCAD.DraftWorkingPlane.v else: self.constraintAxis = FreeCAD.DraftWorkingPlane.axis # calculating constrained point cdelta = fcvec.project(delta,self.constraintAxis) npoint = self.basepoint.add(cdelta) # setting constrain line if self.constrainLine: if point != npoint: self.constrainLine.p1(point) self.constrainLine.p2(npoint) self.constrainLine.on() else: self.constrainLine.off() return npoint
def getDeviation(self): "returns the deviation angle between the u axis and the horizontal plane" proj = Vector(self.u.x,self.u.y,0) if self.u.getAngle(proj) == 0: return 0 else: norm = proj.cross(self.u) return DraftVecUtils.angle(self.u,proj,norm)
def equals(p1, p2): '''returns True if vertexes have same coordinates within precision amount of digits ''' precision = 12 p = precision u = Vector(p1.X, p1.Y, p1.Z) v = Vector(p2.X, p2.Y, p2.Z) vector = (u.sub(v)) isNull = (round(vector.x, p) == 0 and round(vector.y, p) == 0 and round(vector.z, p) == 0) return isNull
def alignToPointAndAxis_SVG(self, point, axis, offset): # based on cases table self.doc = FreeCAD.ActiveDocument self.axis = axis; self.axis.normalize() ref_vec = Vector(0.0, 1.0, 0.0) if ((abs(axis.x) > abs(axis.y)) and (abs(axis.y) > abs(axis.z))): ref_vec = Vector(0.0, 0., 1.0) self.u = axis.negative().cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis) #projcase = "Case new" elif ((abs(axis.y) > abs(axis.z)) and (abs(axis.z) >= abs(axis.x))): ref_vec = Vector(1.0, 0.0, 0.0) self.u = axis.negative().cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis) #projcase = "Y>Z, View Y" elif ((abs(axis.y) >= abs(axis.x)) and (abs(axis.x) > abs(axis.z))): ref_vec = Vector(0.0, 0., 1.0) self.u = axis.cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis) #projcase = "ehem. XY, Case XY" elif ((abs(axis.x) > abs(axis.z)) and (abs(axis.z) >= abs(axis.y))): self.u = axis.cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis) #projcase = "X>Z, View X" elif ((abs(axis.z) >= abs(axis.y)) and (abs(axis.y) > abs(axis.x))): ref_vec = Vector(1.0, 0., 0.0) self.u = axis.cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis) #projcase = "Y>X, Case YZ" else: self.u = axis.negative().cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi/2, self.axis) #projcase = "else" #spat_vec = self.u.cross(self.v) #spat_res = spat_vec.dot(axis) #FreeCAD.Console.PrintMessage(projcase + " spat Prod = " + str(spat_res) + "\n") offsetVector = Vector(axis); offsetVector.multiply(offset) self.position = point.add(offsetVector) self.weak = False
def __init__(self): # keep track of active document. Reset view when doc changes. self.doc = None # self.weak is true if the plane has been defined by self.setup or has been reset self.weak = True # u, v axes and position define plane, perpendicular axis is handy, though redundant. self.u = Vector(1,0,0) self.v = Vector(0,1,0) self.axis = Vector(0,0,1) self.position = Vector(0,0,0) # a placeholder for a stored state self.stored = None
def projectPointOld(self, p, direction=None): '''project point onto plane, default direction is orthogonal. Obsolete''' if not direction: direction = self.axis t = Vector(direction) #t.normalize() a = round(t.getAngle(self.axis),DraftVecUtils.precision()) pp = round((math.pi)/2,DraftVecUtils.precision()) if a == pp: return p t.multiply(self.offsetToPoint(p, direction)) return p.add(t)
def setString(self,text=None): "sets the dim string to the given value or auto value" self.dimnode.param1.setValue(.5) p1 = Vector(self.dimnode.pnts.getValues()[0].getValue()) p2 = Vector(self.dimnode.pnts.getValues()[-1].getValue()) m = self.dimnode.datumtype.getValue() if m == 2: self.Distance = (DraftVecUtils.project(p2.sub(p1),Vector(1,0,0))).Length elif m == 3: self.Distance = (DraftVecUtils.project(p2.sub(p1),Vector(0,1,0))).Length else: self.Distance = (p2.sub(p1)).Length if not text: text = Draft.getParam("dimPrecision",2) text = "%."+str(text)+"f" text = (text % self.Distance) self.dimnode.string.setValue(text)
def __init__(self, dotted=False, scolor=None, swidth=None): self.origin = Vector(0, 0, 0) line = coin.SoLineSet() line.numVertices.setValue(5) self.coords = coin.SoCoordinate3() # this is the coordinate self.coords.point.setValues(0, 5, [[0, 0, 0], [2, 0, 0], [2, 2, 0], [0, 2, 0], [0, 0, 0]]) Tracker.__init__(self, dotted, scolor, swidth, [self.coords, line]) self.u = plane.u self.v = plane.v
def alignToPointAndAxis(self, point, axis, offset, upvec=None): self.doc = FreeCAD.ActiveDocument self.axis = axis; self.axis.normalize() if (DraftVecUtils.equals(axis, Vector(1,0,0))): self.u = Vector(0,1,0) self.v = Vector(0,0,1) elif (DraftVecUtils.equals(axis, Vector(-1,0,0))): self.u = Vector(0,-1,0) self.v = Vector(0,0,1) elif upvec: self.v = upvec self.v.normalize() self.u = self.v.cross(self.axis) else: self.v = axis.cross(Vector(1,0,0)) self.v.normalize() self.u = DraftVecUtils.rotate(self.v, -math.pi/2, self.axis) offsetVector = Vector(axis); offsetVector.multiply(offset) self.position = point.add(offsetVector) self.weak = False
def __init__(self,dotted=False,scolor=None,swidth=None,face=False): self.origin = Vector(0,0,0) line = coin.SoLineSet() line.numVertices.setValue(5) self.coords = coin.SoCoordinate3() # this is the coordinate self.coords.point.setValues(0,50,[[0,0,0],[2,0,0],[2,2,0],[0,2,0],[0,0,0]]) if face: m1 = coin.SoMaterial() m1.transparency.setValue(0.5) m1.diffuseColor.setValue([0.5,0.5,1.0]) f = coin.SoIndexedFaceSet() f.coordIndex.setValues([0,1,2,3]) Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line,m1,f],name="rectangleTracker") else: Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line],name="rectangleTracker") self.u = FreeCAD.DraftWorkingPlane.u self.v = FreeCAD.DraftWorkingPlane.v
def createGeometry(self,obj): import Part, DraftGeomUtils # getting default values height = width = length = 1 if hasattr(obj,"Length"): if obj.Length: length = obj.Length if hasattr(obj,"Width"): if obj.Width: width = obj.Width if hasattr(obj,"Height"): if obj.Height: height = obj.Height # creating base shape pl = obj.Placement base = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Normal == Vector(0,0,0): p = FreeCAD.Placement(obj.Base.Placement) normal = p.Rotation.multVec(Vector(0,0,1)) else: normal = Vector(obj.Normal) normal = normal.multiply(height) base = obj.Base.Shape.copy() if base.Solids: pass elif base.Faces: base = base.extrude(normal) elif (len(base.Wires) == 1): if base.Wires[0].isClosed(): base = Part.Face(base.Wires[0]) base = base.extrude(normal) else: if obj.Normal == Vector(0,0,0): normal = Vector(0,0,1) else: normal = Vector(obj.Normal) normal = normal.multiply(height) l2 = length/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(-l2,-w2,0) v2 = Vector(l2,-w2,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base = Part.makePolygon([v1,v2,v3,v4,v1]) base = Part.Face(base) base = base.extrude(normal) if base: # applying adds and subs if not base.isNull(): for app in obj.Additions: if hasattr(app,"Shape"): if not app.Shape.isNull(): base = base.fuse(app.Shape) app.ViewObject.hide() # to be removed for hole in obj.Subtractions: if hasattr(hole,"Shape"): if not hole.Shape.isNull(): base = base.cut(hole.Shape) hole.ViewObject.hide() # to be removed # applying axes pts = self.getAxisPoints(obj) apl = self.getAxisPlacement(obj) if pts: fsh = [] for i in range(len(pts)): if hasattr(obj,"Exclude"): if i in obj.Exclude: continue sh = base.copy() if apl: sh.Placement.Rotation = apl.Rotation sh.translate(pts[i]) fsh.append(sh) obj.Shape = Part.makeCompound(fsh) # finalizing else: if base: if not base.isNull(): base = base.removeSplitter() obj.Shape = base if not DraftGeomUtils.isNull(pl): obj.Placement = pl
def getExtrusionData(self,obj): """returns (shape,extrusion vector,placement) or None""" import Part,DraftGeomUtils data = ArchComponent.Component.getExtrusionData(self,obj) if data: if not isinstance(data[0],list): # multifuses not considered here return data length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value if not height: for p in obj.InList: if Draft.getType(p) == "Floor": if p.Height.Value: height = p.Height.Value if obj.Normal == Vector(0,0,0): normal = Vector(0,0,1) else: normal = Vector(obj.Normal) base = None placement = None basewires = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: if obj.Base.Shape.Solids: return None elif obj.Face > 0: if len(obj.Base.Shape.Faces) >= obj.Face: face = obj.Base.Shape.Faces[obj.Face-1] # this wall is based on a specific face of its base object normal = face.normalAt(0,0) if normal.getAngle(Vector(0,0,1)) > math.pi/4: normal.multiply(width) base = face.extrude(normal) if obj.Align == "Center": base.translate(normal.negative().multiply(0.5)) elif obj.Align == "Right": base.translate(normal.negative()) else: normal.multiply(height) base = face.extrude(normal) base,placement = self.rebase(base) return (base,normal,placement) elif obj.Base.Shape.Faces: if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces): return None else: base,placement = self.rebase(obj.Base.Shape) elif obj.Base.Shape.Wires: basewires = obj.Base.Shape.Wires elif len(obj.Base.Shape.Edges) == 1: basewires = [Part.Wire(obj.Base.Shape.Edges)] if basewires and width: baseface = None for wire in basewires: e = wire.Edges[0] if isinstance(e.Curve,Part.Circle): dvec = e.Vertexes[0].Point.sub(e.Curve.Center) else: dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal) if not DraftVecUtils.isNull(dvec): dvec.normalize() sh = None if obj.Align == "Left": dvec.multiply(width) if obj.Offset.Value: dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Right": dvec.multiply(width) dvec = dvec.negative() if obj.Offset.Value: dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Center": dvec.multiply(width/2) w1 = DraftGeomUtils.offsetWire(wire,dvec) dvec = dvec.negative() w2 = DraftGeomUtils.offsetWire(wire,dvec) sh = DraftGeomUtils.bind(w1,w2) if sh: sh.fix(0.1,0,1) # fixes self-intersecting wires f = Part.Face(sh) if baseface: baseface = baseface.fuse(f) else: baseface = f if baseface: base,placement = self.rebase(baseface) else: l2 = length/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(-l2,-w2,0) v2 = Vector(l2,-w2,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])) placement = FreeCAD.Placement() if base and placement: extrusion = normal.multiply(height) return (base,extrusion,placement) return None
def execute(self,obj): "creates the panel shape" if self.clone(obj): return import Part, DraftGeomUtils # base tests if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return elif obj.Base.isDerivedFrom("Mesh::Feature"): if not obj.Base.Mesh.isSolid(): return else: if obj.Length.Value: length = obj.Length.Value else: return if obj.Width.Value: width = obj.Width.Value else: return if obj.Thickness.Value: thickness = obj.Thickness.Value else: if not obj.Base: return elif obj.Base.isDerivedFrom("Part::Feature"): if not obj.Base.Shape.Solids: return # creating base shape pl = obj.Placement base = None normal = None baseprofile = None if obj.Base: base = obj.Base.Shape.copy() if not base.Solids: p = FreeCAD.Placement(obj.Base.Placement) if base.Faces: baseprofile = base normal = baseprofile.Faces[0].normalAt(0,0).multiply(thickness) base = base.extrude(normal) elif base.Wires: closed = True for w in base.Wires: if not w.isClosed(): closed = False if closed: baseprofile = ArchCommands.makeFace(base.Wires) normal = baseprofile.normalAt(0,0).multiply(thickness) base = baseprofile.extrude(normal) elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids: base = sh else: normal = Vector(0,0,1).multiply(thickness) l2 = length/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(-l2,-w2,0) v2 = Vector(l2,-w2,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base = Part.makePolygon([v1,v2,v3,v4,v1]) baseprofile = Part.Face(base) base = baseprofile.extrude(normal) if hasattr(obj,"Area"): if baseprofile: obj.Area = baseprofile.Area if hasattr(obj,"WaveLength"): if baseprofile and obj.WaveLength.Value and obj.WaveHeight.Value: # corrugated element bb = baseprofile.BoundBox bb.enlarge(bb.DiagonalLength) p1 = Vector(bb.getPoint(0).x,bb.getPoint(0).y,bb.Center.z) if obj.WaveType == "Curved": p2 = p1.add(Vector(obj.WaveLength.Value/2,0,obj.WaveHeight.Value)) p3 = p2.add(Vector(obj.WaveLength.Value/2,0,-obj.WaveHeight.Value)) e1 = Part.Arc(p1,p2,p3).toShape() p4 = p3.add(Vector(obj.WaveLength.Value/2,0,-obj.WaveHeight.Value)) p5 = p4.add(Vector(obj.WaveLength.Value/2,0,obj.WaveHeight.Value)) e2 = Part.Arc(p3,p4,p5).toShape() else: if obj.WaveHeight.Value < obj.WaveLength.Value: p2 = p1.add(Vector(obj.WaveHeight.Value,0,obj.WaveHeight.Value)) p3 = p2.add(Vector(obj.WaveLength.Value-2*obj.WaveHeight.Value,0,0)) p4 = p3.add(Vector(obj.WaveHeight.Value,0,-obj.WaveHeight.Value)) e1 = Part.makePolygon([p1,p2,p3,p4]) p5 = p4.add(Vector(obj.WaveHeight.Value,0,-obj.WaveHeight.Value)) p6 = p5.add(Vector(obj.WaveLength.Value-2*obj.WaveHeight.Value,0,0)) p7 = p6.add(Vector(obj.WaveHeight.Value,0,obj.WaveHeight.Value)) e2 = Part.makePolygon([p4,p5,p6,p7]) else: p2 = p1.add(Vector(obj.WaveLength.Value/2,0,obj.WaveHeight.Value)) p3 = p2.add(Vector(obj.WaveLength.Value/2,0,-obj.WaveHeight.Value)) e1 = Part.makePolygon([p1,p2,p3]) p4 = p3.add(Vector(obj.WaveLength.Value/2,0,-obj.WaveHeight.Value)) p5 = p4.add(Vector(obj.WaveLength.Value/2,0,obj.WaveHeight.Value)) e2 = Part.makePolygon([p3,p4,p5]) edges = [e1,e2] for i in range(int(bb.XLength/(obj.WaveLength.Value*2))): e1 = e1.copy() e1.translate(Vector(obj.WaveLength.Value*2,0,0)) e2 = e2.copy() e2.translate(Vector(obj.WaveLength.Value*2,0,0)) edges.extend([e1,e2]) basewire = Part.Wire(edges) baseface = basewire.extrude(Vector(0,bb.YLength,0)) base = baseface.extrude(Vector(0,0,thickness)) rot = FreeCAD.Rotation(FreeCAD.Vector(0,0,1),normal) base.rotate(bb.Center,rot.Axis,math.degrees(rot.Angle)) if obj.WaveDirection.Value: base.rotate(bb.Center,normal,obj.WaveDirection.Value) n1 = normal.negative().normalize().multiply(obj.WaveHeight.Value*2) self.vol = baseprofile.copy() self.vol.translate(n1) self.vol = self.vol.extrude(n1.negative().multiply(2)) base = self.vol.common(base) base = base.removeSplitter() if not base: FreeCAD.Console.PrintError(transpate("Arch","Error computing shape of ")+obj.Label+"\n") return False if base and (obj.Sheets > 1) and normal and thickness: bases = [base] for i in range(1,obj.Sheets): n = FreeCAD.Vector(normal).normalize().multiply(i*thickness) b = base.copy() b.translate(n) bases.append(b) base = Part.makeCompound(bases) if base and normal and hasattr(obj,"Offset"): if obj.Offset.Value: v = DraftVecUtils.scaleTo(normal,obj.Offset.Value) base.translate(v) # process subshapes base = self.processSubShapes(obj,base,pl) # applying if base: if not base.isNull(): if base.isValid() and base.Solids: if base.Volume < 0: base.reverse() if base.Volume < 0: FreeCAD.Console.PrintError(translate("Arch","Couldn't compute a shape")) return base = base.removeSplitter() obj.Shape = base if not pl.isNull(): obj.Placement = pl
def getDeviation(self): "returns a deviation vector that represents the base of the circle" import Part c = Part.makeCircle(1, Vector(0, 0, 0), self.normal) return c.Vertexes[0].Point
def test00(self): """Check Tag origin.""" tag = Tag(0, 77, 13, 4, 5, 90, True) self.assertCoincide(tag.originAt(3), Vector(77, 13, 3))
def getLength(self): "returns the length of the line" p1 = Vector(self.coords.point.getValues()[0].getValue()) p2 = Vector(self.coords.point.getValues()[-1].getValue()) return (p2.sub(p1)).Length
def makeStraightStairs(self,obj,edge,numberofsteps=None): "builds a simple, straight staircase from a straight edge" # general data import Part,DraftGeomUtils if not numberofsteps: numberofsteps = obj.NumberOfSteps v = DraftGeomUtils.vec(edge) vLength = DraftVecUtils.scaleTo(v,float(edge.Length)/(numberofsteps-1)) vLength = Vector(vLength.x,vLength.y,0) if round(v.z,Draft.precision()) != 0: h = v.z else: h = obj.Height.Value vHeight = Vector(0,0,float(h)/numberofsteps) vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0,0,1)),obj.Width.Value) vBase = edge.Vertexes[0].Point vNose = DraftVecUtils.scaleTo(vLength,-abs(obj.Nosing.Value)) a = math.atan(vHeight.Length/vLength.Length) #print "stair data:",vLength.Length,":",vHeight.Length # steps for i in range(numberofsteps-1): p1 = vBase.add((Vector(vLength).multiply(i)).add(Vector(vHeight).multiply(i+1))) p1 = self.align(p1,obj.Align,vWidth) p1 = p1.add(vNose).add(Vector(0,0,-abs(obj.TreadThickness.Value))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) step = Part.Face(Part.makePolygon([p1,p2,p3,p4,p1])) if obj.TreadThickness.Value: step = step.extrude(Vector(0,0,abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) # structure lProfile = [] struct = None if obj.Structure == "Massive": if obj.StructureThickness.Value: for i in range(numberofsteps-1): if not lProfile: lProfile.append(vBase) last = lProfile[-1] if len(lProfile) == 1: last = last.add(Vector(0,0,-abs(obj.TreadThickness.Value))) lProfile.append(last.add(vHeight)) lProfile.append(lProfile[-1].add(vLength)) resHeight1 = obj.StructureThickness.Value/math.cos(a) lProfile.append(lProfile[-1].add(Vector(0,0,-resHeight1))) resHeight2 = ((numberofsteps-1)*vHeight.Length)-(resHeight1+obj.TreadThickness.Value) resLength = (vLength.Length/vHeight.Length)*resHeight2 h = DraftVecUtils.scaleTo(vLength,-resLength) lProfile.append(lProfile[-1].add(Vector(h.x,h.y,-resHeight2))) lProfile.append(vBase) #print lProfile pol = Part.makePolygon(lProfile) struct = Part.Face(pol) evec = vWidth if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) struct.translate(mvec) evec = DraftVecUtils.scaleTo(evec,evec.Length-(2*mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer","Two stringers"]: if obj.StringerWidth.Value and obj.StructureThickness.Value: hyp = math.sqrt(vHeight.Length**2 + vLength.Length**2) l1 = Vector(vLength).multiply(numberofsteps-1) h1 = Vector(vHeight).multiply(numberofsteps-1).add(Vector(0,0,-abs(obj.TreadThickness.Value))) p1 = vBase.add(l1).add(h1) p1 = self.align(p1,obj.Align,vWidth) lProfile.append(p1) h2 = (obj.StructureThickness.Value/vLength.Length)*hyp lProfile.append(lProfile[-1].add(Vector(0,0,-abs(h2)))) h3 = lProfile[-1].z-vBase.z l3 = (h3/vHeight.Length)*vLength.Length v3 = DraftVecUtils.scaleTo(vLength,-l3) lProfile.append(lProfile[-1].add(Vector(0,0,-abs(h3))).add(v3)) l4 = (obj.StructureThickness.Value/vHeight.Length)*hyp v4 = DraftVecUtils.scaleTo(vLength,-l4) lProfile.append(lProfile[-1].add(v4)) lProfile.append(lProfile[0]) #print lProfile pol = Part.makePolygon(lProfile) pol = Part.Face(pol) evec = DraftVecUtils.scaleTo(vWidth,obj.StringerWidth.Value) if obj.Structure == "One stringer": if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) else: mvec = DraftVecUtils.scaleTo(vWidth,(vWidth.Length/2)-obj.StringerWidth.Value/2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1,s2]) if struct: self.structures.append(struct)
def __init__(self, obj, _rootRib, _path, _enveloppe, _leadingedge, _traillingedge, _rootChord=200, _tipChord=100, _panelLength=100, _tipTwist=0, _dihedral=0, axis=Vector(0.0, 0.0, 0.0), items=5, OffsetStart=0, OffsetEnd=0, _distribution='linear', _distributionReverse=False, extract=False, Twist=0, _ribs=[]): #_rootRib,_tipRib, '''Add some custom properties to our box feature''' self.obj = obj obj.addProperty( "App::PropertyLink", "Base", "WingPanel", QtCore.QT_TRANSLATE_NOOP( "App::Property", "Tip Rib of the panel")).Base = _rootRib # obj.addProperty( "App::PropertyLink", "Enveloppe", "WPRibs", QtCore.QT_TRANSLATE_NOOP( "App::Property", "Eveloppe of wing")).Enveloppe = _enveloppe obj.addProperty( "App::PropertyLink", "Path", "WPRibs", QtCore.QT_TRANSLATE_NOOP("App::Property", "Path of wing")).Path = _path # generated Ribs obj.addProperty( "App::PropertyLinkList", "Ribs", "WPRibs", QtCore.QT_TRANSLATE_NOOP("App::Property", "Ribs of the panel")).Ribs = _ribs # need to convert into function not attributes obj.addProperty("App::PropertyLength", "TipChord", "WPRibs", QtCore.QT_TRANSLATE_NOOP( "App::Property", "Tip Chord")).TipChord = _tipChord obj.addProperty( "App::PropertyLength", "RootChord", "WPRibs", QtCore.QT_TRANSLATE_NOOP("App::Property", "Root Chord")).RootChord = _rootChord obj.addProperty( "App::PropertyLength", "PanelLength", "Design", QtCore.QT_TRANSLATE_NOOP( "App::Property", "Panel Length")).PanelLength = _panelLength # need to convert into function not attributes obj.addProperty("App::PropertyVector", "Axis", "WingPanel", "Direction axis").Axis = axis obj.addProperty( "App::PropertyLinkList", "Hullcurves", "WingEdge", "Bounding curves").Hullcurves = [_leadingedge, _traillingedge] # leadingEdge : bord d'attaque obj.addProperty( "App::PropertyLinkList", "Edges", "WingEdges", QtCore.QT_TRANSLATE_NOOP( "App::Property", "Select the leading edge of the panal, line or Spline") ).Edges = [] obj.addProperty( "App::PropertyLink", "LeadingEdge", "WingEdges", QtCore.QT_TRANSLATE_NOOP( "App::Property", "Select the leading edge of the panal, line or Spline") ).LeadingEdge = _leadingedge # trailing edge : bord de fuite obj.addProperty( "App::PropertyLink", "TrailingEdge", "WingEdges", QtCore.QT_TRANSLATE_NOOP( "App::Property", "Select the trailing edge of the panel, line or Spline") ).TrailingEdge = _traillingedge obj.addProperty("App::PropertyAngle", "TipTwist", "Design", QtCore.QT_TRANSLATE_NOOP( "App::Property", "Tip Twist")).TipTwist = _tipTwist obj.addProperty("App::PropertyAngle", "Dihedral", "Design", QtCore.QT_TRANSLATE_NOOP( "App::Property", "Dihedral")).Dihedral = _dihedral #obj.addProperty("App::PropertyLinkList","Ribs","WingPanel",QtCore.QT_TRANSLATE_NOOP("App::Property","list of ribs")).Ribs=[] obj.addProperty("App::PropertyBool", "Solid", "Design", QtCore.QT_TRANSLATE_NOOP("App::Property", "Solid")).Solid = False obj.addProperty("App::PropertyBool", "Surface", "Design", QtCore.QT_TRANSLATE_NOOP("App::Property", "Surface")).Surface = False obj.addProperty("App::PropertyBool", "Structure", "Design", QtCore.QT_TRANSLATE_NOOP("App::Property", "Surface")).Structure = False obj.addProperty("App::PropertyQuantity", "Items", "Design", "Nr. of array items").Items = items obj.addProperty("App::PropertyFloat", "OffsetStart", "Design", "Offset of the first part in Axis direction" ).OffsetStart = OffsetStart obj.addProperty( "App::PropertyFloat", "OffsetEnd", "Design", "Offset of the last part from the end in opposite Axis direction" ).OffsetEnd = OffsetEnd obj.addProperty("App::PropertyFloat", "Twist", "Design", "Rotate around Axis in degrees").Twist = Twist obj.addProperty( "App::PropertyEnumeration", "Distribution", "Design", QtCore.QT_TRANSLATE_NOOP( "App::Property", "Algorithm for distance between elements")) obj.addProperty( "App::PropertyBool", "DistributionReverse", "Design", QtCore.QT_TRANSLATE_NOOP( "App::Property", "Reverses direction of Distribution algorithm" )).DistributionReverse = _distributionReverse obj.Distribution = [ 'linear', 'parabolic', 'x³', 'sinusoidal', 'elliptic' ] obj.Distribution = _distribution self.extract = extract self.doScaleXYZ = [] self.doScaleXYZsum = [False, False, False] obj.Base.Visibility = False obj.Proxy = self
def scaleByBoundbox2(shape, boundbox, doScaleXYZ): basebbox = shape.BoundBox scalevec = Vector(1, 1, 1) x = shape.Placement.Base.x y = shape.Placement.Base.y z = shape.Placement.Base.z if doScaleXYZ[0] and basebbox.XLength > epsilon: scalevec.x = boundbox.XLength / basebbox.XLength if doScaleXYZ[1] and basebbox.YLength > epsilon: scalevec.y = boundbox.YLength / basebbox.YLength if doScaleXYZ[2] and basebbox.ZLength > epsilon: scalevec.z = boundbox.ZLength / basebbox.ZLength scalevec.x = boundbox.XLength scalevec.y = boundbox.YLength scalevec.z = boundbox.ZLength if scalevec.x < epsilon: if doScaleXYZ[0]: scalevec.x = epsilon else: scalevec.x = 1 if scalevec.y < epsilon: if doScaleXYZ[1]: scalevec.y = epsilon else: scalevec.y = 1 if scalevec.z < epsilon: if doScaleXYZ[2]: scalevec.z = epsilon else: scalevec.z = 1 if doScaleXYZ[0]: x += boundbox.XMin - basebbox.XMin * scalevec.x if doScaleXYZ[1]: y += boundbox.YMin - basebbox.YMin * scalevec.y if doScaleXYZ[2]: z += boundbox.ZMin - basebbox.ZMin * scalevec.z return x, y, z, scalevec.x, scalevec.y, scalevec.z
def test50(self): """Verify proper wire(s) aggregation from a Path.""" commands = [] commands.append(Path.Command('G1', {'X': 1})) commands.append(Path.Command('G1', {'Y': 1})) commands.append(Path.Command('G0', {'X': 0})) commands.append(Path.Command('G1', {'Y': 0})) wire = PathGeom.wireForPath(Path.Path(commands)) self.assertEqual(len(wire.Edges), 4) self.assertLine(wire.Edges[0], Vector(0, 0, 0), Vector(1, 0, 0)) self.assertLine(wire.Edges[1], Vector(1, 0, 0), Vector(1, 1, 0)) self.assertLine(wire.Edges[2], Vector(1, 1, 0), Vector(0, 1, 0)) self.assertLine(wire.Edges[3], Vector(0, 1, 0), Vector(0, 0, 0)) wires = PathGeom.wiresForPath(Path.Path(commands)) self.assertEqual(len(wires), 2) self.assertEqual(len(wires[0].Edges), 2) self.assertLine(wires[0].Edges[0], Vector(0, 0, 0), Vector(1, 0, 0)) self.assertLine(wires[0].Edges[1], Vector(1, 0, 0), Vector(1, 1, 0)) self.assertEqual(len(wires[1].Edges), 1) self.assertLine(wires[1].Edges[0], Vector(0, 1, 0), Vector(0, 0, 0))
def test30(self): """Verify proper geometry for arcs with rising and fall ing Z-axis are created.""" #print("------ rising helix -------") p1 = Vector(0, 1, 0) p2 = Vector(1, 0, 2) self.assertCurve( PathGeom.edgeForCmd( Path.Command('G2', { 'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'I': 0, 'J': -1, 'K': 1 }), p1), p1, Vector(1 / math.sqrt(2), 1 / math.sqrt(2), 1), p2) p1 = Vector(-1, 0, 0) p2 = Vector(0, -1, 2) self.assertCurve( PathGeom.edgeForCmd( Path.Command('G3', { 'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'I': 1, 'J': 0, 'K': 1 }), p1), p1, Vector(-1 / math.sqrt(2), -1 / math.sqrt(2), 1), p2) #print("------ falling helix -------") p1 = Vector(0, -1, 2) p2 = Vector(-1, 0, 0) self.assertCurve( PathGeom.edgeForCmd( Path.Command('G2', { 'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'I': 0, 'J': 1, 'K': -1 }), p1), p1, Vector(-1 / math.sqrt(2), -1 / math.sqrt(2), 1), p2) p1 = Vector(-1, 0, 2) p2 = Vector(0, -1, 0) self.assertCurve( PathGeom.edgeForCmd( Path.Command('G3', { 'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'I': 1, 'J': 0, 'K': -1 }), p1), p1, Vector(-1 / math.sqrt(2), -1 / math.sqrt(2), 1), p2)
def assertCircle(self, edge, pt, r): """Verivy that edge is a circle at given location.""" curve = edge.Curve self.assertIs(type(curve), Part.Circle) self.assertCoincide(curve.Center, Vector(pt.x, pt.y, pt.z)) self.assertRoughly(curve.Radius, r)
def get(self): p = self.coords.point.getValues()[0] return Vector(p[0], p[1], p[2])
def getExtrusionData(self,obj): """returns (shape,extrusion vector,placement) or None""" import Part,DraftGeomUtils data = ArchComponent.Component.getExtrusionData(self,obj) if data: if not isinstance(data[0],list): # multifuses not considered here return data length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value if not height: for p in obj.InList: if Draft.getType(p) in ["Floor","BuildingPart"]: if p.Height.Value: height = p.Height.Value if not height: return None if obj.Normal == Vector(0,0,0): normal = Vector(0,0,1) else: normal = Vector(obj.Normal) base = None placement = None self.basewires = None # build wall layers layers = [] if hasattr(obj,"Material"): if obj.Material: if hasattr(obj.Material,"Materials"): varwidth = 0 restwidth = width - sum(obj.Material.Thicknesses) if restwidth > 0: varwidth = [t for t in obj.Material.Thicknesses if t == 0] if varwidth: varwidth = restwidth/len(varwidth) for t in obj.Material.Thicknesses: if t: layers.append(t) elif varwidth: layers.append(varwidth) if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: if obj.Base.Shape.Solids: return None elif obj.Face > 0: if len(obj.Base.Shape.Faces) >= obj.Face: face = obj.Base.Shape.Faces[obj.Face-1] # this wall is based on a specific face of its base object if obj.Normal != Vector(0,0,0): normal = face.normalAt(0,0) if normal.getAngle(Vector(0,0,1)) > math.pi/4: normal.multiply(width) base = face.extrude(normal) if obj.Align == "Center": base.translate(normal.negative().multiply(0.5)) elif obj.Align == "Right": base.translate(normal.negative()) else: normal.multiply(height) base = face.extrude(normal) base,placement = self.rebase(base) return (base,normal,placement) elif obj.Base.Shape.Faces: if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces): return None else: base,placement = self.rebase(obj.Base.Shape) elif len(obj.Base.Shape.Edges) == 1: self.basewires = [Part.Wire(obj.Base.Shape.Edges)] else: # self.basewires = obj.Base.Shape.Wires self.basewires = [] for cluster in Part.getSortedClusters(obj.Base.Shape.Edges): for c in Part.sortEdges(cluster): self.basewires.append(Part.Wire(c)) if self.basewires and width: if (len(self.basewires) == 1) and layers: self.basewires = [self.basewires[0] for l in layers] layeroffset = 0 baseface = None for i,wire in enumerate(self.basewires): e = wire.Edges[0] if isinstance(e.Curve,Part.Circle): dvec = e.Vertexes[0].Point.sub(e.Curve.Center) else: dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal) if not DraftVecUtils.isNull(dvec): dvec.normalize() sh = None if obj.Align == "Left": off = obj.Offset.Value if layers: off = off+layeroffset dvec.multiply(layers[i]) layeroffset += layers[i] else: dvec.multiply(width) if off: dvec2 = DraftVecUtils.scaleTo(dvec,off) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Right": dvec = dvec.negative() off = obj.Offset.Value if layers: off = off+layeroffset dvec.multiply(layers[i]) layeroffset += layers[i] else: dvec.multiply(width) if off: dvec2 = DraftVecUtils.scaleTo(dvec,off) wire = DraftGeomUtils.offsetWire(wire,dvec2) w2 = DraftGeomUtils.offsetWire(wire,dvec) w1 = Part.Wire(Part.__sortEdges__(wire.Edges)) sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Center": if layers: off = width/2-layeroffset d1 = Vector(dvec).multiply(off) w1 = DraftGeomUtils.offsetWire(wire,d1) layeroffset += layers[i] off = width/2-layeroffset d1 = Vector(dvec).multiply(off) w2 = DraftGeomUtils.offsetWire(wire,d1) else: dvec.multiply(width/2) w1 = DraftGeomUtils.offsetWire(wire,dvec) dvec = dvec.negative() w2 = DraftGeomUtils.offsetWire(wire,dvec) sh = DraftGeomUtils.bind(w1,w2) if sh: sh.fix(0.1,0,1) # fixes self-intersecting wires f = Part.Face(sh) if baseface: if layers: baseface.append(f) else: baseface = baseface.fuse(f) # baseface = baseface.removeSplitter() s = DraftGeomUtils.removeSplitter(baseface) if s: baseface = s else: if layers: baseface = [f] else: baseface = f if baseface: base,placement = self.rebase(baseface) else: if layers: totalwidth = sum(layers) offset = 0 base = [] for l in layers: l2 = length/2 or 0.5 w1 = -totalwidth/2 + offset w2 = w1 + l v1 = Vector(-l2,w1,0) v2 = Vector(l2,w1,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base.append(Part.Face(Part.makePolygon([v1,v2,v3,v4,v1]))) offset += l else: l2 = length/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(-l2,-w2,0) v2 = Vector(l2,-w2,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])) placement = FreeCAD.Placement() if base and placement: extrusion = normal.multiply(height) if placement.Rotation.Angle > 0: extrusion = placement.inverse().Rotation.multVec(extrusion) return (base,extrusion,placement) return None
def execute(self,obj): "creates the structure shape" import Part, DraftGeomUtils # getting default values length = 1 width = 1 height = 1 if hasattr(obj,"Length"): if obj.Length.Value: length = obj.Length.Value if hasattr(obj,"Width"): if obj.Width.Value: width = obj.Width.Value if hasattr(obj,"Height"): if obj.Height.Value: height = obj.Height.Value else: for p in obj.InList: if Draft.getType(p) == "Floor": if p.Height.Value: height = p.Height.Value # creating base shape pl = obj.Placement base = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return if hasattr(obj,"Tool"): if obj.Tool: try: base = obj.Tool.Shape.copy().makePipe(obj.Base.Shape.copy()) except: FreeCAD.Console.PrintError(translate("Arch","Error: The base shape couldn't be extruded along this tool object")) return if not base: if obj.Normal == Vector(0,0,0): p = FreeCAD.Placement(obj.Base.Placement) normal = p.Rotation.multVec(Vector(0,0,1)) else: normal = Vector(obj.Normal) normal = normal.multiply(height) base = obj.Base.Shape.copy() if base.Solids: pass elif base.Faces: self.BaseProfile = base self.ExtrusionVector = normal base = base.extrude(normal) elif (len(base.Wires) == 1): if base.Wires[0].isClosed(): base = Part.Face(base.Wires[0]) self.BaseProfile = base self.ExtrusionVector = normal base = base.extrude(normal) elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids: base = sh else: if obj.Normal == Vector(0,0,0): if length > height: normal = Vector(1,0,0).multiply(length) else: normal = Vector(0,0,1).multiply(height) else: normal = Vector(obj.Normal).multiply(height) self.ExtrusionVector = normal if length > height: h2 = height/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(0,-w2,-h2) v2 = Vector(0,-w2,h2) v3 = Vector(0,w2,h2) v4 = Vector(0,w2,-h2) else: l2 = length/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(-l2,-w2,0) v2 = Vector(l2,-w2,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base = Part.makePolygon([v1,v2,v3,v4,v1]) base = Part.Face(base) self.BaseProfile = base base = base.extrude(self.ExtrusionVector) base = self.processSubShapes(obj,base,pl) if base: # applying axes pts = self.getAxisPoints(obj) apl = self.getAxisPlacement(obj) if pts: fsh = [] for i in range(len(pts)): if hasattr(obj,"Exclude"): if i in obj.Exclude: continue sh = base.copy() if apl: sh.Placement.Rotation = apl.Rotation sh.translate(pts[i]) fsh.append(sh) obj.Shape = Part.makeCompound(fsh) # finalizing else: if base: if not base.isNull(): if base.isValid() and base.Solids: if base.Volume < 0: base.reverse() if base.Volume < 0: FreeCAD.Console.PrintError(translate("Arch","Couldn't compute a shape")) return base = base.removeSplitter() obj.Shape = base if not pl.isNull(): obj.Placement = pl
def scaleByBoundbox(shape, boundbox, doScaleXYZ, copy=True): basebbox = shape.BoundBox #basebbox=[1.0,1.0,1.0] scalevec = Vector(1, 1, 1) if doScaleXYZ[0] and basebbox.XLength > epsilon: scalevec.x = boundbox.XLength / basebbox.XLength if doScaleXYZ[1] and basebbox.YLength > epsilon: scalevec.y = boundbox.YLength / basebbox.YLength if doScaleXYZ[2] and basebbox.ZLength > epsilon: scalevec.z = boundbox.ZLength / basebbox.ZLength scalevec.x = boundbox.XLength scalevec.y = boundbox.YLength scalevec.z = boundbox.ZLength if scalevec.x < epsilon: if doScaleXYZ[0]: scalevec.x = epsilon else: scalevec.x = 1 if scalevec.y < epsilon: if doScaleXYZ[1]: scalevec.y = epsilon else: scalevec.y = 1 if scalevec.z < epsilon: if doScaleXYZ[2]: scalevec.z = epsilon else: scalevec.z = 1 _rib = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Rib00") print("Scale in scaleByBoundbox") print(scalevec) WingRib( _rib, "/Users/fredericnivoix/Library/Preferences/FreeCAD/Mod/AirPlaneDesign/wingribprofil/naca/naca2412.dat", False, 0, scalevec.x, 0, 0, 0, 0, 0, 0) ViewProviderWingRib(_rib.ViewObject) _rib.Placement = shape.Placement #dolly = scale(shape, scalevec, basebbox.Center, copy) #dolly.Placement = shape.Placement if doScaleXYZ[0]: _rib.Placement.Base.x += boundbox.XMin - basebbox.XMin * scalevec.x if doScaleXYZ[1]: _rib.Placement.Base.y += boundbox.YMin - basebbox.YMin * scalevec.y if doScaleXYZ[2]: _rib.Placement.Base.z += boundbox.ZMin - basebbox.ZMin * scalevec.z return _rib #dolly
def displacement(ship, draft, roll=0.0, trim=0.0, yaw=0.0): """ Compute the ship displacement. @param ship Ship instance. @param draft Ship draft. @param roll Ship roll angle. @param trim Ship trim angle. @param yaw Ship yaw angle. Ussually you don't want to use this value. @return [disp, B, Cb], \n - disp = Ship displacement [ton]. - B = Bouyance center [m]. - Cb = Block coefficient. @note Bouyance center will returned as a FreeCAD.Vector instance. @note Returned Bouyance center is in the non modified ship coordinates """ # We will take a duplicate of ship shape in order to conviniently # manipulate it shape = ship.Shape.copy() shape.translate(Vector(0.0, 0.0, -draft * Units.Metre.Value)) shape.rotate(Vector(0.0, 0.0, 0.0), Vector(1.0, 0.0, 0.0), roll) shape.rotate(Vector(0.0, 0.0, 0.0), Vector(0.0, -1.0, 0.0), trim) shape.rotate(Vector(0.0, 0.0, 0.0), Vector(0.0, 0.0, 1.0), yaw) bbox = shape.BoundBox xmin = bbox.XMin xmax = bbox.XMax # Create the "sea" box to intersect the ship L = xmax - xmin B = bbox.YMax - bbox.YMin p = Vector(-1.5*L, -1.5*B, bbox.ZMin - 1.0) try: box = Part.makeBox(3.0*L, 3.0*B, - bbox.ZMin + 1.0, p) except: return [0.0, Vector(), 0.0] vol = 0.0 cog = Vector() for solid in shape.Solids: # Compute the common part of the "sea" with the ship try: common = box.common(solid) except: continue # Get the data vol = vol + common.Volume / Units.Metre.Value**3 for s in common.Solids: sCoG = s.CenterOfMass cog.x = cog.x + sCoG.x * s.Volume / Units.Metre.Value**4 cog.y = cog.y + sCoG.y * s.Volume / Units.Metre.Value**4 cog.z = cog.z + sCoG.z * s.Volume / Units.Metre.Value**4 cog.x = cog.x / vol cog.y = cog.y / vol cog.z = cog.z / vol Vol = L * B * abs(bbox.ZMin) / Units.Metre.Value**3 # Undo the transformations B = Vector() B.x = cog.x * math.cos(math.radians(-yaw)) - \ cog.y * math.sin(math.radians(-yaw)) B.y = cog.x * math.sin(math.radians(-yaw)) + \ cog.y * math.cos(math.radians(-yaw)) B.z = cog.z cog.x = B.x * math.cos(math.radians(-trim)) - \ B.z * math.sin(math.radians(-trim)) cog.y = B.y cog.z = B.x * math.sin(math.radians(-trim)) + \ B.z * math.cos(math.radians(-trim)) B.x = cog.x B.y = cog.y * math.cos(math.radians(-roll)) - \ cog.z * math.sin(math.radians(-roll)) B.z = cog.y * math.sin(math.radians(-roll)) + \ cog.z * math.cos(math.radians(-roll)) B.z = B.z + draft # Return the computed data dens = 1.025 # [tons/m3], salt water return [dens*vol, B, vol/Vol]
def make(initial_placement: Placement = Placement(), origin_translation_offset: Vector = Vector()): """Make an extruder. :param initial_placement: Initial placement for part. :param origin_translation_offset: Offset part from origin. :return: Extruder object. """ main_part_width = 50 main_part_length = 87 main_part_bottom_base_overhang_width = 5 main_part = MainExtruderPart.make( main_part_width, main_part_length, main_part_bottom_base_overhang_width) cooling_and_sensor_slanted_side_width = 4 cooling_and_sensor_mount = CoolingAndSensorMount.make( cooling_and_sensor_slanted_side_width, main_part_length, main_part_bottom_base_overhang_width) cooling_and_sensor_mount.translate( Vector(0, main_part_bottom_base_overhang_width, 0)) blower_radius = 45 / 2 blower_width = 15.4 blower = Part.makeCylinder(blower_radius, blower_width) blower.rotate(Vector(0, 0, 0), Vector(0, -1, 0), 90) blower_y = 15.25 + blower_radius blower.translate( Vector(-cooling_and_sensor_slanted_side_width, blower_y, blower_radius)) # TODO: Remove duplication of sensor_holder_width # from extruder_model.py and cooling_and_sensor_mount.py # Should blower box even use sensor_holder_width, # or should the blower be independent from knowledge of # cooling and sensor mount? sensor_holder_width = 25 blower_box_y_offset = main_part_bottom_base_overhang_width + \ CoolingAndSensorMount.vent_box_width blower_box = Part.makeBox(blower_width, blower_y - blower_box_y_offset, sensor_holder_width) blower_box.translate( Vector(-cooling_and_sensor_slanted_side_width - blower_width, blower_box_y_offset, 0)) motor = make_motor() motor.translate(Vector(0, 0, MainExtruderPart.base_height)) parts = [ main_part, cooling_and_sensor_mount, blower, blower_box, motor ] dimensions = (main_part_width, main_part_length, MainExtruderPart.base_height) move_parts(parts, initial_placement, origin_translation_offset, dimensions) extruder = reduce(lambda union, part: union.fuse(part), parts) # removeSplitter() refines shape return extruder.removeSplitter()
def execute(self, obj): import Part pl = obj.Placement p1 = Vector(-obj.Width.Value / 2, -obj.Height.Value / 2, 0) p2 = Vector(obj.Width.Value / 2, -obj.Height.Value / 2, 0) p3 = Vector(obj.Width.Value / 2, (-obj.Height.Value / 2) + obj.FlangeThickness.Value, 0) p4 = Vector(obj.WebThickness.Value / 2, (-obj.Height.Value / 2) + obj.FlangeThickness.Value, 0) p5 = Vector(obj.WebThickness.Value / 2, obj.Height.Value / 2 - obj.FlangeThickness.Value, 0) p6 = Vector(obj.Width.Value / 2, obj.Height.Value / 2 - obj.FlangeThickness.Value, 0) p7 = Vector(obj.Width.Value / 2, obj.Height.Value / 2, 0) p8 = Vector(-obj.Width.Value / 2, obj.Height.Value / 2, 0) p9 = Vector(-obj.Width.Value / 2, obj.Height.Value / 2 - obj.FlangeThickness.Value, 0) p10 = Vector(-obj.WebThickness.Value / 2, obj.Height.Value / 2 - obj.FlangeThickness.Value, 0) p11 = Vector(-obj.WebThickness.Value / 2, (-obj.Height.Value / 2) + obj.FlangeThickness.Value, 0) p12 = Vector(-obj.Width.Value / 2, (-obj.Height.Value / 2) + obj.FlangeThickness.Value, 0) p = Part.makePolygon( [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p1]) p = Part.Face(p) #p.reverse() obj.Shape = p obj.Placement = pl
def isDrillable(obj, candidate, tooldiameter=None, includePartials=False): """ Checks candidates to see if they can be drilled. Candidates can be either faces - circular or cylindrical or circular edges. The tooldiameter can be optionally passed. if passed, the check will return False for any holes smaller than the tooldiameter. obj=Shape candidate = Face or Edge tooldiameter=float """ PathLog.track('obj: {} candidate: {} tooldiameter {}'.format(obj, candidate, tooldiameter)) drillable = False if candidate.ShapeType == 'Face': face = candidate # eliminate flat faces if (round(face.ParameterRange[0], 8) == 0.0) and (round(face.ParameterRange[1], 8) == round(math.pi * 2, 8)): for edge in face.Edges: # Find seam edge and check if aligned to Z axis. if (isinstance(edge.Curve, Part.Line)): PathLog.debug("candidate is a circle") v0 = edge.Vertexes[0].Point v1 = edge.Vertexes[1].Point #check if the cylinder seam is vertically aligned. Eliminate tilted holes if (numpy.isclose(v1.sub(v0).x, 0, rtol=1e-05, atol=1e-06)) and \ (numpy.isclose(v1.sub(v0).y, 0, rtol=1e-05, atol=1e-06)): drillable = True # vector of top center lsp = Vector(face.BoundBox.Center.x, face.BoundBox.Center.y, face.BoundBox.ZMax) # vector of bottom center lep = Vector(face.BoundBox.Center.x, face.BoundBox.Center.y, face.BoundBox.ZMin) # check if the cylindrical 'lids' are inside the base # object. This eliminates extruded circles but allows # actual holes. if obj.isInside(lsp, 1e-6, False) or obj.isInside(lep, 1e-6, False): PathLog.track("inside check failed. lsp: {} lep: {}".format(lsp,lep)) drillable = False # eliminate elliptical holes elif not hasattr(face.Surface, "Radius"): PathLog.debug("candidate face has no radius attribute") drillable = False else: if tooldiameter is not None: drillable = face.Surface.Radius >= tooldiameter/2 else: drillable = True else: for edge in candidate.Edges: if isinstance(edge.Curve, Part.Circle) and (includePartials or edge.isClosed()): PathLog.debug("candidate is a circle or ellipse") if not hasattr(edge.Curve, "Radius"): PathLog.debug("No radius. Ellipse.") drillable = False else: PathLog.debug("Has Radius, Circle") if tooldiameter is not None: drillable = edge.Curve.Radius >= tooldiameter/2 if not drillable: FreeCAD.Console.PrintMessage( "Found a drillable hole with diameter: {}: " "too small for the current tool with " "diameter: {}".format(edge.Curve.Radius*2, tooldiameter)) else: drillable = True PathLog.debug("candidate is drillable: {}".format(drillable)) return drillable
def createGeometry(self,obj): import Part, DraftGeomUtils # getting default values height = width = length = 1 if hasattr(obj,"Length"): if obj.Length: length = obj.Length if hasattr(obj,"Width"): if obj.Width: width = obj.Width if hasattr(obj,"Height"): if obj.Height: height = obj.Height # creating base shape pl = obj.Placement base = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Normal == Vector(0,0,0): p = FreeCAD.Placement(obj.Base.Placement) normal = p.Rotation.multVec(Vector(0,0,1)) else: normal = Vector(obj.Normal) normal = normal.multiply(height) base = obj.Base.Shape.copy() if base.Solids: pass elif base.Faces: base = base.extrude(normal) elif (len(base.Wires) == 1): if base.Wires[0].isClosed(): base = Part.Face(base.Wires[0]) base = base.extrude(normal) elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids: base = sh else: if obj.Normal == Vector(0,0,0): normal = Vector(0,0,1) else: normal = Vector(obj.Normal) normal = normal.multiply(height) l2 = length/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(-l2,-w2,0) v2 = Vector(l2,-w2,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) base = Part.makePolygon([v1,v2,v3,v4,v1]) base = Part.Face(base) base = base.extrude(normal) base = self.processSubShapes(obj,base) if base: # applying axes pts = self.getAxisPoints(obj) apl = self.getAxisPlacement(obj) if pts: fsh = [] for i in range(len(pts)): if hasattr(obj,"Exclude"): if i in obj.Exclude: continue sh = base.copy() if apl: sh.Placement.Rotation = apl.Rotation sh.translate(pts[i]) fsh.append(sh) obj.Shape = Part.makeCompound(fsh) # finalizing else: if base: if not base.isNull(): if base.isValid() and base.Solids: if base.Volume < 0: base.reverse() if base.Volume < 0: FreeCAD.Console.PrintError(str(translate("Arch","Couldn't compute the wall shape"))) return base = base.removeSplitter() obj.Shape = base if not DraftGeomUtils.isNull(pl): obj.Placement = pl
def update(self, L, B, T, sectionsL, sectionsB, sectionsT, shape): """ Update the 3D view annotations. @param L Ship Lpp. @param B Ship beam. @param T Ship draft. @param sectionsL Transversal sections. @param sectionsB Longitudinal sections. @param sectionsT Water lines. @param shape Ship surfaces shell @return Sections object. None if errors happens. """ msg = QtGui.QApplication.translate( "ship_console", "Computing sections", None) FreeCAD.Console.PrintMessage(msg + '...\n') # Destroy all previous entities self.clean() # Receive data nL = len(sectionsL) nB = len(sectionsB) nT = len(sectionsT) if not (nL or nB or nT): return None # Found sections sections = [] for i in range(0, nL): pos = sectionsL[i] * Units.Metre.Value # Cut ship section = shape.slice(Vector(1.0, 0.0, 0.0), pos) for j in range(0, len(section)): edges = section[j].Edges # We have 3 cases, # * when the section is before midship (starboard side drawn) # * When the section is midship (both sides drawn) # * When the section is after midship (board side drawn) if pos > 0.01 * L * Units.Metre.Value: for k in range(len(edges) - 1, -1, -1): edge = edges[k] bbox = edge.BoundBox if bbox.YMin < -0.01 * B * Units.Metre.Value: del edges[k] elif pos < -0.01 * L * Units.Metre.Value: for k in range(len(edges) - 1, -1, -1): edge = edges[k] bbox = edge.BoundBox if bbox.YMax > 0.01 * B * Units.Metre.Value: del edges[k] sections.extend(edges) for i in range(0, nB): pos = sectionsB[i] * Units.Metre.Value section = shape.slice(Vector(0.0, 1.0, 0.0), pos) for j in range(0, len(section)): edges = section[j].Edges # The longitudinal sections are printed in both sides. section[j] = section[j].mirror(Vector(0.0, 0.0, 0.0), Vector(0.0, 1.0, 0.0)) edges2 = section[j].Edges sections.extend(edges) sections.extend(edges2) for i in range(0, nT): pos = sectionsT[i] * Units.Metre.Value section = shape.slice(Vector(0.0, 0.0, 1.0), pos) for j in range(0, len(section)): edges = section[j].Edges # We have 3 cases, # * when the section is below draft (starboard side drawn) # * When the section is draft (both sides drawn) # * When the section is above draft (starboard side drawn) if pos > T * 1.01 * Units.Metre.Value: for k in range(len(edges) - 1, -1, -1): edge = edges[k] bbox = edge.BoundBox if bbox.YMax > 0.01 * B * Units.Metre.Value: del edges[k] elif pos < T * 0.99 * Units.Metre.Value: for k in range(len(edges) - 1, -1, -1): edge = edges[k] bbox = edge.BoundBox if bbox.YMin < -0.01 * B * Units.Metre.Value: del edges[k] sections.extend(edges) # Transform and join all the B-splines into a shape if not sections: msg = QtGui.QApplication.translate( "ship_console", "Any valid ship section found", None) FreeCAD.Console.PrintWarning(msg + '\n') return obj = sections[0] for i in range(1, len(sections)): # Just create a group of edges obj = obj.oldFuse(sections[i]) Part.show(obj) objs = FreeCAD.ActiveDocument.Objects self.obj = objs[len(objs) - 1] self.obj.Label = 'OutlineDraw' return self.obj
def _zoom_camera(self, use_bound_box=True): """ Fancy routine to smooth zoom the camera """ print('zoom') _camera = ViewState().view.getCameraNode() _start_pos = Vector(_camera.position.getValue().getValue()) _start_ht = _camera.height.getValue() _center = Vector(self.camera_state['position']) _height = self.camera_state['height'] if use_bound_box: _bound_box = self.camera_state['bound box'] #get the center of the camera, setting the z coordinate positive _center = Vector(_bound_box.Center) _center.z = 1.0 #calculate the camera height = bounding box larger dim + 15% _height = _bound_box.XMax - _bound_box.XMin _dy = _bound_box.YMax - _bound_box.YMin if _dy > _height: _height = _dy _height += 0.15 * _height _frames = 60.0 #calculate a total change value _pct_chg = abs(_height - _start_ht) / (_height + _start_ht) #at 50% change or more, use 60 frames, #otherwise scale frames to a minimum of 10 frames if _pct_chg < 0.5: _frames *= _pct_chg * 2.0 if _frames < 10.0: _frames = 10.0 #build cosine-based animation curve and reverse _steps = [ math.cos((_i/_frames) * (math.pi/2.0)) * _frames\ for _i in range(0, int(_frames)) ] _steps = _steps[::-1] #calculate position and height deltas for transition loop _d_pos = _center - _start_pos _d_pos.multiply(1.0 / _frames) _d_ht = (_height - _start_ht) / _frames for _v in _steps: #set the camera ViewState().view.getCameraNode().position.setValue( tuple(_start_pos + (_d_pos * _v))) ViewState().view.getCameraNode().height.setValue(_start_ht + (_d_ht * _v)) Gui.updateGui() ViewState().view.redraw()
#* * #*************************************************************************** import FreeCADGui , WorkingPlane1, math, re from pivy import coin from FreeCAD import Vector from drawGui import * #from draftlibs import fcvec, fcgeo import fcvec, fcgeo from functools import partial import Part # sets the default working plane plane = WorkingPlane1.plane() FreeCAD.DDADockWidget = plane plane.alignToPointAndAxis(Vector(0, 0, 0), Vector(0, 0, 1), 0) #--------------------------------------------------------------------------- # Trackers #--------------------------------------------------------------------------- class Tracker: "A generic Draft Tracker, to be used by other specific trackers" # 辅助绘图工具 def __init__(self, dotted=False, scolor=None, swidth=None, children=[], ontop=False): self.ontop = ontop color = coin.SoBaseColor() color.rgb = scolor or FreeCADGui.DDADockWidget.getDefaultColor("ui") drawstyle = coin.SoDrawStyle() if swidth:
def displacement(ship, draft=None, roll=Units.parseQuantity("0 deg"), trim=Units.parseQuantity("0 deg")): """Compute the ship displacement Position arguments: ship -- Ship object (see createShip) Keyword arguments: draft -- Ship draft (Design ship draft by default) roll -- Roll angle (0 degrees by default) trim -- Trim angle (0 degrees by default) Returned values: disp -- The ship displacement (a density of the water of 1025 kg/m^3 is assumed) B -- Bouyance application point, i.e. Center of mass of the underwater side Cb -- Block coefficient The Bouyance center is refered to the original ship position. """ if draft is None: draft = ship.Draft shape, base_z = placeShipShape(ship.Shape.copy(), draft, roll, trim) shape = getUnderwaterSide(shape) vol = 0.0 cog = Vector() if len(shape.Solids) > 0: for solid in shape.Solids: vol += solid.Volume sCoG = solid.CenterOfMass cog.x = cog.x + sCoG.x * solid.Volume cog.y = cog.y + sCoG.y * solid.Volume cog.z = cog.z + sCoG.z * solid.Volume cog.x = cog.x / vol cog.y = cog.y / vol cog.z = cog.z / vol bbox = shape.BoundBox Vol = (bbox.XMax - bbox.XMin) * (bbox.YMax - bbox.YMin) * abs(bbox.ZMin) # Undo the transformations on the bouyance point B = Part.Point(Vector(cog.x, cog.y, cog.z)) m = Matrix() m.move(Vector(0.0, 0.0, draft)) m.move(Vector(-draft * math.sin(trim.getValueAs("rad")), 0.0, 0.0)) m.rotateY(trim.getValueAs("rad")) m.move(Vector(0.0, -draft * math.sin(roll.getValueAs("rad")), base_z)) m.rotateX(-roll.getValueAs("rad")) B.transform(m) try: cb = vol / Vol except ZeroDivisionError: msg = QtGui.QApplication.translate( "ship_console", "ZeroDivisionError: Null volume found during the displacement" " computation!", None, QtGui.QApplication.UnicodeUTF8) App.Console.PrintError(msg + '\n') cb = 0.0 # Return the computed data return (DENS * Units.Quantity(vol, Units.Volume), Vector(B.X, B.Y, B.Z), cb)
def p1(self, point=None): "sets or gets the first point of the line" if point: self.coords.point.set1Value(0, point.x, point.y, point.z) else: return Vector(self.coords.point.getValues()[0].getValue())
def getExtrusionData(self,obj): """returns (shape,extrusion vector,placement) or None""" import Part,DraftGeomUtils data = ArchComponent.Component.getExtrusionData(self,obj) if data: return data length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value normal = None if not height: for p in obj.InList: if Draft.getType(p) == "Floor": if p.Height.Value: height = p.Height.Value base = None placement = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape: if obj.Base.Shape.Solids: return None elif obj.Base.Shape.Faces: if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces): return None else: base,placement = self.rebase(obj.Base.Shape) normal = obj.Base.Shape.Faces[0].normalAt(0,0) elif obj.Base.Shape.Wires: baseface = None if hasattr(obj,"FaceMaker"): if obj.FaceMaker != "None": try: baseface = Part.makeFace(obj.Base.Shape.Wires,"Part::FaceMaker"+str(obj.FaceMaker)) except: FreeCAD.Console.PrintError(translate("Arch","Facemaker returned an error")+"\n") return None if len(baseface.Faces) > 1: baseface = baseface.Faces[0] normal = baseface.normalAt(0,0) if not baseface: for w in obj.Base.Shape.Wires: w.fix(0.1,0,1) # fixes self-intersecting wires f = Part.Face(w) if baseface: baseface = baseface.fuse(f) else: baseface = f normal = f.normalAt(0,0) base,placement = self.rebase(baseface) elif (len(obj.Base.Shape.Edges) == 1) and (len(obj.Base.Shape.Vertexes) == 1): # closed edge w = Part.Wire(obj.Base.Shape.Edges[0]) baseface = Part.Face(w) base,placement = self.rebase(baseface) elif length and width and height: if (length > height) and (obj.Role != "Slab"): h2 = height/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(0,-w2,-h2) v2 = Vector(0,-w2,h2) v3 = Vector(0,w2,h2) v4 = Vector(0,w2,-h2) else: l2 = length/2 or 0.5 w2 = width/2 or 0.5 v1 = Vector(-l2,-w2,0) v2 = Vector(l2,-w2,0) v3 = Vector(l2,w2,0) v4 = Vector(-l2,w2,0) import Part baseface = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1])) base,placement = self.rebase(baseface) if base and placement: if obj.Normal == Vector(0,0,0): if not normal: normal = Vector(0,0,1) else: normal = Vector(obj.Normal) if (length > height) and (obj.Role != "Slab"): extrusion = normal.multiply(length) else: extrusion = normal.multiply(height) return (base,extrusion,placement) return None
def p2(self, point=None): "sets or gets the second point of the line" if point: self.coords.point.set1Value(1, point.x, point.y, point.z) else: return Vector(self.coords.point.getValues()[-1].getValue())
def setup(doc=None, solvertype="elmer"): # init FreeCAD document if doc is None: doc = init_doc() # explanation object # just keep the following line and change text string in get_explanation method manager.add_explanation_obj( doc, get_explanation(manager.get_header(get_information()))) # geometric objects # name is important because the other method in this module use obj name geom_obj = doc.addObject("PartDesign::Body", "Body") base_sketch = geom_obj.newObject("Sketcher::SketchObject", "Base_Sketch") base_sketch.Support = (doc.getObject("XY_Plane"), [""]) base_sketch.MapMode = "FlatFace" base_geoList = [ Part.LineSegment(Vector(0.000000, 0.000000, 0), Vector(57.407921, 0.000000, 0)), Part.LineSegment(Vector(57.407921, 0.000000, 0), Vector(57.407921, 35.205284, 0)), Part.LineSegment(Vector(57.407921, 35.205284, 0), Vector(0.000000, 35.205284, 0)), Part.LineSegment(Vector(0.000000, 35.205284, 0), Vector(0.000000, 0.000000, 0)) ] base_sketch.addGeometry(base_geoList, False) base_conList = [ Sketcher.Constraint("Coincident", 0, 2, 1, 1), Sketcher.Constraint("Coincident", 1, 2, 2, 1), Sketcher.Constraint("Coincident", 2, 2, 3, 1), Sketcher.Constraint("Coincident", 3, 2, 0, 1), Sketcher.Constraint("Horizontal", 0), Sketcher.Constraint("Horizontal", 2), Sketcher.Constraint("Vertical", 1), Sketcher.Constraint("Vertical", 3), Sketcher.Constraint("Coincident", 0, 1, -1, 1), Sketcher.Constraint("DistanceY", 1, 1, 1, 2, 35.205284), Sketcher.Constraint("DistanceX", 0, 1, 0, 2, 57.407921) ] base_sketch.addConstraint(base_conList) base_sketch.setDatum(9, Units.Quantity("5000.000000 mm")) base_sketch.setDatum(10, Units.Quantity("5000.000000 mm")) pad = geom_obj.newObject("PartDesign::Pad", "Pad") pad.Profile = base_sketch pad.Length = 7500.0 pad.Length2 = 1000.0 upper_sketch = geom_obj.newObject("Sketcher::SketchObject", "Upper_Sketch") upper_sketch.Support = None upper_sketch.MapMode = "Deactivated" upper_sketch.Placement = FreeCAD.Placement(Vector(0, 0, 1000), Rotation(Vector(0, 0, 1), 0)) upper_geoList = [ Part.LineSegment(Vector(25.560951, 4958.778320, 0), Vector(5068.406250, 4958.778320, 0)), Part.LineSegment(Vector(5068.406250, 4958.778320, 0), Vector(5037.082520, -21.422216, 0)), Part.LineSegment(Vector(5037.082520, 0.000000, 0), Vector(1309.763672, -21.422216, 0)), Part.LineSegment(Vector(1309.763672, 0.000000, 0), Vector(1372.406982, 1544.678467, 0)), Part.LineSegment(Vector(1372.406982, 1544.678467, 0), Vector(-37.083382, 1544.678467, 0)), Part.LineSegment(Vector(0.000000, 1544.678467, 0), Vector(25.560951, 4958.778320, 0)) ] upper_sketch.addGeometry(upper_geoList, False) upper_conList = [ Sketcher.Constraint("Horizontal", 0), Sketcher.Constraint("Coincident", 1, 1, 0, 2), Sketcher.Constraint("PointOnObject", 1, 2, -1), Sketcher.Constraint("Vertical", 1), Sketcher.Constraint("Coincident", 2, 1, 1, 2), Sketcher.Constraint("PointOnObject", 2, 2, -1), Sketcher.Constraint("Coincident", 3, 1, 2, 2), Sketcher.Constraint("Coincident", 4, 1, 3, 2), Sketcher.Constraint("PointOnObject", 4, 2, -2), Sketcher.Constraint("Horizontal", 4), Sketcher.Constraint("Coincident", 5, 1, 4, 2), Sketcher.Constraint("Coincident", 5, 2, 0, 1), Sketcher.Constraint("Vertical", 5), Sketcher.Constraint("Vertical", 3), Sketcher.Constraint("DistanceX", 0, 1, 0, 2, 5037.082520), Sketcher.Constraint("DistanceY", 1, 2, 1, 1, 4958.778320), Sketcher.Constraint("DistanceY", 3, 1, 3, 2, 1544.678467), Sketcher.Constraint("DistanceX", 4, 2, 4, 1, 1309.763672) ] upper_sketch.addConstraint(upper_conList) upper_sketch.setDatum(14, Units.Quantity("5000.000000 mm")) upper_sketch.setDatum(15, Units.Quantity("5000.000000 mm")) upper_sketch.setDatum(16, Units.Quantity("1500.000000 mm")) upper_sketch.setDatum(17, Units.Quantity("1500.000000 mm")) pocket = geom_obj.newObject("PartDesign::Pocket", "Pocket") pocket.Profile = upper_sketch pocket.Length = 1500.0 pocket.Length2 = 100.0 pocket.Reversed = 1 doc.recompute() if FreeCAD.GuiUp: geom_obj.ViewObject.Document.activeView().viewAxonometric() geom_obj.ViewObject.Document.activeView().fitAll() # analysis analysis = ObjectsFem.makeAnalysis(doc, "Analysis") # solver if solvertype == "elmer": solver_obj = ObjectsFem.makeSolverElmer(doc, "SolverElmer") ObjectsFem.makeEquationElectrostatic(doc, solver_obj) ObjectsFem.makeEquationElectricforce(doc, solver_obj) else: FreeCAD.Console.PrintWarning( "Not known or not supported solver type: {}. " "No solver object was created.\n".format(solvertype)) analysis.addObject(solver_obj) # material material_obj = ObjectsFem.makeMaterialFluid(doc, "FemMaterial") mat = material_obj.Material mat["Name"] = "Air-Generic" mat["Density"] = "1.20 kg/m^3" mat["KinematicViscosity"] = "15.11 mm^2/s" mat["VolumetricThermalExpansionCoefficient"] = "0.00 mm/m/K" mat["ThermalConductivity"] = "0.03 W/m/K" mat["ThermalExpansionCoefficient"] = "0.0034/K" mat["SpecificHeat"] = "1.00 J/kg/K" mat["RelativePermittivity"] = "1.00" material_obj.Material = mat analysis.addObject(material_obj) # constraint potential 0V name_pot1 = "ElectrostaticPotential1" con_elect_pot1 = ObjectsFem.makeConstraintElectrostaticPotential( doc, name_pot1) con_elect_pot1.References = [(geom_obj, "Face2")] con_elect_pot1.Potential = "0 V" con_elect_pot1.CapacitanceBody = 1 con_elect_pot1.CapacitanceBodyEnabled = True con_elect_pot1.PotentialEnabled = True analysis.addObject(con_elect_pot1) # constraint potential 1V name_pot2 = "ElectrostaticPotential2" con_elect_pot2 = ObjectsFem.makeConstraintElectrostaticPotential( doc, name_pot2) con_elect_pot2.References = [(geom_obj, "Face4"), (geom_obj, "Face5"), (geom_obj, "Face6"), (geom_obj, "Face11")] con_elect_pot2.Potential = "1 V" con_elect_pot2.CapacitanceBody = 2 con_elect_pot2.CapacitanceBodyEnabled = True con_elect_pot2.PotentialEnabled = True con_elect_pot2.ElectricForcecalculation = True analysis.addObject(con_elect_pot2) # mesh from .meshes.mesh_electricforce_elmer_nongui6_tetra10 import create_nodes, create_elements fem_mesh = Fem.FemMesh() control = create_nodes(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating nodes.\n") control = create_elements(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject( ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Part = geom_obj femmesh_obj.SecondOrderLinear = False # mesh_region mesh_region = ObjectsFem.makeMeshRegion(doc, femmesh_obj, name="MeshRegion") mesh_region.CharacteristicLength = "300 mm" mesh_region.References = [(geom_obj, "Face4"), (geom_obj, "Face5"), (geom_obj, "Face6"), (geom_obj, "Face11")] doc.recompute() return doc
def externalFaces(self, shape): """ Returns detected external faces. @param shape Shape where external faces wanted. @return List of external faces detected. """ result = [] faces = shape.Faces bbox = shape.BoundBox L = bbox.XMax - bbox.XMin B = bbox.YMax - bbox.YMin T = bbox.ZMax - bbox.ZMin dist = math.sqrt(L*L + B*B + T*T) msg = QtGui.QApplication.translate( "ship_console", "Computing external faces", None) App.Console.PrintMessage(msg + '...\n') # Valid/unvalid faces detection loop for i in range(len(faces)): App.Console.PrintMessage("\t{} / {}\n".format(i + 1, len(faces))) f = faces[i] # Create a line normal to surface at middle point u = 0.0 v = 0.0 try: surf = f.Surface u = 0.5*(surf.getUKnots()[0]+surf.getUKnots()[-1]) v = 0.5*(surf.getVKnots()[0]+surf.getVKnots()[-1]) except: cog = f.CenterOfMass [u, v] = f.Surface.parameter(cog) p0 = f.valueAt(u, v) try: n = f.normalAt(u, v).normalize() except: continue p1 = p0 + n.multiply(1.5 * dist) line = Part.makeLine(p0, p1) # Look for faces in front of this nPoints = 0 for j in range(len(faces)): f2 = faces[j] section = self.lineFaceSection(line, f2) if len(section) <= 2: continue # Add points discarding start and end nPoints = nPoints + len(section) - 2 # In order to avoid special directions we can modify line # normal a little bit. angle = 5 line.rotate(p0, Vector(1, 0, 0), angle) line.rotate(p0, Vector(0, 1, 0), angle) line.rotate(p0, Vector(0, 0, 1), angle) nPoints2 = 0 for j in range(len(faces)): if i == j: continue f2 = faces[j] section = self.lineFaceSection(line, f2) if len(section) <= 2: continue # Add points discarding start and end nPoints2 = nPoints + len(section) - 2 # If the number of intersection points is pair, is a # external face. So if we found an odd points intersection, # face must be discarded. if (nPoints % 2) or (nPoints2 % 2): continue result.append(f) self.timer.start(0.0) self.loop.exec_() if(not self.running): break return result
def getSize(self): "returns (length,width) of the rectangle" p1 = Vector(self.coords.point.getValues()[0].getValue()) p2 = Vector(self.coords.point.getValues()[2].getValue()) diag = p2.sub(p1) return ((DraftVecUtils.project(diag,self.u)).Length,(DraftVecUtils.project(diag,self.v)).Length)
def makeStraightLanding(self,obj,edge,numberofsteps=None): "builds a landing from a straight edge" # general data if not numberofsteps: numberofsteps = obj.NumberOfSteps import Part,DraftGeomUtils v = DraftGeomUtils.vec(edge) vLength = Vector(v.x,v.y,0) vWidth = vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0,0,1)),obj.Width.Value) vBase = edge.Vertexes[0].Point vNose = DraftVecUtils.scaleTo(vLength,-abs(obj.Nosing.Value)) h = obj.Height.Value l = obj.Length.Value if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): l = obj.Base.Shape.Length if obj.Base.Shape.BoundBox.ZLength: h = obj.Base.Shape.BoundBox.ZLength fLength = float(l-obj.Width.Value)/(numberofsteps-2) fHeight = float(h)/numberofsteps a = math.atan(fHeight/fLength) print "landing data:",fLength,":",fHeight # step p1 = self.align(vBase,obj.Align,vWidth) p1 = p1.add(vNose).add(Vector(0,0,-abs(obj.TreadThickness.Value))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) step = Part.Face(Part.makePolygon([p1,p2,p3,p4,p1])) if obj.TreadThickness.Value: step = step.extrude(Vector(0,0,abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) # structure lProfile = [] struct = None p7 = None p1 = p1.add(DraftVecUtils.neg(vNose)) p2 = p1.add(Vector(0,0,-fHeight)).add(Vector(0,0,-obj.StructureThickness.Value/math.cos(a))) resheight = p1.sub(p2).Length - obj.StructureThickness.Value reslength = resheight / math.tan(a) p3 = p2.add(DraftVecUtils.scaleTo(vLength,reslength)).add(Vector(0,0,resheight)) p6 = p1.add(vLength) if obj.TreadThickness.Value: p7 = p6.add(Vector(0,0,obj.TreadThickness.Value)) reslength = fLength + (obj.StructureThickness.Value/math.sin(a)-(fHeight-obj.TreadThickness.Value)/math.tan(a)) if p7: p5 = p7.add(DraftVecUtils.scaleTo(vLength,reslength)) else: p5 = p6.add(DraftVecUtils.scaleTo(vLength,reslength)) resheight = obj.StructureThickness.Value + obj.TreadThickness.Value reslength = resheight/math.tan(a) p4 = p5.add(DraftVecUtils.scaleTo(vLength,-reslength)).add(Vector(0,0,-resheight)) if obj.Structure == "Massive": if obj.StructureThickness.Value: if p7: struct = Part.Face(Part.makePolygon([p1,p2,p3,p4,p5,p7,p6,p1])) else: struct = Part.Face(Part.makePolygon([p1,p2,p3,p4,p5,p6,p1])) evec = vWidth if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) struct.translate(mvec) evec = DraftVecUtils.scaleTo(evec,evec.Length-(2*mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer","Two stringers"]: if obj.StringerWidth.Value and obj.StructureThickness.Value: p1b = p1.add(Vector(0,0,-fHeight)) reslength = fHeight/math.tan(a) p1c = p1.add(DraftVecUtils.scaleTo(vLength,reslength)) p5b = None p5c = None if obj.TreadThickness.Value: reslength = obj.StructureThickness.Value/math.sin(a) p5b = p5.add(DraftVecUtils.scaleTo(vLength,-reslength)) reslength = obj.TreadThickness.Value/math.tan(a) p5c = p5b.add(DraftVecUtils.scaleTo(vLength,-reslength)).add(Vector(0,0,-obj.TreadThickness.Value)) pol = Part.Face(Part.makePolygon([p1c,p1b,p2,p3,p4,p5,p5b,p5c,p1c])) else: pol = Part.Face(Part.makePolygon([p1c,p1b,p2,p3,p4,p5,p1c])) evec = DraftVecUtils.scaleTo(vWidth,obj.StringerWidth.Value) if obj.Structure == "One stringer": if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) else: mvec = DraftVecUtils.scaleTo(vWidth,(vWidth.Length/2)-obj.StringerWidth.Value/2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth,obj.StructureOffset.Value) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1,s2]) if struct: self.structures.append(struct)
def p3(self, point=None): "sets or gets the opposite (diagonal) point of the rectangle" if point: self.update(point) else: return Vector(self.coords.point.getValues()[2].getValue())
def execute(self, obj): "creates the structure shape" import Part, DraftGeomUtils if self.clone(obj): return normal, length, width, height = self.getDefaultValues(obj) # creating base shape pl = obj.Placement base = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return if not obj.Base.Shape.isValid(): if not obj.Base.Shape.Solids: # let pass invalid objects if they have solids... return if hasattr(obj, "Tool"): if obj.Tool: try: base = obj.Tool.Shape.copy().makePipe( obj.Base.Shape.copy()) except Part.OCCError: FreeCAD.Console.PrintError( translate( "Arch", "Error: The base shape couldn't be extruded along this tool object" )) return if not base: if not height: return if obj.Normal == Vector(0, 0, 0): p = FreeCAD.Placement(obj.Base.Placement) normal = p.Rotation.multVec(normal) else: normal = Vector(obj.Normal) normal = normal.multiply(height) base = obj.Base.Shape.copy() if base.Solids: pass elif base.Faces: base = base.extrude(normal) elif (len(base.Wires) == 1): if base.Wires[0].isClosed(): try: base = Part.Face(base.Wires[0]) base = base.extrude(normal) except Part.OCCError: FreeCAD.Console.PrintError( obj.Label + " : " + str( translate( "Arch", "Unable to extrude the base shape\n" ))) return elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids and ( not sh.isNull()): base = sh else: FreeCAD.Console.PrintWarning( str( translate( "Arch", "This mesh is an invalid solid"))) obj.Base.ViewObject.show() else: base = self.getProfiles(obj) if base: if length > height: normal = normal.multiply(length) else: normal = normal.multiply(height) base = Part.Face(base[0]) base = base.extrude(normal) base = self.processSubShapes(obj, base, pl) self.applyShape(obj, base, pl)
def p2(self): "gets the second point (on u axis) of the rectangle" return Vector(self.coords.point.getValues()[3].getValue())
def execute(self,obj): "creates the structure shape" import Part, DraftGeomUtils if self.clone(obj): return normal,length,width,height = self.getDefaultValues(obj) # creating base shape pl = obj.Placement base = None if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return if not obj.Base.Shape.isValid(): if not obj.Base.Shape.Solids: # let pass invalid objects if they have solids... return if hasattr(obj,"Tool"): if obj.Tool: try: base = obj.Tool.Shape.copy().makePipe(obj.Base.Shape.copy()) except Part.OCCError: FreeCAD.Console.PrintError(translate("Arch","Error: The base shape couldn't be extruded along this tool object")) return if not base: if not height: return if obj.Normal == Vector(0,0,0): p = FreeCAD.Placement(obj.Base.Placement) normal = p.Rotation.multVec(normal) else: normal = Vector(obj.Normal) normal = normal.multiply(height) base = obj.Base.Shape.copy() if base.Solids: pass elif base.Faces: base = base.extrude(normal) elif (len(base.Wires) == 1): if base.Wires[0].isClosed(): try: base = Part.Face(base.Wires[0]) base = base.extrude(normal) except Part.OCCError: FreeCAD.Console.PrintError(obj.Label+" : "+str(translate("Arch","Unable to extrude the base shape\n"))) return elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids and (not sh.isNull()): base = sh else: FreeCAD.Console.PrintWarning(str(translate("Arch","This mesh is an invalid solid"))) obj.Base.ViewObject.show() else: base = self.getProfiles(obj) if base: if length > height: normal = normal.multiply(length) else: normal = normal.multiply(height) base = Part.Face(base[0]) base = base.extrude(normal) base = self.processSubShapes(obj,base,pl) self.applyShape(obj,base,pl)
def p1(self, point=None): "sets or gets the base point of the rectangle" if point: self.setorigin(point) else: return Vector(self.coords.point.getValues()[0].getValue())
class rectangleTracker(Tracker): "A Rectangle tracker, used by the rectangle tool" def __init__(self,dotted=False,scolor=None,swidth=None,face=False): self.origin = Vector(0,0,0) line = coin.SoLineSet() line.numVertices.setValue(5) self.coords = coin.SoCoordinate3() # this is the coordinate self.coords.point.setValues(0,50,[[0,0,0],[2,0,0],[2,2,0],[0,2,0],[0,0,0]]) if face: m1 = coin.SoMaterial() m1.transparency.setValue(0.5) m1.diffuseColor.setValue([0.5,0.5,1.0]) f = coin.SoIndexedFaceSet() f.coordIndex.setValues([0,1,2,3]) Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line,m1,f],name="rectangleTracker") else: Tracker.__init__(self,dotted,scolor,swidth,[self.coords,line],name="rectangleTracker") self.u = FreeCAD.DraftWorkingPlane.u self.v = FreeCAD.DraftWorkingPlane.v def setorigin(self,point): "sets the base point of the rectangle" self.coords.point.set1Value(0,point.x,point.y,point.z) self.coords.point.set1Value(4,point.x,point.y,point.z) self.origin = point def update(self,point): "sets the opposite (diagonal) point of the rectangle" diagonal = point.sub(self.origin) inpoint1 = self.origin.add(DraftVecUtils.project(diagonal,self.v)) inpoint2 = self.origin.add(DraftVecUtils.project(diagonal,self.u)) self.coords.point.set1Value(1,inpoint1.x,inpoint1.y,inpoint1.z) self.coords.point.set1Value(2,point.x,point.y,point.z) self.coords.point.set1Value(3,inpoint2.x,inpoint2.y,inpoint2.z) def setPlane(self,u,v=None): '''sets given (u,v) vectors as working plane. You can give only u and v will be deduced automatically given current workplane''' self.u = u if v: self.v = v else: norm = FreeCAD.DraftWorkingPlane.u.cross(FreeCAD.DraftWorkingPlane.v) self.v = self.u.cross(norm) def p1(self,point=None): "sets or gets the base point of the rectangle" if point: self.setorigin(point) else: return Vector(self.coords.point.getValues()[0].getValue()) def p2(self): "gets the second point (on u axis) of the rectangle" return Vector(self.coords.point.getValues()[3].getValue()) def p3(self,point=None): "sets or gets the opposite (diagonal) point of the rectangle" if point: self.update(point) else: return Vector(self.coords.point.getValues()[2].getValue()) def p4(self): "gets the fourth point (on v axis) of the rectangle" return Vector(self.coords.point.getValues()[1].getValue()) def getSize(self): "returns (length,width) of the rectangle" p1 = Vector(self.coords.point.getValues()[0].getValue()) p2 = Vector(self.coords.point.getValues()[2].getValue()) diag = p2.sub(p1) return ((DraftVecUtils.project(diag,self.u)).Length,(DraftVecUtils.project(diag,self.v)).Length) def getNormal(self): "returns the normal of the rectangle" return (self.u.cross(self.v)).normalize()
class rectangleTracker(Tracker): "A Rectangle tracker, used by the rectangle tool" def __init__(self, dotted=False, scolor=None, swidth=None, face=False): self.origin = Vector(0, 0, 0) line = coin.SoLineSet() line.numVertices.setValue(5) self.coords = coin.SoCoordinate3() # this is the coordinate self.coords.point.setValues( 0, 50, [[0, 0, 0], [2, 0, 0], [2, 2, 0], [0, 2, 0], [0, 0, 0]]) if face: m1 = coin.SoMaterial() m1.transparency.setValue(0.5) m1.diffuseColor.setValue([0.5, 0.5, 1.0]) f = coin.SoIndexedFaceSet() f.coordIndex.setValues([0, 1, 2, 3]) Tracker.__init__(self, dotted, scolor, swidth, [self.coords, line, m1, f], name="rectangleTracker") else: Tracker.__init__(self, dotted, scolor, swidth, [self.coords, line], name="rectangleTracker") self.u = FreeCAD.DraftWorkingPlane.u self.v = FreeCAD.DraftWorkingPlane.v def setorigin(self, point): "sets the base point of the rectangle" self.coords.point.set1Value(0, point.x, point.y, point.z) self.coords.point.set1Value(4, point.x, point.y, point.z) self.origin = point def update(self, point): "sets the opposite (diagonal) point of the rectangle" diagonal = point.sub(self.origin) inpoint1 = self.origin.add(DraftVecUtils.project(diagonal, self.v)) inpoint2 = self.origin.add(DraftVecUtils.project(diagonal, self.u)) self.coords.point.set1Value(1, inpoint1.x, inpoint1.y, inpoint1.z) self.coords.point.set1Value(2, point.x, point.y, point.z) self.coords.point.set1Value(3, inpoint2.x, inpoint2.y, inpoint2.z) def setPlane(self, u, v=None): '''sets given (u,v) vectors as working plane. You can give only u and v will be deduced automatically given current workplane''' self.u = u if v: self.v = v else: norm = FreeCAD.DraftWorkingPlane.u.cross( FreeCAD.DraftWorkingPlane.v) self.v = self.u.cross(norm) def p1(self, point=None): "sets or gets the base point of the rectangle" if point: self.setorigin(point) else: return Vector(self.coords.point.getValues()[0].getValue()) def p2(self): "gets the second point (on u axis) of the rectangle" return Vector(self.coords.point.getValues()[3].getValue()) def p3(self, point=None): "sets or gets the opposite (diagonal) point of the rectangle" if point: self.update(point) else: return Vector(self.coords.point.getValues()[2].getValue()) def p4(self): "gets the fourth point (on v axis) of the rectangle" return Vector(self.coords.point.getValues()[1].getValue()) def getSize(self): "returns (length,width) of the rectangle" p1 = Vector(self.coords.point.getValues()[0].getValue()) p2 = Vector(self.coords.point.getValues()[2].getValue()) diag = p2.sub(p1) return ((DraftVecUtils.project(diag, self.u)).Length, (DraftVecUtils.project(diag, self.v)).Length) def getNormal(self): "returns the normal of the rectangle" return (self.u.cross(self.v)).normalize() def isInside(self, point): "returns True if the given point is inside the rectangle" vp = point.sub(self.p1()) uv = self.p2().sub(self.p1()) vv = self.p4().sub(self.p1()) uvp = DraftVecUtils.project(vp, uv) vvp = DraftVecUtils.project(vp, vv) if uvp.getAngle(uv) < 1: if vvp.getAngle(vv) < 1: if uvp.Length <= uv.Length: if vvp.Length <= vv.Length: return True return False
def onChanged(self, vobj, prop): if prop == "LineColor": if hasattr(vobj, "LineColor"): l = vobj.LineColor self.mat1.diffuseColor.setValue([l[0], l[1], l[2]]) self.mat2.diffuseColor.setValue([l[0], l[1], l[2]]) elif prop == "Transparency": if hasattr(vobj, "Transparency"): self.mat2.transparency.setValue(vobj.Transparency / 100.0) elif prop in ["DisplayLength", "DisplayHeight", "ArrowSize"]: if hasattr(vobj, "DisplayLength") and hasattr( vobj, "DisplayHeight"): ld = vobj.DisplayLength.Value / 2 hd = vobj.DisplayHeight.Value / 2 elif hasattr(vobj, "DisplaySize"): # old objects ld = vobj.DisplaySize.Value / 2 hd = vobj.DisplaySize.Value / 2 else: ld = 1 hd = 1 verts = [] fverts = [] for v in [[-ld, -hd], [ld, -hd], [ld, hd], [-ld, hd]]: if hasattr(vobj, "ArrowSize"): l1 = vobj.ArrowSize.Value if vobj.ArrowSize.Value > 0 else 0.1 else: l1 = 0.1 l2 = l1 / 3 pl = FreeCAD.Placement(vobj.Object.Placement) p1 = pl.multVec(Vector(v[0], v[1], 0)) p2 = pl.multVec(Vector(v[0], v[1], -l1)) p3 = pl.multVec(Vector(v[0] - l2, v[1], -l1 + l2)) p4 = pl.multVec(Vector(v[0] + l2, v[1], -l1 + l2)) p5 = pl.multVec(Vector(v[0], v[1] - l2, -l1 + l2)) p6 = pl.multVec(Vector(v[0], v[1] + l2, -l1 + l2)) verts.extend([[p1.x, p1.y, p1.z], [p2.x, p2.y, p2.z]]) fverts.append([p1.x, p1.y, p1.z]) verts.extend([[p2.x, p2.y, p2.z], [p3.x, p3.y, p3.z], [p4.x, p4.y, p4.z], [p2.x, p2.y, p2.z]]) verts.extend([[p2.x, p2.y, p2.z], [p5.x, p5.y, p5.z], [p6.x, p6.y, p6.z], [p2.x, p2.y, p2.z]]) verts.extend(fverts + [fverts[0]]) self.lcoords.point.setValues(verts) self.fcoords.point.setValues(fverts) elif prop == "LineWidth": self.drawstyle.lineWidth = vobj.LineWidth elif prop in ["CutView", "CutMargin"]: if hasattr(vobj, "CutView") and FreeCADGui.ActiveDocument.ActiveView: sg = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph() if vobj.CutView: if self.clip: sg.removeChild(self.clip) self.clip = None for o in Draft.getGroupContents(vobj.Object.Objects, walls=True): if hasattr(o.ViewObject, "Lighting"): o.ViewObject.Lighting = "One side" self.clip = coin.SoClipPlane() self.clip.on.setValue(True) norm = vobj.Object.Proxy.getNormal(vobj.Object) mp = vobj.Object.Shape.CenterOfMass mp = DraftVecUtils.project(mp, norm) dist = mp.Length #- 0.1 # to not clip exactly on the section object norm = norm.negative() marg = 1 if hasattr(vobj, "CutMargin"): marg = vobj.CutMargin.Value if mp.getAngle(norm) > 1: dist += marg dist = -dist else: dist -= marg plane = coin.SbPlane(coin.SbVec3f(norm.x, norm.y, norm.z), dist) self.clip.plane.setValue(plane) sg.insertChild(self.clip, 0) else: if self.clip: sg.removeChild(self.clip) self.clip = None return
def FSMesh(obj, recompute=False): """ Get free surface mesh in matrix mode. @param obj Created Part::FeaturePython object. @param recompute True if mesh must be recomputed, False otherwise. @return Faces matrix """ nx = obj.FS_Nx ny = obj.FS_Ny if not recompute: faces = [] for i in range(0,nx): faces.append([]) for j in range(0,ny): faces[i].append(FreeSurfaceFace(obj.FS_Position[j + i*ny], obj.FS_Normal[j + i*ny], obj.FS_Area[j + i*ny])) return faces # Transform positions into a mesh pos = [] for i in range(0,nx): pos.append([]) for j in range(0,ny): pos[i].append(obj.FS_Position[j + i*ny]) # Recompute normals and dimensions normal = [] l = [] b = [] for i in range(0,nx): normal.append([]) l.append([]) b.append([]) for j in range(0,ny): i0 = i-1 i1 = i+1 fi = 1.0 j0 = j-1 j1 = j+1 fj = 1.0 if i == 0: i0 = i i1 = i+1 fi = 2.0 if i == nx-1: i0 = i-1 i1 = i fi = 2.0 if j == 0: j0 = j j1 = j+1 fj = 2.0 if j == ny-1: j0 = j-1 j1 = j fj = 2.0 l[i].append(fi*(obj.FS_Position[j + i1*ny].x - obj.FS_Position[j + i0*ny].x)) b[i].append(fj*(obj.FS_Position[j1 + i*ny].y - obj.FS_Position[j0 + i*ny].y)) xvec = Vector(obj.FS_Position[j + i1*ny].x - obj.FS_Position[j + i0*ny].x, obj.FS_Position[j + i1*ny].y - obj.FS_Position[j + i0*ny].y, obj.FS_Position[j + i1*ny].z - obj.FS_Position[j + i0*ny].z) yvec = Vector(obj.FS_Position[j1 + i*ny].x - obj.FS_Position[j0 + i*ny].x, obj.FS_Position[j1 + i*ny].y - obj.FS_Position[j0 + i*ny].y, obj.FS_Position[j1 + i*ny].z - obj.FS_Position[j0 + i*ny].z) n = Vector(xvec.cross(yvec)) # Z positive normal[i].append(n.normalize()) # Create faces faces = [] for i in range(0,nx): faces.append([]) for j in range(0,ny): faces[i].append(FreeSurfaceFace(pos[i][j], normal[i][j], l[i][j], b[i][j])) # Reconstruct mesh data for i in range(0,nx): for j in range(0,ny): obj.FS_Position[j + i*ny] = faces[i][j].pos obj.FS_Normal[j + i*ny] = faces[i][j].normal obj.FS_Area[j + i*ny] = faces[i][j].area return faces
def xy(point): """(point) Convenience function to return the projection of the Vector in the XY-plane.""" return Vector(point.x, point.y, 0)
def transF(p): p0 = p - flatcentre return p0 * cs + Vector(-p0.y, p0.x, 0) * sn + uvcentre + explodev
def p4(self): "gets the fourth point (on v axis) of the rectangle" return Vector(self.coords.point.getValues()[1].getValue())