org.jbox2d.collision.shapes.PolygonShape Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of playn-jbox2d Show documentation
Show all versions of playn-jbox2d Show documentation
A GWT-compatible port of JBox2D, for use with PlayN games.
/*******************************************************************************
* Copyright (c) 2011, Daniel Murphy
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL MURPHY BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
/*
* JBox2D - A Java Port of Erin Catto's Box2D
*
* JBox2D homepage: http://jbox2d.sourceforge.net/
* Box2D homepage: http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
package org.jbox2d.collision.shapes;
import org.jbox2d.collision.AABB;
import org.jbox2d.collision.RayCastInput;
import org.jbox2d.collision.RayCastOutput;
import org.jbox2d.common.Mat22;
import org.jbox2d.common.Settings;
import org.jbox2d.common.Transform;
import org.jbox2d.common.Vec2;
//Updated to rev 100
/** A convex polygon shape. Create using Body.createShape(ShapeDef), not the ructor here. */
public class PolygonShape extends Shape {
/** Dump lots of debug information. */
private static boolean m_debug = false;
/**
* Local position of the shape centroid in parent body frame.
*/
public final Vec2 m_centroid = new Vec2();
/**
* The vertices of the shape. Note: use getVertexCount(), not m_vertices.length, to
* get number of active vertices.
*/
public final Vec2 m_vertices[];
/**
* The normals of the shape. Note: use getVertexCount(), not m_normals.length, to get
* number of active normals.
*/
public final Vec2 m_normals[];
/**
* Number of active vertices in the shape.
*/
public int m_vertexCount;
// pooling
private final Vec2 pool1 = new Vec2();
private final Vec2 pool2 = new Vec2();
private final Vec2 pool3 = new Vec2();
private final Vec2 pool4 = new Vec2();
private final Vec2 pool5 = new Vec2();
private final Vec2 pool6 = new Vec2();
private Transform poolt1 = new Transform();
public PolygonShape() {
m_type = ShapeType.POLYGON;
m_vertexCount = 0;
m_vertices = new Vec2[Settings.maxPolygonVertices];
for (int i = 0; i < m_vertices.length; i++) {
m_vertices[i] = new Vec2();
}
m_normals = new Vec2[Settings.maxPolygonVertices];
for (int i = 0; i < m_normals.length; i++) {
m_normals[i] = new Vec2();
}
m_radius = Settings.polygonRadius;
m_centroid.setZero();
}
@Override
public final Shape clone() {
PolygonShape shape = new PolygonShape();
shape.m_centroid.set(this.m_centroid);
for (int i = 0; i < shape.m_normals.length; i++) {
shape.m_normals[i].set(m_normals[i]);
shape.m_vertices[i].set(m_vertices[i]);
}
shape.m_radius = this.m_radius;
shape.m_vertexCount = this.m_vertexCount;
return shape;
}
/**
* Get the supporting vertex index in the given direction.
*
* @param d
* @return
*/
public final int getSupport(final Vec2 d) {
int bestIndex = 0;
float bestValue = Vec2.dot(m_vertices[0], d);
for (int i = 1; i < m_vertexCount; i++) {
float value = Vec2.dot(m_vertices[i], d);
if (value > bestValue) {
bestIndex = i;
bestValue = value;
}
}
return bestIndex;
}
/**
* Get the supporting vertex in the given direction.
*
* @param d
* @return
*/
public final Vec2 getSupportVertex(final Vec2 d) {
int bestIndex = 0;
float bestValue = Vec2.dot(m_vertices[0], d);
for (int i = 1; i < m_vertexCount; i++) {
float value = Vec2.dot(m_vertices[i], d);
if (value > bestValue) {
bestIndex = i;
bestValue = value;
}
}
return m_vertices[bestIndex];
}
/**
* Copy vertices. This assumes the vertices define a convex polygon.
* It is assumed that the exterior is the the right of each edge.
*/
public final void set(final Vec2[] vertices, final int count) {
assert (2 <= count && count <= Settings.maxPolygonVertices);
m_vertexCount = count;
// Copy vertices.
for (int i = 0; i < m_vertexCount; ++i) {
if(m_vertices[i] == null){
m_vertices[i] = new Vec2();
}
m_vertices[i].set(vertices[i]);
}
final Vec2 edge = pool1;
// Compute normals. Ensure the edges have non-zero length.
for (int i = 0; i < m_vertexCount; ++i) {
final int i1 = i;
final int i2 = i + 1 < m_vertexCount ? i + 1 : 0;
edge.set(m_vertices[i2]).subLocal(m_vertices[i1]);
assert (edge.lengthSquared() > Settings.EPSILON * Settings.EPSILON);
Vec2.crossToOut(edge, 1f, m_normals[i]);
m_normals[i].normalize();
}
if (m_debug) {
final Vec2 r = pool2;
// Ensure the polygon is convex and the interior
// is to the left of each edge.
for (int i = 0; i < m_vertexCount; ++i) {
final int i1 = i;
final int i2 = i + 1 < m_vertexCount ? i + 1 : 0;
edge.set(m_vertices[i2]).subLocal(m_vertices[i1]);
for (int j = 0; j < m_vertexCount; ++j) {
// Don't check vertices on the current edge.
if (j == i1 || j == i2) {
continue;
}
r.set(m_vertices[j]).subLocal(m_vertices[i1]);
// Your polygon is non-convex (it has an indentation) or
// has colinear edges.
final float s = Vec2.cross(edge, r);
assert (s > 0.0f);
}
}
}
// Compute the polygon centroid.
computeCentroidToOut(m_vertices, m_vertexCount, m_centroid);
}
/**
* Build vertices to represent an axis-aligned box.
*
* @param hx
* the half-width.
* @param hy
* the half-height.
*/
public final void setAsBox(final float hx, final float hy) {
m_vertexCount = 4;
m_vertices[0].set(-hx, -hy);
m_vertices[1].set(hx, -hy);
m_vertices[2].set(hx, hy);
m_vertices[3].set(-hx, hy);
m_normals[0].set(0.0f, -1.0f);
m_normals[1].set(1.0f, 0.0f);
m_normals[2].set(0.0f, 1.0f);
m_normals[3].set(-1.0f, 0.0f);
m_centroid.setZero();
}
/**
* Build vertices to represent an oriented box.
*
* @param hx
* the half-width.
* @param hy
* the half-height.
* @param center
* the center of the box in local coordinates.
* @param angle
* the rotation of the box in local coordinates.
*/
public final void setAsBox(final float hx, final float hy, final Vec2 center, final float angle) {
m_vertexCount = 4;
m_vertices[0].set(-hx, -hy);
m_vertices[1].set(hx, -hy);
m_vertices[2].set(hx, hy);
m_vertices[3].set(-hx, hy);
m_normals[0].set(0.0f, -1.0f);
m_normals[1].set(1.0f, 0.0f);
m_normals[2].set(0.0f, 1.0f);
m_normals[3].set(-1.0f, 0.0f);
m_centroid.set(center);
final Transform xf = poolt1;
xf.position.set(center);
xf.R.set(angle);
// Transform vertices and normals.
for (int i = 0; i < m_vertexCount; ++i) {
Transform.mulToOut(xf, m_vertices[i], m_vertices[i]);
Mat22.mulToOut(xf.R, m_normals[i], m_normals[i]);
}
}
/**
* Set this as a single edge.
*
* @param v1
* @param v2
*/
public final void setAsEdge(final Vec2 v1, final Vec2 v2) {
m_vertexCount = 2;
m_vertices[0].set(v1);
m_vertices[1].set(v2);
m_centroid.set(v1).addLocal(v2).mulLocal(0.5f);
// = 0.5f * (v1 + v2);
m_normals[0].set(v2).subLocal(v1);
Vec2.crossToOut(m_normals[0], 1f, m_normals[0]);
// m_normals[0] = Cross(v2 - v1, 1.0f);
m_normals[0].normalize();
m_normals[1].set(m_normals[0]).negateLocal();
}
/**
* @see Shape#testPoint(Transform, Vec2)
*/
@Override
public final boolean testPoint(final Transform xf, final Vec2 p) {
final Vec2 pLocal = pool1;
pLocal.set(p).subLocal(xf.position);
Mat22.mulTransToOut(xf.R, pLocal, pLocal);
if (m_debug) {
System.out.println("--testPoint debug--");
System.out.println("Vertices: ");
for (int i = 0; i < m_vertexCount; ++i) {
System.out.println(m_vertices[i]);
}
System.out.println("pLocal: " + pLocal);
}
final Vec2 temp = pool2;
for (int i = 0; i < m_vertexCount; ++i) {
temp.set(pLocal).subLocal(m_vertices[i]);
final float dot = Vec2.dot(m_normals[i], temp);
if (dot > 0.0f) {
return false;
}
}
return true;
}
/**
* @see Shape#computeAABB(AABB, Transform)
*/
@Override
public final void computeAABB(final AABB argAabb, final Transform argXf) {
final Vec2 lower = pool1;
final Vec2 upper = pool2;
final Vec2 v = pool3;
Transform.mulToOut(argXf, m_vertices[0], lower);
upper.set(lower);
for (int i = 1; i < m_vertexCount; ++i) {
Transform.mulToOut(argXf, m_vertices[i], v);
// Vec2 v = Mul(xf, m_vertices[i]);
Vec2.minToOut(lower, v, lower);
Vec2.maxToOut(upper, v, upper);
}
// Vec2 r(m_radius, m_radius);
// aabb->lowerBound = lower - r;
// aabb->upperBound = upper + r;
argAabb.lowerBound.x = lower.x - m_radius;
argAabb.lowerBound.y = lower.y - m_radius;
argAabb.upperBound.x = upper.x + m_radius;
argAabb.upperBound.y = upper.y + m_radius;
}
// djm pooling, and from above
/*
* private static final TLVec2 tlNormalL = new TLVec2();
* private static final TLMassData tlMd = new TLMassData();
* private static final FloatArray tldepths = new FloatArray();
* private static final TLVec2 tlIntoVec = new TLVec2();
* private static final TLVec2 tlOutoVec = new TLVec2();
* private static final TLVec2 tlP2b = new TLVec2();
* private static final TLVec2 tlP3 = new TLVec2();
* private static final TLVec2 tlcenter = new TLVec2();
* /*
* @see Shape#computeSubmergedArea(Vec2, float, XForm, Vec2)
* public float computeSubmergedArea(final Vec2 normal, float offset, Transform xf,
* Vec2 c) {
* final Vec2 normalL = tlNormalL.get();
* final MassData md = tlMd.get();
* //Transform plane into shape co-ordinates
* Mat22.mulTransToOut(xf.R,normal, normalL);
* float offsetL = offset - Vec2.dot(normal,xf.position);
* final Float[] depths = tldepths.get(Settings.maxPolygonVertices);
* int diveCount = 0;
* int intoIndex = -1;
* int outoIndex = -1;
* boolean lastSubmerged = false;
* int i = 0;
* for (i = 0; i < m_vertexCount; ++i){
* depths[i] = Vec2.dot(normalL,m_vertices[i]) - offsetL;
* boolean isSubmerged = depths[i]<-Settings.EPSILON;
* if (i > 0){
* if (isSubmerged){
* if (!lastSubmerged){
* intoIndex = i-1;
* diveCount++;
* }
* }
* else{
* if (lastSubmerged){
* outoIndex = i-1;
* diveCount++;
* }
* }
* }
* lastSubmerged = isSubmerged;
* }
* switch(diveCount){
* case 0:
* if (lastSubmerged){
* //Completely submerged
* computeMass(md, 1.0f);
* Transform.mulToOut(xf,md.center, c);
* return md.mass;
* }
* else{
* return 0;
* }
* case 1:
* if(intoIndex==-1){
* intoIndex = m_vertexCount-1;
* }
* else{
* outoIndex = m_vertexCount-1;
* }
* break;
* }
* final Vec2 intoVec = tlIntoVec.get();
* final Vec2 outoVec = tlOutoVec.get();
* final Vec2 e1 = tle1.get();
* final Vec2 e2 = tle2.get();
* int intoIndex2 = (intoIndex+1) % m_vertexCount;
* int outoIndex2 = (outoIndex+1) % m_vertexCount;
* float intoLambda = (0 - depths[intoIndex]) / (depths[intoIndex2] -
* depths[intoIndex]);
* float outoLambda = (0 - depths[outoIndex]) / (depths[outoIndex2] -
* depths[outoIndex]);
* intoVec.set(m_vertices[intoIndex].x*(1-intoLambda)+m_vertices[intoIndex2].x*intoLambda
* ,
* m_vertices[intoIndex].y*(1-intoLambda)+m_vertices[intoIndex2].y*intoLambda);
* outoVec.set(m_vertices[outoIndex].x*(1-outoLambda)+m_vertices[outoIndex2].x*outoLambda
* ,
* m_vertices[outoIndex].y*(1-outoLambda)+m_vertices[outoIndex2].y*outoLambda);
* // Initialize accumulator
* float area = 0;
* final Vec2 center = tlcenter.get();
* center.setZero();
* final Vec2 p2b = tlP2b.get().set(m_vertices[intoIndex2]);
* final Vec2 p3 = tlP3.get();
* p3.setZero();
* float k_inv3 = 1.0f / 3.0f;
* // An awkward loop from intoIndex2+1 to outIndex2
* i = intoIndex2;
* while (i != outoIndex2){
* i = (i+1) % m_vertexCount;
* if (i == outoIndex2){
* p3.set(outoVec);
* }
* else{
* p3.set(m_vertices[i]);
* }
* // Add the triangle formed by intoVec,p2,p3
* {
* e1.set(p2b).subLocal(intoVec);
* e2.set(p3).subLocal(intoVec);
* float D = Vec2.cross(e1, e2);
* float triangleArea = 0.5f * D;
* area += triangleArea;
* // Area weighted centroid
* center.x += triangleArea * k_inv3 * (intoVec.x + p2b.x + p3.x);
* center.y += triangleArea * k_inv3 * (intoVec.y + p2b.y + p3.y);
* }
* //
* p2b.set(p3);
* }
* // Normalize and transform centroid
* center.x *= 1.0f / area;
* center.y *= 1.0f / area;
* Transform.mulToOut(xf, center, c);
* return area;
* }
*/
/*
* Get the supporting vertex index in the given direction.
* @param d
* @return
* public final int getSupport( final Vec2 d){
* int bestIndex = 0;
* float bestValue = Vec2.dot(m_vertices[0], d);
* for (int i = 1; i < m_vertexCount; ++i){
* final float value = Vec2.dot(m_vertices[i], d);
* if (value > bestValue){
* bestIndex = i;
* bestValue = value;
* }
* }
* return bestIndex;
* }
* /**
* Get the supporting vertex in the given direction.
* @param d
* @return
* public final Vec2 getSupportVertex( final Vec2 d){
* int bestIndex = 0;
* float bestValue = Vec2.dot(m_vertices[0], d);
* for (int i = 1; i < m_vertexCount; ++i){
* final float value = Vec2.dot(m_vertices[i], d);
* if (value > bestValue){
* bestIndex = i;
* bestValue = value;
* }
* }
* return m_vertices[bestIndex];
* }
*/
/**
* Get the vertex count.
*
* @return
*/
public final int getVertexCount() {
return m_vertexCount;
}
/**
* Get a vertex by index.
*
* @param index
* @return
*/
public final Vec2 getVertex(final int index) {
assert (0 <= index && index < m_vertexCount);
return m_vertices[index];
}
/**
* @see org.jbox2d.collision.shapes.Shape#raycast(RayCastOutput, RayCastInput, Transform)
*/
@Override
public final boolean raycast(RayCastOutput argOutput, RayCastInput argInput, Transform argXf) {
final Vec2 p1 = pool1;
final Vec2 p2 = pool2;
final Vec2 d = pool3;
final Vec2 temp = pool4;
p1.set(argInput.p1).subLocal(argXf.position);
Mat22.mulTransToOut(argXf.R, p1, p1);
p2.set(argInput.p2).subLocal(argXf.position);
Mat22.mulTransToOut(argXf.R, p2, p2);
d.set(p2).subLocal(p1);
if (m_vertexCount == 2) {
Vec2 v1 = m_vertices[0];
Vec2 v2 = m_vertices[1];
Vec2 normal = m_normals[0];
// q = p1 + t * d
// dot(normal, q - v1) = 0
// dot(normal, p1 - v1) + t * dot(normal, d) = 0
temp.set(v1).subLocal(p1);
float numerator = Vec2.dot(normal, temp);
float denominator = Vec2.dot(normal, d);
if (denominator == 0.0f) {
return false;
}
float t = numerator / denominator;
if (t < 0.0f || 1.0f < t) {
return false;
}
final Vec2 q = pool5;
final Vec2 r = pool6;
// Vec2 q = p1 + t * d;
temp.set(d).mulLocal(t);
q.set(p1).addLocal(temp);
// q = v1 + s * r
// s = dot(q - v1, r) / dot(r, r)
// Vec2 r = v2 - v1;
r.set(v2).subLocal(v1);
float rr = Vec2.dot(r, r);
if (rr == 0.0f) {
return false;
}
temp.set(q).subLocal(v1);
float s = Vec2.dot(temp, r) / rr;
if (s < 0.0f || 1.0f < s) {
return false;
}
argOutput.fraction = t;
if (numerator > 0.0f) {
// argOutput.normal = -normal;
argOutput.normal.set(normal).mulLocal(-1);
}
else {
// output.normal = normal;
argOutput.normal.set(normal);
}
return true;
}
else {
float lower = 0, upper = argInput.maxFraction;
int index = -1;
for (int i = 0; i < m_vertexCount; ++i) {
// p = p1 + a * d
// dot(normal, p - v) = 0
// dot(normal, p1 - v) + a * dot(normal, d) = 0
temp.set(m_vertices[i]).subLocal(p1);
final float numerator = Vec2.dot(m_normals[i], temp);
final float denominator = Vec2.dot(m_normals[i], d);
if (denominator == 0.0f) {
if (numerator < 0.0f) {
return false;
}
}
else {
// Note: we want this predicate without division:
// lower < numerator / denominator, where denominator < 0
// Since denominator < 0, we have to flip the inequality:
// lower < numerator / denominator <==> denominator * lower >
// numerator.
if (denominator < 0.0f && numerator < lower * denominator) {
// Increase lower.
// The segment enters this half-space.
lower = numerator / denominator;
index = i;
}
else if (denominator > 0.0f && numerator < upper * denominator) {
// Decrease upper.
// The segment exits this half-space.
upper = numerator / denominator;
}
}
if (upper < lower) {
return false;
}
}
assert (0.0f <= lower && lower <= argInput.maxFraction);
if (index >= 0) {
argOutput.fraction = lower;
Mat22.mulToOut(argXf.R, m_normals[index], argOutput.normal);
// normal = Mul(xf.R, m_normals[index]);
return true;
}
}
return false;
}
public final void computeCentroidToOut(final Vec2[] vs, final int count, final Vec2 out) {
assert (count >= 3);
out.set(0.0f, 0.0f);
float area = 0.0f;
if (count == 2) {
out.set(vs[0]).addLocal(vs[1]).mulLocal(.5f);
return;
}
// pRef is the reference point for forming triangles.
// It's location doesn't change the result (except for rounding error).
final Vec2 pRef = pool1;
pRef.setZero();
final Vec2 e1 = pool2;
final Vec2 e2 = pool3;
final float inv3 = 1.0f / 3.0f;
for (int i = 0; i < count; ++i) {
// Triangle vertices.
final Vec2 p1 = pRef;
final Vec2 p2 = vs[i];
final Vec2 p3 = i + 1 < count ? vs[i + 1] : vs[0];
e1.set(p2).subLocal(p1);
e2.set(p3).subLocal(p1);
final float D = Vec2.cross(e1, e2);
final float triangleArea = 0.5f * D;
area += triangleArea;
// Area weighted centroid
out.addLocal(p1).addLocal(p2).addLocal(p3).mulLocal(triangleArea * inv3);
}
// Centroid
assert (area > Settings.EPSILON);
out.mulLocal(1.0f / area);
}
/**
* @see Shape#computeMass(MassData, float)
*/
@Override
public void computeMass(final MassData massData, float 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 (m_vertexCount >= 2);
// A line segment has zero mass.
if (m_vertexCount == 2) {
// massData.center = 0.5f * (m_vertices[0] + m_vertices[1]);
massData.center.set(m_vertices[0]).addLocal(m_vertices[1]).mulLocal(0.5f);
massData.mass = 0.0f;
massData.I = 0.0f;
return;
}
final Vec2 center = pool1;
center.setZero();
float area = 0.0f;
float I = 0.0f;
// pRef is the reference point for forming triangles.
// It's location doesn't change the result (except for rounding error).
final Vec2 pRef = pool2;
pRef.setZero();
final float k_inv3 = 1.0f / 3.0f;
final Vec2 e1 = pool3;
final Vec2 e2 = pool4;
for (int i = 0; i < m_vertexCount; ++i) {
// Triangle vertices.
final Vec2 p1 = pRef;
final Vec2 p2 = m_vertices[i];
final Vec2 p3 = i + 1 < m_vertexCount ? m_vertices[i + 1] : m_vertices[0];
e1.set(p2);
e1.subLocal(p1);
e2.set(p3);
e2.subLocal(p1);
final float D = Vec2.cross(e1, e2);
final float triangleArea = 0.5f * 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 float px = p1.x, py = p1.y;
final float ex1 = e1.x, ey1 = e1.y;
final float ex2 = e2.x, ey2 = e2.y;
final float intx2 = k_inv3 * (0.25f * (ex1 * ex1 + ex2 * ex1 + ex2 * ex2) + (px * ex1 + px * ex2)) + 0.5f
* px * px;
final float inty2 = k_inv3 * (0.25f * (ey1 * ey1 + ey2 * ey1 + ey2 * ey2) + (py * ey1 + py * ey2)) + 0.5f
* py * py;
I += D * (intx2 + inty2);
}
// Total mass
massData.mass = density * area;
// Center of mass
assert (area > Settings.EPSILON);
center.mulLocal(1.0f / area);
massData.center.set(center);
// Inertia tensor relative to the local origin.
massData.I = I * density;
}
/*
* Get the local centroid relative to the parent body. /
* public Vec2 getCentroid() {
* return m_centroid.clone();
* }
*/
/** Get the vertices in local coordinates. */
public Vec2[] getVertices() {
return m_vertices;
}
/** Get the edge normal vectors. There is one for each vertex. */
public Vec2[] getNormals() {
return m_normals;
}
/** Get the centroid and apply the supplied transform. */
public Vec2 centroid(final Transform xf) {
return Transform.mul(xf, m_centroid);
}
/** Get the centroid and apply the supplied transform. */
public Vec2 centroidToOut(final Transform xf, final Vec2 out) {
Transform.mulToOut(xf, m_centroid, out);
return out;
}
}