Browse Source

Add comments, remove todos, extend example.

pull/7402/head
Jan-Peter Zurek 5 years ago
parent
commit
e8f2d3e3f3
  1. 162
      samples/RenderDemo/Pages/Transform3DPage.axaml
  2. 44
      samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs
  3. 50
      src/Avalonia.Visuals/Matrix.cs
  4. 73
      src/Avalonia.Visuals/Media/Rotate3DTransform.cs
  5. 29
      src/Avalonia.Visuals/Point.cs

162
samples/RenderDemo/Pages/Transform3DPage.axaml

@ -2,12 +2,12 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="400"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="700"
x:Class="RenderDemo.Pages.Transform3DPage">
<UserControl.Styles>
<Styles>
<Styles.Resources>
<Template x:Key="Acorn">
<Template x:Key="TestContent">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,*" Margin="5">
<TextBlock>I'm a text</TextBlock>
<Button Grid.Row="0" Grid.Column="1" Content="A Button"></Button>
@ -21,11 +21,9 @@
</Template>
</Styles.Resources>
<Style Selector="Border.Test">
<Setter Property="Canvas.Top" Value="-100" />
<Setter Property="Canvas.Left" Value="-100" />
<Setter Property="Width" Value="200" />
<Setter Property="Height" Value="200" />
<Setter Property="Child" Value="{StaticResource Acorn}" />
<Setter Property="Child" Value="{StaticResource TestContent}" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="Black" />
</Style>
@ -41,23 +39,23 @@
<Animation Duration="0:0:10"
IterationCount="Infinite">
<KeyFrame Cue="0%">
<Setter Property="Rotate3DTransform.RotationX" Value="0" />
<Setter Property="Rotate3DTransform.AngleX" Value="0" />
<Setter Property="ZIndex" Value="4" />
</KeyFrame>
<KeyFrame Cue="25%">
<Setter Property="Rotate3DTransform.RotationX" Value="90" />
<Setter Property="Rotate3DTransform.AngleX" Value="90" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="50%">
<Setter Property="Rotate3DTransform.RotationX" Value="180" />
<Setter Property="Rotate3DTransform.AngleX" Value="180" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="75%">
<Setter Property="Rotate3DTransform.RotationX" Value="270" />
<Setter Property="Rotate3DTransform.AngleX" Value="270" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="Rotate3DTransform.RotationX" Value="360" />
<Setter Property="Rotate3DTransform.AngleX" Value="360" />
<Setter Property="ZIndex" Value="4" />
</KeyFrame>
</Animation>
@ -69,23 +67,23 @@
<Animation Duration="0:0:10"
IterationCount="Infinite">
<KeyFrame Cue="0%">
<Setter Property="Rotate3DTransform.RotationX" Value="90" />
<Setter Property="Rotate3DTransform.AngleX" Value="90" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="25%">
<Setter Property="Rotate3DTransform.RotationX" Value="180" />
<Setter Property="Rotate3DTransform.AngleX" Value="180" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="50%">
<Setter Property="Rotate3DTransform.RotationX" Value="270" />
<Setter Property="Rotate3DTransform.AngleX" Value="270" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="75%">
<Setter Property="Rotate3DTransform.RotationX" Value="360" />
<Setter Property="Rotate3DTransform.AngleX" Value="360" />
<Setter Property="ZIndex" Value="4" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="Rotate3DTransform.RotationX" Value="450" />
<Setter Property="Rotate3DTransform.AngleX" Value="450" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
</Animation>
@ -97,23 +95,23 @@
<Animation Duration="0:0:10"
IterationCount="Infinite">
<KeyFrame Cue="0%">
<Setter Property="Rotate3DTransform.RotationX" Value="180" />
<Setter Property="Rotate3DTransform.AngleX" Value="180" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="25%">
<Setter Property="Rotate3DTransform.RotationX" Value="270" />
<Setter Property="Rotate3DTransform.AngleX" Value="270" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="50%">
<Setter Property="Rotate3DTransform.RotationX" Value="360" />
<Setter Property="Rotate3DTransform.AngleX" Value="360" />
<Setter Property="ZIndex" Value="4" />
</KeyFrame>
<KeyFrame Cue="75%">
<Setter Property="Rotate3DTransform.RotationX" Value="450" />
<Setter Property="Rotate3DTransform.AngleX" Value="450" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="Rotate3DTransform.RotationX" Value="540" />
<Setter Property="Rotate3DTransform.AngleX" Value="540" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
</Animation>
@ -125,67 +123,119 @@
<Animation Duration="0:0:10"
IterationCount="Infinite">
<KeyFrame Cue="0%">
<Setter Property="Rotate3DTransform.RotationX" Value="270" />
<Setter Property="Rotate3DTransform.AngleX" Value="270" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="25%">
<Setter Property="Rotate3DTransform.RotationX" Value="360" />
<Setter Property="Rotate3DTransform.AngleX" Value="360" />
<Setter Property="ZIndex" Value="4" />
</KeyFrame>
<KeyFrame Cue="50%">
<Setter Property="Rotate3DTransform.RotationX" Value="450" />
<Setter Property="Rotate3DTransform.AngleX" Value="450" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="75%">
<Setter Property="Rotate3DTransform.RotationX" Value="540" />
<Setter Property="Rotate3DTransform.AngleX" Value="540" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="Rotate3DTransform.RotationX" Value="630" />
<Setter Property="Rotate3DTransform.AngleX" Value="630" />
<Setter Property="ZIndex" Value="1" />
</KeyFrame>
</Animation>
</Style.Animations>
<Setter Property="Background" Value="Orange" />
</Style>
<Style Selector="Border.Free">
<Setter Property="Width" Value="200" />
<Setter Property="Height" Value="200" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="Background">
<LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="1" Color="Blue"/>
</LinearGradientBrush>
</Setter>
</Style>
<Style Selector="Label">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style Selector="Slider">
<Setter Property="Width" Value="100" />
</Style>
</Styles>
</UserControl.Styles>
<Grid RowDefinitions="*,Auto">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" ClipToBounds="False">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" ClipToBounds="False">
<StackPanel.Clock>
<Clock />
</StackPanel.Clock>
<Canvas ClipToBounds="False">
<Border Classes="Test Rect1">
<Grid ColumnDefinitions="*,50,*" RowDefinitions="*,Auto">
<Canvas Grid.Row="0" Grid.Column="0" ClipToBounds="False" Width="200" Height="200" Margin="20">
<Border Classes="Test Rect1">
<Border.RenderTransform>
<Rotate3DTransform CenterZ="-100"
Depth="{Binding Depth}"/>
</Border.RenderTransform>
</Border>
<Border Classes="Test Rect2">
<Border.RenderTransform>
<Rotate3DTransform CenterZ="-100"
Depth="{Binding Depth}"/>
</Border.RenderTransform>
</Border>
<Border Classes="Test Rect3">
<Border.RenderTransform>
<Rotate3DTransform CenterZ="-100"
Depth="{Binding Depth}"/>
</Border.RenderTransform>
</Border>
<Border Classes="Test Rect4">
<Border.RenderTransform>
<Rotate3DTransform CenterZ="-100"
Depth="{Binding Depth}"/>
</Border.RenderTransform>
</Border>
</Canvas>
<Grid Grid.Column="0" Grid.Row="1" RowDefinitions="*,*,*,*,*,*,*" ColumnDefinitions="*,Auto" Margin="20">
<Label Grid.Row="0" Grid.Column="0">Depth: </Label>
<Slider Width="100" Grid.Row="0" Grid.Column="1" Value="{Binding Depth}" Minimum="100" Maximum="300" />
</Grid>
<Border Grid.Row="0" Grid.Column="2" Classes="Free">
<Border.RenderTransform>
<Rotate3DTransform CenterZ="-100"
Depth="{Binding Depth}"/>
<Rotate3DTransform Depth="{Binding Depth2}"
CenterX="{Binding CenterX}"
CenterY="{Binding CenterY}"
CenterZ="{Binding CenterZ}"
AngleX="{Binding AngleX}"
AngleY="{Binding AngleY}"
AngleZ="{Binding AngleZ}"/>
</Border.RenderTransform>
</Border>
<!--<Border Classes="Test Rect2">
<Border.RenderTransform>
<Rotate3DTransform CenterZ="-100"
Depth="{Binding Depth}"/>
</Border.RenderTransform>
</Border>-->
<Border Classes="Test Rect3">
<Border.RenderTransform>
<Rotate3DTransform CenterZ="-100"
Depth="{Binding Depth}"/>
</Border.RenderTransform>
</Border>
<!--<Border Classes="Test Rect4">
<Border.RenderTransform>
<Rotate3DTransform CenterZ="-100"
Depth="{Binding Depth}"/>
</Border.RenderTransform>
</Border>-->
</Canvas>
</StackPanel>
<StackPanel Grid.Row="1">
<TextBlock>Depth: </TextBlock>
<TextBlock Text="{Binding Depth}" />
<Slider VerticalAlignment="Bottom" Value="{Binding Depth}" Minimum="100" Maximum="300" />
<Grid Grid.Column="2" Grid.Row="1" RowDefinitions="*,*,*,*,*,*,*" ColumnDefinitions="*,Auto" Margin="20">
<Label Grid.Row="0" Grid.Column="0">Depth: </Label>
<Slider Grid.Row="0" Grid.Column="1" Value="{Binding Depth2}" Minimum="100" Maximum="300" />
<Label Grid.Row="1" Grid.Column="0">Center X: </Label>
<Slider Grid.Row="1" Grid.Column="1" Value="{Binding CenterX}" Minimum="-100" Maximum="100" />
<Label Grid.Row="2" Grid.Column="0">Center Y: </Label>
<Slider Grid.Row="2" Grid.Column="1" Value="{Binding CenterY}" Minimum="-100" Maximum="100" />
<Label Grid.Row="3" Grid.Column="0">Center Z: </Label>
<Slider Grid.Row="3" Grid.Column="1" Value="{Binding CenterZ}" Minimum="-100" Maximum="100" />
<Label Grid.Row="4" Grid.Column="0">Angle X: </Label>
<Slider Grid.Row="4" Grid.Column="1" Value="{Binding AngleX}" Minimum="0" Maximum="360" />
<Label Grid.Row="5" Grid.Column="0">Angle Y: </Label>
<Slider Grid.Row="5" Grid.Column="1" Value="{Binding AngleY}" Minimum="0" Maximum="360" />
<Label Grid.Row="6" Grid.Column="0">Angle Z: </Label>
<Slider Grid.Row="6" Grid.Column="1" Value="{Binding AngleZ}" Minimum="0" Maximum="360" />
</Grid>
</Grid>
</StackPanel>
</Grid>
</UserControl>

