From 3e2fa6dd5909fa7a2913e854ba6a48870fbc3498 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Sun, 19 Jan 2020 12:08:58 +0100 Subject: [PATCH] Little improvement and tentative fix for #12 --- .../core/render/hires/HiresModelRenderer.java | 4 +- .../bluecolored/bluemap/core/util/AABB.java | 267 ++---------------- .../bluemap/core/world/SlicedWorld.java | 2 +- .../bluecolored/bluemap/core/world/World.java | 2 +- 4 files changed, 33 insertions(+), 242 deletions(-) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/hires/HiresModelRenderer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/hires/HiresModelRenderer.java index 0ef028bc..93a5a692 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/hires/HiresModelRenderer.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/hires/HiresModelRenderer.java @@ -52,8 +52,8 @@ public HiresModelRenderer(ResourcePack resourcePack, RenderSettings renderSettin } public HiresModel render(WorldTile tile, AABB region) { - Vector3i modelMin = region.getMin().toInt(); - Vector3i modelMax = region.getMax().toInt(); + Vector3i modelMin = region.getMin(); + Vector3i modelMax = region.getMax(); Vector3i min = modelMin.max(renderSettings.getMin()); Vector3i max = modelMax.min(renderSettings.getMax()); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/AABB.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/AABB.java index 1c1aa58f..48e66349 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/AABB.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/AABB.java @@ -24,42 +24,28 @@ */ package de.bluecolored.bluemap.core.util; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import java.util.Optional; - +import com.flowpowered.math.GenericMath; import com.flowpowered.math.vector.Vector3d; import com.flowpowered.math.vector.Vector3i; /** * An axis aligned bounding box. That is, an un-rotated cuboid. * It is represented by its minimum and maximum corners. - * - *

The box will never be degenerate: the corners are always not equal and - * respect the minimum and maximum properties.

+ * + * Using integers, the box has a minimum size of 1 in each direction. * *

This class is immutable, all objects returned are either new instances or * itself.

