diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index f6083bc94..3155fa68e 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -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) diff --git a/src/Mod/Arch/ArchSpace.py b/src/Mod/Arch/ArchSpace.py index 9a7669e46..685f0160d 100644 --- a/src/Mod/Arch/ArchSpace.py +++ b/src/Mod/Arch/ArchSpace.py @@ -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):