/// <summary> /// Encodes a bearing based on the list of coordinates and the BEARDIST parameter. /// </summary> /// <param name="coordinates"></param> /// <returns></returns> public static Degree EncodeBearing(List <GeoCoordinate> coordinates) { var distance = 0.0; var previous = coordinates[0]; PointF2D bearingPosition = null; for (int idx = 1; idx < coordinates.Count; idx++) { var current = new GeoCoordinate(coordinates[idx].Latitude, coordinates[idx].Longitude); var currentSegmentDistance = current.DistanceReal(previous).Value; var currentDistance = currentSegmentDistance + distance; if (currentDistance > Parameters.BEARDIST) { // the coordinate to calculate the beardist is in this segment! // calculate where. var relativeDistance = Parameters.BEARDIST - distance; var relativeOffset = relativeDistance / currentSegmentDistance; bearingPosition = previous + ((current - previous) * relativeOffset); break; } distance = currentDistance; previous = current; } if (bearingPosition == null) { // use the toCoordinate as the last 'current'. // if edge is too short use target coordinate. bearingPosition = coordinates[coordinates.Count - 1]; } // calculate offset. var offset = (bearingPosition - coordinates[0]); // convert offset to meters. var north = new VectorF2D(0, 1); // north. var xMeters = new GeoCoordinate(coordinates[0].Latitude, coordinates[0].Longitude + offset[0]).DistanceReal( coordinates[0]).Value; if (offset[0] < 0) { // invert offset. xMeters = -xMeters; } var yMeters = new GeoCoordinate(coordinates[0].Latitude + offset[1], coordinates[0].Longitude).DistanceReal( coordinates[0]).Value; if (offset[1] < 0) { // invert offset. yMeters = -yMeters; } var direction = new VectorF2D(xMeters, yMeters).Normalize(); return(direction.Angle(north)); }
public static IList <PointF2D> Calculate(IList <PointF2D> points) { if (points.Count < 3) { throw new ArgumentOutOfRangeException(string.Format("Cannot calculate the convex hull of {0} points!", (object)points.Count)); } PointF2D pointF2D1 = points[0]; foreach (PointF2D point in (IEnumerable <PointF2D>)points) { if (pointF2D1[0] > point[0]) { pointF2D1 = point; } else if (pointF2D1[0] == point[0] && pointF2D1[1] < point[1]) { pointF2D1 = point; } } PointF2D pointF2D2 = new PointF2D(new double[2] { pointF2D1[0], pointF2D1[1] - 10.0 }); VectorF2D vectorF2D = pointF2D1 - pointF2D2; List <PointF2D> pointF2DList = new List <PointF2D>(); PointF2D pointF2D3 = pointF2D1; pointF2DList.Add(pointF2D3); do { double num1 = double.MaxValue; PointF2D pointF2D4 = (PointF2D)null; foreach (PointF2D point in (IEnumerable <PointF2D>)points) { if (point != pointF2D3) { VectorF2D v = point - pointF2D3; double num2 = vectorF2D.Angle(v).Value; if (num2 < num1) { num1 = num2; pointF2D4 = point; } } } vectorF2D = pointF2D4 - pointF2D3; pointF2D3 = pointF2D4; pointF2DList.Add(pointF2D3); }while (pointF2D3 != pointF2D1); return((IList <PointF2D>)pointF2DList); }
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; } }
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; } }
/// <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; } }
/// <summary> /// Calculates a polygon out of a list of points. The resulting polygon the convex hull of all points. /// </summary> /// <param name="points"></param> /// <returns></returns> public static IList <PointF2D> Calculate(IList <PointF2D> points) { if (points.Count < 3) { throw new ArgumentOutOfRangeException(string.Format("Cannot calculate the convex hull of {0} points!", points.Count)); } // find the 'left-most' and 'top-most' point. PointF2D start = points[0]; foreach (PointF2D point in points) { if (start[0] > point[0]) { start = point; } else if (start[0] == point[0]) { if (start[1] < point[01]) { start = point; } } } // produce the first reference vector. double[] before_start_coords = new double[] { start[0], start[1] - 10 }; PointF2D before_start = new PointF2D(before_start_coords); VectorF2D reference = start - before_start; // start the gift-wrapping! List <PointF2D> result = new List <PointF2D>(); PointF2D current = start; result.Add(current); do { // find the point with the smallest angle. double angle = double.MaxValue; PointF2D next = null; foreach (PointF2D point in points) { if (point != current) { VectorF2D next_vector = point - current; double next_angle = reference.Angle(next_vector).Value; if (next_angle < angle) { angle = next_angle; next = point; } } } // the found point is the next one. reference = next - current; current = next; result.Add(current); }while(current != start); // return the result. return(result); }
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; } }