Skip to content

Commit

Permalink
use matrix
Browse files Browse the repository at this point in the history
  • Loading branch information
RomanSoloweow committed Jul 3, 2020
1 parent 22d284d commit ed27f81
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 18 deletions.
129 changes: 129 additions & 0 deletions SimpleStateMachineNodeEditor/Helpers/Extensions/MatrixExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using System.Windows;
using System.Windows.Media;
using static System.Math;

namespace SimpleStateMachineNodeEditor.Helpers.Extensions
{
public static class MatrixExtension
{
/// <summary>
/// Creates a translation matrix using the specified offsets.
/// </summary>
/// <param name="offsetX">X-coordinate offset.</param>
/// <param name="offsetY">Y-coordinate offset.</param>
/// <returns>The created translation matrix.</returns>
public static Matrix Translate(double offsetX, double offsetY)
{
return new Matrix(1.0, 0.0, 0.0, 1.0, offsetX, offsetY);
}

/// <summary>
/// Prepends a translation around the center of provided matrix.
/// </summary>
/// <param name="matrix">The matrix to prepend translation.</param>
/// <param name="offsetX">X-coordinate offset.</param>
/// <param name="offsetY">Y-coordinate offset.</param>
/// <returns>The created translation matrix.</returns>
public static Matrix TranslatePrepend(Matrix matrix, double offsetX, double offsetY)
{
return Translate(offsetX, offsetY) * matrix;
}

/// <summary>
/// Creates a matrix that scales along the x-axis and y-axis.
/// </summary>
/// <param name="scaleX">Scaling factor that is applied along the x-axis.</param>
/// <param name="scaleY">Scaling factor that is applied along the y-axis.</param>
/// <returns>The created scaling matrix.</returns>
public static Matrix Scale(double scaleX, double scaleY)
{
return new Matrix(scaleX, 0, 0, scaleY, 0.0, 0.0);
}

/// <summary>
/// Creates a matrix that is scaling from a specified center.
/// </summary>
/// <param name="scaleX">Scaling factor that is applied along the x-axis.</param>
/// <param name="scaleY">Scaling factor that is applied along the y-axis.</param>
/// <param name="centerX">The center X-coordinate of the scaling.</param>
/// <param name="centerY">The center Y-coordinate of the scaling.</param>
/// <returns>The created scaling matrix.</returns>
public static Matrix ScaleAt(double scaleX, double scaleY, double centerX, double centerY)
{
return new Matrix(scaleX, 0, 0, scaleY, centerX - (scaleX * centerX), centerY - (scaleY * centerY));
}

/// <summary>
/// Prepends a scale around the center of provided matrix.
/// </summary>
/// <param name="matrix">The matrix to prepend scale.</param>
/// <param name="scaleX">Scaling factor that is applied along the x-axis.</param>
/// <param name="scaleY">Scaling factor that is applied along the y-axis.</param>
/// <param name="centerX">The center X-coordinate of the scaling.</param>
/// <param name="centerY">The center Y-coordinate of the scaling.</param>
/// <returns>The created scaling matrix.</returns>
public static Matrix ScaleAtPrepend(Matrix matrix, double scaleX, double scaleY, double centerX, double centerY)
{
return ScaleAt(scaleX, scaleY, centerX, centerY) * matrix;
}

/// <summary>
/// Creates a skew matrix.
/// </summary>
/// <param name="angleX">Angle of skew along the X-axis in radians.</param>
/// <param name="angleY">Angle of skew along the Y-axis in radians.</param>
/// <returns>When the method completes, contains the created skew matrix.</returns>
public static Matrix Skew(float angleX, float angleY)
{
return new Matrix(1.0, Tan(angleX), Tan(angleY), 1.0, 0.0, 0.0);
}

/// <summary>
/// Creates a matrix that rotates.
/// </summary>
/// <param name="radians">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis.</param>
/// <returns>The created rotation matrix.</returns>
public static Matrix Rotation(double radians)
{
double cos = Cos(radians);
double sin = Sin(radians);
return new Matrix(cos, sin, -sin, cos, 0, 0);
}

/// <summary>
/// Creates a matrix that rotates about a specified center.
/// </summary>
/// <param name="angle">Angle of rotation in radians.</param>
/// <param name="centerX">The center X-coordinate of the rotation.</param>
/// <param name="centerY">The center Y-coordinate of the rotation.</param>
/// <returns>The created rotation matrix.</returns>
public static Matrix Rotation(double angle, double centerX, double centerY)
{
return Translate(-centerX, -centerY) * Rotation(angle) * Translate(centerX, centerY);
}

/// <summary>
/// Creates a matrix that rotates about a specified center.
/// </summary>
/// <param name="angle">Angle of rotation in radians.</param>
/// <param name="center">The center of the rotation.</param>
/// <returns>The created rotation matrix.</returns>
public static Matrix Rotation(double angle, Vector center)
{
return Translate(-center.X, -center.Y) * Rotation(angle) * Translate(center.X, center.Y);
}

/// <summary>
/// Transforms a point by this matrix.
/// </summary>
/// <param name="matrix">The matrix to use as a transformation matrix.</param>
/// <param name="point">>The original point to apply the transformation.</param>
/// <returns>The result of the transformation for the input point.</returns>
public static Point TransformPoint(Matrix matrix, Point point)
{
return new Point(
(point.X * matrix.M11) + (point.Y * matrix.M21) + matrix.OffsetX,
(point.X * matrix.M12) + (point.Y * matrix.M22) + matrix.OffsetY);
}
}
}
2 changes: 1 addition & 1 deletion SimpleStateMachineNodeEditor/Helpers/MyUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public static void FindParents<TParent1, TParent2>(DependencyObject currentObjec
} while ((parent1 == default(TParent1)) || (parent2 == default(TParent2)));
}

