public static Vector2d Min(Vector2d v1, Vector2d v2)
 {
     return new Vector2d(
         (v1.x < v2.x) ? v1.x : v2.x,
         (v1.y < v2.y) ? v1.y : v2.y
         );
 }
 // using column vectors
 public Matrix2d(Vector2d v1, Vector2d v2)
 {
     a = v1.x;
     b = v2.x;
     c = v1.y;
     d = v2.y;
 }
 public static Vector2d Max(Vector2d v1, Vector2d v2)
 {
     return new Vector2d(
         (v1.x > v2.x) ? v1.x : v2.x,
         (v1.y > v2.y) ? v1.y : v2.y
         );
 }
        public void Drag(Vector2d pt)
        {
            edPt = pt;
            edVec = MapToSphere(pt);

            double epsilon = 1.0e-5;
            Vector3d prep = stVec.Cross(edVec);

            if (prep.Length() > epsilon)
                quat = new Vector4d(prep, stVec.Dot(edVec));
            else
                quat = new Vector4d();
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            this.currMousePosition = new Vector2d(e.X, this.Height - e.Y);
            this.isMouseDown = false;

            if (currMeshRecord == null) return;

            switch (Program.currentMode)
            {
                case Program.EnumOperationMode.Viewing:
                    if (currMousePosition.Equals(mouseDownPosition)) break;
                    Matrix4d m = ball.GetMatrix();
                    this.currTransformation = m * currTransformation;
            //					this.currInverseTransformation = this.currTransformation.Inverse();
                    this.ball.End();
                    this.Refresh();
                    break;

                case Program.EnumOperationMode.Selection:
                    switch (Program.toolsProperty.SelectionMethod)
                    {
                        case ToolsProperty.EnumSelectingMethod.Rectangle:
                            SelectVertexByRect();
                            break;
                        case ToolsProperty.EnumSelectingMethod.Point:
                            //SelectVertexByPoint();
                            break;
                    }
                    currMeshRecord.Mesh.GroupingFlags();
                    this.Refresh();
                    break;

                case Program.EnumOperationMode.Sketching:
                    if (e.Button == MouseButtons.Left  && currMeshRecord.CrossBoundaryBrushes != null)
                    {
                        this.Project2Mesh();

                        this.faces_on_strokes.Add(curr_f_stroke);
                        this.strokes.Add(curr_v_stroke);
                        this.strokes_on_Srceen.Add(strokeScreenPos);

                        if (currMeshRecord.CrossBoundaryBrushes != null && this.curr_v_stroke.Count >= 2)
                        {
                            if (!this.multi_stroke)
                            {
                                this.Cut();
                                this.Refresh();
                            }
                            else
                            {
                                currMeshRecord.CrossBoundaryBrushes.RemovePrevCut();
                                this.Cut();
                                this.Refresh();
                            }
                        }
                        this.Refresh();
                    }
                    break;

                case Program.EnumOperationMode.Moving:

                    this.Refresh();
                    break;
            }
        }
 public Vector4d(Vector2d v, double z, double w)
 {
     this.x = v.x;
     this.y = v.y;
     this.z = z;
     this.w = w;
 }
 public Vector4d(Vector2d v)
 {
     this.x = v.x;
     this.y = v.y;
     this.z = 0;
     this.w = 0;
 }
 public Vector3d(Vector2d v, double z)
 {
     this.x = v.x;
     this.y = v.y;
     this.z = z;
 }
 private bool PointInTriangle(Vector2d p, Vector2d a, Vector2d b, Vector2d c)
 {
     if (SameSide(p,a,b,c) && SameSide(p,b,a,c) && SameSide(p,c, a,b))
         return true;
     return false;
 }
 public void Click(Vector2d pt, MotionType type)
 {
     this.stPt = pt;
     this.stVec = MapToSphere(pt);
     this.type = type;
 }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            this.currMousePosition = new Vector2d(e.X, this.Height - e.Y);

            if (currMeshRecord == null) return;

            switch (Program.currentMode)
            {
                case Program.EnumOperationMode.Viewing:
                    switch (e.Button)
                    {
                        case MouseButtons.Left: ball.Drag(currMousePosition); break;
                        case MouseButtons.Middle: ball.Drag(currMousePosition / this.scaleRatio); break;
                        case MouseButtons.Right: ball.Drag(currMousePosition); break;
                    }
                    this.Refresh();
                    break;

                case Program.EnumOperationMode.Selection:
                    if (isMouseDown)
                        this.Refresh();
                    break;
                case Program.EnumOperationMode.Sketching:
                    if (e.Button == MouseButtons.Left  && currMeshRecord.CrossBoundaryBrushes != null)
                    {
                        if ((currMousePosition - prevMousePosition).Length() > 1)
                        {

                            this.strokeScreenPos.Add(currMousePosition);
                            prevMousePosition.x = currMousePosition.x;
                            prevMousePosition.y = currMousePosition.y;

                        }
                        this.Refresh();
                    }
                    break;

                case Program.EnumOperationMode.Moving:
                    if (isMouseDown)
                    {
                        Vector2d p = currMousePosition - new Vector2d(projectedCenter.x, projectedCenter.y);
                        int d = 0;
                        p.x += 100;
                        p.y += 100;
                        switch (e.Button)
                        {
                            case MouseButtons.Right: movingBall.Drag(p); break;
                            case MouseButtons.Left: movingBall.Drag(p / this.scaleRatio); d = 1; break;
                            case MouseButtons.Middle: movingBall.Drag(p); break;
                        }
                        Matrix4d currInverseTransformation = this.currTransformation.Inverse();
                        Matrix4d tran = currInverseTransformation * this.movingBall.GetMatrix() * currTransformation;
                        //Matrix4d tran = currTransformation * this.movingBall.GetMatrix() * currInverseTransformation;
                        double[] pos = this.currMeshRecord.Mesh.VertexPos;
                        for (int i = 0; i < handleIndex.Count; i++)
                        {
                            int j = handleIndex[i] * 3;
                            Vector4d q = new Vector4d((Vector3d)this.oldHandlePos[i], d);
                            q = tran * (q - this.handleCenter) + this.handleCenter;
                            pos[j] = q.x;
                            pos[j + 1] = q.y;
                            pos[j + 2] = q.z;
                        }

                        this.Refresh();
                    }
                    break;
            }
        }
 public double Dot(Vector2d v)
 {
     return x*v.x + y*v.y;
 }
        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;

            if (currMeshRecord == null) return;

            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.Sketching:
                    if (e.Button == MouseButtons.Left && currMeshRecord.CrossBoundaryBrushes != null)
                    {
                        if (!this.multi_stroke)
                        {
                            this.strokes.Clear();
                            this.faces_on_strokes.Clear();
                            this.strokes_on_Srceen.Clear();
                        }

                        this.curr_f_stroke = new List<int>();
                        this.curr_v_stroke = new List<int>();
                        this.strokeScreenPos = new List<Vector2d>();

                        this.strokeScreenPos.Add(currMousePosition);
                        prevMousePosition.x = currMousePosition.x;
                        prevMousePosition.y = currMousePosition.y;
                    }
                    break;

                case Program.EnumOperationMode.Moving:

                    break;
            }
        }
        public void Project2Mesh()
        {
            if (this.strokeScreenPos.Count < 1) return;

            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;

            foreach (Vector2d pos in this.strokeScreenPos)
            {
                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 (projector.GetDepthValue((int)v.x, (int)v.y) - v.z < eps) continue;

                    double dis = (u - pos).Length();
                    if (dis < minDis)
                    {
                        minIndex = i;
                        minDis = dis;
                    }
                }
                if (minIndex != -1)
                {
                    this.curr_v_stroke.Add(minIndex);
                }

                minIndex = -1;
                for (int i = 0, j = 0; i < m.FaceCount; i++, j += 3)
                {
                    int c0 = m.FaceIndex[j]*3;
                    int c1 = m.FaceIndex[j + 1]*3;
                    int c2 = m.FaceIndex[j + 2]*3;
                    Vector3d v0 = projector.Project(m.VertexPos, c0);
                    Vector3d v1 = projector.Project(m.VertexPos, c1);
                    Vector3d v2 = projector.Project(m.VertexPos, c2);
                    Vector2d u0 = new Vector2d(v0.x, v0.y);
                    Vector2d u1 = new Vector2d(v1.x, v1.y);
                    Vector2d u2 = new Vector2d(v2.x, v2.y);

                    if (!viewport.Contains((int)v0.x, (int)v0.y)) continue;
                    if (projector.GetDepthValue((int)v0.x, (int)v0.y) - v0.z < eps) continue;
                    if (PointInTriangle(pos, u0, u1, u2))
                    {
                        minIndex = i;
                        this.curr_f_stroke.Add(minIndex);
                        break;
                    }
                }
            }
        }
        private int SelectVertexByPoint(Vector2d currPos)
        {
            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 (projector.GetDepthValue((int)v.x, (int)v.y) - v.z < eps) continue;

                double dis = (u - currPos).Length();
                if (dis < minDis)
                {
                    minIndex = i;
                    minDis = dis;
                }
            }
            if (minIndex == -1) return -1;
            //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;
            }

            return minIndex;
        }
        private int SelectFaceByPoint(Vector2d screen_pos)
        {
            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;

            int minIndex = -1;
            for (int i = 0, j = 0; i < m.FaceCount; i++, j += 3)
            {
                int c0 = m.FaceIndex[j]*3;
                int c1 = m.FaceIndex[j + 1]*3;
                int c2 = m.FaceIndex[j + 2]*3;
                Vector3d v0 = projector.Project(m.VertexPos, c0);
                Vector3d v1 = projector.Project(m.VertexPos, c1);
                Vector3d v2 = projector.Project(m.VertexPos, c2);
                Vector2d u0 = new Vector2d(v0.x, v0.y);
                Vector2d u1 = new Vector2d(v1.x, v1.y);
                Vector2d u2 = new Vector2d(v2.x, v2.y);

                if (!viewport.Contains((int)v0.x, (int)v0.y)) continue;
                if (projector.GetDepthValue((int)v0.x, (int)v0.y) - v0.z < eps) continue;
                if (PointInTriangle(screen_pos, u0, u1, u2))
                {
                    minIndex = i;
                    break;
                }
            }
            return minIndex;
        }
 // -- whether two points p1 and p2 are on the same side of edge ab --
 private bool SameSide(Vector2d p1, Vector2d p2, Vector2d a, Vector2d b)
 {
     Vector3d A = new Vector3d(a);
     Vector3d B = new Vector3d(b);
     Vector3d P = new Vector3d(p1);
     Vector3d Q = new Vector3d(p2);
     Vector3d E = B-A;
     Vector3d cp1 = E.Cross(P-A);
     Vector3d cp2 = E.Cross(Q-A);
     if (cp1.Dot(cp2) >= 0)
         return true;
     return false;
 }
 public bool Equals(Vector2d v)
 {
     return (this.x == v.x) && (this.y == v.y) ? true : false;
 }
        private Vector3d MapToSphere(Vector2d pt)
        {
            Vector2d v = new Vector2d();
            v.x = (w - pt.x) * adjustWidth;
            v.y = (h - pt.y) * adjustHeight;

            double lenSq = v.Dot(v);
            if (lenSq > 1.0)
            {
                double norm = 1.0 / Math.Sqrt(lenSq);
                return new Vector3d(v.x * norm, v.y * norm, 0);
            }
            else
            {
                return new Vector3d(v.x, v.y, Math.Sqrt(1.0 - lenSq));
            }
        }