示例#1
0
 /// <summary>
 /// Generates phase lines.
 /// </summary>
 /// <param name="mg">
 /// The MilGraphic associated with the phase lines.
 /// </param>
 /// <param name="anchors">
 /// The map locations of the polyline vertices.
 /// </param>
 /// <param name="points">
 /// The map locations converted to the ResourceDictionary space.
 /// </param>
 /// <returns>
 /// The graphical Path associated with the phase lines.
 /// </returns>
 public static Path GeneratePhaseLine(
     MilGraphic mg,
     IList <ILocation> anchors,
     out IList <Point> points)
 {
     return(MilZone.GenerateLines(mg, false, anchors.Count, anchors, out points));
 }
示例#2
0
        /// <summary>
        /// Set the text labels for the mil air zones, in a text block.
        /// </summary>
        /// <param name="mg">
        /// The MilGraphic associated with the labels.
        /// </param>
        /// <param name="labels">
        /// The label strings.
        /// </param>
        /// <returns>
        /// A TextBlock containing the label strings.
        /// </returns>
        private static TextBlock GenerateLabels(MilGraphic mg, string[] labels)
        {
            var tb = new TextBlock
            {
                Style      = SymbolData.GetStyle("BT20"),
                Foreground = mg.ContentControl.Brush,
            };

            tb.SetBinding(UIElement.VisibilityProperty,
                          new Binding {
                Source = mg.TextVisibility, Mode = BindingMode.OneWay
            });

            var count = labels.Length;

            for (int i = 0; i < count; i++)
            {
                tb.Inlines.Add(new Run {
                    Text = labels[i]
                });
                if (i < count - 1)
                {
                    tb.Inlines.Add(new LineBreak());
                }
            }

            tb.FindTextExtent();
            tb.SetValue(Canvas.TopProperty, mg.LabelOffset.Y * HalfSize);
            tb.SetValue(Canvas.LeftProperty, (mg.LabelOffset.X * HalfSize) - (tb.Width / 2.0));

            return(tb);
        }
示例#3
0
        /// <summary>
        /// Adds a generic zone with labels to the MilGraphic and returns the list of transformed points.
        /// </summary>
        /// <param name="mg">
        /// The MilGraphic to receive the zone and the labels.
        /// </param>
        /// <param name="anchors">
        /// The list of map locations making up the zone.
        /// </param>
        /// <param name="labels">
        /// The labels associated with the zone.
        /// </param>
        /// <returns>
        /// The list of map locations transformed into ResourceDictionary space.
        /// </returns>
        public static IList <Point> AddZone(MilGraphic mg, IList <ILocation> anchors, string[] labels)
        {
            IList <Point> points;

            ApplyOffset(mg);    // applies offset to any existing text
            mg.AddChild("Boundary", GenerateLines(mg, true, anchors.Count, anchors, out points));
            mg.AddChild("Labels", GenerateLabels(mg, labels));
            return(points);
        }
示例#4
0
        /// <summary>
        /// Set the text labels for the mil lines, in a text block
        /// </summary>
        /// <param name="mg">
        /// The MilGraphic associated with the labels.
        /// </param>
        /// <param name="labels">
        /// The label strings.
        /// </param>
        /// <param name="pointStart">
        /// The starting point of the line to label.
        /// </param>
        /// <param name="pointEnd">
        /// The ending point of the line to label.
        /// </param>
        /// <param name="origin">
        /// The origin coordinate for the object as a whole.
        /// </param>
        /// <param name="offset">
        /// The multiplicative offset for the object as a whole.
        /// </param>
        /// <returns>
        /// The TextBlock representing the labels.
        /// </returns>
        public static TextBlock GenerateLabels(
            MilGraphic mg, string[] labels, Point pointStart, Point pointEnd, Point origin, Point offset)
        {
            bool            leftSide;
            MatrixTransform mt = GenerateLabelTransform(pointStart, pointEnd, origin, out leftSide);
            var             tb = new TextBlock
            {
                Style           = SymbolData.GetStyle("BT20"),
                RenderTransform = mt,
                Foreground      = mg.ContentControl.Brush,
                Name            = "Skip" + counter++
            };

            tb.SetBinding(UIElement.VisibilityProperty,
                          new Binding {
                Source = mg.TextVisibility, Mode = BindingMode.OneWay
            });

            var count = labels.Length;

            for (int i = 0; i < count; i++)
            {
                tb.Inlines.Add(new Run {
                    Text = labels[i]
                });
                if (i < count - 1)
                {
                    tb.Inlines.Add(new LineBreak());
                }
            }

            tb.FindTextExtent();
            double left;

            // if (offset.Y == 0.5)
            if (Math.Abs(offset.Y - 0.5) <= double.Epsilon)
            {
                left = leftSide ? tb.Width : 0.0;
            }
            else
            {
                left = leftSide ? 0.0 : tb.Width;
            }

            //// if (left != 0)
            ////if (Math.Abs(left) > double.Epsilon)
            ////{
            ////    tb.TextAlignment = TextAlignment.Right;
            ////}

            ////Point p = mt.Matrix.Rotate(new Point(tb.Height / 2.0, left));
            Point p = mt.Matrix.Rotate(new Point(offset.Y * tb.Height, offset.X * left));

            tb.SetValue(Canvas.TopProperty, pointStart.Y - p.X);
            tb.SetValue(Canvas.LeftProperty, pointStart.X - p.Y);
            return(tb);
        }
