srecord noeq G22MeshMapper_v2(G22Mesh mesh1, G22Mesh mesh2) { // import the important classes delegate Anchor, Curve to G22Mesh. delegate mapAnchor, unmapAnchor, tempMapAnchor to mm. // params settable bool chooseAnchor1AtRandom; // output G22MeshMapping mm; // index structures MultiMap anchorsByArity2; // EXCEPTIONS (e.g. meshes don't match in signature) // set to the reason why when a mapping is deemed impossible settable O rejectedBecause; bool rejected() { ret rejectedBecause != null; } // INTERNAL VARS bool prechecksDone; S sig1, sig2; Anchor anchor1; // first anchor to map G22MeshMapping get() { ret mm; } // Do the whole search, but in "random" mode (may fail) void run_random { search_step1(); while (search_step2()); } // random mode void search_step1() { prechecks(); if (rejected()) ret; // make empty mapping mm = new G22MeshMapping(mesh1, mesh2); anchorsByArity2 = multiMapIndex(mesh2.anchors(), a -> a.arity()); // Choose first anchor to map - this is arbitrary // (not a backtracking point) Anchor anchor1 = chooseAnchor1AtRandom ? random(mesh1.anchors()) : first(mesh1.anchors()); // Choose which anchor to map it to // (first backtracking point) L options = anchorsByArity2.get(anchor1.arity()); // ret BacktrackingOptions(options, ...); ??? Anchor anchor2 = random(options); print("G22MeshMapper_v2 step1: Connecting " + anchor1 + " to " + anchor2); mapAnchor(anchor1, anchor2); } // random mode bool search_step2() { bool change; for (curve1 : mesh1.curves()) { // skip if curve is already mapped if (mm.isMapped(curve1)) continue; // with print("Curve is mapped: " + curve1); print("Looking to match " + curve1); // check if anchors are mapped Anchor start2 = mm.get(curve1.start); Anchor end2 = mm.get(curve1.end); // If neither anchor is mapped, postpone this curve if (start2 == null && end2 == null) continue; // with print("Curve is not discovered yet: " + curve1); // Start at the mapped anchor, choose a viable curve in mesh2 to map to bool startAtEnd = end2 != null; Anchor a1 = curve1.anchor(startAtEnd); Anchor a1other = curve1.anchor(!startAtEnd); Anchor a2 = mm.get(curve1.anchor(startAtEnd)); print(+a1); print(+a2); print(+a1other); new L possibleCurves; for (c2 : a2.curves()) { if (mm.isMapped(c2)) continue; // with print("Curve already mapped: " + c2); // check for arity match Anchor a3 = c2.anchorOpposite(a2); print(+a3); int arity1 = a3.arity(), arity2 = a1other.arity(); if (arity1 != arity2) continue with print("Arity mismatch (" + arity1 + "/" + arity2 + ") for curve " + c2); // This curve is viable as a mapping target possibleCurves.add(c2); } print(l(possibleCurves) + "/" + l(a2.curves()) + " possible curve(s) to map " + curve1 + " to:"); pnl(possibleCurves); if (empty(possibleCurves)) ret false with rejectedBecause("Could not map curve " + curve1); // Map the curve Curve c2 = random(possibleCurves); bool flipped = c2.start() != a2; print("Mapping curve " + curve1 + " to " + c2); mm.mapCurve(curve1, c2, flipped); set change; } ret change; } Search newSearch() { ret new Search; } // backtracking version class Search extends VStackComputableWithStep is IMakeEmptyClone { Anchor anchor2; public selfType makeEmptyClone() { ret new selfType; } void step(VStack stack) { cast stack to BStack; if (step == 0) { prechecks(); if (rejected()) stack.ret(); step = 1; } else if (step == 1) { // make empty mapping mm = new G22MeshMapping(mesh1, mesh2); anchorsByArity2 = multiMapIndex(mesh2.anchors(), a -> a.arity()); // Choose first anchor to map - this is arbitrary // (not a backtracking point) anchor1 = chooseAnchor1AtRandom ? random(mesh1.anchors()) : first(mesh1.anchors()); // Choose which anchor to map it to (first backtracking point). // List should never be empty because we checked the signatures first. L anchor2options = anchorsByArity2.get(anchor1.arity()); step = 2; stack.options(this, map(anchor2options, anchor2 -> instance -> instance.anchor2 = anchor2)); } else if (step == 2) { print("G22MeshMapper_v2 step1: Connecting " + anchor1 + " to " + anchor2); stack.temp(tempMapAnchor(anchor1, anchor2)); step = 3; } else if (step == 3) { stack.call(new Step2); step = 4; } else { if (isTrue(stack.subResult())) step = 3; else stack.return(); } } } class Step2 extends VStackComputableWithStep is IMakeEmptyClone { bool change; Iterator curve1iterator; Curve curve1, c2; Anchor a2; public selfType makeEmptyClone() { ret new selfType; } void step(VStack stack) { cast stack to BStack; if (step == 0) { curve1iterator = iterator(mesh1.curves()); step++; } else if (step == 1) { if (!curve1iterator.hasNext()) ret with stack.return(change); curve1 = curve1iterator.next(); print("Looking to match " + curve1); // skip if curve is already mapped if (mm.isMapped(curve1)) { print("Curve is mapped: " + curve1); ret; // continue loop } // check if anchors are mapped Anchor start2 = mm.get(curve1.start); Anchor end2 = mm.get(curve1.end); // If neither anchor is mapped, postpone this curve if (start2 == null && end2 == null) { //print("Curve is not discovered yet: " + curve1); ret; // continue loop; } // Start at the mapped anchor, choose a viable curve in mesh2 to map to bool startAtEnd = end2 != null; Anchor a1 = curve1.anchor(startAtEnd); Anchor a1other = curve1.anchor(!startAtEnd); a2 = mm.get(curve1.anchor(startAtEnd)); print(+a1); print(+a2); print(+a1other); new L possibleCurves; for (c2 : a2.curves()) { if (mm.isMapped(c2)) { //print("Curve already mapped: " + c2); continue; // continue loop } // check for arity match Anchor a3 = c2.anchorOpposite(a2); print(+a3); int arity1 = a3.arity(), arity2 = a1other.arity(); if (arity1 != arity2) { print("Arity mismatch (" + arity1 + "/" + arity2 + ") for curve " + c2); continue; // continue loop } // This curve is viable as a mapping target possibleCurves.add(c2); print("Possible curve!"); } print(l(possibleCurves) + "/" + l(a2.curves()) + " possible curve(s) to map " + curve1 + " to: "); pnl(possibleCurves); if (empty(possibleCurves)) { stack.temp(tempRejectedBecause("Could not map curve " + curve1)); ret with stack.ret(false); } // Go through all curve mappings step = 2; stack.options(this, map(possibleCurves, c2 -> instance -> instance.c2 = c2)); ret; } else { bool flipped = c2.start() != a2; print("Mapping curve " + curve1 + " to " + c2); stack.temp(mm.tempMapCurve(curve1, c2, flipped)); set change; // continue loop step = 1; } } } protected void prechecks { set prechecksDone; sig1 = mesh1.signature(); sig2 = mesh1.signature(); if (!eq(sig1, sig2)) ret with rejectedBecause(G22SignatureMismatch(mesh1, mesh2)); } AutoCloseable tempRejectedBecause(O reason) { rejectedBecause(reason); ret -> rejectedBecause(null); } }