Skip to content

Commit

Permalink
Python more numpy (elalish#656)
Browse files Browse the repository at this point in the history
* [python] numpy updates and cleanup

Also add CrossSection::Bounds()

* cleanup - const and reference args in py bind

* fix unnamed args

* all_apis.py more coverage

* fixup - more param renaming, docstring fixes

* fixup - run black

* fixup - move const to left side

* fixup extrude.py get_volume

* fix python examples for api update
  • Loading branch information
wrongbad committed Dec 19, 2023
1 parent bc0bded commit 7d564cf
Show file tree
Hide file tree
Showing 11 changed files with 572 additions and 612 deletions.
101 changes: 101 additions & 0 deletions bindings/python/examples/all_apis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from manifold3d import *
import numpy as np


def all_root_level():
set_min_circular_angle(10)
set_min_circular_edge_length(1)
set_circular_segments(22)
n = get_circular_segments(1)
assert n == 22
poly = [[0, 0], [1, 0], [1, 1]]
tris = triangulate([poly])
tris = triangulate([np.array(poly)])


def all_cross_section():
poly = [[0, 0], [1, 0], [1, 1]]
c = CrossSection([np.array(poly)])
c = CrossSection([poly])
c = CrossSection() + c
a = c.area()
c = CrossSection.batch_hull([c, c.translate((1, 0))])
b = c.bounds()
c = CrossSection.circle(1)
cs = c.decompose()
m = c.extrude(1)
c = c.hull()
c = CrossSection.hull_points(poly)
c = CrossSection.hull_points(np.array(poly))
e = c.is_empty()
c = c.mirror((0, 1))
n = c.num_contour()
n = c.num_vert()
c = c.offset(1, JoinType.Round)
m = c.revolve()
c = c.rotate(90)
c = c.scale((2, 2))
c = c.simplify()
c = CrossSection.square((1, 1))
p = c.to_polygons()
c = c.transform([[1, 0, 0], [0, 1, 0]])
c = c.translate((1, 1))
c = c.warp(lambda p: (p[0] + 1, p[1] / 2))
c = c.warp_batch(lambda ps: ps * [1, 0.5] + [1, 0])


def all_manifold():
mesh = Manifold.sphere(1).to_mesh()
m = Manifold(mesh)
m = Manifold() + m
m = m.as_original()
m = Manifold.batch_hull([m, m.translate((0, 0, 1))])
b = m.bounding_box()
m = m.calculate_curvature(4, 5)
m = Manifold.compose([m, m.translate((5, 0, 0))])
m = Manifold.cube((1, 1, 1))
m = Manifold.cylinder(1, 1)
ms = m.decompose()
g = m.genus()
a = m.surface_area()
v = m.volume()
m = m.hull()
m = m.hull_points(mesh.vert_properties)
e = m.is_empty()
m = m.mirror((0, 0, 1))
n = m.num_edge()
n = m.num_prop()
n = m.num_prop_vert()
n = m.num_tri()
n = m.num_vert()
i = m.original_id()
p = m.precision()
c = m.project()
m = m.refine(2)
i = Manifold.reserve_ids(1)
m = m.scale((1, 2, 3))
m = m.set_properties(3, lambda pos, prop: pos)
c = m.slice(0.5)
m = Manifold.smooth(mesh, [0], [0.5])
m = Manifold.sphere(1)
m, n = m.split(m.translate((1, 0, 0)))
m, n = m.split_by_plane((0, 0, 1), 0)
e = m.status()
m = Manifold.tetrahedron()
mesh = m.to_mesh()
m = m.transform([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]])
m = m.translate((0, 0, 0))
m = m.trim_by_plane((0, 0, 1), 0)
m = m.warp(lambda p: (p[0] + 1, p[1] / 2, p[2] * 2))
m = m.warp_batch(lambda ps: ps * [1, 0.5, 2] + [1, 0, 0])


def run():
all_root_level()
all_cross_section()
all_manifold()
return Manifold()


if __name__ == "__main__":
run()
42 changes: 24 additions & 18 deletions bindings/python/examples/bricks.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,44 +28,50 @@


