StrokeNodeOperations.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / MS / Internal / Ink / StrokeNodeOperations.cs / 1 / StrokeNodeOperations.cs

                            //------------------------------------------------------------------------ 
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
//----------------------------------------------------------------------- 
using System;
using System.Collections.Generic; 
using System.Windows; 
using System.Windows.Ink;
using System.Windows.Media; 
using System.Windows.Input;
using System.Diagnostics;
using MS.Utility;
using MS.Internal; 

namespace MS.Internal.Ink 
{ 
    /// 
    /// The base operations class that implements polygonal node operations by default. 
    /// 
    internal partial class StrokeNodeOperations
    {
        #region Static API 

        ///  
        /// 
        /// 
        ///  
        /// 
        internal static StrokeNodeOperations CreateInstance(StylusShape nodeShape)
        {
            if (nodeShape == null) 
            {
                throw new ArgumentNullException("nodeShape"); 
            } 
            if (nodeShape.IsEllipse)
            { 
                return new EllipticalNodeOperations(nodeShape);
            }
            return new StrokeNodeOperations(nodeShape);
        } 
        #endregion
 
        #region API 

        ///  
        /// Constructor
        /// 
        /// shape of the nodes
        internal StrokeNodeOperations(StylusShape nodeShape) 
        {
            System.Diagnostics.Debug.Assert(nodeShape != null); 
            _vertices = nodeShape.GetVerticesAsVectors(); 
        }
 
        /// 
        /// This is probably not the best (design-wise) but the cheapest way to tell
        /// EllipticalNodeOperations from all other implementations of node operations.
        ///  
        internal virtual bool IsNodeShapeEllipse { get { return false; } }
 
        ///  
        /// Computes the bounds of a node
        ///  
        /// node to compute bounds of
        /// bounds of the node
        internal Rect GetNodeBounds(StrokeNodeData node)
        { 
            if (_shapeBounds.IsEmpty)
            { 
                int i; 
                for (i = 0; (i + 1) < _vertices.Length; i += 2)
                { 
                    _shapeBounds.Union(new Rect((Point)_vertices[i], (Point)_vertices[i + 1]));
                }
                if (i < _vertices.Length)
                { 
                    _shapeBounds.Union((Point)_vertices[i]);
                } 
            } 

            Rect boundingBox = _shapeBounds; 
            System.Diagnostics.Debug.Assert((boundingBox.X <= 0) && (boundingBox.Y <= 0));

            double pressureFactor = node.PressureFactor;
            if (!DoubleUtil.AreClose(pressureFactor,1d)) 
            {
                boundingBox = new Rect( 
                    _shapeBounds.X * pressureFactor, 
                    _shapeBounds.Y * pressureFactor,
                    _shapeBounds.Width * pressureFactor, 
                    _shapeBounds.Height * pressureFactor);
            }

            boundingBox.Location += (Vector)node.Position; 

            return boundingBox; 
        } 

        internal void GetNodeContourPoints(StrokeNodeData node, List pointBuffer) 
        {
            double pressureFactor = node.PressureFactor;
            if (DoubleUtil.AreClose(pressureFactor, 1d))
            { 
                for (int i = 0; i < _vertices.Length; i++)
                { 
                    pointBuffer.Add(node.Position + _vertices[i]); 
                }
            } 
            else
            {
                for (int i = 0; i < _vertices.Length; i++)
                { 
                    pointBuffer.Add(node.Position + (_vertices[i] * pressureFactor));
                } 
            } 
        }
 
        /// 
        /// Returns an enumerator for edges of the contour comprised by a given node
        /// and its connecting quadrangle.
        /// Used for hit-testing a stroke against an other stroke (stroke and point erasing) 
        /// 
        /// node 
        /// quadrangle connecting the node to the preceeding node 
        /// contour segments enumerator
        internal virtual IEnumerable GetContourSegments(StrokeNodeData node, Quad quad) 
        {
            System.Diagnostics.Debug.Assert(node.IsEmpty == false);

            if (quad.IsEmpty) 
            {
                Point vertex = node.Position + (_vertices[_vertices.Length - 1] * node.PressureFactor); 
                for (int i = 0; i < _vertices.Length; i++) 
                {
                    Point nextVertex = node.Position + (_vertices[i] * node.PressureFactor); 
                    yield return new ContourSegment(vertex, nextVertex);
                    vertex = nextVertex;
                }
            } 
            else
            { 
                yield return new ContourSegment(quad.A, quad.B); 

                for (int i = 0, count = _vertices.Length; i < count; i++) 
                {
                    Point vertex = node.Position + (_vertices[i] * node.PressureFactor);
                    if (vertex == quad.B)
                    { 
                        for (int j = 0; (j < count) && (vertex != quad.C); j++)
                        { 
                            i = (i + 1) % count; 
                            Point nextVertex = node.Position + (_vertices[i] * node.PressureFactor);
                            yield return new ContourSegment(vertex, nextVertex); 
                            vertex = nextVertex;
                        }
                        break;
                    } 
                }
 
                yield return new ContourSegment(quad.C, quad.D); 
                yield return new ContourSegment(quad.D, quad.A);
            } 
        }

        /// 
        /// ISSUE-2004/06/15- temporary workaround to avoid hit-testing ellipses with ellipses 
        /// 
        ///  
        ///  
        /// 
        internal virtual IEnumerable GetNonBezierContourSegments(StrokeNodeData beginNode, StrokeNodeData endNode) 
        {
            Quad quad = beginNode.IsEmpty ? Quad.Empty : GetConnectingQuad(beginNode, endNode);
            return GetContourSegments(endNode, quad);
        } 

 
        ///  
        /// Finds connecting points for a pair of stroke nodes (of a polygonal shape)
        ///  
        /// a node to connect
        /// another node, next to beginNode
        /// connecting quadrangle, that can be empty if one node is inside the other
        internal virtual Quad GetConnectingQuad(StrokeNodeData beginNode, StrokeNodeData endNode) 
        {
            // Return an empty quad if either of the nodes is empty (not a node) 
            // or if both nodes are at the same position. 
            if (beginNode.IsEmpty || endNode.IsEmpty || DoubleUtil.AreClose(beginNode.Position, endNode.Position))
            { 
                return Quad.Empty;
            }

            // By definition, Quad's vertices (A,B,C,D) are ordered clockwise with points A and D located 
            // on the beginNode and B and C on the endNode. Basically, we're looking for segments AB and CD.
            // We iterate through the vertices of the beginNode, at each vertex we analyze location of the 
            // connecting segment relative to the node's edges at the vertex, and enforce these rules: 
            //  - if the vector of the connecting segment at a vertex V[i] is on the left from vector V[i]V[i+1]
            //    and not on the left from vector V[i-1]V[i], then it's the AB segment of the quad (V[i] == A). 
            //  - if the vector of the connecting segment at a vertex V[i] is on the left from vector V[i-1]V[i]
            //    and not on the left from vector V[i]V[i+1], then it's the CD segment of the quad (V[i] == D).
            //
 
            Quad quad = Quad.Empty;
            bool foundAB = false, foundCD = false; 
 
            // There's no need to build shapes of the two nodes in order to find their connecting quad.
            // It's the spine vector between the nodes and their scaling diff (pressure delta) is all 
            // that matters here.
            Vector spine = endNode.Position - beginNode.Position;
            double pressureDelta = endNode.PressureFactor - beginNode.PressureFactor;
 
            // Iterate through the vertices of the default shape
            int count = _vertices.Length; 
            for (int i = 0, j = count - 1; i < count; i++, j = ((j + 1) % count)) 
            {
                // Compute vector of the connecting segment at the vertex [i] 
                Vector connection = spine + _vertices[i] * pressureDelta;
                if ((pressureDelta != 0) && (connection.X == 0) && (connection.Y == 0))
                {
                    // One of the nodes,                       |----| 
                    // as well as the connecting quad,         |__  |
                    // is entirely inside the other node.      |  | | 
                    //                                 [i] --> |__|_| 
                    return Quad.Empty;
                } 

                // Find out where this vector is about the node edge [i][i+1]
                // (The vars names "goingTo" and "comingFrom" refer direction of the line defined
                // by the connecting vector applied at vertex [i], relative to the contour of the node shape. 
                // Using these terms, (comingFrom != Right && goingTo == Left) corresponds to the segment AB,
                // and (comingFrom == Right && goingTo != Left) describes the DC. 
                HitResult goingTo = WhereIsVectorAboutVector(connection, _vertices[(i + 1) % count] - _vertices[i]); 

                if (goingTo == HitResult.Left) 
                {
                    if (false == foundAB)
                    {
                        // Find out where the node edge [i-1][i] is about the connecting vector 
                        HitResult comingFrom = WhereIsVectorAboutVector(_vertices[i] - _vertices[j], connection);
                        if (HitResult.Right != comingFrom) 
                        { 
                            foundAB = true;
                            quad.A = beginNode.Position + _vertices[i] * beginNode.PressureFactor; 
                            quad.B = endNode.Position + _vertices[i] * endNode.PressureFactor;
                            if (true == foundCD)
                            {
                                // Found all 4 points. Break out from the 'for' loop. 
                                break;
                            } 
                        } 
                    }
                } 
                else
                {
                    if (false == foundCD)
                    { 
                        // Find out where the node edge [i-1][i] is about the connecting vector
                        HitResult comingFrom = WhereIsVectorAboutVector(_vertices[i] - _vertices[j], connection); 
                        if (HitResult.Right == comingFrom) 
                        {
                            foundCD = true; 
                            quad.C = endNode.Position + _vertices[i] * endNode.PressureFactor;
                            quad.D = beginNode.Position + _vertices[i] * beginNode.PressureFactor;
                            if (true == foundAB)
                            { 
                                // Found all 4 points. Break out from the 'for' loop.
                                break; 
                            } 
                        }
                    } 
                }
            }

            if (!foundAB || !foundCD ||   // (2) 
                ((pressureDelta != 0) && Vector.Determinant(quad.B - quad.A, quad.D - quad.A) == 0)) // (1)
            { 
                //                                          _____        _______ 
                // One of the nodes,                    (1) |__  |   (2) | ___  |
                // as well as the connecting quad,          |  | |       | |  | | 
                // is entirely inside the other node.       |__| |       | |__| |
                //                                          |____|       |___ __|
                return Quad.Empty;
            } 

            return quad; 
        } 

