Esempio n. 1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="path"></param>
        /// <param name="stylusShape"></param>
        /// <returns></returns>
        public bool HitTest(IEnumerable <Point> path, StylusShape stylusShape)
        {
            // Check the input parameters
            if (path == null)
            {
                throw new System.ArgumentNullException("path");
            }
            if (stylusShape == null)
            {
                throw new System.ArgumentNullException("stylusShape");
            }

            if (IEnumerablePointHelper.GetCount(path) == 0)
            {
                return(false);
            }

            ErasingStroke erasingStroke = new ErasingStroke(stylusShape);

            erasingStroke.MoveTo(path);

            Rect erasingBounds = erasingStroke.Bounds;

            if (erasingBounds.IsEmpty)
            {
                return(false);
            }

            if (erasingBounds.IntersectsWith(this.GetBounds()))
            {
                return(erasingStroke.HitTest(StrokeNodeIterator.GetIterator(this, this.DrawingAttributes)));
            }

            return(false);
        }
Esempio n. 2
0
        /// <summary>
        /// The implementation behind the public methods AddPoint/AddPoints
        /// </summary>
        /// <param name="points">a set of points representing the last increment
        /// in the moving of the erasing shape</param>
        protected override void AddPointsCore(IEnumerable <Point> points)
        {
            System.Diagnostics.Debug.Assert((points != null) && (IEnumerablePointHelper.GetCount(points) != 0));
            System.Diagnostics.Debug.Assert(_erasingStroke != null);

            // Move the shape through the new points and build the contour of the move.
            _erasingStroke.MoveTo(points);
            Rect erasingBounds = _erasingStroke.Bounds;

            if (erasingBounds.IsEmpty)
            {
                return;
            }

            List <StrokeHitEventArgs> strokeHitEventArgCollection = null;

            // Do nothing if there's nobody listening to the events
            if (StrokeHit != null)
            {
                List <StrokeIntersection> eraseAt = new List <StrokeIntersection>();

                // Test stroke by stroke and collect the results.
                for (int x = 0; x < this.StrokeInfos.Count; x++)
                {
                    StrokeInfo strokeInfo = this.StrokeInfos[x];

                    // Skip the stroke if its bounding box doesn't intersect with the one of the hitting shape.
                    if ((erasingBounds.IntersectsWith(strokeInfo.StrokeBounds) == false) ||
                        (_erasingStroke.EraseTest(StrokeNodeIterator.GetIterator(strokeInfo.Stroke, strokeInfo.Stroke.DrawingAttributes), eraseAt) == false))
                    {
                        continue;
                    }

                    // Create an event args to raise after done with hit-testing
                    // We don't fire these events right away because user is expected to
                    // modify the stroke collection in her event handler, and that would
                    // invalidate this foreach loop.
                    if (strokeHitEventArgCollection == null)
                    {
                        strokeHitEventArgCollection = new List <StrokeHitEventArgs>();
                    }
                    strokeHitEventArgCollection.Add(new StrokeHitEventArgs(strokeInfo.Stroke, eraseAt.ToArray()));
                    // We must clear eraseAt or it will contain invalid results for the next strokes
                    eraseAt.Clear();
                }
            }

            // Raise StrokeHit event if needed.
            if (strokeHitEventArgCollection != null)
            {
                System.Diagnostics.Debug.Assert(strokeHitEventArgCollection.Count != 0);
                for (int x = 0; x < strokeHitEventArgCollection.Count; x++)
                {
                    StrokeHitEventArgs eventArgs = strokeHitEventArgCollection[x];

                    System.Diagnostics.Debug.Assert(eventArgs.HitStroke != null);
                    OnStrokeHit(eventArgs);
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Erases all ink hit by the contour of an erasing stroke
        /// </summary>
        /// <param name="eraserShape">Shape of the eraser</param>
        /// <param name="eraserPath">a path making the spine of the erasing stroke </param>
        public void Erase(IEnumerable <Point> eraserPath, StylusShape eraserShape)
        {
            // Check the input parameters
            if (eraserShape == null)
            {
                throw new System.ArgumentNullException(SR.Get(SRID.SCEraseShape));
            }
            if (eraserPath == null)
            {
                throw new System.ArgumentNullException(SR.Get(SRID.SCErasePath));
            }
            if (IEnumerablePointHelper.GetCount(eraserPath) == 0)
            {
                return;
            }

            ErasingStroke erasingStroke = new ErasingStroke(eraserShape, eraserPath);

            for (int i = 0; i < this.Count; i++)
            {
                Stroke stroke = this[i];

                List <StrokeIntersection> intersections = new List <StrokeIntersection>();
                erasingStroke.EraseTest(StrokeNodeIterator.GetIterator(stroke, stroke.DrawingAttributes), intersections);
                StrokeCollection eraseResult = stroke.Erase(intersections.ToArray());

                UpdateStrokeCollection(stroke, eraseResult, ref i);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Erases all ink inside a lasso
        /// </summary>
        /// <param name="lassoPoints">lasso to erase within</param>
        public void Erase(IEnumerable <Point> lassoPoints)
        {
            // Check the input parameters
            if (lassoPoints == null)
            {
                throw new System.ArgumentNullException("lassoPoints");
            }
            int length = IEnumerablePointHelper.GetCount(lassoPoints);

            if (length == 0)
            {
                throw new ArgumentException(SR.Get(SRID.EmptyArray));
            }

            if (length < 3)
            {
                return;
            }

            Lasso lasso = new SingleLoopLasso();

            lasso.AddPoints(lassoPoints);
            for (int i = 0; i < this.Count; i++)
            {
                Stroke stroke = this[i];

                StrokeCollection eraseResult = stroke.Erase(stroke.HitTest(lasso));
                UpdateStrokeCollection(stroke, eraseResult, ref i);
            }
        }
Esempio n. 5
0
        /// <summary>Hit tests all segments within a contour generated with shape and path</summary>
        /// <param name="shape"></param>
        /// <param name="path"></param>
        /// <returns>StrokeIntersection array for these segments</returns>
        internal StrokeIntersection[] EraseTest(IEnumerable <Point> path, StylusShape shape)
        {
            System.Diagnostics.Debug.Assert(shape != null);
            System.Diagnostics.Debug.Assert(path != null);
            if (IEnumerablePointHelper.GetCount(path) == 0)
            {
                return(Array.Empty <StrokeIntersection>());
            }

            ErasingStroke             erasingStroke = new ErasingStroke(shape, path);
            List <StrokeIntersection> intersections = new List <StrokeIntersection>();

            erasingStroke.EraseTest(StrokeNodeIterator.GetIterator(this, this.DrawingAttributes), intersections);
            return(intersections.ToArray());
        }
Esempio n. 6
0
        /// <summary>
        /// Erase with lasso points.
        /// </summary>
        /// <param name="lassoPoints">Lasso points to erase with</param>
        /// <returns>The after-erasing strokes</returns>
        public StrokeCollection GetEraseResult(IEnumerable <Point> lassoPoints)
        {
            // Check the input parameters
            if (lassoPoints == null)
            {
                throw new System.ArgumentNullException("lassoPoints");
            }

            if (IEnumerablePointHelper.GetCount(lassoPoints) == 0)
            {
                throw new ArgumentException(SR.Get(SRID.EmptyArray));
            }

            Lasso lasso = new SingleLoopLasso();

            lasso.AddPoints(lassoPoints);
            return(this.Erase(this.HitTest(lasso)));
        }
Esempio n. 7
0
        /// <summary>
        /// Issue: what's the return value
        /// </summary>
        /// <param name="path"></param>
        /// <param name="stylusShape"></param>
        /// <returns></returns>
        public StrokeCollection HitTest(IEnumerable <Point> path, StylusShape stylusShape)
        {
            // Check the input parameters
            if (stylusShape == null)
            {
                throw new System.ArgumentNullException("stylusShape");
            }
            if (path == null)
            {
                throw new System.ArgumentNullException("path");
            }
            if (IEnumerablePointHelper.GetCount(path) == 0)
            {
                return(new StrokeCollection());
            }

            // validate input
            ErasingStroke erasingStroke = new ErasingStroke(stylusShape, path);
            Rect          erasingBounds = erasingStroke.Bounds;

            if (erasingBounds.IsEmpty)
            {
                return(new StrokeCollection());
            }
            StrokeCollection hits = new StrokeCollection();

            foreach (Stroke stroke in this)
            {
                // samgeo - Presharp issue
                // Presharp gives a warning when get methods might deref a null.  It's complaining
                // here that 'stroke'' could be null, but StrokeCollection never allows nulls to be added
                // so this is not possible
#pragma warning disable 1634, 1691
#pragma warning suppress 6506
                if (erasingBounds.IntersectsWith(stroke.GetBounds()) &&
                    erasingStroke.HitTest(StrokeNodeIterator.GetIterator(stroke, stroke.DrawingAttributes)))
                {
                    hits.Add(stroke);
                }
#pragma warning restore 1634, 1691
            }

            return(hits);
        }
Esempio n. 8
0
        /// <summary>
        /// Adds an array of points representing an incremental move of the hit-testing tool
        /// </summary>
        /// <param name="points">points representing an incremental move of the hitting tool</param>
        public void AddPoints(IEnumerable <Point> points)
        {
            if (points == null)
            {
                throw new System.ArgumentNullException("points");
            }

            if (IEnumerablePointHelper.GetCount(points) == 0)
            {
                throw new System.ArgumentException(SR.Get(SRID.EmptyArrayNotAllowedAsArgument), "points");
            }

            if (false == _fValid)
            {
                throw new System.InvalidOperationException(SR.Get(SRID.EndHitTestingCalled));
            }

            System.Diagnostics.Debug.Assert(_strokes != null);

            AddPointsCore(points);
        }
Esempio n. 9
0
        /// <summary>
        /// Clips out all ink outside a given lasso
        /// </summary>
        /// <param name="lassoPoints">lasso</param>
        public void Clip(IEnumerable <Point> lassoPoints)
        {
            // Check the input parameters
            if (lassoPoints == null)
            {
                throw new System.ArgumentNullException("lassoPoints");
            }

            int length = IEnumerablePointHelper.GetCount(lassoPoints);

            if (length == 0)
            {
                throw new ArgumentException(SR.Get(SRID.EmptyArray));
            }

            if (length < 3)
            {
                //
                // if you're clipping with a point or a line with
                // two points, it doesn't matter where the line is or if it
                // intersects any of the strokes, the point or line has no region
                // so technically everything in the strokecollection
                // should be removed
                //
                this.Clear(); //raises the appropriate events
                return;
            }

            Lasso lasso = new SingleLoopLasso();

            lasso.AddPoints(lassoPoints);

            for (int i = 0; i < this.Count; i++)
            {
                Stroke           stroke     = this[i];
                StrokeCollection clipResult = stroke.Clip(stroke.HitTest(lasso));
                UpdateStrokeCollection(stroke, clipResult, ref i);
            }
        }
Esempio n. 10
0
        /// <summary>
        /// The implementation behind the public methods AddPoint/AddPoints
        /// </summary>
        /// <param name="points">new points to add to the lasso</param>
        protected override void AddPointsCore(IEnumerable <Point> points)
        {
            System.Diagnostics.Debug.Assert((points != null) && (IEnumerablePointHelper.GetCount(points) != 0));

            // Add the new points to the lasso
            int lastPointIndex = (0 != _lasso.PointCount) ? (_lasso.PointCount - 1) : 0;

            _lasso.AddPoints(points);

            // Do nothing if there's not enough points, or there's nobody listening
            // The points may be filtered out, so if all the points are filtered out, (lastPointIndex == (_lasso.PointCount - 1).
            // For this case, check if the incremental lasso is disabled (i.e., points modified).
            if ((_lasso.IsEmpty) || (lastPointIndex == (_lasso.PointCount - 1) && false == _lasso.IsIncrementalLassoDirty) ||
                (SelectionChanged == null))
            {
                return;
            }

            // Variables for possible HitChanged events to fire
            StrokeCollection strokesHit   = null;
            StrokeCollection strokesUnhit = null;

            // Create a lasso that represents the current increment
            Lasso lassoUpdate = new Lasso();

            if (false == _lasso.IsIncrementalLassoDirty)
            {
                if (0 < lastPointIndex)
                {
                    lassoUpdate.AddPoint(_lasso[0]);
                }

                // Only the points the have been successfully added to _lasso will be added to
                // lassoUpdate.
                for (; lastPointIndex < _lasso.PointCount; lastPointIndex++)
                {
                    lassoUpdate.AddPoint(_lasso[lastPointIndex]);
                }
            }

            // Enumerate through the strokes and update their hit-test results
            foreach (StrokeInfo strokeInfo in this.StrokeInfos)
            {
                Lasso lasso;
                if (true == strokeInfo.IsDirty || true == _lasso.IsIncrementalLassoDirty)
                {
                    // If this is the first time this stroke gets hit-tested with this lasso,
                    // or if the stroke (or its DAs) has changed since the last hit-testing,
                    // or if the lasso points have been modified,
                    // then (re)hit-test this stroke against the entire lasso.
                    lasso = _lasso;
                    strokeInfo.IsDirty = false;
                }
                else
                {
                    // Otherwise, hit-test it against the lasso increment first and then only
                    // those ink points that are in that small lasso need to be hit-tested
                    // against the big (entire) lasso.
                    // This is supposed to be a significant piece of optimization, since
                    // lasso increments are usually very small, they are defined by just
                    // a few points and they don't capture and/or release too many ink nodes.
                    lasso = lassoUpdate;
                }

                // Skip those stroke which bounding box doesn't even intersects with the lasso bounds
                double hitWeightChange = 0f;
                if (lasso.Bounds.IntersectsWith(strokeInfo.StrokeBounds))
                {
                    // Get the stroke node points for the hit-testing.
                    StylusPointCollection stylusPoints = strokeInfo.StylusPoints;

                    // Find out if the lasso update has changed the hit count of the stroke.
                    for (int i = 0; i < stylusPoints.Count; i++)
                    {
                        // Consider only the points that become captured/released with this particular update
                        if (true == lasso.Contains((Point)stylusPoints[i]))
                        {
                            double weight = strokeInfo.GetPointWeight(i);

                            if (lasso == _lasso || _lasso.Contains((Point)stylusPoints[i]))
                            {
                                hitWeightChange += weight;
                            }
                            else
                            {
                                hitWeightChange -= weight;
                            }
                        }
                    }
                }

                // Update the stroke hit weight and check whether it has crossed the margin
                // in either direction since the last update.
                if ((hitWeightChange != 0) || (lasso == _lasso))
                {
                    strokeInfo.HitWeight = (lasso == _lasso) ? hitWeightChange : (strokeInfo.HitWeight + hitWeightChange);
                    bool isHit = DoubleUtil.GreaterThanOrClose(strokeInfo.HitWeight, strokeInfo.TotalWeight * _percentIntersect / 100f - Stroke.PercentageTolerance);

                    if (strokeInfo.IsHit != isHit)
                    {
                        strokeInfo.IsHit = isHit;
                        if (isHit)
                        {
                            // The hit count became greater than the margin percentage, the stroke
                            // needs to be reported for selection
                            if (null == strokesHit)
                            {
                                strokesHit = new StrokeCollection();
                            }
                            strokesHit.Add(strokeInfo.Stroke);
                        }
                        else
                        {
                            // The hit count just became less than the margin percentage,
                            // the stroke needs to be reported for de-selection
                            if (null == strokesUnhit)
                            {
                                strokesUnhit = new StrokeCollection();
                            }
                            strokesUnhit.Add(strokeInfo.Stroke);
                        }
                    }
                }
            }

            _lasso.IsIncrementalLassoDirty = false;
            // Raise StrokesHitChanged event if any strokes has changed thier
            // hit status and there're the event subscribers.
            if ((null != strokesHit) || (null != strokesUnhit))
            {
                OnSelectionChanged(new LassoSelectionChangedEventArgs(strokesHit, strokesUnhit));
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Hit-testing with lasso
        /// </summary>
        /// <param name="lassoPoints">points making the lasso</param>
        /// <param name="percentageWithinLasso">the margin value to tell whether a stroke
        /// is in or outside of the rect</param>
        /// <returns>collection of strokes found inside the rectangle</returns>
        public StrokeCollection HitTest(IEnumerable <Point> lassoPoints, int percentageWithinLasso)
        {
            // Check the input parameters
            if (lassoPoints == null)
            {
                throw new System.ArgumentNullException("lassoPoints");
            }
            if ((percentageWithinLasso < 0) || (percentageWithinLasso > 100))
            {
                throw new System.ArgumentOutOfRangeException("percentageWithinLasso");
            }

            if (IEnumerablePointHelper.GetCount(lassoPoints) < 3)
            {
                return(new StrokeCollection());
            }

            Lasso lasso = new SingleLoopLasso();

            lasso.AddPoints(lassoPoints);

            // Enumerate through the strokes and collect those captured by the lasso.
            StrokeCollection lassoedStrokes = new StrokeCollection();

            foreach (Stroke stroke in this)
            {
                if (percentageWithinLasso == 0)
                {
                    lassoedStrokes.Add(stroke);
                }
                else
                {
                    StrokeInfo strokeInfo = null;
                    try
                    {
                        strokeInfo = new StrokeInfo(stroke);

                        StylusPointCollection stylusPoints = strokeInfo.StylusPoints;
                        double target = strokeInfo.TotalWeight * percentageWithinLasso / 100.0f - Stroke.PercentageTolerance;

                        for (int i = 0; i < stylusPoints.Count; i++)
                        {
                            if (true == lasso.Contains((Point)stylusPoints[i]))
                            {
                                target -= strokeInfo.GetPointWeight(i);
                                if (DoubleUtil.LessThanOrClose(target, 0f))
                                {
                                    lassoedStrokes.Add(stroke);
                                    break;
                                }
                            }
                        }
                    }
                    finally
                    {
                        if (strokeInfo != null)
                        {
                            //detach from event handlers, or else we leak.
                            strokeInfo.Detach();
                        }
                    }
                }
            }

            // Return the resulting collection
            return(lassoedStrokes);
        }