WPF画布:旋转分组形状

发布于 2025-01-26 00:07:18 字数 4878 浏览 1 评论 0原文

在我的WPF应用程序中,我试图在画布内旋转一组分组形状。我使用以下链接中提到的公式将形状对象顶部/左定位分组。

在2D中旋转一个点

如果旋转点(PX,PY)围绕点(ox,oy),theta会得到:

  p'x = cos(theta) * (px-ox) - sin(theta) * (py-oy) + ox
  p'y = sin(theta) * (px-ox) + cos(theta) * (py-oy) + oy

由于我的旋转对象是一个分组的对象,因此可以包含多级儿童。当我在画布中解开分组的形状时,我需要在同一位置上获取子形状的位置和角度,该位置可在父母分组的形状对象中可用。我如何计算子对象的位置。

样品分组的对象如下图所示:

  • 矩形(父形)
    • 矩形(儿童形状1)
    • 三角形(儿童形状2)

canvas canvas gopted shape rotation rotation 左侧显示旋转的分组形状,而右侧则显示旋转的未分组的子形状。

对于所有组中的所有形状,我都有以下信息:

  • 有关父X&的子形状位置; y(child_x& child_y)
  • 儿童形状角度相对于父母组(child_angle)
  • 父母群体角度和位置,尊重canvas(parent_x,parent_y&amp _ parent_y&parent_angle)
  • 子女形状宽度和
  • 父母身高的宽度和高度,是我如何塑造我如何塑造

我如何获得的。未分组后,儿童形状的位置和角度(矩形和三角形)?儿童形状应放在小组中时放置在帆布中的同一位置。我如何计算儿童形状的位置和角度,谢谢。

下面的代码我正在用于存储形状相关参数和分组和分组的逻辑。

/// <summary>
/// ShapeDiagram can be any shape like Rectangle/Triangle/Ellipse etc.
/// For now I am using only Rectangle template for 'ShapeDiagram' type.
/// </summary>
public class ShapeDiagram
{
    public double Left { get; set; }
    public double Top { get; set; }
    public double Angle { get; set; }
    public double Width { get; set; }
    public double Height { get; set; }
}

/// <summary>
/// Group can have more than one 'ShapeDiagram' elements. A custom shape can be created using child 'ShapeDiagram' elements.
/// User can rotate multiple 'ShapeDiagram' elements and create a group.
/// Group will have a rectangle border around the childrens as shown in the above image.
/// Group rectangle border is created using templates based on type like GroupShapeDigram or ShapeDiagram.
/// </summary>
public class GroupShapeDiagram : ShapeDiagram
{
    public ObservableCollection<ShapeDiagram> Childrens { get; set; }

}

/// <summary>
/// This class is binded to canvas and canvas child elements are binded to 'CanvasChildrens'
/// </summary>
public class ShapeHandler
{
    private ObservableCollection<ShapeDiagram> canvasChildrens;
    public ObservableCollection<ShapeDiagram> CanvasChildrens { get => canvasChildrens; set => canvasChildrens = value; }

    public ShapeHandler()
    {
        this.CanvasChildrens = new ObservableCollection<ShapeDiagram>();
    }

    public void AddCanvasChild(ShapeDiagram shape)
    {
        if(shape != null)
        {
            this.CanvasChildrens.Add(shape);
        }
    }

    public void RemoveCanvasChild(ShapeDiagram shape)
    {
        if (shape != null)
        {
            this.CanvasChildrens.Remove(shape);
        }
    }


    public GroupShapeDiagram DoGrouping(ObservableCollection<ShapeDiagram> childrens)
    {
        GroupShapeDiagram newGroup = new GroupShapeDiagram();

        newGroup.Childrens = childrens;
        newGroup.Angle = 0;
        newGroup.Top = 0;
        newGroup.Left = 0;
        newGroup.Width = GetNewGroupWidth(childrens);
        newGroup.Height = GetNewGroupHeight(childrens);

        // Add new group in the canvas child shapes collection
        this.CanvasChildrens.Add(newGroup);

        return newGroup;
    }

