Beispiel #1
0
        /// <summary>
        /// Generate the top labels for the symbol.
        /// </summary>
        /// <param name="high">
        /// The height at which to generate the labels.
        /// </param>
        /// <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 GenerateTop(double high, string symbolCode, IDictionary <string, string> labels, Style style)
        {
            if (!SymbolData.Check(ref symbolCode))
            {
                return(null);
            }

            if (labels == null)
            {
                return(null);
            }

            var middle = new TextBlock {
                Style = style                          /*TopLabels*/
            };

            bool gotLine = false;

            ProcessLabels(labels, true, new[] { "C" }, middle, ref gotLine);
            var height = gotLine ? (double)middle.GetValue(TextBlock.LineHeightProperty) : 0.0;

            middle.FindTextExtent();

            // This positions the top line just above the symbol, I think
            SetTopLeft(middle, -middle.Width / 2.0, high - height);
            return(middle);
        }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
        /// <summary>
        /// Sets the width and height of the base symbol based on the symbol code,
        /// as well as the top and left properties,
        /// checking first to see if the canvas already has such limits.
        /// </summary>
        /// <param name="symbolCode">
        /// The symbol code for the symbol.
        /// </param>
        private void SetLimits(string symbolCode)
        {
            this.SetValue(Canvas.TopProperty, 0.0);
            this.SetValue(Canvas.LeftProperty, 0.0);

            if (this.ApplyTemplate())
            {
                if (VisualTreeHelper.GetChild(this, 0) is Canvas canvas &&
                    !double.IsNaN(canvas.Height))
                {
                    this.Height = canvas.Height;
                    this.Width  = canvas.Width;
                    this.SetValue(Canvas.TopProperty, canvas.GetValue(Canvas.TopProperty));
                    this.SetValue(Canvas.LeftProperty, canvas.GetValue(Canvas.LeftProperty));
                    return;
                }
            }

            // Need to handle those symbols that still don't have bounds
            Rect rect = SymbolData.GetBounds(symbolCode);

            if (!rect.IsEmpty)
            {
                this.Height = rect.Height;
                this.Width  = rect.Width;
            }
            else
            {
                this.Height = this.Width = 0.0;
            }
        }
Beispiel #4
0
        /// <summary>
        /// Generate the headquarters rendering for the passed in symbol.
        /// </summary>
        /// <param name="ms">
        /// The military symbol for which to provide the headquarters rendering.
        /// </param>
        /// <returns>
        /// The graphics Shape object that represents the headquarters rendering.
        /// </returns>
        private static Shape GenerateHeadquarters(MilSymbol ms)
        {
            Rect   b = ms.BaseRect;
            double headquartersFactor = SymbolData.GetHqFactor(ms.SymbolCode);

            return(new Path
            {
                Style = SymbolData.GetStyle("BS10"),
                Data = new PathGeometry
                {
                    Figures = new PathFigureCollection
                    {
                        new PathFigure
                        {
                            // The +/- HalfWidth accounts for the Bounds being on the outside of the symbol
                            StartPoint = new Point(b.Left + SymbolData.HalfWidth, b.Top + (headquartersFactor * b.Height)),
                            Segments = new PathSegmentCollection
                            {
                                new LineSegment {
                                    Point = new Point(b.Left + SymbolData.HalfWidth, b.Bottom + (0.3 * b.Width))
                                }
                            }
                        }
                    }
                }
            });
        }
Beispiel #5
0
        /// <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);
        }
