Attributes ========== In **attribute modeling**, attributes are typed spatial fields. They acquire a name only when attached to a node in your ``Node`` tree. They describe quantities that vary through the interior of a part—modulus, color, material volume fractions, and more—using the same sampling idea as implicit geometry: at each point, the engine evaluates whether you are inside the solid and, when you are, evaluates the attached fields at that location. Conceptually, each attribute implements a **sample** at ``(x, y, z)`` together with the signed distance ``d`` to the surface. Expression strings (see the math expressions guide) can use coordinates and ``d``; results are aggregated under string names so renderers and compilers can pick them up consistently. **Interface you use in Python** * Attach fields to geometry with ``node.set_attribute(name, attribute)``. * Use **canonical names** from ``DefaultAttributes`` (e.g. ``MODULUS``, ``COLOR_RGBA``, ``VOLUME_FRACTIONS``) so downstream tools know which field to read. * **``FloatAttribute``** — one scalar per point (physical scalars, temperatures, etc.). * **``Vec3Attribute``** — three components per point, with composition methods for directions and displacements. * **``Vec4Attribute``** — four components per point (typical use: linear RGBA in ``[0, 1]``). * **``VolumeFractionsAttribute``** — maps material IDs to fractions at each point; fractions should sum to 1 where mixtures apply. * Python function support is **Numba-only**. Use ``numba.cfunc`` with the signature ``float64(float64, float64, float64, float64)``. Attributes are only evaluated where the geometry exists (inside or on the surface), so expensive expressions are not run in empty space. Examples -------- The patterns below mirror the getting-started guide (lessons 4–6); they show the minimal attach-and-name workflow. **Scalar field (constant or expression)** .. code-block:: python import pyvcad as pv cube = pv.RectPrism(pv.Vec3(0, 0, 0), pv.Vec3(10, 10, 10)) cube.set_attribute(pv.DefaultAttributes.MODULUS, pv.FloatAttribute(5.0)) cube = pv.RectPrism(pv.Vec3(0, 0, 0), pv.Vec3(10, 10, 50)) cube.set_attribute( pv.DefaultAttributes.MODULUS, pv.FloatAttribute("0.18 * z + 5.5"), ) **Scalar field (Numba function)** .. code-block:: python import pyvcad as pv from numba import cfunc, types @cfunc(types.float64(types.float64, types.float64, types.float64, types.float64)) def modulus_gradient(x, y, z, d): return 0.18 * z + 5.5 cube = pv.RectPrism(pv.Vec3(0, 0, 0), pv.Vec3(10, 10, 50)) cube.set_attribute( pv.DefaultAttributes.MODULUS, pv.FloatAttribute(modulus_gradient), ) **RGBA color field** .. code-block:: python cube = pv.RectPrism(pv.Vec3(0, 0, 0), pv.Vec3(50, 10, 10)) color = pv.Vec4Attribute("x/50 + 0.5", "-x/50 + 0.5", "x/50 + 0.5", "1.0") cube.set_attribute(pv.DefaultAttributes.COLOR_RGBA, color) **Volume fractions (multi-material)** .. code-block:: python materials = pv.default_materials cube = pv.RectPrism(pv.Vec3(0, 0, 0), pv.Vec3(50, 10, 10)) cube.set_attribute( pv.DefaultAttributes.VOLUME_FRACTIONS, pv.VolumeFractionsAttribute( [ ("x/50 + 0.5", materials.id("blue")), ("-x/50 + 0.5", materials.id("red")), ] ), ) See :ref:`guide-getting-started` for full lessons, hierarchy/priority rules, and expression details. See also the Python functions guide at :doc:`/guides/numba-attributes`. .. currentmodule:: pyvcad Core types ---------- .. autoclass:: Attribute :members: :undoc-members: :special-members: __init__ .. autoclass:: FloatAttribute :members: :undoc-members: :special-members: __init__ .. autoclass:: Vec3Attribute :members: :undoc-members: :special-members: __init__ .. autoclass:: Vec4Attribute :members: :undoc-members: :special-members: __init__ .. autoclass:: VolumeFractionsAttribute :members: :undoc-members: :special-members: __init__ .. autoclass:: DerivedFloatAttribute :members: :undoc-members: :special-members: __init__ .. autoclass:: AttributeSamples :members: :undoc-members: :special-members: __init__ Converters ^^^^^^^^^^ .. autoclass:: AttributeConverterBase :members: :undoc-members: :special-members: __init__ .. autoclass:: LookupTableEntry :members: :undoc-members: :special-members: __init__ .. autoclass:: LookupTableConverter :members: :undoc-members: :special-members: __init__ .. autoclass:: ExpressionConverter :members: :undoc-members: :special-members: __init__ .. _pyvcad-default-attribute-names-and-types: Default attribute names and types --------------------------------- Use these **name** strings with :meth:`Node.set_attribute` so compilers, renderers, and your own code agree on which field is which. Each ``*_TYPE`` value is the :class:`Attribute.ReturnType` that matches the corresponding name. .. module:: pyvcad.DefaultAttributes .. rubric:: Name strings .. py:data:: NONE :type: str :annotation: = 'none' .. py:data:: MODULUS :type: str :annotation: = 'modulus' .. py:data:: TOUGHNESS :type: str :annotation: = 'toughness' .. py:data:: ELONGATION :type: str :annotation: = 'elongation' .. py:data:: SHORE_HARDNESS :type: str :annotation: = 'shore_hardness' .. py:data:: TEMPERATURE :type: str :annotation: = 'temperature' .. py:data:: HU :type: str :annotation: = 'hu' .. py:data:: VOLUME_FRACTIONS :type: str :annotation: = 'volume_fractions' .. py:data:: COLOR_RGBA :type: str :annotation: = 'color_rgba' .. py:data:: COLOR_RGB :type: str :annotation: = 'color_rgb' .. py:data:: DENSITY :type: str :annotation: = 'density' .. py:data:: INFILL_DENSITY :type: str :annotation: = 'infill_density' .. py:data:: FUZZY_SKIN_POINT_DISTANCE :type: str :annotation: = 'fuzzy_skin_point_distance' .. py:data:: FUZZY_SKIN_THICKNESS :type: str :annotation: = 'fuzzy_skin_thickness' .. py:data:: FLOW_RATE :type: str :annotation: = 'flow_rate' .. rubric:: Return-type helpers .. py:data:: MODULUS_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.dbl .. py:data:: TOUGHNSS_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.dbl .. py:data:: ELONGATION_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.dbl .. py:data:: SHORE_HARDNESS_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.dbl .. py:data:: TEMPERATURE_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.dbl .. py:data:: HU_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.dbl .. py:data:: VOLUME_FRACTIONS_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.vfm_ptr .. py:data:: COLOR_RGBA_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.vec4 .. py:data:: COLOR_RGB_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.vec3 .. py:data:: DENSITY_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.dbl .. py:data:: INFILL_DENSITY_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.dbl .. py:data:: FUZZY_SKIN_POINT_DISTANCE_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.dbl .. py:data:: FUZZY_SKIN_THICKNESS_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.dbl .. py:data:: FLOW_RATE_TYPE :type: Attribute.ReturnType :annotation: = Attribute.ReturnType.dbl .. rubric:: Functions .. autofunction:: get_return_type_by_name