BlueMapAPI/src/main/java/de/bluecolored/bluemap/api/math/Shape.java

205 lines
7.1 KiB
Java

/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.bluecolored.bluemap.api.math;
import com.flowpowered.math.vector.Vector2d;
import de.bluecolored.bluemap.api.debug.DebugDump;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
/**
* A shape consisting of 3 or more {@link Vector2d}-points on a plane.
*/
@DebugDump
public class Shape {
private final Vector2d[] points;
@Nullable
private Vector2d min = null, max = null;
public Shape(Vector2d... points) {
if (points.length < 3) throw new IllegalArgumentException("A shape has to have at least 3 points!");
this.points = points;
}
/**
* Getter for the amount of points in this shape.
* @return the amount of points
*/
public int getPointCount() {
return points.length;
}
public Vector2d getPoint(int i) {
return points[i];
}
/**
* Getter for <b>a copy</b> of the points array.<br>
* <i>(A shape is immutable once created)</i>
* @return the points of this shape
*/
public Vector2d[] getPoints() {
return Arrays.copyOf(points, points.length);
}
/**
* Calculates and returns the minimum corner of the axis-aligned-bounding-box of this shape.
* @return the min of the AABB of this shape
*/
public Vector2d getMin() {
if (this.min == null) {
Vector2d min = points[0];
for (int i = 1; i < points.length; i++) {
min = min.min(points[i]);
}
this.min = min;
}
return this.min;
}
/**
* Calculates and returns the maximum corner of the axis-aligned-bounding-box of this shape.
* @return the max of the AABB of this shape
*/
public Vector2d getMax() {
if (this.max == null) {
Vector2d max = points[0];
for (int i = 1; i < points.length; i++) {
max = max.max(points[i]);
}
this.max = max;
}
return this.max;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Shape shape = (Shape) o;
return Arrays.equals(points, shape.points);
}
@Override
public int hashCode() {
return Arrays.hashCode(points);
}
/**
* Creates a {@link Shape} representing a rectangle spanning over pos1 and pos2
* @param pos1 one corner of the rectangle
* @param pos2 the opposite corner of the rectangle
* @return the created {@link Shape}
*/
public static Shape createRect(Vector2d pos1, Vector2d pos2) {
Vector2d min = pos1.min(pos2);
Vector2d max = pos1.max(pos2);
return new Shape(
min,
new Vector2d(max.getX(), min.getY()),
max,
new Vector2d(min.getX(), max.getY())
);
}
/**
* Creates a {@link Shape} representing a rectangle spanning over two points
* @param x1 x position of one corner of the rectangle
* @param y1 y position of one corner of the rectangle
* @param x2 x position of the opposite corner of the rectangle
* @param y2 y position of the opposite corner of the rectangle
* @return the created {@link Shape}
*/
public static Shape createRect(double x1, double y1, double x2, double y2) {
return createRect(new Vector2d(x1, y1), new Vector2d(x2, y2));
}
/**
* Creates a {@link Shape} representing an ellipse.
* @param centerPos the center of the ellipse
* @param radiusX the x radius of the ellipse
* @param radiusY the y radius of the ellipse
* @param points the amount of points used to create the ellipse (at least 3)
* @return the created {@link Shape}
*/
public static Shape createEllipse(Vector2d centerPos, double radiusX, double radiusY, int points) {
if (points < 3) throw new IllegalArgumentException("A shape has to have at least 3 points!");
Vector2d[] pointArray = new Vector2d[points];
double segmentAngle = 2 * Math.PI / points;
double angle = 0d;
for (int i = 0; i < points; i++) {
pointArray[i] = centerPos.add(Math.sin(angle) * radiusX, Math.cos(angle) * radiusY);
angle += segmentAngle;
}
return new Shape(pointArray);
}
/**
* Creates a {@link Shape} representing an ellipse.
* @param centerX the x-position of the center of the ellipse
* @param centerY the y-position of the center of the ellipse
* @param radiusX the x radius of the ellipse
* @param radiusY the y radius of the ellipse
* @param points the amount of points used to create the ellipse (at least 3)
* @return the created {@link Shape}
*/
public static Shape createEllipse(double centerX, double centerY, double radiusX, double radiusY, int points) {
return createEllipse(new Vector2d(centerX, centerY), radiusX, radiusY, points);
}
/**
* Creates a {@link Shape} representing a circle.
* @param centerPos the center of the circle
* @param radius the radius of the circle
* @param points the amount of points used to create the circle (at least 3)
* @return the created {@link Shape}
*/
public static Shape createCircle(Vector2d centerPos, double radius, int points) {
return createEllipse(centerPos, radius, radius, points);
}
/**
* Creates a {@link Shape} representing a circle.
* @param centerX the x-position of the center of the circle
* @param centerY the y-position of the center of the circle
* @param radius the radius of the circle
* @param points the amount of points used to create the circle (at least 3)
* @return the created {@link Shape}
*/
public static Shape createCircle(double centerX, double centerY, double radius, int points) {
return createCircle(new Vector2d(centerX, centerY), radius, points);
}
}