diff --git a/panda/src/collide/collisionPolygon.cxx b/panda/src/collide/collisionPolygon.cxx index 0e25e5a57f..9f82ff811c 100644 --- a/panda/src/collide/collisionPolygon.cxx +++ b/panda/src/collide/collisionPolygon.cxx @@ -67,6 +67,11 @@ make_copy() { // Description: Verifies that the indicated set of points will define // a valid CollisionPolygon: that is, at least three // non-collinear points, with no points repeated. +// +// This does not check that the polygon defined is +// convex; that check is made later, once we have +// projected the points to 2-d space where the decision +// is easier. //////////////////////////////////////////////////////////////////// bool CollisionPolygon:: verify_points(const LPoint3f *begin, const LPoint3f *end) { @@ -477,6 +482,47 @@ is_inside(const LPoint2f &p) const { } +//////////////////////////////////////////////////////////////////// +// Function: CollisionPolygon::is_concave +// Access: Private +// Description: Returns true if the CollisionPolygon is concave +// (which is an error), or false otherwise. +//////////////////////////////////////////////////////////////////// +bool CollisionPolygon:: +is_concave() const { + nassertr(_points.size() >= 3, true); + + LPoint2f p0 = _points[0]; + LPoint2f p1 = _points[1]; + float dx1 = p1[0] - p0[0]; + float dy1 = p1[1] - p0[1]; + p0 = p1; + p1 = _points[2]; + + float dx2 = p1[0] - p0[0]; + float dy2 = p1[1] - p0[1]; + int asum = ((dx1 * dy2 - dx2 * dy1 >= 0.0) ? 1 : 0); + + for (size_t i = 0; i < _points.size() - 1; i++) { + p0 = p1; + p1 = _points[(i+3) % _points.size()]; + + dx1 = dx2; + dy1 = dy2; + dx2 = p1[0] - p0[0]; + dy2 = p1[1] - p0[1]; + int csum = ((dx1 * dy2 - dx2 * dy1 >= 0.0) ? 1 : 0); + + if (csum ^ asum) { + // Oops, the polygon is concave. + return true; + } + } + + // The polygon is safely convex. + return false; +} + //////////////////////////////////////////////////////////////////// // Function: CollisionPolygon::setup_points // Access: Private @@ -587,6 +633,20 @@ setup_points(const LPoint3f *begin, const LPoint3f *end) { _median += _points[n]; } _median /= _points.size(); + +#ifndef NDEBUG + // Now make sure the points define a convex polygon. + if (is_concave()) { + collide_cat.error() << "Invalid concave CollisionPolygon defined:\n"; + const LPoint3f *pi; + for (pi = begin; pi != end; ++pi) { + collide_cat.error(false) << " " << (*pi) << "\n"; + } + collide_cat.error(false) + << " normal " << normal << " with length " << normal.length() << "\n"; + _points.clear(); + } +#endif } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/collide/collisionPolygon.h b/panda/src/collide/collisionPolygon.h index fe4eda5bd4..9a459bf76c 100644 --- a/panda/src/collide/collisionPolygon.h +++ b/panda/src/collide/collisionPolygon.h @@ -65,6 +65,7 @@ protected: private: bool is_inside(const LPoint2f &p) const; + bool is_concave() const; void setup_points(const LPoint3f *begin, const LPoint3f *end); LPoint2f to_2d(const LPoint3f &point3d) const; diff --git a/panda/src/egg/eggPolygon.I b/panda/src/egg/eggPolygon.I index ad082930aa..22a9e0d0cf 100644 --- a/panda/src/egg/eggPolygon.I +++ b/panda/src/egg/eggPolygon.I @@ -74,6 +74,6 @@ recompute_polygon_normal() { //////////////////////////////////////////////////////////////////// INLINE bool EggPolygon:: triangulate_into(EggGroupNode *container, bool convex_also) const { - EggPolygon *copy = new EggPolygon(*this); + PT(EggPolygon) copy = new EggPolygon(*this); return copy->triangulate_poly(container, convex_also); } diff --git a/panda/src/egg/eggPolygon.cxx b/panda/src/egg/eggPolygon.cxx index e42d8ec972..36a0b6a566 100644 --- a/panda/src/egg/eggPolygon.cxx +++ b/panda/src/egg/eggPolygon.cxx @@ -307,6 +307,10 @@ decomp_concave(EggGroupNode *container, int asum, int x, int y) const { // otherwise, only concave polygons will be subdivided, // and convex polygons will be copied unchanged into the // container. +// +// It is assumed that the EggPolygon is not already a +// child of any other group when this function is +// called. //////////////////////////////////////////////////////////////////// bool EggPolygon:: triangulate_poly(EggGroupNode *container, bool convex_also) { diff --git a/panda/src/egg2sg/eggLoader.cxx b/panda/src/egg2sg/eggLoader.cxx index 622706c31a..502fc58827 100644 --- a/panda/src/egg2sg/eggLoader.cxx +++ b/panda/src/egg2sg/eggLoader.cxx @@ -1818,6 +1818,7 @@ create_collision_polygons(CollisionNode *cnode, EggPolygon *egg_poly, EggGroup::CollideFlags flags) { PT(EggGroup) group = new EggGroup; + if (!egg_poly->triangulate_into(group, false)) { egg2sg_cat.warning() << "Degenerate collision polygon in " << parent_group->get_name()