Exemplo n.º 1
0
    def testfun(translation):
        translated_convex_cube = ConvexPolyhedron(convex_cube.vertices +
                                                  translation)

        translated_inertia = translate_inertia_tensor(
            translation, convex_cube_inertia_tensor, convex_cube_volume)
        mc_tensor = compute_inertia_mc(translated_convex_cube.vertices,
                                       convex_cube_volume, 1e4)

        uncentered_inertia_tensor = translated_convex_cube._compute_inertia_tensor(
            False)
        assert np.allclose(
            translated_inertia,
            uncentered_inertia_tensor,
            atol=2e-1,
            rtol=2e-1,
        )
        assert np.allclose(mc_tensor,
                           uncentered_inertia_tensor,
                           atol=2e-1,
                           rtol=2e-1)

        assert np.allclose(mc_tensor, translated_inertia, atol=1e-2, rtol=1e-2)
        assert np.allclose(mc_tensor,
                           translated_convex_cube.inertia_tensor,
                           atol=1e-2,
                           rtol=1e-2)
Exemplo n.º 2
0
    def testfun(points, rotation):
        vertices = tet.vertices + points
        shape = ConvexPolyhedron(vertices)
        rotated_shape = ConvexPolyhedron(rowan.rotate(rotation, vertices))

        mat = rowan.to_matrix(rotation)
        rotated_inertia = rotate_order2_tensor(mat, shape.inertia_tensor)

        assert np.allclose(rotated_inertia, rotated_shape.inertia_tensor)
Exemplo n.º 3
0
def test_diagonalize_inertia(points):
    """Test that we can orient a polyhedron along its principal axes."""
    # Some of the points might be in the interior of the hull, but the
    # ConvexPolyhedron is constructed from the hull anyway so that's fine.
    poly = ConvexPolyhedron(points)

    try:
        poly.diagonalize_inertia()
        it = poly.inertia_tensor
        assert np.allclose(np.diag(np.diag(it)), it)
    except ValueError:
        # Triangulation can fail, this is a limitation of polytri and not something we
        # can address without implementing a more robust algorithm.
        return
Exemplo n.º 4
0
def test_volume_damasceno_shapes(shape):
    if shape["name"] in ("RESERVED", "Sphere"):
        return
    vertices = shape["vertices"]
    poly = ConvexPolyhedron(vertices)
    hull = ConvexHull(vertices)
    assert np.isclose(poly.volume, hull.volume)
Exemplo n.º 5
0
def compute_inertia_mc(vertices, num_samples=1e6):
    """Compute inertia tensor via Monte Carlo integration.

    Using Monte Carlo integration provides a means to test the results of an
    analytical calculation.

    Args:
        num_samples (int): The number of samples to use.

    Returns:
        float: The 3x3 inertia tensor.
    """
    mins = np.min(vertices, axis=0)
    maxs = np.max(vertices, axis=0)

    points = np.random.rand(int(num_samples), 3) * (maxs - mins) + mins

    hull = Delaunay(vertices)
    inside = hull.find_simplex(points) >= 0

    i_xx = np.mean(points[inside][:, 1] ** 2 + points[inside][:, 2] ** 2)
    i_yy = np.mean(points[inside][:, 0] ** 2 + points[inside][:, 2] ** 2)
    i_zz = np.mean(points[inside][:, 0] ** 2 + points[inside][:, 1] ** 2)
    i_xy = np.mean(-points[inside][:, 0] * points[inside][:, 1])
    i_xz = np.mean(-points[inside][:, 0] * points[inside][:, 2])
    i_yz = np.mean(-points[inside][:, 1] * points[inside][:, 2])

    poly = ConvexPolyhedron(vertices)

    inertia_tensor = (
        np.array([[i_xx, i_xy, i_xz], [i_xy, i_yy, i_yz], [i_xz, i_yz, i_zz]])
        * poly.volume
    )

    return inertia_tensor
Exemplo n.º 6
0
def test_minimal_centered_bounding_sphere():
    """Validate circumsphere by testing the polyhedron.

    This checks that all points outside this circumsphere are also outside the
    polyhedron. Note that this is a necessary but not sufficient condition for
    correctness.
    """
    # Building convex polyhedra is the slowest part of this test, so rather
    # than testing all the shapes from this particular dataset every time we
    # instead test a random subset each time the test runs. To further speed
    # the tests, we build all convex polyhedra ahead of time. Each set of
    # random points is tested against a different random polyhedron.
    import random

    family = DOI_SHAPE_REPOSITORIES["10.1126/science.1220869"][0]
    shapes = [
        ConvexPolyhedron(s["vertices"]) for s in random.sample(
            [s for s in family.data.values() if len(s["vertices"])],
            len(family.data) // 5,
        )
    ]

    # Use a nested function to avoid warnings from hypothesis. While the shape
    # does get modified inside the testfun, it's simply being recentered each
    # time, which is not destructive since it can be overwritten in subsequent
    # calls.
    # See https://github.com/HypothesisWorks/hypothesis/issues/377
    @settings(deadline=2000)
    @given(
        center=arrays(np.float64, (3, ),
                      elements=floats(-10, 10, width=64),
                      unique=True),
        points=arrays(np.float64, (50, 3),
                      elements=floats(-1, 1, width=64),
                      unique=True),
        shape_index=integers(0,
                             len(shapes) - 1),
    )
    def testfun(center, points, shape_index):
        poly = shapes[shape_index]
        poly.center = center

        sphere = poly.minimal_centered_bounding_sphere
        scaled_points = points * sphere.radius + sphere.center
        points_outside = np.logical_not(sphere.is_inside(scaled_points))

        # Verify that all points outside the circumsphere are also outside the
        # polyhedron.
        assert not np.any(
            np.logical_and(points_outside, poly.is_inside(scaled_points)))

        with pytest.deprecated_call():
            assert sphere_isclose(sphere, poly.circumsphere_from_center)

    testfun()
