예제 #1
0
        /// <summary>
        /// Get the "hit-segments"
        /// </summary>
        internal static                   StrokeFIndices[] GetHitSegments(StrokeIntersection[] intersections)
        {
            System.Diagnostics.Debug.Assert(intersections != null);
            System.Diagnostics.Debug.Assert(intersections.Length > 0);

            List <StrokeFIndices> hitFIndices = new List <StrokeFIndices>(intersections.Length);

            for (int j = 0; j < intersections.Length; j++)
            {
                System.Diagnostics.Debug.Assert(!intersections[j].IsEmpty);
                if (!intersections[j].HitSegment.IsEmpty)
                {
                    if (hitFIndices.Count > 0 &&
                        hitFIndices[hitFIndices.Count - 1].EndFIndex >=
                        intersections[j].HitSegment.BeginFIndex)
                    {
                        //merge
                        StrokeFIndices sfiPrevious = hitFIndices[hitFIndices.Count - 1];
                        sfiPrevious.EndFIndex = intersections[j].HitSegment.EndFIndex;
                        hitFIndices[hitFIndices.Count - 1] = sfiPrevious;
                    }
                    else
                    {
                        hitFIndices.Add(intersections[j].HitSegment);
                    }
                }
            }
            return(hitFIndices.ToArray());
        }
예제 #2
0
 /// <summary>
 /// ToString
 /// </summary>
 public override string ToString()
 {
     return("{" + StrokeFIndices.GetStringRepresentation(_hitSegment.BeginFIndex) + ","
            + StrokeFIndices.GetStringRepresentation(_inSegment.BeginFIndex) + ","
            + StrokeFIndices.GetStringRepresentation(_inSegment.EndFIndex) + ","
            + StrokeFIndices.GetStringRepresentation(_hitSegment.EndFIndex) + "}");
 }
예제 #3
0
파일: Stroke.cs 프로젝트: dox0/DotNet471RS3
        /// <summary>
        /// Clip
        /// </summary>
        /// <param name="cutAt">Fragment markers for clipping</param>
        private StrokeCollection Clip(StrokeFIndices[] cutAt)
        {
            System.Diagnostics.Debug.Assert(cutAt != null);
            System.Diagnostics.Debug.Assert(cutAt.Length != 0);

#if DEBUG
            //
            // Assert there are  no overlaps between multiple StrokeFIndices
            //
            AssertSortedNoOverlap(cutAt);
#endif

            StrokeCollection leftovers = new StrokeCollection();
            if (cutAt.Length == 0)
            {
                return(leftovers);
            }

            if ((cutAt.Length == 1) && cutAt[0].IsFull)
            {
                leftovers.Add(this.Clone()); //clip and erase always return clones
                return(leftovers);
            }


            StylusPointCollection sourceStylusPoints = this.StylusPoints;
            if (this.DrawingAttributes.FitToCurve)
            {
                sourceStylusPoints = this.GetBezierStylusPoints();
            }

            //
            // Assert the findices are NOT out of range with the packets
            //
            System.Diagnostics.Debug.Assert(false == ((!DoubleUtil.AreClose(cutAt[cutAt.Length - 1].EndFIndex, StrokeFIndices.AfterLast)) &&
                                                      Math.Ceiling(cutAt[cutAt.Length - 1].EndFIndex) > sourceStylusPoints.Count - 1));

            for (int i = 0; i < cutAt.Length; i++)
            {
                StrokeFIndices fragment = cutAt[i];
                if (DoubleUtil.GreaterThanOrClose(fragment.BeginFIndex, fragment.EndFIndex))
                {
                    // ISSUE-2004/06/26-vsmirnov - temporary workaround for bugs
                    // in point erasing: drop invalid fragments
                    System.Diagnostics.Debug.Assert(DoubleUtil.LessThan(fragment.BeginFIndex, fragment.EndFIndex));
                    continue;
                }

                Stroke stroke = Copy(sourceStylusPoints, fragment.BeginFIndex, fragment.EndFIndex);

                // Add the stroke to the output collection
                leftovers.Add(stroke);
            }

            return(leftovers);
        }
        /// <summary>
        /// Helper method to calculate the exact location to cut
        /// </summary>
        /// <param name="spineVector">Vector the relative location of the two inking nodes</param>
        /// <param name="hitBegin">the begin point of the hitting segment</param>
        /// <param name="hitEnd">the end point of the hitting segment</param>
        /// <param name="endRadius">endNode radius</param>
        /// <param name="beginRadius">beginNode radius</param>
        /// <param name="result">StrokeFIndices representing the location for cutting</param>
        private void CalculateCutLocations(
            Vector spineVector, Vector hitBegin, Vector hitEnd, double endRadius, double beginRadius, ref StrokeFIndices result)
        {
            // Find out whether the {hitBegin, hitEnd} segment intersects with the contour
            // of the stroke segment, and find the lower index of the fragment to cut out.
            if (!DoubleUtil.AreClose(result.EndFIndex, StrokeFIndices.AfterLast))
            {
                if (WhereIsNodeAboutSegment(spineVector, hitBegin, hitEnd) == HitResult.Left)
                {
                    double findex = 1 - ClipTest(spineVector, endRadius, beginRadius, hitBegin, hitEnd);
                    if (findex > result.EndFIndex)
                    {
                        result.EndFIndex = findex;
                    }
                }
            }

            // Find out whether the {hitBegin, hitEnd} segment intersects with the contour
            // of the stroke segment, and find the higher index of the fragment to cut out.
            if (!DoubleUtil.AreClose(result.BeginFIndex, StrokeFIndices.BeforeFirst))
            {
                hitBegin -= spineVector;
                hitEnd -= spineVector;
                if (WhereIsNodeAboutSegment(-spineVector, hitBegin, hitEnd) == HitResult.Left)
                {
                    double findex = ClipTest(-spineVector, beginRadius, endRadius, hitBegin, hitEnd);
                    if (findex < result.BeginFIndex)
                    {
                        result.BeginFIndex = findex;
                    }
                }
            }
        }
