コード例 #1
0
ファイル: Lasso.cs プロジェクト: beda2280/wpf-1
        /// <summary>
        /// Helper function to find out the hit test result
        /// </summary>
        private void ProduceHitTestResults(
            List <LassoCrossing> crossingList, List <StrokeIntersection> strokeIntersections)
        {
            bool previousSegmentInsideLasso = false;

            for (int x = 0; x <= crossingList.Count; x++)
            {
                bool currentSegmentWithinLasso = false;
                bool canMerge         = true;
                StrokeIntersection si = new StrokeIntersection();
                if (x == 0)
                {
                    si.HitBegin = StrokeFIndices.BeforeFirst;
                    si.InBegin  = StrokeFIndices.BeforeFirst;
                }
                else
                {
                    si.InBegin  = crossingList[x - 1].FIndices.EndFIndex;
                    si.HitBegin = crossingList[x - 1].FIndices.BeginFIndex;
                    currentSegmentWithinLasso = SegmentWithinLasso(crossingList[x - 1].EndNode, si.InBegin);
                }

                if (x == crossingList.Count)
                {
                    // For a special case when the last intersection is something like (1.2, AL).
                    // As a result the last InSegment should be empty.
                    if (DoubleUtil.AreClose(si.InBegin, StrokeFIndices.AfterLast))
                    {
                        si.InEnd = StrokeFIndices.BeforeFirst;
                    }
                    else
                    {
                        si.InEnd = StrokeFIndices.AfterLast;
                    }
                    si.HitEnd = StrokeFIndices.AfterLast;
                }
                else
                {
                    si.InEnd = crossingList[x].FIndices.BeginFIndex;

                    // For a speical case when the first intersection is something like (BF, 0.67).
                    // As a result the first InSegment should be empty
                    if (DoubleUtil.AreClose(si.InEnd, StrokeFIndices.BeforeFirst))
                    {
                        System.Diagnostics.Debug.Assert(DoubleUtil.AreClose(si.InBegin, StrokeFIndices.BeforeFirst));
                        si.InBegin = StrokeFIndices.AfterLast;
                    }

                    si.HitEnd = crossingList[x].FIndices.EndFIndex;
                    currentSegmentWithinLasso = SegmentWithinLasso(crossingList[x].StartNode, si.InEnd);

                    // If both the start and end position of the current crossing is
                    // outside the lasso, the crossing is a hit-only intersection, i.e., the in-segment is empty.
                    if (!currentSegmentWithinLasso && !SegmentWithinLasso(crossingList[x].EndNode, si.HitEnd))
                    {
                        currentSegmentWithinLasso = true;
                        si.HitBegin = crossingList[x].FIndices.BeginFIndex;
                        si.InBegin  = StrokeFIndices.AfterLast;
                        si.InEnd    = StrokeFIndices.BeforeFirst;
                        canMerge    = false;
                    }
                }

                if (currentSegmentWithinLasso)
                {
                    if (x > 0 && previousSegmentInsideLasso && canMerge)
                    {
                        // we need to consolidate with the previous segment
                        StrokeIntersection previousIntersection = strokeIntersections[strokeIntersections.Count - 1];

                        // For example: previousIntersection = [BF, AL, BF, 0.0027], si = [BF, 0.0027, 0.049, 0.063]
                        if (previousIntersection.InSegment.IsEmpty)
                        {
                            previousIntersection.InBegin = si.InBegin;
                        }
                        previousIntersection.InEnd  = si.InEnd;
                        previousIntersection.HitEnd = si.HitEnd;
                        strokeIntersections[strokeIntersections.Count - 1] = previousIntersection;
                    }
                    else
                    {
                        strokeIntersections.Add(si);
                    }

                    if (DoubleUtil.AreClose(si.HitEnd, StrokeFIndices.AfterLast))
                    {
                        // The strokeIntersections already cover the end of the stroke. No need to continue.
                        return;
                    }
                }
                previousSegmentInsideLasso = currentSegmentWithinLasso;
            }
        }
