Example #1
0
    def test_equality(self):
        # Same object
        self.assertEqualToItself(Cuboid(11, 11, 11))

        # Equal objects
        self.assertEqual (Cuboid(11, 11, 11), Cuboid(11, 11, 11))

        # Different objects
        self.assertNotEqual(Cuboid(11, 11, 11), Cuboid(11, 11, 12))
Example #2
0
    def test_to_scad(self):
        sphere = Sphere(2)
        cube = Cuboid(10, 10, 10)
        cylinder = Frustum(origin, Z, 11, 11)

        self.assertEqual(
            Difference([sphere, cube, cylinder]).to_scad(),
            ScadObject("difference", None, None, [
                sphere.to_scad(),
                cube.to_scad(),
                cylinder.to_scad(),
            ]))
Example #3
0
    def test_multiplication(self):
        a = Sphere(2)
        b = Cuboid(10, 10, 10)
        c = Frustum(origin, Z, 11, 11)
        d = Cuboid(20, 20, 20)

        self.assertEqual(    a  *  b             , Intersection([a, b      ]))
        self.assertEqual(    c  *  c             , Intersection([c, c      ]))
        self.assertEqual(   (a  *  b) * c        , Intersection([a, b, c   ]))
        self.assertEqual(    a  * (b  * c)       , Intersection([a, b, c   ]))
        self.assertEqual(    a  *  b  *  c  * d  , Intersection([a, b, c, d]))
        self.assertEqual(  ((a  *  b) *  c) * d  , Intersection([a, b, c, d]))
        self.assertEqual(    a  * (b  * (c  * d)), Intersection([a, b, c, d]))
        self.assertEqual(   (a  *  b) * (c  * d) , Intersection([a, b, c, d]))
Example #4
0
    def test_subtraction(self):
        a = Sphere(2)
        b = Cuboid(10, 10, 10)
        c = Frustum(origin, Z, 11, 11)
        d = Cuboid(20, 20, 20)

        # Difference is non-associative, so we get nested differences
        self.assertEqual(    a  -  b             , Difference([a, b      ]))
        self.assertEqual(    c  -  c             , Difference([c, c      ]))
        self.assertEqual(   (a  -  b) - c        , Difference([a, b, c   ]))
        self.assertEqual(    a  - (b  - c)       , Difference([a, Difference([b, c])]))
        self.assertEqual(    a  -  b  -  c  - d  , Difference([a, b, c, d]))
        self.assertEqual(  ((a  -  b) -  c) - d  , Difference([a, b, c, d]))
        self.assertEqual(    a  - (b  - (c  - d)), Difference([a, Difference([b, Difference([c, d])])]))
        self.assertEqual(   (a  -  b) - (c  - d) , Difference([Difference([a, b]), Difference([c, d])]))
Example #5
0
    def test_sum(self):
        sphere = Sphere(2)
        cube = Cuboid(10, 10, 10)
        cylinder = Frustum(origin, Z, 11, 11)
        objects = [sphere, cube, cylinder]

        self.assertEqual(sum(objects, Union.empty()), Union(objects))
Example #6
0
    def test_to_scad(self):
        sphere = Sphere(2)
        cube = Cuboid(10, 10, 10)
        cylinder = Frustum(origin, Z, 11, 11)

        self.assertEqual(
            Union([sphere, cube, cylinder]).to_scad(),
            ScadObject("union", None, None, [
                sphere.to_scad(),
                cube.to_scad(),
                cylinder.to_scad(),
            ]))

        # Empty
        self.assertEqual(
            Union([]).to_scad(), ScadObject("union", None, None, None))