*/ public class AABB { - private final Vector3d min; - private final Vector3d max; - private Vector3d size = null; + private final Vector3i min; + private final Vector3i max; + private Vector3i size = null; private Vector3d center = null; - - /** - * Constructs a new bounding box from two opposite corners. - * Fails the resulting box would be degenerate (a dimension is 0). - * - * @param firstCorner The first corner - * @param secondCorner The second corner - */ - public AABB(Vector3i firstCorner, Vector3i secondCorner) { - this(checkNotNull(firstCorner, "firstCorner").toDouble(), checkNotNull(secondCorner, "secondCorner").toDouble()); - } - + /** * Constructs a new bounding box from two opposite corners. * Fails the resulting box would be degenerate (a dimension is 0). @@ -71,8 +57,8 @@ public AABB(Vector3i firstCorner, Vector3i secondCorner) { * @param y2 The second corner y coordinate * @param z2 The second corner z coordinate */ - public AABB(double x1, double y1, double z1, double x2, double y2, double z2) { - this(new Vector3d(x1, y1, z1), new Vector3d(x2, y2, z2)); + public AABB(int x1, int y1, int z1, int x2, int y2, int z2) { + this(new Vector3i(x1, y1, z1), new Vector3i(x2, y2, z2)); } /** @@ -82,14 +68,11 @@ public AABB(double x1, double y1, double z1, double x2, double y2, double z2) { * @param firstCorner The first corner * @param secondCorner The second corner */ - public AABB(Vector3d firstCorner, Vector3d secondCorner) { + public AABB(Vector3i firstCorner, Vector3i secondCorner) { checkNotNull(firstCorner, "firstCorner"); checkNotNull(secondCorner, "secondCorner"); this.min = firstCorner.min(secondCorner); this.max = firstCorner.max(secondCorner); - checkArgument(this.min.getX() != this.max.getX(), "The box is degenerate on x"); - checkArgument(this.min.getY() != this.max.getY(), "The box is degenerate on y"); - checkArgument(this.min.getZ() != this.max.getZ(), "The box is degenerate on z"); } /** @@ -97,7 +80,7 @@ public AABB(Vector3d firstCorner, Vector3d secondCorner) { * * @return The minimum corner */ - public Vector3d getMin() { + public Vector3i getMin() { return this.min; } @@ -106,7 +89,7 @@ public Vector3d getMin() { * * @return The maximum corner */ - public Vector3d getMax() { + public Vector3i getMax() { return this.max; } @@ -117,7 +100,7 @@ public Vector3d getMax() { */ public Vector3d getCenter() { if (this.center == null) { - this.center = this.min.add(getSize().div(2)); + this.center = this.min.toDouble().add(getSize().toDouble().div(2)); } return this.center; } @@ -127,9 +110,9 @@ public Vector3d getCenter() { * * @return The size */ - public Vector3d getSize() { + public Vector3i getSize() { if (this.size == null) { - this.size = this.max.sub(this.min); + this.size = this.max.sub(this.min).add(Vector3i.ONE); } return this.size; } @@ -165,6 +148,18 @@ public boolean contains(Vector3d point) { * @return Whether or not the box contains the point */ public boolean contains(double x, double y, double z) { + return contains(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z)); + } + + /** + * Checks if the bounding box contains a point. + * + * @param x The x coordinate of the point + * @param y The y coordinate of the point + * @param z The z coordinate of the point + * @return Whether or not the box contains the point + */ + public boolean contains(int x, int y, int z) { return this.min.getX() <= x && this.max.getX() >= x && this.min.getY() <= y && this.max.getY() >= y && this.min.getZ() <= z && this.max.getZ() >= z; @@ -183,156 +178,6 @@ public boolean intersects(AABB other) { && this.max.getZ() >= other.getMin().getZ() && other.getMax().getZ() >= this.min.getZ(); } - /** - * Tests for intersection between the box and a ray defined by a starting - * point and a direction. - * - * @param start The starting point of the ray - * @param direction The direction of the ray - * @return An intersection point, if any - */ - public Optional intersects(Vector3d start, Vector3d direction) { - checkNotNull(start, "start"); - checkNotNull(direction, "direction"); - // Adapted from: https://github.com/flow/react/blob/develop/src/main/java/com/flowpowered/react/collision/RayCaster.java#L156 - // The box is interpreted as 6 infinite perpendicular places, one for each face (being expanded infinitely) - // "t" variables are multipliers: start + direction * t gives the intersection point - // Find the intersections on the -x and +x planes, oriented by direction - final double txMin; - final double txMax; - final Vector3d xNormal; - if (Math.copySign(1, direction.getX()) > 0) { - txMin = (this.min.getX() - start.getX()) / direction.getX(); - txMax = (this.max.getX() - start.getX()) / direction.getX(); - xNormal = Vector3d.UNIT_X; - } else { - txMin = (this.max.getX() - start.getX()) / direction.getX(); - txMax = (this.min.getX() - start.getX()) / direction.getX(); - xNormal = Vector3d.UNIT_X.negate(); - } - // Find the intersections on the -y and +y planes, oriented by direction - final double tyMin; - final double tyMax; - final Vector3d yNormal; - if (Math.copySign(1, direction.getY()) > 0) { - tyMin = (this.min.getY() - start.getY()) / direction.getY(); - tyMax = (this.max.getY() - start.getY()) / direction.getY(); - yNormal = Vector3d.UNIT_Y; - } else { - tyMin = (this.max.getY() - start.getY()) / direction.getY(); - tyMax = (this.min.getY() - start.getY()) / direction.getY(); - yNormal = Vector3d.UNIT_Y.negate(); - } - // The ray should intersect the -x plane before the +y plane and intersect - // the -y plane before the +x plane, else it is outside the box - if (txMin > tyMax || txMax < tyMin) { - return Optional.empty(); - } - // Keep track of the intersection normal which also helps with floating point errors - Vector3d normalMax; - Vector3d normalMin; - // The ray intersects only the furthest min plane on the box and only the closest - // max plane on the box - double tMin; - if (tyMin == txMin) { - tMin = tyMin; - normalMin = xNormal.negate().sub(yNormal); - } else if (tyMin > txMin) { - tMin = tyMin; - normalMin = yNormal.negate(); - } else { - tMin = txMin; - normalMin = xNormal.negate(); - } - double tMax; - if (tyMax == txMax) { - tMax = tyMax; - normalMax = xNormal.add(yNormal); - } else if (tyMax < txMax) { - tMax = tyMax; - normalMax = yNormal; - } else { - tMax = txMax; - normalMax = xNormal; - } - // Find the intersections on the -z and +z planes, oriented by direction - final double tzMin; - final double tzMax; - final Vector3d zNormal; - if (Math.copySign(1, direction.getZ()) > 0) { - tzMin = (this.min.getZ() - start.getZ()) / direction.getZ(); - tzMax = (this.max.getZ() - start.getZ()) / direction.getZ(); - zNormal = Vector3d.UNIT_Z; - } else { - tzMin = (this.max.getZ() - start.getZ()) / direction.getZ(); - tzMax = (this.min.getZ() - start.getZ()) / direction.getZ(); - zNormal = Vector3d.UNIT_Z.negate(); - } - // The ray intersects only the furthest min plane on the box and only the closest - // max plane on the box - if (tMin > tzMax || tMax < tzMin) { - return Optional.empty(); - } - // The ray should intersect the closest plane outside first and the furthest - // plane outside last - if (tzMin == tMin) { - normalMin = normalMin.sub(zNormal); - } else if (tzMin > tMin) { - tMin = tzMin; - normalMin = zNormal.negate(); - } - if (tzMax == tMax) { - normalMax = normalMax.add(zNormal); - } else if (tzMax < tMax) { - tMax = tzMax; - normalMax = zNormal; - } - // Both intersection points are behind the start, there are no intersections - if (tMax < 0) { - return Optional.empty(); - } - // Find the final intersection multiplier and normal - final double t; - Vector3d normal; - if (tMin < 0) { - // Only the furthest intersection is after the start, so use it - t = tMax; - normal = normalMax; - } else { - // Both are after the start, use the closest one - t = tMin; - normal = normalMin; - } - normal = normal.normalize(); - // To avoid rounding point errors leaving the intersection point just off the plane - // we check the normal to use the actual plane value from the box coordinates - final double x; - final double y; - final double z; - if (normal.getX() > 0) { - x = this.max.getX(); - } else if (normal.getX() < 0) { - x = this.min.getX(); - } else { - x = direction.getX() * t + start.getX(); - } - if (normal.getY() > 0) { - y = this.max.getY(); - } else if (normal.getY() < 0) { - y = this.min.getY(); - } else { - y = direction.getY() * t + start.getY(); - } - if (normal.getZ() > 0) { - z = this.max.getZ(); - } else if (normal.getZ() < 0) { - z = this.min.getZ(); - } else { - z = direction.getZ() * t + start.getZ(); - } - return Optional.of(new IntersectionPoint(new Vector3d(x, y, z), normal)); - } - /** * Offsets this bounding box by a given amount and returns a new box. * @@ -344,17 +189,6 @@ public AABB offset(Vector3i offset) { return offset(offset.getX(), offset.getY(), offset.getZ()); } - /** - * Offsets this bounding box by a given amount and returns a new box. - * - * @param offset The offset to apply - * @return The new offset box - */ - public AABB offset(Vector3d offset) { - checkNotNull(offset, "offset"); - return offset(offset.getX(), offset.getY(), offset.getZ()); - } - /** * Offsets this bounding box by a given amount and returns a new box. * @@ -363,53 +197,10 @@ public AABB offset(Vector3d offset) { * @param z The amount of offset for the z coordinate * @return The new offset box */ - public AABB offset(double x, double y, double z) { + public AABB offset(int x, int y, int z) { return new AABB(this.min.add(x, y, z), this.max.add(x, y, z)); } - - /** - * Expands this bounding box by a given amount in both directions and - * returns a new box. The expansion is applied half and half to the - * minimum and maximum corners. - * - * @param amount The amount of expansion to apply - * @return The new expanded box - */ - public AABB expand(Vector3i amount) { - checkNotNull(amount, "amount"); - return expand(amount.getX(), amount.getY(), amount.getZ()); - } - - /** - * Expands this bounding box by a given amount in both directions and - * returns a new box. The expansion is applied half and half to the - * minimum and maximum corners. - * - * @param amount The amount of expansion to apply - * @return The new expanded box - */ - public AABB expand(Vector3d amount) { - checkNotNull(amount, "amount"); - return expand(amount.getX(), amount.getY(), amount.getZ()); - } - - /** - * Expands this bounding box by a given amount in both directions and - * returns a new box. The expansion is applied half and half to the - * minimum and maximum corners. - * - * @param x The amount of expansion for the x coordinate - * @param y The amount of expansion for the y coordinate - * @param z The amount of expansion for the z coordinate - * @return The new expanded box - */ - public AABB expand(double x, double y, double z) { - x /= 2; - y /= 2; - z /= 2; - return new AABB(this.min.sub(x, y, z), this.max.add(x, y, z)); - } - + @Override public boolean equals(Object other) { if (this == other) { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/SlicedWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/SlicedWorld.java index e9ef7a4f..7870b0b6 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/SlicedWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/SlicedWorld.java @@ -132,7 +132,7 @@ public boolean isChunkGenerated(Vector2i chunkPos) throws IOException { @Override public boolean isAreaGenerated(AABB area) throws IOException { - if (!isInside(blockPosToChunkPos(area.getMin().toInt())) && !isInside(blockPosToChunkPos(area.getMax().toInt()))) return false; + if (!isInside(blockPosToChunkPos(area.getMin())) && !isInside(blockPosToChunkPos(area.getMax()))) return false; return world.isAreaGenerated(area); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java index b9993870..d04dc341 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java @@ -94,7 +94,7 @@ public default Collection getChunkList(){ * @throws IOException */ public default boolean isAreaGenerated(AABB area) throws IOException { - return isAreaGenerated(area.getMin().toInt(), area.getMax().toInt()); + return isAreaGenerated(area.getMin(), area.getMax()); } /**