From bec797443b46508f239ecda865282bd3f5a2bab6 Mon Sep 17 00:00:00 2001 From: Simp Date: Sun, 5 Jul 2020 03:33:22 -0400 Subject: [PATCH 1/5] shapes! * Added variety of 2D and 3D shape classes * Added ShapeUtil class for shape-supporting functions * Added alternate direction method to VectorUtil * Added Plane utility class for describing a plane in space --- .../com/projectkorra/core/util/ShapeUtil.java | 138 ++++++++++++++++++ .../projectkorra/core/util/VectorUtil.java | 14 ++ .../projectkorra/core/util/math/Plane.java | 42 ++++++ .../projectkorra/core/util/shape/Circle.java | 66 +++++++++ .../projectkorra/core/util/shape/Cuboid.java | 110 ++++++++++++++ .../projectkorra/core/util/shape/Polygon.java | 41 ++++++ .../core/util/shape/Polyhedron.java | 36 +++++ .../core/util/shape/Rectangle.java | 84 +++++++++++ .../projectkorra/core/util/shape/Shape.java | 13 ++ .../projectkorra/core/util/shape/Sphere.java | 104 +++++++++++++ .../core/util/shape/Tetrahedron.java | 109 ++++++++++++++ .../core/util/shape/Triangle.java | 68 +++++++++ 12 files changed, 825 insertions(+) create mode 100644 src/main/java/com/projectkorra/core/util/ShapeUtil.java create mode 100644 src/main/java/com/projectkorra/core/util/math/Plane.java create mode 100644 src/main/java/com/projectkorra/core/util/shape/Circle.java create mode 100644 src/main/java/com/projectkorra/core/util/shape/Cuboid.java create mode 100644 src/main/java/com/projectkorra/core/util/shape/Polygon.java create mode 100644 src/main/java/com/projectkorra/core/util/shape/Polyhedron.java create mode 100644 src/main/java/com/projectkorra/core/util/shape/Rectangle.java create mode 100644 src/main/java/com/projectkorra/core/util/shape/Shape.java create mode 100644 src/main/java/com/projectkorra/core/util/shape/Sphere.java create mode 100644 src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java create mode 100644 src/main/java/com/projectkorra/core/util/shape/Triangle.java diff --git a/src/main/java/com/projectkorra/core/util/ShapeUtil.java b/src/main/java/com/projectkorra/core/util/ShapeUtil.java new file mode 100644 index 0000000..21562b5 --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/ShapeUtil.java @@ -0,0 +1,138 @@ +package com.projectkorra.core.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.block.data.BlockData; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import com.projectkorra.core.util.ParticleUtil.DirectionalParticle; +import com.projectkorra.core.util.ParticleUtil.NoteColor; +import com.projectkorra.core.util.shape.Shape; + +public class ShapeUtil { + + private ShapeUtil() {} + + /** + * Take the given shape and construct its locations to the given collection + * @param shape shape to collect + * @param locs where to collect to + */ + public static void collect(Shape shape, Collection locs) { + shape.construct((loc) -> locs.add(loc)); + } + + /** + * Show the shape using the given particle + * @param shape shape to show + * @param particle particle to show with + */ + public static void showParticle(Shape shape, Particle particle) { + shape.construct((loc) -> ParticleUtil.spawn(particle, loc)); + } + + /** + * Show the shape using BLOCK_CRACK and the given data + * @param shape shape to show + * @param block data to use for particle + */ + public static void showBlockCrack(Shape shape, BlockData block) { + shape.construct((loc) -> ParticleUtil.spawnBlockCrack(block, loc)); + } + + /** + * Show the shape using BLOCK_DUST and the given data + * @param shape shape to show + * @param block data to use for particle + */ + public static void showBlockDust(Shape shape, BlockData block) { + shape.construct((loc) -> ParticleUtil.spawnBlockDust(block, loc)); + } + + /** + * Show the shape using colored NOTE particles + * @param shape shape to show + * @param color note color + */ + public static void showColoredNote(Shape shape, NoteColor color) { + shape.construct((loc) -> ParticleUtil.spawnColoredNote(color, loc)); + } + + /** + * Show the shape using colored REDSTONE particles + * @param shape shape to show + * @param color redstone color + * @param size redstone size + */ + public static void showColoredRedstone(Shape shape, Color color, float size) { + shape.construct((loc) -> ParticleUtil.spawnColoredRedstone(color, size, loc)); + } + + /** + * Show the shape using colored MOB_SPELL particles + * @param shape shape to show + * @param color spell color + * @param ambient true for transparency + */ + public static void showColoredSpell(Shape shape, Color color, boolean ambient) { + shape.construct((loc) -> ParticleUtil.spawnColoredSpell(color, ambient, loc)); + } + + /** + * Show the shape using a directional particle + * @param shape shape to show + * @param type particle to show + * @param direction to move particles in + */ + public static void showDirectional(Shape shape, DirectionalParticle type, Vector direction) { + shape.construct((loc) -> ParticleUtil.spawnWithDirection(type, direction, loc)); + } + + /** + * Show the shape using FALLING_DUST particles + * @param shape shape to show + * @param block data to use for particles + */ + public static void showFallingDust(Shape shape, BlockData block) { + shape.construct((loc) -> ParticleUtil.spawnFallingDust(block, loc)); + } + + /** + * Show the shape using ITEM_CRACK particles + * @param shape shape to show + * @param item data to use for particles + */ + public static void showItemCrack(Shape shape, ItemStack item) { + shape.construct((loc) -> ParticleUtil.spawnItemCrack(item, loc)); + } + + /** + * Construct the given shape into a List + * @param shape shape to construct + * @return List of shape locations + */ + public static List toList(Shape shape) { + List locs = new ArrayList<>(); + shape.construct((loc) -> locs.add(loc)); + return locs; + } + + /** + * Construct the given shape into a Set + * @param shape shape to construct + * @return Set of shape locations + */ + public static Set toSet(Shape shape) { + Set locs = new HashSet<>(); + shape.construct((loc) -> locs.add(loc)); + return locs; + } +} diff --git a/src/main/java/com/projectkorra/core/util/VectorUtil.java b/src/main/java/com/projectkorra/core/util/VectorUtil.java index ff7389f..c079c62 100644 --- a/src/main/java/com/projectkorra/core/util/VectorUtil.java +++ b/src/main/java/com/projectkorra/core/util/VectorUtil.java @@ -22,6 +22,20 @@ public static Vector direction(Location from, Location to) { return new Vector(to.getX() - from.getX(), to.getY() - from.getY(), to.getZ() - from.getZ()); } + /** + * Get a vector for the direction of the given yaw and pitch + * @param yaw horizontal rotation, between +/- 180 + * @param pitch vertical rotation, between -/+ 90 (negative is up) + * @return vector from yaw and pitch + */ + public static Vector direction(float yaw, float pitch) { + double y = Math.sin(-Math.toRadians(pitch)); + double xz = Math.cos(Math.toRadians(pitch)); + double x = -xz * Math.sin(Math.toRadians(yaw)); + double z = xz * Math.cos(Math.toRadians(yaw)); + return new Vector(x, y, z); + } + /** * Returns an orthogonal vector from an axis * @param axis vector to be orthogonal of diff --git a/src/main/java/com/projectkorra/core/util/math/Plane.java b/src/main/java/com/projectkorra/core/util/math/Plane.java new file mode 100644 index 0000000..6c9ca53 --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/math/Plane.java @@ -0,0 +1,42 @@ +package com.projectkorra.core.util.math; + +import org.apache.commons.lang.Validate; +import org.bukkit.Location; +import org.bukkit.util.Vector; + +import com.projectkorra.core.util.VectorUtil; + +public class Plane { + + public static final Plane XY = new Plane(UnitVector.POSITIVE_X.normal(), UnitVector.POSITIVE_Y.normal()); + public static final Plane ZY = new Plane(UnitVector.POSITIVE_Z.normal(), UnitVector.POSITIVE_Y.normal()); + public static final Plane XZ = new Plane(UnitVector.POSITIVE_X.normal(), UnitVector.POSITIVE_Z.normal()); + + private Vector horizontal, vertical; + + private Plane(Vector horizontal, Vector vertical) { + this.horizontal = horizontal.clone().normalize(); + this.vertical = vertical.clone().normalize(); + } + + public Vector getHorizontalAxis() { + return horizontal.clone(); + } + + public Vector getVerticalAxis() { + return vertical.clone(); + } + + public Location moveAlongAxes(Location position, double rightward, double upward) { + return position.add(horizontal.clone().multiply(rightward)).add(vertical.clone().multiply(upward)); + } + + public static Plane fromPerpendicular(Vector perpendicular) throws IllegalArgumentException { + Validate.isTrue(!perpendicular.equals(UnitVector.ZERO.normal()), "Perpendicular vector cannot be zero"); + + Vector horizontal = VectorUtil.orthogonal(perpendicular, 1, Angle.radians(0)); + Vector vertical = VectorUtil.orthogonal(perpendicular, 1, Angle.degrees(90)); + + return new Plane(horizontal, vertical); + } +} diff --git a/src/main/java/com/projectkorra/core/util/shape/Circle.java b/src/main/java/com/projectkorra/core/util/shape/Circle.java new file mode 100644 index 0000000..34cb537 --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/shape/Circle.java @@ -0,0 +1,66 @@ +package com.projectkorra.core.util.shape; + +import java.util.function.Consumer; + +import org.bukkit.Location; + +import com.projectkorra.core.util.math.Angle; +import com.projectkorra.core.util.math.Angle.AngleMode; +import com.projectkorra.core.util.math.Plane; + +public class Circle extends Polygon { + + private double radius; + private Angle theta; + + public Circle(Location center, double radius, Angle theta) { + this(center, radius, theta, Plane.XZ, true); + } + + public Circle(Location center, double radius, Angle theta, Plane reference) { + this(center, radius, theta, reference, true); + } + + public Circle(Location center, double radius, Angle theta, Plane reference, boolean hollow) { + super(center, reference, hollow); + this.radius = radius; + this.theta = theta; + + if (theta.getRawValue() <= 0) { + theta.set(AngleMode.DEGREES, 1); + } + } + + @Override + public void construct(Consumer func) { + double angle = theta.getValue(AngleMode.RADIANS); + + if (!hollow) { + for (double r = 0.0; r < radius; r += 0.1) { + for (double i = 0.0; i < 2 * Math.PI; i += angle) { + func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(i), r * Math.sin(i))); + } + } + } + + for (double i = 0.0; i < 2 * Math.PI; i += angle) { + func.accept(reference.moveAlongAxes(center.clone(), radius * Math.cos(i), radius * Math.sin(i))); + } + } + + public double getRadius() { + return radius; + } + + public void setRadius(double radius) { + this.radius = radius; + } + + public Angle getTheta() { + return theta; + } + + public void setTheta(Angle theta) { + this.theta = theta; + } +} diff --git a/src/main/java/com/projectkorra/core/util/shape/Cuboid.java b/src/main/java/com/projectkorra/core/util/shape/Cuboid.java new file mode 100644 index 0000000..1eb59a8 --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/shape/Cuboid.java @@ -0,0 +1,110 @@ +package com.projectkorra.core.util.shape; + +import java.util.function.Consumer; + +import org.bukkit.Location; +import org.bukkit.util.Vector; + +import com.projectkorra.core.util.math.Plane; +import com.projectkorra.core.util.math.UnitVector; + +public class Cuboid extends Polyhedron { + + private double length, height, width, interval; + + public Cuboid(Location center, double sides, double interval) { + this(center, sides, sides, sides, interval, UnitVector.POSITIVE_Y.normal(), true); + } + + public Cuboid(Location center, double sides, double interval, Vector upwards) { + this(center, sides, sides, sides, interval, upwards, true); + } + + public Cuboid(Location center, double sides, double interval, Vector upwards, boolean hollow) { + this(center, sides, sides, sides, interval, upwards, hollow); + } + + public Cuboid(Location center, double length, double height, double width, double interval) { + this(center, length, height, width, interval, UnitVector.POSITIVE_Y.normal(), true); + } + + public Cuboid(Location center, double length, double height, double width, double interval, Vector upwards) { + this(center, length, height, width, interval, upwards, true); + } + + public Cuboid(Location center, double length, double height, double width, double interval, Vector upwards, boolean hollow) { + super(center, upwards, hollow); + this.length = Math.max(length, 0.1); + this.height = Math.max(height, 0.1); + this.width = Math.max(width, 0.1); + this.interval = Math.max(interval, 0.01); + } + + @Override + public void construct(Consumer func) { + Plane horizontal = Plane.fromPerpendicular(upwards.normalize()); + + if (hollow) { + for (double x = -length / 2; x <= length / 2; x += interval) { + func.accept(horizontal.moveAlongAxes(center.clone(), x, -width / 2).add(upwards.clone().multiply(-height / 2))); + func.accept(horizontal.moveAlongAxes(center.clone(), x, -width / 2).add(upwards.clone().multiply(height / 2))); + func.accept(horizontal.moveAlongAxes(center.clone(), x, width / 2).add(upwards.clone().multiply(-height / 2))); + func.accept(horizontal.moveAlongAxes(center.clone(), x, width / 2).add(upwards.clone().multiply(height / 2))); + } + + for (double y = -length / 2; y <= length / 2; y += interval) { + func.accept(horizontal.moveAlongAxes(center.clone(), -length / 2, -width / 2).add(upwards.clone().multiply(y))); + func.accept(horizontal.moveAlongAxes(center.clone(), length / 2, -width / 2).add(upwards.clone().multiply(y))); + func.accept(horizontal.moveAlongAxes(center.clone(), -length / 2, width / 2).add(upwards.clone().multiply(y))); + func.accept(horizontal.moveAlongAxes(center.clone(), length / 2, width / 2).add(upwards.clone().multiply(y))); + } + + for (double z = -length / 2; z <= length / 2; z += interval) { + func.accept(horizontal.moveAlongAxes(center.clone(), -length / 2, z).add(upwards.clone().multiply(-height / 2))); + func.accept(horizontal.moveAlongAxes(center.clone(), -length / 2, z).add(upwards.clone().multiply(height / 2))); + func.accept(horizontal.moveAlongAxes(center.clone(), length / 2, z).add(upwards.clone().multiply(-height / 2))); + func.accept(horizontal.moveAlongAxes(center.clone(), length / 2, z).add(upwards.clone().multiply(height / 2))); + } + } else { + for (double x = -length / 2; x <= length / 2; x += interval) { + for (double y = -height / 2; y <= height / 2; y += interval) { + for (double z = -width / 2; z <= width / 2; z += interval) { + func.accept(horizontal.moveAlongAxes(center.clone(), x, z).add(upwards.clone().multiply(y))); + } + } + } + } + } + + public double getLength() { + return length; + } + + public void setLength(double length) { + this.length = length; + } + + public double getHeight() { + return height; + } + + public void setHeight(double height) { + this.height = height; + } + + public double getWidth() { + return width; + } + + public void setWidth(double width) { + this.width = width; + } + + public double getInterval() { + return interval; + } + + public void setInterval(double interval) { + this.interval = interval; + } +} diff --git a/src/main/java/com/projectkorra/core/util/shape/Polygon.java b/src/main/java/com/projectkorra/core/util/shape/Polygon.java new file mode 100644 index 0000000..5836026 --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/shape/Polygon.java @@ -0,0 +1,41 @@ +package com.projectkorra.core.util.shape; + +import org.bukkit.Location; + +import com.projectkorra.core.util.math.Plane; + +public abstract class Polygon implements Shape { + + protected Location center; + protected Plane reference; + protected boolean hollow; + + public Polygon(Location center, Plane reference, boolean hollow) { + this.center = center; + this.reference = reference; + this.hollow = hollow; + } + + @Override + public Location getCenter() { + return center; + } + + public Plane getReference() { + return reference; + } + + public void setReference(Plane reference) { + this.reference = reference; + } + + @Override + public boolean isHollow() { + return hollow; + } + + @Override + public void setHollow(boolean hollow) { + this.hollow = hollow; + } +} diff --git a/src/main/java/com/projectkorra/core/util/shape/Polyhedron.java b/src/main/java/com/projectkorra/core/util/shape/Polyhedron.java new file mode 100644 index 0000000..a56afe3 --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/shape/Polyhedron.java @@ -0,0 +1,36 @@ +package com.projectkorra.core.util.shape; + +import org.bukkit.Location; +import org.bukkit.util.Vector; + +public abstract class Polyhedron implements Shape { + + protected Location center; + protected Vector upwards; + protected boolean hollow; + + public Polyhedron(Location center, Vector upwards, boolean hollow) { + this.center = center; + this.upwards = upwards.normalize(); + this.hollow = hollow; + } + + @Override + public Location getCenter() { + return center; + } + + public Vector getUpwards() { + return upwards; + } + + @Override + public boolean isHollow() { + return hollow; + } + + @Override + public void setHollow(boolean hollow) { + this.hollow = hollow; + } +} diff --git a/src/main/java/com/projectkorra/core/util/shape/Rectangle.java b/src/main/java/com/projectkorra/core/util/shape/Rectangle.java new file mode 100644 index 0000000..2fb4f83 --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/shape/Rectangle.java @@ -0,0 +1,84 @@ +package com.projectkorra.core.util.shape; + +import java.util.function.Consumer; + +import org.bukkit.Location; + +import com.projectkorra.core.util.math.Plane; + +public class Rectangle extends Polygon { + + private double length, height, interval; + + public Rectangle(Location center, double sides, double interval) { + this(center, sides, sides, interval, Plane.XZ, true); + } + + public Rectangle(Location center, double length, double height, double interval) { + this(center, length, height, interval, Plane.XZ, true); + } + + public Rectangle(Location center, double sides, double interval, Plane reference) { + this(center, sides, sides, interval, reference, true); + } + + public Rectangle(Location center, double sides, double interval, Plane reference, boolean hollow) { + this(center, sides, sides, interval, reference, hollow); + } + + public Rectangle(Location center, double length, double height, double interval, Plane reference) { + this(center, length, height, interval, reference, true); + } + + public Rectangle(Location center, double length, double height, double interval, Plane reference, boolean hollow) { + super(center, reference, hollow); + this.length = Math.max(length, 0.1); + this.height = Math.max(height, 0.1); + this.interval = Math.max(interval, 0.01); + } + + @Override + public void construct(Consumer func) { + if (hollow) { + for (double x = -length / 2; x <= length / 2; x += interval) { + func.accept(reference.moveAlongAxes(center.clone(), x, height / 2)); + func.accept(reference.moveAlongAxes(center.clone(), x, -height / 2)); + } + + for (double z = -length / 2; z <= length / 2; z += interval) { + func.accept(reference.moveAlongAxes(center.clone(), length / 2, z)); + func.accept(reference.moveAlongAxes(center.clone(), -length / 2, z)); + } + } else { + for (double i = -length / 2; i <= length / 2; i += interval) { + for (double j = -height / 2; j <= height / 2; j += interval) { + func.accept(reference.moveAlongAxes(center.clone(), i, j)); + } + } + } + } + + public double getLength() { + return length; + } + + public void setLength(double length) { + this.length = length; + } + + public double getHeight() { + return height; + } + + public void setHeight(double height) { + this.height = height; + } + + public double getInterval() { + return interval; + } + + public void setInterval(double interval) { + this.interval = interval; + } +} diff --git a/src/main/java/com/projectkorra/core/util/shape/Shape.java b/src/main/java/com/projectkorra/core/util/shape/Shape.java new file mode 100644 index 0000000..db9c8b3 --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/shape/Shape.java @@ -0,0 +1,13 @@ +package com.projectkorra.core.util.shape; + +import java.util.function.Consumer; + +import org.bukkit.Location; + +public interface Shape { + + public void construct(Consumer func); + public Location getCenter(); + public boolean isHollow(); + public void setHollow(boolean hollow); +} diff --git a/src/main/java/com/projectkorra/core/util/shape/Sphere.java b/src/main/java/com/projectkorra/core/util/shape/Sphere.java new file mode 100644 index 0000000..bec146d --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/shape/Sphere.java @@ -0,0 +1,104 @@ +package com.projectkorra.core.util.shape; + +import java.util.function.Consumer; + +import org.bukkit.Location; +import org.bukkit.util.Vector; + +import com.projectkorra.core.util.math.Angle; +import com.projectkorra.core.util.math.Angle.AngleMode; +import com.projectkorra.core.util.math.Plane; +import com.projectkorra.core.util.math.UnitVector; + +public class Sphere extends Polyhedron { + + private double radius; + private Angle theta, phi; + + public Sphere(Location center, double radius, Angle both) { + this(center, radius, both, both, UnitVector.POSITIVE_Y.normal(), true); + } + + public Sphere(Location center, double radius, Angle both, Vector upwards) { + this(center, radius, both, both, upwards, true); + } + + public Sphere(Location center, double radius, Angle theta, Angle phi) { + this(center, radius, theta, phi, UnitVector.POSITIVE_Y.normal(), true); + } + + public Sphere(Location center, double radius, Angle theta, Angle phi, Vector upwards) { + this(center, radius, theta, phi, upwards, true); + } + + public Sphere(Location center, double radius, Angle theta, Angle phi, Vector upwards, boolean hollow) { + super(center, upwards, hollow); + this.radius = radius; + this.theta = theta; + this.phi = phi; + + if (theta.getRawValue() <= 0) { + theta.set(AngleMode.DEGREES, 1); + } + + if (phi.getRawValue() <= 0) { + phi.set(AngleMode.DEGREES, 1); + } + } + + @Override + public void construct(Consumer func) { + double angleTheta = theta.getValue(AngleMode.RADIANS); + double anglePhi = phi.getValue(AngleMode.RADIANS); + Plane horizontal = Plane.fromPerpendicular(upwards.normalize()); + + if (!hollow) { + for (double r = 0.0; r < radius; r += 0.1) { + for (double i = 0.0; i < Math.PI; i += angleTheta) { + double yv = r * Math.cos(i); + + for (double j = 0.0; j < 2 * Math.PI; j += anglePhi) { + double xv = r * Math.sin(i) * Math.cos(j); + double zv = r * Math.sin(i) * Math.sin(j); + func.accept(horizontal.moveAlongAxes(center.clone(), xv, zv).add(upwards.clone().multiply(yv))); + } + } + } + } + + for (double i = 0.0; i < Math.PI; i += angleTheta) { + double yv = radius * Math.cos(i); + + for (double j = 0.0; j < 2 * Math.PI; j += anglePhi) { + double xv = radius * Math.sin(i) * Math.cos(j); + double zv = radius * Math.sin(i) * Math.sin(j); + + func.accept(horizontal.moveAlongAxes(center.clone(), xv, zv).add(upwards.clone().multiply(yv))); + } + } + } + + public double getRadius() { + return radius; + } + + public void setRadius(double radius) { + this.radius = radius; + } + + public Angle getTheta() { + return theta; + } + + public void setTheta(Angle theta) { + this.theta = theta; + } + + public Angle getPhi() { + return phi; + } + + public void setPhi(Angle phi) { + this.phi = phi; + } +} diff --git a/src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java b/src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java new file mode 100644 index 0000000..a3c9b8d --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java @@ -0,0 +1,109 @@ +package com.projectkorra.core.util.shape; + +import java.util.function.Consumer; + +import org.bukkit.Location; +import org.bukkit.util.Vector; + +import com.projectkorra.core.util.math.Plane; +import com.projectkorra.core.util.math.UnitVector; + +public class Tetrahedron extends Polyhedron { + + private double length, height, width, interval; + + public Tetrahedron(Location center, double sides, double interval) { + this(center, sides, sides, sides, interval, UnitVector.POSITIVE_Y.normal(), true); + } + + public Tetrahedron(Location center, double sides, double interval, Vector upwards) { + this(center, sides, sides, sides, interval, upwards, true); + } + + public Tetrahedron(Location center, double sides, double interval, Vector upwards, boolean hollow) { + this(center, sides, sides, sides, interval, upwards, hollow); + } + + public Tetrahedron(Location center, double length, double height, double width, double interval) { + this(center, length, height, width, interval, UnitVector.POSITIVE_Y.normal(), true); + } + + public Tetrahedron(Location center, double length, double height, double width, double interval, Vector upwards) { + this(center, length, height, width, interval, upwards, true); + } + + public Tetrahedron(Location center, double length, double height, double width, double interval, Vector upwards, boolean hollow) { + super(center, upwards, hollow); + this.length = Math.max(length, 0.1); + this.height = Math.max(height, 0.1); + this.width = Math.max(width, 0.1); + this.interval = Math.max(interval, 0.01); + } + + @Override + public void construct(Consumer func) { + Plane horizontal = Plane.fromPerpendicular(upwards.normalize()); + + if (hollow) { + for (double x = -length / 2; x <= length / 2 + interval / 2; x += interval) { + func.accept(horizontal.moveAlongAxes(center.clone(), x, -width / 2).add(upwards.clone().multiply(height / 2))); + func.accept(horizontal.moveAlongAxes(center.clone(), x, (-width / 2) + (width) * (1 - Math.abs(x) / (length / 2))).add(upwards.clone().multiply(height / 2))); + } + + for (double y = -height / 2; y <= height / 2; y += interval) { + double percent = (y + height / 2) / height; + double xv = percent * length / 2; + double zv = percent * width / 2; + func.accept(horizontal.moveAlongAxes(center.clone(), 0, zv).add(upwards.clone().multiply(y))); + func.accept(horizontal.moveAlongAxes(center.clone(), xv, -zv).add(upwards.clone().multiply(y))); + func.accept(horizontal.moveAlongAxes(center.clone(), -xv, -zv).add(upwards.clone().multiply(y))); + } + } else { + for (double y = -height / 2; y <= height / 2; y += interval) { + double percent = (y + height / 2) / height; + double xv = percent * length; + double zv = percent * width; + + for (double x = -xv / 2; x <= xv / 2; x += interval) { + double zBound = (-zv / 2) + zv * (1 - Math.abs(x) / (xv / 2)); + + for (double z = -zv / 2; z <= zBound; z += interval) { + func.accept(horizontal.moveAlongAxes(center.clone(), x, z).add(upwards.clone().multiply(y))); + } + } + } + } + } + + public double getLength() { + return length; + } + + public void setLength(double length) { + this.length = length; + } + + public double getHeight() { + return height; + } + + public void setHeight(double height) { + this.height = height; + } + + public double getWidth() { + return width; + } + + public void setWidth(double width) { + this.width = width; + } + + public double getInterval() { + return interval; + } + + public void setInterval(double interval) { + this.interval = interval; + } +} diff --git a/src/main/java/com/projectkorra/core/util/shape/Triangle.java b/src/main/java/com/projectkorra/core/util/shape/Triangle.java new file mode 100644 index 0000000..e070f60 --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/shape/Triangle.java @@ -0,0 +1,68 @@ +package com.projectkorra.core.util.shape; + +import java.util.function.Consumer; + +import org.bukkit.Location; + +import com.projectkorra.core.util.math.Plane; + +public class Triangle extends Polygon { + + private double height, length, interval; + + public Triangle(Location center, double height, double length, double interval) { + this(center, height, length, interval, Plane.XZ, true); + } + + public Triangle(Location center, double height, double length, double interval, Plane reference) { + this(center, height, length, interval, reference, true); + } + + public Triangle(Location center, double height, double length, double interval, Plane reference, boolean hollow) { + super(center, reference, hollow); + this.height = Math.max(height, 0.1); + this.length = Math.max(length, 0.1); + this.interval = Math.max(interval, 0.01); + } + + @Override + public void construct(Consumer func) { + if (hollow) { + for (double x = -length / 2; x <= length / 2; x += interval) { + func.accept(reference.moveAlongAxes(center.clone(), x, -height / 2)); + func.accept(reference.moveAlongAxes(center.clone(), x, (-height / 2) + (height) * (1 - Math.abs(x) / (length / 2)))); + } + } else { + for (double x = -length / 2; x <= length / 2; x += interval) { + double yBound = (-height / 2) + (height) * (1 - Math.abs(x) / (length / 2)); + for (double y = -height / 2; y <= yBound; y += interval) { + func.accept(reference.moveAlongAxes(center.clone(), x, y)); + } + } + } + } + + public double getHeight() { + return height; + } + + public void setHeight(double height) { + this.height = height; + } + + public double getLength() { + return length; + } + + public void setLength(double length) { + this.length = length; + } + + public double getInterval() { + return interval; + } + + public void setInterval(double interval) { + this.interval = interval; + } +} From 605d66c86be5735f0ed82f08e4bc41e5674e870f Mon Sep 17 00:00:00 2001 From: Simp Date: Tue, 7 Jul 2020 03:35:58 -0400 Subject: [PATCH 2/5] some additions and changes --- .../com/projectkorra/core/util/ShapeUtil.java | 18 ++++- .../projectkorra/core/util/math/Angle.java | 8 ++ .../projectkorra/core/util/shape/Circle.java | 28 +++++-- .../core/util/shape/CircleArc.java | 80 +++++++++++++++++++ .../projectkorra/core/util/shape/Shape.java | 5 ++ 5 files changed, 131 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/projectkorra/core/util/shape/CircleArc.java diff --git a/src/main/java/com/projectkorra/core/util/ShapeUtil.java b/src/main/java/com/projectkorra/core/util/ShapeUtil.java index 21562b5..9a6cf3a 100644 --- a/src/main/java/com/projectkorra/core/util/ShapeUtil.java +++ b/src/main/java/com/projectkorra/core/util/ShapeUtil.java @@ -5,6 +5,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Predicate; import org.bukkit.Color; import org.bukkit.Location; @@ -23,13 +24,28 @@ private ShapeUtil() {} /** * Take the given shape and construct its locations to the given collection - * @param shape shape to collect + * @param shape shape to construct * @param locs where to collect to */ public static void collect(Shape shape, Collection locs) { shape.construct((loc) -> locs.add(loc)); } + /** + * Take the given shape and construct only the locations which pass the + * filter test to the given collection + * @param shape shape to construct + * @param locs where to collect to + * @param filter any location that passes this test is added to the collection + */ + public static void collect(Shape shape, Collection locs, Predicate filter) { + shape.construct((loc) -> { + if (filter.test(loc)) { + locs.add(loc); + } + }); + } + /** * Show the shape using the given particle * @param shape shape to show diff --git a/src/main/java/com/projectkorra/core/util/math/Angle.java b/src/main/java/com/projectkorra/core/util/math/Angle.java index a05ce1d..4ebe506 100644 --- a/src/main/java/com/projectkorra/core/util/math/Angle.java +++ b/src/main/java/com/projectkorra/core/util/math/Angle.java @@ -35,6 +35,14 @@ public void setValue(double value) { this.value = value; } + public void increment(double value) { + this.value += value; + } + + public void decrement(double value) { + this.value -= value; + } + public static Angle radians(double value) { return new Angle(AngleMode.RADIANS, value); } diff --git a/src/main/java/com/projectkorra/core/util/shape/Circle.java b/src/main/java/com/projectkorra/core/util/shape/Circle.java index 34cb537..c741622 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Circle.java +++ b/src/main/java/com/projectkorra/core/util/shape/Circle.java @@ -11,20 +11,25 @@ public class Circle extends Polygon { private double radius; - private Angle theta; + private Angle theta, initial; public Circle(Location center, double radius, Angle theta) { - this(center, radius, theta, Plane.XZ, true); + this(center, radius, theta, Angle.radians(0), Plane.XZ, true); } - public Circle(Location center, double radius, Angle theta, Plane reference) { - this(center, radius, theta, reference, true); + public Circle(Location center, double radius, Angle theta, Angle initial) { + this(center, radius, theta, initial, Plane.XZ, true); } - public Circle(Location center, double radius, Angle theta, Plane reference, boolean hollow) { + public Circle(Location center, double radius, Angle theta, Angle initial, Plane reference) { + this(center, radius, theta, initial, reference, true); + } + + public Circle(Location center, double radius, Angle theta, Angle initial, Plane reference, boolean hollow) { super(center, reference, hollow); this.radius = radius; this.theta = theta; + this.initial = initial; if (theta.getRawValue() <= 0) { theta.set(AngleMode.DEGREES, 1); @@ -34,16 +39,17 @@ public Circle(Location center, double radius, Angle theta, Plane reference, bool @Override public void construct(Consumer func) { double angle = theta.getValue(AngleMode.RADIANS); + double init = initial.getValue(AngleMode.RADIANS); if (!hollow) { for (double r = 0.0; r < radius; r += 0.1) { - for (double i = 0.0; i < 2 * Math.PI; i += angle) { + for (double i = init; i < init + 2 * Math.PI; i += angle) { func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(i), r * Math.sin(i))); } } } - for (double i = 0.0; i < 2 * Math.PI; i += angle) { + for (double i = init; i < init + 2 * Math.PI; i += angle) { func.accept(reference.moveAlongAxes(center.clone(), radius * Math.cos(i), radius * Math.sin(i))); } } @@ -63,4 +69,12 @@ public Angle getTheta() { public void setTheta(Angle theta) { this.theta = theta; } + + public Angle getInitial() { + return initial; + } + + public void setInitial(Angle initial) { + this.initial = initial; + } } diff --git a/src/main/java/com/projectkorra/core/util/shape/CircleArc.java b/src/main/java/com/projectkorra/core/util/shape/CircleArc.java new file mode 100644 index 0000000..f3e4f5f --- /dev/null +++ b/src/main/java/com/projectkorra/core/util/shape/CircleArc.java @@ -0,0 +1,80 @@ +package com.projectkorra.core.util.shape; + +import java.util.function.Consumer; + +import org.bukkit.Location; + +import com.projectkorra.core.util.math.Angle; +import com.projectkorra.core.util.math.Plane; +import com.projectkorra.core.util.math.Angle.AngleMode; + +public class CircleArc extends Polygon { + + private double radius; + private float yaw; + private Angle theta, interval; + + public CircleArc(Location center, double radius, float yaw, Angle theta, Angle interval, Plane reference, boolean hollow) { + super(center, reference, hollow); + this.radius = Math.max(radius, 0.1); + this.yaw = yaw; + this.theta = theta; + this.interval = interval; + } + + @Override + public void construct(Consumer func) { + float lower = yaw - (float) theta.getValue(AngleMode.DEGREES) / 2; + float upper = yaw + (float) theta.getValue(AngleMode.DEGREES) / 2; + double angle = interval.getValue(AngleMode.DEGREES); + + if (!hollow) { + for (double y = lower; y <= upper; y += angle) { + for (double r = 0.0; r <= radius; r += 0.1) { + func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(Math.toRadians(y)), r * Math.sin(Math.toRadians(y)))); + } + } + } else { + for (double r = 0.0; r < radius; r += 0.1) { + func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(Math.toRadians(lower)), r * Math.sin(Math.toRadians(lower)))); + func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(Math.toRadians(upper)), r * Math.sin(Math.toRadians(upper)))); + } + + for (double y = lower; y <= upper; y += angle) { + func.accept(reference.moveAlongAxes(center.clone(), radius * Math.cos(Math.toRadians(y)), radius * Math.sin(Math.toRadians(y)))); + } + } + } + + public double getRadius() { + return radius; + } + + public void setRadius(double radius) { + this.radius = radius; + } + + public float getYaw() { + return yaw; + } + + public void setYaw(float yaw) { + this.yaw = yaw; + } + + public Angle getTheta() { + return theta; + } + + public void setTheta(Angle theta) { + this.theta = theta; + } + + public Angle getInterval() { + return interval; + } + + public void setInterval(Angle interval) { + this.interval = interval; + } +} diff --git a/src/main/java/com/projectkorra/core/util/shape/Shape.java b/src/main/java/com/projectkorra/core/util/shape/Shape.java index db9c8b3..a4a71af 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Shape.java +++ b/src/main/java/com/projectkorra/core/util/shape/Shape.java @@ -6,6 +6,11 @@ public interface Shape { + /** + * Method for constructing the shape and applying + * the given Consumer function to each location + * @param func what to do with each location + */ public void construct(Consumer func); public Location getCenter(); public boolean isHollow(); From 26210c549df1c22683fc7ccb611a9bdb2a2c3bfe Mon Sep 17 00:00:00 2001 From: Simp Date: Thu, 9 Jul 2020 04:41:47 -0400 Subject: [PATCH 3/5] math comments --- .../projectkorra/core/util/shape/Circle.java | 10 ++++-- .../core/util/shape/CircleArc.java | 31 +++++++++++++------ .../projectkorra/core/util/shape/Cuboid.java | 8 +++-- .../core/util/shape/Rectangle.java | 3 ++ .../projectkorra/core/util/shape/Sphere.java | 12 ++++--- .../core/util/shape/Tetrahedron.java | 6 +++- .../core/util/shape/Triangle.java | 2 ++ 7 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/projectkorra/core/util/shape/Circle.java b/src/main/java/com/projectkorra/core/util/shape/Circle.java index c741622..212d37b 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Circle.java +++ b/src/main/java/com/projectkorra/core/util/shape/Circle.java @@ -38,17 +38,21 @@ public Circle(Location center, double radius, Angle theta, Angle initial, Plane @Override public void construct(Consumer func) { - double angle = theta.getValue(AngleMode.RADIANS); - double init = initial.getValue(AngleMode.RADIANS); + double angle = theta.getValue(AngleMode.RADIANS); // angle between each location in the circle + double init = initial.getValue(AngleMode.RADIANS); // initial angle for the circle to start from if (!hollow) { - for (double r = 0.0; r < radius; r += 0.1) { + double rinc = radius * angle / (2 * Math.PI); // interval between each circle generated when not hollow + + // construct the inner bits of the circle + for (double r = 0.0; r < radius; r += rinc) { for (double i = init; i < init + 2 * Math.PI; i += angle) { func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(i), r * Math.sin(i))); } } } + // construct outer ring of circle only for (double i = init; i < init + 2 * Math.PI; i += angle) { func.accept(reference.moveAlongAxes(center.clone(), radius * Math.cos(i), radius * Math.sin(i))); } diff --git a/src/main/java/com/projectkorra/core/util/shape/CircleArc.java b/src/main/java/com/projectkorra/core/util/shape/CircleArc.java index f3e4f5f..ca13f41 100644 --- a/src/main/java/com/projectkorra/core/util/shape/CircleArc.java +++ b/src/main/java/com/projectkorra/core/util/shape/CircleArc.java @@ -4,6 +4,7 @@ import org.bukkit.Location; +import com.projectkorra.core.util.VectorUtil; import com.projectkorra.core.util.math.Angle; import com.projectkorra.core.util.math.Plane; import com.projectkorra.core.util.math.Angle.AngleMode; @@ -14,6 +15,14 @@ public class CircleArc extends Polygon { private float yaw; private Angle theta, interval; + public CircleArc(Location center, double radius, float yaw, Angle theta, Angle interval) { + this(center, radius, yaw, theta, interval, Plane.fromPerpendicular(VectorUtil.direction(-90, -90)), true); + } + + public CircleArc(Location center, double radius, float yaw, Angle theta, Angle interval, Plane reference) { + this(center, radius, yaw, theta, interval, reference, true); + } + public CircleArc(Location center, double radius, float yaw, Angle theta, Angle interval, Plane reference, boolean hollow) { super(center, reference, hollow); this.radius = Math.max(radius, 0.1); @@ -24,24 +33,28 @@ public CircleArc(Location center, double radius, float yaw, Angle theta, Angle i @Override public void construct(Consumer func) { - float lower = yaw - (float) theta.getValue(AngleMode.DEGREES) / 2; - float upper = yaw + (float) theta.getValue(AngleMode.DEGREES) / 2; - double angle = interval.getValue(AngleMode.DEGREES); + double lower = Math.toRadians(yaw - theta.getValue(AngleMode.DEGREES) / 2); // lower bound for the yaw + double upper = Math.toRadians(yaw + theta.getValue(AngleMode.DEGREES) / 2); // upper bound for the yaw + double angle = interval.getValue(AngleMode.RADIANS); // angle between each location of the arc + double rinc = radius * angle / theta.getValue(AngleMode.RADIANS); // interval between each location along the radius if (!hollow) { + // construct each location for (double y = lower; y <= upper; y += angle) { - for (double r = 0.0; r <= radius; r += 0.1) { - func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(Math.toRadians(y)), r * Math.sin(Math.toRadians(y)))); + for (double r = 0.0; r <= radius; r += rinc) { + func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(y), r * Math.sin(y))); } } } else { - for (double r = 0.0; r < radius; r += 0.1) { - func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(Math.toRadians(lower)), r * Math.sin(Math.toRadians(lower)))); - func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(Math.toRadians(upper)), r * Math.sin(Math.toRadians(upper)))); + // construct the sides for the outline + for (double r = 0.0; r < radius; r += rinc) { + func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(lower), r * Math.sin(lower))); + func.accept(reference.moveAlongAxes(center.clone(), r * Math.cos(upper), r * Math.sin(upper))); } + // construct the curve for the outline for (double y = lower; y <= upper; y += angle) { - func.accept(reference.moveAlongAxes(center.clone(), radius * Math.cos(Math.toRadians(y)), radius * Math.sin(Math.toRadians(y)))); + func.accept(reference.moveAlongAxes(center.clone(), radius * Math.cos(y), radius * Math.sin(y))); } } } diff --git a/src/main/java/com/projectkorra/core/util/shape/Cuboid.java b/src/main/java/com/projectkorra/core/util/shape/Cuboid.java index 1eb59a8..852dd4b 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Cuboid.java +++ b/src/main/java/com/projectkorra/core/util/shape/Cuboid.java @@ -45,6 +45,7 @@ public void construct(Consumer func) { Plane horizontal = Plane.fromPerpendicular(upwards.normalize()); if (hollow) { + // construct lines along the horizontal plane horizontal axis for (double x = -length / 2; x <= length / 2; x += interval) { func.accept(horizontal.moveAlongAxes(center.clone(), x, -width / 2).add(upwards.clone().multiply(-height / 2))); func.accept(horizontal.moveAlongAxes(center.clone(), x, -width / 2).add(upwards.clone().multiply(height / 2))); @@ -52,20 +53,23 @@ public void construct(Consumer func) { func.accept(horizontal.moveAlongAxes(center.clone(), x, width / 2).add(upwards.clone().multiply(height / 2))); } - for (double y = -length / 2; y <= length / 2; y += interval) { + // construct lines along the upwards vector + for (double y = -height / 2; y <= height / 2; y += interval) { func.accept(horizontal.moveAlongAxes(center.clone(), -length / 2, -width / 2).add(upwards.clone().multiply(y))); func.accept(horizontal.moveAlongAxes(center.clone(), length / 2, -width / 2).add(upwards.clone().multiply(y))); func.accept(horizontal.moveAlongAxes(center.clone(), -length / 2, width / 2).add(upwards.clone().multiply(y))); func.accept(horizontal.moveAlongAxes(center.clone(), length / 2, width / 2).add(upwards.clone().multiply(y))); } - for (double z = -length / 2; z <= length / 2; z += interval) { + // construct lines along the horizontal plane vertical axis + for (double z = -width / 2; z <= width / 2; z += interval) { func.accept(horizontal.moveAlongAxes(center.clone(), -length / 2, z).add(upwards.clone().multiply(-height / 2))); func.accept(horizontal.moveAlongAxes(center.clone(), -length / 2, z).add(upwards.clone().multiply(height / 2))); func.accept(horizontal.moveAlongAxes(center.clone(), length / 2, z).add(upwards.clone().multiply(-height / 2))); func.accept(horizontal.moveAlongAxes(center.clone(), length / 2, z).add(upwards.clone().multiply(height / 2))); } } else { + // construct whole cuboid for (double x = -length / 2; x <= length / 2; x += interval) { for (double y = -height / 2; y <= height / 2; y += interval) { for (double z = -width / 2; z <= width / 2; z += interval) { diff --git a/src/main/java/com/projectkorra/core/util/shape/Rectangle.java b/src/main/java/com/projectkorra/core/util/shape/Rectangle.java index 2fb4f83..bb4a66c 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Rectangle.java +++ b/src/main/java/com/projectkorra/core/util/shape/Rectangle.java @@ -40,16 +40,19 @@ public Rectangle(Location center, double length, double height, double interval, @Override public void construct(Consumer func) { if (hollow) { + // construct sides along reference plane horizontal axis for (double x = -length / 2; x <= length / 2; x += interval) { func.accept(reference.moveAlongAxes(center.clone(), x, height / 2)); func.accept(reference.moveAlongAxes(center.clone(), x, -height / 2)); } + // construct sides along reference plane vertical axis for (double z = -length / 2; z <= length / 2; z += interval) { func.accept(reference.moveAlongAxes(center.clone(), length / 2, z)); func.accept(reference.moveAlongAxes(center.clone(), -length / 2, z)); } } else { + // construct all locations within reference plane for (double i = -length / 2; i <= length / 2; i += interval) { for (double j = -height / 2; j <= height / 2; j += interval) { func.accept(reference.moveAlongAxes(center.clone(), i, j)); diff --git a/src/main/java/com/projectkorra/core/util/shape/Sphere.java b/src/main/java/com/projectkorra/core/util/shape/Sphere.java index bec146d..7292d34 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Sphere.java +++ b/src/main/java/com/projectkorra/core/util/shape/Sphere.java @@ -48,12 +48,15 @@ public Sphere(Location center, double radius, Angle theta, Angle phi, Vector upw @Override public void construct(Consumer func) { - double angleTheta = theta.getValue(AngleMode.RADIANS); - double anglePhi = phi.getValue(AngleMode.RADIANS); - Plane horizontal = Plane.fromPerpendicular(upwards.normalize()); + double angleTheta = theta.getValue(AngleMode.RADIANS); // angle between each location along the pitch + double anglePhi = phi.getValue(AngleMode.RADIANS); // angle between each location along the yaw + Plane horizontal = Plane.fromPerpendicular(upwards.normalize()); // horizontal reference plane if (!hollow) { - for (double r = 0.0; r < radius; r += 0.1) { + double rinc = radius * angleTheta / (2 * Math.PI); + + // construct the inner bits + for (double r = 0.0; r < radius; r += rinc) { for (double i = 0.0; i < Math.PI; i += angleTheta) { double yv = r * Math.cos(i); @@ -66,6 +69,7 @@ public void construct(Consumer func) { } } + // construct outer shell for (double i = 0.0; i < Math.PI; i += angleTheta) { double yv = radius * Math.cos(i); diff --git a/src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java b/src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java index a3c9b8d..f2e6289 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java +++ b/src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java @@ -42,14 +42,16 @@ public Tetrahedron(Location center, double length, double height, double width, @Override public void construct(Consumer func) { - Plane horizontal = Plane.fromPerpendicular(upwards.normalize()); + Plane horizontal = Plane.fromPerpendicular(upwards.normalize()); // horizontal reference plane if (hollow) { + // construct triangle base for (double x = -length / 2; x <= length / 2 + interval / 2; x += interval) { func.accept(horizontal.moveAlongAxes(center.clone(), x, -width / 2).add(upwards.clone().multiply(height / 2))); func.accept(horizontal.moveAlongAxes(center.clone(), x, (-width / 2) + (width) * (1 - Math.abs(x) / (length / 2))).add(upwards.clone().multiply(height / 2))); } + // construct face outlines for (double y = -height / 2; y <= height / 2; y += interval) { double percent = (y + height / 2) / height; double xv = percent * length / 2; @@ -59,11 +61,13 @@ public void construct(Consumer func) { func.accept(horizontal.moveAlongAxes(center.clone(), -xv, -zv).add(upwards.clone().multiply(y))); } } else { + // construct filled triangles at each height interval for (double y = -height / 2; y <= height / 2; y += interval) { double percent = (y + height / 2) / height; double xv = percent * length; double zv = percent * width; + // construct filled triangle for this height interval for (double x = -xv / 2; x <= xv / 2; x += interval) { double zBound = (-zv / 2) + zv * (1 - Math.abs(x) / (xv / 2)); diff --git a/src/main/java/com/projectkorra/core/util/shape/Triangle.java b/src/main/java/com/projectkorra/core/util/shape/Triangle.java index e070f60..d11ec03 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Triangle.java +++ b/src/main/java/com/projectkorra/core/util/shape/Triangle.java @@ -28,11 +28,13 @@ public Triangle(Location center, double height, double length, double interval, @Override public void construct(Consumer func) { if (hollow) { + // construct outline locations for (double x = -length / 2; x <= length / 2; x += interval) { func.accept(reference.moveAlongAxes(center.clone(), x, -height / 2)); func.accept(reference.moveAlongAxes(center.clone(), x, (-height / 2) + (height) * (1 - Math.abs(x) / (length / 2)))); } } else { + // construct all locations for (double x = -length / 2; x <= length / 2; x += interval) { double yBound = (-height / 2) + (height) * (1 - Math.abs(x) / (length / 2)); for (double y = -height / 2; y <= yBound; y += interval) { From ae52692f34424aada3c9c33e9f3d2659aa48a69c Mon Sep 17 00:00:00 2001 From: Simp Date: Sat, 11 Jul 2020 18:28:33 -0400 Subject: [PATCH 4/5] docs --- .../projectkorra/core/util/shape/Circle.java | 30 ++++++++++++ .../core/util/shape/CircleArc.java | 27 +++++++++++ .../projectkorra/core/util/shape/Cuboid.java | 48 +++++++++++++++++++ .../projectkorra/core/util/shape/Polygon.java | 3 ++ .../core/util/shape/Polyhedron.java | 3 ++ .../core/util/shape/Rectangle.java | 45 +++++++++++++++++ .../projectkorra/core/util/shape/Sphere.java | 37 ++++++++++++++ .../core/util/shape/Tetrahedron.java | 48 +++++++++++++++++++ .../core/util/shape/Triangle.java | 24 ++++++++++ 9 files changed, 265 insertions(+) diff --git a/src/main/java/com/projectkorra/core/util/shape/Circle.java b/src/main/java/com/projectkorra/core/util/shape/Circle.java index 212d37b..f0c944a 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Circle.java +++ b/src/main/java/com/projectkorra/core/util/shape/Circle.java @@ -13,18 +13,48 @@ public class Circle extends Polygon { private double radius; private Angle theta, initial; + /** + * Creates a hollow circle in the XZ plane with no initial angle + * @param center center location + * @param radius distance from center to any point on the circle + * @param theta angle between each location in the circle + */ public Circle(Location center, double radius, Angle theta) { this(center, radius, theta, Angle.radians(0), Plane.XZ, true); } + /** + * Creates a hollow circle in the XZ plane + * @param center center location + * @param radius distance from center to any point on the circle + * @param theta angle between each location in the circle + * @param initial angle to start constructing circle from + */ public Circle(Location center, double radius, Angle theta, Angle initial) { this(center, radius, theta, initial, Plane.XZ, true); } + /** + * Creates a hollow circle + * @param center center location + * @param radius distance from center to any point on the circle + * @param theta angle between each location in the circle + * @param initial angle to start constructing circle from + * @param reference plane to construct circle in + */ public Circle(Location center, double radius, Angle theta, Angle initial, Plane reference) { this(center, radius, theta, initial, reference, true); } + /** + * Creates a circle + * @param center center location + * @param radius distance from center to any point on the circle + * @param theta angle between each location in the circle + * @param initial angle to start constructing circle from + * @param reference plane to construct circle in + * @param hollow true to only draw outline + */ public Circle(Location center, double radius, Angle theta, Angle initial, Plane reference, boolean hollow) { super(center, reference, hollow); this.radius = radius; diff --git a/src/main/java/com/projectkorra/core/util/shape/CircleArc.java b/src/main/java/com/projectkorra/core/util/shape/CircleArc.java index ca13f41..b1e2c53 100644 --- a/src/main/java/com/projectkorra/core/util/shape/CircleArc.java +++ b/src/main/java/com/projectkorra/core/util/shape/CircleArc.java @@ -15,14 +15,41 @@ public class CircleArc extends Polygon { private float yaw; private Angle theta, interval; + /** + * Creates a hollow arc of a circle in the XZ plane + * @param center center of the circle (not the arc) + * @param radius distance from center to points on the arc + * @param yaw starting angle + * @param theta angular magnitude of the arc + * @param interval angle between each location + */ public CircleArc(Location center, double radius, float yaw, Angle theta, Angle interval) { this(center, radius, yaw, theta, interval, Plane.fromPerpendicular(VectorUtil.direction(-90, -90)), true); } + /** + * Creates a hollow arc of a circle + * @param center center of the circle (not the arc) + * @param radius distance from center to points on the arc + * @param yaw starting angle + * @param theta angular magnitude of the arc + * @param interval angle between each location + * @param reference plane the circle exists in + */ public CircleArc(Location center, double radius, float yaw, Angle theta, Angle interval, Plane reference) { this(center, radius, yaw, theta, interval, reference, true); } + /** + * Creates an arc of a circle + * @param center center of the circle (not the arc) + * @param radius distance from center to points on the arc + * @param yaw starting angle + * @param theta angular magnitude of the arc + * @param interval angle between each location + * @param reference plane the circle exists in + * @param hollow true to only draw outline + */ public CircleArc(Location center, double radius, float yaw, Angle theta, Angle interval, Plane reference, boolean hollow) { super(center, reference, hollow); this.radius = Math.max(radius, 0.1); diff --git a/src/main/java/com/projectkorra/core/util/shape/Cuboid.java b/src/main/java/com/projectkorra/core/util/shape/Cuboid.java index 852dd4b..4b18237 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Cuboid.java +++ b/src/main/java/com/projectkorra/core/util/shape/Cuboid.java @@ -12,26 +12,74 @@ public class Cuboid extends Polyhedron { private double length, height, width, interval; + /** + * Creates a hollow cuboid pointed up along the y-axis + * @param center center location + * @param sides magnitude of length, height, and width + * @param interval distance between each location + */ public Cuboid(Location center, double sides, double interval) { this(center, sides, sides, sides, interval, UnitVector.POSITIVE_Y.normal(), true); } + /** + * Creates a hollow cuboid + * @param center center location + * @param sides magnitude of length, height, and width + * @param interval distance between each location + * @param upwards upwards direction + */ public Cuboid(Location center, double sides, double interval, Vector upwards) { this(center, sides, sides, sides, interval, upwards, true); } + /** + * Creates a cuboid + * @param center center location + * @param sides magnitude of length, height, and width + * @param interval distance between each location + * @param upwards upwards direction + * @param hollow true to only draw outline + */ public Cuboid(Location center, double sides, double interval, Vector upwards, boolean hollow) { this(center, sides, sides, sides, interval, upwards, hollow); } + /** + * Creates a hollow cuboid pointed up along the y-axis + * @param center center location + * @param length horizontal magnitude of reference plane + * @param height magnitude of upwards vector + * @param width vertical magnitude of reference plane + * @param interval distance between each location + */ public Cuboid(Location center, double length, double height, double width, double interval) { this(center, length, height, width, interval, UnitVector.POSITIVE_Y.normal(), true); } + /** + * Creates a hollow cuboid + * @param center center location + * @param length horizontal magnitude of reference plane + * @param height magnitude of upwards vector + * @param width vertical magnitude of reference plane + * @param interval distance between each location + * @param upwards upwards direction + */ public Cuboid(Location center, double length, double height, double width, double interval, Vector upwards) { this(center, length, height, width, interval, upwards, true); } + /** + * Creates a cuboid + * @param center center location + * @param length horizontal magnitude of reference plane + * @param height magnitude of upwards vector + * @param width vertical magnitude of reference plane + * @param interval distance between each location + * @param upwards upwards direction + * @param hollow true to only draw outline + */ public Cuboid(Location center, double length, double height, double width, double interval, Vector upwards, boolean hollow) { super(center, upwards, hollow); this.length = Math.max(length, 0.1); diff --git a/src/main/java/com/projectkorra/core/util/shape/Polygon.java b/src/main/java/com/projectkorra/core/util/shape/Polygon.java index 5836026..521edc8 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Polygon.java +++ b/src/main/java/com/projectkorra/core/util/shape/Polygon.java @@ -4,6 +4,9 @@ import com.projectkorra.core.util.math.Plane; +/** + * Class containing information important to all 2D shapes + */ public abstract class Polygon implements Shape { protected Location center; diff --git a/src/main/java/com/projectkorra/core/util/shape/Polyhedron.java b/src/main/java/com/projectkorra/core/util/shape/Polyhedron.java index a56afe3..7a11833 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Polyhedron.java +++ b/src/main/java/com/projectkorra/core/util/shape/Polyhedron.java @@ -3,6 +3,9 @@ import org.bukkit.Location; import org.bukkit.util.Vector; +/** + * Class containing information important to all 3D shapes + */ public abstract class Polyhedron implements Shape { protected Location center; diff --git a/src/main/java/com/projectkorra/core/util/shape/Rectangle.java b/src/main/java/com/projectkorra/core/util/shape/Rectangle.java index bb4a66c..50657a7 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Rectangle.java +++ b/src/main/java/com/projectkorra/core/util/shape/Rectangle.java @@ -10,26 +10,71 @@ public class Rectangle extends Polygon { private double length, height, interval; + /** + * Creates a hollow rectangle in the XZ plane + * @param center center location + * @param sides magnitude of length and height + * @param interval distance between each location + */ public Rectangle(Location center, double sides, double interval) { this(center, sides, sides, interval, Plane.XZ, true); } + /** + * Creates a hollow rectangle in the XZ plane + * @param center center location + * @param length horizontal magnitude in the reference plane + * @param height vertical magnitude in the reference plane + * @param interval distance between each location + */ public Rectangle(Location center, double length, double height, double interval) { this(center, length, height, interval, Plane.XZ, true); } + /** + * Creates a hollow rectangle + * @param center center location + * @param sides magnitude of length and height + * @param interval distance between each location + * @param reference plane the rectangle exists in + */ public Rectangle(Location center, double sides, double interval, Plane reference) { this(center, sides, sides, interval, reference, true); } + /** + * Creates a rectangle + * @param center center location + * @param sides magnitude of length and height + * @param interval distance between each location + * @param reference plane the rectangle exists in + * @param hollow true to only draw outline + */ public Rectangle(Location center, double sides, double interval, Plane reference, boolean hollow) { this(center, sides, sides, interval, reference, hollow); } + /** + * Creates a hollow rectangle + * @param center center location + * @param length horizontal magnitude in the reference plane + * @param height vertical magnitude in the reference plane + * @param interval distance between each location + * @param reference plane the rectangle exists in + */ public Rectangle(Location center, double length, double height, double interval, Plane reference) { this(center, length, height, interval, reference, true); } + /** + * Creates a rectangle + * @param center center location + * @param length horizontal magnitude in the reference plane + * @param height vertical magnitude in the reference plane + * @param interval distance between each location + * @param reference plane the rectangle exists in + * @param hollow true to only draw outline + */ public Rectangle(Location center, double length, double height, double interval, Plane reference, boolean hollow) { super(center, reference, hollow); this.length = Math.max(length, 0.1); diff --git a/src/main/java/com/projectkorra/core/util/shape/Sphere.java b/src/main/java/com/projectkorra/core/util/shape/Sphere.java index 7292d34..23cb018 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Sphere.java +++ b/src/main/java/com/projectkorra/core/util/shape/Sphere.java @@ -15,22 +15,59 @@ public class Sphere extends Polyhedron { private double radius; private Angle theta, phi; + /** + * Creates a hollow sphere pointed up along the y-axis + * @param center center location + * @param radius distance between the center and any location on the sphere + * @param both angle between locations along both pitch and yaw + */ public Sphere(Location center, double radius, Angle both) { this(center, radius, both, both, UnitVector.POSITIVE_Y.normal(), true); } + /** + * Creates a hollow sphere + * @param center center location + * @param radius distance between the center and any location on the sphere + * @param both angle between locations along both pitch and yaw + * @param upwards upwards direction to construct horizontal plane from + */ public Sphere(Location center, double radius, Angle both, Vector upwards) { this(center, radius, both, both, upwards, true); } + /** + * Creates a hollow sphere pointed up along the y-axis + * @param center center location + * @param radius distance between the center and any location on the sphere + * @param theta angle between each location along the pitch + * @param phi angle between each location along the yaw + */ public Sphere(Location center, double radius, Angle theta, Angle phi) { this(center, radius, theta, phi, UnitVector.POSITIVE_Y.normal(), true); } + /** + * Creates a hollow sphere + * @param center center location + * @param radius distance between the center and any location on the sphere + * @param theta angle between each location along the pitch + * @param phi angle between each location along the yaw + * @param upwards upwards direction to construct horizontal plane from + */ public Sphere(Location center, double radius, Angle theta, Angle phi, Vector upwards) { this(center, radius, theta, phi, upwards, true); } + /** + * Creates a sphere + * @param center center location + * @param radius distance between the center and any location on the sphere + * @param theta angle between each location along the pitch + * @param phi angle between each location along the yaw + * @param upwards upwards direction to construct horizontal plane from + * @param hollow true to draw only the outline + */ public Sphere(Location center, double radius, Angle theta, Angle phi, Vector upwards, boolean hollow) { super(center, upwards, hollow); this.radius = radius; diff --git a/src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java b/src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java index f2e6289..ab87ce9 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java +++ b/src/main/java/com/projectkorra/core/util/shape/Tetrahedron.java @@ -12,26 +12,74 @@ public class Tetrahedron extends Polyhedron { private double length, height, width, interval; + /** + * Creates hollow a tetrahedron (pyramid) using the y-axis for upwards direction + * @param center center location + * @param sides magnitude of the length, height, and width + * @param interval distance between each location + */ public Tetrahedron(Location center, double sides, double interval) { this(center, sides, sides, sides, interval, UnitVector.POSITIVE_Y.normal(), true); } + /** + * Creates hollow a tetrahedron (pyramid) + * @param center center location + * @param sides magnitude of the length, height, and width + * @param interval distance between each location + * @param upwards upwards direction for this shape, used to construct the perpendicular plane + */ public Tetrahedron(Location center, double sides, double interval, Vector upwards) { this(center, sides, sides, sides, interval, upwards, true); } + /** + * Creates a tetrahedron (pyramid) + * @param center center location + * @param sides magnitude of the length, height, and width + * @param interval distance between each location + * @param upwards upwards direction for this shape, used to construct the perpendicular plane + * @param hollow true to only draw the outline + */ public Tetrahedron(Location center, double sides, double interval, Vector upwards, boolean hollow) { this(center, sides, sides, sides, interval, upwards, hollow); } + /** + * Creates a hollow tetrahedron (pyramid) using the y-axis for upwards direction + * @param center center location + * @param length horizontal magnitude in the reference plane + * @param height magnitude of the upwards vector + * @param width vertical magnitude in the reference plane + * @param interval distance between each location + */ public Tetrahedron(Location center, double length, double height, double width, double interval) { this(center, length, height, width, interval, UnitVector.POSITIVE_Y.normal(), true); } + /** + * Creates a hollow tetrahedron (pyramid) + * @param center center location + * @param length horizontal magnitude in the reference plane + * @param height magnitude of the upwards vector + * @param width vertical magnitude in the reference plane + * @param interval distance between each location + * @param upwards upwards direction for this shape, used to construct the perpendicular plane + */ public Tetrahedron(Location center, double length, double height, double width, double interval, Vector upwards) { this(center, length, height, width, interval, upwards, true); } + /** + * Creates a tetrahedron (pyramid) + * @param center center location + * @param length horizontal magnitude in the reference plane + * @param height magnitude of the upwards vector + * @param width vertical magnitude in the reference plane + * @param interval distance between each location + * @param upwards upwards direction for this shape, used to construct the perpendicular plane + * @param hollow true to only draw the outline + */ public Tetrahedron(Location center, double length, double height, double width, double interval, Vector upwards, boolean hollow) { super(center, upwards, hollow); this.length = Math.max(length, 0.1); diff --git a/src/main/java/com/projectkorra/core/util/shape/Triangle.java b/src/main/java/com/projectkorra/core/util/shape/Triangle.java index d11ec03..102d2f9 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Triangle.java +++ b/src/main/java/com/projectkorra/core/util/shape/Triangle.java @@ -10,14 +10,38 @@ public class Triangle extends Polygon { private double height, length, interval; + /** + * Creates a hollow triangle in the XZ plane + * @param center center location + * @param height vertical magnitude in the reference plane + * @param length horizontal magnitude in the reference plane + * @param interval distance between each location in the triangle + */ public Triangle(Location center, double height, double length, double interval) { this(center, height, length, interval, Plane.XZ, true); } + /** + * Creates a hollow triangle + * @param center center location + * @param height vertical magnitude in the reference plane + * @param length horizontal magnitude in the reference plane + * @param interval distance between each location in the triangle + * @param reference plane the triangle exists within + */ public Triangle(Location center, double height, double length, double interval, Plane reference) { this(center, height, length, interval, reference, true); } + /** + * Creates a triangle + * @param center center location + * @param height vertical magnitude in the reference plane + * @param length horizontal magnitude in the reference plane + * @param interval distance between each location in the triangle + * @param reference plane the triangle exists within + * @param hollow true if only drawing the outline + */ public Triangle(Location center, double height, double length, double interval, Plane reference, boolean hollow) { super(center, reference, hollow); this.height = Math.max(height, 0.1); From 55c0cc10900720bf304c960128372a87c7daf12c Mon Sep 17 00:00:00 2001 From: Simp Date: Sun, 12 Jul 2020 02:14:35 -0400 Subject: [PATCH 5/5] normalize Polyhedron#getUpwards --- src/main/java/com/projectkorra/core/util/shape/Polyhedron.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/projectkorra/core/util/shape/Polyhedron.java b/src/main/java/com/projectkorra/core/util/shape/Polyhedron.java index 7a11833..d693ca3 100644 --- a/src/main/java/com/projectkorra/core/util/shape/Polyhedron.java +++ b/src/main/java/com/projectkorra/core/util/shape/Polyhedron.java @@ -24,7 +24,7 @@ public Location getCenter() { } public Vector getUpwards() { - return upwards; + return upwards.normalize(); } @Override