Dart Documentationbox2d_consoleSimplex

Simplex class

Class for internal use by Distance.dart.

class Simplex {
  final SimplexVertex v1;
  final SimplexVertex v2;
  final SimplexVertex v3;
  final List<SimplexVertex> vertices;
  int count;

  Simplex() :
    count = 0,
    v1 = new SimplexVertex(),
    v2 = new SimplexVertex(),
    v3 = new SimplexVertex(),
    vertices = new List<SimplexVertex>(3),
    e13 = new Vector(),
    e12 = new Vector(),
    e23 = new Vector(),
    case2 = new Vector(),
    case22 = new Vector(),
    case3 = new Vector(),
    case33 = new Vector() {

    vertices[0] = v1;
    vertices[1] = v2;
    vertices[2] = v3;
  }

  /** Pooling. */
  final Vector e13;
  final Vector e23;
  final Vector e12;
  final Vector case2;
  final Vector case22;
  final Vector case3;
  final Vector case33;

  void readCache(SimplexCache cache, DistanceProxy proxyA,
      Transform transformA, DistanceProxy proxyB,
      Transform transformB) {
    assert (cache.count <= 3);

    // Copy data from cache.
    count = cache.count;

    for (int i = 0; i < count; ++i) {
      SimplexVertex v = vertices[i];
      v.indexA = cache.indexA[i];
      v.indexB = cache.indexB[i];
      Vector wALocal = proxyA.vertices[v.indexA];
      Vector wBLocal = proxyB.vertices[v.indexB];
      Transform.mulToOut(transformA, wALocal, v.wA);
      Transform.mulToOut(transformB, wBLocal, v.wB);
      v.w.setFrom(v.wB).subLocal(v.wA);
      v.a = 0.0;
    }

    // Compute the new simplex metric, if it is substantially different than
    // old metric then flush the simplex.
    if (count > 1) {
      num metric1 = cache.metric;
      num metric2 = getMetric();
      if (metric2 < 0.5 * metric1 || 2.0 * metric1 < metric2 || metric2 <
          Settings.EPSILON) {
        // Reset the simplex.
        count = 0;
      }
    }

    // If the cache is empty or invalid ...
    if (count == 0) {
      SimplexVertex v = vertices[0];
      v.indexA = 0;
      v.indexB = 0;
      Vector wALocal = proxyA.vertices[0];
      Vector wBLocal = proxyB.vertices[0];
      Transform.mulToOut(transformA, wALocal, v.wA);
      Transform.mulToOut(transformB, wBLocal, v.wB);
      v.w.setFrom(v.wB).subLocal(v.wA);
      count = 1;
    }
  }

  void writeCache(SimplexCache cache) {
    cache.metric = getMetric();
    cache.count = count;

    for (int i = 0; i < count; ++i) {
      cache.indexA[i] = (vertices[i].indexA);
      cache.indexB[i] = (vertices[i].indexB);
    }
  }

  void getSearchDirection(Vector out) {
    switch (count) {
      case 1 :
        out.setFrom(v1.w).negateLocal();
        return;
      case 2 :
        e12.setFrom(v2.w).subLocal(v1.w);
        // use out for a temp variable real quick
        out.setFrom(v1.w).negateLocal();
        num sgn = Vector.crossVectors(e12, out);

        if (sgn > 0) {
          // Origin is left of e12.
          Vector.crossNumAndVectorToOut(1, e12, out);
        }
        else {
          // Origin is right of e12.
          Vector.crossVectorAndNumToOut(e12, 1, out);
        }
        break;
      default :
        assert (false);
        out.setZero();
        return;
    }
  }


  /**
   * this returns pooled objects. don't keep or modify them
   */
  void getClosestPoint(Vector out) {
    switch (count) {
      case 0 :
        assert (false);
        out.setZero();
        return;
      case 1 :
        out.setFrom(v1.w);
        return;
      case 2 :
        case22.setFrom(v2.w).mulLocal(v2.a);
        case2.setFrom(v1.w).mulLocal(v1.a).addLocal(case22);
        out.setFrom(case2);
        return;
      case 3 :
        out.setZero();
        return;
      default :
        assert (false);
        out.setZero();
        return;
    }
  }


