/// <summary> /// Takes the symbol code and matches one of the stencils in the resource dictionary. /// </summary> /// <param name="symbolCode"> /// The symbol code for which to look up the stencil. /// </param> /// <returns> /// The string that should be used to get the ResourceDictionary entry for this symbol. /// </returns> public static string CodeToStencil(string symbolCode) { if (!SymbolData.Check(ref symbolCode)) { return(null); } int schemeKey = CodingScheme.GetCode(symbolCode); // Weather short circuits most considerations, at least for now if (schemeKey == CodingScheme.Weather) { return(symbolCode); } string stencil = symbolCode.Substring(0, 10).ToUpperInvariant(); int dash = stencil.IndexOf('-', 4); if (dash > 0) { stencil = stencil.Substring(0, dash); } // Replace remaining '-'s with '_'s stencil = stencil.Replace('-', '_'); // Return one of the four (approximately) that we know about int identityKey = StandardIdentity.GetNormalizedStandardIdentity(symbolCode); // Need the battle dimension int dimensionKey = CategoryBattleDimension.GetCode(symbolCode); // If we have a Z battle dimension cut right to the chase. // Get a blank stencil so we can add a question mark. if (dimensionKey == CategoryBattleDimension.BdUnknown) { return("I" + StandardIdentity.ToChar(identityKey) + "ZP"); } string tail = stencil.Substring(2, 1) + "P" + stencil.Substring(4); // If we have EmergenctManagement and a NaturalEvent, get rid of the standard identity // or if we have a tactical graphic, get rid of the standard identity if ((schemeKey == CodingScheme.EmergencyManagement && dimensionKey == CategoryBattleDimension.EmNaturalEvents) || schemeKey == CodingScheme.TacticalGraphics) { return(stencil.Substring(0, 1) + "_" + tail); } // If framed, we'll include the base affiliation if (dimensionKey != CategoryBattleDimension.BdOther) { return(stencil.Substring(0, 1) + StandardIdentity.ToChar(identityKey) + tail); } // Otherwise, we're looking for an unframed element return(stencil.Substring(0, 1) + "." + tail); }
/// <summary> /// Generate the Joker, Faker, or "eXercise" character. /// </summary> /// <param name="symbolCode"> /// The symbol code for which to generate the large character string. /// </param> /// <param name="labels"> /// A dictionary of the labels to be drawn. /// </param> /// <param name="style"> /// The style to apply to the labels. /// </param> /// <returns> /// The TextBlock that incorporates the labels. /// </returns> internal static TextBlock GenerateJokerFakerExercise(string symbolCode, IDictionary <string, string> labels, Style style) { // Check for matching code char theChar = StandardIdentity.GetExerciseAmplifyingDescriptor(symbolCode); if (theChar == (char)0) { return(null); } #if WINDOWS_UWP string theString = theChar.ToString(); #else string theString = theChar.ToString(Culture); #endif if (labels != null && labels.ContainsKey("F")) { theString += " " + labels["F"]; } Rect r = SymbolData.GetBounds(symbolCode); var tb = new TextBlock { Style = style, // BigLabels, Text = theString }; tb.FindTextExtent(); tb.SetValue(Canvas.TopProperty, r.Top - tb.Height); tb.SetValue(Canvas.LeftProperty, r.Right); return(tb); }
/// <summary> /// Checks to see if the symbol requires a dashed outline. /// </summary> /// <param name="symbolCode"> /// The symbol code to check. /// </param> /// <returns> /// A boolean to indicate whether the outline should be dashed. /// </returns> internal static bool IsDashed(string symbolCode) { if (!Check(ref symbolCode)) { return(false); } switch (StandardIdentity.GetCode(symbolCode)) { case StandardIdentity.Pending: case StandardIdentity.AssumedFriend: case StandardIdentity.Suspect: case StandardIdentity.ExercisePending: case StandardIdentity.ExerciseAssumedFriend: { return(true); } default: if (StatusOperationalCapacity.GetCode(symbolCode) == StatusOperationalCapacity.AnticipatedPlanned) { return(true); } return(false); } }
/// <summary> /// Generates a static tooltip for a given symbol code. /// </summary> /// <param name="symbolCode">The symbol code which needs the tooltip.</param> /// <returns>A string representing a tooltip.</returns> private static string GenerateTooltip(string symbolCode) { var desc = new StringBuilder(MilAppendix.Description(symbolCode)); desc.AppendLine("Affiliation: " + StandardIdentity.GetName(symbolCode)); desc.AppendLine("Condition: " + StatusOperationalCapacity.GetName(symbolCode)); desc.AppendLine("Order of battle: " + OrderOfBattle.GetName(symbolCode)); desc.AppendLine("Country: " + Countries.GetName(symbolCode)); desc.Append("Modifier: " + CombinedModifierCode.GetName(symbolCode)); return(desc.ToString(0, desc.Length)); }
/// <summary> /// This is the current background color for this particular symbol /// </summary> /// <param name="symbolCode">The symbol code</param> /// <returns>A brush representing the current background color for the symbol code</returns> public static Brush FindColorScheme(string symbolCode) { if (!SymbolData.Check(ref symbolCode)) { return(null); } if (OrderOfBattle.GetCode(symbolCode) == OrderOfBattle.Civilian) { if (StandardIdentity.IsColorHostile(symbolCode)) { return(GetDefault(Reds, ColorScheme)); } return(GetDefault(Purples, ColorScheme)); } switch (StandardIdentity.GetCode(symbolCode)) { case StandardIdentity.AssumedFriend: case StandardIdentity.ExerciseFriend: case StandardIdentity.Friend: case StandardIdentity.ExerciseAssumedFriend: return(GetDefault(Blues, ColorScheme)); case StandardIdentity.Hostile: case StandardIdentity.Joker: case StandardIdentity.Faker: case StandardIdentity.Suspect: return(GetDefault(Reds, ColorScheme)); case StandardIdentity.ExerciseNeutral: case StandardIdentity.Neutral: return(GetDefault(Greens, ColorScheme)); case StandardIdentity.ExercisePending: case StandardIdentity.Pending: case StandardIdentity.Unknown: case StandardIdentity.ExerciseUnknown: return(GetDefault(Yellows, ColorScheme)); default: return(null); } }
/// <summary> /// Generate the right labels for the symbol. /// </summary> /// <param name="symbolCode"> /// The symbol code for which to generate the labels. /// </param> /// <param name="labels"> /// The dictionary of labels to generate. /// </param> /// <param name="style"> /// The style with which to render the labels. /// </param> /// <returns> /// A TextBlock that represents the rendered labels. /// </returns> internal static TextBlock GenerateRight(string symbolCode, IDictionary <string, string> labels, Style style) { // Pick off the left-oriented strings and write them out if (labels == null) { return(null); } var right = new TextBlock { Style = style /*RightLabels*/ }; bool gotLine = false; // If we have an X, J, or K modifier character, skip label F because it is already written out. if (StandardIdentity.GetExerciseAmplifyingDescriptor(symbolCode) != (char)0) { ProcessLabels(labels, false, new[] { string.Empty }, right, ref gotLine); } else { ProcessLabels(labels, false, new[] { "F" }, right, ref gotLine); } var height = gotLine ? (double)right.GetValue(TextBlock.LineHeightProperty) : 0.0; // At this point we need to process the remaining labels as if each row has a label. // Otherwise some label lines may appear in the wrong position // if other label lines are empty. // Setting "gotLine" to true forces a new line for each of the label lines. // More complicated logic might consider the height of the text block, prior to // the elimination of the empty lines. gotLine = true; ProcessLabels(labels, false, new[] { "G" }, right, ref gotLine); ProcessLabels(labels, false, new[] { "H" }, right, ref gotLine); ProcessLabels(labels, false, new[] { "M" }, right, ref gotLine); ProcessLabels(labels, true, new[] { "J", "K", "L", "N", "P" }, right, ref gotLine); TruncateNewLines(right); Rect b = SymbolData.GetBounds(symbolCode); SetTopLeft(right, b.Right + (height / 5.0), b.Top - height); return(right); }
public void StandardIdentityTest() { int gc = StandardIdentity.GetCode(string.Empty); Assert.AreEqual(gc, (char)0); gc = StandardIdentity.GetCode(null); Assert.AreEqual(gc, (char)0); gc = StandardIdentity.GetCode("qqqqqqqqqqqqqqq"); Assert.AreEqual(gc, (char)0); string str = StandardIdentity.GetName(string.Empty); Assert.AreEqual(str, string.Empty); str = StandardIdentity.GetName(null); Assert.AreEqual(str, string.Empty); str = StandardIdentity.GetName("qqqqqqqqqqqqqqq"); Assert.AreEqual(str, string.Empty); str = StandardIdentity.GetName("qApqqqqqqqqqqqn"); Assert.AreEqual(str, "Assumed Friend"); }
/// <summary> /// When is the top of the symbol flat? /// Answer: /// 1. normalize StandardIdentity to 'F', 'H', 'N' or 'U' /// 2. return true when it is Subsurface /// 3. return true when it is Neutral /// 4. return true when it is Friendly Units, Installations, or SOF /// 5. return true when it is Friendly Emergency Operations /// a. technically, friendly emergency equipment is not flat /// </summary> /// <param name="symbolCode"> /// The symbol code to check for a flat top to the symbol. /// </param> /// <returns> /// Returns a boolean to indicate whether the top of the symbol is flat. /// </returns> internal static bool IsTopFlat(string symbolCode) { if (!Check(ref symbolCode)) { return(false); } int dimensionKey = CategoryBattleDimension.GetCode(symbolCode); if (dimensionKey == CategoryBattleDimension.BdSubsurface) { return(true); } int identityKey = StandardIdentity.GetNormalizedStandardIdentity(symbolCode); if (identityKey == StandardIdentity.Neutral) { return(true); } if (identityKey == StandardIdentity.Friend) { if (dimensionKey == CategoryBattleDimension.BdSpace || dimensionKey == CategoryBattleDimension.BdAir || dimensionKey == CategoryBattleDimension.BdSeaSurface || dimensionKey == CategoryBattleDimension.BdUnknown) { return(false); } if (IsEquipment(symbolCode)) { return(false); } return(true); } return(false); }
/// <summary> /// Writes out the CXML file. /// </summary> /// <param name="ms"> /// The symbol for which to generate the CXML. /// </param> /// <param name="rootName"> /// The name to use for the symbol. /// </param> private void WriteCxml(MilSymbol ms, string rootName) { var symbolCode = (CodingScheme.GetCode(ms.SymbolCode) != CodingScheme.Weather) ? rootName + "*****" : ms.SymbolCode; var description = MilAppendix.Description(symbolCode); var lines = description.Split(new[] { '\n' }); var lineCount = lines.Length - 1; // the last line is empty var sb = new StringBuilder(); sb.AppendFormat(@"<Item Id=""{0}"" Name=""{1}"" Img=""Symbols\{1}.png"" Href="""">", this.index++, rootName); sb.AppendLine(); if (lineCount > 0) { sb.AppendFormat(@" <Description>""{0}""</Description>", lines[lineCount - 1].Trim(new[] { ' ', '\n', '\r' })); sb.AppendLine(); } else { sb.AppendFormat(@" <Description>""""</Description>"); sb.AppendLine(); } sb.AppendLine(@" <Facets>"); sb.AppendLine(@" <Facet Name=""Affiliation"">"); sb.AppendFormat(@" <String Value=""{0}"" />", StandardIdentity.GetName(symbolCode)); sb.AppendLine(); sb.AppendLine(@" </Facet>"); sb.AppendLine(@" <Facet Name=""Battle Dimension"">"); sb.AppendFormat(@" <String Value=""{0}"" />", CategoryBattleDimension.GetName(symbolCode)); sb.AppendLine(); sb.AppendLine(@" </Facet>"); if (lineCount > 2) { sb.AppendLine(@" <Facet Name=""Type"">"); sb.AppendFormat(@" <String Value=""{0}"" />", lines[2].Trim(new[] { ' ', '\n', '\r' })); sb.AppendLine(); sb.AppendLine(@" </Facet>"); } sb.AppendLine(@" <Facet Name=""Coding Scheme"">"); sb.AppendFormat(@" <String Value=""{0}"" />", CodingScheme.GetName(symbolCode)); sb.AppendLine(); sb.AppendLine(@" </Facet>"); if (lineCount - 1 > 3) { sb.AppendLine(@" <Facet Name=""Key Phrases"">"); for (var i = 3; i < lineCount - 1; i++) { sb.AppendFormat(@" <String Value=""{0}"" />", lines[i].Trim(new[] { ' ', '\n', '\r' })); sb.AppendLine(); } sb.AppendLine(@" </Facet>"); } sb.AppendLine(@" </Facets>"); sb.AppendLine(@"</Item>"); #if DO_WRITES this.cxmlStream.Write(sb.ToString()); #endif }
/// <summary> /// Adds the black ribbon at the top of the symbol for the standard identity "Space". /// </summary> /// <param name="symbolCode">The symbol code for the space entity.</param> /// <returns>The shape representing the black ribbon overlay for a space entity.</returns> internal static Shape GenerateSpace(string symbolCode) { if (!SymbolData.Check(ref symbolCode)) { return(null); } if (CategoryBattleDimension.GetCode(symbolCode) != CategoryBattleDimension.BdSpace) { return(null); } // Handy points for future reference // Inside for unknown ground // <Path Data="F0 M-61,-140 C-30,-175 30,-175 61,-140" /> // Inside for hostile ground // <Polygon Points="-61,-105 0,-166 61,-105" /> switch (StandardIdentity.GetNormalizedStandardIdentity(symbolCode)) { case StandardIdentity.Friend: { return(GenerateBlackSpline( new Point(-61, -107), new Point(-23, -148), new Point(23, -148), new Point(61, -107))); } case StandardIdentity.Unknown: { return(GenerateBlackSpline( new Point(-61, -117), new Point(-30, -160), new Point(30, -160), new Point(61, -117))); } case StandardIdentity.Hostile: { return(new Path { Fill = new SolidColorBrush(Colors.Black), Data = new PathGeometry { Figures = new PathFigureCollection { new PathFigure { StartPoint = new Point(-61, -93), Segments = new PathSegmentCollection { new LineSegment { Point = new Point(0, -149) }, new LineSegment { Point = new Point(61, -93) } } } } } }); } case StandardIdentity.Neutral: { return(new Path { Fill = new SolidColorBrush(Colors.Black), Data = new PathGeometry { Figures = new PathFigureCollection { new PathFigure { StartPoint = new Point(-127, -104), Segments = new PathSegmentCollection { new LineSegment { Point = new Point(127, -104) }, new LineSegment { Point = new Point(127, -139) }, new LineSegment { Point = new Point(-127, -139) } } } } } }); } } return(null); }
/// <summary> /// Generate the installation rendering for the passed in symbol. /// </summary> /// <param name="ms"> /// The military symbol for which to provide the installation rendering. /// </param> /// <param name="height"> /// The height at which to provide the installation rendering. /// </param> /// <returns> /// The graphics Shape object that represents the installation rendering. /// </returns> private static Shape GenerateInstallation(MilSymbol ms, out double height) { //// U&PGW ZSGF full unknown (flat) //// AP full air (not flat) //// U subsurface (flat) //// N&L ZSGF full neutral (flat) //// AP full air (flat) //// U subsurface (flat) //// H&S ZSGF full hostile (not flat) //// AP full air (not flat) //// U subsurface (flat) //// F&ADMJK Z(IG)S full friendly (not flat) //// F(~IG) full friendly (flat) //// AP full air (not flat) //// U subsurface (flat) height = -185; Brush br = new SolidColorBrush(Colors.Black); int si = StandardIdentity.GetNormalizedStandardIdentity(ms.SymbolCode); if (SymbolData.IsTopFlat(ms.SymbolCode)) { double t = ms.BaseRect.Top; if (si == StandardIdentity.Unknown) { t += SymbolData.HalfWidth; } height = t - 30; return(GenericInstallation(br, height, t)); } int bd = CategoryBattleDimension.GetCode(ms.SymbolCode); bool ap = bd == CategoryBattleDimension.BdSpace || bd == CategoryBattleDimension.BdAir; // The cases cover those surfaces which are flat on top versus those that are not switch (si) { case StandardIdentity.Unknown: // Outside for unknown space if (ap) { return(UnknownSpaceInstallation(br, height)); } return(UnknownGroundInstallation(br, height)); case StandardIdentity.Hostile: // Outside for hostile space if (ap) { height = -165; return(HostileSpaceInstallation(br, height)); } return(HostileGroundInstallation(br, height)); case StandardIdentity.Friend: height = -175; // Outside for friendly space if (ap) { return(FriendSpaceInstallation(br, height)); } return(FriendCircleInstallation(br, height)); } return(null); }
/// <summary> /// Generate the task force rendering for the passed in symbol. /// </summary> /// <param name="ms"> /// The military symbol for which to provide the task force rendering. /// </param> /// <param name="height"> /// The height at which to provide the task force rendering. /// </param> /// <returns> /// The graphics Path object that represents the task force rendering. /// </returns> private static Path GenerateTaskForce(MilSymbol ms, out double height) { height = -185; double bottom = 0; const double Wide = 54; int si = StandardIdentity.GetNormalizedStandardIdentity(ms.SymbolCode); if (SymbolData.IsTopFlat(ms.SymbolCode)) { bottom = ms.BaseRect.Top; if (si == StandardIdentity.Unknown) { bottom += SymbolData.HalfWidth; } height = bottom - 75; } else { int bd = CategoryBattleDimension.GetCode(ms.SymbolCode); bool ap = bd == CategoryBattleDimension.BdSpace || bd == CategoryBattleDimension.BdAir; // The cases cover those surfaces which are flat on top versus those that are not switch (si) { case StandardIdentity.Unknown: if (ap) { height = -230; // space bottom = -133; } else { height = -250; // ground bottom = -154; } break; case StandardIdentity.Hostile: if (ap) { height = -230; // space bottom = -107; } else { height = -253; // ground bottom = -119; } break; case StandardIdentity.Friend: height = -222; if (ap) { bottom = -121; // space } else { bottom = -137; // ground circles } break; } } return(new Path { Style = SymbolData.GetStyle("BS10"), Data = new PathGeometry { Figures = new PathFigureCollection { new PathFigure { StartPoint = new Point(Wide, bottom), Segments = new PathSegmentCollection { new LineSegment { Point = new Point(Wide, height) }, new LineSegment { Point = new Point(-Wide, height) }, new LineSegment { Point = new Point(-Wide, bottom) } } } } } }); }
/// <summary> /// Return the headquarters factor to help position the headquarters staff /// </summary> /// <param name="sc"> /// The symbol code for the headquarters. /// </param> /// <returns> /// A fractional offset as a double ranging from 0.0 to 1.0. /// </returns> internal static double GetHqFactor(string sc) { if (!Check(ref sc)) { return(0); } int identityKey = StandardIdentity.GetNormalizedStandardIdentity(sc); int dimensionKey = NormalizeBattleDimension(sc); switch (identityKey) { case StandardIdentity.Friend: if (dimensionKey == CategoryBattleDimension.BdSpace || dimensionKey == CategoryBattleDimension.BdAir) { return(1.0); } if (dimensionKey == CategoryBattleDimension.BdSubsurface) { return(0.0); } if (dimensionKey == CategoryBattleDimension.BdSeaSurface || dimensionKey == CategoryBattleDimension.BdOther || IsEquipment(sc)) { return(0.5); // of course there is no headquarters that is also equipment } return(1.0); case StandardIdentity.Hostile: if (dimensionKey == CategoryBattleDimension.BdSpace || dimensionKey == CategoryBattleDimension.BdAir) { return(1.0); } if (dimensionKey == CategoryBattleDimension.BdSubsurface) { return(0.0); } return(0.5); case StandardIdentity.Neutral: return(1.0); case StandardIdentity.Unknown: if (dimensionKey == CategoryBattleDimension.BdSpace || dimensionKey == CategoryBattleDimension.BdAir) { return(0.7); } if (dimensionKey == CategoryBattleDimension.BdSubsurface) { return(0.3); } return(0.5); } return(0.0); }
/// <summary> /// This function returns the symbol bounds and some scaling factors /// (area and height) for the various standard symbol backgrounds. /// The exceptions to these sizes are the symbols that have headquarters /// or installations built-in. /// If that built-in is in the normal symbol code place (SymbolCode[10-11]) /// we're OK. /// But the designers threw in a few curveballs that we're going to special /// case for now. /// </summary> /// <param name="sc"> /// The symbol code. /// </param> /// <returns> /// A Scaling object representing the bounding rectangle and various scaling factors. /// </returns> public static Scaling GetScaling(string sc) { if (!Check(ref sc)) { return(new Scaling(Rect.Empty, 300.0 * 300.0, 300.0)); } int identityKey = StandardIdentity.GetNormalizedStandardIdentity(sc); int dimensionKey = NormalizeBattleDimension(sc); switch (identityKey) { case StandardIdentity.Friend: if (dimensionKey == CategoryBattleDimension.BdSpace || dimensionKey == CategoryBattleDimension.BdAir) { return(Rects["F137149A"]); } if (dimensionKey == CategoryBattleDimension.BdSubsurface) { return(Rects["F137149U"]); } if (dimensionKey == CategoryBattleDimension.BdSeaSurface || dimensionKey == CategoryBattleDimension.BdOther || IsEquipment(sc)) { return(Rects["F149149G"]); } return(Rects["F185125G"]); case StandardIdentity.Hostile: if (dimensionKey == CategoryBattleDimension.BdSpace || dimensionKey == CategoryBattleDimension.BdAir) { return(Rects["H137161A"]); } if (dimensionKey == CategoryBattleDimension.BdSubsurface) { return(Rects["H137161U"]); } return(Rects["H180180G"]); case StandardIdentity.Neutral: if (dimensionKey == CategoryBattleDimension.BdSpace || dimensionKey == CategoryBattleDimension.BdAir) { return(Rects["N137149A"]); } if (dimensionKey == CategoryBattleDimension.BdSubsurface) { return(Rects["N137149U"]); } return(Rects["N137137G"]); case StandardIdentity.Unknown: if (dimensionKey == CategoryBattleDimension.BdSpace || dimensionKey == CategoryBattleDimension.BdAir) { return(Rects["U183161A"]); } if (dimensionKey == CategoryBattleDimension.BdSubsurface) { return(Rects["U183161U"]); } return(Rects["U178178G"]); } return(new Scaling(Rect.Empty, 300.0 * 300.0, 300.0)); }