Skip to content

Commit

Permalink
Add two-dimensional connectivities
Browse files Browse the repository at this point in the history
  • Loading branch information
haykam821 authored and Patbox committed Nov 17, 2024
1 parent b8e4da9 commit 5e6c20c
Show file tree
Hide file tree
Showing 2 changed files with 255 additions and 8 deletions.
62 changes: 54 additions & 8 deletions src/main/java/xyz/nucleoid/plasmid/api/util/BlockTraversal.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,30 +141,54 @@ boolean isComplete() {
* @see <a href="https://en.wikipedia.org/wiki/Pixel_connectivity#3-dimensional">3-dimensional pixel connectivity</a>
*/
public static final class Connectivity {
public static final Connectivity SIX = create(Connectivity::six);
public static final Connectivity EIGHTEEN = create(Connectivity::eighteen);
public static final Connectivity TWENTY_SIX = create(Connectivity::twentySix);
public static final Connectivity SIX = create(Connectivity::generateSix);
public static final Connectivity EIGHTEEN = create(Connectivity::generateEighteen);
public static final Connectivity TWENTY_SIX = create(Connectivity::generateTwentySix);

private static final Connectivity FOUR_X = create(consumer -> generateFour(Direction.Axis.X, consumer));
private static final Connectivity FOUR_Y = create(consumer -> generateFour(Direction.Axis.Y, consumer));
private static final Connectivity FOUR_Z = create(consumer -> generateFour(Direction.Axis.Z, consumer));

private static final Connectivity EIGHT_X = create(consumer -> generateEight(Direction.Axis.X, consumer));
private static final Connectivity EIGHT_Y = create(consumer -> generateEight(Direction.Axis.Y, consumer));
private static final Connectivity EIGHT_Z = create(consumer -> generateEight(Direction.Axis.Z, consumer));

final Vec3i[] offsets;

Connectivity(Vec3i[] offsets) {
this.offsets = offsets;
}

public static Connectivity four(Direction.Axis orthogonalAxis) {
return switch (orthogonalAxis) {
case X -> FOUR_X;
case Y -> FOUR_Y;
case Z -> FOUR_Z;
};
}

public static Connectivity eight(Direction.Axis orthogonalAxis) {
return switch (orthogonalAxis) {
case X -> EIGHT_X;
case Y -> EIGHT_Y;
case Z -> EIGHT_Z;
};
}

static Connectivity create(Consumer<Consumer<Vec3i>> generator) {
var offsets = new ArrayList<Vec3i>();
generator.accept(offsets::add);
return new Connectivity(offsets.toArray(new Vec3i[0]));
}

private static void six(Consumer<Vec3i> consumer) {
private static void generateSix(Consumer<Vec3i> consumer) {
for (var direction : Direction.values()) {
consumer.accept(direction.getVector());
}
}

private static void eighteen(Consumer<Vec3i> consumer) {
six(consumer);
private static void generateEighteen(Consumer<Vec3i> consumer) {
generateSix(consumer);

for (int x = -1; x <= 1; x += 2) {
for (int y = -1; y <= 1; y += 2) {
Expand All @@ -175,8 +199,8 @@ private static void eighteen(Consumer<Vec3i> consumer) {
}
}

private static void twentySix(Consumer<Vec3i> consumer) {
eighteen(consumer);
private static void generateTwentySix(Consumer<Vec3i> consumer) {
generateEighteen(consumer);

for (int z = -1; z <= 1; z += 2) {
for (int x = -1; x <= 1; x += 2) {
Expand All @@ -186,6 +210,28 @@ private static void twentySix(Consumer<Vec3i> consumer) {
}
}
}

private static void generateFour(Direction.Axis orthogonalAxis, Consumer<Vec3i> consumer) {
for (var direction : Direction.values()) {
if (direction.getAxis() != orthogonalAxis) {
consumer.accept(direction.getVector());
}
}
}

private static void generateEight(Direction.Axis orthogonalAxis, Consumer<Vec3i> consumer) {
generateFour(orthogonalAxis, consumer);

for (int x = -1; x <= 1; x += 2) {
for (int y = -1; y <= 1; y += 2) {
consumer.accept(switch (orthogonalAxis) {
case X -> new BlockPos(0, x, y);
case Y -> new BlockPos(y, 0, x);
case Z -> new BlockPos(x, y, 0);
});
}
}
}
}

/**
Expand Down
201 changes: 201 additions & 0 deletions src/test/java/xyz/nucleoid/plasmid/test/BlockTraversalTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
package xyz.nucleoid.plasmid.test;

import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import xyz.nucleoid.plasmid.api.util.BlockTraversal;
import org.junit.jupiter.api.Test;

import java.util.HashSet;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.*;

public class BlockTraversalTests {
@Test
public void testSixConnectivity() {
var expected = Set.of(
new BlockPos(-1, 0, 0),
new BlockPos(0, -1, 0),
new BlockPos(0, 0, -1),
new BlockPos(1, 0, 0),
new BlockPos(0, 1, 0),
new BlockPos(0, 0, 1)
);

var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.SIX);
assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal);
}

@Test
public void testEighteenConnectivity() {
var expected = Set.of(
new BlockPos(-1, 0, 0),
new BlockPos(0, -1, 0),
new BlockPos(0, 0, -1),
new BlockPos(1, 0, 0),
new BlockPos(0, 1, 0),
new BlockPos(0, 0, 1),

new BlockPos(-1, -1, 0),
new BlockPos(-1, 0, -1),
new BlockPos(0, -1, -1),
new BlockPos(1, -1, 0),
new BlockPos(1, 0, -1),
new BlockPos(0, 1, -1),
new BlockPos(-1, 1, 0),
new BlockPos(-1, 0, 1),
new BlockPos(0, -1, 1),
new BlockPos(1, 1, 0),
new BlockPos(1, 0, 1),
new BlockPos(0, 1, 1)
);

var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.EIGHTEEN);
assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal);
}

@Test
public void testTwentySixConnectivity() {
var expected = Set.of(
new BlockPos(-1, 0, 0),
new BlockPos(0, -1, 0),
new BlockPos(0, 0, -1),
new BlockPos(1, 0, 0),
new BlockPos(0, 1, 0),
new BlockPos(0, 0, 1),

new BlockPos(-1, -1, 0),
new BlockPos(-1, 0, -1),
new BlockPos(0, -1, -1),
new BlockPos(1, -1, 0),
new BlockPos(1, 0, -1),
new BlockPos(0, 1, -1),
new BlockPos(-1, 1, 0),
new BlockPos(-1, 0, 1),
new BlockPos(0, -1, 1),
new BlockPos(1, 1, 0),
new BlockPos(1, 0, 1),
new BlockPos(0, 1, 1),

new BlockPos(-1, -1, -1),
new BlockPos(-1, -1, 1),
new BlockPos(-1, 1, -1),
new BlockPos(-1, 1, 1),
new BlockPos(1, -1, -1),
new BlockPos(1, -1, 1),
new BlockPos(1, 1, -1),
new BlockPos(1, 1, 1)
);

var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.TWENTY_SIX);
assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal);
}

@Test
public void testFourConnectivityAxisX() {
var expected = Set.of(
new BlockPos(0, -1, 0),
new BlockPos(0, 1, 0),
new BlockPos(0, 0, -1),
new BlockPos(0, 0, 1)
);

var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.four(Direction.Axis.X));
assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal);
}

@Test
public void testFourConnectivityAxisY() {
var expected = Set.of(
new BlockPos(0, 0, -1),
new BlockPos(0, 0, 1),
new BlockPos(-1, 0, 0),
new BlockPos(1, 0, 0)
);

var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.four(Direction.Axis.Y));
assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal);
}

@Test
public void testFourConnectivityAxisZ() {
var expected = Set.of(
new BlockPos(-1, 0, 0),
new BlockPos(1, 0, 0),
new BlockPos(0, -1, 0),
new BlockPos(0, 1, 0)
);

var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.four(Direction.Axis.Z));
assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal);
}

@Test
public void testEightConnectivityAxisX() {
var expected = Set.of(
new BlockPos(0, -1, 0),
new BlockPos(0, 1, 0),
new BlockPos(0, 0, -1),
new BlockPos(0, 0, 1),

new BlockPos(0, -1, -1),
new BlockPos(0, -1, 1),
new BlockPos(0, 1, -1),
new BlockPos(0, 1, 1)
);

var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.eight(Direction.Axis.X));
assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal);
}

@Test
public void testEightConnectivityAxisY() {
var expected = Set.of(
new BlockPos(0, 0, -1),
new BlockPos(0, 0, 1),
new BlockPos(-1, 0, 0),
new BlockPos(1, 0, 0),

new BlockPos(-1, 0, -1),
new BlockPos(-1, 0, 1),
new BlockPos(1, 0, -1),
new BlockPos(1, 0, 1)
);

var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.eight(Direction.Axis.Y));
assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal);
}

@Test
public void testEightConnectivityAxisZ() {
var expected = Set.of(
new BlockPos(-1, 0, 0),
new BlockPos(1, 0, 0),
new BlockPos(0, -1, 0),
new BlockPos(0, 1, 0),

new BlockPos(-1, -1, 0),
new BlockPos(-1, 1, 0),
new BlockPos(1, -1, 0),
new BlockPos(1, 1, 0)
);

var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.eight(Direction.Axis.Z));
assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal);
}

private void assertSingleTraversalVisits(Set<BlockPos> expected, BlockPos origin, BlockTraversal traversal) {
Set<BlockPos> actual = new HashSet<>();

traversal.accept(origin, (pos, fromPos, depth) -> {
if (depth >= 1) {
actual.add(pos.toImmutable());
return BlockTraversal.Result.TERMINATE;
}

return BlockTraversal.Result.CONTINUE;
});

assertEquals(expected, actual);
}
}

0 comments on commit 5e6c20c

Please sign in to comment.