示例#5
0
        /// <summary>
        /// Plots a 3+ point tactical graphic
        /// </summary>
        /// <param name="sc">
        /// The symbol code to plot.
        /// </param>
        /// <param name="loc">
        /// The location collection that defines the spatial extent of the symbol.
        /// </param>
        public void PlotSymbol(string sc, ILocationCollection loc)
        {
            this.pg = new MilGraphic(sc, loc);
            ToolTipService.SetToolTip(this.pg, sc);
            this.milsymLayer.AddSymbol(this.pg);

            // Draw the base and transformed base vectors
            this.polyLayer.AddPolyline(loc, new SolidColorBrush(Colors.Blue));
        }
示例#6
0
        /// <summary>
        /// Plots a 3+ point tactical graphic
        /// </summary>
        /// <param name="symbolCode">
        /// The symbol code to plot.
        /// </param>
        /// <param name="triads">
        /// The map locations for the graphic.
        /// </param>
        /// <param name="offset">
        /// An offset used to displace the graphic.
        /// </param>
        public void PlotSymbol(string symbolCode, ILocationCollection[] triads, Point offset)
        {
            var sc = symbolCode;

            foreach (var old in triads)
            {
                sc = NextCode(sc);

                var lc = this.milsymFactory.LocationCollection();
                foreach (var loc in old)
                {
                    lc.Add(this.milsymFactory.Location(Order.LatLon, loc.Latitude - offset.Y, loc.Longitude + offset.X));
                }

                var saveLoc = this.milsymFactory.LocationCollection();

                // Test to make sure presentation is still consistent with points re-ordered
                if (lc.Count == 3)
                {
                    saveLoc.Add(lc[2]);
                    saveLoc.Add(lc[1]);
                    saveLoc.Add(lc[0]);
                }
                else
                {
                    foreach (var loc in lc)
                    {
                        saveLoc.Add(loc); // can't re-order with four points
                    }
                }

                var spline = sc.Contains("GFGPGLL");
                var pg     = new MilGraphic(
                    sc,
                    saveLoc,
                    labelOffset: new Offset(-0.25, 0.25),
                    labelString: "T=Hello;T1=Denver;X=2000' AGL;X1=4000' AGL",
                    labelW: new DateTime(2010, 12, 18).ToString(CultureInfo.InvariantCulture),
                    labelW1: new DateTime(2010, 12, 19).ToString(CultureInfo.InvariantCulture),
                    isSpline: spline);

                ToolTipService.SetToolTip(pg, sc);
                this.milsymLayer.AddSymbol(pg);

                // Draw the base and transformed base vectors
                //this.polyLayer.AddPolyline(saveLoc, new SolidColorBrush(Colors.Orange));
                //this.polyLayer.AddPolyline(lc, new SolidColorBrush(Colors.Purple));
            }
        }
示例#7
0
        /// <summary>
        /// Apply an offset to all the text elements from the ResourceDictionary's template
        /// </summary>
        /// <param name="mg">
        /// The MilGraphic containing the text elements.
        /// </param>
        private static void ApplyOffset(MilGraphic mg)
        {
            var canvas = VisualTreeHelper.GetChild(mg.ContentControl, 0) as Canvas;

            if (canvas == null)
            {
                return;
            }

            foreach (var tb in canvas.Children.OfType <TextBlock>())
            {
                tb.FindTextExtent();
                tb.SetValue(Canvas.TopProperty, (mg.LabelOffset.Y * HalfSize) - tb.Height);
                tb.SetValue(Canvas.LeftProperty, (mg.LabelOffset.X * HalfSize) - (tb.Width / 2.0));
            }
        }
示例#8
0
        /// <summary>
        /// Adds an air zone to the MilGraphic and returns the list of transformed points.
        /// </summary>
        /// <param name="mg">
        /// The MilGraphic to receive the air zone.
        /// </param>
        /// <param name="anchors">
        /// The list of map locations making up the zone.
        /// </param>
        /// <returns>
        /// The list of map locations transformed into ResourceDictionary space.
        /// </returns>
        public static IList <Point> AddAirZone(MilGraphic mg, IList <ILocation> anchors)
        {
            IList <Point> points;

            ApplyOffset(mg);    // applies offset to any existing text
            mg.AddChild("Boundary", GenerateLines(mg, true, anchors.Count, anchors, out points));
            var labels = new[]
            {
                mg.LabelT,
                "Min Alt: " + mg.LabelX,
                "Max Alt: " + mg.LabelX1,
                "Time from: " + mg.LabelW,
                "Time to: " + mg.LabelW1
            };

            mg.AddChild("Labels", GenerateLabels(mg, labels));
            return(points);
        }
示例#9
0
        /// <summary>
        /// A generic polyline drawing method with labels at either end of end
        /// </summary>
        /// <param name="mg">
        /// The MilGraphic for the associated polyline.
        /// </param>
        /// <param name="gl">
        /// The actual line generator to call.
        /// </param>
        /// <param name="labels">
        /// The labels for the line ends.
        /// </param>
        /// <param name="anchors">
        /// The map locations of the vertices.
        /// </param>
        /// <returns>
        /// The map locations converted to the ResourceDictionary space.
        /// </returns>
        public static IList <Point> AddLines(
            MilGraphic mg, GenerateLines gl, string[] labels, IList <ILocation> anchors)
        {
            IList <Point> points;

            mg.AddChild("Boundary", gl(mg, anchors, out points));

            if (labels != null)
            {
                var   c      = points.Count;
                Point origin = points[0];

                // Offset = new Point(1.0, 0.5)
                mg.AddChild("StartLabel", GenerateLabels(mg, labels, points[0], points[1], origin, new Point(1.0, 0.5)));
                mg.AddChild("EndLabel", GenerateLabels(mg, labels, points[c - 1], points[c - 2], origin, new Point(1.0, 0.5)));
            }

            return(points);
        }
示例#10
0
        /// <summary>
        /// Adds a weapons free zone to the MilGraphic and returns the list of transformed points.
        /// </summary>
        /// <param name="mg">
        /// The MilGraphic to receive the weapons free zone.
        /// </param>
        /// <param name="anchors">
        /// The list of map locations making up the zone.
        /// </param>
        /// <returns>
        /// The list of map locations transformed into ResourceDictionary space.
        /// </returns>
        public static IList <Point> AddWeaponsFreeZone(MilGraphic mg, IList <ILocation> anchors)
        {
            IList <Point> points;

            ApplyOffset(mg);    // applies offset to any existing text
            Path path = GenerateLines(mg, true, anchors.Count, anchors, out points);

            path.Fill = HatchBrush(mg.ContentControl.Brush);
            mg.AddChild("Boundary", path);
            var labels = new[]
            {
                mg.LabelT,
                "Time from: " + mg.LabelW,
                "Time to: " + mg.LabelW1
            };

            mg.AddChild("Labels", GenerateLabels(mg, labels));
            return(points);
        }
示例#11
0
 /// <summary>
 /// Generates obstacle lines for the associated MilGraphic.
 /// </summary>
 /// <param name="mg">
 /// The associated MilGraphic.
 /// </param>
 /// <param name="anchors">
 /// The map locations of the vertices.
 /// </param>
 /// <returns>
 /// The map locations converted to the ResourceDictionary space.
 /// </returns>
 public static IList <Point> AddObstacles(MilGraphic mg, IList <ILocation> anchors)
 {
     return(AddLines(mg, GenerateFlot, null, anchors));
 }
示例#12
0
 /// <summary>
 /// Generates forward line of own troops for the associated MilGraphic.
 /// </summary>
 /// <param name="mg">
 /// The associated MilGraphic.
 /// </param>
 /// <param name="anchors">
 /// The map locations of the vertices.
 /// </param>
 /// <returns>
 /// The map locations converted to the ResourceDictionary space.
 /// </returns>
 public static IList <Point> AddFlot(MilGraphic mg, IList <ILocation> anchors)
 {
     return(AddLines(mg, GenerateFlot, new[] { "FLOT" }, anchors));
 }
