MODULEcopy l and remove any duplicates. Very inefficient for big lists...; <* PRAGMA LL *> IMPORT Animate, AnimationPath, GraphVBT, GraphVBTExtras, RefList, Math, Matrix2D, MG, MGV, R2; TYPE RotateAnimation = Animate.T BRANDED OBJECT center: GraphVBT.Vertex; angle: REAL; vertices: RefList.T; OVERRIDES length := LengthAnim; doStep := DoStepRotate END; PROCEDURE GraphAnim LengthAnim (<* UNUSED *> anim: Animate.T; <* UNUSED *> v : MG.V; <* UNUSED *> mg : MG.T ): INTEGER = BEGIN RETURN 100 END LengthAnim; <* LL <+ VBT.mu *> PROCEDUREDoStepRotate ( anim : RotateAnimation; time, timePrev: REAL; <* UNUSED *> v : MG.V; <* UNUSED *> mg : MG.T ) = VAR vertices := anim.vertices; vertex : GraphVBT.Vertex; center := anim.center.pos; m := Matrix2D.Concat3( Matrix2D.Translate(-center[0], -center[1]), Matrix2D.Rotate((time - timePrev) * -anim.angle * FLOAT(Math.Degree, REAL)), Matrix2D.Translate(center[0], center[1])); BEGIN LOCK anim.center.graph.mu DO WHILE vertices # NIL DO vertex := vertices.head; vertices := vertices.tail; vertex.move(Matrix2D.Transform(m, vertex.pos)); END; END; END DoStepRotate;
PROCEDURERemoveDups (l: RefList.T): RefList.T = VAR res, ll: RefList.T; v : REFANY; found : BOOLEAN; BEGIN WHILE l # NIL DO v := l.head; l := l.tail; ll := res; found := FALSE; WHILE ll # NIL DO found := found OR ll.head = v; ll := ll.tail END; IF NOT found THEN res := RefList.Cons(v, res); END; END; RETURN res; END RemoveDups; PROCEDURERotate (center : GraphVBT.Vertex; angle : REAL; vertices: RefList.T (* of GraphVBT.Vertex *)) = VAR mgv := GraphVBTExtras.GetMG(center.graph); BEGIN IF vertices = NIL THEN RETURN END; MGV.AddAnimation( mgv, NEW(RotateAnimation, center := center, angle := angle, vertices := RemoveDups(vertices)).init(), NIL) END Rotate; TYPE MoveAnimation = Animate.T BRANDED OBJECT graph : GraphVBT.T; path : AnimationPath.MultipleEdgePath; vertices: RefList.T; (* cheap cache of last position if animation isn't shared *) posPrev : R2.T; timePrev: REAL := -1.0; OVERRIDES length := LengthAnim; doStep := DoStepMove END; <* LL <+ VBT.mu *> PROCEDUREDoStepMove ( anim : MoveAnimation; time, timePrev: REAL; <* UNUSED *> v : MG.V; <* UNUSED *> mg : MG.T ) = VAR vertices := anim.vertices; pos, posPrev, delta: R2.T; vertex : GraphVBT.Vertex; BEGIN LOCK anim.graph.mu DO pos := anim.path.pos(time); IF anim.timePrev = timePrev THEN posPrev := anim.posPrev; ELSE posPrev := anim.path.pos(timePrev); END; delta := R2.Sub(pos, posPrev); WHILE vertices # NIL DO vertex := vertices.head; vertices := vertices.tail; vertex.move(R2.Add(vertex.pos, delta)); END; anim.timePrev := time; anim.posPrev := pos; END; END DoStepMove; PROCEDUREMoveAlongEdges (edges : RefList.T (* of GraphVBT.Edge *); vertices: RefList.T (* of GraphVBT.Vertex *)) = VAR graph := NARROW(vertices.head, GraphVBT.Vertex).graph; BEGIN MGV.AddAnimation( GraphVBTExtras.GetMG(graph), NEW(MoveAnimation, graph := graph, path := NEW(AnimationPath.MultipleEdgePath).init(edges), vertices := RemoveDups(vertices)).init(), NIL); END MoveAlongEdges; BEGIN END GraphAnim.