Exemplo n.º 1
0
        /// <summary>
        /// Calculates the bounds with respect to rotation angle and horizontal/vertical alignment.
        /// </summary>
        /// <param name="bounds">The size of the object to calculate bounds for.</param>
        /// <param name="angle">The rotation angle (degrees).</param>
        /// <param name="horizontalAlignment">The horizontal alignment.</param>
        /// <param name="verticalAlignment">The vertical alignment.</param>
        /// <returns>A minimum bounding rectangle.</returns>
        public static OxyRect GetBounds(this OxySize bounds, double angle, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment)
        {
            var u = horizontalAlignment == HorizontalAlignment.Left ? 0 : horizontalAlignment == HorizontalAlignment.Center ? 0.5 : 1;
            var v = verticalAlignment == VerticalAlignment.Top ? 0 : verticalAlignment == VerticalAlignment.Middle ? 0.5 : 1;

            var origin = new ScreenVector(u * bounds.Width, v * bounds.Height);

            if (angle == 0)
            {
                return new OxyRect(-origin.X, -origin.Y, bounds.Width, bounds.Height);
            }

            // the corners of the rectangle
            var p0 = new ScreenVector(0, 0) - origin;
            var p1 = new ScreenVector(bounds.Width, 0) - origin;
            var p2 = new ScreenVector(bounds.Width, bounds.Height) - origin;
            var p3 = new ScreenVector(0, bounds.Height) - origin;

            var theta = angle * Math.PI / 180.0;
            var costh = Math.Cos(theta);
            var sinth = Math.Sin(theta);
            Func<ScreenVector, ScreenVector> rotate = p => new ScreenVector((costh * p.X) - (sinth * p.Y), (sinth * p.X) + (costh * p.Y));

            var q0 = rotate(p0);
            var q1 = rotate(p1);
            var q2 = rotate(p2);
            var q3 = rotate(p3);

            var x = Math.Min(Math.Min(q0.X, q1.X), Math.Min(q2.X, q3.X));
            var y = Math.Min(Math.Min(q0.Y, q1.Y), Math.Min(q2.Y, q3.Y));
            var w = Math.Max(Math.Max(q0.X - x, q1.X - x), Math.Max(q2.X - x, q3.X - x));
            var h = Math.Max(Math.Max(q0.Y - y, q1.Y - y), Math.Max(q2.Y - y, q3.Y - y));

            return new OxyRect(x, y, w, h);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Gets the polygon outline of the specified rotated and aligned box.
        /// </summary>
        /// <param name="size">The size of the  box.</param>
        /// <param name="origin">The origin of the box.</param>
        /// <param name="angle">The rotation angle of the box.</param>
        /// <param name="horizontalAlignment">The horizontal alignment of the box.</param>
        /// <param name="verticalAlignment">The vertical alignment of the box.</param>
        /// <returns>A sequence of points defining the polygon outline of the box.</returns>
        public static IEnumerable<ScreenPoint> GetPolygon(this OxySize size, ScreenPoint origin, double angle, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment)
        {
            var u = horizontalAlignment == HorizontalAlignment.Left ? 0 : horizontalAlignment == HorizontalAlignment.Center ? 0.5 : 1;
            var v = verticalAlignment == VerticalAlignment.Top ? 0 : verticalAlignment == VerticalAlignment.Middle ? 0.5 : 1;

            var offset = new ScreenVector(u * size.Width, v * size.Height);

            // the corners of the rectangle
            var p0 = new ScreenVector(0, 0) - offset;
            var p1 = new ScreenVector(size.Width, 0) - offset;
            var p2 = new ScreenVector(size.Width, size.Height) - offset;
            var p3 = new ScreenVector(0, size.Height) - offset;

            if (angle != 0)
            {
                var theta = angle * Math.PI / 180.0;
                var costh = Math.Cos(theta);
                var sinth = Math.Sin(theta);
                Func<ScreenVector, ScreenVector> rotate = p => new ScreenVector((costh * p.X) - (sinth * p.Y), (sinth * p.X) + (costh * p.Y));

                p0 = rotate(p0);
                p1 = rotate(p1);
                p2 = rotate(p2);
                p3 = rotate(p3);
            }

            yield return origin + p0;
            yield return origin + p1;
            yield return origin + p2;
            yield return origin + p3;
        }
Exemplo n.º 3
0
        /// <summary>
        /// Gets the polygon outline of the specified rotated and aligned box.
        /// </summary>
        /// <param name="size">The size of the  box.</param>
        /// <param name="origin">The origin of the box.</param>
        /// <param name="angle">The rotation angle of the box.</param>
        /// <param name="horizontalAlignment">The horizontal alignment of the box.</param>
        /// <param name="verticalAlignment">The vertical alignment of the box.</param>
        /// <returns>A sequence of points defining the polygon outline of the box.</returns>
        public static IEnumerable <ScreenPoint> GetPolygon(this OxySize size, ScreenPoint origin, double angle, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment)
        {
            var u = horizontalAlignment == HorizontalAlignment.Left ? 0 : horizontalAlignment == HorizontalAlignment.Center ? 0.5 : 1;
            var v = verticalAlignment == VerticalAlignment.Top ? 0 : verticalAlignment == VerticalAlignment.Middle ? 0.5 : 1;

            var offset = new ScreenVector(u * size.Width, v * size.Height);

            // the corners of the rectangle
            var p0 = new ScreenVector(0, 0) - offset;
            var p1 = new ScreenVector(size.Width, 0) - offset;
            var p2 = new ScreenVector(size.Width, size.Height) - offset;
            var p3 = new ScreenVector(0, size.Height) - offset;

            if (angle != 0)
            {
                var theta = angle * Math.PI / 180.0;
                var costh = Math.Cos(theta);
                var sinth = Math.Sin(theta);
                Func <ScreenVector, ScreenVector> rotate = p => new ScreenVector((costh * p.X) - (sinth * p.Y), (sinth * p.X) + (costh * p.Y));

                p0 = rotate(p0);
                p1 = rotate(p1);
                p2 = rotate(p2);
                p3 = rotate(p3);
            }

            yield return(origin + p0);

            yield return(origin + p1);

            yield return(origin + p2);

            yield return(origin + p3);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Calculates the bounds with respect to rotation angle and horizontal/vertical alignment.
        /// </summary>
        /// <param name="bounds">The size of the object to calculate bounds for.</param>
        /// <param name="angle">The rotation angle (degrees).</param>
        /// <param name="horizontalAlignment">The horizontal alignment.</param>
        /// <param name="verticalAlignment">The vertical alignment.</param>
        /// <returns>A minimum bounding rectangle.</returns>
        public static OxyRect GetBounds(this OxySize bounds, double angle, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment)
        {
            var u = horizontalAlignment == HorizontalAlignment.Left ? 0 : horizontalAlignment == HorizontalAlignment.Center ? 0.5 : 1;
            var v = verticalAlignment == VerticalAlignment.Top ? 0 : verticalAlignment == VerticalAlignment.Middle ? 0.5 : 1;

            var origin = new ScreenVector(u * bounds.Width, v * bounds.Height);

            if (angle == 0)
            {
                return(new OxyRect(-origin.X, -origin.Y, bounds.Width, bounds.Height));
            }

            // the corners of the rectangle
            var p0 = new ScreenVector(0, 0) - origin;
            var p1 = new ScreenVector(bounds.Width, 0) - origin;
            var p2 = new ScreenVector(bounds.Width, bounds.Height) - origin;
            var p3 = new ScreenVector(0, bounds.Height) - origin;

            var theta = angle * Math.PI / 180.0;
            var costh = Math.Cos(theta);
            var sinth = Math.Sin(theta);
            Func <ScreenVector, ScreenVector> rotate = p => new ScreenVector((costh * p.X) - (sinth * p.Y), (sinth * p.X) + (costh * p.Y));

            var q0 = rotate(p0);
            var q1 = rotate(p1);
            var q2 = rotate(p2);
            var q3 = rotate(p3);

            var x = Math.Min(Math.Min(q0.X, q1.X), Math.Min(q2.X, q3.X));
            var y = Math.Min(Math.Min(q0.Y, q1.Y), Math.Min(q2.Y, q3.Y));
            var w = Math.Max(Math.Max(q0.X - x, q1.X - x), Math.Max(q2.X - x, q3.X - x));
            var h = Math.Max(Math.Max(q0.Y - y, q1.Y - y), Math.Max(q2.Y - y, q3.Y - y));

            return(new OxyRect(x, y, w, h));
        }
        /// <summary>
        /// Gets the coordinates of the (rotated) background rectangle.
        /// </summary>
        /// <param name="position">
        /// The position.
        /// </param>
        /// <param name="size">
        /// The size.
        /// </param>
        /// <param name="padding">
        /// The padding.
        /// </param>
        /// <param name="rotation">
        /// The rotation.
        /// </param>
        /// <param name="horizontalAlignment">
        /// The horizontal alignment.
        /// </param>
        /// <param name="verticalAlignment">
        /// The vertical alignment.
        /// </param>
        /// <returns>
        /// The background rectangle coordinates.
        /// </returns>
        private static IList <ScreenPoint> GetTextBounds(
            ScreenPoint position,
            OxySize size,
            OxyThickness padding,
            double rotation,
            HorizontalTextAlign horizontalAlignment,
            VerticalTextAlign verticalAlignment)
        {
            double left, right, top, bottom;

            switch (horizontalAlignment)
            {
            case HorizontalTextAlign.Center:
                left  = -size.Width * 0.5;
                right = -left;
                break;

            case HorizontalTextAlign.Right:
                left  = -size.Width;
                right = 0;
                break;

            default:
                left  = 0;
                right = size.Width;
                break;
            }

            switch (verticalAlignment)
            {
            case VerticalTextAlign.Middle:
                top    = -size.Height * 0.5;
                bottom = -top;
                break;

            case VerticalTextAlign.Bottom:
                top    = -size.Height;
                bottom = 0;
                break;

            default:
                top    = 0;
                bottom = size.Height;
                break;
            }

            double cost    = Math.Cos(rotation / 180 * Math.PI);
            double sint    = Math.Sin(rotation / 180 * Math.PI);
            var    u       = new ScreenVector(cost, sint);
            var    v       = new ScreenVector(-sint, cost);
            var    polygon = new ScreenPoint[4];

            polygon[0] = position + u * (left - padding.Left) + v * (top - padding.Top);
            polygon[1] = position + u * (right + padding.Right) + v * (top - padding.Top);
            polygon[2] = position + u * (right + padding.Right) + v * (bottom + padding.Bottom);
            polygon[3] = position + u * (left - padding.Left) + v * (bottom + padding.Bottom);
            return(polygon);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Draws the text.
        /// </summary>
        /// <param name="p">The p.</param>
        /// <param name="text">The text.</param>
        /// <param name="c">The c.</param>
        /// <param name="fontFamily">The font family.</param>
        /// <param name="fontSize">Size of the font.</param>
        /// <param name="fontWeight">The font weight.</param>
        /// <param name="rotate">The rotate.</param>
        /// <param name="halign">The horizontal alignment.</param>
        /// <param name="valign">The vertical alignment.</param>
        /// <param name="maxSize">Size of the max.</param>
        public override void DrawText(
            ScreenPoint p,
            string text,
            OxyColor c,
            string fontFamily,
            double fontSize,
            double fontWeight,
            double rotate,
            HorizontalAlignment halign,
            VerticalAlignment valign,
            OxySize?maxSize)
        {
            if (string.IsNullOrEmpty(text))
            {
                return;
            }

            var lines = Regex.Split(text, "\r\n");

            if (valign == VerticalAlignment.Bottom)
            {
                for (var i = lines.Length - 1; i >= 0; i--)
                {
                    var line = lines[i];
                    var size = this.MeasureText(line, fontFamily, fontSize, fontWeight);
                    this.w.WriteText(p, line, c, fontFamily, fontSize, fontWeight, rotate, halign, valign);

                    p += new ScreenVector(Math.Sin(rotate / 180.0 * Math.PI) * size.Height, Math.Cos(rotate / 180.0 * Math.PI) * size.Height);
                }
            }
            else
            {
                foreach (var line in lines)
                {
                    var size = this.MeasureText(line, fontFamily, fontSize, fontWeight);
                    this.w.WriteText(p, line, c, fontFamily, fontSize, fontWeight, rotate, halign, valign);

                    p += new ScreenVector(-Math.Sin(rotate / 180.0 * Math.PI) * size.Height, Math.Cos(rotate / 180.0 * Math.PI) * size.Height);
                }
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Distorts the specified points.
        /// </summary>
        /// <param name="points">The input points.</param>
        /// <returns>
        /// The distorted points.
        /// </returns>
        private ScreenPoint[] Distort(IEnumerable <ScreenPoint> points)
        {
            // See the Mathematica / Matplotlib solutions
            // http://jakevdp.github.io/blog/2012/10/07/xkcd-style-plots-in-matplotlib/
            // http://jakevdp.github.io/blog/2013/07/10/XKCD-plots-in-matplotlib/
            // http://mathematica.stackexchange.com/questions/11350/xkcd-style-graphs
            // http://www.mail-archive.com/[email protected]/msg25499.html
            // http://nbviewer.ipython.org/gist/anonymous/3835181
            // http://matplotlib.org/xkcd/
            // http://xkcd.com/

            // The following code is just to show that some randomness is working - this should be improved
            IList <ScreenPoint> interpolated = this.Interpolate(points, this.InterpolationDistance).ToArray();
            var result        = new ScreenPoint[interpolated.Count];
            var randomNumbers = this.GenerateRandomNumbers(interpolated.Count);

            randomNumbers = this.ApplyMovingAverage(randomNumbers, 5);

            var    d  = this.DistortionFactor;
            double d2 = d / 2;

            for (int i = 0; i < interpolated.Count; i++)
            {
                if (i == 0 || i == interpolated.Count - 1)
                {
                    result[i] = interpolated[i];
                    continue;
                }

                var tangent = interpolated[i + 1] - interpolated[i - 1];
                tangent.Normalize();
                var normal = new ScreenVector(tangent.Y, -tangent.X);

                var delta = normal * ((randomNumbers[i] * d) - d2);
                result[i] = interpolated[i] + delta;
            }

            return(result);
        }
Exemplo n.º 8
0
            public override void Render(IRenderContext rc, PlotModel model)
            {
                // transform to screen coordinates
                var p0 = this.Transform(this.StartPoint);
                var p1 = this.Transform(this.EndPoint);

                var direction = p1 - p0;
                var normal = new ScreenVector(direction.Y, -direction.X);

                // the end points of the arrow head, scaled by length of arrow
                var p2 = p1 - (direction * 0.2) + (normal * 0.1);
                var p3 = p1 - (direction * 0.2) - (normal * 0.1);

                // draw the line segments
                rc.DrawLineSegments(new[] { p0, p1, p1, p2, p1, p3 }, this.ActualColor, this.StrokeThickness);
            }
Exemplo n.º 9
0
        /// <summary>
        /// Draws the text.
        /// </summary>
        /// <param name="p">The p.</param>
        /// <param name="text">The text.</param>
        /// <param name="c">The c.</param>
        /// <param name="fontFamily">The font family.</param>
        /// <param name="fontSize">Size of the font.</param>
        /// <param name="fontWeight">The font weight.</param>
        /// <param name="rotate">The rotate.</param>
        /// <param name="halign">The horizontal alignment.</param>
        /// <param name="valign">The vertical alignment.</param>
        /// <param name="maxSize">Size of the max.</param>
        public override void DrawText(
            ScreenPoint p,
            string text,
            OxyColor c,
            string fontFamily,
            double fontSize,
            double fontWeight,
            double rotate,
            HorizontalAlignment halign,
            VerticalAlignment valign,
            OxySize? maxSize)
        {
            if (string.IsNullOrEmpty(text))
            {
                return;
            }

            var lines = Regex.Split(text, "\r\n");
            if (valign == VerticalAlignment.Bottom)
            {
                for (var i = lines.Length - 1; i >= 0; i--)
                {
                    var line = lines[i];
                    var size = this.MeasureText(line, fontFamily, fontSize, fontWeight);
                    this.w.WriteText(p, line, c, fontFamily, fontSize, fontWeight, rotate, halign, valign);

                    p += new ScreenVector(Math.Sin(rotate / 180.0 * Math.PI) * size.Height, Math.Cos(rotate / 180.0 * Math.PI) * size.Height);
                }
            }
            else
            {
                foreach (var line in lines)
                {
                    var size = this.MeasureText(line, fontFamily, fontSize, fontWeight);
                    this.w.WriteText(p, line, c, fontFamily, fontSize, fontWeight, rotate, halign, valign);

                    p += new ScreenVector(-Math.Sin(rotate / 180.0 * Math.PI) * size.Height, Math.Cos(rotate / 180.0 * Math.PI) * size.Height);
                }
            }
        }
Exemplo n.º 10
0
        /// <summary>
        /// Draws the text.
        /// </summary>
        /// <param name="p">The p.</param>
        /// <param name="text">The text.</param>
        /// <param name="c">The c.</param>
        /// <param name="fontFamily">The font family.</param>
        /// <param name="fontSize">Size of the font.</param>
        /// <param name="fontWeight">The font weight.</param>
        /// <param name="rotate">The rotate.</param>
        /// <param name="halign">The horizontal alignment.</param>
        /// <param name="valign">The vertical alignment.</param>
        /// <param name="maxSize">Size of the max.</param>
        public override void DrawText(
            ScreenPoint p,
            string text,
            OxyColor c,
            string fontFamily,
            double fontSize,
            double fontWeight,
            double rotate,
            HorizontalAlignment halign,
            VerticalAlignment valign,
            OxySize?maxSize)
        {
            if (string.IsNullOrEmpty(text))
            {
                return;
            }

            var lines = StringHelper.SplitLines(text);

            var textSize   = this.MeasureText(text, fontFamily, fontSize, fontWeight);
            var lineHeight = textSize.Height / lines.Length;
            var lineOffset = new ScreenVector(-Math.Sin(rotate / 180.0 * Math.PI) * lineHeight, +Math.Cos(rotate / 180.0 * Math.PI) * lineHeight);

            if (this.UseVerticalTextAlignmentWorkaround)
            {
                // offset the position, and set the valign to neutral value of `Bottom`
                double offsetRatio = valign == VerticalAlignment.Bottom ? (1.0 - lines.Length) : valign == VerticalAlignment.Top ? 1.0 : (1.0 - (lines.Length / 2.0));
                valign = VerticalAlignment.Bottom;

                p += lineOffset * offsetRatio;

                foreach (var line in lines)
                {
                    var size = this.MeasureText(line, fontFamily, fontSize, fontWeight);
                    this.w.WriteText(p, line, c, fontFamily, fontSize, fontWeight, rotate, halign, valign);

                    p += lineOffset;
                }
            }
            else
            {
                if (valign == VerticalAlignment.Bottom)
                {
                    for (var i = lines.Length - 1; i >= 0; i--)
                    {
                        var line = lines[i];
                        var size = this.MeasureText(line, fontFamily, fontSize, fontWeight);
                        this.w.WriteText(p, line, c, fontFamily, fontSize, fontWeight, rotate, halign, valign);

                        p -= lineOffset;
                    }
                }
                else
                {
                    foreach (var line in lines)
                    {
                        var size = this.MeasureText(line, fontFamily, fontSize, fontWeight);
                        this.w.WriteText(p, line, c, fontFamily, fontSize, fontWeight, rotate, halign, valign);

                        p += lineOffset;
                    }
                }
            }
        }
Exemplo n.º 11
0
        /// <summary>
        /// Called when a touch gesture is moving.
        /// </summary>
        /// <param name="touches">The touches.</param>
        /// <param name="evt">The event arguments.</param>
        public override void TouchesMoved(NSSet touches, UIEvent evt)
        {
            // it seems to be easier to handle touch events here than using UIPanGesturRecognizer and UIPinchGestureRecognizer
            base.TouchesMoved(touches, evt);

            // convert the touch points to an array
            var ta = touches.ToArray<UITouch>();

            if (ta.Length > 0)
            {
                // get current and previous location of the first touch point
                var t1 = ta[0];
                var l1 = t1.LocationInView(this).ToScreenPoint();
                var pl1 = t1.PreviousLocationInView(this).ToScreenPoint();
                var l = l1;
                var t = l1 - pl1;
                var s = new ScreenVector(1, 1);
                if (ta.Length > 1)
                {
                    // get current and previous location of the second touch point
                    var t2 = ta[1];
                    var l2 = t2.LocationInView(this).ToScreenPoint();
                    var pl2 = t2.PreviousLocationInView(this).ToScreenPoint();
                    var d = l1 - l2;
                    var pd = pl1 - pl2;
                    if (!this.KeepAspectRatioWhenPinching)
                    {
                        var scalex = System.Math.Abs(pd.X) > 0 ? System.Math.Abs(d.X / pd.X) : 1;
                        var scaley = System.Math.Abs(pd.Y) > 0 ? System.Math.Abs(d.Y / pd.Y) : 1;
                        s = new ScreenVector(scalex, scaley);
                    }
                    else
                    {
                        var scale = pd.Length > 0 ? d.Length / pd.Length : 1;
                        s = new ScreenVector(scale, scale);
                    }
                }

                var e = new OxyTouchEventArgs { Position = l, DeltaTranslation = t, DeltaScale = s };
                this.ActualController.HandleTouchDelta(this, e);
            }
        }
        /// <summary>
        /// Gets the coordinates of the (rotated) background rectangle.
        /// </summary>
        /// <param name="position">
        /// The position.
        /// </param>
        /// <param name="size">
        /// The size.
        /// </param>
        /// <param name="padding">
        /// The padding.
        /// </param>
        /// <param name="rotation">
        /// The rotation.
        /// </param>
        /// <param name="horizontalAlignment">
        /// The horizontal alignment.
        /// </param>
        /// <param name="verticalAlignment">
        /// The vertical alignment.
        /// </param>
        /// <returns>
        /// The background rectangle coordinates.
        /// </returns>
        private static IList<ScreenPoint> GetTextBounds(
            ScreenPoint position,
            OxySize size,
            OxyThickness padding,
            double rotation,
            HorizontalTextAlign horizontalAlignment,
            VerticalTextAlign verticalAlignment)
        {
            double left, right, top, bottom;
            switch (horizontalAlignment)
            {
                case HorizontalTextAlign.Center:
                    left = -size.Width * 0.5;
                    right = -left;
                    break;
                case HorizontalTextAlign.Right:
                    left = -size.Width;
                    right = 0;
                    break;
                default:
                    left = 0;
                    right = size.Width;
                    break;
            }

            switch (verticalAlignment)
            {
                case VerticalTextAlign.Middle:
                    top = -size.Height * 0.5;
                    bottom = -top;
                    break;
                case VerticalTextAlign.Bottom:
                    top = -size.Height;
                    bottom = 0;
                    break;
                default:
                    top = 0;
                    bottom = size.Height;
                    break;
            }

            double cost = Math.Cos(rotation / 180 * Math.PI);
            double sint = Math.Sin(rotation / 180 * Math.PI);
            var u = new ScreenVector(cost, sint);
            var v = new ScreenVector(-sint, cost);
            var polygon = new ScreenPoint[4];
            polygon[0] = position + u * (left - padding.Left) + v * (top - padding.Top);
            polygon[1] = position + u * (right + padding.Right) + v * (top - padding.Top);
            polygon[2] = position + u * (right + padding.Right) + v * (bottom + padding.Bottom);
            polygon[3] = position + u * (left - padding.Left) + v * (bottom + padding.Bottom);
            return polygon;
        }
Exemplo n.º 13
0
        /// <summary>
        /// Distorts the specified points.
        /// </summary>
        /// <param name="points">The input points.</param>
        /// <returns>
        /// The distorted points.
        /// </returns>
        private ScreenPoint[] Distort(IEnumerable<ScreenPoint> points)
        {
            // See the Mathematica / Matplotlib solutions
            // http://jakevdp.github.io/blog/2012/10/07/xkcd-style-plots-in-matplotlib/
            // http://jakevdp.github.io/blog/2013/07/10/XKCD-plots-in-matplotlib/
            // http://mathematica.stackexchange.com/questions/11350/xkcd-style-graphs
            // http://www.mail-archive.com/[email protected]/msg25499.html
            // http://nbviewer.ipython.org/gist/anonymous/3835181
            // http://matplotlib.org/xkcd/
            // http://xkcd.com/

            // The following code is just to show that some randomness is working - this should be improved
            IList<ScreenPoint> interpolated = this.Interpolate(points, this.InterpolationDistance).ToArray();
            var result = new ScreenPoint[interpolated.Count];
            var randomNumbers = this.GenerateRandomNumbers(interpolated.Count);
            randomNumbers = this.ApplyMovingAverage(randomNumbers, 5);

            var d = this.DistortionFactor;
            double d2 = d / 2;
            for (int i = 0; i < interpolated.Count; i++)
            {
                if (i == 0 || i == interpolated.Count - 1)
                {
                    result[i] = interpolated[i];
                    continue;
                }

                var tangent = interpolated[i + 1] - interpolated[i - 1];
                tangent.Normalize();
                var normal = new ScreenVector(tangent.Y, -tangent.X);

                var delta = normal * ((randomNumbers[i] * d) - d2);
                result[i] = interpolated[i] + delta;
            }

            return result;
        }