Arch: Structural nodes - closes #1313

This commit is contained in:
Yorik van Havre 2013-12-15 17:45:12 -02:00
parent c6fbcbe086
commit 2b10890a04
2 changed files with 222 additions and 140 deletions

View File

@ -536,6 +536,8 @@ class _Structure(ArchComponent.Component):
str(translate("Arch","The element numbers to exclude when this structure is based on axes")))
obj.addProperty("App::PropertyEnumeration","Role","Arch",
str(translate("Arch","The role of this structural element")))
obj.addProperty("App::PropertyVectorList","Nodes","Arch",
str(translate("Arch","The structural nodes of this element")))
self.Type = "Structure"
obj.Length = 1
obj.Width = 1
@ -543,35 +545,8 @@ class _Structure(ArchComponent.Component):
obj.Role = Roles
def execute(self,obj):
self.createGeometry(obj)
"creates the structure shape"
def onChanged(self,obj,prop):
self.hideSubobjects(obj,prop)
if prop in ["Base","Tool","Length","Width","Height","Normal","Additions","Subtractions","Axes"]:
self.createGeometry(obj)
def getAxisPoints(self,obj):
"returns the gridpoints of linked axes"
import DraftGeomUtils
pts = []
if len(obj.Axes) == 1:
for e in obj.Axes[0].Shape.Edges:
pts.append(e.Vertexes[0].Point)
elif len(obj.Axes) >= 2:
set1 = obj.Axes[0].Shape.Edges
set2 = obj.Axes[1].Shape.Edges
for e1 in set1:
for e2 in set2:
pts.extend(DraftGeomUtils.findIntersection(e1,e2))
return pts
def getAxisPlacement(self,obj):
"returns an axis placement"
if obj.Axes:
return obj.Axes[0].Placement
return None
def createGeometry(self,obj):
import Part, DraftGeomUtils
# getting default values
@ -609,10 +584,14 @@ class _Structure(ArchComponent.Component):
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"):
@ -623,19 +602,31 @@ class _Structure(ArchComponent.Component):
base = sh
else:
if obj.Normal == Vector(0,0,0):
normal = Vector(0,0,1)
if length > height:
normal = Vector(1,0,0).multiply(length)
else:
normal = Vector(0,0,1).multiply(height)
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)
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)
base = base.extrude(normal)
self.BaseProfile = base
base = base.extrude(self.ExtrusionVector)
base = self.processSubShapes(obj,base)
@ -657,7 +648,6 @@ class _Structure(ArchComponent.Component):
obj.Shape = Part.makeCompound(fsh)
# finalizing
else:
if base:
if not base.isNull():
@ -672,16 +662,116 @@ class _Structure(ArchComponent.Component):
if not DraftGeomUtils.isNull(pl):
obj.Placement = pl
def onChanged(self,obj,prop):
self.hideSubobjects(obj,prop)
if prop == "Shape":
if obj.Nodes:
if hasattr(self,"nodes"):
if self.nodes:
if obj.Nodes != self.nodes:
# nodes are set manually: don't touch them
return
else:
# nodes haven't been calculated yet, but are set (file load)
# we calculate the nodes now but don't change the property
if hasattr(self,"BaseProfile") and hasattr(self,"ExtrusionVector"):
p1 = self.BaseProfile.CenterOfMass
p2 = p1.add(self.ExtrusionVector)
self.nodes = [p1,p2]
return
if hasattr(self,"BaseProfile") and hasattr(self,"ExtrusionVector"):
p1 = self.BaseProfile.CenterOfMass
p2 = p1.add(self.ExtrusionVector)
self.nodes = [p1,p2]
#print "calculating nodes: ",self.nodes
obj.Nodes = self.nodes
def getAxisPoints(self,obj):
"returns the gridpoints of linked axes"
import DraftGeomUtils
pts = []
if len(obj.Axes) == 1:
for e in obj.Axes[0].Shape.Edges:
pts.append(e.Vertexes[0].Point)
elif len(obj.Axes) >= 2:
set1 = obj.Axes[0].Shape.Edges
set2 = obj.Axes[1].Shape.Edges
for e1 in set1:
for e2 in set2:
pts.extend(DraftGeomUtils.findIntersection(e1,e2))
return pts
def getAxisPlacement(self,obj):
"returns an axis placement"
if obj.Axes:
return obj.Axes[0].Placement
return None
class _ViewProviderStructure(ArchComponent.ViewProviderComponent):
"A View Provider for the Structure object"
def __init__(self,vobj):
ArchComponent.ViewProviderComponent.__init__(self,vobj)
vobj.addProperty("App::PropertyBool","ShowNodes","Arch","If the nodes are visible or not").ShowNodes = False
vobj.addProperty("App::PropertyFloat","NodeLine","Base","The width of the nodes line")
vobj.addProperty("App::PropertyFloat","NodeSize","Base","The size of the node points")
vobj.addProperty("App::PropertyColor","NodeColor","Base","The color of the nodes line")
vobj.NodeColor = (1.0,1.0,1.0,1.0)
vobj.NodeSize = 6
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Structure_Tree.svg"
def updateData(self,obj,prop):
if prop == "Nodes":
if obj.Nodes:
if hasattr(self,"nodes"):
p = []
for n in obj.Nodes:
p.append([n.x,n.y,n.z])
self.coords.point.setValues(0,len(p),p)
self.pointset.numPoints.setValue(len(p))
self.lineset.coordIndex.setValues(0,len(p)+1,range(len(p))+[-1])
def onChanged(self,vobj,prop):
if prop == "ShowNodes":
if hasattr(self,"nodes"):
vobj.Annotation.removeChild(self.nodes)
del self.nodes
if vobj.ShowNodes:
from pivy import coin
self.nodes = coin.SoAnnotation()
self.coords = coin.SoCoordinate3()
self.mat = coin.SoMaterial()
self.pointstyle = coin.SoDrawStyle()
self.pointstyle.style = coin.SoDrawStyle.POINTS
self.pointset = coin.SoType.fromName("SoBrepPointSet").createInstance()
self.linestyle = coin.SoDrawStyle()
self.linestyle.style = coin.SoDrawStyle.LINES
self.lineset = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
self.nodes.addChild(self.coords)
self.nodes.addChild(self.mat)
self.nodes.addChild(self.pointstyle)
self.nodes.addChild(self.pointset)
self.nodes.addChild(self.linestyle)
self.nodes.addChild(self.lineset)
vobj.Annotation.addChild(self.nodes)
self.updateData(vobj.Object,"Nodes")
self.onChanged(vobj,"NodeColor")
self.onChanged(vobj,"NodeLine")
self.onChanged(vobj,"NodeSize")
elif prop == "NodeColor":
if hasattr(self,"mat"):
l = vobj.NodeColor
self.mat.diffuseColor.setValue([l[0],l[1],l[2]])
elif prop == "NodeLine":
if hasattr(self,"linestyle"):
self.linestyle.lineWidth = vobj.NodeLine
elif prop == "NodeSize":
if hasattr(self,"pointstyle"):
self.pointstyle.pointSize = vobj.NodeSize
ArchComponent.ViewProviderComponent.onChanged(self,vobj,prop)
class _Profile(Draft._DraftObject):
@ -695,13 +785,6 @@ class _Profile(Draft._DraftObject):
Draft._DraftObject.__init__(self,obj,"Profile")
def execute(self,obj):
self.createGeometry(obj)
def onChanged(self,obj,prop):
if prop in ["Width","Height","WebThickness","FlangeThickness"]:
self.createGeometry(obj)
def createGeometry(self,obj):
import Part
pl = obj.Placement
p1 = Vector(-obj.Width/2,-obj.Height/2,0)
@ -720,6 +803,10 @@ class _Profile(Draft._DraftObject):
p = Part.Face(p)
obj.Shape = p
obj.Placement = pl
def onChanged(self,obj,prop):
if prop in ["Width","Height","WebThickness","FlangeThickness"]:
self.execute(obj)
FreeCADGui.addCommand('Arch_Structure',_CommandStructure())

