mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-25 21:40:05 +00:00
Rejection details on surface course diagnostics
Valley solver rejections carry the failing measure (required cut, exposed stations, missing head) through the planner diagnostics; the transect probe prints them.
This commit is contained in:
1 parent
8848167c22
commit
13bce7aa42
9 files changed
+77
-39
No files matched your search
@@ -926,7 +926,7 @@ final class HydrologyCaveCourseFilter {
|
|||||||
kind,
|
kind,
|
||||||
type,
|
type,
|
||||||
representative.start(),
|
representative.start(),
|
||||||
rejection
|
rejection, 0
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1035,7 +1035,7 @@ final class HydrologyCaveCourseFilter {
|
|||||||
kind,
|
kind,
|
||||||
type,
|
type,
|
||||||
representative.start(),
|
representative.start(),
|
||||||
HydrologyCandidateRejection.CAVE_CONTAINMENT
|
HydrologyCandidateRejection.CAVE_CONTAINMENT, 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -7,7 +7,8 @@ public record HydrologyDiagnosticCandidate(
|
|||||||
HydrologyCandidateKind kind,
|
HydrologyCandidateKind kind,
|
||||||
HydrologyFeatureType projectedType,
|
HydrologyFeatureType projectedType,
|
||||||
HydrologyPoint point,
|
HydrologyPoint point,
|
||||||
HydrologyCandidateRejection rejection
|
HydrologyCandidateRejection rejection,
|
||||||
|
int detail
|
||||||
) {
|
) {
|
||||||
public HydrologyDiagnosticCandidate {
|
public HydrologyDiagnosticCandidate {
|
||||||
Objects.requireNonNull(kind, "kind");
|
Objects.requireNonNull(kind, "kind");
|
||||||
|
|||||||
@@ -1925,7 +1925,7 @@ public final class HydrologyPlanner {
|
|||||||
HydrologyCandidateKind.OUTLET,
|
HydrologyCandidateKind.OUTLET,
|
||||||
candidate.outlet().type(),
|
candidate.outlet().type(),
|
||||||
candidate.outlet().landwardPoint(),
|
candidate.outlet().landwardPoint(),
|
||||||
HydrologyCandidateRejection.OUTLET_LIMIT
|
HydrologyCandidateRejection.OUTLET_LIMIT, 0
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2007,7 +2007,10 @@ public final class HydrologyPlanner {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Largest rise a surface drainage edge may take: the cut the valley solver will still accept. */
|
/**
|
||||||
|
* Largest rise a surface drainage edge may take. Heads only fall, so a rise along a route becomes a cut
|
||||||
|
* of at least that rise; the lattice may climb no more than the cut the valley solver still accepts.
|
||||||
|
*/
|
||||||
private int maximumSurfaceEdgeRise() {
|
private int maximumSurfaceEdgeRise() {
|
||||||
int permitted = settings.surface().maximumIncision() - settings.surface().banks().inset() - settings.surface().minimumDepth();
|
int permitted = settings.surface().maximumIncision() - settings.surface().banks().inset() - settings.surface().minimumDepth();
|
||||||
return Math.max(1, permitted);
|
return Math.max(1, permitted);
|
||||||
@@ -2522,7 +2525,7 @@ public final class HydrologyPlanner {
|
|||||||
HydrologyCandidateKind.SOURCE,
|
HydrologyCandidateKind.SOURCE,
|
||||||
surface ? HydrologyFeatureType.SURFACE_POOL : HydrologyFeatureType.UNDERGROUND_POOL,
|
surface ? HydrologyFeatureType.SURFACE_POOL : HydrologyFeatureType.UNDERGROUND_POOL,
|
||||||
new HydrologyPoint(node.x(), y, node.z()),
|
new HydrologyPoint(node.x(), y, node.z()),
|
||||||
rejection
|
rejection, 0
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4134,7 +4137,7 @@ public final class HydrologyPlanner {
|
|||||||
.reversed()
|
.reversed()
|
||||||
.thenComparingLong(SurfaceCourseDraft::courseId));
|
.thenComparingLong(SurfaceCourseDraft::courseId));
|
||||||
RiverCourse mainCourse = null;
|
RiverCourse mainCourse = null;
|
||||||
HashMap<Long, HydrologyCandidateRejection> mainRejections = new HashMap<>();
|
HashMap<Long, SurfaceCourseBuild> mainRejections = new HashMap<>();
|
||||||
for (SurfaceCourseDraft draft : outletDrafts) {
|
for (SurfaceCourseDraft draft : outletDrafts) {
|
||||||
SurfaceCourseBuild candidate = buildSurfaceCourse(
|
SurfaceCourseBuild candidate = buildSurfaceCourse(
|
||||||
draft.courseId(),
|
draft.courseId(),
|
||||||
@@ -4143,7 +4146,7 @@ public final class HydrologyPlanner {
|
|||||||
draft.path()
|
draft.path()
|
||||||
);
|
);
|
||||||
if (candidate.course() == null) {
|
if (candidate.course() == null) {
|
||||||
mainRejections.put(draft.courseId(), candidate.rejection());
|
mainRejections.put(draft.courseId(), candidate);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mainCourse = candidate.course();
|
mainCourse = candidate.course();
|
||||||
@@ -4152,11 +4155,13 @@ public final class HydrologyPlanner {
|
|||||||
}
|
}
|
||||||
if (mainCourse == null) {
|
if (mainCourse == null) {
|
||||||
for (SurfaceCourseDraft draft : outletDrafts) {
|
for (SurfaceCourseDraft draft : outletDrafts) {
|
||||||
|
SurfaceCourseBuild rejected = mainRejections.get(draft.courseId());
|
||||||
addCompiledSourceDiagnostic(
|
addCompiledSourceDiagnostic(
|
||||||
draft.source(),
|
draft.source(),
|
||||||
true,
|
true,
|
||||||
draft.courseId(),
|
draft.courseId(),
|
||||||
mainRejections.get(draft.courseId()),
|
rejected.rejection(),
|
||||||
|
rejected.rejectionDetail(),
|
||||||
diagnostics
|
diagnostics
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -4180,7 +4185,7 @@ public final class HydrologyPlanner {
|
|||||||
CoursePath path
|
CoursePath path
|
||||||
) {
|
) {
|
||||||
if (path.points().size() < 2) {
|
if (path.points().size() < 2) {
|
||||||
return SurfaceCourseBuild.rejected(HydrologyCandidateRejection.COURSE_TOO_SHORT);
|
return SurfaceCourseBuild.rejected(HydrologyCandidateRejection.COURSE_TOO_SHORT, 0);
|
||||||
}
|
}
|
||||||
RiverOutlet outlet = path.outlet();
|
RiverOutlet outlet = path.outlet();
|
||||||
boolean surfaceSinkhole = path.reachesOutlet() && surfaceSinkhole(outlet);
|
boolean surfaceSinkhole = path.reachesOutlet() && surfaceSinkhole(outlet);
|
||||||
@@ -4203,7 +4208,7 @@ public final class HydrologyPlanner {
|
|||||||
terminalHead
|
terminalHead
|
||||||
);
|
);
|
||||||
if (!result.accepted()) {
|
if (!result.accepted()) {
|
||||||
return SurfaceCourseBuild.rejected(result.rejection());
|
return SurfaceCourseBuild.rejected(result.rejection(), result.rejectionDetail());
|
||||||
}
|
}
|
||||||
ArrayList<HydraulicSegment> segments = new ArrayList<>(result.segments());
|
ArrayList<HydraulicSegment> segments = new ArrayList<>(result.segments());
|
||||||
if (path.reachesOutlet()) {
|
if (path.reachesOutlet()) {
|
||||||
@@ -4226,7 +4231,7 @@ public final class HydrologyPlanner {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (path.organicSurfaceRequired() && !surfaceShapeAccepted(path.points())) {
|
if (path.organicSurfaceRequired() && !surfaceShapeAccepted(path.points())) {
|
||||||
return SurfaceCourseBuild.rejected(HydrologyCandidateRejection.SURFACE_SHAPE_UNSUPPORTED);
|
return SurfaceCourseBuild.rejected(HydrologyCandidateRejection.SURFACE_SHAPE_UNSUPPORTED, 0);
|
||||||
}
|
}
|
||||||
int discharge = maximumSurfaceDischarge(path.edges());
|
int discharge = maximumSurfaceDischarge(path.edges());
|
||||||
return SurfaceCourseBuild.accepted(new RiverCourse(
|
return SurfaceCourseBuild.accepted(new RiverCourse(
|
||||||
@@ -4458,6 +4463,17 @@ public final class HydrologyPlanner {
|
|||||||
long courseId,
|
long courseId,
|
||||||
HydrologyCandidateRejection rejection,
|
HydrologyCandidateRejection rejection,
|
||||||
List<HydrologyDiagnosticCandidate> diagnostics
|
List<HydrologyDiagnosticCandidate> diagnostics
|
||||||
|
) {
|
||||||
|
addCompiledSourceDiagnostic(source, surface, courseId, rejection, 0, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCompiledSourceDiagnostic(
|
||||||
|
GridNode source,
|
||||||
|
boolean surface,
|
||||||
|
long courseId,
|
||||||
|
HydrologyCandidateRejection rejection,
|
||||||
|
int detail,
|
||||||
|
List<HydrologyDiagnosticCandidate> diagnostics
|
||||||
) {
|
) {
|
||||||
int y = surface ? source.terrain().naturalHeight() : source.terrain().caveFluidY();
|
int y = surface ? source.terrain().naturalHeight() : source.terrain().caveFluidY();
|
||||||
diagnostics.add(new HydrologyDiagnosticCandidate(
|
diagnostics.add(new HydrologyDiagnosticCandidate(
|
||||||
@@ -4465,7 +4481,8 @@ public final class HydrologyPlanner {
|
|||||||
HydrologyCandidateKind.SOURCE,
|
HydrologyCandidateKind.SOURCE,
|
||||||
surface ? HydrologyFeatureType.SURFACE_POOL : HydrologyFeatureType.UNDERGROUND_POOL,
|
surface ? HydrologyFeatureType.SURFACE_POOL : HydrologyFeatureType.UNDERGROUND_POOL,
|
||||||
new HydrologyPoint(source.x(), y, source.z()),
|
new HydrologyPoint(source.x(), y, source.z()),
|
||||||
rejection
|
rejection,
|
||||||
|
detail
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6244,7 +6261,7 @@ public final class HydrologyPlanner {
|
|||||||
HydrologyCandidateKind.DEEP_FLUID,
|
HydrologyCandidateKind.DEEP_FLUID,
|
||||||
deepFluid.containedPools() ? HydrologyFeatureType.DEEP_POOL : HydrologyFeatureType.DEEP_CHANNEL,
|
deepFluid.containedPools() ? HydrologyFeatureType.DEEP_POOL : HydrologyFeatureType.DEEP_CHANNEL,
|
||||||
new HydrologyPoint(site.x(), site.head(), site.z()),
|
new HydrologyPoint(site.x(), site.head(), site.z()),
|
||||||
rejection
|
rejection, 0
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7259,7 +7276,7 @@ public final class HydrologyPlanner {
|
|||||||
HydrologyCandidateKind.SOURCE,
|
HydrologyCandidateKind.SOURCE,
|
||||||
HydrologyFeatureType.SURFACE_POOL,
|
HydrologyFeatureType.SURFACE_POOL,
|
||||||
representative.start(),
|
representative.start(),
|
||||||
HydrologyCandidateRejection.SOURCE_SPACING
|
HydrologyCandidateRejection.SOURCE_SPACING, 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7385,7 +7402,8 @@ public final class HydrologyPlanner {
|
|||||||
|
|
||||||
private record SurfaceCourseBuild(
|
private record SurfaceCourseBuild(
|
||||||
RiverCourse course,
|
RiverCourse course,
|
||||||
HydrologyCandidateRejection rejection
|
HydrologyCandidateRejection rejection,
|
||||||
|
int rejectionDetail
|
||||||
) {
|
) {
|
||||||
private SurfaceCourseBuild {
|
private SurfaceCourseBuild {
|
||||||
if ((course == null) == (rejection == null)) {
|
if ((course == null) == (rejection == null)) {
|
||||||
@@ -7394,11 +7412,11 @@ public final class HydrologyPlanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static SurfaceCourseBuild accepted(RiverCourse course) {
|
private static SurfaceCourseBuild accepted(RiverCourse course) {
|
||||||
return new SurfaceCourseBuild(Objects.requireNonNull(course, "course"), null);
|
return new SurfaceCourseBuild(Objects.requireNonNull(course, "course"), null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SurfaceCourseBuild rejected(HydrologyCandidateRejection rejection) {
|
private static SurfaceCourseBuild rejected(HydrologyCandidateRejection rejection, int detail) {
|
||||||
return new SurfaceCourseBuild(null, Objects.requireNonNull(rejection, "rejection"));
|
return new SurfaceCourseBuild(null, Objects.requireNonNull(rejection, "rejection"), detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -46,7 +46,7 @@ public final class SurfaceCourseBuilder {
|
|||||||
ValleyProfile valley = new ValleyProfileSolver(surface, sampler, seaLevel, minimumCourseLength)
|
ValleyProfile valley = new ValleyProfileSolver(surface, sampler, seaLevel, minimumCourseLength)
|
||||||
.solve(centerline, channel, terminal, terminalHead);
|
.solve(centerline, channel, terminal, terminalHead);
|
||||||
if (!valley.accepted()) {
|
if (!valley.accepted()) {
|
||||||
return SurfaceCourseResult.rejected(valley.rejection());
|
return SurfaceCourseResult.rejected(valley.rejection(), valley.rejectionDetail());
|
||||||
}
|
}
|
||||||
int exposed = valley.exposedStations();
|
int exposed = valley.exposedStations();
|
||||||
boolean coastalDrop = directOcean && valley.head()[exposed - 1] > seaLevel;
|
boolean coastalDrop = directOcean && valley.head()[exposed - 1] > seaLevel;
|
||||||
@@ -82,7 +82,7 @@ public final class SurfaceCourseBuilder {
|
|||||||
List<HydraulicSegment> segments = SurfaceSegmentLabeler.label(
|
List<HydraulicSegment> segments = SurfaceSegmentLabeler.label(
|
||||||
worldSeed, courseId, x, z, head, width, depth, surface.banks());
|
worldSeed, courseId, x, z, head, width, depth, surface.banks());
|
||||||
if (segments.isEmpty()) {
|
if (segments.isEmpty()) {
|
||||||
return SurfaceCourseResult.rejected(HydrologyCandidateRejection.COURSE_TOO_SHORT);
|
return SurfaceCourseResult.rejected(HydrologyCandidateRejection.COURSE_TOO_SHORT, stations);
|
||||||
}
|
}
|
||||||
HydraulicSegment last = segments.getLast();
|
HydraulicSegment last = segments.getLast();
|
||||||
int lastStation = stations - 1;
|
int lastStation = stations - 1;
|
||||||
@@ -92,7 +92,8 @@ public final class SurfaceCourseBuilder {
|
|||||||
last.width(),
|
last.width(),
|
||||||
last.depth(),
|
last.depth(),
|
||||||
new HydrologyPoint(x[lastStation], head[lastStation], z[lastStation]),
|
new HydrologyPoint(x[lastStation], head[lastStation], z[lastStation]),
|
||||||
null
|
null,
|
||||||
|
0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+4
-3
@@ -13,7 +13,8 @@ public record SurfaceCourseResult(
|
|||||||
int lastWidth,
|
int lastWidth,
|
||||||
int lastDepth,
|
int lastDepth,
|
||||||
HydrologyPoint pathEnd,
|
HydrologyPoint pathEnd,
|
||||||
HydrologyCandidateRejection rejection
|
HydrologyCandidateRejection rejection,
|
||||||
|
int rejectionDetail
|
||||||
) {
|
) {
|
||||||
public SurfaceCourseResult {
|
public SurfaceCourseResult {
|
||||||
segments = List.copyOf(Objects.requireNonNull(segments, "segments"));
|
segments = List.copyOf(Objects.requireNonNull(segments, "segments"));
|
||||||
@@ -23,7 +24,7 @@ public record SurfaceCourseResult(
|
|||||||
return rejection == null;
|
return rejection == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SurfaceCourseResult rejected(HydrologyCandidateRejection rejection) {
|
public static SurfaceCourseResult rejected(HydrologyCandidateRejection rejection, int detail) {
|
||||||
return new SurfaceCourseResult(List.of(), 0, 0, 0, null, Objects.requireNonNull(rejection, "rejection"));
|
return new SurfaceCourseResult(List.of(), 0, 0, 0, null, Objects.requireNonNull(rejection, "rejection"), detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,17 +8,19 @@ public record ValleyProfile(
|
|||||||
int[] crossMax,
|
int[] crossMax,
|
||||||
int[] centerNatural,
|
int[] centerNatural,
|
||||||
int exposedStations,
|
int exposedStations,
|
||||||
HydrologyCandidateRejection rejection
|
HydrologyCandidateRejection rejection,
|
||||||
|
int rejectionDetail
|
||||||
) {
|
) {
|
||||||
public boolean accepted() {
|
public boolean accepted() {
|
||||||
return rejection == null;
|
return rejection == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ValleyProfile fromHeads(int[] head, int exposedStations) {
|
public static ValleyProfile fromHeads(int[] head, int exposedStations) {
|
||||||
return new ValleyProfile(head, new int[0], new int[0], new int[0], exposedStations, null);
|
return new ValleyProfile(head, new int[0], new int[0], new int[0], exposedStations, null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ValleyProfile rejected(HydrologyCandidateRejection rejection) {
|
/** {@code detail} names the measure that failed: exposed stations, required cut, or missing head. */
|
||||||
return new ValleyProfile(new int[0], new int[0], new int[0], new int[0], 0, rejection);
|
public static ValleyProfile rejected(HydrologyCandidateRejection rejection, int detail) {
|
||||||
|
return new ValleyProfile(new int[0], new int[0], new int[0], new int[0], 0, rejection, detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+13
-8
@@ -79,10 +79,10 @@ public final class ValleyProfileSolver {
|
|||||||
crossMax[station] = maximum;
|
crossMax[station] = maximum;
|
||||||
}
|
}
|
||||||
if (exposed < 2 || exposed < minimumCourseLength) {
|
if (exposed < 2 || exposed < minimumCourseLength) {
|
||||||
return ValleyProfile.rejected(HydrologyCandidateRejection.COURSE_TOO_SHORT);
|
return ValleyProfile.rejected(HydrologyCandidateRejection.COURSE_TOO_SHORT, exposed);
|
||||||
}
|
}
|
||||||
if (exposed < count && terminal != SurfaceTerminal.OCEAN_MOUTH) {
|
if (exposed < count && terminal != SurfaceTerminal.OCEAN_MOUTH) {
|
||||||
return ValleyProfile.rejected(HydrologyCandidateRejection.SURFACE_EXPOSURE);
|
return ValleyProfile.rejected(HydrologyCandidateRejection.SURFACE_EXPOSURE, exposed);
|
||||||
}
|
}
|
||||||
int inset = surface.banks().inset();
|
int inset = surface.banks().inset();
|
||||||
int[] head = new int[count];
|
int[] head = new int[count];
|
||||||
@@ -101,19 +101,24 @@ public final class ValleyProfileSolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (terminal == SurfaceTerminal.SINKHOLE && head[exposed - 1] < terminalHead) {
|
if (terminal == SurfaceTerminal.SINKHOLE && head[exposed - 1] < terminalHead) {
|
||||||
return ValleyProfile.rejected(HydrologyCandidateRejection.SURFACE_SINKHOLE_CLEARANCE);
|
return ValleyProfile.rejected(HydrologyCandidateRejection.SURFACE_SINKHOLE_CLEARANCE, terminalHead - head[exposed - 1]);
|
||||||
}
|
}
|
||||||
if (terminal == SurfaceTerminal.COASTAL_GROTTO && head[exposed - 1] < terminalHead) {
|
if (terminal == SurfaceTerminal.COASTAL_GROTTO && head[exposed - 1] < terminalHead) {
|
||||||
return ValleyProfile.rejected(HydrologyCandidateRejection.SURFACE_HEAD_RANGE);
|
return ValleyProfile.rejected(HydrologyCandidateRejection.SURFACE_HEAD_RANGE, terminalHead - head[exposed - 1]);
|
||||||
}
|
}
|
||||||
int maximumIncision = surface.maximumIncision();
|
int maximumIncision = surface.maximumIncision();
|
||||||
|
int deepestCut = 0;
|
||||||
|
boolean rejected = false;
|
||||||
for (int station = 0; station < exposed; station++) {
|
for (int station = 0; station < exposed; station++) {
|
||||||
int permitted = Math.min(maximumIncision, (int) StrictMath.floor(maximumIncision * incisionMultiplier[station]));
|
int permitted = Math.min(maximumIncision, (int) StrictMath.floor(maximumIncision * incisionMultiplier[station]));
|
||||||
int bed = head[station] - (int) StrictMath.round(channel.depth()[station]);
|
int bed = head[station] - (int) StrictMath.round(channel.depth()[station]);
|
||||||
if (centerNatural[station] - bed > permitted) {
|
int cut = centerNatural[station] - bed;
|
||||||
return ValleyProfile.rejected(HydrologyCandidateRejection.SURFACE_CORRIDOR_UNSUPPORTED);
|
deepestCut = Math.max(deepestCut, cut);
|
||||||
}
|
rejected |= cut > permitted;
|
||||||
}
|
}
|
||||||
return new ValleyProfile(head, crossMin, crossMax, centerNatural, exposed, null);
|
if (rejected) {
|
||||||
|
return ValleyProfile.rejected(HydrologyCandidateRejection.SURFACE_CORRIDOR_UNSUPPORTED, deepestCut);
|
||||||
|
}
|
||||||
|
return new ValleyProfile(head, crossMin, crossMax, centerNatural, exposed, null, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -143,7 +143,7 @@ public class IrisRendererRiverTest {
|
|||||||
HydrologyCandidateKind.SOURCE,
|
HydrologyCandidateKind.SOURCE,
|
||||||
HydrologyFeatureType.SURFACE_POOL,
|
HydrologyFeatureType.SURFACE_POOL,
|
||||||
new HydrologyPoint(0, 80, 0),
|
new HydrologyPoint(0, 80, 0),
|
||||||
HydrologyCandidateRejection.NO_LEGAL_OUTLET
|
HydrologyCandidateRejection.NO_LEGAL_OUTLET, 0
|
||||||
);
|
);
|
||||||
when(engine.getComplex()).thenReturn(complex);
|
when(engine.getComplex()).thenReturn(complex);
|
||||||
when(complex.getHydrologyRuntime()).thenReturn(runtime);
|
when(complex.getHydrologyRuntime()).thenReturn(runtime);
|
||||||
|
|||||||
@@ -219,13 +219,23 @@ public final class RiverTransectProbe {
|
|||||||
|
|
||||||
static List<String> rejectionLines(HydrologyTile tile) {
|
static List<String> rejectionLines(HydrologyTile tile) {
|
||||||
TreeMap<String, Integer> counts = new TreeMap<>();
|
TreeMap<String, Integer> counts = new TreeMap<>();
|
||||||
|
TreeMap<String, ArrayList<Integer>> details = new TreeMap<>();
|
||||||
for (HydrologyDiagnosticCandidate candidate : tile.diagnosticCandidates()) {
|
for (HydrologyDiagnosticCandidate candidate : tile.diagnosticCandidates()) {
|
||||||
String key = "rejected " + candidate.kind() + " " + candidate.projectedType() + " " + candidate.rejection();
|
String key = "rejected " + candidate.kind() + " " + candidate.projectedType() + " " + candidate.rejection();
|
||||||
counts.merge(key, 1, Integer::sum);
|
counts.merge(key, 1, Integer::sum);
|
||||||
|
if (candidate.detail() != 0) {
|
||||||
|
details.computeIfAbsent(key, (String ignored) -> new ArrayList<>()).add(candidate.detail());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ArrayList<String> lines = new ArrayList<>(counts.size());
|
ArrayList<String> lines = new ArrayList<>(counts.size());
|
||||||
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
|
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
|
||||||
lines.add(entry.getKey() + " x" + entry.getValue());
|
ArrayList<Integer> values = details.get(entry.getKey());
|
||||||
|
String suffix = "";
|
||||||
|
if (values != null) {
|
||||||
|
values.sort(null);
|
||||||
|
suffix = " detail=" + values.subList(0, Math.min(values.size(), 24));
|
||||||
|
}
|
||||||
|
lines.add(entry.getKey() + " x" + entry.getValue() + suffix);
|
||||||
}
|
}
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user