示例#13
0
 /// <summary>
 /// Generates phase lines for the associated MilGraphic.
 /// </summary>
 /// <param name="mg">
 /// The associated MilGraphic.
 /// </param>
 /// <param name="anchors">
 /// The map locations of the vertices.
 /// </param>
 /// <returns>
 /// The map locations converted to the ResourceDictionary space.
 /// </returns>
 public static IList <Point> AddPhaseLine(MilGraphic mg, IList <ILocation> anchors)
 {
     return(AddLines(mg, GeneratePhaseLine, new[] { "PL " + mg.LabelT }, anchors));
 }
示例#14
0
 /// <summary>
 /// Generates boundary lines for the associated MilGraphic.
 /// </summary>
 /// <param name="mg">
 /// The associated MilGraphic.
 /// </param>
 /// <param name="anchors">
 /// The map locations of the vertices.
 /// </param>
 /// <returns>
 /// The map locations converted to the ResourceDictionary space.
 /// </returns>
 public static IList <Point> AddBoundary(MilGraphic mg, IList <ILocation> anchors)
 {
     return(AddLines(mg, GenerateBoundaryLine, null, anchors));
 }
示例#15
0
 /// <summary>
 /// Generates phase lines for the associated MilGraphic.
 /// </summary>
 /// <param name="mg">
 /// The associated MilGraphic.
 /// </param>
 /// <param name="anchors">
 /// The map locations of the vertices.
 /// </param>
 /// <param name="header">
 /// The labels.
 /// </param>
 /// <returns>
 /// The map locations converted to the ResourceDictionary space.
 /// </returns>
 public static IList <Point> AddPhaseLineType(MilGraphic mg, IList <ILocation> anchors, string header)
 {
     return(AddLines(mg, GeneratePhaseLine, new[] { header, "(PL " + mg.LabelT + ")" }, anchors));
 }
