예제 #1
0
 static bool AddIfFarEnough(DList <DragPoint> points, DragPoint dp)
 {
     if (points.Count == 0 || points.Last.Point.Sub(dp.Point).Quadrance() >= MathEx.Square(MinDistBetweenDragPoints))
     {
         points.Add(dp);
         return(true);
     }
     return(false);
 }
예제 #2
0
        public GestureAnalyzer(Control control)
        {
            _control = control;
            if (IsDesignTime)
            {
                return;                           // Rx crashes the designer
            }
            var mouseMove  = Observable.FromEventPattern <MouseEventArgs>(control, "MouseMove");
            var lMouseDown = Observable.FromEventPattern <MouseEventArgs>(control, "MouseDown").Where(e => e.EventArgs.Button == MouseButtons.Left);
            var lMouseUp   = Observable.FromEventPattern <MouseEventArgs>(control, "MouseUp").Where(e => e.EventArgs.Button == MouseButtons.Left);

            lMouseDown.SelectMany(start =>
            {
                int prevTicks = Environment.TickCount, msec;
                var state     = MouseClickStarted(start.EventArgs);
                _dragState    = state;
                _control.Focus();
                return(mouseMove
                       .StartWith(start)
                       .TakeUntil(lMouseUp)
                       .Do(e =>
                {
                    if (!state.IsComplete)
                    {
                        prevTicks += (msec = Environment.TickCount - prevTicks);
                        var pt = (Point <float>)e.EventArgs.Location.AsLoyc();
                        if (state.MousePoints.Count == 0 || pt.Sub(state.MousePoints.Last.Point) != Vector <float> .Zero)
                        {
                            var dp = new DragPoint(pt, msec, state.MousePoints);
                            state.UnfilteredMousePoints.Add(dp);
                            AddFiltered(state, dp);
                            AnalyzeGesture(state, false);
                        }
                    }
                }, () =>
                {
                    if (!state.IsComplete)
                    {
                        AnalyzeGesture(state, true);
                    }
                    _dragState = null;
                }));
            })
            .Subscribe();
        }
예제 #3
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));
        }
예제 #4
0
 public DragPoint(DragPoint original, Matrix matrix)
 {
     Point         = matrix.Transform(original.Point);
     MsecSincePrev = original.MsecSincePrev;
     AngleMod256   = original.AngleMod256;           // rotation not supported
 }