/* * ----------------------------------------------------------------------- * Copyright © 2013-2015 Meno Hochschild, <http://www.menodata.de/> * ----------------------------------------------------------------------- * This file (IntervalRelation.java) is part of project Time4J. * * Time4J is free software: You can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * Time4J is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Time4J. If not, see <http://www.gnu.org/licenses/>. * ----------------------------------------------------------------------- */ package net.time4j.range; import net.time4j.engine.Temporal; /** * <p>Represents an Allen-relation between two intervals. </p> * * <p>Given any two intervals, there is always a unique and distinct relation * between them without ambivalence. There are 13 possible relations. </p> * * <div style="margin-top:10px;"> * <table border="1"> * <caption>Allen-Relations</caption> * <tr> * <td>precedes</td><td><img src="doc-files/precedes.jpg" alt="precedes"></td> * </tr> * <tr> * <td>meets</td><td><img src="doc-files/meets.jpg" alt="meets"></td> * </tr> * <tr> * <td>overlaps</td><td><img src="doc-files/overlaps.jpg" alt="overlaps"></td> * </tr> * <tr> * <td>finishedBy</td><td><img src="doc-files/finishedBy.jpg" alt="finishedBy"></td> * </tr> * <tr> * <td>encloses</td><td><img src="doc-files/encloses.jpg" alt="encloses"></td> * </tr> * <tr> * <td>starts</td><td><img src="doc-files/starts.jpg" alt="starts"></td> * </tr> * <tr> * <td>equivalent</td><td><img src="doc-files/equivalent.jpg" alt="equivalent"></td> * </tr> * <tr> * <td>startedBy</td><td><img src="doc-files/startedBy.jpg" alt="startedBy"></td> * </tr> * <tr> * <td>enclosedBy</td><td><img src="doc-files/enclosedBy.jpg" alt="enclosedBy"></td> * </tr> * <tr> * <td>finishes</td><td><img src="doc-files/finishes.jpg" alt="finishes"></td> * </tr> * <tr> * <td>overlappedBy</td><td><img src="doc-files/overlappedBy.jpg" alt="overlappedBy"></td> * </tr> * <tr> * <td>metBy</td><td><img src="doc-files/metBy.jpg" alt="metBy"></td> * </tr> * <tr> * <td>precededBy</td><td><img src="doc-files/precededBy.jpg" alt="precededBy"></td> * </tr> * </table> * </div> * * <p>Further explanations can be found at the website of * <a href="http://www.ics.uci.edu/~alspaugh/cls/shr/allen.html">Allen's * interval algebra</a>. </p> * * @author Meno Hochschild * @since 2.0 */ /*[deutsch] * <p>Repräsentiert eine Allen-Beziehung zwischen zwei Intervallen. </p> * * <p>Sind zwei Intervalle gegeben, so läßt sich immer eindeutig * genau eine Beziehung zwischen diesen zwei Intervallen angeben. Insgesamt * gibt es 13 mögliche Beziehungen. </p> * * <div style="margin-top:10px;"> * <table border="1"> * <caption>Allen-Relationen</caption> * <tr> * <td>precedes</td><td><img src="doc-files/precedes.jpg" alt="precedes"></td> * </tr> * <tr> * <td>meets</td><td><img src="doc-files/meets.jpg" alt="meets"></td> * </tr> * <tr> * <td>overlaps</td><td><img src="doc-files/overlaps.jpg" alt="overlaps"></td> * </tr> * <tr> * <td>finishedBy</td><td><img src="doc-files/finishedBy.jpg" alt="finishedBy"></td> * </tr> * <tr> * <td>encloses</td><td><img src="doc-files/encloses.jpg" alt="encloses"></td> * </tr> * <tr> * <td>starts</td><td><img src="doc-files/starts.jpg" alt="starts"></td> * </tr> * <tr> * <td>equivalent</td><td><img src="doc-files/equivalent.jpg" alt="equivalent"></td> * </tr> * <tr> * <td>startedBy</td><td><img src="doc-files/startedBy.jpg" alt="startedBy"></td> * </tr> * <tr> * <td>enclosedBy</td><td><img src="doc-files/enclosedBy.jpg" alt="enclosedBy"></td> * </tr> * <tr> * <td>finishes</td><td><img src="doc-files/finishes.jpg" alt="finishes"></td> * </tr> * <tr> * <td>overlappedBy</td><td><img src="doc-files/overlappedBy.jpg" alt="overlappedBy"></td> * </tr> * <tr> * <td>metBy</td><td><img src="doc-files/metBy.jpg" alt="metBy"></td> * </tr> * <tr> * <td>precededBy</td><td><img src="doc-files/precededBy.jpg" alt="precededBy"></td> * </tr> * </table> * </div> * * <p>Weitere Erklärungen gibt es auf der Webseite von * <a href="http://www.ics.uci.edu/~alspaugh/cls/shr/allen.html">Allen's * Interval-Algebra</a>. </p> * * @author Meno Hochschild * @since 2.0 */ public enum IntervalRelation { //~ Statische Felder/Initialisierungen -------------------------------- /** * <p>See {@link IsoInterval#precedes(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#precedes(IsoInterval)}. </p> */ PRECEDES, /** * <p>See {@link IsoInterval#meets(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#meets(IsoInterval)}. </p> */ MEETS, /** * <p>See {@link IsoInterval#overlaps(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#overlaps(IsoInterval)}. </p> */ OVERLAPS, /** * <p>See {@link IsoInterval#finishes(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#finishes(IsoInterval)}. </p> */ FINISHES, /** * <p>See {@link IsoInterval#starts(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#starts(IsoInterval)}. </p> */ STARTS, /** * <p>See {@link IsoInterval#encloses(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#encloses(IsoInterval)}. </p> */ ENCLOSES, /** * <p>See {@link IsoInterval#equivalentTo(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#equivalentTo(IsoInterval)}. </p> */ EQUIVALENT, /** * <p>See {@link IsoInterval#enclosedBy(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#enclosedBy(IsoInterval)}. </p> */ ENCLOSED_BY, /** * <p>See {@link IsoInterval#startedBy(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#startedBy(IsoInterval)}. </p> */ STARTED_BY, /** * <p>See {@link IsoInterval#finishedBy(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#finishedBy(IsoInterval)}. </p> */ FINISHED_BY, /** * <p>See {@link IsoInterval#overlappedBy(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#overlappedBy(IsoInterval)}. </p> */ OVERLAPPED_BY, /** * <p>See {@link IsoInterval#metBy(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#metBy(IsoInterval)}. </p> */ MET_BY, /** * <p>See {@link IsoInterval#precededBy(IsoInterval)}. </p> */ /*[deutsch] * <p>Siehe {@link IsoInterval#precededBy(IsoInterval)}. </p> */ PRECEDED_BY; private static final IntervalRelation[] VALUES = IntervalRelation.values(); private static final IntervalRelation[] A_AFTER_B = { ENCLOSED_BY, FINISHES, OVERLAPPED_BY, MET_BY, PRECEDED_BY}; private static final IntervalRelation[] EQUAL_START = { STARTS, EQUIVALENT, STARTED_BY}; private static final IntervalRelation[] A_BEFORE_B = { PRECEDES, MEETS, OVERLAPS, FINISHED_BY, ENCLOSES}; //~ Methoden ---------------------------------------------------------- /** * <p>Determines the opposite relation. </p> * * @return opposite relation * @since 2.0 */ /*[deutsch] * <p>Bestimmt die gegenteilige Beziehung. </p> * * @return opposite relation * @since 2.0 */ public IntervalRelation inverse() { return VALUES[12 - this.ordinal()]; } /** * <p>Does this relation match the relation between given intervals? </p> * * @param a first interval * @param b second interval * @return {@code true} if both intervals have this relation to each other * else {@code false} * @since 2.0 */ /*[deutsch] * <p>Passt diese Beziehung zu der zwischen den angegebenen * Intervallen? </p> * * @param a first interval * @param b second interval * @return {@code true} if both intervals have this relation to each other * else {@code false} * @since 2.0 */ public boolean matches( DateInterval a, DateInterval b ) { return this.matches0(a, b); } /** * <p>Does this relation match the relation between given intervals? </p> * * @param a first interval * @param b second interval * @return {@code true} if both intervals have this relation to each other * else {@code false} * @since 2.0 */ /*[deutsch] * <p>Passt diese Beziehung zu der zwischen den angegebenen * Intervallen? </p> * * @param a first interval * @param b second interval * @return {@code true} if both intervals have this relation to each other * else {@code false} * @since 2.0 */ public boolean matches( ClockInterval a, ClockInterval b ) { return this.matches0(a, b); } /** * <p>Does this relation match the relation between given intervals? </p> * * @param a first interval * @param b second interval * @return {@code true} if both intervals have this relation to each other * else {@code false} * @since 2.0 */ /*[deutsch] * <p>Passt diese Beziehung zu der zwischen den angegebenen * Intervallen? </p> * * @param a first interval * @param b second interval * @return {@code true} if both intervals have this relation to each other * else {@code false} * @since 2.0 */ public boolean matches( TimestampInterval a, TimestampInterval b ) { return this.matches0(a, b); } /** * <p>Does this relation match the relation between given intervals? </p> * * @param a first interval * @param b second interval * @return {@code true} if both intervals have this relation to each other * else {@code false} * @since 2.0 */ /*[deutsch] * <p>Passt diese Beziehung zu der zwischen den angegebenen * Intervallen? </p> * * @param a first interval * @param b second interval * @return {@code true} if both intervals have this relation to each other * else {@code false} * @since 2.0 */ public boolean matches( MomentInterval a, MomentInterval b ) { return this.matches0(a, b); } /** * <p>Determines the relation between given intervals. </p> * * @param a first interval * @param b second interval * @return relation between given intervals * @since 2.0 */ /*[deutsch] * <p>Bestimmt die Beziehung zwischen den angegebenen Intervallen. </p> * * @param a first interval * @param b second interval * @return relation between given intervals * @since 2.0 */ public static IntervalRelation between( DateInterval a, DateInterval b ) { return between0(a, b); } /** * <p>Determines the relation between given intervals. </p> * * @param a first interval * @param b second interval * @return relation between given intervals * @since 2.0 */ /*[deutsch] * <p>Bestimmt die Beziehung zwischen den angegebenen Intervallen. </p> * * @param a first interval * @param b second interval * @return relation between given intervals * @since 2.0 */ public static IntervalRelation between( ClockInterval a, ClockInterval b ) { return between0(a, b); } /** * <p>Determines the relation between given intervals. </p> * * @param a first interval * @param b second interval * @return relation between given intervals * @since 2.0 */ /*[deutsch] * <p>Bestimmt die Beziehung zwischen den angegebenen Intervallen. </p> * * @param a first interval * @param b second interval * @return relation between given intervals * @since 2.0 */ public static IntervalRelation between( TimestampInterval a, TimestampInterval b ) { return between0(a, b); } /** * <p>Determines the relation between given intervals. </p> * * @param a first interval * @param b second interval * @return relation between given intervals * @since 2.0 */ /*[deutsch] * <p>Bestimmt die Beziehung zwischen den angegebenen Intervallen. </p> * * @param a first interval * @param b second interval * @return relation between given intervals * @since 2.0 */ public static IntervalRelation between( MomentInterval a, MomentInterval b ) { return between0(a, b); } private <T extends Temporal<? super T>, I extends IsoInterval<T, I>> boolean matches0( I a, I b ) { switch (this) { case PRECEDES: return a.precedes(b); case MEETS: return a.meets(b); case OVERLAPS: return a.overlaps(b); case FINISHES: return a.finishes(b); case STARTS: return a.starts(b); case ENCLOSES: return a.encloses(b); case EQUIVALENT: return a.equivalentTo(b); case ENCLOSED_BY: return a.enclosedBy(b); case STARTED_BY: return a.startedBy(b); case FINISHED_BY: return a.finishedBy(b); case OVERLAPPED_BY: return a.overlappedBy(b); case MET_BY: return a.metBy(b); case PRECEDED_BY: return a.precededBy(b); default: throw new UnsupportedOperationException(this.name()); } } private static <T extends Temporal<? super T>, I extends IsoInterval<T, I>> IntervalRelation between0( I a, I b ) { IntervalRelation[] candidates; T t1 = a.getStart().getTemporal(); T t2 = b.getStart().getTemporal(); if ((t1 != null) && (t2 != null)) { if (t1.isAfter(t2)) { candidates = A_AFTER_B; } else if (t1.isSimultaneous(t2)) { candidates = EQUAL_START; } else { candidates = A_BEFORE_B; } } else if ((t1 == null) && (t2 == null)) { candidates = EQUAL_START; } else if ((t1 == null) && (t2 != null)) { candidates = A_BEFORE_B; } else { candidates = A_AFTER_B; } for (IntervalRelation relation : candidates) { if (relation.matches0(a, b)) { return relation; } } // should never happen! throw new IllegalStateException( "Cannot determine relation between: " + a + " and " + b); } }