gpt4 book ai didi

c# - 旋转和打印正方形

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:30:29 26 4
gpt4 key购买 nike

有一个关于 c# 赋值的快速问题,wpf。任务是读入一个 XML 文件,其中包含一个根面板的描述,然后它遵循一个固定的模式,其中每个面板都有多个子面板,每个子面板可以有多个子模式。很明显。我可以很好地阅读它,遍历模型也没有问题。

问题是:我必须在 wpf Canvas 上打印这些面板。父子面板的关系如下:

  • 根面板有 X Y 坐标来确定它的起点。其他面板没有
  • 每个面板,包括根面板,都有宽度和高度(不一定相同)
  • 每个面板(根面板除外)都有一个属性“attachedToSide”,其值介于 0 到 3 之间。该值表示应将子项放置在父项的哪一侧。
  • 在父面板上打印面板时,我们应该始终将面板的“0”侧与父面板相对。

所以为了证明:请看下面的草稿。打印根面板。根节点有 4 个子节点。将面板置于根的右侧。该面板将具有属性 attachedToSide='1' 以表示它应该贴在其父面板的一侧。现在由于规则是 0 侧应该粘在父级上,所以我们必须将它翻转 90°。故事就这样继续下去。

enter image description here

现在,打印本身就没有问题了。我有点挣扎的地方是计算每个方 block 的实际位置。 parent 的第一个 child 很容易,但从那时起,我必须根据前面的面板进行一些计算以正确定位它们,并且我不想走嵌套 if 语句的路线。可能存在一个非常简单的算法来解决这个问题,但由于我不在那个领域,所以我有点挣扎。谁能给我一个正确方向的插入?

详细信息:这一切也纯粹是 mvvm(只是为了它),所以代码隐藏中的代码为 0。这些形状是一个带有自定义项目面板模板和项目模板的项目集合,我通过将旋转角度绑定(bind)到模型中的属性来进行旋转。

最佳答案

user3386109 的回答将我推向了正确的方向,但我得到了一些关于帮助我解决这个问题的额外信息。看看这个例子:example

父级打印时 0 面朝下(这是标准的)。它有 3 个 child :右、上、左。现在,父级是我收到 X、Y 坐标的唯一面板。 (X,Y) 是 0 边的中心。另外我得到宽度和高度。对于以后的所有子项,我会得到父项所在的宽度、高度和边。由于子项应始终通过自己的 0 边连接到其父项,因此我可以使用 user3386109 已经显示的 mod-wrapping 公式非常轻松地计算出子项的底边:bottom side child = (bottom side parent + 6 - parents attachment side) % 4

这是最简单的部分。现在,一个复杂的问题是每个子项都可以比父项更宽或更窄,比父项更高或更低。这可能会使计算我们需要绘制的左上角 (X,Y) 点变得复杂。然而,我一直知道的一件事是, child 所依附的父方的中心点应该与接触该父方的子方中心相同(参见图片上的红线,那将告诉你我的意思)。

现在我使用了以下方法:我决定计算左上角的坐标,假设我可以“直立”地画 child ,所以底部是 0 侧。然后,我会沿着那个点旋转。

举个例子:

enter image description here

注意黑色的父面板。我从 XML 中知道我需要将子面板附加到父面板的第一面。因此,我从它自己的 0 侧中心计算父 1 侧的中心点。我知道那将是 child 0 边的中心,因为那是我需要将它们连接在一起的地方。然后我计算 child 的左上角 (X,Y) 坐标,这很简单。之后,我可以沿着它的中心 0 侧点旋转 child 。然后我们得到以下结果,父子连接在中心, child 也以正确的方式旋转。

enter image description here

简而言之,它始终是相同的方法:

  • 以父级的 0 侧为中心(我们将存储在每个面板对象中)
  • 相对于那个点,计算 child 的0侧中心在什么地方
  • 如果我们有那个点,计算 child 的左上角点,这样我们就知道从哪里画画了
  • 沿着它的 0 侧中心点旋转 child (我们知道从底部那一侧开始的旋转度数)

完成。一个额外的并发症是每个 child 都会收到一个特定的“偏移”值。简而言之,这是一个正值或负值,表示将子项推向某个方向(仍然依附于父项)。这个问题只要调整好坐标就很容易解决了。

现在,要计算所有点,很明显这完全取决于父旋转、自身旋转等。在检查变化时,我得出的结论是很多公式看起来非常相似。完整的解释需要大量的打字,坦率地说,我懒得打扰。但是:这里是根据给定的父矩形、子宽度、它应该位于父矩形的哪一侧的高度以及偏移量创建子矩形的代码。

    private static Rectangle CreateRectangle(string name, float width, float height, int sideOfParent, float offset, Rectangle parent)
{
Rectangle rect = new Rectangle() { Name = name, Width = width, Height = height, Offset = offset };
// Calculate which side should be at the bottom, depending on the bottom side of the parent,
// and which side of the parent the new rectangle should be attached to
rect.BottomSide = (parent.BottomSide + 6 - sideOfParent) % 4;

// Calculate the bottom mid point of the rectangle
// If | bottom side parent - bottom side child | = 2, just take over the mid bottom point of the parent
if (Math.Abs(parent.BottomSide - rect.BottomSide) == 2) { rect.MidBottom = parent.MidBottom; }
else
{
// Alternative cases
// Formulas for both bottom side parent = 0 or 2 are very similar per bottom side child variation (only plus/minus changes for Y formulas)
// Formulas for both bottom side parent = 1 or 3 are vary similar per bottom side child variation (only plus/minus changes for X formulas)
// Therefor, we create a "mutator" 1 / -1 if needed, to multiply one part of the formula with, so that we either add or subtract
Point parPoint = parent.MidBottom;
if (parent.BottomSide % 2 == 0)
{
// Parent has 0 or 2 at the bottom
int mutator = (parent.BottomSide == 0) ? 1 : -1;
switch (rect.BottomSide % 2 == 0)
{
case true: rect.MidBottom = new Point(parPoint.X, parPoint.Y - (mutator * parent.Height)); break;
case false:
if (rect.BottomSide == 1) rect.MidBottom = new Point(parPoint.X + (parent.Width / 2), parPoint.Y - (mutator * (parent.Height / 2)));
else rect.MidBottom = new Point(parPoint.X - (parent.Width / 2), parPoint.Y - (mutator * (parent.Height / 2)));
break;
}
}
else
{
// Parent has 1 or 3 at the bottom
int mutator = (parent.BottomSide == 1) ? 1 : -1;
switch (rect.BottomSide % 2 == 1)
{
case true: rect.MidBottom = new Point(parPoint.X + (mutator * parent.Height), parPoint.Y); break;
case false:
if (rect.BottomSide == 0) rect.MidBottom = new Point(parPoint.X + (mutator * (parent.Height / 2)), parPoint.Y - (parent.Width / 2));
else rect.MidBottom = new Point(parPoint.X + (mutator * (parent.Height / 2)), parPoint.Y + (parent.Width / 2));
break;
}
}
}

return rect;
}

所有这一切的现实生活结果示例:

enter image description here

正如我已经提到的,实际绘图只是通过将 ItemCollection 放在标准网格上、绑定(bind)到矩形集合并在其中设置适当的 ItemsPanel 和 ItemTemplate、标准 WPF 来完成。

关于c# - 旋转和打印正方形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40306066/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com