コード例 #1
1
        public void Out_Of_Bounds_Control_Should_Not_Be_Rendered()
        {
            TestControl target;
            var container = new Canvas
            {
                Width = 100,
                Height = 100,
                ClipToBounds = true,
                Children = new Controls.Controls
                {
                    (target = new TestControl
                    {
                        Width = 10,
                        Height = 10,
                        ClipToBounds = true,
                        [Canvas.LeftProperty] = 110,
                        [Canvas.TopProperty] = 110,
                    })
                }
            };

            Render(container);

            Assert.False(target.Rendered);
        }
コード例 #2
1
        public void Opacity_Mask_Masks_Element()
        {
            var target = new Canvas
            {
                OpacityMask = new LinearGradientBrush
                {
                    StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
                    EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative),
                    GradientStops = new List<GradientStop>
                    {
                        new GradientStop(Color.FromUInt32(0xffffffff), 0),
                        new GradientStop(Color.FromUInt32(0x00ffffff), 1)
                    }
                },
                Width = 76,
                Height = 76,
                Children = new Avalonia.Controls.Controls
                {
                    new Path
                    {
                        Width = 32,
                        Height = 40,
                        [Canvas.LeftProperty] = 23,
                        [Canvas.TopProperty] = 18,
                        Stretch = Stretch.Fill,
                        Fill = Brushes.Red,
                        Data = StreamGeometry.Parse("F1 M 27,18L 23,26L 33,30L 24,38L 33,46L 23,50L 27,58L 45,58L 55,38L 45,18L 27,18 Z")
                    }
                }
            };

            RenderToFile(target);
            CompareImages();
        }
コード例 #3
1
        public void Negative_Margin_Should_Be_Respected()
        {
            TestControl target;
            var container = new Canvas
            {
                Width = 100,
                Height = 100,
                ClipToBounds = true,
                Children = new Controls.Controls
                {
                    new Border
                    {
                        Margin = new Thickness(100, 100, 0, 0),
                        Child = target = new TestControl
                        {
                            Width = 10,
                            Height = 10,
                            Margin = new Thickness(-100, -100, 0, 0),
                        }
                    }
                }
            };

            Render(container);

            Assert.True(target.Rendered);
        }
コード例 #4
1
        public void RenderTransform_Should_Be_Respected()
        {
            TestControl target;
            var container = new Canvas
            {
                Width = 100,
                Height = 100,
                ClipToBounds = true,
                Children = new Controls.Controls
                {
                    (target = new TestControl
                    {
                        Width = 10,
                        Height = 10,
                        [Canvas.LeftProperty] = 110,
                        [Canvas.TopProperty] = 110,
                        RenderTransform = new TranslateTransform(-100, -100),
                    })
                }
            };

            Render(container);

            Assert.True(target.Rendered);
        }
コード例 #5
0
        public void Geometry_Clip_Clips_Path()
        {
            var target = new Canvas
            {
                Clip = StreamGeometry.Parse("F1 M 0,0  H 76 V 76 Z"),
                Width = 76,
                Height = 76,
                Children = new Avalonia.Controls.Controls
                {
                    new Path
                    {
                        Width = 32,
                        Height = 40,
                        [Canvas.LeftProperty] = 23,
                        [Canvas.TopProperty] = 18,
                        Stretch = Stretch.Fill,
                        Fill = Brushes.Black,
                        Data = StreamGeometry.Parse("F1 M 27,18L 23,26L 33,30L 24,38L 33,46L 23,50L 27,58L 45,58L 55,38L 45,18L 27,18 Z")
                    }
                }
            };

            RenderToFile(target);
            CompareImages();
        }
