Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

261
LINES

< > BotCompany Repo | #1035369 // G22MeshMapper_v2 - tries to map mesh1 to mesh2 [dev.]

JavaX fragment (include) [tags: use-pretranspiled]

Transpiled version (25187L) is out of date.

srecord noeq G22MeshMapper_v2(G22Mesh mesh1, G22Mesh mesh2) {
  // import the important classes
  delegate Anchor, Curve to G22Mesh.
  delegate mapAnchor, unmapAnchor, tempMapAnchor to mm.
  delegate MappedCurve to G22MeshMapping.
  
  // params
  
  settable bool chooseAnchor1AtRandom;
  
  // output
  
  G22MeshMapping mm;
  settable L debugOutput;
  
  // for visualization
  settable float contrast = 0.25f;
  settable int brightness = 128;
  
  // index structures
  
  MultiMap<Int, Anchor> 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; }
  
  Search newSearch() {
    ret new Search;
  }
  
  // backtracking version
  class Search extends VStackComputableWithStep<Void> 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<Anchor> 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);
        add(debugOutput, "Mapping anchor");
        stack.temp(tempMapAnchor(anchor1, anchor2));
        stack.temp(-> add(debugOutput, print("Unmapping anchor")));
        
        addMappingToDebugOutput();
        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<Bool> is IMakeEmptyClone {
    bool change;
    Iterator<Curve> curve1iterator;
    Curve curve1;
    MappedCurve c2;
    Anchor a2;
    
    public selfType makeEmptyClone() { ret new selfType; }
    
    void step(VStack stack) {
      cast stack to BStack<?>;
      
      if (step == 0) {
        print(n2(mesh1.curves(), "curve") + " in mesh1, mapped: " + l(mm.curveMap));
        print("mesh1.curves: " + map identityHashCode(mesh1.curves()));
        print("mapped: " + map identityHashCode(keys(mm.curveMap)));
        print("mapped (backward map): " + map identityHashCode(keys(mm.curveBackwardMap)));
        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
        MappedCurve curve1mapping = mm.get(curve1);
        if (curve1mapping != null) {
          print("Curve is mapped: " + curve1);
          assertTrue("mesh2 contains curve1mapping", mesh2.containsCurve(curve1mapping!));
          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;
        }
        
        new L<MappedCurve> possibleCurves;
        
        if (start2 != null && end2 != null) {
          // Both anchors are mapped already, choose
          // one the curves connecting them in mesh2.
          
          for (curve2 : start2.curves())
            if (curve2.connectedTo(end2)) {
              bool flipped = curve2.end == start2;
              possibleCurves.add(new MappedCurve(curve2, flipped));
            }
        } else {
          // Only one anchor is mapped.
          // 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);
        
          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
            bool flipped = c2.start() != a2;
            possibleCurves.add(new MappedCurve(c2, flipped));
            print("Possible curve!");
          }
        }
      
        addPossibleCurvesToDebugOutput(curve1, possibleCurves);
        print(l(possibleCurves)
          + " 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 {
        print("Mapping curve " + curve1 + " to " + c2);
        add(debugOutput, print("Mapping curve"));
        stack.temp(mm.tempMapCurve(curve1, c2!, c2.flipped));
        stack.temp(-> add(debugOutput, "Unmapping curve"));
        addMappingToDebugOutput();
        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);
  }
  
  void addMappingToDebugOutput() {
    if (debugOutput == null) ret;
    
    O error = mm.validityError();
    addIfNotNull(debugOutput, error);
    
    // use full meshes as background
    var img1 = mesh1.getBufferedImage();
    var img2 = mesh2.getBufferedImage();
    for (img : ll(img1, img2))
      bufferedImageContrastAndBrightness(img, contrast, brightness);
      
    mm.drawMappedPartOfMesh1(createGraphics(img1));
    mm.drawMappedPartOfMesh2(createGraphics(img2));
    addPair(debugOutput, img1, img2);
  }
  
  void addPossibleCurvesToDebugOutput(Curve c1, Cl<MappedCurve> possibleCurves) {
    if (debugOutput == null) ret;
    
    // use full meshes as background
    var img1 = mesh1.getBufferedImage();
    var img2 = mesh2.getBufferedImage();
    for (img : ll(img1, img2))
      bufferedImageContrastAndBrightness(img, contrast, brightness);
    
    new G22VisualizeMeshes().drawCurve(createGraphics(img1), c1);  
    for (curve : possibleCurves) {
      new G22VisualizeMeshes vm;
      if (curve.flipped)
        vm.curveColor(Color.green);
      vm.drawCurve(createGraphics(img2), curve!);
    }
      
    add(debugOutput, n2(possibleCurves, "possible curve"));
    addPair(debugOutput, img1, img2);
  }
}

Author comment

Began life as a copy of #1035358

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1035369
Snippet name: G22MeshMapper_v2 - tries to map mesh1 to mesh2 [dev.]
Eternal ID of this version: #1035369/62
Text MD5: 636e2740d06ed46e3dee923d159620b9
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-05-06 19:54:18
Source code size: 8561 bytes / 261 lines
Pitched / IR pitched: No / No
Views / Downloads: 223 / 502
Version history: 61 change(s)
Referenced in: #1003674 - Standard Classes + Interfaces (LIVE continued in #1034167)
#1035416 - G22MeshMapper_v2 backup with random mode