piqnt / planck.js

2D JavaScript Physics Engine
http://piqnt.com/planck.js/
MIT License
4.88k stars 236 forks source link

Convex shape test fails #218

Closed quinton-ashley closed 2 years ago

quinton-ashley commented 2 years ago

Hi it's me again, I'm still working on integrating planck in p5.play v3

I want to make it so that closed non-convex shapes will not become polygons, they will become chains. In this example the big hourglass object should be a chain not a rectangle.

https://molleindustria.github.io/p5.play/examples/v3.html?fileName=hourglass.js

I tried to used the validate function from the PolygonShape class but it didn't really work. It always returns false so I'm not using it currently.

Is there something I'm missing here?

/**
* Validate convexity. This is a very time consuming operation.
* TODO: This function I copied from planck's source seemingly doesn't work.
*
* @private
* @returns true if valid
*/
_isConvexPoly(vecs) {
    for (let i = 0; i < vecs.length; ++i) {
        const i1 = i;
        const i2 = i < vecs.length - 1 ? i1 + 1 : 0;
        const p = vecs[i1];
        const e = pl.Vec2.sub(vecs[i2], p);

        for (let j = 0; j < vecs.length; ++j) {
            if (j == i1 || j == i2) {
                continue;
            }

            const v = pl.Vec2.sub(vecs[j], p);
            const c = pl.Vec2.cross(e, v);
            if (c < 0.0) {
                return false;
            }
        }
    }

    return true;
}
zOadT commented 2 years ago

Could you provide an example that doesn't work? I just checked an easy case and it worked there. Maybe one thing to keep in mind is that the order of vertices matter (i.e. it is possible that _isConvexPoly(vecs) returns false while _isConvexPoly(vecs.reverse()) returns true)

quinton-ashley commented 2 years ago

This hourglass shape is not convex, the function should return false:

[
    {
        "x": -1.7666666666666677,
        "y": -2.886751345948129
    },
    {
        "x": -0.10000000000000048,
        "y": -4.736951571734001e-16
    },
    {
        "x": -1.7666666666666664,
        "y": 2.886751345948129
    },
    {
        "x": 1.7666666666666666,
        "y": 2.886751345948129
    },
    {
        "x": 0.10000000000000071,
        "y": 0
    },
    {
        "x": 1.7666666666666677,
        "y": -2.8867513459481287
    },
    {
        "x": -1.7666666666666657,
        "y": -2.886751345948129
    }
]

Here is a hexagon that is convex:

[
    {
        "x": 0.6666666666666666,
        "y": -1.1547005383792515
    },
    {
        "x": 1.3333333333333333,
        "y": 8.972490118592747e-17
    },
    {
        "x": 0.6666666666666672,
        "y": 1.1547005383792515
    },
    {
        "x": -0.6666666666666662,
        "y": 1.1547005383792515
    },
    {
        "x": -1.3333333333333333,
        "y": 8.972490118592747e-17
    },
    {
        "x": -0.6666666666666666,
        "y": -1.1547005383792515
    },
    {
        "x": 0.6666666666666666,
        "y": -1.1547005383792517
    }
]

I think it's a rounding error cause c is just barely negative, having a value of -1.4802973661668753e-16

zOadT commented 2 years ago

Ah ok, the problem is that you define your starting point twice.

_isConvexPoly([
    {
        "x": 0.6666666666666666,
        "y": -1.1547005383792515
    },
    {
        "x": 1.3333333333333333,
        "y": 8.972490118592747e-17
    },
    {
        "x": 0.6666666666666672,
        "y": 1.1547005383792515
    },
    {
        "x": -0.6666666666666662,
        "y": 1.1547005383792515
    },
    {
        "x": -1.3333333333333333,
        "y": 8.972490118592747e-17
    },
    {
        "x": -0.6666666666666666,
        "y": -1.1547005383792515
    }
])

returns true

quinton-ashley commented 2 years ago

Ah nice, slicing off the last point worked! Thank you :)