Пример #1
0
 def test_do_not_intersect_or_overlap(self):
     bbox1 = BoundingBox([(0, 0, 0), (3, 3, 3)])
     bbox2 = BoundingBox([(4, 4, 4), (9, 9, 9)])
     bbox3 = BoundingBox([(-2, -2, -2), (-1, -1, -1)])
     for a, b in permutations([bbox1, bbox2, bbox3], 2):
         assert a.has_intersection(b) is False
         assert a.has_overlap(b) is False
Пример #2
0
def multi_recursive(entities: Iterable['DXFEntity'],
                    cache: Cache = None) -> Iterable[BoundingBox]:
    """ Yields all bounding boxes for the given `entities` **or** all bounding
    boxes for their sub entities. If an entity (INSERT) has sub entities, only
    the bounding boxes of these sub entities will be yielded, **not** the
    bounding box of entity (INSERT) itself.

    """
    flat_entities = disassemble.recursive_decompose(entities)
    primitives = disassemble.to_primitives(flat_entities)
    for primitive in primitives:
        if primitive.is_empty:
            continue

        entity = primitive.entity
        if cache is not None:
            box = cache.get(entity)
            if box is None:
                box = BoundingBox(primitive.vertices())
                if box.has_data:
                    cache.store(entity, box)
        else:
            box = BoundingBox(primitive.vertices())

        if box.has_data:
            yield box
Пример #3
0
 def test_smaller_inside_bigger_intersection(self):
     b1 = BoundingBox([(0, 0, 0), (3, 3, 3)])
     b2 = BoundingBox([(1, 1, 1), (2, 2, 2)])
     b = b1.intersection(b2)
     assert b.size.isclose((1, 1, 1))
     assert b.extmin.isclose((1, 1, 1))
     assert b.extmax.isclose((2, 2, 2))
Пример #4
0
 def test_do_intersect_and_overlap(self):
     bbox1 = BoundingBox([(0, 0, 0), (10, 10, 10)])
     bbox2 = BoundingBox([(1, 1, 1), (9, 9, 9)])
     bbox3 = BoundingBox([(-1, -1, -1), (1.001, 1.001, 1.001)])
     for a, b in permutations([bbox1, bbox2, bbox3], 2):
         assert a.has_intersection(b) is True
         assert a.has_overlap(b) is True
Пример #5
0
def intersection_line_line_3d(
    line1: Sequence[Vec3],
    line2: Sequence[Vec3],
    virtual: bool = True,
    abs_tol: float = 1e-10,
) -> Optional[Vec3]:
    """
    Returns the intersection point of two 3D lines, returns ``None`` if lines
    do not intersect.

    Args:
        line1: first line as tuple of two points as :class:`Vec3` objects
        line2: second line as tuple of two points as :class:`Vec3` objects
        virtual: ``True`` returns any intersection point, ``False`` returns only
            real intersection points
        abs_tol: absolute tolerance for comparisons

    .. versionadded:: 0.17.2

    """
    from ezdxf.math import intersection_ray_ray_3d, BoundingBox
    res = intersection_ray_ray_3d(line1, line2, abs_tol)
    if len(res) != 1:
        return None

    point = res[0]
    if virtual:
        return point
    if BoundingBox(line1).inside(point) and BoundingBox(line2).inside(point):
        return point
    return None
Пример #6
0
def extents(entities: Iterable['DXFEntity'],
            cache: Cache = None) -> BoundingBox:
    """ Returns a single bounding box for all given `entities`. """
    _extends = BoundingBox()
    for box in multi_flat(entities, cache):
        _extends.extend(box)
    return _extends
Пример #7
0
 def bbox(self) -> BoundingBox:
     if self.acdb_ole2frame is not None:
         v10 = self.acdb_ole2frame.get_first_value(10, None)
         v11 = self.acdb_ole2frame.get_first_value(11, None)
         if v10 is not None and v11 is not None:
             return BoundingBox([Vec3(v10), Vec3(v11)])
     return BoundingBox()
Пример #8
0
 def test_any_inside(self):
     bbox1 = BoundingBox([(0, 0, 0), (7, 7, 7)])
     bbox2 = BoundingBox([(1, 1, 1), (9, 9, 9)])
     empty = BoundingBox()
     assert bbox1.any_inside(bbox2) is True
     assert bbox2.any_inside(bbox1) is True
     assert bbox1.any_inside(empty) is False
     assert empty.any_inside(bbox1) is False