  void getWitnessPoints(Vector pA, Vector pB) {
    switch (count) {
      case 0 :
        assert (false);
        break;

      case 1 :
        pA.setFrom(v1.wA);
        pB.setFrom(v1.wB);
        break;

      case 2 :
        case2.setFrom(v1.wA).mulLocal(v1.a);
        pA.setFrom(v2.wA).mulLocal(v2.a).addLocal(case2);
        case2.setFrom(v1.wB).mulLocal(v1.a);
        pB.setFrom(v2.wB).mulLocal(v2.a).addLocal(case2);

        break;

      case 3 :
        pA.setFrom(v1.wA).mulLocal(v1.a);
        case3.setFrom(v2.wA).mulLocal(v2.a);
        case33.setFrom(v3.wA).mulLocal(v3.a);
        pA.addLocal(case3).addLocal(case33);
        pB.setFrom(pA);
        break;

      default :
        assert (false);
        break;
    }
  }

  num getMetric() {
    switch (count) {
      case 0 :
        assert (false);
        return 0.0;

      case 1 :
        return 0.0;

      case 2 :
        return MathBox.distance(v1.w, v2.w);

      case 3 :
        case3.setFrom(v2.w).subLocal(v1.w);
        case33.setFrom(v3.w).subLocal(v1.w);
        return Vector.crossVectors(case3, case33);

      default :
        assert (false);
        return 0.0;
    }
  }

  /**
   * Solve a line segment using barycentric coordinates.
   */
  void solve2() {
    Vector w1 = v1.w;
    Vector w2 = v2.w;
    e12.setFrom(w2).subLocal(w1);

    // w1 region
    num d12_2 = -Vector.dot(w1, e12);
    if (d12_2 <= 0.0) {
      // a2 <= 0, so we clamp it to 0
      v1.a = 1.0;
      count = 1;
      return;
    }

    // w2 region
    num d12_1 = Vector.dot(w2, e12);
    if (d12_1 <= 0.0) {
      // a1 <= 0, so we clamp it to 0
      v2.a = 1.0;
      count = 1;
      v1.setFrom(v2);
      return;
    }

    // Must be in e12 region.
    num inv_d12 = 1.0 / (d12_1 + d12_2);
    v1.a = d12_1 * inv_d12;
    v2.a = d12_2 * inv_d12;
    count = 2;
  }

  /**
   * Solve a line segment using barycentric coordinates.<br/>
   * Possible regions:<br/>
   * - points[2]<br/>
   * - edge points[0]-points[2]<br/>
   * - edge points[1]-points[2]<br/>
   * - inside the triangle
   */
  void solve3() {
    Vector w1 = v1.w;
    Vector w2 = v2.w;
    Vector w3 = v3.w;

    // Edge12
    e12.setFrom(w2).subLocal(w1);
    num w1e12 = Vector.dot(w1, e12);
    num w2e12 = Vector.dot(w2, e12);
    num d12_1 = w2e12;
    num d12_2 = -w1e12;

    // Edge13
    e13.setFrom(w3).subLocal(w1);
    num w1e13 = Vector.dot(w1, e13);
    num w3e13 = Vector.dot(w3, e13);
    num d13_1 = w3e13;
    num d13_2 = -w1e13;

    // Edge23
    e23.setFrom(w3).subLocal(w2);
    num w2e23 = Vector.dot(w2, e23);
    num w3e23 = Vector.dot(w3, e23);
    num d23_1 = w3e23;
    num d23_2 = -w2e23;

    // Triangle123
    num n123 = Vector.crossVectors(e12, e13);

    num d123_1 = n123 * Vector.crossVectors(w2, w3);
    num d123_2 = n123 * Vector.crossVectors(w3, w1);
    num d123_3 = n123 * Vector.crossVectors(w1, w2);

    // w1 region
    if (d12_2 <= 0.0 && d13_2 <= 0.0) {
      v1.a = 1.0;
      count = 1;
      return;
    }

    // e12
    if (d12_1 > 0.0 && d12_2 > 0.0 && d123_3 <= 0.0) {
      num inv_d12 = 1.0 / (d12_1 + d12_2);
      v1.a = d12_1 * inv_d12;
      v2.a = d12_2 * inv_d12;
      count = 2;
      return;
    }

    // e13
    if (d13_1 > 0.0 && d13_2 > 0.0 && d123_2 <= 0.0) {
      num inv_d13 = 1.0 / (d13_1 + d13_2);
      v1.a = d13_1 * inv_d13;
      v3.a = d13_2 * inv_d13;
      count = 2;
      v2.setFrom(v3);
      return;
    }

    // w2 region
    if (d12_1 <= 0.0 && d23_2 <= 0.0) {
      v2.a = 1.0;
      count = 1;
      v1.setFrom(v2);
      return;
    }

    // w3 region
    if (d13_1 <= 0.0 && d23_1 <= 0.0) {
      v3.a = 1.0;
      count = 1;
      v1.setFrom(v3);
      return;
    }

    // e23
    if (d23_1 > 0.0 && d23_2 > 0.0 && d123_1 <= 0.0) {
      num inv_d23 = 1.0 / (d23_1 + d23_2);
      v2.a = d23_1 * inv_d23;
      v3.a = d23_2 * inv_d23;
      count = 2;
      v1.setFrom(v3);
      return;
    }

    // Must be in triangle123
    num inv_d123 = 1.0 / (d123_1 + d123_2 + d123_3);
    v1.a = d123_1 * inv_d123;
    v2.a = d123_2 * inv_d123;
    v3.a = d123_3 * inv_d123;
    count = 3;
  }
}

