/*
* Strongback
* Copyright 2015, Strongback and individual contributors by the @authors tag.
* See the COPYRIGHT.txt in the distribution for a full listing of individual
* contributors.
*
* Licensed under the MIT License; you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* 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 org.strongback.components;
import java.util.function.DoubleSupplier;
import org.strongback.annotation.ThreadSafe;
/**
* A sensor that determines the positional heading, or angular displacement, in degrees. A compass is an {@link AngleSensor}
* with an additional method to determine {@link #getHeading() heading}. It also can be {@link #zero() zeroed} to return angles
* and heading relative to another. Negative values are assumed to be counter-clockwise and positive values are clockwise.
*
* @author Randall Hauch
*/
@ThreadSafe
public interface Compass extends AngleSensor {
/**
* Gets the angular displacement of in degrees in the range [0, 360).
*
* @return the heading of this {@link Compass}
*/
public default double getHeading() {
double positiveOrNegative = getAngle() % 360;
return positiveOrNegative >= 0 ? positiveOrNegative : 360 + positiveOrNegative;
}
/**
* Compute the change in heading between the {@link #getHeading() current heading} and the target heading, using the given
* tolerance for the difference. The result is the angle that this sensor must rotate to reach the target heading, which may
* be positive or negative.
*
* @param targetHeading the target heading
* @param tolerance the allowed tolerance in degrees between the two headings
* @return the angular displacement required for this sensor to reach the target heading, or 0.0d if the two headings are
* already within the specified {@code tolerance}
*/
default public double computeHeadingChangeTo(double targetHeading, double tolerance) {
double diff = targetHeading - this.getHeading();
return Math.abs(diff) <= Math.abs(tolerance) ? 0.0 : diff;
}
/**
* Create a angle sensor for the given function that returns the angle.
*
* @param angleSupplier the function that returns the angle; may not be null
* @return the angle sensor
*/
public static Compass create(DoubleSupplier angleSupplier) {
return new Compass() {
private volatile double zero = 0;
@Override
public double getAngle() {
return angleSupplier.getAsDouble() - zero;
}
@Override
public Compass zero() {
zero = angleSupplier.getAsDouble();
return this;
}
};
}
}