예제 #5
0
 /// <summary>
 /// Helper method used to determine if we came up with a bogus result during hit testing
 /// </summary>
 protected bool IsInvalidCutTestResult(StrokeFIndices result)
 {
     //
     // check for three invalid states
     // 1) BeforeFirst == AfterLast
     // 2) BeforeFirst, < 0
     // 3) > 1, AfterLast
     //
     if (DoubleUtil.AreClose(result.BeginFIndex, result.EndFIndex) ||
         DoubleUtil.AreClose(result.BeginFIndex, StrokeFIndices.BeforeFirst) && result.EndFIndex < 0.0f ||
         result.BeginFIndex > 1.0f && DoubleUtil.AreClose(result.EndFIndex, StrokeFIndices.AfterLast))
     {
         return true;
     }
     return false;
 }
예제 #6
0
        /// <summary>
        /// Helper function to Hit-test against the two stroke nodes only (excluding the connecting quad). 
        /// </summary>
        /// <param name="hitSegment"></param>
        /// <param name="beginNode"></param>
        /// <param name="endNode"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        private bool HitTestStrokeNodes(
            ContourSegment hitSegment, StrokeNodeData beginNode, StrokeNodeData endNode, ref StrokeFIndices result)
        {
            // First, find out if hitSegment intersects with either of the ink nodes
            bool isHit = false;
            for (int node = 0; node < 2; node++)
            {
                Point position;
                double pressureFactor;
                if (node == 0)
                {
                    if (isHit && DoubleUtil.AreClose(result.BeginFIndex, StrokeFIndices.BeforeFirst))
                    {
                        continue;
                    }
                    position = beginNode.Position;
                    pressureFactor = beginNode.PressureFactor;
                }
                else
                {
                    if (isHit && DoubleUtil.AreClose(result.EndFIndex, StrokeFIndices.AfterLast))
                    {
                        continue;
                    }
                    position = endNode.Position;
                    pressureFactor = endNode.PressureFactor;
                }

                Vector hitBegin, hitEnd;

                // Adjust the segment for the node's pressure factor
                if (hitSegment.IsArc)
                {
                    hitBegin = hitSegment.Begin - position + hitSegment.Radius;
                    hitEnd = hitSegment.Radius;
                }
                else
                {
                    hitBegin = hitSegment.Begin - position;
                    hitEnd = hitBegin + hitSegment.Vector;
                }

                if (pressureFactor != 1)
                {
                    System.Diagnostics.Debug.Assert(DoubleUtil.IsZero(pressureFactor) == false);
                    hitBegin /= pressureFactor;
                    hitEnd /= pressureFactor;
                }
                // Hit-test the node against the segment
                if (hitSegment.IsArc
                    ? HitTestPolygonCircle(_vertices, hitBegin, hitEnd)
                    : HitTestPolygonSegment(_vertices, hitBegin, hitEnd))
                {
                    isHit = true;
                    if (node == 0)
                    {
                        result.BeginFIndex = StrokeFIndices.BeforeFirst;
                        if (DoubleUtil.AreClose(result.EndFIndex, StrokeFIndices.AfterLast))
                        {
                            break;
                        }
                    }
                    else
                    {
                        result.EndFIndex = StrokeFIndices.AfterLast;
                        if (beginNode.IsEmpty)
                        {
                            result.BeginFIndex = StrokeFIndices.BeforeFirst;
                            break;
                        }
                        if (DoubleUtil.AreClose(result.BeginFIndex, StrokeFIndices.BeforeFirst))
                        {
                            break;
                        }
                    }
                }
            }
            return isHit;
        }