        ///  
        /// Hit-tests ink segment defined by two nodes against a linear segment.
        /// 
        /// Begin node of the ink segment
        /// End node of the ink segment 
        /// Pre-computed quadrangle connecting the two ink nodes
        /// Begin point of the hitting segment 
        /// End point of the hitting segment 
        /// true if there's intersection, false otherwise
        internal virtual bool HitTest( 
            StrokeNodeData beginNode, StrokeNodeData endNode, Quad quad, Point hitBeginPoint, Point hitEndPoint)
        {
            // Check for special cases when the endNode is the very first one (beginNode.IsEmpty)
            // or one node is completely inside the other. In either case the connecting quad 
            // would be Empty and we need to hit-test against the biggest node (the one with
            // the greater PressureFactor) 
            if (quad.IsEmpty) 
            {
                Point position; 
                double pressureFactor;
                if (beginNode.IsEmpty || (endNode.PressureFactor > beginNode.PressureFactor))
                {
                    position = endNode.Position; 
                    pressureFactor = endNode.PressureFactor;
                } 
                else 
                {
                    position = beginNode.Position; 
                    pressureFactor = beginNode.PressureFactor;
                }

                // Find the coordinates of the hitting segment relative to the ink node 
                Vector hitBegin = hitBeginPoint - position, hitEnd = hitEndPoint - position;
                if (pressureFactor != 1) 
                { 
                    // Instead of applying pressure to the node, do reverse scaling on
                    // the hitting segment. This allows us use the original array of vertices 
                    // in hit-testing.
                    System.Diagnostics.Debug.Assert(DoubleUtil.IsZero(pressureFactor) == false);
                    hitBegin /= pressureFactor;
                    hitEnd /= pressureFactor; 
                }
                return HitTestPolygonSegment(_vertices, hitBegin, hitEnd); 
            } 
            else
            { 
                // Iterate through the vertices of the contour of the ink segment
                // check where the hitting segment is about them, return false if it's
                // on the outer (left) side of the ink contour. This implementation might
                // look more complex than straightforward separated hit-testing of three 
                // polygons (beginNode, quad, endNode), but it's supposed to be more optimal
                // because the number of edges it hit-tests is approximately twice less 
                // than with the straightforward implementation. 

                // Start with the segment quad.C->quad.D 
                Vector hitBegin = hitBeginPoint - beginNode.Position;
                Vector hitEnd = hitEndPoint - beginNode.Position;
                HitResult hitResult = WhereIsSegmentAboutSegment(
                    hitBegin, hitEnd, quad.C - beginNode.Position, quad.D - beginNode.Position); 
                if (HitResult.Left == hitResult)
                { 
                    return false; 
                }
 
                // Continue clockwise from quad.D to quad.C

                HitResult firstResult = hitResult, lastResult = hitResult;
                double pressureFactor = beginNode.PressureFactor; 

                // Find the index of the vertex that is quad.D 
                // Use count var to avoid infinite loop, normally it shouldn't 
                // happen but it doesn't hurt to check it just in case.
                int i = 0, count = _vertices.Length; 
                Vector vertex = new Vector();
                for (i = 0; i < count; i++)
                {
                    vertex = _vertices[i] * pressureFactor; 
                    // Here and in a few more places down the code, when comparing
                    // a quad's vertex vs a scaled shape vertex, it's important to 
                    // compute them the same way as in GetConnectingQuad, so that not 
                    // hit that double's computation error. For instance, sometimes the
                    // expression (vertex == quad.D - beginNode.Position) gives 'false' 
                    // while the expression below gives 'true'. (Another workaround is to
                    // use DoubleUtil.AreClose but that;d be less performant)
                    if ((beginNode.Position + vertex) == quad.D)
                    { 
                        break;
                    } 
                } 
                System.Diagnostics.Debug.Assert(count > 0);
                // This loop does the iteration thru the edges of the ink segment 
                // clockwise from quad.D to quad.C.
                for (int node = 0; node < 2; node++)
                {
                    Point nodePosition = (node == 0) ? beginNode.Position : endNode.Position; 
                    Point end = (node == 0) ? quad.A : quad.C;
 
                    count = _vertices.Length; 
                    while (((nodePosition + vertex) != end) && (count != 0))
                    { 
                        i = (i + 1) % _vertices.Length;
                        Vector nextVertex = (pressureFactor == 1) ? _vertices[i] : (_vertices[i] * pressureFactor);
                        hitResult = WhereIsSegmentAboutSegment(hitBegin, hitEnd, vertex, nextVertex);
                        if (HitResult.Hit == hitResult) 
                        {
                            return true; 
                        } 
                        if (true == IsOutside(hitResult, lastResult))
                        { 
                            return false;
                        }
                        lastResult = hitResult;
                        vertex = nextVertex; 
                        count--;
                    } 
                    System.Diagnostics.Debug.Assert(count > 0); 

                    if (node == 0) 
                    {
                        // The first iteration is done thru the outer segments of beginNode
                        // and ends at quad.A, for the second one make some adjustments
                        // to continue iterating through quad.AB and the outer segments of 
                        // endNode up to quad.C
                        pressureFactor = endNode.PressureFactor; 
 
                        Vector spineVector = endNode.Position - beginNode.Position;
                        vertex -= spineVector; 
                        hitBegin -= spineVector;
                        hitEnd -= spineVector;

                        // Find the index of the vertex that is quad.B 
                        count = _vertices.Length;
                        while (((endNode.Position + _vertices[i] * pressureFactor) != quad.B) && (count != 0)) 
                        { 
                            i = (i + 1) % _vertices.Length;
                            count--; 
                        }
                        System.Diagnostics.Debug.Assert(count > 0);
                        i--;
                    } 
                }
                return (false == IsOutside(firstResult, hitResult)); 
            } 
        }
 
        /// 
        /// Hit-tests a stroke segment defined by two nodes against another stroke segment.
        /// 
        /// Begin node of the stroke segment to hit-test. Can be empty (none) 
        /// End node of the stroke segment
        /// Pre-computed quadrangle connecting the two nodes. 
        /// Can be empty if the begion node is empty or when one node is entirely inside the other 
        /// a collection of basic segments outlining the hitting contour
        /// true if the contours intersect or overlap 
        internal virtual bool HitTest(
            StrokeNodeData beginNode, StrokeNodeData endNode, Quad quad, IEnumerable hitContour)
        {
            // Check for special cases when the endNode is the very first one (beginNode.IsEmpty) 
            // or one node is completely inside the other. In either case the connecting quad
            // would be Empty and we need to hittest against the biggest node (the one with 
            // the greater PressureFactor) 
            if (quad.IsEmpty)
            { 
                // NTRAID#Window OS bug-1029694-2004/10/15-xiaotu, refactor the code to make it a method
                // to increase the maintainability of the program. FxCop bug.

                // Make a call to hit-test the biggest node the hitting contour. 
                return HitTestPolygonContourSegments(hitContour, beginNode, endNode);
            } 
            else 
            {
                // NTRAID#Window OS bug-1029694-2004/10/15-xiaotu, refactor the code to make it a method 
                // to increase the maintainability of the program. FxCop bug.

                // HitTest the the hitting contour against the inking contour
                return HitTestInkContour(hitContour, quad, beginNode, endNode); 
            }
        } 
 
        /// 
        /// Hit-tests ink segment defined by two nodes against a linear segment. 
        /// 
        /// Begin node of the ink segment
        /// End node of the ink segment
        /// Pre-computed quadrangle connecting the two ink nodes 
        /// Begin point of the hitting segment
        /// End point of the hitting segment 
        /// Exact location to cut at represented by StrokeFIndices 
        internal virtual StrokeFIndices CutTest(
            StrokeNodeData beginNode, StrokeNodeData endNode, Quad quad, Point hitBeginPoint, Point hitEndPoint) 
        {
            StrokeFIndices result = StrokeFIndices.Empty;

            // First, find out if the hitting segment intersects with either of the ink nodes 
            for (int node = (beginNode.IsEmpty ? 1 : 0); node < 2; node++)
            { 
                Point position = (node == 0) ? beginNode.Position : endNode.Position; 
                double pressureFactor = (node == 0) ? beginNode.PressureFactor : endNode.PressureFactor;
 
                // Adjust the segment for the node's pressure factor
                Vector hitBegin = hitBeginPoint - position;
                Vector hitEnd = hitEndPoint - position;
                if (pressureFactor != 1) 
                {
                    System.Diagnostics.Debug.Assert(DoubleUtil.IsZero(pressureFactor) == false); 
                    hitBegin /= pressureFactor; 
                    hitEnd /= pressureFactor;
                } 
                // Hit-test the node against the segment
                if (true == HitTestPolygonSegment(_vertices, hitBegin, hitEnd))
                {
                    if (node == 0) 
                    {
                        result.BeginFIndex = StrokeFIndices.BeforeFirst; 
                        result.EndFIndex = 0; 
                    }
                    else 
                    {
                        result.EndFIndex = StrokeFIndices.AfterLast;
                        if (beginNode.IsEmpty)
                        { 
                            result.BeginFIndex = StrokeFIndices.BeforeFirst;
                        } 
                        else if (result.BeginFIndex != StrokeFIndices.BeforeFirst) 
                        {
                            result.BeginFIndex = 1; 
                        }
                    }
                }
            } 

            // If both nodes are hit, return. 
            if (result.IsFull) 
            {
                return result; 
            }
            // If there's no hit at all, return.
            if (result.IsEmpty && (quad.IsEmpty || !HitTestQuadSegment(quad, hitBeginPoint, hitEndPoint)))
            { 
                return result;
            } 
 
            // The segments do intersect. Find findices on the ink segment to cut it at.
            if (result.BeginFIndex != StrokeFIndices.BeforeFirst) 
            {
                // The begin node is not hit, i.e. the begin findex is on this spine segment, find it.
                result.BeginFIndex = ClipTest(
                    (endNode.Position - beginNode.Position) / beginNode.PressureFactor, 
                    (endNode.PressureFactor / beginNode.PressureFactor) - 1,
                    (hitBeginPoint - beginNode.Position) / beginNode.PressureFactor, 
                    (hitEndPoint - beginNode.Position) / beginNode.PressureFactor); 
            }
 
            if (result.EndFIndex != StrokeFIndices.AfterLast)
            {
                // The end node is not hit, i.e. the end findex is on this spine segment, find it.
                result.EndFIndex = 1 - ClipTest( 
                    (beginNode.Position - endNode.Position) / endNode.PressureFactor,
                    (beginNode.PressureFactor / endNode.PressureFactor) - 1, 
                    (hitBeginPoint - endNode.Position) / endNode.PressureFactor, 
                    (hitEndPoint - endNode.Position) / endNode.PressureFactor);
            } 

            if (IsInvalidCutTestResult(result))
            {
                return StrokeFIndices.Empty; 
            }
 
            return result; 
        }
 
        /// 
        /// CutTest
        /// 
        /// Begin node of the stroke segment to hit-test. Can be empty (none) 
        /// End node of the stroke segment
        /// Pre-computed quadrangle connecting the two nodes. 
        /// Can be empty if the begion node is empty or when one node is entirely inside the other 
        /// a collection of basic segments outlining the hitting contour
        ///  
        internal virtual StrokeFIndices CutTest(
            StrokeNodeData beginNode, StrokeNodeData endNode, Quad quad, IEnumerable hitContour)
        {
            if (beginNode.IsEmpty) 
            {
                if (HitTest(beginNode, endNode, quad, hitContour) == true) 
                { 
                    return StrokeFIndices.Full;
                } 
                return StrokeFIndices.Empty;
            }

            StrokeFIndices result = StrokeFIndices.Empty; 
            bool isInside = true;
            Vector spineVector = (endNode.Position - beginNode.Position) / beginNode.PressureFactor; 
            Vector spineVectorReversed = (beginNode.Position - endNode.Position) / endNode.PressureFactor; 
            double pressureDelta = (endNode.PressureFactor / beginNode.PressureFactor) - 1;
            double pressureDeltaReversed = (beginNode.PressureFactor / endNode.PressureFactor) - 1; 

            foreach (ContourSegment hitSegment in hitContour)
            {
                // NTRAID#Window OS bug-1029694-2004/10/19-xiaotu, refactor the code to make it a method 
                // to increase the maintainability of the program. FxCop bug.
 
                // First, find out if hitSegment intersects with either of the ink nodes 
                bool isHit = HitTestStrokeNodes(hitSegment,beginNode,endNode, ref result);
 
                // If both nodes are hit, return.
                if (result.IsFull)
                {
                    return result; 
                }
 
                // If neither of the nodes is hit, hit-test the connecting quad 
                if (isHit == false)
                { 
                    // If neither of the nodes is hit and the contour of one node is entirely
                    // inside the contour of the other node, then done with this hitting segment
                    if (!quad.IsEmpty)
                    { 
                        isHit = hitSegment.IsArc
                             ? HitTestQuadCircle(quad, hitSegment.Begin + hitSegment.Radius, hitSegment.Radius) 
                             : HitTestQuadSegment(quad, hitSegment.Begin, hitSegment.End); 
                    }
 
                    if (isHit == false)
                    {
                        if (isInside == true)
                        { 
                            isInside = hitSegment.IsArc
                                ? (WhereIsVectorAboutArc(endNode.Position - hitSegment.Begin - hitSegment.Radius, 
                                    -hitSegment.Radius, hitSegment.Vector - hitSegment.Radius) != HitResult.Hit) 
                                : (WhereIsVectorAboutVector(
                                    endNode.Position - hitSegment.Begin, hitSegment.Vector) == HitResult.Right); 
                        }
                        continue;
                    }
                } 

                isInside = false; 
 
                // NTRAID#Window OS bug-1029694-2004/10/15-xiaotu, refactor the code to make it a new method
                // CalculateClipLocation to increase the maintainability of the program. FxCop bug. 

                // If the begin node is not hit, find the begin findex on the ink segment to cut it at
                if (!DoubleUtil.AreClose(result.BeginFIndex, StrokeFIndices.BeforeFirst))
                { 
                    double findex = CalculateClipLocation(hitSegment, beginNode, spineVector, pressureDelta);
                    if (findex != StrokeFIndices.BeforeFirst) 
                    { 
                        System.Diagnostics.Debug.Assert(findex >= 0 && findex <= 1);
                        if (result.BeginFIndex > findex) 
                        {
                            result.BeginFIndex = findex;
                        }
                    } 
                }
 
                // If the end node is not hit, find the end findex on the ink segment to cut it at 
                if (!DoubleUtil.AreClose(result.EndFIndex, StrokeFIndices.AfterLast))
                { 
                    double findex = CalculateClipLocation(hitSegment, endNode, spineVectorReversed, pressureDeltaReversed);
                    if (findex != StrokeFIndices.BeforeFirst)
                    {
                        System.Diagnostics.Debug.Assert(findex >= 0 && findex <= 1); 
                        findex = 1 - findex;
                        if (result.EndFIndex < findex) 
                        { 
                            result.EndFIndex = findex;
                        } 
                    }
                }
            }
 
            if (DoubleUtil.AreClose(result.BeginFIndex, StrokeFIndices.AfterLast))
            { 
                if (!DoubleUtil.AreClose(result.EndFIndex, StrokeFIndices.BeforeFirst)) 
                {
                    result.BeginFIndex = StrokeFIndices.BeforeFirst; 
                }
            }
            else if (DoubleUtil.AreClose(result.EndFIndex, StrokeFIndices.BeforeFirst))
            { 
                result.EndFIndex = StrokeFIndices.AfterLast;
            } 
 
            if (IsInvalidCutTestResult(result))
            { 
                return StrokeFIndices.Empty;
            }

            return (result.IsEmpty && isInside) ? StrokeFIndices.Full : result; 
        }
 