Example #7
0
    def test_to_scad(self):
        self.ignore_scad_comments = True

        # Unit axis to unit axis
        self.assertScadObjectTarget(RotateFromTo(X, Y), None, "rotate", None, [("a", 90), ("v", [ 0,  0,  1])], None)
        self.assertScadObjectTarget(RotateFromTo(Y, Z), None, "rotate", None, [("a", 90), ("v", [ 1,  0,  0])], None)
        self.assertScadObjectTarget(RotateFromTo(Z, X), None, "rotate", None, [("a", 90), ("v", [ 0,  1,  0])], None)
        self.assertScadObjectTarget(RotateFromTo(Y, X), None, "rotate", None, [("a", 90), ("v", [ 0,  0, -1])], None)
        self.assertScadObjectTarget(RotateFromTo(Z, Y), None, "rotate", None, [("a", 90), ("v", [-1,  0,  0])], None)
        self.assertScadObjectTarget(RotateFromTo(X, Z), None, "rotate", None, [("a", 90), ("v", [ 0, -1,  0])], None)

        # Unit axis to unit axis with different length
        self.assertScadObjectTarget(RotateFromTo(X, 2 * Y), None, "rotate", None, [("a", 90), ("v", [0, 0, 1])], None)

        # Different signs for X/Y axes
        self.assertScadObjectTarget(RotateFromTo( X,  Y), None, "rotate", None, [("a", 90), ("v", [ 0,  0,  1])], None)
        self.assertScadObjectTarget(RotateFromTo( X, -Y), None, "rotate", None, [("a", 90), ("v", [ 0,  0, -1])], None)
        self.assertScadObjectTarget(RotateFromTo(-X,  Y), None, "rotate", None, [("a", 90), ("v", [ 0,  0, -1])], None)
        self.assertScadObjectTarget(RotateFromTo(-X, -Y), None, "rotate", None, [("a", 90), ("v", [ 0,  0,  1])], None)
        self.assertScadObjectTarget(RotateFromTo( Y,  X), None, "rotate", None, [("a", 90), ("v", [ 0,  0, -1])], None)
        self.assertScadObjectTarget(RotateFromTo( Y, -X), None, "rotate", None, [("a", 90), ("v", [ 0,  0,  1])], None)
        self.assertScadObjectTarget(RotateFromTo(-Y,  X), None, "rotate", None, [("a", 90), ("v", [ 0,  0,  1])], None)
        self.assertScadObjectTarget(RotateFromTo(-Y, -X), None, "rotate", None, [("a", 90), ("v", [ 0,  0, -1])], None)

        # Same direction (no effect). This generates a zero XYZ transform (not
        # an empty ScadObject, which would also be possible).
        cube = Cuboid(2, 2, 2).to_scad()
        self.assertScadObjectTarget(RotateFromTo(X        , X        ), None, "rotate", [[0, 0, 0]], None, None)
        self.assertScadObjectTarget(RotateFromTo(X        , X        ), cube, "rotate", [[0, 0, 0]], None, [cube])
        self.assertScadObjectTarget(RotateFromTo([1, 2, 3], [2, 4, 6]), cube, "rotate", [[0, 0, 0]], None, [cube])

        # Opposite direction (ambiguous rotation)
        self.assertIn(("a", 180), RotateFromTo(X        , -X          , ignore_ambiguity=True).to_scad(None)._kw_parameters)
        self.assertIn(("a", 180), RotateFromTo([1, 2, 3], [-2, -4, -6], ignore_ambiguity=True).to_scad(None)._kw_parameters)
Example #8
0
    def test_repr(self):
        t = Translate([10, 20, 30])
        cube = Cuboid(1, 1, 1)

        self.assertRepr(
            Transformed(t, cube),
            "Transformed(Translate(Vector(10, 20, 30)), Cuboid(1, 1, 1))")
Example #9
0
    def test_construction(self):
        sphere = Sphere(11)
        cube = Cuboid(22, 22, 22)
        cylinder = Frustum(origin, Z, 11, 11)
        object_list = [sphere, cube, cylinder]

        # Empty
        Csg([])

        # With objects
        self.assertEqual(Csg(object_list).children, object_list)

        # With generator
        self.assertEqual(Csg(o for o in object_list).children, object_list)

        # With invalid objects
        with self.assertRaises(TypeError):
            Csg(None)  # None instead of empty list
        with self.assertRaises(TypeError):
            Csg([Sphere])  # Class instead of object
        with self.assertRaises(TypeError):
            Csg(sphere)  # Object instead of list
        with self.assertRaises(TypeError):
            Csg([None])  # List with invalid value
        with self.assertRaises(TypeError):
            Csg([sphere, None])  # List with object and invalid value
