// 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); } }