Пример #9
0
 def test_init_none(self):
     bbox = BoundingBox()
     assert bbox.is_empty is True
     assert bbox.has_data is False
     bbox.extend([(0, 0, 0), (10, 10, 10)])
     assert bbox.size == (10, 10, 10)
     assert bbox.is_empty is False
     assert bbox.has_data is True
Пример #10
0
 def test_do_not_intersect_or_overlap_empty(self):
     bbox = BoundingBox([(0, 0, 0), (3, 3, 3)])
     empty = BoundingBox()
     assert bbox.has_intersection(empty) is False
     assert bbox.has_overlap(empty) is False
     assert empty.has_intersection(bbox) is False
     assert empty.has_overlap(bbox) is False
     assert empty.has_intersection(empty) is False
     assert empty.has_overlap(empty) is False
Пример #11
0
def test_nearly_vertical_parallel_lines_in_linear_trace_builder():
    width = 30
    trace = LinearTrace()
    trace.add_station((0, 100), width, width)
    trace.add_station((0, 100_000), width, width)
    trace.add_station((0.001, 0), width, width)
    bbox = BoundingBox()
    for face in trace.faces():
        bbox.extend(face)
    assert bbox.extmin.y > -100
Пример #12
0
def box_split(points: List[AnyVec], max_size: int) -> Sequence[Node]:
    n = len(points)
    size = BoundingBox(points).size.xyz
    dim = size.index(max(size))
    points.sort(key=lambda vec: vec[dim])
    k = math.ceil(n / max_size)
    return tuple(
        make_node(points[i : i + k], max_size, box_split)
        for i in range(0, n, k)
    )
Пример #13
0
def extends(entities: Iterable['DXFEntity'],
            cache: Cache = None) -> BoundingBox:
    """ Returns a single bounding box for the given `entities` and their sub
    entities. Good caching behavior!

    """
    _extends = BoundingBox()
    for box in multi_flat(entities, cache):
        _extends.extend(box)
    return _extends
Пример #14
0
    def test_init(self):
        bbox = BoundingBox([(0, 0, 0), (10, 10, 10)])
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (10, 10, 10)

        bbox = BoundingBox([(10, 10, 10), (0, 0, 0)])
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (10, 10, 10)

        bbox = BoundingBox([(7, -2, 9), (-1, 8, -3)])
        assert bbox.extmin == (-1, -2, -3)
        assert bbox.extmax == (7, 8, 9)
Пример #15
0
 def test_cube_vertices_returns_vertices_in_counter_clockwise_order(self):
     bbox = BoundingBox([(0, 0, 0), (1, 2, 3)])
     assert bbox.cube_vertices() == Vec3.tuple([
         (0, 0, 0),  # bottom layer
         (1, 0, 0),
         (1, 2, 0),
         (0, 2, 0),
         (0, 0, 3),  # top layer
         (1, 0, 3),
         (1, 2, 3),
         (0, 2, 3),
     ])
Пример #16
0
def extents(entities: Iterable['DXFEntity'], *,
            flatten: float = MAX_FLATTENING_DISTANCE,
            cache: Cache = None) -> BoundingBox:
    """ Returns a single bounding box for all given `entities`.

    Calculate bounding boxes from flattened curves, if argument `flatten`
    is not 0 (max flattening distance), else from control points.

    """
    _extends = BoundingBox()
    for box in multi_flat(entities, flatten=flatten, cache=cache):
        _extends.extend(box)
    return _extends
Пример #17
0
def extents(entities: Iterable['DXFEntity'],
            *,
            flatten: bool = True,
            cache: Cache = None) -> BoundingBox:
    """ Returns a single bounding box for all given `entities`.

    Calculate bounding boxes from flattened curves, if argument `flatten` is
    ``True``, else from control points.

    """
    _extends = BoundingBox()
    for box in multi_flat(entities, flatten=flatten, cache=cache):
        _extends.extend(box)
    return _extends
