为什么两个转换不适用于 Helix 工具包对象
Why does two Transform do not work with a Helix Toolkit Object
我整理了一些代码,通过使用 WPF 滑块控件来操作两个 Helix Toolkit Torus 对象。此代码是其他一些更复杂问题的原型。
当我仅应用平移或旋转变换时,环面对象移动或旋转。然而,当我都只应用了颂歌作品中列出的最后一个时(本例中为旋转)。如果我注释掉旋转变换,翻译工作。
我尝试了 TransformGroup 方法,然后除了 Helix Tool 工具包中定义的依赖对象(例如 TorusDiameter)之外没有任何效果。
正如您从代码中看到的那样,一次只能进行一个转换,因为一次只能移动一个滑块。
我有两个问题:
(1) 为什么Transform的多应用(行)不起作用?我怎样才能让它发挥作用?
(2) 我在事件处理程序 MyTorusChanged 中放置了一个消息框。它似乎只在一开始就被解雇了。我是 WPF 的新手。 Transform 如何在不通过事件处理程序的情况下工作?
视图模型:
// April 08, 2019, Dr. I. Konuk
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using HelixToolkit.Wpf;
namespace AnimatedTorusDemo
{
class MyTorusViewModel : ModelVisual3D
{
// origin of torus object
public Point3D TorusOrigin { get; set; }
public double translationX { get; set; }
public double translationY { get; set; }
public double translationZ { get; set; }
// translation transformation parameter properties
public static readonly DependencyProperty TranslationXProperty =
DependencyProperty.Register("TranslationX", typeof(double), typeof(MyTorusViewModel),
new UIPropertyMetadata(0.0));
public static readonly DependencyProperty TranslationYProperty =
DependencyProperty.Register("TranslationY", typeof(double), typeof(MyTorusViewModel),
new UIPropertyMetadata(0.0));
public static readonly DependencyProperty TranslationZProperty =
DependencyProperty.Register("TranslationZ", typeof(double), typeof(MyTorusViewModel),
new UIPropertyMetadata(0.0));
public double TranslationX
{
get { return (double)GetValue(TranslationXProperty); }
set { SetValue(TranslationXProperty, value); translationX = value; }
}
public double TranslationY
{
get { return (double)GetValue(TranslationYProperty); }
set { SetValue(TranslationYProperty, value); translationY = value; }
}
public double TranslationZ
{
get { return (double)GetValue(TranslationZProperty); }
set { SetValue(TranslationZProperty, value); translationZ = value; }
}
// MyTorusProperty
// notice the callback function definition via Metadata
public static DependencyProperty MyTorusProperty =
DependencyProperty.Register("MyTorus", typeof(TorusVisual3D), typeof(MyTorusViewModel),
new UIPropertyMetadata(null, MyTorusChanged));
public TorusVisual3D MyTorus
{
get => (TorusVisual3D)GetValue(MyTorusProperty);
set { SetValue(MyTorusProperty, value); }
}
// rotation angle property
// Gets or sets the rotation angle (angle of torus).
public static readonly DependencyProperty RotationAngleProperty =
DependencyProperty.Register("RotationAngle", typeof(double), typeof(MyTorusViewModel),
new UIPropertyMetadata(45.0));
public double RotationAngle
{
get { return (double)GetValue(RotationAngleProperty); }
set { SetValue(RotationAngleProperty, value); }
}
public static AxisAngleRotation3D axisAngleRotation = new AxisAngleRotation3D(new Vector3D(1, 0, 0), 0);
public static readonly DependencyProperty TorusAxisAngleProperty =
DependencyProperty.Register("TorusAxisAngle", typeof(AxisAngleRotation3D), typeof(MyTorusViewModel),
new UIPropertyMetadata(axisAngleRotation));
public AxisAngleRotation3D TorusAxisAngle
{
get { return (AxisAngleRotation3D)GetValue(TorusAxisAngleProperty); }
set { SetValue(TorusAxisAngleProperty, value); }
}
// callback function used updating visuals (torus obejects)
protected static void MyTorusChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
((MyTorusViewModel)obj).UpdateVisuals();
}
// member function to update visuals
private void UpdateVisuals()
{
MessageBox.Show("UpdateVisuals");
Children.Clear();
// each instance must have a torus object assigned for each MyTorusViewModel before
if (MyTorus == null) return;
MyTorus.ThetaDiv = 36;
MyTorus.PhiDiv = 24;
// translation
var torusTranslate = new TranslateTransform3D(new Vector3D(translationX, translationY, translationZ));
MyTorus.Transform = torusTranslate;
// rotation
var torusRotate = new RotateTransform3D();
TorusAxisAngle = new AxisAngleRotation3D();
TorusAxisAngle.Axis= new Vector3D(0, 1, 0);
TorusAxisAngle.Angle = RotationAngle;
torusRotate.Rotation = TorusAxisAngle;
MyTorus.Transform = torusRotate;
// transform group
var torusTransformGroup = new Transform3DGroup();
torusTransformGroup.Children.Add(torusTranslate);
// MyTorus.Transform = torusTransformGroup;
Children.Add(MyTorus);
}
}
}
xaml:
<Window x:Class="AnimatedTorusDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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"
xmlns:h="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf"
xmlns:local="clr-namespace:AnimatedTorusDemo"
mc:Ignorable="d"
Title="MainWindow" Height="750" Width="800">
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="4*" />
<RowDefinition Height="0.75*" />
<RowDefinition Height="0.75*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<h:HelixViewport3D x:Name="TorusView" ZoomExtentsWhenLoaded="True" ShowCoordinateSystem="True" PanGesture="LeftClick" >
<h:DefaultLights/>
</h:HelixViewport3D>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Bottom" Opacity="0.9" >
<Slider x:Name="translationX1Slider" Value="0" Minimum="-5.0" Maximum="5.0" Width="150" Margin="10"
/>
<Slider x:Name="translationY1Slider" Value="0" Minimum="-5.0" Maximum="5.0" Width="150" Margin="10"
/>
<Slider x:Name="translationZ1Slider" Value="1" Minimum="-3" Maximum="3" Width="150" Margin="10"
/>
<Slider x:Name="rotation1Slider" Value="45" Minimum="0" Maximum="360" Width="150" Margin="10"
/>
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Bottom" Opacity="0.9" >
<Slider x:Name="translationX2Slider" Value="0" Minimum="-5.0" Maximum="5.0" Width="150" Margin="10"
/>
<Slider x:Name="translationY2Slider" Value="0" Minimum="-5" Maximum="5" Width="150" Margin="10"
/>
<Slider x:Name="translationZ2Slider" Value="-1" Minimum="-3" Maximum="3" Width="150" Margin="10"
/>
<Slider x:Name="rotation2Slider" Value="45" Minimum="0" Maximum="360" Width="150" Margin="10"
/>
</StackPanel>
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Bottom" Opacity="0.9" >
<Slider x:Name="torusDiameterSlider" Minimum="1" Maximum="10" Width="150" Margin="10"
/>
<Slider x:Name="tubeDiameterSlider" Value="1" Minimum="0.5" Maximum="5" Width="150" Margin="10"
/>
<Slider x:Name="thetaDivSlider" Value="36" Minimum="3" Maximum="256" Width="150" Margin="10"
/>
<Slider x:Name="phiDivSlider" Value="24" Minimum="3" Maximum="256" Width="150" Margin="10"/>
</StackPanel>
</Grid>
</Window>
主要window:
// April 08, 2019, Dr. I. Konuk
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Windows.Media.Media3D;
using HelixToolkit.Wpf;
namespace AnimatedTorusDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly ModelVisual3D model;
private MyTorusViewModel visual1;
private MyTorusViewModel visual2;
public MainWindow()
{
InitializeComponent();
model = new ModelVisual3D();
visual1 = new MyTorusViewModel();
var mytorus1 = new TorusVisual3D();
mytorus1.Fill = Brushes.Red;
visual1.MyTorus = mytorus1;
visual2 = new MyTorusViewModel();
var mytorus2 = new TorusVisual3D();
mytorus2.Fill = Brushes.Blue;
visual2.MyTorus = mytorus2;
mytorus2.TorusDiameter = 5;
// bindings with sliders in code
// Helix Toolkit dependencyproperties:
// a) Geometry:
BindingOperations.SetBinding(mytorus1, HelixToolkit.Wpf.TorusVisual3D.TorusDiameterProperty,
new Binding("Value") { Source = torusDiameterSlider });
BindingOperations.SetBinding(mytorus1, HelixToolkit.Wpf.TorusVisual3D.TubeDiameterProperty,
new Binding("Value") { Source = tubeDiameterSlider });
// b) Translation:
// Dependency properties defined in MyTorusView Model
BindingOperations.SetBinding(mytorus1.Transform, TranslateTransform3D.OffsetXProperty,
new Binding("Value") { Source = translationX1Slider });
BindingOperations.SetBinding(mytorus1.Transform, TranslateTransform3D.OffsetYProperty,
new Binding("Value") { Source = translationY1Slider });
BindingOperations.SetBinding(mytorus1.Transform, TranslateTransform3D.OffsetZProperty,
new Binding("Value") { Source = translationZ1Slider });
BindingOperations.SetBinding(mytorus2.Transform, TranslateTransform3D.OffsetXProperty,
new Binding("Value") { Source = translationX2Slider });
BindingOperations.SetBinding(mytorus2.Transform, TranslateTransform3D.OffsetYProperty,
new Binding("Value") { Source = translationY2Slider });
BindingOperations.SetBinding(mytorus2.Transform, TranslateTransform3D.OffsetZProperty,
new Binding("Value") { Source = translationZ2Slider });
// b) Rotation
BindingOperations.SetBinding(visual1.TorusAxisAngle, AxisAngleRotation3D.AngleProperty,
new Binding("Value") { Source = rotation1Slider });
BindingOperations.SetBinding(visual2.TorusAxisAngle, AxisAngleRotation3D.AngleProperty,
new Binding("Value") { Source = rotation2Slider });
model.Children.Add(visual1);
model.Children.Add(visual2);
TorusView.Children.Add(model);
this.DataContext = this;
}
}
}
当您应用旋转并将其设置为 .transform 属性 时,它会将包含平移的先前转换替换为仅包含旋转的新转换。相反,您需要做的是获取最新的变换矩阵(包括翻译)并对其应用旋转,然后重置 .transform 属性。
我对这个问题的回答回答了你问题的第一部分:
请将您的其他问题作为一个单独的问题提出(每个问题一个问题)。参考这个link原因:https://meta.stackexchange.com/questions/222735/can-i-ask-only-one-question-per-post
我整理了一些代码,通过使用 WPF 滑块控件来操作两个 Helix Toolkit Torus 对象。此代码是其他一些更复杂问题的原型。
当我仅应用平移或旋转变换时,环面对象移动或旋转。然而,当我都只应用了颂歌作品中列出的最后一个时(本例中为旋转)。如果我注释掉旋转变换,翻译工作。
我尝试了 TransformGroup 方法,然后除了 Helix Tool 工具包中定义的依赖对象(例如 TorusDiameter)之外没有任何效果。
正如您从代码中看到的那样,一次只能进行一个转换,因为一次只能移动一个滑块。
我有两个问题:
(1) 为什么Transform的多应用(行)不起作用?我怎样才能让它发挥作用?
(2) 我在事件处理程序 MyTorusChanged 中放置了一个消息框。它似乎只在一开始就被解雇了。我是 WPF 的新手。 Transform 如何在不通过事件处理程序的情况下工作?
视图模型:
// April 08, 2019, Dr. I. Konuk
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using HelixToolkit.Wpf;
namespace AnimatedTorusDemo
{
class MyTorusViewModel : ModelVisual3D
{
// origin of torus object
public Point3D TorusOrigin { get; set; }
public double translationX { get; set; }
public double translationY { get; set; }
public double translationZ { get; set; }
// translation transformation parameter properties
public static readonly DependencyProperty TranslationXProperty =
DependencyProperty.Register("TranslationX", typeof(double), typeof(MyTorusViewModel),
new UIPropertyMetadata(0.0));
public static readonly DependencyProperty TranslationYProperty =
DependencyProperty.Register("TranslationY", typeof(double), typeof(MyTorusViewModel),
new UIPropertyMetadata(0.0));
public static readonly DependencyProperty TranslationZProperty =
DependencyProperty.Register("TranslationZ", typeof(double), typeof(MyTorusViewModel),
new UIPropertyMetadata(0.0));
public double TranslationX
{
get { return (double)GetValue(TranslationXProperty); }
set { SetValue(TranslationXProperty, value); translationX = value; }
}
public double TranslationY
{
get { return (double)GetValue(TranslationYProperty); }
set { SetValue(TranslationYProperty, value); translationY = value; }
}
public double TranslationZ
{
get { return (double)GetValue(TranslationZProperty); }
set { SetValue(TranslationZProperty, value); translationZ = value; }
}
// MyTorusProperty
// notice the callback function definition via Metadata
public static DependencyProperty MyTorusProperty =
DependencyProperty.Register("MyTorus", typeof(TorusVisual3D), typeof(MyTorusViewModel),
new UIPropertyMetadata(null, MyTorusChanged));
public TorusVisual3D MyTorus
{
get => (TorusVisual3D)GetValue(MyTorusProperty);
set { SetValue(MyTorusProperty, value); }
}
// rotation angle property
// Gets or sets the rotation angle (angle of torus).
public static readonly DependencyProperty RotationAngleProperty =
DependencyProperty.Register("RotationAngle", typeof(double), typeof(MyTorusViewModel),
new UIPropertyMetadata(45.0));
public double RotationAngle
{
get { return (double)GetValue(RotationAngleProperty); }
set { SetValue(RotationAngleProperty, value); }
}
public static AxisAngleRotation3D axisAngleRotation = new AxisAngleRotation3D(new Vector3D(1, 0, 0), 0);
public static readonly DependencyProperty TorusAxisAngleProperty =
DependencyProperty.Register("TorusAxisAngle", typeof(AxisAngleRotation3D), typeof(MyTorusViewModel),
new UIPropertyMetadata(axisAngleRotation));
public AxisAngleRotation3D TorusAxisAngle
{
get { return (AxisAngleRotation3D)GetValue(TorusAxisAngleProperty); }
set { SetValue(TorusAxisAngleProperty, value); }
}
// callback function used updating visuals (torus obejects)
protected static void MyTorusChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
((MyTorusViewModel)obj).UpdateVisuals();
}
// member function to update visuals
private void UpdateVisuals()
{
MessageBox.Show("UpdateVisuals");
Children.Clear();
// each instance must have a torus object assigned for each MyTorusViewModel before
if (MyTorus == null) return;
MyTorus.ThetaDiv = 36;
MyTorus.PhiDiv = 24;
// translation
var torusTranslate = new TranslateTransform3D(new Vector3D(translationX, translationY, translationZ));
MyTorus.Transform = torusTranslate;
// rotation
var torusRotate = new RotateTransform3D();
TorusAxisAngle = new AxisAngleRotation3D();
TorusAxisAngle.Axis= new Vector3D(0, 1, 0);
TorusAxisAngle.Angle = RotationAngle;
torusRotate.Rotation = TorusAxisAngle;
MyTorus.Transform = torusRotate;
// transform group
var torusTransformGroup = new Transform3DGroup();
torusTransformGroup.Children.Add(torusTranslate);
// MyTorus.Transform = torusTransformGroup;
Children.Add(MyTorus);
}
}
}
xaml:
<Window x:Class="AnimatedTorusDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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"
xmlns:h="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf"
xmlns:local="clr-namespace:AnimatedTorusDemo"
mc:Ignorable="d"
Title="MainWindow" Height="750" Width="800">
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="4*" />
<RowDefinition Height="0.75*" />
<RowDefinition Height="0.75*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<h:HelixViewport3D x:Name="TorusView" ZoomExtentsWhenLoaded="True" ShowCoordinateSystem="True" PanGesture="LeftClick" >
<h:DefaultLights/>
</h:HelixViewport3D>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Bottom" Opacity="0.9" >
<Slider x:Name="translationX1Slider" Value="0" Minimum="-5.0" Maximum="5.0" Width="150" Margin="10"
/>
<Slider x:Name="translationY1Slider" Value="0" Minimum="-5.0" Maximum="5.0" Width="150" Margin="10"
/>
<Slider x:Name="translationZ1Slider" Value="1" Minimum="-3" Maximum="3" Width="150" Margin="10"
/>
<Slider x:Name="rotation1Slider" Value="45" Minimum="0" Maximum="360" Width="150" Margin="10"
/>
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Bottom" Opacity="0.9" >
<Slider x:Name="translationX2Slider" Value="0" Minimum="-5.0" Maximum="5.0" Width="150" Margin="10"
/>
<Slider x:Name="translationY2Slider" Value="0" Minimum="-5" Maximum="5" Width="150" Margin="10"
/>
<Slider x:Name="translationZ2Slider" Value="-1" Minimum="-3" Maximum="3" Width="150" Margin="10"
/>
<Slider x:Name="rotation2Slider" Value="45" Minimum="0" Maximum="360" Width="150" Margin="10"
/>
</StackPanel>
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Bottom" Opacity="0.9" >
<Slider x:Name="torusDiameterSlider" Minimum="1" Maximum="10" Width="150" Margin="10"
/>
<Slider x:Name="tubeDiameterSlider" Value="1" Minimum="0.5" Maximum="5" Width="150" Margin="10"
/>
<Slider x:Name="thetaDivSlider" Value="36" Minimum="3" Maximum="256" Width="150" Margin="10"
/>
<Slider x:Name="phiDivSlider" Value="24" Minimum="3" Maximum="256" Width="150" Margin="10"/>
</StackPanel>
</Grid>
</Window>
主要window:
// April 08, 2019, Dr. I. Konuk
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Windows.Media.Media3D;
using HelixToolkit.Wpf;
namespace AnimatedTorusDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly ModelVisual3D model;
private MyTorusViewModel visual1;
private MyTorusViewModel visual2;
public MainWindow()
{
InitializeComponent();
model = new ModelVisual3D();
visual1 = new MyTorusViewModel();
var mytorus1 = new TorusVisual3D();
mytorus1.Fill = Brushes.Red;
visual1.MyTorus = mytorus1;
visual2 = new MyTorusViewModel();
var mytorus2 = new TorusVisual3D();
mytorus2.Fill = Brushes.Blue;
visual2.MyTorus = mytorus2;
mytorus2.TorusDiameter = 5;
// bindings with sliders in code
// Helix Toolkit dependencyproperties:
// a) Geometry:
BindingOperations.SetBinding(mytorus1, HelixToolkit.Wpf.TorusVisual3D.TorusDiameterProperty,
new Binding("Value") { Source = torusDiameterSlider });
BindingOperations.SetBinding(mytorus1, HelixToolkit.Wpf.TorusVisual3D.TubeDiameterProperty,
new Binding("Value") { Source = tubeDiameterSlider });
// b) Translation:
// Dependency properties defined in MyTorusView Model
BindingOperations.SetBinding(mytorus1.Transform, TranslateTransform3D.OffsetXProperty,
new Binding("Value") { Source = translationX1Slider });
BindingOperations.SetBinding(mytorus1.Transform, TranslateTransform3D.OffsetYProperty,
new Binding("Value") { Source = translationY1Slider });
BindingOperations.SetBinding(mytorus1.Transform, TranslateTransform3D.OffsetZProperty,
new Binding("Value") { Source = translationZ1Slider });
BindingOperations.SetBinding(mytorus2.Transform, TranslateTransform3D.OffsetXProperty,
new Binding("Value") { Source = translationX2Slider });
BindingOperations.SetBinding(mytorus2.Transform, TranslateTransform3D.OffsetYProperty,
new Binding("Value") { Source = translationY2Slider });
BindingOperations.SetBinding(mytorus2.Transform, TranslateTransform3D.OffsetZProperty,
new Binding("Value") { Source = translationZ2Slider });
// b) Rotation
BindingOperations.SetBinding(visual1.TorusAxisAngle, AxisAngleRotation3D.AngleProperty,
new Binding("Value") { Source = rotation1Slider });
BindingOperations.SetBinding(visual2.TorusAxisAngle, AxisAngleRotation3D.AngleProperty,
new Binding("Value") { Source = rotation2Slider });
model.Children.Add(visual1);
model.Children.Add(visual2);
TorusView.Children.Add(model);
this.DataContext = this;
}
}
}
当您应用旋转并将其设置为 .transform 属性 时,它会将包含平移的先前转换替换为仅包含旋转的新转换。相反,您需要做的是获取最新的变换矩阵(包括翻译)并对其应用旋转,然后重置 .transform 属性。
我对这个问题的回答回答了你问题的第一部分: