public void DrawLineTextSegment(Target2DWrapper <global::Android.Graphics.Canvas> target, double[] xTransformed, double[] yTransformed, string text, int color, double size, int?haloColor, int?haloRadius, double middlePosition, float[] characterWidths, double textLength, float characterHeight) { _paint.Color = new global::Android.Graphics.Color(color); _paint.SetStyle(global::Android.Graphics.Paint.Style.Fill); // see if the text is 'upside down'. double averageAngle = 0; double first = middlePosition - (textLength / 2.0); PointF2D current = Polyline2D.PositionAtPosition(xTransformed, yTransformed, first); for (int idx = 0; idx < text.Length; idx++) { double nextPosition = middlePosition - (textLength / 2.0) + ((textLength / (text.Length)) * (idx + 1)); PointF2D next = Polyline2D.PositionAtPosition(xTransformed, yTransformed, nextPosition); // Translate to the final position, the center of line-segment between 'current' and 'next' //PointF2D position = current + ((next - current) / 2.0); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = ((Degree)horizontal.Angle(vector)).Value; averageAngle = averageAngle + angleDegrees; current = next; } averageAngle = averageAngle / text.Length; // reverse if 'upside down'. double[] xText = xTransformed; double[] yText = yTransformed; if (averageAngle > 90 && averageAngle < 180 + 90) { // the average angle is > PI => means upside down. xText = xTransformed.Reverse <double>().ToArray <double>(); yText = yTransformed.Reverse <double>().ToArray <double>(); } // calculate a central position along the line. first = middlePosition - (textLength / 2.0); current = Polyline2D.PositionAtPosition(xText, yText, first); double nextPosition2 = first; for (int idx = 0; idx < text.Length; idx++) { nextPosition2 = nextPosition2 + characterWidths[idx]; //double nextPosition = middle - (textLength / 2.0) + ((textLength / (text.Length)) * (idx + 1)); PointF2D next = Polyline2D.PositionAtPosition(xText, yText, nextPosition2); char currentChar = text[idx]; global::Android.Graphics.Path characterPath = new global::Android.Graphics.Path(); _paint.GetTextPath(text, idx, idx + 1, 0, 0, characterPath); using (characterPath) { // Transformation matrix to move the character to the correct location. // Note that all actions on the Matrix class are prepended, so we apply them in reverse. var transform = new Matrix(); // Translate to the final position, the center of line-segment between 'current' and 'next' PointF2D position = current; //PointF2D position = current + ((next - current) / 2.0); //double[] transformed = this.Tranform(position[0], position[1]); transform.SetTranslate((float)position[0], (float)position[1]); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = ((Degree)horizontal.Angle(vector)).Value; // Rotate the character transform.PreRotate((float)angleDegrees); // Translate the character so the centre of its base is over the origin transform.PreTranslate(0, characterHeight / 2.5f); //transform.Scale((float)this.FromPixels(_target, _view, 1), // (float)this.FromPixels(_target, _view, 1)); characterPath.Transform(transform); if (haloColor.HasValue && haloRadius.HasValue && haloRadius.Value > 0) { _paint.SetStyle(global::Android.Graphics.Paint.Style.FillAndStroke); _paint.StrokeWidth = haloRadius.Value; _paint.Color = new global::Android.Graphics.Color(haloColor.Value); using (global::Android.Graphics.Path haloPath = new global::Android.Graphics.Path()) { _paint.GetFillPath(characterPath, haloPath); // Draw the character target.Target.DrawPath(haloPath, _paint); } } // Draw the character _paint.SetStyle(global::Android.Graphics.Paint.Style.Fill); _paint.StrokeWidth = 0; _paint.Color = new global::Android.Graphics.Color(color); target.Target.DrawPath(characterPath, _paint); } current = next; } }
/// <summary> /// Draws text along a line segment. /// </summary> /// <param name="target"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="text"></param> /// <param name="color"></param> /// <param name="size"></param> /// <param name="haloColor"></param> /// <param name="haloRadius"></param> /// <param name="middlePosition"></param> /// <param name="characterWidths"></param> /// <param name="textLength"></param> /// <param name="font"></param> /// <param name="characterHeight"></param> /// <param name="haloBrush"></param> /// <param name="brush"></param> private void DrawLineTextSegment(Target2DWrapper <Graphics> target, double[] x, double[] y, string text, int color, double size, int?haloColor, int?haloRadius, double middlePosition, float[] characterWidths, double textLength, Font font, float characterHeight, Brush haloBrush, Brush brush) { // see if the text is 'upside down'. double averageAngle = 0; double first = middlePosition - (textLength / 2.0); PointF2D current = Polyline2D.PositionAtPosition(x, y, first); for (int idx = 0; idx < text.Length; idx++) { double nextPosition = middlePosition - (textLength / 2.0) + ((textLength / (text.Length)) * (idx + 1)); PointF2D next = Polyline2D.PositionAtPosition(x, y, nextPosition); // Translate to the final position, the center of line-segment between 'current' and 'next' // PointF2D position = current + ((next - current) / 2.0); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = ((Degree)horizontal.Angle(vector)).Value; averageAngle = averageAngle + angleDegrees; current = next; } averageAngle = averageAngle / text.Length; // reverse if 'upside down'. double[] xText = x; double[] yText = y; if (averageAngle > 90 && averageAngle < 180 + 90) { // the average angle is > PI => means upside down. xText = x.Reverse <double>().ToArray <double>(); yText = y.Reverse <double>().ToArray <double>(); } // calculate a central position along the line. first = middlePosition - (textLength / 2.0); current = Polyline2D.PositionAtPosition(xText, yText, first); double nextPosition2 = first; for (int idx = 0; idx < text.Length; idx++) { nextPosition2 = nextPosition2 + characterWidths[idx]; //double nextPosition = middle - (textLength / 2.0) + ((textLength / (text.Length)) * (idx + 1)); PointF2D next = Polyline2D.PositionAtPosition(xText, yText, nextPosition2); char currentChar = text[idx]; using (GraphicsPath characterPath = new GraphicsPath()) { characterPath.AddString(currentChar.ToString(), font.FontFamily, (int)font.Style, font.Size, Point.Empty, StringFormat.GenericTypographic); // var pathBounds = characterPath.GetBounds(); // Transformation matrix to move the character to the correct location. // Note that all actions on the Matrix class are prepended, so we apply them in reverse. var transform = new Matrix(); // Translate to the final position, the center of line-segment between 'current' and 'next' PointF2D position = current; //PointF2D position = current + ((next - current) / 2.0); double[] transformed = this.Tranform(position[0], position[1]); transform.Translate((float)transformed[0], (float)transformed[1]); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = ((Degree)horizontal.Angle(vector)).Value; // Rotate the character transform.Rotate((float)angleDegrees); // Translate the character so the centre of its base is over the origin transform.Translate(0, -characterHeight / 2.5f); //transform.Scale((float)this.FromPixels(_target, _view, 1), // (float)this.FromPixels(_target, _view, 1)); characterPath.Transform(transform); if (haloColor.HasValue && haloRadius.HasValue && haloRadius.Value > 0) { GraphicsPath haloPath = characterPath.Clone() as GraphicsPath; using (haloPath) { haloPath.Widen(new Pen(haloBrush, haloRadius.Value * 2)); // Draw the character target.Target.FillPath(haloBrush, haloPath); } } // Draw the character target.Target.FillPath(brush, characterPath); } current = next; } }
private void DrawLineTextSegment(Target2DWrapper <CGContextWrapper> target, double[] xTransformed, double[] yTransformed, ushort[] glyphs, int color, int?haloColor, int?haloRadius, double middlePosition, float[] characterWidths, double textLength, float charachterHeight, CTFont font) { // see if text is 'upside down' double averageAngle = 0; double first = middlePosition - (textLength / 2.0); PointF2D current = Polyline2D.PositionAtPosition(xTransformed, yTransformed, first); for (int idx = 0; idx < glyphs.Length; idx++) { double nextPosition = middlePosition - (textLength / 2.0) + ((textLength / (glyphs.Length)) * (idx + 1)); PointF2D next = Polyline2D.PositionAtPosition(xTransformed, yTransformed, nextPosition); // translate to the final position, the center of the line segment between 'current' and 'next'. //PointF2D position = current + ((next - current) / 2.0); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = ((Degree)horizontal.Angle(vector)).Value; averageAngle = averageAngle + angleDegrees; current = next; } averageAngle = averageAngle / glyphs.Length; // revers if 'upside down' double[] xText = xTransformed; double[] yText = yTransformed; if (averageAngle > 90 && averageAngle < 180 + 90) { xText = xTransformed.Reverse().ToArray(); yText = yTransformed.Reverse().ToArray(); } first = middlePosition - (textLength / 2.0); current = Polyline2D.PositionAtPosition(xText, yText, first); double nextPosition2 = first; for (int idx = 0; idx < glyphs.Length; idx++) { nextPosition2 = nextPosition2 + characterWidths[idx]; PointF2D next = Polyline2D.PositionAtPosition(xText, yText, nextPosition2); //ushort currentChar = glyphs [idx]; PointF2D position = current; target.Target.CGContext.SaveState(); // translate to the final position, the center of the line segment between 'current' and 'next'. // double[] transformed = this.Tranform(position[0], position[1]); // target.Target.CGContext.TranslateCTM ( // (float)transformed [0], // (float)transformed [1]); target.Target.CGContext.TranslateCTM((float)position[0], (float)position[1]); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = (horizontal.Angle(vector)).Value; // rotate the character. target.Target.CGContext.RotateCTM((float)angleDegrees); // rotate the text to point down no matter what the map tilt is. //target.Target.CGContext.RotateCTM ((float)_view.Angle.Value); // translate the character so the center of its base is over the origin. target.Target.CGContext.TranslateCTM(0, charachterHeight / 3.0f); // rotate 'upside down' target.Target.CGContext.ConcatCTM(new CGAffineTransform(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f)); target.Target.CGContext.BeginPath(); CGPath path = font.GetPathForGlyph(glyphs[idx]); if (haloRadius.HasValue && haloColor.HasValue) { // also draw the halo. using (CGPath haloPath = path.CopyByStrokingPath( haloRadius.Value * 2, CGLineCap.Round, CGLineJoin.Round, 0)) { SimpleColor haloSimpleColor = SimpleColor.FromArgb(haloColor.Value); target.Target.CGContext.SetFillColor(haloSimpleColor.R / 256.0f, haloSimpleColor.G / 256.0f, haloSimpleColor.B / 256.0f, haloSimpleColor.A / 256.0f); target.Target.CGContext.BeginPath(); target.Target.CGContext.AddPath(haloPath); target.Target.CGContext.DrawPath(CGPathDrawingMode.Fill); } } // set the fill color as the regular text-color. SimpleColor simpleColor = SimpleColor.FromArgb(color); target.Target.CGContext.SetFillColor(simpleColor.R / 256.0f, simpleColor.G / 256.0f, simpleColor.B / 256.0f, simpleColor.A / 256.0f); // draw the text paths. target.Target.CGContext.BeginPath(); target.Target.CGContext.AddPath(path); target.Target.CGContext.DrawPath(CGPathDrawingMode.Fill); // target.Target.CGContext.AddPath (path); // if (haloRadius.HasValue && haloColor.HasValue) { // also draw the halo. // target.Target.CGContext.DrawPath (CGPathDrawingMode.FillStroke); // } else { // target.Target.CGContext.DrawPath (CGPathDrawingMode.Fill); // } //target.Target.CGContext.ClosePath (); target.Target.CGContext.RestoreState(); current = next; } }
private void DrawLineTextSegment(Target2DWrapper <CGContextWrapper> target, double[] x, double[] y, ushort[] glyphs, int color, int?haloColor, int?haloRadius, double middlePosition, float[] characterWidths, double textLength, float charachterHeight, CTFont font) { // see if text is 'upside down' double averageAngle = 0; double first = middlePosition - (textLength / 2.0); PointF2D current = Polyline2D.PositionAtPosition(x, y, first); for (int idx = 0; idx < glyphs.Length; idx++) { double nextPosition = middlePosition - (textLength / 2.0) + ((textLength / (glyphs.Length)) * (idx + 1)); PointF2D next = Polyline2D.PositionAtPosition(x, y, nextPosition); // translate to the final position, the center of the line segment between 'current' and 'next'. //PointF2D position = current + ((next - current) / 2.0); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = ((Degree)horizontal.Angle(vector)).Value; averageAngle = averageAngle + angleDegrees; current = next; } averageAngle = averageAngle / glyphs.Length; // revers if 'upside down' double[] xText = x; double[] yText = y; if (averageAngle > 90 && averageAngle < 180 + 90) { xText = x.Reverse().ToArray(); yText = y.Reverse().ToArray(); } first = middlePosition - (textLength / 2.0); current = Polyline2D.PositionAtPosition(xText, yText, first); //target.Target.CGContext.SaveState (); //target.Target.CGContext.TranslateCTM (xText[0], yText[0]); double nextPosition2 = first; for (int idx = 0; idx < glyphs.Length; idx++) { nextPosition2 = nextPosition2 + characterWidths [idx]; PointF2D next = Polyline2D.PositionAtPosition(xText, yText, nextPosition2); //ushort currentChar = glyphs [idx]; PointF2D position = current; target.Target.CGContext.SaveState(); // translate to the final position, the center of the line segment between 'current' and 'next'. double[] transformed = this.Tranform(position[0], position[1]); target.Target.CGContext.TranslateCTM( (float)transformed [0], (float)transformed [1]); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = (horizontal.Angle(vector)).Value; // rotate the character. target.Target.CGContext.RotateCTM((float)angleDegrees); // // // translate the character so the center of its base is over the origin. target.Target.CGContext.TranslateCTM(0, charachterHeight / 3.0f); // rotate 'upside down' target.Target.CGContext.ConcatCTM(new CGAffineTransform(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f)); target.Target.CGContext.BeginPath(); CGPath path = font.GetPathForGlyph(glyphs [idx]); target.Target.CGContext.AddPath(path); if (haloRadius.HasValue && haloColor.HasValue) // also draw the halo. { target.Target.CGContext.DrawPath(CGPathDrawingMode.FillStroke); } else { target.Target.CGContext.DrawPath(CGPathDrawingMode.Fill); } //target.Target.CGContext.ClosePath (); target.Target.CGContext.RestoreState(); current = next; } }