Example #10
0
    def test_to_scad(self):
        sphere = Sphere(2)
        cube = Cuboid(10, 10, 10)
        cylinder = Frustum(origin, Z, 5, 5)

        mixed = Union(
            [Intersection([sphere, cylinder]),
             Difference([cube, sphere])])
        self.assertEqual(
            mixed.to_scad(),
            ScadObject("union", None, None, [
                ScadObject(
                    "intersection", None, None,
                    [sphere.to_scad(), cylinder.to_scad()]),
                ScadObject("difference", None, None,
                           [cube.to_scad(), sphere.to_scad()]),
            ]))
Example #11
0
    def test_csg_generators(self):
        sphere = Sphere(11)
        cuboid = Cuboid(11, 22, 33)
        cylinder = Frustum(origin, Z, 11, 11)
        object_list = [sphere, cuboid, cylinder]

        self.assertEqual(union(object_list), Union(object_list))
        self.assertEqual(difference(object_list), Difference(object_list))
        self.assertEqual(intersection(object_list), Intersection(object_list))
Example #12
0
    def test_addition(self):
        a = Sphere(2)
        b = Cuboid(10, 10, 10)
        c = Frustum(origin, Z, 11, 11)
        d = Cuboid(20, 20, 20)

        self.assertEqual(   a +  b               , Union([a, b      ]))
        self.assertEqual(   c +  c               , Union([c, c      ]))
        self.assertEqual(  (a +  b) + c          , Union([a, b, c   ]))
        self.assertEqual(   a + (b  + c)         , Union([a, b, c   ]))
        self.assertEqual(    a  +  b  +  c  + d  , Union([a, b, c, d]))
        self.assertEqual(  ((a  +  b) +  c) + d  , Union([a, b, c, d]))
        self.assertEqual(    a  + (b  + (c  + d)), Union([a, b, c, d]))
        self.assertEqual(   (a  +  b) + (c  + d) , Union([a, b, c, d]))

        # Empty union
        self.assertEqual(Union([]) + Union([]), Union([]))
        self.assertEqual(Union([]) + a, Union([a]))
        self.assertEqual(a + Union([]), Union([a]))
Example #13
0
    def test_equality(self):
        sphere = Sphere(11)
        cube = Cuboid(22, 22, 22)
        cylinder = Frustum(origin, Z, 11, 11)
        objects = [sphere, cube, cylinder]

        # Different types of CSG are not equal, even if their children are identical
        self.assertNotEqual(Union(objects), Intersection(objects))
        self.assertNotEqual(Intersection(objects), Difference(objects))
        self.assertNotEqual(Difference(objects), Union(objects))
Example #14
0
    def test_equality(self):
        scale1a = ScaleUniform(1)
        scale1b = ScaleUniform(1)
        scale2 = ScaleUniform(2)

        cube1a = Cuboid(1, 1, 1)
        cube1b = Cuboid(1, 1, 1)
        cube2 = Cuboid(2, 2, 2)

        self.assertEqual(Transformed(scale1a, cube1a),
                         Transformed(scale1a, cube1b))  # Equal objects
        self.assertEqual(Transformed(scale1a, cube1a),
                         Transformed(scale1b, cube1a))  # Equal transform
        self.assertNotEqual(Transformed(scale1a, cube1a),
                            cube1a)  # Transformed / original
        self.assertNotEqual(Transformed(scale1a, cube1a),
                            Transformed(scale2, cube1a))  # Different transform
        self.assertNotEqual(Transformed(scale1a, cube1a),
                            Transformed(scale1a, cube2))  # Different objects