예제 #7
0
파일: StrokeNode.cs 프로젝트: JianwenSun/cc
        /// <summary>
        /// Bind the StrokeFIndices for lasso hit test results.
        /// </summary>
        /// <param name="fragment"></param>
        /// <returns></returns>
        private StrokeFIndices BindFIndicesForLassoHitTest(StrokeFIndices fragment)
        {

            System.Diagnostics.Debug.Assert(IsValid);
            if (!fragment.IsEmpty)
            {
                // Adjust BeginFIndex
                if (DoubleUtil.AreClose(fragment.BeginFIndex, StrokeFIndices.BeforeFirst))
                {
                    // set it to be the index of the previous node, indicating intersection start from previous node
                     fragment.BeginFIndex = (_index == 0 ? StrokeFIndices.BeforeFirst:_index - 1);
                }
                else
                {
                    // Adjust findices which are on this segment of the spine (i.e. between 0 and 1)
                    System.Diagnostics.Debug.Assert(DoubleUtil.GreaterThanOrClose(fragment.BeginFIndex, 0f));
                    
                    System.Diagnostics.Debug.Assert(DoubleUtil.LessThanOrClose(fragment.BeginFIndex, 1f));

                    // Adjust the value to consider index, say from 0.75 to 3.75 (for _index = 4)
                    fragment.BeginFIndex += _index - 1;
                }

                //Adjust EndFIndex
                if (DoubleUtil.AreClose(fragment.EndFIndex, StrokeFIndices.AfterLast))
                {
                    // set it to be the index of the current node, indicating the intersection cover the end of the node
                    fragment.EndFIndex = (_isLastNode ? StrokeFIndices.AfterLast:_index);
                }
                else
                {
                    System.Diagnostics.Debug.Assert(DoubleUtil.GreaterThanOrClose(fragment.EndFIndex, 0f));

                    System.Diagnostics.Debug.Assert(DoubleUtil.LessThanOrClose(fragment.EndFIndex, 1f));
                    // Ajust the value to consider the index
                    fragment.EndFIndex += _index - 1;
                }
            }
            return fragment;
        }
