BIM: add regression and functional test for ArchWall's MakeBlock feature (#27002)

Co-authored-by: Roy-043 <70520633+Roy-043@users.noreply.github.com>
This commit is contained in:
Furgo
2026-01-23 11:37:36 +01:00
committed by GitHub
parent 45b621b454
commit 21069b6f19

View File

@@ -369,3 +369,107 @@ class TestArchWall(TestArchBase.TestArchBase):
delta=1e-6,
msg="Placement.Rotation was not updated correctly.",
)
def test_wall_makeblocks(self):
"""Test the 'MakeBlocks' feature of Arch Wall.
This is a regression test for https://github.com/FreeCAD/FreeCAD/issues/26982, and
a basic, functional test for the MakeBlocks code path.
"""
operation = "Checking Arch Wall MakeBlocks functional correctness..."
self.printTestMessage(operation)
# Block parameters
L, H, W = 1000.0, 600.0, 200.0
BL, BH = 400.0, 200.0 # Block Length and Height
O1, O2 = 0.0, 200.0 # Row offsets
# Create base line
p1 = App.Vector(0, 0, 0)
p2 = App.Vector(L, 0, 0)
line = Draft.makeLine(p1, p2)
self.document.recompute()
# Create wall based on line and block parameters
wall = Arch.makeWall(line, width=W, height=H)
wall.BlockLength = BL
wall.BlockHeight = BH
wall.Joint = 0 # For test and volume calculation simplicity
wall.OffsetFirst = O1
wall.OffsetSecond = O2
def calc_row(row_start):
"""
Simulates the 1D block-segmentation logic for a single horizontal course.
This helper replicates the "sawing" algorithm found in _Wall.execute:
1. It places the first vertical joint at 'row_start'.
2. It advances the cutting position by 'BlockLength' (BL).
3. It measures the resulting segments between joints.
4. It classifies segments equal to 'BL' as 'Entire' and any
remainder (at the start or end of the row) as 'Broken'.
Args:
row_start (float): The distance from the start of the wall to the first vertical
joint.
Returns:
tuple (int, int): A pair of integers (entire_count, broken_count)
predicted for this specific row.
"""
row_entire, row_broken = 0, 0
current_pos = row_start
last_pos = 0.0
# Mimic the logic in ArchWall:
# while offset < (Length - Joint): create cut at offset
# Perform the cuts and record the resulting segments
segments = []
while current_pos < L:
if current_pos > 0:
segments.append(current_pos - last_pos)
last_pos = current_pos
current_pos += BL
if last_pos < L:
segments.append(L - last_pos)
# Classify segments
for seg_len in segments:
if abs(seg_len - BL) < 0.1: # Threshold for "Entire"
row_entire += 1
else:
row_broken += 1
return row_entire, row_broken
# Calculate expectations based on total courses (rows)
num_rows = int(H // BH)
expected_entire = 0
expected_broken = 0
# Effectively "lay the bricks" in a running bond pattern: alternate offsets per even/odd row
for r in range(num_rows):
ent, brk = calc_row(O1 if r % 2 == 0 else O2)
expected_entire += ent
expected_broken += brk
# Enable the feature, triggering the #26982 bug via the code path in _Wall.execute()
wall.MakeBlocks = True
self.document.recompute()
# Regression check: did we crash?
self.assertFalse(wall.Shape.isNull(), "Wall shape should not be null")
# Functional check: compare dynamic calculation to property values
self.assertEqual(
wall.CountEntire,
expected_entire,
f"Mismatch in Entire blocks. Expected {expected_entire}, got {wall.CountEntire}",
)
self.assertEqual(
wall.CountBroken,
expected_broken,
f"Mismatch in Broken blocks. Expected {expected_broken}, got {wall.CountBroken}",
)
# Integrity check: volume correctness
expected_vol = L * W * H
self.assertAlmostEqual(wall.Shape.Volume, expected_vol, places=3)