mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
fix long, skinny polygon bug
This commit is contained in:
parent
f19767bc37
commit
30a9478362
@ -140,6 +140,31 @@ flush_level() {
|
|||||||
_test_pcollector.flush_level();
|
_test_pcollector.flush_level();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: CollisionPolygon::is_right
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: Returns true if the 2-d v1 is to the right of v2.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE bool CollisionPolygon::
|
||||||
|
is_right(const LVector2f &v1, const LVector2f &v2) {
|
||||||
|
return (v1[0] * v2[1] - v1[1] * v2[0]) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: CollisionPolygon::dist_to_line
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: Returns the linear distance of p to the line defined
|
||||||
|
// by f and f+v, where v is a normalized vector. The
|
||||||
|
// result is negative if p is left of the line, positive
|
||||||
|
// if it is right of the line.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE float CollisionPolygon::
|
||||||
|
dist_to_line(const LPoint2f &p,
|
||||||
|
const LPoint2f &f, const LVector2f &v) {
|
||||||
|
LVector2f v1 = (p - f);
|
||||||
|
return (v1[0] * v[1] - v1[1] * v[0]);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: CollisionPolygon::to_2d
|
// Function: CollisionPolygon::to_2d
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -170,7 +195,7 @@ calc_to_3d_mat(LMatrix4f &to_3d_mat) const {
|
|||||||
|
|
||||||
// The up vector, on the other hand, is completely arbitrary.
|
// The up vector, on the other hand, is completely arbitrary.
|
||||||
|
|
||||||
look_at(to_3d_mat, get_plane().get_normal(),
|
look_at(to_3d_mat, -get_plane().get_normal(),
|
||||||
LVector3f(0.0f, 0.0f, 1.0f), CS_zup_right);
|
LVector3f(0.0f, 0.0f, 1.0f), CS_zup_right);
|
||||||
to_3d_mat.set_row(3, get_plane().get_point());
|
to_3d_mat.set_row(3, get_plane().get_point());
|
||||||
}
|
}
|
||||||
|
@ -48,30 +48,6 @@ PStatCollector CollisionPolygon::_volume_pcollector("Collision Volumes:Collision
|
|||||||
PStatCollector CollisionPolygon::_test_pcollector("Collision Tests:CollisionPolygon");
|
PStatCollector CollisionPolygon::_test_pcollector("Collision Tests:CollisionPolygon");
|
||||||
TypeHandle CollisionPolygon::_type_handle;
|
TypeHandle CollisionPolygon::_type_handle;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: is_right
|
|
||||||
// Description: Returns true if the 2-d v1 is to the right of v2.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
INLINE bool
|
|
||||||
is_right(const LVector2f &v1, const LVector2f &v2) {
|
|
||||||
return (-v1[0] * v2[1] + v1[1] * v2[0]) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: dist_to_line
|
|
||||||
// Description: Returns the linear distance of p to the line defined
|
|
||||||
// by f and f+v, where v is a normalized vector. The
|
|
||||||
// result is negative if p is left of the line, positive
|
|
||||||
// if it is right of the line.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
INLINE float
|
|
||||||
dist_to_line(const LPoint2f &p,
|
|
||||||
const LPoint2f &f, const LVector2f &v) {
|
|
||||||
LVector2f v1 = (p - f);
|
|
||||||
return (-v1[0] * v[1] + v1[1] * v[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: CollisionPolygon::Copy Constructor
|
// Function: CollisionPolygon::Copy Constructor
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -234,6 +210,7 @@ xform(const LMatrix4f &mat) {
|
|||||||
rederive_to_3d_mat(to_3d_mat);
|
rederive_to_3d_mat(to_3d_mat);
|
||||||
|
|
||||||
pvector<LPoint3f> verts;
|
pvector<LPoint3f> verts;
|
||||||
|
verts.reserve(_points.size());
|
||||||
Points::const_iterator pi;
|
Points::const_iterator pi;
|
||||||
for (pi = _points.begin(); pi != _points.end(); ++pi) {
|
for (pi = _points.begin(); pi != _points.end(); ++pi) {
|
||||||
verts.push_back(to_3d((*pi)._p, to_3d_mat) * mat);
|
verts.push_back(to_3d((*pi)._p, to_3d_mat) * mat);
|
||||||
@ -824,6 +801,126 @@ fill_viz_geom() {
|
|||||||
draw_polygon(_viz_geom, _bounds_viz_geom, _points);
|
draw_polygon(_viz_geom, _bounds_viz_geom, _points);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: CollisionPolygon::dist_to_line_segment
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: Returns the linear distance of p to the line segment
|
||||||
|
// defined by f and t, where v = (t - f).normalize().
|
||||||
|
// The result is negative if p is left of the line,
|
||||||
|
// positive if it is right of the line. If the result
|
||||||
|
// is positive, it is constrained by endpoints of the
|
||||||
|
// line segment (i.e. the result might be larger than it
|
||||||
|
// would be for a straight distance-to-line test). If
|
||||||
|
// the result is negative, we don't bother.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
float CollisionPolygon::
|
||||||
|
dist_to_line_segment(const LPoint2f &p,
|
||||||
|
const LPoint2f &f, const LPoint2f &t,
|
||||||
|
const LVector2f &v) {
|
||||||
|
LVector2f v1 = (p - f);
|
||||||
|
float d = (v1[0] * v[1] - v1[1] * v[0]);
|
||||||
|
if (d < 0.0f) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the nearest point on the line.
|
||||||
|
LPoint2f q = p + LVector2f(-v[1], v[0]) * d;
|
||||||
|
|
||||||
|
// Now constrain that point to the line segment.
|
||||||
|
if (v[0] > 0.0f) {
|
||||||
|
// X+
|
||||||
|
if (v[1] > 0.0f) {
|
||||||
|
// Y+
|
||||||
|
if (v[0] > v[1]) {
|
||||||
|
// X-dominant.
|
||||||
|
if (q[0] < f[0]) {
|
||||||
|
return (p - f).length();
|
||||||
|
} if (q[0] > t[0]) {
|
||||||
|
return (p - t).length();
|
||||||
|
} else {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Y-dominant.
|
||||||
|
if (q[1] < f[1]) {
|
||||||
|
return (p - f).length();
|
||||||
|
} if (q[1] > t[1]) {
|
||||||
|
return (p - t).length();
|
||||||
|
} else {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Y-
|
||||||
|
if (v[0] > -v[1]) {
|
||||||
|
// X-dominant.
|
||||||
|
if (q[0] < f[0]) {
|
||||||
|
return (p - f).length();
|
||||||
|
} if (q[0] > t[0]) {
|
||||||
|
return (p - t).length();
|
||||||
|
} else {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Y-dominant.
|
||||||
|
if (q[1] > f[1]) {
|
||||||
|
return (p - f).length();
|
||||||
|
} if (q[1] < t[1]) {
|
||||||
|
return (p - t).length();
|
||||||
|
} else {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// X-
|
||||||
|
if (v[1] > 0.0f) {
|
||||||
|
// Y+
|
||||||
|
if (-v[0] > v[1]) {
|
||||||
|
// X-dominant.
|
||||||
|
if (q[0] > f[0]) {
|
||||||
|
return (p - f).length();
|
||||||
|
} if (q[0] < t[0]) {
|
||||||
|
return (p - t).length();
|
||||||
|
} else {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Y-dominant.
|
||||||
|
if (q[1] < f[1]) {
|
||||||
|
return (p - f).length();
|
||||||
|
} if (q[1] > t[1]) {
|
||||||
|
return (p - t).length();
|
||||||
|
} else {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Y-
|
||||||
|
if (-v[0] > -v[1]) {
|
||||||
|
// X-dominant.
|
||||||
|
if (q[0] > f[0]) {
|
||||||
|
return (p - f).length();
|
||||||
|
} if (q[0] < t[0]) {
|
||||||
|
return (p - t).length();
|
||||||
|
} else {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Y-dominant.
|
||||||
|
if (q[1] > f[1]) {
|
||||||
|
return (p - f).length();
|
||||||
|
} if (q[1] < t[1]) {
|
||||||
|
return (p - t).length();
|
||||||
|
} else {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: CollisionPolygon::compute_vectors
|
// Function: CollisionPolygon::compute_vectors
|
||||||
// Access: Private, Static
|
// Access: Private, Static
|
||||||
@ -933,18 +1030,37 @@ dist_to_polygon(const LPoint2f &p, const CollisionPolygon::Points &points) const
|
|||||||
|
|
||||||
// We know that that the polygon is convex and is defined with the
|
// We know that that the polygon is convex and is defined with the
|
||||||
// points in counterclockwise order. Therefore, we simply compare
|
// points in counterclockwise order. Therefore, we simply compare
|
||||||
// the signed distance to each line; the answer is the maximum of
|
// the signed distance to each line segment; we ignore any negative
|
||||||
// these. (This doesn't quite get the right answer if the closest
|
// values, and take the minimum of all the positive values.
|
||||||
// part of the polygon is one of the vertices, but it's close enough
|
|
||||||
// for these purposes.)
|
|
||||||
|
|
||||||
float max_dist = dist_to_line(p, points.front()._p, points.front()._v);
|
// If all values are negative, the point is within the polygon; we
|
||||||
|
// therefore return an arbitrary negative result.
|
||||||
|
|
||||||
|
bool got_dist = false;
|
||||||
|
float best_dist = -1.0f;
|
||||||
|
|
||||||
for (size_t i = 1; i < points.size(); i++) {
|
size_t num_points = points.size();
|
||||||
max_dist = max(max_dist, dist_to_line(p, points[i]._p, points[i]._v));
|
for (size_t i = 0; i < num_points - 1; ++i) {
|
||||||
|
float d = dist_to_line_segment(p, points[i]._p, points[i + 1]._p,
|
||||||
|
points[i]._v);
|
||||||
|
if (d >= 0.0f) {
|
||||||
|
if (!got_dist || d < best_dist) {
|
||||||
|
best_dist = d;
|
||||||
|
got_dist = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return max_dist;
|
float d = dist_to_line_segment(p, points[num_points - 1]._p, points[0]._p,
|
||||||
|
points[num_points - 1]._v);
|
||||||
|
if (d >= 0.0f) {
|
||||||
|
if (!got_dist || d < best_dist) {
|
||||||
|
best_dist = d;
|
||||||
|
got_dist = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return best_dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -1260,6 +1376,27 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
|||||||
_points.push_back(PointDef(p, v));
|
_points.push_back(PointDef(p, v));
|
||||||
}
|
}
|
||||||
_to_2d_mat.read_datagram(scan);
|
_to_2d_mat.read_datagram(scan);
|
||||||
|
|
||||||
|
if (manager->get_file_minor_ver() < 13) {
|
||||||
|
// Before bam version 6.13, we were inadvertently storing
|
||||||
|
// CollisionPolygon vertices clockwise, instead of
|
||||||
|
// counter-clockwise. Correct that by re-projecting.
|
||||||
|
if (_points.size() >= 3) {
|
||||||
|
LMatrix4f to_3d_mat;
|
||||||
|
rederive_to_3d_mat(to_3d_mat);
|
||||||
|
|
||||||
|
pvector<LPoint3f> verts;
|
||||||
|
verts.reserve(_points.size());
|
||||||
|
Points::const_iterator pi;
|
||||||
|
for (pi = _points.begin(); pi != _points.end(); ++pi) {
|
||||||
|
verts.push_back(to_3d((*pi)._p, to_3d_mat));
|
||||||
|
}
|
||||||
|
|
||||||
|
const LPoint3f *verts_begin = &verts[0];
|
||||||
|
const LPoint3f *verts_end = verts_begin + verts.size();
|
||||||
|
setup_points(verts_begin, verts_end);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,6 +93,14 @@ protected:
|
|||||||
|
|
||||||
virtual void fill_viz_geom();
|
virtual void fill_viz_geom();
|
||||||
|
|
||||||
|
private:
|
||||||
|
INLINE static bool is_right(const LVector2f &v1, const LVector2f &v2);
|
||||||
|
INLINE static float dist_to_line(const LPoint2f &p,
|
||||||
|
const LPoint2f &f, const LVector2f &v);
|
||||||
|
static float dist_to_line_segment(const LPoint2f &p,
|
||||||
|
const LPoint2f &f, const LPoint2f &t,
|
||||||
|
const LVector2f &v);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class PointDef {
|
class PointDef {
|
||||||
public:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user