
Now, when executing a newly created feature fails, an error message is displayed. Moreover, messages are going to be displayed where only warnings were dumped to console, previously.
224 lines
8.8 KiB
Python
224 lines
8.8 KiB
Python
#***************************************************************************
|
|
#* *
|
|
#* Copyright (c) 2015 - Victor Titov (DeepSOIC) *
|
|
#* <vv.titov@gmail.com> *
|
|
#* *
|
|
#* 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 *
|
|
#* *
|
|
#***************************************************************************
|
|
|
|
|
|
from latticeCommon import *
|
|
|
|
|
|
__title__="BoundingBox module for FreeCAD"
|
|
__author__ = "DeepSOIC"
|
|
__url__ = ""
|
|
|
|
|
|
|
|
# -------------------------- common stuff --------------------------------------------------
|
|
|
|
def boundBox2RealBox(bb):
|
|
base = FreeCAD.Vector(bb.XMin, bb.YMin, bb.ZMin)
|
|
OX = FreeCAD.Vector(1, 0, 0)
|
|
OY = FreeCAD.Vector(0, 1, 0)
|
|
OZ = FreeCAD.Vector(0, 0, 1)
|
|
if bb.XLength > DistConfusion and bb.YLength > DistConfusion and bb.ZLength > DistConfusion :
|
|
return Part.makeBox(bb.XLength,bb.YLength,bb.ZLength, base, OZ)
|
|
elif bb.XLength > DistConfusion and bb.YLength > DistConfusion:
|
|
return Part.makePlane(bb.XLength, bb.YLength, base, OZ, OX)
|
|
elif bb.XLength > DistConfusion and bb.ZLength > DistConfusion :
|
|
return Part.makePlane(bb.XLength, bb.ZLength, base, OY*-1, OX)
|
|
elif bb.YLength > DistConfusion and bb.ZLength > DistConfusion :
|
|
return Part.makePlane(bb.YLength, bb.ZLength, base, OX, OY)
|
|
elif bb.XLength > DistConfusion:
|
|
return Part.makeLine(base, base + OX*bb.XLength)
|
|
elif bb.YLength > DistConfusion:
|
|
return Part.makeLine(base, base + OY*bb.YLength)
|
|
elif bb.ZLength > DistConfusion:
|
|
return Part.makeLine(base, base + OZ*bb.ZLength)
|
|
else:
|
|
raise ValueError("Bounding box is zero")
|
|
|
|
def scaledBoundBox(bb, scale):
|
|
bb2 = FreeCAD.BoundBox(bb)
|
|
cnt = bb.Center
|
|
bb2.XMin = (bb.XMin - cnt.x)*scale + cnt.x
|
|
bb2.YMin = (bb.YMin - cnt.y)*scale + cnt.y
|
|
bb2.ZMin = (bb.ZMin - cnt.z)*scale + cnt.z
|
|
bb2.XMax = (bb.XMax - cnt.x)*scale + cnt.x
|
|
bb2.YMax = (bb.YMax - cnt.y)*scale + cnt.y
|
|
bb2.ZMax = (bb.ZMax - cnt.z)*scale + cnt.z
|
|
return bb2
|
|
|
|
def getPrecisionBoundBox(shape):
|
|
# First, we need a box that for sure contains the object.
|
|
# We use imprecise bound box, scaled up twice. The scaling
|
|
# is required, because the imprecise bound box is often a
|
|
# bit smaller than the shape.
|
|
bb = scaledBoundBox(shape.BoundBox, 2.0)
|
|
# Make sure bound box is not collapsed in any direction,
|
|
# to make sure boundBox2RealBox returns a box, not plane
|
|
# or line
|
|
if bb.XLength < DistConfusion or bb.YLength < DistConfusion or bb.ZLength < DistConfusion:
|
|
bb.enlarge(1.0)
|
|
|
|
# Make a boundingbox shape and compute distances from faces
|
|
# of this enlarged bounding box to the actual shape. Shrink
|
|
# the boundbox by the distances.
|
|
bbshape = boundBox2RealBox(bb)
|
|
#FIXME: it may be a good idea to not use hard-coded face indexes
|
|
bb.XMin = bb.XMin + shape.distToShape(bbshape.Faces[0])[0]
|
|
bb.YMin = bb.YMin + shape.distToShape(bbshape.Faces[2])[0]
|
|
bb.ZMin = bb.ZMin + shape.distToShape(bbshape.Faces[4])[0]
|
|
bb.XMax = bb.XMax - shape.distToShape(bbshape.Faces[1])[0]
|
|
bb.YMax = bb.YMax - shape.distToShape(bbshape.Faces[3])[0]
|
|
bb.ZMax = bb.ZMax - shape.distToShape(bbshape.Faces[5])[0]
|
|
return bb
|
|
|
|
|
|
def makeBoundBox(name):
|
|
'''makeBoundBox(name): makes a BoundBox object.'''
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
|
|
_BoundBox(obj)
|
|
_ViewProviderBoundBox(obj.ViewObject)
|
|
return obj
|
|
|
|
class _BoundBox:
|
|
"The BoundBox object"
|
|
def __init__(self,obj):
|
|
self.Type = "BoundBox"
|
|
obj.addProperty("App::PropertyLink","Base","BoundBox","Object to make boundingbox")
|
|
obj.addProperty("App::PropertyBool","Precision","BoundBox","Use precise alorithm (slower).")
|
|
obj.Precision = True
|
|
obj.addProperty("App::PropertyBool","InLocalSpace","BoundBox","Construct bounding box in local coordinate space of the object, not in global.")
|
|
|
|
# read-only properties:
|
|
prop = "Size"
|
|
obj.addProperty("App::PropertyVector",prop,"Info","Diagonal vector of bounding box")
|
|
obj.setEditorMode(prop, 1) # set read-only
|
|
|
|
prop = "Center"
|
|
obj.addProperty("App::PropertyVector",prop,"Info","Center of bounding box")
|
|
obj.setEditorMode(prop, 1) # set read-only
|
|
|
|
obj.Proxy = self
|
|
|
|
|
|
def execute(self,obj):
|
|
shape = obj.Base.Shape
|
|
plm = obj.Base.Placement
|
|
|
|
if obj.InLocalSpace:
|
|
shape = shape.copy()
|
|
shape.transformShape(plm.inverse().toMatrix())
|
|
|
|
bb = None
|
|
if obj.Precision:
|
|
bb = getPrecisionBoundBox(shape)
|
|
else:
|
|
bb = shape.BoundBox
|
|
rst = boundBox2RealBox(bb)
|
|
|
|
if obj.InLocalSpace:
|
|
rst.transformShape(plm.toMatrix(), True) #True is for Copy argument
|
|
|
|
#Fill in read-only properties
|
|
obj.Size = FreeCAD.Vector(bb.XLength,bb.YLength,bb.ZLength)
|
|
|
|
cnt = bb.Center
|
|
if obj.InLocalSpace:
|
|
cnt = plm.multVec(cnt)
|
|
obj.Center = cnt
|
|
|
|
obj.Shape = rst
|
|
return
|
|
|
|
|
|
class _ViewProviderBoundBox:
|
|
"A View Provider for the BoundBox object"
|
|
|
|
def __init__(self,vobj):
|
|
vobj.Proxy = self
|
|
vobj.DisplayMode = "Wireframe"
|
|
|
|
def getIcon(self):
|
|
return getIconPath("Lattice_BoundBox.svg")
|
|
|
|
def attach(self, vobj):
|
|
self.ViewObject = vobj
|
|
self.Object = vobj.Object
|
|
|
|
|
|
def setEdit(self,vobj,mode):
|
|
return False
|
|
|
|
def unsetEdit(self,vobj,mode):
|
|
return
|
|
|
|
def __getstate__(self):
|
|
return None
|
|
|
|
def __setstate__(self,state):
|
|
return None
|
|
|
|
def CreateBoundBox(name):
|
|
FreeCAD.ActiveDocument.openTransaction("Create BoundBox")
|
|
FreeCADGui.addModule("latticeBoundBox")
|
|
FreeCADGui.addModule("latticeExecuter")
|
|
FreeCADGui.doCommand("f = latticeBoundBox.makeBoundBox(name='"+name+"')")
|
|
FreeCADGui.doCommand("f.Base = FreeCADGui.Selection.getSelection()[0]")
|
|
FreeCADGui.doCommand("latticeExecuter.executeFeature(f)")
|
|
FreeCADGui.doCommand("f = None")
|
|
FreeCAD.ActiveDocument.commitTransaction()
|
|
|
|
|
|
# -------------------------- /common stuff --------------------------------------------------
|
|
|
|
# -------------------------- Gui command --------------------------------------------------
|
|
|
|
class _CommandBoundBox:
|
|
"Command to create BoundBox feature"
|
|
def GetResources(self):
|
|
return {'Pixmap' : getIconPath("Lattice_BoundBox.svg"),
|
|
'MenuText': QtCore.QT_TRANSLATE_NOOP("Lattice_BoundBox","Parametric bounding box"),
|
|
'Accel': "",
|
|
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Lattice_BoundBox","Make a box that precisely fits the object")}
|
|
|
|
def Activated(self):
|
|
if len(FreeCADGui.Selection.getSelection()) == 1 :
|
|
CreateBoundBox(name = "BoundBox")
|
|
else:
|
|
mb = QtGui.QMessageBox()
|
|
mb.setIcon(mb.Icon.Warning)
|
|
mb.setText(translate("Lattice_BoundBox", "Select a shape to make a bounding box for, first!", None))
|
|
mb.setWindowTitle(translate("Lattice_BoundBox","Bad selection", None))
|
|
mb.exec_()
|
|
|
|
def IsActive(self):
|
|
if FreeCAD.ActiveDocument:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
FreeCADGui.addCommand('Lattice_BoundBox', _CommandBoundBox())
|
|
|
|
exportedCommands = ['Lattice_BoundBox']
|
|
|
|
# -------------------------- /Gui command --------------------------------------------------
|