Attributes
Attributes map handles to mesh elements (e.g., to a vertex) to values (e.g., a vertex position). They are realized as a list of vectors of same size: if a new element is pushed, all vectors for this element grow simultaneously. Attributes can be disabled and enabled. Disabled attributes remain unchanged while enabled attributes grow.
Note that an efficient implementation of attribute lists may define a particular type for this list (as a named tuple). This requires that all attributes must be defined during initialization (i.e., there is no way to add attributes later). Disable attributes that are currently not required.
Indexing
Attributes are indexed by handles, tuples of handles, arrays of handles, or generators (that yield handles):
# Let ma be a managed attribute list and x one of its attributes.
# Let ma be index by handles of type H.
h = H(1)
x[h] == 0 # read single
x[h] = 1 # write single
#= read multiple
x[(h,h)] # yields tuples (x[h], x[h])
x[[h,h]] # yields array [x[h], x[h]]
sum(x[used(ma)]) # sums x for all handles generated by used(ma)
x[used(ma)] # yields generator
#= write multiple
i = H(2)
x[(h, i)] = 1
x[(h, i)] = (1,2)
x[[h, i]] = [1,2]
x[used(ma)] = 1
x[used(ma)] = 1:n_used(ma)
Base.empty!
— Methodempty!(ma::ManagedAttributes)
Remove all elements.
Base.similar
— MethodCreate attribute of same type and state but empty vector.
Base.sizehint!
— MethodApply Base.sizehint!
to all enabled attributes.
Base.vec
— Methodv = vec(a)
Reference vector data of a
.
PMeshAttributes.attrlength
— MethodGet number of entries in attributes. This is the length
of [vec](@ref)(attr)
for any enabled attribute attr
in a
.
length(a)
gives the number of attributes in a
.
PMeshAttributes.attrspecs
— Functions = attrspecs(a::Attribute)
s = attrspecs(attrs::Attributes)
Query specifications for single attribute a
or list of Attributes
. The returned specifications can be used with constructors createattribute
and createattributes
.
The second form returns a NamedTuple
or Vector{Pair}
depending on the type of Attributes
.
attrspecs
doesn't include the indextype
!
See also specifyattr
PMeshAttributes.clone
— Functionnewattrs = clone(attrs::Attributes)
Create identical copy of attrs
but don't copy data for disabled attributes.
PMeshAttributes.clone
— Methodanew = clone(a::Attribute)
Create identical copy (deepcopy
of vector) of enabled attribute, don;t copy vector data for disabled attribute.
PMeshAttributes.countunused
— Methodn = countunused(ma::ManagedAttributes)
Count – i.e., compute in O(n_total(ma))
– the number of unused elements.
See also countused
PMeshAttributes.countused
— Methodn = countused(ma::ManagedAttributes)
Count – i.e., compute in O(n_total(ma))
– the number of used elements.
See also countunused
PMeshAttributes.createattribute
— Functiona = createattribute(T[, h=Int; enabled=true, x0=zero(T))
a = createattribute((t::Type, enabled::Bool, x0)[, h=Int])
Create Attribute
of type T
and index type h
with default value x0
.
The second form creates an attribute from a specification tuple from specifyattr
.
See also Attribute
, attrspecs
, specifyattr
PMeshAttributes.createattributes
— Functiona = createattributes(:name => spec, ... [; htyp=Int])
a = createattributes((:name => spec, ...) [; htyp=Int])
a = createattributes([:name => spec, ...], [; htyp=Int])
a = createattributes(Dict(:name => spec, ...), [; htyp=Int])
Create Attributes
from list with common index/handle type htyp
. The two calls create NamedTuple
s, the second two calls create Dict
s.
The specification is given as a list (Tuple
or Vector
) or Pair
s or 2-Tuple
s. The preferred notation is Pair
s and :name => spec
(instead of (:name, spec)
.
The specification spec
for each attribute is either a single type (attribute is enabled with zero
default values, see Attribute
) or the result from specifyattr
.
See also specifyattr
, Attribute
PMeshAttributes.defaultvalue
— MethodQuery default value of Attribute
a
.
See also setdefaultvalue!
PMeshAttributes.enabled
— MethodQuery Dict
of enabled attributes.
PMeshAttributes.handles
— Methodfor h in handles(ma::ManagedAttributes[; i0 = I(1))
...
end
Generate all indices/handles from Int(i0)
to n_total
independent of isused
state.
PMeshAttributes.hasattr
— FunctionDoes attrs
include an attribute name
?
PMeshAttributes.indextype
— Methodindextype(a::Attributes)
Query index or handle type for a
.
PMeshAttributes.indices
— Methodis = indices(ma::ManagedAttributes[; i0 = I(1))
Integer range of all indices from Int(i0)
to n_total
indices
returns a UnitRange
, whereas handles
generates handles (of type I
) from integer indices.
See also handles
PMeshAttributes.initattr!
— Methodinitattr!(ma, n[, use=true)
Create n
elements with used
state.
Initializes empty ma
: requires n_total(ma) == 0
.
PMeshAttributes.isconsistent
— Methodsucccess = isconsistent(ma::ManagedAttributes)
Apply consistency checks, print diagnostic messages.
PMeshAttributes.isconsistent
— Methodresult::Bool = isconsistent(attrs)
Apply consistency checks.
PMeshAttributes.iscontiguous
— Methodiscontiguous(ma::ManagedAttributes)
Does ma
represent a sequence of elements that are all used, i.e., there are no "gaps" in the sequence used
.
PMeshAttributes.isenabled
— MethodPMeshAttributes.isindex
— Methodisindex(ma::ManagedAttributes, i)
Is i
a valid index to ma
, i.e., is it within the range from 1
to n_total
.
This is only a test on range and not on the used state.
See also isused
, isindexused
PMeshAttributes.isindexused
— Methodisindexused(ma::ManagedAttributes, i)
Does index i
refer to a used element? Tests used state for a valid index.
This method requires a valid index, i.e., isindex
PMeshAttributes.isunusedindex
— Methodisunusedindex(ma::ManagedAttributes, i)
Does index i
refer to an unused element? This implies isindex
and not isindexused
.
See also isindex
, isindexused
PMeshAttributes.isused
— Methodisused(ma::ManagedAttributes, i)
Does index i
refer to a used element? This implies isindex
and isindexused
.
See also isindex
, isindexused
, setused!
PMeshAttributes.n_total
— Methodn = n_total(ma::ManagedAttributes)
Get total number of – used and unsued – elements.
PMeshAttributes.nextunused
— Methodj = nextunused(predicate, ma::ManagedAttributes[, i0])
Get index of next used vertex from i0
.
PMeshAttributes.nextused
— Methodj = nextused(predicate, ma::ManagedAttributes[, i0])
Get index of next used vertex from i0
.
See also isused
, nextwith
, nextunused
PMeshAttributes.nextwith
— Methodj = nextwith(predicate, ma::ManagedAttributes[, i0])
Get next index from i0
that satisfies predicate(ma, i0)
. Returns invalid handle I(0)
if no such handle exists.
The index i0
is a handle (type), and the method returns a handle.
See also nextused
PMeshAttributes.pushattr!
— MethodPush default value onto all enabled attributes.
PMeshAttributes.pushattr!
— Methodpushattr!(ma::ManagedAttributes[, use=true])
Push new elements with use
state.
PMeshAttributes.resizeattr!
— MethodResize all enabled attributes, grow with default values.
PMeshAttributes.setallused!
— MethodPMeshAttributes.setdefaultvalue!
— MethodSet default value of Attribute
a
used with pushattr!
and resizeattr!
.
PMeshAttributes.setenabled!
— Functionsetenabled!(attr[, state::Bool=true])
setenabled!(attrs, (:name, state::Bool); initialize=true)
setenabled!(attrs, dict::Dict{Symbol, Bool); initialize=true)
Set enabled state
for attribute name
or for all attributes name => state
in dict
. Fill with defaultvalue
if initialize==true
.
See also Attributes
, isenabled
, enabled
PMeshAttributes.setunused!
— Methodsetunused!(ma::ManagedAttributes, i)
Unset used state for element at index i
.
See also isused
, setunused!
PMeshAttributes.setused!
— Functionsetused!(ma::ManagedAttributes, i)
setused!(ma::ManagedAttributes, i, state::Bool)
Set (or unset) used state for element at index i
.
See also isused
, setunused!
PMeshAttributes.shrinkdisabled!
— Functionshrinkdisabled!(a)
shrinkdisabled!(attrs)
Replace vec(a)
by empty array if !isenabled(a)
. Apply to all attrs
.
PMeshAttributes.shrinkdisabled!
— Methodshrinkdisabled!(a::Attribute)
"Free" memory for data of any disabled attribute in a
: the data vector is replaced by a zero-length vector.
PMeshAttributes.specifyattr
— Methodspec = specifyattr(T [; enabled=true, x0=zero(T)])
Yields specification of an Attribute
for use with createattributes
. The returned spec
is a 3-Tuple
, possibly with with default values for the optional keyword arguments.
See also createattributes
, Attribute
PMeshAttributes.unused
— Methodfor h in unused(ma::ManagedAttributes)
...
end
Generate sequence of all unused elements.
PMeshAttributes.used
— Methodfor h in used(ma::ManagedAttributes)
...
end
Generate sequence of all used elements.
PMeshAttributes.Attribute
— Type# create an attribute with default value x0
a= createattribute(typ::Type{T}[, index::Type[; enabled=true, x0=zero(typ))
indextype(a) # query index type
eltype(a) # query element type T
isenabled(a)
vec(a) # get raw Vector{T}
length(a) # get length of vec(a)
sizehint!(a, n) # same as sizehint!(vec(a))
a[h] # access by index or handle
defaultvalue(a) # query default value
setdefaultvalue!(a)
An attribute of a mesh.
Attributes are stored for vertices, faces, half-edges and edges of a mesh. Whenever the number of elements (vertices or factes or ...) changes, all associated attributes change in size. Attributes can disabled such that they will not resize until they are enabled again.
Typically, one operates on a Dict
-like set of named Attributes
'.
Each attribute is vector-valued and stores per-element values, which can be accessed by indices or handles: pass Hnd
type as index
.
See also Attributes
PMeshAttributes.FlagsType
— TypeType for manage attribute flags.
PMeshAttributes.ManagedAttributes
— TypeSpecify abstract managed attribute with index/handle type I
.
Mapping attribute values
Attribute values can be map
ed by functions, i.e., one can construct "virtual read-only" attributes. Such mapped attributes can be evaluated using the same indexing as for attributes.
# x is an attribute, f and g are functions
fx = map(f, x)
fx[h] # is equivalent to f.(x[h])
fx = f ∘ x # is equivalent to map(f, x)
gfx = g ∘ fx # maps by g ∘ f
gfx[h] # is equivalent to g.(f.(x[h])) == g.(fx(h))
gfx = fx ∘ g # maps by f ∘ g
gfx[h] # is equivalent to f.(g.(x[h])) == f.(gx(h))
Note that for any composition with ∘
(from left or from right), the attribute is always evaluated first, i.e., you compose the mapping.
Base.map
— Methodfa = map(f, attr) x = fa[idx]
Combine reading attr
with a map f
. Think of fa
as a "read-only, virtual attribute".
Using map
as above is equivalent to
x = f.(attr[idx])
Composition can be used as a syntactic alternative or for composing maps, e.g.,
fa = f ∘ attr
x = fa[idx]
gfa = g ∘ fa
y = gfa[idx] # y == g.(f.(x)) == (g ∘ f).(x)
fga = fa ∘ g
y = fga[idx] # y == f.(g.(x)) == (f ∘ g).(x)
PMeshAttributes.MappedAttribute
— TypeMap attribute values