| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| __title__ = "FreeCAD Arch Curtain Wall" |
| __author__ = "Yorik van Havre" |
| __url__ = "https://www.freecad.org" |
|
|
| |
| |
| |
| |
| |
|
|
| """ |
| Curtain wall tool |
| |
| Abstract: Curtain walls need a surface to work on (base). |
| They then divide each face of that surface into quads, |
| using the face parameters grid. |
| |
| The vertical lines can then receive one type of profile |
| (vertical mullions), the horizontal ones another |
| (horizontal mullions), and the quads a third (panels). |
| |
| We then have two cases, depending on each quad: Either the |
| four corners of each quad are coplanar, in which case the |
| panel filling is rectangular, or they don't, in which case |
| the facet is triangulated and receives a third mullion |
| (diagonal mullion). |
| """ |
|
|
| import math |
|
|
| import FreeCAD |
| import ArchCommands |
| import ArchComponent |
| import DraftVecUtils |
|
|
| from draftutils import params |
|
|
| if FreeCAD.GuiUp: |
| from PySide.QtCore import QT_TRANSLATE_NOOP |
| import FreeCADGui |
| from draftutils.translate import translate |
| else: |
| |
| def translate(ctxt, txt): |
| return txt |
|
|
| def QT_TRANSLATE_NOOP(ctxt, txt): |
| return txt |
|
|
| |
|
|
| ANGLETOLERANCE = 0.67 |
|
|
|
|
| class CurtainWall(ArchComponent.Component): |
| "The curtain wall object" |
|
|
| def __init__(self, obj): |
|
|
| ArchComponent.Component.__init__(self, obj) |
| self.Type = "CurtainWall" |
| self.setProperties(obj) |
| obj.IfcType = "Curtain Wall" |
|
|
| def setProperties(self, obj): |
|
|
| pl = obj.PropertiesList |
| vsize = 50 |
| hsize = 50 |
| if not "Host" in pl: |
| obj.addProperty( |
| "App::PropertyLink", |
| "Host", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP("App::Property", "An optional host object for this curtain wall"), |
| locked=True, |
| ) |
| if not "Height" in pl: |
| obj.addProperty( |
| "App::PropertyLength", |
| "Height", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", "The height of the curtain wall, if based on an edge" |
| ), |
| locked=True, |
| ) |
| obj.Height = params.get_param_arch("WallHeight") |
| if not "VerticalMullionNumber" in pl: |
| obj.addProperty( |
| "App::PropertyInteger", |
| "VerticalMullionNumber", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP("App::Property", "The number of vertical mullions"), |
| locked=True, |
| ) |
| obj.setEditorMode("VerticalMullionNumber", 1) |
| if not "VerticalMullionAlignment" in pl: |
| obj.addProperty( |
| "App::PropertyBool", |
| "VerticalMullionAlignment", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "If the profile of the vertical mullions get aligned with the surface or not", |
| ), |
| locked=True, |
| ) |
| if not "VerticalSections" in pl: |
| obj.addProperty( |
| "App::PropertyInteger", |
| "VerticalSections", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", "The number of vertical sections of this curtain wall" |
| ), |
| locked=True, |
| ) |
| obj.VerticalSections = 1 |
| if "VerticalMullionSize" in pl: |
| |
| vsize = obj.VerticalMullionSize.Value |
| obj.removeProperty("VerticalMullionSize") |
| if not "VerticalMullionHeight" in pl: |
| obj.addProperty( |
| "App::PropertyLength", |
| "VerticalMullionHeight", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "The height of the vertical mullions profile, if no profile is used", |
| ), |
| locked=True, |
| ) |
| obj.VerticalMullionHeight = vsize |
| if not "VerticalMullionWidth" in pl: |
| obj.addProperty( |
| "App::PropertyLength", |
| "VerticalMullionWidth", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "The width of the vertical mullions profile, if no profile is used", |
| ), |
| locked=True, |
| ) |
| obj.VerticalMullionWidth = vsize |
| if not "VerticalMullionProfile" in pl: |
| obj.addProperty( |
| "App::PropertyLink", |
| "VerticalMullionProfile", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "A profile for vertical mullions (disables vertical mullion size)", |
| ), |
| locked=True, |
| ) |
| if not "HorizontalMullionNumber" in pl: |
| obj.addProperty( |
| "App::PropertyInteger", |
| "HorizontalMullionNumber", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP("App::Property", "The number of horizontal mullions"), |
| locked=True, |
| ) |
| obj.setEditorMode("HorizontalMullionNumber", 1) |
| if not "HorizontalMullionAlignment" in pl: |
| obj.addProperty( |
| "App::PropertyBool", |
| "HorizontalMullionAlignment", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "If the profile of the horizontal mullions gets aligned with the surface or not", |
| ), |
| locked=True, |
| ) |
| if not "HorizontalSections" in pl: |
| obj.addProperty( |
| "App::PropertyInteger", |
| "HorizontalSections", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", "The number of horizontal sections of this curtain wall" |
| ), |
| locked=True, |
| ) |
| obj.HorizontalSections = 1 |
| if "HorizontalMullionSize" in pl: |
| |
| hsize = obj.HorizontalMullionSize.Value |
| obj.removeProperty("HorizontalMullionSize") |
| if not "HorizontalMullionHeight" in pl: |
| obj.addProperty( |
| "App::PropertyLength", |
| "HorizontalMullionHeight", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "The height of the horizontal mullions profile, if no profile is used", |
| ), |
| locked=True, |
| ) |
| obj.HorizontalMullionHeight = hsize |
| if not "HorizontalMullionWidth" in pl: |
| obj.addProperty( |
| "App::PropertyLength", |
| "HorizontalMullionWidth", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "The width of the horizontal mullions profile, if no profile is used", |
| ), |
| locked=True, |
| ) |
| obj.HorizontalMullionWidth = hsize |
| if not "HorizontalMullionProfile" in pl: |
| obj.addProperty( |
| "App::PropertyLink", |
| "HorizontalMullionProfile", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "A profile for horizontal mullions (disables horizontal mullion size)", |
| ), |
| locked=True, |
| ) |
| if not "DiagonalMullionNumber" in pl: |
| obj.addProperty( |
| "App::PropertyInteger", |
| "DiagonalMullionNumber", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP("App::Property", "The number of diagonal mullions"), |
| locked=True, |
| ) |
| obj.setEditorMode("DiagonalMullionNumber", 1) |
| if not "DiagonalMullionSize" in pl: |
| obj.addProperty( |
| "App::PropertyLength", |
| "DiagonalMullionSize", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "The size of the diagonal mullions, if any, if no profile is used", |
| ), |
| locked=True, |
| ) |
| obj.DiagonalMullionSize = 50 |
| if not "DiagonalMullionProfile" in pl: |
| obj.addProperty( |
| "App::PropertyLink", |
| "DiagonalMullionProfile", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "A profile for diagonal mullions, if any (disables horizontal mullion size)", |
| ), |
| locked=True, |
| ) |
| if not "PanelNumber" in pl: |
| obj.addProperty( |
| "App::PropertyInteger", |
| "PanelNumber", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP("App::Property", "The number of panels"), |
| locked=True, |
| ) |
| obj.setEditorMode("PanelNumber", 1) |
| if not "PanelThickness" in pl: |
| obj.addProperty( |
| "App::PropertyLength", |
| "PanelThickness", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP("App::Property", "The thickness of the panels"), |
| locked=True, |
| ) |
| obj.PanelThickness = 20 |
| if not "SwapHorizontalVertical" in pl: |
| obj.addProperty( |
| "App::PropertyBool", |
| "SwapHorizontalVertical", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP("App::Property", "Swaps horizontal and vertical lines"), |
| locked=True, |
| ) |
| if not "Refine" in pl: |
| obj.addProperty( |
| "App::PropertyBool", |
| "Refine", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", "Perform subtractions between components so none overlap" |
| ), |
| locked=True, |
| ) |
| if not "CenterProfiles" in pl: |
| obj.addProperty( |
| "App::PropertyBool", |
| "CenterProfiles", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP("App::Property", "Centers the profile over the edges or not"), |
| locked=True, |
| ) |
| obj.CenterProfiles = True |
| if not "VerticalDirection" in pl: |
| obj.addProperty( |
| "App::PropertyVector", |
| "VerticalDirection", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "The vertical direction reference to be used by this object to deduce vertical/horizontal directions. Keep it close to the actual vertical direction of your curtain wall", |
| ), |
| locked=True, |
| ) |
| obj.VerticalDirection = FreeCAD.Vector(0, 0, 1) |
| if not "OverrideEdges" in pl: |
| obj.addProperty( |
| "App::PropertyStringList", |
| "OverrideEdges", |
| "CurtainWall", |
| QT_TRANSLATE_NOOP( |
| "App::Property", |
| "Input are index numbers of edges of Base ArchSketch/Sketch geometries (in Edit mode). Selected edges are used to create the shape of this Arch Curtain Wall (instead of using all edges by default). [ENHANCED by ArchSketch] GUI 'Edit Curtain Wall' Tool is provided in external Add-on ('SketchArch') to let users to select the edges interactively. 'Toponaming-Tolerant' if ArchSketch is used in Base (and SketchArch Add-on is installed). Warning : Not 'Toponaming-Tolerant' if just Sketch is used. Property is ignored if Base ArchSketch provided the selected edges.", |
| ), |
| locked=True, |
| ) |
|
|
| def onDocumentRestored(self, obj): |
|
|
| ArchComponent.Component.onDocumentRestored(self, obj) |
| self.setProperties(obj) |
|
|
| def loads(self, state): |
|
|
| self.Type = "CurtainWall" |
|
|
| def onChanged(self, obj, prop): |
|
|
| ArchComponent.Component.onChanged(self, obj, prop) |
|
|
| def execute(self, obj): |
|
|
| if self.clone(obj): |
| return |
| if not self.ensureBase(obj): |
| return |
|
|
| import Part |
| import DraftGeomUtils |
|
|
| pl = obj.Placement |
|
|
| |
| if not obj.Base: |
| FreeCAD.Console.PrintLog(obj.Label + ": no base\n") |
| return |
| if not hasattr(obj.Base, "Shape"): |
| FreeCAD.Console.PrintLog(obj.Label + ": invalid base\n") |
| return |
| if obj.VerticalMullionProfile: |
| if not hasattr(obj.VerticalMullionProfile, "Shape"): |
| FreeCAD.Console.PrintLog(obj.Label + ": invalid vertical mullion profile\n") |
| return |
| if obj.HorizontalMullionProfile: |
| if not hasattr(obj.HorizontalMullionProfile, "Shape"): |
| FreeCAD.Console.PrintLog(obj.Label + ": invalid horizontal mullion profile\n") |
| return |
| if obj.DiagonalMullionProfile: |
| if not hasattr(obj.DiagonalMullionProfile, "Shape"): |
| FreeCAD.Console.PrintLog(obj.Label + ": invalid diagonal mullion profile\n") |
| return |
|
|
| facets = [] |
| faces = [] |
|
|
| curtainWallBaseShapeEdges = None |
| curtainWallEdges = None |
| if obj.Base.Shape.Faces: |
| faces = obj.Base.Shape.Faces |
| elif obj.Height.Value and obj.VerticalDirection.Length: |
| ext = FreeCAD.Vector(obj.VerticalDirection) |
| ext.normalize() |
| ext = ext.multiply(obj.Height.Value) |
| if hasattr(obj.Base, "Proxy"): |
| if hasattr(obj.Base.Proxy, "getCurtainWallBaseShapeEdgesInfo"): |
| curtainWallBaseShapeEdges = obj.Base.Proxy.getCurtainWallBaseShapeEdgesInfo( |
| obj.Base |
| ) |
| |
| |
| if ( |
| curtainWallBaseShapeEdges |
| ): |
| curtainWallEdges = curtainWallBaseShapeEdges.get("curtainWallEdges") |
| elif obj.Base.isDerivedFrom("Sketcher::SketchObject"): |
| skGeom = obj.Base.GeometryFacadeList |
| skGeomEdges = [] |
| skPlacement = obj.Base.Placement |
| for ig, geom in enumerate(skGeom): |
| if (not obj.OverrideEdges and not geom.Construction) or str( |
| ig |
| ) in obj.OverrideEdges: |
| |
| |
| if isinstance( |
| geom.Geometry, (Part.LineSegment, Part.Circle, Part.ArcOfCircle) |
| ): |
| skGeomEdgesI = geom.Geometry.toShape() |
| skGeomEdges.append(skGeomEdgesI) |
| curtainWallEdges = [] |
| for edge in skGeomEdges: |
| edge.Placement = edge.Placement.multiply(skPlacement) |
| curtainWallEdges.append(edge) |
| if not curtainWallEdges: |
| curtainWallEdges = obj.Base.Shape.Edges |
| if curtainWallEdges: |
| faces = [edge.extrude(ext) for edge in curtainWallEdges] |
| if not faces: |
| FreeCAD.Console.PrintLog(obj.Label + ": unable to build base faces\n") |
| return |
|
|
| |
| for face in faces: |
|
|
| fp = face.ParameterRange |
|
|
| |
| vdir = obj.VerticalDirection |
| if not vdir.Length: |
| vdir = FreeCAD.Vector(0, 0, 1) |
| vdir.normalize() |
|
|
| |
| |
| |
| |
| face_plane = face.findPlane() |
|
|
| if face_plane: |
| if ( |
| -0.001 < face_plane.Axis[2] < 0.001 |
| ): |
| faceVert = True |
| |
| |
| |
| if obj.SwapHorizontalVertical: |
| vertsec = obj.HorizontalSections |
| horizsec = obj.VerticalSections |
| else: |
| vertsec = obj.VerticalSections |
| horizsec = obj.HorizontalSections |
| else: |
| faceVert = False |
| else: |
| |
| faceVert = False |
|
|
| |
| if not faceVert: |
| |
| |
| |
| |
| |
| basevector = face.valueAt(fp[1], fp[3]).sub(face.valueAt(fp[0], fp[2])) |
| bv_angle = basevector.getAngle(vdir) |
| if (bv_angle <= math.pi / 2 + ANGLETOLERANCE) and ( |
| bv_angle >= math.pi / 2 - ANGLETOLERANCE |
| ): |
| facedir = True |
| if obj.SwapHorizontalVertical: |
| vertsec = obj.HorizontalSections |
| horizsec = obj.VerticalSections |
| else: |
| vertsec = obj.VerticalSections |
| horizsec = obj.HorizontalSections |
| else: |
| facedir = False |
| if obj.SwapHorizontalVertical: |
| vertsec = obj.VerticalSections |
| horizsec = obj.HorizontalSections |
| else: |
| vertsec = obj.HorizontalSections |
| horizsec = obj.VerticalSections |
|
|
| hstep = fp[1] - fp[0] |
| if vertsec: |
| hstep = hstep / vertsec |
| vstep = fp[3] - fp[2] |
| if horizsec: |
| vstep = vstep / horizsec |
|
|
| |
| for i in range(vertsec or 1): |
| for j in range(horizsec or 1): |
| p0 = face.valueAt(fp[0] + i * hstep, fp[2] + j * vstep) |
| p1 = face.valueAt(fp[0] + (i + 1) * hstep, fp[2] + j * vstep) |
| p2 = face.valueAt(fp[0] + (i + 1) * hstep, fp[2] + (j + 1) * vstep) |
| p3 = face.valueAt(fp[0] + i * hstep, fp[2] + (j + 1) * vstep) |
| facet = Part.Face(Part.makePolygon([p0, p1, p2, p3, p0])) |
| facets.append(facet) |
|
|
| if not facets: |
| FreeCAD.Console.PrintLog(obj.Label + ": failed to subdivide shape\n") |
| return |
|
|
| baseshape = Part.makeShell(facets) |
|
|
| |
| edgetable = {} |
| for face in baseshape.Faces: |
| for edge in face.Edges: |
| ec = edge.hashCode() |
| if ec in edgetable: |
| edgetable[ec].append(face) |
| else: |
| edgetable[ec] = [face] |
| self.edgenormals = {} |
| for ec, faces in edgetable.items(): |
| if len(faces) == 1: |
| self.edgenormals[ec] = faces[0].normalAt(0, 0) |
| else: |
| n = faces[0].normalAt(0, 0).add(faces[1].normalAt(0, 0)) |
| if n.Length > 0.001: |
| n.normalize() |
| else: |
| |
| n = faces[0].normalAt(0, 0) |
| self.edgenormals[ec] = n |
|
|
| |
| hedges = [] |
| vedges = [] |
| for edge in baseshape.Edges: |
| v = edge.Vertexes[-1].Point.sub(edge.Vertexes[0].Point) |
| a = v.getAngle(vdir) |
| if (a <= math.pi / 2 + ANGLETOLERANCE) and (a >= math.pi / 2 - ANGLETOLERANCE): |
| hedges.append(edge) |
| else: |
| vedges.append(edge) |
|
|
| |
| vmullions = [] |
| vprofile = self.getMullionProfile(obj, "Vertical") |
| if vprofile and vertsec: |
| for vedge in vedges: |
| vn = self.edgenormals[vedge.hashCode()] |
| if (vn.x != 0) or (vn.y != 0): |
| avn = FreeCAD.Vector(vn.x, vn.y, 0) |
| rot = FreeCAD.Rotation(FreeCAD.Vector(0, -1, 0), avn) |
| else: |
| rot = FreeCAD.Rotation() |
| if obj.VerticalMullionAlignment: |
| ev = vedge.Vertexes[-1].Point.sub(vedge.Vertexes[0].Point) |
| rot = FreeCAD.Rotation(FreeCAD.Vector(1, 0, 0), ev).multiply(rot) |
| vmullions.append(self.makeMullion(vedge, vprofile, rot, obj.CenterProfiles)) |
|
|
| |
| hmullions = [] |
| hprofile = self.getMullionProfile(obj, "Horizontal") |
| if hprofile and horizsec: |
| for hedge in hedges: |
| rot = FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), -90) |
| vn = self.edgenormals[hedge.hashCode()] |
| if (vn.x != 0) or (vn.y != 0): |
| avn = FreeCAD.Vector(vn.x, vn.y, 0) |
| rot = FreeCAD.Rotation(FreeCAD.Vector(0, -1, 0), avn).multiply(rot) |
| if obj.HorizontalMullionAlignment: |
| rot = FreeCAD.Rotation(avn, vn).multiply(rot) |
| hmullions.append(self.makeMullion(hedge, hprofile, rot, obj.CenterProfiles)) |
|
|
| |
| panels = [] |
| dedges = [] |
| if obj.PanelThickness.Value: |
| for face in baseshape.Faces: |
| verts = [v.Point for v in face.OuterWire.OrderedVertexes] |
| if DraftGeomUtils.isPlanar(verts): |
| panel = self.makePanel(verts, obj.PanelThickness.Value) |
| panels.append(panel) |
| elif len(verts) == 4: |
| verts1 = [verts[0], verts[1], verts[2]] |
| panel = self.makePanel(verts1, obj.PanelThickness.Value) |
| panels.append(panel) |
| verts2 = [verts[0], verts[2], verts[3]] |
| panel = self.makePanel(verts2, obj.PanelThickness.Value) |
| panels.append(panel) |
| dedges.append(Part.makeLine(verts[0], verts[2])) |
|
|
| |
| dmullions = [] |
| if dedges: |
| n = dedges[0].Vertexes[-1].Point.sub(dedges[0].Point) |
| dprofile = self.getMullionProfile(obj, "Diagonal") |
| if dprofile: |
| for dedge in dedges: |
| rot = FreeCAD.Rotation( |
| FreeCAD.Vector(0, 0, 1), |
| dedge.Vertexes[-1].Point.sub(dedge.Vertexes[0].Point), |
| ) |
| dmullions.append(self.makeMullion(dedge, dprofile, rot, obj.CenterProfiles)) |
|
|
| |
| if obj.Refine: |
| subvmullion = None |
| subhmullion = None |
| subdmullion = None |
| if vmullions: |
| subvmullion = vmullions[0].copy() |
| for m in vmullions[1:]: |
| subvmullion = subvmullion.fuse(m) |
| if hmullions: |
| subhmullion = hmullions[0].copy() |
| for m in hmullions[1:]: |
| subhmullion = subhmullion.fuse(m) |
| if dmullions: |
| subdmullion = dmullions[0].copy() |
| for m in dmullions[1:]: |
| subdmullion = subdmullion.fuse(m) |
| if subvmullion: |
| hmullions = [m.cut(subvmullion) for m in hmullions] |
| if subhmullion: |
| dmullions = [m.cut(subvmullion) for m in dmullions] |
| dmullions = [m.cut(subhmullion) for m in dmullions] |
| panels = [m.cut(subvmullion) for m in panels] |
| panels = [m.cut(subhmullion) for m in panels] |
| if subdmullion: |
| panels = [m.cut(subdmullion) for m in panels] |
|
|
| |
| obj.VerticalMullionNumber = len(vmullions) |
| obj.HorizontalMullionNumber = len(hmullions) |
| obj.DiagonalMullionNumber = len(dmullions) |
| obj.PanelNumber = len(panels) |
| shape = Part.makeCompound(vmullions + hmullions + dmullions + panels) |
| shape = self.processSubShapes(obj, shape, pl) |
| self.applyShape(obj, shape, pl) |
|
|
| def makePanel(self, verts, thickness): |
| """creates a panel from face points and thickness""" |
|
|
| import Part |
|
|
| panel = Part.Face(Part.makePolygon(verts + [verts[0]])) |
| n = panel.normalAt(0, 0) |
| n.multiply(thickness) |
| panel = panel.extrude(n) |
| return panel |
|
|
| def makeMullion(self, edge, profile, rotation, recenter=False): |
| """creates a mullions from an edge and a profile""" |
|
|
| center = FreeCAD.Vector(0, 0, 0) |
| if recenter: |
| if hasattr(profile, "CenterOfMass"): |
| center = profile.CenterOfMass |
| elif hasattr(profile, "BoundBox"): |
| center = profile.BoundBox.Center |
| p0 = edge.Vertexes[0].Point |
| p1 = edge.Vertexes[-1].Point |
| mullion = profile.copy() |
| if rotation: |
| mullion = mullion.rotate(center, rotation.Axis, math.degrees(rotation.Angle)) |
| mullion = mullion.translate(p0.sub(center)) |
| mullion = mullion.extrude(p1.sub(p0)) |
| return mullion |
|
|
| def getMullionProfile(self, obj, direction): |
| """returns a profile shape already properly oriented, ready for extrude""" |
|
|
| import Part |
| import DraftGeomUtils |
|
|
| prof = getattr(obj, direction + "MullionProfile") |
| proh = getattr(obj, direction + "MullionHeight").Value |
| prow = getattr(obj, direction + "MullionWidth").Value |
| if prof: |
| profile = prof.Shape.copy() |
| else: |
| if (not proh) or (not prow): |
| return None |
| profile = Part.Face(Part.makePlane(prow, proh, FreeCAD.Vector(-prow / 2, -proh / 2, 0))) |
| return profile |
|
|
| def getProjectedLength(self, v, ref): |
| """gets a signed length from projecting a vector on another""" |
|
|
| proj = DraftVecUtils.project(v, ref) |
| if proj.getAngle(ref) < 1: |
| return proj.Length |
| else: |
| return -proj.Length |
|
|
|
|
| class ViewProviderCurtainWall(ArchComponent.ViewProviderComponent): |
| "A View Provider for the CurtainWall object" |
|
|
| def __init__(self, vobj): |
|
|
| ArchComponent.ViewProviderComponent.__init__(self, vobj) |
|
|
| def getIcon(self): |
|
|
| import Arch_rc |
|
|
| return ":/icons/Arch_CurtainWall_Tree.svg" |
|
|
| def updateData(self, obj, prop): |
|
|
| if prop == "Shape": |
| self.colorize(obj, force=True) |
|
|
| def onChanged(self, vobj, prop): |
|
|
| if (prop in ["DiffuseColor", "Transparency"]) and vobj.Object: |
| self.colorize(vobj.Object) |
| elif prop == "ShapeColor": |
| self.colorize(vobj.Object, force=True) |
| ArchComponent.ViewProviderComponent.onChanged(self, vobj, prop) |
|
|
| def colorize(self, obj, force=False): |
| "setting different part colors" |
|
|
| if not obj.Shape or not obj.Shape.Solids: |
| return |
| if not obj.ViewObject: |
| return |
| basecolor = obj.ViewObject.ShapeColor |
| basetransparency = obj.ViewObject.Transparency / 100.0 |
| panelcolor = ArchCommands.getDefaultColor("WindowGlass") |
| paneltransparency = 0.7 |
| if hasattr(obj, "Material") and obj.Material and hasattr(obj.Material, "Materials"): |
| if obj.Material.Names: |
| if "Frame" in obj.Material.Names: |
| mat = obj.Material.Materials[obj.Material.Names.index("Frame")] |
| if ("DiffuseColor" in mat.Material) and ("(" in mat.Material["DiffuseColor"]): |
| basecolor = tuple( |
| [float(f) for f in mat.Material["DiffuseColor"].strip("()").split(",")] |
| ) |
| if "Glass panel" in obj.Material.Names: |
| mat = obj.Material.Materials[obj.Material.Names.index("Glass panel")] |
| if ("DiffuseColor" in mat.Material) and ("(" in mat.Material["DiffuseColor"]): |
| panelcolor = tuple( |
| [float(f) for f in mat.Material["DiffuseColor"].strip("()").split(",")] |
| ) |
| if "Transparency" in mat.Material: |
| paneltransparency = float(mat.Material["Transparency"]) / 100.0 |
| elif "Solid panel" in obj.Material.Names: |
| mat = obj.Material.Materials[obj.Material.Names.index("Solid panel")] |
| if ("DiffuseColor" in mat.Material) and ("(" in mat.Material["DiffuseColor"]): |
| panelcolor = tuple( |
| [float(f) for f in mat.Material["DiffuseColor"].strip("()").split(",")] |
| ) |
| paneltransparency = 0 |
| basecolor = basecolor[:3] + (1.0 - basetransparency,) |
| panelcolor = panelcolor[:3] + (1.0 - paneltransparency,) |
| colors = [] |
| nmullions = ( |
| obj.VerticalMullionNumber + obj.HorizontalMullionNumber + obj.DiagonalMullionNumber |
| ) |
| for i, solid in enumerate(obj.Shape.Solids): |
| for _ in solid.Faces: |
| if i < nmullions: |
| colors.append(basecolor) |
| else: |
| colors.append(panelcolor) |
| if self.areDifferentColors(colors, obj.ViewObject.DiffuseColor) or force: |
| obj.ViewObject.DiffuseColor = colors |
|
|