/// <summary>
        /// 
        /// </summary>
        /// <param name="bezier"></param>
        /// <param name="point"></param>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        /// <returns></returns>
        public static bool Contains(XBezier bezier, Vector2 point, double dx, double dy)
        {
            Vector2[] vertices = new Vector2[4];
            int k;
            Vector2[] convexHull;

            vertices[0] = new Vector2(bezier.Point1.X + dx, bezier.Point1.Y + dy);
            vertices[1] = new Vector2(bezier.Point2.X + dx, bezier.Point2.Y + dy);
            vertices[2] = new Vector2(bezier.Point3.X + dx, bezier.Point3.Y + dy);
            vertices[3] = new Vector2(bezier.Point4.X + dx, bezier.Point4.Y + dy);

            mc.ConvexHull(vertices, out convexHull, out k);

            return Contains(point.X, point.Y, convexHull, k);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dc"></param>
        /// <param name="bezier"></param>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        /// <param name="db"></param>
        /// <param name="r"></param>
        public void Draw(object dc, XBezier bezier, double dx, double dy, ImmutableArray<ShapeProperty> db, Record r)
        {
            var _dc = dc as DrawingContext;

            var style = bezier.Style;
            if (style == null)
                return;

            double thickness = style.Thickness / _state.Zoom;
            double half = thickness / 2.0;

            Tuple<Brush, Pen> cache = null;
            Brush fill;
            Pen stroke;
            if (_enableStyleCache
                && _styleCache.TryGetValue(style, out cache))
            {
                fill = cache.Item1;
                stroke = cache.Item2;
            }
            else
            {
                fill = CreateBrush(style.Fill);
                stroke = CreatePen(style, thickness);
                if (_enableStyleCache)
                    _styleCache.Add(style, Tuple.Create(fill, stroke));
            }

            PathGeometry pg = null;
            if (_enableBezierCache
                && _bezierCache.TryGetValue(bezier, out pg))
            {
                var pf = pg.Figures[0];
                pf.StartPoint = new Point(bezier.Point1.X + dx, bezier.Point1.Y + dy);
                pf.IsFilled = bezier.IsFilled;
                var bs = pf.Segments[0] as BezierSegment;
                bs.Point1 = new Point(bezier.Point2.X + dx, bezier.Point2.Y + dy);
                bs.Point2 = new Point(bezier.Point3.X + dx, bezier.Point3.Y + dy);
                bs.Point3 = new Point(bezier.Point4.X + dx, bezier.Point4.Y + dy);
                bs.IsStroked = bezier.IsStroked;
            }
            else
            {
                var pf = new PathFigure()
                {
                    StartPoint = new Point(bezier.Point1.X + dx, bezier.Point1.Y + dy),
                    IsFilled = bezier.IsFilled
                };
                var bs = new BezierSegment(
                        new Point(bezier.Point2.X + dx, bezier.Point2.Y + dy),
                        new Point(bezier.Point3.X + dx, bezier.Point3.Y + dy),
                        new Point(bezier.Point4.X + dx, bezier.Point4.Y + dy),
                        bezier.IsStroked);
                //bs.Freeze();
                pf.Segments.Add(bs);
                //pf.Freeze();
                pg = new PathGeometry();
                pg.Figures.Add(pf);
                //pg.Freeze();

                if (_enableBezierCache)
                    _bezierCache.Add(bezier, pg);
            }

            DrawPathGeometryInternal(_dc, half, fill, stroke, bezier.IsStroked, bezier.IsFilled, pg);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="bezier"></param>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        /// <returns></returns>
        public static Vector2[] GetVertices(XBezier bezier, double dx, double dy)
        {
            Vector2[] vertices = new Vector2[4];
            int k;
            Vector2[] convexHull;

            vertices[0] = new Vector2(bezier.Point1.X + dx, bezier.Point1.Y + dy);
            vertices[1] = new Vector2(bezier.Point2.X + dx, bezier.Point2.Y + dy);
            vertices[2] = new Vector2(bezier.Point3.X + dx, bezier.Point3.Y + dy);
            vertices[3] = new Vector2(bezier.Point4.X + dx, bezier.Point4.Y + dy);

            mc.ConvexHull(vertices, out convexHull, out k);

            return convexHull.Take(k).ToArray();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="gfx"></param>
        /// <param name="bezier"></param>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        /// <param name="db"></param>
        /// <param name="r"></param>
        public void Draw(object gfx, XBezier bezier, double dx, double dy, ImmutableArray<ShapeProperty> db, Record r)
        {
            var _gfx = gfx as Graphics;

            Brush brush = ToSolidBrush(bezier.Style.Fill);
            Pen pen = ToPen(bezier.Style, _scaleToPage);

            if (bezier.IsFilled)
            {
                var path = new GraphicsPath();
                path.AddBezier(
                    _scaleToPage(bezier.Point1.X),
                    _scaleToPage(bezier.Point1.Y),
                    _scaleToPage(bezier.Point2.X),
                    _scaleToPage(bezier.Point2.Y),
                    _scaleToPage(bezier.Point3.X),
                    _scaleToPage(bezier.Point3.Y),
                    _scaleToPage(bezier.Point4.X),
                    _scaleToPage(bezier.Point4.Y));
                _gfx.FillPath(brush, path);
            }

            if (bezier.IsStroked)
            {
                _gfx.DrawBezier(
                    pen,
                    _scaleToPage(bezier.Point1.X),
                    _scaleToPage(bezier.Point1.Y),
                    _scaleToPage(bezier.Point2.X),
                    _scaleToPage(bezier.Point2.Y),
                    _scaleToPage(bezier.Point3.X),
                    _scaleToPage(bezier.Point3.Y),
                    _scaleToPage(bezier.Point4.X),
                    _scaleToPage(bezier.Point4.Y));
            }

            brush.Dispose();
            pen.Dispose();
        }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="x"></param>
 /// <param name="y"></param>
 public override void LeftDown(double x, double y)
 {
     double sx = _editor.Project.Options.SnapToGrid ? Editor.Snap(x, _editor.Project.Options.SnapX) : x;
     double sy = _editor.Project.Options.SnapToGrid ? Editor.Snap(y, _editor.Project.Options.SnapY) : y;
     switch (_currentState)
     {
         case State.None:
             {
                 _shape = XBezier.Create(
                     sx, sy,
                     _editor.Project.CurrentStyleLibrary.CurrentStyle,
                     _editor.Project.Options.PointShape,
                     _editor.Project.Options.DefaultIsStroked,
                     _editor.Project.Options.DefaultIsFilled);
                 if (_editor.Project.Options.TryToConnect)
                 {
                     TryToConnectPoint1(_shape as XBezier, sx, sy);
                 }
                 _editor.Project.CurrentContainer.WorkingLayer.Shapes = _editor.Project.CurrentContainer.WorkingLayer.Shapes.Add(_shape);
                 _editor.Project.CurrentContainer.WorkingLayer.Invalidate();
                 ToStateOne();
                 Move(_shape as XBezier);
                 _editor.Project.CurrentContainer.HelperLayer.Invalidate();
                 _currentState = State.One;
                 _editor.CancelAvailable = true;
             }
             break;
         case State.One:
             {
                 var bezier = _shape as XBezier;
                 if (bezier != null)
                 {
                     bezier.Point3.X = sx;
                     bezier.Point3.Y = sy;
                     bezier.Point4.X = sx;
                     bezier.Point4.Y = sy;
                     if (_editor.Project.Options.TryToConnect)
                     {
                         TryToConnectPoint4(_shape as XBezier, sx, sy);
                     }
                     _editor.Project.CurrentContainer.WorkingLayer.Invalidate();
                     ToStateTwo();
                     Move(_shape as XBezier);
                     _editor.Project.CurrentContainer.HelperLayer.Invalidate();
                     _currentState = State.Two;
                 }
             }
             break;
         case State.Two:
             {
                 var bezier = _shape as XBezier;
                 if (bezier != null)
                 {
                     bezier.Point2.X = sx;
                     bezier.Point2.Y = sy;
                     if (_editor.Project.Options.TryToConnect)
                     {
                         TryToConnectPoint2(_shape as XBezier, sx, sy);
                     }
                     _editor.Project.CurrentContainer.WorkingLayer.Invalidate();
                     ToStateThree();
                     Move(_shape as XBezier);
                     _editor.Project.CurrentContainer.HelperLayer.Invalidate();
                     _currentState = State.Three;
                 }
             }
             break;
         case State.Three:
             {
                 var bezier = _shape as XBezier;
                 if (bezier != null)
                 {
                     bezier.Point3.X = sx;
                     bezier.Point3.Y = sy;
                     if (_editor.Project.Options.TryToConnect)
                     {
                         TryToConnectPoint3(_shape as XBezier, sx, sy);
                     }
                     _editor.Project.CurrentContainer.WorkingLayer.Shapes = _editor.Project.CurrentContainer.WorkingLayer.Shapes.Remove(_shape);
                     Remove();
                     Finalize(_shape as XBezier);
                     _editor.AddWithHistory(_shape);
                     _currentState = State.None;
                     _editor.CancelAvailable = false;
                 }
             }
             break;
     }
 }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="bezier"></param>
 /// <param name="x"></param>
 /// <param name="y"></param>
 public void TryToConnectPoint4(XBezier bezier, double x, double y)
 {
     var result = ShapeBounds.HitTest(_editor.Project.CurrentContainer, new Vector2(x, y), _editor.Project.Options.HitTreshold);
     if (result != null && result is XPoint)
     {
         bezier.Point4 = result as XPoint;
     }
 }