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 Sphere implements IShape {
private Coord start;
private Coord end;
public Sphere(Coord start, Coord end){
this.start = new Coord(start);
this.end = new Coord(end);
}
@Override
public Iterator<Coord> iterator() {
return new SphereIterator(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 SphereIterator implements Iterator<Coord>{
private Coord centre;
private int radius;
private int layer;
private int row;
private int col;
private Cardinal dir;
private boolean top;
public SphereIterator(Coord centre, Coord end){
this.centre = new Coord(centre);
Coord s = new Coord(centre);
Coord e = new Coord(end);
Coord.correct(s, e);
Coord diff = e.sub(s);
int r = diff.getX();
r = r < diff.getY() ? diff.getY() : r;
r = r < diff.getZ() ? diff.getZ() : r;
this.radius = r;
layer = 0;
row = 0;
col = 0;
top = true;
this.dir = Cardinal.NORTH;
}
@Override
public boolean hasNext() {
return layer < radius;
}
@Override
public Coord next() {
Coord toReturn = new Coord(centre);
toReturn.add(top ? Cardinal.UP : Cardinal.DOWN, layer);
toReturn.add(dir, row);
toReturn.add(Cardinal.left(dir), col);
if(this.dir != Cardinal.NORTH || top){
if(this.dir == Cardinal.NORTH){
top = false;
}
dir = Cardinal.left(dir);
return toReturn;
}
col += 1;
if(inRange(col, layer, row)){
dir = Cardinal.left(dir);
top = true;
return toReturn;
} else {
col = 0;
}
row += 1;
if(inRange(col, layer, row)){
dir = Cardinal.left(dir);
top = true;
return toReturn;
} else {
row = 0;
}
layer += 1;
dir = Cardinal.left(dir);
top = true;
return toReturn;
}
private boolean inRange(int x, int y, int z){
return x * x + y * y + z * z < radius * radius;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}