从连续的固定尺寸矩形制作更宽的矩形?

时间:2014-01-07 04:45:08

标签: c++ algorithm stl

我正在努力为我的游戏添加Tile碰撞。

我所做的是,我浏览每个物体并获得它们周围的边缘。

我返回一个Vec2向量,它对应于每个周围边缘区块的左上角位置。

那些被置于一组Vec2中,所以只留下唯一的。

从那里,可以构建固定大小的矩形。

enter image description here

但是,我要求将连续的矩形合并为1。

所以在这个例子中,我们将这8个固定矩形变为3。

最右边的一个会保持不变。

x轴上的6将变为1,x轴上的最左边和下面的那个将变为1.

鉴于我有一个Vec2表示每个tile方块的左上角位置,我知道方块的宽度,我怎么能计算一个新的Rectangle(x,y,w,h)向量并合并固定方块?

    void TilePhysicsManager::update()
        {
            m_locationSet.clear(); //clear the unique locations

            for (b2Body* b = m_b2world->GetBodyList(); b; b = b->GetNext())
            {
                if(b->GetType() == b2_dynamicBody)
                {
                    PhysicsObject* obj = (PhysicsObject*)b->GetUserData();
                    const std::vector<Vec2>& edgeTiles = m_tileWorld->getSideTiles(*obj,1.5f);

                    //add in locations (duplicates will be rejected)
                    for(int i = 0; i < edgeTiles.size(); ++i)
                    {
                        m_locationSet.insert(edgeTiles[i]);
                    }

                }
            }

            int objIndex = 0; //index of which dummy object we need

            for(std::set<Vec2>::iterator it = m_locationSet.begin(); it != m_locationSet.end(); ++it)
            {
                //if our memory pool is not big enough, grow it
                if(objIndex >= count())
                {
                    allocNewObject();
                }

                m_objects[objIndex]->setLocation(*it);
                objIndex++;
            }
}

由于

2 个答案:

答案 0 :(得分:1)

我认为最简单快速的方法是在“垂直连续条带”扩展之后进行“水平连续条带”扩展,反之亦然。

例如:

  • 计算绑定矩形。垂直条带的数量是高度除以固定矩形的高度。
  • 创建一系列条形元素。存储每个条带的最小和最大X坐标。使用最小和最大协调来构造更宽的矩形。

enter image description here enter image description here

  • 然后,应用水平条带扩展。 (在我们的例子中,垂直条带扩展后我们将有4个矩形。)

enter image description here enter image description here

  • 创建一系列条形元素。存储每个条带的最小和最大Y坐标。使用最小和最大协调来构造更宽的矩形。
  • 检查更宽的垂直条带是否可以进一步扩展,如果是,则展开。

<强>结论:

  • 该算法假设每个条带中没有不连续性。

<强>实施

  • 以下是C#

    中的优化实现
    private List<Rectangle> Merge(Rectangle[] r) {
        // Computing the bound
        Rectangle bound = new Rectangle(r[0].X, r[0].Y, r[0].Width, r[0].Height);
        for (int i = 1; i < r.Length; ++i) {
            bound.X = Math.Min(bound.X, r[i].X);
            bound.Y = Math.Min(bound.Y, r[i].Y);
            bound.Width = Math.Max(bound.Right, r[i].Right) - bound.X;
            bound.Height = Math.Max(bound.Bottom, r[i].Bottom) - bound.Y;
        }
    
        // Create number of rectangle will be created by vertical strip expansion
        Rectangle[] m = new Rectangle[bound.Height / RECT_HEIGHT];
        for (int i = 0; i < m.Length; ++i) {
            m[i] = new Rectangle(Int32.MaxValue, bound.Y +  i * RECT_HEIGHT, 0, RECT_HEIGHT);
        }
    
        for (int i = 0; i < r.Length; ++i) {
            int index = (r[i].Y - bound.Y) / RECT_HEIGHT;
    
            if (m[index].Width <= 0) {
                m[index].Width = r[i].Width;
                m[index].X = r[i].X;
            } else {
                int right = m[index].Right;
                m[index].X = Math.Min(m[index].X, r[i].X);
                m[index].Width = Math.Max(right, r[i].Right) - m[index].X;
            }
        }
    
        // Merge horozontally
        for (int i = m.Length - 1; i > 0; --i) {
            // can only merge when two rect has the same X and Width
            if ((m[i].X == m[i - 1].X) && (m[i].Width == m[i - 1].Width)) {
                m[i - 1].Height += m[i].Height; // expanse the rectangle
                m[i].Width = 0;                // remove one rectangle
            }
        }
    
        // Remove all the empty rectangle
        List<Rectangle> result = new List<Rectangle>();
        for (int i = m.Length - 1; i >= 0; --i) {
            if (m[i].Width > 0)
                result.Add(m[i]);
        }
    
        return result;
    }
    

以下是通过以下实现生成的结果。左侧是初始矩形,右侧是结果。

  • 如果可以合并两个垂直框,则创建一个更大的矩形。

enter image description here

  • 将垂直框放在水平框上的优先级

enter image description here

  • 在一个垂直条带中的两个盒子之间存在间断空间。结果不是我们期望的结果。

enter image description here

答案 1 :(得分:0)

我认为问题陈述有点模糊不清。在给出的示例中,有多种可能的方法将给定的图块分组为最大的,不重叠的较大矩形。具体来说,左上角的图块可以按照您的建议与行的其余部分合并,也可以与下面的图块合并。

就算法而言,我首先想到的是逐个从集合中取出图块并通过它们的邻居展开它们。在展开多个图块的矩形时,只需检查该边缘上的所有图块是否都有一个邻居(剩下的内容)。一旦发现矩形无法在任何方向上展开,您就完成了,并可以继续前进到下一个图块。

这种方法对我来说似乎是O(n ^ 2),可能会有所改进,但在实践中很容易成为非问题,具体取决于规模和需要评估的频率(使用静态水平几何,我不希望经常这样做。

使用这样的方法要警惕的一件事是不要错误地在迭代它时从容器中删除元素。糟糕的iterator juju。只需复印一份。