### Initialize Environment and Dependencies Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_mpc/adaptive_mpc.ipynb Setup the project environment and load necessary packages for RegionTrees and plotting. ```julia using Pkg pkg"activate ." ``` ```julia using RegionTrees using StaticArrays: SVector using Plots ``` -------------------------------- ### Build an Adaptively Sampled Distance Field Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt A complete example showing how to build an ASDF using a custom refinery that checks error at body and face centers. ```julia using RegionTrees using StaticArrays using LinearAlgebra # Define a signed distance function for a circle circle_sdf(x) = norm(x - SVector(0.0, 0.0)) - 0.5 # Custom refinery for signed distance fields struct ASDFRefinery <: AbstractRefinery sdf::Function atol::Float64 # absolute tolerance rtol::Float64 # relative tolerance min_size::Float64 end function RegionTrees.needs_refinement(r::ASDFRefinery, cell::Cell) # Stop if cell is too small minimum(cell.boundary.widths) < r.min_size && return false # Check error at body and face centers for point in body_and_face_centers(cell.boundary) true_value = r.sdf(point) # Use cell data as the approximation approx_value = cell.data error = abs(true_value - approx_value) if error > r.atol && error > r.rtol * abs(true_value) return true end end return false end function RegionTrees.refine_data(r::ASDFRefinery, cell::Cell, indices) child_c = center(child_boundary(cell, indices)) r.sdf(child_c) end # Build the ASDF origin = SVector(-1.0, -1.0) widths = SVector(2.0, 2.0) boundary = HyperRectangle(origin, widths) # Initialize root with SDF value at center root = Cell(boundary, circle_sdf(center(boundary))) # Create refinery and run adaptive sampling refinery = ASDFRefinery(circle_sdf, 0.02, 0.02, 0.01) adaptivesampling!(root, refinery) # Query the ASDF function query_asdf(tree, point) leaf = findleaf(tree, point) return leaf.data end # Test queries println("SDF at origin: ", query_asdf(root, SVector(0.0, 0.0))) # ≈ -0.5 println("SDF at (0.5, 0): ", query_asdf(root, SVector(0.5, 0.0))) # ≈ 0.0 println("SDF at (1, 0): ", query_asdf(root, SVector(0.9, 0.0))) # ≈ 0.4 # Statistics leaves = collect(allleaves(root)) cells = collect(allcells(root)) println("Total cells: ", length(cells)) println("Total leaves: ", length(leaves)) ``` -------------------------------- ### Import Dependencies Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Load the necessary modules for working with RegionTrees. ```julia using RegionTrees using StaticArrays: SVector using Plots ``` -------------------------------- ### Generate a Quadtree with Adaptive Sampling Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_mpc/adaptive_mpc.ipynb Initializes a HyperRectangle boundary and uses the adaptivesampling! function to refine the quadtree based on the MPC refinery. ```python boundary = RegionTrees.HyperRectangle(SVector(-10., -10), SVector(20., 20)) refinery = mpc.MPCRefinery() root = RegionTrees.Cell(boundary, mpc.refine_data(refinery, boundary)) adaptivesampling!(root, refinery) ``` -------------------------------- ### Activate Project Environment Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_distance_fields/adaptive_distances.ipynb Activates the current Julia project environment. Ensure you are in the project's root directory. ```julia using Pkg pkg"activate ." ``` -------------------------------- ### Navigate Tree Cells Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Demonstrates accessing children, navigating to parents, and handling the root cell's parent property. ```julia # Access children of a cell for child in children(root) println(child.boundary.origin) end # Navigate to parent deep_cell = root[1,1][1,1] println(parent(deep_cell) === root[1,1]) # true println(parent(parent(deep_cell)) === root) # true # Root has no parent println(parent(root)) # nothing ``` -------------------------------- ### Import StaticArrays and RegionTrees Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_distance_fields/adaptive_distances.ipynb Imports necessary libraries for static arrays and the RegionTrees package. StaticArrays provides efficient fixed-size arrays. ```julia import StaticArrays: SVector using RegionTrees ``` -------------------------------- ### Implement Custom Refinery Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Define a custom refinery type to control adaptive splitting. ```julia import RegionTrees: AbstractRefinery, needs_refinement, refine_data struct MyRefinery <: AbstractRefinery tolerance::Float64 end function needs_refinement(r::MyRefinery, cell) maximum(cell.boundary.widths) > r.tolerance end function refine_data(r::MyRefinery, cell::Cell, indices) boundary = child_boundary(cell, indices) "child with widths: $(boundary.widths)" end ``` -------------------------------- ### Create a Root Cell Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Initialize a basic Cell spanning from [0, 0] with length 1 along each axis. ```julia root = Cell(SVector(0., 0), SVector(1., 1)) ``` -------------------------------- ### Perform adaptive sampling on a root cell Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Initializes a refinery with a specified threshold and executes the adaptive sampling process on a root HyperRectangle. ```julia r = MyRefinery(0.05) root = Cell(SVector(0., 0), SVector(1., 1), "root") adaptivesampling!(root, r) ``` -------------------------------- ### Create Cell with Data Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Initialize a cell with a data payload. ```julia cell = Cell(SVector(0., 0), SVector(1., 1), "A") ``` -------------------------------- ### Simulate and Plot Approximate Controller Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_mpc/adaptive_mpc.ipynb Runs a simulation using the approximate controller and plots the resulting state trajectory. ```python t, q, v = simulate(approx_controller, 10.0, 0.0, 0.1, 10) ``` ```python plot(q, v, xlim=(-10, 10), ylim=(-10, 10), xlabel="q", ylabel="v", legend=nothing) ``` -------------------------------- ### Visualize Simulation Results Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_mpc/adaptive_mpc.ipynb Plots the state space portrait and time-series data for the simulation. ```julia # State space portrait of the solution, starting from q=10, v=0 plot(q, v, xlim=(-10, 10), ylim=(-10, 10), xlabel="q", ylabel="v", legend=nothing) ``` ```julia plot(t, q, xlabel="t", ylabel="q", legend=nothing) ``` ```julia plot(t, v, xlabel="t", ylabel="v", legend=nothing) ``` -------------------------------- ### adaptivesampling! - Automatic Tree Refinement Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Automatically refines a tree based on a refinery's criteria using a queue-based approach. ```APIDOC ## adaptivesampling! - Automatic Tree Refinement ### Description The `adaptivesampling!` function automatically refines a tree based on a refinery's criteria. It processes cells in a queue, splitting those that need refinement and adding their children to the queue. ### Method `adaptivesampling!(root::Cell, refinery::AbstractRefinery) ### Parameters - **root** (Cell) - The root cell of the tree to be refined. - **refinery** (AbstractRefinery) - An object implementing the `AbstractRefinery` interface. ### Request Example ```julia using RegionTrees using StaticArrays using LinearAlgebra # Define a signed distance function (distance from origin) signed_distance(x) = norm(x) - 0.5 # Circle of radius 0.5 # Create a root cell root = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0)) # Define a custom refinery struct DistanceRefinery <: AbstractRefinery max_distance_error::Float64 min_cell_size::Float64 end function RegionTrees.needs_refinement(refinery::DistanceRefinery, cell::Cell) minimum(cell.boundary.widths) < refinery.min_cell_size && return false c = center(cell) # Refine if the distance function varies significantly or if the cell is too large # This is a simplified example; a real implementation might check corners or use more sophisticated criteria return abs(signed_distance(c)) > 0.1 # Example criterion end function RegionTrees.refine_data(refinery::DistanceRefinery, cell::Cell, indices) child_center = center(child_boundary(cell, indices)) return signed_distance(child_center) end refinery = DistanceRefinery(0.1, 0.01) # Perform adaptive sampling adaptivesampling!(root, refinery) # Now 'root' tree is adaptively refined based on the signed_distance function ``` ``` -------------------------------- ### Implement MPC Module Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_mpc/adaptive_mpc.ipynb Defines the MPC problem for a double-integrator system and the MPCRefinery struct to interface with RegionTrees. ```julia module mpc using JuMP using Gurobi using StaticArrays using Interpolations using RegionTrees import RegionTrees: AbstractRefinery, needs_refinement, refine_data const env = Gurobi.Env() # Solve the MPC problem from a given initial position and velocity function run_mpc(q0, v0) model = Model(solver=GurobiSolver(env, OutputFlag=0)) num_time_steps = 10 dt = 0.1 u_limit = 3 C_q = 100 c_vfinal = 100 C_u = 1 @variable model q[1:num_time_steps] @variable model v[1:num_time_steps] @variable model u[1:num_time_steps] @constraint model [i=2:num_time_steps] q[i] == q[i-1] + v[i-1] * dt @constraint model [i=2:num_time_steps] v[i] == v[i-1] + u[i-1] * dt @constraint model u .<= u_limit @constraint model u .>= -u_limit @constraint model q[1] == q0 @constraint model v[1] == v0 @objective model Min C_q * sum{q[i]^2, i=1:num_time_steps} + c_vfinal * v[end]^2 + C_u * sum{u[i]^2, i=1:num_time_steps} solve(model) getvalue(q), getvalue(v), getvalue(u) end # The MPCRefinery provides enough behavior to implement the # RegionTrees AdaptiveSampling interface, which lets us generate # a quadtree of initial states and their corresponding MPC solutions. struct MPCRefinery <: AbstractRefinery end function evaluate(cell, point) p = (point - cell.boundary.origin) ./ cell.boundary.widths cell.data(p[1] + 1, p[2] + 1) end # A cell in the quadtree needs refinement if its interpolated solution # derived from its vertices is not a good fit for the true MPC solution # at its center and the center of each of its faces function needs_refinement(::MPCRefinery, cell) for x in body_and_face_centers(cell.boundary) value_interp = evaluate(cell, x) value_true = run_mpc(x[1], x[2])[3] if !isapprox(value_interp[1], value_true[1], rtol=1e-1, atol=1e-1) return true end end false end # The data element associated with a cell is a bilinear interpolation # of the MPC function evaluated at the vertices of the cell. function refine_data(r::MPCRefinery, cell::Cell, indices) refine_data(r, child_boundary(cell, indices)) end function refine_data(::MPCRefinery, boundary::HyperRectangle) f = v -> run_mpc(v[1], v[2])[3] interpolate(f.(vertices(boundary)), BSpline(Linear())) end end ``` -------------------------------- ### Sample Body and Face Centers Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Iterates over the center and face centers of a HyperRectangle, useful for adaptive refinement evaluation. ```julia using RegionTrees using StaticArrays rect = HyperRectangle(SVector(0.0, 0.0), SVector(2.0, 2.0)) # Iterate over body center and face centers for point in body_and_face_centers(rect) println(point) end # Output: # [1.0, 1.0] - body center # [0.0, 1.0] - left face center # [2.0, 1.0] - right face center # [1.0, 0.0] - bottom face center # [1.0, 2.0] - top face center # Length is 2*N + 1 (1 body + 2 faces per dimension) println(length(body_and_face_centers(rect))) # 5 for 2D ``` -------------------------------- ### Simulate Control Function Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_mpc/adaptive_mpc.ipynb Simulates the double-integrator system using the MPC controller. ```julia # Simulate a given control function for the double integerator # model. function simulate(controller, q0, v0, dt, timespan) num_time_steps = timespan / dt qs = [q0] vs = [v0] ts = [0.0] q = q0 v = v0 for t in 0:dt:(timespan) u = controller(t, q, v) q += v * dt v += u * dt push!(qs, q) push!(vs, v) push!(ts, t) end ts, qs, vs end ``` ```julia controller = (t, q, v) -> begin q, v, u = mpc.run_mpc(q, v) u[1] end ``` ```julia t, q, v = simulate(controller, 10.0, 0.0, 0.1, 10) ``` -------------------------------- ### Cell Navigation and Access Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Demonstrates how to access children and parents of cells within the RegionTrees structure. ```APIDOC ## Cell Navigation and Access ### Description This section covers accessing children of a cell and navigating to the parent cell. ### Accessing Children Iterate through the children of a cell using a `for` loop. ```julia # Access children of a cell for child in children(root) println(child.boundary.origin) end ``` ### Navigating to Parent Use the `parent()` function to get the parent of a cell. The root cell has no parent. ```julia # Navigate to parent deep_cell = root[1,1][1,1] println(parent(deep_cell) === root[1,1]) # true println(parent(parent(deep_cell)) === root) # true # Root has no parent println(parent(root)) # nothing ``` ``` -------------------------------- ### Plot Cells Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Visualize the current tree structure. ```julia plt = plot(xlim=(0, 1), ylim=(0, 1), legend=nothing) for leaf in allleaves(root) v = hcat(collect(vertices(leaf.boundary))...) plot!(plt, v[1,[1,2,4,3,1]], v[2,[1,2,4,3,1]]) end plt ``` -------------------------------- ### Automatic Tree Refinement Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Uses adaptivesampling! to refine the tree based on a provided refinery. ```julia using RegionTrees using StaticArrays using LinearAlgebra # Define a signed distance function (distance from origin) signed_distance(x) = norm(x) - 0.5 # Circle of radius 0.5 ``` -------------------------------- ### Define Custom Refinement Strategy Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Implements a custom refinery by extending AbstractRefinery with needs_refinement and refine_data. ```julia using RegionTrees using StaticArrays using LinearAlgebra # Define a custom refinery for adaptive function sampling struct FunctionRefinery <: AbstractRefinery f::Function max_error::Float64 min_cell_size::Float64 end # Determine if a cell needs to be split function RegionTrees.needs_refinement(refinery::FunctionRefinery, cell::Cell) # Don't split below minimum size minimum(cell.boundary.widths) < refinery.min_cell_size && return false # Check if function varies too much within cell c = center(cell) center_value = refinery.f(c) for vertex in vertices(cell) vertex_value = refinery.f(SVector(vertex...)) if abs(center_value - vertex_value) > refinery.max_error return true end end return false end # Compute data for child cells function RegionTrees.refine_data(refinery::FunctionRefinery, cell::Cell, indices) child_center = center(child_boundary(cell, indices)) refinery.f(child_center) end # Example usage f(x) = sin(x[1]) * cos(x[2]) refinery = FunctionRefinery(f, 0.1, 0.01) ``` -------------------------------- ### Define an Approximate Controller Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_mpc/adaptive_mpc.ipynb Creates a controller function that looks up the current state in the quadtree and evaluates the interpolation. ```python approx_controller = (t, q, v) -> begin x = [q, v] leaf = RegionTrees.findleaf(root, x) u = mpc.evaluate(leaf, x) u[1] end ``` -------------------------------- ### Visualize Quadtree Regions Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_mpc/adaptive_mpc.ipynb Iterates through all leaves in the quadtree to plot the boundaries of each region. ```python plt = plot(xlim=(-10, 10), ylim=(-10, 10), legend=nothing, grid=false) for cell in RegionTrees.allleaves(root) v = hcat(collect(RegionTrees.vertices(cell.boundary))...) plot!(v[1,[1,2,4,3,1]], v[2,[1,2,4,3,1]]) end plt ``` -------------------------------- ### Include and Use Adaptive Distance Fields Module Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_distance_fields/adaptive_distances.ipynb Includes the adaptive distance fields module and makes its functions available. This module provides functionality for adaptive sampling of distance fields. ```julia include("adaptive_distance_fields.jl") using .AdaptivelySampledDistanceFields: ASDF, evaluate ``` -------------------------------- ### Implement a Custom DistanceRefinery Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Defines a custom refinery that refines cells based on a distance function and tolerance, and demonstrates its usage with adaptivesampling!. ```julia struct DistanceRefinery <: AbstractRefinery distance_func::Function tolerance::Float64 min_size::Float64 end function RegionTrees.needs_refinement(r::DistanceRefinery, cell::Cell) minimum(cell.boundary.widths) < r.min_size && return false # Refine if the zero-crossing might be in this cell d_center = abs(r.distance_func(center(cell))) cell_radius = norm(cell.boundary.widths) / 2 return d_center < cell_radius + r.tolerance end function RegionTrees.refine_data(r::DistanceRefinery, cell::Cell, indices) child_c = center(child_boundary(cell, indices)) r.distance_func(child_c) end # Create root cell and run adaptive sampling root = Cell( HyperRectangle(SVector(-1.0, -1.0), SVector(2.0, 2.0)), signed_distance(SVector(0.0, 0.0)) ) refinery = DistanceRefinery(signed_distance, 0.01, 0.05) adaptivesampling!(root, refinery) # The tree is now adaptively refined around the circle boundary println("Total leaves: ", length(collect(allleaves(root)))) ``` -------------------------------- ### Import Plots Package Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_distance_fields/adaptive_distances.ipynb Imports the Plots package for data visualization. This is required for creating plots and visualizations. ```julia using Plots ``` -------------------------------- ### Iterate Over All Cells Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Uses breadth-first traversal to visit every cell in the tree. ```julia using RegionTrees using StaticArrays # Create a tree with multiple levels root = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0)) split!(root) split!(root[1,1]) # Iterate over all cells cell_count = 0 for cell in allcells(root) cell_count += 1 println("Cell at $(cell.boundary.origin), leaf=$(isleaf(cell))") end println("Total cells: $cell_count") # 1 root + 4 children + 4 grandchildren = 9 ``` -------------------------------- ### children and parent - Tree Navigation Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Navigate the tree structure by accessing a cell's children or parent reference. ```APIDOC ## children and parent - Tree Navigation ### Description Navigate the tree structure by accessing a cell's children or parent reference. ### Usage Example ```julia using RegionTrees using StaticArrays # Create a nested tree structure root = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0)) split!(root) split!(root[1,1]) # Split the first child ``` ``` -------------------------------- ### Split with Data Generator Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Use a function to generate data for children dynamically. ```julia c = Cell(SVector(0., 0), SVector(1., 1), "root") function getdata(cell, child_indices) "$(cell.data) child $(child_indices)" end split!(c, getdata) split!(c[1,1], getdata) split!(c[1,2], getdata) split!(c[1,2][2,2], getdata) c[1,2][2,2][1,1].data ``` -------------------------------- ### Navigate Region Tree Children and Parent in Julia Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Allows navigation through the tree structure by accessing a cell's children or its parent reference. Essential for traversing and manipulating the tree. ```julia using RegionTrees using StaticArrays # Create a nested tree structure root = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0)) split!(root) split!(root[1,1]) # Split the first child ``` -------------------------------- ### Retrieve HyperRectangle Face Vertices Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Shows how to group vertices by each face of a HyperRectangle using the faces function. ```julia using RegionTrees using StaticArrays rect = HyperRectangle(SVector(0.0, 0.0, 0.0), SVector(1.0, 1.0, 1.0)) f = faces(rect) # In 3D, there are 6 faces (2 per dimension) # Each face contains 4 vertices for face in f println("Face vertices: $face") end ``` -------------------------------- ### Retrieve HyperRectangle Vertices Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Demonstrates how to extract all corner vertices of a HyperRectangle using the vertices function. ```julia using RegionTrees using StaticArrays # 3D bounding box rect = HyperRectangle(SVector(-1.0, -2.0, -3.0), SVector(2.0, 4.0, 6.0)) v = vertices(rect) # Access vertices by index println(v[1,1,1]) # [-1.0, -2.0, -3.0] - minimum corner println(v[2,2,2]) # [1.0, 2.0, 3.0] - maximum corner println(v[2,1,1]) # [1.0, -2.0, -3.0] - x-max, y-min, z-min ``` -------------------------------- ### Split with Custom Data Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Provide specific data for each child during a split. ```julia split!(cell, ["B", "C", "D", "E"]) cell[1,1].data cell[2,1].data ``` -------------------------------- ### Verify Children Count Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Assert that the cell has been split into four children. ```julia @assert length(children(root)) == 4 ``` -------------------------------- ### Create and Use HyperRectangle in Julia Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Defines an N-dimensional axis-aligned bounding box. Use HyperRectangle for defining spatial boundaries of cells in region trees. Supports origin and widths vectors, and provides functions for center and vertices. ```julia using RegionTrees using StaticArrays # Create a 2D rectangle (origin at (-1, -1), size 2x2) rect_2d = HyperRectangle(SVector(-1.0, -1.0), SVector(2.0, 2.0)) # Create a 3D bounding box rect_3d = HyperRectangle(SVector(-1.0, -2.0, -3.0), SVector(2.0, 4.0, 6.0)) # Access properties println(rect_3d.origin) # SVector(-1.0, -2.0, -3.0) println(rect_3d.widths) # SVector(2.0, 4.0, 6.0) # Get the center point c = center(rect_3d) # Returns SVector(0.0, 0.0, 0.0) # Get all vertices (corners) of the rectangle v = vertices(rect_3d) # v[1,1,1] == [-1, -2, -3] (minimum corner) # v[2,2,2] == [1, 2, 3] (maximum corner) ``` -------------------------------- ### Split Cell into Children in Julia Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Subdivides a leaf cell into 2^N children. Use split! to create a hierarchical structure. Data for children can be provided as an array or a function. If no data is specified, parent data is inherited. ```julia using RegionTrees using StaticArrays # Create a 3D cell cell = Cell(SVector(-1.0, -2.0, -3.0), SVector(2.0, 4.0, 6.0), 0) # Split with explicit data array (8 children in 3D) split!(cell, [1, 2, 3, 4, 5, 6, 7, 8]) # After splitting, cell is no longer a leaf println(isleaf(cell)) # false # Access children using indices println(cell[1,1,1].data) # 1 println(cell[2,1,1].data) # 2 println(cell[2,2,2].data) # 8 # Children have proper boundary relationships println(cell[1,1,1].boundary.origin) # Same as parent origin println(cell[2,2,2].boundary.origin + cell[2,2,2].boundary.widths) # Same as parent's far corner # Split with a function (receives cell and indices) cell2d = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0)) split!(cell2d, (c, indices) -> sum(indices)) # Split without specifying data (inherits parent data) cell3 = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0), "inherited") split!(cell3) # All children get "inherited" as data ``` -------------------------------- ### Split a Cell Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Refine a cell by splitting it into children. ```julia split!(root) ``` -------------------------------- ### AbstractRefinery - Custom Refinement Strategy Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Defines an abstract type for creating custom adaptive sampling strategies by implementing `needs_refinement` and `refine_data`. ```APIDOC ## AbstractRefinery - Custom Refinement Strategy ### Description The `AbstractRefinery` is an abstract type for defining custom adaptive sampling strategies. Implement `needs_refinement` and `refine_data` methods to create your own refinery. ### Example Usage ```julia using RegionTrees using StaticArrays using LinearAlgebra # Define a custom refinery for adaptive function sampling struct FunctionRefinery <: AbstractRefinery f::Function max_error::Float64 min_cell_size::Float64 end # Determine if a cell needs to be split function RegionTrees.needs_refinement(refinery::FunctionRefinery, cell::Cell) # Don't split below minimum size minimum(cell.boundary.widths) < refinery.min_cell_size && return false # Check if function varies too much within cell c = center(cell) center_value = refinery.f(c) for vertex in vertices(cell) vertex_value = refinery.f(SVector(vertex...)) if abs(center_value - vertex_value) > refinery.max_error return true end end return false end # Compute data for child cells function RegionTrees.refine_data(refinery::FunctionRefinery, cell::Cell, indices) child_center = center(child_boundary(cell, indices)) refinery.f(child_center) end # Example usage f(x) = sin(x[1]) * cos(x[2]) refinery = FunctionRefinery(f, 0.1, 0.01) ``` ``` -------------------------------- ### Access Nested Children Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Access children of children using nested indexing. ```julia root[1,1][1,1] root[1,1][1,2] ``` -------------------------------- ### Define and Initialize Adaptive Distance Field Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_distance_fields/adaptive_distances.ipynb Defines a distance function `s` and initializes an Adaptive Sampled Distance Field (ASDF) with the function and bounds. The function calculates the Euclidean distance from a point to the origin. ```julia s = x -> sqrt(sum((x - SVector(0, 0)).^2)) adf = ASDF(s, SVector(-1., -1), SVector(2., 2)) ``` -------------------------------- ### Iterate Over Ancestors Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Traverses upwards from a specific cell to the root. ```julia using RegionTrees using StaticArrays # Create a deep tree root = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0)) split!(root) split!(root[1,1]) # Get all parents of a deep cell deep_cell = root[1,1][1,2] parents = collect(allparents(deep_cell)) println(length(parents)) # 2 (immediate parent + root) println(parents[1] === root[1,1]) # true println(parents[2] === root) # true # Root has no parents root_parents = collect(allparents(root)) println(length(root_parents)) # 0 ``` -------------------------------- ### Check Cell Type Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Inspect the type of the cell, which includes the data payload type. ```julia typeof(cell) ``` -------------------------------- ### Check Leaf Status Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Verify if a cell is a leaf node. ```julia isleaf(root) ``` -------------------------------- ### Tree Iteration Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Functions for iterating over cells within a RegionTrees tree. ```APIDOC ## Tree Iteration ### allcells - Iterate Over All Cells #### Description The `allcells` function returns a channel that yields all cells in the tree (both internal nodes and leaves) via breadth-first traversal. #### Method `allcells(root::Cell) #### Parameters - **root** (Cell) - The root cell of the tree. #### Request Example ```julia using RegionTrees using StaticArrays # Create a tree with multiple levels root = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0)) split!(root) split!(root[1,1]) # Iterate over all cells cell_count = 0 for cell in allcells(root) cell_count += 1 println("Cell at $(cell.boundary.origin), leaf=$(isleaf(cell))") end println("Total cells: $cell_count") # 1 root + 4 children + 4 grandchildren = 9 ``` ### allleaves - Iterate Over Leaf Cells Only #### Description The `allleaves` function returns a channel that yields only the leaf cells (cells with no children) in the tree. #### Method `allleaves(root::Cell) #### Parameters - **root** (Cell) - The root cell of the tree. #### Request Example ```julia using RegionTrees using StaticArrays # Create a partially split tree root = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0)) split!(root) split!(root[1,1]) # Only split one child # Collect all leaves leaves = collect(allleaves(root)) println(length(leaves)) # 7 leaves (3 unsplit children + 4 grandchildren) # Process all leaves for leaf in allleaves(root) @assert isleaf(leaf) println("Leaf boundary: $(leaf.boundary)") end ``` ### allparents - Iterate Over Ancestors #### Description The `allparents` function returns a channel that yields all ancestor cells of a given cell, starting from the immediate parent up to the root. #### Method `allparents(cell::Cell) #### Parameters - **cell** (Cell) - The cell for which to find parents. #### Request Example ```julia using RegionTrees using StaticArrays # Create a deep tree root = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0)) split!(root) split!(root[1,1]) # Get all parents of a deep cell deep_cell = root[1,1][1,2] parents = collect(allparents(deep_cell)) println(length(parents)) # 2 (immediate parent + root) println(parents[1] === root[1,1]) # true println(parents[2] === root) # true # Root has no parents root_parents = collect(allparents(root)) println(length(root_parents)) # 0 ``` ``` -------------------------------- ### Create and Use Cell in Julia Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Represents a node in a region tree, containing a boundary, data payload, and child/parent references. Use Cell for building hierarchical spatial structures. Can be a leaf or an internal node. ```julia using RegionTrees using StaticArrays # Create a root cell with origin, widths, and optional data payload root = Cell(SVector(-1.0, -2.0, -3.0), SVector(2.0, 4.0, 6.0), "my_data") # Alternative: create from a HyperRectangle boundary = HyperRectangle(SVector(0.0, 0.0), SVector(1.0, 1.0)) cell = Cell(boundary, 42) # Data payload is the integer 42 # Access cell properties println(cell.boundary.origin) # SVector(0.0, 0.0) println(cell.boundary.widths) # SVector(1.0, 1.0) println(cell.data) # 42 # Check if cell is a leaf (no children) println(isleaf(cell)) # true # Get center and vertices println(center(cell)) # SVector(0.5, 0.5) println(vertices(cell)) # All corner points ``` -------------------------------- ### Plot Adaptive Distance Field and Tree Leaves Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/adaptive_distance_fields/adaptive_distances.ipynb Generates a contour plot of the adaptive distance field and overlays the boundaries of the tree leaves. This visualization helps understand the spatial partitioning and sampling. ```julia plt = plot(xlim=(-1, 1), ylim=(-1, 1), legend=nothing) x = range(-1, stop=1, length=50) y = range(-1, stop=1, length=50) contour!(plt, x, y, (x, y) -> evaluate(adf, SVector(x, y)), fill=true) for leaf in allleaves(adf) v = hcat(collect(vertices(leaf.boundary))...) plot!(plt, v[1,[1,2,4,3,1]], v[2,[1,2,4,3,1]], color=:white) end plt ``` -------------------------------- ### Access Cell Data Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Retrieve the data payload from a cell. ```julia cell.data ``` -------------------------------- ### child_boundary - Compute Child Boundary Before Split Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Computes the boundary of a child cell at given indices without actually splitting the cell. ```APIDOC ## child_boundary - Compute Child Boundary Before Split ### Description The `child_boundary` function computes what the boundary of a child cell would be at given indices, without actually splitting the cell. ### Method `child_boundary(cell::Cell, indices::Tuple{Vararg{Int}}) ### Parameters - **cell** (Cell) - The parent cell. - **indices** (Tuple{Vararg{Int}}) - The indices of the child cell (e.g., (1,1)). ### Request Example ```julia using RegionTrees using StaticArrays cell = Cell(SVector(0.0, 0.0), SVector(2.0, 2.0)) # Get boundary for child at indices (1,1) - lower-left quadrant child_rect = child_boundary(cell, (1, 1)) println(child_rect.origin) # SVector(0.0, 0.0) println(child_rect.widths) # SVector(1.0, 1.0) # Get boundary for child at indices (2,2) - upper-right quadrant child_rect2 = child_boundary(cell, (2, 2)) println(child_rect2.origin) # SVector(1.0, 1.0) println(child_rect2.widths) # SVector(1.0, 1.0) ``` ### Response Example ```julia # Output for child_rect: # SVector{2, Float64}(0.0, 0.0) # SVector{2, Float64}(1.0, 1.0) # Output for child_rect2: # SVector{2, Float64}(1.0, 1.0) # SVector{2, Float64}(1.0, 1.0) ``` ``` -------------------------------- ### Cell - Tree Node with Data Payload Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt The primary building block of a region tree. Each cell contains a boundary (HyperRectangle), an arbitrary data payload, and references to its children (if split) and parent. Cells can be leaves or internal nodes. ```APIDOC ## Cell - Tree Node with Data Payload ### Description The `Cell` struct is the primary building block of a region tree. Each cell contains a boundary (HyperRectangle), an arbitrary data payload, and references to its children (if split) and parent. Cells can be leaves or internal nodes. ### Usage Example ```julia using RegionTrees using StaticArrays # Create a root cell with origin, widths, and optional data payload root = Cell(SVector(-1.0, -2.0, -3.0), SVector(2.0, 4.0, 6.0), "my_data") # Alternative: create from a HyperRectangle boundary = HyperRectangle(SVector(0.0, 0.0), SVector(1.0, 1.0)) cell = Cell(boundary, 42) # Data payload is the integer 42 # Access cell properties println(cell.boundary.origin) # SVector(0.0, 0.0) println(cell.boundary.widths) # SVector(1.0, 1.0) println(cell.data) # 42 # Check if cell is a leaf (no children) println(isleaf(cell)) # true # Get center and vertices println(center(cell)) # SVector(0.5, 0.5) println(vertices(cell)) # All corner points ``` ``` -------------------------------- ### Iterate Over Leaf Cells Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Retrieves only the leaf nodes of the tree. ```julia using RegionTrees using StaticArrays # Create a partially split tree root = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0)) split!(root) split!(root[1,1]) # Only split one child # Collect all leaves leaves = collect(allleaves(root)) println(length(leaves)) # 7 leaves (3 unsplit children + 4 grandchildren) # Process all leaves for leaf in allleaves(root) @assert isleaf(leaf) println("Leaf boundary: $(leaf.boundary)") end ``` -------------------------------- ### split! - Subdivide a Cell Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Divides a leaf cell into 2^N children (4 children in 2D, 8 in 3D). You can provide data for each child cell using an array or a function. ```APIDOC ## split! - Subdivide a Cell ### Description The `split!` function divides a leaf cell into 2^N children (4 children in 2D, 8 in 3D). You can provide data for each child cell using an array or a function. ### Usage Example ```julia using RegionTrees using StaticArrays # Create a 3D cell cell = Cell(SVector(-1.0, -2.0, -3.0), SVector(2.0, 4.0, 6.0), 0) # Split with explicit data array (8 children in 3D) split!(cell, [1, 2, 3, 4, 5, 6, 7, 8]) # After splitting, cell is no longer a leaf println(isleaf(cell)) # false # Access children using indices println(cell[1,1,1].data) # 1 println(cell[2,1,1].data) # 2 println(cell[2,2,2].data) # 8 # Children have proper boundary relationships println(cell[1,1,1].boundary.origin) # Same as parent origin println(cell[2,2,2].boundary.origin + cell[2,2,2].boundary.widths) # Same as parent's far corner # Split with a function (receives cell and indices) cell2d = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0)) split!(cell2d, (c, indices) -> sum(indices)) # Split without specifying data (inherits parent data) cell3 = Cell(SVector(0.0, 0.0), SVector(1.0, 1.0), "inherited") split!(cell3) # All children get "inherited" as data ``` ``` -------------------------------- ### Access Child Cells Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Access specific child cells using indexing or the children function. ```julia root[1,1] children(root)[1,1] ``` -------------------------------- ### Compute Child Boundary Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Calculates the boundary of a potential child cell without performing a split operation. ```julia using RegionTrees using StaticArrays cell = Cell(SVector(0.0, 0.0), SVector(2.0, 2.0)) # Get boundary for child at indices (1,1) - lower-left quadrant child_rect = child_boundary(cell, (1, 1)) println(child_rect.origin) # SVector(0.0, 0.0) println(child_rect.widths) # SVector(1.0, 1.0) # Get boundary for child at indices (2,2) - upper-right quadrant child_rect2 = child_boundary(cell, (2, 2)) println(child_rect2.origin) # SVector(1.0, 1.0) println(child_rect2.widths) # SVector(1.0, 1.0) ``` -------------------------------- ### Access leaf node data Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Retrieves the data stored within a specific nested leaf node of the tree structure. ```julia root[1,1][1,1][1,1][1,1][1,1].data ``` -------------------------------- ### HyperRectangle - N-Dimensional Bounding Box Source: https://context7.com/juliageometry/regiontrees.jl/llms.txt Represents an N-dimensional axis-aligned bounding box defined by an origin point and width vector. It serves as the fundamental spatial boundary for cells in the region tree. ```APIDOC ## HyperRectangle - N-Dimensional Bounding Box ### Description The `HyperRectangle` struct represents an N-dimensional axis-aligned bounding box defined by an origin point and width vector. It serves as the fundamental spatial boundary for cells in the region tree. ### Usage Example ```julia using RegionTrees using StaticArrays # Create a 2D rectangle (origin at (-1, -1), size 2x2) rect_2d = HyperRectangle(SVector(-1.0, -1.0), SVector(2.0, 2.0)) # Create a 3D bounding box rect_3d = HyperRectangle(SVector(-1.0, -2.0, -3.0), SVector(2.0, 4.0, 6.0)) # Access properties println(rect_3d.origin) # SVector(-1.0, -2.0, -3.0) println(rect_3d.widths) # SVector(2.0, 4.0, 6.0) # Get the center point c = center(rect_3d) # Returns SVector(0.0, 0.0, 0.0) # Get all vertices (corners) of the rectangle v = vertices(rect_3d) # v[1,1,1] == [-1, -2, -3] (minimum corner) # v[2,2,2] == [1, 2, 3] (maximum corner) ``` ``` -------------------------------- ### Refine Child Cell Source: https://github.com/juliageometry/regiontrees.jl/blob/master/examples/demo/demo.ipynb Perform a split on a specific child cell. ```julia split!(root[1,1]) ```