コード例 #6
0
        private void Render()
        {
            if (Document != null)
            {
                double width = Math.Min(MaxRenderWidth, Math.Max(MinRenderWidth, this.Bounds.Width - MinVariation - 13));

                if (forcedRerender || double.IsNaN(lastRenderedWidth) || width != lastRenderedWidth && width < lastRenderedWidth - MinVariation || width > lastRenderedWidth + MinVariation)
                {
                    Page pag;
                    Dictionary <string, string> linkDestinations;

                    try
                    {
                        pag = Renderer.RenderSinglePage(this.Document, width, out linkDestinations);
                    }
                    catch
                    {
                        pag = new Page(width, 0);
                        linkDestinations = new Dictionary <string, string>();
                    }

                    Dictionary <string, Delegate>       taggedActions         = new Dictionary <string, Delegate>();
                    Dictionary <string, Avalonia.Point> linkDestinationPoints = new Dictionary <string, Avalonia.Point>();

                    foreach (KeyValuePair <string, string> linkDestination in linkDestinations)
                    {
                        string url = linkDestination.Value;

                        taggedActions.Add(linkDestination.Key, (Func <RenderAction, IEnumerable <RenderAction> >)(act =>
                        {
                            act.PointerEnter += (s, e) =>
                            {
                                act.Parent.Cursor = new Avalonia.Input.Cursor(Avalonia.Input.StandardCursorType.Hand);
                            };

                            act.PointerLeave += (s, e) =>
                            {
                                act.Parent.Cursor = new Avalonia.Input.Cursor(Avalonia.Input.StandardCursorType.Arrow);
                            };

                            act.PointerPressed += (s, e) =>
                            {
                                if (url.StartsWith("#"))
                                {
                                    if (linkDestinationPoints.TryGetValue(url.Substring(1), out Avalonia.Point target))
                                    {
                                        ScrollViewer scrollViewer = this.FindControl <ScrollViewer>("ScrollViewer");

                                        scrollViewer.Offset = new Vector(Math.Max(Math.Min(scrollViewer.Offset.X, target.X), target.X - scrollViewer.Viewport.Width), target.Y);
                                    }
                                }
                                else
                                {
                                    System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo()
                                    {
                                        FileName = url, UseShellExecute = true
                                    });
                                }
                            };

                            if (act.ActionType == RenderAction.ActionTypes.Path)
                            {
                                linkDestinationPoints[linkDestination.Key] = act.Geometry.Bounds.TopLeft.Transform(act.Transform);
                            }
                            else if (act.ActionType == RenderAction.ActionTypes.Text)
                            {
                                linkDestinationPoints[linkDestination.Key] = act.Text.Bounds.TopLeft.Transform(act.Transform);
                            }
                            else if (act.ActionType == RenderAction.ActionTypes.RasterImage)
                            {
                                linkDestinationPoints[linkDestination.Key] = act.ImageDestination.Value.TopLeft.Transform(act.Transform);
                            }

                            return(new RenderAction[] { act });
                        }));

                        if (url.StartsWith("#"))
                        {
                            if (!taggedActions.ContainsKey(url.Substring(1)))
                            {
                                taggedActions.Add(url.Substring(1), (Func <RenderAction, IEnumerable <RenderAction> >)(act =>
                                {
                                    if (act.ActionType == RenderAction.ActionTypes.Path)
                                    {
                                        linkDestinationPoints[url.Substring(1)] = act.Geometry.Bounds.TopLeft.Transform(act.Transform);
                                    }
                                    else if (act.ActionType == RenderAction.ActionTypes.Text)
                                    {
                                        linkDestinationPoints[url.Substring(1)] = act.Text.Bounds.TopLeft.Transform(act.Transform);
                                    }
                                    else if (act.ActionType == RenderAction.ActionTypes.RasterImage)
                                    {
                                        linkDestinationPoints[url.Substring(1)] = act.ImageDestination.Value.TopLeft.Transform(act.Transform);
                                    }

                                    return(new RenderAction[] { act });
                                }));
                            }
                        }
                    }

                    Avalonia.Controls.Canvas can = pag.PaintToCanvas(false, taggedActions, false, this.TextConversionOption);

                    this.FindControl <ScrollViewer>("ScrollViewer").Content = can;
                    this.FindControl <ScrollViewer>("ScrollViewer").Padding = new Thickness(0, 0, 0, 0);
                    lastRenderedWidth = width;
                    forcedRerender    = false;
                }
                else
                {
                    this.FindControl <ScrollViewer>("ScrollViewer").Padding = new Thickness(0, 0, width - lastRenderedWidth, 0);
                }
            }
        }
