internal void RecalculateCurvesAndAnnotations()
            {
                // Display the Along-side segment text (in direction of elements)
                double displayAlongSideTextMinDistance = CSUnitsForPixels(40);
                double displayTotalTextMinDistance     = CSUnitsForPixels(60);
                double totalAlongLengthInMeters        = 0.0;

                // The offset in pixels above the lines
                double offsetPixelsInCSUnits          = CSUnitsForPixels(2);
                double totalTextOffsetPixelsInCSUnits = CSUnitsForPixels(15);

                _geometry.Clear();

                for (int nr = 0; nr < _coordinates.Count - 1; nr++)
                {
                    var isLast         = nr >= _coordinates.Count - 2;
                    var style          = _isFinalized || !isLast ? _lineStyle : _grayLineStyle;
                    var fromCoordinate = _coordinates[nr];
                    var toCoordinate   = _coordinates[nr + 1];

                    var line = new Line {
                        X1 = fromCoordinate.X, Y1 = fromCoordinate.Y, X2 = toCoordinate.X, Y2 = toCoordinate.Y, Stroke = style
                    };
                    _geometry.Add(line);

                    var alongLengthInCSUnits = fromCoordinate.DistanceTo(toCoordinate);
                    var alongLengthInMeters  = LiteMapMeasurerBase.LengthInMeters(CoordinateSystem, Transform, fromCoordinate, toCoordinate);

                    totalAlongLengthInMeters += alongLengthInMeters;

                    if (alongLengthInCSUnits > displayAlongSideTextMinDistance)
                    {
                        var    baseToIntermediateCoordinate      = fromCoordinate.Middle(toCoordinate);
                        double baseToIntermediateCoordinateAngle = MathSE.NormalizedAngle(fromCoordinate.AngleTo(toCoordinate));

                        //TextAlignment alignment = TextAlignment.Bottom;
                        TextAlignment alignment = TextAlignment.Center;

                        if (baseToIntermediateCoordinateAngle > MathSE.HalfPI && baseToIntermediateCoordinateAngle < 3 * MathSE.HalfPI)
                        {
                            baseToIntermediateCoordinateAngle += MathSE.PI;
                        }

                        // Get the text slightly up (couple of pixels), to make sure it is drawn loose from the line
                        double upAngle = baseToIntermediateCoordinateAngle + MathSE.HalfPI;
                        baseToIntermediateCoordinate = Coordinate.NewAtDistanceAngleFrom(baseToIntermediateCoordinate, offsetPixelsInCSUnits, upAngle);

                        _geometry.Add(AnnotationForLength(this.CoordinateSystem, baseToIntermediateCoordinate, baseToIntermediateCoordinateAngle, _segmentAnnotationStyle, 9, alongLengthInMeters, alignment, 15));

                        if (alongLengthInCSUnits > displayTotalTextMinDistance)
                        {
                            // Now do the total Length at the coordinates themselves (but within the loop, so only when length of previous is long enough)
                            if (isLast && !toCoordinate.Equals(_coordinates[0]))
                            {
                                // If this is the last coordinate; just place the thingie at a decent offset
                                var direction = fromCoordinate.AngleTo(toCoordinate);
                                var position  = Coordinate.NewAtDistanceAngleFrom(toCoordinate, totalTextOffsetPixelsInCSUnits, direction);

                                _geometry.Add(AnnotationForLength(this.CoordinateSystem, position, 0.0, _totalAnnotationStyle, 9, totalAlongLengthInMeters, alignment, 0));
                            }
                            else
                            {
                                // Not the last coordinate - so we need to calculate a decent position for the coordinate
                                // at the intersection of the two segments it is placed between
                                var nextCoordinate = isLast ? _coordinates[1] : _coordinates[nr + 2];

                                // Only place the lot, when the next coordinate is suffiently away as well
                                var alongLengthNextInCSUnits = toCoordinate.DistanceTo(nextCoordinate);
                                if (alongLengthNextInCSUnits > displayTotalTextMinDistance)
                                {
                                    var angleBetween = (fromCoordinate - toCoordinate).AngleWith(nextCoordinate - toCoordinate);
                                    int extra        = 25;
                                    // Make sure we get the right direction
                                    if (nextCoordinate.SideOf(fromCoordinate, toCoordinate) == GeometrySide.Left)
                                    {
                                        angleBetween = -angleBetween;
                                        extra        = 0;
                                    }

                                    var direction = fromCoordinate.AngleTo(toCoordinate) + (angleBetween / 2.0);
                                    var position  = Coordinate.NewAtDistanceAngleFrom(toCoordinate, totalTextOffsetPixelsInCSUnits, direction);

                                    _geometry.Add(AnnotationForLength(this.CoordinateSystem, position, 0.0, _totalAnnotationStyle, 9, totalAlongLengthInMeters, alignment, extra));
                                }
                            }
                        }
                    }
                } // For-loop with coords

                if (_coordinates.Count > 2)
                {
                    // We could display the area of the measurer
                    var closedRing = CreateClosedRing(this.CoordinateSystem, _coordinates);
                    var area       = CalculateAreaContribution(closedRing);

                    if (area > 0)
                    {
                        _geometry.Add(AnnotationForArea(this.CoordinateSystem, closedRing.CenterCoordinate(PolygonCentreCoordinateMode.CentreOfEnvelope), _areaAnnotationStyle, 9, area));
                    }
                }
            }