        ///  
        /// Cutting ink with polygonal tip shapes with a linear segment
        ///  
        /// Vector representing the starting and ending point for the inking
        ///             segment
        /// Represents the difference in the node size for startNode and endNode.
        ///              pressureDelta = (endNode.PressureFactor / beginNode.PressureFactor) - 1 
        /// Start point of the hitting segment
        /// End point of the hitting segment 
        /// a double representing the point of clipping 
        private double ClipTest(Vector spineVector, double pressureDelta, Vector hitBegin, Vector hitEnd)
        { 
            // Let's represent the vertices for the startNode are N1, N2, ..., Ni and for the endNode, M1, M2,
            // ..., Mi.
            // When ink tip shape is a convex polygon, one may iterate in a constant direction
            // (for instance, clockwise) through the edges of the polygon P1 and hit test the cutting segment 
            // against quadrangles NIMIMI+1NI+1 with MI on the left side off the vector NINI+1.
            // If the cutting segment intersects the quadrangle, on the intersected part of the segment, 
            // one may then find point Q (the nearest to the line NINI+1) and point QP 
            // (the point of the intersection of the segment NIMI and vector NI+1NI started at Q).
            // Next, 
            //                      QP = NI + s * LengthOf(MI - NI)                         (1)
            //                      s = LengthOf(QP - NI ) / LengthOf(MI - NI).                     (2)
            // If the cutting segment intersects more than one quadrant, one may then use the smallest s
            // to find the split point: 
            //                      S = P1 + s * LengthOf(P2 - P1)                          (3)
            double findex = StrokeFIndices.AfterLast; 
            Vector hitVector = hitEnd - hitBegin; 
            Vector lastVertex = _vertices[_vertices.Length - 1];
 
            // Note the definition of pressureDelta = (endNode.PressureFactor / beginNode.PressureFactor) - 1
            // So the equation below gives
            //   nextNode = spineVector + (endNode.PressureFactor / beginNode.PressureFactor)*lastVertex - lastVertex
            // As a result, nextNode is a Vector pointing from lastVertex of the beginNode to the correspoinding "lastVertex" 
            // of the endNode.
            Vector nextNode = spineVector + lastVertex * pressureDelta; 
            bool testNextEdge = false; 

            for (int k = 0, count = _vertices.Length; k < count || (k == count && testNextEdge); k++) 
            {
                Vector vertex = _vertices[k % count];
                Vector nextVertex = vertex - lastVertex;
 
                // Point from vertex in beginNode to the corresponding "vertex" in endNode
                Vector nextVertexNextNode = spineVector + (vertex * pressureDelta); 
 
                // Find out a "nextNode" on the endNode (nextNode) that is on the left side off the vector
                // (lastVertex, vertex). 
                if ((DoubleUtil.IsZero(nextNode.X) && DoubleUtil.IsZero(nextNode.Y)) ||
                    (!testNextEdge && (HitResult.Left != WhereIsVectorAboutVector(nextNode, nextVertex))))
                {
                    lastVertex = vertex; 
                    nextNode = nextVertexNextNode;
                    continue; 
                } 

                // Now we need to do hit testing of the hitting segment against quarangle (NI, MI, MI+1, NI+1), 
                // that is, (lastVertex, nextNode, nextVertexNextNode, vertex)

                testNextEdge = false;
                HitResult hit = HitResult.Left; 
                int side = 0;
                for (int i = 0; i < 2; i++) 
                { 
                    Vector hitPoint = ((0 == i) ? hitBegin : hitEnd) - lastVertex;
 
                    hit = WhereIsVectorAboutVector(hitPoint, nextNode);
                    if (hit == HitResult.Hit)
                    {
                        double r = (Math.Abs(nextNode.X) < Math.Abs(nextNode.Y)) //DoubleUtil.IsZero(nextNode.X) 
                            ? (hitPoint.Y / nextNode.Y)
                            : (hitPoint.X / nextNode.X); 
                        if ((findex > r) && DoubleUtil.IsBetweenZeroAndOne(r)) 
                        {
                            findex = r; 
                        }
                    }
                    else if (hit == HitResult.Right)
                    { 
                         side++;
                        if (HitResult.Left == WhereIsVectorAboutVector( 
                            hitPoint - nextVertex, nextVertexNextNode)) 
                        {
                            double r = GetPositionBetweenLines(nextVertex, nextNode, hitPoint); 
                            if ((findex > r) && DoubleUtil.IsBetweenZeroAndOne(r))
                            {
                                findex = r;
                            } 
                        }
                        else 
                        { 
                            testNextEdge = true;
                        } 
                    }
                    else
                    {
                        side--; 
                    }
                } 
 
                //
                if (0 == side) 
                {
                    if (hit == HitResult.Hit)
                    {
                        // This segment is collinear with the edge connecting the nodes, 
                        // no need to hit-test the other edges.
                        System.Diagnostics.Debug.Assert(true == DoubleUtil.IsBetweenZeroAndOne(findex)); 
                        break; 
                    }
                    // The hitting segment intersects the line of the edge connecting 
                    // the nodes. Find the findex of the intersection point.
                    double det = -Vector.Determinant(nextNode, hitVector);
                    if (DoubleUtil.IsZero(det) == false)
                    { 
                        double s = Vector.Determinant(hitVector, hitBegin - lastVertex) / det;
                        if ((findex > s) && DoubleUtil.IsBetweenZeroAndOne(s)) 
                        { 
                            findex = s;
                        } 
                    }
                }
                //
                lastVertex = vertex; 
                nextNode = nextVertexNextNode;
            } 
            return AdjustFIndex(findex); 
        }
 
        /// 
        /// Clip-Testing a polygonal inking segment against an arc (circle)
        /// 
        /// Vector representing the starting and ending point for the inking 
        ///             segment
        /// Represents the difference in the node size for startNode and endNode. 
        ///              pressureDelta = (endNode.PressureFactor / beginNode.PressureFactor) - 1 
        /// The center of the hitting circle
        /// The radius of the hitting circle 
        /// a double representing the point of clipping
        private double ClipTestArc(Vector spineVector, double pressureDelta, Vector hitCenter, Vector hitRadius)
        {
            // NTRAID#WINDOWS-1448096-2006/1/9-SAMGEO, this code is not called, but will be in VNext 
            throw new NotImplementedException();
            /* 
            double findex = StrokeFIndices.AfterLast; 

            double radiusSquared = hitRadius.LengthSquared; 
            Vector vertex, lastVertex = _vertices[_vertices.Length - 1];
            Vector nextVertexNextNode, nextNode = spineVector + lastVertex * pressureDelta;
            bool testNextEdge = false;
 
            for (int k = 0, count = _vertices.Length;
                k < count || (k == count && testNextEdge); 
                k++, lastVertex = vertex, nextNode = nextVertexNextNode) 
            {
                vertex = _vertices[k % count]; 
                Vector nextVertex = vertex - lastVertex;
                nextVertexNextNode = spineVector + (vertex * pressureDelta);

                if (DoubleUtil.IsZero(nextNode.X) && DoubleUtil.IsZero(nextNode.Y)) 
                {
                    continue; 
                } 

                bool testConnectingEdge = false; 

                if (HitResult.Left == WhereIsVectorAboutVector(nextNode, nextVertex))
                {
                    testNextEdge = false; 

                    Vector normal = GetProjection(lastVertex - hitCenter, vertex - hitCenter); 
                    if (radiusSquared <= normal.LengthSquared) 
                    {
                        if (WhereIsVectorAboutVector(hitCenter - lastVertex, nextVertex) == HitResult.Left) 
                        {
                            Vector hitPoint = hitCenter + (normal * Math.Sqrt(radiusSquared / normal.LengthSquared));
                            if (HitResult.Right == WhereIsVectorAboutVector(hitPoint - vertex, nextVertexNextNode))
                            { 
                                testNextEdge = true;
                            } 
                            else if (HitResult.Left == WhereIsVectorAboutVector(hitPoint - lastVertex, nextNode)) 
                            {
                                testConnectingEdge = true; 
                            }
                            else
                            {
                                // this is it 
                                findex = GetPositionBetweenLines(nextVertex, nextNode, hitPoint - lastVertex);
                                System.Diagnostics.Debug.Assert(DoubleUtil.IsBetweenZeroAndOne(findex)); 
                                break; 
                            }
                        } 
                    }
                    else if (HitResult.Right == WhereIsVectorAboutVector(hitCenter + normal - lastVertex, nextNode))
                    {
                        testNextEdge = true; 
                    }
                    else 
                    { 
                        testConnectingEdge = true;
                    } 
                }
                else if (testNextEdge == true)
                {
                    testNextEdge = false; 
                    testConnectingEdge = true;
                } 
 
                if (testConnectingEdge)
                { 
                    // Find out the projection of hitCenter on nextNode
                    Vector v = lastVertex - hitCenter;
                    double findexNearest = GetProjectionFIndex(v, v + nextNode);
 
                    if (findexNearest > 0)
                    { 
                        Vector nearest = nextNode * findexNearest; 
                        double squaredDistanceFromNearestToHitPoint = radiusSquared - (nearest + v).LengthSquared;
                        if (DoubleUtil.IsZero(squaredDistanceFromNearestToHitPoint) && (findexNearest <= 1)) 
                        {
                            if (findexNearest < findex)
                            {
                                findex = findexNearest; 
                            }
                        } 
                        else if ((squaredDistanceFromNearestToHitPoint > 0) 
                            && (nearest.LengthSquared >= squaredDistanceFromNearestToHitPoint))
                        { 
                            double hitPointFIndex = findexNearest - Math.Sqrt(
                                squaredDistanceFromNearestToHitPoint / nextNode.LengthSquared);
                            System.Diagnostics.Debug.Assert(DoubleUtil.GreaterThanOrClose(hitPointFIndex, 0));
                            if (hitPointFIndex < findex) 
                            {
                                findex = hitPointFIndex; 
                            } 
                        }
                    } 
                }
            }

            return AdjustFIndex(findex); 
            */
        } 
 
