[faq] why is drawing or collision off center? (Centroids CreatePolygonBody CreatePolygonGeom)

May 15, 2009 at 9:18 AM
Edited Jun 22, 2009 at 12:40 PM

the problem: you create a rectangle with CreateRectangleBody and everything works fine. you create the same rectangle with CreatePolygonBody and the drawing or collision seems to be off center and behaves strangely. the problem are usually the Centroids.

keep in mind that a Body is just a point, is just a point, IS JUST A POINT! CreatePolygonBody() is a convenience method to calculate a correct MomentOfInertia (MOI) for the given polygon. the Body will still be only a point. when you create a Body via CreatePolygonBody you provide absolute vertices. the Bodys position is however probably not where you might expect it. have a look at the internal code:

public Body CreatePolygonBody( Vertices vertices, float mass )
{
Body body = new Body();
body.Mass = mass;
body.MomentOfInertia = mass * vertices.GetMomentOfInertia();
body.position = vertices.GetCentroid();
return body;
}

what Farseer does here is to calculate the corresponding MOI from the polygon. the MOI is independent from the absolute vertex positions. the actual position of the Body is then set to the centroid (in absolute coordinates). so either you know where the centroid position will be after creating the polygon Body (usually when defining the Body by an external vector application) or you set it where you want afterwards via Body::SetPosition(). so CreatePolygonBody() was just calculating the MOI and used the absolute centroid position as a good starting position. if you want a differnt one, just set your own position afters. this is not a problem, because as we should know now already, a Body is just a point.

when you create a Geom via CreatePolygonGeom(), Farseer doesn't care if you specify it in absolute or relative vertices. have a look at the corresponding code:

public Geom CreatePolygonGeom( Body body, Vertices vertices, Vector2 offset, float rotationOffset, float collisionGridCellSize )
{
//adjust the verts to be relative to 0,0
Vector2 centroid = vertices.GetCentroid();
vertices.Translate( -centroid );
if( collisionGridCellSize <= 0 )
{
collisionGridCellSize = CalculateGridCellSizeFromAABB( vertices );
}
Geom geometry = new Geom( body, vertices, offset, rotationOffset, collisionGridCellSize );
return geometry;
}

Farseer calculates the centroid of the Geom and translates all vertices relative to 0, 0 (which will be relative to its Body afterwards). after normalizing the Geom relative to the body, all vertices are translate by the offset parameter. hence, independent if you specify the vertices in absolute or relative coordinates, they Geom is first centered around the Body and then translated by the offset.

also have a look here: http://www.codeplex.com/FarseerPhysics/Thread/View.aspx?ThreadId=19911