How can I create concave polygons in Farseer 3.3.1?

Topics: User Forum
Nov 13, 2013 at 4:49 PM
My sprite has a concave shape and I need polygons to create a body for it. How can I do that?
How can I create a body with a concave shape?
I use this sprite: http://openclipart.org/detail/26953/myheart-by-maqndon

Here is my code to create convex polygons. How should I change my code to create concave polygons?
            Body Heart;
            Texture2D HeartSprite;
            List<Vertices> list = new List<Vertices>();
            Vector2 _origin;
            float _scale;
            HeartSprite = Content.Load<Texture2D>("heartbig");
            //create the heart
            uint[] data = new uint[HeartSprite.Width * HeartSprite.Height];
            HeartSprite.GetData(data);
            Vertices textureVertices = PolygonTools.CreatePolygon(data, HeartSprite.Width, false);
            Vector2 centroid = -textureVertices.GetCentroid();
            textureVertices.Translate(ref centroid);
            _origin = -centroid;
            textureVertices = SimplifyTools.ReduceByDistance(textureVertices, 4f);
            list = BayazitDecomposer.ConvexPartition(textureVertices);
            _scale = 1f;
            Vector2 vertScale = new Vector2(ConvertUnits.ToSimUnits(1)) * _scale;
            foreach (Vertices vertices in list)
            {
                vertices.Scale(ref vertScale);
            }

            Heart = BodyFactory.CreateCompoundPolygon(world, list, 1.0f, BodyType.Static);
            Heart.IsSensor = true;
            Heart.Position = new Vector2(4.20f, 2.00f);
            Heart.Rotation = 0f;
Nov 15, 2013 at 7:33 AM
Farseer Physics only supports Convex polygons. Generally you need to use the decomposition tools to convert one Concave polygon, to multiple Convex polygons.
See 'Convex decomposition' in the documentation.
Nov 15, 2013 at 3:17 PM
Which decomposition tool should I use for this sprite?
http://openclipart.org/detail/26953/myheart-by-maqndon
Nov 16, 2013 at 8:36 AM
Just tried in the 3.3.1 XNA texture sample:
            _polygonTexture = ScreenManager.Content.Load<Texture2D>("Samples/MyHeart");
            uint[] data = new uint[_polygonTexture.Width * _polygonTexture.Height];
            _polygonTexture.GetData(data);
            Vertices textureVertices = PolygonTools.CreatePolygon(data, _polygonTexture.Width, false);
            Vector2 centroid = -textureVertices.GetCentroid();
            textureVertices.Translate(ref centroid);
            _origin = -centroid;
            textureVertices = SimplifyTools.ReduceByDistance(textureVertices, 4f);
            List<Vertices> list = BayazitDecomposer.ConvexPartition(textureVertices);
            _scale = 1f;
            Vector2 vertScale = new Vector2(ConvertUnits.ToSimUnits(1f)) * _scale;
            foreach (Vertices vertices in list)
            {
                vertices.Scale(ref vertScale);
            }
            _compound = BodyFactory.CreateCompoundPolygon(World, list, 1f, BodyType.Dynamic);
            _compound.BodyType = BodyType.Dynamic;
And it did not have any problems. I don't see anything wrong with your code.
May I ask what the problem you are having is?
Nov 16, 2013 at 9:23 AM
I have a problem with the collision between the heart and a ball. The ball isn't falling directly through the heart when it touches both sides of the heart simultaneously. The ball stops for a second and only after that it is falling through the heart. You can see that in this video: http://de.tinypic.com/r/zy8pw3/5
Why is the ball not falling directly through the heart in this case? Something must be wrong.

On the other hand, if the ball only touches one side of the heart, it's working correctly and the ball is falling directly through the heart. You can see that in this video: http://de.tinypic.com/r/2nujfv7/5
See this thread for more informations: http://farseerphysics.codeplex.com/discussions/467231
Nov 17, 2013 at 6:35 AM
Edited Nov 17, 2013 at 6:38 AM
Your problems all seem to be related to the fact, that you are removing a body during a step.
Change:
    public bool Heart_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
    {
        if (fixtureB.CollisionCategories == Category.Cat15)
            //remove the heart body if the ball touches it
            world.RemoveBody(fixtureA.Body);
        return true;
    }
To:
    bool removeHeart = false;
    public bool Heart_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
    {
        if (fixtureB.CollisionCategories == Category.Cat15)
            //remove the heart body if the ball touches it
            removeHeart = true;
        return true;
    }
In your update method add:
    if (removeHeart)
    {
        world.RemoveBody(Heart);
        removeHeart = false;
    }
Marked as answer by Wizard999 on 11/17/2013 at 2:37 AM
Nov 17, 2013 at 10:36 AM
Thanx. It works now.