Dart Documentationbox2d_htmlPolygonShape

PolygonShape class

Convex Polygon Shape. Create using Body.createShape(ShapeDef) rather than the constructor here, which is off-limits to the likes of you.

class PolygonShape extends Shape {
  /**
   * Local position of the shape centroid in parent body frame.
   */
  final Vector centroid;

  /**
   * The vertices of the shape. Note: Use getVertexCount() rather than
   * vertices.length to get the number of active vertices.
   */
  final List<Vector> vertices;

  /**
   * The normals of the shape. Note: Use getVertexCount() rather than
   * normals.length to get the number of active normals.
   */
  final List<Vector> normals;

  int vertexCount;

  /**
   * Constructs a new PolygonShape.
   */
  PolygonShape() :
      super(ShapeType.POLYGON, Settings.POLYGON_RADIUS),
      vertexCount = 0,
      vertices = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
      normals = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
      centroid = new Vector() {
    for (int i = 0; i < vertices.length; ++i)
      vertices[i] = new Vector();
    for (int i = 0; i < normals.length; ++i)
      normals[i] = new Vector();
  }

  /**
   * Constructs a new PolygonShape equal to the given shape.
   */
  PolygonShape.copy(PolygonShape other) :
      super(ShapeType.POLYGON, other.radius),
      vertexCount = other.vertexCount,
      vertices = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
      normals = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
      centroid = new Vector.copy(other.centroid) {
    // Copy the vertices and normals from the other polygon shape.
    for (int i = 0; i < other.vertices.length; ++i)
      vertices[i] = new Vector.copy(other.vertices[i]);

    for (int i = 0; i < other.normals.length; ++i)
      normals[i] = new Vector.copy(other.normals[i]);
  }

  /**
   * Get the supporting vertex index in the given direction.
   */
  int getSupport(Vector d) {
    int bestIndex = 0;
    num bestValue = Vector.dot(vertices[0], d);
    for (int i = 1; i < vertexCount; ++i) {
      num value = Vector.dot(vertices[i], d);
      if (value > bestValue) {
        bestIndex = i;
        bestValue = value;
      }
    }
    return bestIndex;
  }

  Shape clone() => new PolygonShape.copy(this);

  /**
   * Get the supporting vertex in the given direction.
   */
  Vector getSupportVertex(Vector d) => vertices[getSupport(d)];

  /**
   * Copy vertices. This assumes the vertices define a convex polygon.
   * It is assumed that the exterior is the the right of each edge.
   * TODO(dominich): Consider removing [count].
   */
  void setFrom(List<Vector> otherVertices, int count) {
    assert (2 <= count && count <= Settings.MAX_POLYGON_VERTICES);
    vertexCount = count;

    // Copy vertices.
    for (int i = 0; i < vertexCount; ++i) {
      assert(vertices[i] !== null);
      vertices[i].setFrom(otherVertices[i]);
    }

    Vector edge = new Vector();

    // Compute normals. Ensure the edges have non-zero length.
    for (int i = 0; i < vertexCount; ++i) {
      final int i1 = i;
      final int i2 = i + 1 < vertexCount ? i + 1 : 0;
      edge.setFrom(vertices[i2]).subLocal(vertices[i1]);

      assert (edge.lengthSquared > Settings.EPSILON * Settings.EPSILON);
      Vector.crossVectorAndNumToOut(edge, 1, normals[i]);
      normals[i].normalize();
    }

    // Compute the polygon centroid.
    computeCentroidToOut(vertices, vertexCount, centroid);
  }

  /**
   * Build vertices to represent an axis-aligned box.
   * hx is the half-width of the body and hy is the half height.
   */
  void setAsBox(num hx, num hy) {
    vertexCount = 4;
    vertices[0].setCoords(-hx, -hy);
    vertices[1].setCoords(hx, -hy);
    vertices[2].setCoords(hx, hy);
    vertices[3].setCoords(-hx, hy);
    normals[0].setCoords(0.0, -1.0);
    normals[1].setCoords(1.0, 0.0);
    normals[2].setCoords(0.0, 1.0);
    normals[3].setCoords(-1.0, 0.0);
    centroid.setZero();
  }