View File

@ -395,100 +395,8 @@ class _Wall(ArchComponent.Component):
obj.Length = 1
def execute(self,obj):
self.createGeometry(obj)
def onChanged(self,obj,prop):
self.hideSubobjects(obj,prop)
if prop in ["Base","Height","Width","Align","Additions","Subtractions","Face"]:
self.createGeometry(obj)
# propagate movements to children windows
if prop == "Placement":
if obj.Shape:
if not obj.Shape.isNull():
vo = obj.Shape.Placement.Base
vn = obj.Placement.Base
if not DraftVecUtils.equals(vo,vn):
delta = vn.sub(vo)
for o in obj.OutList:
if (Draft.getType(o) == "Window") or Draft.isClone(o,"Window"):
o.Placement.move(delta)
ArchComponent.Component.onChanged(self,obj,prop)
def getDefaultValues(self,obj):
"returns normal,width,height values from this wall"
length = 1
if hasattr(obj,"Length"):
if obj.Length:
length = obj.Length
width = 1
if hasattr(obj,"Width"):
if obj.Width:
width = obj.Width
height = normal = None
if hasattr(obj,"Height"):
if obj.Height:
height = obj.Height
else:
for p in obj.InList:
if Draft.getType(p) == "Floor":
height = p.Height
if not height:
height = 1
if hasattr(obj,"Normal"):
if obj.Normal == Vector(0,0,0):
normal = Vector(0,0,1)
else:
normal = Vector(obj.Normal)
else:
normal = Vector(0,0,1)
return normal,length,width,height
def getBase(self,obj,wire,normal,width,height):
"returns a full shape from a base wire"
import DraftGeomUtils,Part
flat = False
if hasattr(obj.ViewObject,"DisplayMode"):
flat = (obj.ViewObject.DisplayMode == "Flat 2D")
dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal)
if not DraftVecUtils.isNull(dvec):
dvec.normalize()
if obj.Align == "Left":
dvec.multiply(width)
if hasattr(obj,"Offset"):
if obj.Offset:
dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset)
wire = DraftGeomUtils.offsetWire(wire,dvec2)
w2 = DraftGeomUtils.offsetWire(wire,dvec)
w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
sh = DraftGeomUtils.bind(w1,w2)
elif obj.Align == "Right":
dvec.multiply(width)
dvec = dvec.negative()
if hasattr(obj,"Offset"):
if obj.Offset:
dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset)
wire = DraftGeomUtils.offsetWire(wire,dvec2)
w2 = DraftGeomUtils.offsetWire(wire,dvec)
w1 = Part.Wire(DraftGeomUtils.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)
# fixing self-intersections
sh.fix(0.1,0,1)
self.BaseProfile = sh
if height and (not flat):
norm = Vector(normal).multiply(height)
sh = sh.extrude(norm)
self.ExtrusionVector = norm
return sh
def createGeometry(self,obj):
"builds the wall shape"
import Part, DraftGeomUtils
pl = obj.Placement
normal,length,width,height = self.getDefaultValues(obj)
@ -577,6 +485,93 @@ class _Wall(ArchComponent.Component):
obj.Shape = base
if not DraftGeomUtils.isNull(pl):
obj.Placement = pl
def onChanged(self,obj,prop):
self.hideSubobjects(obj,prop)
# propagate movements to children windows
if prop == "Placement":
if obj.Shape:
if not obj.Shape.isNull():
vo = obj.Shape.Placement.Base
vn = obj.Placement.Base
if not DraftVecUtils.equals(vo,vn):
delta = vn.sub(vo)
for o in obj.OutList:
if (Draft.getType(o) == "Window") or Draft.isClone(o,"Window"):
o.Placement.move(delta)
ArchComponent.Component.onChanged(self,obj,prop)
def getDefaultValues(self,obj):
"returns normal,width,height values from this wall"
length = 1
if hasattr(obj,"Length"):
if obj.Length:
length = obj.Length
width = 1
if hasattr(obj,"Width"):
if obj.Width:
width = obj.Width
height = normal = None
if hasattr(obj,"Height"):
if obj.Height:
height = obj.Height
else:
for p in obj.InList:
if Draft.getType(p) == "Floor":
height = p.Height
if not height:
height = 1
if hasattr(obj,"Normal"):
if obj.Normal == Vector(0,0,0):
normal = Vector(0,0,1)
else:
normal = Vector(obj.Normal)
else:
normal = Vector(0,0,1)
return normal,length,width,height
def getBase(self,obj,wire,normal,width,height):
"returns a full shape from a base wire"
import DraftGeomUtils,Part
flat = False
if hasattr(obj.ViewObject,"DisplayMode"):
flat = (obj.ViewObject.DisplayMode == "Flat 2D")
dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal)
if not DraftVecUtils.isNull(dvec):
dvec.normalize()
if obj.Align == "Left":
dvec.multiply(width)
if hasattr(obj,"Offset"):
if obj.Offset:
dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset)
wire = DraftGeomUtils.offsetWire(wire,dvec2)
w2 = DraftGeomUtils.offsetWire(wire,dvec)
w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
sh = DraftGeomUtils.bind(w1,w2)
elif obj.Align == "Right":
dvec.multiply(width)
dvec = dvec.negative()
if hasattr(obj,"Offset"):
if obj.Offset:
dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset)
wire = DraftGeomUtils.offsetWire(wire,dvec2)
w2 = DraftGeomUtils.offsetWire(wire,dvec)
w1 = Part.Wire(DraftGeomUtils.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)
# fixing self-intersections
sh.fix(0.1,0,1)
self.BaseProfile = sh
if height and (not flat):
self.ExtrusionVector = Vector(normal).multiply(height)
sh = sh.extrude(self.ExtrusionVector)
return sh
class _ViewProviderWall(ArchComponent.ViewProviderComponent):
"A View Provider for the Wall object"
@ -596,7 +591,7 @@ class _ViewProviderWall(ArchComponent.ViewProviderComponent):
return ArchComponent.ViewProviderComponent.getDisplayModes(self,vobj)+["Flat 2D"]
def setDisplayMode(self,mode):
self.Object.Proxy.createGeometry(self.Object)
self.Object.Proxy.execute(self.Object)
if mode == "Flat 2D":
return "Flat Lines"
else: