Arch: Further work on Space object

This commit is contained in:
Yorik van Havre 2013-07-17 13:23:33 -03:00
parent a882476c25
commit dcb2ebf2ec
2 changed files with 79 additions and 33 deletions

View File

@ -319,17 +319,27 @@ def getCutVolume(cutplane,shapes):
import Part
if not isinstance(shapes,list):
shapes = [shapes]
placement = FreeCAD.Placement(cutplane.Placement)
# building boundbox
bb = shapes[0].BoundBox
for sh in shapes[1:]:
bb.add(sh.BoundBox)
bb.enlarge(1)
# building cutplane space
placement = None
um = vm = wm = 0
ax = placement.Rotation.multVec(FreeCAD.Vector(0,0,1))
u = placement.Rotation.multVec(FreeCAD.Vector(1,0,0))
v = placement.Rotation.multVec(FreeCAD.Vector(0,1,0))
if not bb.isCutPlane(placement.Base,ax):
try:
if hasattr(cutplane,"Shape"):
p = cutplane.Shape.copy().Faces[0]
else:
p = cutplane.copy().Faces[0]
except:
FreeCAD.Console.PrintMessage(str(translate("Arch","Invalid cutplane")))
return None,None,None
ce = p.CenterOfMass
ax = p.normalAt(0,0)
u = p.Vertexes[1].Point.sub(p.Vertexes[0].Point).normalize()
v = u.cross(ax)
if not bb.isCutPlane(ce,ax):
FreeCAD.Console.PrintMessage(str(translate("Arch","No objects are cut by the plane")))
return None,None,None
else:
@ -342,20 +352,23 @@ def getCutVolume(cutplane,shapes):
FreeCAD.Vector(bb.XMax,bb.YMin,bb.ZMax),
FreeCAD.Vector(bb.XMax,bb.YMax,bb.ZMax)]
for c in corners:
dv = c.sub(placement.Base)
dv = c.sub(ce)
um1 = DraftVecUtils.project(dv,u).Length
um = max(um,um1)
vm1 = DraftVecUtils.project(dv,v).Length
vm = max(vm,vm1)
wm1 = DraftVecUtils.project(dv,ax).Length
wm = max(wm,wm1)
p1 = FreeCAD.Vector(-um,vm,0)
p2 = FreeCAD.Vector(um,vm,0)
p3 = FreeCAD.Vector(um,-vm,0)
p4 = FreeCAD.Vector(-um,-vm,0)
vu = DraftVecUtils.scaleTo(u,um)
vui = DraftVecUtils.neg(vu)
vv = DraftVecUtils.scaleTo(v,vm)
vvi = DraftVecUtils.neg(vv)
p1 = ce.add(vu.add(vvi))
p2 = ce.add(vu.add(vv))
p3 = ce.add(vui.add(vv))
p4 = ce.add(vui.add(vvi))
cutface = Part.makePolygon([p1,p2,p3,p4,p1])
cutface = Part.Face(cutface)
cutface.Placement = placement
cutnormal = DraftVecUtils.scaleTo(ax,wm)
cutvolume = cutface.extrude(cutnormal)
cutnormal = DraftVecUtils.neg(cutnormal)

View File

@ -26,7 +26,9 @@ from DraftTools import translate
from PyQt4 import QtCore
def makeSpace(objects):
"""makeSpace(objects): Creates a space objects from the given boundary objects"""
"""makeSpace(objects): Creates a space object from the given objects. Objects can be one
document object, in which case it becomes the base shape of the space object, or a list of
selection objects as got from getSelectionEx(), or a list of tuples (object, subobjectname)"""
if not objects:
return
if not isinstance(objects,list):
@ -38,8 +40,13 @@ def makeSpace(objects):
obj.Base = objects[0]
objects[0].ViewObject.hide()
else:
obj.Objects = objects
obj.Proxy.addSubobjects(objects)
def addSpaceBoundary(space,subobjects):
"""addSpaceBoundary(space,subobjects): adds the given subobjects to the given space"""
import Draft
if Draft.getType(space) == "Space":
space.Proxy.addSubobjects(space,subobjects)
class _CommandSpace:
"the Arch Space command definition"
@ -69,7 +76,7 @@ class _Space(ArchComponent.Component):
obj.Proxy = self
obj.addProperty("App::PropertyLink","Base","Base",
str(translate("Arch","A base shape defining this space")))
obj.addProperty("App::PropertyLinkList","Objects","Base",
obj.addProperty("App::PropertyLinkSubList","Boundaries","Base",
str(translate("Arch","The objects that make the boundaries of this space object")))
self.Type = "Space"
@ -77,8 +84,24 @@ class _Space(ArchComponent.Component):
self.getShape(obj)
def onChanged(self,obj,prop):
if prop in ["Objects","Base"]:
print prop
if prop in ["Boundaries","Base"]:
self.getShape(obj)
def addSubobjects(self,obj,subobjects):
"adds subobjects to this space"
objs = []
for o in subobjects:
print o
if isinstance(o,tuple) or isinstance(o,list):
objs.append(tuple(o))
else:
for el in o.SubElementNames:
if "Face" in el:
print "adding ",el
objs.append((o.Object,el))
print "boundaries to add: ",objs
obj.Boundaries = objs
def getShape(self,obj):
"computes a shape"
@ -86,55 +109,65 @@ class _Space(ArchComponent.Component):
shape = None
faces = []
print "starting compute"
# 1: if we have a base shape, we use it
if obj.Base:
if obj.Base.isDerivedFrom("Part::Feature"):
if obj.Base.Shape.Solids:
shape = obj.Base.Shape.Solids[0]
shape = obj.Base.Shape.Solids[0].copy()
# 2: if not, add all bounding boxes of considered objects and build a first shape
if shape:
print "got shape from base object"
bb = shape.BoundBox
else:
bb = None
for obj in obj.Objects:
if obj.isDerivedFrom("Part::Feature"):
for b in obj.Boundaries:
if b[0].isDerivedFrom("Part::Feature"):
if not bb:
bb = obj.Shape.BoundBox
bb = b[0].Shape.BoundBox
else:
bb.add(obj.Shape.BoundBox)
bb.add(b[0].Shape.BoundBox)
if not bb:
return
shape = Part.makeBox(bb.XLength,bb.YLength,bb.ZLength,FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin))
print "created shape from boundbox"
# 3: identify all faces pointing towards the center of our shape
# 3: identifing boundary faces
goodfaces = []
for obj in obj.Objects:
if obj.isDerivedFrom("Part::Feature"):
faces.extend(obj.Shape.Faces)
for face in faces:
pt = face.CenterOfMass
norm = face.normalAt(1,1) #TODO calculate for curved faces
v1 = bb.Center.sub(pt)
if v1.getAngle(norm) < math.pi/2:
goodfaces.append(face)
faces = goodfaces
for b in obj.Boundaries:
if b[0].isDerivedFrom("Part::Feature"):
if "Face" in b[1]:
fn = int(b[1][4:])-1
faces.append(b[0].Shape.Faces[fn])
print "adding face ",fn," of object ",b[0].Name
print "total: ", len(faces), " faces"
# 4: get cutvolumes from faces
cutvolumes = []
for f in faces:
f = f.copy()
f.reverse()
cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(f,shape)
if cutvolume:
cutvolumes.append(cutvolume)
print "generated 1 cutvolume"
cutvolumes.append(cutvolume.copy())
#Part.show(cutvolume)
for v in cutvolumes:
print "cutting"
shape = shape.cut(v)
# 5: get the final shape
if shape:
if shape.Solids:
print "setting objects shape"
shape = shape.Solids[0]
obj.Shape = shape
return
print "something went wrong, bailing out"
class _ViewProviderSpace(ArchComponent.ViewProviderComponent):