コード例 #2
0
ファイル: Lasso.cs プロジェクト: beda2280/wpf-1
        internal StrokeIntersection[] HitTest(StrokeNodeIterator iterator)
        {
            System.Diagnostics.Debug.Assert(_points != null);
            System.Diagnostics.Debug.Assert(iterator != null);

            if (_points.Count < 3)
            {
                //
                // it takes at least 3 points to create a lasso
                //
                return(Array.Empty <StrokeIntersection>());
            }

            //
            // We're about to perform hit testing with a lasso.
            // To do so we need to iterate through each StrokeNode.
            // As we do, we calculate the bounding rect between it
            // and the previous StrokeNode and store this in 'currentStrokeSegmentBounds'
            //
            // Next, we check to see if that StrokeNode pair's bounding box intersects
            // with the bounding box of the Lasso points.  If not, we continue iterating through
            // StrokeNode pairs.
            //
            // If it does, we do a more granular hit test by pairing points in the Lasso, getting
            // their bounding box and seeing if that bounding box intersects our current StrokeNode
            // pair
            //

            Point lastNodePosition           = new Point();
            Point lassoLastPoint             = _points[_points.Count - 1];
            Rect  currentStrokeSegmentBounds = Rect.Empty;

            // Initilize the current crossing to be an empty one
            LassoCrossing currentCrossing = LassoCrossing.EmptyCrossing;

            // Creat a list to hold all the crossings
            List <LassoCrossing> crossingList = new List <LassoCrossing>();

            for (int i = 0; i < iterator.Count; i++)
            {
                StrokeNode strokeNode = iterator[i];
                Rect       nodeBounds = strokeNode.GetBounds();
                currentStrokeSegmentBounds.Union(nodeBounds);

                // Skip the node if it's outside of the lasso's bounds
                if (currentStrokeSegmentBounds.IntersectsWith(_bounds) == true)
                {
                    // currentStrokeSegmentBounds, made up of the bounding box of
                    // this StrokeNode unioned with the last StrokeNode,
                    // intersects the lasso bounding box.
                    //
                    // Now we need to iterate through the lasso points and find out where they cross
                    //
                    Point lastPoint = lassoLastPoint;
                    foreach (Point point in _points)
                    {
                        //
                        // calculate a segment of the lasso from the last point
                        // to the current point
                        //
                        Rect lassoSegmentBounds = new Rect(lastPoint, point);

                        //
                        // see if this lasso segment intersects with the current stroke segment
                        //
                        if (!currentStrokeSegmentBounds.IntersectsWith(lassoSegmentBounds))
                        {
                            lastPoint = point;
                            continue;
                        }

                        //
                        // the lasso segment DOES intersect with the current stroke segment
                        // find out precisely where
                        //
                        StrokeFIndices strokeFIndices = strokeNode.CutTest(lastPoint, point);

                        lastPoint = point;
                        if (strokeFIndices.IsEmpty)
                        {
                            // current lasso segment does not hit the stroke segment, continue with the next lasso point
                            continue;
                        }

                        // Create a potentially new crossing for the current hit testing result.
                        LassoCrossing potentialNewCrossing = new LassoCrossing(strokeFIndices, strokeNode);

                        // Try to merge with the current crossing. If the merge is succussful (return true), the new crossing is actually
                        // continueing the current crossing, so do not start a new crossing. Otherwise, start a new one and add the existing
                        // one to the list.
                        if (!currentCrossing.Merge(potentialNewCrossing))
                        {
                            // start a new crossing and add the existing on to the list
                            crossingList.Add(currentCrossing);
                            currentCrossing = potentialNewCrossing;
                        }
                    }
                }

                // Continue with the next node
                currentStrokeSegmentBounds = nodeBounds;
                lastNodePosition           = strokeNode.Position;
            }


            // Adding the last crossing to the list, if valid
            if (!currentCrossing.IsEmpty)
            {
                crossingList.Add(currentCrossing);
            }

            // Handle the special case of no intersection at all
            if (crossingList.Count == 0)
            {
                // the stroke was either completely inside the lasso
                // or outside the lasso
                if (this.Contains(lastNodePosition))
                {
                    StrokeIntersection[] strokeIntersections = new StrokeIntersection[1];
                    strokeIntersections[0] = StrokeIntersection.Full;
                    return(strokeIntersections);
                }
                else
                {
                    return(Array.Empty <StrokeIntersection>());
                }
            }

            // It is still possible that the current crossing list is not sorted or overlapping.
            // Sort the list and merge the overlapping ones.
            SortAndMerge(ref crossingList);

            // Produce the hit test results and store them in a list
            List <StrokeIntersection> strokeIntersectionList = new List <StrokeIntersection>();

            ProduceHitTestResults(crossingList, strokeIntersectionList);

            return(strokeIntersectionList.ToArray());
        }