package greymerk.roguelike.worldgen.shapes; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import greymerk.roguelike.worldgen.Cardinal; import greymerk.roguelike.worldgen.Coord; import greymerk.roguelike.worldgen.IBlockFactory; import greymerk.roguelike.worldgen.IWorldEditor; public class RectPyramid implements IShape { private Coord start; private Coord end; public RectPyramid(Coord start, Coord end){ this.start = new Coord(start); this.end = new Coord(end); } @Override public Iterator<Coord> iterator() { return new SquarePyramidIterator(start, end); } @Override public void fill(IWorldEditor editor, Random rand, IBlockFactory block) { fill(editor, rand, block, true, true); } @Override public void fill(IWorldEditor editor, Random rand, IBlockFactory block, boolean fillAir, boolean replaceSolid) { for (Coord pos : this){ block.set(editor, rand, pos, fillAir, replaceSolid); } } @Override public List<Coord> get() { List<Coord> shape = new ArrayList<Coord>(); for (Coord pos : this){ shape.add(pos); } return shape; } private class SquarePyramidIterator implements Iterator<Coord>{ Coord start; Coord diff; Coord cursor; Cardinal dir; double thetaX; double thetaZ; public SquarePyramidIterator(Coord start, Coord end){ this.start = new Coord(start); Coord s = new Coord(start); Coord e = new Coord(end); Coord.correct(s, e); cursor = new Coord(0,0,0); dir = Cardinal.NORTH; diff = new Coord(e); diff.sub(s); double hx = Math.sqrt(Math.pow(diff.getX(), 2) + Math.pow(diff.getY(), 2)); thetaX = Math.acos((double)diff.getY() / hx); double hz = Math.sqrt(Math.pow(diff.getZ(), 2) + Math.pow(diff.getY(), 2)); thetaZ = Math.acos((double)diff.getY() / hz); } @Override public boolean hasNext() { return cursor.getY() < this.diff.getY(); } @Override public Coord next() { Coord toReturn = new Coord(start); toReturn.add(Cardinal.UP, cursor.getY()); if(dir == Cardinal.NORTH || dir == Cardinal.SOUTH){ toReturn.add(Cardinal.left(dir), cursor.getX()); toReturn.add(dir, cursor.getZ()); } else { toReturn.add(dir, cursor.getX()); toReturn.add(Cardinal.left(dir), cursor.getZ()); } if(this.dir != Cardinal.NORTH){ dir = Cardinal.left(dir); return toReturn; } cursor.add(Cardinal.SOUTH); if(inRange(cursor)){ dir = Cardinal.left(dir); return toReturn; } cursor = new Coord(cursor.getX(), cursor.getY(), 0); cursor.add(Cardinal.EAST); if(inRange(cursor)){ dir = Cardinal.left(dir); return toReturn; } cursor = new Coord(0, cursor.getY(), cursor.getZ()); cursor.add(Cardinal.UP); dir = Cardinal.left(dir); return toReturn; } @Override public void remove() { throw new UnsupportedOperationException(); } private boolean inRange(Coord pos){ int y = diff.getY() - cursor.getY(); if(!(cursor.getX() < Math.tan(thetaX) * y)){ return false; } if(!(cursor.getZ() < Math.tan(thetaZ) * y)){ return false; } return true; } } }