示例#16
0
        /// <summary>
        /// AddArrow generates the missing points for an arrow's tail as appropriate for Bing's mercator projection
        /// </summary>
        /// <param name="mg">
        /// The MilGraphic representing the arrow shape.
        /// </param>
        /// <param name="inPoints">
        /// The points from the resource dictionary entry for the particular symbol.
        /// </param>
        /// <param name="inAnchors">
        /// The points representing the map coordinates of the arrow's head to tail points.
        /// </param>
        /// <returns>
        /// A list of points that represent the head to tail coordinates of the arrow
        /// </returns>
        public static IList <Point> AddArrow(
            MilGraphic mg, IList <Point> inPoints, IList <ILocation> inAnchors)
        {
            ////                  ·N-1
            ////                  |\
            ////      ------------  \ 
            ////      ·1             ·0
            ////      ------------  /
            ////                  |/

            // First point [0] is the head of the arrow.
            // Second point [1] is the end of the first arrow segment.
            // Subsequent points define additional arrow segment ends.
            // Last point [N - 1] is the top of the arrowhead (different from 2525B).
            // Looks like the height of the arrow body is 1/2 of the height of the arrow head.

            // Convert the points into "pixel" space. To keep a constant arrow
            // width it makes more sense to do the computations in this space.
            var           count  = mg.Anchors.Count;
            IList <Point> points = MapHelper.LatLonsToPixels(mg.Anchors, 4.0);

            // This is the projection of the arrowhead onto the arrow baseline
            var pt = MapHelper.CalculateProjection(points[0], points[1], points[count - 1]);

            // The origin is the first point in this points array
            var origin = points[0];

            // Compute half the width of the arrow
            var distance = 0.5 * PointHelper.Magnitude(pt, points[count - 1]);

            // Let's go ahead and compute the unit vectors in the direction
            // of each vector making up the arrow, starting at the head and
            // moving towards the tail.
            var unitVectors = new Point[count - 2];

            for (int i = 0; i < count - 2; i++)
            {
                unitVectors[i] = MapHelper.Normalize(points[i], points[i + 1]);
            }

            var leftNormal  = new Point[count - 2];
            var rightNormal = new Point[count - 2];

            // Now compute the "left" and "right" perpendicular unit vectors
            Point normal;

            for (int i = 0; i < count - 2; i++)
            {
                // The rightNormal vectors cross with the unit vector to give a +1 in Z
                // The leftNormal vectors cross with the unit vector to give a -1 in Z
                normal = new Point(unitVectors[i].Y, -unitVectors[i].X);
                var cross = (normal.X * unitVectors[i].Y) - (normal.Y * unitVectors[i].X);
                leftNormal[i]  = (cross < 0.0) ? normal : new Point(-normal.X, -normal.Y);
                rightNormal[i] = (cross < 0.0) ? new Point(-normal.X, -normal.Y) : normal;
            }

            // We're not mitering any of these angles - that's up to the user.
            // So we're bisecting the angle between two vectors and moving
            // out a distance based on the tangent of that angle.
            // This gives us the outside point.
            // So outsidePoint = point[i] + d * outsideVector[i-1] + d / tan(<) * unitVector[i-1]
            // where < is acos(dot(unitVector[i-1], unitVector[i])).
            //
            //                         ______. d * tan(<)
            //                        d|<
            //        i-1------->-------+i
            //                          \
            //                           \
            //                             i+1

            // Need to flip the starting points if Aviation, Airborne or RotaryWing
            bool flip = mg.StencilType == "AxisOfAdvanceAviation" ||
                        mg.StencilType == "AxisOfAdvanceAirborne" ||
                        mg.StencilType == "AxisOfAdvanceRotaryWing";
            var fwd = PointHelper.LinearCombination(pt, distance, leftNormal[0]);
            var bck = PointHelper.LinearCombination(pt, distance, rightNormal[0]);

            // Start the arrow's body - first point defined by the top of the arrowhead
            var arrow = new List <Point> {
                flip?bck : fwd
            };
            var backArrow = new List <Point> {
                flip?fwd : bck
            };

            for (int i = 0; i < count - 2; i++)
            {
                // Get bisected angle
                // Use the half-angle tangent formula here instead of the brute force method
                // var angle = Math.Atan2(
                //    unitVectors[i].Y * unitVectors[i + 1].X - unitVectors[i].X * unitVectors[i + 1].Y,
                //    unitVectors[i].X * unitVectors[i + 1].X + unitVectors[i].Y * unitVectors[i + 1].Y) / 2.0;
                // var tangent = Math.Tan(angle);
                var tangent = (i == count - 3) ? 0.0 :
                              ((unitVectors[i].Y * unitVectors[i + 1].X) - (unitVectors[i].X * unitVectors[i + 1].Y)) /
                              ((unitVectors[i].X * unitVectors[i + 1].X) + (unitVectors[i].Y * unitVectors[i + 1].Y) + 1.0);

                // points[i+1] + distance * (leftNormal[i] + tangent * unitVectors[i])
                arrow.Add(
                    PointHelper.LinearCombination(
                        points[i + 1], distance, PointHelper.LinearCombination(leftNormal[i], tangent, unitVectors[i])));

                // points[i+1] + distance * (rightNormal[i] - tangent * unitVectors[i])
                backArrow.Add(
                    PointHelper.LinearCombination(
                        points[i + 1], distance, PointHelper.LinearCombination(rightNormal[i], -tangent, unitVectors[i])));
            }

            points.Clear();

            count = backArrow.Count;
            for (int i = count - 1; i >= 0; i--)
            {
                arrow.Add(backArrow[i]);
            }

            // Add the origin and the projected arrowhead point to the list of arrow points.
            // We need to get these points transformed and this
            // is currently the only way to do it.
            // We'll have to remove them later from the list.
            arrow.Add(origin);
            arrow.Add(pt);

            mg.IsSpline = false;
            IList <ILocation> anchors = arrow.Select(a => MapHelper.PixelToLatLon(a, 4.0)).ToList();

            Path path = MilZone.GenerateLines(mg, false, anchors.Count - 2, anchors, out points);

            // OK, let's record the transformed origin and kill these extra points.
            int index = points.Count - 1;

            pt = points[index];
            points.RemoveAt(index);
            anchors.RemoveAt(index);
            index--;
            origin = points[index];
            points.RemoveAt(index);
            anchors.RemoveAt(index);

            double newScaleFactor;

            MilGraphic.FullTransformation(mg, path, null, points, anchors, origin, out newScaleFactor);

            // We also need the oldScaleFactor - the scaleFactor that the rest of the graphic will be using.
            double oldScaleFactor;

            MilGraphic.ComputeScales(MapHelper.ComputeTransform(inPoints, inAnchors), out oldScaleFactor);

            // OK now we need to scale the transform matrix relative to the oldScaleFactor
            var r = newScaleFactor / oldScaleFactor;

            SetPathMatrix(r, path);
            mg.AddChild("Boundary", path);
            if (mg.StencilType == "AxisOfAdvanceForFeint")
            {
                // We need to add LabelT but the position (right after the projection
                // of the arrow head onto the main arrow axis) needs to be scaled according
                // to our transformation which uses the "r" scale factor.
                var pointNew = PointHelper.LinearCombination(origin, r, PointHelper.Minus(pt, origin));
                mg.AddChild(
                    "Label",
                    MilLine.GenerateLabels(mg, new[] { mg.LabelT }, pointNew, origin, origin, new Point(1.0, 0.5)));
            }
            else if (mg.StencilType == "AxisOfAdvanceRotaryWing")
            {
                // Add rotary wing symbol by appending to existing path
                AddRotaryWing(path, points);
            }

            return(points);
        }