Example #15
0
    def test_multiplication_with_object_and_transform(self):
        # Multiplication is used for both intersection (Object * Object) and transform (Transform * Object)
        a = Sphere(2)
        b = Cuboid(3, 3, 3)
        s = ScaleAxes(1, 2, -1)
        t = Translate([0, 0, 0])

        self.assertEqual( t * (a  * b), Transformed(t, Intersection([a, b])))
        self.assertEqual((t *  a) * b , Intersection([Transformed(t, a), b]))
        self.assertEqual((s *  t) * a , Transformed(Chained([s, t]), a))
        self.assertEqual( s * (t  * a), Transformed(Chained([s, t]), a))
Example #16
0
def cube(size):
    """Generate a cube.

    The cube will have one corner at the origin, will be aligned with the
    axes, and extend in the positive axis directions.

    Signatures (convenience forms only):
      * cube(size)
    """

    size = number.convert(size, "size")
    return Cuboid(size, size, size)
Example #17
0
    def test_invalid_operations(self):
        a = Sphere(2)
        b = Cuboid(10, 10, 10)
        s = ScaleUniform(1)
        t = Translate([0, 0, 0])

        for target in [a, t, t*a, a+b, a-b, a*b, s*t]:
            for invalid in [None, 0, 0.0, ""]:
                with self.assertRaises(TypeError): target + invalid
                with self.assertRaises(TypeError): target - invalid
                with self.assertRaises(TypeError): target * invalid
                with self.assertRaises(TypeError): invalid + target
                with self.assertRaises(TypeError): invalid - target
                with self.assertRaises(TypeError): invalid * target
Example #18
0
def cuboid(size_or_x_or_xyz, y=None, z=None):
    """Generate a cuboid.

    The cuboid will have one corner at the origin, will be aligned with the
    axes, and extend in the positive axis directions.

    Signatures (convenience forms only):
      * cuboid(size)
      * cuboid(x, y, z)
      * cuboid(xyz)

    xzy can be Vector, list, or tuple. Note that for convenience, a Vector can
    be used for xyz even though xyz is not strictly a vector.
    """

    if both(y, z):
        return Cuboid(size_or_x_or_xyz, y, z)
    elif neither(y, z) and number.valid(size_or_x_or_xyz):
        return Cuboid(size_or_x_or_xyz, size_or_x_or_xyz, size_or_x_or_xyz)
    elif neither(y, z) and Vector.valid_type(size_or_x_or_xyz):
        return Cuboid(*size_or_x_or_xyz)
    else:
        raise TypeError("y and z can only be specified together")
Example #19
0
    def test_construction(self):
        # Transformed objects can also be created by multiplying a transform with an object. This is
        # tested in test_object.py, as it concerns the operators defined by Object.

        # Transformed object
        t = Translate([10, 20, 30])
        cube = Cuboid(1, 1, 1)

        with self.assertNothingRaised():
            Transformed(t, cube)

        with self.assertRaises(TypeError):
            Transformed(t, t)
        with self.assertRaises(TypeError):
            Transformed(cube, cube)
        with self.assertRaises(TypeError):
            Transformed(t, None)
        with self.assertRaises(TypeError):
            Transformed(None, cube)
Example #20
0
    def test_equality(self):
        sphere = Sphere(11)
        cuboid = Cuboid(11, 22, 33)
        cylinder = Frustum(origin, Z, 11, 11)
        objects = [sphere, cuboid, cylinder]

        # Same object
        self.assertEqualToItself(Union([]))
        self.assertEqualToItself(Union(objects))

        # Equal objects
        self.assertEqual(Union([]), Union([]))
        self.assertEqual(Union(objects), Union(objects))

        # Different objects
        self.assertNotEqual(Union(objects), Union([sphere, cuboid]))
        self.assertNotEqual(Union([cuboid, sphere]), Union([sphere, cuboid]))

        # Equal objects from different specifications
        self.assertEqual(Union.empty(), Union([]))
