vrld / HC

General purpose collision detection library for the use with LÖVE.
http://hc.readthedocs.org/
404 stars 48 forks source link

Triangulate function can cause sub-polygons with 0 vertices after removing collinears, hence throwing error on assert #55

Closed martin-braun closed 6 years ago

martin-braun commented 6 years ago

When creating a polygon in HC, it will start to "triangulate" the polygon, meaning to create a lot of sub polygons with three points each. So I have created my debug case to follow up what is happening exactly.

print("polygon points", 0,0 , 12,0 , 12,4 , 11,4 , 11,5 , 5,5 , 5,4 , 0,4 , 0,0)
shape = collider:polygon(0,0 , 12,0 , 12,4 , 11,4 , 11,5 , 5,5 , 5,4 , 0,4 , 0,0)

this is my call

I added two prints in polygon.lua from HC:

function Polygon:init(...)
    local vertices = removeCollinear( toVertexList({}, ...) )
    print("Num of vertices after calling removeCollinear", #vertices) -- my added line
    assert(#vertices >= 3, "Need at least 3 non collinear points to build polygon (got "..#vertices..")")
 -- function continues here
print("Triangulates", p.x,p.y, q.x,q.y, r.x,r.y) -- added line
triangles[#triangles+1] = newPolygon(p.x,p.y, q.x,q.y, r.x,r.y) -- this does HC at Polygon:triangulate()

Output: image

Here is the polygon (green) and it's triangulated polygons (blue). At last it tries to triangulate the polygon with the red dots, all in one line, hence it throws that error.

image

Obviously, when triangulating a polygon that has no collinears, there is a risk you end up with a polygon that has collinears again. In this example, HC seems to pick three points of the resulting shape in a sub step of triangulating that are all collinears, hence HC will try to create a polygon with 0 vertices, after removing all collinears of that new sub triangle polygon shape.

Internally, this happens for two reasons.

  1. the removeCollinear function removes the first and the last dot, because they are on the same spot. This is wrong. Even when having the same start and end dot is wrong, it should at least keep one of those.

  2. The shape that is left over by the bug above (12,0 , 12,4 , 11,4 , 11,5 , 5,5 , 5,4 , 0,4) causes HC to try to form a sub polygon with 3 collinears (11,4 , 5,4 , 0,4). I tried to overcome this problem by using the triangulate function of LÖVE (love.math.triangulate), but it also returns a triangle with that coordinates. Regardless if this is a bug or not, HC should check if the dots are collinears before trying to create a triangle for the shape.