Beispiel #6
0
        /// <summary>
        /// Generate a TextBlock label based on an integer value.
        /// </summary>
        /// <param name="x">
        /// The x coordinate for the TextBlock.
        /// </param>
        /// <param name="y">
        /// The y coordinate for the TextBlock.
        /// </param>
        /// <param name="integerLabel">
        /// The integer label to be displayed.
        /// </param>
        /// <param name="style">
        /// The style for the label.
        /// </param>
        /// <returns>
        /// The TextBlock containing the integer as a label.
        /// </returns>
        internal static TextBlock IntegerLabel(
            double x,               // a reference point for the horizontal location
            double y,               // the top of the label - for now
            string integerLabel,    // the label
            string style)           // the label's style
        {
            var label = new TextBlock
            {
                Style = SymbolData.GetStyle(style)
            };

            double result;

            if (!double.TryParse(integerLabel, out result))
            {
                return(null);
            }

            if (result < 0.0 || result > 99999.0)
            {
                return(null); // negative or too many digits
            }

            integerLabel = Math.Round(result).ToString(Culture);
            label.Text   = integerLabel;
            label.FindTextExtent();
            var multiplier =
                (label.TextAlignment == TextAlignment.Center) ? 0.5 :
                (label.TextAlignment == TextAlignment.Right) ? 1.0 : 0.0;

            SetTopLeft(label, x - (multiplier * label.Width), y);
            return(label);
        }
Beispiel #7
0
        /// <summary>
        /// Initializes static members of the <see cref="MilLabels"/> class.
        /// </summary>
        static MilLabels()
        {
            var styles = new Style[LabelCount];

            styles[TopLabels]              = SymbolData.GetStyle("TopLabels");
            styles[BigLabels]              = SymbolData.GetStyle("BigLabels");
            styles[LeftLabels]             = SymbolData.GetStyle("LeftLabels");
            styles[RightLabels]            = SymbolData.GetStyle("RightLabels");
            styles[TacticalGraphicsLabels] = SymbolData.GetStyle("TacticalGraphicsLabels");
            LabelStyles.Add(DefaultStyle, styles);
        }
Beispiel #8
0
        /// <summary>
        /// Generate the feint dummy rendering for the passed in symbol.
        /// </summary>
        /// <param name="ms">
        /// The military symbol for which to provide the feint dummy rendering.
        /// </param>
        /// <param name="height">
        /// The height at which to provide the feint dummy rendering.
        /// </param>
        /// <returns>
        /// The graphics Path object that represents the feint dummy rendering.
        /// </returns>
        private static Path GenerateFeintDummy(MilSymbol ms, ref double height)
        {
            if (!string.IsNullOrEmpty(Echelon.GetEchelonSymbol(ms.SymbolCode)))
            {
                height = ms.Bounds.Top;
            }

            if (SymbolData.IsTopFlat(ms.SymbolCode))
            {
                double minimum = ms.BaseRect.Top;
                if (height >= minimum)
                {
                    height = minimum - 28;
                }
            }

            double bottom = height + 23;

            height = height - 27;
            const double Wide = 126;

            var st = new Style(typeof(Shape))
            {
                BasedOn = SymbolData.GetStyle("BS10")
            };

            st.SetDashArray(3, 1);

            return(new Path
            {
                Style = st,
                Data = new PathGeometry
                {
                    Figures = new PathFigureCollection
                    {
                        new PathFigure
                        {
                            StartPoint = new Point(-Wide, bottom),
                            Segments = new PathSegmentCollection
                            {
                                new LineSegment {
                                    Point = new Point(0.0, height)
                                },
                                new LineSegment {
                                    Point = new Point(Wide, bottom)
                                }
                            }
                        }
                    }
                }
            });
        }
Beispiel #9
0
        /// <summary>
        /// Computes the scale factor used when scaling the symbol.
        /// </summary>
        /// <param name="symbolCode">
        /// The symbol code whose scale factor we need.
        /// </param>
        private void SetScaleFactor(string symbolCode)
        {
            this.scaleFactor = 1.0;
            switch (ScaleType)
            {
            case ScaleTypeValues.EqualAreas:
                this.scaleFactor = 1.0 / SymbolData.GetScaling(symbolCode).AreaFactor;
                break;

            case ScaleTypeValues.EqualHeights:
                this.scaleFactor = 1.0 / SymbolData.GetScaling(symbolCode).LinearFactor;
                break;
            }
        }
