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); }
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(); }
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); }
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); }
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(); }
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); } } }
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; }; }