将任意三角形装入有限的盒子中

Packing arbitrary triangles into a finite box?

本文关键字:盒子 任意 三角形 装入      更新时间:2023-10-16

我需要将三角形尽可能紧密地打包到一个盒子中,作为3D优化的一部分(我正在将不同纹理的alpha-using片段填充到单个不同纹理中,用于深度排序,因此纹理不会随着每个新的tri而切换)

有一个算法来做这个吗?三角形本身可以被制作成可玩的(可转换成直角,有效地使其成为填充框算法),但我希望尽可能避免这种情况,因为它会扭曲底层纹理艺术。

"严格合理" ->总比什么都没有好。

这些代码片段提供了一个简单的解决方案,将形状(也包括三角形)一条带一条带地填充到矩形中。

public abstract class Shape {
    protected Point offset = new Point();
    public abstract int getHeight();
    public abstract int getWidth();
}
public class Triangle extends Shape {
    // all points are relative to offset (from Shape)
    Point top = new Point(); // top.y is always 0, left.y >= 0 right.y >= 0 
    Point left = new Point(); // left.x < right.x
    Point right = new Point();
    public int getHeight() {
        return left.y >= right.y ? left.y : right.y;
    }
    public int getWidth() {
        int xmin = left.x <= top.x ? left.x : top.x;
        int xmax = right.x >= top.x ? right.x : top.x;
        return xmax - xmin;
    }
}
public class StuffRectangle extends Shape {
    private Point ww = new Point();
    private ArrayList<Shape> maintained = new ArrayList<Shape>();
    private int insx;
    private int insy;
    private int maxy;
    public int getHeight() {
        return ww.y;
    }
    public int getWidth() {
        return ww.x;
    }
    public void clear() {
        insx = 0;
        insy = 0;
        maxy = 0;
        maintained.clear();
    }
    /**
     * Fill the rectangle band by band.
     * 
     * The inserted shapes are removed from the provided shape collection.
     * 
     * @param shapes
     *            the shapes to insert
     * @return the count of inserted shapes.
     */
    public int stuff(Collection<Shape> shapes) {
        int inserted = 0;
        for (;;) {
            int insertedInPass = 0;
            for (Iterator<Shape> i = shapes.iterator(); i.hasNext();) {
                Shape shape = i.next();
                // does the shape fit into current band?
                int sx = shape.getWidth();
                if (insx + sx > getWidth())
                    continue;
                int sy = shape.getHeight();
                if (insy + sy > getHeight())
                    continue;
                // does fit
                ++insertedInPass;
                // remove from shapes
                i.remove();
                // add to maintained and adjust offset
                maintained.add(shape);
                shape.offset.x = insx;
                shape.offset.y = insy;
                insx += sx;
                if (sy > maxy)
                    maxy = sy;
            }
            inserted += insertedInPass;
            if (shapes.isEmpty())
                break;
            // nothing fits current band - try a new band
            if (insertedInPass == 0) {
                // already a new band - does not fit at all
                if (insx == 0)
                    break;
                // start new band
                insx = 0;
                insy += maxy;
                maxy = 0;
                continue;
            }
        }
        return inserted;
    }
}