Example #21
0
    def test_to_scad(self):
        r = RotateXyz(60, 30, 15)
        s = ScaleAxes(1, 2, -1)
        cube = Cuboid(11, 11, 11)

        # Simple transform
        self.assertEqual(
            Transformed(r, cube).to_scad(),
            ScadObject("rotate", [[60, 30, 15]], None, [
                ScadObject("cube", [[11, 11, 11]], None, None),
            ]))

        # Chained transform
        self.assertEqual(
            Transformed(Chained([r, s]), cube).to_scad(),
            ScadObject("rotate", [[60, 30, 15]], None, [
                ScadObject("scale", [[1, 2, -1]], None, [
                    ScadObject("cube", [[11, 11, 11]], None, None),
                ])
            ]))
Example #22
0
    def test_to_tree(self):
        a = Sphere(2)
        b = Cuboid(3, 3, 3)
        s = ScaleAxes(1, 2, -1)
        t = Translate([0, 0, 0])

        part = a + s*t*b

        actual = part.to_tree()
        expected = Node(part, [
            Node(a),
            Node(s*t*b, [
                Node(s*t, [
                    Node(s),
                    Node(t),
                ]),
                Node(b),
            ]),
        ])

        self.assertEqual(actual, expected)
Example #23
0
    def test_render_to_file(self):
        part = Sphere(0.6) + Cuboid(1, 2, 3) - Frustum([0, 0, 0], [0, 0, 4], 0.5, 0.5)

        expected_file_name = os.path.join(os.path.dirname(__file__), "test_scad_object_render_to_file_expected.scad")
        actual_file_name   = os.path.join(os.path.dirname(__file__), "test_scad_object_render_to_file_actual.scad")

        self.assertTrue(os.path.isfile(expected_file_name))
        self.assertFalse(os.path.exists(actual_file_name))

        try:
            render_to_file(part, actual_file_name, fn=60)
            with open(actual_file_name) as actual_file:
                actual = actual_file.read()
            with open(expected_file_name) as expected_file:
                expected = expected_file.read()

            self.assertNotEqual(expected, "")
            self.assertEqual(actual, expected)
        finally:
            if os.path.exists(actual_file_name):
                os.unlink(actual_file_name)
Example #24
0
    def test_cuboid_generators(self):
        self.assertEqual(cuboid(1), Cuboid(1, 1, 1))
        self.assertEqual(cuboid(1, 2, 3), Cuboid(1, 2, 3))
        self.assertEqual(cuboid([1, 2, 3]), Cuboid(1, 2, 3))
        self.assertEqual(cuboid((1, 2, 3)), Cuboid(1, 2, 3))
        self.assertEqual(cuboid(Vector(1, 2, 3)), Cuboid(1, 2, 3))

        self.assertEqual(cube(1), Cuboid(1, 1, 1))

        with self.assertRaises(TypeError):
            cuboid(1, 2)
        with self.assertRaises(TypeError):
            cuboid(None)
        with self.assertRaises(TypeError):
            cuboid("1")
        with self.assertRaises(TypeError):
            cuboid(1, 2, None)
        with self.assertRaises(TypeError):
            cuboid(1, None, 2)
        with self.assertRaises(TypeError):
            cuboid(1, 2, "3")
Example #25
0
 def to_scad(self):
     return (Cuboid(inf, inf, inf).translate([-inf / 2, -inf / 2, -inf]).up(
         self._offset).rotate(frm=Z, to=self._normal,
                              ignore_ambiguity=True).to_scad().comment(
                                  str(self)))
Example #26
0
from cadlib.object.primitives import Cuboid
from cadlib.scad import render_to_file
from cadlib.transform.primitives import RotateXyz

object = Cuboid(2, 3, 4)
rotate = RotateXyz([20, 0, 45])
assembly = rotate * object

render_to_file(assembly, "adhoc_test.scad")
Example #27
0
from cadlib.object.primitives import Sphere, Cuboid, Frustum
# from cadlib.object.generators import *
#from cadlib.transform.primitives import RotateXyz, ScaleAxes, Translate
from cadlib.util.vector import X, Y, Z
from cadlib.scad import render_to_file

