BIM: Renamed Arch to BIM
This commit is contained in:
committed by
Yorik van Havre
parent
23fc3bb5bc
commit
f21a3b3ec9
229
src/Mod/BIM/ArchFrame.py
Normal file
229
src/Mod/BIM/ArchFrame.py
Normal file
@@ -0,0 +1,229 @@
|
||||
#***************************************************************************
|
||||
#* Copyright (c) 2013 Yorik van Havre <yorik@uncreated.net> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
import FreeCAD
|
||||
import ArchComponent
|
||||
import Draft
|
||||
import DraftVecUtils
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from draftutils.translate import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt,txt):
|
||||
return txt
|
||||
def QT_TRANSLATE_NOOP(ctxt,txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
## @package ArchFrame
|
||||
# \ingroup ARCH
|
||||
# \brief The Frame object and tools
|
||||
#
|
||||
# This module provides tools to build Frame objects.
|
||||
# Frames are objects made of a profile and an object with
|
||||
# edges along which the profile gets extruded
|
||||
|
||||
__title__ = "FreeCAD Arch Frame"
|
||||
__author__ = "Yorik van Havre"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
|
||||
|
||||
class _Frame(ArchComponent.Component):
|
||||
|
||||
"A parametric frame object"
|
||||
|
||||
def __init__(self,obj):
|
||||
ArchComponent.Component.__init__(self,obj)
|
||||
self.setProperties(obj)
|
||||
obj.IfcType = "Railing"
|
||||
|
||||
def setProperties(self,obj):
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "Profile" in pl:
|
||||
obj.addProperty("App::PropertyLink","Profile","Frame",QT_TRANSLATE_NOOP("App::Property","The profile used to build this frame"))
|
||||
if not "Align" in pl:
|
||||
obj.addProperty("App::PropertyBool","Align","Frame",QT_TRANSLATE_NOOP("App::Property","Specifies if the profile must be aligned with the extrusion wires"))
|
||||
obj.Align = True
|
||||
if not "Offset" in pl:
|
||||
obj.addProperty("App::PropertyVectorDistance","Offset","Frame",QT_TRANSLATE_NOOP("App::Property","An offset vector between the base sketch and the frame"))
|
||||
if not "BasePoint" in pl:
|
||||
obj.addProperty("App::PropertyInteger","BasePoint","Frame",QT_TRANSLATE_NOOP("App::Property","Crossing point of the path on the profile."))
|
||||
if not "ProfilePlacement" in pl:
|
||||
obj.addProperty("App::PropertyPlacement","ProfilePlacement","Frame",QT_TRANSLATE_NOOP("App::Property","An optional additional placement to add to the profile before extruding it"))
|
||||
if not "Rotation" in pl:
|
||||
obj.addProperty("App::PropertyAngle","Rotation","Frame",QT_TRANSLATE_NOOP("App::Property","The rotation of the profile around its extrusion axis"))
|
||||
if not "Edges" in pl:
|
||||
obj.addProperty("App::PropertyEnumeration","Edges","Frame",QT_TRANSLATE_NOOP("App::Property","The type of edges to consider"))
|
||||
obj.Edges = ["All edges","Vertical edges","Horizontal edges","Bottom horizontal edges","Top horizontal edges"]
|
||||
if not "Fuse" in pl:
|
||||
obj.addProperty("App::PropertyBool","Fuse","Frame",QT_TRANSLATE_NOOP("App::Property","If true, geometry is fused, otherwise a compound"))
|
||||
self.Type = "Frame"
|
||||
|
||||
def onDocumentRestored(self,obj):
|
||||
|
||||
ArchComponent.Component.onDocumentRestored(self,obj)
|
||||
self.setProperties(obj)
|
||||
|
||||
def execute(self,obj):
|
||||
|
||||
if self.clone(obj):
|
||||
return
|
||||
|
||||
if not obj.Base:
|
||||
return
|
||||
if not obj.Base.Shape:
|
||||
return
|
||||
if not obj.Base.Shape.Wires:
|
||||
return
|
||||
|
||||
pl = obj.Placement
|
||||
if obj.Base.Shape.Solids:
|
||||
obj.Shape = obj.Base.Shape.copy()
|
||||
if not pl.isNull():
|
||||
obj.Placement = obj.Shape.Placement.multiply(pl)
|
||||
else:
|
||||
if not obj.Profile:
|
||||
return
|
||||
if not obj.Profile.Shape:
|
||||
return
|
||||
if obj.Profile.Shape.findPlane() is None:
|
||||
return
|
||||
if not obj.Profile.Shape.Wires:
|
||||
return
|
||||
if not obj.Profile.Shape.Faces:
|
||||
for w in obj.Profile.Shape.Wires:
|
||||
if not w.isClosed():
|
||||
return
|
||||
import math
|
||||
import DraftGeomUtils
|
||||
import Part
|
||||
baseprofile = obj.Profile.Shape.copy()
|
||||
if hasattr(obj,"ProfilePlacement"):
|
||||
if not obj.ProfilePlacement.isNull():
|
||||
baseprofile.Placement = obj.ProfilePlacement.multiply(baseprofile.Placement)
|
||||
if not baseprofile.Faces:
|
||||
f = []
|
||||
for w in baseprofile.Wires:
|
||||
f.append(Part.Face(w))
|
||||
if len(f) == 1:
|
||||
baseprofile = f[0]
|
||||
else:
|
||||
baseprofile = Part.makeCompound(f)
|
||||
shapes = []
|
||||
normal = DraftGeomUtils.getNormal(obj.Base.Shape)
|
||||
edges = obj.Base.Shape.Edges
|
||||
if hasattr(obj,"Edges"):
|
||||
if obj.Edges == "Vertical edges":
|
||||
rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(0,1,0))
|
||||
edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
|
||||
elif obj.Edges == "Horizontal edges":
|
||||
rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
|
||||
edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
|
||||
elif obj.Edges == "Top horizontal edges":
|
||||
rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
|
||||
edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
|
||||
edges = sorted(edges,key=lambda x: x.CenterOfMass.z,reverse=True)
|
||||
z = edges[0].CenterOfMass.z
|
||||
edges = [e for e in edges if abs(e.CenterOfMass.z-z) < 0.00001]
|
||||
elif obj.Edges == "Bottom horizontal edges":
|
||||
rv = obj.Base.Placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
|
||||
edges = [e for e in edges if round(rv.getAngle(e.tangentAt(e.FirstParameter)),4) in [0,3.1416]]
|
||||
edges = sorted(edges,key=lambda x: x.CenterOfMass.z)
|
||||
z = edges[0].CenterOfMass.z
|
||||
edges = [e for e in edges if abs(e.CenterOfMass.z-z) < 0.00001]
|
||||
for e in edges:
|
||||
bvec = DraftGeomUtils.vec(e)
|
||||
bpoint = e.Vertexes[0].Point
|
||||
profile = baseprofile.copy()
|
||||
rot = None # New rotation.
|
||||
# Supplying FreeCAD.Rotation() with two parallel vectors and
|
||||
# a null vector may seem strange, but the function is perfectly
|
||||
# able to handle this. Its algorithm will use default axes in
|
||||
# such cases.
|
||||
if obj.Align:
|
||||
if normal is None:
|
||||
rot = FreeCAD.Rotation(FreeCAD.Vector(), bvec, bvec, "ZYX")
|
||||
else:
|
||||
rot = FreeCAD.Rotation(FreeCAD.Vector(), normal, bvec, "ZYX")
|
||||
profile.Placement.Rotation = rot
|
||||
if hasattr(obj, "BasePoint"):
|
||||
edges = Part.__sortEdges__(profile.Edges)
|
||||
basepointliste = [profile.Placement.Base]
|
||||
for edge in edges:
|
||||
basepointliste.append(DraftGeomUtils.findMidpoint(edge))
|
||||
basepointliste.append(edge.Vertexes[-1].Point)
|
||||
try:
|
||||
basepoint = basepointliste[obj.BasePoint]
|
||||
except IndexError:
|
||||
FreeCAD.Console.PrintMessage(translate("Arch", "Crossing point not found in profile.")+"\n")
|
||||
basepoint = basepointliste[0]
|
||||
else:
|
||||
basepoint = profile.Placement.Base
|
||||
delta = bpoint.sub(basepoint) # Translation vector.
|
||||
if obj.Offset and (not DraftVecUtils.isNull(obj.Offset)):
|
||||
if rot is None:
|
||||
delta = delta + obj.Offset
|
||||
else:
|
||||
delta = delta + rot.multVec(obj.Offset)
|
||||
profile.translate(delta)
|
||||
if obj.Rotation:
|
||||
profile.rotate(bpoint, bvec, obj.Rotation)
|
||||
# profile = wire.makePipeShell([profile], True, False, 2) TODO buggy
|
||||
profile = profile.extrude(bvec)
|
||||
shapes.append(profile)
|
||||
if shapes:
|
||||
if hasattr(obj,"Fuse"):
|
||||
if obj.Fuse:
|
||||
if len(shapes) > 1:
|
||||
s = shapes[0].multiFuse(shapes[1:])
|
||||
s = s.removeSplitter()
|
||||
obj.Shape = s
|
||||
obj.Placement = pl
|
||||
return
|
||||
obj.Shape = Part.makeCompound(shapes)
|
||||
obj.Placement = pl
|
||||
|
||||
|
||||
class _ViewProviderFrame(ArchComponent.ViewProviderComponent):
|
||||
|
||||
"A View Provider for the Frame object"
|
||||
|
||||
def __init__(self,vobj):
|
||||
|
||||
ArchComponent.ViewProviderComponent.__init__(self,vobj)
|
||||
|
||||
def getIcon(self):
|
||||
|
||||
import Arch_rc
|
||||
return ":/icons/Arch_Frame_Tree.svg"
|
||||
|
||||
def claimChildren(self):
|
||||
|
||||
p = []
|
||||
if hasattr(self,"Object"):
|
||||
if self.Object.Profile:
|
||||
p = [self.Object.Profile]
|
||||
return ArchComponent.ViewProviderComponent.claimChildren(self)+p
|
||||
|
||||
Reference in New Issue
Block a user