Constructors

new Simplex() #

Simplex() :
  count = 0,
  v1 = new SimplexVertex(),
  v2 = new SimplexVertex(),
  v3 = new SimplexVertex(),
  vertices = new List<SimplexVertex>(3),
  e13 = new Vector(),
  e12 = new Vector(),
  e23 = new Vector(),
  case2 = new Vector(),
  case22 = new Vector(),
  case3 = new Vector(),
  case33 = new Vector() {

  vertices[0] = v1;
  vertices[1] = v2;
  vertices[2] = v3;
}

Properties

final Vector case2 #

final Vector case2;

final Vector case22 #

final Vector case22;

final Vector case3 #

final Vector case3;

final Vector case33 #

final Vector case33;

int count #

int count;

final Vector e12 #

final Vector e12;

final Vector e13 #

Pooling.

final Vector e13;

final Vector e23 #

final Vector e23;

final Type runtimeType #

inherited from Object

A representation of the runtime type of the object.

external Type get runtimeType;

final SimplexVertex v1 #

final SimplexVertex v1;

final SimplexVertex v2 #

final SimplexVertex v2;

final SimplexVertex v3 #

final SimplexVertex v3;

final List<SimplexVertex> vertices #

final List<SimplexVertex> vertices;

Operators

bool operator ==(other) #

inherited from Object

The equality operator.

The default behavior for all Objects is to return true if and only if this and other are the same object.

If a subclass overrides the equality operator it should override the hashCode method as well to maintain consistency.

bool operator ==(other) => identical(this, other);

Methods

void getClosestPoint(Vector out) #

this returns pooled objects. don't keep or modify them

void getClosestPoint(Vector out) {
  switch (count) {
    case 0 :
      assert (false);
      out.setZero();
      return;
    case 1 :
      out.setFrom(v1.w);
      return;
    case 2 :
      case22.setFrom(v2.w).mulLocal(v2.a);
      case2.setFrom(v1.w).mulLocal(v1.a).addLocal(case22);
      out.setFrom(case2);
      return;
    case 3 :
      out.setZero();
      return;
    default :
      assert (false);
      out.setZero();
      return;
  }
}

num getMetric() #

num getMetric() {
  switch (count) {
    case 0 :
      assert (false);
      return 0.0;

    case 1 :
      return 0.0;

    case 2 :
      return MathBox.distance(v1.w, v2.w);

    case 3 :
      case3.setFrom(v2.w).subLocal(v1.w);
      case33.setFrom(v3.w).subLocal(v1.w);
      return Vector.crossVectors(case3, case33);

    default :
      assert (false);
      return 0.0;
  }
}

void getSearchDirection(Vector out) #

void getSearchDirection(Vector out) {
  switch (count) {
    case 1 :
      out.setFrom(v1.w).negateLocal();
      return;
    case 2 :
      e12.setFrom(v2.w).subLocal(v1.w);
      // use out for a temp variable real quick
      out.setFrom(v1.w).negateLocal();
      num sgn = Vector.crossVectors(e12, out);

      if (sgn > 0) {
        // Origin is left of e12.
        Vector.crossNumAndVectorToOut(1, e12, out);
      }
      else {
        // Origin is right of e12.
        Vector.crossVectorAndNumToOut(e12, 1, out);
      }
      break;
    default :
      assert (false);
      out.setZero();
      return;
  }
}

