Exemplo n.º 1
0
        /// <summary>
        /// Calculates the element's rendered size.
        /// </summary>
        /// <param name="element">The element to measure.</param>
        /// <returns>The rendered size.</returns>
        public static Size GetRenderedSize(FrameworkElement element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            double width  = element.ActualWidth;
            double height = element.ActualHeight;

            MatrixTransform t = GetGlobalTransformation(element);

            Point upperLeft  = t.Transform(new Point(0, 0));
            Point upperRight = t.Transform(new Point(width, 0));
            Point lowerLeft  = t.Transform(new Point(0, height));
            Point lowerRight = t.Transform(new Point(width, height));

            List <Point> allBoundingPoints = new List <Point>()
            {
                upperLeft, upperRight, lowerLeft, lowerRight
            };

            var minBoundingX = allBoundingPoints.Min(point => point.X);
            var minBoundingY = allBoundingPoints.Min(point => point.Y);
            var maxBoundingX = allBoundingPoints.Max(point => point.X);
            var maxBoundingY = allBoundingPoints.Max(point => point.Y);

            Size s = new Size(maxBoundingX - minBoundingX, maxBoundingY - minBoundingY);

            return(s);
        }
        private Point GetScaledValue(DataValue d)
        {
            double availableHeight = this.ActualHeight - 1;
            Point  point           = scaleTransform.Transform(new Point(d.X, d.Y));

            return(new Point(point.X, availableHeight - point.Y));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Gets the resolution in DPI of the target device of a visual.
        /// </summary>
        static public Point GetResolution(Visual visual)
        {
            Point dpi = new Point(120, 120);

            PresentationSource source = PresentationSource.FromVisual(visual);

            if (source == null)
            {
                return(dpi);
            }

            CompositionTarget target = source.CompositionTarget;

            Matrix          m = target.TransformToDevice;
            MatrixTransform t = new MatrixTransform(m);

            Point pt1 = new Point(0, 0);

            pt1 = t.Transform(pt1);

            Point pt2 = new Point(96, 96);

            pt2 = t.Transform(pt2);

            dpi.X = pt2.X - pt1.X;
            dpi.Y = pt2.Y - pt1.Y;
            return(dpi);
        }
Exemplo n.º 4
0
        void Manipulation(ManipulationDeltaEventArgs e)
        {
            var mt = new MatrixTransform(ShapeUtils.GetTransform(e));

            var Point1 = mt.Transform(new Point(line.X1, line.Y1));
            var Point2 = mt.Transform(new Point(line.X2, line.Y2));

            line.X1 = Point1.X;
            line.Y1 = Point1.Y;
            line.X2 = Point2.X;
            line.Y2 = Point2.Y;
        }
Exemplo n.º 5
0
        private void Manipulation(ManipulationDeltaEventArgs e)
        {
            var mt         = new MatrixTransform(ShapeUtils.GetTransform(e));
            var newTopLeft = mt.Transform(getBadgePos());

            setBadgePos(newTopLeft.X, newTopLeft.Y);
        }
Exemplo n.º 6
0
        internal override void BeforeArrange()
        {
            graphToCanvas.Matrix = new Matrix(xAxis.Scale, 0, 0, -yAxis.Scale, -xAxis.Offset - xAxis.AxisPadding.Lower, yAxis.Offset + yAxis.AxisTotalLength - yAxis.AxisPadding.Upper);
            canvasToGraph        = (MatrixTransform)(graphToCanvas.Inverse);
            Curve.FilterMinMax(canvasToGraph, new Rect(new Point(xAxis.Min, yAxis.Min), new Point(xAxis.Max, yAxis.Max)));
            if (host.UseDirect2D == true && !host.direct2DControl.InitializationFailed)
            {
                lineD2D.Geometry = curve.ToDirect2DPathGeometry(lineD2D.Factory, graphToCanvas);
                markersD2D.SetGeometry((MarkersType)GetValue(MarkersTypeProperty), (double)GetValue(MarkersSizeProperty));
                //host.direct2DControl.RequestRender();
            }
            else
            {
                line.Data    = LineGeometries.PathGeometryFromCurve(curve, graphToCanvas);
                markers.Data = MarkerGeometries.MarkersAsGeometry(Curve, graphToCanvas, (MarkersType)GetValue(MarkersTypeProperty), (double)GetValue(MarkersSizeProperty));
            }
            Point annotationPoint = graphToCanvas.Transform(new Point(curve.xTransformed[0], curve.yTransformed[0]));

            annotation.SetValue(Canvas.TopProperty, annotationPoint.Y); annotation.SetValue(Canvas.LeftProperty, annotationPoint.X);
        }
        private void AddScaledValues(PathFigure figure, int start, int end)
        {
            double height          = this.ActualHeight - 1;
            double availableHeight = height;
            double width           = this.ActualWidth;

            int    len    = series.Values.Count;
            double offset = Canvas.GetLeft(Graph);


            bool started = (figure.Segments.Count > 0);

            for (int i = start; i < end; i++)
            {
                DataValue d = series.Values[i];

                // add graph segment
                Point point = scaleTransform.Transform(new Point(d.X, d.Y));
                point = zoomTransform.Transform(point);
                double y = availableHeight - point.Y;
                double x = point.X;

                double rx = x + offset;
                if (rx > 0)
                {
                    Point pt = new Point(x, y);
                    if (!started)
                    {
                        figure.StartPoint = pt;
                        started           = true;
                    }
                    else
                    {
                        figure.Segments.Add(new LineSegment()
                        {
                            Point = pt
                        });
                    }
                }
            }
        }
Exemplo n.º 8
0
        protected override void OnRender(DrawingContext dc)
        {
            // Draw background
            dc.DrawRectangle(Brushes.White, null, new Rect(RenderSize));

            Transform t = new MatrixTransform(TheModel.GetTikzToScreenTransform().ToWpfMatrix());

            t.Freeze();

            Pen pen = new Pen(Brushes.WhiteSmoke, 1);

            pen.Freeze();

            TheModel.DrawRaster(
                (p1, p2) => dc.DrawLine(pen, t.Transform(p1), t.Transform(p2)),
                (r1, r2) =>
            {
                EllipseGeometry eg = new EllipseGeometry(new Point(0, 0), r1, r2);
                eg.Transform       = t;
                eg.Freeze();
                dc.DrawGeometry(null, pen, eg);
            });
        }
Exemplo n.º 9
0
        public Point GetPlacementTargetOffset()
        {
            Point            offset = new Point();
            FrameworkElement target = ExtensionSurface.GetPlacementTarget(this);

            if (null != target)
            {
                FrameworkElement commonRoot     = target.FindCommonVisualAncestor(this) as FrameworkElement;
                MatrixTransform  transform      = (MatrixTransform)target.TransformToAncestor(commonRoot);
                Point            targetPosition = transform.Transform(new Point());
                Point            windowPosition = ExtensionSurface.GetPosition(this);
                offset.X = targetPosition.X - windowPosition.X;
                offset.Y = targetPosition.Y - windowPosition.Y;
            }
            return(offset);
        }
Exemplo n.º 10
0
        public static List <Point> Generate(int n = 1000, double width = 1.0, double height = 1.0)
        {
            // Probabilities
            double[] p = { 0.85, .92, .99, 1.00 };

            // Transformations
            var a1     = new MatrixTransform(new System.Windows.Media.Matrix(0.85, -0.04, 0.04, 0.85, 0, 1.6));
            var a2     = new MatrixTransform(new System.Windows.Media.Matrix(0.20, 0.23, -0.26, 0.22, 0, 1.6));
            var a3     = new MatrixTransform(new System.Windows.Media.Matrix(-0.15, 0.26, 0.28, 0.24, 0, 0.44));
            var a4     = new MatrixTransform(new System.Windows.Media.Matrix(0, 0, 0, 0.16, 0, 0));
            var random = new Random(17);
            var point  = new Point(0.5, 0.5);
            var points = new List <Point>();

            // Transformation for [-3,3,0,10] => output coordinates
            var T = new MatrixTransform(new System.Windows.Media.Matrix(width / 6.0, 0, 0, -height / 10.1, width / 2.0, height));

            for (int i = 0; i < n; i++)
            {
                var r = random.NextDouble();

                if (r < p[0])
                {
                    point = a1.Transform(point);
                }
                else if (r < p[1])
                {
                    point = a2.Transform(point);
                }
                else if (r < p[2])
                {
                    point = a3.Transform(point);
                }
                else
                {
                    point = a4.Transform(point);
                }

                points.Add(T.Transform(point));
            }

            return(points);
        }
Exemplo n.º 11
0
        private void viewport_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
        {
            if (e.PinchManipulation != null)
            {
                double newWidth, newHieght;


                if (m_Width < m_Height)  // box new size between image size and viewport actual size
                {
                    newHieght = m_Height * m_Zoom * e.PinchManipulation.CumulativeScale;
                    newHieght = Math.Max(viewport.ActualHeight, newHieght);
                    newHieght = Math.Min(newHieght, m_Height);
                    newWidth  = newHieght * m_Width / m_Height;
                }
                else
                {
                    newWidth  = m_Width * m_Zoom * e.PinchManipulation.CumulativeScale;
                    newWidth  = Math.Max(viewport.ActualWidth, newWidth);
                    newWidth  = Math.Min(newWidth, m_Width);
                    newHieght = newWidth * m_Height / m_Width;
                }


                if (newWidth < m_Width && newHieght < m_Height)
                {
                    // Tells image positione in viewport (offset)
                    MatrixTransform transform = image.TransformToVisual(viewport) as MatrixTransform;
                    // Calculate center of pinch gesture on image (not screen)
                    Point pinchCenterOnImage = transform.Transform(e.PinchManipulation.Original.Center);
                    // Calculate relative point (0-1) of pinch center in image
                    Point relativeCenter = new Point(e.PinchManipulation.Original.Center.X / image.Width, e.PinchManipulation.Original.Center.Y / image.Height);
                    // Calculate and set new origin point of viewport
                    Point newOriginPoint = new Point(relativeCenter.X * newWidth - pinchCenterOnImage.X, relativeCenter.Y * newHieght - pinchCenterOnImage.Y);
                    viewport.SetViewportOrigin(newOriginPoint);
                }

                image.Width  = newWidth;
                image.Height = newHieght;

                // Set new view port bound
                viewport.Bounds = new Rect(0, 0, newWidth, newHieght);
            }
        }
Exemplo n.º 12
0
        private void ViewportControl_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
        {
            if (e.PinchManipulation != null)
            {
                double newWidth, newHieght;

                if (m_Width < m_Height)
                {
                    newHieght = m_Height * m_Zoom * e.PinchManipulation.CumulativeScale;
                    newHieght = Math.Max(viewport.ActualHeight, newHieght);
                    newHieght = Math.Min(newHieght, m_Height);
                    newWidth  = newHieght * m_Width / m_Height;
                }
                else
                {
                    newWidth  = m_Width * m_Zoom * e.PinchManipulation.CumulativeScale;
                    newWidth  = Math.Max(viewport.ActualWidth, newWidth);
                    newWidth  = Math.Min(newWidth, m_Width);
                    newHieght = newWidth * m_Height / m_Width;
                }

                if (newWidth < m_Width && newHieght < m_Height)
                {
                    MatrixTransform transform = map.TransformToVisual(viewport) as MatrixTransform;

                    Point pinchCenterOnImage = transform.Transform(e.PinchManipulation.Original.Center);
                    Point relativeCenter     = new Point(e.PinchManipulation.Original.Center.X / map.Width, e.PinchManipulation.Original.Center.Y / map.Height);
                    Point newOriginPoint     = new Point(relativeCenter.X * newWidth - pinchCenterOnImage.X, relativeCenter.Y * newHieght - pinchCenterOnImage.Y);

                    viewport.SetViewportOrigin(newOriginPoint);
                }

                _mapTransform.ScaleX = map.Width / m_Width;
                _mapTransform.ScaleY = map.Width / m_Width;

                map.Width  = newWidth;
                map.Height = newHieght;

                viewport.Bounds = new Rect(0, 0, newWidth, newHieght);

                e.Handled = true;
            }
        }
Exemplo n.º 13
0
        internal int CurveIndexFromCanvasPoint(Point canvasPoint)
        {
            Point  graphPoint = canvasToGraph.Transform(canvasPoint);
            double value      = curve.SortedValues == SortedValues.X ? graphPoint.X : graphPoint.Y;
            int    index      = Curve.GetInterpolatedIndex(curve.TransformedSorted, value);

            if (index == (curve.xTransformed.Length - 1))
            {
                return(curve.SortedToUnsorted[curve.xTransformed.Length - 1]);
            }
            // otherwise return nearest:
            if ((curve.TransformedSorted[index + 1] - value) < (value - curve.TransformedSorted[index]))
            {
                return(curve.SortedToUnsorted[index + 1]);
            }
            else
            {
                return(curve.SortedToUnsorted[index]);
            }
        }
Exemplo n.º 14
0
        public static Pt[] GetOutline(FrameworkElement elt, FrameworkElement parent)
        {
            if (parent == null)
            {
                return(new Pt[0]);
            }

            elt.UpdateLayout();
            GeneralTransform trans = new MatrixTransform(Mat.Identity);

            try {
                trans = elt.TransformToAncestor(parent);
            }
            catch (System.InvalidOperationException ex) {
            }

            Pt[] bounds = new Pt[] { new Pt(), new Pt(elt.ActualWidth, 0), new Pt(elt.ActualWidth, elt.ActualHeight), new Pt(0, elt.ActualHeight) };
            for (int i = 0; i < bounds.Length; i++)
            {
                bounds[i] = trans.Transform(bounds[i]);
            }
            return(bounds);
        }
Exemplo n.º 15
0
        void PlaceWindow(ExtensionWindow window)
        {
            if (null != window)
            {
                FrameworkElement  target    = ExtensionSurface.GetPlacementTarget(window);
                PositionAlignment alignment = ExtensionSurface.GetAlignment(window);
                PlacementMode     mode      = ExtensionSurface.GetMode(window);
                Point             position  = ExtensionSurface.GetPosition(window);

                Point            calculatedPosition = new Point();
                FrameworkElement commonRoot         = null;
                MatrixTransform  transform          = null;

                switch (mode)
                {
                case PlacementMode.Relative:
                    if (null != target)
                    {
                        commonRoot = target.FindCommonVisualAncestor(this) as FrameworkElement;
                        if (null == commonRoot)
                        {
                            return;
                        }
                        transform = (MatrixTransform)target.TransformToAncestor(commonRoot);
                    }
                    else
                    {
                        if (!DesignerProperties.GetIsInDesignMode(this))
                        {
                            Fx.Assert(string.Format(CultureInfo.InvariantCulture, "PlacementTarget must be set in RelativeMode on ExtensionSurface '{0}'", this.Name));
                        }
                    }
                    break;

                case PlacementMode.Absolute:
                    calculatedPosition = position;
                    break;

                default:
                    Fx.Assert(string.Format(CultureInfo.CurrentCulture, "ExtensionWindowPlacement.Mode {0} specified in ExtensionWindow '{1}' is not supported for ExtensionSurface", mode, window.Name));
                    return;
                }

                if (PlacementMode.Relative == mode)
                {
                    if (null != target)
                    {
                        double x;
                        double y;
                        switch (alignment)
                        {
                        case PositionAlignment.LeftTop:
                            calculatedPosition = transform.Transform(calculatedPosition);
                            break;

                        case PositionAlignment.LeftBottom:
                            calculatedPosition = transform.Transform(new Point(0.0, target.ActualHeight));
                            break;

                        case PositionAlignment.RightTop:
                            calculatedPosition = transform.Transform(new Point(target.ActualWidth, 0.0));
                            break;

                        case PositionAlignment.RightBottom:
                            calculatedPosition = transform.Transform(new Point(target.ActualWidth, target.ActualHeight));
                            break;

                        case PositionAlignment.Center:
                            calculatedPosition = transform.Transform(calculatedPosition);
                            x = ((target.ActualWidth * transform.Matrix.M11) - window.Width) / 2.0;
                            y = ((target.ActualHeight * transform.Matrix.M22) - window.Height) / 2.0;
                            calculatedPosition.Offset(x, y);
                            break;

                        case PositionAlignment.CenterHorizontal:
                            calculatedPosition = transform.Transform(calculatedPosition);
                            x = ((target.ActualWidth * transform.Matrix.M11) - window.Width) / 2.0;
                            calculatedPosition.Offset(x, 0.0);
                            break;

                        case PositionAlignment.CenterVertical:
                            calculatedPosition = transform.Transform(calculatedPosition);
                            y = ((target.ActualHeight * transform.Matrix.M22) - window.Height) / 2.0;
                            calculatedPosition.Offset(0.0, y);
                            break;

                        default:
                            Fx.Assert(string.Format(CultureInfo.CurrentCulture, "ExtensionWindowPlacement.Position = '{0}' is not supported", alignment));
                            return;
                        }
                    }
                }
                SetWindowPosition(window, calculatedPosition);
            }
        }
Exemplo n.º 16
0
 /// <summary>
 /// Transforms a geographic location to a viewport coordinates point.
 /// </summary>
 public Point LocationToViewportPoint(Location location)
 {
     return(viewportTransform.Transform(mapTransform.Transform(location)));
 }
Exemplo n.º 17
0
        protected override void OnDragDelta(object sender, DragDeltaEventArgs e)
        {
            double deltaVertical = 0, deltaHorizontal = 0;
            Point  dragDelta = new Point(e.HorizontalChange, e.VerticalChange);

            dragDelta = GridManager.AdjustPointToGrid(dragDelta);

            Matrix m = ((Transform)this.TransformToVisual(_controlledItem)).Value;

            m.OffsetX = 0;
            m.OffsetY = 0;
            System.Windows.Media.Transform t = new MatrixTransform(m);
            dragDelta = t.Transform(dragDelta);

            Rect r = new Rect(Canvas.GetLeft(_controlledItem), Canvas.GetTop(_controlledItem),
                              _controlledItem.Width, _controlledItem.Height);

            //r = GridManager.AdjustRectToGrid(r);

            switch (base.VerticalAlignment)
            {
            case System.Windows.VerticalAlignment.Bottom:
                deltaVertical = Math.Min(-dragDelta.Y, _controlledItem.ActualHeight - Height);

                r.Height -= deltaVertical;
                break;

            case System.Windows.VerticalAlignment.Top:
                deltaVertical = Math.Min(dragDelta.Y, _controlledItem.ActualHeight - Height);
                Point p = _controlledItem.RenderTransform.Transform(new Point(0, deltaVertical));
                r.Y      += p.Y;
                r.X      += p.X;
                r.Height -= deltaVertical;
                break;

            default:
                break;
            }

            switch (base.HorizontalAlignment)
            {
            case System.Windows.HorizontalAlignment.Left:
                deltaHorizontal = Math.Min(dragDelta.X, _controlledItem.ActualWidth - Width);
                Point p = _controlledItem.RenderTransform.Transform(new Point(deltaHorizontal, 0));
                r.Y     += p.Y;
                r.X     += p.X;
                r.Width -= deltaHorizontal;
                break;

            case System.Windows.HorizontalAlignment.Right:
                deltaHorizontal = Math.Min(-dragDelta.X, _controlledItem.ActualWidth - Width);
                r.Width        -= deltaHorizontal;
                break;

            default:
                break;
            }
            Point  sizeDelta      = new Point(deltaHorizontal, deltaVertical);
            Point  sizeDeltaTrans = _controlledItem.RenderTransform.Transform(sizeDelta);
            Vector v = sizeDelta - sizeDeltaTrans;

            r.X = r.X + v.X * _controlledItem.RenderTransformOrigin.X;
            r.Y = r.Y + v.Y * _controlledItem.RenderTransformOrigin.Y;


            EditorHelper.SetDependencyProperty(_controlledItem, Canvas.LeftProperty, r.X);
            EditorHelper.SetDependencyProperty(_controlledItem, Canvas.TopProperty, r.Y);
            EditorHelper.SetDependencyProperty(_controlledItem, FrameworkElement.WidthProperty, r.Width);
            EditorHelper.SetDependencyProperty(_controlledItem, FrameworkElement.HeightProperty, r.Height);
        }
        /// <summary>
        /// Draws a mouse cursor on the adorened element
        /// </summary>
        /// <param name="drawingContext"></param>
        protected override void OnRender(DrawingContext drawingContext)
        {
            GeneralTransform inverse = elementTransform.Inverse;

            if (inverse == null)
            {
                return;
            }

            Brush blackBrush = new SolidColorBrush(Colors.Black);

            float radius = 15;

            if (locked)
            {
                // Draw the little circle around the lock point

                Point point = elementTransform.Transform(lockPoint);
                drawingContext.DrawEllipse(null, new Pen(blackBrush, 3), point, 2.5, 2.5);
                drawingContext.DrawEllipse(null, new Pen(new SolidColorBrush(Colors.White), 2), point, 2.5, 2.5);

                // Draw the big yellow circle

                var yellowPen = new Pen(new SolidColorBrush(Colors.Yellow), 2);
                var blackPen  = new Pen(blackBrush, 3);
                drawingContext.DrawEllipse(null, blackPen, mousePoint, radius, radius);
                drawingContext.DrawEllipse(null, yellowPen, mousePoint, radius, radius);
            }
            else
            {
                // Draw the target symbol

                var blackPen = new Pen(blackBrush, .7);
                drawingContext.DrawEllipse(null, blackPen, mousePoint, radius, radius);
                drawingContext.DrawLine(blackPen, new Point(mousePoint.X - radius * 1.6, mousePoint.Y),
                                        new Point(mousePoint.X - 2, mousePoint.Y));
                drawingContext.DrawLine(blackPen, new Point(mousePoint.X + radius * 1.6, mousePoint.Y),
                                        new Point(mousePoint.X + 2, mousePoint.Y));
                drawingContext.DrawLine(blackPen, new Point(mousePoint.X, mousePoint.Y - radius * 1.6),
                                        new Point(mousePoint.X, mousePoint.Y - 2));
                drawingContext.DrawLine(blackPen, new Point(mousePoint.X, mousePoint.Y + radius * 1.6),
                                        new Point(mousePoint.X, mousePoint.Y + 2));
            }

            // Draw the coordinate text

            // Works out the number of decimal places required to show the difference between
            // 2 pixels. E.g if pixels are .1 apart then use 2 places etc
            Rect rect = inverse.TransformBounds(new Rect(0, 0, 1, 1));

            int xFigures = Math.Max(1, (int)(Math.Ceiling(-Math.Log10(rect.Width)) + .1));
            int yFigures = Math.Max(1, (int)(Math.Ceiling(-Math.Log10(rect.Height)) + .1));

            // Number of significant figures for the x coordinate
            string xFormat = "#0." + new string('#', xFigures);
            /// Number of significant figures for the y coordinate
            string yFormat = "#0." + new string('#', yFigures);

            Point coordinate = locked ? lockPoint : inverse.Transform(mousePoint);

            string coordinateText = coordinate.X.ToString(xFormat) + "," + coordinate.Y.ToString(yFormat);

            if (flipYAxis)
            {
                drawingContext.PushTransform(new ScaleTransform(1, 1));
            }
            else
            {
                drawingContext.PushTransform(new ScaleTransform(1, -1));
            }

            var formattedText = new FormattedText(coordinateText, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                                                  new Typeface("Arial"), 10, blackBrush);
            var textBoxPen = new Pen(new SolidColorBrush(Color.FromArgb(127, 255, 255, 255)), 1);

            Rect textBoxRect = flipYAxis
                                   ?
                               new Rect(new Point(mousePoint.X + radius * .7, mousePoint.Y + radius * .7),
                                        new Size(formattedText.Width, formattedText.Height))
                                   :
                               new Rect(new Point(mousePoint.X + radius * .7, -mousePoint.Y + radius * .7),
                                        new Size(formattedText.Width, formattedText.Height));

            double diff = textBoxRect.Right + 3 - ((FrameworkElement)AdornedElement).ActualWidth;

            if (diff > 0)
            {
                textBoxRect.Location = new Point(textBoxRect.Left - diff, textBoxRect.Top);
            }

            drawingContext.DrawRectangle(textBoxPen.Brush, textBoxPen, textBoxRect);
            drawingContext.DrawText(formattedText, textBoxRect.Location);
            drawingContext.Pop();
        }
Exemplo n.º 19
0
        /// <summary>
        /// Renders a bitmap using any affine transformation and transparency into this bitmap
        /// Unlike Silverlight's Render() method, this one uses 2-3 times less memory, and is the same or better quality
        /// The algorithm is simple dx/dy (bresenham-like) step by step painting, optimized with fixed point and fast bilinear filtering
        /// It's used in Fantasia Painter for drawing stickers and 3D objects on screen
        /// </summary>
        /// <param name="bmp">Destination bitmap.</param>
        /// <param name="source">The source WriteableBitmap.</param>
        /// <param name="shouldClear">If true, the the destination bitmap will be set to all clear (0) before rendering.</param>
        /// <param name="opacity">opacity of the source bitmap to render, between 0 and 1 inclusive</param>
        /// <param name="transform">Transformation to apply</param>
        public static void BlitRender(this BitmapBuffer bmp, BitmapBuffer source, bool shouldClear = true, float opacity = 1f, GeneralTransform transform = null)
        {
            const int PRECISION_SHIFT = 10;
            const int PRECISION_VALUE = (1 << PRECISION_SHIFT);
            const int PRECISION_MASK  = PRECISION_VALUE - 1;

            using (BitmapContext destContext = bmp.GetBitmapContext())
            {
                if (transform == null)
                {
                    transform = new MatrixTransform(Affine.IdentityMatrix);
                }

                int[]           destPixels = destContext.Pixels;
                int             destWidth  = destContext.Width;
                int             destHeight = destContext.Height;
                MatrixTransform inverse    = transform.Inverse;
                if (shouldClear)
                {
                    destContext.Clear();
                }

                using (BitmapContext sourceContext = source.GetBitmapContext(ReadWriteMode.ReadOnly))
                {
                    var sourcePixels = sourceContext.Pixels;
                    int sourceWidth  = sourceContext.Width;
                    int sourceHeight = sourceContext.Height;

                    RectD sourceRect = new RectD(0, 0, sourceWidth, sourceHeight);
                    RectD destRect   = new RectD(0, 0, destWidth, destHeight);
                    RectD bounds     = transform.TransformBounds(sourceRect);
                    bounds.Intersect(destRect);

                    int startX = (int)bounds.Left;
                    int startY = (int)bounds.Top;
                    int endX   = (int)bounds.Right;
                    int endY   = (int)bounds.Bottom;

#if NETFX_CORE
                    Point zeroZero = inverse.TransformPoint(new Point(startX, startY));
                    Point oneZero  = inverse.TransformPoint(new Point(startX + 1, startY));
                    Point zeroOne  = inverse.TransformPoint(new Point(startX, startY + 1));
#else
                    PointD zeroZero = inverse.Transform(new PointD(startX, startY));
                    PointD oneZero  = inverse.Transform(new PointD(startX + 1, startY));
                    PointD zeroOne  = inverse.Transform(new PointD(startX, startY + 1));
#endif
                    float sourceXf = ((float)zeroZero.X);
                    float sourceYf = ((float)zeroZero.Y);
                    int   dxDx     = (int)((((float)oneZero.X) - sourceXf) * PRECISION_VALUE); // for 1 unit in X coord, how much does X change in source texture?
                    int   dxDy     = (int)((((float)oneZero.Y) - sourceYf) * PRECISION_VALUE); // for 1 unit in X coord, how much does Y change in source texture?
                    int   dyDx     = (int)((((float)zeroOne.X) - sourceXf) * PRECISION_VALUE); // for 1 unit in Y coord, how much does X change in source texture?
                    int   dyDy     = (int)((((float)zeroOne.Y) - sourceYf) * PRECISION_VALUE); // for 1 unit in Y coord, how much does Y change in source texture?

                    int sourceX           = (int)(((float)zeroZero.X) * PRECISION_VALUE);
                    int sourceY           = (int)(((float)zeroZero.Y) * PRECISION_VALUE);
                    int sourceWidthFixed  = sourceWidth << PRECISION_SHIFT;
                    int sourceHeightFixed = sourceHeight << PRECISION_SHIFT;

                    int opacityInt = (int)(opacity * 255);

                    int index = 0;
                    for (int destY = startY; destY < endY; destY++)
                    {
                        index = destY * destWidth + startX;
                        int savedSourceX = sourceX;
                        int savedSourceY = sourceY;

                        for (int destX = startX; destX < endX; destX++)
                        {
                            if ((sourceX >= 0) && (sourceX < sourceWidthFixed) && (sourceY >= 0) && (sourceY < sourceHeightFixed))
                            {
                                // bilinear filtering
                                int xFloor = sourceX >> PRECISION_SHIFT;
                                int yFloor = sourceY >> PRECISION_SHIFT;

                                if (xFloor < 0)
                                {
                                    xFloor = 0;
                                }
                                if (yFloor < 0)
                                {
                                    yFloor = 0;
                                }

                                int xCeil = xFloor + 1;
                                int yCeil = yFloor + 1;

                                if (xCeil >= sourceWidth)
                                {
                                    xFloor = sourceWidth - 1;
                                    xCeil  = 0;
                                }
                                else
                                {
                                    xCeil = 1;
                                }

                                if (yCeil >= sourceHeight)
                                {
                                    yFloor = sourceHeight - 1;
                                    yCeil  = 0;
                                }
                                else
                                {
                                    yCeil = sourceWidth;
                                }

                                int i1 = yFloor * sourceWidth + xFloor;
                                int p1 = sourcePixels[i1];
                                int p2 = sourcePixels[i1 + xCeil];
                                int p3 = sourcePixels[i1 + yCeil];
                                int p4 = sourcePixels[i1 + yCeil + xCeil];

                                int xFrac = sourceX & PRECISION_MASK;
                                int yFrac = sourceY & PRECISION_MASK;

                                // alpha
                                byte a1 = (byte)(p1 >> 24);
                                byte a2 = (byte)(p2 >> 24);
                                byte a3 = (byte)(p3 >> 24);
                                byte a4 = (byte)(p4 >> 24);

                                int  comp1, comp2;
                                byte a;

                                if ((a1 == a2) && (a1 == a3) && (a1 == a4))
                                {
                                    if (a1 == 0)
                                    {
                                        destPixels[index] = 0;

                                        sourceX += dxDx;
                                        sourceY += dxDy;
                                        index++;
                                        continue;
                                    }

                                    a = a1;
                                }
                                else
                                {
                                    comp1 = a1 + ((xFrac * (a2 - a1)) >> PRECISION_SHIFT);
                                    comp2 = a3 + ((xFrac * (a4 - a3)) >> PRECISION_SHIFT);
                                    a     = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT));
                                }

                                // red
                                comp1 = ((byte)(p1 >> 16)) + ((xFrac * (((byte)(p2 >> 16)) - ((byte)(p1 >> 16)))) >> PRECISION_SHIFT);
                                comp2 = ((byte)(p3 >> 16)) + ((xFrac * (((byte)(p4 >> 16)) - ((byte)(p3 >> 16)))) >> PRECISION_SHIFT);
                                byte r = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT));

                                // green
                                comp1 = ((byte)(p1 >> 8)) + ((xFrac * (((byte)(p2 >> 8)) - ((byte)(p1 >> 8)))) >> PRECISION_SHIFT);
                                comp2 = ((byte)(p3 >> 8)) + ((xFrac * (((byte)(p4 >> 8)) - ((byte)(p3 >> 8)))) >> PRECISION_SHIFT);
                                byte g = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT));

                                // blue
                                comp1 = ((byte)p1) + ((xFrac * (((byte)p2) - ((byte)p1))) >> PRECISION_SHIFT);
                                comp2 = ((byte)p3) + ((xFrac * (((byte)p4) - ((byte)p3))) >> PRECISION_SHIFT);
                                byte b = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT));

                                // save updated pixel
                                if (opacityInt != 255)
                                {
                                    a = (byte)((a * opacityInt) >> 8);
                                    r = (byte)((r * opacityInt) >> 8);
                                    g = (byte)((g * opacityInt) >> 8);
                                    b = (byte)((b * opacityInt) >> 8);
                                }
                                destPixels[index] = (a << 24) | (r << 16) | (g << 8) | b;
                            }

                            sourceX += dxDx;
                            sourceY += dxDy;
                            index++;
                        }

                        sourceX = savedSourceX + dyDx;
                        sourceY = savedSourceY + dyDy;
                    }
                }
            }
        }
        private void LoadSampleLinesData(double lineThickness, Rect targetRect)
        {
            // Read many lines from a custom bin file format.
            // The bin file was created from a metafile (wmf) file that was read by Ab2d.ReaderWmf,
            // then the lines were grouped by color and saved to a custom bin file.

            Rect bounds;
            var  lines = ReadLineDataFromBin(AppDomain.CurrentDomain.BaseDirectory + @"Resources\palazz_sport.bin", out bounds);


            Point targetCenter = new Point(targetRect.X + targetRect.Width * 0.5, targetRect.Y + targetRect.Height * 0.5);

            double xScale = targetRect.Width / bounds.Width;
            double yScale = targetRect.Height / bounds.Height;

            double scale = Math.Min(xScale, yScale); // Preserve aspect ratio - so use the minimal scale

            double xOffset = targetCenter.X - bounds.Width * scale * 0.5;
            double yOffset = targetCenter.Y + bounds.Height * scale * 0.5; // targetCenter.Y - bounds.Height * scale * 0.5 + bounds.Height * scale // because we flipped y we need to offset by height


            var matrixTransform = new MatrixTransform(scale, 0,
                                                      0, -scale, // We also need to flip y axis because here y axis is pointing up
                                                      xOffset, yOffset);

            for (var i = 0; i < lines.Count; i++)
            {
                var oneLineData = lines[i];
                var positions   = oneLineData.Positions;

                var point3DCollection = new Point3DCollection(positions.Count);
                for (var j = 0; j < positions.Count; j++)
                {
                    var p = new Point(positions[j].X, positions[j].Y);
                    p = matrixTransform.Transform(p);

                    point3DCollection.Add(new Point3D(p.X, p.Y, 0));
                }

                if (oneLineData.IsLineStrip)
                {
                    var polyLineVisual3D = new PolyLineVisual3D()
                    {
                        Positions     = point3DCollection,
                        LineColor     = oneLineData.LineColor,
                        LineThickness = lineThickness < 0 ? oneLineData.LineThickness : lineThickness
                    };

                    RootLinesVisual3D.Children.Add(polyLineVisual3D);
                }
                else
                {
                    var multiLineVisual3D = new MultiLineVisual3D()
                    {
                        Positions     = point3DCollection,
                        LineColor     = oneLineData.LineColor,
                        LineThickness = lineThickness < 0 ? oneLineData.LineThickness : lineThickness
                    };

                    RootLinesVisual3D.Children.Add(multiLineVisual3D);
                }
            }
        }