Skip to content

Commit 6daf9c0

Browse files
authored
Improve performance render many shapes (#589)
* Measure elapsed time render and erase 400 shapes * Batch AIS display and erase viewer updates * Update coarse limits on render and erase time
1 parent ea90e46 commit 6daf9c0

2 files changed

Lines changed: 48 additions & 2 deletions

File tree

cq_editor/widgets/viewer.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,12 +306,14 @@ def display(self, ais):
306306
def display_many(self, ais_list, fit=None):
307307
context = self._get_context()
308308
for ais in ais_list:
309-
context.Display(ais, True)
309+
context.Display(ais, False)
310310

311311
if self.preferences["Fit automatically"] and fit is None:
312312
self.fit()
313313
elif fit:
314314
self.fit()
315+
elif ais_list:
316+
context.UpdateCurrentViewer()
315317

316318
@pyqtSlot(QTreeWidgetItem, int)
317319
def update_item(self, item, col):
@@ -334,7 +336,9 @@ def remove_items(self, ais_items):
334336

335337
ctx = self._get_context()
336338
for ais in ais_items:
337-
ctx.Erase(ais, True)
339+
ctx.Erase(ais, False)
340+
if ais_items:
341+
ctx.UpdateCurrentViewer()
338342

339343
@pyqtSlot()
340344
def redraw(self):

tests/test_app.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from path import Path
22
import os, sys, asyncio
3+
from time import perf_counter
34

45
if sys.platform == "win32":
56
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
@@ -70,6 +71,19 @@
7071
code_nested_top = """import test_nested_bottom
7172
"""
7273

74+
code_many_shapes = """from cadquery.func import *
75+
76+
num = 20
77+
78+
for i in range(1, num + 1, 1):
79+
for j in range(1, num + 1, 1):
80+
globals()[f"b_{i}_{j}"] = box(1, 1, 1).move(
81+
x=1.1 * i,
82+
y=1.1 * j,
83+
z=0,
84+
)
85+
"""
86+
7387
code_nested_bottom = """a=1
7488
"""
7589

@@ -272,6 +286,34 @@ def test_render(main):
272286
assert obj_tree_comp.CQ.childCount() == 3
273287

274288

289+
def test_many_shapes_render_and_erase_time(main_clean):
290+
qtbot, win = main_clean
291+
292+
editor = win.components["editor"]
293+
debugger = win.components["debugger"]
294+
object_tree = win.components["object_tree"]
295+
viewer = win.components["viewer"]
296+
297+
debugger.preferences["Reload CQ"] = False
298+
object_tree.preferences["Clear all before each run"] = True
299+
viewer.preferences["Fit automatically"] = True
300+
editor.set_text(code_many_shapes)
301+
302+
start = perf_counter()
303+
debugger._actions["Run"][0].triggered.emit()
304+
render_elapsed = perf_counter() - start
305+
306+
assert object_tree.CQ.childCount() == 20 * 20
307+
308+
start = perf_counter()
309+
object_tree.removeObjects()
310+
erase_elapsed = perf_counter() - start
311+
312+
assert object_tree.CQ.childCount() == 0
313+
assert render_elapsed < 2, f"400-shape render took {render_elapsed:.3f}s"
314+
assert erase_elapsed < 2, f"400-shape erase took {erase_elapsed:.3f}s"
315+
316+
275317
def test_export(main, mocker):
276318

277319
qtbot, win = main

0 commit comments

Comments
 (0)