Beispiel #10
0
        /// <summary>
        /// Return the cache of styles for the particular symbol.
        /// </summary>
        /// <param name="style">
        /// The style for which to retrieve the array of styles.
        /// </param>
        /// <returns>
        /// An array of styles, such as left labels, right labels, etc. that match the passed in style.
        /// </returns>
        internal static Style[] GetStyles(Style style)
        {
            if (style == null)
            {
                return(LabelStyles[DefaultStyle]);
            }

            if (LabelStyles.ContainsKey(style))
            {
                return(LabelStyles[style]);
            }

            var styles = new Style[LabelCount];

            styles[TopLabels] = new Style(typeof(TextBlock))
            {
                BasedOn = SymbolData.GetStyle("TopLabels")
            };
            styles[BigLabels] = new Style(typeof(TextBlock))
            {
                BasedOn = SymbolData.GetStyle("BigLabels")
            };
            styles[LeftLabels] = new Style(typeof(TextBlock))
            {
                BasedOn = SymbolData.GetStyle("LeftLabels")
            };
            styles[RightLabels] = new Style(typeof(TextBlock))
            {
                BasedOn = SymbolData.GetStyle("RightLabels")
            };
            styles[TacticalGraphicsLabels] = new Style(typeof(TextBlock))
            {
                BasedOn = SymbolData.GetStyle("TacticalGraphicsLabels")
            };

            var tb = new TextBlock {
                Style = style
            };

            SetSingleProperty(TextBlock.ForegroundProperty, tb.Foreground, ref styles);
            SetSingleProperty(TextBlock.FontSizeProperty, tb.FontSize, ref styles);
            SetSingleProperty(TextBlock.FontFamilyProperty, tb.FontFamily, ref styles);
            SetSingleProperty(TextBlock.FontWeightProperty, tb.FontWeight, ref styles);
            LabelStyles.Add(style, styles);
            return(styles);
        }
Beispiel #11
0
        /// <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);
            }
        }
Beispiel #12
0
        /// <summary>
        /// Returns the arrow representing a direction of travel for a mil symbol
        /// </summary>
        /// <param name="symbolCode">Code for the mil symbol</param>
        /// <param name="labels">The labels for the symbol, we're looking for "Q"</param>
        /// <param name="extraOffset">An extra offset for tactical graphics</param>
        /// <returns>The arrow shape representing the direction of travel</returns>
        internal static Shape GenerateQ(
            string symbolCode,
            IDictionary <string, string> labels,
            double extraOffset)
        {
            if (!SymbolData.Check(ref symbolCode))
            {
                return(null);
            }

            string q;

            if (!labels.TryGetValue("Q", out q))
            {
                return(null);
            }

            double angle;

            if (!double.TryParse(q, out angle))
            {
                return(null);
            }

            double off = 0.0;

            if (CategoryBattleDimension.GetCode(symbolCode) == CategoryBattleDimension.BdGround)
            {
                off = SymbolData.GetBounds(symbolCode).Bottom;
            }

            off += extraOffset;
            return(new Path
            {
                Style = SymbolData.GetStyle("BS10"),
                Data = new PathGeometry
                {
                    Figures = new PathFigureCollection
                    {
                        GenerateArrowPoints(off, angle)
                    }
                }
            });
        }
Beispiel #13
0
        /// <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);
        }
Beispiel #14
0
        /// <summary>
        /// Generate the left 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 GenerateLeft(string symbolCode, IDictionary <string, string> labels, Style style)
        {
            if (!SymbolData.Check(ref symbolCode))
            {
                return(null);
            }

            // Pick off the left-oriented strings and write them out
            if (labels == null)
            {
                return(null);
            }

            var left = new TextBlock {
                Style = style                        /*LeftLabels*/
            };

            bool gotLine = false;

            ProcessLabels(labels, false, new[] { "W" }, left, ref gotLine);
            var height = gotLine ? (double)left.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[] { "X", "Y" }, left, ref gotLine);
            ProcessLabels(labels, false, new[] { "V" }, left, ref gotLine);
            ProcessLabels(labels, false, new[] { "T" }, left, ref gotLine);
            ProcessLabels(labels, true, new[] { "Z" }, left, ref gotLine);
            TruncateNewLines(left);

            Rect b = SymbolData.GetBounds(symbolCode);

            left.FindTextExtent();
            SetTopLeft(left, b.Left - left.Width - 10, b.Top - height);
            return(left); // we're only doing this to support unit test
        }