Exemplo n.º 7
0
def test_maximal_centered_bounded_sphere_convex_hulls(points, test_points):
    hull = ConvexHull(points)
    poly = ConvexPolyhedron(points[hull.vertices])
    try:
        insphere = poly.maximal_centered_bounded_sphere
    except ValueError as e:
        # Ignore cases where triangulation fails, we're not interested in
        # trying to get polytri to work for nearly degenerate cases.
        if str(e) == "Triangulation failed":
            assume(False)
    assert poly.is_inside(insphere.center)

    test_points *= insphere.radius * 3
    points_in_sphere = insphere.is_inside(test_points)
    points_in_poly = poly.is_inside(test_points)
    assert np.all(points_in_sphere <= points_in_poly)
    assert insphere.volume < poly.volume

    with pytest.deprecated_call():
        assert sphere_isclose(insphere, poly.insphere_from_center)
Exemplo n.º 8
0
def test_center(shape):
    poly = ConvexPolyhedron(shape["vertices"])
    coxeter_result = poly.center
    num_samples = 1000
    accept = False
    while num_samples < 1e8:
        try:
            mc_result = compute_centroid_mc(shape["vertices"], num_samples)
            assert np.allclose(coxeter_result, mc_result, atol=1e-1)
            accept = True
            break
        except AssertionError:
            num_samples *= 10
            continue
    if not accept:
        raise AssertionError("The test failed for shape {}.\nMC Result: "
                             "\n{}\ncoxeter result: \n{}".format(
                                 shape["name"], mc_result, coxeter_result))
Exemplo n.º 9
0
def test_moment_inertia_damasceno_shapes(shape):
    # These shapes pass the test for a sufficiently high number of samples, but
    # the number is too high to be worth running them regularly.
    bad_shapes = [
        "Augmented Truncated Dodecahedron",
        "Deltoidal Hexecontahedron",
        "Disdyakis Triacontahedron",
        "Truncated Dodecahedron",
        "Truncated Icosidodecahedron",
        "Metabiaugmented Truncated Dodecahedron",
        "Pentagonal Hexecontahedron",
        "Paragyrate Diminished Rhombicosidodecahedron",
        "Square Cupola",
        "Triaugmented Truncated Dodecahedron",
        "Parabiaugmented Truncated Dodecahedron",
    ]
    if shape["name"] in ["RESERVED", "Sphere"] + bad_shapes:
        return

    np.random.seed(0)
    poly = ConvexPolyhedron(shape["vertices"])
    coxeter_result = poly.inertia_tensor
    volume = poly.volume
    num_samples = 1000
    accept = False
    # Loop over different sampling rates to minimize the test runtime.
    while num_samples < 1e8:
        try:
            mc_result = compute_inertia_mc(poly.vertices, volume, num_samples)
            assert np.allclose(coxeter_result, mc_result, atol=1e-1)
            accept = True
            break
        except AssertionError:
            num_samples *= 10
            continue
    if not accept:
        raise AssertionError("The test failed for shape {}.\nMC Result: "
                             "\n{}\ncoxeter result: \n{}".format(
                                 shape["name"], mc_result, coxeter_result))
Exemplo n.º 10
0
def convex_cube():
    return ConvexPolyhedron(get_cube_points())
Exemplo n.º 11
0
def test_convex_surface_area(points):
    """Check the surface areas of various convex sets."""
    hull = ConvexHull(points)
    poly = ConvexPolyhedron(points[hull.vertices])
    assert np.isclose(hull.area, poly.surface_area)
Exemplo n.º 12
0
def test_convex_volume(points):
    """Check the volumes of various convex sets."""
    hull = ConvexHull(points)
    poly = ConvexPolyhedron(hull.points[hull.vertices])
    assert np.isclose(hull.volume, poly.volume)
Exemplo n.º 13
0
 def check_rotation_invariance(quat):
     rotated_poly = ConvexPolyhedron(rowan.rotate(quat, poly.vertices))
     assert sphere_isclose(poly_insphere, rotated_poly.insphere, atol=1e-4)