  /**
   * Build vertices to represent an oriented box. hx is the halfwidth, hy the
   * half-height, center is the center of the box in local coordinates and angle
   * is the rotation of the box in local coordinates.
   */
  void setAsBoxWithCenterAndAngle(num hx, num hy, Vector center, num angle) {
    vertexCount = 4;
    vertices[0].setCoords(-hx, -hy);
    vertices[1].setCoords(hx, -hy);
    vertices[2].setCoords(hx, hy);
    vertices[3].setCoords(-hx, hy);
    normals[0].setCoords(0.0, -1.0);
    normals[1].setCoords(1.0, 0.0);
    normals[2].setCoords(0.0, 1.0);
    normals[3].setCoords(-1.0, 0.0);
    centroid.setFrom(center);

    Transform xf = new Transform();
    xf.position.setFrom(center);
    xf.rotation.setAngle(angle);

    // Transform vertices and normals.
    for (int i = 0; i < vertexCount; ++i) {
      Transform.mulToOut(xf, vertices[i], vertices[i]);
      Matrix22.mulMatrixAndVectorToOut(xf.rotation, normals[i], normals[i]);
    }
  }

  /**
   * Set this as a single edge.
   */
  void setAsEdge(Vector v1, Vector v2) {
    vertexCount = 2;
    vertices[0].setFrom(v1);
    vertices[1].setFrom(v2);
    centroid.setFrom(v1).addLocal(v2).mulLocal(0.5);
    normals[0].setFrom(v2).subLocal(v1);
    Vector.crossVectorAndNumToOut(normals[0], 1, normals[0]);
    normals[0].normalize();
    normals[1].setFrom(normals[0]).negateLocal();
  }

  /**
   * See Shape.testPoint(Transform, Vector).
   */
  bool testPoint(Transform xf, Vector p) {
    Vector pLocal = new Vector();

    pLocal.setFrom(p).subLocal(xf.position);
    Matrix22.mulTransMatrixAndVectorToOut(xf.rotation, pLocal, pLocal);

    Vector temp = new Vector();

    for (int i = 0; i < vertexCount; ++i) {
      temp.setFrom(pLocal).subLocal(vertices[i]);
      if (Vector.dot(normals[i], temp) > 0)
        return false;
    }

    return true;
  }

  /**
   * See Shape.computeAxisAlignedBox(AABB, Transform).
   */
  void computeAxisAlignedBox(AxisAlignedBox argAabb, Transform argXf) {
    final Vector lower = new Vector();
    final Vector upper = new Vector();
    final Vector v = new Vector();

    Transform.mulToOut(argXf, vertices[0], lower);
    upper.setFrom(lower);

    for (int i = 1; i < vertexCount; ++i) {
      Transform.mulToOut(argXf, vertices[i], v);
      Vector.minToOut(lower, v, lower);
      Vector.maxToOut(upper, v, upper);
    }

    argAabb.lowerBound.x = lower.x - radius;
    argAabb.lowerBound.y = lower.y - radius;
    argAabb.upperBound.x = upper.x + radius;
    argAabb.upperBound.y = upper.y + radius;
  }

  /**
   * Get a vertex by index.
   */
  Vector getVertex(int index) => vertices[index];

