Source code for pyvcad_metamaterials.grading

"""Map-first material grading helpers for architected structures."""

# Third-party
from numba import cfunc, types

# OpenVCAD
import pyvcad as pv

# Local
from .lattices import _unit_cell, graph_lattice
from .tpms import tpms


_SIGNATURE = types.float64(types.float64, types.float64, types.float64, types.float64)


[docs] def skin_core_tpms( cell_map, skin_material, core_material, kind="gyroid", wall_thickness=2.0, skin_ratio=0.35, transition=0.15, ): """Build a mapped TPMS with material graded through each wall's depth.""" if not 0.0 <= skin_ratio <= 1.0: raise ValueError("skin_ratio must lie between zero and one") if not isinstance(wall_thickness, (int, float)): raise TypeError("skin_core_tpms currently requires constant wall_thickness") node = tpms(cell_map, kind, wall_thickness=wall_thickness) threshold = -0.5 * float(wall_thickness) * float(skin_ratio) band = max(float(transition), 1e-6) @cfunc(_SIGNATURE) def skin_fraction(x, y, z, d): value = (d - threshold) / band + 0.5 return min(1.0, max(0.0, value)) @cfunc(_SIGNATURE) def core_fraction(x, y, z, d): value = (d - threshold) / band + 0.5 return 1.0 - min(1.0, max(0.0, value)) node.set_attribute( pv.DefaultAttributes.VOLUME_FRACTIONS, pv.VolumeFractionsAttribute([ (skin_fraction, int(skin_material)), (core_fraction, int(core_material)), ]), ) return node
[docs] def per_strut_material(cell_map, unit_cell, selector, beam_radius=0.8, node_radius=None): """Assign native material tags to unit-cell edges selected by orientation or position.""" graph = _unit_cell(unit_cell) tags = [int(selector(graph.vertices[a], graph.vertices[b])) for a, b in graph.edges] tagged = pv.GraphUnitCell( graph.vertices, graph.edges, vertex_tags=graph.vertex_tags, edge_tags=graph.edge_tags, orientation_tags=graph.orientation_tags, material_tags=tags, ) return graph_lattice(cell_map, tagged, beam_radius=beam_radius, node_radius=node_radius)