Пример #1
0
    private void inkoverlay_Stroke(object sender, InkCollectorStrokeEventArgs e)
    {
        dbg.WriteLine("----- inkoverlay_Stroke -----");

        // Ensure we're on the UI thread.
        dbg.Assert(!this.InvokeRequired);

        // Check to make sure we're not erasing.
        if (inkoverlay.EditingMode == InkOverlayEditingMode.Delete)
        {
            return;
        }

        try         // To prevent exceptions from propagating back to ink runtime.
        {
            // Hook for tap-to-select feature, in lasso-mode.
            if (inkoverlay.EditingMode == InkOverlayEditingMode.Select)
            {
                TryTapToSelect(e.Stroke);
                return;
            }

            // Analyze stroke geometry.
            bool    closed;
            Point[] vertices;
            double  tolerance = 500.0;            //Heuristic: 500 seems about right.
            StrokeAnalyzer.AnalyzeClosedness(e.Stroke, tolerance, out closed, out vertices);

            // Interpret stroke in document-context: first, consider closed strokes.
            if (closed)
            {
                // Check for a small elliptical-gesture over two or more bodies.
                // If so, it's a pin joint!
                Rectangle bbox = e.Stroke.GetBoundingBox();
                Point     midp = Geometry.Midpoint(bbox);

                RigidBodyBase[] hits = doc.HitTestBodies(midp);

                if (hits.Length >= 2 && bbox.Width < 1000 && bbox.Height < 1000)
                {
                    RigidBodyBase top    = hits[0];
                    RigidBodyBase bottom = hits[1];

                    // Snap to CG if close to either top's or bottom's.
                    if (Geometry.DistanceBetween(midp, top.CG) < 500.0)
                    {
                        midp = top.CG;
                    }
                    else if (Geometry.DistanceBetween(midp, bottom.CG) < 500.0)
                    {
                        midp = bottom.CG;
                    }

                    dbg.WriteLine("new JointMech");

                    JointMech newmech = new JointMech();
                    newmech.EndpointA = BodyRef.For(bottom, midp);
                    newmech.EndpointB = BodyRef.For(top, midp);

                    newmech.strokeid = e.Stroke.Id;
                    doc.Mechanisms.Add(newmech);

                    // Repaint area around the newmech (unions with stroke bbox, below).
                    Rectangle dirtybbox = newmech.BoundingBox;
                    InvalidateInkSpaceRectangle(dirtybbox);
                    return;
                }
                else
                {
                    // Larger stroke, and/or no centerpoint hits -- form a new solid body.
                    RigidBodyBase newbody = MakeBodyFromClosedStroke(e.Stroke, vertices);

                    // Repaint area around the newbody (unions with stroke bbox, below).
                    Rectangle dirtybbox = newbody.BoundingBox;
                    InvalidateInkSpaceRectangle(dirtybbox);

                    // Select it, to show the smart tag.
                    inkoverlay.Selection = this.MakeSingleStrokeCollection(e.Stroke);
                    return;
                }
            }

            // An unclosed stroke --
            // Check if head and/or tail is hit on existing bodies.
            int   np = e.Stroke.PacketCount;
            Point head = e.Stroke.GetPoint(0), tail = e.Stroke.GetPoint(np - 1);

            RigidBodyBase[] headhits = doc.HitTestBodies(head);
            RigidBodyBase[] tailhits = doc.HitTestBodies(tail);

            if (headhits.Length == 0 && tailhits.Length == 0)
            {
                // Neither head or tail hit, so let's try harder to make a body
                // out of this stroke.
                Point[] dummy;
                tolerance = 2000.0;                 //Heuristic: vastly relax closure tolerance.
                StrokeAnalyzer.AnalyzeClosedness(e.Stroke, tolerance, out closed, out dummy);

                if (closed)
                {
                    RigidBodyBase newbody = MakeBodyFromClosedStroke(e.Stroke, vertices);

                    // Repaint area around the newbody (unions with stroke bbox, below).
                    Rectangle dirtybbox = newbody.BoundingBox;
                    InvalidateInkSpaceRectangle(dirtybbox);

                    // Select it, to show the smart tag.
                    inkoverlay.Selection = this.MakeSingleStrokeCollection(e.Stroke);
                    return;
                }
                else if (Geometry.DistanceBetween(head, tail) > 500.0)
                {
                    // Interpret this stroke as a gravity-vector.
                    GravitationalForceMech newgrav = new GravitationalForceMech();
                    newgrav.Body   = null;                   // Applies to all bodies!
                    newgrav.origin = head;
                    newgrav.vector = Vector.FromPoints(head, tail);

                    // Repaint area around the gravity vector (unions with stroke bbox, below).
                    Rectangle dirtybbox = newgrav.BoundingBox;
                    InvalidateInkSpaceRectangle(dirtybbox);

                    // Throw out the current gravity-vector stroke, if it exists.
                    if (doc.Gravity != null)
                    {
                        dirtybbox = doc.Gravity.BoundingBox;
                        InvalidateInkSpaceRectangle(dirtybbox);

                        Stroke old = GetStrokeById(doc.Gravity.strokeid);
                        doc.Ink.DeleteStroke(old);
                    }

                    newgrav.strokeid = e.Stroke.Id;
                    doc.Gravity      = newgrav;
                    return;
                }
                else
                {
                    // This stroke is probably an accidental tap -- discard it.
                    e.Cancel = true;
                    return;
                }
            }

            if (headhits.Length > 0 && tailhits.Length == 0)
            {
                // If only the head is hit, it must be an 'attractive force'.
                RigidBodyBase body = headhits[0];

                dbg.WriteLine("new ExternalForceMech");

                ExternalForceMech newmech = new ExternalForceMech();
                newmech.Body   = BodyRef.For(body, head);
                newmech.vector = Vector.FromPoints(head, tail);

                newmech.strokeid = e.Stroke.Id;
                doc.Mechanisms.Add(newmech);

                // Repaint area around the newmech (unions with stroke bbox, below).
                Rectangle dirtybbox = newmech.BoundingBox;
                InvalidateInkSpaceRectangle(dirtybbox);
                return;
            }

            if (headhits.Length == 0 && tailhits.Length > 0)
            {
                // If only the tail is hit, it must be a 'propulsive force'.
                RigidBodyBase body = tailhits[0];

                dbg.WriteLine("new PropulsiveForceMech");

                PropulsiveForceMech newmech = new PropulsiveForceMech();
                newmech.Body   = BodyRef.For(body, tail);
                newmech.vector = Vector.FromPoints(head, tail);

                newmech.strokeid = e.Stroke.Id;
                doc.Mechanisms.Add(newmech);

                // Repaint area around the newmech (unions with stroke bbox, below).
                Rectangle dirtybbox = newmech.BoundingBox;
                InvalidateInkSpaceRectangle(dirtybbox);
                return;
            }

            if (true)             // scope
            {
                // Create a binding mechanism between two bodies.
                RigidBodyBase headbody = headhits[0], tailbody = tailhits[0];

                // If both the head and the tail hit same object,
                // attach the head to the one behind.
                if (Object.ReferenceEquals(headbody, tailbody))
                {
                    if (headhits.Length > 1)
                    {
                        headbody = headhits[1];
                    }
                    else if (tailhits.Length > 1)
                    {
                        tailbody = tailhits[1];
                    }
                    else
                    {
                        // Don't self-connect. We will perhaps interpret the stroke as an
                        // anchor-gesture or a selection-gesture,
                        // but if we cannot, we will cancel.
                        int nc = e.Stroke.PolylineCusps.Length;
                        if (np <= 25)
                        {
                            inkoverlay.Selection = MakeSingleStrokeCollection(headbody.strokeid);
                            SetEditingMode(InkOverlayEditingMode.Select, false);
                        }
                        else if (np <= 150 && (nc >= 3 && nc <= 5))
                        {
                            headbody.anchored = !headbody.anchored;                             //toggle
                        }

                        e.Cancel = true;

                        // Repaint area around the headbody (unions with stroke bbox, below).
                        Rectangle dirtybbox = headbody.BoundingBox;
                        InvalidateInkSpaceRectangle(dirtybbox);
                        return;
                    }
                }

                // Create a rope, rod, or spring out of the stroke.
                MechanismBase newmech = MakeRodRopeOrSpring(e.Stroke, headbody, tailbody);

                if (newmech != null)
                {
                    // Repaint area around the newmech (unions with stroke bbox, below).
                    Rectangle dirtybbox = newmech.BoundingBox;
                    InvalidateInkSpaceRectangle(dirtybbox);
                    return;
                }
                else
                {
                    // Throw out the stroke, and return.
                    e.Cancel = true;
                    return;
                }
            }
        }
        catch (Exception ex)
        {
            // Cancel the stroke, and log the error.
            e.Cancel = true;
            Global.HandleThreadException(this, new System.Threading.ThreadExceptionEventArgs(ex));
        }
        finally
        {
            // Repaint the area around the stroke (unions with newbody/mech region, above).
            Rectangle dirtybbox = e.Stroke.GetBoundingBox();
            InvalidateInkSpaceRectangle(dirtybbox);
        }
    }