# def test_case(name, object):
#     print(name)
#     print("    Cadlib tree:")
#     print(object.to_tree().format(top_indent="        "))
#     print("    OpenSCAD tree:")
#     print(object.to_scad().to_tree().format(top_indent="        "))
#     print("    OpenSCAD source:")
#     print(object.to_scad().to_code(top_indent="        "))

c = Cuboid(50, 50, 50).rotate(Z, 30).right(25)

#c = Frustum(0, 20*Y, 5, 5)  # TODO base/cap/center
print(c.to_tree().format())
s = Sphere(25)

#c2 = Cuboid(10, 10, 10).top_face.at([0, 0, 0])

assembly = c + s.center.at(c.top_face) + c2

print(assembly.to_scad().to_tree().format())
print(assembly.to_scad().to_code())

render_to_file(assembly, "anchor_test.scad", fn=30)
Example #28
0
from cadlib.object.primitives import Cuboid, Cylinder, Sphere
from cadlib.util.vector import Z


def test_case(name, object):
    print(name)
    print("    Cadlib tree:")
    print(object.to_tree().format(top_indent="        "))
    print("    OpenSCAD tree:")
    print(object.to_scad().to_tree().format(top_indent="        "))


o1 = Cuboid(10, 10, 10)
o2 = Cylinder(Z, 5, 5)
o3 = Sphere(2)

test_case("2-intersection", o1 * o2)
test_case("3-intersection (1)", (o1 * o2) * o3)
test_case("3-intersection (2)", o1 * (o2 * o3))
test_case("2-union", o1 + o2)
test_case("2-difference", o1 - o2)
Example #29
0
    def test_transform_shortcuts(self):
        a = Cuboid(11, 11, 11)

        self.assertEqual(a.up     (1), Transformed(Translate([ 0,  0,  1]), a))
        self.assertEqual(a.down   (2), Transformed(Translate([ 0,  0, -2]), a))
        self.assertEqual(a.left   (3), Transformed(Translate([-3,  0,  0]), a))
        self.assertEqual(a.right  (4), Transformed(Translate([ 4,  0,  0]), a))
        self.assertEqual(a.forward(5), Transformed(Translate([ 0,  5,  0]), a))
        self.assertEqual(a.back   (6), Transformed(Translate([ 0, -6,  0]), a))

        self.assertEqual(a.yaw_left  (1), Transformed(RotateYpr( 1,  0,  0), a))
        self.assertEqual(a.yaw_right (2), Transformed(RotateYpr(-2,  0,  0), a))
        self.assertEqual(a.pitch_up  (3), Transformed(RotateYpr( 0,  3,  0), a))
        self.assertEqual(a.pitch_down(4), Transformed(RotateYpr( 0, -4,  0), a))
        self.assertEqual(a.roll_right(5), Transformed(RotateYpr( 0,  0,  5), a))
        self.assertEqual(a.roll_left (6), Transformed(RotateYpr( 0,  0, -6), a))
Example #30
0
    def test_postfix_transform(self):
        cube = Cuboid(11, 11, 11)

        # Vectors
        rv = [60, 34, 30]
        sv = [ 2,  1,  1]
        tv = [10, 20, 30]

        # Transforms
        r = RotateXyz(*rv)
        s = ScaleAxes (*sv)
        t = Translate(tv)

        # Long shortcuts
        self.assertEqual(cube.rotate   (xyz = rv).scale(sv)   .translate(tv), t * s * r * cube)
        self.assertEqual(cube.transform(r)       .scale(sv)   .transform(t) , t * s * r * cube)
        self.assertEqual(cube.rotate   (xyz = rv).transform(s).translate(tv), t * s * r * cube)
        self.assertEqual(cube.transform(s * r)   .transform(t)              , t * s * r * cube)
        self.assertEqual(cube.scale([1, 2, 3]), ScaleAxes(1, 2, 3) * cube)
        self.assertEqual(cube.scale(2), ScaleUniform(2) * cube)
        self.assertEqual(cube.scale([1, 2, 3], 4), ScaleAxisFactor([1, 2, 3], 4) * cube)

        # Error
        with self.assertRaises(TypeError): cube.transform(cube)