/// <summary> /// Get the Geometry of the Stroke /// </summary> /// <param name="drawingAttributes"></param> /// <returns></returns> public Geometry GetGeometry(DrawingAttributes drawingAttributes) { if (drawingAttributes == null) { throw new ArgumentNullException("drawingAttributes"); } bool geometricallyEqual = DrawingAttributes.GeometricallyEqual(drawingAttributes, this.DrawingAttributes); // need to recalculate the PathGemetry if the DA passed in is "geometrically" different from // this DA, or if the cached PathGeometry is dirty. if (false == geometricallyEqual || (true == geometricallyEqual && null == _cachedGeometry)) { //Recalculate _pathGeometry; StrokeNodeIterator iterator = StrokeNodeIterator.GetIterator(this, drawingAttributes); Geometry geometry; Rect bounds; StrokeRenderer.CalcGeometryAndBounds(iterator, drawingAttributes, #if DEBUG_RENDERING_FEEDBACK null, 0d, false, #endif true, //calc bounds out geometry, out bounds); // return the calculated value directly. We cannot cache the result since the DA passed in // is "geometrically" different from this.DrawingAttributes. if (false == geometricallyEqual) { return(geometry); } // Cache the value and set _isPathGeometryDirty to false; SetGeometry(geometry); SetBounds(bounds); return(geometry); } // return a ref to our _cachedGeometry System.Diagnostics.Debug.Assert(_cachedGeometry != null && _cachedGeometry.IsFrozen); return(_cachedGeometry); }
/// <summary> /// The core functionality to draw a stroke. The function can be called from the following code paths. /// i) From StrokeVisual.OnRender /// a. Highlighter strokes have been grouped and the correct opacity has been set on the container visual. /// b. For a highlighter stroke with color.A != 255, the DA passed in is a copy with color.A set to 255. /// c. _drawAsHollow can be true, i.e., Selected stroke is drawn as hollow /// ii) From StrokeCollection.Draw. /// a. Highlighter strokes have been grouped and the correct opacity has been pushed. /// b. For a highlighter stroke with color.A != 255, the DA passed in is a copy with color.A set to 255. /// c. _drawAsHollow is always false, i.e., Selected stroke is not drawn as hollow /// iii) From Stroke.Draw /// a. The correct opacity has been pushed for a highlighter stroke /// b. For a highlighter stroke with color.A != 255, the DA passed in is a copy with color.A set to 255. /// c. _drawAsHollow is always false, i.e., Selected stroke is not drawn as hollow /// We need to document the following: /// 1) our default implementation so developers can see what we've done here - /// including how we handle IsHollow /// 2) the fact that opacity has already been set up correctly for the call. /// 3) that developers should not call base.DrawCore if they override this /// </summary> /// <param name="drawingContext">DrawingContext to draw on</param> /// <param name="drawingAttributes">DrawingAttributes to draw with</param> protected virtual void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes) { if (null == drawingContext) { throw new System.ArgumentNullException("drawingContext"); } if (null == drawingAttributes) { throw new System.ArgumentNullException("drawingAttributes"); } if (_drawAsHollow == true) { // Draw as hollow. Our profiler result shows that the two-pass-rendering approach is about 5 times // faster that using GetOutlinePathGeometry. // also, the minimum display size for selected ink is our default width / height Matrix innerTransform, outerTransform; DrawingAttributes selectedDA = drawingAttributes.Clone(); selectedDA.Height = Math.Max(selectedDA.Height, DrawingAttributes.DefaultHeight); selectedDA.Width = Math.Max(selectedDA.Width, DrawingAttributes.DefaultWidth); CalcHollowTransforms(selectedDA, out innerTransform, out outerTransform); // First pass drawing. Use drawingAttributes.Color to create a solid color brush. The stroke will be drawn as // 1 avalon-unit higher and wider (HollowLineSize = 1.0f) selectedDA.StylusTipTransform = outerTransform; SolidColorBrush brush = new SolidColorBrush(drawingAttributes.Color); brush.Freeze(); drawingContext.DrawGeometry(brush, null, GetGeometry(selectedDA)); //Second pass drawing with a white color brush. The stroke will be drawn as // 1 avalon-unit shorter and narrower (HollowLineSize = 1.0f) if the actual-width/height (considering StylusTipTransform) // is larger than HollowLineSize. Otherwise the same size stroke is drawn. selectedDA.StylusTipTransform = innerTransform; drawingContext.DrawGeometry(Brushes.White, null, GetGeometry(selectedDA)); } else { #if DEBUG_RENDERING_FEEDBACK //render debug feedback? Guid guid = new Guid("52053C24-CBDD-4547-AAA1-DEFEBF7FD1E1"); if (this.ContainsPropertyData(guid)) { double thickness = (double)this.GetPropertyData(guid); //first, draw the outline of the stroke drawingContext.DrawGeometry(null, new Pen(Brushes.Black, thickness), GetGeometry()); Geometry g2; Rect b2; //next, overlay the connecting quad points StrokeRenderer.CalcGeometryAndBounds(StrokeNodeIterator.GetIterator(this, drawingAttributes), drawingAttributes, drawingContext, thickness, true, true, //calc bounds out g2, out b2); } else { #endif SolidColorBrush brush = new SolidColorBrush(drawingAttributes.Color); brush.Freeze(); drawingContext.DrawGeometry(brush, null, GetGeometry(drawingAttributes)); #if DEBUG_RENDERING_FEEDBACK } #endif } }