// A "mesh" is a set of points ("anchors") connected through curves.
// An anchor is either
// -the end of a curve
// -an intersection of curves
// -or a randomly chosen point along a curve (type 3)
// A type 3 anchor can be necessary to define an "o" shape
// (because such a shape doesn't have an anchor point per se,
// so we just choose one point along the ring).
// Sometimes however, a type 3 anchor is an artifact of the mesh
// finding process and can be eliminated, reducing the anchor and
// curve count by 1.
srecord noeq G22SkeletonToMesh
(IImageRegion
region) is Steppable {
new Map anchors; // in pseudo-random order (HashSet order)
new L curves; // also in no particular order
sclass Curve {
Anchor start, end;
OnePathWithOrigin path; // origin = start.pt
}
sclass Anchor {
Pt pt;
L curvesStartingHere;
}
// TEMPORARY DATA
ItIt regionIterator;
new L queue;
new CompactLongSet points;
// directionToExplore is a onePathDirection (1 to 8)
srecord noeq WorkItem(Anchor anchor, int directionToExplore) {}
public bool step() {
if (regionIterator == null)
regionIterator = region.pixelIterator();
if (nempty(queue))
set initialized;
Pt p = region.firstPixel();
if (p == null) false;
queue.add(pair(null, p));
}
if (regionIterator.hasNext()) {
Pt p = regionIterator.next();
if (empty(queue)) false;
Pair pair = popFirst(queue);
Pt prev = pair.a, p = pair.b;
Pt mapped = lookupOrKeep(ptMap, p);
bool seen = ptMap.containsKey(p);
Pt mapTo = p;
if (prev != null) {
if (distantEnough(prev, mapped))
foundLink(prev, mapped);
else
mapTo = prev;
}
if (!seen) {
ptMap.put(p, mapTo);
Pt linkFrom = mapTo;
for (int dir = 1; dir <= 8; dir++) {
Pt p2 = ptPlus(p, onePathDirection(dir));
if (region.contains(p2))
queue.add(pair(linkFrom, p2));
}
}
true;
}
bool distantEnough(Pt a, Pt b) {
ret a != null && b != null
&& (absDiff(a.x, b.x) >= minDist || absDiff(a.y, b.y) >= minDist);
}
}