LassoHelper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / Ink / LassoHelper.cs / 1305600 / LassoHelper.cs

                            //------------------------------------------------------------------------ 
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
// 
//----------------------------------------------------------------------- 

using System; 
using System.Windows; 
using System.Windows.Media;
using System.Windows.Ink; 
using System.Collections;
using System.Collections.Generic;
using System.Windows.Documents;
 
namespace MS.Internal.Ink
{ 
    #region LassoHelper 
    /// 
    /// An internal helper class to draw lasso as a sequence of dots 
    /// closed with a rubber line. LassoSelectionBehavior creates an object of
    /// this class to render a single lasso, so, for simplicity,
    /// LassoHelper objects are indended for one-time use only.
    ///  
    internal class LassoHelper
    { 
        #region Fields 

        // Visuals, geometry builders and drawing stuff 
        DrawingVisual       _containerVisual = null;
        Brush               _brush = null;
        Pen                 _pen = null;
        //Pen                 _linePen = null; 

        // 
        bool                _isActivated = false; 
        Point               _firstLassoPoint;
        Point               _lastLassoPoint; 
        int                 _count = 0;

        // Entire lasso. Collected to hit test InkCanvas' subelements after stylus up.
        List         _lasso = null; 
        Rect                _boundingBox;
 
        // NTRAID#T2-00000-2003/07/14-vsmirnov - some of these are probably not in [....] 
        // with the spec (which is not available at this moment), and also might
        // need to be different for the high contrast mode. 
        public const double  MinDistanceSquared     = 49.0;
        const double  DotRadius                     = 2.5;
        const double  DotCircumferenceThickness     = 0.5;
        const double  ConnectLineThickness          = 0.75; 
        const double  ConnectLineOpacity            = 0.75;
        static readonly Color DotColor              = Colors.Orange;     //FromArgb(1, 0.89f, 0.3607f, 0.1843f); 
        static readonly Color DotCircumferenceColor = Colors.White; 

        #endregion 

        #region Public API
        /// 
        /// Read-only access to the container visual for dynamic drawing a lasso 
        /// 
        public Visual Visual 
        { 
            get
            { 
                EnsureVisual();
                return _containerVisual;
            }
        } 

        /// TBS 
        public Point[] AddPoints(List points) 
        {
            if (null == points) 
                throw new ArgumentNullException("points");

            // Lazy initialization.
            EnsureReady(); 

            List justAdded = new List(); 
            int count = points.Count; 
            for ( int i = 0; i < count ; i++ )
            { 
                Point point = points[i];

                if (0 == _count)
                { 
                    AddLassoPoint(point);
 
                    justAdded.Add(point); 
                    _lasso.Add(point);
                    _boundingBox.Union(point); 

                    _firstLassoPoint = point;
                    _lastLassoPoint = point;
                    _count++; 
                }
                else 
                { 
                    Vector last2next = point - _lastLassoPoint;
                    double distanceSquared = last2next.LengthSquared; 

                    // Avoid using Sqrt when the distance is equal to the step.
                    if (DoubleUtil.AreClose(MinDistanceSquared, distanceSquared))
                    { 
                        AddLassoPoint(point);
                        justAdded.Add(point); 
                        _lasso.Add(point); 
                        _boundingBox.Union(point);
 
                        _lastLassoPoint = point;
                        _count++;

                    } 
                    else if (MinDistanceSquared < distanceSquared)
                    { 
                        double step = Math.Sqrt(MinDistanceSquared / distanceSquared); 
                        Point last = _lastLassoPoint;
                        for (double findex = step; findex < 1.0f; findex += step) 
                        {
                            Point lassoPoint = last + (last2next * findex);
                            AddLassoPoint(lassoPoint);
                            justAdded.Add(lassoPoint); 
                            _lasso.Add(lassoPoint);
                            _boundingBox.Union(lassoPoint); 
 
                            _lastLassoPoint = lassoPoint;
                            _count++; 

                        }
                    }
                } 
            }
 
            // still working on perf here. 
            // Draw a line between the last point and the first one.
            //if (_count > 1) 
            //{
            //    DrawingContext dc = _containerVisual.RenderOpen();
            //    dc.DrawLine(_linePen, _firstLassoPoint, _lastLassoPoint);
            //    dc.Close(); 
            //}
 
            return justAdded.ToArray(); 
        }
 
        ///// 
        ///// Draws a single lasso dot with the center at the given point.
        ///// 
        private void AddLassoPoint(Point lassoPoint) 
        {
            DrawingVisual dv = new DrawingVisual(); 
            DrawingContext dc = null; 
            try
            { 
                dc = dv.RenderOpen();
                dc.DrawEllipse(_brush, _pen, lassoPoint, DotRadius, DotRadius);
            }
            finally 
            {
                if (dc != null) 
                { 
                    dc.Close();
                } 
            }

            // Add the new visual to the container.
            _containerVisual.Children.Add(dv); 
        }
 
        #endregion 