44
samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs

@ -8,10 +8,54 @@ namespace RenderDemo.ViewModels
{
private double _depth = 200;
private double _depth2 = 200;
private double _centerX = 0;
private double _centerY = 0;
private double _centerZ = 0;
private double _angleX = 0;
private double _angleY = 0;
private double _angleZ = 0;
public double Depth
{
get => _depth;
set => RaiseAndSetIfChanged(ref _depth, value);
}
public double Depth2
{
get => _depth2;
set => RaiseAndSetIfChanged(ref _depth2, value);
}
public double CenterX
{
get => _centerX;
set => RaiseAndSetIfChanged(ref _centerX, value);
}
public double CenterY
{
get => _centerY;
set => RaiseAndSetIfChanged(ref _centerY, value);
}
public double CenterZ
{
get => _centerZ;
set => RaiseAndSetIfChanged(ref _centerZ, value);
}
public double AngleX
{
get => _angleX;
set => RaiseAndSetIfChanged(ref _angleX, value);
}
public double AngleY
{
get => _angleY;
set => RaiseAndSetIfChanged(ref _angleY, value);
}
public double AngleZ
{
get => _angleZ;
set => RaiseAndSetIfChanged(ref _angleZ, value);
}
}
}

50
src/Avalonia.Visuals/Matrix.cs

