package openmods.shapes;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import java.util.List;
import openmods.utils.CollectionUtils;
import openmods.utils.render.GeometryUtils;
public class ShapeEquilateral2dGenerator extends DefaultShapeGenerator {
private static class Trig {
final double sin;
final double cos;
public Trig(double sin, double cos) {
this.sin = sin;
this.cos = cos;
}
}
private static class Point {
final int x;
final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "[" + x + "," + y + "]";
}
}
private enum Symmetry {
TwoFold(Math.PI) {
@Override
public IShapeable createMirroredShapeable(final IShapeable shapeable) {
return new IShapeable() {
@Override
public void setBlock(int x, int y, int z) {
if (z >= 0) {
shapeable.setBlock(x, y, +z);
shapeable.setBlock(x, y, -z);
}
}
};
}
@Override
public Point mirrorLastPoint(Point point) {
return new Point(point.x, -point.y);
}
},
FourFold(Math.PI / 2) {
@Override
public IShapeable createMirroredShapeable(final IShapeable shapeable) {
return new IShapeable() {
@Override
public void setBlock(int x, int y, int z) {
if (x >= 0 && z >= 0) {
shapeable.setBlock(+x, y, -z);
shapeable.setBlock(-x, y, -z);
shapeable.setBlock(-x, y, +z);
shapeable.setBlock(+x, y, +z);
}
}
};
}
@Override
public Point mirrorLastPoint(Point point) {
return new Point(-point.x, point.y);
}
},
EightFold(Math.PI / 4) {
@Override
public IShapeable createMirroredShapeable(final IShapeable shapeable) {
return new IShapeable() {
@Override
public void setBlock(int x, int y, int z) {
if (x >= z) {
shapeable.setBlock(+x, y, -z);
shapeable.setBlock(-x, y, -z);
shapeable.setBlock(-x, y, +z);
shapeable.setBlock(+x, y, +z);
shapeable.setBlock(+z, y, -x);
shapeable.setBlock(-z, y, -x);
shapeable.setBlock(-z, y, +x);
shapeable.setBlock(+z, y, +x);
}
}
};
}
@Override
public Point mirrorLastPoint(Point point) {
return new Point(point.y, point.x);
}
};
public abstract IShapeable createMirroredShapeable(IShapeable shapeable);
public abstract Point mirrorLastPoint(Point point);
public final double angleLimit;
private Symmetry(double angleLimit) {
this.angleLimit = angleLimit;
}
}
private static Symmetry findSymmetry(int sides) {
if (sides % 4 == 0) return Symmetry.EightFold;
if (sides % 2 == 0) return Symmetry.FourFold;
return Symmetry.TwoFold;
}
private final Symmetry symmetry;
private final Trig[] angles;
public ShapeEquilateral2dGenerator(int sides) {
this.symmetry = findSymmetry(sides);
final List<Trig> angles = Lists.newArrayList();
for (int i = 0; i < sides; i++) {
final double d = 2 * Math.PI * i / sides;
if (d > this.symmetry.angleLimit) break;
angles.add(new Trig(Math.sin(d), Math.cos(d)));
}
this.angles = angles.toArray(new Trig[angles.size()]);
}
@Override
public void generateShape(int minX, final int minY, int minZ, int maxX, final int maxY, int maxZ, final IShapeable shapeable) {
final IShapeable columnShapeable = new IShapeable() {
@Override
public void setBlock(int x, int ingored, int z) {
for (int y = minY; y <= maxY; y++)
shapeable.setBlock(x, y, z);
}
};
final double middleX = (maxX + minX) / 2.0;
final double radiusX = (maxX - minX) / 2.0;
final double middleZ = (maxZ + minZ) / 2.0;
final double radiusZ = (maxZ - minZ) / 2.0;
final Point[] points = CollectionUtils.transform(angles, new Function<Trig, Point>() {
@Override
public Point apply(Trig input) {
int x = (int)Math.round(middleX + radiusX * input.cos);
int z = (int)Math.round(middleZ + radiusZ * input.sin);
return new Point(x, z);
}
});
final IShapeable mirroredShapeable = symmetry.createMirroredShapeable(columnShapeable);
Point prevPoint = points[0];
for (int i = 1; i < points.length; i++) {
final Point point = points[i];
GeometryUtils.line2D(0, prevPoint.x, prevPoint.y, point.x, point.y, mirroredShapeable);
prevPoint = point;
}
final Point lastPoint = symmetry.mirrorLastPoint(prevPoint);
GeometryUtils.line2D(0, prevPoint.x, prevPoint.y, lastPoint.x, lastPoint.y, mirroredShapeable);
}
}