        #region ArePointsInLasso 
        /// Copy-pasted Platform's Lasso.Contains(...)
        public bool ArePointsInLasso(Point[] points, int percentIntersect)
        {
            System.Diagnostics.Debug.Assert(null != points); 
            System.Diagnostics.Debug.Assert((0 <= percentIntersect) && (100 >= percentIntersect));
 
            // Find out how many of the points need to be inside the lasso to satisfy the percentIntersect. 
            int marginCount = (points.Length * percentIntersect) / 100;
 
            if ((0 == marginCount) || (50 <= ((points.Length * percentIntersect) % 100)))
            {
                marginCount++;
            } 

            // Check if any point on the stroke is within the lasso or not. 
            // This is done by checking all segments on the left side of the point. 
            // If the no of such segments is odd then the point is within the lasso otherwise not.
            int countPointsInLasso = 0; 

            foreach (Point point in points)
            {
                if (true == Contains(point)) 
                {
                    countPointsInLasso++; 
                    if (countPointsInLasso == marginCount) 
                        break;
                } 
            }

            return (countPointsInLasso == marginCount);
        } 

        /// TBS 
        private bool Contains(Point point) 
        {
            if (false == _boundingBox.Contains(point)) 
            {
                return false;
            }
 
            bool isHigher = false;
            int last = _lasso.Count; 
 
            while (--last >= 0)
            { 
                if (false == DoubleUtil.AreClose(_lasso[last].Y, point.Y))
                {
                    isHigher = point.Y < _lasso[last].Y;
                    break; 
                }
            } 
 
            bool isInside = false, isOnClosingSegment = false;
            Point prevLassoPoint = _lasso[_lasso.Count - 1]; 

            for (int i = 0; i < _lasso.Count; i++)
            {
                Point lassoPoint = _lasso[i]; 

                if (DoubleUtil.AreClose(lassoPoint.Y, point.Y)) 
                { 
                    if (DoubleUtil.AreClose(lassoPoint.X, point.X))
                    { 
                        isInside = true;
                        break;
                    }
 
                    if ((0 != i) && DoubleUtil.AreClose(prevLassoPoint.Y, point.Y)
                        && DoubleUtil.GreaterThanOrClose(point.X, Math.Min(prevLassoPoint.X, lassoPoint.X)) 
                        && DoubleUtil.LessThanOrClose(point.X, Math.Max(prevLassoPoint.X, lassoPoint.X))) 
                    {
                        isInside = true; 
                        break;
                    }
                }
                else if (isHigher != (point.Y < lassoPoint.Y)) 
                {
                    isHigher = !isHigher; 
                    if (DoubleUtil.GreaterThanOrClose(point.X, Math.Max(prevLassoPoint.X, lassoPoint.X))) 
                    {
                        // there certainly is an intersection on the left 
                        isInside = !isInside;

                        // The closing segment is the only exclusive one. Special case it.
                        if ((0 == i) && DoubleUtil.AreClose(point.X, Math.Max(prevLassoPoint.X, lassoPoint.X))) 
                        {
                            isOnClosingSegment = true; 
                        } 
                    }
                    else if (DoubleUtil.GreaterThanOrClose(point.X, Math.Min(prevLassoPoint.X, lassoPoint.X))) 
                    {
                        // The X of the point lies within the x ranges for the segment.
                        // Calculate the x value of the point where the segment intersects with the line.
                        Vector lassoSegment = lassoPoint - prevLassoPoint; 
                        double x = prevLassoPoint.X + (lassoSegment.X / lassoSegment.Y) * (point.Y - prevLassoPoint.Y);
 
                        if (DoubleUtil.GreaterThanOrClose(point.X, x)) 
                        {
                            isInside = !isInside; 
                            if ((0 == i) && DoubleUtil.AreClose(point.X, x))
                            {
                                isOnClosingSegment = true;
                            } 
                        }
                    } 
                } 

                prevLassoPoint = lassoPoint; 
            }

            return isInside ? !isOnClosingSegment : false;
        } 
        #endregion
 
        #region Implementation helpers 
        ///  Creates the container visual when needed.
        private void EnsureVisual() 
        {
            if (null == _containerVisual)
            {
                _containerVisual = new DrawingVisual(); 
            }
        } 
 
        /// 
        /// Creates and initializes objects required for drawing 
        /// 
        private void EnsureReady()
        {
            if (false == _isActivated) 
            {
                _isActivated = true; 
 
                EnsureVisual();
 
                _brush = new SolidColorBrush(DotColor);
                _brush.Freeze();

                //_linePen = new Pen(new SolidColorBrush(Colors.DarkGray), ConnectLineThickness); 
                //_linePen.Brush.Opacity = ConnectLineOpacity;
                //_linePen.LineJoin = PenLineJoin.Round; 
 
                _pen = new Pen(new SolidColorBrush(DotCircumferenceColor), DotCircumferenceThickness);
                _pen.LineJoin = PenLineJoin.Round; 
                _pen.Freeze();

                _lasso = new List(100);
                _boundingBox = Rect.Empty; 

                _count = 0; 
            } 
        }
 
        #endregion
    }

    #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