I need to pack triangles into a box as tightly as reasonable, as part of a 3D optimization (I'm stuffing alpha-using segments of different textures into a single different texture, for use with depth-sorting, so textures don't switch with every new tri)
Is there an algorithm for doing this? The triangles themselves can be made to be plyable (transformable to be right angles, effectively making this a box-stuffing algorithm instead), but I would like to avoid this if possible, as it would distort the underlying texture art.
"tight as reasonable" -> Something working is better than nothing.
These code fragments provide a simple solution to stuff shapes (also triangles) band by band into a rectangle.
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; } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With