        /// 
        /// Internal access to __vertices 
        /// 
        /// 
        internal Vector[] GetVertices()
        { 
            return _vertices;
        } 
 
        /// 
        /// Helper function to hit-test the biggest node against hitting contour segments 
        /// 
        /// a collection of basic segments outlining the hitting contour
        /// Begin node of the stroke segment to hit-test. Can be empty (none)
        /// End node of the stroke segment 
        /// true if hit; false otherwise
        private bool HitTestPolygonContourSegments( 
            IEnumerable hitContour, StrokeNodeData beginNode, StrokeNodeData endNode) 
        {
            bool isHit = false; 

            // The bool variable isInside is used here to track that case. It answers to
            // 'Is ink contour inside if the hitting contour?'. It's initialized to 'true"
            // and then verified for each edge of the hitting contour until there's a hit or 
            // until it's false.
            bool isInside = true; 
 
            Point position;
            double pressureFactor; 
            if (beginNode.IsEmpty || endNode.PressureFactor > beginNode.PressureFactor)
            {
                position = endNode.Position;
                pressureFactor = endNode.PressureFactor; 
            }
            else 
            { 
                position = beginNode.Position;
                pressureFactor = beginNode.PressureFactor; 
            }

            // Enumerate through the segments of the hitting contour and test them
            // one by one against the contour of the ink node. 
            foreach (ContourSegment hitSegment in hitContour)
            { 
                if (hitSegment.IsArc) 
                {
                    // Adjust the arc for the node' pressure factor. 
                    Vector hitCenter = hitSegment.Begin + hitSegment.Radius - position;
                    Vector hitRadius = hitSegment.Radius;
                    if (!DoubleUtil.AreClose(pressureFactor, 1d))
                    { 
                        System.Diagnostics.Debug.Assert(DoubleUtil.IsZero(pressureFactor) == false);
                        hitCenter /= pressureFactor; 
                        hitRadius /= pressureFactor; 
                    }
                    // If the segment is an arc, hit-test against the entire circle the arc is part of. 
                    if (true == HitTestPolygonCircle(_vertices, hitCenter, hitRadius))
                    {
                        isHit = true;
                        break; 
                    }
                    // 
                    if (isInside && (WhereIsVectorAboutArc( 
                        position - hitSegment.Begin - hitSegment.Radius,
                        -hitSegment.Radius, hitSegment.Vector - hitSegment.Radius) == HitResult.Hit)) 
                    {
                        isInside = false;
                    }
                } 
                else
                { 
                    // Adjust the segment for the node's pressure factor 
                    Vector hitBegin = hitSegment.Begin - position;
                    Vector hitEnd = hitBegin + hitSegment.Vector; 
                    if (!DoubleUtil.AreClose(pressureFactor, 1d))
                    {
                        System.Diagnostics.Debug.Assert(DoubleUtil.IsZero(pressureFactor) == false);
                        hitBegin /= pressureFactor; 
                        hitEnd /= pressureFactor;
                    } 
                    // Hit-test the node against the segment 
                    if (true == HitTestPolygonSegment(_vertices, hitBegin, hitEnd))
                    { 
                        isHit = true;
                        break;
                    }
                    // 
                    if (isInside && WhereIsVectorAboutVector(
                        position - hitSegment.Begin, hitSegment.Vector) != HitResult.Right) 
                    { 
                        isInside = false;
                    } 
                }
            }
            return (isInside || isHit);
        } 

        ///  
        /// Helper function to HitTest the the hitting contour against the inking contour 
        /// 
        /// a collection of basic segments outlining the hitting contour 
        /// A connecting quad
        /// Begin node of the stroke segment to hit-test. Can be empty (none)
        /// End node of the stroke segment
        /// true if hit; false otherwise 
        private bool HitTestInkContour(
            IEnumerable hitContour, Quad quad, StrokeNodeData beginNode, StrokeNodeData endNode) 
        { 
            System.Diagnostics.Debug.Assert(!quad.IsEmpty);
            bool isHit = false; 

            // When hit-testing a contour against another contour, like in this case,
            // the default implementation checks whether any edge (segment) of the hitting
            // contour intersects with the contour of the ink segment. But this doesn't cover 
            // the case when the ink segment is entirely inside of the hitting segment.
            // The bool variable isInside is used here to track that case. It answers to 
            // 'Is ink contour inside if the hitting contour?'. It's initialized to 'true" 
            // and then verified for each edge of the hitting contour until there's a hit or
            // until it's false. 
            bool isInside = true;

            // The ink connecting quad is not empty, enumerate through the segments of the
            // hitting contour and hit-test them one by one against the ink contour. 
            foreach (ContourSegment hitSegment in hitContour)
            { 
                // Iterate through the vertices of the contour of the ink segment 
                // check where the hit segment is about them, return false if it's
                // on the left side off either of the ink contour segments. 

                Vector hitBegin, hitEnd;
                HitResult hitResult;
 
                // Start with the segment quad.C->quad.D
                if (hitSegment.IsArc) 
                { 
                    hitBegin = hitSegment.Begin + hitSegment.Radius - beginNode.Position;
                    hitEnd = hitSegment.Radius; 
                    hitResult = WhereIsCircleAboutSegment(
                        hitBegin, hitEnd, quad.C - beginNode.Position, quad.D - beginNode.Position);
                }
                else 
                {
                    hitBegin = hitSegment.Begin - beginNode.Position; 
                    hitEnd = hitBegin + hitSegment.Vector; 
                    hitResult = WhereIsSegmentAboutSegment(
                        hitBegin, hitEnd, quad.C - beginNode.Position, quad.D - beginNode.Position); 
                }
                if (HitResult.Left == hitResult)
                {
                    if (isInside) 
                    {
                        isInside = hitSegment.IsArc 
                            ? (WhereIsVectorAboutArc(-hitBegin, -hitSegment.Radius, hitSegment.Vector - hitSegment.Radius) != HitResult.Hit) 
                            : (WhereIsVectorAboutVector(-hitBegin, hitSegment.Vector) == HitResult.Right);
                    } 
                    // This hitSegment is completely outside of the ink contour,
                    // continue with the next one.
                    continue;
                } 

                // Continue clockwise from quad.D to quad.A, then to quad.B, ..., quad.C 
 
                HitResult firstResult = hitResult, lastResult = hitResult;
                double pressureFactor = beginNode.PressureFactor; 

                // Find the index of the vertex that is quad.D
                // Use count var to avoid infinite loop, normally this shouldn't
                // happen but it doesn't hurt to check it just in case. 
                int i = 0, count = _vertices.Length;
                Vector vertex = new Vector(); 
                for (i = 0; i < count; i++) 
                {
                    vertex = _vertices[i] * pressureFactor; 
                    if (DoubleUtil.AreClose((beginNode.Position + vertex), quad.D))
                    {
                        break;
                    } 
                }
                System.Diagnostics.Debug.Assert(i < count); 
 
                int k;
                for (k = 0; k < 2; k++) 
                {
                    count = _vertices.Length;
                    Point nodePosition = (k == 0) ? beginNode.Position : endNode.Position;
                    Point end = (k == 0) ? quad.A : quad.C; 

                    // Iterate over the vertices on 
                    //          beginNode(k=0)from quad.D to quad.A 
                    //    or
                    //          endNode(k=1)from quad.A to quad.B ... to quad.C 
                    while (((nodePosition + vertex) != end) && (count != 0))
                    {
                        // Find out the next vertex
                        i = (i + 1) % _vertices.Length; 
                        Vector nextVertex = _vertices[i] * pressureFactor;
 
                        // Hit-test the hitting segment against the current edge 
                        hitResult = hitSegment.IsArc
                            ? WhereIsCircleAboutSegment(hitBegin, hitEnd, vertex, nextVertex) 
                            : WhereIsSegmentAboutSegment(hitBegin, hitEnd, vertex, nextVertex);

                        if (HitResult.Hit == hitResult)
                        { 
                            return true;  //Got a hit
                        } 
                        if (true == IsOutside(hitResult, lastResult)) 
                        {
                            // This hitSegment is definitely outside the ink contour, drop it. 
                            // Change k to something > 2 to leave the for loop and skip
                            // IsOutside at the bottom
                            k = 3;
                            break; 
                        }
                        lastResult = hitResult; 
                        vertex = nextVertex; 
                        count--;
                    } 
                    System.Diagnostics.Debug.Assert(count > 0);

                    if (k == 0)
                    { 
                        // Make some adjustments for the second one to continue iterating through
                        // quad.AB and the outer segments of endNode up to quad.C 
                        pressureFactor = endNode.PressureFactor; 
                        Vector spineVector = endNode.Position - beginNode.Position;
                        vertex -= spineVector; // now vertex = quad.A - spineVector 
                        hitBegin -= spineVector; // adjust hitBegin to the space of endNode
                        if (hitSegment.IsArc == false)
                        {
                            hitEnd -= spineVector; 
                        }
 
                        // Find the index of the vertex that is quad.B 
                        count = _vertices.Length;
                        while (!DoubleUtil.AreClose((endNode.Position + _vertices[i] * pressureFactor), quad.B) && (count != 0)) 
                        {
                            i = (i + 1) % _vertices.Length;
                            count--;
                        } 
                        System.Diagnostics.Debug.Assert(count > 0);
                        i--; 
                    } 
                }
                if ((k == 2) && (false == IsOutside(firstResult, hitResult))) 
                {
                    isHit = true;
                    break;
                } 
                //
                if (isInside) 
                { 
                    isInside = hitSegment.IsArc
                        ? (WhereIsVectorAboutArc(-hitBegin, -hitSegment.Radius, hitSegment.Vector - hitSegment.Radius) != HitResult.Hit) 
                        : (WhereIsVectorAboutVector(-hitBegin, hitSegment.Vector) == HitResult.Right);
                }
            }
            return (isHit||isInside); 
        }
 
 
        /// 
        /// Helper function to Hit-test against the two stroke nodes only (excluding the connecting quad). 
        /// 
        /// 
        /// 
        ///  
        /// 
        ///  
        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;
        } 

        ///  
        ///  Calculate the clip location 
        /// 
        /// the hitting segment 
        /// begin node
        /// 
        /// 
        /// the clip location. not-clip if return StrokeFIndices.BeforeFirst 
        private double CalculateClipLocation(
            ContourSegment hitSegment, StrokeNodeData beginNode, Vector spineVector, double pressureDelta) 
        { 
            double findex = StrokeFIndices.BeforeFirst;
            bool clipIt = hitSegment.IsArc ? true 
                //? (WhereIsVectorAboutArc(beginNode.Position - hitSegment.Begin - hitSegment.Radius,
                //            -hitSegment.Radius, hitSegment.Vector - hitSegment.Radius) == HitResult.Hit)
                : (WhereIsVectorAboutVector(
                                   beginNode.Position - hitSegment.Begin, hitSegment.Vector) == HitResult.Left); 
            if (clipIt)
            { 
                findex = hitSegment.IsArc 
                    ? ClipTestArc(spineVector, pressureDelta,
                        (hitSegment.Begin + hitSegment.Radius - beginNode.Position) / beginNode.PressureFactor, 
                        hitSegment.Radius / beginNode.PressureFactor)
                    : ClipTest(spineVector, pressureDelta,
                        (hitSegment.Begin - beginNode.Position) / beginNode.PressureFactor,
                        (hitSegment.End - beginNode.Position) / beginNode.PressureFactor); 

                // NTRAID#WINDOWS-1384646-2005/11/17-WAYNEZEN, 
                // ClipTest returns StrokeFIndices.AfterLast to indicate a false hit test. 
                // But the caller CutTest expects StrokeFIndices.BeforeFirst when there is no hit.
                if ( findex == StrokeFIndices.AfterLast ) 
                {
                    findex = StrokeFIndices.BeforeFirst;
                }
                else 
                {
                    System.Diagnostics.Debug.Assert(findex >= 0 && findex <= 1); 
                } 
            }
            return findex; 
        }

