Algorithm 需要算法来绘制重叠的矩形

Algorithm 需要算法来绘制重叠的矩形,algorithm,rectangles,Algorithm,Rectangles,我需要帮助高效地绘制/剔除一系列不透明矩形,换句话说,这是桌子上的一堆索引卡。具体内容如下: 没有旋转,所以一切都是简单的整数坐标,轴对齐 卡片是完全不透明的 卡片可以有任意整数X,Y位置 所有的卡片大小都一样 我有一张按z顺序排列的卡片清单 我认为我(基本上)有两个选择: 1) 蛮力画师的方法,桌面视口中的所有卡片都以相反的z顺序完全绘制。优点:简单。缺点:a)需要屏幕外缓冲区以避免闪烁;b)在绘制每张卡的昂贵区域时可能会浪费大量时间,而该区域最终可能会被遮挡,最糟糕的情况是整个卡都被覆盖

我需要帮助高效地绘制/剔除一系列不透明矩形,换句话说,这是桌子上的一堆索引卡。具体内容如下:

  • 没有旋转,所以一切都是简单的整数坐标,轴对齐
  • 卡片是完全不透明的
  • 卡片可以有任意整数X,Y位置
  • 所有的卡片大小都一样
  • 我有一张按z顺序排列的卡片清单
我认为我(基本上)有两个选择:

1) 蛮力画师的方法,桌面视口中的所有卡片都以相反的z顺序完全绘制。优点:简单。缺点:a)需要屏幕外缓冲区以避免闪烁;b)在绘制每张卡的昂贵区域时可能会浪费大量时间,而该区域最终可能会被遮挡,最糟糕的情况是整个卡都被覆盖

2) 一种算法,为每张卡生成一个可见(或模糊)矩形列表,这样就只绘制可见部分

选择2是我需要建议的地方,特别是在算法方面,以及“更聪明”的抽签周期的赞成和反对意见

任何与语言/平台无关的建议都将不胜感激。如果有必要,这将在MS Windows上实现

我愿意接受任何建议,包括混合方法。我意识到一个精确的答案可能非常依赖于代码的细节,但我很高兴即使在这一点上有广义的概念


附加说明:将有可能有数千张卡片堆叠在彼此的顶部,因此我强烈希望避免使用纯暴力画师的方法-至少不需要某种预处理来剔除完全模糊的卡片。同样的情况也适用于许多紧密平铺的卡片,更糟糕的是,它们只显示边框——如果可能的话,我不想在这些情况下绘制复杂的内部结构。

只从最底部到最顶部绘制每张卡片的轮廓线怎么样?然后可以进行整体填充来绘制轮廓的内部。这样,您将只重新绘制与存在交点的边界相对应的几个像素

编辑:上传图片来帮助我解释这个想法

第一步是标记指定Z顺序的卡的边框(左上图)。通过这种方式,会有覆盖,但仅覆盖少量像素的边界

之后,可以按照以下两条规则绘制卡的纹理(首先是最低Z顺序):

  • 从边界开始,绘制空白,直到到达边界
  • 如果边框的Z顺序是当前顺序,则绘制它
  • 如果找到的边框Z顺序小于当前Z顺序,则继续绘制,因为它是空白的
  • 否则,您会发现一个Z顺序更大的边框,因此跳过该块
  • 下一张牌

希望有帮助:)

好的,下面是一些松散的伪代码,我认为可以如何解决这个问题

从按z顺序排序的卡片列表开始。每张卡都有一个可见的矩形列表(稍后解释),只需要从一个矩形开始,设置为卡的完整边界框。循环首先从最低的z顺序卡开始

Cards.SortZOrder();
foreach Card in Cards do
  Card.ResetVisibleRects; // VisibleRects.DeleteAll; VisibleRects.Add(BoundingBox);

CurrentCard = Cards.Last;
TestCard = CurrentCard;
这里的想法是,我们将从“当前”牌向上工作,看看每一张更高的牌对它有什么影响。当我们测试每一张更高的卡时,有3种可能性。它要么完全遗漏,要么完全模糊,要么部分模糊。对于完全未命中,我们忽略测试卡,因为它不会影响当前卡。对于一张完全模糊的卡片,我们当前的卡片被剔除。部分重叠是可见矩形列表出现的地方,因为部分重叠可以(潜在地)将下部矩形一分为二。(如果您只需抓取两张扑克牌或索引卡,很容易看出这是如何进行的。如果共享任何边,则顶部的扑克牌会导致底部的扑克牌调整其中一条边;如果没有共享边,则底部的扑克牌会分成两个矩形。)

警告:这是非常未优化、未展开的代码。。。只是为了谈谈原则。是的,我要用“goto”。。。如果你一定要嘲笑我的话

[GetNextCard]
TestCard = Cards.NextHighest(TestCard);

[OverlapTest]
// Test the overlap of TestCard against all our VisibleRects.
// The first time through this test, CurrentCard will have only one
// rect in the VisibleRect list, but that rect may get split up later.
// OverlapTests() checks each rect in the VisibleRects list, and
// creates an Overlap record for any of the rects that do overlap,
// like: Overlap.RectIndex, Overlap.Type. It also summarizes the
// results into the .Summary field. 

Result = CurrentCard.OverlapTests(TestCard);

case Result.Summary
  none: 
    goto [GetNextCard];

  complete:
    CurrentCard.Culled = true;

    // we're now done with this CurrentCard, so we move upwards
    CurrentCard = TestCard;
    goto [GetNextCard]

  partial:
    // since there was some overlap, we need to adjust,
    // split, or delete some or all of our visible rectangles.
    // (we won't delete them all, that would have been caught above)

    foreach Overlap in Result.Overlaps
      R = CurrentCard.VisibleRects[Overlap.RectIndex];
      case Overlap.Type
        partial: CurrentCard.SplitOrAdjust(R, TestCard);
        complete: CurrentCard.Delete(R);
      end case

    // so we've either added new rects, or deleted some, but either 
    // way, we're done with this test card. We leave CurrentCard
    // where it is and loop to look at the next higher card.
    goto [GetNextCard]
CurrentCard=Cards时进行测试。由于最上面的卡始终是完全可见的,所以测试首先进行

这里还有一些想法

我认为这在实际代码中相当简单。最复杂的事情是把一个长方形一分为二,考虑到它都是整数数学,即使这很简单

此外,不必在每个喷漆周期都执行此操作。仅当内容、位置或z顺序发生任何变化时才需要执行此操作


在向上传递列表后,您将看到一个绘制就绪的卡片列表,每个未剔除的卡片至少有一个矩形,可能位于显示的剪裁/脏区域内。当你画一张卡片时,你可以查看它的可见矩形列表,并且有可能跳过绘制卡片的某些部分,这些部分的渲染成本可能会很高。

我在用C编写扑克程序时遇到了类似的情况。从内存中,我相信我所需要计算的只是给定了卡片位置和尺寸的无效矩形,然后将其传递给paint方法,而不是允许它对窗口进行完全刷新。对不起,如果这有点模糊,但它是大约10年前。是的,有点模糊:)这是关于“计算无效矩形”的部分,这是问题的核心。另外,任何一张卡都可能有多个无效的矩形,这取决于上面的内容。“完全刷新”只是任何绘制周期的衍生情况,因为整个屏幕可能被标记为无效。它们可能是非常松散的平铺,只有一点重叠,在这种情况下,我确实需要下部卡片的内容可见。如果边框重叠,是否要显示下部而不是c