    public void DoUnGrouping(GroupShapeDiagram group)
    {
        // Remove selected group from the canvas child shapes collection
        this.CanvasChildrens.Remove(group);

        // TO-DO: Now adjust the group child shapes to correct location
        foreach(ShapeDiagram childShape in group.Childrens)
        {
            // *** This is where i am not getting correct values for Top/Left/Angle for child shapes after ungrouping
            childShape.Top += group.Top;
            childShape.Left += group.Left;
            childShape.Angle += group.Angle;
        }
    }

    private double GetNewGroupWidth(ObservableCollection<ShapeDiagram> childrens)
    {
        double maxWidth = 300;

        // TO-DO: Logic to get max width of all childrens with some buffer width, for now I am returning 300 as default group width

        return maxWidth;
    }

    private double GetNewGroupHeight(ObservableCollection<ShapeDiagram> childrens)
    {
        double maxHeight = 300;

        // TO-DO: Logic to get max heigth of all childrens with some buffer heigth, for now I am returning 300 as default group height

        return maxHeight;
    }

}

这是我正在使用的更新完整的示例代码,我正在使用该代码我的应用程序。 shapesdesignercode

谢谢 iamhum

In my WPF application, I am trying to rotate a set of grouped shapes inside a canvas. I am getting grouped shape object TOP/LEFT position using the formulae mentioned in the below link.

Rotate a point by another point in 2D

If you rotate point (px, py) around point (ox, oy) by angle theta you'll get:

  p'x = cos(theta) * (px-ox) - sin(theta) * (py-oy) + ox
  p'y = sin(theta) * (px-ox) + cos(theta) * (py-oy) + oy

Since my rotated object is a grouped object it can contain multi level child. When I am ungrouping the grouped shape in canvas, I need to get the position and angle of the child shapes at the same position which is available in parent grouped shape object. How I can calculate the position of child object.

Sample Grouped object as shown in below image:

  • Rectangle (Parent Shape)
    • Rectangle (Child Shape 1)
    • Triangle (Child Shape 2)

Canvas grouped shape rotation
Left part shows the rotated grouped shape whereas right part shows the rotated ungrouped child shapes.

For all shapes with in group, I have below information:

  • Child shape position with respect to parent group X & Y (Child_X & Child_Y)
  • Child shape angle with respect to parent group (Child_Angle)
  • Parent group angle and position with respect canvas (Parent_X, Parent_Y & Parent_Angle)
  • Width and Height of child shapes
  • Width and Height of Parent shapes

How I can get the location and angle for child shapes (Rectangle and triangle) after ungrouping? The child shapes should get placed at the same location in canvas where they are placed when they are inside the group. How I can calculate the location and angle for child shapes, Thanks in advance.

Below code I am using for storing the shape related parameters and logic for grouping and ungrouping.

/// <summary>
/// ShapeDiagram can be any shape like Rectangle/Triangle/Ellipse etc.
/// For now I am using only Rectangle template for 'ShapeDiagram' type.
/// </summary>
public class ShapeDiagram
{
    public double Left { get; set; }
    public double Top { get; set; }
    public double Angle { get; set; }
    public double Width { get; set; }
    public double Height { get; set; }
}

/// <summary>
/// Group can have more than one 'ShapeDiagram' elements. A custom shape can be created using child 'ShapeDiagram' elements.
/// User can rotate multiple 'ShapeDiagram' elements and create a group.
/// Group will have a rectangle border around the childrens as shown in the above image.
/// Group rectangle border is created using templates based on type like GroupShapeDigram or ShapeDiagram.
/// </summary>
public class GroupShapeDiagram : ShapeDiagram
{
    public ObservableCollection<ShapeDiagram> Childrens { get; set; }

}