示例#17
0
        /// <summary>
        /// The main zone generating method.
        /// </summary>
        /// <param name="mg">
        /// The MilGraphic associated with the zone to be generated.
        /// </param>
        /// <param name="isClosed">
        /// Whether or not the zone outline is to be closed since this method can be used for polylines as well.
        /// </param>
        /// <param name="count">
        /// The count of the map locations making up the zone.
        /// </param>
        /// <param name="anchors">
        /// The map locations making up the zone.
        /// </param>
        /// <param name="pointAnchors">
        /// The locations in ResourceDictionary space.
        /// </param>
        /// <returns>
        /// A Path representing the map locations, to be associated with the MilGraphic.
        /// </returns>
        public static Path GenerateLines(
            MilGraphic mg,
            bool isClosed,        // do we close the boundary
            int count,            // the number of transformed points to use in boundary
            IList <ILocation> anchors,
            out IList <Point> pointAnchors)
        {
            IList <Point> pointCp1 = null;
            IList <Point> pointCp2 = null;

            pointAnchors = MapHelper.LatLonsToPixels(anchors, 2.0);

            // Need to convert the cardinal spline points into Bezier spline control points
            if (mg.IsSpline)
            {
                ClosedBezierSpline.GetCurveControlPoints(count, pointAnchors, out pointCp1, out pointCp2);
            }

            ScaleData(pointAnchors, pointCp1, pointCp2);

            // Generate Bezier or line segments for insertion into a figure collection
            PathFigureCollection figures;

            if (mg.IsSpline)
            {
                figures = new PathFigureCollection
                {
                    new PathFigure
                    {
                        Segments = GenerateBezierSegments(count, pointAnchors, pointCp1, pointCp2, isClosed)
                    }
                };
            }
            else
            {
                switch (mg.StencilType)
                {
                case "ObstacleZone":
                case "ObstacleBelt":
                    pointAnchors.Add(pointAnchors[0]);
                    figures = MilLine.GenerateDecoratedSegments(
                        mg, DecoratedType.Triangular, false, count + 1, pointAnchors);
                    pointAnchors.RemoveAt(count);
                    break;

                case "ObstacleRestrictedArea":
                case "ObstacleFreeArea":
                    pointAnchors.Add(pointAnchors[0]);
                    figures = MilLine.GenerateDecoratedSegments(
                        mg, DecoratedType.Triangular, true, count + 1, pointAnchors);
                    pointAnchors.RemoveAt(count);
                    break;

                case "Boundaries":
                    figures = MilLine.GenerateDecoratedSegments(mg, DecoratedType.Echelon, true, count, pointAnchors);
                    var labels      = new[] { mg.LabelT, Echelon.GetEchelonSymbol(mg.SymbolCode), mg.LabelT1 };
                    int figureCount = figures.Count;
                    for (int i = 0; i < figureCount - 1; i++)
                    {
                        var pls = figures[i].Segments[0] as PolyLineSegment;
                        if (pls == null)
                        {
                            continue;
                        }

                        var pc = pls.Points.Count - 1;
                        if (pc > 0)
                        {
                            mg.AddChild(
                                "Label" + i,
                                MilLine.GenerateLabels(
                                    mg, labels, pls.Points[pc], pls.Points[pc - 1], pointAnchors[0], new Point(1.0, 0.5)));
                        }
                    }

                    break;

                default:
                    figures = new PathFigureCollection
                    {
                        new PathFigure
                        {
                            Segments = GeneratePolygonSegments(count, pointAnchors)
                        }
                    };
                    break;
                }
            }

            // In most cases we have a single figure
            figures[0].StartPoint = pointAnchors[0];
            figures[0].IsClosed   = isClosed;

            var path = new Path
            {
                Data = new PathGeometry {
                    Figures = figures
                },
                Style = mg.ContentControl.UnframedLine
            };

            if (mg.StencilType == "ObstacleRestrictedArea")
            {
                path.Fill = HatchBrush(mg.ContentControl.Brush);
            }
#if WINDOWS_UWP
            path.SetBinding(Shape.StrokeThicknessProperty, new Binding()
            {
                Path = new PropertyPath("LineThickness"), Source = mg.ContentControl
            });
#else
            path.SetBinding(Shape.StrokeThicknessProperty, new Binding("LineThickness")
            {
                Source = mg.ContentControl
            });
#endif
            return(path);
        }