Beispiel #15
0
        /// <summary>
        /// Generate the middle label 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>
        /// <returns>
        /// A TextBlock that represents the rendered labels.
        /// </returns>
        internal static TextBlock GenerateMiddle(string symbolCode, IDictionary <string, string> labels)
        {
            if (!SymbolData.Check(ref symbolCode))
            {
                return(null);
            }

            if (labels == null)
            {
                return(null);
            }

            var middle = new TextBlock {
                Style = SymbolData.GetStyle("MiddleLabels")
            };

            bool gotLine = false;

            ProcessLabels(labels, true, new[] { "AA" }, middle, ref gotLine);
            middle.FindTextExtent();
            SetTopLeft(middle, -middle.Width / 2, -middle.Height / 2);
            return(middle);
        }
Beispiel #16
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MilSymbolBase"/> class.
        /// </summary>
        /// <param name="symbolCode">
        /// The symbol code for this symbol.
        /// </param>
        /// <param name="lineBrush">
        /// An optional line brush for outlining the symbol.
        /// </param>
        /// <param name="fillBrush">
        /// An optional fill brush for filling the symbol's background.
        /// </param>
        public MilSymbolBase(string symbolCode, Brush lineBrush, Brush fillBrush)
        {
            if (symbolCode == null)
            {
                this.empty = true;
                return;
            }

            string stencil = CodeToStencil(symbolCode);

            if (MilAppendix.NoTemplate(stencil))
            {
                this.empty = true;
                return;
            }

            this.DataContext = this;

            // Will need to treat weather and tactical graphics carefully
            int schemeKey = CodingScheme.GetCode(symbolCode);

            if (schemeKey == CodingScheme.Weather)
            {
                // These symbols can change color - so we bind to Line and Fill
                if (symbolCode.StartsWith("WAS-WSTS"))
                {
                    if (lineBrush == null)
                    {
                        lineBrush = MilBrush.Rust;
                    }

                    if (fillBrush == null)
                    {
                        fillBrush = MilBrush.Rust;
                    }

                    this.SetLines(lineBrush);
                    this.SetLineFills(lineBrush, fillBrush);
                }

                this.Template = SymbolData.GetControlTemplate(stencil); // gets the template - the main thing
                this.empty    = this.Template == null;
                if (!this.empty)
                {
                    this.SetLimits(symbolCode);
                }

                return;
            }

            // If the standard identity (StandardIdentity) is some type of pending, we'll need the
            // anticipated (dashhed) outline for the frame.
            this.needDashed = SymbolData.IsDashed(symbolCode);

            // There are occasions when we need a line style that matches affiliation and present
            int  dimensionKey = CategoryBattleDimension.GetCode(symbolCode);
            bool needUnframed =
                schemeKey == CodingScheme.TacticalGraphics ||
                dimensionKey == CategoryBattleDimension.BdOther ||
                (schemeKey == CodingScheme.Warfighting &&
                 dimensionKey == CategoryBattleDimension.BdSubsurface);

            if (needUnframed)
            {
                this.unframedLine = MilBrush.GetLinePresent(MilBrush.FindColorScheme(symbolCode));
                this.SetUnframedLines(lineBrush);
            }

            this.SetLines(lineBrush);

            // Get a brush style if user didn't specify
            if (fillBrush == null)
            {
                fillBrush = MilBrush.FindColorScheme(symbolCode);
            }

            if (needUnframed)
            {
                this.SetUnframedLineFills(fillBrush);
            }

            this.SetLineFills(lineBrush, fillBrush);

            this.Template = SymbolData.GetControlTemplate(stencil); // gets the template - the main thing
            this.empty    = this.Template == null;
            if (!this.empty)
            {
                this.SetLimits(symbolCode);
            }
        }
Beispiel #17
0
        /// <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);
        }