  /**
   * Compute the centroid and store the value in the given out parameter.
   */
  void computeCentroidToOut(List<Vector> vs, int count, Vector out) {
    assert (count >= 3);

    out.setCoords(0.0, 0.0);
    num area = 0.0;

    if (count == 2) {
      out.setFrom(vs[0]).addLocal(vs[1]).mulLocal(.5);
      return;
    }

    // pRef is the reference point for forming triangles.
    // It's location doesn't change the result (except for rounding error).
    final Vector pRef = new Vector();
    pRef.setZero();

    final Vector e1 = new Vector();
    final Vector e2 = new Vector();

    final num inv3 = 1.0 / 3.0;

    for (int i = 0; i < count; ++i) {
      // Triangle vertices.
      final Vector p1 = pRef;
      final Vector p2 = vs[i];
      final Vector p3 = i + 1 < count ? vs[i + 1] : vs[0];

      e1.setFrom(p2).subLocal(p1);
      e2.setFrom(p3).subLocal(p1);

      final num D = Vector.crossVectors(e1, e2);

      final num triangleArea = 0.5 * D;
      area += triangleArea;

      // Area weighted centroid
      out.addLocal(p1).addLocal(p2).addLocal(p3).mulLocal(triangleArea * inv3);
    }

    // Centroid
    assert (area > Settings.EPSILON);
    out.mulLocal(1.0 / area);
  }

  /**
   * See Shape.computeMass(MassData)
   */
  void computeMass(MassData massData, num density) {
    // Polygon mass, centroid, and inertia.
    // Let rho be the polygon density in mass per unit area.
    // Then:
    // mass = rho * int(dA)
    // centroid.x = (1/mass) * rho * int(x * dA)
    // centroid.y = (1/mass) * rho * int(y * dA)
    // I = rho * int((x*x + y*y) * dA)
    //
    // We can compute these integrals by summing all the integrals
    // for each triangle of the polygon. To evaluate the integral
    // for a single triangle, we make a change of variables to
    // the (u,v) coordinates of the triangle:
    // x = x0 + e1x * u + e2x * v
    // y = y0 + e1y * u + e2y * v
    // where 0 <= u && 0 <= v && u + v <= 1.
    //
    // We integrate u from [0,1-v] and then v from [0,1].
    // We also need to use the Jacobian of the transformation:
    // D = cross(e1, e2)
    //
    // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
    //
    // The rest of the derivation is handled by computer algebra.

    assert (vertexCount >= 2);

    // A line segment has zero mass.
    if (vertexCount == 2) {
      // massData.center = 0.5 * (vertices[0] + vertices[1]);
      massData.center.setFrom(vertices[0]).addLocal(vertices[1]).mulLocal(0.5);
      massData.mass = 0.0;
      massData.inertia = 0.0;
      return;
    }

    final Vector center = new Vector();
    center.setZero();
    num area = 0.0;
    num I = 0.0;

    // pRef is the reference point for forming triangles.
    // It's location doesn't change the result (except for rounding error).
    final Vector pRef = new Vector();
    pRef.setZero();

    final num k_inv3 = 1.0 / 3.0;

    final Vector e1 = new Vector();
    final Vector e2 = new Vector();

    for (int i = 0; i < vertexCount; ++i) {
      // Triangle vertices.
      final Vector p1 = pRef;
      final Vector p2 = vertices[i];
      final Vector p3 = i + 1 < vertexCount ? vertices[i + 1] : vertices[0];

      e1.setFrom(p2);
      e1.subLocal(p1);

      e2.setFrom(p3);
      e2.subLocal(p1);

      final num D = Vector.crossVectors(e1, e2);

      final num triangleArea = 0.5 * D;
      area += triangleArea;

      // Area weighted centroid
      center.x += triangleArea * k_inv3 * (p1.x + p2.x + p3.x);
      center.y += triangleArea * k_inv3 * (p1.y + p2.y + p3.y);

      final num px = p1.x;
      final num py = p1.y;
      final num ex1 = e1.x;
      final num ey1 = e1.y;
      final num ex2 = e2.x;
      final num ey2 = e2.y;

      final num intx2 = k_inv3 * (0.25 * (ex1 * ex1 + ex2 * ex1 + ex2 * ex2) +
          (px * ex1 + px * ex2)) + 0.5 * px * px;
      final num inty2 = k_inv3 * (0.25 * (ey1 * ey1 + ey2 * ey1 + ey2 * ey2) +
          (py * ey1 + py * ey2)) + 0.5 * py * py;

      I += D * (intx2 + inty2);
    }

    // Total mass
    massData.mass = density * area;

    // Center of mass
    assert (area > Settings.EPSILON);
    center.mulLocal(1.0 / area);
    massData.center.setFrom(center);

    // Inertia tensor relative to the local origin.
    massData.inertia = I * density;
  }