def brick():
return Manifold.cube(brick_length, brick_depth, brick_height)
return Manifold.cube([brick_length, brick_depth, brick_height])


def halfbrick():
return Manifold.cube((brick_length - mortar_gap) / 2, brick_depth, brick_height)
return Manifold.cube([(brick_length - mortar_gap) / 2, brick_depth, brick_height])


def row(length):
bricks = [
brick().translate((brick_length + mortar_gap) * x, 0, 0) for x in range(length)
brick().translate([(brick_length + mortar_gap) * x, 0, 0])
for x in range(length)
]
return Manifold(bricks)
return sum(bricks, Manifold())


def wall(length, height, alternate=0):
bricks = [
row(length).translate(
((z + alternate) % 2) * (brick_depth + mortar_gap),
0,
(brick_height + mortar_gap) * z,
[
((z + alternate) % 2) * (brick_depth + mortar_gap),
0,
(brick_height + mortar_gap) * z,
]
)
for z in range(height)
]
return Manifold(bricks)
return sum(bricks, Manifold())


def walls(length, width, height):
return Manifold(
return sum(
[
wall(length, height),
wall(width, height, 1).rotate(0, 0, 90).translate(brick_depth, 0, 0),
wall(width, height, 1).rotate([0, 0, 90]).translate([brick_depth, 0, 0]),
wall(length, height, 1).translate(
0, (width) * (brick_length + mortar_gap), 0
[0, (width) * (brick_length + mortar_gap), 0]
),
wall(width, height)
.rotate(0, 0, 90)
.translate((length + 0.5) * (brick_length + mortar_gap) - mortar_gap, 0, 0),
]
.rotate([0, 0, 90])
.translate(
[(length + 0.5) * (brick_length + mortar_gap) - mortar_gap, 0, 0]
),
],
Manifold(),
)


Expand All @@ -74,21 +80,21 @@ def floor(length, width):
if length > 1 and width > 1:
results.append(
floor(length - 1, width - 1).translate(
brick_depth + mortar_gap, brick_depth + mortar_gap, 0
[brick_depth + mortar_gap, brick_depth + mortar_gap, 0]
)
)
if length == 1 and width > 1:
results.append(row(width - 1).rotate(0, 0, 90))
if width == 1 and length > 1:
results.append(
row(length - 1).translate(
2 * (brick_depth + mortar_gap), brick_depth + mortar_gap, 0
[2 * (brick_depth + mortar_gap), brick_depth + mortar_gap, 0]
)
)
results.append(
halfbrick().translate(brick_depth + mortar_gap, brick_depth + mortar_gap, 0)
halfbrick().translate([brick_depth + mortar_gap, brick_depth + mortar_gap, 0])
)
return Manifold(results)
return sum(results, Manifold())


def run(width=10, length=10, height=10):
Expand Down
8 changes: 4 additions & 4 deletions bindings/python/examples/cube_with_dents.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@


def run(n=5, overlap=True):
a = Manifold.cube(n, n, 0.5).translate(-0.5, -0.5, -0.5)
a = Manifold.cube([n, n, 0.5]).translate([-0.5, -0.5, -0.5])

spheres = [
Manifold.sphere(0.45 if overlap else 0.55, 50).translate(i, j, 0)
Manifold.sphere(0.45 if overlap else 0.55, 50).translate([i, j, 0])
for i in range(n)
for j in range(n)
]
spheres = reduce(lambda a, b: a + b, spheres)
# spheres = reduce(lambda a, b: a + b, spheres)

return a - spheres
return a - sum(spheres, Manifold())
6 changes: 3 additions & 3 deletions bindings/python/examples/extrude.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ def run():
# extrude a polygon to create a manifold
extruded_polygon = cross_section.extrude(10.0)
eps = 0.001
observed_volume = extruded_polygon.get_volume()
observed_volume = extruded_polygon.volume()
expected_volume = 10.0
if abs(observed_volume - expected_volume) > eps:
raise Exception(
f"observed_volume={observed_volume} differs from expected_volume={expected_volume}"
)
observed_surface_area = extruded_polygon.get_surface_area()
observed_surface_area = extruded_polygon.surface_area()
expected_surface_area = 42.0
if abs(observed_surface_area - expected_surface_area) > eps:
raise Exception(
f"observed_surface_area={observed_surface_area} differs from expected_surface_area={expected_surface_area}"
)