        /// 
        /// Helper method used to determine if we came up with a bogus result during hit testing 
        /// 
        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;
        }
 
        #endregion
 
        #region Instance data 

        // Shape parameters 
        private Rect        _shapeBounds = Rect.Empty;
        protected Vector[]    _vertices;

        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------ 
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
//----------------------------------------------------------------------- 
using System;
using System.Collections.Generic; 
using System.Windows; 
using System.Windows.Ink;
using System.Windows.Media; 
using System.Windows.Input;
using System.Diagnostics;
using MS.Utility;
using MS.Internal; 

namespace MS.Internal.Ink 
{ 
    /// 
    /// The base operations class that implements polygonal node operations by default. 
    /// 
    internal partial class StrokeNodeOperations
    {
        #region Static API 

        ///  
        /// 
        /// 
        ///  
        /// 
        internal static StrokeNodeOperations CreateInstance(StylusShape nodeShape)
        {
            if (nodeShape == null) 
            {
                throw new ArgumentNullException("nodeShape"); 
            } 
            if (nodeShape.IsEllipse)
            { 
                return new EllipticalNodeOperations(nodeShape);
            }
            return new StrokeNodeOperations(nodeShape);
        } 
        #endregion
 
        #region API 

        ///  
        /// Constructor
        /// 
        /// shape of the nodes
        internal StrokeNodeOperations(StylusShape nodeShape) 
        {
            System.Diagnostics.Debug.Assert(nodeShape != null); 
            _vertices = nodeShape.GetVerticesAsVectors(); 
        }
 
        /// 
        /// This is probably not the best (design-wise) but the cheapest way to tell
        /// EllipticalNodeOperations from all other implementations of node operations.
        ///  
        internal virtual bool IsNodeShapeEllipse { get { return false; } }
 
        ///  
        /// Computes the bounds of a node
        ///  
        /// node to compute bounds of
        /// bounds of the node
        internal Rect GetNodeBounds(StrokeNodeData node)
        { 
            if (_shapeBounds.IsEmpty)
            { 
                int i; 
                for (i = 0; (i + 1) < _vertices.Length; i += 2)
                { 
                    _shapeBounds.Union(new Rect((Point)_vertices[i], (Point)_vertices[i + 1]));
                }
                if (i < _vertices.Length)
                { 
                    _shapeBounds.Union((Point)_vertices[i]);
                } 
            } 

            Rect boundingBox = _shapeBounds; 
            System.Diagnostics.Debug.Assert((boundingBox.X <= 0) && (boundingBox.Y <= 0));

            double pressureFactor = node.PressureFactor;
            if (!DoubleUtil.AreClose(pressureFactor,1d)) 
            {
                boundingBox = new Rect( 
                    _shapeBounds.X * pressureFactor, 
                    _shapeBounds.Y * pressureFactor,
                    _shapeBounds.Width * pressureFactor, 
                    _shapeBounds.Height * pressureFactor);
            }

            boundingBox.Location += (Vector)node.Position; 

            return boundingBox; 
        } 

        internal void GetNodeContourPoints(StrokeNodeData node, List pointBuffer) 
        {
            double pressureFactor = node.PressureFactor;
            if (DoubleUtil.AreClose(pressureFactor, 1d))
            { 
                for (int i = 0; i < _vertices.Length; i++)
                { 
                    pointBuffer.Add(node.Position + _vertices[i]); 
                }
            } 
            else
            {
                for (int i = 0; i < _vertices.Length; i++)
                { 
                    pointBuffer.Add(node.Position + (_vertices[i] * pressureFactor));
                } 
            } 
        }
 
        /// 
        /// Returns an enumerator for edges of the contour comprised by a given node
        /// and its connecting quadrangle.
        /// Used for hit-testing a stroke against an other stroke (stroke and point erasing) 
        /// 
        /// node 
        /// quadrangle connecting the node to the preceeding node 
        /// contour segments enumerator
        internal virtual IEnumerable GetContourSegments(StrokeNodeData node, Quad quad) 
        {
            System.Diagnostics.Debug.Assert(node.IsEmpty == false);

            if (quad.IsEmpty) 
            {
                Point vertex = node.Position + (_vertices[_vertices.Length - 1] * node.PressureFactor); 
                for (int i = 0; i < _vertices.Length; i++) 
                {
                    Point nextVertex = node.Position + (_vertices[i] * node.PressureFactor); 
                    yield return new ContourSegment(vertex, nextVertex);
                    vertex = nextVertex;
                }
            } 
            else
            { 
                yield return new ContourSegment(quad.A, quad.B); 

                for (int i = 0, count = _vertices.Length; i < count; i++) 
                {
                    Point vertex = node.Position + (_vertices[i] * node.PressureFactor);
                    if (vertex == quad.B)
                    { 
                        for (int j = 0; (j < count) && (vertex != quad.C); j++)
                        { 
                            i = (i + 1) % count; 
                            Point nextVertex = node.Position + (_vertices[i] * node.PressureFactor);
                            yield return new ContourSegment(vertex, nextVertex); 
                            vertex = nextVertex;
                        }
                        break;
                    } 
                }
 
                yield return new ContourSegment(quad.C, quad.D); 
                yield return new ContourSegment(quad.D, quad.A);
            } 
        }

        /// 
        /// ISSUE-2004/06/15- temporary workaround to avoid hit-testing ellipses with ellipses 
        /// 
        ///  
        ///  
        /// 
        internal virtual IEnumerable GetNonBezierContourSegments(StrokeNodeData beginNode, StrokeNodeData endNode) 
        {
            Quad quad = beginNode.IsEmpty ? Quad.Empty : GetConnectingQuad(beginNode, endNode);
            return GetContourSegments(endNode, quad);
        } 

 
        ///  
        /// Finds connecting points for a pair of stroke nodes (of a polygonal shape)
        ///  
        /// a node to connect
        /// another node, next to beginNode
        /// connecting quadrangle, that can be empty if one node is inside the other
        internal virtual Quad GetConnectingQuad(StrokeNodeData beginNode, StrokeNodeData endNode) 
        {
            // Return an empty quad if either of the nodes is empty (not a node) 
            // or if both nodes are at the same position. 
            if (beginNode.IsEmpty || endNode.IsEmpty || DoubleUtil.AreClose(beginNode.Position, endNode.Position))
            { 
                return Quad.Empty;
            }

            // By definition, Quad's vertices (A,B,C,D) are ordered clockwise with points A and D located 
            // on the beginNode and B and C on the endNode. Basically, we're looking for segments AB and CD.
            // We iterate through the vertices of the beginNode, at each vertex we analyze location of the 
            // connecting segment relative to the node's edges at the vertex, and enforce these rules: 
            //  - if the vector of the connecting segment at a vertex V[i] is on the left from vector V[i]V[i+1]
            //    and not on the left from vector V[i-1]V[i], then it's the AB segment of the quad (V[i] == A). 
            //  - if the vector of the connecting segment at a vertex V[i] is on the left from vector V[i-1]V[i]
            //    and not on the left from vector V[i]V[i+1], then it's the CD segment of the quad (V[i] == D).
            //
 
            Quad quad = Quad.Empty;
            bool foundAB = false, foundCD = false; 
 
            // There's no need to build shapes of the two nodes in order to find their connecting quad.
            // It's the spine vector between the nodes and their scaling diff (pressure delta) is all 
            // that matters here.
            Vector spine = endNode.Position - beginNode.Position;
            double pressureDelta = endNode.PressureFactor - beginNode.PressureFactor;
 
            // Iterate through the vertices of the default shape
            int count = _vertices.Length; 
            for (int i = 0, j = count - 1; i < count; i++, j = ((j + 1) % count)) 
            {
                // Compute vector of the connecting segment at the vertex [i] 
                Vector connection = spine + _vertices[i] * pressureDelta;
                if ((pressureDelta != 0) && (connection.X == 0) && (connection.Y == 0))
                {
                    // One of the nodes,                       |----| 
                    // as well as the connecting quad,         |__  |
                    // is entirely inside the other node.      |  | | 
                    //                                 [i] --> |__|_| 
                    return Quad.Empty;
                } 

                // Find out where this vector is about the node edge [i][i+1]
                // (The vars names "goingTo" and "comingFrom" refer direction of the line defined
                // by the connecting vector applied at vertex [i], relative to the contour of the node shape. 
                // Using these terms, (comingFrom != Right && goingTo == Left) corresponds to the segment AB,
                // and (comingFrom == Right && goingTo != Left) describes the DC. 
                HitResult goingTo = WhereIsVectorAboutVector(connection, _vertices[(i + 1) % count] - _vertices[i]); 

                if (goingTo == HitResult.Left) 
                {
                    if (false == foundAB)
                    {
                        // Find out where the node edge [i-1][i] is about the connecting vector 
                        HitResult comingFrom = WhereIsVectorAboutVector(_vertices[i] - _vertices[j], connection);
                        if (HitResult.Right != comingFrom) 
                        { 
                            foundAB = true;
                            quad.A = beginNode.Position + _vertices[i] * beginNode.PressureFactor; 
                            quad.B = endNode.Position + _vertices[i] * endNode.PressureFactor;
                            if (true == foundCD)
                            {
                                // Found all 4 points. Break out from the 'for' loop. 
                                break;
                            } 
                        } 
                    }
                } 
                else
                {
                    if (false == foundCD)
                    { 
                        // Find out where the node edge [i-1][i] is about the connecting vector
                        HitResult comingFrom = WhereIsVectorAboutVector(_vertices[i] - _vertices[j], connection); 
                        if (HitResult.Right == comingFrom) 
                        {
                            foundCD = true; 
                            quad.C = endNode.Position + _vertices[i] * endNode.PressureFactor;
                            quad.D = beginNode.Position + _vertices[i] * beginNode.PressureFactor;
                            if (true == foundAB)
                            { 
                                // Found all 4 points. Break out from the 'for' loop.
                                break; 
                            } 
                        }
                    } 
                }
            }

            if (!foundAB || !foundCD ||   // (2) 
                ((pressureDelta != 0) && Vector.Determinant(quad.B - quad.A, quad.D - quad.A) == 0)) // (1)
            { 
                //                                          _____        _______ 
                // One of the nodes,                    (1) |__  |   (2) | ___  |
                // as well as the connecting quad,          |  | |       | |  | | 
                // is entirely inside the other node.       |__| |       | |__| |
                //                                          |____|       |___ __|
                return Quad.Empty;
            } 

            return quad; 
        } 