public static void PanelToImage(Panel panel, string filename, ImageFormats format)
public static void PanelToImage(FrameworkElement panel, string filename, ImageFormats format)
{
int width = (int)panel.ActualWidth;
int height = (int)panel.ActualHeight;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ ReactiveUI 11.4.17</PackageReleaseNotes>
<PackageReference Include="ReactiveUI.WPF" Version="11.4.17" />
<PackageReference Include="Splat" Version="9.4.5" />
<PackageReference Include="Splat.Drawing" Version="9.4.5" />
<PackageReference Include="Wpf.Controls.PanAndZoom" Version="2.3.3" />
<PackageReference Include="Wpf.Controls.PanAndZoom" Version="3.0.999-build20200622-01" />
</ItemGroup>

<ItemGroup>
Expand Down
13 changes: 6 additions & 7 deletions SimpleStateMachineNodeEditor/View/ViewNodesCanvas.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
xmlns:paz="clr-namespace:Wpf.Controls.PanAndZoom;assembly=Wpf.Controls.PanAndZoom"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Focusable="True" AllowDrop="True" ClipToBounds="True">
<paz:ZoomBorder Name="zoomBorder" Stretch="None" ZoomSpeed="1.2"
<!--<paz:ZoomBorder Name="zoomBorder" Stretch="None" ZoomSpeed="1.2"
Background="SlateBlue" ClipToBounds="True" Focusable="True"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Grid.Row="4" Grid.Column="1" >
<Canvas x:Name="Canvas" Background="{DynamicResource ColorNodesCanvasBackground}">
Grid.Row="4" Grid.Column="1" EnablePan="False" MaxZoomX="5" MaxZoomY="5" MinZoomX="0.2" MinZoomY="0.2">-->
<Border Name="BorderElement" Background="SlateBlue">
<Canvas x:Name="Canvas" Background="{DynamicResource ColorNodesCanvasBackground}" ClipToBounds="True">
<local:ViewSelector x:Name="Selector" Panel.ZIndex="999"/>
<local:ViewCutter x:Name="Cutter" Panel.ZIndex="999"/>

Expand All @@ -24,7 +24,6 @@
VirtualizingPanel.CacheLength="1"
VirtualizingPanel.CacheLengthUnit="Page"
VirtualizingPanel.ScrollUnit="Pixel">

<ItemsControl.RenderTransform>
<TransformGroup x:Name="TransformGroup">
<ScaleTransform x:Name="Scale" ScaleX="1" ScaleY="1" />
Expand All @@ -35,7 +34,7 @@
</ItemsControl.RenderTransform>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid x:Name="ElementGrid" Background="{x:Null}">
<Grid x:Name="ElementGrid" Background="Pink">
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Expand All @@ -55,7 +54,7 @@
</ItemsControl.ItemsSource>
</ItemsControl>
</Canvas>
</paz:ZoomBorder>
</Border>
<UserControl.ContextMenu >
<ContextMenu Template="{DynamicResource TemplateContextMenu}" Background="{DynamicResource ColorMenuBackground}" Foreground="{DynamicResource ColorMenuForeground}" BorderBrush="{DynamicResource ColorMenuBorder}" OpacityMask="{DynamicResource ColorMenuBackgroundMouseOver}" BorderThickness="1" HorizontalAlignment="Left" VerticalAlignment="Center" >
<MenuItem Header="Add" x:Name="ItemAddNode" InputGestureText="Ctrl + N" Style="{DynamicResource StyleContextMenuItem}" >
Expand Down
33 changes: 25 additions & 8 deletions SimpleStateMachineNodeEditor/View/ViewNodesCanvas.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,14 @@ public ViewNodesCanvas()
private void SetupBinding()
{
this.WhenActivated(disposable =>
{
{
this.OneWayBind(this.ViewModel, x => x.NodesForView, x => x.Nodes.Collection).DisposeWith(disposable);
this.OneWayBind(this.ViewModel, x => x.Connects, x => x.Connects.Collection).DisposeWith(disposable);
this.OneWayBind(this.ViewModel, x => x.Scale.Scales.X, x => x.Scale.ScaleX).DisposeWith(disposable);
//this.OneWayBind(this.ViewModel, x => x.Scale.Scales.X, x => x.Scale.ScaleX).DisposeWith(disposable);
this.OneWayBind(this.ViewModel, x => x.Scale.Scales.Y, x => x.Scale.ScaleY).DisposeWith(disposable);
//this.OneWayBind(this.ViewModel, x => x.Scale.Scales.Y, x => x.Scale.ScaleY).DisposeWith(disposable);
this.OneWayBind(this.ViewModel, x => x.Selector, x => x.Selector.ViewModel).DisposeWith(disposable);
Expand Down Expand Up @@ -114,6 +113,10 @@ private void SetupSubscriptions()
this.WhenAnyValue(x => x.ViewModel.Selector.Size).WithoutParameter().InvokeCommand(ViewModel, x => x.CommandSelectorIntersect).DisposeWith(disposable);
this.WhenAnyValue(x => x.ViewModel.Cutter.EndPoint).WithoutParameter().InvokeCommand(ViewModel, x => x.CommandCutterIntersect).DisposeWith(disposable);
this.WhenAnyValue(x => x.ViewModel.ImagePath).Where(x => !string.IsNullOrEmpty(x)).Subscribe(value => SaveCanvasToImage(value, ImageFormats.JPEG)).DisposeWith(disposable);
//here need use ZoomIn and ZoomOut
//this.WhenAnyValue(x=>x.ViewModel.Scale.Value).Subscribe(x=> {this.zoomBorder.ZoomDeltaTo })
});
}

Expand All @@ -128,12 +131,12 @@ private void SetupEvents()
this.Events().MouseRightButtonDown.Subscribe(e => OnEventMouseRightDown(e)).DisposeWith(disposable);
this.Events().MouseUp.Subscribe(e => OnEventMouseUp(e)).DisposeWith(disposable);
this.Events().MouseMove.Subscribe(e => OnEventMouseMove(e)).DisposeWith(disposable);
this.Events().MouseWheel.Subscribe(e => OnEventMouseWheel(e)).DisposeWith(disposable);
this.BorderElement.Events().MouseWheel.Subscribe(e => OnEventMouseWheel(e)).DisposeWith(disposable);
this.Events().DragOver.Subscribe(e => OnEventDragOver(e)).DisposeWith(disposable);
this.Cutter.Events().MouseLeftButtonUp.InvokeCommand(this.ViewModel.CommandDeleteSelectedConnectors).DisposeWith(disposable);
this.Events().PreviewMouseLeftButtonDown.Subscribe(e => OnEventPreviewMouseLeftButtonDown(e)).DisposeWith(disposable);
this.Events().PreviewMouseRightButtonDown.Subscribe(e => OnEventPreviewMouseRightButtonDown(e)).DisposeWith(disposable);
this.WhenAnyValue(x => x.ViewModel.Scale.Value).Subscribe(value => { this.Canvas.Height /= value; this.Canvas.Width /= value; }).DisposeWith(disposable);
//this.WhenAnyValue(x => x.ViewModel.Scale.Value).Subscribe(value => { this.Canvas.Height /= value; this.Canvas.Width /= value; }).DisposeWith(disposable);
});
}
private void OnEventMouseLeftDown(MouseButtonEventArgs e)
Expand Down Expand Up @@ -170,7 +173,20 @@ private void OnEventMouseRightDown(MouseButtonEventArgs e)
}
private void OnEventMouseWheel(MouseWheelEventArgs e)
{
this.ViewModel.CommandZoom.ExecuteWithSubscribe(e.Delta);
//this.ElementItemControl.Width = ActualWidth + 100;
Point point = e.GetPosition(this.Canvas);
//this.Scale.CenterX = point.X;
//this.Scale.CenterY = point.Y;

Matrix value = this.Canvas.RenderTransform.Value;
double step = 1.2;
double zoom = e.Delta > 0 ? step : 1 / step;
value = MatrixExtension.ScaleAtPrepend(value,zoom, zoom, point.X, point.Y);
this.Canvas.RenderTransform = new MatrixTransform(value);

//this.ViewModel.CommandZoom.ExecuteWithSubscribe(e.Delta);
//_element.RenderTransform = new MatrixTransform(_matrix);

}
private void OnEventMouseUp(MouseButtonEventArgs e)
{
Expand Down Expand Up @@ -203,7 +219,7 @@ private void OnEventMouseMove(MouseEventArgs e)
}
private void OnEventDragOver(DragEventArgs e)
{
Point point = e.GetPosition(this);
Point point = e.GetPosition(this.Canvas);
if (this.ViewModel.DraggedConnect != null)
{
point = point.Subtraction(2);
Expand Down Expand Up @@ -236,6 +252,7 @@ private Point GetDeltaMove()

private void SaveCanvasToImage(string filename, ImageFormats format)
{
//this.zoomBorder.Uniform();
MyUtils.PanelToImage(this.Canvas, filename, format);
ViewModel.CommandLogDebug.ExecuteWithSubscribe(String.Format("Scheme was exported to \"{0}\"", filename));
}
Expand Down
2 changes: 1 addition & 1 deletion SimpleStateMachineNodeEditor/View/ViewSelector.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ private void OnMouseMoves(MouseEventArgs e)
//find canvas
ViewNodesCanvas NodesCanvas = MyUtils.FindParent<ViewNodesCanvas>(this);

ViewModel.Point2 = e.GetPosition(NodesCanvas);
ViewModel.Point2 = e.GetPosition(NodesCanvas.Canvas);

e.Handled = true;
}
Expand Down

0 comments on commit ed27f81

Please sign in to comment.