7. Tagging Mechanics
We discussed the basics of Monocurl animations, but theres still a few things that are awkward. Let me introduce a few problems to illustrate the benefit tags will bring.
7.1 Problems
- What if we're transforming something and it's not matching the way we want?
- What if we want to apply an operation to only some parts of a mesh-tree, and leave the rest unchanged?
- What if we want to apply an animation to a subset of mesh-tree?
7.2 Tags
It turns out, all of these can be solved via tags.
DEFINITION Every mesh in a mesh-tree has an associated tag, which is just a vector of numbers.
The key idea is that this allows us to easily pick subsets because we can look at a given mesh's tag and decide if we want the operation to apply to the mesh or not. This solves problems 2 and 3.
The other problem about matching might seem a bit unrelated, but in fact it's really an issue of identity. Tags also provide identity. In particular, there is a variant of Transform, TagTransform, in which the matching algorithm is to match tags of the source to tags of the second.
7.3 Tag Transform Example
Here are some examples of TagTransform. Suppose we are trying to animate a sorting operation. A traditional transform does not emphasize the nature of the sorting operation.
func Bars(array) = identity:
var ret = {}
for y in array
ret += Rect:
center: ORIGIN
width: 0.25
height: y / 2
tag: {}
stroke: BLACK
ret = XStack:
mesh_vector: ret
align_dir: DOWN
ret = Centered(ret, ORIGIN)
element: ret
tree bars = Bars:
array: {3,1,0,2,2,1,4,5,1}
p += Set:
vars&: bars
bars.array = sort(bars.array)
p += Transform:
meshes&: bars
time: 1
The issue is that we're not matching the rectangles with their sorted parts. However, if we assign tags properly and use TagTransform, the sorting is emphasized.
func Bars(tagged_array) = identity:
var ret = {}
for pair in tagged_array
ret += Rect:
center: ORIGIN
width: 0.25
height: pair[0] / 2
tag: {pair[1]}
stroke: BLACK
ret = XStack:
mesh_vector: ret
align_dir: DOWN
ret = Centered(ret, ORIGIN)
element: ret
tree bars = Bars:
tagged_array: right_key({3,1,0,2,2,1,4,5,1})
p += Set:
vars&: bars
bars.tagged_array = sort(bars.tagged_array)
p += TagTransform:
meshes&: bars
time: 1
IMPORTANT Notice how we use right_key to help us out with the tagging. Now, in both the initial and sorted meshes, the tags line up correctly (in particular, in the initial mesh-tree the tag is just the index, and in the sorted one, the tag is the index it came from). Since the tags line up correctly, TagTransform looks good.
7.4 Operation on Tags Example
Here, we decide to only shift a subset of a mesh-tree. In general, the way operators works is that the selected meshes have the operation apply to them, and the unselected meshes are returned as is. Note that unselected are still returned though. This allows them to be chained.
func Bars(tagged_array) = identity:
var ret = {}
for pair in tagged_array
ret += Rect:
center: ORIGIN
width: 0.25
height: pair[0] / 2
tag: {pair[1]}
stroke: BLACK
ret = XStack:
mesh_vector: ret
align_dir: DOWN
ret = Centered(ret, ORIGIN)
element: ret
tree bars = Bars:
tagged_array: right_key({3,1,0,2,2,1,4,5,1})
p += Set:
vars&: bars
/* The shift only applies to a subset */
bars = Shifted:
root: bars
tag_predicate(tag): tag[0] < 4
delta: UP
p += TagTransform:
meshes&: bars
time: 1
Notice the usage of tag_predicate in the Shifted operation, which dictates whether or not the mesh should be shifted. While in our particular case we could have just done this with a for loop, this becomes impractical for complex and large mesh-trees.
7.5 Remarks and Conclusion
REMARK We also note that multiple meshes in a mesh-tree can have the same tag (which is often the case when we give it the empty tag, and is otherwise useful for treating two meshes as the same).
Tags are pretty powerful. In general, tags are useful for differentiating different types of meshes, and different instances within classes. For example, if we're making a Graph mesh, this could be used to tag edges and to tag nodes. This is what we mean when we say tagging is identity.