Add more no headless test for snap

This commit is contained in:
Bruno Perdigão
2026-05-31 22:19:41 -03:00
committed by Bruno Perdigão
parent 792a0c7da1
commit 3f270df11e
3 changed files with 181 additions and 36 deletions
+1 -1
View File
@@ -362,7 +362,7 @@ endif
.PHONY: test-modal
test-modal:
blender --enable-event-simulate --python test/modal/test_modal.py
blender --enable-event-simulate --python test/modal/test_modal.py --window-maximized
# Reregistering test is not added to the standard test suite because during unregister
# Blender removes all Bonsai dependencies breaking dev-environment symlinks.
+41 -2
View File
@@ -1,7 +1,7 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1');
FILE_NAME('snap.ifc','2026-04-28T11:17:26-03:00',(),(),'IfcOpenShell 0.0.0','Bonsai 0.8.6-alpha260415-29fe41e','Nobody');
FILE_NAME('snap.ifc','2026-05-31T21:32:39-03:00',(),(),'IfcOpenShell 0.0.0','Bonsai 0.8.6-alpha260430-a712367','Nobody');
FILE_SCHEMA(('IFC4'));
ENDSEC;
DATA;
@@ -1144,7 +1144,7 @@ DATA;
#1220=IFCREPRESENTATIONMAP(#1207,#1219);
#1221=IFCTYPEPRODUCT('0klFX9AjnEnPBkdIURv8XD',$,'NAME-TAG',$,'IfcAnnotation/TEXT',(#1203),(#1220),$);
#1222=IFCWALL('3fphKxC81BMwRc46o$1Cqj',$,'Wall_02',$,$,#1336,#1230,$,$);
#1223=IFCRELCONTAINEDINSPATIALSTRUCTURE('2EB4R7ETPDiw0Rbe6drZly',$,$,$,(#1486,#1320),#42);
#1223=IFCRELCONTAINEDINSPATIALSTRUCTURE('2EB4R7ETPDiw0Rbe6drZly',$,$,$,(#1513,#1486,#1320,#1545),#42);
#1224=IFCRELDEFINESBYTYPE('0jBmsPz3v5HvFHMoyoj824',$,$,$,(#1222,#1249),#71);
#1225=IFCMATERIALLAYERSETUSAGE(#74,.AXIS2.,.POSITIVE.,0.,$);
#1226=IFCRELASSOCIATESMATERIAL('0q0BFzauPCjBOVG64mRZDH',$,$,$,(#1222),#1225);
@@ -1225,5 +1225,44 @@ DATA;
#1510=IFCDIRECTION((1.,0.,0.));
#1511=IFCAXIS2PLACEMENT3D(#1508,#1509,#1510);
#1512=IFCLOCALPLACEMENT(#65,#1511);
#1513=IFCSLAB('0VbnYWxhj2CvlANx9odXFl',$,'Slab',$,$,#1521,#1528,$,$);
#1514=IFCRELDEFINESBYTYPE('2gPl7v_sfDchsCMRc9DNak',$,$,$,(#1513),#108);
#1515=IFCMATERIALLAYERSETUSAGE(#111,.AXIS3.,.POSITIVE.,-200.,$);
#1516=IFCRELASSOCIATESMATERIAL('3e$Ju5XVL2YhZkvCqEpR4x',$,$,$,(#1513),#1515);
#1517=IFCCARTESIANPOINT((-3.13916466154751E-05,100.000001490116,0.));
#1518=IFCDIRECTION((0.,0.,1.));
#1519=IFCDIRECTION((1.,0.,0.));
#1520=IFCAXIS2PLACEMENT3D(#1517,#1518,#1519);
#1521=IFCLOCALPLACEMENT(#65,#1520);
#1522=IFCCARTESIANPOINTLIST2D(((0.,0.),(0.00754979009798262,-100000.),(100000.007629395,-99999.9847412109),(99999.9847412109,0.0137314200401306),(0.,0.)));
#1523=IFCINDEXEDPOLYCURVE(#1522,$,$);
#1524=IFCDIRECTION((0.,0.,1.));
#1525=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#1523);
#1526=IFCEXTRUDEDAREASOLID(#1525,#1535,#1524,200.);
#1527=IFCSHAPEREPRESENTATION(#15,'Body','SweptSolid',(#1526));
#1528=IFCPRODUCTDEFINITIONSHAPE($,$,(#1527));
#1529=IFCPROPERTYSET('28pnRt0NXCjOi1lCnPN6KX',$,'EPset_Parametric',$,(#1531));
#1530=IFCRELDEFINESBYPROPERTIES('0nMlPeDT5D$OSy1tx9_6Ob',$,$,$,(#1513),#1529);
#1531=IFCPROPERTYSINGLEVALUE('Engine',$,IFCLABEL('Bonsai.DumbLayer3'),$);
#1532=IFCCARTESIANPOINT((-0.,-0.,-200.));
#1533=IFCDIRECTION((0.,0.,1.));
#1534=IFCDIRECTION((1.,0.,0.));
#1535=IFCAXIS2PLACEMENT3D(#1532,#1533,#1534);
#1536=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,1999.99987792969),(0.,1999.99987792969,0.),(0.,1999.99987792969,1999.99987792969),(1999.99987792969,0.,0.),(1999.99987792969,0.,1999.99987792969),(1999.99987792969,1999.99987792969,0.),(1999.99987792969,1999.99987792969,1999.99987792969)));
#1537=IFCINDEXEDPOLYGONALFACE((1,2,4,3));
#1538=IFCINDEXEDPOLYGONALFACE((3,4,8,7));
#1539=IFCINDEXEDPOLYGONALFACE((7,8,6,5));
#1540=IFCINDEXEDPOLYGONALFACE((5,6,2,1));
#1541=IFCINDEXEDPOLYGONALFACE((3,7,5,1));
#1542=IFCINDEXEDPOLYGONALFACE((8,4,2,6));
#1543=IFCPOLYGONALFACESET(#1536,$,(#1537,#1538,#1539,#1540,#1541,#1542),$);
#1544=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#1543));
#1545=IFCBUILDINGELEMENTPROXY('1vHaLvW0jCZfGnicRbz_9o',$,'Cube',$,$,#1551,#1546,$,.COMPLEX.);
#1546=IFCPRODUCTDEFINITIONSHAPE($,$,(#1544));
#1547=IFCCARTESIANPOINT((1000000.06103516,1000000.06103516,0.));
#1548=IFCDIRECTION((0.,0.,1.));
#1549=IFCDIRECTION((1.,0.,0.));
#1550=IFCAXIS2PLACEMENT3D(#1547,#1548,#1549);
#1551=IFCLOCALPLACEMENT(#65,#1550);
ENDSEC;
END-ISO-10303-21;
+139 -33
View File
@@ -20,6 +20,7 @@
import inspect
import os
import sys
import time
import bpy
import ifcopenshell
@@ -113,21 +114,25 @@ def new_project():
props.template_file = "0"
tool.Blender.get_addon_preferences().should_play_chaching_sound = False
def get_area_and_region(window):
area = next(area for area in window.screen.areas if area.type == "VIEW_3D")
region = next(region for region in area.regions if region.type == "WINDOW")
return area, region
def test_snap_object_detection(window):
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", 0, 0)
area, region = get_area_and_region(window)
x = round(area.width * 0.5 + area.x)
y = round(area.height * 0.54 + area.y)
def test_snap_object_detection(window, x, y):
yield from preset_event_simulate(window, "ESC", "TAP", x, y)
measure_settings = tool.Project.get_measure_tool_settings()
measure_settings.measurement_type = "POLYLINE"
for obj in tool.Blender.get_selected_objects():
obj.select_set(False)
for area in bpy.context.screen.areas:
if area.type == "VIEW_3D":
for region in area.regions:
if region.type == "WINDOW":
with bpy.context.temp_override(area=area, region=region, space_data=area.spaces[0]):
bpy.ops.bim.measure_tool("INVOKE_DEFAULT", measure_type="POLYLINE")
break
with bpy.context.temp_override(area=area, region=region, space_data=area.spaces[0]):
bpy.ops.bim.measure_tool("INVOKE_DEFAULT", measure_type="POLYLINE")
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x, y)
yield from preset_event_simulate(window, "LEFTMOUSE", "TAP", x, y)
@@ -156,9 +161,66 @@ def test_snap_object_detection(window, x, y):
yield from preset_event_simulate(window, "RET", "TAP", x, y)
yield "FINISHED"
def test_snap_partially_behind_camera(window):
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", 0, 0)
area, region = get_area_and_region(window)
x = round(area.width * 0.20 + area.x)
y = round(area.height * 0.15 + area.y)
yield from preset_event_simulate(window, "ESC", "TAP", x, y)
measure_settings = tool.Project.get_measure_tool_settings()
measure_settings.measurement_type = "POLYLINE"
for obj in tool.Blender.get_selected_objects():
obj.select_set(False)
with bpy.context.temp_override(area=area, region=region, space_data=area.spaces[0]):
bpy.ops.bim.measure_tool("INVOKE_DEFAULT", measure_type="POLYLINE")
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x, y)
yield from preset_event_simulate(window, "LEFTMOUSE", "TAP", x, y)
snap_point = tool.Model.get_polyline_props().snap_mouse_point[0]
assert_msg = "First click should have a snap_object"
assert snap_point.snap_object, assert_msg
_assert_pass(assert_msg)
assert_msg = "snap_object should be a string with the object name"
assert type(snap_point.snap_object) == str, assert_msg
_assert_pass(assert_msg)
assert_msg = "snap_type should be 'Edge'"
assert snap_point.snap_type == "Edge", assert_msg
_assert_pass(assert_msg)
assert_msg = "Object should be an IfcSlab"
assert snap_point.snap_object.split("/")[0] == "IfcSlab", assert_msg
_assert_pass(assert_msg)
offset = 200
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x + offset, y)
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x + offset, y)
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x + offset, y)
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x + offset, y)
yield from preset_event_simulate(window, "LEFTMOUSE", "TAP", x - offset, y)
snap_point = tool.Model.get_polyline_props().snap_mouse_point[0]
assert_msg = "Second click should have a snap_object"
assert snap_point.snap_object, assert_msg
_assert_pass(assert_msg)
assert_msg = "snap_object should be a string with the object name"
assert type(snap_point.snap_object) == str, assert_msg
_assert_pass(assert_msg)
assert_msg = "snap_type should be 'Face'"
assert snap_point.snap_type == "Face", assert_msg
_assert_pass(assert_msg)
assert_msg = "Object should be an IfcSlab"
assert snap_point.snap_object.split("/")[0] == "IfcSlab", assert_msg
_assert_pass(assert_msg)
yield from preset_event_simulate(window, "RET", "TAP", x, y)
yield "FINISHED"
def test_snap_in_xray_mode(window):
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", 0, 0)
area, region = get_area_and_region(window)
x = round(area.width * 0.68+ area.x)
y = round(area.height * 0.54 + area.y)
def test_snap_in_xray_mode(window, x, y):
area = next(area for area in bpy.context.screen.areas if area.type == "VIEW_3D")
area.spaces[0].shading.show_xray = True
yield from preset_event_simulate(window, "ESC", "TAP", x, y)
@@ -167,13 +229,8 @@ def test_snap_in_xray_mode(window, x, y):
measure_settings.measurement_type = "POLYLINE"
for obj in tool.Blender.get_selected_objects():
obj.select_set(False)
for area in bpy.context.screen.areas:
if area.type == "VIEW_3D":
for region in area.regions:
if region.type == "WINDOW":
with bpy.context.temp_override(area=area, region=region, space_data=area.spaces[0]):
bpy.ops.bim.measure_tool("INVOKE_DEFAULT", measure_type="POLYLINE")
break
with bpy.context.temp_override(area=area, region=region, space_data=area.spaces[0]):
bpy.ops.bim.measure_tool("INVOKE_DEFAULT", measure_type="POLYLINE")
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x, y)
yield from preset_event_simulate(window, "LEFTMOUSE", "TAP", x, y)
@@ -187,29 +244,76 @@ def test_snap_in_xray_mode(window, x, y):
assert_msg = "Object should be an IfcFurniture"
assert snap_point.snap_object.split("/")[0] == "IfcFurniture", assert_msg
_assert_pass(assert_msg)
yield from preset_event_simulate(window, "RET", "TAP", x, y)
yield "FINISHED"
def test_snap_far_from_origin(window):
bpy.context.view_layer.objects.active = None
bpy.ops.object.select_all(action="DESELECT")
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", 0, 0)
area, region = get_area_and_region(window)
x = round(area.width * 0.155 + area.x)
y = round(area.height * 0.18 + area.y)
yield from preset_event_simulate(window, "ESC", "TAP", x, y)
bpy.data.objects['IfcBuildingElementProxy/Cube'].select_set(True)
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x, y)
with bpy.context.temp_override(area=area, region=region, space_data=area.spaces[0]):
bpy.ops.view3d.view_selected()
measure_settings = tool.Project.get_measure_tool_settings()
measure_settings.measurement_type = "POLYLINE"
for obj in tool.Blender.get_selected_objects():
obj.select_set(False)
with bpy.context.temp_override(area=area, region=region, space_data=area.spaces[0]):
bpy.ops.bim.measure_tool("INVOKE_DEFAULT", measure_type="POLYLINE")
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x, y)
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x, y)
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x, y)
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x, y)
yield from preset_event_simulate(window, "LEFTMOUSE", "TAP", x, y)
snap_point = tool.Model.get_polyline_props().snap_mouse_point[0]
assert_msg = "First click should have a snap_object"
assert snap_point.snap_object, assert_msg
_assert_pass(assert_msg)
assert_msg = "snap_object should be a string with the object name"
assert type(snap_point.snap_object) == str, assert_msg
_assert_pass(assert_msg)
assert_msg = "snap_type should be 'Vertex'"
assert snap_point.snap_type == "Vertex", assert_msg
_assert_pass(assert_msg)
print(snap_point.x)
print(round(snap_point.x, 3))
assert_msg = "x should be 1000000"
assert round(snap_point.x, 3) == 1000.0, assert_msg
_assert_pass(assert_msg)
assert_msg = "y should be 1000000"
assert round(snap_point.y, 3) == 1000.0, assert_msg
_assert_pass(assert_msg)
yield from preset_event_simulate(window, "RET", "TAP", x, y)
yield "FINISHED"
def test_draw_polyline_wall(window, x, y):
yield from preset_event_simulate(window, "ESC", "TAP", x, y)
area, region = get_area_and_region(window)
for obj in tool.Blender.get_selected_objects():
obj.select_set(False)
for area in bpy.context.screen.areas:
if area.type == "VIEW_3D":
for region in area.regions:
if region.type == "WINDOW":
with bpy.context.temp_override(area=area, region=region, space_data=area.spaces[0]):
props = tool.Model.get_model_props()
ifc = tool.Ifc.get()
relating_type = ifc.by_type("IfcWallType")[0]
with bpy.context.temp_override(area=area, region=region, space_data=area.spaces[0]):
props = tool.Model.get_model_props()
ifc = tool.Ifc.get()
relating_type = ifc.by_type("IfcWallType")[0]
if tool.Model.get_usage_type(relating_type) == "LAYER2":
props.ifc_class = "IfcWallType"
props.relating_type_id = str(relating_type.id())
if tool.Model.get_usage_type(relating_type) == "LAYER2":
props.ifc_class = "IfcWallType"
props.relating_type_id = str(relating_type.id())
bpy.ops.bim.draw_polyline_wall("INVOKE_DEFAULT")
break
bpy.ops.bim.draw_polyline_wall("INVOKE_DEFAULT")
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x, y)
yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x, y)
@@ -251,8 +355,10 @@ def run_tests():
bpy.ops.bim.load_project(filepath=filepath)
window = _get_valid_window()
test_queue = [
lambda w=window: test_snap_object_detection(w, 960, 540),
lambda w=window: test_snap_in_xray_mode(w, 1200, 540),
lambda w=window: test_snap_object_detection(w),
lambda w=window: test_snap_partially_behind_camera(w),
lambda w=window: test_snap_in_xray_mode(w),
lambda w=window: test_snap_far_from_origin(w),
]
else:
cleanup()
@@ -266,7 +372,7 @@ def run_tests():
run_iter_from_timer(
test_fn(),
on_complete=_next,
on_error=lambda e: _handle_error(e, lambda: None),
on_error=lambda e: _handle_error(e, _next),
)
_next()