Пример #18
0
 def test_contains_other_bounding_box(self):
     box_a = BoundingBox([(0, 0, 0), (10, 10, 10)])
     box_b = BoundingBox([(1, 1, 1), (9, 9, 9)])
     box_c = BoundingBox([(1, 1, 1), (11, 11, 11)])
     assert box_a.contains(box_b) is True
     assert box_a.contains(box_a) is True  # self contained
     assert box_b.contains(box_a) is False
     assert box_a.contains(box_c) is False
Пример #19
0
 def test_find_points_in_bbox(self, tree):
     bbox = BoundingBox([(45, 0, 0), (55, 0, 0)])
     points = list(tree.points_in_bbox(bbox))
     assert len(points) == 11
     expected_x_coords = set(range(45, 56))
     x_coords = set(int(p.x) for p in points)
     assert x_coords == expected_x_coords
Пример #20
0
def test_2d_polyline_including_width_to_primitive():
    from ezdxf.layouts import VirtualLayout

    vl = VirtualLayout()

    p1 = (0, 0, 1, 1, 0)
    p2 = (2, 0, 0, 0, 0)
    lwp = vl.add_lwpolyline([p1, p2], dxfattribs={"elevation": 1})
    p2d = vl.add_polyline2d([p1, p2],
                            format="xyseb",
                            dxfattribs={"elevation": (0, 0, 1)})

    for e in [lwp, p2d]:
        p = disassemble.make_primitive(e)
        assert p.is_empty is False
        assert p.path is None
        assert (
            p.mesh
            is not None), "2D polylines including width should create a mesh"
        vertices = list(p.vertices())
        assert len(vertices) == 4

        box = BoundingBox(vertices)
        assert box.extmin.isclose((0, -0.5, 1)), "vertices should be in WCS"
        assert box.extmax.isclose((2, 0.5, 1)), "vertices should be in WCS"
Пример #21
0
 def transform(self, m: Matrix44):
     self.bounding_box = BoundingBox([
         m.transform(self.bounding_box.extmin),
         m.transform(self.bounding_box.extmax),
     ])
     for e in self.entities:
         e.transform(m)
Пример #22
0
def test_Vec2_compatibility():
    tree = RTree([Vec2(x, 0) for x in range(100)], max_node_size=5)
    bbox = BoundingBox([(45, 0, 0), (55, 0, 0)])
    points = list(tree.points_in_bbox(bbox))
    assert len(points) == 11
    expected_x_coords = set(range(45, 56))
    x_coords = set(int(p.x) for p in points)
    assert x_coords == expected_x_coords
    assert any(isinstance(p, Vec2) for p in points)
Пример #23
0
def export_path(path):
    doc = ezdxf.new()
    msp = doc.modelspace()
    bbox = BoundingBox(path)
    msp.add_polyline3d(path, dxfattribs={'layer': 'Path', 'color': 2})
    spline = msp.add_spline(dxfattribs={'layer': 'B-spline', 'color': 1})
    curve = global_bspline_interpolation(path)
    spline.apply_construction_tool(curve)
    doc.set_modelspace_vport(center=bbox.center, height=bbox.size[1])
    doc.saveas(DIR / 'path1.dxf')
Пример #24
0
    def test_inside(self):
        bbox = BoundingBox([(0, 0, 0), (10, 10, 10)])
        assert bbox.inside((0, 0, 0)) is True
        assert bbox.inside((-1, 0, 0)) is False
        assert bbox.inside((0, -1, 0)) is False
        assert bbox.inside((0, 0, -1)) is False

        assert bbox.inside((5, 5, 5)) is True

        assert bbox.inside((10, 10, 10)) is True
        assert bbox.inside((11, 10, 10)) is False
        assert bbox.inside((10, 11, 10)) is False
        assert bbox.inside((10, 10, 11)) is False
Пример #25
0
    def test_extend(self):
        bbox = BoundingBox([(0, 0, 0), (10, 10, 10)])
        bbox.extend([(5, 5, 5)])
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (10, 10, 10)

        bbox.extend([(15, 16, 17)])
        assert bbox.extmin == (0, 0, 0)
        assert bbox.extmax == (15, 16, 17)

        bbox.extend([(-15, -16, -17)])
        assert bbox.extmin == (-15, -16, -17)
        assert bbox.extmax == (15, 16, 17)