Пример #2
0
    public void inkoverlay_StrokeImpl(InkCollectorStrokeEventArgs e)
    {
        dbg.WriteLine("----- inkoverlay_StrokeImpl -----");

        // Previso verificar o modo. Se estiver em um modo que não seja a edição, salva
        // o modo atual e coloca na edição. No final volto ao modo que estava

        // Primeiro passo é salvar o modo de edição autal e colocar no modo de deleção
        InkOverlayEditingMode em =  inkoverlay.EditingMode;
        SetEditingMode(InkOverlayEditingMode.Ink,true);

        try // To prevent exceptions from propagating back to ink runtime.
        {
            /*
            // Hook for tap-to-select feature, in lasso-mode.
            if (inkoverlay.EditingMode == InkOverlayEditingMode.Select)
            {
                //////////////// USO DO STROKE //////////////////////
                TryTapToSelect(e.Stroke);
                return;
            } */

            // Analyze stroke geometry.
            bool closed;
            Point[] vertices;
            double tolerance = 500.0; //Heuristic: 500 seems about right.
            //////////////// USO DO STROKE //////////////////////
            StrokeAnalyzer.AnalyzeClosedness(e.Stroke, tolerance, out closed, out vertices);

            // Se for um desenho fechado...
            // Interpret stroke in document-context: first, consider closed strokes.
            if (closed)
            {
                // Check for a small elliptical-gesture over two or more bodies.
                // If so, it's a pin joint!
                //////////////// USO DO STROKE //////////////////////
                Rectangle bbox = e.Stroke.GetBoundingBox();
                Point midp = Geometry.Midpoint(bbox);

                RigidBodyBase[] hits = doc.HitTestBodies(midp);

                if (hits.Length >= 2 && bbox.Width < 1000 && bbox.Height < 1000)
                {
                    RigidBodyBase top = hits[0];
                    RigidBodyBase bottom = hits[1];

                    // Snap to CG if close to either top's or bottom's.
                    if (Geometry.DistanceBetween(midp,top.CG) < 500.0)
                        midp = top.CG;
                    else if (Geometry.DistanceBetween(midp,bottom.CG) < 500.0)
                        midp = bottom.CG;

                    dbg.WriteLine("new JointMech");

                    JointMech newmech = new JointMech();
                    newmech.EndpointA = BodyRef.For(bottom,midp);
                    newmech.EndpointB = BodyRef.For(top,midp);

                    //////////////// USO DO STROKE //////////////////////
                    newmech.strokeid = e.Stroke.Id;
                    doc.Mechanisms.Add(newmech);

                    // Repaint area around the newmech (unions with stroke bbox, below).
                    Rectangle dirtybbox = newmech.BoundingBox;
                    InvalidateInkSpaceRectangle(dirtybbox);
                    return;
                }
                else
                {
                    // Larger stroke, and/or no centerpoint hits -- form a new solid body.
                    //////////////// USO DO STROKE //////////////////////
                    RigidBodyBase newbody = MakeBodyFromClosedStroke(e.Stroke,vertices);

                    // Repaint area around the newbody (unions with stroke bbox, below).
                    Rectangle dirtybbox = newbody.BoundingBox;
                    InvalidateInkSpaceRectangle(dirtybbox);

                    // Select it, to show the smart tag.
                    //////////////// USO DO STROKE //////////////////////

                    // TESTE: Retirada da selecion
                    // TESTE: inkoverlay.Selection = this.MakeSingleStrokeCollection(e.Stroke);
                    // inkoverlay.Selection = this.MakeSingleStrokeCollectionImpl();
                    return;
                }
            }

            // Caso senha um desenho aberto...
            // An unclosed stroke --
            // Check if head and/or tail is hit on existing bodies.
            //////////////// USO DO STROKE //////////////////////
            int np = e.Stroke.PacketCount;
            Point head = e.Stroke.GetPoint(0), tail = e.Stroke.GetPoint(np-1);

            RigidBodyBase[] headhits = doc.HitTestBodies(head);
            RigidBodyBase[] tailhits = doc.HitTestBodies(tail);

            if (headhits.Length == 0 && tailhits.Length == 0)
            {
                // Neither head or tail hit, so let's try harder to make a body
                // out of this stroke.
                Point[] dummy;
                tolerance = 2000.0; //Heuristic: vastly relax closure tolerance.
                //////////////// USO DO STROKE //////////////////////
                StrokeAnalyzer.AnalyzeClosedness(e.Stroke, tolerance, out closed, out dummy);

                if (closed)
                {
                    //////////////// USO DO STROKE //////////////////////
                    RigidBodyBase newbody = MakeBodyFromClosedStroke(e.Stroke,vertices);

                    // Repaint area around the newbody (unions with stroke bbox, below).
                    Rectangle dirtybbox = newbody.BoundingBox;
                    InvalidateInkSpaceRectangle(dirtybbox);

                    // Select it, to show the smart tag.
                    //////////////// USO DO STROKE //////////////////////
                    // TESTE: Retirada da selecion
                    // inkoverlay.Selection = this.MakeSingleStrokeCollection(e.Stroke);
                    return;
                }
                else if (Geometry.DistanceBetween(head,tail) > 500.0)
                {
                    // Interpret this stroke as a gravity-vector.
                    GravitationalForceMech newgrav = new GravitationalForceMech();
                    newgrav.Body = null; // Applies to all bodies!
                    newgrav.origin = head;
                    newgrav.vector = Vector.FromPoints(head,tail);

                    // Repaint area around the gravity vector (unions with stroke bbox, below).
                    Rectangle dirtybbox = newgrav.BoundingBox;
                    InvalidateInkSpaceRectangle(dirtybbox);

                    // Throw out the current gravity-vector stroke, if it exists.
                    if (doc.Gravity != null)
                    {
                        dirtybbox = doc.Gravity.BoundingBox;
                        InvalidateInkSpaceRectangle(dirtybbox);

                        // Testes de remoçao do Gravity Strike

                        if(doc.Ink.Strokes.Count > 0)
                        {
                            foreach (Stroke S in doc.Ink.Strokes)
                            {
                                if (S.Id == doc.Gravity.strokeid)
                                {
                                    doc.Ink.DeleteStroke(S);
                                }
                            }
                        }
                    }

                    //////////////// USO DO STROKE //////////////////////
                    newgrav.strokeid = e.Stroke.Id;
                    doc.Gravity = newgrav;
                    return;
                }
                else
                {
                    // This stroke is probably an accidental tap -- discard it.
                    e.Cancel = true;
                    return;
                }
            }

            if (headhits.Length > 0 && tailhits.Length == 0)
            {
                // If only the head is hit, it must be an 'attractive force'.
                RigidBodyBase body = headhits[0];

                dbg.WriteLine("new ExternalForceMech");

                ExternalForceMech newmech = new ExternalForceMech();
                newmech.Body = BodyRef.For(body,head);
                newmech.vector = Vector.FromPoints(head,tail);

                //////////////// USO DO STROKE //////////////////////
                newmech.strokeid = e.Stroke.Id;
                doc.Mechanisms.Add(newmech);

                // Repaint area around the newmech (unions with stroke bbox, below).
                Rectangle dirtybbox = newmech.BoundingBox;
                InvalidateInkSpaceRectangle(dirtybbox);
                return;
            }

            if (headhits.Length == 0 && tailhits.Length > 0)
            {
                // If only the tail is hit, it must be a 'propulsive force'.
                RigidBodyBase body = tailhits[0];

                dbg.WriteLine("new PropulsiveForceMech");

                PropulsiveForceMech newmech = new PropulsiveForceMech();
                newmech.Body = BodyRef.For(body,tail);
                newmech.vector = Vector.FromPoints(head,tail);

                //////////////// USO DO STROKE //////////////////////
                newmech.strokeid = e.Stroke.Id;
                doc.Mechanisms.Add(newmech);

                // Repaint area around the newmech (unions with stroke bbox, below).
                Rectangle dirtybbox = newmech.BoundingBox;
                InvalidateInkSpaceRectangle(dirtybbox);
                return;
            }

            if (true) // scope
            {
                // Create a binding mechanism between two bodies.
                RigidBodyBase headbody = headhits[0], tailbody = tailhits[0];

                // If both the head and the tail hit same object,
                // attach the head to the one behind.
                if (Object.ReferenceEquals(headbody,tailbody))
                {
                    if (headhits.Length > 1)
                        headbody = headhits[1];
                    else if (tailhits.Length > 1)
                        tailbody = tailhits[1];
                    else
                    {
                        // Aqui é feita a seleção. Remotamente não faço nada

                        // Don't self-connect. We will perhaps interpret the stroke as an
                        // anchor-gesture or a selection-gesture,
                        // but if we cannot, we will cancel.
                        //////////////// USO DO STROKE //////////////////////
                        int nc = e.Stroke.PolylineCusps.Length;
                        if (np <= 25)
                        {
                            // TESTE: Retirada da selecion
                            // inkoverlay.Selection = MakeSingleStrokeCollection(headbody.strokeid);
                            SetEditingMode(InkOverlayEditingMode.Select,false);
                        }
                        else if (np <= 150 && (nc >= 3 && nc <= 5))
                        {
                            headbody.anchored = !headbody.anchored; //toggle
                        }

                        e.Cancel = true;

                        // Repaint area around the headbody (unions with stroke bbox, below).
                        Rectangle dirtybbox = headbody.BoundingBox;
                        InvalidateInkSpaceRectangle(dirtybbox);
                        return;
                    }
                }

                // Create a rope, rod, or spring out of the stroke.
                //////////////// USO DO STROKE //////////////////////
                MechanismBase newmech = MakeRodRopeOrSpring(e.Stroke,headbody,tailbody);

                if (newmech != null)
                {
                    // Repaint area around the newmech (unions with stroke bbox, below).
                    Rectangle dirtybbox = newmech.BoundingBox;
                    InvalidateInkSpaceRectangle(dirtybbox);
                    return;
                }
                else
                {
                    // Throw out the stroke, and return.
                    e.Cancel = true;
                    return;
                }
            }
        }
        catch (Exception ex)
        {
            // Cancel the stroke, and log the error.
            e.Cancel = true;
            Global.HandleThreadException(this, new System.Threading.ThreadExceptionEventArgs(ex));
        }
        finally
        {
            // Repaint the area around the stroke (unions with newbody/mech region, above).
            //////////////// USO DO STROKE //////////////////////
            Rectangle dirtybbox = e.Stroke.GetBoundingBox();
            InvalidateInkSpaceRectangle(dirtybbox);

            SetEditingMode(em,true);
        }
    }