Skip to content

Commit 4594b3e

Browse files
memory allocation for surface has been rearranged to avoid fragmentation
1 parent 483ef52 commit 4594b3e

10 files changed

Lines changed: 898 additions & 94 deletions

File tree

examples/lua/11_raycast.lua

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
-- 11_raycast.lua: Ray tracing through CSG geometry
2+
--
3+
-- Standalone: yes (no data files needed)
4+
-- Usage: bin/alea examples/lua/11_raycast.lua
5+
--
6+
-- Geometry: concentric spheres (fuel / moderator / void)
7+
-- Cell 1: fuel (mat 1) r < 5
8+
-- Cell 2: moderator (mat 2) 5 <= r < 10
9+
-- Cell 3: void (mat 0) r >= 10
10+
11+
print("=== Ray Tracing ===\n")
12+
13+
local sys = alea.create()
14+
15+
-- Build concentric spheres
16+
local s1 = sys:sphere(1, 0, 0, 0, 5)
17+
local s2 = sys:sphere(2, 0, 0, 0, 10)
18+
19+
sys:cell{id = 1, region = sys:inside(s1), material = 1, density = 10.0}
20+
sys:cell{id = 2, region = sys:outside(s1) * sys:inside(s2), material = 2, density = 1.0}
21+
sys:cell{id = 3, region = sys:outside(s2), material = 0, density = 0.0}
22+
23+
sys:build_universe_index()
24+
25+
-- Cast a ray along the X axis through the center
26+
print("--- Basic Raycast ---")
27+
local result = sys:raycast(-20, 0, 0, 1, 0, 0, 100)
28+
29+
print(string.format(" Segments: %d", result:segment_count()))
30+
print(string.format(" %-12s %-12s %-8s %-6s %-8s", "t_enter", "t_exit", "cell_id", "mat", "density"))
31+
print(string.rep("-", 54))
32+
33+
for i = 1, result:segment_count() do
34+
local seg = result:segment(i)
35+
print(string.format(" %12.4f %12.4f %-8d %-6d %8.2f",
36+
seg.t_enter, seg.t_exit, seg.cell_id, seg.material_id, seg.density))
37+
end
38+
39+
-- Path lengths by material
40+
print("\n--- Path Lengths ---")
41+
local total = result:path_length(-1)
42+
local fuel = result:path_length(1)
43+
local mod = result:path_length(2)
44+
print(string.format(" Total path: %8.4f", total))
45+
print(string.format(" In fuel (mat 1):%8.4f", fuel))
46+
print(string.format(" In mod (mat 2):%8.4f", mod))
47+
48+
-- Get all segments at once
49+
print("\n--- All Segments (batch) ---")
50+
local segs = result:segments()
51+
print(string.format(" Retrieved %d segments at once", #segs))
52+
53+
-- Cast rays from multiple directions
54+
print("\n--- Multi-Direction Rays ---")
55+
local directions = {
56+
{ 1, 0, 0, "along +X"},
57+
{ 0, 1, 0, "along +Y"},
58+
{ 0, 0, 1, "along +Z"},
59+
{ 1, 1, 1, "along diagonal"},
60+
}
61+
62+
for _, dir in ipairs(directions) do
63+
local dx, dy, dz = dir[1], dir[2], dir[3]
64+
-- Normalize direction
65+
local len = math.sqrt(dx*dx + dy*dy + dz*dz)
66+
dx, dy, dz = dx/len, dy/len, dz/len
67+
68+
local r = sys:raycast(-20*dx, -20*dy, -20*dz, dx, dy, dz, 100)
69+
print(string.format(" %-16s segments=%d fuel_path=%.4f total_path=%.4f",
70+
dir[4], r:segment_count(), r:path_length(1), r:path_length(-1)))
71+
end
72+
73+
-- Cell-aware raycast (uses per-cell surface indices)
74+
print("\n--- Cell-Aware Raycast ---")
75+
local result2 = sys:raycast_cell_aware(-20, 0, 0, 1, 0, 0, 100)
76+
print(string.format(" Segments: %d", result2:segment_count()))
77+
print(string.format(" Fuel path: %.4f (should match basic raycast)", result2:path_length(1)))
78+
79+
-- Find first cell hit by a ray
80+
print("\n--- First Cell Hit ---")
81+
local origins = {
82+
{-20, 0, 0, "from -X"},
83+
{ 20, 0, 0, "from +X"},
84+
{ 0, 0, 20, "from +Z"},
85+
}
86+
87+
for _, orig in ipairs(origins) do
88+
local cell_id, t = sys:ray_first_cell(orig[1], orig[2], orig[3], -orig[1], -orig[2], -orig[3], 100)
89+
if cell_id then
90+
print(string.format(" %-12s first cell=%d at t=%.4f", orig[4], cell_id, t))
91+
else
92+
print(string.format(" %-12s no cell hit", orig[4]))
93+
end
94+
end
95+
96+
print("\n11_raycast: OK")

examples/lua/12_slice.lua

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
-- 12_slice.lua: 2D cross-section slicing and curve extraction
2+
--
3+
-- Standalone: yes (no data files needed)
4+
-- Usage: bin/alea examples/lua/12_slice.lua
5+
--
6+
-- Geometry: concentric spheres (fuel / moderator / void)
7+
-- Cell 1: fuel (mat 1) r < 5
8+
-- Cell 2: moderator (mat 2) 5 <= r < 10
9+
-- Cell 3: void (mat 0) r >= 10
10+
11+
print("=== 2D Slicing ===\n")
12+
13+
local sys = alea.create()
14+
15+
-- Build concentric spheres
16+
local s1 = sys:sphere(1, 0, 0, 0, 5)
17+
local s2 = sys:sphere(2, 0, 0, 0, 10)
18+
19+
sys:cell{id = 1, region = sys:inside(s1), material = 1, density = 10.0}
20+
sys:cell{id = 2, region = sys:outside(s1) * sys:inside(s2), material = 2, density = 1.0}
21+
sys:cell{id = 3, region = sys:outside(s2), material = 0, density = 0.0}
22+
23+
sys:build_universe_index()
24+
25+
-- Create an axis-aligned Z slice at z=0
26+
print("--- Axis-Aligned Slice (Z=0) ---")
27+
local view = alea.slice_view_axis(2, 0.0, -15, 15, -15, 15)
28+
print(string.format(" Viewport: u=[%.1f, %.1f] v=[%.1f, %.1f]",
29+
view.u_min, view.u_max, view.v_min, view.v_max))
30+
31+
-- Sample the slice on a grid
32+
local nu, nv = 16, 16
33+
local grid = sys:find_cells_grid(view, nu, nv)
34+
print(string.format(" Grid: %dx%d = %d points", nu, nv, #grid.cell_ids))
35+
36+
-- Count cells and materials found
37+
local cell_counts = {}
38+
local mat_counts = {}
39+
for i = 1, #grid.cell_ids do
40+
local cid = grid.cell_ids[i]
41+
local mid = grid.material_ids[i]
42+
cell_counts[cid] = (cell_counts[cid] or 0) + 1
43+
mat_counts[mid] = (mat_counts[mid] or 0) + 1
44+
end
45+
46+
print(" Cells found:")
47+
local ckeys = {}
48+
for k in pairs(cell_counts) do ckeys[#ckeys + 1] = k end
49+
table.sort(ckeys)
50+
for _, cid in ipairs(ckeys) do
51+
print(string.format(" cell %d: %d samples", cid, cell_counts[cid]))
52+
end
53+
54+
-- Count errors
55+
local n_ok, n_overlap, n_undef = 0, 0, 0
56+
for _, e in ipairs(grid.errors) do
57+
if e == 0 then n_ok = n_ok + 1
58+
elseif e == 1 then n_overlap = n_overlap + 1
59+
else n_undef = n_undef + 1
60+
end
61+
end
62+
print(string.format(" Errors: %d ok, %d overlap, %d undefined", n_ok, n_overlap, n_undef))
63+
64+
-- Analytical curves
65+
print("\n--- Slice Curves ---")
66+
local curves = sys:get_slice_curves(view)
67+
print(string.format(" Curve count: %d", curves:count()))
68+
69+
for i = 1, curves:count() do
70+
local c = curves:get(i)
71+
if c.type == "circle" then
72+
print(string.format(" [%d] %s (surface %d): center=(%.2f, %.2f) radius=%.2f",
73+
i, c.type, c.surface_id, c.data.cx, c.data.cy, c.data.radius))
74+
elseif c.type == "line" then
75+
print(string.format(" [%d] %s (surface %d): p=(%.2f, %.2f) d=(%.2f, %.2f)",
76+
i, c.type, c.surface_id, c.data.px, c.data.py, c.data.dx, c.data.dy))
77+
else
78+
print(string.format(" [%d] %s (surface %d)", i, c.type, c.surface_id))
79+
end
80+
end
81+
82+
local u0, u1, v0, v1 = curves:bounds()
83+
print(string.format(" Curve bounds: u=[%.2f, %.2f] v=[%.2f, %.2f]", u0, u1, v0, v1))
84+
85+
-- Label positions for cell IDs
86+
print("\n--- Label Positions ---")
87+
local labels = alea.find_label_positions(grid.cell_ids, nu, nv, 1)
88+
print(string.format(" Found %d labels", #labels))
89+
for _, lbl in ipairs(labels) do
90+
print(string.format(" ID %d at pixel (%d, %d), size=%d px",
91+
lbl.id, lbl.px, lbl.py, lbl.pixel_count))
92+
end
93+
94+
-- Surface label positions
95+
local slabels = alea.find_surface_label_positions(curves,
96+
view.u_min, view.u_max, view.v_min, view.v_max, nu, nv, 0)
97+
print(string.format(" Surface labels: %d", #slabels))
98+
99+
-- Arbitrary-orientation slice (diagonal through model)
100+
print("\n--- Arbitrary Slice ---")
101+
local view2 = alea.slice_view(0, 0, 0, 0, 0, 1, 0, 1, 0, -15, 15, -15, 15)
102+
local grid2 = sys:find_cells_grid(view2, 8, 8)
103+
print(string.format(" Grid: 8x8 = %d points", #grid2.cell_ids))
104+
105+
-- Grid with depth control
106+
print("\n--- Depth Control ---")
107+
local grid_root = sys:find_cells_grid(view, 8, 8, 0)
108+
local grid_inner = sys:find_cells_grid(view, 8, 8, -1)
109+
print(string.format(" Root level: %d points", #grid_root.cell_ids))
110+
print(string.format(" Innermost (-1): %d points", #grid_inner.cell_ids))
111+
112+
print("\n12_slice: OK")

examples/lua/13_render.lua

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
-- 13_render.lua: 3D rendering of CSG geometry
2+
--
3+
-- Standalone: yes (no data files needed)
4+
-- Usage: bin/alea examples/lua/13_render.lua
5+
--
6+
-- Geometry: concentric spheres (fuel / moderator / void)
7+
-- Cell 1: fuel (mat 1) r < 5
8+
-- Cell 2: moderator (mat 2) 5 <= r < 10
9+
-- Cell 3: void (mat 0) r >= 10
10+
--
11+
-- Writes images to /tmp/alea_example_render_*.{ppm,bmp}
12+
13+
print("=== 3D Rendering ===\n")
14+
15+
local sys = alea.create()
16+
17+
-- Build concentric spheres
18+
local s1 = sys:sphere(1, 0, 0, 0, 5)
19+
local s2 = sys:sphere(2, 0, 0, 0, 10)
20+
21+
sys:cell{id = 1, region = sys:inside(s1), material = 1, density = 10.0}
22+
sys:cell{id = 2, region = sys:outside(s1) * sys:inside(s2), material = 2, density = 1.0}
23+
sys:cell{id = 3, region = sys:outside(s2), material = 0, density = 0.0}
24+
25+
sys:build_universe_index()
26+
27+
-- Inspect default config
28+
print("--- Default Config ---")
29+
local cfg = alea.render_config()
30+
print(string.format(" Default size: %dx%d", cfg.width, cfg.height))
31+
print(string.format(" FOV: %.1f Shadows: %d Edges: %d", cfg.fov, cfg.shadows, cfg.edges))
32+
print(string.format(" Color mode: %d Render mode: %d", cfg.color_mode, cfg.render_mode))
33+
34+
-- Auto camera setup
35+
print("\n--- Camera Setup ---")
36+
local cam = sys:render_camera_setup{width = 128, height = 128}
37+
print(string.format(" Eye: (%.2f, %.2f, %.2f)", cam.eye[1], cam.eye[2], cam.eye[3]))
38+
print(string.format(" Target: (%.2f, %.2f, %.2f)", cam.target[1], cam.target[2], cam.target[3]))
39+
print(string.format(" Forward: (%.2f, %.2f, %.2f)", cam.forward[1], cam.forward[2], cam.forward[3]))
40+
print(string.format(" Auto-fit: %s", tostring(cam.auto_fit)))
41+
42+
-- Basic render with auto camera
43+
print("\n--- Basic Render (auto camera) ---")
44+
local fb = sys:render{width = 64, height = 64}
45+
print(string.format(" Framebuffer: %dx%d", fb:width(), fb:height()))
46+
47+
fb:edge_darken()
48+
fb:write_ppm("/tmp/alea_example_render_basic.ppm")
49+
print(" Written: /tmp/alea_example_render_basic.ppm")
50+
51+
-- Render with explicit camera position
52+
print("\n--- Custom Camera ---")
53+
local fb2 = sys:render{
54+
width = 64,
55+
height = 64,
56+
eye = {25, 25, 15},
57+
target = {0, 0, 0},
58+
fov = 45,
59+
shadows = 1,
60+
edges = 1,
61+
}
62+
fb2:edge_darken()
63+
fb2:write_bmp("/tmp/alea_example_render_custom.bmp")
64+
print(string.format(" Framebuffer: %dx%d", fb2:width(), fb2:height()))
65+
print(" Written: /tmp/alea_example_render_custom.bmp")
66+
67+
-- Render with clipping plane (cut away top half)
68+
print("\n--- Clipping Plane (z < 0 visible) ---")
69+
local fb3 = sys:render{
70+
width = 64,
71+
height = 64,
72+
eye = {25, 25, 15},
73+
target = {0, 0, 0},
74+
fov = 45,
75+
clips = {{0, 0, -1, 0}}, -- visible where -z + 0 > 0, i.e. z < 0
76+
}
77+
fb3:edge_darken()
78+
fb3:write_ppm("/tmp/alea_example_render_clipped.ppm")
79+
print(" Written: /tmp/alea_example_render_clipped.ppm")
80+
81+
-- Multiple output formats
82+
print("\n--- Output Formats ---")
83+
fb:write_ppm("/tmp/alea_example_render.ppm")
84+
fb:write_bmp("/tmp/alea_example_render.bmp")
85+
print(" PPM: /tmp/alea_example_render.ppm")
86+
print(" BMP: /tmp/alea_example_render.bmp")
87+
88+
print("\n13_render: OK")

examples/lua/14_mesh.lua

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
-- 14_mesh.lua: Mesh sampling and export (Gmsh, VTK)
2+
--
3+
-- Standalone: yes (no data files needed)
4+
-- Usage: bin/alea examples/lua/14_mesh.lua
5+
--
6+
-- Geometry: concentric spheres (fuel / moderator / void)
7+
-- Cell 1: fuel (mat 1) r < 5
8+
-- Cell 2: moderator (mat 2) 5 <= r < 10
9+
-- Cell 3: void (mat 0) r >= 10
10+
--
11+
-- Writes mesh files to /tmp/alea_example_mesh_*
12+
13+
print("=== Mesh Export ===\n")
14+
15+
local sys = alea.create()
16+
17+
-- Build concentric spheres
18+
local s1 = sys:sphere(1, 0, 0, 0, 5)
19+
local s2 = sys:sphere(2, 0, 0, 0, 10)
20+
21+
sys:cell{id = 1, region = sys:inside(s1), material = 1, density = 10.0}
22+
sys:cell{id = 2, region = sys:outside(s1) * sys:inside(s2), material = 2, density = 1.0}
23+
sys:cell{id = 3, region = sys:outside(s2), material = 0, density = 0.0}
24+
25+
sys:build_universe_index()
26+
27+
-- Step-by-step mesh sampling with inspection
28+
print("--- Mesh Sample (10x10x10) ---")
29+
local mesh = sys:mesh_sample{nx = 10, ny = 10, nz = 10}
30+
31+
local info = mesh:info()
32+
print(string.format(" Grid: %dx%dx%d = %d voxels", info.nx, info.ny, info.nz, info.nx * info.ny * info.nz))
33+
print(string.format(" Materials found: %d", info.num_materials))
34+
print(" Unique materials:")
35+
for _, mid in ipairs(info.unique_materials) do
36+
print(string.format(" material %d", mid))
37+
end
38+
39+
-- Inspect material distribution
40+
print("\n--- Material Distribution ---")
41+
local mids = mesh:material_ids()
42+
local cids = mesh:cell_ids()
43+
print(string.format(" Material IDs: %d entries", #mids))
44+
print(string.format(" Cell IDs: %d entries", #cids))
45+
46+
local mat_dist = {}
47+
for _, mid in ipairs(mids) do
48+
mat_dist[mid] = (mat_dist[mid] or 0) + 1
49+
end
50+
51+
local mkeys = {}
52+
for k in pairs(mat_dist) do mkeys[#mkeys + 1] = k end
53+
table.sort(mkeys)
54+
55+
print(string.format(" %-10s %-8s %-8s", "Material", "Voxels", "Fraction"))
56+
print(string.rep("-", 30))
57+
local total = #mids
58+
for _, mid in ipairs(mkeys) do
59+
local n = mat_dist[mid]
60+
print(string.format(" %-10d %-8d %7.1f%%", mid, n, 100 * n / total))
61+
end
62+
63+
-- Export to Gmsh format
64+
print("\n--- Export Gmsh ---")
65+
mesh:export(0, "/tmp/alea_example_mesh.msh")
66+
print(" Written: /tmp/alea_example_mesh.msh")
67+
68+
-- Export to VTK format
69+
print("\n--- Export VTK ---")
70+
mesh:export(1, "/tmp/alea_example_mesh.vtk")
71+
print(" Written: /tmp/alea_example_mesh.vtk")
72+
73+
-- One-shot export (sample + write in one call)
74+
print("\n--- One-Shot Export ---")
75+
sys:mesh_export({nx = 8, ny = 8, nz = 8, format = 0}, "/tmp/alea_example_mesh_quick.msh")
76+
sys:mesh_export({nx = 8, ny = 8, nz = 8, format = 1}, "/tmp/alea_example_mesh_quick.vtk")
77+
print(" Written: /tmp/alea_example_mesh_quick.msh")
78+
print(" Written: /tmp/alea_example_mesh_quick.vtk")
79+
80+
-- Mesh with explicit bounds (smaller region around the fuel)
81+
print("\n--- Bounded Mesh (fuel region only) ---")
82+
local mesh2 = sys:mesh_sample{
83+
nx = 8, ny = 8, nz = 8,
84+
x_min = -6, x_max = 6,
85+
y_min = -6, y_max = 6,
86+
z_min = -6, z_max = 6,
87+
}
88+
local info2 = mesh2:info()
89+
print(string.format(" Grid: %dx%dx%d", info2.nx, info2.ny, info2.nz))
90+
print(string.format(" Materials: %d", info2.num_materials))
91+
92+
print("\n14_mesh: OK")

0 commit comments

Comments
 (0)