Beispiel #18
0
        /// <summary>
        /// Generates the correct combination of task force, installation, and feint dummy for a symbol.
        /// </summary>
        /// <param name="ms">
        /// The symbol to which the generated rendering is attached.
        /// </param>
        /// <param name="symbolCode">
        /// The symbol code for the given symbol
        /// </param>
        /// <returns>
        /// The maximum height of the generated rendering.
        /// </returns>
        internal static double Generate(MilSymbol ms, string symbolCode)
        {
            // This is the maximum height generated by this combination of pieces
            Rect r = ms.BaseRect;

            if (r.IsEmpty)
            {
                return(0);
            }

            double height = r.Top;

            if (!SymbolData.Check(ref symbolCode))
            {
                return(height);
            }

            char code = ModifierCode.GetCode(symbolCode);

            switch (code)
            {
            case ModifierCode.Headquarters:     // headquarters
                ms.AddChild("HQ", GenerateHeadquarters(ms));
                break;

            case ModifierCode.TaskForceHeadquarters:     // task force, headquarters
                ms.AddChild("TF", GenerateTaskForce(ms, out height));
                ms.AddChild("HQ", GenerateHeadquarters(ms));
                break;

            case ModifierCode.FeintDummyHeadquarters:     // feint dummy, headquarters
                ms.AddChild("FD", GenerateFeintDummy(ms, ref height));
                ms.AddChild("HQ", GenerateHeadquarters(ms));
                break;

            case ModifierCode.FeintDummyTaskForceHeadquarters:     // feint dummy, task force, headquarters
                ms.AddChild("TF", GenerateTaskForce(ms, out height));
                ms.AddChild("FD", GenerateFeintDummy(ms, ref height));
                ms.AddChild("HQ", GenerateHeadquarters(ms));
                break;

            case ModifierCode.TaskForce:     // task force
                ms.AddChild("TF", GenerateTaskForce(ms, out height));
                break;

            case ModifierCode.FeintDummy:     // feint dummy
                ms.AddChild("FD", GenerateFeintDummy(ms, ref height));
                break;

            case ModifierCode.FeintDummyTaskForce:     // feint dummy/task force
                ms.AddChild("TF", GenerateTaskForce(ms, out height));
                ms.AddChild("FD", GenerateFeintDummy(ms, ref height));
                break;

            case ModifierCode.Installation:     // installation
                ms.AddChild("Installation", GenerateInstallation(ms, out height));

                // There is an unfortunate overloading of the echelon character in the standard
                if (Echelon.GetCode(symbolCode) == 'B')
                {
                    ms.AddChild("FD", GenerateFeintDummy(ms, ref height));
                }

                break;

            case ModifierCode.Mobility:  // mobility
            case ModifierCode.Towed:     // towed
                break;
            }

            return(height);
        }
Beispiel #19
0
        /// <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)
                                }
                            }
                        }
                    }
                }
            });
        }
Beispiel #20
0
        /// <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);
        }
