public static Point[] ComparePoints(PathGeometry user, PathGeometry target, double progress) { Point pU, pT1, pT2, tU, tT1, tT2; user.GetPointAtFractionLength(progress, out pU, out tU); target.GetPointAtFractionLength(progress, out pT1, out tT1); target.GetPointAtFractionLength(1-progress, out pT2, out tT2); return new[] {pU, pT1, pT2}; }
//Size newArrangeOverride(Size finalSize) protected override Size ArrangeOverride(Size finalSize) { var bezier = new QuadraticBezierSegment(InnerPoint, new Point(finalSize.Width, finalSize.Height), true); var pathFigure = new PathFigure(new Point(10, 10), new[] { bezier }, false); var pathLength = TextOnPathBase.GetPathFigureLength(pathFigure); var neededSpace = 0.0; // finalSize.Width; foreach (UIElement child in Children) { //child.Measure(new Size(Double.PositiveInfinity, // Double.PositiveInfinity)); neededSpace += child.DesiredSize.Width; } if (!pathLength.Equals(0.0) && !neededSpace.Equals(0.0) && !finalSize.Width.Equals(0.0)) { var spaceAvail = pathLength - neededSpace; var spaceStep = spaceAvail / Children.Count; var stepPerc = spaceStep / spaceAvail; var scalingFactor = pathLength / neededSpace; var pathGeometry = new PathGeometry(new[] {pathFigure}); var baseline = scalingFactor; var progress = 0.0; // stepPerc / 2; foreach (UIElement element in Children) { var width = /*scalingFactor**/element.DesiredSize.Width; progress += stepPerc / 2; Point point, tangent; pathGeometry.GetPointAtFractionLength(progress, out point, out tangent); var transformGroup = new TransformGroup(); //transformGroup.Children.Add( // new ScaleTransform(scalingFactor, scalingFactor)); transformGroup.Children.Add( new RotateTransform(Math.Atan2(tangent.Y, tangent.X) *180/Math.PI, width/2, baseline)); //transformGroup.Children.Add( // new TranslateTransform(point.X - width / 2, // point.Y - baseline)); element.RenderTransform = transformGroup; element.Arrange(new Rect(point.X, point.Y, element.DesiredSize.Width, element.DesiredSize.Height)); progress += stepPerc / 2; } } return base.ArrangeOverride(finalSize); }
private Point GetPosition(double value, EllipseGeometry geometry) { var pathGeometry = geometry.GetOutlinedPathGeometry(); if (pathGeometry.Figures.Count == 0) return geometry.Center; var outherGeometry = new PathGeometry(new[] { pathGeometry.Figures[0] }); Point outherPoint, outherTangent; outherGeometry.GetPointAtFractionLength(value, out outherPoint, out outherTangent); return outherPoint; }
// Create an ESRI polyline based on a densified representation of WPFs ArcSegment public static ESRI.ArcGIS.Client.Geometry.Polyline ConstructArcSegment(ESRI.ArcGIS.Client.Geometry.MapPoint startPoint, ESRI.ArcGIS.Client.Geometry.MapPoint endPoint, double radius, bool isMinor, SweepDirection direction) { if (endPoint == null) return null; // WPF ArcSegment has issue with high coordinates values. // Bring coordinates down to 0,0 and translate back to real world later. double startX = startPoint.X; double startY = startPoint.Y; double absRadius = Math.Abs(radius); // We need to switch the curve direction, b/c we are starting with the end point if (radius > 0) direction = direction == SweepDirection.Clockwise ? SweepDirection.Counterclockwise : SweepDirection.Clockwise; Size radiusAspect = new Size(absRadius, absRadius); Point myEndPoint = new Point(endPoint.X - startX, endPoint.Y - startY); bool isLargeArc = !isMinor; ArcSegment wpfArcSegment = new ArcSegment(myEndPoint, radiusAspect, 0, isLargeArc, direction, false); // compose one or more segments into a collection var pathcoll = new PathSegmentCollection(); pathcoll.Add(wpfArcSegment); // create a figure based on the set of segments var pathFigure = new PathFigure(); pathFigure.Segments = pathcoll; pathFigure.IsClosed = false; // compose a collection of figures var figureCollection = new PathFigureCollection(); figureCollection.Add(pathFigure); // create a path-geometry using the figures collection var geometryPath = new PathGeometry(figureCollection); ESRI.ArcGIS.Client.Geometry.PointCollection pointCollection = new ESRI.ArcGIS.Client.Geometry.PointCollection(); double numSegments = 1.0 / 50; // Default 50 Point point, tangent; Point pointA, pointB; geometryPath.GetPointAtFractionLength(0, out pointA, out tangent); geometryPath.GetPointAtFractionLength(numSegments, out pointB, out tangent); double partDistance = LineLength(pointA.X, pointA.Y, pointB.X, pointB.Y); if (partDistance > 1.0) numSegments /= partDistance; if (1 / numSegments > 160) // cap it at 160 vertexes numSegments = 1.0 / 160; // Server is having issue with 185+ vertexes (180 seems ok) for (double fraction = 0.0; fraction < 1.0; fraction += numSegments) { geometryPath.GetPointAtFractionLength(fraction, out point, out tangent); pointCollection.Add(new ESRI.ArcGIS.Client.Geometry.MapPoint(point.X + startX, point.Y + startY)); } pointCollection.Add(endPoint); // faction 1 can be skipped, so add it here. ESRI.ArcGIS.Client.Geometry.Polyline polyline = new ESRI.ArcGIS.Client.Geometry.Polyline(); polyline.Paths.Add(pointCollection); return polyline; }
/// <summary> /// Positionates each child in an arc line form depending on the Bend and amount of child controls. /// </summary> /// <param name="finalSize">The maximum possible space given by the parent control.</param> /// <returns>The calculated needed space in sum of all available child controls.</returns> protected override Size ArrangeOverride(Size finalSize) { if (InternalChildren.Count <= 0 || !(finalSize.Width > 0)) return base.ArrangeOverride(finalSize); ResetArc(finalSize); var pathLength = PathCalculator.GetPathFigureLength(_figure); var pathGeometry = new PathGeometry(new PathFigure[] { _figure }); var distance = (double)1 / (double)(InternalChildren.Count + 1); var position = distance; foreach (UIElement child in InternalChildren) { Point point, tangent; pathGeometry.GetPointAtFractionLength(position, out point, out tangent); Size childSize = child.DesiredSize; point.X -= childSize.Width / 2; point.Y -= childSize.Height; child.Arrange(new Rect(point, childSize)); if (RotateElements) { var elementCenter = new Size(childSize.Width / 2, childSize.Height / 2); var transforms = new TransformGroup(); transforms.Children.Add(new RotateTransform((Math.Atan2(tangent.Y, tangent.X) * 180 / Math.PI), elementCenter.Width, elementCenter.Height)); child.RenderTransform = transforms; } else child.RenderTransform = null; position += distance; } return base.ArrangeOverride(finalSize); }
//protected override Size ArrangeOverride(Size finalSize) Size OriginalArrangeOverride(Size finalSize) { var pathLength = TextOnPathBase.GetPathFigureLength(PathFigure); var textLength = 0.0; // finalSize.Width; foreach (UIElement child in Children) { //child.Measure(new Size(Double.PositiveInfinity, // Double.PositiveInfinity)); textLength += child.DesiredSize.Width; } if (!pathLength.Equals(0.0) && !textLength.Equals(0.0) && !finalSize.Width.Equals(0.0)) { var scalingFactor = pathLength/textLength; var pathGeometry = new PathGeometry(new PathFigure[] {PathFigure}); var baseline = scalingFactor; var progress = 0.0; foreach (UIElement element in Children) { var width = scalingFactor*element.DesiredSize.Width; progress += width/2/pathLength; Point point, tangent; pathGeometry.GetPointAtFractionLength(progress, out point, out tangent); var transformGroup = new TransformGroup(); //transformGroup.Children.Add( // new ScaleTransform(scalingFactor, scalingFactor)); transformGroup.Children.Add( new RotateTransform(Math.Atan2(tangent.Y, tangent.X) *180/Math.PI, width/2, baseline)); //transformGroup.Children.Add( // new TranslateTransform(point.X - width / 2, // point.Y - baseline)); element.RenderTransform = transformGroup; element.Arrange(new Rect(point.X, point.Y, element.DesiredSize.Width, element.DesiredSize.Height)); progress += width/2/pathLength; } } return base.ArrangeOverride(finalSize); }
void OrientTextOnPath() { var pathLength = TextOnPathBase.GetPathFigureLength(PathFigure); var textLength = 0.0; foreach (UIElement child in _mainPanel.Children) { child.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity)); textLength += child.DesiredSize.Width; } if (pathLength == 0 || textLength == 0) return; var scalingFactor = pathLength / textLength; var pathGeometry = new PathGeometry(new PathFigure[] { PathFigure }); var baseline = scalingFactor * Fontsize * FontFamily.Baseline; var progress = 0.0; foreach (UIElement child in _mainPanel.Children) { var width = scalingFactor * child.DesiredSize.Width; progress += width / 2 / pathLength; Point point, tangent; pathGeometry.GetPointAtFractionLength(progress, out point, out tangent); var transformGroup = new TransformGroup(); transformGroup.Children.Add( new ScaleTransform(scalingFactor, scalingFactor)); transformGroup.Children.Add( new RotateTransform(Math.Atan2(tangent.Y, tangent.X) * 180 / Math.PI, width / 2, baseline)); transformGroup.Children.Add( new TranslateTransform(point.X - width / 2, point.Y - baseline)); child.RenderTransform = transformGroup; progress += width / 2 / pathLength; } }
/// <summary> /// Positionates each child in an ellipse form depending on the amount of child controls. /// </summary> /// <param name="finalSize">The maximum possible space given by the parent control.</param> /// <returns>The calculated needed space in sum of all available child controls.</returns> protected override Size ArrangeOverride(Size finalSize) { if (finalSize.Height <= 0 || finalSize.Width <= 0) return finalSize; if (InternalChildren.Count <= 0) return base.ArrangeOverride(finalSize); ResetEllipse(finalSize); var figure = _ellipse.GetOutlinedPathGeometry().Figures[0]; var pathGeometry = new PathGeometry(new[] { figure }); var points = new List<Point>(); var tangents = new List<Point>(); var distance = (double)1 / (double)InternalChildren.Count; var position = GetElementStartPositionValue(); foreach (var child in InternalChildren) { Point point, tangent; pathGeometry.GetPointAtFractionLength(position, out point, out tangent); points.Add(point); tangents.Add(tangent); position += distance; if (position > 1) position -= 1; } if (EllipseRotateDirection == SweepDirection.Counterclockwise) { points.Reverse(); tangents.Reverse(); var point = points.Last(); points.Remove(point); points.Insert(0, point); var tangent = tangents.Last(); tangents.Remove(tangent); tangents.Insert(0, tangent); } int pos = 0; foreach (UIElement child in InternalChildren) { var childSize = child.DesiredSize; var elementPos = points[pos]; elementPos.X -= childSize.Width / 2; elementPos.Y -= childSize.Height / 2; child.SnapsToDevicePixels = true; child.Arrange(new Rect(elementPos, childSize)); if (RotateElements) { var elementCenter = new Size(childSize.Width / 2, childSize.Height / 2); var transforms = new TransformGroup(); var centerPoint = new Point(finalSize.Width / 2, finalSize.Height / 2); var angle = CalculatePileToPlayerAngle(elementPos, centerPoint); transforms.Children.Add(new RotateTransform(angle, elementCenter.Width, elementCenter.Height)); //transforms.Children.Add(new RotateTransform((Math.Atan2(tangents[pos].Y, tangents[pos].X) // * 180 // / Math.PI) // + GetElementsRotateDirectionValue(), // elementCenter.Width, // elementCenter.Height)); child.RenderTransform = transforms; } else child.RenderTransform = null; ++pos; } return base.ArrangeOverride(finalSize); }
private void DrawStartAlignedTextPath(DrawingContext dc, PathGeometry pathGeometry, ISvgAnimatedLength startOffset, TextAlignment alignment) { if (pathGeometry == null || pathGeometry.Figures == null || pathGeometry.Figures.Count != 1) { return; } _pathLength = GetPathFigureLength(pathGeometry.Figures[0]); if (_pathLength == 0 || _textLength == 0) return; //double scalingFactor = pathLength / textLength; double scalingFactor = 1.0; // Not scaling the text to fit... double progress = 0; if (startOffset != null) { ISvgLength offsetLength = startOffset.AnimVal; if (offsetLength != null) { switch (offsetLength.UnitType) { case SvgLengthType.Percentage: if ((float)offsetLength.ValueInSpecifiedUnits != 0) { progress += offsetLength.ValueInSpecifiedUnits / 100d; } break; } } } //PathGeometry pathGeometry = // new PathGeometry(new PathFigure[] { PathFigure }); Point ptOld = new Point(0, 0); for (int i = 0; i < _formattedChars.Count; i++) { FormattedText formText = _formattedChars[i]; double width = scalingFactor * formText.WidthIncludingTrailingWhitespace; double baseline = scalingFactor * formText.Baseline; progress += width / 2 / _pathLength; Point point, tangent; pathGeometry.GetPointAtFractionLength(progress, out point, out tangent); if (i != 0) { if (point == ptOld) { break; } } dc.PushTransform( new TranslateTransform(point.X - width / 2, point.Y - baseline)); dc.PushTransform( new RotateTransform(Math.Atan2(tangent.Y, tangent.X) * 180 / Math.PI, width / 2, baseline)); //dc.PushTransform( // new ScaleTransform(scalingFactor, scalingFactor)); dc.DrawText(formText, _formattedOrigins[i]); dc.Pop(); dc.Pop(); //dc.Pop(); progress += width / 2 / _pathLength; ptOld = point; } }
private void DrawEndAlignedTextPath(DrawingContext dc, PathGeometry pathGeometry, ISvgAnimatedLength startOffset) { if (pathGeometry == null || pathGeometry.Figures == null || pathGeometry.Figures.Count != 1) { return; } _pathLength = GetPathFigureLength(pathGeometry.Figures[0]); if (_pathLength == 0 || _textLength == 0) return; //double scalingFactor = pathLength / textLength; double scalingFactor = 1.0; // Not scaling the text to fit... double progress = 1.0; //PathGeometry pathGeometry = // new PathGeometry(new PathFigure[] { PathFigure }); Point ptOld = new Point(0, 0); int itemCount = _formattedChars.Count - 1; for (int i = itemCount; i >= 0; i--) { FormattedText formText = _formattedChars[i]; double width = scalingFactor * formText.WidthIncludingTrailingWhitespace; double baseline = scalingFactor * formText.Baseline; progress -= width / 2 / _pathLength; Point point, tangent; pathGeometry.GetPointAtFractionLength(progress, out point, out tangent); if (i != itemCount) { if (point == ptOld) { break; } } dc.PushTransform( new TranslateTransform(point.X - width / 2, point.Y - baseline)); dc.PushTransform( new RotateTransform(Math.Atan2(tangent.Y, tangent.X) * 180 / Math.PI, width / 2, baseline)); //dc.PushTransform( // new ScaleTransform(scalingFactor, scalingFactor)); dc.DrawText(formText, _formattedOrigins[i]); dc.Pop(); dc.Pop(); //dc.Pop(); progress -= width / 2 / _pathLength; ptOld = point; } }
private void OrientTextOnPath() { double pathFigureLength = TextOnPathBase.GetPathFigureLength(this.PathFigure); double num = 0.0; foreach (UIElement uIElement in this.mainPanel.Children) { uIElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); num += uIElement.DesiredSize.Width; } if (pathFigureLength != 0.0 && num != 0.0) { double num2 = pathFigureLength / num; PathGeometry pathGeometry = new PathGeometry(new PathFigure[] { this.PathFigure }); double num3 = num2 * 100.0 * base.FontFamily.Baseline; double num4 = 0.0; foreach (UIElement uIElement in this.mainPanel.Children) { double num5 = num2 * uIElement.DesiredSize.Width; num4 += num5 / 2.0 / pathFigureLength; Point point; Point point2; pathGeometry.GetPointAtFractionLength(num4, out point, out point2); uIElement.RenderTransform = new TransformGroup { Children = { new ScaleTransform(num2, num2), new RotateTransform(Math.Atan2(point2.Y, point2.X) * 180.0 / 3.1415926535897931, num5 / 2.0, num3), new TranslateTransform(point.X - num5 / 2.0, point.Y - num3) } }; num4 += num5 / 2.0 / pathFigureLength; } } }
protected virtual void TransformVisualChildren() { this.measureRect = new Rect(); this.ContentRect = RectangleD.Empty; if (this.pathLength == 0 || this.textLength == 0 || this.textHeight == 0) return; if (this.formattedChars.Count != this.visualChildren.Count) return; double scalingFactor; double fontSize = this.FontSize; if (fontSize.IsFinite() && fontSize > 0) { // Scale to particular height, but not longer than the path scalingFactor = Math.Min(fontSize / this.textHeight, this.pathLength / this.textLength); } else { // Scale to the length of the path scalingFactor = this.pathLength / this.textLength; } PathGeometry pathGeometry = new PathGeometry(new PathFigure[] { PathFigure }); // If we're not scaled to the full path length, then center in what we do use double progressFraction = ((this.pathLength - this.textLength * scalingFactor) / 2) / this.pathLength; for (int index = 0; index < visualChildren.Count; index++) { FormattedText formText = this.formattedChars[index]; double width = scalingFactor * formText.WidthIncludingTrailingWhitespace; double height = scalingFactor * (formText.Height); double baseline = scalingFactor * formText.Baseline; progressFraction += width / 2 / this.pathLength; Point point, tangent; pathGeometry.GetPointAtFractionLength(progressFraction, out point, out tangent); DrawingVisual drawingVisual = this.visualChildren[index] as DrawingVisual; TransformGroup transformGroup = drawingVisual.Transform as TransformGroup; ScaleTransform scaleTransform = transformGroup.Children[0] as ScaleTransform; RotateTransform rotateTransform = transformGroup.Children[1] as RotateTransform; TranslateTransform translateTransform = transformGroup.Children[2] as TranslateTransform; scaleTransform.ScaleX = scalingFactor; scaleTransform.ScaleY = scalingFactor; rotateTransform.Angle = Math.Atan2(tangent.Y, tangent.X) * 180 / Math.PI; rotateTransform.CenterX = width / 2; rotateTransform.CenterY = baseline; translateTransform.X = point.X - width / 2; translateTransform.Y = this.FontVerticallyCentered ? (point.Y - height / 2 - this.FontBaseline) : (point.Y - baseline - this.FontBaseline); Rect rc = drawingVisual.ContentBounds; rc.Transform(transformGroup.Value); this.ContentRect = this.ContentRect.UnionD(new RectangleD(rc)); this.measureRect.Union(rc); progressFraction += width / 2 / pathLength; } InvalidateMeasure(); }
void WarpAllPoints(PathGeometry warpedTextPathGeometry, PathGeometry flattenedTextPathGeometry) { PathGeometry pathGeometry = new PathGeometry(new PathFigure[] { PathFigure }); double scalingFactor = pathLength / textLength; LoopThroughAllFlattenedPathPoints(warpedTextPathGeometry, flattenedTextPathGeometry, delegate(Point pointSrc) { double fractionLength = Math.Max(0, Math.Min(1, pointSrc.X / textLength)); double offsetFromBaseline = scalingFactor * (baseline - pointSrc.Y); Point pathPoint, pathTangent; pathGeometry.GetPointAtFractionLength(fractionLength, out pathPoint, out pathTangent); double angle = Math.Atan2(pathTangent.Y, pathTangent.X); Point pointDst = new Point(); pointDst.X = pathPoint.X + offsetFromBaseline * Math.Sin(angle); pointDst.Y = pathPoint.Y - offsetFromBaseline * Math.Cos(angle); return pointDst; }); if (ShiftToOrigin) { Rect boundsRect = warpedTextPathGeometry.Bounds; LoopThroughAllFlattenedPathPoints(warpedTextPathGeometry, warpedTextPathGeometry, delegate(Point pointSrc) { Point pointDst = new Point(); pointDst.X = pointSrc.X - boundsRect.Left; pointDst.Y = pointSrc.Y - boundsRect.Top; return pointDst; }); } }
protected virtual void TransformVisualChildren() { boundingRect = new Rect(); if (pathLength == 0 || textLength == 0) return; if (formattedChars.Count != visualChildren.Count) return; double scalingFactor = pathLength / textLength; PathGeometry pathGeometry = new PathGeometry(new PathFigure[] { PathFigure }); double progress = 0; boundingRect = new Rect(); for (int index = 0; index < visualChildren.Count; index++) { FormattedText formText = formattedChars[index]; double width = scalingFactor * formText.WidthIncludingTrailingWhitespace; double baseline = scalingFactor * formText.Baseline; progress += width / 2 / pathLength; Point point, tangent; pathGeometry.GetPointAtFractionLength(progress, out point, out tangent); DrawingVisual drawingVisual = visualChildren[index] as DrawingVisual; TransformGroup transformGroup = drawingVisual.Transform as TransformGroup; ScaleTransform scaleTransform = transformGroup.Children[0] as ScaleTransform; RotateTransform rotateTransform = transformGroup.Children[1] as RotateTransform; TranslateTransform translateTransform = transformGroup.Children[2] as TranslateTransform; scaleTransform.ScaleX = scalingFactor; scaleTransform.ScaleY = scalingFactor; rotateTransform.Angle = Math.Atan2(tangent.Y, tangent.X) * 180 / Math.PI; rotateTransform.CenterX = width / 2; rotateTransform.CenterY = baseline; translateTransform.X = point.X - width / 2; translateTransform.Y = point.Y - baseline; Rect rect = drawingVisual.ContentBounds; rect.Transform(transformGroup.Value); boundingRect.Union(rect); progress += width / 2 / pathLength; } InvalidateMeasure(); }
protected virtual void TransformVisualChildren() { this.boundingRect = default(Rect); if (this.pathLength != 0.0 && this.textLength != 0.0) { if (this.formattedChars.Count == this.visualChildren.Count) { double num = this.pathLength / this.textLength; PathGeometry pathGeometry = new PathGeometry(new PathFigure[] { base.PathFigure }); double num2 = 0.0; this.boundingRect = default(Rect); for (int i = 0; i < this.visualChildren.Count; i++) { FormattedText formattedText = this.formattedChars[i]; double num3 = num * formattedText.WidthIncludingTrailingWhitespace; double num4 = num * formattedText.Baseline; num2 += num3 / 2.0 / this.pathLength; Point point; Point point2; pathGeometry.GetPointAtFractionLength(num2, out point, out point2); DrawingVisual drawingVisual = this.visualChildren[i] as DrawingVisual; TransformGroup transformGroup = drawingVisual.Transform as TransformGroup; ScaleTransform scaleTransform = transformGroup.Children[0] as ScaleTransform; RotateTransform rotateTransform = transformGroup.Children[1] as RotateTransform; TranslateTransform translateTransform = transformGroup.Children[2] as TranslateTransform; scaleTransform.ScaleX = num; scaleTransform.ScaleY = num; rotateTransform.Angle = Math.Atan2(point2.Y, point2.X) * 180.0 / 3.1415926535897931; rotateTransform.CenterX = num3 / 2.0; rotateTransform.CenterY = num4; translateTransform.X = point.X - num3 / 2.0; translateTransform.Y = point.Y - num4; Rect contentBounds = drawingVisual.ContentBounds; contentBounds.Transform(transformGroup.Value); this.boundingRect.Union(contentBounds); num2 += num3 / 2.0 / this.pathLength; } base.InvalidateMeasure(); } } }
private void WarpAllPoints(PathGeometry warpedTextPathGeometry, PathGeometry flattenedTextPathGeometry) { PathGeometry pathGeometry = new PathGeometry(new PathFigure[] { base.PathFigure }); double scalingFactor = this.pathLength / this.textLength; this.LoopThroughAllFlattenedPathPoints(warpedTextPathGeometry, flattenedTextPathGeometry, delegate(Point pointSrc) { double progress = Math.Max(0.0, Math.Min(1.0, pointSrc.X / this.textLength)); double num = scalingFactor * (this.baseline - pointSrc.Y); Point point; Point point2; pathGeometry.GetPointAtFractionLength(progress, out point, out point2); double num2 = Math.Atan2(point2.Y, point2.X); return new Point { X = point.X + num * Math.Sin(num2), Y = point.Y - num * Math.Cos(num2) }; }); if (this.ShiftToOrigin) { Rect boundsRect = warpedTextPathGeometry.Bounds; this.LoopThroughAllFlattenedPathPoints(warpedTextPathGeometry, warpedTextPathGeometry, (Point pointSrc) => new Point { X = pointSrc.X - boundsRect.Left, Y = pointSrc.Y - boundsRect.Top }); } }
DrawBezierLabel ( DrawingContext oDrawingContext, GraphDrawingContext oGraphDrawingContext, FormattedText oFormattedText, Point oEdgeEndpoint1, Point oEdgeEndpoint2, PathGeometry oBezierCurve, Double dLabelOriginAsFractionOfEdgeLength, Double dEdgeLength, Double dBufferWidth, Color oLabelTextColor, Color oTranslucentRectangleColor, Double dFontSize ) { Debug.Assert(oDrawingContext != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oFormattedText != null); Debug.Assert(oBezierCurve != null); Debug.Assert(dLabelOriginAsFractionOfEdgeLength >= 0); Debug.Assert(dEdgeLength >= 0); Debug.Assert(dBufferWidth >= 0); Debug.Assert(dFontSize > 0); AssertValid(); // This method uses a modified version of the technique described in // "Render Text On A Path With WPF," by Charles Petzold, at // http://msdn.microsoft.com/en-us/magazine/dd263097.aspx. if (oEdgeEndpoint2.X < oEdgeEndpoint1.X) { // Don't let text be drawn upside-down. WpfGraphicsUtil.SwapPoints(ref oEdgeEndpoint1, ref oEdgeEndpoint2); oBezierCurve = WpfPathGeometryUtil.ReverseQuadraticBezierCurve( oBezierCurve); } Double dTextWidth = oFormattedText.Width; Double dTextWidthToEdgeLengthRatio = dTextWidth / dEdgeLength; Double dLineOffset = 0; Point oOrigin = new Point(0, 0); String [] asLines = oFormattedText.Text.Split( new char[] {'\r', '\n'} ); foreach (String sLine in asLines) { // The label characters will be drawn one by one using positions // computed by PathGeometry.GetPointAtFractionLength(). The first // character will be at dLabelOriginAsFractionOfEdgeLength. Double dFractionOfEdgeLength = dLabelOriginAsFractionOfEdgeLength; Boolean bUsedEllipses = false; foreach (Char c in sLine) { if (bUsedEllipses) { break; } Point oPointAtFractionLength; Point oPointTangent; oBezierCurve.GetPointAtFractionLength(dFractionOfEdgeLength, out oPointAtFractionLength, out oPointTangent); Double dCharacterAngleDegrees = MathUtil.RadiansToDegrees( Math.Atan2(oPointTangent.Y, oPointTangent.X) ); String sChar = c.ToString(); if ( (oPointAtFractionLength - oEdgeEndpoint2).Length <= 6.0 * dBufferWidth) { // There is probably not enough room for the rest of the // string. Terminate it with ellipses. (The buffer width // multiple was determined experimentally.) bUsedEllipses = true; sChar = "..."; } FormattedText oCharacterFormattedText = m_oFormattedTextManager.CreateFormattedText( sChar, oLabelTextColor, dFontSize, m_dGraphScale); Double dCharacterWidth = oCharacterFormattedText.WidthIncludingTrailingWhitespace; Double dCharacterHeight = oCharacterFormattedText.Height; // Apply a RotateTransform to make the character's base // approximately parallel to the Bezier curve's tangent, and a // TranslateTransform to vertically position the character. oDrawingContext.PushTransform( new TranslateTransform( oPointAtFractionLength.X, oPointAtFractionLength.Y - (oFormattedText.Height / 2.0) + dLineOffset ) ); oDrawingContext.PushTransform( new RotateTransform( dCharacterAngleDegrees, 0, (oFormattedText.Height / 2.0) - dLineOffset ) ); // A translucent rectangle is drawn for each character. // Rounding errors cause the underlying edge to show through // faintly between the rectangles, which is a bug. How to fix // this? Rect oTranslucentRectangle = new Rect( oOrigin, new Size(dCharacterWidth, dCharacterHeight) ); DrawTranslucentRectangle(oDrawingContext, oTranslucentRectangle, oTranslucentRectangleColor); oDrawingContext.DrawText(oCharacterFormattedText, oOrigin); oDrawingContext.Pop(); oDrawingContext.Pop(); dFractionOfEdgeLength += dCharacterWidth / dEdgeLength; } dLineOffset += oFormattedText.Height / asLines.Length; } }
protected override void OnRender(DrawingContext dc) { if (this.pathLength != 0.0 && this.textLength != 0.0) { double num = this.pathLength / this.textLength; num = 1.0; double num2 = 0.0; PathGeometry pathGeometry = new PathGeometry(new PathFigure[] { base.PathFigure }); foreach (FormattedText current in this.formattedChars) { double num3 = num * current.WidthIncludingTrailingWhitespace; double num4 = num * current.Baseline; num2 += num3 / 2.0 / this.pathLength; Point point; Point point2; pathGeometry.GetPointAtFractionLength(num2, out point, out point2); dc.PushTransform(new TranslateTransform(point.X - num3 / 2.0, point.Y - num4)); dc.PushTransform(new RotateTransform(Math.Atan2(point2.Y, point2.X) * 180.0 / 3.1415926535897931, num3 / 2.0, num4)); dc.PushTransform(new ScaleTransform(num, num)); dc.DrawText(current, new Point(0.0, 0.0)); dc.Pop(); dc.Pop(); dc.Pop(); num2 += num3 / 2.0 / this.pathLength; } } }