IsOrientableManifoldWithBoundaries method

bool IsOrientableManifoldWithBoundaries()

Implementation

bool IsOrientableManifoldWithBoundaries() {
  final LinkedHashMap<Edge3, Object> incidenceE =
      LinkedHashMap<Edge3, Object>();

  bool addEdge(VM.Vector3 v1, VM.Vector3 v2, Object face) {
    final Edge3 edge = Edge3(v1, v2);

    final Object f = incidenceE.putIfAbsent(edge, () => face);
    if (f != face) {
      LogWarn("unexpected duplicate edge:  ${edge}");
      return true;
    } else {
      return false;
    }
  }

  for (Face3 f3 in faces3) {
    VM.Vector3 va = vertices[f3.a];
    VM.Vector3 vb = vertices[f3.b];
    VM.Vector3 vc = vertices[f3.c];
    if (addEdge(va, vb, f3) | addEdge(vb, vc, f3) | addEdge(vc, va, f3)) {
      return false;
    }
  }

  for (Face4 f4 in faces4) {
    VM.Vector3 va = vertices[f4.a];
    VM.Vector3 vb = vertices[f4.b];
    VM.Vector3 vc = vertices[f4.c];
    VM.Vector3 vd = vertices[f4.d];
    if (addEdge(va, vb, f4) |
        addEdge(vb, vc, f4) |
        addEdge(vc, va, f4) |
        // same split as in  GenerateFaceIndices()
        addEdge(va, vc, f4) |
        addEdge(vc, vd, f4) |
        addEdge(vd, va, f4)) {
      return false;
    }
  }
  // check that each edge is incident to two faces with compatible orientation
  for (Edge3 e in incidenceE.keys) {
    Edge3 f = Edge3(e.v2, e.v1);
    if (!incidenceE.containsKey(f)) {
      LogWarn("unpaired edge ${e.v1}->${e.v2}");
      return false;
    }
  }

  // fan property
  // print("build incidenceV from ${incidenceE.length} edges");
  final LinkedHashMap<VM.Vector3, List<VM.Vector3>> incidenceV =
      LinkedHashMap<VM.Vector3, List<VM.Vector3>>(hashCode: hashVector3);
  for (Edge3 e in incidenceE.keys) {
    incidenceV.putIfAbsent(e.v1, () => <VM.Vector3>[]).add(e.v2);
  }

  bool formsLoop(List<VM.Vector3> lst) {
    for (int i = 0; i < lst.length; ++i) {
      VM.Vector3 v1 = i == 0 ? lst.last : lst[i - 1];
      // print("fan ${v1} ${lst}");
      bool found = false;
      for (int j = i; j < lst.length; ++j) {
        VM.Vector3 v2 = lst[j];
        if (incidenceE.containsKey(Edge3(v1, v2))) {
          lst[j] = lst[i];
          lst[i] = v2;
          found = true;
          break;
        }
      }
      if (!found) {
        return false;
      }
    }
    return true;
  }

  //print ("check loops");
  for (List<VM.Vector3> lst in incidenceV.values) {
    if (!formsLoop(lst)) {
      LogWarn("fan issues for ${lst}");
      return false;
    }
  }
  return true;
}