  /**
   * Get the centroid and apply the supplied transform.
   */
  Vector applyTransformToCentroid(Transform xf) => Transform.mul(xf, centroid);

  /**
   * Get the centroid and apply the supplied transform. Return the result
   * through the return parameter out.
   */
  Vector centroidToOut(Transform xf, Vector out) {
    Transform.mulToOut(xf, centroid, out);
    return out;
  }
}

Extends

Shape > PolygonShape

Constructors

new PolygonShape() #

Constructs a new PolygonShape.

PolygonShape() :
    super(ShapeType.POLYGON, Settings.POLYGON_RADIUS),
    vertexCount = 0,
    vertices = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
    normals = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
    centroid = new Vector() {
  for (int i = 0; i < vertices.length; ++i)
    vertices[i] = new Vector();
  for (int i = 0; i < normals.length; ++i)
    normals[i] = new Vector();
}

new PolygonShape.copy(PolygonShape other) #

Constructs a new PolygonShape equal to the given shape.

PolygonShape.copy(PolygonShape other) :
    super(ShapeType.POLYGON, other.radius),
    vertexCount = other.vertexCount,
    vertices = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
    normals = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
    centroid = new Vector.copy(other.centroid) {
  // Copy the vertices and normals from the other polygon shape.
  for (int i = 0; i < other.vertices.length; ++i)
    vertices[i] = new Vector.copy(other.vertices[i]);

  for (int i = 0; i < other.normals.length; ++i)
    normals[i] = new Vector.copy(other.normals[i]);
}

Properties

final Vector centroid #

Local position of the shape centroid in parent body frame.

final Vector centroid;

final List<Vector> normals #

The normals of the shape. Note: Use getVertexCount() rather than normals.length to get the number of active normals.

final List<Vector> normals;

num radius #

inherited from Shape

Shape radius.

num radius;

final Type runtimeType #

inherited from Object

A representation of the runtime type of the object.

external Type get runtimeType;

int type #

inherited from Shape

The type of shape. Either circle or polygon.

int type;

int vertexCount #

int vertexCount;

final List<Vector> vertices #

The vertices of the shape. Note: Use getVertexCount() rather than vertices.length to get the number of active vertices.

final List<Vector> 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

Vector applyTransformToCentroid(Transform xf) #

Get the centroid and apply the supplied transform.

Vector applyTransformToCentroid(Transform xf) => Transform.mul(xf, centroid);

Vector centroidToOut(Transform xf, Vector out) #

Get the centroid and apply the supplied transform. Return the result through the return parameter out.

Vector centroidToOut(Transform xf, Vector out) {
  Transform.mulToOut(xf, centroid, out);
  return out;
}

Shape clone() #

Returns a clone of this shape.

docs inherited from Shape
Shape clone() => new PolygonShape.copy(this);

void computeAxisAlignedBox(AxisAlignedBox argAabb, Transform argXf) #

See Shape.computeAxisAlignedBox(AABB, Transform).

void computeAxisAlignedBox(AxisAlignedBox argAabb, Transform argXf) {
  final Vector lower = new Vector();
  final Vector upper = new Vector();
  final Vector v = new Vector();

  Transform.mulToOut(argXf, vertices[0], lower);
  upper.setFrom(lower);

  for (int i = 1; i < vertexCount; ++i) {
    Transform.mulToOut(argXf, vertices[i], v);
    Vector.minToOut(lower, v, lower);
    Vector.maxToOut(upper, v, upper);
  }

  argAabb.lowerBound.x = lower.x - radius;
  argAabb.lowerBound.y = lower.y - radius;
  argAabb.upperBound.x = upper.x + radius;
  argAabb.upperBound.y = upper.y + radius;
}

