예제 #1
0
        /// <summary>Adds a point to DragState with a filtering algorithm. The
        /// default filtering algorithm supports "backing up the mouse" for erasure.</summary>
        /// <returns>true if a point was added, false if not.</returns>
        protected virtual bool AddFiltered(DragState state, DragPoint dp)
        {
            var points = state.MousePoints;

            if (points.Count < 2)
            {
                return(AddIfFarEnough(points, dp));
            }

            var newSeg = (LineSegment <float>)points.Last.Point.To(dp.Point);
            // Strategy:
            // 1. Stroke the new segment with a simple rectangle with no endcap.
            //    The rectangle will be a thin box around the point (halfwidth
            //    is 1..2)
            var newRect   = SimpleStroke(newSeg, EraseThreshold1);
            var newRectBB = newRect.ToBoundingBox();

            // 2. Identify the most recent intersection point between this rectangle
            //    (newRect) and the line being drawn. (if there is no such point,
            //    there is no erasure. Done.)
            // 2b. That intersection point is the one _entering_ the rectangle. Find
            //    the previous intersection point, the one that exits the rectangle.
            //    this is the beginning of the region to potentially erase.
            var           older       = points.Reverse().AdjacentPairs().Select(pair => pair.B.Point.To(pair.A.Point));
            Point <float> beginning   = default(Point <float>);
            bool          keepLooking = false;
            int           offs        = 0;
            var           e           = older.GetEnumerator();

            for (; e.MoveNext(); offs++)
            {
                var seg  = e.Current;
                var list = FindIntersectionsWith(seg, newRect, true).ToList();
                if (list.Count != 0)
                {
                    var min = list.MinOrDefault(p => p.A);
                    beginning = min.B;
                    if (!(offs == 0 && min.A == 1))
                    {
                        if (keepLooking || !PolygonMath.IsPointInPolygon(newRect, seg.A))
                        {
                            break;
                        }
                        keepLooking = true;
                    }
                }
                else if (offs == 0)
                {
                }                                       // todo: use IsPointInPolygon if itscs unstable
            }

            int iFirst = points.Count - 1 - offs;             // index of the first point inside the region (iFirst-1 is outside)

            if (iFirst > 0)
            {
                // 3. Between here and there, identify the farthest point away from the
                //    new point (dp.Point).
                var region       = ((IList <DragPoint>)points).Slice(iFirst);
                int offsFarthest = region.IndexOfMax(p => (p.Point.Sub(dp.Point)).Quadrance());
                int iFarthest    = iFirst + offsFarthest;
                // 4. Make sure that all the points between here and there are close to
                //    this line (within, say... 8 pixels). If so, we have erasure.
                var seg = dp.Point.To(points[iFarthest].Point);
                if (region.All(p => p.Point.DistanceTo(seg) < EraseThreshold2))
                {
                    // 5. Respond to erasure by deleting all the points between there
                    //    and here, not including the first or last point.
                    // 5b. Consider adding the intersection point found in step 2b to
                    //    the point list, before adding the new point.
                    points.Resize(iFirst);
                    if (points.Count == 0 || (points.Last.Point.Sub(beginning)).Length() >= MinDistBetweenDragPoints)
                    {
                        points.Add(new DragPoint(beginning, 10, points));
                    }
                }
            }

            return(AddIfFarEnough(points, dp));
        }