private void SelectVertexByRect()
        {
            Vector2d        minV      = Vector2d.Min(mouseDownPosition, currMousePosition);
            Vector2d        size      = Vector2d.Max(mouseDownPosition, currMousePosition) - minV;
            Rectangle       rect      = new Rectangle((int)minV.x, (int)minV.y, (int)size.x, (int)size.y);
            Rectangle       viewport  = new Rectangle(0, 0, this.Width, this.Height);
            OpenGLProjector projector = new OpenGLProjector();
            Mesh            m         = currMeshRecord.Mesh;
            bool            laser     = Program.toolsProperty.Laser;
            double          eps       = Program.toolsProperty.DepthTolerance;

            if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
            {
                for (int i = 0, j = 0; i < m.VertexCount; i++, j += 3)
                {
                    Vector3d v = projector.Project(m.VertexPos, j);
                    if (viewport.Contains((int)v.x, (int)v.y))
                    {
                        bool flag = rect.Contains((int)v.x, (int)v.y);
                        flag &= (laser || projector.GetDepthValue((int)v.x, (int)v.y) - v.z >= eps);
                        if (flag)
                        {
                            m.Flag[i] = (byte)1;
                        }
                    }
                }
            }

            else if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
            {
                for (int i = 0, j = 0; i < m.VertexCount; i++, j += 3)
                {
                    Vector3d v = projector.Project(m.VertexPos, j);
                    if (viewport.Contains((int)v.x, (int)v.y))
                    {
                        bool flag = rect.Contains((int)v.x, (int)v.y);
                        flag &= (laser || projector.GetDepthValue((int)v.x, (int)v.y) - v.z >= eps);
                        if (flag)
                        {
                            m.Flag[i] = (byte)0;
                        }
                    }
                }
            }

            else
            {
                for (int i = 0, j = 0; i < m.VertexCount; i++, j += 3)
                {
                    Vector3d v = projector.Project(m.VertexPos, j);
                    if (viewport.Contains((int)v.x, (int)v.y))
                    {
                        bool flag = rect.Contains((int)v.x, (int)v.y);
                        flag     &= (laser || projector.GetDepthValue((int)v.x, (int)v.y) - v.z >= eps);
                        m.Flag[i] = (byte)((flag) ? 1 : 0);
                    }
                }
            }
        }
        private void SelectVertexByPoint()
        {
            Rectangle       viewport  = new Rectangle(0, 0, this.Width, this.Height);
            OpenGLProjector projector = new OpenGLProjector();
            Mesh            m         = currMeshRecord.Mesh;
            bool            laser     = Program.toolsProperty.Laser;
            double          eps       = Program.toolsProperty.DepthTolerance;

            double minDis   = double.MaxValue;
            int    minIndex = -1;

            for (int i = 0, j = 0; i < m.VertexCount; i++, j += 3)
            {
                Vector3d v = projector.Project(m.VertexPos, j);
                Vector2d u = new Vector2d(v.x, v.y);
                if (!viewport.Contains((int)v.x, (int)v.y))
                {
                    continue;
                }
                if (!laser && projector.GetDepthValue((int)v.x, (int)v.y) - v.z < eps)
                {
                    continue;
                }

                double dis = (u - currMousePosition).Length();
                if (dis < minDis)
                {
                    minIndex = i;
                    minDis   = dis;
                }
            }
            if (minIndex == -1)
            {
                return;
            }
            //FormMain.CurrForm.OutputText("selected vertex: " + minIndex.ToString());

            if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
            {
                m.Flag[minIndex] = (byte)1;
            }
            else if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
            {
                m.Flag[minIndex] = (byte)0;
            }
            else
            {
                for (int i = 0; i < m.VertexCount; i++)
                {
                    m.Flag[i] = (byte)0;
                }
                m.Flag[minIndex] = (byte)1;
            }
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            this.currMousePosition = new Vector2d(e.X, this.Height - e.Y);
            this.mouseDownPosition = currMousePosition;
            this.isMouseDown       = true;

            switch (Program.currentMode)
            {
            case Program.EnumOperationMode.Viewing:
                switch (e.Button)
                {
                case MouseButtons.Left: ball.Click(currMousePosition, Trackball.MotionType.Rotation); break;

                case MouseButtons.Middle: ball.Click(currMousePosition / this.scaleRatio, Trackball.MotionType.Pan); break;

                case MouseButtons.Right: ball.Click(currMousePosition, Trackball.MotionType.Scale); break;
                }
                break;

            case Program.EnumOperationMode.Selection:
                break;

            case Program.EnumOperationMode.Moving:
                if (this.StartMoving() == true)
                {
                    Vector2d p = mouseDownPosition - new Vector2d(projectedCenter.x, projectedCenter.y);
                    p.x += 100;
                    p.y += 100;
                    switch (e.Button)
                    {
                    case MouseButtons.Right: movingBall.Click(p, Trackball.MotionType.Rotation); break;

                    case MouseButtons.Left: movingBall.Click(p / this.scaleRatio, Trackball.MotionType.Pan); break;

                    case MouseButtons.Middle: movingBall.Click(p, Trackball.MotionType.Scale); break;
                    }
                    if (currMeshRecord.Deformer != null)
                    {
                        currMeshRecord.Deformer.MouseDown();
                    }
                    this.Refresh();
                }
                break;

            case Program.EnumOperationMode.PickSkeNode:
                if (skeHandleIndex != -1)
                {
                    this.GrabContext();
                    OpenGLProjector projector = new OpenGLProjector();
                    Deformer        deformer  = currMeshRecord.Deformer;
                    this.skeHandleCenter = new Vector4d(skeHandlepos, 0);
                    this.projectedCenter = projector.Project(skeHandlepos);

                    Vector2d p = mouseDownPosition - new Vector2d(projectedCenter.x, projectedCenter.y);
                    p.x += 100;
                    p.y += 100;
                    switch (e.Button)
                    {
                    case MouseButtons.Left: movingBall.Click(p / this.scaleRatio, Trackball.MotionType.Pan); break;
                    }
                    if (currMeshRecord.Deformer != null)
                    {
                        currMeshRecord.Deformer.MouseDown();
                    }
                    this.Refresh();
                }
                break;
            }
        }
        private bool StartMoving()
        {
            // find closest selected vertex
            this.GrabContext();
            OpenGLProjector projector = new OpenGLProjector();
            Mesh            m         = currMeshRecord.Mesh;
            Deformer        deformer  = currMeshRecord.Deformer;
            Rectangle       viewport  = new Rectangle(0, 0, this.Width, this.Height);
            double          eps       = Program.toolsProperty.DepthTolerance;
            double          minDis    = double.MaxValue;
            int             minIndex  = -1;

            for (int i = 0, j = 0; i < m.VertexCount; i++, j += 3)
            {
                if (m.Flag[i] == 0)
                {
                    continue;
                }
                Vector3d v3d = projector.Project(m.VertexPos, j);
                Vector2d v   = new Vector2d(v3d.x, v3d.y);
                if (viewport.Contains((int)v.x, (int)v.y) == false)
                {
                    continue;
                }
                if (projector.GetDepthValue((int)v.x, (int)v.y) - v3d.z < eps)
                {
                    continue;
                }

                double dis = (v - mouseDownPosition).Length();
                if (dis < minDis)
                {
                    minDis   = dis;
                    minIndex = i;
                }
            }
            if (minIndex == -1)
            {
                this.handleFlag = -1;
                this.handleIndex.Clear();
                this.oldHandlePos.Clear();
                return(false);
            }

            // find boundary box
            int flag = m.Flag[minIndex];

            this.handleFlag = flag;
            this.handleIndex.Clear();
            this.oldHandlePos.Clear();

            Vector3d c     = new Vector3d(0, 0, 0);
            int      count = 0;

            {
                for (int i = 0; i < m.VertexCount; i++)
                {
                    if (m.Flag[i] == flag)
                    {
                        Vector3d p = new Vector3d(m.VertexPos, i * 3);
                        c += p;
                        this.handleIndex.Add(i);
                        this.oldHandlePos.Add(p);
                        count++;
                    }
                }
            }
            c /= (double)count;

            this.handleCenter    = new Vector4d(c, 0);
            this.projectedCenter = projector.Project(handleCenter.x, handleCenter.y, handleCenter.z);
            return(true);
        }