/* * Copyright 2016 Ali Moghnieh * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.supaham.commons.bukkit.utils; import com.google.common.base.Preconditions; import org.bukkit.util.Vector; import javax.annotation.Nonnull; /** * Represents an {@link ImmutableVector} with the given components being optionally relative. This class plays nice * with Both {@link ImmutableVector} and {@link Vector}, both through {@link #equals(Object)} & {@link #equals(Vector)} * and {@link #with(ImmutableVector)} & {@link #with(Vector)} */ public class RelativeVector extends ImmutableVector { private final boolean xRelative; private final boolean yRelative; private final boolean zRelative; public RelativeVector(double x, double y, double z, boolean xRelative, boolean yRelative, boolean zRelative) { super(x, y, z); this.xRelative = xRelative; this.yRelative = yRelative; this.zRelative = zRelative; } /** * Returns whether this {@link RelativeVector} is equal to an {@link ImmutableVector}. If this vector has relativity * (as in {@link #isRelative()} returns true), and {@code obj} isn't of type {@link RelativeVector} then {@code * false} is immediately returned. Otherwise, component relativity and the components themselves are compared against * each other and the result of equivalency is returned. Alternatively, if this vector has no relativity, * {@link ImmutableVector#equals(Object)} is called and this RelativeVector is treated exactly like a * {@link ImmutableVector}. * * @param obj object to compare * * @return whether this RelativeVector is equal to {@code obj} */ @Override public boolean equals(Object obj) { // The following if-else makes us equal with ImmutableVector instances if we don't have relativity. if (!(obj instanceof ImmutableVector)) { return false; } else if (!isRelative()) { return super.equals(obj); // Treat this RelativeVector as if it were a normal ImmutableVector } // We've got relativity, the other object must be of type RelativeVector to even have relativity like us. if (!(obj instanceof RelativeVector)) { return false; } RelativeVector o2 = (RelativeVector) obj; return super.equals(obj) && ((this.xRelative == o2.xRelative) && (this.yRelative == o2.yRelative) && (this.zRelative == o2.zRelative)); } /** * Returns whether this {@link RelativeVector} is equal to a {@link Vector}. If this vector has relativity (as in * {@link #isRelative()} returns true), then {@code false} is immediately returned as {@code o} is a vector of exact * coordinates. Otherwise, the normal {@link ImmutableVector} check of xyz components is done and that result is * returned. * * @param o vector to check * * @return whether {@code o} is equal to this RelativeVector */ @Override public boolean equals(Vector o) { // If we're relative then no way could we be equal to a vector of exact coordinates. if (isRelative()) { return false; } // We're not relative, check if our coordinates are equal. return super.equals(o); } /** * Returns a new ImmutableVector combined of this relative vector with a {@link Vector}. If this vector has no * relativity (as in {@link #isRelative()} returns false), this same RelativeVector is returned. Otherwise, each * component keeps it initial value and if the component is relative the vector's same component is added to provide * relativity. * * @param vector vector to combine with this * * @return either this or a new ImmutableVector of the combination */ @SuppressWarnings("Duplicates") public ImmutableVector with(@Nonnull Vector vector) { Preconditions.checkNotNull(vector, "vector cannot be null."); if (!isRelative()) { // Nothing in this vector is relative, return this vector of exact coordinates. return this; } double x = isXRelative() ? vector.getX() + getX() : getX(); double y = isYRelative() ? vector.getY() + getY() : getY(); double z = isZRelative() ? vector.getZ() + getZ() : getZ(); return new ImmutableVector(x, y, z); } /** * Returns a new ImmutableVector combined of this relative vector with a {@link ImmutableVector}. If this vector has * no relativity (as in {@link #isRelative()} returns false), this same RelativeVector is returned. Otherwise, each * component keeps it initial value and if the component is relative the vector's same component is added to provide * relativity. * * @param vector vector to combine with this * * @return either this or a new ImmutableVector of the combination */ @SuppressWarnings("Duplicates") public ImmutableVector with(@Nonnull ImmutableVector vector) { Preconditions.checkNotNull(vector, "vector cannot be null."); if (!isRelative()) { // Nothing in this vector is relative, return this vector of exact coordinates. return this; } double x = isXRelative() ? vector.getX() + getX() : getX(); double y = isYRelative() ? vector.getY() + getY() : getY(); double z = isZRelative() ? vector.getZ() + getZ() : getZ(); return new ImmutableVector(x, y, z); } public boolean isRelative() { return isXRelative() || isYRelative() || isZRelative(); } public boolean isXRelative() { return xRelative; } public boolean isYRelative() { return yRelative; } public boolean isZRelative() { return zRelative; } }