示例#1
0
        /// <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));
        }
示例#2
0
        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);
        }
示例#3
0
        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;
            }
        }
示例#4
0
        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;
            }
        }
示例#5
0
        /// <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;
            }
        }
示例#6
0
        /// <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;
            }
        }