mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
Threads in python app
This commit is contained in:
@@ -7,6 +7,7 @@ import sys
|
||||
import time
|
||||
import operator
|
||||
import functools
|
||||
import multiprocessing
|
||||
|
||||
import OCC.AIS
|
||||
|
||||
@@ -54,6 +55,43 @@ 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')
|
||||
|
||||
class geometry_creation_thread(QtCore.QThread):
|
||||
def __init__(self, signals, settings, f):
|
||||
QtCore.QThread.__init__(self)
|
||||
self.signals = signals
|
||||
self.settings = settings
|
||||
self.f = f
|
||||
|
||||
def run(self):
|
||||
t0 = time.time()
|
||||
|
||||
# detect concurrency from hardware, we need to have
|
||||
# at least two threads because otherwise the interface
|
||||
# is different
|
||||
# is different
|
||||
it = iterator(self.settings, self.f, max(2, multiprocessing.cpu_count()))
|
||||
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):
|
||||
@@ -393,62 +431,59 @@ class application(QtWidgets.QApplication):
|
||||
self.product_to_ais = {}
|
||||
self.counter = 0
|
||||
self.window = widget
|
||||
self.thread = None
|
||||
|
||||
def initialize(self):
|
||||
self.InitDriver()
|
||||
self._display.Select = self.HandleSelection
|
||||
|
||||
def load_file(self, f, setting=None):
|
||||
|
||||
if setting is None:
|
||||
setting = settings()
|
||||
setting.set(setting.USE_PYTHON_OPENCASCADE, True)
|
||||
|
||||
def finished(self, file_shapes):
|
||||
it, f, shapes = file_shapes
|
||||
v = self._display
|
||||
|
||||
|
||||
t = {0: time.time()}
|
||||
|
||||
def update(dt=None):
|
||||
t1 = time.time()
|
||||
if t1 - t[0] > (dt or -1):
|
||||
if dt is None or t1 - t[0] > dt:
|
||||
v.FitAll()
|
||||
v.Repaint()
|
||||
t[0] = t1
|
||||
|
||||
terminate = [False]
|
||||
self.window.window_closed.connect(lambda *args: operator.setitem(terminate, 0, True))
|
||||
|
||||
t0 = time.time()
|
||||
|
||||
it = iterator(setting, f)
|
||||
if not it.initialize():
|
||||
return
|
||||
|
||||
old_progress = -1
|
||||
while True:
|
||||
if terminate[0]:
|
||||
break
|
||||
shape = it.get()
|
||||
product = f[shape.data.id]
|
||||
|
||||
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'}:
|
||||
v.Context.Erase(ais, True)
|
||||
progress = it.progress() // 2
|
||||
if progress > old_progress:
|
||||
print("\r[" + "#" * progress + " " * (50 - progress) + "]", end="")
|
||||
old_progress = progress
|
||||
if not it.next():
|
||||
break
|
||||
update(0.2)
|
||||
|
||||
print("\rOpened file in %.2f seconds%s" % (time.time() - t0, " " * 25))
|
||||
|
||||
|
||||
update(1.)
|
||||
|
||||
update()
|
||||
|
||||
self.thread = None
|
||||
|
||||
def load_file(self, f, setting=None):
|
||||
|
||||
if self.thread is not None:
|
||||
return
|
||||
|
||||
if setting is None:
|
||||
setting = settings()
|
||||
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.signals.completed.connect(self.finished)
|
||||
self.thread.start()
|
||||
|
||||
def select(self, product):
|
||||
ais = self.product_to_ais.get(product)
|
||||
|
||||
@@ -47,9 +47,11 @@ def wrap_shape_creation(settings, shape):
|
||||
if has_occ:
|
||||
from . import occ_utils as utils
|
||||
|
||||
def wrap_shape_creation(settings, shape): return utils.create_shape_from_serialization(shape) if getattr(settings,
|
||||
'use_python_opencascade',
|
||||
False) else shape
|
||||
def wrap_shape_creation(settings, shape):
|
||||
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
|
||||
@@ -77,13 +79,13 @@ _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):
|
||||
def __init__(self, settings, file_or_filename, num_threads = 1):
|
||||
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)
|
||||
_iterator.__init__(self, settings, file_or_filename)
|
||||
_iterator.__init__(self, settings, file_or_filename, num_threads)
|
||||
|
||||
if has_occ:
|
||||
def get(self):
|
||||
|
||||
Reference in New Issue
Block a user