【问题标题】:Equivalent of glOrtho in WPFWPF 中 glOrtho 的等价物
【发布时间】:2012-10-27 13:29:55
【问题描述】:

在 OpenGL 中我可以这样做:

glOrtho(-10, 10, -10, 10, -1, 1)

建立一个坐标系,其中x的范围是-10到10,y的范围是-10到10。

有没有办法在 WPF 中改变画布的坐标系?

【问题讨论】:

  • 你将如何在 Canvas 中定位元素? TopLeftRightBottom 属性将失去意义。

标签: c# wpf xaml


【解决方案1】:

我在 Canvas 上创建了一个扩展方法,允许您设置笛卡尔坐标系。一个示例调用是:

canvas.SetCoordinateSystem(-10, 10, -10, 10)

这将设置canvas 的坐标系,使x 从-10 变为10,y 从-10 变为10。

扩展方法如下:

public static Canvas SetCoordinateSystem(this Canvas canvas, Double xMin, Double xMax, Double yMin, Double yMax)
{
    var width = xMax - xMin;
    var height = yMax - yMin;

    var translateX = -xMin;
    var translateY = height + yMin;

    var group = new TransformGroup();

    group.Children.Add(new TranslateTransform(translateX, -translateY));
    group.Children.Add(new ScaleTransform(canvas.ActualWidth / width, canvas.ActualHeight / -height));

    canvas.RenderTransform = group;

    return canvas;
}

这是一个演示程序,它在画布上绘制 Sin(x) 以及 X 和 Y 轴:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;

namespace CanvasScale
{
    public static class CanvasUtils
    {
        public static Canvas SetCoordinateSystem(this Canvas canvas, Double xMin, Double xMax, Double yMin, Double yMax)
        {
            var width = xMax - xMin;
            var height = yMax - yMin;

            var translateX = -xMin;
            var translateY = height + yMin;

            var group = new TransformGroup();

            group.Children.Add(new TranslateTransform(translateX, -translateY));
            group.Children.Add(new ScaleTransform(canvas.ActualWidth / width, canvas.ActualHeight / -height));

            canvas.RenderTransform = group;

            return canvas;
        }
    }

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

            var canvas = new Canvas();

            Content = canvas;

            SizeChanged += (s, e) => canvas.SetCoordinateSystem(-10, 10, -10, 10);                

            canvas.Children.Add(new Line() { X1 = -10, Y1 = 0, X2 = 10, Y2 = 0, Stroke = Brushes.Black, StrokeThickness = 0.2 });
            canvas.Children.Add(new Line() { X1 = 0, Y1 = -10, X2 = 0, Y2 = 10, Stroke = Brushes.Black, StrokeThickness = 0.2 });

            var polyline = new Polyline()
            {
                Stroke = Brushes.BurlyWood,
                StrokeThickness = 0.1,
                Points = new PointCollection()
            };

            for (var x = -10.0; x <= 10.0; x += 0.1)
                polyline.Points.Add(new Point(x, Math.Sin(x)));

            canvas.Children.Add(polyline);
        }
    }
}

它是这样的:

【讨论】:

  • 请注意,在 InitializeComponent() 之后 canvas.ActualHeight 可以(并且是)零,因此 0 / x = 0 并且您已将 ScaleTransform 设置为 {0;0}。这可能会令人困惑,因为画布在视觉上消失了......解决方案:force Measure && Arrange
【解决方案2】:

OrthographicCamera 提供正交投影,而不是更常见的透视投影 (PerspectiveCamera)。

要确定从相机可见的坐标“范围”,您可能需要调整WidthPosition 属性。

【讨论】:

    【解决方案3】:

    只要您没有同时设置 Canvas.TopCanvas.LeftCanvas.RightCanvas.Bottom 属性,您可以将 Canvas 中每个子项的 LayoutTransformRenderTransform 属性设置为适当的TransformGroup 或MatrixTransform

    Rect viewport = new Rect(-10, -10, 20, 20);
    double scaleX = ActualWidth / viewport.Width;
    double scaleY = ActualHeight / viewport.Height;
    RenderTransform = new MatrixTransform(
        scaleX, 0d, 0d, scaleY, -viewport.X * scaleX, -viewport.Y * scaleY);
    

    【讨论】:

    • 嗨克莱门斯。我最终按照这些思路做了一些事情。我添加了一个answer
    猜你喜欢
    • 2023-04-01
    • 2010-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-09
    • 2015-10-17
    • 1970-01-01
    相关资源
    最近更新 更多