void computeCentroidToOut(List<Vector> vs, int count, Vector out) #

Compute the centroid and store the value in the given out parameter.

void computeCentroidToOut(List<Vector> vs, int count, Vector out) {
  assert (count >= 3);

  out.setCoords(0.0, 0.0);
  num area = 0.0;

  if (count == 2) {
    out.setFrom(vs[0]).addLocal(vs[1]).mulLocal(.5);
    return;
  }

  // pRef is the reference point for forming triangles.
  // It's location doesn't change the result (except for rounding error).
  final Vector pRef = new Vector();
  pRef.setZero();

  final Vector e1 = new Vector();
  final Vector e2 = new Vector();

  final num inv3 = 1.0 / 3.0;

  for (int i = 0; i < count; ++i) {
    // Triangle vertices.
    final Vector p1 = pRef;
    final Vector p2 = vs[i];
    final Vector p3 = i + 1 < count ? vs[i + 1] : vs[0];

    e1.setFrom(p2).subLocal(p1);
    e2.setFrom(p3).subLocal(p1);

    final num D = Vector.crossVectors(e1, e2);

    final num triangleArea = 0.5 * D;
    area += triangleArea;

    // Area weighted centroid
    out.addLocal(p1).addLocal(p2).addLocal(p3).mulLocal(triangleArea * inv3);
  }

  // Centroid
  assert (area > Settings.EPSILON);
  out.mulLocal(1.0 / area);
}

void computeMass(MassData massData, num density) #

See Shape.computeMass(MassData)

void computeMass(MassData massData, num density) {
  // Polygon mass, centroid, and inertia.
  // Let rho be the polygon density in mass per unit area.
  // Then:
  // mass = rho * int(dA)
  // centroid.x = (1/mass) * rho * int(x * dA)
  // centroid.y = (1/mass) * rho * int(y * dA)
  // I = rho * int((x*x + y*y) * dA)
  //
  // We can compute these integrals by summing all the integrals
  // for each triangle of the polygon. To evaluate the integral
  // for a single triangle, we make a change of variables to
  // the (u,v) coordinates of the triangle:
  // x = x0 + e1x * u + e2x * v
  // y = y0 + e1y * u + e2y * v
  // where 0 <= u && 0 <= v && u + v <= 1.
  //
  // We integrate u from [0,1-v] and then v from [0,1].
  // We also need to use the Jacobian of the transformation:
  // D = cross(e1, e2)
  //
  // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
  //
  // The rest of the derivation is handled by computer algebra.

  assert (vertexCount >= 2);

  // A line segment has zero mass.
  if (vertexCount == 2) {
    // massData.center = 0.5 * (vertices[0] + vertices[1]);
    massData.center.setFrom(vertices[0]).addLocal(vertices[1]).mulLocal(0.5);
    massData.mass = 0.0;
    massData.inertia = 0.0;
    return;
  }

  final Vector center = new Vector();
  center.setZero();
  num area = 0.0;
  num I = 0.0;

  // pRef is the reference point for forming triangles.
  // It's location doesn't change the result (except for rounding error).
  final Vector pRef = new Vector();
  pRef.setZero();

  final num k_inv3 = 1.0 / 3.0;

  final Vector e1 = new Vector();
  final Vector e2 = new Vector();

  for (int i = 0; i < vertexCount; ++i) {
    // Triangle vertices.
    final Vector p1 = pRef;
    final Vector p2 = vertices[i];
    final Vector p3 = i + 1 < vertexCount ? vertices[i + 1] : vertices[0];

    e1.setFrom(p2);
    e1.subLocal(p1);

    e2.setFrom(p3);
    e2.subLocal(p1);

    final num D = Vector.crossVectors(e1, e2);

    final num triangleArea = 0.5 * D;
    area += triangleArea;

    // Area weighted centroid
    center.x += triangleArea * k_inv3 * (p1.x + p2.x + p3.x);
    center.y += triangleArea * k_inv3 * (p1.y + p2.y + p3.y);

    final num px = p1.x;
    final num py = p1.y;
    final num ex1 = e1.x;
    final num ey1 = e1.y;
    final num ex2 = e2.x;
    final num ey2 = e2.y;

    final num intx2 = k_inv3 * (0.25 * (ex1 * ex1 + ex2 * ex1 + ex2 * ex2) +
        (px * ex1 + px * ex2)) + 0.5 * px * px;
    final num inty2 = k_inv3 * (0.25 * (ey1 * ey1 + ey2 * ey1 + ey2 * ey2) +
        (py * ey1 + py * ey2)) + 0.5 * py * py;

    I += D * (intx2 + inty2);
  }

  // Total mass
  massData.mass = density * area;

  // Center of mass
  assert (area > Settings.EPSILON);
  center.mulLocal(1.0 / area);
  massData.center.setFrom(center);

  // Inertia tensor relative to the local origin.
  massData.inertia = I * density;
}