        ///  
        /// Hit-tests ink segment defined by two nodes against a linear segment.
        /// 
        /// Begin node of the ink segment
        /// End node of the ink segment 
        /// Pre-computed quadrangle connecting the two ink nodes
        /// Begin point of the hitting segment 
        /// End point of the hitting segment 
        /// true if there's intersection, false otherwise
        internal virtual bool HitTest( 
            StrokeNodeData beginNode, StrokeNodeData endNode, Quad quad, Point hitBeginPoint, Point hitEndPoint)
        {
            // Check for special cases when the endNode is the very first one (beginNode.IsEmpty)
            // or one node is completely inside the other. In either case the connecting quad 
            // would be Empty and we need to hit-test against the biggest node (the one with
            // the greater PressureFactor) 
            if (quad.IsEmpty) 
            {
                Point position; 
                double pressureFactor;
                if (beginNode.IsEmpty || (endNode.PressureFactor > beginNode.PressureFactor))
                {
                    position = endNode.Position; 
                    pressureFactor = endNode.PressureFactor;
                } 
                else 
                {
                    position = beginNode.Position; 
                    pressureFactor = beginNode.PressureFactor;
                }

                // Find the coordinates of the hitting segment relative to the ink node 
                Vector hitBegin = hitBeginPoint - position, hitEnd = hitEndPoint - position;
                if (pressureFactor != 1) 
                { 
                    // Instead of applying pressure to the node, do reverse scaling on
                    // the hitting segment. This allows us use the original array of vertices 
                    // in hit-testing.
                    System.Diagnostics.Debug.Assert(DoubleUtil.IsZero(pressureFactor) == false);
                    hitBegin /= pressureFactor;
                    hitEnd /= pressureFactor; 
                }
                return HitTestPolygonSegment(_vertices, hitBegin, hitEnd); 
            } 
            else
            { 
                // Iterate through the vertices of the contour of the ink segment
                // check where the hitting segment is about them, return false if it's
                // on the outer (left) side of the ink contour. This implementation might
                // look more complex than straightforward separated hit-testing of three 
                // polygons (beginNode, quad, endNode), but it's supposed to be more optimal
                // because the number of edges it hit-tests is approximately twice less 
                // than with the straightforward implementation. 

                // Start with the segment quad.C->quad.D 
                Vector hitBegin = hitBeginPoint - beginNode.Position;
                Vector hitEnd = hitEndPoint - beginNode.Position;
                HitResult hitResult = WhereIsSegmentAboutSegment(
                    hitBegin, hitEnd, quad.C - beginNode.Position, quad.D - beginNode.Position); 
                if (HitResult.Left == hitResult)
                { 
                    return false; 
                }
 
                // Continue clockwise from quad.D to quad.C

                HitResult firstResult = hitResult, lastResult = hitResult;
                double pressureFactor = beginNode.PressureFactor; 

                // Find the index of the vertex that is quad.D 
                // Use count var to avoid infinite loop, normally it shouldn't 
                // happen but it doesn't hurt to check it just in case.
                int i = 0, count = _vertices.Length; 
                Vector vertex = new Vector();
                for (i = 0; i < count; i++)
                {
                    vertex = _vertices[i] * pressureFactor; 
                    // Here and in a few more places down the code, when comparing
                    // a quad's vertex vs a scaled shape vertex, it's important to 
                    // compute them the same way as in GetConnectingQuad, so that not 
                    // hit that double's computation error. For instance, sometimes the
                    // expression (vertex == quad.D - beginNode.Position) gives 'false' 
                    // while the expression below gives 'true'. (Another workaround is to
                    // use DoubleUtil.AreClose but that;d be less performant)
                    if ((beginNode.Position + vertex) == quad.D)
                    { 
                        break;
                    } 
                } 
                System.Diagnostics.Debug.Assert(count > 0);
                // This loop does the iteration thru the edges of the ink segment 
                // clockwise from quad.D to quad.C.
                for (int node = 0; node < 2; node++)
                {
                    Point nodePosition = (node == 0) ? beginNode.Position : endNode.Position; 
                    Point end = (node == 0) ? quad.A : quad.C;
 
                    count = _vertices.Length; 
                    while (((nodePosition + vertex) != end) && (count != 0))
                    { 
                        i = (i + 1) % _vertices.Length;
                        Vector nextVertex = (pressureFactor == 1) ? _vertices[i] : (_vertices[i] * pressureFactor);
                        hitResult = WhereIsSegmentAboutSegment(hitBegin, hitEnd, vertex, nextVertex);
                        if (HitResult.Hit == hitResult) 
                        {
                            return true; 
                        } 
                        if (true == IsOutside(hitResult, lastResult))
                        { 
                            return false;
                        }
                        lastResult = hitResult;
                        vertex = nextVertex; 
                        count--;
                    } 
                    System.Diagnostics.Debug.Assert(count > 0); 

                    if (node == 0) 
                    {
                        // The first iteration is done thru the outer segments of beginNode
                        // and ends at quad.A, for the second one make some adjustments
                        // to continue iterating through quad.AB and the outer segments of 
                        // endNode up to quad.C
                        pressureFactor = endNode.PressureFactor; 
 
                        Vector spineVector = endNode.Position - beginNode.Position;
                        vertex -= spineVector; 
                        hitBegin -= spineVector;
                        hitEnd -= spineVector;

                        // Find the index of the vertex that is quad.B 
                        count = _vertices.Length;
                        while (((endNode.Position + _vertices[i] * pressureFactor) != quad.B) && (count != 0)) 
                        { 
                            i = (i + 1) % _vertices.Length;
                            count--; 
                        }
                        System.Diagnostics.Debug.Assert(count > 0);
                        i--;
                    } 
                }
                return (false == IsOutside(firstResult, hitResult)); 
            } 
        }
 
        /// 
        /// Hit-tests a stroke segment defined by two nodes against another stroke segment.
        /// 
        /// Begin node of the stroke segment to hit-test. Can be empty (none) 
        /// End node of the stroke segment
        /// Pre-computed quadrangle connecting the two nodes. 
        /// Can be empty if the begion node is empty or when one node is entirely inside the other 
        /// a collection of basic segments outlining the hitting contour
        /// true if the contours intersect or overlap 
        internal virtual bool HitTest(
            StrokeNodeData beginNode, StrokeNodeData endNode, Quad quad, IEnumerable hitContour)
        {
            // Check for special cases when the endNode is the very first one (beginNode.IsEmpty) 
            // or one node is completely inside the other. In either case the connecting quad
            // would be Empty and we need to hittest against the biggest node (the one with 
            // the greater PressureFactor) 
            if (quad.IsEmpty)
            { 
                // NTRAID#Window OS bug-1029694-2004/10/15-xiaotu, refactor the code to make it a method
                // to increase the maintainability of the program. FxCop bug.

                // Make a call to hit-test the biggest node the hitting contour. 
                return HitTestPolygonContourSegments(hitContour, beginNode, endNode);
            } 
            else 
            {
                // NTRAID#Window OS bug-1029694-2004/10/15-xiaotu, refactor the code to make it a method 
                // to increase the maintainability of the program. FxCop bug.

                // HitTest the the hitting contour against the inking contour
                return HitTestInkContour(hitContour, quad, beginNode, endNode); 
            }
        } 
 
        /// 
        /// Hit-tests ink segment defined by two nodes against a linear segment. 
        /// 
        /// Begin node of the ink segment
        /// End node of the ink segment
        /// Pre-computed quadrangle connecting the two ink nodes 
        /// Begin point of the hitting segment
        /// End point of the hitting segment 
        /// Exact location to cut at represented by StrokeFIndices 
        internal virtual StrokeFIndices CutTest(
            StrokeNodeData beginNode, StrokeNodeData endNode, Quad quad, Point hitBeginPoint, Point hitEndPoint) 
        {
            StrokeFIndices result = StrokeFIndices.Empty;

            // First, find out if the hitting segment intersects with either of the ink nodes 
            for (int node = (beginNode.IsEmpty ? 1 : 0); node < 2; node++)
            { 
                Point position = (node == 0) ? beginNode.Position : endNode.Position; 
                double pressureFactor = (node == 0) ? beginNode.PressureFactor : endNode.PressureFactor;
 
                // Adjust the segment for the node's pressure factor
                Vector hitBegin = hitBeginPoint - position;
                Vector hitEnd = hitEndPoint - position;
                if (pressureFactor != 1) 
                {
                    System.Diagnostics.Debug.Assert(DoubleUtil.IsZero(pressureFactor) == false); 
                    hitBegin /= pressureFactor; 
                    hitEnd /= pressureFactor;
                } 
                // Hit-test the node against the segment
                if (true == HitTestPolygonSegment(_vertices, hitBegin, hitEnd))
                {
                    if (node == 0) 
                    {
                        result.BeginFIndex = StrokeFIndices.BeforeFirst; 
                        result.EndFIndex = 0; 
                    }
                    else 
                    {
                        result.EndFIndex = StrokeFIndices.AfterLast;
                        if (beginNode.IsEmpty)
                        { 
                            result.BeginFIndex = StrokeFIndices.BeforeFirst;
                        } 
                        else if (result.BeginFIndex != StrokeFIndices.BeforeFirst) 
                        {
                            result.BeginFIndex = 1; 
                        }
                    }
                }
            } 

            // If both nodes are hit, return. 
            if (result.IsFull) 
            {
                return result; 
            }
            // If there's no hit at all, return.
            if (result.IsEmpty && (quad.IsEmpty || !HitTestQuadSegment(quad, hitBeginPoint, hitEndPoint)))
            { 
                return result;
            } 
 
            // The segments do intersect. Find findices on the ink segment to cut it at.
            if (result.BeginFIndex != StrokeFIndices.BeforeFirst) 
            {
                // The begin node is not hit, i.e. the begin findex is on this spine segment, find it.
                result.BeginFIndex = ClipTest(
                    (endNode.Position - beginNode.Position) / beginNode.PressureFactor, 
                    (endNode.PressureFactor / beginNode.PressureFactor) - 1,
                    (hitBeginPoint - beginNode.Position) / beginNode.PressureFactor, 
                    (hitEndPoint - beginNode.Position) / beginNode.PressureFactor); 
            }
 
            if (result.EndFIndex != StrokeFIndices.AfterLast)
            {
                // The end node is not hit, i.e. the end findex is on this spine segment, find it.
                result.EndFIndex = 1 - ClipTest( 
                    (beginNode.Position - endNode.Position) / endNode.PressureFactor,
                    (beginNode.PressureFactor / endNode.PressureFactor) - 1, 
                    (hitBeginPoint - endNode.Position) / endNode.PressureFactor, 
                    (hitEndPoint - endNode.Position) / endNode.PressureFactor);
            } 

            if (IsInvalidCutTestResult(result))
            {
                return StrokeFIndices.Empty; 
            }
 
            return result; 
        }
 
        /// 
        /// CutTest
        /// 
        /// Begin node of the stroke segment to hit-test. Can be empty (none) 
        /// End node of the stroke segment
        /// Pre-computed quadrangle connecting the two nodes. 
        /// Can be empty if the begion node is empty or when one node is entirely inside the other 
        /// a collection of basic segments outlining the hitting contour
        ///  
        internal virtual StrokeFIndices CutTest(
            StrokeNodeData beginNode, StrokeNodeData endNode, Quad quad, IEnumerable hitContour)
        {
            if (beginNode.IsEmpty) 
            {
                if (HitTest(beginNode, endNode, quad, hitContour) == true) 
                { 
                    return StrokeFIndices.Full;
                } 
                return StrokeFIndices.Empty;
            }

            StrokeFIndices result = StrokeFIndices.Empty; 
            bool isInside = true;
            Vector spineVector = (endNode.Position - beginNode.Position) / beginNode.PressureFactor; 
            Vector spineVectorReversed = (beginNode.Position - endNode.Position) / endNode.PressureFactor; 
            double pressureDelta = (endNode.PressureFactor / beginNode.PressureFactor) - 1;
            double pressureDeltaReversed = (beginNode.PressureFactor / endNode.PressureFactor) - 1; 

            foreach (ContourSegment hitSegment in hitContour)
            {
                // NTRAID#Window OS bug-1029694-2004/10/19-xiaotu, refactor the code to make it a method 
                // to increase the maintainability of the program. FxCop bug.
 
                // First, find out if hitSegment intersects with either of the ink nodes 
                bool isHit = HitTestStrokeNodes(hitSegment,beginNode,endNode, ref result);
 
                // If both nodes are hit, return.
                if (result.IsFull)
                {
                    return result; 
                }
 
                // If neither of the nodes is hit, hit-test the connecting quad 
                if (isHit == false)
                { 
                    // If neither of the nodes is hit and the contour of one node is entirely
                    // inside the contour of the other node, then done with this hitting segment
                    if (!quad.IsEmpty)
                    { 
                        isHit = hitSegment.IsArc
                             ? HitTestQuadCircle(quad, hitSegment.Begin + hitSegment.Radius, hitSegment.Radius) 
                             : HitTestQuadSegment(quad, hitSegment.Begin, hitSegment.End); 
                    }
 
                    if (isHit == false)
                    {
                        if (isInside == true)
                        { 
                            isInside = hitSegment.IsArc
                                ? (WhereIsVectorAboutArc(endNode.Position - hitSegment.Begin - hitSegment.Radius, 
                                    -hitSegment.Radius, hitSegment.Vector - hitSegment.Radius) != HitResult.Hit) 
                                : (WhereIsVectorAboutVector(
                                    endNode.Position - hitSegment.Begin, hitSegment.Vector) == HitResult.Right); 
                        }
                        continue;
                    }
                } 

                isInside = false; 
 
                // NTRAID#Window OS bug-1029694-2004/10/15-xiaotu, refactor the code to make it a new method
                // CalculateClipLocation to increase the maintainability of the program. FxCop bug. 

                // If the begin node is not hit, find the begin findex on the ink segment to cut it at
                if (!DoubleUtil.AreClose(result.BeginFIndex, StrokeFIndices.BeforeFirst))
                { 
                    double findex = CalculateClipLocation(hitSegment, beginNode, spineVector, pressureDelta);
                    if (findex != StrokeFIndices.BeforeFirst) 
                    { 
                        System.Diagnostics.Debug.Assert(findex >= 0 && findex <= 1);
                        if (result.BeginFIndex > findex) 
                        {
                            result.BeginFIndex = findex;
                        }
                    } 
                }
 
                // If the end node is not hit, find the end findex on the ink segment to cut it at 
                if (!DoubleUtil.AreClose(result.EndFIndex, StrokeFIndices.AfterLast))
                { 
                    double findex = CalculateClipLocation(hitSegment, endNode, spineVectorReversed, pressureDeltaReversed);
                    if (findex != StrokeFIndices.BeforeFirst)
                    {
                        System.Diagnostics.Debug.Assert(findex >= 0 && findex <= 1); 
                        findex = 1 - findex;
                        if (result.EndFIndex < findex) 
                        { 
                            result.EndFIndex = findex;
                        } 
                    }
                }
            }
 
            if (DoubleUtil.AreClose(result.BeginFIndex, StrokeFIndices.AfterLast))
            { 
                if (!DoubleUtil.AreClose(result.EndFIndex, StrokeFIndices.BeforeFirst)) 
                {
                    result.BeginFIndex = StrokeFIndices.BeforeFirst; 
                }
            }
            else if (DoubleUtil.AreClose(result.EndFIndex, StrokeFIndices.BeforeFirst))
            { 
                result.EndFIndex = StrokeFIndices.AfterLast;
            } 
 
            if (IsInvalidCutTestResult(result))
            { 
                return StrokeFIndices.Empty;
            }

            return (result.IsEmpty && isInside) ? StrokeFIndices.Full : result; 
        }
 