void getWitnessPoints(Vector pA, Vector pB) #

void getWitnessPoints(Vector pA, Vector pB) {
  switch (count) {
    case 0 :
      assert (false);
      break;

    case 1 :
      pA.setFrom(v1.wA);
      pB.setFrom(v1.wB);
      break;

    case 2 :
      case2.setFrom(v1.wA).mulLocal(v1.a);
      pA.setFrom(v2.wA).mulLocal(v2.a).addLocal(case2);
      case2.setFrom(v1.wB).mulLocal(v1.a);
      pB.setFrom(v2.wB).mulLocal(v2.a).addLocal(case2);

      break;

    case 3 :
      pA.setFrom(v1.wA).mulLocal(v1.a);
      case3.setFrom(v2.wA).mulLocal(v2.a);
      case33.setFrom(v3.wA).mulLocal(v3.a);
      pA.addLocal(case3).addLocal(case33);
      pB.setFrom(pA);
      break;

    default :
      assert (false);
      break;
  }
}

int hashCode() #

inherited from Object

Get a hash code for this object.

All objects have hash codes. Hash codes are guaranteed to be the same for objects that are equal when compared using the equality operator ==. Other than that there are no guarantees about the hash codes. They will not be consistent between runs and there are no distribution guarantees.

If a subclass overrides hashCode it should override the equality operator as well to maintain consistency.

external int hashCode();

noSuchMethod(String name, List args) #

inherited from Object

noSuchMethod is invoked when users invoke a non-existant method on an object. The name of the method and the arguments of the invocation are passed to noSuchMethod. If noSuchMethod returns a value, that value becomes the result of the original invocation.

The default behavior of noSuchMethod is to throw a noSuchMethodError.

external Dynamic noSuchMethod(String name, List args);

const Object() #

inherited from Object

Creates a new Object instance.

Object instances have no meaningful state, and are only useful through their identity. An Object instance is equal to itself only.

const Object();

void readCache(SimplexCache cache, DistanceProxy proxyA, Transform transformA, DistanceProxy proxyB, Transform transformB) #

void readCache(SimplexCache cache, DistanceProxy proxyA,
    Transform transformA, DistanceProxy proxyB,
    Transform transformB) {
  assert (cache.count <= 3);

  // Copy data from cache.
  count = cache.count;

  for (int i = 0; i < count; ++i) {
    SimplexVertex v = vertices[i];
    v.indexA = cache.indexA[i];
    v.indexB = cache.indexB[i];
    Vector wALocal = proxyA.vertices[v.indexA];
    Vector wBLocal = proxyB.vertices[v.indexB];
    Transform.mulToOut(transformA, wALocal, v.wA);
    Transform.mulToOut(transformB, wBLocal, v.wB);
    v.w.setFrom(v.wB).subLocal(v.wA);
    v.a = 0.0;
  }

  // Compute the new simplex metric, if it is substantially different than
  // old metric then flush the simplex.
  if (count > 1) {
    num metric1 = cache.metric;
    num metric2 = getMetric();
    if (metric2 < 0.5 * metric1 || 2.0 * metric1 < metric2 || metric2 <
        Settings.EPSILON) {
      // Reset the simplex.
      count = 0;
    }
  }

  // If the cache is empty or invalid ...
  if (count == 0) {
    SimplexVertex v = vertices[0];
    v.indexA = 0;
    v.indexB = 0;
    Vector wALocal = proxyA.vertices[0];
    Vector wBLocal = proxyB.vertices[0];
    Transform.mulToOut(transformA, wALocal, v.wA);
    Transform.mulToOut(transformB, wBLocal, v.wB);
    v.w.setFrom(v.wB).subLocal(v.wA);
    count = 1;
  }
}

new Simplex() #

Simplex() :
  count = 0,
  v1 = new SimplexVertex(),
  v2 = new SimplexVertex(),
  v3 = new SimplexVertex(),
  vertices = new List<SimplexVertex>(3),
  e13 = new Vector(),
  e12 = new Vector(),
  e23 = new Vector(),
  case2 = new Vector(),
  case22 = new Vector(),
  case3 = new Vector(),
  case33 = new Vector() {

  vertices[0] = v1;
  vertices[1] = v2;
  vertices[2] = v3;
}

void solve2() #

Solve a line segment using barycentric coordinates.