int getSupport(Vector d) #

Get the supporting vertex index in the given direction.

int getSupport(Vector d) {
  int bestIndex = 0;
  num bestValue = Vector.dot(vertices[0], d);
  for (int i = 1; i < vertexCount; ++i) {
    num value = Vector.dot(vertices[i], d);
    if (value > bestValue) {
      bestIndex = i;
      bestValue = value;
    }
  }
  return bestIndex;
}

Vector getSupportVertex(Vector d) #

Get the supporting vertex in the given direction.

Vector getSupportVertex(Vector d) => vertices[getSupport(d)];

Vector getVertex(int index) #

Get a vertex by index.

Vector getVertex(int index) => vertices[index];

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();

new PolygonShape() #

Constructs a new PolygonShape.

PolygonShape() :
    super(ShapeType.POLYGON, Settings.POLYGON_RADIUS),
    vertexCount = 0,
    vertices = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
    normals = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
    centroid = new Vector() {
  for (int i = 0; i < vertices.length; ++i)
    vertices[i] = new Vector();
  for (int i = 0; i < normals.length; ++i)
    normals[i] = new Vector();
}

new PolygonShape.copy(PolygonShape other) #

Constructs a new PolygonShape equal to the given shape.

PolygonShape.copy(PolygonShape other) :
    super(ShapeType.POLYGON, other.radius),
    vertexCount = other.vertexCount,
    vertices = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
    normals = new List<Vector>(Settings.MAX_POLYGON_VERTICES),
    centroid = new Vector.copy(other.centroid) {
  // Copy the vertices and normals from the other polygon shape.
  for (int i = 0; i < other.vertices.length; ++i)
    vertices[i] = new Vector.copy(other.vertices[i]);

  for (int i = 0; i < other.normals.length; ++i)
    normals[i] = new Vector.copy(other.normals[i]);
}

void setAsBox(num hx, num hy) #

Build vertices to represent an axis-aligned box. hx is the half-width of the body and hy is the half height.

void setAsBox(num hx, num hy) {
  vertexCount = 4;
  vertices[0].setCoords(-hx, -hy);
  vertices[1].setCoords(hx, -hy);
  vertices[2].setCoords(hx, hy);
  vertices[3].setCoords(-hx, hy);
  normals[0].setCoords(0.0, -1.0);
  normals[1].setCoords(1.0, 0.0);
  normals[2].setCoords(0.0, 1.0);
  normals[3].setCoords(-1.0, 0.0);
  centroid.setZero();
}

