in endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/ExtentSelector.java [416:523]
public void evaluate(final GeographicBoundingBox bbox, final Temporal startTime, final Temporal endTime, final T object) {
/*
* Get the geographic and temporal intersections. If there is no intersection, no more analysis is done.
* Note that the intersection is allowed to be zero (empty), which is not the same as no intersection.
* An empty intersection may happen if the AOI is a single point or the TOI is a single instant.
*/
Temporal tmin = startTime;
Temporal tmax = endTime;
if (tmin != null && minTOI != null && TemporalDate.compare(tmin, minTOI) < 0) tmin = minTOI;
if (tmax != null && maxTOI != null && TemporalDate.compare(tmax, maxTOI) > 0) tmax = maxTOI;
final Duration duration;
if (tmin != null && tmax != null) {
duration = Duration.between(tmin, tmax);
if (duration.isNegative()) return;
} else {
duration = null;
}
final double area = Extents.area(Extents.intersection(bbox, areaOfInterest));
if (Double.isNaN(area) && bbox != null) {
return;
}
/*
* Accept the given object if it is the first one (`best == null`) or if it meets the first
* criterion documented in class javadoc (i.e. covers a longer time than previous object).
* Other special cases:
*
* - duration == null while old value has a duration: reject (with comparison < 0).
* - duration != null while old value had no duration: accept (with comparison > 0).
*
* Those special cases are controlled by the +1 or -1 argument in calls to `compare(…)`.
* The same pattern is applied for all criteria in inner conditions, using one of:
*
* comparison(…, -1) <= 0
* comparison(…, +1) >= 0
*
* The criteria are always tested as below:
*
* if ((comparison = comparison(…, ±1)) ⪌ 0) {
* if (comparison != 0) return;
* // Compute and test criteria.
* }
*/
final Duration durationRounded = round(duration);
int comparison, remainingFieldsToCompute = OVERTIME;
if (best != null && (comparison = compare(durationRounded, longestTime, -1)) <= 0) {
if (comparison != 0) return;
/*
* Criterion #2: select the object having smallest amount of time outside Time Of Interest (TOI).
* See class javadoc for a rational about why this criterion is applied before `temporalDistance`.
*/
remainingFieldsToCompute = TEMPORAL_DISTANCE;
final Duration et = overtime(startTime, endTime, duration);
if ((comparison = compare(et, overtime, +1)) >= 0) {
if (comparison != 0) return;
/*
* Criterion #3: select the object having median time closest to TOI median time.
* This condition is skipped in the "alternate condition ordering" mode.
*/
remainingFieldsToCompute = OUTSIDE_AREA;
final double td = temporalDistance(startTime, endTime);
if (alternateOrdering || (comparison = compare(td, temporalDistance, +1)) >= 0) {
if (comparison != 0) return;
/*
* Criterion #4: select the object covering largest geographic area.
*/
if ((comparison = compare(area, largestArea, -1)) <= 0) {
if (comparison != 0) return;
/*
* Criterion #5: select the object having less surface outside Area Of Interest (AOI).
* Tested before `pseudoDistance` criterion for consistency with temporal domain.
*/
remainingFieldsToCompute = PSEUDO_DISTANCE;
final double out = Extents.area(bbox) - area;
if ((comparison = compare(out, outsideArea, +1)) >= 0) {
if (comparison != 0) return;
/*
* Criterion #5: select the object having center closest to AOI center.
* Distances are computed with inexact formulas (not a real distance).
* TOI is also compared here in "alternate condition ordering" mode.
*/
remainingFieldsToCompute = NONE;
final double pd = pseudoDistance(bbox);
if (compare(pd, pseudoDistance, +1) >= 0) {
if (comparison != 0 || !alternateOrdering) return;
}
if (alternateOrdering && compare(td, temporalDistance, +1) >= 0) {
return;
}
pseudoDistance = pd;
}
outsideArea = out;
}
// largestArea = area; assigned below because was computed early.
}
temporalDistance = td;
}
overtime = et;
}
longestTime = durationRounded;
largestArea = area;
switch (remainingFieldsToCompute) { // Intentional fallthrough in every cases.
case OVERTIME: overtime = overtime(startTime, endTime, duration);
case TEMPORAL_DISTANCE: temporalDistance = temporalDistance(startTime, endTime);
case OUTSIDE_AREA: outsideArea = Extents.area(bbox) - area;
case PSEUDO_DISTANCE: pseudoDistance = pseudoDistance(bbox);
}
best = object;
}