@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.Linq;
using System.Numerics;
using Avalonia.Utilities;
namespace Avalonia
@ -277,7 +278,7 @@ namespace Avalonia
{
return angle * 0.0174532925;
}
/// <summary>
/// Appends another matrix as post-multiplication operation.
/// Equivalent to this * value;
@ -310,14 +311,57 @@ namespace Avalonia
/// </remarks>
public double GetDeterminant()
{
//return (_m11 * _m22) - (_m12 * _m21); //TODO: ensure new implementation yields the same result as before, when pers is 0,0,1
// implemented using "Laplace expansion":
return _m11 * (_m22 * _m33 - _m23 * _m32)
- _m12 * (_m21 * _m33 - _m23 * _m31)
+ _m13 * (_m21 * _m32 - _m22 * _m31);
}
/// <summary>
/// Transforms the point with the matrix
/// </summary>
/// <param name="p">The point to be transformed</param>
/// <returns>The transformed point</returns>
public Point Transform(Point p)
{
Point transformedResult;
// If this matrix contains a non-affine transform with need to extend
// the point to a 3D vector and flatten it back for 2d display
// by multiplying X and Y with the inverse of the Z axis.
// The code below also works with affine transformations, but for performance (and compatibility)
// reasons we will use the more complex calculation only if necessary
if (ContainsPerspective())
{
var m44 = new Matrix4x4(
(float)M11, (float)M12, (float)M13, 0,
(float)M21, (float)M22, (float)M23, 0,
(float)M31, (float)M32, (float)M33, 0,
0, 0, 0, 1
);
var vector = new Vector3((float)p.X, (float)p.Y, 1);
var transformedVector = Vector3.Transform(vector, m44);
var z = 1 / transformedVector.Z;
transformedResult = new Point(transformedVector.X * z, transformedVector.Y * z);
}
else
{
var x = p.X;
var y = p.Y;
var xAdd = y * M21 + M31;
var yAdd = x * M12 + M32;
x *= M11;
x += xAdd;
y *= M22;
y += yAdd;
transformedResult = new Point(x, y);
}
return transformedResult;
}
/// <summary>
/// Returns a boolean indicating whether the matrix is equal to the other given matrix.
/// </summary>