void setAsBoxWithCenterAndAngle(num hx, num hy, Vector center, num angle) #

Build vertices to represent an oriented box. hx is the halfwidth, hy the half-height, center is the center of the box in local coordinates and angle is the rotation of the box in local coordinates.

void setAsBoxWithCenterAndAngle(num hx, num hy, Vector center, num angle) {
  vertexCount = 4;
  vertices[0].setCoords(-hx, -hy);
  vertices[1].setCoords(hx, -hy);
  vertices[2].setCoords(hx, hy);
  vertices[3].setCoords(-hx, hy);
  normals[0].setCoords(0.0, -1.0);
  normals[1].setCoords(1.0, 0.0);
  normals[2].setCoords(0.0, 1.0);
  normals[3].setCoords(-1.0, 0.0);
  centroid.setFrom(center);

  Transform xf = new Transform();
  xf.position.setFrom(center);
  xf.rotation.setAngle(angle);

  // Transform vertices and normals.
  for (int i = 0; i < vertexCount; ++i) {
    Transform.mulToOut(xf, vertices[i], vertices[i]);
    Matrix22.mulMatrixAndVectorToOut(xf.rotation, normals[i], normals[i]);
  }
}

void setAsEdge(Vector v1, Vector v2) #

Set this as a single edge.

void setAsEdge(Vector v1, Vector v2) {
  vertexCount = 2;
  vertices[0].setFrom(v1);
  vertices[1].setFrom(v2);
  centroid.setFrom(v1).addLocal(v2).mulLocal(0.5);
  normals[0].setFrom(v2).subLocal(v1);
  Vector.crossVectorAndNumToOut(normals[0], 1, normals[0]);
  normals[0].normalize();
  normals[1].setFrom(normals[0]).negateLocal();
}

void setFrom(List<Vector> otherVertices, int count) #

Copy vertices. This assumes the vertices define a convex polygon. It is assumed that the exterior is the the right of each edge. TODO(dominich): Consider removing count.

void setFrom(List<Vector> otherVertices, int count) {
  assert (2 <= count && count <= Settings.MAX_POLYGON_VERTICES);
  vertexCount = count;

  // Copy vertices.
  for (int i = 0; i < vertexCount; ++i) {
    assert(vertices[i] !== null);
    vertices[i].setFrom(otherVertices[i]);
  }

  Vector edge = new Vector();

  // Compute normals. Ensure the edges have non-zero length.
  for (int i = 0; i < vertexCount; ++i) {
    final int i1 = i;
    final int i2 = i + 1 < vertexCount ? i + 1 : 0;
    edge.setFrom(vertices[i2]).subLocal(vertices[i1]);

    assert (edge.lengthSquared > Settings.EPSILON * Settings.EPSILON);
    Vector.crossVectorAndNumToOut(edge, 1, normals[i]);
    normals[i].normalize();
  }

  // Compute the polygon centroid.
  computeCentroidToOut(vertices, vertexCount, centroid);
}

new Shape([int type = ShapeType.UNKNOWN, num radius = 0]) #

inherited from Shape

Constructs a new shape of unknown type.

Shape([int type = ShapeType.UNKNOWN, num radius = 0]) :
  type = type,
  radius = radius { }

bool testPoint(Transform xf, Vector p) #

See Shape.testPoint(Transform, Vector).

bool testPoint(Transform xf, Vector p) {
  Vector pLocal = new Vector();

  pLocal.setFrom(p).subLocal(xf.position);
  Matrix22.mulTransMatrixAndVectorToOut(xf.rotation, pLocal, pLocal);

  Vector temp = new Vector();

  for (int i = 0; i < vertexCount; ++i) {
    temp.setFrom(pLocal).subLocal(vertices[i]);
    if (Vector.dot(normals[i], temp) > 0)
      return false;
  }

  return true;
}

String toString() #

inherited from Object

Returns a string representation of this object.

external String toString();