Beispiel #21
0
        /// <summary>
        /// Generate the labels for the single point weather symbology.
        /// </summary>
        /// <param name="symbolCode">
        /// The weather symbol code.
        /// </param>
        /// <param name="labels">
        /// The dictionary of labels to be displayed with the weather symbology.
        /// </param>
        /// <param name="addChild">
        /// The delegate that will actually add the child to the UIElement.
        /// </param>
        internal static void GenerateWeather(string symbolCode, IDictionary <string, string> labels, AddChild addChild)
        {
            if (!SymbolData.Check(ref symbolCode))
            {
                return;
            }

            if (labels == null)
            {
                return;
            }

            // There are very few weather codes that require labels - so we'll handle them via a case statement
            string label;

            switch (symbolCode)
            {
            case "WOS-HDS---P----":                // X - altitude
            {
                double depth  = 0.0;
                var    ok     = labels.ContainsKey("X") && double.TryParse(labels["X"], out depth);
                var    splits = (ok ? depth.ToString(Culture) : "6.3").Split('.');
                var    meters = IntegerLabel(0, -100, splits[0], "MeterDepthLabel");
                addChild("Meters", meters);

                // Plot the first fractional digit offset
                if (splits.Length > 1)
                {
                    meters.FindTextExtent();
                    addChild(
                        "Decimeters",
                        IntegerLabel(meters.Width / 2, -25, splits[1].Substring(0, 1), "DecimeterDepthLabel"));
                }

                return;
            }

            case "WAS-WSF-LVP----":                // X - altitude
            {
                label = labels.ContainsKey("X") ? labels["X"] : "100";
                addChild("Altitude", IntegerLabel(63, -55, label, "FreezeLabel"));
                return;
            }

            case "WAS-WST-LVP----":                // X - altitude
            {
                label = labels.ContainsKey("X") ? labels["X"] : "380";
                addChild("Altitude", IntegerLabel(0, -61, label, "TropoLabel"));
                return;
            }

            case "WAS-PLT---P----":                // low pressure
            {
                label = labels.ContainsKey("X") ? labels["X"] : "270";
                addChild("Altitude", IntegerLabel(0, -136, label, "PressureLabel"));
                return;
            }

            case "WAS-PHT---P----":                // high pressure
            {
                label = labels.ContainsKey("X") ? labels["X"] : "460";
                addChild("Altitude", IntegerLabel(0, 2, label, "PressureLabel"));
                return;
            }

            case "WAS-WC----P----":
            {
                int cloudCover;     // 0 through 9}
                if (labels.ContainsKey("AA") &&
                    int.TryParse(labels["AA"], out cloudCover))
                {
                    addChild("CloudCover", WindBarb.GenerateCloudCover(2, cloudCover));
                }

                return;
            }

            case "WAS-WP----P----": // wind barb
            {
                int cloudCover;     // 0 through 9}
                if (labels.ContainsKey("AA") &&
                    int.TryParse(labels["AA"], out cloudCover))
                {
                    addChild("CloudCover", WindBarb.GenerateCloudCover(1, cloudCover));
                }

                double speed;            // in knots
                double?speedIn = null;
                if (labels.ContainsKey("Z") &&
                    double.TryParse(labels["Z"], out speed))
                {
                    speedIn = speed;
                }

                bool southernHemisphere = labels.ContainsKey("Y") && labels["Y"].ToUpper() == "S";

                double direction;        // in degrees
                if (labels.ContainsKey("Q") &&
                    double.TryParse(labels["Q"], out direction))
                {
                    addChild("Wind", WindBarb.GenerateWind(speedIn, direction, southernHemisphere));
                }

                return;
            }
            }
        }