예제 #8
0
        /// <summary> 
        ///
        /// </summary>
        /// <param name="cutAt">Fragment markers for clipping</param>
        /// <returns>Survived fragments of current Stroke as a StrokeCollection</returns> 
        private StrokeCollection Erase(StrokeFIndices[] cutAt)
        { 
            System.Diagnostics.Debug.Assert(cutAt != null); 
            System.Diagnostics.Debug.Assert(cutAt.Length != 0);
 
#if DEBUG
            //
            // Assert there are  no overlaps between multiple StrokeFIndices
            // 
            AssertSortedNoOverlap(cutAt);
#endif 
 
            StrokeCollection leftovers = new StrokeCollection();
            // Return an empty collection if the entire stroke it to erase 
            if ((cutAt.Length == 0) || ((cutAt.Length == 1) && cutAt[0].IsFull))
            {
                return leftovers;
            } 

            StylusPointCollection sourceStylusPoints = this.StylusPoints; 
            if (this.DrawingAttributes.FitToCurve) 
            {
                sourceStylusPoints = this.GetBezierStylusPoints(); 
            }

            //
            // Assert the findices are NOT out of range with the packets 
            //
            System.Diagnostics.Debug.Assert(false == ((!DoubleUtil.AreClose(cutAt[cutAt.Length - 1].EndFIndex, StrokeFIndices.AfterLast)) && 
                                        Math.Ceiling(cutAt[cutAt.Length - 1].EndFIndex) > sourceStylusPoints.Count - 1)); 

 
            int i = 0;
            double beginFIndex = StrokeFIndices.BeforeFirst;
            if (cutAt[0].BeginFIndex == StrokeFIndices.BeforeFirst)
            { 
                beginFIndex = cutAt[0].EndFIndex;
                i++; 
            } 
            for (; i < cutAt.Length; i++)
            { 
                StrokeFIndices fragment = cutAt[i];
                if(DoubleUtil.GreaterThanOrClose(beginFIndex, fragment.BeginFIndex))
                {
                    // ISSUE-2004/06/26-vsmirnov - temporary workaround for bugs 
                    // in point erasing: drop invalid fragments
                    System.Diagnostics.Debug.Assert(DoubleUtil.LessThan(beginFIndex, fragment.BeginFIndex)); 
                    continue; 
                }
 

                Stroke stroke = Copy(sourceStylusPoints, beginFIndex, fragment.BeginFIndex);
                // Add the stroke to the output collection
                leftovers.Add(stroke); 

                beginFIndex = fragment.EndFIndex; 
            } 

            if (beginFIndex != StrokeFIndices.AfterLast) 
            {
                Stroke stroke = Copy(sourceStylusPoints, beginFIndex, StrokeFIndices.AfterLast);

                // Add the stroke to the output collection 
                leftovers.Add(stroke);
            } 
 
            return leftovers;
        } 
예제 #9
0
 private bool IsValidStrokeFIndices(StrokeFIndices findex) 
 {
     return (!double.IsNaN(findex.BeginFIndex) && !double.IsNaN(findex.EndFIndex) && findex.BeginFIndex < findex.EndFIndex); 
 } 
예제 #10
0
 /// <summary>
 /// Helper method used to validate that the strokefindices in the array 
 /// are sorted and there are no overlaps
 /// </summary>
 /// <param name="fragments">fragments</param>
 private void AssertSortedNoOverlap(StrokeFIndices[] fragments) 
 {
     if (fragments.Length == 0) 
     { 
         return;
     } 
     if (fragments.Length == 1)
     {
         System.Diagnostics.Debug.Assert(IsValidStrokeFIndices(fragments[0]));
         return; 
     }
     double current = StrokeFIndices.BeforeFirst; 
     for (int x = 0; x < fragments.Length; x++) 
     {
         if (fragments[x].BeginFIndex <= current) 
         {
             //
             // when x == 0, we're just starting, any value is valid
             // 
             System.Diagnostics.Debug.Assert(x == 0);
         } 
         current = fragments[x].BeginFIndex; 
         System.Diagnostics.Debug.Assert(IsValidStrokeFIndices(fragments[x]) && fragments[x].EndFIndex > current);
         current = fragments[x].EndFIndex; 
     }
 }