# get bounding box from manifold
observed_bbox = extruded_polygon.bounding_box
observed_bbox = extruded_polygon.bounding_box()
expected_bbox = (0.0, 0.0, 0.0, 1.0, 1.0, 10.0)
if observed_bbox != expected_bbox:
raise Exception(
Expand Down
14 changes: 9 additions & 5 deletions bindings/python/examples/gyroid_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
"""

import math
import sys
import numpy as np

sys.path.append("/Users/k/projects/python/badcad/wip/manifold/build/bindings/python")

from manifold3d import Mesh, Manifold


Expand All @@ -31,28 +35,28 @@ def gyroid(x, y, z):


def gyroid_levelset(level, period, size, n):
return Manifold.from_mesh(
return Manifold(
Mesh.level_set(
gyroid,
[-period, -period, -period, period, period, period],
period / n,
level,
)
).scale(size / period)
).scale([size / period] * 3)


def rhombic_dodecahedron(size):
box = Manifold.cube(size * math.sqrt(2.0) * np.array([1, 1, 2]), True)
result = box.rotate(90, 45) ^ box.rotate(90, 45, 90)
return result ^ box.rotate(0, 0, 45)
result = box.rotate([90, 45, 0]) ^ box.rotate([90, 45, 90])
return result ^ box.rotate([0, 0, 45])


def gyroid_module(size=20, n=15):
period = math.pi * 2.0
result = (
gyroid_levelset(-0.4, period, size, n) ^ rhombic_dodecahedron(size)
) - gyroid_levelset(0.4, period, size, n)
return result.rotate(-45, 0, 90).translate(0, 0, size / math.sqrt(2.0))
return result.rotate([-45, 0, 90]).translate([0, 0, size / math.sqrt(2.0)])


def run(size=20, n=15):
Expand Down
2 changes: 1 addition & 1 deletion bindings/python/examples/maze.py
Original file line number Diff line number Diff line change
Expand Up @@ -4039,4 +4039,4 @@ def ball(*args):

ball([10, 10, 10], 0.4)

return Manifold.cube((n + 1) * np.array([1, 1, 1])) - Manifold(cavity)
return Manifold.cube([n + 1] * 3) - sum(cavity, Manifold())
3 changes: 2 additions & 1 deletion bindings/python/examples/scallop.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ def colorCurvature(_pos, oldProp):
blue = [0, 0, 1]
return [(1 - b) * blue[i] + b * red[i] for i in range(3)]

edges, smoothing = zip(*sharpenedEdges)
return (
Manifold.smooth(scallop, sharpenedEdges)
Manifold.smooth(scallop, edges, smoothing)
.refine(n)
.calculate_curvature(-1, 0)
.set_properties(3, colorCurvature)
Expand Down
4 changes: 2 additions & 2 deletions bindings/python/examples/split_cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@


def run():
a = Manifold.cube(1.0, 1.0, 1.0)
b = Manifold.cube(1.0, 1.0, 1.0).rotate(45.0, 45.0, 45.0)
a = Manifold.cube([1.0, 1.0, 1.0])
b = Manifold.cube([1.0, 1.0, 1.0]).rotate([45.0, 45.0, 45.0])
return a.split(b)[0]
4 changes: 3 additions & 1 deletion bindings/python/examples/sponge.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,6 @@ def run(n=1):
result -= hole.rotate([90, 0, 0])
result -= hole.rotate([0, 90, 0])

return result.trim_by_plane([1, 1, 1], 0).set_properties(4, posColors).scale(100)
return (
result.trim_by_plane([1, 1, 1], 0).set_properties(4, posColors).scale([100] * 3)
)
2 changes: 1 addition & 1 deletion bindings/python/examples/union_failure.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
def run():
# for some reason this causes collider error
obj = Manifold.cube()
obj += Manifold([Manifold.cube()]).rotate(0, 0, 45 + 180)
obj += Manifold.cube().rotate([0, 0, 45 + 180])
return obj
Loading

0 comments on commit 7d564cf

Please sign in to comment.