black ifcopenshell-python

This commit is contained in:
htlcnn
2020-11-01 20:08:27 +07:00
committed by Dion Moult
parent 2c9d6a47f4
commit 286c77e3b0
27 changed files with 1502 additions and 979 deletions
@@ -21,15 +21,18 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
def _has_occ():
try:
import OCC.Core.BRepTools
return True
except ImportError:
pass
try:
import OCC.BRepTools
return True
except ImportError:
pass
@@ -41,5 +44,5 @@ has_occ = _has_occ()
if has_occ:
from . import occ_utils as utils
from .main import *
@@ -12,9 +12,10 @@ import multiprocessing
import OCC.AIS
from collections import defaultdict, OrderedDict
try: # python 3.3+
from collections.abc import Iterable
except ModuleNotFoundError: # python 2
except ModuleNotFoundError: # python 2
from collections import Iterable
try:
@@ -23,7 +24,7 @@ except NameError:
# Python 3
QString = str
os.environ['QT_API'] = 'pyqt5'
os.environ["QT_API"] = "pyqt5"
try:
from pyqode.qt import QtCore
except BaseException:
@@ -59,11 +60,13 @@ from .. import version as ifcopenshell_version
if ifcopenshell_version < "0.6":
# not yet ported
from .. import get_supertype
class geometry_creation_signals(QtCore.QObject):
completed = QtCore.pyqtSignal('PyQt_PyObject')
progress = QtCore.pyqtSignal('PyQt_PyObject')
completed = QtCore.pyqtSignal("PyQt_PyObject")
progress = QtCore.pyqtSignal("PyQt_PyObject")
class geometry_creation_thread(QtCore.QThread):
def __init__(self, signals, settings, f):
QtCore.QThread.__init__(self)
@@ -82,25 +85,27 @@ class geometry_creation_thread(QtCore.QThread):
if not it.initialize():
self.signals.completed.emit([])
return
def _():
old_progress = -1
while True:
shape = it.get()
if shape:
yield shape
if not it.next():
break
self.signals.completed.emit((it, self.f, list(_())))
class configuration(object):
def __init__(self):
try:
import ConfigParser
Cfg = ConfigParser.RawConfigParser
except BaseException:
import configparser
@@ -122,7 +127,11 @@ class configuration(object):
if not os.path.exists(conf_file):
config = Cfg()
config.add_section("snippets")
config.set("snippets", "print all wall ids", self.config_encode("""
config.set(
"snippets",
"print all wall ids",
self.config_encode(
"""
###########################################################################
# A simple script that iterates over all walls in the current model #
# and prints their Globally unique IDs (GUIDS) to the console window #
@@ -130,9 +139,15 @@ class configuration(object):
for wall in model.by_type("IfcWall"):
print ("wall with global id: "+str(wall.GlobalId))
""".lstrip()))
""".lstrip()
),
)
config.set("snippets", "print properties of current selection", self.config_encode("""
config.set(
"snippets",
"print properties of current selection",
self.config_encode(
"""
###########################################################################
# A simple script that iterates over all IfcPropertySets of the currently #
# selected object and prints them to the console #
@@ -147,8 +162,10 @@ if selection:
for prop in relDefinesByProperties.RelatingPropertyDefinition.HasProperties:
print ("{:<20} :{}".format(prop.Name,prop.NominalValue.wrappedValue))
print ("\\n")
""".lstrip()))
with open(conf_file, 'w') as configfile:
""".lstrip()
),
)
with open(conf_file, "w") as configfile:
config.write(configfile)
self.config = Cfg()
@@ -191,7 +208,7 @@ class application(QtWidgets.QApplication):
action = menu.exec_(self.mapToGlobal(event.pos()))
index = self.selectionModel().currentIndex()
inst = index.data(QtCore.Qt.UserRole)
if hasattr(inst, 'toPyObject'):
if hasattr(inst, "toPyObject"):
inst = inst
if action in visibility:
self.instanceVisibilityChanged.emit(inst, visibility.index(action))
@@ -200,7 +217,7 @@ class application(QtWidgets.QApplication):
def clicked_(self, index):
inst = index.data(QtCore.Qt.UserRole)
if hasattr(inst, 'toPyObject'):
if hasattr(inst, "toPyObject"):
inst = inst
if inst:
self.instanceSelected.emit(inst)
@@ -209,14 +226,15 @@ class application(QtWidgets.QApplication):
itm = self.product_to_item.get(product)
if itm is None:
return
self.selectionModel().setCurrentIndex(itm,
QtCore.QItemSelectionModel.SelectCurrent | QtCore.QItemSelectionModel.Rows)
self.selectionModel().setCurrentIndex(
itm, QtCore.QItemSelectionModel.SelectCurrent | QtCore.QItemSelectionModel.Rows
)
class decomposition_treeview(abstract_treeview):
"""Treeview with typical IFC decomposition relationships"""
ATTRIBUTES = ['Entity', 'GlobalId', 'Name']
ATTRIBUTES = ["Entity", "GlobalId", "Name"]
def parent(self, instance):
if instance.is_a("IfcOpeningElement"):
@@ -247,10 +265,10 @@ class application(QtWidgets.QApplication):
if (parent is None or parent in items) and product not in items:
sl = []
for attr in ATTRS:
if attr == 'Entity':
if attr == "Entity":
sl.append(product.is_a())
else:
sl.append(getattr(product, attr) or '')
sl.append(getattr(product, attr) or "")
itm = items[product] = QtWidgets.QTreeWidgetItem(items.get(parent, self), sl)
itm.setData(0, QtCore.Qt.UserRole, product)
self.children[parent].append(product)
@@ -262,13 +280,14 @@ class application(QtWidgets.QApplication):
"""Treeview with typical IFC decomposition relationships"""
ATTRIBUTES = ['Name']
ATTRIBUTES = ["Name"]
def load_file(self, f, **kwargs):
products = list(f.by_type("IfcProduct"))
types = set(map(lambda i: i.is_a(), products))
items = {}
for t in types:
def add(t):
s = get_supertype(t)
if s:
@@ -284,7 +303,7 @@ class application(QtWidgets.QApplication):
for p in products:
t = QString(p.is_a())
itm = items[p] = QtWidgets.QTreeWidgetItem(items.get(t, self), [p.Name or '<no name>'])
itm = items[p] = QtWidgets.QTreeWidgetItem(items.get(t, self), [p.Name or "<no name>"])
itm.setData(0, QtCore.Qt.UserRole, t)
self.children[t].append(p)
@@ -293,7 +312,6 @@ class application(QtWidgets.QApplication):
self.expandAll()
class property_table(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.layout = QtWidgets.QVBoxLayout(self)
@@ -338,7 +356,7 @@ class application(QtWidgets.QApplication):
value_str = value_str.wrappedValue
if isinstance(value_str, unicode):
value_str = value_str.encode('utf-8')
value_str = value_str.encode("utf-8")
else:
value_str = str(value_str)
@@ -392,6 +410,7 @@ class application(QtWidgets.QApplication):
propsets.append(process_pset(propset))
except Exception as e:
import traceback
print("failed to load properties: {}".format(e))
traceback.print_exc()
@@ -408,7 +427,7 @@ class application(QtWidgets.QApplication):
def ais_to_key(ais_handle):
def yield_shapes():
ais = ais_handle.GetObject()
if hasattr(ais, 'Shape'):
if hasattr(ais, "Shape"):
yield ais.Shape()
return
shp = OCC.AIS.Handle_AIS_Shape.DownCast(ais_handle)
@@ -444,7 +463,7 @@ class application(QtWidgets.QApplication):
def finished(self, file_shapes):
it, f, shapes = file_shapes
v = self._display
t = {0: time.time()}
def update(dt=None):
@@ -453,29 +472,29 @@ class application(QtWidgets.QApplication):
v.FitAll()
v.Repaint()
t[0] = t1
for shape in shapes:
ais = display_shape(shape, viewer_handle=v)
product = f[shape.data.id]
ais.GetObject().SetSelectionPriority(self.counter)
self.ais_to_product[self.counter] = product
self.product_to_ais[product] = ais
self.counter += 1
QtWidgets.QApplication.processEvents()
if product.is_a() in {'IfcSpace', 'IfcOpeningElement'}:
if product.is_a() in {"IfcSpace", "IfcOpeningElement"}:
v.Context.Erase(ais, True)
update(1.)
update(1.0)
update()
self.thread = None
def load_file(self, f, setting=None):
if self.thread is not None:
return
@@ -483,10 +502,10 @@ class application(QtWidgets.QApplication):
setting = settings()
setting.set(setting.INCLUDE_CURVES, True)
setting.set(setting.USE_PYTHON_OPENCASCADE, True)
self.signals = geometry_creation_signals()
thread = self.thread = geometry_creation_thread(self.signals, setting, f)
self.window.window_closed.connect(lambda *args: thread.terminate())
self.window.window_closed.connect(lambda *args: thread.terminate())
self.signals.completed.connect(self.finished)
self.thread.start()
@@ -509,23 +528,31 @@ class application(QtWidgets.QApplication):
def toggle_visibility(self, product_or_products, flag):
v = self._display.Context
if flag:
def visibility(ais, last):
v.Erase(ais, last)
else:
def visibility(ais, last):
v.Display(ais, last)
self.toggle(product_or_products, visibility)
def toggle_wireframe(self, product_or_products, flag):
v = self._display.Context
if flag:
def wireframe(ais, last):
if v.IsDisplayed(ais):
v.SetDisplayMode(ais, 0, last)
else:
def wireframe(ais, last):
if v.IsDisplayed(ais):
v.SetDisplayMode(ais, 1, last)
self.toggle(product_or_products, wireframe)
def HandleSelection(self, X, Y):
@@ -588,12 +615,12 @@ class application(QtWidgets.QApplication):
self.window.resize(800, 600)
splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
splitter.addWidget(self.tabs)
self.tabs.addTab(self.tree, 'Decomposition')
self.tabs.addTab(self.tree2, 'Types')
self.tabs.addTab(self.tree, "Decomposition")
self.tabs.addTab(self.tree2, "Types")
self.tabs.addTab(self.propview, "Properties")
splitter2 = QtWidgets.QSplitter(QtCore.Qt.Vertical)
splitter2.addWidget(self.canvas)
self.editor = code_edit(self.canvas, configuration().options('snippets'))
self.editor = code_edit(self.canvas, configuration().options("snippets"))
splitter2.addWidget(self.editor)
splitter.addWidget(splitter2)
splitter.setSizes([200, 600])
@@ -603,9 +630,9 @@ class application(QtWidgets.QApplication):
self.components = [self.tree, self.tree2, self.canvas, self.propview, self.editor]
self.files = {}
self.window.add_menu_item('File', '&Open', self.browse, shortcut='CTRL+O')
self.window.add_menu_item('File', '&Close', self.clear, shortcut='CTRL+W')
self.window.add_menu_item('File', '&Exit', self.window.close, shortcut='ALT+F4')
self.window.add_menu_item("File", "&Open", self.browse, shortcut="CTRL+O")
self.window.add_menu_item("File", "&Close", self.clear, shortcut="CTRL+W")
self.window.add_menu_item("File", "&Exit", self.window.close, shortcut="ALT+F4")
self.tree.instanceSelected.connect(self.makeSelectionHandler(self.tree))
self.tree2.instanceSelected.connect(self.makeSelectionHandler(self.tree2))
@@ -629,8 +656,9 @@ class application(QtWidgets.QApplication):
sys.exit(self.exec_())
def browse(self):
filename = QtWidgets.QFileDialog.getOpenFileName(self.window, 'Open file', ".",
"Industry Foundation Classes (*.ifc)")[0]
filename = QtWidgets.QFileDialog.getOpenFileName(
self.window, "Open file", ".", "Industry Foundation Classes (*.ifc)"
)[0]
self.load(filename)
def clear(self):
@@ -70,7 +70,7 @@ class code_edit(QtWidgets.QWidget):
sys.stderr = sys.__stderr__
def select(self, product):
self.c = self.Console({'model': self.model, 'viewer': self.viewer, 'selection': product})
self.c = self.Console({"model": self.model, "viewer": self.viewer, "selection": product})
def __init__(self, viewer, snippets=None):
self.model = None
@@ -92,8 +92,7 @@ class code_edit(QtWidgets.QWidget):
editor.backend.start(server.__file__)
editor.panels.append(panels.FoldingPanel())
editor.panels.append(panels.LineNumberPanel())
editor.panels.append(panels.SearchAndReplacePanel(),
panels.SearchAndReplacePanel.Position.BOTTOM)
editor.panels.append(panels.SearchAndReplacePanel(), panels.SearchAndReplacePanel.Position.BOTTOM)
editor.panels.append(panels.EncodingPanel(), api.Panel.Position.TOP)
editor.add_separator()
editor.panels.append(pypanels.QuickDocPanel(), api.Panel.Position.BOTTOM)
@@ -116,7 +115,7 @@ class code_edit(QtWidgets.QWidget):
editor.modes.append(pymodes.PyIndenterMode())
editor.show()
else:
editor.setStyleSheet('font-size: 10pt; font-family: Consolas, Courier;')
editor.setStyleSheet("font-size: 10pt; font-family: Consolas, Courier;")
self.editor = editor
self.snippets = snippets
@@ -131,7 +130,7 @@ class code_edit(QtWidgets.QWidget):
self.layout.addWidget(self.editor)
self.output = QtWidgets.QTextEdit()
self.output.setReadOnly(True)
self.output.setStyleSheet('font-size: 10pt; font-family: Consolas, Courier; background-color: #444;')
self.output.setStyleSheet("font-size: 10pt; font-family: Consolas, Courier; background-color: #444;")
self.layout.addWidget(self.output)
def replace_snippet(self, number=None):
@@ -145,5 +144,5 @@ class code_edit(QtWidgets.QWidget):
output = []
sys.stdout = StdoutRedirector(self.output)
self.model = f
self.c = self.Console({'model': self.model, 'selection': None, 'viewer': self.viewer})
self.c = self.Console({"model": self.model, "selection": None, "viewer": self.viewer})
sys.stdout = sys.__stdout__
@@ -45,11 +45,12 @@ if has_occ:
from OCC import TopoDS
def wrap_shape_creation(settings, shape):
if getattr(settings, 'use_python_opencascade', False):
if getattr(settings, "use_python_opencascade", False):
return utils.create_shape_from_serialization(shape)
else:
return shape
# Subclass the settings module to provide an additional
# setting to enable pythonOCC when available
class settings(ifcopenshell_wrapper.settings):
@@ -73,60 +74,57 @@ _iterator = ifcopenshell_wrapper.iterator_double_precision
# Make sure people are able to use python's platform agnostic paths
class iterator(_iterator):
def __init__(self, settings, file_or_filename, num_threads = 1, include = None, exclude = None):
def __init__(self, settings, file_or_filename, num_threads=1, include=None, exclude=None):
self.settings = settings
if isinstance(file_or_filename, file):
file_or_filename = file_or_filename.wrapped_data
else:
file_or_filename = os.path.abspath(file_or_filename)
if include is not None and exclude is not None:
raise ValueError("include and exclude cannot be specified simultaneously")
if include is not None or exclude is not None:
# Couldn't get the typemaps properly applied using %extend so we
# replicate the SWIG-generated __init__ call on the output of a
# free function.
# @todo verify this works with SWIG 4
include_or_exclude = include if exclude is None else exclude
include_or_exclude_type = set(x.__class__.__name__ for x in include_or_exclude)
print(include_or_exclude_type)
if include_or_exclude_type == {"entity_instance"}:
if not all(inst.is_a("IfcProduct") for inst in include_or_exclude):
raise ValueError("include and exclude need to be an aggregate of IfcProduct")
initializer = ifcopenshell_wrapper.\
construct_iterator_double_precision_with_include_exclude_globalid
decode_unicode = lambda x: x.encode('ascii') if x.__class__.__name__ == "unicode" else x
include_or_exclude = list(map(decode_unicode, map(operator.attrgetter('GlobalId'), include_or_exclude)))
initializer = ifcopenshell_wrapper.construct_iterator_double_precision_with_include_exclude_globalid
decode_unicode = lambda x: x.encode("ascii") if x.__class__.__name__ == "unicode" else x
include_or_exclude = list(map(decode_unicode, map(operator.attrgetter("GlobalId"), include_or_exclude)))
else:
initializer = ifcopenshell_wrapper.\
construct_iterator_double_precision_with_include_exclude
initializer = ifcopenshell_wrapper.construct_iterator_double_precision_with_include_exclude
self.this = initializer(
self.settings,
file_or_filename,
include_or_exclude,
include is not None,
num_threads)
self.settings, file_or_filename, include_or_exclude, include is not None, num_threads
)
else:
_iterator.__init__(self, settings, file_or_filename, num_threads)
if has_occ:
def get(self):
return wrap_shape_creation(self.settings, _iterator.get(self))
def __iter__(self):
if self.initialize():
while True:
yield self.get()
if not self.next(): break
if not self.next():
break
class tree(ifcopenshell_wrapper.tree):
def __init__(self, file=None, settings=None):
args = [self]
if file is not None:
@@ -166,7 +164,7 @@ class tree(ifcopenshell_wrapper.tree):
if "extend" in kwargs or "completely_within" in kwargs:
args.append(kwargs.get("completely_within", False))
if "extend" in kwargs:
args.append(kwargs.get("extend", -1.e-5))
args.append(kwargs.get("extend", -1.0e-5))
return [entity_instance(e) for e in ifcopenshell_wrapper.tree.select_box(*args)]
@@ -193,14 +191,11 @@ def create_shape(settings, inst, repr=None):
"""
return wrap_shape_creation(
settings,
ifcopenshell_wrapper.create_shape(
settings,
inst.wrapped_data,
repr.wrapped_data if repr is not None else None
))
ifcopenshell_wrapper.create_shape(settings, inst.wrapped_data, repr.wrapped_data if repr is not None else None),
)
def iterate(settings, file_or_filename, num_threads = 1, include = None, exclude = None):
def iterate(settings, file_or_filename, num_threads=1, include=None, exclude=None):
it = iterator(settings, file_or_filename, num_threads, include, exclude)
if it.initialize():
while True:
@@ -214,13 +209,17 @@ def make_shape_function(fn):
return None if e is None else entity_instance(e)
if has_occ:
def _(schema, string_or_shape, *args):
if isinstance(string_or_shape, TopoDS.TopoDS_Shape):
string_or_shape = utils.serialize_shape(string_or_shape)
return entity_instance_or_none(fn(schema, string_or_shape, *args))
else:
def _(schema, string, *args):
return entity_instance_or_none(fn(schema, string, *args))
return _
@@ -26,35 +26,38 @@ import operator
import warnings
from collections import namedtuple
try: # python 3.3+
from collections.abc import Iterable
except ModuleNotFoundError: # python 2
except ModuleNotFoundError: # python 2
from collections import Iterable
try:
from OCC.Core import V3d, TopoDS, gp, AIS, Quantity, BRepTools, Graphic3d
USE_OCCT_HANDLE = False
except ImportError:
from OCC import V3d, TopoDS, gp, AIS, Quantity, BRepTools, Graphic3d
USE_OCCT_HANDLE = True
shape_tuple = namedtuple('shape_tuple', ('data', 'geometry', 'styles'))
shape_tuple = namedtuple("shape_tuple", ("data", "geometry", "styles"))
handle, main_loop, add_menu, add_function_to_menu = None, None, None, None
DEFAULT_STYLES = {
"DEFAULT": (.7, .7, .7),
"IfcWall": (.8, .8, .8),
"IfcSite": (.75, .8, .65),
"IfcSlab": (.4, .4, .4),
"IfcWallStandardCase": (.9, .9, .9),
"IfcWall": (.9, .9, .9),
"IfcWindow": (.75, .8, .75, .3),
"IfcDoor": (.55, .3, .15),
"IfcBeam": (.75, .7, .7),
"IfcRailing": (.65, .6, .6),
"IfcMember": (.65, .6, .6),
"IfcPlate": (.8, .8, .8)
"DEFAULT": (0.7, 0.7, 0.7),
"IfcWall": (0.8, 0.8, 0.8),
"IfcSite": (0.75, 0.8, 0.65),
"IfcSlab": (0.4, 0.4, 0.4),
"IfcWallStandardCase": (0.9, 0.9, 0.9),
"IfcWall": (0.9, 0.9, 0.9),
"IfcWindow": (0.75, 0.8, 0.75, 0.3),
"IfcDoor": (0.55, 0.3, 0.15),
"IfcBeam": (0.75, 0.7, 0.7),
"IfcRailing": (0.65, 0.6, 0.6),
"IfcMember": (0.65, 0.6, 0.6),
"IfcPlate": (0.8, 0.8, 0.8),
}
@@ -82,7 +85,7 @@ def initialize_display():
for l in lights:
viewer.DelLight(l)
if hasattr(V3d, 'V3d_TypeOfOrientation_Yup_AxoRight'):
if hasattr(V3d, "V3d_TypeOfOrientation_Yup_AxoRight"):
dirs = [[V3d.V3d_TypeOfOrientation_Yup_AxoRight], [V3d.V3d_TypeOfOrientation_Zup_AxoRight]]
else:
dirs = [(3, 2, 1), (-1, -2, -3)]
@@ -117,7 +120,7 @@ def display_shape(shape, clr=None, viewer_handle=None):
if representation and not clr:
if len(set(representation.styles)) == 1:
clr = representation.styles[0]
if min(clr) < 0. or max(clr) > 1.:
if min(clr) < 0.0 or max(clr) > 1.0:
clr = DEFAULT_STYLES.get(representation.data.type, DEFAULT_STYLES["DEFAULT"])
if clr:
@@ -125,8 +128,9 @@ def display_shape(shape, clr=None, viewer_handle=None):
ais.SetMaterial(material)
if isinstance(clr, str):
qclr = getattr(Quantity, "Quantity_NOC_%s" % clr.upper(),
getattr(Quantity, "Quantity_NOC_%s1" % clr.upper(), None))
qclr = getattr(
Quantity, "Quantity_NOC_%s" % clr.upper(), getattr(Quantity, "Quantity_NOC_%s1" % clr.upper(), None)
)
if qclr is None:
raise Exception("No color named '%s'" % clr.upper())
elif isinstance(clr, Iterable):
@@ -140,8 +144,8 @@ def display_shape(shape, clr=None, viewer_handle=None):
raise Exception("Object of type %r cannot be used as a color." % type(clr))
ais.SetColor(qclr)
if isinstance(clr, tuple) and len(clr) == 4 and clr[3] < 1.:
ais.SetTransparency(1. - clr[3])
if isinstance(clr, tuple) and len(clr) == 4 and clr[3] < 1.0:
ais.SetTransparency(1.0 - clr[3])
elif representation and hasattr(AIS, "AIS_MultipleConnectedShape"):
default_style_applied = None
@@ -155,13 +159,14 @@ def display_shape(shape, clr=None, viewer_handle=None):
else:
for shp, stl in zip(subshapes, representation.styles):
subshape = AIS.AIS_Shape(shp)
if min(stl) < 0. or max(stl) > 1.:
default_style_applied = stl = DEFAULT_STYLES.get(representation.data.type,
DEFAULT_STYLES["DEFAULT"])
if min(stl) < 0.0 or max(stl) > 1.0:
default_style_applied = stl = DEFAULT_STYLES.get(
representation.data.type, DEFAULT_STYLES["DEFAULT"]
)
subshape.SetColor(Quantity.Quantity_Color(stl[0], stl[1], stl[2], Quantity.Quantity_TOC_RGB))
subshape.SetMaterial(material)
if len(stl) == 4 and stl[3] < 1.:
subshape.SetTransparency(1. - stl[3])
if len(stl) == 4 and stl[3] < 1.0:
subshape.SetTransparency(1.0 - stl[3])
ais.Connect(subshape.GetHandle())
# For some reason it is necessary to set transparency here again
@@ -169,14 +174,14 @@ def display_shape(shape, clr=None, viewer_handle=None):
applied_styles = representation.styles
if default_style_applied:
if len(default_style_applied) == 3:
default_style_applied += (1.,)
default_style_applied += (1.0,)
applied_styles += (default_style_applied,)
if len(applied_styles):
# The only way for this not to be true if is the entire shape is NULL
min_transp = min(map(operator.itemgetter(3), applied_styles))
if min_transp < 1.:
ais.SetTransparency(1.)
if min_transp < 1.0:
ais.SetTransparency(1.0)
else:
ais = AIS.AIS_Shape(shape)
@@ -199,10 +204,10 @@ def set_shape_transparency(ais, t):
def get_bounding_box_center(bbox):
bbmin = [0.] * 3
bbmax = [0.] * 3
bbmin = [0.0] * 3
bbmax = [0.0] * 3
bbmin[0], bbmin[1], bbmin[2], bbmax[0], bbmax[1], bbmax[2] = bbox.Get()
return gp.gp_Pnt(*map(lambda xy: (xy[0] + xy[1]) / 2., zip(bbmin, bbmax)))
return gp.gp_Pnt(*map(lambda xy: (xy[0] + xy[1]) / 2.0, zip(bbmin, bbmax)))
def serialize_shape(shape):
@@ -226,7 +231,7 @@ def create_shape_from_serialization(brep_object):
except BaseException:
pass
styles = tuple(styles[i:i + 4] for i in range(0, len(styles), 4))
styles = tuple(styles[i : i + 4] for i in range(0, len(styles), 4))
if not brep_data:
return shape_tuple(brep_object, None, styles)