コード例 #7
0
        public MainWindow()
        {
            InitializeComponent();

            // Create scene object
            Scene scene = new Scene();

            #region Populate scene with function surface

            // Number of sample points per coordinate
            int resolution = 20;

            // Boundary values
            double minX = -2;
            double maxX = 2;

            double minZ = -2;
            double maxZ = 2;

            // Arrays to hold point coordinate and vertex normals
            Point3D[][]            points  = new Point3D[resolution + 1][];
            NormalizedVector3D[][] normals = new NormalizedVector3D[resolution + 1][];

            // Compute the sample point coordinates and normals
            for (int x = 0; x <= resolution; x++)
            {
                points[x]  = new Point3D[resolution + 1];
                normals[x] = new NormalizedVector3D[resolution + 1];

                // Convert sample index to coordinate
                double X = minX + x * (maxX - minX) / resolution;

                for (int z = 0; z <= resolution; z++)
                {
                    // Convert sample index to coordinate
                    double Z = minZ + z * (maxZ - minZ) / resolution;

                    // Compute function f(x, z) = 4 * x * exp(-(x^2 + z^2))
                    double funcVal = 4 * X * Math.Exp(-(X * X + Z * Z));

                    // Scale everything by 100 to avoid underflow
                    points[x][z] = new Point3D(X * 100, -funcVal * 100, Z * 100);

                    // Compute the surface normal using the gradient of the function F(x, y, z) = f(x, z) + y (note that the y axis points down)
                    double normalX = 4 * Math.Exp(-(X * X + Z * Z)) * (1 - 2 * X * X);
                    double normalY = 1;
                    double normalZ = -8 * X * Z * Math.Exp(-(X * X + Z * Z));

                    NormalizedVector3D normal = new NormalizedVector3D(normalX, normalY, normalZ);

                    normals[x][z] = normal;
                }
            }

            // Create triangles using the previously computed coordinates and normals
            for (int x = 0; x < resolution; x++)
            {
                for (int z = 0; z < resolution; z++)
                {
                    Triangle3DElement triangle1 = new Triangle3DElement(points[x][z + 1], points[x + 1][z + 1], points[x + 1][z], normals[x][z + 1], normals[x + 1][z + 1], normals[x + 1][z]);
                    triangle1.Fill.Add(new PhongMaterial(Colours.CornflowerBlue)
                    {
                        SpecularReflectionCoefficient = 0
                    });

                    Triangle3DElement triangle2 = new Triangle3DElement(points[x][z + 1], points[x + 1][z], points[x][z], normals[x][z + 1], normals[x + 1][z], normals[x][z]);
                    triangle2.Fill.Add(new PhongMaterial(Colours.CornflowerBlue)
                    {
                        SpecularReflectionCoefficient = 0
                    });

                    scene.AddElement(triangle1);
                    scene.AddElement(triangle2);

                    // Also add the reversed triangles, otherwise the "bottom" side of the surface would be culled when looking from below
                    // Not reversing the normals, otherwise everything at the it would be dark (unless we also add another light source)

                    Triangle3DElement triangle3 = new Triangle3DElement(points[x][z + 1], points[x + 1][z], points[x + 1][z + 1], normals[x][z + 1], normals[x + 1][z], normals[x + 1][z + 1]);
                    triangle3.Fill.Add(new PhongMaterial(Colours.CornflowerBlue)
                    {
                        SpecularReflectionCoefficient = 0
                    });

                    Triangle3DElement triangle4 = new Triangle3DElement(points[x][z + 1], points[x][z], points[x + 1][z], normals[x][z + 1], normals[x][z], normals[x + 1][z]);
                    triangle4.Fill.Add(new PhongMaterial(Colours.CornflowerBlue)
                    {
                        SpecularReflectionCoefficient = 0
                    });

                    scene.AddElement(triangle3);
                    scene.AddElement(triangle4);
                }
            }

            #endregion

            // Create a camera
            PerspectiveCamera camera = new PerspectiveCamera(new Point3D(-300, -200, -400), new NormalizedVector3D(3, 2, 4), 100, new Size(115, 115), 1);

            // Generic renderer initialised as a VectorRenderer
            IRenderer renderer = new VectorRenderer()
            {
                DefaultOverFill = 0.05
            };

            // Main light source
            ParallelLightSource light = new ParallelLightSource(0.75, new NormalizedVector3D(0.25, 1, 0.1));

            // Light source array
            ILightSource[] lights = new ILightSource[] { new AmbientLightSource(0.1), light };

            // Render the scene
            Page pag = renderer.Render(scene, lights, camera);

            // Display the rendered scene on the window
            Avalonia.Controls.Canvas can = pag.PaintToCanvas();
            this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Children.Add(can);
            this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Width  = can.Width;
            this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Height = can.Height;

            // Function to recreate the renderer based on the options selected in the UI
            void updateRenderer()
            {
                // VectorRenderer
                if (this.FindControl <ComboBox>("RendererBox").SelectedIndex == 0)
                {
                    renderer = new VectorRenderer()
                    {
                        DefaultOverFill = 0.05
                    };

                    this.FindControl <TextBlock>("ResolutionBlock").IsVisible       = false;
                    this.FindControl <TextBlock>("ResolutionHeightBlock").IsVisible = false;
                    this.FindControl <TextBlock>("ResolutionWidthBlock").IsVisible  = false;

                    this.FindControl <NumericUpDown>("ResolutionWidthNUD").IsVisible  = false;
                    this.FindControl <NumericUpDown>("ResolutionHeightNUD").IsVisible = false;

                    this.FindControl <CheckBox>("AntialiasingBox").IsVisible = false;
                }
                // RasterRenderer
                else if (this.FindControl <ComboBox>("RendererBox").SelectedIndex == 1)
                {
                    int width  = (int)Math.Round(this.FindControl <NumericUpDown>("ResolutionWidthNUD").Value);
                    int height = (int)Math.Round(this.FindControl <NumericUpDown>("ResolutionHeightNUD").Value);

                    renderer = new RasterRenderer(width, height);

                    this.FindControl <TextBlock>("ResolutionBlock").IsVisible       = true;
                    this.FindControl <TextBlock>("ResolutionHeightBlock").IsVisible = true;
                    this.FindControl <TextBlock>("ResolutionWidthBlock").IsVisible  = true;

                    this.FindControl <NumericUpDown>("ResolutionWidthNUD").IsVisible  = true;
                    this.FindControl <NumericUpDown>("ResolutionHeightNUD").IsVisible = true;

                    this.FindControl <CheckBox>("AntialiasingBox").IsVisible = false;
                }
                // RaycastingRenderer
                else if (this.FindControl <ComboBox>("RendererBox").SelectedIndex == 2)
                {
                    int width  = (int)Math.Round(this.FindControl <NumericUpDown>("ResolutionWidthNUD").Value);
                    int height = (int)Math.Round(this.FindControl <NumericUpDown>("ResolutionHeightNUD").Value);

                    this.FindControl <TextBlock>("ResolutionBlock").IsVisible       = true;
                    this.FindControl <TextBlock>("ResolutionHeightBlock").IsVisible = true;
                    this.FindControl <TextBlock>("ResolutionWidthBlock").IsVisible  = true;

                    this.FindControl <NumericUpDown>("ResolutionWidthNUD").IsVisible  = true;
                    this.FindControl <NumericUpDown>("ResolutionHeightNUD").IsVisible = true;

                    this.FindControl <CheckBox>("AntialiasingBox").IsVisible = true;

                    renderer = new RaycastingRenderer(width, height)
                    {
                        AntiAliasing = this.FindControl <CheckBox>("AntialiasingBox").IsChecked == true ? RaycastingRenderer.AntiAliasings.Bilinear4X : RaycastingRenderer.AntiAliasings.None
                    };
                }

                // Render the scene and display it on the window
                Avalonia.Controls.Canvas can = renderer.Render(scene, lights, camera).PaintToCanvas();
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Children.Clear();
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Children.Add(can);
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Width  = can.Width;
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Height = can.Height;
            }

            // Add events to controls changing rendering parameters
            this.FindControl <ComboBox>("RendererBox").SelectionChanged          += (s, e) => updateRenderer();
            this.FindControl <NumericUpDown>("ResolutionWidthNUD").ValueChanged  += (s, e) => updateRenderer();
            this.FindControl <NumericUpDown>("ResolutionHeightNUD").ValueChanged += (s, e) => updateRenderer();
            this.FindControl <CheckBox>("AntialiasingBox").Click += (s, e) => updateRenderer();

            // Camera reset button
            this.FindControl <Button>("ResetCameraButton").Click += (s, e) =>
            {
                camera = new PerspectiveCamera(new Point3D(-300, -200, -400), new NormalizedVector3D(3, 2, 4), 100, new Size(115, 115), 1);
                Avalonia.Controls.Canvas can = renderer.Render(scene, lights, camera).PaintToCanvas();
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Children.Clear();
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Children.Add(can);
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Width  = can.Width;
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Height = can.Height;
            };


            // Code to handle mouse events moving the camera on the canvas

            bool         isPressed    = false;
            PointerPoint pointerPress = null;
            double       lastTheta    = 0;
            double       lastPhi      = 0;
            double       lastX        = 0;
            double       lastY        = 0;

            // Start drag
            this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").PointerPressed += (s, e) =>
            {
                pointerPress = e.GetCurrentPoint(this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas"));
                lastTheta    = 0;
                lastPhi      = 0;
                lastX        = 0;
                lastY        = 0;
                isPressed    = true;
            };

            // Drag end
            this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").PointerReleased += (s, e) =>
            {
                isPressed = false;
            };

            this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").PointerMoved += (s, e) =>
            {
                // While dragging
                if (isPressed)
                {
                    PointerPoint point = e.GetCurrentPoint(this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas"));

                    // Left button: orbit
                    if (pointerPress.Properties.PointerUpdateKind == PointerUpdateKind.LeftButtonPressed)
                    {
                        double dx = (point.Position.X - pointerPress.Position.X) / this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Width;
                        double dy = (point.Position.Y - pointerPress.Position.Y) / this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Height;
                        if (dx >= -1 && dx <= 1 && dy >= -1 && dy <= 1)
                        {
                            double theta = Math.Asin(dx) * 2;
                            double phi   = Math.Asin(dy) * 2;

                            camera.Orbit(theta - lastTheta, phi - lastPhi);

                            Avalonia.Controls.Canvas can = renderer.Render(scene, lights, camera).PaintToCanvas();
                            this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Children.Clear();
                            this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Children.Add(can);
                            this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Width  = can.Width;
                            this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Height = can.Height;

                            lastTheta = theta;
                            lastPhi   = phi;
                        }
                    }
                    // Right button: pan
                    else if (pointerPress.Properties.PointerUpdateKind == PointerUpdateKind.RightButtonPressed)
                    {
                        double dx = point.Position.X - pointerPress.Position.X;
                        double dy = point.Position.Y - pointerPress.Position.Y;

                        camera.Pan(dx - lastX, dy - lastY);
                        Avalonia.Controls.Canvas can = renderer.Render(scene, lights, camera).PaintToCanvas();
                        this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Children.Clear();
                        this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Children.Add(can);
                        this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Width  = can.Width;
                        this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Height = can.Height;

                        lastX = dx;
                        lastY = dy;
                    }
                }
            };

            // Mouse wheel: zoom
            this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").PointerWheelChanged += (s, e) =>
            {
                camera.Zoom(e.Delta.Y * 100);
                Avalonia.Controls.Canvas can = renderer.Render(scene, lights, camera).PaintToCanvas();
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Children.Clear();
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Children.Add(can);
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Width  = can.Width;
                this.FindControl <Avalonia.Controls.Canvas>("ContainerCanvas").Height = can.Height;
            };
        }