/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="stylusShape"></param> /// <returns></returns> public bool HitTest(IEnumerable <Point> path, StylusShape stylusShape) { // Check the input parameters if (path == null) { throw new System.ArgumentNullException("path"); } if (stylusShape == null) { throw new System.ArgumentNullException("stylusShape"); } if (IEnumerablePointHelper.GetCount(path) == 0) { return(false); } ErasingStroke erasingStroke = new ErasingStroke(stylusShape); erasingStroke.MoveTo(path); Rect erasingBounds = erasingStroke.Bounds; if (erasingBounds.IsEmpty) { return(false); } if (erasingBounds.IntersectsWith(this.GetBounds())) { return(erasingStroke.HitTest(StrokeNodeIterator.GetIterator(this, this.DrawingAttributes))); } return(false); }
/// <summary> /// Erases all ink hit by the contour of an erasing stroke /// </summary> /// <param name="eraserShape">Shape of the eraser</param> /// <param name="eraserPath">a path making the spine of the erasing stroke </param> public void Erase(IEnumerable <Point> eraserPath, StylusShape eraserShape) { // Check the input parameters if (eraserShape == null) { throw new System.ArgumentNullException(SR.Get(SRID.SCEraseShape)); } if (eraserPath == null) { throw new System.ArgumentNullException(SR.Get(SRID.SCErasePath)); } if (IEnumerablePointHelper.GetCount(eraserPath) == 0) { return; } ErasingStroke erasingStroke = new ErasingStroke(eraserShape, eraserPath); for (int i = 0; i < this.Count; i++) { Stroke stroke = this[i]; List <StrokeIntersection> intersections = new List <StrokeIntersection>(); erasingStroke.EraseTest(StrokeNodeIterator.GetIterator(stroke, stroke.DrawingAttributes), intersections); StrokeCollection eraseResult = stroke.Erase(intersections.ToArray()); UpdateStrokeCollection(stroke, eraseResult, ref i); } }
/// <summary> /// Creates an incremental hit-tester for hit-testing with a shape. /// Scenarios: stroke-erasing and point-erasing /// </summary> /// <param name="eraserShape">shape of the eraser</param> /// <returns>an instance of IncrementalStrokeHitTester</returns> public IncrementalStrokeHitTester GetIncrementalStrokeHitTester(StylusShape eraserShape) { if (eraserShape == null) { throw new System.ArgumentNullException("eraserShape"); } return(new IncrementalStrokeHitTester(this, eraserShape)); }
/// <summary> /// C-tor /// </summary> /// <param name="strokes">strokes to hit-test for erasing</param> /// <param name="eraserShape">erasing shape</param> internal IncrementalStrokeHitTester(StrokeCollection strokes, StylusShape eraserShape) : base(strokes) { System.Diagnostics.Debug.Assert(eraserShape != null); // Create an ErasingStroke objects that implements the actual hit-testing _erasingStroke = new ErasingStroke(eraserShape); }
/// <summary> /// /// </summary> /// <param name="nodeShape"></param> /// <returns></returns> internal static StrokeNodeOperations CreateInstance(StylusShape nodeShape) { if (nodeShape == null) { throw new ArgumentNullException("nodeShape"); } if (nodeShape.IsEllipse) { return new EllipticalNodeOperations(nodeShape); } return new StrokeNodeOperations(nodeShape); }
/// <summary> /// Constructor /// </summary> /// <param name="nodeShape"></param> internal EllipticalNodeOperations(StylusShape nodeShape) : base(nodeShape) { System.Diagnostics.Debug.Assert((nodeShape != null) && nodeShape.IsEllipse); _radii = new Size(nodeShape.Width * 0.5, nodeShape.Height * 0.5); // All operations with ellipses become simple(r) if transfrom ellipses into circles. // Use the max of the radii for the radius of the circle _radius = Math.Max(_radii.Width, _radii.Height); // Compute ellipse-to-circle and circle-to-elliipse transforms. The former is used // in hit-testing operations while the latter is used when computing vertices of // a quadrangle connecting two ellipses _transform = nodeShape.Transform; _nodeShapeToCircle = _transform; Debug.Assert(_nodeShapeToCircle.HasInverse, "About to invert a non-invertible transform"); _nodeShapeToCircle.Invert(); if (DoubleUtil.AreClose(_radii.Width, _radii.Height)) { _circleToNodeShape = _transform; } else { // Reverse the rotation if (false == DoubleUtil.IsZero(nodeShape.Rotation)) { _nodeShapeToCircle.Rotate(-nodeShape.Rotation); Debug.Assert(_nodeShapeToCircle.HasInverse, "Just rotated an invertible transform and produced a non-invertible one"); } // Scale to enlarge double sx, sy; if (_radii.Width > _radii.Height) { sx = 1; sy = _radii.Width / _radii.Height; } else { sx = _radii.Height / _radii.Width; sy = 1; } _nodeShapeToCircle.Scale(sx, sy); Debug.Assert(_nodeShapeToCircle.HasInverse, "Just scaled an invertible transform and produced a non-invertible one"); _circleToNodeShape = _nodeShapeToCircle; _circleToNodeShape.Invert(); } }
/// <summary> /// Erase with an eraser with passed in shape /// </summary> /// <param name="eraserPath">The path to erase</param> /// <param name="eraserShape">Shape of the eraser</param> /// <returns></returns> public StrokeCollection GetEraseResult(IEnumerable <Point> eraserPath, StylusShape eraserShape) { // Check the input parameters if (eraserShape == null) { throw new System.ArgumentNullException("eraserShape"); } if (eraserPath == null) { throw new System.ArgumentNullException("eraserPath"); } return(this.Erase(this.EraseTest(eraserPath, eraserShape))); }
/// <summary>Hit tests all segments within a contour generated with shape and path</summary> /// <param name="shape"></param> /// <param name="path"></param> /// <returns>StrokeIntersection array for these segments</returns> internal StrokeIntersection[] EraseTest(IEnumerable <Point> path, StylusShape shape) { System.Diagnostics.Debug.Assert(shape != null); System.Diagnostics.Debug.Assert(path != null); if (IEnumerablePointHelper.GetCount(path) == 0) { return(Array.Empty <StrokeIntersection>()); } ErasingStroke erasingStroke = new ErasingStroke(shape, path); List <StrokeIntersection> intersections = new List <StrokeIntersection>(); erasingStroke.EraseTest(StrokeNodeIterator.GetIterator(this, this.DrawingAttributes), intersections); return(intersections.ToArray()); }
/// <summary> /// Return all hit strokes that the StylusShape intersects and returns them in a StrokeCollection /// </summary> private StrokeCollection PointHitTest(Point point, StylusShape shape) { // Create the collection to return StrokeCollection hits = new StrokeCollection(); for (int i = 0; i < this.Count; i++) { Stroke stroke = this[i]; if (stroke.HitTest(new Point[] { point }, shape)) { hits.Add(stroke); } } return(hits); }
/// <summary> /// Issue: what's the return value /// </summary> /// <param name="path"></param> /// <param name="stylusShape"></param> /// <returns></returns> public StrokeCollection HitTest(IEnumerable <Point> path, StylusShape stylusShape) { // Check the input parameters if (stylusShape == null) { throw new System.ArgumentNullException("stylusShape"); } if (path == null) { throw new System.ArgumentNullException("path"); } if (IEnumerablePointHelper.GetCount(path) == 0) { return(new StrokeCollection()); } // validate input ErasingStroke erasingStroke = new ErasingStroke(stylusShape, path); Rect erasingBounds = erasingStroke.Bounds; if (erasingBounds.IsEmpty) { return(new StrokeCollection()); } StrokeCollection hits = new StrokeCollection(); foreach (Stroke stroke in this) { // samgeo - Presharp issue // Presharp gives a warning when get methods might deref a null. It's complaining // here that 'stroke'' could be null, but StrokeCollection never allows nulls to be added // so this is not possible #pragma warning disable 1634, 1691 #pragma warning suppress 6506 if (erasingBounds.IntersectsWith(stroke.GetBounds()) && erasingStroke.HitTest(StrokeNodeIterator.GetIterator(stroke, stroke.DrawingAttributes))) { hits.Add(stroke); } #pragma warning restore 1634, 1691 } return(hits); }
/// <summary> /// Returns a Bezier smoothed version of the StylusPoints /// </summary> /// <returns></returns> public StylusPointCollection GetBezierStylusPoints() { // Since we can't compute Bezier for single point stroke, we should return. if (_stylusPoints.Count < 2) { return(_stylusPoints); } // Construct the Bezier approximation Bezier bezier = new Bezier(); if (!bezier.ConstructBezierState(_stylusPoints, DrawingAttributes.FittingError)) { //construction failed, return a clone of the original points return(_stylusPoints.Clone()); } double tolerance = 0.5; StylusShape stylusShape = this.DrawingAttributes.StylusShape; if (null != stylusShape) { Rect shapeBoundingBox = stylusShape.BoundingBox; double min = Math.Min(shapeBoundingBox.Width, shapeBoundingBox.Height); tolerance = Math.Log10(min + min); tolerance *= (StrokeCollectionSerializer.AvalonToHimetricMultiplier / 2); if (tolerance < 0.5) { //don't allow tolerance to drop below .5 or we //can wind up with an huge amount of bezier points tolerance = 0.5; } } List <Point> bezierPoints = bezier.Flatten(tolerance); return(GetInterpolatedStylusPoints(bezierPoints)); }
/// <summary> /// Create a point eraser cursor from StylusShape /// </summary> /// <param name="stylusShape">Eraser Shape</param> /// <param name="tranform">Transform</param> /// <returns></returns> internal static Cursor GetPointEraserCursor(StylusShape stylusShape, Matrix tranform) { Debug.Assert(DoubleUtil.IsZero(tranform.OffsetX) && DoubleUtil.IsZero(tranform.OffsetY), "The EraserShape cannot be translated."); Debug.Assert(tranform.HasInverse, "The transform has to be invertable."); // Create a DA with IsHollow being set. A point eraser will be rendered to a hollow stroke. DrawingAttributes da = new DrawingAttributes(); if (stylusShape.GetType() == typeof(RectangleStylusShape)) { da.StylusTip = StylusTip.Rectangle; } else { da.StylusTip = StylusTip.Ellipse; } da.Height = stylusShape.Height; da.Width = stylusShape.Width; da.Color = Colors.Black; if ( !tranform.IsIdentity ) { // Apply the LayoutTransform and/or RenderTransform da.StylusTipTransform *= tranform; } if ( !DoubleUtil.IsZero(stylusShape.Rotation) ) { // Apply the tip rotation Matrix rotationMatrix = Matrix.Identity; rotationMatrix.Rotate(stylusShape.Rotation); da.StylusTipTransform *= rotationMatrix; } // Forward to GetPenCursor. return GetPenCursor(da, true, false/*isRightToLeft*/); }
/// <summary> /// Erase with an eraser with passed in shape /// </summary> /// <param name="eraserPath">The path to erase</param> /// <param name="eraserShape">Shape of the eraser</param> /// <returns></returns> public StrokeCollection GetEraseResult(IEnumerable<Point> eraserPath, StylusShape eraserShape) { // Check the input parameters if (eraserShape == null) { throw new System.ArgumentNullException("eraserShape"); } if (eraserPath == null) { throw new System.ArgumentNullException("eraserPath"); } return this.Erase(this.EraseTest(eraserPath, eraserShape)); }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="stylusShape"></param> /// <returns></returns> public bool HitTest(IEnumerable<Point> path, StylusShape stylusShape) { // Check the input parameters if (path == null) { throw new System.ArgumentNullException("path"); } if (stylusShape == null) { throw new System.ArgumentNullException("stylusShape"); } if (IEnumerablePointHelper.GetCount(path) == 0) { return false; } ErasingStroke erasingStroke = new ErasingStroke(stylusShape); erasingStroke.MoveTo(path); Rect erasingBounds = erasingStroke.Bounds; if (erasingBounds.IsEmpty) { return false; } if (erasingBounds.IntersectsWith(this.GetBounds())) { return erasingStroke.HitTest(StrokeNodeIterator.GetIterator(this, this.DrawingAttributes)); } return false; }
/// <summary>Hit tests all segments within a contour generated with shape and path</summary> /// <param name="shape"></param> /// <param name="path"></param> /// <returns>StrokeIntersection array for these segments</returns> internal StrokeIntersection[] EraseTest(IEnumerable<Point> path, StylusShape shape) { System.Diagnostics.Debug.Assert(shape != null); System.Diagnostics.Debug.Assert(path != null); if (IEnumerablePointHelper.GetCount(path) == 0) { return new StrokeIntersection[0]; } ErasingStroke erasingStroke = new ErasingStroke(shape, path); List<StrokeIntersection> intersections = new List<StrokeIntersection>(); erasingStroke.EraseTest(StrokeNodeIterator.GetIterator(this, this.DrawingAttributes), intersections); return intersections.ToArray(); }
/// <summary> /// Constructor /// </summary> /// <param name="nodeShape">shape of the nodes</param> internal StrokeNodeOperations(StylusShape nodeShape) { System.Diagnostics.Debug.Assert(nodeShape != null); _vertices = nodeShape.GetVerticesAsVectors(); }
public bool HitTest(IEnumerable<System.Windows.Point> path, StylusShape stylusShape) { return default(bool); }
public IncrementalStrokeHitTester GetIncrementalStrokeHitTester(StylusShape eraserShape) { return(default(IncrementalStrokeHitTester)); }
public void Erase(IEnumerable <System.Windows.Point> eraserPath, StylusShape eraserShape) { }
public System.Windows.Ink.StrokeCollection HitTest(IEnumerable <System.Windows.Point> path, StylusShape stylusShape) { return(default(System.Windows.Ink.StrokeCollection)); }
public StrokeCollection GetEraseResult(IEnumerable <System.Windows.Point> eraserPath, StylusShape eraserShape) { return(default(StrokeCollection)); }
/// <summary> /// Constructor for an incremental node enumerator that builds nodes /// from array(s) of points and a given stylus shape. /// </summary> /// <param name="nodeShape">a shape that defines the stroke contour</param> internal StrokeNodeIterator(StylusShape nodeShape) : this( null, //stylusPoints StrokeNodeOperations.CreateInstance(nodeShape), false) //usePressure) { }
/// <summary> /// Constructor for incremental erasing /// </summary> /// <param name="erasingShape">The shape of the eraser's tip</param> internal ErasingStroke(StylusShape erasingShape) { System.Diagnostics.Debug.Assert(erasingShape != null); _nodeIterator = new StrokeNodeIterator(erasingShape); }
public StrokeCollection GetEraseResult(IEnumerable<System.Windows.Point> eraserPath, StylusShape eraserShape) { return default(StrokeCollection); }
public bool HitTest(IEnumerable <System.Windows.Point> path, StylusShape stylusShape) { return(default(bool)); }
/// <summary> /// Constructor for static (atomic) erasing /// </summary> /// <param name="erasingShape">The shape of the eraser's tip</param> /// <param name="path">the spine of the erasing stroke</param> internal ErasingStroke(StylusShape erasingShape, IEnumerable<Point> path) : this(erasingShape) { MoveTo(path); }