mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-26 18:21:59 +00:00
fixed #1233 grid cropping
This commit is contained in:
@@ -329,49 +329,39 @@ def clip_segment(bounds, segm):
|
|||||||
"""
|
"""
|
||||||
# Liang–Barsky algorithm
|
# Liang–Barsky algorithm
|
||||||
|
|
||||||
def iszero(v):
|
|
||||||
return abs(v) < 1e-10
|
|
||||||
|
|
||||||
xmin, xmax, ymin, ymax = bounds
|
xmin, xmax, ymin, ymax = bounds
|
||||||
p1, p2 = segm
|
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
|
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]
|
tt = (
|
||||||
neg = [0]
|
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)):
|
if None in tt:
|
||||||
# parallel to a boundary and outside it
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if not iszero(dlt.x):
|
t1 = max(0, max(t[0] for t in tt))
|
||||||
t_l = q_l / -dlt.x
|
t2 = min(1, min(t[1] for t in tt))
|
||||||
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)
|
|
||||||
|
|
||||||
if not iszero(dlt.y):
|
if t1 >= t2:
|
||||||
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:
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
p1c = p1 + dlt * t1
|
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