//Create new point/plane extending to target
        public CollisionLink Branch(Vector2 point)
        {
            CollisionLink  link  = new CollisionLink(_parent, point);
            CollisionPlane plane = new CollisionPlane(_parent, this, link);

            return(link);
        }
        public void SwapLinks()
        {
            CollisionLink l = _linkLeft;

            _linkLeft  = _linkRight;
            _linkRight = l;
        }
        private void SwapLinks()
        {
            CollisionLink l = _linkLeft;

            _linkLeft  = _linkRight;
            _linkRight = l;
        }
        public CollisionLink Split(Vector2 point)
        {
            CollisionLink  link  = new CollisionLink(_parent, point);
            CollisionPlane plane = new CollisionPlane(_parent, link, _linkRight);

            LinkRight = link;
            return(link);
        }
        public CollisionPlane(CollisionObject parent, CollisionLink left, CollisionLink right)
        {
            _parent = parent;
            _parent._planes.Add(this);

            LinkLeft  = left;
            LinkRight = right;
        }
        //Connects two points together to create a plane
        public unsafe CollisionPlane Connect(CollisionLink p)
        {
            //Don't connect if not on same object
            if ((p == this) || (this._parent != p._parent))
            {
                return(null);
            }

            //Don't connect if plane already exists
            foreach (CollisionPlane plane in _members)
            {
                if (p._members.Contains(plane))
                {
                    return(null);
                }
            }

            return(new CollisionPlane(_parent, this, p));
        }
        //internal CollisionLink Splinter()
        //{
        //    if (_members.Count <= 1)
        //        return null;

        //    CollisionPlane plane = _members[1];
        //    CollisionLink link = new CollisionLink(_parent, _value);

        //    if (plane._linkLeft == this)
        //        plane.LinkLeft = link;
        //    else
        //        plane.LinkRight = link;


        //    return link;
        //}

        public CollisionLink[] Split()
        {
            int count = _members.Count - 1;

            CollisionLink[] links = new CollisionLink[count];
            for (int i = 0; i < count; i++)
            {
                if (_members[0]._linkLeft == this)
                {
                    _members[0].LinkLeft = links[i] = Clone();
                }
                else
                {
                    _members[0].LinkRight = links[i] = Clone();
                }
            }

            return(links);
        }
        public CollisionLink Split(Vector2 point)
        {
            CollisionLink  link  = new CollisionLink(_parent, point);
            CollisionPlane plane = new CollisionPlane(_parent, link, _linkRight);

            plane._material = _material;
            plane._flags    = _flags;
            plane._flags2   = _flags2;
            plane._type     = _type;
            if (IsRightLedge)
            {
                IsRightLedge = false;
            }
            if (IsLeftLedge)
            {
                plane.IsLeftLedge = false;
            }
            LinkRight = link;
            return(link);
        }
        public bool Merge(CollisionLink link)
        {
            if (_parent != link._parent)
            {
                return(false);
            }

            CollisionPlane plane;

            for (int i = link._members.Count; --i >= 0;)
            {
                plane = link._members[0];

                if (plane._linkLeft == link)
                {
                    if (plane._linkRight == this)
                    {
                        plane.Delete();
                    }
                    else
                    {
                        plane.LinkLeft = this;
                    }
                }
                else
                {
                    if (plane._linkLeft == this)
                    {
                        plane.Delete();
                    }
                    else
                    {
                        plane.LinkRight = this;
                    }
                }
            }

            //_value = (_value + link._value) / 2.0f;

            return(true);
        }
 private void SwapLinks()
 {
     CollisionLink l = _linkLeft;
     _linkLeft = _linkRight;
     _linkRight = l;
 }
 //Create new point/plane extending to target
 public CollisionLink Branch(Vector2 point)
 {
     CollisionLink link = new CollisionLink(_parent, point);
     CollisionPlane plane = new CollisionPlane(_parent, this, link);
     return link;
 }
 public CollisionLink Split(Vector2 point)
 {
     CollisionLink link = new CollisionLink(_parent, point);
     CollisionPlane plane = new CollisionPlane(_parent, link, _linkRight);
     LinkRight = link;
     return link;
 }
        public CollisionPlane(CollisionObject parent, CollisionLink left, CollisionLink right)
        {
            _parent = parent;
            _parent._planes.Add(this);

            LinkLeft = left;
            LinkRight = right;
        }
        //internal CollisionLink Splinter()
        //{
        //    if (_members.Count <= 1)
        //        return null;
        //    CollisionPlane plane = _members[1];
        //    CollisionLink link = new CollisionLink(_parent, _value);
        //    if (plane._linkLeft == this)
        //        plane.LinkLeft = link;
        //    else
        //        plane.LinkRight = link;
        //    return link;
        //}
        public CollisionLink[] Split()
        {
            int count = _members.Count - 1;
            CollisionLink[] links = new CollisionLink[count];
            for (int i = 0; i < count; i++)
                if (_members[0]._linkLeft == this)
                    _members[0].LinkLeft = links[i] = Clone();
                else
                    _members[0].LinkRight = links[i] = Clone();

            return links;
        }
        public bool Merge(CollisionLink link)
        {
            if (_parent != link._parent)
                return false;

            CollisionPlane plane;
            for (int i = link._members.Count; --i >= 0; )
            {
                plane = link._members[0];

                if (plane._linkLeft == link)
                {
                    if (plane._linkRight == this)
                        plane.Delete();
                    else
                        plane.LinkLeft = this;
                }
                else
                {
                    if (plane._linkLeft == this)
                        plane.Delete();
                    else
                        plane.LinkRight = this;
                }
            }

            //_value = (_value + link._value) / 2.0f;

            return true;
        }
        //Connects two points together to create a plane
        public unsafe CollisionPlane Connect(CollisionLink p)
        {
            //Don't connect if not on same object
            if ((p == this) || (this._parent != p._parent))
                return null;

            //Don't connect if plane already exists
            foreach (CollisionPlane plane in _members)
                if (p._members.Contains(plane))
                    return null;

            return new CollisionPlane(_parent, this, p);
        }
 public void Delete()
 {
     LinkLeft  = null;
     LinkRight = null;
     _parent._planes.Remove(this);
 }
        private void _modelPanel_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                bool create = Control.ModifierKeys == Keys.Alt;
                bool add = Control.ModifierKeys == Keys.Shift;
                bool subtract = Control.ModifierKeys == Keys.Control;
                bool move = Control.ModifierKeys == (Keys.Control | Keys.Shift);

                float depth = _modelPanel.GetDepth(e.X, e.Y);
                Vector3 target = _modelPanel.UnProject(e.X, e.Y, depth);
                Vector2 point;

                if (!move && (depth < 1.0f))
                {
                    point = (Vector2)target;

                    //Hit-detect points first
                    foreach (CollisionObject obj in _targetNode._objects)
                        if (obj._render)
                            foreach (CollisionLink p in obj._points)
                                if (p.Value.Contained(point, point, PointSelectRadius))
                                {
                                    if (create)
                                    {
                                        //Connect all selected links to point
                                        foreach (CollisionLink l in _selectedLinks)
                                            l.Connect(p);

                                        //Select point
                                        ClearSelection();
                                        p._highlight = true;
                                        _selectedLinks.Add(p);
                                        SelectionModified();

                                        _modelPanel.Invalidate();
                                        return;
                                    }

                                    if (subtract)
                                    {
                                        p._highlight = false;
                                        _selectedLinks.Remove(p);
                                        _modelPanel.Invalidate();
                                        SelectionModified();
                                    }
                                    else if (!_selectedLinks.Contains(p))
                                    {
                                        if (!add)
                                            ClearSelection();

                                        _selectedLinks.Add(p);
                                        p._highlight = true;
                                        _modelPanel.Invalidate();
                                        SelectionModified();
                                    }

                                    if ((!add) && (!subtract))
                                        BeginHover(target);
                                    //Single Link Selected
                                    return;
                                }

                    float dist;
                    float bestDist = float.MaxValue;
                    CollisionPlane bestMatch = null;

                    //Hit-detect planes finding best match
                    foreach (CollisionObject obj in _targetNode._objects)
                        if (obj._render)
                            foreach (CollisionPlane p in obj._planes)
                                if (point.Contained(p.PointLeft, p.PointRight, PointSelectRadius))
                                {
                                    dist = point.TrueDistance(p.PointLeft) + point.TrueDistance(p.PointRight) - p.PointLeft.TrueDistance(p.PointRight);
                                    if (dist < bestDist)
                                    { bestDist = dist; bestMatch = p; }
                                }

                    if (bestMatch != null)
                    {
                        if (create)
                        {
                            ClearSelection();

                            _selectedLinks.Add(bestMatch.Split(point));
                            _selectedLinks[0]._highlight = true;
                            SelectionModified();
                            _modelPanel.Invalidate();

                            _creating = true;
                            BeginHover(target);

                            return;
                        }

                        if (subtract)
                        {
                            _selectedLinks.Remove(bestMatch._linkLeft);
                            _selectedLinks.Remove(bestMatch._linkRight);
                            bestMatch._linkLeft._highlight = bestMatch._linkRight._highlight = false;
                            _modelPanel.Invalidate();

                            SelectionModified();
                            return;
                        }

                        //Select both points
                        if (!_selectedLinks.Contains(bestMatch._linkLeft) || !_selectedLinks.Contains(bestMatch._linkRight))
                        {
                            if (!add)
                                ClearSelection();

                            _selectedLinks.Add(bestMatch._linkLeft);
                            _selectedLinks.Add(bestMatch._linkRight);
                            bestMatch._linkLeft._highlight = bestMatch._linkRight._highlight = true;
                            _modelPanel.Invalidate();

                            SelectionModified();
                        }

                        if (!add)
                            BeginHover(target);
                        //Single Platform Selected;
                        return;
                    }
                }

                //Nothing found :(

                //Trace ray to Z axis
                target = Vector3.IntersectZ(target, _modelPanel.UnProject(e.X, e.Y, 0.0f), 0.0f);
                point = (Vector2)target;

                if (create)
                {
                    if (_selectedLinks.Count == 0)
                    {
                        if (_selectedObject == null)
                            return;

                        _creating = true;

                        //Create two points and hover
                        CollisionLink point1 = new CollisionLink(_selectedObject, point).Branch(point);

                        _selectedLinks.Add(point1);
                        point1._highlight = true;

                        SelectionModified();
                        BeginHover(target);
                        _modelPanel.Invalidate();
                        return;
                    }
                    else if (_selectedLinks.Count == 1)
                    {
                        //Create new plane extending to point
                        CollisionLink link = _selectedLinks[0];
                        _selectedLinks[0] = link.Branch((Vector2)target);
                        _selectedLinks[0]._highlight = true;
                        link._highlight = false;
                        SelectionModified();
                        _modelPanel.Invalidate();

                        //Hover new point so it can be moved
                        BeginHover(target);
                        return;
                    }
                    else
                    {
                        //Find two closest points and insert between
                        CollisionPlane bestMatch = null;
                        if (_selectedPlanes.Count == 1)
                            bestMatch = _selectedPlanes[0];
                        else
                        {
                            float dist;
                            float bestDist = float.MaxValue;

                            foreach (CollisionPlane p in _selectedPlanes)
                            {
                                dist = point.TrueDistance(p.PointLeft) + point.TrueDistance(p.PointRight) - p.PointLeft.TrueDistance(p.PointRight);
                                if (dist < bestDist)
                                { bestDist = dist; bestMatch = p; }
                            }
                        }

                        ClearSelection();

                        _selectedLinks.Add(bestMatch.Split(point));
                        _selectedLinks[0]._highlight = true;
                        SelectionModified();
                        _modelPanel.Invalidate();

                        _creating = true;
                        BeginHover(target);

                        return;
                    }
                }

                if (move)
                {
                    if (_selectedLinks.Count > 0)
                        BeginHover(target);
                    return;
                }

                if (!add && !subtract)
                    ClearSelection();

                BeginSelection(target, subtract);
            }
        }