示例#18
0
        /// <summary>
        /// Generates multiple types of decorated lines.
        /// </summary>
        /// <param name="mg">
        /// The MilGraphic associated with the decorated lines.
        /// </param>
        /// <param name="anchors">
        /// The map locations of the polyline vertices.
        /// </param>
        /// <param name="points">
        /// The map locations converted to the ResourceDictionary space.
        /// </param>
        /// <returns>
        /// The graphical Path associated with the decorated lines.
        /// </returns>
        public static Path GenerateFlot(
            MilGraphic mg,
            IList <ILocation> anchors,
            out IList <Point> points)
        {
            // Convert the points into "pixel" space. To keep a constant arrow
            // width it makes more sense to do the computations in this space.
            var count = anchors.Count;

            points = MapHelper.LatLonsToPixels(anchors, 4.0);

            // Convert everything into a Cartesian space about [-300, 300] in each direction
            MilZone.ScaleData(points, null, null);

            // Now generate a collection of arcs along these line segments
            var style = mg.ContentControl.UnframedLine;

            PathFigureCollection figures;

            if (mg.StencilType == "FortifiedArea")
            {
                points.Add(points[0]);
                figures = GenerateDecoratedSegments(mg, DecoratedType.Square, false, count + 1, points);
                points.RemoveAt(count);
            }
            else if (mg.StencilType == "ObstacleLine")
            {
                figures = GenerateDecoratedSegments(mg, DecoratedType.Triangular, false, count, points);
            }
            else if (mg.StencilType == "AntiTankDitchUnderConstruction")
            {
                figures = GenerateDecoratedSegments(mg, DecoratedType.Saw, false, count, points);
            }
            else if (mg.StencilType == "AntiTankDitchComplete")
            {
                figures = GenerateDecoratedSegments(mg, DecoratedType.Saw, false, count, points);
                style   = mg.ContentControl.UnframedLineFill;
            }
            else if (mg.StencilType == "AntiTankDitchAntiMine")
            {
                figures = GenerateDecoratedSegments(mg, DecoratedType.SolidTriangular, false, count, points);
                style   = mg.ContentControl.UnframedLineFill;
            }
            else
            {
                figures = new PathFigureCollection {
                    new PathFigure {
                        Segments = GenerateArcSegments(count, points)
                    }
                };
            }

            // Set the start point for the first figure (usually there is only one figure)
            figures[0].StartPoint = points[0];
            var path = new Path
            {
                Data = new PathGeometry {
                    Figures = figures
                },
                Style = style
            };

#if WINDOWS_UWP
            path.SetBinding(Shape.StrokeThicknessProperty, new Binding()
            {
                Path = new PropertyPath("LineThickness"), Source = mg.ContentControl
            });
#else
            path.SetBinding(Shape.StrokeThicknessProperty, new Binding("LineThickness")
            {
                Source = mg.ContentControl
            });
#endif
            return(path);
        }
