Skip to content

Commit 929d1ef

Browse files
committed
Convert VolumeStream to use Vector3d's
There's effectively a problem with positions of blocks, they're technically considered the corners of a dotted world, and since transformations are performed on the double accuracy positioning, we want to be able to retain those positions as much as possible throughout however many transformations on a volume are made. This is mostly to support the ability to rotate and mirror volumes in their entirety. The implementations are already semi-functional, pending some off by one errors to be found and fixed. Signed-off-by: Gabriel Harris-Rouquette <[email protected]>
1 parent 31c75ac commit 929d1ef

File tree

8 files changed

+60
-34
lines changed

8 files changed

+60
-34
lines changed

src/main/java/org/spongepowered/api/world/volume/stream/VolumeApplicators.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public final class VolumeApplicators {
6767
* @return A blockstate based VolumeApplicator
6868
*/
6969
public static <M extends BlockVolume.Modifiable<M>> VolumeApplicator<M, BlockState, Boolean> applyBlocks() {
70-
return ((volume, element) -> volume.setBlock(element.position(), element.type()));
70+
return ((volume, element) -> volume.setBlock(element.position().round().toInt(), element.type()));
7171
}
7272

7373
/**
@@ -82,7 +82,7 @@ public static <M extends BlockVolume.Modifiable<M>> VolumeApplicator<M, BlockSta
8282
*/
8383
public static <M extends PhysicsAwareMutableBlockVolume<M>> VolumeApplicator<M, BlockState, Boolean> applyBlocks(final BlockChangeFlag flag) {
8484
Objects.requireNonNull(flag, "BlockChangeFlag cannot be null!");
85-
return ((volume, element) -> volume.setBlock(element.position(), element.type(), flag));
85+
return ((volume, element) -> volume.setBlock(element.position().round().toInt(), element.type(), flag));
8686
}
8787

8888
/**
@@ -95,8 +95,8 @@ public static <M extends PhysicsAwareMutableBlockVolume<M>> VolumeApplicator<M,
9595
*/
9696
public static <M extends BlockEntityVolume.Modifiable<M>> VolumeApplicator<M, BlockEntity, Boolean> applyBlockEntities() {
9797
return (volume, element) -> {
98-
if (volume.setBlock(element.position(), element.type().block())) {
99-
volume.addBlockEntity(element.position(), element.type());
98+
if (volume.setBlock(element.position().round().toInt(), element.type().block())) {
99+
volume.addBlockEntity(element.position().round().toInt(), element.type());
100100
return true;
101101
}
102102
return false;
@@ -118,13 +118,13 @@ public static <M extends BlockEntityVolume.Modifiable<M>> VolumeApplicator<M, Op
118118
final Optional<? extends BlockEntity> blockEntityOpt = element.type();
119119
if (blockEntityOpt.isPresent()) {
120120
final BlockEntity blockEntity = blockEntityOpt.get();
121-
if (volume.setBlock(element.position(), blockEntity.block())) {
122-
volume.addBlockEntity(element.position(), blockEntity);
121+
if (volume.setBlock(element.position().round().toInt(), blockEntity.block())) {
122+
volume.addBlockEntity(element.position().round().toInt(), blockEntity);
123123
return true;
124124
}
125125
return false;
126126
} else {
127-
return volume.removeBlock(element.position());
127+
return volume.removeBlock(element.position().round().toInt());
128128
}
129129
};
130130
}
@@ -140,8 +140,8 @@ public static <M extends BlockEntityVolume.Modifiable<M>> VolumeApplicator<M, Op
140140
*/
141141
public static <M extends BlockVolume.Modifiable<M>> VolumeApplicator<M, Optional<BlockState>, Boolean> applyOrRemoveBlockState() {
142142
return (volume, element) -> element.type()
143-
.map(blockState -> volume.setBlock(element.position(), blockState))
144-
.orElseGet(() -> volume.removeBlock(element.position()));
143+
.map(blockState -> volume.setBlock(element.position().round().toInt(), blockState))
144+
.orElseGet(() -> volume.removeBlock(element.position().round().toInt()));
145145
}
146146

147147
/**
@@ -155,8 +155,8 @@ public static <M extends BlockVolume.Modifiable<M>> VolumeApplicator<M, Optional
155155
*/
156156
public static <M extends PhysicsAwareMutableBlockVolume<M>> VolumeApplicator<M, Optional<BlockState>, Boolean> applyOrRemoveBlockState(final BlockChangeFlag flag) {
157157
return (volume, element) -> element.type()
158-
.map(blockState -> volume.setBlock(element.position(), blockState, flag))
159-
.orElseGet(() -> volume.removeBlock(element.position()));
158+
.map(blockState -> volume.setBlock(element.position().round().toInt(), blockState, flag))
159+
.orElseGet(() -> volume.removeBlock(element.position().round().toInt()));
160160
}
161161

162162
/**
@@ -182,7 +182,7 @@ public static <M extends PhysicsAwareMutableBlockVolume<M>> VolumeApplicator<M,
182182
*/
183183
public static <M extends BlockEntityArchetypeVolume.Modifiable<M>> VolumeApplicator<M, BlockEntityArchetype, Boolean> applyBlockEntityArchetypes() {
184184
return (volume, element) -> {
185-
volume.addBlockEntity(element.position(), element.type());
185+
volume.addBlockEntity(element.position().round().toInt(), element.type());
186186
return true;
187187
};
188188
}
@@ -208,7 +208,7 @@ public static <M extends EntityVolume.Modifiable<M>> VolumeApplicator<M, Entity,
208208
* @return A volume applicator that applies biomes to volumes
209209
*/
210210
public static <M extends BiomeVolume.Modifiable<M>> VolumeApplicator<M, Biome, Boolean> applyBiomes() {
211-
return (volume, element) -> volume.setBiome(element.position(), element.type());
211+
return (volume, element) -> volume.setBiome(element.position().round().toInt(), element.type());
212212
}
213213

214214
@SuppressWarnings("unchecked")

src/main/java/org/spongepowered/api/world/volume/stream/VolumeConsumer.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,9 @@
2929
@FunctionalInterface
3030
public interface VolumeConsumer<V extends Volume, T> {
3131

32-
void consume(V volume, T type, int x, int y, int z);
32+
default void consume(final V volume, final T type, final int x, final int y, final int z) {
33+
this.consume(volume, type, x + 0.5, y + 0.5, z + 0.5);
34+
}
35+
36+
void consume(V volume, T type, double x, double y, double z);
3337
}

src/main/java/org/spongepowered/api/world/volume/stream/VolumeElement.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import org.checkerframework.checker.nullness.qual.NonNull;
2828
import org.checkerframework.checker.nullness.qual.Nullable;
2929
import org.spongepowered.api.world.volume.Volume;
30-
import org.spongepowered.math.vector.Vector3i;
30+
import org.spongepowered.math.vector.Vector3d;
3131

3232
import java.lang.ref.WeakReference;
3333
import java.util.Objects;
@@ -36,15 +36,15 @@
3636

3737
public interface VolumeElement<V extends Volume, T> {
3838

39-
static <W extends Volume, T> VolumeElement<W, T> of(final Supplier<W> volume, final Supplier<? extends T> type, final Vector3i position) {
39+
static <W extends Volume, T> VolumeElement<W, T> of(final Supplier<W> volume, final Supplier<? extends T> type, final Vector3d position) {
4040
return new VolumeElement<W, T>() {
4141
@Override
4242
public W volume() {
4343
return volume.get();
4444
}
4545

4646
@Override
47-
public Vector3i position() {
47+
public Vector3d position() {
4848
return position;
4949
}
5050

@@ -83,13 +83,13 @@ public int hashCode() {
8383
};
8484
}
8585

86-
static <V extends Volume, T> VolumeElement<V, T> of(final V volume, final Supplier<? extends T> type, final Vector3i position) {
86+
static <V extends Volume, T> VolumeElement<V, T> of(final V volume, final Supplier<? extends T> type, final Vector3d position) {
8787
final WeakReference<V> volumeRef = new WeakReference<>(volume);
8888
final Supplier<V> volumeSupplier = () -> Objects.requireNonNull(volumeRef.get(), "Volume de-referenced");
8989
return VolumeElement.of(volumeSupplier, type, position);
9090
}
9191

92-
static <V extends Volume, T> VolumeElement<V, T> of(final V volume, final T type, final Vector3i position) {
92+
static <V extends Volume, T> VolumeElement<V, T> of(final V volume, final T type, final Vector3d position) {
9393
final WeakReference<V> volumeRef = new WeakReference<>(volume);
9494
final Supplier<V> volumeSupplier = () -> Objects.requireNonNull(volumeRef.get(), "Volume de-referenced");
9595
final WeakReference<T> typeRef = new WeakReference<>(type);
@@ -106,7 +106,7 @@ static <V extends Volume, T> VolumeElement<V, T> of(final V volume, final T type
106106
*/
107107
V volume();
108108

109-
Vector3i position();
109+
Vector3d position();
110110

111111
T type();
112112

src/main/java/org/spongepowered/api/world/volume/stream/VolumeFlatMapper.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,9 @@
3232
@FunctionalInterface
3333
public interface VolumeFlatMapper<V extends Volume, T> {
3434

35-
Optional<? extends T> map(V volume, Supplier<T> value, int x, int y, int z);
35+
default Optional<? extends T> map(final V volume, final Supplier<T> value, final int x, final int y, final int z) {
36+
return this.map(volume, value, x + 0.5, y + 0.5, z + 0.5);
37+
}
38+
39+
Optional<? extends T> map(V volume, Supplier<T> value, double x, double y, double z);
3640
}

src/main/java/org/spongepowered/api/world/volume/stream/VolumeMapper.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,9 @@
3131
@FunctionalInterface
3232
public interface VolumeMapper<V extends Volume, T, Out> {
3333

34-
Out map(V volume, Supplier<T> value, int x, int y, int z);
34+
default Out map(final V volume, final Supplier<T> value, final int x, final int y, final int z) {
35+
return this.map(volume, value, x + 0.5, y + 0.5, z + 0.5);
36+
}
37+
38+
Out map(V volume, Supplier<T> value, double x, double y, double z);
3539
}

src/main/java/org/spongepowered/api/world/volume/stream/VolumePositionTranslators.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
public final class VolumePositionTranslators {
3939

40+
public static final Vector3d BLOCK_OFFSET = new Vector3d(0.5, 0.5, 0.5);
41+
4042
public static <W extends Volume, E> VolumePositionTranslator<W, E> identity() {
4143
return element -> element;
4244
}
@@ -46,24 +48,32 @@ public static <W extends Volume> VolumePositionTranslator<W, BlockState> rotateB
4648
}
4749

4850
public static <W extends Volume, E> VolumePositionTranslator<W, E> rotateOn(final Vector3i start, final Vector3d center, final Rotation rotation,
49-
final BiFunction<Vector3i, E, E> elementRotation
51+
final BiFunction<Vector3d, E, E> elementRotation
5052
) {
5153
return element -> {
5254
final Quaterniond q = Quaterniond.fromAngleDegAxis(rotation.angle().degrees(), 0, 1, 0);
53-
final Vector3i v = q.rotate(center).add(element.position().toDouble().sub(start.toDouble())).round().toInt();
55+
final Vector3d v = q.rotate(center).add(element.position().sub(start.toDouble()));
5456
return VolumeElement.of(element.volume(), elementRotation.apply(v, element.type()), v);
5557
};
5658
}
5759

5860
public static <W extends Volume, E> VolumePositionTranslator<W, E> relativeTo(final Vector3i newOrigin) {
61+
return VolumePositionTranslators.relativeTo(newOrigin.toDouble().add(VolumePositionTranslators.BLOCK_OFFSET));
62+
}
63+
64+
public static <W extends Volume, E> VolumePositionTranslator<W, E> relativeTo(final Vector3d newOrigin) {
5965
return element -> VolumeElement.of(element.volume(), element.type(), element.position().add(newOrigin));
6066
}
6167

6268
public static <W extends Volume, E> VolumePositionTranslator<W, E> offset(final Vector3i min) {
69+
return VolumePositionTranslators.offset(min.toDouble().add(VolumePositionTranslators.BLOCK_OFFSET));
70+
}
71+
72+
public static <W extends Volume, E> VolumePositionTranslator<W, E> offset(final Vector3d min) {
6373
return element -> VolumeElement.of(element.volume(), element.type(), element.position().sub(min));
6474
}
6575

66-
public static <W extends Volume, E> VolumePositionTranslator<W, E> position(final Function<Vector3i, Vector3i> func) {
76+
public static <W extends Volume, E> VolumePositionTranslator<W, E> position(final Function<Vector3d, Vector3d> func) {
6777
Objects.requireNonNull(func, "Position function cannot be null!");
6878
return element -> VolumeElement.of(element.volume(), element.type(), func.apply(element.position()));
6979
}

src/main/java/org/spongepowered/api/world/volume/stream/VolumePredicate.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@
3131
@FunctionalInterface
3232
public interface VolumePredicate<V extends Volume, T> {
3333

34-
boolean test(V volume, Supplier<T> element, int x, int y, int z);
34+
boolean test(V volume, Supplier<T> element, double x, double y, double z);
35+
36+
default boolean test(final V volume, final Supplier<T> element, final int x, final int y, final int z) {
37+
return this.test(volume, element, x + 0.5, y + 0.5, z + 0.5);
38+
}
3539

3640
default VolumePredicate<V, T> and(final VolumePredicate<V, T> other) {
3741
return (volume, element, x, y, z) -> this.test(volume, element, x, y, z) && other.test(volume, element, x, y, z);

src/main/java/org/spongepowered/api/world/volume/stream/VolumeStream.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
import org.spongepowered.api.world.volume.MutableVolume;
2828
import org.spongepowered.api.world.volume.Volume;
29-
import org.spongepowered.math.vector.Vector3i;
29+
import org.spongepowered.math.vector.Vector3d;
3030

3131
import java.util.Optional;
3232
import java.util.function.Consumer;
@@ -67,19 +67,19 @@ public interface VolumeStream<V extends Volume, T> {
6767
VolumeStream<V, T> filter(VolumePredicate<V, T> predicate);
6868

6969
default VolumeStream<V, T> filter(final Predicate<VolumeElement<V, ? super T>> predicate) {
70-
return this.filter((volume, element, x, y, z) -> predicate.test(VolumeElement.of(volume, element, new Vector3i(x, y, z))));
70+
return this.filter((volume, element, x, y, z) -> predicate.test(VolumeElement.of(volume, element, new Vector3d(x, y, z))));
7171
}
7272

7373
<Out> VolumeStream<V, Out> map(VolumeMapper<V, T, Out> mapper);
7474

7575
default <Out> VolumeStream<V, Out> map(final Function<VolumeElement<V, T>, ? extends Out> mapper) {
76-
return this.map((volume, value, x, y, z) -> mapper.apply(VolumeElement.of(volume, value, new Vector3i(x, y, z))));
76+
return this.map((volume, value, x, y, z) -> mapper.apply(VolumeElement.of(volume, value, new Vector3d(x, y, z))));
7777
}
7878

7979
VolumeStream<V, Optional<? extends T>> flatMap(VolumeFlatMapper<V, T> mapper);
8080

8181
default VolumeStream<V, Optional<? extends T>> flatMap(final Function<VolumeElement<V, T>, Optional<? extends T>> mapper) {
82-
return this.flatMap((volume, value, x, y, z) -> mapper.apply(VolumeElement.of(volume, value, new Vector3i(x, y, z))));
82+
return this.flatMap((volume, value, x, y, z) -> mapper.apply(VolumeElement.of(volume, value, new Vector3d(x, y, z))));
8383
}
8484

8585
VolumeStream<V, T> transform(VolumePositionTranslator<V, T> transformer);
@@ -89,19 +89,19 @@ default VolumeStream<V, Optional<? extends T>> flatMap(final Function<VolumeElem
8989
boolean allMatch(VolumePredicate<V, ? super T> predicate);
9090

9191
default boolean allMatch(final Predicate<VolumeElement<V, ? super T>> predicate) {
92-
return this.allMatch((volume, element, x, y, z) -> predicate.test(VolumeElement.of(volume, element, new Vector3i(x, y, z))));
92+
return this.allMatch((volume, element, x, y, z) -> predicate.test(VolumeElement.of(volume, element, new Vector3d(x, y, z))));
9393
}
9494

9595
boolean noneMatch(VolumePredicate<V, ? super T> predicate);
9696

9797
default boolean noneMatch(final Predicate<VolumeElement<V, ? super T>> predicate) {
98-
return this.noneMatch((volume, element, x, y, z) -> predicate.test(VolumeElement.of(volume, element, new Vector3i(x, y, z))));
98+
return this.noneMatch((volume, element, x, y, z) -> predicate.test(VolumeElement.of(volume, element, new Vector3d(x, y, z))));
9999
}
100100

101101
boolean anyMatch(VolumePredicate<V, ? super T> predicate);
102102

103103
default boolean anyMatch(final Predicate<VolumeElement<V, ? super T>> predicate) {
104-
return this.anyMatch((volume, element, x, y, z) -> predicate.test(VolumeElement.of(volume, element, new Vector3i(x, y, z))));
104+
return this.anyMatch((volume, element, x, y, z) -> predicate.test(VolumeElement.of(volume, element, new Vector3d(x, y, z))));
105105
}
106106

107107
Optional<VolumeElement<V, T>> findFirst();
@@ -119,7 +119,7 @@ default <W extends MutableVolume> void apply(final VolumeCollector<W, T, ?> coll
119119
void forEach(VolumeConsumer<V, T> visitor);
120120

121121
default void forEach(final Consumer<VolumeElement<V, T>> consumer) {
122-
this.forEach((volume, type, x, y, z) -> consumer.accept(VolumeElement.of(volume, type, new Vector3i(x, y, z))));
122+
this.forEach((volume, type, x, y, z) -> consumer.accept(VolumeElement.of(volume, type, new Vector3d(x, y, z))));
123123
}
124124

125125
}

0 commit comments

Comments
 (0)