示例#1
0
        /* Determines whether the stroke coule be interpreted as a
         * scratchout by checking that the length is greater than
         * three times the width of its bounding box, that it has
         * at least three self intersections, and its height is at
         * most three quarters of its width.
         */
        public static bool isScratchOut(Stroke s)
        {
            Rectangle rect   = s.GetBoundingBox();
            double    length = StrokeManager.StrokeLength(s);

            return(length > 3 * rect.Width && rect.Height <= rect.Width * 3 / 4 && s.SelfIntersections.Length > 2);
        }
示例#2
0
 /* Returns true if the stroke is somewhat closed in the
  * sense that it comes back to itself.  Accomplishes
  * this by checking the distance between the first point
  * in the stroke and the last point in the stroke.
  */
 public static bool isClosed(Stroke s, double tolerance)
 {
     if (s == null)
     {
         return(false);
     }
     Point[] pts = { s.GetPoint(0), s.GetPoint(s.PacketCount - 1) };
     return(StrokeManager.Distance(pts[0], pts[1]) <= tolerance);
 }
示例#3
0
        //Gets the length of a stroke
        public static double StrokeLength(Stroke e)
        {
            double dist = 0;

            Point[] points = e.GetPoints();
            for (int i = 0; i < points.Length - 1; i++)
            {
                dist += StrokeManager.Distance(points[i], points[i + 1]);
            }
            return(dist);
        }
示例#4
0
        public void Render(InkOverlay i, Graphics g)
        {
            int width  = weight.ToString().Length *15;
            int height = 18;

            stroke.DrawingAttributes       = i.DefaultDrawingAttributes.Clone();
            stroke.DrawingAttributes.Color = color;
            i.Renderer.Draw(g, stroke);

            Rectangle rect   = StrokeManager.InkSpaceToPixelRect(i, g, stroke.GetBoundingBox());
            Point     center = new Point(rect.X + rect.Width / 2 - width / 2, rect.Y + rect.Height / 2 - height / 2);

            g.FillRectangle(new SolidBrush(Color.White), center.X, center.Y, width, height);
            g.DrawString(weight.ToString(), new Font("Courier New", 14, FontStyle.Bold), new SolidBrush(Color.Black), center);
        }
示例#5
0
        public Node(Stroke stroke)
        {
            this.stroke = stroke;
            this.id     = stroke.Id;
            Rectangle r = stroke.GetBoundingBox();

            //Determine whether this node is a rectangle or not
            isRect      = r.Width * Math.PI < StrokeManager.StrokeLength(stroke);
            centerPoint = new Point(r.X + r.Width / 2, r.Y + r.Height / 2);
            fillColor   = DEFAULT;
            edges       = new Edges();
            textColor   = TEXT_DEFAULT;
            text        = "";
            //Set initial distance to infinity (max int)
            distance = Int32.MaxValue;
        }
示例#6
0
        /* Returns true if the stroke resembles a rectangle given a tolerance.
         * Accomplishes this by taking the perimeter of a rectangle that
         * would be bounded in the area the stroke is bounded and
         * comparing it to the length of the stroke.
         */
        public static bool FitsRectProperties(Stroke e, double tolerance)
        {
            if (e == null || FitsCircleProperties(e, CIRCLE_TOLERANCE))
            {
                return(false);
            }
            Rectangle r = e.GetBoundingBox();

            if (r.Height < MIN_WIDTH || r.Width < MIN_WIDTH)
            {
                return(false);
            }
            double perimeter    = r.Height * 2 + r.Width * 2;
            double strokeLength = StrokeManager.StrokeLength(e);

            return(Math.Abs(perimeter - strokeLength) <= tolerance);
        }
示例#7
0
        /* Returns true if the stroke resembles a circle given a tolerance.
         * Accomplishes this by taking the perimeter of a circle that
         * would be bounded in the area the stroke is bounded and
         * comparing it to the length of the stroke.
         */
        public static bool FitsCircleProperties(Stroke e, double tolerance)
        {
            if (e == null)
            {
                return(false);
            }
            Rectangle r      = e.GetBoundingBox();
            double    radius = StrokeManager.Avg(r.Height, r.Width) / 2.0;

            if (radius < MIN_WIDTH / 2)
            {
                return(false);
            }
            double perimeter = 2.0 * radius * Math.PI;

            Point[] points       = e.GetPoints();
            double  strokeLength = StrokeManager.StrokeLength(e);

            return(Math.Abs(perimeter - strokeLength) <= tolerance);
        }