示例#19
0
        /// <summary>
        /// Generate a collection of decorated segments along a polyline
        /// </summary>
        /// <param name="mg">
        /// The MilGraphic to receive the decorated line segments.
        /// </param>
        /// <param name="type">
        /// The type of decoration from the enumerated values.
        /// </param>
        /// <param name="drawInside">
        /// Whether to draw the features on the "interior" of the figure.
        /// </param>
        /// <param name="count">
        /// The vertex count.
        /// </param>
        /// <param name="pts">
        /// The array of vertices.
        /// </param>
        /// <returns>
        /// A graphic object representing the decorated lines.
        /// </returns>
        public static PathFigureCollection GenerateDecoratedSegments(
            MilGraphic mg, DecoratedType type, bool drawInside, int count, IList <Point> pts)
        {
            // Most of the time we'll have a single PathFigure consisting
            // of a single PolyLineSegment.
            // But occasionally the PathFigure will have more segments
            // and occasionally there will be more than one path figure.
            var pfc = new PathFigureCollection();

            // Collect the points we're passing through
            var ptsLoc = new PointCollection();

            // In many cases there will be only one polyline segment
            // but sometimes we'll have multiple segments which may,
            // or may not require multiple paths.
            var segments = new PathSegmentCollection();

            double totalHypot;
            var    hypots  = CalculateHypots(count, pts, out totalHypot);
            var    arcSize = 0.5 * (totalHypot / Math.Max(1, (int)(totalHypot / (2.0 * ArcSize))));

            bool odd = true;        // switch between even and odd

            int totalCount = 0;

            var leftOver = 0.0;

            // Break each segment up into parts
            for (var i = 1; i < count; ++i)
            {
                // Get the angle of the line segment
                Point para    = MapHelper.Normalize(pts[i - 1], pts[i]);
                var   perp    = new Point(-para.Y, para.X);
                Point outside = PointHelper.Add(para, perp);
                if (drawInside != PointHelper.PointInPolygon(outside, count - 1, pts))
                {
                    perp = new Point(para.Y, -para.X);
                }

                // Need to round here to make sure we get last segment
                var segNum = (int)Math.Floor((hypots[i] + leftOver + 0.5) / arcSize);

                // Advance along the line segment using the arcSize
                var   nextPt = pts[i - 1];
                Point lastPt = nextPt;
                for (var j = 0; j < segNum; j++)
                {
                    var stepSize = (j == 0) ? arcSize - leftOver : arcSize;
                    nextPt = PointHelper.LinearCombination(nextPt, stepSize, para);
                    if (type == DecoratedType.Saw)
                    {
                        var mid = PointHelper.MidPoint(nextPt, lastPt);
                        ptsLoc.Add(PointHelper.LinearCombination(mid, stepSize, perp));
                    }

                    if (odd)
                    {
                        // Add the mines to the anti-tank ditch
                        if (type == DecoratedType.SolidTriangular)
                        {
                            var r    = stepSize / 3.0;
                            var p1   = PointHelper.MidPoint(nextPt, lastPt);
                            var p2   = PointHelper.LinearCombination(p1, r, perp);
                            var p3   = PointHelper.LinearCombination(p2, 2.0 * r, perp);
                            var size = new Size(r, r);
                            ptsLoc.Add(p1);
                            ptsLoc.Add(p2);
                            segments.Add(new PolyLineSegment {
                                Points = ptsLoc
                            });
                            segments.Add(new ArcSegment {
                                Point = p3, Size = size
                            });
                            segments.Add(new ArcSegment {
                                Point = p2, Size = size
                            });
                            ptsLoc = new PointCollection {
                                p1
                            };
                        }
                    }
                    else
                    {
                        if (type == DecoratedType.Triangular ||
                            type == DecoratedType.SolidTriangular)
                        {
                            var mid = PointHelper.MidPoint(nextPt, lastPt);
                            ptsLoc.Add(PointHelper.LinearCombination(mid, stepSize, perp));
                        }
                        else if (type == DecoratedType.Square)
                        {
                            ptsLoc.Add(PointHelper.LinearCombination(lastPt, stepSize, perp));
                            ptsLoc.Add(PointHelper.LinearCombination(nextPt, stepSize, perp));
                        }
                    }

                    if (type == DecoratedType.Echelon)
                    {
                        // Skip every fifth line segment - approximately.
                        // Ignore the fixups at the vertices.
                        if ((++totalCount % 5) == 0)
                        {
                            segments.Add(new PolyLineSegment {
                                Points = ptsLoc
                            });
                            pfc.Add(new PathFigure {
                                Segments = segments, StartPoint = ptsLoc[0]
                            });
                            ptsLoc   = new PointCollection();
                            segments = new PathSegmentCollection();
                        }

                        odd = false;    // force odd to always be true - picks up every vertex
                    }

                    ptsLoc.Add(nextPt);
                    odd    = !odd;
                    lastPt = nextPt;
                }

                if (odd && PointHelper.Magnitude(nextPt, pts[i]) > 1.0)
                {
                    ptsLoc.Add(pts[i]);
                }

                leftOver = hypots[i] - MapHelper.Hypoteneuse(nextPt, pts[i - 1]);
            }

            if (type == DecoratedType.Saw ||
                type == DecoratedType.SolidTriangular)
            {
                for (int i = count - 2; i >= 0; i--)
                {
                    ptsLoc.Add(pts[i]);
                }
            }

            if (ptsLoc.Count > 0)
            {
                segments.Add(new PolyLineSegment {
                    Points = ptsLoc
                });
            }

            if (segments.Count > 0)
            {
                var pf = new PathFigure {
                    Segments = segments
                };

                // For the echelon type we need to set the start point of this segment
                if (type == DecoratedType.Echelon)
                {
                    pf.StartPoint = ptsLoc[0];
                }

                pfc.Add(pf);
            }

            return(pfc);
        }