001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.math3.geometry.spherical.oned;
018
019import org.apache.commons.math3.exception.NumberIsTooLargeException;
020import org.apache.commons.math3.exception.util.LocalizedFormats;
021import org.apache.commons.math3.geometry.partitioning.Region.Location;
022import org.apache.commons.math3.util.FastMath;
023import org.apache.commons.math3.util.MathUtils;
024import org.apache.commons.math3.util.Precision;
025
026
027/** This class represents an arc on a circle.
028 * @see ArcsSet
029 * @since 3.3
030 */
031public class Arc {
032
033    /** The lower angular bound of the arc. */
034    private final double lower;
035
036    /** The upper angular bound of the arc. */
037    private final double upper;
038
039    /** Middle point of the arc. */
040    private final double middle;
041
042    /** Tolerance below which angles are considered identical. */
043    private final double tolerance;
044
045    /** Simple constructor.
046     * <p>
047     * If either {@code lower} is equals to {@code upper} or
048     * the interval exceeds \( 2 \pi \), the arc is considered
049     * to be the full circle and its initial defining boundaries
050     * will be forgotten. {@code lower} is not allowed to be
051     * greater than {@code upper} (an exception is thrown in this case).
052     * {@code lower} will be canonicalized between 0 and \( 2 \pi \), and
053     * upper shifted accordingly, so the {@link #getInf()} and {@link #getSup()}
054     * may not return the value used at instance construction.
055     * </p>
056     * @param lower lower angular bound of the arc
057     * @param upper upper angular bound of the arc
058     * @param tolerance tolerance below which angles are considered identical
059     * @exception NumberIsTooLargeException if lower is greater than upper
060     */
061    public Arc(final double lower, final double upper, final double tolerance)
062        throws NumberIsTooLargeException {
063        this.tolerance = tolerance;
064        if (Precision.equals(lower, upper, 0) || (upper - lower) >= MathUtils.TWO_PI) {
065            // the arc must cover the whole circle
066            this.lower  = 0;
067            this.upper  = MathUtils.TWO_PI;
068            this.middle = FastMath.PI;
069        } else  if (lower <= upper) {
070            this.lower  = MathUtils.normalizeAngle(lower, FastMath.PI);
071            this.upper  = this.lower + (upper - lower);
072            this.middle = 0.5 * (this.lower + this.upper);
073        } else {
074            throw new NumberIsTooLargeException(LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
075                                                lower, upper, true);
076        }
077    }
078
079    /** Get the lower angular bound of the arc.
080     * @return lower angular bound of the arc,
081     * always between 0 and \( 2 \pi \)
082     */
083    public double getInf() {
084        return lower;
085    }
086
087    /** Get the upper angular bound of the arc.
088     * @return upper angular bound of the arc,
089     * always between {@link #getInf()} and {@link #getInf()} \( + 2 \pi \)
090     */
091    public double getSup() {
092        return upper;
093    }
094
095    /** Get the angular size of the arc.
096     * @return angular size of the arc
097     */
098    public double getSize() {
099        return upper - lower;
100    }
101
102    /** Get the barycenter of the arc.
103     * @return barycenter of the arc
104     */
105    public double getBarycenter() {
106        return middle;
107    }
108
109    /** Get the tolerance below which angles are considered identical.
110     * @return tolerance below which angles are considered identical
111     */
112    public double getTolerance() {
113        return tolerance;
114    }
115
116    /** Check a point with respect to the arc.
117     * @param point point to check
118     * @return a code representing the point status: either {@link
119     * Location#INSIDE}, {@link Location#OUTSIDE} or {@link Location#BOUNDARY}
120     */
121    public Location checkPoint(final double point) {
122        final double normalizedPoint = MathUtils.normalizeAngle(point, middle);
123        if (normalizedPoint < lower - tolerance || normalizedPoint > upper + tolerance) {
124            return Location.OUTSIDE;
125        } else if (normalizedPoint > lower + tolerance && normalizedPoint < upper - tolerance) {
126            return Location.INSIDE;
127        } else {
128            return (getSize() >= MathUtils.TWO_PI - tolerance) ? Location.INSIDE : Location.BOUNDARY;
129        }
130    }
131
132}