        ///  
        /// Cutting ink with polygonal tip shapes with a linear segment
        ///  
        /// Vector representing the starting and ending point for the inking
        ///             segment
        /// Represents the difference in the node size for startNode and endNode.
        ///              pressureDelta = (endNode.PressureFactor / beginNode.PressureFactor) - 1 
        /// Start point of the hitting segment
        /// End point of the hitting segment 
        /// a double representing the point of clipping 
        private double ClipTest(Vector spineVector, double pressureDelta, Vector hitBegin, Vector hitEnd)
        { 
            // Let's represent the vertices for the startNode are N1, N2, ..., Ni and for the endNode, M1, M2,
            // ..., Mi.
            // When ink tip shape is a convex polygon, one may iterate in a constant direction
            // (for instance, clockwise) through the edges of the polygon P1 and hit test the cutting segment 
            // against quadrangles NIMIMI+1NI+1 with MI on the left side off the vector NINI+1.
            // If the cutting segment intersects the quadrangle, on the intersected part of the segment, 
            // one may then find point Q (the nearest to the line NINI+1) and point QP 
            // (the point of the intersection of the segment NIMI and vector NI+1NI started at Q).
            // Next, 
            //                      QP = NI + s * LengthOf(MI - NI)                         (1)
            //                      s = LengthOf(QP - NI ) / LengthOf(MI - NI).                     (2)
            // If the cutting segment intersects more than one quadrant, one may then use the smallest s
            // to find the split point: 
            //                      S = P1 + s * LengthOf(P2 - P1)                          (3)
            double findex = StrokeFIndices.AfterLast; 
            Vector hitVector = hitEnd - hitBegin; 
            Vector lastVertex = _vertices[_vertices.Length - 1];
 
            // Note the definition of pressureDelta = (endNode.PressureFactor / beginNode.PressureFactor) - 1
            // So the equation below gives
            //   nextNode = spineVector + (endNode.PressureFactor / beginNode.PressureFactor)*lastVertex - lastVertex
            // As a result, nextNode is a Vector pointing from lastVertex of the beginNode to the correspoinding "lastVertex" 
            // of the endNode.
            Vector nextNode = spineVector + lastVertex * pressureDelta; 
            bool testNextEdge = false; 

            for (int k = 0, count = _vertices.Length; k < count || (k == count && testNextEdge); k++) 
            {
                Vector vertex = _vertices[k % count];
                Vector nextVertex = vertex - lastVertex;
 
                // Point from vertex in beginNode to the corresponding "vertex" in endNode
                Vector nextVertexNextNode = spineVector + (vertex * pressureDelta); 
 
                // Find out a "nextNode" on the endNode (nextNode) that is on the left side off the vector
                // (lastVertex, vertex). 
                if ((DoubleUtil.IsZero(nextNode.X) && DoubleUtil.IsZero(nextNode.Y)) ||
                    (!testNextEdge && (HitResult.Left != WhereIsVectorAboutVector(nextNode, nextVertex))))
                {
                    lastVertex = vertex; 
                    nextNode = nextVertexNextNode;
                    continue; 
                } 

                // Now we need to do hit testing of the hitting segment against quarangle (NI, MI, MI+1, NI+1), 
                // that is, (lastVertex, nextNode, nextVertexNextNode, vertex)

                testNextEdge = false;
                HitResult hit = HitResult.Left; 
                int side = 0;
                for (int i = 0; i < 2; i++) 
                { 
                    Vector hitPoint = ((0 == i) ? hitBegin : hitEnd) - lastVertex;
 
                    hit = WhereIsVectorAboutVector(hitPoint, nextNode);
                    if (hit == HitResult.Hit)
                    {
                        double r = (Math.Abs(nextNode.X) < Math.Abs(nextNode.Y)) //DoubleUtil.IsZero(nextNode.X) 
                            ? (hitPoint.Y / nextNode.Y)
                            : (hitPoint.X / nextNode.X); 
                        if ((findex > r) && DoubleUtil.IsBetweenZeroAndOne(r)) 
                        {
                            findex = r; 
                        }
                    }
                    else if (hit == HitResult.Right)
                    { 
                         side++;
                        if (HitResult.Left == WhereIsVectorAboutVector( 
                            hitPoint - nextVertex, nextVertexNextNode)) 
                        {
                            double r = GetPositionBetweenLines(nextVertex, nextNode, hitPoint); 
                            if ((findex > r) && DoubleUtil.IsBetweenZeroAndOne(r))
                            {
                                findex = r;
                            } 
                        }
                        else 
                        { 
                            testNextEdge = true;
                        } 
                    }
                    else
                    {
                        side--; 
                    }
                } 
 
                //
                if (0 == side) 
                {
                    if (hit == HitResult.Hit)
                    {
                        // This segment is collinear with the edge connecting the nodes, 
                        // no need to hit-test the other edges.
                        System.Diagnostics.Debug.Assert(true == DoubleUtil.IsBetweenZeroAndOne(findex)); 
                        break; 
                    }
                    // The hitting segment intersects the line of the edge connecting 
                    // the nodes. Find the findex of the intersection point.
                    double det = -Vector.Determinant(nextNode, hitVector);
                    if (DoubleUtil.IsZero(det) == false)
                    { 
                        double s = Vector.Determinant(hitVector, hitBegin - lastVertex) / det;
                        if ((findex > s) && DoubleUtil.IsBetweenZeroAndOne(s)) 
                        { 
                            findex = s;
                        } 
                    }
                }
                //
                lastVertex = vertex; 
                nextNode = nextVertexNextNode;
            } 
            return AdjustFIndex(findex); 
        }
 
        /// 
        /// Clip-Testing a polygonal inking segment against an arc (circle)
        /// 
        /// Vector representing the starting and ending point for the inking 
        ///             segment
        /// Represents the difference in the node size for startNode and endNode. 
        ///              pressureDelta = (endNode.PressureFactor / beginNode.PressureFactor) - 1 
        /// The center of the hitting circle
        /// The radius of the hitting circle 
        /// a double representing the point of clipping
        private double ClipTestArc(Vector spineVector, double pressureDelta, Vector hitCenter, Vector hitRadius)
        {
            // NTRAID#WINDOWS-1448096-2006/1/9-SAMGEO, this code is not called, but will be in VNext 
            throw new NotImplementedException();
            /* 
            double findex = StrokeFIndices.AfterLast; 

            double radiusSquared = hitRadius.LengthSquared; 
            Vector vertex, lastVertex = _vertices[_vertices.Length - 1];
            Vector nextVertexNextNode, nextNode = spineVector + lastVertex * pressureDelta;
            bool testNextEdge = false;
 
            for (int k = 0, count = _vertices.Length;
                k < count || (k == count && testNextEdge); 
                k++, lastVertex = vertex, nextNode = nextVertexNextNode) 
            {
                vertex = _vertices[k % count]; 
                Vector nextVertex = vertex - lastVertex;
                nextVertexNextNode = spineVector + (vertex * pressureDelta);

                if (DoubleUtil.IsZero(nextNode.X) && DoubleUtil.IsZero(nextNode.Y)) 
                {
                    continue; 
                } 

                bool testConnectingEdge = false; 

                if (HitResult.Left == WhereIsVectorAboutVector(nextNode, nextVertex))
                {
                    testNextEdge = false; 

                    Vector normal = GetProjection(lastVertex - hitCenter, vertex - hitCenter); 
                    if (radiusSquared <= normal.LengthSquared) 
                    {
                        if (WhereIsVectorAboutVector(hitCenter - lastVertex, nextVertex) == HitResult.Left) 
                        {
                            Vector hitPoint = hitCenter + (normal * Math.Sqrt(radiusSquared / normal.LengthSquared));
                            if (HitResult.Right == WhereIsVectorAboutVector(hitPoint - vertex, nextVertexNextNode))
                            { 
                                testNextEdge = true;
                            } 
                            else if (HitResult.Left == WhereIsVectorAboutVector(hitPoint - lastVertex, nextNode)) 
                            {
                                testConnectingEdge = true; 
                            }
                            else
                            {
                                // this is it 
                                findex = GetPositionBetweenLines(nextVertex, nextNode, hitPoint - lastVertex);
                                System.Diagnostics.Debug.Assert(DoubleUtil.IsBetweenZeroAndOne(findex)); 
                                break; 
                            }
                        } 
                    }
                    else if (HitResult.Right == WhereIsVectorAboutVector(hitCenter + normal - lastVertex, nextNode))
                    {
                        testNextEdge = true; 
                    }
                    else 
                    { 
                        testConnectingEdge = true;
                    } 
                }
                else if (testNextEdge == true)
                {
                    testNextEdge = false; 
                    testConnectingEdge = true;
                } 
 
                if (testConnectingEdge)
                { 
                    // Find out the projection of hitCenter on nextNode
                    Vector v = lastVertex - hitCenter;
                    double findexNearest = GetProjectionFIndex(v, v + nextNode);
 
                    if (findexNearest > 0)
                    { 
                        Vector nearest = nextNode * findexNearest; 
                        double squaredDistanceFromNearestToHitPoint = radiusSquared - (nearest + v).LengthSquared;
                        if (DoubleUtil.IsZero(squaredDistanceFromNearestToHitPoint) && (findexNearest <= 1)) 
                        {
                            if (findexNearest < findex)
                            {
                                findex = findexNearest; 
                            }
                        } 
                        else if ((squaredDistanceFromNearestToHitPoint > 0) 
                            && (nearest.LengthSquared >= squaredDistanceFromNearestToHitPoint))
                        { 
                            double hitPointFIndex = findexNearest - Math.Sqrt(
                                squaredDistanceFromNearestToHitPoint / nextNode.LengthSquared);
                            System.Diagnostics.Debug.Assert(DoubleUtil.GreaterThanOrClose(hitPointFIndex, 0));
                            if (hitPointFIndex < findex) 
                            {
                                findex = hitPointFIndex; 
                            } 
                        }
                    } 
                }
            }

            return AdjustFIndex(findex); 
            */
        } 
 
        /// 
        /// Internal access to __vertices 
        /// 
        /// 
        internal Vector[] GetVertices()
        { 
            return _vertices;
        } 
 
