/// <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 } } }