示例#8
0
        private void inkOverlay_StrokesDeleting(object sender, InkOverlayStrokesDeletingEventArgs e)
        {
            if (this.InvokeRequired)
            {
                return;
            }
            Strokes strokes = e.StrokesToDelete;

            //Remove the corresponding nodes and edges for each stroke
            for (int i = 0; i < strokes.Count; i++)
            {
                if (StrokeManager.isClosed(strokes[i], 0))
                {
                    graph.Remove(graph.Nodes.getNode(strokes[i]));
                }
                else
                {
                    graph.Remove(graph.Edges.getEdge(strokes[i]));
                }
            }
            Invalidate();
        }
示例#9
0
        /* Checks if the stroke drawn is within the range of a
         * edge from Graph g.  The range of an edge is roughly
         * around its center.
         */
        public static Edge HitEdgeTest(Stroke s, Graph g)
        {
            if (StrokeManager.StrokeLength(s) > HIT_TEST_THRESHOLD)
            {
                return(null);
            }
            float distance = 1300;
            Edge  hitedge  = null;

            for (int i = 0; i < g.Edges.Length(); i++)
            {
                float     tmp;
                Edge      e    = g.Edges[i];
                Rectangle rect = e.Stroke.GetBoundingBox();
                Point     p    = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
                s.NearestPoint(p, out tmp);
                if (tmp < distance)
                {
                    distance = tmp;
                    hitedge  = e;
                }
            }
            return(hitedge);
        }
示例#10
0
        public void Render(InkOverlay i, Graphics g)
        {
            if (stroke.Deleted == true)
            {
                return;
            }
            Rectangle rect = StrokeManager.InkSpaceToPixelRect(i, g, stroke.GetBoundingBox());

            if (isRect)
            {
                g.FillRectangle(new SolidBrush(fillColor), rect);
            }
            else
            {
                g.FillEllipse(new SolidBrush(fillColor), rect);
            }

            i.Renderer.Draw(g, stroke);
            Point[] p = { new Point(centerPoint.X, centerPoint.Y) };
            i.Renderer.InkSpaceToPixel(g, ref p);
            p[0].X -= 15;
            p[0].Y -= 10;
            g.DrawString(text, new Font("Arial", 10), new SolidBrush(textColor), p[0]);
        }
示例#11
0
 //Renders each edge and node and also marks the home and destination nodes
 public void Render(InkOverlay i, Graphics g)
 {
     for (int j = 0; j < edges.Length(); j++)
     {
         edges[j].Render(i, g);
     }
     for (int j = 0; j < nodes.Length(); j++)
     {
         nodes[j].Render(i, g);
         if (nodes[j].Equals(home))
         {
             g.DrawString("*", new Font("Arial", 30), new SolidBrush(Color.Green), StrokeManager.InkSpaceToPixelRect(i, g, nodes[j].Stroke.GetBoundingBox()));
         }
         else if (nodes[j].Equals(destination))
         {
             g.DrawString("X", new Font("Arial", 14, FontStyle.Bold), new SolidBrush(Color.Red), StrokeManager.InkSpaceToPixelRect(i, g, nodes[j].Stroke.GetBoundingBox()));
         }
     }
 }
