public static Geometry CreateGeometry(GunPitchLimitsComponent traverse,
                                              TurretYawLimits yawLimits,
                                              double size,
                                              Point center,
                                              double geometryRotation = 0,
                                              double margin           = 0,
                                              double padding          = 0,
                                              Func <double, double> verticalTraverseTransform = null)
        {
            if (verticalTraverseTransform == null)
            {
                verticalTraverseTransform = GunTraverseHelper.DefaultVerticalTraverseTransform;
            }

            if (traverse.HasSingularValue && yawLimits.Range == 360)
            {
                var radius = size / 2 - margin;
                return(new EllipseGeometry(center, radius, radius));
            }
            else
            {
                var maxRadiusInDegrees = traverse.GetMaxValue();
                var scale = (size / 2 - margin - padding) / maxRadiusInDegrees;

                Func <double, double> radiusConverter = r => padding + Math.Max(verticalTraverseTransform(r) * scale, 0);

                return(GunTraverseHelper.CreateGeometry(traverse, yawLimits, center, radiusConverter, geometryRotation));
            }
        }
        public void SetTraverse(GunPitchLimitsComponent gunPitch, TurretYawLimits turretYaw)
        {
            this.CurveCanvas.Children.Clear();

            if (gunPitch == null)
            {
                return;
            }

            var traverseFigureStrokeStyle = this.FindResource("TraverseFigure") as Style;

            var maxRadius = gunPitch.GetMaxValue();
            //maxRadius = Math.Ceiling(maxRadius / 5) * 5;
            const double margin = 1;

            var scale      = 80 / (maxRadius + margin);
            var size       = scale * maxRadius * 2;
            var center     = new Point(100, 100);
            var figurePath = new Path
            {
                Data = GunTraverseHelper.CreateGeometry(gunPitch,
                                                        turretYaw,
                                                        size,
                                                        center,
                                                        90,
                                                        scale * margin,
                                                        verticalTraverseTransform: v => v + 1),
                Style = traverseFigureStrokeStyle
            };

            this.CurveCanvas.Children.Add(figurePath);

            // draw references
            var thinReferenceGeometry  = new GeometryGroup();
            var thickReferenceGeometry = new GeometryGroup();

            const double referenceCircleGap     = 20;
            const double halfReferenceCircleGap = referenceCircleGap / 2;

            var sign         = Math.Sign(maxRadius);
            var absMaxRadius = Math.Abs(maxRadius);

            var thickDivisor = absMaxRadius > 45 ? 20 : absMaxRadius > 25 ? 10 : 5;
            var thinDivisor  = absMaxRadius > 25 ? 5 : 1;

            for (var i = thinDivisor; i <= absMaxRadius; i += thinDivisor)
            {
                var radius = scale * i * sign;

                Geometry geometry;

                var isThickRing = i % thickDivisor == 0;
                if (absMaxRadius < 10 || isThickRing)
                {
                    var gapHalfAngle = Math.Asin(halfReferenceCircleGap / radius) * 180 / Math.PI;
                    if (double.IsNaN(gapHalfAngle))
                    {
                        gapHalfAngle = 180;
                    }
                    var startPoint = GunTraverseHelper.PolarToCartesian(center, radius, gapHalfAngle);
                    var endPoint   = GunTraverseHelper.PolarToCartesian(center, radius, 360 - gapHalfAngle);
                    var arc        = new ArcSegment(endPoint, new Size(radius, radius), 360 - gapHalfAngle * 2, true, SweepDirection.Counterclockwise, true);
                    var figure     = new PathFigure(startPoint, new[] { arc }, false);
                    geometry = new PathGeometry(new[] { figure });


                    var referenceTextContainer = new Grid
                    {
                        Width  = 20,
                        Height = referenceCircleGap
                    };
                    var referenceTextContainerPosition = GunTraverseHelper.PolarToCartesian(center, radius, 0);
                    Canvas.SetLeft(referenceTextContainer, referenceTextContainerPosition.X - 10);
                    Canvas.SetTop(referenceTextContainer, referenceTextContainerPosition.Y - halfReferenceCircleGap);

                    var referenceText = new TextBlock
                    {
                        Text = (i * sign).ToString(),
                        HorizontalAlignment = HorizontalAlignment.Center,
                        VerticalAlignment   = VerticalAlignment.Center,
                        FontSize            = isThickRing ? 10 : 8,
                        Foreground          = isThickRing ? Brushes.White : new SolidColorBrush(Color.FromArgb(0x80, 0xff, 0xff, 0xff))
                    };


                    referenceTextContainer.Children.Add(referenceText);

                    this.CurveCanvas.Children.Add(referenceTextContainer);
                }
                else
                {
                    geometry = new EllipseGeometry(center, radius, radius);
                }

                if (isThickRing)
                {
                    thickReferenceGeometry.Children.Add(geometry);
                }
                else
                {
                    thinReferenceGeometry.Children.Add(geometry);
                }
            }

            var thinReferencePath = new Path
            {
                Data  = thinReferenceGeometry,
                Style = this.FindResource("ThinReferenceStroke") as Style
            };

            this.CurveCanvas.Children.Add(thinReferencePath);

            var thickReferencePath = new Path
            {
                Data  = thickReferenceGeometry,
                Style = this.FindResource("ThickReferenceStroke") as Style
            };

            this.CurveCanvas.Children.Add(thickReferencePath);
        }
        private void UpdateTraverseBoundary()
        {
            if (this.ElevationLimits == null)
            {
                this.BoundaryCanvas.Children.Clear();
                return;
            }

            double size;
            double radius;
            Point  center;

            this.GetDimentions(out size, out radius, out center);
            if (size == 0)
            {
                return;
            }

            var oneThirdsRadius = radius / 3;

            var maxElevation  = this.ElevationLimits.GetMaxValue();
            var maxDepression = this.DepressionLimits.GetMaxValue();
            var maxTraverse   = -maxElevation + maxDepression;

            // elevation/outer figure

            _elevationRadiusConverter         = r => (-r + maxDepression) / maxTraverse * oneThirdsRadius * 2 + oneThirdsRadius;
            _depressionRadiusConverter        = r => (maxDepression - r) / maxTraverse * oneThirdsRadius * 2 + oneThirdsRadius;
            _inverseVerticalTraverseConverter = r => - ((r - oneThirdsRadius) / (oneThirdsRadius * 2) * maxTraverse - maxDepression);

            var elevationGeometry  = GunTraverseHelper.CreateGeometry(this.ElevationLimits, this.TurretYawLimits, center, _elevationRadiusConverter);
            var depressionGeometry = GunTraverseHelper.CreateGeometry(this.DepressionLimits, this.TurretYawLimits, center, _depressionRadiusConverter);

            var combinedGeometry = new CombinedGeometry(GeometryCombineMode.Exclude, elevationGeometry, depressionGeometry);

            var figure = new Path {
                Data = combinedGeometry
            };

            var borderStyle    = this.FindResource("Border") as Style;
            var delimiterStyle = this.FindResource("Delimiter") as Style;

            figure.Style = borderStyle;

            var delimiterCircle     = new Ellipse();
            var delimiterCircleSize = _depressionRadiusConverter(0) * 2;

            delimiterCircle.Width  = delimiterCircleSize;
            delimiterCircle.Height = delimiterCircleSize;
            delimiterCircle.Style  = delimiterStyle;

            Canvas.SetLeft(delimiterCircle, (size - delimiterCircleSize) / 2);
            Canvas.SetTop(delimiterCircle, (size - delimiterCircleSize) / 2);

            this.BoundaryCanvas.Children.Clear();

            this.BoundaryCanvas.Children.Add(delimiterCircle);
            this.BoundaryCanvas.Children.Add(figure);

            Canvas.SetLeft(this.YawDirectionLine, center.X);
            Canvas.SetTop(this.YawDirectionLine, center.Y);
        }