package com.vitco.low;
import com.threed.jpct.SimpleVector;
import com.vitco.util.graphic.Util3D;
import com.vitco.util.misc.IntegerTools;
/**
* Indexes a 1600 ^ 3 cube.
*
* Defines mappings X x Y x Z -> Integer and reverse.
*/
public class CubeIndexer {
// dimension/radius
public static final short width = 1600; // up to 1600 is fine, because 1625^3 < Integer.MAX_VALUE - Integer.MIN_VALUE
public static final short radius = 800;
public static final int widthwidth = width * width;
// needs to be dividable by width ^ 2 and not smaller than Integer.MIN_VALUE
public static final int min = - 2145280000;
private static final int minOffset = radius + min/widthwidth;
// compute the 1d representation for the position (x right, y up, z into background)
public static int getId(short[] pos) {
return min + (pos[0] + radius) + (pos[2] + radius) * width + (pos[1] + radius) * widthwidth;
}
// compute the 1d representation for the position (x right, y up, z into background)
public static int getId(int x, int y, int z) {
return min + (x + radius) + (z + radius) * width + (y + radius) * widthwidth;
}
// get shift value (value that needs to be added to another pos id to
// shift it by that much into that direction)
public static int getShiftOperand(int shiftX, int shiftY, int shiftZ) {
return getId(shiftX,shiftY,shiftZ) + 95999200;
}
// compute the 1d representation for the position (x right, y up, z into background)
public static short[] getPos(int id) {
short x = (short) (IntegerTools.ifloormod2(id, width) - radius);
short z = (short) (IntegerTools.ifloordiv2(IntegerTools.ifloormod2(id,widthwidth),width) - radius);
short y = (short) (IntegerTools.ifloordiv2(id,widthwidth) - minOffset);
return new short[]{x,y,z};
}
// change position depending on orientation (move into direction)
public static int change(int pos, int orientation) {
switch (orientation) {
case 0: return changeX(pos, true);
case 1: return changeX(pos, false);
case 2: return changeY(pos, true);
case 3: return changeY(pos, false);
case 4: return changeZ(pos, true);
default: return changeZ(pos, false);
}
}
public static int changeX(int pos, boolean add) {
return pos + (add ? 1 : -1);
}
public static int changeY(int pos, boolean add) {
return pos + (add ? widthwidth : -widthwidth);
}
public static int changeZ(int pos, boolean add) {
return pos + (add ? width : -width);
}
// --------------------
// declare all triangles of the max box of this indexer
// Note: this is required to check if a ray hits the bounding box
private static final int intRadius = radius;
private static final SimpleVector upperLeftFront=new SimpleVector(-intRadius,-intRadius,-intRadius);
private static final SimpleVector upperRightFront=new SimpleVector(intRadius,-intRadius,-intRadius);
private static final SimpleVector lowerLeftFront=new SimpleVector(-intRadius, intRadius,-intRadius);
private static final SimpleVector lowerRightFront=new SimpleVector(intRadius, intRadius,-intRadius);
private static final SimpleVector upperLeftBack = new SimpleVector( -intRadius, -intRadius, intRadius);
private static final SimpleVector upperRightBack = new SimpleVector(intRadius, -intRadius, intRadius);
private static final SimpleVector lowerLeftBack = new SimpleVector( -intRadius, intRadius, intRadius);
private static final SimpleVector lowerRightBack = new SimpleVector(intRadius, intRadius, intRadius);
public static final SimpleVector[][] triangles = new SimpleVector[][]{
// Front
new SimpleVector[]{CubeIndexer.upperLeftFront, CubeIndexer.upperRightFront, CubeIndexer.lowerLeftFront}, // xy
new SimpleVector[]{CubeIndexer.upperRightFront, CubeIndexer.lowerRightFront, CubeIndexer.lowerLeftFront},
// Back
new SimpleVector[]{CubeIndexer.upperLeftBack, CubeIndexer.lowerLeftBack, CubeIndexer.upperRightBack},
new SimpleVector[]{CubeIndexer.upperRightBack, CubeIndexer.lowerLeftBack, CubeIndexer.lowerRightBack},
// Upper
new SimpleVector[]{CubeIndexer.upperLeftBack, CubeIndexer.upperRightBack, CubeIndexer.upperLeftFront}, // xz
new SimpleVector[]{CubeIndexer.upperRightBack, CubeIndexer.upperRightFront, CubeIndexer.upperLeftFront},
// Lower
new SimpleVector[]{CubeIndexer.lowerLeftBack, CubeIndexer.lowerLeftFront, CubeIndexer.lowerRightBack},
new SimpleVector[]{CubeIndexer.lowerRightBack, CubeIndexer.lowerLeftFront, CubeIndexer.lowerRightFront},
// Left
new SimpleVector[]{CubeIndexer.upperLeftBack, CubeIndexer.upperLeftFront, CubeIndexer.lowerLeftBack}, // yz
new SimpleVector[]{CubeIndexer.lowerLeftBack, CubeIndexer.upperLeftFront, CubeIndexer.lowerLeftFront},
// Right
new SimpleVector[]{CubeIndexer.upperRightBack, CubeIndexer.lowerRightBack, CubeIndexer.upperRightFront},
new SimpleVector[]{CubeIndexer.lowerRightBack, CubeIndexer.lowerRightFront, CubeIndexer.upperRightFront}
};
// If the origin is outside the limits of the max box this function tries to shift the
// origin into the max box or returns null if this is not possible
public static SimpleVector validateRay(SimpleVector origin, SimpleVector dir) {
if (origin.x < -CubeIndexer.radius || origin.x > CubeIndexer.radius ||
origin.y < -CubeIndexer.radius || origin.y > CubeIndexer.radius ||
origin.z < -CubeIndexer.radius || origin.z > CubeIndexer.radius
) {
// move origin into max box of hull manager
// We do this by checking all triangles of the bounding box until we hit one (or not)
boolean found = false;
for (SimpleVector[] triangle : CubeIndexer.triangles) {
SimpleVector newOrigin = Util3D.rayTriangleIntersects(triangle[0], triangle[1], triangle[2], origin, dir, true);
if (newOrigin != null) {
origin = newOrigin;
found = true;
break;
}
}
// no scaling possible since the CubeIndexer max box was not hit
if (!found) {
return null;
}
}
return origin;
}
}