示例#12
0
        private void inkOverlay_Stroke(object sender, InkCollectorStrokeEventArgs e)
        {
            if (this.InvokeRequired)
            {
                return;
            }

            //in effect, this is reseting the timer to start from the beginning.
            edgeTimer.Stop();
            edgeTimer.Start();

            //Check if the stroke was a tap, and if it was, get the node it tapped.
            Node n = StrokeManager.TappedNode(e.Stroke, graph);

            if (n != null)
            {
                //If its eraser mode, delete it.
                if (inkOverlay.EditingMode == InkOverlayEditingMode.Delete)
                {
                    graph.Remove(n);
                }
                else
                {
                    //Any other mode, select it and change to selection mode
                    int[] ids = { n.Stroke.Id };
                    selectionButton(sender, e);
                    inkOverlay.Selection = e.Stroke.Ink.CreateStrokes(ids);
                }
                e.Stroke.Ink.DeleteStroke(e.Stroke);
                Invalidate();
                return;
            }

            //The following code is for pen mode only strokes
            if (inkOverlay.EditingMode != InkOverlayEditingMode.Ink)
            {
                return;
            }

            //If a stroke is inside a node, store it in n
            n = StrokeManager.HitNodeTest(e.Stroke, graph);

            //If the stroke is closed and it's a start, assign a home or destination
            if (StrokeManager.isClosed(e.Stroke) && n != null && StrokeManager.isStar(e.Stroke))
            {
                graph.AssignNode(n);
                RecognizeWeight();                  //Attempt at recognizing weight is made after every stroke.
            }
            //If the stroke is closed and it is not enclosed in a node and is a circle, make a circular node
            else if (StrokeManager.isClosed(e.Stroke) && n == null && e.Stroke.PacketCount > StrokeManager.SMALLEST_N_SIZE && StrokeManager.FitsCircleProperties(e.Stroke))
            {
                Stroke circle     = StrokeManager.makeCircle(inkOverlay, e.Stroke);
                Node   circleNode = new Node(circle);
                graph.Add(circleNode);
                RecognizeWeight();
            }
            //If the stroke is close and it is not enclosed in a node and is a rectangle, make a rectangular node
            else if (StrokeManager.isClosed(e.Stroke) && n == null && e.Stroke.PacketCount > StrokeManager.SMALLEST_N_SIZE && StrokeManager.FitsRectProperties(e.Stroke))
            {
                Stroke rect     = StrokeManager.makeRect(inkOverlay, e.Stroke);
                Node   rectNode = new Node(rect);
                graph.Add(rectNode);
                RecognizeWeight();
            }
            //if the stroke isn't closed, then it is an edge.
            else if (!StrokeManager.isClosed(e.Stroke))
            {
                //Get all the nodes hit by this stroke and create edges for them
                Nodes edgeNodes = StrokeManager.ifEdgeGetNodes(e.Stroke, graph);
                if (edgeNodes != null && !StrokeManager.isScratchOut(e.Stroke))
                {
                    for (int i = 0; i < edgeNodes.Length() - 1; i++)
                    {
                        if (!Edge.hasEdge(edgeNodes[i], edgeNodes[i + 1]))
                        {
                            Edge edge = new Edge(edgeNodes[i], edgeNodes[i + 1], inkOverlay);
                            graph.Add(edge);
                        }
                    }
                }
                else if (StrokeManager.isScratchOut(e.Stroke))
                {
                    ArrayList objs = StrokeManager.HitObjects(e.Stroke, graph);
                    for (int i = 0; i < objs.Count; i++)
                    {
                        graph.Remove(objs[i]);
                    }
                }

                RecognizeWeight();
            }
            else
            {
                //if all of the above fails, then the stroke is considered for edge weights
                Edge hitEdge = StrokeManager.HitEdgeTest(e.Stroke, graph);
                if (hitEdge != null)
                {
                    /* if the edge hit is the same as the previous one,
                     * accumulate strokes for it before recognizing,
                     * if it's a different edge, then recognize and add this
                     * stroke to the new edge.
                     */
                    if (prevEdgeHit == null)
                    {
                        prevEdgeHit = hitEdge;
                    }
                    if (hitEdge.Equals(prevEdgeHit))
                    {
                        myRecognizer.Strokes.Add(StrokeManager.CopyStroke(e.Stroke));
                    }
                    else
                    {
                        RecognizeWeight();
                        prevEdgeHit = hitEdge;
                        myRecognizer.Strokes.Add(StrokeManager.CopyStroke(e.Stroke));
                    }
                }
            }
            e.Stroke.Ink.DeleteStroke(e.Stroke);
            Invalidate();
        }