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 Ellipsoid implements IShape { private Coord start; private Coord end; public Ellipsoid(Coord start, Coord end){ this.start = new Coord(start); this.end = new Coord(end); } @Override public Iterator<Coord> iterator() { return new EllipsoidIterator(start, end); } @Override public void fill(IWorldEditor editor, Random rand, IBlockFactory block) { this.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> copy = new ArrayList<Coord>(); for(Coord pos : this){ copy.add(pos); } return copy; } private class EllipsoidIterator implements Iterator<Coord>{ private Coord centre; private Coord diff; private Coord cursor; private Cardinal dir; private boolean top; public EllipsoidIterator(Coord centre, Coord end){ this.centre = new Coord(centre); Coord s = new Coord(centre); Coord e = new Coord(end); this.diff = e.sub(s); this.diff = new Coord(Math.abs(diff.getX()), Math.abs(diff.getY()), Math.abs(diff.getZ())); cursor = new Coord(0,0,0); top = true; this.dir = Cardinal.NORTH; } @Override public boolean hasNext() { return cursor.getY() < diff.getY(); } @Override public Coord next() { Coord toReturn = new Coord(centre); toReturn.add(top ? Cardinal.UP : Cardinal.DOWN, 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 || top){ if(this.dir == Cardinal.NORTH){ top = false; } dir = Cardinal.left(dir); return toReturn; } cursor.add(Cardinal.SOUTH); if(inRange(cursor)){ dir = Cardinal.left(dir); top = true; return toReturn; } else { cursor = new Coord(cursor.getX(), cursor.getY(), 0); } cursor.add(Cardinal.EAST); if(inRange(cursor)){ dir = Cardinal.left(dir); top = true; return toReturn; } else { cursor = new Coord(0, cursor.getY(), cursor.getZ()); } cursor.add(Cardinal.UP); dir = Cardinal.left(dir); top = true; return toReturn; } private boolean inRange(Coord pos){ double x = pos.getX(); double y = pos.getY(); double z = pos.getZ(); double rx = this.diff.getX() == 0 ? 1 : this.diff.getX(); double ry = this.diff.getY() == 0 ? 1 : this.diff.getY(); double rz = this.diff.getZ() == 0 ? 1 : this.diff.getZ(); return ((x / rx) * (x / rx)) + ((y / ry) * (y / ry)) + ((z / rz) * (z / rz)) <= 1; } @Override public void remove() { throw new UnsupportedOperationException(); } } }