Beispiel #22
0
        /// <summary>
        /// Generate the labels for single point technical graphics.
        /// </summary>
        /// <param name="symbolCode">
        /// The symbol code for the technical graphic.
        /// </param>
        /// <param name="labels">
        /// The dictionary of labels for the technical graphic.
        /// </param>
        /// <param name="style">
        /// The style for the labels.
        /// </param>
        /// <param name="addChild">
        /// The delegate that actually adds the label to the UIElement.
        /// </param>
        internal static void GenerateTacticalGraphics(
            string symbolCode, IDictionary <string, string> labels, Style style, AddChild addChild)
        {
            if (!SymbolData.Check(ref symbolCode))
            {
                return;
            }

            if (labels == null)
            {
                return;
            }

            string stencil = MilSymbolBase.CodeToStencil(symbolCode);

            double    extraOffset;
            TextBlock tb;

            // These are special case codes that require labels
            switch (stencil)
            {
            case "G_MPNDP":
            case "G_MPNDA":
            case "G_MPNDT":
            case "G_MPNDE":
            case "G_MPNDB":
            case "G_MPNDO":
            case "G_MPNDD":
            case "G_FPPCS":
            case "G_FPPCB":
            case "G_FPPCR":
            case "G_FPPCH":
            case "G_FPPCL":
                TacticalGraphicsPointLabels(labels, addChild, new[] { "H", "N", "T", "W" }, style);
                break;

            case "G_GPGPP":
                TacticalGraphicsPointLabels(labels, addChild, new[] { "H", "H1", "N", "T", "W-" }, style);
                break;

            case "G_GPGPPK":
            case "G_GPGPPL":
            case "G_GPGPPP":
            case "G_GPGPPR":
            case "G_GPGPPE":
            case "G_GPGPPS":
            case "G_GPGPPA":
            case "G_GPOPP":
            case "G_MPBCP":
            case "G_SPPX":
            case "G_SPPC":
            case "G_SPPY":
            case "G_SPPT":
            case "G_SPPD":
            case "G_SPPE":
            case "G_SPPL":
            case "G_SPPM":
            case "G_SPPR":
            case "G_SPPU":
            case "G_SPPO":
            case "G_SPPI":
            case "G_SPPN":
            case "G_SPPSZ":
            case "G_SPPSA":
            case "G_SPPSB":
            case "G_SPPSC":
            case "G_SPPSD":
            case "G_SPPSE":
            case "G_SPPSF":
            case "G_SPPSG":
            case "G_SPPSH":
            case "G_SPPSI":
            case "G_SPPSJ":
            case "G_SPPAS":
            case "G_SPPAT":
                TacticalGraphicsPointLabels(labels, addChild, new[] { "H", "N", "T", "W-" }, style);
                break;

            case "G_GPGPRI":
                GenerateSingleLabel(labels, "T", 0, -246, 0.5, 0.5, style, addChild);
                break;

            case "G_GPGPH":
                GenerateSingleLabel(labels, "H", 0, 0, 0.5, 0.5, style, addChild);
                break;

            case "G_GPGPPC":
                GenerateSingleLabel(labels, "T", 0, -175, 0.5, 0.5, style, addChild);
                break;

            case "G_GPGPPD":
                GenerateSingleLabel(labels, "T", 0, 0, 0.5, 0.25, style, addChild);
                break;

            case "G_GPGPPW":
                GenerateSingleLabel(labels, "T", 50, 0, 0.0, 0.5, style, addChild);
                break;

            case "G_GPAPP":
            case "G_GPAPC":
                GenerateSingleLabel(labels, "T", 0, 0, 0.5, 0.25, style, addChild);
                break;

            case "G_GPDPT":
                GenerateSingleLabel(labels, "T", 87, -87, 0.5, 0.5, style, addChild);
                break;

            case "G_MPOHTL":
                GenerateSingleLabel(labels, "X", 50, -250, 0.0, 0.0, style, addChild);
                break;

            case "G_MPOHTH":
                GenerateSingleLabel(labels, "X", 50, -230, 0.0, 0.0, style, addChild);
                break;

            case "G_MPNZ":
                GenerateSingleLabel(labels, "W", -110, -300, 1.0, 0.0, style, addChild);
                GenerateSingleLabel(labels, "V", -110, -200, 1.0, 0.0, style, addChild);
                GenerateSingleLabel(labels, "T", -110, -100, 1.0, 0.0, style, addChild);
                GenerateSingleLabel(labels, "H", 110, -300, 0.0, 0.0, style, addChild);
                GenerateSingleLabel(labels, "N", 110, -100, 0.0, 0.0, style, addChild);
                GenerateSingleLabel(labels, "C", 0, -300, 0.5, 1.0, style, addChild);
                tb = GenerateSingleLabel(labels, "Y", 0, 0, 0.5, 0.0, style, addChild);
                tb.FindTextExtent();
                extraOffset = tb != null ? tb.Height : 0.1;
                addChild("Q", GenerateQ(symbolCode, labels, extraOffset));
                break;

            case "G_MPNEB":
                GenerateSingleLabel(labels, "W", -110, -300, 1.0, 0.0, style, addChild);
                GenerateSingleLabel(labels, "T", -110, -100, 1.0, 0.0, style, addChild);
                GenerateSingleLabel(labels, "H", 110, -300, 0.0, 0.0, style, addChild);
                GenerateSingleLabel(labels, "N", 110, -100, 0.0, 0.0, style, addChild);
                tb = GenerateSingleLabel(labels, "Y", 0, 0, 0.5, 0.0, style, addChild);
                tb.FindTextExtent();
                extraOffset = tb != null ? tb.Height : 0.1;
                addChild("Q", GenerateQ(symbolCode, labels, extraOffset));
                break;

            case "G_MPNEC":
                GenerateSingleLabel(labels, "W", -94, -300, 1.0, 0.0, style, addChild);
                GenerateSingleLabel(labels, "T", -94, -100, 1.0, 0.0, style, addChild);
                GenerateSingleLabel(labels, "H", 94, -300, 0.0, 0.0, style, addChild);
                GenerateSingleLabel(labels, "N", 94, -100, 0.0, 0.0, style, addChild);
                tb = GenerateSingleLabel(labels, "Y", 0, 0, 0.5, 0.0, style, addChild);
                tb.FindTextExtent();
                extraOffset = tb != null ? tb.Height : 0.1;
                addChild("Q", GenerateQ(symbolCode, labels, extraOffset));
                break;

            case "G_FPPTS":
                GenerateSingleLabel(labels, "H", 50, 75, 0.0, 0.5, style, addChild);
                GenerateSingleLabel(labels, "H1", -50, 75, 1.0, 0.5, style, addChild);
                GenerateSingleLabel(labels, "T", 50, -75, 0.0, 0.5, style, addChild);
                break;

            case "G_FPPTN":
                GenerateSingleLabel(labels, "T", 50, -75, 0.0, 0.5, style, addChild);
                break;

            case "G_FPPCF":
                GenerateSingleLabel(labels, "T", 50, 0, 0.0, 0.5, style, addChild);
                break;
            }
        }
