mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
fixed #1233 grid cropping
This commit is contained in:
@@ -329,49 +329,39 @@ def clip_segment(bounds, segm):
|
||||
"""
|
||||
# Liang–Barsky algorithm
|
||||
|
||||
def iszero(v):
|
||||
return abs(v) < 1e-10
|
||||
|
||||
xmin, xmax, ymin, ymax = bounds
|
||||
p1, p2 = segm
|
||||
|
||||
def clip_side(p, q):
|
||||
if abs(p) < 1e-10: # ~= 0, parallel to the side
|
||||
if q < 0:
|
||||
return None # outside
|
||||
else:
|
||||
return 0, 1 # inside
|
||||
|
||||
t = q / p # the intersection point
|
||||
|
||||
if p < 0: # entering
|
||||
return t, 1
|
||||
else: # leaving
|
||||
return 0, t
|
||||
|
||||
dlt = p2 - p1
|
||||
q_l = p1.x - xmin
|
||||
q_r = xmax - p1.x
|
||||
q_t = p1.y - ymin
|
||||
q_b = ymax - p1.y
|
||||
|
||||
pos = [1]
|
||||
neg = [0]
|
||||
tt = (
|
||||
clip_side(-dlt.x, p1.x - xmin), # left
|
||||
clip_side(+dlt.x, xmax - p1.x), # right
|
||||
clip_side(-dlt.y, p1.y - ymin), # bottom
|
||||
clip_side(+dlt.y, ymax - p1.y), # top
|
||||
)
|
||||
|
||||
if (iszero(dlt.x) and (q_l < 0 or q_r < 0)) or (iszero(dlt.y) and (q_t < 0 or q_b < 0)):
|
||||
# parallel to a boundary and outside it
|
||||
if None in tt:
|
||||
return None
|
||||
|
||||
if not iszero(dlt.x):
|
||||
t_l = q_l / -dlt.x
|
||||
t_r = q_r / dlt.x
|
||||
if t_l < 0:
|
||||
neg.append(t_l)
|
||||
pos.append(t_r)
|
||||
else:
|
||||
neg.append(t_r)
|
||||
pos.append(t_l)
|
||||
t1 = max(0, max(t[0] for t in tt))
|
||||
t2 = min(1, min(t[1] for t in tt))
|
||||
|
||||
if not iszero(dlt.y):
|
||||
t_t = q_t / -dlt.y
|
||||
t_b = q_b / dlt.y
|
||||
if t_t < 0:
|
||||
neg.append(t_t)
|
||||
pos.append(t_b)
|
||||
else:
|
||||
neg.append(t_b)
|
||||
pos.append(t_t)
|
||||
|
||||
t1 = max(neg)
|
||||
t2 = min(pos)
|
||||
|
||||
if t1 > t2:
|
||||
if t1 >= t2:
|
||||
return None
|
||||
|
||||
p1c = p1 + dlt * t1
|
||||
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
Requires pytest installed under blender
|
||||
|
||||
Usage: `blender -b -P runpytest.py -- ARGS`
|
||||
"""
|
||||
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
argv = [__file__]
|
||||
|
||||
if '--' in sys.argv:
|
||||
i = sys.argv.index('--')
|
||||
argv += sys.argv[i+1:]
|
||||
|
||||
pytest.main(argv)
|
||||
@@ -0,0 +1,53 @@
|
||||
import pytest
|
||||
from mathutils import Vector
|
||||
|
||||
from blenderbim.bim.helper import clip_segment
|
||||
|
||||
|
||||
BOUNDS = (10, 30, 10, 30)
|
||||
|
||||
SEGMENTS_INSIDE = (
|
||||
(Vector((15, 20)), Vector((25, 20))),
|
||||
(Vector((20, 15)), Vector((20, 25))),
|
||||
(Vector((15, 15)), Vector((25, 25))),
|
||||
(Vector((15, 25)), Vector((25, 15))),
|
||||
)
|
||||
|
||||
SEGMENTS_OUTSIDE = (
|
||||
(Vector((15, 35)), Vector((25, 35))),
|
||||
(Vector((25, 35)), Vector((35, 25))),
|
||||
(Vector((35, 25)), Vector((35, 15))),
|
||||
(Vector((35, 15)), Vector((25, 5))),
|
||||
(Vector((25, 5)), Vector((15, 5))),
|
||||
(Vector((15, 5)), Vector((5, 15))),
|
||||
(Vector((5, 15)), Vector((5, 25))),
|
||||
(Vector((5, 25)), Vector((15, 35)))
|
||||
)
|
||||
|
||||
SEGMENTS_CLIPPED = (
|
||||
((Vector((5, 20)), Vector((15, 20))), (Vector((10, 20)), Vector((15, 20)))),
|
||||
((Vector((25, 20)), Vector((35, 20))), (Vector((25, 20)), Vector((30, 20)))),
|
||||
((Vector((20, 5)), Vector((20, 15))), (Vector((20, 10)), Vector((20, 15)))),
|
||||
((Vector((20, 15)), Vector((20, 35))), (Vector((20, 15)), Vector((20, 30)))),
|
||||
((Vector((5, 20)), Vector((20, 35))), (Vector((10, 25)), Vector((15, 30)))),
|
||||
((Vector((5, 20)), Vector((20, 5))), (Vector((10, 15)), Vector((15, 10)))),
|
||||
((Vector((35, 20)), Vector((20, 35))), (Vector((30, 25)), Vector((25, 30)))),
|
||||
((Vector((35, 20)), Vector((20, 5))), (Vector((30, 15)), Vector((25, 10)))),
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize('segment', SEGMENTS_INSIDE)
|
||||
def test_clip_inside(segment):
|
||||
clipped = clip_segment(BOUNDS, segment)
|
||||
assert clipped == segment
|
||||
|
||||
|
||||
@pytest.mark.parametrize('segment', SEGMENTS_OUTSIDE)
|
||||
def test_clip_outside(segment):
|
||||
clipped = clip_segment(BOUNDS, segment)
|
||||
assert clipped is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize('segment,expected', SEGMENTS_CLIPPED)
|
||||
def test_clip_crossing(segment, expected):
|
||||
clipped = clip_segment(BOUNDS, segment)
|
||||
assert clipped == expected
|
||||
Reference in New Issue
Block a user