private void BuildDistortion(GraphicsPath source)
        {
            _sourceBounds = source.GetBounds();

            _distortionPath = new GraphicsPath(source.FillMode);

            _lowerLeft  = new PointF(_sourceBounds.Left, _sourceBounds.Bottom);
            _lowerRight = new PointF(_sourceBounds.Right, _sourceBounds.Bottom);
            _upperLeft  = new PointF(_sourceBounds.Left, _sourceBounds.Top);
            _upperRight = new PointF(_sourceBounds.Right, _sourceBounds.Top);

            _distortionPath.AddLine(_lowerLeft, _upperLeft);

            _distortionPath.AddBezier(_upperLeft,
                                      new PointF(_sourceBounds.Left, _sourceBounds.Top + ((_sourceBounds.Height * (float)Intensity)) * -1),
                                      new PointF(_sourceBounds.Right, _sourceBounds.Top + ((_sourceBounds.Height * (float)Intensity)) * -1),
                                      _upperRight);

            _distortionPath.AddLine(_upperRight, _lowerRight);

            _distortionPath.AddBezier(_lowerRight,
                                      new PointF(_sourceBounds.Right, _sourceBounds.Bottom + (_sourceBounds.Height * (float)Intensity)),
                                      new PointF(_sourceBounds.Left, _sourceBounds.Bottom + (_sourceBounds.Height * (float)Intensity)),
                                      _lowerLeft);

            _distortionPath.Flatten();
            _distortionPoints = ClipperUtility.ConvertToClipperPolygons(_distortionPath);
            _distortionBounds = _distortionPath.GetBounds();
        }
        private void GetBoundedPoints(out PointF upperBoundPoint, out PointF lowerBoundPoint, PointF source)
        {
            if (_boundCache.ContainsKey(source.X))
            {
                upperBoundPoint = _boundCache[source.X][0];
                lowerBoundPoint = _boundCache[source.X][1];
                return;
            }

            var Path   = new GraphicsPath();
            var UpperX = source.X * (_sourceBounds.Width / (_upperRight.X - _upperLeft.X));
            var LowerX = source.X * (_sourceBounds.Width / (_lowerRight.X - _lowerLeft.X));

            Path.AddPolygon(new PointF[] {
                new PointF(_distortionBounds.Left, _distortionBounds.Bottom),
                new PointF(_distortionBounds.Left, _distortionBounds.Top),
                new PointF(UpperX, _distortionBounds.Top),
                new PointF(LowerX, _distortionBounds.Bottom),
            });
            Path.CloseFigure();
            var ClippingPath = ClipperUtility.ConvertToClipperPolygons(Path);

            Path.Dispose();

            var ClippedPath = ClipperUtility.Clip(ClippingPath, _distortionPoints);

            if (Math.Abs(source.X - _sourceBounds.Left) < .1 || Math.Abs(source.X - _sourceBounds.Right) < .1)
            {
                upperBoundPoint = new PointF(_sourceBounds.Left, _sourceBounds.Top);
                lowerBoundPoint = new PointF(_sourceBounds.Left, _sourceBounds.Bottom);
            }
            else
            {
                var Points       = ClippedPath.PathPoints;
                var QuickBounded = Points.Where(p => Math.Abs(p.X - LowerX) < .01);
                if (QuickBounded.Any())
                {
                    upperBoundPoint = Points.Where(p => Math.Abs(p.X - LowerX) < .01).OrderBy(p => p.Y).First();
                    lowerBoundPoint = Points.Where(p => Math.Abs(p.X - LowerX) < .01).OrderByDescending(p => p.Y).First();
                    _boundCache.Add(source.X, new PointF[] { upperBoundPoint, lowerBoundPoint });
                }
                else
                {
                    var RightMostPoints = Points.OrderByDescending(p => p.X).Take(2).ToList();
                    upperBoundPoint = RightMostPoints.OrderBy(p => p.Y).First();
                    lowerBoundPoint = RightMostPoints.OrderByDescending(p => p.Y).First();
                }
                ClippedPath.Dispose();
            }
        }