/// <summary>
/// This class is binded to canvas and canvas child elements are binded to 'CanvasChildrens'
/// </summary>
public class ShapeHandler
{
    private ObservableCollection<ShapeDiagram> canvasChildrens;
    public ObservableCollection<ShapeDiagram> CanvasChildrens { get => canvasChildrens; set => canvasChildrens = value; }

    public ShapeHandler()
    {
        this.CanvasChildrens = new ObservableCollection<ShapeDiagram>();
    }

    public void AddCanvasChild(ShapeDiagram shape)
    {
        if(shape != null)
        {
            this.CanvasChildrens.Add(shape);
        }
    }

    public void RemoveCanvasChild(ShapeDiagram shape)
    {
        if (shape != null)
        {
            this.CanvasChildrens.Remove(shape);
        }
    }


    public GroupShapeDiagram DoGrouping(ObservableCollection<ShapeDiagram> childrens)
    {
        GroupShapeDiagram newGroup = new GroupShapeDiagram();

        newGroup.Childrens = childrens;
        newGroup.Angle = 0;
        newGroup.Top = 0;
        newGroup.Left = 0;
        newGroup.Width = GetNewGroupWidth(childrens);
        newGroup.Height = GetNewGroupHeight(childrens);

        // Add new group in the canvas child shapes collection
        this.CanvasChildrens.Add(newGroup);

        return newGroup;
    }

    public void DoUnGrouping(GroupShapeDiagram group)
    {
        // Remove selected group from the canvas child shapes collection
        this.CanvasChildrens.Remove(group);

        // TO-DO: Now adjust the group child shapes to correct location
        foreach(ShapeDiagram childShape in group.Childrens)
        {
            // *** This is where i am not getting correct values for Top/Left/Angle for child shapes after ungrouping
            childShape.Top += group.Top;
            childShape.Left += group.Left;
            childShape.Angle += group.Angle;
        }
    }

    private double GetNewGroupWidth(ObservableCollection<ShapeDiagram> childrens)
    {
        double maxWidth = 300;

        // TO-DO: Logic to get max width of all childrens with some buffer width, for now I am returning 300 as default group width

        return maxWidth;
    }

    private double GetNewGroupHeight(ObservableCollection<ShapeDiagram> childrens)
    {
        double maxHeight = 300;

        // TO-DO: Logic to get max heigth of all childrens with some buffer heigth, for now I am returning 300 as default group height

        return maxHeight;
    }

}

Here is the updated complete sample code which I am using for my application.
ShapesDesignerCode

Thanks,
IamHuM

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

左秋 2025-02-02 00:07:18

我尚不清楚您如何旋转形状以及如何获得所需的值以执行计算以及实际需要什么意义。您仍然没有透露足够的细节来为您提供一个工作解决方案。

如果您需要在Canvas上的形状位置。

如果您需要形状左上角的新绝对位置,则可以使用矩阵来计算它们:

double rotationAngle;
Point rotationCenter;
Point shapePositionOnCanvas;
var transformationMatrix = new Matrix();
transformationMatrix.RotateAt(rotationAngle, rotationCenter.X, rotationCenter.Y);
Point topLeftShapePosition = transformationMatrix.Transform(shapePositionOnCanvas);

It's not clear to me how you rotate the shapes and how you can get the required values to perform the calculations and what point you actually need. You still didn't reveal enough details to give you a working solution.

In case you need the shape position on the Canvas, you can reference the Canvas.Left and Canvas.Top properties and the angle of your group.

In case you need the new absolute location of the top-left corner of the shape, you can use the Matrix to calculate them:

double rotationAngle;
Point rotationCenter;
Point shapePositionOnCanvas;
var transformationMatrix = new Matrix();
transformationMatrix.RotateAt(rotationAngle, rotationCenter.X, rotationCenter.Y);
Point topLeftShapePosition = transformationMatrix.Transform(shapePositionOnCanvas);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文