diff --git a/HiderCore/src/de/steamwar/hullhider/Hull.java b/HiderCore/src/de/steamwar/hullhider/Hull.java index 081e47fe..02f8c56c 100644 --- a/HiderCore/src/de/steamwar/hullhider/Hull.java +++ b/HiderCore/src/de/steamwar/hullhider/Hull.java @@ -77,6 +77,7 @@ public class Hull { private final BitSet visibility; private final HashMap visibilityDirections = new HashMap<>(); // The blocks the rays of each direction got inside private final HashMap branches = new HashMap<>(); // The diagonal directions a ray along a single axis branches into + private final StepBeside[] stepsBeside; // The steps that can lead into or past a block, see uncoverBeside() private final HashSet uncoveredSurface = new HashSet<>(); private final Viewers viewers; @@ -108,6 +109,7 @@ public class Hull { ? Arrays.stream(directions).filter(v -> v.sqLength() >= 2 && dot(v, direction) == 1).toArray(IntVector[]::new) : NO_BRANCHES); } + stepsBeside = computeStepsBeside(); } /** @@ -333,49 +335,61 @@ public class Hull { uncoverBeside(uncovered, root); forEachBorderStart(root, direction -> startRay(uncovered, root, direction)); - uncoveredSurface.addAll(new HashSet<>(uncovered)); + uncoveredSurface.addAll(uncovered); uncoveredSurface.remove(root); } /** * Continues the rays inside the blocks in front of the block, or of which a diagonal ray moves past the block. - * The block lies in front of or beside the start of a step if it is the start moved along some or all axes of the direction. */ private void uncoverBeside(List uncovered, IntVector root) { - for (IntVector direction : directions) { - if (direction.sqLength() == 0) continue; + for (StepBeside step : stepsBeside) { + int x = root.x - step.part.x; + int y = root.y - step.part.y; + int z = root.z - step.part.z; + if (!region.contains(x, y, z)) continue; - for (IntVector part : directions) { - if (part.sqLength() == 0 || !isPartOf(part, direction)) continue; - - IntVector from = root.add(-part.x, -part.y, -part.z); - if (!from.notInRegion(region) && isInside(from.toId(region), direction)) { - uncoverNext(uncovered, from, direction, visibilityDirections.get(direction), branches.get(direction)); + int id = region.toIndex(x, y, z); + for (BitSet ray : step.rays) { + if (ray.get(id)) { + uncoverNext(uncovered, new IntVector(x, y, z), step.direction, step.directionalVisibility, step.branchDirections); + break; } } } } + /** + * The block lies in front of or beside the start of a step if it is the start moved along some or all axes of the direction. + * The rays of the direction and the rays along a single axis branching into it take the step. + */ + private StepBeside[] computeStepsBeside() { + List steps = new ArrayList<>(); + for (IntVector direction : directions) { + if (direction.sqLength() == 0) continue; + + BitSet[] rays = Arrays.stream(directions) + .filter(ray -> ray.equals(direction) || ray.sqLength() == 1 && direction.sqLength() > 1 && dot(ray, direction) == 1) + .map(visibilityDirections::get) + .toArray(BitSet[]::new); + for (IntVector part : directions) { + if (part.sqLength() > 0 && isPartOf(part, direction)) { + steps.add(new StepBeside(direction, part, visibilityDirections.get(direction), branches.get(direction), rays)); + } + } + } + return steps.toArray(new StepBeside[0]); + } + + private record StepBeside(IntVector direction, IntVector part, BitSet directionalVisibility, IntVector[] branchDirections, BitSet[] rays) { + } + private static boolean isPartOf(IntVector part, IntVector direction) { return (part.x == 0 || part.x == direction.x) && (part.y == 0 || part.y == direction.y) && (part.z == 0 || part.z == direction.z); } - /** - * @return whether a ray moving in the direction is inside the block: a ray of this direction or a branch of a ray along a single axis - */ - private boolean isInside(int id, IntVector direction) { - if (visibilityDirections.get(direction).get(id)) return true; - - for (IntVector cardinal : directions) { - if (cardinal.sqLength() == 1 && dot(cardinal, direction) == 1 && visibilityDirections.get(cardinal).get(id)) { - return true; - } - } - return false; - } - private static int dot(IntVector a, IntVector b) { return a.x * b.x + a.y * b.y + a.z * b.z; }