build123d/tests/test_direct_api/test_shape.py
gumyr ffc97ef6f0
Some checks are pending
benchmarks / benchmarks (macos-13, 3.12) (push) Waiting to run
benchmarks / benchmarks (macos-14, 3.12) (push) Waiting to run
benchmarks / benchmarks (ubuntu-latest, 3.12) (push) Waiting to run
benchmarks / benchmarks (windows-latest, 3.12) (push) Waiting to run
Upload coverage reports to Codecov / run (push) Waiting to run
pylint / lint (3.10) (push) Waiting to run
Run type checker / typecheck (3.10) (push) Waiting to run
Run type checker / typecheck (3.13) (push) Waiting to run
Wheel building and publishing / Build wheel on ubuntu-latest (push) Waiting to run
Wheel building and publishing / upload_pypi (push) Blocked by required conditions
tests / tests (macos-13, 3.10) (push) Waiting to run
tests / tests (macos-13, 3.13) (push) Waiting to run
tests / tests (macos-14, 3.10) (push) Waiting to run
tests / tests (macos-14, 3.13) (push) Waiting to run
tests / tests (ubuntu-latest, 3.10) (push) Waiting to run
tests / tests (ubuntu-latest, 3.13) (push) Waiting to run
tests / tests (windows-latest, 3.10) (push) Waiting to run
tests / tests (windows-latest, 3.13) (push) Waiting to run
Deprecating Shape.relocate Issue #768
2025-05-27 15:35:34 -04:00

619 lines
24 KiB
Python

