public AnimationPage() { this.InitializeComponent(); var link = this.Intent()["link"]; var tamdoc = TamUtils.getXMLAsset(this.Intent()["link"]); alltams = TamUtils.tamList(tamdoc).Where(t => t.attr("display") != "none"); animtot = alltams.Count(); animnum = int.Parse(this.Intent()["anim"]); Callouts.SetLevel(link); setAnimation(); Callouts.AnimationFinished = () => { PlayPath.Fill = new SolidColorBrush(Colors.Black); PausePath.Fill = new SolidColorBrush(Colors.Transparent); playing = false; }; ManipulationMode = ManipulationModes.TranslateX; ManipulationStarted += (x, e) => x1 = (int)e.Position.X; ManipulationCompleted += (x, e) => { x2 = (int)e.Position.X; if (x1 - x2 > animationView.ActualWidth / 2 && animnum + 1 < animtot) { // swipe left animnum++; setAnimation(); } else if (x2 - x1 > animationView.ActualWidth / 2 && animnum > 0) { // swipe right animnum--; setAnimation(); } }; }
/** * This is called to generate or re-generate the dancers and their * animations based on the call, geometry, and other settings. * @param xtam XML element containing the call * @param intdan Dancer controlled by the user, or -1 if not used */ public IXmlNode setAnimation(IXmlNode xtam, int intdan = -1) { tam = TamUtils.tamXref(xtam); interactiveDancer = intdan; resetAnimation(); return(tam); }
bool matchXMLcall(string calltext, bool fuzzy = false) { var found = false; var matches = false; var ctx0 = this; var ctx = this; // If there are precursors, run them first so the result // will be used to match formations // Needed for calls like "Explode And ..." if (callstack.Count > 0) { ctx = new CallContext(this); ctx.callstack = callstack; ctx.performCall(); } // If actives != dancers, create another call context with just the actives if (ctx.dancers.Count != ctx.actives.Count) { ctx = new CallContext(ctx.actives); } // Try to find a match in the xml animations var callquery = "^" + TamUtils.callnameQuery(calltext) + "$"; var callfiles = TamUtils.calllistdata.Where(x => Regex.Match(x.text, callquery).Success); // Found xml file with call, now look through each animation // First read and extract all the animations to a list var tams = callfiles.SelectMany(d => TamUtils.getXMLAsset(d.link).SelectNodes("/tamination/tam")).ToList(); found = tams.Count > 0; // Now find the animations that match the name and formation tams.Where(tam => Regex.Match(tam.attr("title").ToLower().ReplaceAll("\\W", ""), callquery).Success) .Any(tam => { var f = tam.hasAttr("formation") ? TamUtils.getFormation(tam.attr("formation")) : tam.SelectNodes("formation").First(); var ctx2 = new CallContext(f); var sexy = tam.hasAttr("gender-specific"); // Try to match the formation to the current dancer positions var mm = matchFormations(ctx, ctx2, sexy, fuzzy); if (mm != null) { matches = true; // add XMLCall object to the call stack ctx0.callstack.Add(new XMLCall(tam, mm, ctx2)); ctx0.callname = callname + tam.attr("title") + " "; } return(matches); }); if (found && !matches) { // Found the call but formations did not match throw new FormationNotFoundError(calltext); } return(matches); }
public void reset(string level) { LevelData d = LevelData.find(level); var isIndex = d.dir == "all"; XmlDocument calldoc = TamUtils.getXMLAsset(isIndex ? "src\\callindex.xml" : "src\\calls.xml"); Callouts.SetTitle(d.name); calls = calldoc.SelectNodes(isIndex ? "/calls/call" : $"/calls/call[@{d.selector}]"); searchCallList(""); }
public void matchStandardFormation() { // Make sure newly added animations are finished dancers.ForEach(d => { d.path.recalculate(); d.animateToEnd(); }); // Work on a copy with all dancers active, mapping only uses active dancers var ctx1 = new CallContext(this); ctx1.dancers.ForEach(d => d.data.active = true); BestMapping bestMapping = new BestMapping(); bestMapping.totOffset = -1.0; standardFormations.ForEach(f => { CallContext ctx2 = new CallContext(TamUtils.getFormation(f)); // See if this formation matches var mapping = matchFormations(ctx1, ctx2, sexy: false, fuzzy: true, rotate: true); if (mapping != null) { // If it does, get the offsets var offsets = ctx1.computeFormationOffsets(ctx2, mapping); var totOffset = offsets.Aggregate(0.0, (s, v) => s + v.Length()); // Favor formations closer to the top of the list if (bestMapping.totOffset < 0 || totOffset + 0.1 < bestMapping.totOffset) { bestMapping.name = f; // only used for debugging bestMapping.mapping = mapping; bestMapping.offsets = offsets; bestMapping.totOffset = totOffset; } } }); if (bestMapping.totOffset >= 0) { for (var i = 0; i < dancers.Count; i++) { var d = dancers[i]; if (bestMapping.offsets[i].Length() > 0.1) { // Get the last movement var m = d.path.pop(); // Transform the offset to the dancer's angle d.animateToEnd(); var vd = bestMapping.offsets[i].Rotate(-d.tx.Angle()); // Apply it d.path.add(m.skew(-vd.X, -vd.Y)); d.animateToEnd(); } } } }
// Level off the number of beats for each dancer public void levelBeats() { // get the longest number of beats var maxb = maxBeats(); // add that number as needed by using the "Stand" move dancers.ForEach(d => { var b = maxb - d.path.beats; if (b > 0) { d.path.add(TamUtils.getMove("Stand").changebeats(b)); } }); }
public override void nextAnimation() { if (tutnum >= tutdata.Length) tutnum = 0; var tamdoc = TamUtils.getXMLAsset("src/tutorial.xml"); var gender = settings.Values["gender"]?.ToString() == "Girl" ? Gender.GIRL : Gender.BOY; var offset = gender == Gender.BOY ? 0 : 1; var tamlist = tamdoc.SelectNodes("/tamination/tam"); var tam = tamlist[tutnum * 2 + offset]; Callouts.SetTitle(tam.attr("title")); page.Animation.setAnimation(tam,(int)gender); switch (settings.Values["practicespeed"]?.ToString()) { case "Normal": page.Animation.setSpeed("Normal"); break; case "Moderate": page.Animation.setSpeed("Moderate"); break; default: page.Animation.setSpeed("Slow"); break; } showInstructions(); }
private void searchCallList(string query) { calllistdata.Clear(); var qq = TamUtils.callnameQuery(query); foreach (IXmlNode call in calls) { var title = (string)call.Attributes.GetNamedItem("title").NodeValue; if (Regex.Match(title.ToLower().ReplaceAll("\\W", ""), qq).Success) { var sublevel = (string)call.Attributes.GetNamedItem("sublevel").NodeValue; calllistdata.Add(new CallListItem() { Title = (string)call.Attributes.GetNamedItem("title").NodeValue, Level = (string)call.Attributes.GetNamedItem("sublevel").NodeValue, Link = (string)call.Attributes.GetNamedItem("link").NodeValue }); } } CallList.ItemsSource = calllistdata; }
public virtual void nextAnimation() { var calldoc = TamUtils.getXMLAsset("src/calls.xml"); var selector = LevelData.find(page.Intent()["level"]).selector; var calls = calldoc.SelectNodes($"/calls/call[@{selector}]"); IXmlNode tam = null; var rand = new Random(); while (tam == null) { var e = calls[rand.Next((int)calls.Length)]; // Remember link for definition link = e.attr("link"); var tamdoc = TamUtils.getXMLAsset(link); var tams = tamdoc.SelectNodes("/tamination/tam") // For now, skip any "difficult" animations .Where((IXmlNode x) => { return(x.attr("difficulty") != "3"); }) // Skip any call with parens in the title - it could be a cross-reference // to a concept call from a higher level .Where((IXmlNode x) => { return(!x.attr("title").Contains("(")); }); if (tams.Count() > 0) { tam = tams.ElementAt(rand.Next(tams.Count())); var gender = settings.Values["practicegender"]?.ToString() == "Boy" ? (int)Gender.BOY : (int)Gender.GIRL; page.Animation.setAnimation(tam, gender); switch (settings.Values["practicespeed"]?.ToString()) { case "Normal": page.Animation.setSpeed("Normal"); break; case "Moderate": page.Animation.setSpeed("Moderate"); break; default: page.Animation.setSpeed("Slow"); break; } Callouts.SetTitle(tam.attr("title")); } } }
private void startSequence() { animationView.setAnimation(TamUtils.getFormation(formation)); }
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(); } }
/// <summary> /// Invoked when the application is launched normally by the end user. Other entry points /// will be used when the application is launched to open a specific file, to display /// search results, and so forth. /// </summary> /// <param name="e">Details about the launch request and process.</param> protected override void OnLaunched(LaunchActivatedEventArgs e) { #if DEBUG if (System.Diagnostics.Debugger.IsAttached) { /// this.DebugSettings.EnableFrameRateCounter = true; } #endif TamUtils.init(); //if (screenSize.Length() < 6) // DisplayInformation.AutoRotationPreferences = DisplayOrientations.Portrait; Frame rootFrame = Window.Current.Content as Frame; // Do not repeat app initialization when the Window already has content, // just ensure that the window is active if (rootFrame == null) { // Create a Frame to act as the navigation context and navigate to the first page rootFrame = new Frame(); // TODO: change this value to a cache size that is appropriate for your application rootFrame.CacheSize = 1; if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) { // TODO: Load state from previously suspended application } // Place the frame in the current Window Window.Current.Content = rootFrame; } if (rootFrame.Content == null) { #if WINDOWS_PHONE_APP // Removes the turnstile navigation for startup. if (rootFrame.ContentTransitions != null) { this.transitions = new TransitionCollection(); foreach (var c in rootFrame.ContentTransitions) { this.transitions.Add(c); } } rootFrame.ContentTransitions = null; rootFrame.Navigated += this.RootFrame_FirstNavigated; #endif // When the navigation stack isn't restored navigate to the first page, // configuring the new page by passing required information as a navigation // parameter var screenSize = MainPage.ScreenSize(); var isLandscape = screenSize.Length() > 6 && screenSize.X > screenSize.Y; if (!rootFrame.Navigate(isLandscape ? typeof(FirstLandscapePage) : typeof(PortraitPage), e.Arguments)) { throw new Exception("Failed to create initial page"); } } // Ensure the current window is active Window.Current.Activate(); }
public void reset() { // Fetch the list of animations and build the table var prevtitle = ""; var prevgroup = ""; link = this.Intent()["link"]; Callouts.SetLevel(link); XmlDocument tamdoc = TamUtils.getXMLAsset(link); var title = tamdoc.SelectSingleNode("/tamination").attr("title"); Callouts.SetTitle(title); var tams = TamUtils.tamList(tamdoc); var diffsum = 0; var firstanim = -1; var i = 0; foreach (IXmlNode tam in tams) { if (tam.attr("display") == "none") { continue; } var tamtitle = tam.attr("title"); var from = TamUtils.tamXref(tam).attr("from"); var group = tam.attr("group"); var diffstr = TamUtils.tamXref(tam).attr("difficulty"); var diff = diffstr.Length > 0 ? int.Parse(diffstr) : 0; diffsum += diff; if (group.Length > 0) { // Add header for new group as needed if (group != prevgroup) { if (Regex.Match(group, @"^\s+$").Success) { // Blank group, for calls with no common starting phrase // Add a green separator unless it's the first group if (anims.Count > 0) { anims.Add(new AnimListItem() { celltype = CellType.Separator }); } } else { // Named group e.g. "As Couples.." // Add a header with the group name, which starts // each call in the group anims.Add(new AnimListItem() { celltype = CellType.Header, name = group }); } } from = tamtitle.Replace(group, " ").Trim(); } else if (tamtitle != prevtitle) { // Not a group but a different call // Put out a header with this call anims.Add(new AnimListItem() { celltype = CellType.Header, name = tamtitle + " from" }); } // Build list item for this animation prevtitle = tamtitle; prevgroup = group; // TODO posanim(av.getCount) = i // Remember where the first real animation is in the list if (firstanim < 0) { firstanim = anims.Count; } // TODO selectanim and weblink // ... // Put out a selectable item anims.Add(new AnimListItem() { celltype = Regex.Match(group, @"^\s+$").Success ? CellType.Plain : CellType.Indented, title = tamtitle, name = from, group = group.Length > 0 ? group : tamtitle + " from", animnumber = i, difficulty = diff }); i = i + 1; } if (diffsum <= 0) { DifficultyLegend.Visibility = Visibility.Collapsed; } AnimList.ItemsSource = anims; if (firstanim >= 0) { Callouts.FirstAnimationReady(anims[firstanim]); } }