package com.hypixel.hytale.math.block;
import com.hypixel.hytale.function.predicate.TriIntObjPredicate;
import com.hypixel.hytale.math.util.MathUtil;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class BlockSphereUtil {
public BlockSphereUtil() {
}
public static <T> void forEachBlockExact(int originX, int originY, int originZ, double radius, @Nullable T t, @Nonnull TriIntObjPredicate<T> consumer) {
if (radius <= 0.0) {
throw new IllegalArgumentException(String.valueOf(radius));
} else {
int ceiledRadius = MathUtil.ceil(radius);
double invRadiusXSqr = 1.0 / (double)(ceiledRadius * ceiledRadius);
double invRadiusYSqr = 1.0 / (double)(ceiledRadius * ceiledRadius);
for(int x = -ceiledRadius; x <= ceiledRadius; ++x) {
double qx = 1.0 - (double)(x * x) * invRadiusXSqr;
double dy = Math.sqrt(qx) * (double)ceiledRadius;
int maxY;
int minY = -(maxY = (int)dy);
for(int y = maxY; y >= minY; --y) {
double dz = Math.sqrt(qx - (double)(y * y) * invRadiusYSqr) * (double)ceiledRadius;
int maxZ;
int minZ = -(maxZ = (int)dz);
for(int z = minZ; z <= maxZ; ++z) {
if (!consumer.test(originX + x, originY + y, originZ + z, t)) {
return;
}
}
}
}
}
}
public static <T> void forEachBlock(int originX, int originY, int originZ, int radius, @Nullable T t, @Nonnull TriIntObjPredicate<T> consumer) {
forEachBlock(originX, originY, originZ, radius, radius, radius, t, consumer);
}
public static <T> boolean forEachBlock(int originX, int originY, int originZ, int radiusX, int radiusY, int radiusZ, @Nullable T t, @Nonnull TriIntObjPredicate<T> consumer) {
if (radiusX <= 0) {
throw new IllegalArgumentException(String.valueOf(radiusX));
} else if (radiusY <= 0) {
throw new IllegalArgumentException(String.valueOf(radiusY));
} else if (radiusZ <= 0) {
throw new IllegalArgumentException(String.valueOf(radiusZ));
} else {
float radiusXAdjusted = (float)radiusX + 0.41F;
float radiusYAdjusted = (float)radiusY + 0.41F;
float radiusZAdjusted = (float)radiusZ + 0.41F;
float invRadiusXSqr = 1.0F / (radiusXAdjusted * radiusXAdjusted);
float invRadiusYSqr = 1.0F / (radiusYAdjusted * radiusYAdjusted);
for(int x = 0; x <= radiusX; ++x) {
float qx = 1.0F - (float)(x * x) * invRadiusXSqr;
double dy = Math.sqrt((double)qx) * (double)radiusYAdjusted;
int maxY = (int)dy;
for(int y = 0; y <= maxY; ++y) {
double dz = Math.sqrt((double)(qx - (float)(y * y) * invRadiusYSqr)) * (double)radiusZAdjusted;
int maxZ = (int)dz;
for(int z = 0; z <= maxZ; ++z) {
if (!test(originX, originY, originZ, x, y, z, t, consumer)) {
return false;
}
}
}
}
return true;
}
}
public static <T> void forEachBlock(int originX, int originY, int originZ, int radius, int thickness, @Nullable T t, @Nonnull TriIntObjPredicate<T> consumer) {
forEachBlock(originX, originY, originZ, radius, radius, radius, thickness, t, consumer);
}
public static <T> boolean forEachBlock(int originX, int originY, int originZ, int radiusX, int radiusY, int radiusZ, int thickness, @Nullable T t, @Nonnull TriIntObjPredicate<T> consumer) {
if (thickness < 1) {
return forEachBlock(originX, originY, originZ, radiusX, radiusY, radiusZ, t, consumer);
} else if (radiusX <= 0) {
throw new IllegalArgumentException(String.valueOf(radiusX));
} else if (radiusY <= 0) {
throw new IllegalArgumentException(String.valueOf(radiusY));
} else if (radiusZ <= 0) {
throw new IllegalArgumentException(String.valueOf(radiusZ));
} else {
float radiusXAdjusted = (float)radiusX + 0.41F;
float radiusYAdjusted = (float)radiusY + 0.41F;
float radiusZAdjusted = (float)radiusZ + 0.41F;
float innerRadiusXAdjusted = radiusXAdjusted - (float)thickness;
float innerRadiusYAdjusted = radiusYAdjusted - (float)thickness;
float innerRadiusZAdjusted = radiusZAdjusted - (float)thickness;
float invRadiusX2 = 1.0F / (radiusXAdjusted * radiusXAdjusted);
float invRadiusY2 = 1.0F / (radiusYAdjusted * radiusYAdjusted);
float invRadiusZ2 = 1.0F / (radiusZAdjusted * radiusZAdjusted);
float invInnerRadiusX2 = 1.0F / (innerRadiusXAdjusted * innerRadiusXAdjusted);
float invInnerRadiusY2 = 1.0F / (innerRadiusYAdjusted * innerRadiusYAdjusted);
float invInnerRadiusZ2 = 1.0F / (innerRadiusZAdjusted * innerRadiusZAdjusted);
int y = 0;
for(int y1 = 1; y <= radiusY; ++y1) {
float qy = (float)(y * y) * invRadiusY2;
double dx = Math.sqrt((double)(1.0F - qy)) * (double)radiusXAdjusted;
int maxX = (int)dx;
float innerQy = (float)(y * y) * invInnerRadiusY2;
float outerQy = (float)(y1 * y1) * invRadiusY2;
int x = 0;
for(int x1 = 1; x <= maxX; ++x1) {
float qx = (float)(x * x) * invRadiusX2;
double dz = Math.sqrt((double)(1.0F - qx - qy)) * (double)radiusZAdjusted;
int maxZ = (int)dz;
float innerQx = (float)(x * x) * invInnerRadiusX2;
float outerQx = (float)(x1 * x1) * invRadiusX2;
int z = 0;
for(int z1 = 1; z <= maxZ; ++z1) {
label47: {
float innerQz = (float)(z * z) * invInnerRadiusZ2;
if (innerQx + innerQy + innerQz < 1.0F) {
float outerQz = (float)(z1 * z1) * invRadiusZ2;
if (outerQx + outerQy + outerQz < 1.0F) {
break label47;
}
}
if (!test(originX, originY, originZ, x, y, z, t, consumer)) {
return false;
}
}
++z;
}
++x;
}
++y;
}
return true;
}
}
private static <T> boolean test(int originX, int originY, int originZ, int x, int y, int z, T context, @Nonnull TriIntObjPredicate<T> consumer) {
if (!consumer.test(originX + x, originY + y, originZ + z, context)) {
return false;
} else {
if (x > 0) {
if (!consumer.test(originX - x, originY + y, originZ + z, context)) {
return false;
}
if (y > 0 && !consumer.test(originX - x, originY - y, originZ + z, context)) {
return false;
}
if (z > 0 && !consumer.test(originX - x, originY + y, originZ - z, context)) {
return false;
}
if (y > 0 && z > 0 && !consumer.test(originX - x, originY - y, originZ - z, context)) {
return false;
}
}
if (y > 0) {
if (!consumer.test(originX + x, originY - y, originZ + z, context)) {
return false;
}
if (z > 0 && !consumer.test(originX + x, originY - y, originZ - z, context)) {
return false;
}
}
return z > 0 ? consumer.test(originX + x, originY + y, originZ - z, context) : true;
}
}
}