public Movement(IXmlNode elem) : this(elem.attr("beats").toDouble(), getHands(elem.attr("hands")), elem.attr("cx1").toDouble(), elem.attr("cy1").toDouble(), elem.attr("cx2").toDouble(), elem.attr("cy2").toDouble(), elem.attr("x2").toDouble(), elem.attr("y2").toDouble(), elem.attr(elem.hasAttr("cx3") ? "cx3" : "cx1").toDouble(), elem.attr(elem.hasAttr("cx4") ? "cx4" : "cx2").toDouble(), elem.attr(elem.hasAttr("cy4") ? "cy4" : "cy2").toDouble(), elem.attr(elem.hasAttr("x4") ? "x4" : "x2").toDouble(), elem.attr(elem.hasAttr("y4") ? "y4" : "y2").toDouble(), elem.attr("beats").toDouble()) { }
// Takes a move, which is an XML element that references another XML // path with its "select" attribute // Returns an array of movements public static List <Movement> translateMove(IXmlNode move) { // First retrieve the requested path var movename = move.attr("select"); var pathelem = mdoc.SelectNodes($"//path[@name='{movename}']").First(); // Get the list of movements var movements = translatePath(pathelem); // Get any modifications var scaleX = move.hasAttr("scaleX") ? move.attr("scaleX").toDouble() : 1; var scaleY = (move.hasAttr("scaleY") ? move.attr("scaleY").toDouble() : 1) * (move.hasAttr("reflect") ? -1 : 1); var offsetX = move.hasAttr("offsetX") ? move.attr("offsetX").toDouble() : 0; var offsetY = move.hasAttr("offsetY") ? move.attr("offsetY").toDouble() : 0; var hands = move.attr("hands"); // Sum up the total beats so if beats is given as a modification // we know how much to change each movement var oldbeats = movements.Sum(m => m.beats); var beatfactor = move.hasAttr("beats") ? move.attr("beats").toDouble() / oldbeats : 1; // Now go through the movements applying the modifications // The resulting list is the return value return(movements.Select(m => m.useHands(hands.Length > 0 ? Movement.getHands(hands) : m.hands) .scale(scaleX, scaleY) .skew(offsetX, offsetY) .time(m.beats * beatfactor)).ToList()); }
/** * Returns animation element, looking up cross-reference if needed. */ public static IXmlNode tamXref(IXmlNode tam) { if (tam.hasAttr("xref-link")) { var link = tam.attr("xref-link") + ".xml"; var xdoc = getXMLAsset(link); var s = "//tam"; if (tam.hasAttr("xref-title")) { s += "[@title='" + tam.attr("xref-title") + "']"; } if (tam.hasAttr("xref-from")) { s += "[@from='" + tam.attr("xref-from") + "']"; } return(xdoc.SelectNodes(s).First()); } else { return(tam); } }
public void resetAnimation() { if (tam != null) { leadin = interactiveDancer < 0 ? 2 : 3; leadout = interactiveDancer < 0 ? 2 : 1; // if (isRunnning) // doneCallback(); isRunning = false; beats = 0.0; var tlist = tam.SelectNodes("formation"); var formation = tlist.Length > 0 ? tlist.First() // formation defined in animation : tam.hasAttr("formation") ? TamUtils.getFormation(tam.attr("formation")) // formation reference to formations.xml : tam; // formation passed in for sequencer var flist = formation.SelectNodes("dancer"); dancers = new Dancer[flist.Length * (int)geometry]; // Except for the phantoms, these are the standard colors // used for teaching callers var dancerColor = geometry == GeometryType.HEXAGON ? new Color[] { Colors.Red, Colors.ForestGreen, Colors.Magenta, Colors.Blue, Colors.Yellow, Colors.Cyan, Colors.LightGray, Colors.LightGray, Colors.LightGray, Colors.LightGray } : new Color[] { Colors.Red, ColorUtilities.ColorFromHex(0xff00c000), Colors.Blue, Colors.Yellow, Colors.LightGray, Colors.LightGray, Colors.LightGray, Colors.LightGray }; // Get numbers for dancers and couples // This fetches any custom numbers that might be defined in // the animation to match a Callerlab or Ceder Chest illustration var paths = tam.SelectNodes("path"); var numbers = geometry == GeometryType.HEXAGON ? new string[] { "A", "E", "I", "B", "F", "J", "C", "G", "K", "D", "H", "L", "u", "v", "w", "x", "y", "z" } : geometry == GeometryType.BIGON || paths.Length == 0 ? new string[] { "1", "2", "3", "4", "5", "6", "7", "8" } : TamUtils.getNumbers(tam); var couples = geometry == GeometryType.HEXAGON ? new string[] { "1", "3", "5", "1", "3", "5", "2", "4", "6", "2", "4", "6", "7", "8", "7", "8", "7", "8" } : geometry == GeometryType.BIGON ? new string[] { "1", "2", "3", "4", "5", "6", "7", "8" } : paths.Length == 0 ? new string[] { "1", "3", "1", "3", "2", "4", "2", "4" } : TamUtils.getCouples(tam); var geoms = GeometryMaker.makeAll(geometry); // Select a random dancer of the correct gender for the interactive dancer var icount = -1; var im = Matrix3x2.Identity; if (interactiveDancer > 0) { var rand = new Random(); var selector = interactiveDancer == (int)Gender.BOY ? "dancer[@gender='boy']" : "dancer[@gender='girl']"; var glist = formation.SelectNodes(selector); icount = rand.Next(glist.Count); // If the animations starts with "Heads" or "Sides" // then select the first dancer. // Otherwise the formation could rotate 90 degrees // which would be confusing var title = tam.attr("title"); if (title.Contains("Heads") || title.Contains("Sides")) { icount = 0; } // Find the angle the interactive dancer faces at start // We want to rotate the formation so that direction is up var iangle = glist.Item((uint)icount).attr("angle").toDouble(); im = Matrix.CreateRotation(-iangle.toRadians()) * im; icount = icount * geoms.Count() + 1; } // Create the dancers and set their starting positions int dnum = 0; for (var i = 0; i < flist.Length; i++) { var fd = flist.ElementAt(i); var x = fd.attr("x").toDouble(); var y = fd.attr("y").toDouble(); var angle = fd.attr("angle").toDouble(); var gender = fd.attr("gender"); var g = gender == "boy" ? Gender.BOY : gender == "girl" ? Gender.GIRL : Gender.PHANTOM; var movelist = paths.Length > i?TamUtils.translatePath(paths.ElementAt(i)) : new List <Movement>(); // Each dancer listed in the formation corresponds to // one, two, or three real dancers depending on the geometry foreach (Geometry geom in geoms) { var m = Matrix3x2.Identity * Matrix.CreateRotation(angle.toRadians()) * Matrix.CreateTranslation(x, y) * im; var nstr = g == Gender.PHANTOM ? " " : numbers[dnum]; var cstr = g == Gender.PHANTOM ? " " : couples[dnum]; var c = g == Gender.PHANTOM ? Colors.LightGray : dancerColor[int.Parse(cstr) - 1]; // add one dancer //icount -= 1; if ((int)g == interactiveDancer && --icount == 0) { idancer = new InteractiveDancer(nstr, cstr, g, c, m, geom.clone(), movelist); dancers[dnum] = idancer; } else { dancers[dnum] = new Dancer(nstr, cstr, g, c, m, geom.clone(), movelist); dancers[dnum].hidden = g == Gender.PHANTOM && !showPhantoms; } beats = Math.Max(dancers[dnum].beats + leadout, beats); dnum++; } } // All dancers added // Initialize other stuff parts = tam.attr("parts") + tam.attr("fractions"); hasParts = tam.attr("parts").Length > 0; isRunning = false; beat = -leadin; prevbeat = -leadin; partbeats = partsValues(); // force a redraw canvas.Invalidate(); // ready callback Callouts.animationReady(); } }