mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
560 lines
21 KiB
Python
560 lines
21 KiB
Python
"""
|
|
joints unittests
|
|
|
|
name: test_joints.py
|
|
by: Gumyr
|
|
date: August 24, 2023
|
|
|
|
desc:
|
|
This python module contains the unittests for the Joint base and
|
|
derived classes.
|
|
|
|
license:
|
|
|
|
Copyright 2023 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 under the License is 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.
|
|
|
|
"""
|
|
|
|
import copy
|
|
import unittest
|
|
|
|
from build123d.build_enums import Align, CenterOf, GeomType
|
|
from build123d.build_common import Mode
|
|
from build123d.build_part import BuildPart
|
|
from build123d.build_sketch import BuildSketch
|
|
from build123d.geometry import Axis, Location, Plane, Rotation, Vector, VectorLike
|
|
from build123d.joints import (
|
|
BallJoint,
|
|
CylindricalJoint,
|
|
LinearJoint,
|
|
RevoluteJoint,
|
|
RigidJoint,
|
|
)
|
|
from build123d.objects_part import Box, Cone, Cylinder, Sphere
|
|
from build123d.objects_sketch import Circle
|
|
from build123d.operations_part import extrude
|
|
from build123d.topology import Edge, Solid
|
|
|
|
|
|
class DirectApiTestCase(unittest.TestCase):
|
|
def assertTupleAlmostEquals(
|
|
self,
|
|
first: tuple[float, ...],
|
|
second: tuple[float, ...],
|
|
places: int,
|
|
msg: str = None,
|
|
):
|
|
"""Check Tuples"""
|
|
self.assertEqual(len(second), len(first))
|
|
for i, j in zip(second, first):
|
|
self.assertAlmostEqual(i, j, places, msg=msg)
|
|
|
|
def assertVectorAlmostEquals(
|
|
self, first: Vector, second: VectorLike, places: int, msg: str = None
|
|
):
|
|
second_vector = Vector(second)
|
|
self.assertAlmostEqual(first.X, second_vector.X, places, msg=msg)
|
|
self.assertAlmostEqual(first.Y, second_vector.Y, places, msg=msg)
|
|
self.assertAlmostEqual(first.Z, second_vector.Z, places, msg=msg)
|
|
|
|
|
|
class TestRigidJoint(DirectApiTestCase):
|
|
def test_rigid_joint(self):
|
|
base = Solid.make_box(1, 1, 1)
|
|
j1 = RigidJoint("top", base, Location(Vector(0.5, 0.5, 1)))
|
|
fixed_top = Solid.make_box(1, 1, 1)
|
|
j2 = RigidJoint("bottom", fixed_top, Location((0.5, 0.5, 0)))
|
|
j1.connect_to(j2)
|
|
bbox = fixed_top.bounding_box()
|
|
self.assertVectorAlmostEquals(bbox.min, (0, 0, 1), 5)
|
|
self.assertVectorAlmostEquals(bbox.max, (1, 1, 2), 5)
|
|
|
|
self.assertVectorAlmostEquals(j2.symbol.location.position, (0.5, 0.5, 1), 6)
|
|
self.assertVectorAlmostEquals(j2.symbol.location.orientation, (0, 0, 0), 6)
|
|
|
|
def test_builder(self):
|
|
with BuildPart() as test:
|
|
Box(3, 3, 1)
|
|
RigidJoint("test")
|
|
Cylinder(1, 3)
|
|
|
|
self.assertTrue(isinstance(test.part.joints["test"], RigidJoint))
|
|
|
|
def test_no_to_part(self):
|
|
with self.assertRaises(ValueError):
|
|
RigidJoint("test")
|
|
|
|
def test_error_handling(self):
|
|
j1 = RigidJoint("one", Box(1, 1, 1))
|
|
with self.assertRaises(TypeError):
|
|
j1.connect_to(Solid.make_box(1, 1, 1))
|
|
|
|
with self.assertRaises(TypeError):
|
|
j1.relative_to(Solid.make_box(1, 1, 1))
|
|
|
|
|
|
class TestRevoluteJoint(DirectApiTestCase):
|
|
def test_revolute_joint_with_angle_reference(self):
|
|
revolute_base = Solid.make_cylinder(1, 1)
|
|
j1 = RevoluteJoint(
|
|
label="top",
|
|
to_part=revolute_base,
|
|
axis=Axis((0, 0, 1), (0, 0, 1)),
|
|
angle_reference=(1, 0, 0),
|
|
angular_range=(0, 180),
|
|
)
|
|
fixed_top = Solid.make_box(1, 0.5, 1)
|
|
j2 = RigidJoint("bottom", fixed_top, Location((0.5, 0.25, 0)))
|
|
|
|
j1.connect_to(j2, angle=90)
|
|
bbox = fixed_top.bounding_box()
|
|
self.assertVectorAlmostEquals(bbox.min, (-0.25, -0.5, 1), 5)
|
|
self.assertVectorAlmostEquals(bbox.max, (0.25, 0.5, 2), 5)
|
|
|
|
self.assertVectorAlmostEquals(j2.symbol.location.position, (0, 0, 1), 6)
|
|
self.assertVectorAlmostEquals(j2.symbol.location.orientation, (0, 0, 90), 6)
|
|
self.assertEqual(len(j1.symbol.edges()), 3)
|
|
|
|
def test_revolute_joint_absolute_locations(self):
|
|
b1 = Box(10, 10, 1)
|
|
b2 = Box(5, 5, 1)
|
|
j1 = RigidJoint("j1", b1, Location((-4, -4, 0.5)))
|
|
j2 = RevoluteJoint("j2", b2, Axis((2.5, 2.5, 0), (0, -1, 0)))
|
|
|
|
j1.connect_to(j2, angle=0)
|
|
|
|
self.assertVectorAlmostEquals(j1.location.position, j2.location.position, 5)
|
|
self.assertVectorAlmostEquals(
|
|
j1.location.orientation, j2.location.orientation, 5
|
|
)
|
|
|
|
def test_linear_revolute_joint(self):
|
|
base = Box(10, 10, 2)
|
|
arm = Box(2, 1, 2, align=(Align.CENTER, Align.CENTER, Align.MIN))
|
|
|
|
base_top_edges = (
|
|
base.edges().filter_by(Axis.X, tolerance=30).sort_by(Axis.Z)[-2:]
|
|
)
|
|
linear_axis = Axis(Edge.make_mid_way(*base_top_edges, 0.33))
|
|
j1 = LinearJoint(
|
|
"slot",
|
|
base,
|
|
axis=linear_axis,
|
|
linear_range=(0, base_top_edges[0].length),
|
|
)
|
|
j2 = RevoluteJoint("pin", arm, axis=Axis.Z, angular_range=(0, 360))
|
|
|
|
j1.connect_to(j2, position=6, angle=60)
|
|
|
|
target_location = Rotation(0, 0, 60)
|
|
target_location.position = linear_axis.position + linear_axis.direction * 6
|
|
self.assertVectorAlmostEquals(target_location.position, j2.location.position, 5)
|
|
self.assertVectorAlmostEquals(
|
|
target_location.orientation, j2.location.orientation, 5
|
|
)
|
|
|
|
def test_revolute_joint_non_z_axis(self):
|
|
base_part = Box(6, 4, 2)
|
|
rotating_part = Cone(2, 1, 2)
|
|
j1 = RevoluteJoint("j1", base_part, Axis((3, 0, 1), (0, -1, 0)))
|
|
j2 = RigidJoint("j2", rotating_part, Location((-2, 0, -1), (90, 0, -90)))
|
|
|
|
base_part.joints["j1"].connect_to(rotating_part.joints["j2"], angle=30)
|
|
|
|
self.assertVectorAlmostEquals(base_part.location.position, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(base_part.location.orientation, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(
|
|
rotating_part.location.position, (4.23, 0, 2.87), 2
|
|
)
|
|
self.assertVectorAlmostEquals(
|
|
rotating_part.location.orientation, (0, -30, 0), 5
|
|
)
|
|
|
|
self.assertVectorAlmostEquals(j1.location.position, (3, 0, 1), 5)
|
|
self.assertVectorAlmostEquals(j1.location.orientation, (90, 0, -90), 5)
|
|
self.assertVectorAlmostEquals(j2.location.position, (3, 0, 1), 5)
|
|
self.assertVectorAlmostEquals(j2.location.orientation, (90, 0, -60), 5)
|
|
|
|
def test_revolute_joint_without_angle_reference(self):
|
|
revolute_base = Solid.make_cylinder(1, 1)
|
|
j1 = RevoluteJoint(
|
|
label="top",
|
|
to_part=revolute_base,
|
|
axis=Axis((0, 0, 1), (0, 0, 1)),
|
|
)
|
|
self.assertVectorAlmostEquals(j1.angle_reference, (1, 0, 0), 5)
|
|
|
|
def test_revolute_joint_error_bad_angle_reference(self):
|
|
"""Test that the angle_reference must be normal to the axis"""
|
|
revolute_base = Solid.make_cylinder(1, 1)
|
|
with self.assertRaises(ValueError):
|
|
RevoluteJoint(
|
|
"top",
|
|
revolute_base,
|
|
axis=Axis((0, 0, 1), (0, 0, 1)),
|
|
angle_reference=(1, 0, 1),
|
|
)
|
|
|
|
def test_revolute_joint_error_bad_angle(self):
|
|
"""Test that the joint angle is within bounds"""
|
|
revolute_base = Solid.make_cylinder(1, 1)
|
|
j1 = RevoluteJoint("top", revolute_base, Axis.Z, angular_range=(0, 180))
|
|
fixed_top = Solid.make_box(1, 0.5, 1)
|
|
j2 = RigidJoint("bottom", fixed_top, Location((0.5, 0.25, 0)))
|
|
with self.assertRaises(ValueError):
|
|
j1.connect_to(j2, angle=270)
|
|
|
|
def test_revolute_joint_error_bad_joint_type(self):
|
|
"""Test that the joint angle is within bounds"""
|
|
revolute_base = Solid.make_cylinder(1, 1)
|
|
j1 = RevoluteJoint("top", revolute_base, Axis.Z, (0, 180))
|
|
fixed_top = Solid.make_box(1, 0.5, 1)
|
|
j2 = RevoluteJoint("bottom", fixed_top, Axis.Z, (0, 180))
|
|
with self.assertRaises(TypeError):
|
|
j1.connect_to(j2, angle=0)
|
|
|
|
def test_builder(self):
|
|
with BuildPart() as test:
|
|
Box(3, 3, 1)
|
|
RevoluteJoint("test")
|
|
Cylinder(1, 3)
|
|
|
|
self.assertTrue(isinstance(test.part.joints["test"], RevoluteJoint))
|
|
|
|
def test_no_to_part(self):
|
|
with self.assertRaises(ValueError):
|
|
RevoluteJoint("test")
|
|
|
|
|
|
class TestLinearJoint(DirectApiTestCase):
|
|
def test_linear_rigid_joint(self):
|
|
base = Solid.make_box(1, 1, 1)
|
|
j1 = LinearJoint(
|
|
"top", to_part=base, axis=Axis((0, 0.5, 1), (1, 0, 0)), linear_range=(0, 1)
|
|
)
|
|
fixed_top = Solid.make_box(1, 1, 1)
|
|
j2 = RigidJoint("bottom", fixed_top, Location((0.5, 0.5, 0)))
|
|
j1.connect_to(j2, position=0.25)
|
|
bbox = fixed_top.bounding_box()
|
|
self.assertVectorAlmostEquals(bbox.min, (-0.25, 0, 1), 5)
|
|
self.assertVectorAlmostEquals(bbox.max, (0.75, 1, 2), 5)
|
|
|
|
self.assertVectorAlmostEquals(j2.symbol.location.position, (0.25, 0.5, 1), 6)
|
|
self.assertVectorAlmostEquals(j2.symbol.location.orientation, (0, 0, 0), 6)
|
|
|
|
def test_linear_revolute_joint(self):
|
|
linear_base = Solid.make_box(1, 1, 1)
|
|
j1 = LinearJoint(
|
|
label="top",
|
|
to_part=linear_base,
|
|
axis=Axis((0, 0.5, 1), (1, 0, 0)),
|
|
linear_range=(0, 1),
|
|
)
|
|
revolute_top = Solid.make_box(1, 0.5, 1).locate(Location((-0.5, -0.25, 0)))
|
|
j2 = RevoluteJoint(
|
|
label="top",
|
|
to_part=revolute_top,
|
|
axis=Axis((0, 0, 0), (0, 0, 1)),
|
|
angle_reference=(1, 0, 0),
|
|
angular_range=(0, 180),
|
|
)
|
|
j1.connect_to(j2, position=0.25, angle=90)
|
|
|
|
bbox = revolute_top.bounding_box()
|
|
self.assertVectorAlmostEquals(bbox.min, (0, 0, 1), 5)
|
|
self.assertVectorAlmostEquals(bbox.max, (0.5, 1, 2), 5)
|
|
|
|
self.assertVectorAlmostEquals(j2.symbol.location.position, (0.25, 0.5, 1), 6)
|
|
self.assertVectorAlmostEquals(j2.symbol.location.orientation, (0, 0, 90), 6)
|
|
self.assertEqual(len(j1.symbol.edges()), 2)
|
|
|
|
# Test invalid position
|
|
with self.assertRaises(ValueError):
|
|
j1.connect_to(j2, position=5, angle=90)
|
|
|
|
# Test invalid angle
|
|
with self.assertRaises(ValueError):
|
|
j1.connect_to(j2, position=0.5, angle=270)
|
|
|
|
# Test invalid joint
|
|
with self.assertRaises(TypeError):
|
|
j1.connect_to(Solid.make_box(1, 1, 1), position=0.5, angle=90)
|
|
|
|
def test_builder(self):
|
|
with BuildPart() as test:
|
|
Box(3, 3, 1)
|
|
LinearJoint("test")
|
|
Cylinder(1, 3)
|
|
|
|
self.assertTrue(isinstance(test.part.joints["test"], LinearJoint))
|
|
|
|
def test_no_to_part(self):
|
|
with self.assertRaises(ValueError):
|
|
LinearJoint("test")
|
|
|
|
def test_error_handling(self):
|
|
j1 = LinearJoint("one", Box(1, 1, 1))
|
|
with self.assertRaises(TypeError):
|
|
j1.connect_to(Solid.make_box(1, 1, 1))
|
|
|
|
with self.assertRaises(TypeError):
|
|
j1.relative_to(Solid.make_box(1, 1, 1))
|
|
|
|
|
|
class TestCylindricalJoint(DirectApiTestCase):
|
|
def test_cylindrical_joint(self):
|
|
cylindrical_base = (
|
|
Solid.make_box(1, 1, 1)
|
|
.locate(Location((-0.5, -0.5, 0)))
|
|
.cut(Solid.make_cylinder(0.3, 1))
|
|
)
|
|
j1 = CylindricalJoint(
|
|
"base",
|
|
cylindrical_base,
|
|
Axis((0, 0, 1), (0, 0, -1)),
|
|
angle_reference=(1, 0, 0),
|
|
linear_range=(0, 1),
|
|
angular_range=(0, 90),
|
|
)
|
|
dowel = Solid.make_cylinder(0.3, 1).cut(
|
|
Solid.make_box(1, 1, 1).locate(Location((-0.5, 0, 0)))
|
|
)
|
|
j2 = RigidJoint("bottom", dowel, Location((0, 0, 0), (0, 0, 0)))
|
|
j1.connect_to(j2, position=0.25, angle=90)
|
|
dowel_bbox = dowel.bounding_box()
|
|
self.assertVectorAlmostEquals(dowel_bbox.min, (0, -0.3, -0.25), 5)
|
|
self.assertVectorAlmostEquals(dowel_bbox.max, (0.3, 0.3, 0.75), 5)
|
|
|
|
self.assertVectorAlmostEquals(j1.symbol.location.position, (0, 0, 1), 6)
|
|
self.assertVectorAlmostEquals(
|
|
j1.symbol.location.orientation, (-180, 0, -180), 6
|
|
)
|
|
self.assertEqual(len(j1.symbol.edges()), 3)
|
|
|
|
# Test invalid position
|
|
with self.assertRaises(ValueError):
|
|
j1.connect_to(j2, position=5, angle=90)
|
|
|
|
# Test invalid angle
|
|
with self.assertRaises(ValueError):
|
|
j1.connect_to(j2, position=0.5, angle=270)
|
|
|
|
# Test invalid joint
|
|
with self.assertRaises(TypeError):
|
|
j1.connect_to(Solid.make_box(1, 1, 1), position=0.5, angle=90)
|
|
|
|
def test_cylindrical_joint_error_bad_angle_reference(self):
|
|
"""Test that the angle_reference must be normal to the axis"""
|
|
with self.assertRaises(ValueError):
|
|
CylindricalJoint(
|
|
"base",
|
|
Solid.make_box(1, 1, 1),
|
|
Axis((0, 0, 1), (0, 0, -1)),
|
|
angle_reference=(1, 0, 1),
|
|
linear_range=(0, 1),
|
|
angular_range=(0, 90),
|
|
)
|
|
|
|
def test_cylindrical_joint_error_bad_position_and_angle(self):
|
|
"""Test that the joint angle is within bounds"""
|
|
|
|
j1 = CylindricalJoint(
|
|
"base",
|
|
Solid.make_box(1, 1, 1),
|
|
Axis((0, 0, 1), (0, 0, -1)),
|
|
linear_range=(0, 1),
|
|
angular_range=(0, 90),
|
|
)
|
|
j2 = RigidJoint("bottom", Solid.make_cylinder(1, 1), Location((0.5, 0.25, 0)))
|
|
with self.assertRaises(ValueError):
|
|
j1.connect_to(j2, position=0.5, angle=270)
|
|
|
|
with self.assertRaises(ValueError):
|
|
j1.connect_to(j2, position=4, angle=30)
|
|
|
|
def test_builder(self):
|
|
with BuildPart() as test:
|
|
Box(3, 3, 1)
|
|
CylindricalJoint("test")
|
|
Cylinder(1, 3)
|
|
|
|
self.assertTrue(isinstance(test.part.joints["test"], CylindricalJoint))
|
|
|
|
def test_no_to_part(self):
|
|
with self.assertRaises(ValueError):
|
|
CylindricalJoint("test")
|
|
|
|
def test_error_handling(self):
|
|
j1 = CylindricalJoint("one", Box(1, 1, 1))
|
|
with self.assertRaises(TypeError):
|
|
j1.connect_to(Solid.make_box(1, 1, 1))
|
|
|
|
with self.assertRaises(TypeError):
|
|
j1.relative_to(Solid.make_box(1, 1, 1))
|
|
|
|
|
|
class TestBallJoint(DirectApiTestCase):
|
|
def test_ball_joint(self):
|
|
socket_base = Solid.make_box(1, 1, 1).cut(
|
|
Solid.make_sphere(0.3, Plane((0.5, 0.5, 1)))
|
|
)
|
|
j1 = BallJoint(
|
|
"socket",
|
|
socket_base,
|
|
Location((0.5, 0.5, 1)),
|
|
angular_range=((-45, 45), (-45, 45), (0, 360)),
|
|
)
|
|
ball_rod = Solid.make_cylinder(0.15, 2).fuse(
|
|
Solid.make_sphere(0.3).locate(Location((0, 0, 2)))
|
|
)
|
|
j2 = RigidJoint("ball", ball_rod, Location((0, 0, 2), (180, 0, 0)))
|
|
j1.connect_to(j2, angles=(45, 45, 0))
|
|
self.assertVectorAlmostEquals(
|
|
ball_rod.faces().filter_by(GeomType.PLANE)[0].center(CenterOf.GEOMETRY),
|
|
(1.914213562373095, -0.5, 2),
|
|
5,
|
|
)
|
|
|
|
self.assertVectorAlmostEquals(j1.symbol.location.position, (0.5, 0.5, 1), 6)
|
|
self.assertVectorAlmostEquals(j1.symbol.location.orientation, (0, 0, 0), 6)
|
|
|
|
with self.assertRaises(ValueError):
|
|
j1.connect_to(j2, angles=(90, 45, 0))
|
|
|
|
# Test invalid joint
|
|
with self.assertRaises(TypeError):
|
|
j1.connect_to(Solid.make_box(1, 1, 1), angles=(0, 0, 0))
|
|
|
|
def test_builder(self):
|
|
with BuildPart() as test:
|
|
Box(3, 3, 1)
|
|
BallJoint("test")
|
|
Cylinder(1, 3)
|
|
|
|
self.assertTrue(isinstance(test.part.joints["test"], BallJoint))
|
|
|
|
def test_no_to_part(self):
|
|
with self.assertRaises(ValueError):
|
|
BallJoint("test")
|
|
|
|
def test_error_handling(self):
|
|
j1 = BallJoint("one", Box(1, 1, 1))
|
|
with self.assertRaises(TypeError):
|
|
j1.connect_to(Solid.make_box(1, 1, 1))
|
|
|
|
with self.assertRaises(TypeError):
|
|
j1.relative_to(Solid.make_box(1, 1, 1))
|
|
|
|
|
|
class TestJointOrder(DirectApiTestCase):
|
|
def test_rigid_rigid(self):
|
|
j1 = RigidJoint("one", Box(1, 1, 1), joint_location=Location((1, 2, 3)))
|
|
j2 = RigidJoint("two", Sphere(0.5))
|
|
j1.connect_to(j2)
|
|
self.assertVectorAlmostEquals(j1.parent.location.position, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(j2.parent.location.position, (1, 2, 3), 5)
|
|
|
|
j1 = RigidJoint("one", Box(1, 1, 1), joint_location=Location((1, 2, 3)))
|
|
j2 = RigidJoint("two", Sphere(0.5))
|
|
j2.connect_to(j1)
|
|
self.assertVectorAlmostEquals(j2.parent.location.position, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(j1.parent.location.position, (-1, -2, -3), 5)
|
|
|
|
def test_rigid_ball(self):
|
|
j1 = RigidJoint("one", Box(1, 1, 1), joint_location=Location((1, 2, 3)))
|
|
j2 = BallJoint("two", Sphere(0.5))
|
|
j1.connect_to(j2, angles=(0, 0, 0))
|
|
self.assertVectorAlmostEquals(j1.parent.location.position, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(j2.parent.location.position, (1, 2, 3), 5)
|
|
|
|
j1 = RigidJoint("one", Box(1, 1, 1), joint_location=Location((1, 2, 3)))
|
|
j2 = BallJoint("two", Sphere(0.5))
|
|
j2.connect_to(j1, angles=(0, 0, 0))
|
|
self.assertVectorAlmostEquals(j2.parent.location.position, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(j1.parent.location.position, (-1, -2, -3), 5)
|
|
|
|
def test_rigid_cylindrical(self):
|
|
j1 = RigidJoint("one", Box(1, 1, 1), joint_location=Location((1, 2, 3)))
|
|
j2 = CylindricalJoint("two", Sphere(0.5))
|
|
j1.connect_to(j2, position=0, angle=0)
|
|
self.assertVectorAlmostEquals(j1.parent.location.position, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(j2.parent.location.position, (1, 2, 3), 5)
|
|
|
|
j1 = RigidJoint("one", Box(1, 1, 1), joint_location=Location((1, 2, 3)))
|
|
j2 = CylindricalJoint("two", Sphere(0.5))
|
|
j2.connect_to(j1, position=0, angle=0)
|
|
self.assertVectorAlmostEquals(j2.parent.location.position, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(j1.parent.location.position, (-1, -2, -3), 5)
|
|
|
|
def test_rigid_linear(self):
|
|
j1 = RigidJoint("one", Box(1, 1, 1), joint_location=Location((1, 2, 3)))
|
|
j2 = LinearJoint("two", Sphere(0.5))
|
|
j1.connect_to(j2, position=0)
|
|
self.assertVectorAlmostEquals(j1.parent.location.position, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(j2.parent.location.position, (1, 2, 3), 5)
|
|
|
|
j1 = RigidJoint("one", Box(1, 1, 1), joint_location=Location((1, 2, 3)))
|
|
j2 = LinearJoint("two", Sphere(0.5))
|
|
j2.connect_to(j1, position=0)
|
|
self.assertVectorAlmostEquals(j2.parent.location.position, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(j1.parent.location.position, (-1, -2, -3), 5)
|
|
|
|
def test_rigid_revolute(self):
|
|
j1 = RigidJoint("one", Box(1, 1, 1), joint_location=Location((1, 2, 3)))
|
|
j2 = RevoluteJoint("two", Sphere(0.5))
|
|
j1.connect_to(j2, angle=0)
|
|
self.assertVectorAlmostEquals(j1.parent.location.position, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(j2.parent.location.position, (1, 2, 3), 5)
|
|
|
|
j1 = RigidJoint("one", Box(1, 1, 1), joint_location=Location((1, 2, 3)))
|
|
j2 = RevoluteJoint("two", Sphere(0.5))
|
|
j2.connect_to(j1, angle=0)
|
|
self.assertVectorAlmostEquals(j2.parent.location.position, (0, 0, 0), 5)
|
|
self.assertVectorAlmostEquals(j1.parent.location.position, (-1, -2, -3), 5)
|
|
|
|
|
|
class TestJointCopy(DirectApiTestCase):
|
|
def test_deepcopy(self):
|
|
with BuildPart() as test:
|
|
Box(3, 3, 1)
|
|
RigidJoint("test")
|
|
|
|
test_copy = copy.deepcopy(test.part, None)
|
|
self.assertEqual(test_copy.joints["test"].parent, test_copy)
|
|
|
|
|
|
class TestJointPropagation(DirectApiTestCase):
|
|
def test_algebra_mode(self):
|
|
b = Box(2, 2, 2)
|
|
RigidJoint("top", b, b.faces().sort_by(Axis.Z)[-1].location_at(0.5, 0.5))
|
|
c = b - Cylinder(0.5, 2)
|
|
self.assertVectorAlmostEquals(c.joints["top"].location.position, (0, 0, 1), 5)
|
|
|
|
def test_builder_mode(self):
|
|
with BuildPart() as base_builder:
|
|
Box(6, 6, 6)
|
|
top_face = base_builder.faces().sort_by(Axis.Z)[-1]
|
|
RigidJoint("top", joint_location=top_face.location_at(0.5, 0.5))
|
|
with BuildSketch(base_builder.faces()):
|
|
Circle(2)
|
|
extrude(amount=-1, mode=Mode.SUBTRACT)
|
|
base = base_builder.part
|
|
self.assertVectorAlmostEquals(
|
|
base.joints["top"].location.position, (0, 0, 3), 5
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|