예제 #11
0
        /// <summary>
        /// Hit-testing for point erase.
        /// </summary>
        /// <param name="iterator"></param>
        /// <param name="intersections"></param>
        /// <returns></returns>
        internal bool EraseTest(StrokeNodeIterator iterator, List<StrokeIntersection> intersections)
        {
            System.Diagnostics.Debug.Assert(iterator != null);
            System.Diagnostics.Debug.Assert(intersections != null);
            intersections.Clear();

            List<StrokeFIndices> eraseAt = new List<StrokeFIndices>();

            if ((_erasingStrokeNodes == null) || (_erasingStrokeNodes.Count == 0))
            {
                return false;
            }

            Rect inkSegmentBounds = Rect.Empty;
            for (int x = 0; x < iterator.Count; x++)
            {   
                StrokeNode inkStrokeNode = iterator[x];
                Rect inkNodeBounds = inkStrokeNode.GetBounds();
                inkSegmentBounds.Union(inkNodeBounds);

                if (inkSegmentBounds.IntersectsWith(_bounds))
                {
                    // 

                    int index = eraseAt.Count;
                    foreach (StrokeNode erasingStrokeNode in _erasingStrokeNodes)
                    {
                        if (false == inkSegmentBounds.IntersectsWith(erasingStrokeNode.GetBoundsConnected()))
                        {
                            continue;
                        }

                        StrokeFIndices fragment = inkStrokeNode.CutTest(erasingStrokeNode);
                        if (fragment.IsEmpty)
                        {
                            continue;
                        }

                        // Merge it with the other results for this ink segment
                        bool inserted = false;
                        for (int i = index; i < eraseAt.Count; i++)
                        {
                            StrokeFIndices lastFragment = eraseAt[i];
                            if (fragment.BeginFIndex < lastFragment.EndFIndex)
                            {
                                // If the fragments overlap, merge them
                                if (fragment.EndFIndex > lastFragment.BeginFIndex)
                                {
                                    fragment = new StrokeFIndices(
                                        Math.Min(lastFragment.BeginFIndex, fragment.BeginFIndex),
                                        Math.Max(lastFragment.EndFIndex, fragment.EndFIndex));

                                    // If the fragment doesn't go beyond lastFragment, break
                                    if ((fragment.EndFIndex <= lastFragment.EndFIndex) || ((i + 1) == eraseAt.Count))
                                    {
                                        inserted = true;
                                        eraseAt[i] = fragment;
                                        break;
                                    }
                                    else
                                    {
                                        eraseAt.RemoveAt(i);
                                        i--;
                                    }
                                }
                                // insert otherwise
                                else
                                {
                                    eraseAt.Insert(i, fragment);
                                    inserted = true;
                                    break;
                                }
                            }
                        }

                        // If not merged nor inserted, add it to the end of the list
                        if (false == inserted)
                        {
                            eraseAt.Add(fragment);
                        }
                        // Break out if the entire ink segment is hit - {BeforeFirst, AfterLast}
                        if (eraseAt[eraseAt.Count - 1].IsFull)
                        {
                            break;
                        }
                    }
                    // Merge inter-segment overlapping fragments
                    if ((index > 0) && (index < eraseAt.Count))
                    {
                        StrokeFIndices lastFragment = eraseAt[index - 1];
                        if (DoubleUtil.AreClose(lastFragment.EndFIndex, StrokeFIndices.AfterLast) )
                        {
                            if (DoubleUtil.AreClose(eraseAt[index].BeginFIndex, StrokeFIndices.BeforeFirst))
                            {
                                lastFragment.EndFIndex = eraseAt[index].EndFIndex;
                                eraseAt[index - 1] = lastFragment;
                                eraseAt.RemoveAt(index);
                            }
                            else
                            {
                                lastFragment.EndFIndex = inkStrokeNode.Index;
                                eraseAt[index - 1] = lastFragment;
                            }
                        }
                    }
                }
                // Start next ink segment
                inkSegmentBounds = inkNodeBounds;
            }
            if (eraseAt.Count != 0)
            {
                foreach (StrokeFIndices segment in eraseAt)
                {
                    intersections.Add(new StrokeIntersection(segment.BeginFIndex, StrokeFIndices.AfterLast,
                                            StrokeFIndices.BeforeFirst, segment.EndFIndex));
                }
            }
            return (eraseAt.Count != 0);
        }
예제 #12
0
파일: Lasso.cs 프로젝트: JianwenSun/cc
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="newFIndices"></param>
 /// <param name="strokeNode"></param>
 public LassoCrossing(StrokeFIndices newFIndices, StrokeNode strokeNode)
 {
     System.Diagnostics.Debug.Assert(!newFIndices.IsEmpty);
     System.Diagnostics.Debug.Assert(strokeNode.IsValid);
     FIndices = newFIndices;
     StartNode = EndNode = strokeNode;
 }