"""
build123d imports
name: test_shape.py
by: Gumyr
date: January 22, 2025
desc:
This python module contains tests for the build123d project.
license:
Copyright 2025 Gumyr
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
# Always equal to any other object, to test that __eq__ cooperation is working
import unittest
from random import uniform
from unittest.mock import patch, PropertyMock
import numpy as np
from build123d.build_enums import CenterOf, Keep
from build123d.geometry import (
Axis,
Color,
Location,
Matrix,
Plane,
Pos,
Rotation,
Vector,
)
from build123d.objects_part import Box, Cylinder
from build123d.objects_sketch import Circle
from build123d.operations_part import extrude
from build123d.topology import (
Compound,
Edge,
Face,
Shape,
ShapeList,
Shell,
Solid,
Vertex,
Wire,
)
class AlwaysEqual:
def __eq__(self, other):
return True
class TestShape(unittest.TestCase):
"""Misc Shape tests"""
def test_mirror(self):
box_bb = Solid.make_box(1, 1, 1).mirror(Plane.XZ).bounding_box()
self.assertAlmostEqual(box_bb.min.X, 0, 5)
self.assertAlmostEqual(box_bb.max.X, 1, 5)
self.assertAlmostEqual(box_bb.min.Y, -1, 5)
self.assertAlmostEqual(box_bb.max.Y, 0, 5)
box_bb = Solid.make_box(1, 1, 1).mirror().bounding_box()
self.assertAlmostEqual(box_bb.min.Z, -1, 5)
self.assertAlmostEqual(box_bb.max.Z, 0, 5)
def test_compute_mass(self):
with self.assertRaises(NotImplementedError):
Shape.compute_mass(Vertex())
def test_combined_center(self):
objs = [Solid.make_box(1, 1, 1, Plane((x, 0, 0))) for x in [-2, 1]]
self.assertAlmostEqual(
Shape.combined_center(objs, center_of=CenterOf.MASS),
(0, 0.5, 0.5),
5,
)
objs = [Solid.make_sphere(1, Plane((x, 0, 0))) for x in [-2, 1]]
self.assertAlmostEqual(
Shape.combined_center(objs, center_of=CenterOf.BOUNDING_BOX),
(-0.5, 0, 0),
5,
)
with self.assertRaises(ValueError):
Shape.combined_center(objs, center_of=CenterOf.GEOMETRY)
def test_shape_type(self):
self.assertEqual(Vertex().shape_type, "Vertex")
def test_scale(self):
self.assertAlmostEqual(Solid.make_box(1, 1, 1).scale(2).volume, 2**3, 5)
def test_fuse(self):
box1 = Solid.make_box(1, 1, 1)
box2 = Solid.make_box(1, 1, 1, Plane((1, 0, 0)))
combined = box1.fuse(box2, glue=True)
self.assertTrue(combined.is_valid)
self.assertAlmostEqual(combined.volume, 2, 5)
fuzzy = box1.fuse(box2, tol=1e-6)
self.assertTrue(fuzzy.is_valid)
self.assertAlmostEqual(fuzzy.volume, 2, 5)
def test_faces_intersected_by_axis(self):
box = Solid.make_box(1, 1, 1, Plane((0, 0, 1)))
intersected_faces = box.faces_intersected_by_axis(Axis.Z)
self.assertTrue(box.faces().sort_by(sort_by=Axis.Z)[0] in intersected_faces)
self.assertTrue(box.faces().sort_by(sort_by=Axis.Z)[-1] in intersected_faces)
def test_split(self):
shape = Box(1, 1, 1) - Pos((0, 0, -0.25)) * Box(1, 0.5, 0.5)
split_shape = shape.split(Plane.XY, keep=Keep.BOTTOM)
self.assertTrue(isinstance(split_shape, list))
self.assertEqual(len(split_shape), 2)
self.assertAlmostEqual(split_shape[0].volume + split_shape[1].volume, 0.25, 5)
split_shape = shape.split(Plane.XY, keep=Keep.TOP)
self.assertEqual(len(split_shape.solids()), 1)
self.assertTrue(isinstance(split_shape, Solid))
self.assertAlmostEqual(split_shape.volume, 0.5, 5)
s = Solid.make_cone(1, 0.5, 2, Plane.YZ.offset(10))
tool = Solid.make_sphere(11).rotate(Axis.Z, 90).face()
s2 = s.split(tool, keep=Keep.TOP)
self.assertLess(s2.volume, s.volume)
self.assertGreater(s2.volume, 0.0)
def test_split_by_non_planar_face(self):
box = Solid.make_box(1, 1, 1)
tool = Circle(1).wire()
tool_shell: Shell = Shell.extrude(tool, Vector(0, 0, 1))
top, bottom = box.split(tool_shell, keep=Keep.BOTH)
self.assertFalse(top is None)
self.assertFalse(bottom is None)
self.assertGreater(top.volume, bottom.volume)
def test_split_by_shell(self):
box = Solid.make_box(5, 5, 1)
tool = Wire.make_rect(4, 4)
tool_shell: Shell = Shell.extrude(tool, Vector(0, 0, 1))
split = box.split(tool_shell, keep=Keep.TOP)
inner_vol = 2 * 2
outer_vol = 5 * 5
self.assertAlmostEqual(split.volume, outer_vol - inner_vol)
def test_split_keep_all(self):
shape = Box(1, 1, 1)
split_shape = shape.split(Plane.XY, keep=Keep.ALL)
self.assertTrue(isinstance(split_shape, ShapeList))
self.assertEqual(len(split_shape), 2)
def test_split_edge_by_shell(self):
edge = Edge.make_line((-5, 0, 0), (5, 0, 0))
tool = Wire.make_rect(4, 4)
tool_shell: Shell = Shell.extrude(tool, Vector(0, 0, 1))
top = edge.split(tool_shell, keep=Keep.TOP)
self.assertEqual(len(top), 2)
self.assertAlmostEqual(top[0].length, 3, 5)
def test_split_return_none(self):
shape = Box(1, 1, 1) - Pos((0, 0, -0.25)) * Box(1, 0.5, 0.5)
split_shape = shape.split(Plane.XY, keep=Keep.INSIDE)
self.assertIsNone(split_shape)
def test_split_by_perimeter(self):
# Test 0 - extract a spherical cap
target0 = Solid.make_sphere(10).rotate(Axis.Z, 90)
circle = Plane.YZ.offset(15) * Circle(5).face()
circle_projected = circle.project_to_shape(target0, (-1, 0, 0))[0]
circle_outerwire = circle_projected.edge()
inside0, outside0 = target0.split_by_perimeter(circle_outerwire, Keep.BOTH)
self.assertLess(inside0.area, outside0.area)
# Test 1 - extract ring of a sphere
ring = Pos(Z=15) * (Circle(5) - Circle(3)).face()
ring_projected = ring.project_to_shape(target0, (0, 0, -1))[0]
ring_outerwire = ring_projected.outer_wire()
inside1, outside1 = target0.split_by_perimeter(ring_outerwire, Keep.BOTH)
if isinstance(inside1, list):
inside1 = Compound(inside1)
if isinstance(outside1, list):
outside1 = Compound(outside1)
self.assertLess(inside1.area, outside1.area)
self.assertEqual(len(outside1.faces()), 2)
# Test 2 - extract multiple faces
target2 = Box(1, 10, 10)
square = Face.make_rect(3, 3, Plane((12, 0, 0), z_dir=(1, 0, 0)))
square_projected = square.project_to_shape(target2, (-1, 0, 0))[0]
outside2 = target2.split_by_perimeter(
square_projected.outer_wire(), Keep.OUTSIDE
)
self.assertTrue(isinstance(outside2, Shell))
inside2 = target2.split_by_perimeter(square_projected.outer_wire(), Keep.INSIDE)
self.assertTrue(isinstance(inside2, Face))
# Test 4 - invalid inputs
with self.assertRaises(ValueError):
_, _ = target2.split_by_perimeter(Edge.make_line((0, 0), (1, 0)), Keep.BOTH)
with self.assertRaises(ValueError):
_, _ = target2.split_by_perimeter(Edge.make_circle(1), Keep.TOP)
def test_distance(self):
sphere1 = Solid.make_sphere(1, Plane((-5, 0, 0)))
sphere2 = Solid.make_sphere(1, Plane((5, 0, 0)))
self.assertAlmostEqual(sphere1.distance(sphere2), 8, 5)
def test_distances(self):
sphere1 = Solid.make_sphere(1, Plane((-5, 0, 0)))
sphere2 = Solid.make_sphere(1, Plane((5, 0, 0)))
sphere3 = Solid.make_sphere(1, Plane((-5, 0, 5)))
distances = [8, 3]
for i, distance in enumerate(sphere1.distances(sphere2, sphere3)):
self.assertAlmostEqual(distances[i], distance, 5)
def test_max_fillet(self):
test_solids = [Solid.make_box(10, 8, 2), Solid.make_cone(5, 3, 8)]
max_values = [0.96, 3.84]
for i, test_object in enumerate(test_solids):
with self.subTest("solids" + str(i)):
max = test_object.max_fillet(test_object.edges())
self.assertAlmostEqual(max, max_values[i], 2)
with self.assertRaises(RuntimeError):
test_solids[0].max_fillet(
test_solids[0].edges(), tolerance=1e-6, max_iterations=1
)
with self.assertRaises(ValueError):
box = Solid.make_box(1, 1, 1)
box.fillet(0.75, box.edges())
# invalid_object = box.fillet(0.75, box.edges())
# invalid_object.max_fillet(invalid_object.edges())
@patch.object(Shape, "is_valid", new_callable=PropertyMock, return_value=False)
def test_max_fillet_invalid_shape_raises_error(self, mock_is_valid):
box = Solid.make_box(1, 1, 1)
# Assert that ValueError is raised
with self.assertRaises(ValueError) as max_fillet_context:
max = box.max_fillet(box.edges())
# Check the error message
self.assertEqual(str(max_fillet_context.exception), "Invalid Shape")
# Verify is_valid was called
mock_is_valid.assert_called_once()
def test_locate_bb(self):
bounding_box = Solid.make_cone(1, 2, 1).bounding_box()
relocated_bounding_box = Plane.XZ.from_local_coords(bounding_box)
self.assertAlmostEqual(relocated_bounding_box.min.X, -2, 5)
self.assertAlmostEqual(relocated_bounding_box.max.X, 2, 5)
self.assertAlmostEqual(relocated_bounding_box.min.Y, 0, 5)
self.assertAlmostEqual(relocated_bounding_box.max.Y, -1, 5)
self.assertAlmostEqual(relocated_bounding_box.min.Z, -2, 5)
self.assertAlmostEqual(relocated_bounding_box.max.Z, 2, 5)
def test_is_equal(self):
box = Solid.make_box(1, 1, 1)
self.assertTrue(box.is_equal(box))
def test_equal(self):
box = Solid.make_box(1, 1, 1)
self.assertEqual(box, box)
self.assertEqual(box, AlwaysEqual())
def test_not_equal(self):
box = Solid.make_box(1, 1, 1)
diff = Solid.make_box(1, 2, 3)
self.assertNotEqual(box, diff)
self.assertNotEqual(box, object())
def test_tessellate(self):
box123 = Solid.make_box(1, 2, 3)
verts, triangles = box123.tessellate(1e-6)
self.assertEqual(len(verts), 24)
self.assertEqual(len(triangles), 12)
def test_transformed(self):
"""Validate that transformed works the same as changing location"""
rotation = (uniform(0, 360), uniform(0, 360), uniform(0, 360))
offset = (uniform(0, 50), uniform(0, 50), uniform(0, 50))
shape = Solid.make_box(1, 1, 1).transformed(rotation, offset)
predicted_location = Location(offset) * Rotation(*rotation)
located_shape = Solid.make_box(1, 1, 1).locate(predicted_location)
intersect = shape.intersect(located_shape)
self.assertAlmostEqual(intersect.volume, 1, 5)
def test_position_and_orientation(self):
box = Solid.make_box(1, 1, 1).locate(Location((1, 2, 3), (10, 20, 30)))
self.assertAlmostEqual(box.position, (1, 2, 3), 5)
self.assertAlmostEqual(box.orientation, (10, 20, 30), 5)
def test_distance_to_with_closest_points(self):
s0 = Solid.make_sphere(1).locate(Location((0, 2.1, 0)))
s1 = Solid.make_sphere(1)
distance, pnt0, pnt1 = s0.distance_to_with_closest_points(s1)
self.assertAlmostEqual(distance, 0.1, 5)
self.assertAlmostEqual(pnt0, (0, 1.1, 0), 5)
self.assertAlmostEqual(pnt1, (0, 1, 0), 5)
def test_closest_points(self):
c0 = Edge.make_circle(1).locate(Location((0, 2.1, 0)))
c1 = Edge.make_circle(1)
closest = c0.closest_points(c1)
self.assertAlmostEqual(closest[0], c0.position_at(0.75), 5)
self.assertAlmostEqual(closest[1], c1.position_at(0.25), 5)
def test_distance_to(self):
c0 = Edge.make_circle(1).locate(Location((0, 2.1, 0)))
c1 = Edge.make_circle(1)
distance = c0.distance_to(c1)
self.assertAlmostEqual(distance, 0.1, 5)
def test_intersection(self):
box = Solid.make_box(1, 1, 1)
intersections = (
box.intersect(Axis((0.5, 0.5, 4), (0, 0, -1))).vertices().sort_by(Axis.Z)
)
self.assertAlmostEqual(Vector(intersections[0]), (0.5, 0.5, 0), 5)
self.assertAlmostEqual(Vector(intersections[1]), (0.5, 0.5, 1), 5)
def test_clean_error(self):
"""Note that this test is here to alert build123d to changes in bad OCCT clean behavior
with spheres or hemispheres. The extra edge in a sphere seems to be the cause of this.
"""
sphere = Solid.make_sphere(1)
divider = Solid.make_box(0.1, 3, 3, Plane(origin=(-0.05, -1.5, -1.5)))
positive_half, negative_half = (s.clean() for s in sphere.cut(divider).solids())
self.assertGreater(abs(positive_half.volume - negative_half.volume), 0, 1)
def test_clean_empty(self):
obj = Solid()
self.assertIs(obj, obj.clean())
# def test_relocate(self):
# box = Solid.make_box(10, 10, 10).move(Location((20, -5, -5)))
# cylinder = Solid.make_cylinder(2, 50).move(Location((0, 0, 0), (0, 90, 0)))
# box_with_hole = box.cut(cylinder)
# box_with_hole.relocate(box.location)
# self.assertEqual(box.location, box_with_hole.location)
# bbox1 = box.bounding_box()
# bbox2 = box_with_hole.bounding_box()
# self.assertAlmostEqual(bbox1.min, bbox2.min, 5)
# self.assertAlmostEqual(bbox1.max, bbox2.max, 5)
def test_project_to_viewport(self):
# Basic test
box = Solid.make_box(10, 10, 10)
visible, hidden = box.project_to_viewport((-20, 20, 20))
self.assertEqual(len(visible), 9)
self.assertEqual(len(hidden), 3)
# Contour edges
cyl = Solid.make_cylinder(2, 10)
visible, hidden = cyl.project_to_viewport((-20, 20, 20))
# Note that some edges are broken into two
self.assertEqual(len(visible), 6)
self.assertEqual(len(hidden), 2)
# Hidden contour edges
hole = box - cyl
visible, hidden = hole.project_to_viewport((-20, 20, 20))
self.assertEqual(len(visible), 13)
self.assertEqual(len(hidden), 6)
# Outline edges
sphere = Solid.make_sphere(5)
visible, hidden = sphere.project_to_viewport((-20, 20, 20))
self.assertEqual(len(visible), 1)
self.assertEqual(len(hidden), 0)
def test_vertex(self):
v = Edge.make_circle(1).vertex()
self.assertTrue(isinstance(v, Vertex))
with self.assertWarns(UserWarning):
Wire.make_rect(1, 1).vertex()
def test_edge(self):
e = Edge.make_circle(1).edge()
self.assertTrue(isinstance(e, Edge))
with self.assertWarns(UserWarning):
Wire.make_rect(1, 1).edge()
def test_wire(self):
w = Wire.make_circle(1).wire()
self.assertTrue(isinstance(w, Wire))
with self.assertWarns(UserWarning):
Solid.make_box(1, 1, 1).wire()
def test_compound(self):
c = Compound.make_text("hello", 10)
self.assertTrue(isinstance(c, Compound))
c2 = Compound.make_text("world", 10)
with self.assertWarns(UserWarning):
Compound(children=[c, c2]).compound()
def test_face(self):
f = Face.make_rect(1, 1)
self.assertTrue(isinstance(f, Face))
with self.assertWarns(UserWarning):
Solid.make_box(1, 1, 1).face()
def test_shell(self):
s = Solid.make_sphere(1).shell()
self.assertTrue(isinstance(s, Shell))
with self.assertWarns(UserWarning):
extrude(Compound.make_text("two", 10), amount=5).shell()
def test_solid(self):
s = Solid.make_sphere(1).solid()
self.assertTrue(isinstance(s, Solid))
with self.assertWarns(UserWarning):
Compound(Solid.make_sphere(1).split(Plane.XY, keep=Keep.BOTH)).solid()
def test_manifold(self):
self.assertTrue(Solid.make_box(1, 1, 1).is_manifold)
self.assertTrue(Solid.make_box(1, 1, 1).shell().is_manifold)
self.assertFalse(
Solid.make_box(1, 1, 1)
.shell()
.cut(Solid.make_box(0.5, 0.5, 0.5))
.is_manifold
)
self.assertTrue(
Compound(
children=[Solid.make_box(1, 1, 1), Solid.make_cylinder(1, 1)]
).is_manifold
)
def test_inherit_color(self):
# Create some objects and assign colors to them
b = Box(1, 1, 1).locate(Pos(2, 2, 0))
b.color = Color("blue") # Blue
c = Cylinder(1, 1).locate(Pos(-2, 2, 0))
a = Compound(children=[b, c])
a.color = Color(0, 1, 0)
# Check that assigned colors stay and iheritance works
np.testing.assert_allclose(tuple(a.color), (0, 1, 0, 1), 1e-5)
np.testing.assert_allclose(tuple(b.color), (0, 0, 1, 1), 1e-5)
def test_ocp_section(self):
# Vertex
verts, edges = Vertex(1, 2, 0)._ocp_section(Vertex(1, 2, 0))
self.assertListEqual(verts, []) # ?
self.assertListEqual(edges, [])
verts, edges = Vertex(1, 2, 0)._ocp_section(Edge.make_line((0, 0), (2, 4)))
self.assertListEqual(verts, []) # ?
self.assertListEqual(edges, [])
verts, edges = Vertex(1, 2, 0)._ocp_section(Face.make_rect(5, 5))
np.testing.assert_allclose(tuple(verts[0]), (1, 2, 0), 1e-5)
self.assertListEqual(edges, [])
verts, edges = Vertex(1, 2, 0)._ocp_section(Face.make_plane(Plane.XY))
np.testing.assert_allclose(tuple(verts[0]), (1, 2, 0), 1e-5)
self.assertListEqual(edges, [])
# spline = Spline((-10, 10, -10), (-10, -5, -5), (20, 0, 5))
# cylinder = Pos(Z=-10) * extrude(Circle(5), 20)
# cylinder2 = (Rot((0, 90, 0)) * cylinder).face()
# pln = Plane.XY
# box1 = Box(10, 10, 10, align=(Align.CENTER, Align.CENTER, Align.MIN))
# box2 = Pos(Z=-10) * box1
# # vertices, edges = ocp_section(spline, Face.make_rect(1e6, 1e6, pln))
# vertices1, edges1 = spline.ocp_section(Face.make_plane(pln))
# print(vertices1, edges1)
# vertices2, edges2 = cylinder.ocp_section(Face.make_plane(pln))
# print(vertices2, edges2)
# vertices3, edges3 = cylinder2.ocp_section(Face.make_plane(pln))
# print(vertices3, edges3)
# # vertices4, edges4 = cylinder2.ocp_section(cylinder)
# vertices5, edges5 = box1.ocp_section(Face.make_plane(pln))
# print(vertices5, edges5)
# vertices6, edges6 = box1.ocp_section(box2.faces().sort_by(Axis.Z)[-1])
def test_copy_attributes_to(self):
box = Box(1, 1, 1)
box2 = Box(10, 10, 10)
box.label = "box"
box.color = Color("Red")
box.children = [Box(1, 1, 1), Box(2, 2, 2)]
box.topo_parent = box2
blank = Compound()
box.copy_attributes_to(blank)
self.assertEqual(blank.label, "box")
self.assertTrue(all(c1 == c2 for c1, c2 in zip(blank.color, Color("Red"))))
self.assertTrue(all(c1 == c2 for c1, c2 in zip(blank.children, box.children)))
self.assertEqual(blank.topo_parent, box2)
def test_empty_shape(self):
empty = Solid()
box = Solid.make_box(1, 1, 1)
self.assertIsNone(empty.location)
self.assertIsNone(empty.position)
self.assertIsNone(empty.orientation)
self.assertFalse(empty.is_manifold)
with self.assertRaises(ValueError):
empty.geom_type
self.assertIs(empty, empty.fix())
self.assertEqual(hash(empty), 0)
self.assertFalse(empty.is_same(Solid()))
self.assertFalse(empty.is_equal(Solid()))
self.assertTrue(empty.is_valid)
empty_bbox = empty.bounding_box()
self.assertEqual(tuple(empty_bbox.size), (0, 0, 0))
self.assertIs(empty, empty.mirror(Plane.XY))
self.assertEqual(Shape.compute_mass(empty), 0)
self.assertEqual(empty.entities("Face"), [])
self.assertEqual(empty.area, 0)
self.assertIs(empty, empty.rotate(Axis.Z, 90))
translate_matrix = [
[1.0, 0.0, 0.0, 1.0],
[0.0, 1.0, 0.0, 2.0],
[0.0, 0.0, 1.0, 3.0],
[0.0, 0.0, 0.0, 1.0],
]
self.assertIs(empty, empty.transform_shape(Matrix(translate_matrix)))
self.assertIs(empty, empty.transform_geometry(Matrix(translate_matrix)))
with self.assertRaises(ValueError):
empty.locate(Location())
empty_loc = Location()
empty_loc.wrapped = None
with self.assertRaises(ValueError):
box.locate(empty_loc)
with self.assertRaises(ValueError):
empty.located(Location())
with self.assertRaises(ValueError):
box.located(empty_loc)
with self.assertRaises(ValueError):
empty.move(Location())
with self.assertRaises(ValueError):
box.move(empty_loc)
with self.assertRaises(ValueError):
empty.moved(Location())
with self.assertRaises(ValueError):
box.moved(empty_loc)
# with self.assertRaises(ValueError):
# empty.relocate(Location())
# with self.assertRaises(ValueError):
# box.relocate(empty_loc)
with self.assertRaises(ValueError):
empty.distance_to(Vector(1, 1, 1))
with self.assertRaises(ValueError):
empty.distance_to_with_closest_points(Vector(1, 1, 1))
with self.assertRaises(ValueError):
empty.distance_to(Vector(1, 1, 1))
with self.assertRaises(ValueError):
box.intersect(empty_loc)
self.assertEqual(empty._ocp_section(Vertex(1, 1, 1)), ([], []))
self.assertEqual(empty.faces_intersected_by_axis(Axis.Z), ShapeList())
with self.assertRaises(ValueError):
empty.split_by_perimeter(Circle(1).wire())
with self.assertRaises(ValueError):
empty.distance(Vertex(1, 1, 1))
with self.assertRaises(ValueError):
list(empty.distances(Vertex(0, 0, 0), Vertex(1, 1, 1)))
with self.assertRaises(ValueError):
list(box.distances(empty, Vertex(1, 1, 1)))
with self.assertRaises(ValueError):
empty.mesh(0.001)
with self.assertRaises(ValueError):
empty.tessellate(0.001)
with self.assertRaises(ValueError):
empty.to_splines()
empty_axis = Axis((0, 0, 0), (1, 0, 0))
empty_axis.wrapped = None
with self.assertRaises(ValueError):
box.vertices().group_by(empty_axis)
empty_wire = Wire()
with self.assertRaises(ValueError):
box.vertices().group_by(empty_wire)
with self.assertRaises(ValueError):
box.vertices().sort_by(empty_axis)
with self.assertRaises(ValueError):
box.vertices().sort_by(empty_wire)
def test_empty_selectors(self):
self.assertEqual(Vertex(1, 1, 1).edges(), ShapeList())
self.assertEqual(Vertex(1, 1, 1).wires(), ShapeList())
self.assertEqual(Vertex(1, 1, 1).faces(), ShapeList())
self.assertEqual(Vertex(1, 1, 1).shells(), ShapeList())
self.assertEqual(Vertex(1, 1, 1).solids(), ShapeList())
self.assertEqual(Vertex(1, 1, 1).compounds(), ShapeList())
self.assertIsNone(Vertex(1, 1, 1).edge())
self.assertIsNone(Vertex(1, 1, 1).wire())
self.assertIsNone(Vertex(1, 1, 1).face())
self.assertIsNone(Vertex(1, 1, 1).shell())
self.assertIsNone(Vertex(1, 1, 1).solid())
self.assertIsNone(Vertex(1, 1, 1).compound())
if __name__ == "__main__":
unittest.main()