void solve2() {
  Vector w1 = v1.w;
  Vector w2 = v2.w;
  e12.setFrom(w2).subLocal(w1);

  // w1 region
  num d12_2 = -Vector.dot(w1, e12);
  if (d12_2 <= 0.0) {
    // a2 <= 0, so we clamp it to 0
    v1.a = 1.0;
    count = 1;
    return;
  }

  // w2 region
  num d12_1 = Vector.dot(w2, e12);
  if (d12_1 <= 0.0) {
    // a1 <= 0, so we clamp it to 0
    v2.a = 1.0;
    count = 1;
    v1.setFrom(v2);
    return;
  }

  // Must be in e12 region.
  num inv_d12 = 1.0 / (d12_1 + d12_2);
  v1.a = d12_1 * inv_d12;
  v2.a = d12_2 * inv_d12;
  count = 2;
}

void solve3() #

Solve a line segment using barycentric coordinates.<br/> Possible regions:<br/> - points2<br/> - edge points0-points2<br/> - edge points1-points2<br/> - inside the triangle

void solve3() {
  Vector w1 = v1.w;
  Vector w2 = v2.w;
  Vector w3 = v3.w;

  // Edge12
  e12.setFrom(w2).subLocal(w1);
  num w1e12 = Vector.dot(w1, e12);
  num w2e12 = Vector.dot(w2, e12);
  num d12_1 = w2e12;
  num d12_2 = -w1e12;

  // Edge13
  e13.setFrom(w3).subLocal(w1);
  num w1e13 = Vector.dot(w1, e13);
  num w3e13 = Vector.dot(w3, e13);
  num d13_1 = w3e13;
  num d13_2 = -w1e13;

  // Edge23
  e23.setFrom(w3).subLocal(w2);
  num w2e23 = Vector.dot(w2, e23);
  num w3e23 = Vector.dot(w3, e23);
  num d23_1 = w3e23;
  num d23_2 = -w2e23;

  // Triangle123
  num n123 = Vector.crossVectors(e12, e13);

  num d123_1 = n123 * Vector.crossVectors(w2, w3);
  num d123_2 = n123 * Vector.crossVectors(w3, w1);
  num d123_3 = n123 * Vector.crossVectors(w1, w2);

  // w1 region
  if (d12_2 <= 0.0 && d13_2 <= 0.0) {
    v1.a = 1.0;
    count = 1;
    return;
  }

  // e12
  if (d12_1 > 0.0 && d12_2 > 0.0 && d123_3 <= 0.0) {
    num inv_d12 = 1.0 / (d12_1 + d12_2);
    v1.a = d12_1 * inv_d12;
    v2.a = d12_2 * inv_d12;
    count = 2;
    return;
  }

  // e13
  if (d13_1 > 0.0 && d13_2 > 0.0 && d123_2 <= 0.0) {
    num inv_d13 = 1.0 / (d13_1 + d13_2);
    v1.a = d13_1 * inv_d13;
    v3.a = d13_2 * inv_d13;
    count = 2;
    v2.setFrom(v3);
    return;
  }

  // w2 region
  if (d12_1 <= 0.0 && d23_2 <= 0.0) {
    v2.a = 1.0;
    count = 1;
    v1.setFrom(v2);
    return;
  }

  // w3 region
  if (d13_1 <= 0.0 && d23_1 <= 0.0) {
    v3.a = 1.0;
    count = 1;
    v1.setFrom(v3);
    return;
  }

  // e23
  if (d23_1 > 0.0 && d23_2 > 0.0 && d123_1 <= 0.0) {
    num inv_d23 = 1.0 / (d23_1 + d23_2);
    v2.a = d23_1 * inv_d23;
    v3.a = d23_2 * inv_d23;
    count = 2;
    v1.setFrom(v3);
    return;
  }

  // Must be in triangle123
  num inv_d123 = 1.0 / (d123_1 + d123_2 + d123_3);
  v1.a = d123_1 * inv_d123;
  v2.a = d123_2 * inv_d123;
  v3.a = d123_3 * inv_d123;
  count = 3;
}

String toString() #

inherited from Object

Returns a string representation of this object.

external String toString();

void writeCache(SimplexCache cache) #

void writeCache(SimplexCache cache) {
  cache.metric = getMetric();
  cache.count = count;

  for (int i = 0; i < count; ++i) {
    cache.indexA[i] = (vertices[i].indexA);
    cache.indexB[i] = (vertices[i].indexB);
  }
}