예제 #13
0
파일: StrokeNode.cs 프로젝트: JianwenSun/cc
        /// <summary>
        /// Binds a local fragment to this node by setting the integer part of the
        /// fragment findices equal to the index of the previous node
        /// </summary>
        /// <param name="fragment"></param>
        /// <returns></returns>
        private StrokeFIndices BindFIndices(StrokeFIndices fragment)
        {
            System.Diagnostics.Debug.Assert(IsValid && (_index >= 0));

            if (fragment.IsEmpty == false)
            {
                // Adjust only findices which are on this segment of thew spine (i.e. between 0 and 1)
                if (!DoubleUtil.AreClose(fragment.BeginFIndex, StrokeFIndices.BeforeFirst))
                {
                    System.Diagnostics.Debug.Assert(fragment.BeginFIndex >= 0 && fragment.BeginFIndex <= 1);
                    fragment.BeginFIndex += _index - 1;
                }
                if (!DoubleUtil.AreClose(fragment.EndFIndex, StrokeFIndices.AfterLast))
                {
                    System.Diagnostics.Debug.Assert(fragment.EndFIndex >= 0 && fragment.EndFIndex <= 1);
                    fragment.EndFIndex += _index - 1;
                }
            }
            return fragment;
        }
예제 #14
0
 /// <summary> 
 /// Constructor
 /// </summary> 
 /// <param name="hitBegin"></param> 
 /// <param name="inBegin"></param>
 /// <param name="inEnd"></param> 
 /// <param name="hitEnd"></param>
 internal StrokeIntersection(double hitBegin, double inBegin, double inEnd, double hitEnd)
 {
     //ISSUE-2004/12/06-XiaoTu: should we validate the input? 
     _hitSegment = new StrokeFIndices(hitBegin, hitEnd);
     _inSegment = new StrokeFIndices(inBegin, inEnd); 
 } 
예제 #15
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="hitBegin"></param>
 /// <param name="inBegin"></param>
 /// <param name="inEnd"></param>
 /// <param name="hitEnd"></param>
 internal StrokeIntersection(double hitBegin, double inBegin, double inEnd, double hitEnd)
 {
     //ISSUE-2004/12/06-XiaoTu: should we validate the input?
     _hitSegment = new StrokeFIndices(hitBegin, hitEnd);
     _inSegment  = new StrokeFIndices(inBegin, inEnd);
 }
예제 #16
0
파일: Stroke.cs 프로젝트: dox0/DotNet471RS3
 private bool IsValidStrokeFIndices(StrokeFIndices findex)
 {
     return(!double.IsNaN(findex.BeginFIndex) && !double.IsNaN(findex.EndFIndex) && findex.BeginFIndex < findex.EndFIndex);
 }
예제 #17
-2
파일: Lasso.cs 프로젝트: JianwenSun/cc
            /// <summary>
            /// Merge two crossings into one.
            /// </summary>
            /// <param name="crossing"></param>
            /// <returns>Return true if these two crossings are actually overlapping and merged; false otherwise</returns>
            public bool Merge(LassoCrossing crossing)
            {
                if (crossing.IsEmpty)
                {
                    return false;
                }

                if (FIndices.IsEmpty && !crossing.IsEmpty)
                {
                    FIndices = crossing.FIndices;
                    StartNode = crossing.StartNode;
                    EndNode = crossing.EndNode;
                    return true;
                }

                if(DoubleUtil.GreaterThanOrClose(crossing.FIndices.EndFIndex, FIndices.BeginFIndex) &&
                    DoubleUtil.GreaterThanOrClose(FIndices.EndFIndex, crossing.FIndices.BeginFIndex))
                {
                    if (DoubleUtil.LessThan(crossing.FIndices.BeginFIndex, FIndices.BeginFIndex))
                    {
                        FIndices.BeginFIndex = crossing.FIndices.BeginFIndex;
                        StartNode = crossing.StartNode;
                    }

                    if (DoubleUtil.GreaterThan(crossing.FIndices.EndFIndex, FIndices.EndFIndex))
                    {
                        FIndices.EndFIndex =  crossing.FIndices.EndFIndex;
                        EndNode = crossing.EndNode;
                    }
                    return true;
                }

                return false;
            }