From 9e81e01a2df0ab5beca5f009e906c1fe6594296b Mon Sep 17 00:00:00 2001 From: Trevor Teague Date: Wed, 31 Jan 2024 11:07:37 -0500 Subject: [PATCH 1/4] add mean_curvature test --- tests/test_spheropolyhedron.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_spheropolyhedron.py b/tests/test_spheropolyhedron.py index c744c22e..791d2ddd 100644 --- a/tests/test_spheropolyhedron.py +++ b/tests/test_spheropolyhedron.py @@ -56,6 +56,27 @@ def test_surface_area_polyhedron(convex_cube): assert sphero_cube.surface_area == approx(convex_cube.surface_area) +@given(radius=floats(0.1, 1)) +def test_mean_curvature(radius): + sphero_cube = make_sphero_cube(radius=radius) + h_cube = 3 / 4 + h_sphere = radius + assert np.isclose(sphero_cube.mean_curvature, h_cube + h_sphere) + + +def test_mean_curvature_polyhedron(convex_cube, cube_points): + """Ensure that zero radius gives the same result as a polyhedron.""" + sphero_cube = make_sphero_cube(radius=0) + assert sphero_cube.mean_curvature == approx(convex_cube.mean_curvature) + + +@given(value=floats(0.1, 1)) +def test_set_mean_curvature(value): + sphero_cube = make_sphero_cube(radius=0) + sphero_cube.mean_curvature = value + assert sphero_cube.mean_curvature == approx(value) + + @given(r=floats(0, 1.0)) def test_radius_getter_setter(r): sphero_cube = make_sphero_cube(radius=r) From 28f7ac03abd2a0cef18a50e98e42b36ca8036e5c Mon Sep 17 00:00:00 2001 From: Trevor Teague Date: Wed, 31 Jan 2024 11:24:40 -0500 Subject: [PATCH 2/4] Add changes to convex_spheropolyhedron --- coxeter/shapes/convex_spheropolyhedron.py | 40 ++++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/coxeter/shapes/convex_spheropolyhedron.py b/coxeter/shapes/convex_spheropolyhedron.py index bd112740..eab11733 100644 --- a/coxeter/shapes/convex_spheropolyhedron.py +++ b/coxeter/shapes/convex_spheropolyhedron.py @@ -105,9 +105,9 @@ def volume(self): # 2) The volume of the spherical caps on the vertices, which sum up to # a single sphere with the spheropolyhedron's rounding radius. # 3) The volume of cylindrical wedges along the edges, which are - # computed using a standard cylinder formula then using the dihedral - # angle of the face to determine what fraction of the cylinder to - # include. + # computed using the standard formula for the volume of a cylinder + # and using the dihedral angle of the face to determine what fraction + # of the cylinder to include (the angle between the normals). # 4) The volume of the extruded faces, which is the surface area of # each face multiplied by the rounding radius. v_poly = self.polyhedron.volume @@ -123,7 +123,9 @@ def volume(self): edge_length = np.linalg.norm( self.polyhedron.vertices[edge[0]] - self.polyhedron.vertices[edge[1]] ) - v_cyl += (np.pi * self.radius**2) * (phi / (2 * np.pi)) * edge_length + v_cyl += ( + (np.pi * self.radius**2) * ((np.pi - phi) / (2 * np.pi)) * edge_length + ) return v_poly + v_sphere + v_face + v_cyl @@ -152,9 +154,9 @@ def surface_area(self): # 2) The surface are of the spherical vertex caps, which is just the # surface area of a single sphere with the rounding radius. # 3) The surface area of cylindrical wedges along the edges, which are - # computed using a standard cylinder formula then using the dihedral - # angle of the face to determine what fraction of the cylinder to - # include. + # computed using the standard formula for the volume of a cylinder + # and using the dihedral angle of the face to determine what fraction + # of the cylinder to include (the angle between the normals). a_poly = self.polyhedron.surface_area a_sphere = 4 * np.pi * self.radius**2 a_cyl = 0 @@ -167,7 +169,9 @@ def surface_area(self): edge_length = np.linalg.norm( self.polyhedron.vertices[edge[0]] - self.polyhedron.vertices[edge[1]] ) - a_cyl += (2 * np.pi * self.radius) * (phi / (2 * np.pi)) * edge_length + a_cyl += ( + (2 * np.pi * self.radius) * ((np.pi - phi) / (2 * np.pi)) * edge_length + ) return a_poly + a_sphere + a_cyl @@ -179,6 +183,26 @@ def surface_area(self, value): else: raise ValueError("Surface area must be greater than zero.") + @property + def mean_curvature(self): + """float: Get the mean curvature.""" + # Compute the mean curvature as the sum of 2 terms: + # 1) The mean curvature of the spherical vertex caps, which is just the + # rounding radius of the spheropolyhedron. + # 2) The mean curvature of cylindrical wedges along the edges, which sum + # to the mean curvature of the underlying polyhedron + h_sphere = self.radius + h_cyl = self.polyhedron.mean_curvature + return h_cyl + h_sphere + + @mean_curvature.setter + def mean_curvature(self, value): + if value > 0: + scale = value / self.mean_curvature + self._rescale(scale) + else: + raise ValueError("Mean curvature must be greater than zero.") + def is_inside(self, points): """Determine whether points are contained in this spheropolyhedron. From 3685e3b5cac1b1ce78b8ecdfb6f4b55d247f63c6 Mon Sep 17 00:00:00 2001 From: janbridley Date: Wed, 31 Jan 2024 15:01:44 -0500 Subject: [PATCH 3/4] Replaced pytest approx with np.isclose --- tests/test_spheropolyhedron.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/test_spheropolyhedron.py b/tests/test_spheropolyhedron.py index 791d2ddd..2ed9e2c3 100644 --- a/tests/test_spheropolyhedron.py +++ b/tests/test_spheropolyhedron.py @@ -5,7 +5,6 @@ import pytest from hypothesis import given, settings from hypothesis.strategies import floats -from pytest import approx from conftest import make_sphero_cube @@ -23,14 +22,14 @@ def test_volume(radius): def test_volume_polyhedron(convex_cube, cube_points): """Ensure that zero radius gives the same result as a polyhedron.""" sphero_cube = make_sphero_cube(radius=0) - assert sphero_cube.volume == approx(convex_cube.volume) + assert np.isclose(sphero_cube.volume, convex_cube.volume) @given(value=floats(0.1, 1)) def test_set_volume(value): sphero_cube = make_sphero_cube(radius=0) sphero_cube.volume = value - assert sphero_cube.volume == approx(value) + assert np.isclose(sphero_cube.volume, value) @settings(deadline=1000) @@ -47,13 +46,13 @@ def test_surface_area(radius): def test_set_surface_area(value): sphero_cube = make_sphero_cube(radius=0) sphero_cube.surface_area = value - assert sphero_cube.surface_area == approx(value) + assert np.isclose(sphero_cube.surface_area, (value)) def test_surface_area_polyhedron(convex_cube): """Ensure that zero radius gives the same result as a polyhedron.""" sphero_cube = make_sphero_cube(radius=0) - assert sphero_cube.surface_area == approx(convex_cube.surface_area) + assert np.isclose(sphero_cube.surface_area, convex_cube.surface_area) @given(radius=floats(0.1, 1)) @@ -67,14 +66,14 @@ def test_mean_curvature(radius): def test_mean_curvature_polyhedron(convex_cube, cube_points): """Ensure that zero radius gives the same result as a polyhedron.""" sphero_cube = make_sphero_cube(radius=0) - assert sphero_cube.mean_curvature == approx(convex_cube.mean_curvature) + assert np.isclose(sphero_cube.mean_curvature, convex_cube.mean_curvature) @given(value=floats(0.1, 1)) def test_set_mean_curvature(value): sphero_cube = make_sphero_cube(radius=0) sphero_cube.mean_curvature = value - assert sphero_cube.mean_curvature == approx(value) + assert np.isclose(sphero_cube.mean_curvature, value) @given(r=floats(0, 1.0)) From 412f188bbe4d064acfcf5456429e3065e3ef797d Mon Sep 17 00:00:00 2001 From: janbridley Date: Wed, 31 Jan 2024 15:04:08 -0500 Subject: [PATCH 4/4] Removed extra parentheses --- tests/test_spheropolyhedron.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_spheropolyhedron.py b/tests/test_spheropolyhedron.py index 2ed9e2c3..3a486a87 100644 --- a/tests/test_spheropolyhedron.py +++ b/tests/test_spheropolyhedron.py @@ -46,7 +46,7 @@ def test_surface_area(radius): def test_set_surface_area(value): sphero_cube = make_sphero_cube(radius=0) sphero_cube.surface_area = value - assert np.isclose(sphero_cube.surface_area, (value)) + assert np.isclose(sphero_cube.surface_area, value) def test_surface_area_polyhedron(convex_cube):