Files
create/src/Mod/Arch/ArchFrame.py
luz.paz 8fb5c65736 Arch: [skip ci] fix header uniformity
This PR fixes header uniformity across all Arch files
2019-12-26 18:24:06 +01:00

275 lines
12 KiB
Python

#***************************************************************************
#* 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,Draft,ArchComponent,DraftVecUtils,ArchCommands
from FreeCAD import Vector
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore, QtGui
from DraftTools 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__ = "http://www.freecadweb.org"
def makeFrame(baseobj,profile,name=translate("Arch","Frame")):
"""makeFrame(baseobj,profile,[name]): creates a frame object from a base sketch (or any other object
containing wires) and a profile object (an extrudable 2D object containing faces or closed wires)"""
if not FreeCAD.ActiveDocument:
FreeCAD.Console.PrintError("No active document. Aborting\n")
return
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Frame")
obj.Label = translate("Arch",name)
_Frame(obj)
if FreeCAD.GuiUp:
_ViewProviderFrame(obj.ViewObject)
if baseobj:
obj.Base = baseobj
if profile:
obj.Profile = profile
if FreeCAD.GuiUp:
profile.ViewObject.hide()
return obj
class _CommandFrame:
"the Arch Frame command definition"
def GetResources(self):
return {'Pixmap' : 'Arch_Frame',
'MenuText': QT_TRANSLATE_NOOP("Arch_Frame","Frame"),
'Accel': "F, R",
'ToolTip': QT_TRANSLATE_NOOP("Arch_Frame","Creates a frame object from a planar 2D object (the extrusion path(s)) and a profile. Make sure objects are selected in that order.")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
s = FreeCADGui.Selection.getSelection()
if len(s) == 2:
FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Frame"))
FreeCADGui.addModule("Arch")
FreeCADGui.doCommand("obj = Arch.makeFrame(FreeCAD.ActiveDocument."+s[0].Name+",FreeCAD.ActiveDocument."+s[1].Name+")")
FreeCADGui.addModule("Draft")
FreeCADGui.doCommand("Draft.autogroup(obj)")
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
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.isDerivedFrom("Part::Part2DObject"):
return
if not obj.Profile.Shape:
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 DraftGeomUtils, Part, math
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)
#for wire in obj.Base.Shape.Wires:
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:
#e = wire.Edges[0]
bvec = DraftGeomUtils.vec(e)
bpoint = e.Vertexes[0].Point
profile = baseprofile.copy()
#basepoint = profile.Placement.Base
if hasattr(obj,"BasePoint"):
edges = Part.__sortEdges__(profile.Edges)
basepointliste = [profile.CenterOfMass]
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.CenterOfMass
profile.translate(bpoint.sub(basepoint))
if obj.Align:
axis = profile.Placement.Rotation.multVec(FreeCAD.Vector(0,0,1))
angle = bvec.getAngle(axis)
if round(angle,Draft.precision()) != 0:
if round(angle,Draft.precision()) != round(math.pi,Draft.precision()):
rotaxis = axis.cross(bvec)
profile.rotate(DraftVecUtils.tup(bpoint), DraftVecUtils.tup(rotaxis), math.degrees(angle))
if obj.Rotation:
profile.rotate(DraftVecUtils.tup(bpoint), DraftVecUtils.tup(FreeCAD.Vector(bvec).normalize()), obj.Rotation)
#profile = wire.makePipeShell([profile],True,False,2) TODO buggy
profile = profile.extrude(bvec)
if obj.Offset:
if not DraftVecUtils.isNull(obj.Offset):
profile.translate(obj.Offset)
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
if FreeCAD.GuiUp:
FreeCADGui.addCommand('Arch_Frame',_CommandFrame())