Пример #26
0
def multi_recursive(
    entities: Iterable["DXFEntity"],
    *,
    flatten: float = MAX_FLATTENING_DISTANCE,
    cache: Cache = None,
) -> Iterable[BoundingBox]:
    """Yields all bounding boxes for the given `entities` **or** all bounding
    boxes for their sub entities. If an entity (INSERT) has sub entities, only
    the bounding boxes of these sub entities will be yielded, **not** the
    bounding box of entity (INSERT) itself.

    Calculate bounding boxes from flattened curves, if argument `flatten`
    is not 0 (max flattening distance), else from control points.

    """

    def vertices(p: disassemble.Primitive) -> Iterable[Vec3]:
        if flatten:
            primitive.max_flattening_distance = abs(flatten)
            return primitive.vertices()
        else:
            return disassemble.to_control_vertices([p])

    flat_entities = disassemble.recursive_decompose(entities)
    primitives = disassemble.to_primitives(flat_entities)
    for primitive in primitives:
        if primitive.is_empty:
            continue

        entity = primitive.entity
        if cache is not None:
            box = cache.get(entity)
            if box is None:
                box = BoundingBox(vertices(primitive))
                if box.has_data:
                    cache.store(entity, box)
        else:
            box = BoundingBox(vertices(primitive))

        if box.has_data:
            yield box
Пример #27
0
def build_bundles(paths: Iterable[Path]) -> Iterable[Bundle]:
    def append_holes(holes):
        for hole in holes:
            if isinstance(hole, Path):
                # just for edge cases, in general:
                # holes should be inside of the contour!
                box.extend(hole.control_vertices())
                entities.append(hole.user_data)
            else:
                append_holes(hole)

    # the fast bbox detection algorithm is not very accurate!
    for polygon in nesting.fast_bbox_detection(paths):
        contour = polygon[0]
        box = BoundingBox(contour.control_vertices())
        # optional: add some spacing between items if required:
        box.grow(0.5)
        entities = [contour.user_data]
        for hole in polygon[1:]:
            append_holes(hole)
        yield Bundle(entities, box)
Пример #28
0
 def test_3d_box_contains_2d_box(self):
     box_a = BoundingBox2d([(1, 1),
                            (9, 9)])  # lives in the xy-plane, z-axis is 0
     box_b = BoundingBox([(0, 0, 0), (10, 10, 10)])
     assert box_b.contains(box_a) is True, "xy-plane is included"
     box_c = BoundingBox([(0, 0, 1), (10, 10, 10)])
     assert box_c.contains(box_a) is False, "xy-plane is not included"
Пример #29
0
def export_path(path):
    doc = ezdxf.new()
    msp = doc.modelspace()
    bbox = BoundingBox(path)
    msp.add_polyline3d(path, dxfattribs={"layer": "Path", "color": 2})
    for curve in cubic_bezier_interpolation(path):
        msp.add_polyline3d(curve.approximate(20),
                           dxfattribs={
                               "layer": "Bézier",
                               "color": 1
                           })
    doc.set_modelspace_vport(center=bbox.center, height=bbox.size[1])
    doc.saveas(DIR / "path1.dxf")
Пример #30
0
def multi_recursive(entities: Iterable['DXFEntity'],
                    *,
                    flatten: bool = True,
                    cache: Cache = None) -> Iterable[BoundingBox]:
    """ Yields all bounding boxes for the given `entities` **or** all bounding
    boxes for their sub entities. If an entity (INSERT) has sub entities, only
    the bounding boxes of these sub entities will be yielded, **not** the
    bounding box of entity (INSERT) itself.

    Calculate bounding boxes from flattened curves, if argument `flatten` is
    ``True``, else from control points.

    """
    def vertices(p: disassemble.Primitive) -> Iterable[Vec3]:
        if not flatten:
            return disassemble.to_control_vertices([p])
        return primitive.vertices()

    flat_entities = disassemble.recursive_decompose(entities)
    primitives = disassemble.to_primitives(flat_entities)
    for primitive in primitives:
        if primitive.is_empty:
            continue

        entity = primitive.entity
        if cache is not None:
            box = cache.get(entity)
            if box is None:
                box = BoundingBox(vertices(primitive))
                if box.has_data:
                    cache.store(entity, box)
        else:
            box = BoundingBox(vertices(primitive))

        if box.has_data:
            yield box