srecord noeq G22_RegionToSSIs_v2(IImageRegion region) extends Meta { RGB color; L ssis; new L growingSSIs; settable bool withDiagonals; // TODO private int x1, y; class GrowingSSI { settable int y1; new ShortBuffer data; int y2() { ret y1+l(data)/2; } SSI finish() { ret addAndReturn(ssis, new SSI(y1, y2()).data(data.toArray()) .color(color)); } bool isEmpty() { ret data.isEmpty(); } int lastx1() { ret data.get(l(data)-2); } int lastx2() { ret data.get(l(data)-1); } void add(int x1, int x2) { data.add(toShort_enforce(x1)); data.add(toShort_enforce(x2)); } } void finishSSI(int iSSI) { growingSSIs.remove(iSSI).finish(); } private GrowingSSI startSSI(int iSSI default l(growingSSIs), IntRange range) { var ssi = new GrowingSSI().y1(y); ssi.add(range.start, range.end); ret addAndReturn(growingSSIs, iSSI, ssi); } L get() { if (region == null) null; color = region.color(); ssis = new L; Rect r = region.bounds(); int x1 = this.x1 = r.x1(), y1 = r.y1(), y2 = r.y2(), h = y2-y1, w = r.w; bool scaff = scaffoldingEnabled(); for (y = y1; y < y2; y++) { reMutable y; L streaks = shiftIntRanges(x1, genericStreaks(w, x -> region.contains(x1+x, y))); // advance iSSI & iStreak simultaneously int iStreak = 0, iSSI = 0; int nStreaks = l(streaks); while ping (iStreak < nStreaks) { if (scaff) printVars(+y, +iStreak, +iSSI); var range = streaks.get(iStreak); var ssi = _get(growingSSIs, iSSI); // distinctly left of current SSI? // (or to the right of everything) if (ssi == null || range.end < ssi.lastx1()) { startSSI(iSSI, range); ++iStreak; if (scaff) printVars("Inserted SSI"); continue; } // Now we know that we have another SSI. // Find the rightmost streak still under the current SSI int jStreak = iStreak+1; while (jStreak < nStreaks && streaks.get(jStreak).start < ssi.lastx2()) ++jStreak; range = streaks.get(jStreak-1); // Check if we have to merge with right neighbor(s) int jSSI = iSSI+1; while (jSSI < l(growingSSIs) && range.end > growingSSIs.get(jSSI).lastx1()) ++jSSI; int nSSI = jSSI-iSSI, nStreak = jStreak-iStreak; if (scaff) printVars(+jStreak, +jSSI, +nSSI, +nStreak, +nStreaks, nSSIs := l(growingSSIs)); // Now we go from [iSSI;jSSI) to [iStreak;jStreak) // The only case without structural changes is when // nSSI = nStreak = 1. Then we just add the line. if (nSSI == 1 && nStreak == 1) { ssi.add(x1+range.start, x1+range.end); iSSI = jSSI; iStreak = jStreak; continue; } // Any kind of structural change means end all involved // SSIs and start new ones. while (jSSI-- > iSSI) finishSSI(iSSI); while (iStreak < jStreak) startSSI(streaks.get(iStreak++)); } // end SSIs to the right of all streaks while (iSSI < l(growingSSIs)) finishSSI(iSSI); } for (ssi : cloneAndClear(growingSSIs)) ssi.finish(); ret ssis; } }