73
src/Avalonia.Visuals/Media/Rotate3DTransform.cs

@ -1,5 +1,6 @@
using System;
using System.Numerics;
using Avalonia.Animation.Animators;
namespace Avalonia.Media;
@ -9,22 +10,22 @@ namespace Avalonia.Media;
public class Rotate3DTransform : Transform
{
/// <summary>
/// Defines the <see cref="RotationX"/> property.
/// Defines the <see cref="AngleX"/> property.
/// </summary>
public static readonly StyledProperty<double> RotationXProperty =
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(RotationX));
public static readonly StyledProperty<double> AngleXProperty =
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(AngleX));
/// <summary>
/// Defines the <see cref="RotationY"/> property.
/// Defines the <see cref="AngleY"/> property.
/// </summary>
public static readonly StyledProperty<double> RotationYProperty =
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(RotationY));
public static readonly StyledProperty<double> AngleYProperty =
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(AngleY));
/// <summary>
/// Defines the <see cref="RotationZ"/> property.
/// Defines the <see cref="AngleZ"/> property.
/// </summary>
public static readonly StyledProperty<double> RotationZProperty =
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(RotationZ));
public static readonly StyledProperty<double> AngleZProperty =
AvaloniaProperty.Register<Rotate3DTransform, double>(nameof(AngleZ));
/// <summary>
@ -58,9 +59,9 @@ public class Rotate3DTransform : Transform
/// </summary>
public Rotate3DTransform()
{
this.GetObservable(RotationXProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(RotationYProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(RotationZProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(AngleXProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(AngleYProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(AngleZProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(CenterXProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(CenterYProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(CenterZProperty).Subscribe(_ => RaiseChanged());
@ -70,23 +71,23 @@ public class Rotate3DTransform : Transform
/// <summary>
/// Initializes a new instance of the <see cref="Rotate3DTransform"/> class.
/// </summary>
/// <param name="rotationX">The rotation around the X-Axis</param>
/// <param name="rotationY">The rotation around the Y-Axis</param>
/// <param name="rotationZ">The rotation around the Z-Axis</param>
/// <param name="angleX">The rotation around the X-Axis</param>
/// <param name="angleY">The rotation around the Y-Axis</param>
/// <param name="angleZ">The rotation around the Z-Axis</param>
/// <param name="centerX">The origin of the X-Axis</param>
/// <param name="centerY">The origin of the Y-Axis</param>
/// <param name="centerZ">The origin of the Z-Axis</param>
public Rotate3DTransform(
double rotationX,
double rotationY,
double rotationZ,
double angleX,
double angleY,
double angleZ,
double centerX,
double centerY,
double centerZ) : this()
{
RotationX = rotationX;
RotationY = rotationY;
RotationZ = rotationZ;
AngleX = angleX;
AngleY = angleY;
AngleZ = angleZ;
CenterX = centerX;
CenterY = centerY;
CenterZ = centerZ;
@ -95,32 +96,32 @@ public class Rotate3DTransform : Transform
/// <summary>
/// Sets the rotation around the X-Axis
/// </summary>
public double RotationX
public double AngleX
{
get => GetValue(RotationXProperty);
set => SetValue(RotationXProperty, value);
get => GetValue(AngleXProperty);
set => SetValue(AngleXProperty, value);
}
/// <summary>
/// Sets the rotation around the Y-Axis
/// </summary>
public double RotationY
public double AngleY
{
get => GetValue(RotationYProperty);
set => SetValue(RotationYProperty, value);
get => GetValue(AngleYProperty);
set => SetValue(AngleYProperty, value);
}
/// <summary>
/// Sets the rotation around the Z-Axis
/// </summary>
public double RotationZ
public double AngleZ
{
get => GetValue(RotationZProperty);
set => SetValue(RotationZProperty, value);
get => GetValue(AngleZProperty);
set => SetValue(AngleZProperty, value);
}
/// <summary>
/// Moves the origin of the X-Axis
/// Moves the origin the X-Axis rotates around
/// </summary>
public double CenterX
{
@ -129,7 +130,7 @@ public class Rotate3DTransform : Transform
}
/// <summary>
/// Moves the origin of the Y-Axis
/// Moves the origin the Y-Axis rotates around
/// </summary>
public double CenterY
{
@ -138,7 +139,7 @@ public class Rotate3DTransform : Transform
}
/// <summary>
/// Moves the origin of the Z-Axis
/// Moves the origin the Z-Axis rotates around
/// </summary>
public double CenterZ
{
@ -166,9 +167,9 @@ public class Rotate3DTransform : Transform
matrix44 *= Matrix4x4.CreateTranslation(-(float)CenterX, -(float)CenterY, -(float)CenterZ);
matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(RotationX));
matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(RotationY));
matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(RotationZ));
matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(AngleX));
matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(AngleY));
matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(AngleZ));
matrix44 *= Matrix4x4.CreateTranslation((float)CenterX, (float)CenterY, (float)CenterZ);

29
src/Avalonia.Visuals/Point.cs

@ -243,34 +243,7 @@ namespace Avalonia
/// </summary>
/// <param name="transform">The transform.</param>
/// <returns>The transformed point.</returns>
public Point Transform(Matrix transform)
{
if (transform.ContainsPerspective())
{
var m44 = new Matrix4x4(
(float)transform.M11, (float)transform.M12, (float)transform.M13, 0,
(float)transform.M21, (float)transform.M22, (float)transform.M23, 0,
(float)transform.M31, (float)transform.M32, (float)transform.M33, 0,
0, 0, 0, 1
);
var vector = new Vector3((float)X, (float)Y, 1);
var transformedVector = Vector3.Transform(vector, m44);
var z = 1 / transformedVector.Z;
return new Point(transformedVector.X * z, transformedVector.Y * z);
}
var x = X;
var y = Y;
var xadd = y * transform.M21 + transform.M31;
var yadd = x * transform.M12 + transform.M32;
x *= transform.M11;
x += xadd;
y *= transform.M22;
y += yadd;
return new Point(x, y);
}
public Point Transform(Matrix transform) => transform.Transform(this);
/// <summary>
/// Returns a new point with the specified X coordinate.

Loading…
Cancel
Save