RotateTransform 和三角公式不一致,画布中的对象未对齐

问题描述 投票:0回答:1

我找不到任何智能方法来获取在画布上应用了变换的对象的绝对位置,我决定使用一个点并对它应用我试图跟踪的对象的相同变换,然后我会根据点的坐标知道何时对对象执行某些操作。

当使用三角公式应用旋转并将其与 RotateTransform 函数进行比较时,问题就开始了。这些对象不仅没有对齐,这表明它们没有按照相同的规则绘制,例如对象的顶部/左侧,并且除非我的眼镜非常关闭,否则在使用公式计算时,圆形轨迹似乎会扭曲。我特别不相信数学在我的电脑上完全停止工作。

看下面的图片,我绘制了垂直/水平线来指示画布的中心,然后创建一些逐渐旋转 45 度的椭圆,蓝色的椭圆使用旋转变换,红色的椭圆使用三角公式。蓝色是正确的,红色不仅没有对齐,而且以意想不到的速度旋转。

Blue is right, red is wrong

应用逻辑是:

  • 循环累加角度:0、45、90...
  • 3 个点:画布中心,将 Y 坐标转换为到中心的半径距离,用于绘制红色圆圈的旋转点
  • 蓝色圆圈使用带有 TranslateTransform 和 RotateTransform 的 TransformGroup

XAML:

<Window x:Class="Angle.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:local="clr-namespace:Angle"
        mc:Ignorable="d"
        Title="MainWindow" Height="520" Width="520">
    <Canvas Grid.Row ="0" x:Name="cv" Width="500" Height="500"></Canvas>
</Window>

C#:

using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace Angle
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            int    increment = 45,
                   segments  = 360 / increment;
            double radius    = 150.0,
                   angle     = 0.0;

            Point origin;
            origin.X = cv.Width / 2;
            origin.Y = cv.Height / 2;

            Line verLine = new Line() { X1 = origin.X, X2 = origin.X, Y1 = 0, Y2 = cv.Height },
                 hrzLine = new Line() { X1 = 0, X2 = cv.Width, Y1 = origin.Y, Y2 = origin.Y };

            verLine.Stroke = hrzLine.Stroke = Brushes.Black;
            verLine.StrokeThickness = hrzLine.StrokeThickness = 1;

            cv.Children.Add(verLine);
            cv.Children.Add(hrzLine);

            for (int i = 0; i < segments; i++)
            {
                Point translated, rotated;

                Ellipse usingMath      = new Ellipse() { Width = 20, Height = 20 },
                        usingTransform = new Ellipse() { Width = 20, Height = 20 };

                translated.X = origin.X;
                translated.Y = origin.Y + radius;
                rotated.X = (Math.Cos(angle * Math.PI / 180) * (translated.X - origin.X) - Math.Sin(angle * Math.PI / 180) * (translated.Y - origin.Y) + origin.X);
                rotated.Y = (Math.Sin(angle * Math.PI / 180) * (translated.X - origin.X) + Math.Cos(angle * Math.PI / 180) * (translated.Y - origin.Y) + origin.Y);
                usingMath.RenderTransform   = new TranslateTransform() { X = rotated.X, Y = rotated.Y };

                TransformGroup transf = new TransformGroup();
                transf.Children.Add(new TranslateTransform() { X = translated.X, Y = translated.Y });
                transf.Children.Add(new RotateTransform()    { Angle = angle, CenterX = origin.X, CenterY = origin.Y });
                usingTransform.RenderTransform = transf;

                usingMath.StrokeThickness = usingTransform.StrokeThickness = 4;
                usingMath.Stroke      = Brushes.Red;
                usingTransform.Stroke = Brushes.Blue;
                
                cv.Children.Add(usingMath);
                cv.Children.Add(usingTransform);

                angle += increment;
            }
        }
    }
}

我已经一遍又一遍地检查了这个,肯定在某个地方有一个明显的错误或者我忘记做的事情,也许你可以帮助我找出问题所在?

c# wpf
1个回答
0
投票

你的数学实际上没有任何问题,但它可以简化。

然而,主要问题是椭圆元素不居中,而是在其顶部/左上角对齐。您可以添加负边距,但使用

Path
元素并将
EllipseGeometry
作为其
Data
会很简单。

然后,您可以设置每个 EllipseGeometry 的

Center
属性,或者将 TransformGroup 应用于其
Transform
属性,如下所示。

int increment = 45,
        segments = 360 / increment;
double radius = 150.0,
        angle = 0.0;

Point origin = new Point(cv.Width / 2, cv.Height / 2);
Line verLine = new Line() { X1 = origin.X, X2 = origin.X, Y1 = 0, Y2 = cv.Height },
        hrzLine = new Line() { X1 = 0, X2 = cv.Width, Y1 = origin.Y, Y2 = origin.Y };

verLine.Stroke = hrzLine.Stroke = Brushes.Black;
verLine.StrokeThickness = hrzLine.StrokeThickness = 1;
cv.Children.Add(verLine);
cv.Children.Add(hrzLine);

for (int i = 0; i < segments; i++)
{
    EllipseGeometry usingMath = new EllipseGeometry { RadiusX = 6, RadiusY = 6 };
    EllipseGeometry usingTransform = new EllipseGeometry { RadiusX = 10, RadiusY = 10 };

    Point translated = new Point(origin.X, origin.Y + radius);
    TransformGroup transf = new TransformGroup();
    transf.Children.Add(new TranslateTransform(translated.X, translated.Y));
    transf.Children.Add(new RotateTransform(angle, origin.X, origin.Y));
    usingTransform.Transform = transf;

    double cos = Math.Cos(angle * Math.PI / 180);
    double sin = Math.Sin(angle * Math.PI / 180);
    Point rotated = new Point(sin * radius + origin.X, cos * radius + origin.Y);
    usingMath.Center = rotated;

    cv.Children.Add(new Path { Data = usingMath, Stroke = Brushes.Red, StrokeThickness = 4 });
    cv.Children.Add(new Path { Data = usingTransform, Stroke = Brushes.Blue, StrokeThickness = 4 });

    angle += increment;
}

结果:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.