Skip to content

Commit

Permalink
Merge branch 'master' into fix-minimal_bounding_sphere
Browse files Browse the repository at this point in the history
  • Loading branch information
janbridley authored Feb 13, 2024
2 parents f050e4b + 6dee178 commit f027272
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 17 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/PublishPyPI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ jobs:
python -m pip install --progress-bar off build
- name: Build wheels and sdist
run: python -m build --sdist --wheel --outdir dist/ .
- uses: actions/upload-artifact@v4.0.0
- uses: actions/upload-artifact@v4.3.0
with:
name: wheel
path: dist/*.whl
- uses: actions/upload-artifact@v4.0.0
- uses: actions/upload-artifact@v4.3.0
with:
name: sdist
path: dist/*.tar.gz
Expand All @@ -41,12 +41,12 @@ jobs:
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Download artifact sdist
uses: actions/download-artifact@v4.1.0
uses: actions/download-artifact@v4.1.1
with:
name: sdist
path: dist
- name: Download artifact wheel
uses: actions/download-artifact@v4.1.0
uses: actions/download-artifact@v4.1.1
with:
name: wheel
path: dist
Expand Down
40 changes: 32 additions & 8 deletions coxeter/shapes/convex_spheropolyhedron.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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.
Expand Down
30 changes: 25 additions & 5 deletions tests/test_spheropolyhedron.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand All @@ -47,13 +46,34 @@ 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))
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 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 np.isclose(sphero_cube.mean_curvature, value)


@given(r=floats(0, 1.0))
Expand Down

0 comments on commit f027272

Please sign in to comment.