        /// 
        /// Helper function to hit-test the biggest node against hitting contour segments 
        /// 
        /// a collection of basic segments outlining the hitting contour
        /// Begin node of the stroke segment to hit-test. Can be empty (none)
        /// End node of the stroke segment 
        /// true if hit; false otherwise
        private bool HitTestPolygonContourSegments( 
            IEnumerable hitContour, StrokeNodeData beginNode, StrokeNodeData endNode) 
        {
            bool isHit = false; 

            // The bool variable isInside is used here to track that case. It answers to
            // 'Is ink contour inside if the hitting contour?'. It's initialized to 'true"
            // and then verified for each edge of the hitting contour until there's a hit or 
            // until it's false.
            bool isInside = true; 
 
            Point position;
            double pressureFactor; 
            if (beginNode.IsEmpty || endNode.PressureFactor > beginNode.PressureFactor)
            {
                position = endNode.Position;
                pressureFactor = endNode.PressureFactor; 
            }
            else 
            { 
                position = beginNode.Position;
                pressureFactor = beginNode.PressureFactor; 
            }

            // Enumerate through the segments of the hitting contour and test them
            // one by one against the contour of the ink node. 
            foreach (ContourSegment hitSegment in hitContour)
            { 
                if (hitSegment.IsArc) 
                {
                    // Adjust the arc for the node' pressure factor. 
                    Vector hitCenter = hitSegment.Begin + hitSegment.Radius - position;
                    Vector hitRadius = hitSegment.Radius;
                    if (!DoubleUtil.AreClose(pressureFactor, 1d))
                    { 
                        System.Diagnostics.Debug.Assert(DoubleUtil.IsZero(pressureFactor) == false);
                        hitCenter /= pressureFactor; 
                        hitRadius /= pressureFactor; 
                    }
                    // If the segment is an arc, hit-test against the entire circle the arc is part of. 
                    if (true == HitTestPolygonCircle(_vertices, hitCenter, hitRadius))
                    {
                        isHit = true;
                        break; 
                    }
                    // 
                    if (isInside && (WhereIsVectorAboutArc( 
                        position - hitSegment.Begin - hitSegment.Radius,
                        -hitSegment.Radius, hitSegment.Vector - hitSegment.Radius) == HitResult.Hit)) 
                    {
                        isInside = false;
                    }
                } 
                else
                { 
                    // Adjust the segment for the node's pressure factor 
                    Vector hitBegin = hitSegment.Begin - position;
                    Vector hitEnd = hitBegin + hitSegment.Vector; 
                    if (!DoubleUtil.AreClose(pressureFactor, 1d))
                    {
                        System.Diagnostics.Debug.Assert(DoubleUtil.IsZero(pressureFactor) == false);
                        hitBegin /= pressureFactor; 
                        hitEnd /= pressureFactor;
                    } 
                    // Hit-test the node against the segment 
                    if (true == HitTestPolygonSegment(_vertices, hitBegin, hitEnd))
                    { 
                        isHit = true;
                        break;
                    }
                    // 
                    if (isInside && WhereIsVectorAboutVector(
                        position - hitSegment.Begin, hitSegment.Vector) != HitResult.Right) 
                    { 
                        isInside = false;
                    } 
                }
            }
            return (isInside || isHit);
        } 

        ///  
        /// Helper function to HitTest the the hitting contour against the inking contour 
        /// 
        /// a collection of basic segments outlining the hitting contour 
        /// A connecting quad
        /// Begin node of the stroke segment to hit-test. Can be empty (none)
        /// End node of the stroke segment
        /// true if hit; false otherwise 
        private bool HitTestInkContour(
            IEnumerable hitContour, Quad quad, StrokeNodeData beginNode, StrokeNodeData endNode) 
        { 
            System.Diagnostics.Debug.Assert(!quad.IsEmpty);
            bool isHit = false; 

            // When hit-testing a contour against another contour, like in this case,
            // the default implementation checks whether any edge (segment) of the hitting
            // contour intersects with the contour of the ink segment. But this doesn't cover 
            // the case when the ink segment is entirely inside of the hitting segment.
            // The bool variable isInside is used here to track that case. It answers to 
            // 'Is ink contour inside if the hitting contour?'. It's initialized to 'true" 
            // and then verified for each edge of the hitting contour until there's a hit or
            // until it's false. 
            bool isInside = true;

            // The ink connecting quad is not empty, enumerate through the segments of the
            // hitting contour and hit-test them one by one against the ink contour. 
            foreach (ContourSegment hitSegment in hitContour)
            { 
                // Iterate through the vertices of the contour of the ink segment 
                // check where the hit segment is about them, return false if it's
                // on the left side off either of the ink contour segments. 

                Vector hitBegin, hitEnd;
                HitResult hitResult;
 
                // Start with the segment quad.C->quad.D
                if (hitSegment.IsArc) 
                { 
                    hitBegin = hitSegment.Begin + hitSegment.Radius - beginNode.Position;
                    hitEnd = hitSegment.Radius; 
                    hitResult = WhereIsCircleAboutSegment(
                        hitBegin, hitEnd, quad.C - beginNode.Position, quad.D - beginNode.Position);
                }
                else 
                {
                    hitBegin = hitSegment.Begin - beginNode.Position; 
                    hitEnd = hitBegin + hitSegment.Vector; 
                    hitResult = WhereIsSegmentAboutSegment(
                        hitBegin, hitEnd, quad.C - beginNode.Position, quad.D - beginNode.Position); 
                }
                if (HitResult.Left == hitResult)
                {
                    if (isInside) 
                    {
                        isInside = hitSegment.IsArc 
                            ? (WhereIsVectorAboutArc(-hitBegin, -hitSegment.Radius, hitSegment.Vector - hitSegment.Radius) != HitResult.Hit) 
                            : (WhereIsVectorAboutVector(-hitBegin, hitSegment.Vector) == HitResult.Right);
                    } 
                    // This hitSegment is completely outside of the ink contour,
                    // continue with the next one.
                    continue;
                } 

                // Continue clockwise from quad.D to quad.A, then to quad.B, ..., quad.C 
 
                HitResult firstResult = hitResult, lastResult = hitResult;
                double pressureFactor = beginNode.PressureFactor; 

                // Find the index of the vertex that is quad.D
                // Use count var to avoid infinite loop, normally this shouldn't
                // happen but it doesn't hurt to check it just in case. 
                int i = 0, count = _vertices.Length;
                Vector vertex = new Vector(); 
                for (i = 0; i < count; i++) 
                {
                    vertex = _vertices[i] * pressureFactor; 
                    if (DoubleUtil.AreClose((beginNode.Position + vertex), quad.D))
                    {
                        break;
                    } 
                }
                System.Diagnostics.Debug.Assert(i < count); 
 
                int k;
                for (k = 0; k < 2; k++) 
                {
                    count = _vertices.Length;
                    Point nodePosition = (k == 0) ? beginNode.Position : endNode.Position;
                    Point end = (k == 0) ? quad.A : quad.C; 

                    // Iterate over the vertices on 
                    //          beginNode(k=0)from quad.D to quad.A 
                    //    or
                    //          endNode(k=1)from quad.A to quad.B ... to quad.C 
                    while (((nodePosition + vertex) != end) && (count != 0))
                    {
                        // Find out the next vertex
                        i = (i + 1) % _vertices.Length; 
                        Vector nextVertex = _vertices[i] * pressureFactor;
 
                        // Hit-test the hitting segment against the current edge 
                        hitResult = hitSegment.IsArc
                            ? WhereIsCircleAboutSegment(hitBegin, hitEnd, vertex, nextVertex) 
                            : WhereIsSegmentAboutSegment(hitBegin, hitEnd, vertex, nextVertex);

                        if (HitResult.Hit == hitResult)
                        { 
                            return true;  //Got a hit
                        } 
                        if (true == IsOutside(hitResult, lastResult)) 
                        {
                            // This hitSegment is definitely outside the ink contour, drop it. 
                            // Change k to something > 2 to leave the for loop and skip
                            // IsOutside at the bottom
                            k = 3;
                            break; 
                        }
                        lastResult = hitResult; 
                        vertex = nextVertex; 
                        count--;
                    } 
                    System.Diagnostics.Debug.Assert(count > 0);

                    if (k == 0)
                    { 
                        // Make some adjustments for the second one to continue iterating through
                        // quad.AB and the outer segments of endNode up to quad.C 
                        pressureFactor = endNode.PressureFactor; 
                        Vector spineVector = endNode.Position - beginNode.Position;
                        vertex -= spineVector; // now vertex = quad.A - spineVector 
                        hitBegin -= spineVector; // adjust hitBegin to the space of endNode
                        if (hitSegment.IsArc == false)
                        {
                            hitEnd -= spineVector; 
                        }
 
                        // Find the index of the vertex that is quad.B 
                        count = _vertices.Length;
                        while (!DoubleUtil.AreClose((endNode.Position + _vertices[i] * pressureFactor), quad.B) && (count != 0)) 
                        {
                            i = (i + 1) % _vertices.Length;
                            count--;
                        } 
                        System.Diagnostics.Debug.Assert(count > 0);
                        i--; 
                    } 
                }
                if ((k == 2) && (false == IsOutside(firstResult, hitResult))) 
                {
                    isHit = true;
                    break;
                } 
                //
                if (isInside) 
                { 
                    isInside = hitSegment.IsArc
                        ? (WhereIsVectorAboutArc(-hitBegin, -hitSegment.Radius, hitSegment.Vector - hitSegment.Radius) != HitResult.Hit) 
                        : (WhereIsVectorAboutVector(-hitBegin, hitSegment.Vector) == HitResult.Right);
                }
            }
            return (isHit||isInside); 
        }
 
 
        /// 
        /// Helper function to Hit-test against the two stroke nodes only (excluding the connecting quad). 
        /// 
        /// 
        /// 
        ///  
        /// 
        ///  
        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;
        } 

        ///  
        ///  Calculate the clip location 
        /// 
        /// the hitting segment 
        /// begin node
        /// 
        /// 
        /// the clip location. not-clip if return StrokeFIndices.BeforeFirst 
        private double CalculateClipLocation(
            ContourSegment hitSegment, StrokeNodeData beginNode, Vector spineVector, double pressureDelta) 
        { 
            double findex = StrokeFIndices.BeforeFirst;
            bool clipIt = hitSegment.IsArc ? true 
                //? (WhereIsVectorAboutArc(beginNode.Position - hitSegment.Begin - hitSegment.Radius,
                //            -hitSegment.Radius, hitSegment.Vector - hitSegment.Radius) == HitResult.Hit)
                : (WhereIsVectorAboutVector(
                                   beginNode.Position - hitSegment.Begin, hitSegment.Vector) == HitResult.Left); 
            if (clipIt)
            { 
                findex = hitSegment.IsArc 
                    ? ClipTestArc(spineVector, pressureDelta,
                        (hitSegment.Begin + hitSegment.Radius - beginNode.Position) / beginNode.PressureFactor, 
                        hitSegment.Radius / beginNode.PressureFactor)
                    : ClipTest(spineVector, pressureDelta,
                        (hitSegment.Begin - beginNode.Position) / beginNode.PressureFactor,
                        (hitSegment.End - beginNode.Position) / beginNode.PressureFactor); 

                // NTRAID#WINDOWS-1384646-2005/11/17-WAYNEZEN, 
                // ClipTest returns StrokeFIndices.AfterLast to indicate a false hit test. 
                // But the caller CutTest expects StrokeFIndices.BeforeFirst when there is no hit.
                if ( findex == StrokeFIndices.AfterLast ) 
                {
                    findex = StrokeFIndices.BeforeFirst;
                }
                else 
                {
                    System.Diagnostics.Debug.Assert(findex >= 0 && findex <= 1); 
                } 
            }
            return findex; 
        }

        /// 
        /// Helper method used to determine if we came up with a bogus result during hit testing 
        /// 
        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;
        }
 
        #endregion
 
        #region Instance data 

        // Shape parameters 
        private Rect        _shapeBounds = Rect.Empty;
        protected Vector[]    _vertices;

        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK