Arch: Added 'Clip' property to section planes to clip the rendered contents to the plane limits

This commit is contained in:
Yorik van Havre
2019-04-28 17:29:19 -03:00
parent c0ca04adf9
commit fc17fee860
3 changed files with 57 additions and 27 deletions

View File

@@ -398,9 +398,10 @@ def closeHole(shape):
else:
return solid
def getCutVolume(cutplane,shapes):
"""getCutVolume(cutplane,shapes): returns a cut face and a cut volume
from the given shapes and the given cutting plane"""
def getCutVolume(cutplane,shapes,clip=False):
"""getCutVolume(cutplane,shapes,[clip]): returns a cut face and a cut volume
from the given shapes and the given cutting plane. If clip is True, the cutvolume will
also cut off everything outside the cutplane projection"""
if not shapes:
return None,None,None
if not cutplane.Faces:
@@ -462,6 +463,13 @@ def getCutVolume(cutplane,shapes):
cutvolume = cutface.extrude(cutnormal)
cutnormal = cutnormal.negative()
invcutvolume = cutface.extrude(cutnormal)
if clip:
extrudedplane = p.extrude(cutnormal)
bordervolume = invcutvolume.cut(extrudedplane)
cutvolume = cutvolume.fuse(bordervolume)
cutvolume = cutvolume.removeSplitter()
invcutvolume = extrudedplane
cutface = p
return cutface,cutvolume,invcutvolume
def getShapeFromMesh(mesh,fast=True,tolerance=0.001,flat=False,cut=True):

View File

@@ -99,12 +99,12 @@ def looksLikeDraft(o):
# If there is no shape at all ignore it
if not hasattr(o, 'Shape') or o.Shape.isNull():
return False
# If there are solids in the object, it will be handled later
# by getCutShapes
if len(o.Shape.Solids) > 0:
return False
# If we have a shape, but no volume, it looks like a flat 2D object
return o.Shape.Volume == 0
@@ -133,7 +133,11 @@ def getCutShapes(objs,section,showHidden,groupSshapesByObject=False):
else:
shapes.append(o.Shape)
objectShapes.append((o, [o.Shape]))
cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(section.Shape.copy(),shapes)
clip = False
if hasattr(section, "Clip"):
clip = section.Clip
cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(section.Shape.copy(),shapes,clip)
shapes =[]
if cutvolume:
for o, shapeList in objectShapes:
tmpSshapes = []
@@ -161,10 +165,10 @@ def getCutShapes(objs,section,showHidden,groupSshapesByObject=False):
if len(tmpSshapes) > 0:
sshapes.extend(tmpSshapes)
if groupSshapesByObject:
objectSshapes.append((o, tmpSshapes))
if groupSshapesByObject:
return shapes,hshapes,sshapes,cutface,cutvolume,invcutvolume,objectSshapes
else:
@@ -174,10 +178,10 @@ def getFillForObject(o, defaultFill, section):
if hasattr(section, 'UseMaterialColorForFill') and section.UseMaterialColorForFill:
if hasattr(o, 'Material') and o.Material:
material = o.Material
if hasattr(material, 'Color') and material.Color:
return o.Material.Color
return defaultFill
def getSVG(section, renderMode="Wireframe", allOn=False, showHidden=False, scale=1, rotation=0, linewidth=1, lineColor=(0.0,0.0,0.0), fontsize=1, showFill=False, fillColor=(0.8,0.8,0.8), techdraw=False,fillSpaces=False):
@@ -193,7 +197,7 @@ def getSVG(section, renderMode="Wireframe", allOn=False, showHidden=False, scale
lineColor -- Color of lines for the renderMode "Wireframe".
fillColor -- If showFill is True and renderMode is "Wireframe",
the cut areas are filled with fillColor.
fillSpaces - If True, shows space objects as filled surfaces
fillSpaces - If True, shows space objects as filled surfaces
"""
if not section.Objects:
@@ -255,6 +259,22 @@ def getSVG(section, renderMode="Wireframe", allOn=False, showHidden=False, scale
if section.Proxy.svgcache[4] != fillSpaces:
svgcache = None
if hasattr(section.Proxy,"boolcache") and section.Proxy.boolcache:
vshapes = section.Proxy.boolcache[0]
hshapes = section.Proxy.boolcache[1]
sshapes = section.Proxy.boolcache[2]
cutface = section.Proxy.boolcache[3]
cutvolume = section.Proxy.boolcache[4]
invcutvolume = section.Proxy.boolcache[5]
objectSshapes = section.Proxy.boolcache[6]
else:
if showFill:
vshapes,hshapes,sshapes,cutface,cutvolume,invcutvolume,objectSshapes = getCutShapes(objs,section,showHidden, True)
else:
vshapes,hshapes,sshapes,cutface,cutvolume,invcutvolume = getCutShapes(objs,section,showHidden)
objectSshapes = []
section.Proxy.boolcache = [vshapes,hshapes,sshapes,cutface,cutvolume,invcutvolume,objectSshapes]
# generating SVG
if renderMode in ["Solid",1]:
if not svgcache:
@@ -282,17 +302,13 @@ def getSVG(section, renderMode="Wireframe", allOn=False, showHidden=False, scale
# print(render.info())
section.Proxy.svgcache = [svgcache,renderMode,showHidden,showFill]
else:
if showFill:
shapes,hshapes,sshapes,cutface,cutvolume,invcutvolume,objectSshapes = getCutShapes(objs,section,showHidden, True)
else:
shapes,hshapes,sshapes,cutface,cutvolume,invcutvolume = getCutShapes(objs,section,showHidden)
if not svgcache:
svgcache = ""
# render using the Drawing module
import Drawing, Part
if shapes:
baseshape = Part.makeCompound(shapes)
if vshapes:
baseshape = Part.makeCompound(vshapes)
style = {'stroke': "SVGLINECOLOR",
'stroke-width': "SVGLINEWIDTH"}
svgcache += Drawing.projectToSVG(
@@ -425,9 +441,9 @@ def getDXF(obj):
nonspaces = []
drafts = []
objs = [o for o in objs if ((not(Draft.getType(o) in ["Space","Dimension","Annotation"])) and (not (o.isDerivedFrom("Part::Part2DObject"))))]
shapes,hshapes,sshapes,cutface,cutvolume,invcutvolume = getCutShapes(objs,section,showHidden)
if shapes:
result.append(Drawing.projectToDXF(Part.makeCompound(shapes),direction))
vshapes,hshapes,sshapes,cutface,cutvolume,invcutvolume = getCutShapes(objs,section,showHidden)
if vshapes:
result.append(Drawing.projectToDXF(Part.makeCompound(vshapes),direction))
if sshapes:
result.append(Drawing.projectToDXF(Part.makeCompound(sshapes),direction))
if hshapes:
@@ -488,6 +504,8 @@ class _SectionPlane:
if not "OnlySolids" in pl:
obj.addProperty("App::PropertyBool","OnlySolids","SectionPlane",QT_TRANSLATE_NOOP("App::Property","If false, non-solids will be cut too, with possible wrong results."))
obj.OnlySolids = True
if not "Clip" in pl:
obj.addProperty("App::PropertyBool","Clip","SectionPlane",QT_TRANSLATE_NOOP("App::Property","If True, resulting views will be clipped to the section plane area."))
if not "UseMaterialColorForFill" in pl:
obj.addProperty("App::PropertyBool","UseMaterialColorForFill","SectionPlane",QT_TRANSLATE_NOOP("App::Property","If true, the color of the objects material will be used to fill cut areas."))
obj.UseMaterialColorForFill = False
@@ -510,7 +528,7 @@ class _SectionPlane:
# old objects
l = obj.ViewObject.DisplaySize.Value
h = obj.ViewObject.DisplaySize.Value
p = Part.makePlane(l,l,Vector(l/2,-l/2,0),Vector(0,0,-1))
p = Part.makePlane(l,h,Vector(l/2,-h/2,0),Vector(0,0,-1))
# make sure the normal direction is pointing outwards, you never know what OCC will decide...
if p.normalAt(0,0).getAngle(obj.Placement.Rotation.multVec(FreeCAD.Vector(0,0,1))) > 1:
p.reverse()
@@ -520,8 +538,9 @@ class _SectionPlane:
def onChanged(self,obj,prop):
# clean svg cache if needed
if prop in ["Placement","Objects","OnlySolids","UseMaterialColorForFill"]:
if prop in ["Placement","Objects","OnlySolids","UseMaterialColorForFill","Clip"]:
self.svgcache = None
self.boolcache = None
def getNormal(self,obj):
@@ -891,7 +910,7 @@ class SectionPlaneTaskPanel:
self.delButton = QtGui.QPushButton(self.form)
self.delButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg"))
self.grid.addWidget(self.delButton, 3, 1, 1, 1)
# rotate / resize buttons
self.rlabel = QtGui.QLabel(self.form)
self.grid.addWidget(self.rlabel, 4, 0, 1, 2)
@@ -958,7 +977,7 @@ class SectionPlaneTaskPanel:
comp = FreeCAD.ActiveDocument.getObject(str(it.toolTip(0)))
ArchComponent.removeFromComponent(self.obj,comp)
self.update()
def rotate(self,axis):
if self.obj and self.obj.Shape and self.obj.Shape.Faces:
face = self.obj.Shape.copy()
@@ -966,7 +985,7 @@ class SectionPlaneTaskPanel:
face.rotate(self.obj.Placement.Base, axis, 90)
self.obj.Placement = face.Placement
self.obj.Proxy.execute(self.obj)
def rotateX(self):
self.rotate(FreeCAD.Vector(1,0,0))
@@ -975,7 +994,7 @@ class SectionPlaneTaskPanel:
def rotateZ(self):
self.rotate(FreeCAD.Vector(0,0,1))
def getBB(self):
bb = FreeCAD.BoundBox()
if self.obj:

View File

@@ -5268,7 +5268,10 @@ class _Shape2DView(_DraftObject):
shapes.extend(o.Shape.Solids)
else:
shapes.append(o.Shape.copy())
cutp,cutv,iv =Arch.getCutVolume(obj.Base.Shape,shapes)
clip = False
if hasattr(obj.Base,"Clip"):
clip = obj.Base.Clip
cutp,cutv,iv = Arch.getCutVolume(obj.Base.Shape,shapes,clip)
cuts = []
opl = FreeCAD.Placement(obj.Base.Placement)
proj = opl.Rotation.multVec(FreeCAD.Vector(0,0,1))