srecord noeq RegionToGSI(IImageRegion region) extends Meta { Color color; L ssis; gettable GSI gsi; 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); } IntRange lastRange() { ret isEmpty() ? null : intRange(lastx1(), lastx2()); } // can add this line without breaking coherence? bool canAdd(IntRange r) { ret isEmpty() || intRangesOverlapNempty(r.start, r.end, lastx1()-diag(), lastx2()+diag()); } void add(IntRange r) { if (checkCoherence() && !canAdd(r)) fail("Coherence fail", +lastx1(), +lastx2(), +r); data.add(toShort_enforce(r.start)); data.add(toShort_enforce(r.end)); } } void finishSSI(int iSSI) { growingSSIs.remove(iSSI).finish(); } private GrowingSSI startSSI(int iSSI default l(growingSSIs), IntRange range) { if (scaffoldingEnabled()) printVars("startSSI", +iSSI, +range); var ssi = new GrowingSSI().y1(y); ssi.add(range); ret addAndReturn(growingSSIs, iSSI, ssi); } L lastStreaks() { ret reallyLazyMap(growingSSIs, -> .lastRange()); } int diag() { ret withDiagonals ? 1 : 0; } 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))); // add line to SSI growingSSIs.get(iSSI++).add(streaks.get(iStreak++)); } // remaining SSIs are unpaired, close them while (iSSI < l(growingSSIs)) finishSSI(iSSI); } ret gsi = new GSI(y1, rowStarts, xData); } }