Beispiel #23
0
        /// <summary>
        /// Generates barge mobility object.
        /// </summary>
        /// <param name="symbolCode">
        /// The symbol code containing the mobility indicator for which to create a mobility Shape.
        /// </param>
        /// <returns>
        /// A Shape object representing the mobility object.
        /// </returns>
        public static Shape GenerateMobility(string symbolCode)
        {
            if (!SymbolData.Check(ref symbolCode))
            {
                return(null);
            }

            if (!Mobility.IsMobility(symbolCode))
            {
                return(null);
            }

            Rect         b      = SymbolData.GetBounds(symbolCode);
            double       bottom = b.Bottom + HalfWidth;
            bool         flat   = SymbolData.IsBaseFlat(symbolCode);
            const double X      = End - Rad;

            switch (Mobility.GetCode(symbolCode))
            {
            case Mobility.WheeledLimited:
                return(GenerateWheels(new[] { -X, X }, bottom));

            case Mobility.WheeledCrossCountry:
                return(GenerateWheels(new[] { -X, 0, X }, bottom));

            case Mobility.Tracked:
                return(GenerateTracked(bottom));

            case Mobility.WheeledTracked:
                return(GenerateWheeledTracked(bottom));

            case Mobility.Towed:
                if (flat)
                {
                    bottom += Rad;
                }

                return(GenerateTowed(bottom));

            case Mobility.Railway:
                return(GenerateWheels(new[] { -X, -X + TwoRad, X - TwoRad, X }, bottom));

            case Mobility.OverSnow:
                if (flat)
                {
                    bottom += TwoRad;
                }

                return(GenerateOverSnow(bottom));

            case Mobility.Sled:
                if (!flat)
                {
                    bottom -= TwoRad;
                }

                return(GenerateSled(bottom));

            case Mobility.PackAnimals:
                return(GeneratePackAnimals(bottom));

            case Mobility.Barge:
                return(GenerateBarge(bottom));

            case Mobility.Amphibious:
                return(GenerateAmphibious(bottom));

            case Mobility.TowedArrayShort:
                return(GenerateArray(new[] { -End - TwoSqr, 0.0, End + TwoSqr }, bottom + ThreeSqr - HalfWidth));

            case Mobility.TowedArrayLong:
                if (!flat)
                {
                    bottom -= Sqr + HalfWidth;
                }

                return(GenerateArray(
                           new[]
                {
                    -End - TwoSqr, -HalfEnd - Sqr, 0.0, HalfEnd + Sqr, End + TwoSqr
                },
                           bottom + ThreeSqr - HalfWidth));
            }

            return(null);
        }