示例#2
0
            /// <summary>
            /// Recalculate the output of the curves
            /// </summary>
            internal override void RecalculateCurvesAndAnnotations(bool hasMeasureElements)
            {
                // We only check for valid elements in case we are more away than so many pixels
                double checkValidMinDistance = CSUnitsForPixels(5);

                // Display the Along-side segment text (in direction of base), when more than so many pixels long
                double displayAlongSideTextMinDistance = CSUnitsForPixels(65);

                // Display the Cumulative text when the segment is longer than the specified pixels
                double displayAlongSideEndTextMinDistance = CSUnitsForPixels(100);

                // Display the orthogonal text when the ortho-length is more than the specified pixels
                double displayOrthogonalTextMinDistance = CSUnitsForPixels(65);

                // Display the Ortho Total when the Along-side Distance (the segment in base-direction)
                // is longer than the given length. For clarity to the end-user this could be set to the
                // same value as displaying the segment-length itself but can be done earlier if required.
                double displayOrthogonalEndTextMinAlongDistance = CSUnitsForPixels(50);

                // Keep Ortho-Total-MinOrth-Distance the same as the ortho-distance itself,
                // so total-ortho text does only appear in case the ortho text itself is displayed.
                // If not, the user might confuse this one with the ortho-value itself (since it is
                // displayed and the ortho-text maybe is not yet).
                double displayOrthogonalEndTextMinOrthogonalDistance = CSUnitsForPixels(65);

                // Display the points in case the length of the corresponding segment is longer than the
                // specified pixels
                double displayPointsMinDistance = CSUnitsForPixels(24);

                // Display the points in case the length of the corresponding segment is longer than the
                // specified pixels. This applies to drawing ortho-points in case the along-side segment
                // is longer than the specified pixels.
                double displayOtherPointsMinAlongDistance = CSUnitsForPixels(15);

                // The offset in pixels above the lines (for the segment and ortho texts, not the totals).
                double offsetPixelsInCSUnits = CSUnitsForPixels(2);

                // Initialize the output geometry
                Curves      = new List <Line>();
                Annotations = new List <FrameworkElement>();
                Points      = new List <System.Windows.Shapes.Polygon>();

                // Start by calculating the intermediate (intersection) point.
                CalculateIntermediate();

                // Setting up the along curve (the one going straight again and again)
                var alongCurve = new Curve(new LineString(CoordinateSystem, Start, Intermediate));
                var alongLine  = new Line {
                    X1 = Start.X, Y1 = Start.Y, X2 = Intermediate.X, Y2 = Intermediate.Y, Stroke = _measureLineStyle
                };
                var alongLengthInCSUnits = Start.DistanceTo(Intermediate);
                var alongLengthInMeters  = LiteMapMeasurerBase.LengthInMeters(CoordinateSystem, Transform, Start, Intermediate);

                // Setting up the orthogonal curve
                var orthogonalCurve = new Curve(new LineString(CoordinateSystem, Intermediate, End));
                var orthogonalLine  = new Line {
                    X1 = Intermediate.X, Y1 = Intermediate.Y, X2 = End.X, Y2 = End.Y, Stroke = _measureLineStyle
                };
                var orthogonalLengthInCSUnits = Intermediate.DistanceTo(End);
                var orthogonalLengthInMeters  = LiteMapMeasurerBase.LengthInMeters(CoordinateSystem, Transform, Intermediate, End);

                // Check whether we are Valid (not going in the wrong direction).
                // This applies not to the first point, that can be used to determine the direction, but applies
                // to subsequent points only.
                // We still do use the valid-flag for the first element though, just to indicate that we need to reverse the lot
                Valid = true;
                if (alongLengthInCSUnits > checkValidMinDistance && Math.Abs(Base.Angle - Start.AngleTo(Intermediate)) > 1)
                {
                    if (!First)
                    {
                        alongLine.Stroke      = _measureInvalidLineStyle;
                        orthogonalLine.Stroke = _measureInvalidLineStyle;
                    }
                    Valid = false;
                }

                // Add the curves to the output. These are the along-curve (in the base-line's direction) and the ortho-curve
                Curves.Add(alongLine);
                Curves.Add(orthogonalLine);

                // In case we are not valid do not draw the result, unless we are the first measure-element.
                // In that case we can act as any other, since the first element can be used to determine direction
                if (!Valid && !First)
                {
                    return;
                }

                // The point drawing (dimension endpoints)
                // We can choose to only draw points when all points are capable of being shown (direct and ortho)
                // This leads to a neater way of display the dimensions.
                bool drawPointsDirect = alongLengthInCSUnits > displayPointsMinDistance;
                bool drawPointsOrtho  = orthogonalLengthInCSUnits > displayPointsMinDistance && alongLengthInCSUnits > displayOtherPointsMinAlongDistance;
                bool drawPoints       = drawPointsDirect && drawPointsOrtho;

                // Draw the DimPoints on the direct line, either make dependent on
                // - drawPointsDirect (these can be drawn)
                // - drawPoints       (direct + ortho points can be drawn)
                if (drawPointsDirect)
                {
                    double ptAngle = Start.AngleTo(Intermediate);

                    Points.Add(PointPolygonFor(Start, ptAngle + MathSE.HalfPI, 10, _dimPointStyle));
                    Points.Add(PointPolygonFor(Intermediate, ptAngle - MathSE.HalfPI, 10, _dimPointStyle));
                }

                // Draw the DimPoints on the Orthogonal line, either make dependent on
                // - drawPointsOrtho (these can be drawn)
                // - drawPoints      (ortho + direct points can be drawn)
                if (drawPointsOrtho)
                {
                    double ptAngle2 = End.AngleTo(Intermediate);

                    Points.Add(PointPolygonFor(Intermediate, ptAngle2 - MathSE.HalfPI, 10, _dimPointStyle));
                    Points.Add(PointPolygonFor(End, ptAngle2 + MathSE.HalfPI, 10, _dimPointStyle));
                }

                // Draw the Text in the direct part (segment length)
                if (alongLengthInCSUnits > displayAlongSideTextMinDistance)
                {
                    var    baseToIntermediateCoordinate      = Start.Middle(Intermediate);
                    double baseToIntermediateCoordinateAngle = MathSE.NormalizedAngle(Start.AngleTo(Intermediate));

                    //TextAlignment alignment = TextAlignment.Bottom;
                    TextAlignment alignment = TextAlignment.Center;

                    if (baseToIntermediateCoordinateAngle > MathSE.HalfPI && baseToIntermediateCoordinateAngle < 3 * MathSE.HalfPI)
                    {
                        baseToIntermediateCoordinateAngle += MathSE.PI;
                    }

                    // Get the text slightly up (couple of pixels), to make sure it is drawn loose from the line
                    double upAngle = baseToIntermediateCoordinateAngle + MathSE.HalfPI;
                    baseToIntermediateCoordinate = Coordinate.NewAtDistanceAngleFrom(baseToIntermediateCoordinate, offsetPixelsInCSUnits, upAngle);

                    Annotations.Add(AnnotationForLength(this.CoordinateSystem, baseToIntermediateCoordinate, baseToIntermediateCoordinateAngle, _measureAnnotationStyle, 9, alongLengthInMeters, alignment, 15));
                }

                // Draw the orthogonal Text in the orthogonal part
                if (orthogonalLengthInCSUnits > displayOrthogonalTextMinDistance)
                {
                    var baseToIntermediateCoordinate      = Intermediate.Middle(End);
                    var baseToIntermediateCoordinateAngle = MathSE.NormalizedAngle(Intermediate.AngleTo(End));
                    //var alignment = TextAlignment.Bottom;
                    var alignment = TextAlignment.Center;

                    if (baseToIntermediateCoordinateAngle > MathSE.HalfPI && baseToIntermediateCoordinateAngle < 3 * MathSE.HalfPI)
                    {
                        baseToIntermediateCoordinateAngle += MathSE.PI;
                    }

                    double upAngle = baseToIntermediateCoordinateAngle + MathSE.HalfPI;
                    baseToIntermediateCoordinate = Coordinate.NewAtDistanceAngleFrom(baseToIntermediateCoordinate, offsetPixelsInCSUnits, upAngle);

                    Annotations.Add(AnnotationForLength(this.CoordinateSystem, baseToIntermediateCoordinate, baseToIntermediateCoordinateAngle, _measureAnnotationStyle, 9, orthogonalLengthInMeters, alignment, 15));
                }

                // Draw the segment End and Orthogonal End Texts
                // The total length will not be displayed for the first segment (same value)
                bool allowLengthTotalUnitsDisplay = !First && (alongLengthInCSUnits > displayAlongSideEndTextMinDistance);

                // The ortho length will be displayed in case
                // - the orthogonal value itself is displayed (to make sure the values are understood)
                // - it is the first segment or the length of the along-side is long enough (for the first segment, there is nothing 'in the way')
                bool allowOrthoTotalUnitsDisplay = orthogonalLengthInCSUnits > displayOrthogonalEndTextMinOrthogonalDistance && (alongLengthInCSUnits > displayOrthogonalEndTextMinAlongDistance || First);

                if (allowLengthTotalUnitsDisplay || allowOrthoTotalUnitsDisplay)
                {
                    // Get the text alignments, by checking in which sub-quadrants (divided in 8) each elements' lies
                    // Dependent on these directions, the most appropriate text-alignment will be picked.
                    // This kind of behavior should go with quadrant behavior in core. Should be a one-liner.
                    var alignments = new TextAlignment[]
                    {
                        TextAlignment.Left,
                        TextAlignment.Left,
                        TextAlignment.Center,
                        TextAlignment.Right,
                        TextAlignment.Right,
                        TextAlignment.Right,
                        TextAlignment.Center,
                        TextAlignment.Left
                    };

                    // Do total length, but not for the first dimension-line
                    var directAlignment = TextAlignment.Center;
                    var orthoAlignment  = TextAlignment.Center;

                    double angleToUse  = MathSE.NormalizedAngle(End.AngleTo(Intermediate));
                    double directAngle = MathSE.NormalizedAngle(angleToUse + (Math.PI / 8));
                    for (int nr = 0; nr < 8; nr++)
                    {
                        if (directAngle < ((nr + 1) * Math.PI) / 4)
                        {
                            directAlignment = alignments[nr];
                            orthoAlignment  = alignments[(nr + 4) % 8];
                            break;
                        }
                    }

                    // Get some extra space/distance from the linears and segment texts
                    double extraOrthoDistanceInCSUnits = CSUnitsForPixels(10);
                    if (allowLengthTotalUnitsDisplay)
                    {
                        // Total length
                        Curve allSegmentsCurve          = new Curve(CoordinateSystem, new LineString(CoordinateSystem, Base.End, Intermediate));
                        var   allSegmentsLengthInMeters = LiteMapMeasurerBase.LengthInMeters(CoordinateSystem, Transform, Base.End, Intermediate);

                        // Place the texts at intersections (cumulative totals at end of segments)
                        Coordinate alongTotalCoordinate = Coordinate.NewAtDistanceAngleFrom(Intermediate, extraOrthoDistanceInCSUnits, angleToUse);
                        // Annotations.Add(AnnotationFor(this.CoordinateSystem, alongTotalCoordinate, 0.0, _measureAnnotationStyle, 14, allSegmentsLengthInMeters, directAlignment));
                    }

                    if (allowOrthoTotalUnitsDisplay)
                    {
                        // Place the 'total' text at the end of each point that is actually dimensioned
                        var orthoTotalCoordinate = Coordinate.NewAtDistanceAngleFrom(End, extraOrthoDistanceInCSUnits, angleToUse + Math.PI);
                        var orthoTotalLength     = alongLengthInMeters + orthogonalLengthInMeters;

                        // No-op for now
                        // We could use this to display the orto total text
                    }
                }
            }