47PStatCollector CollisionPolygon::_volume_pcollector(
"Collision Volumes:CollisionPolygon");
48PStatCollector CollisionPolygon::_test_pcollector(
"Collision Tests:CollisionPolygon");
57 _points(copy._points),
58 _to_2d_mat(copy._to_2d_mat)
67 return new CollisionPolygon(*
this);
81 int num_points = end - begin;
90 for (pi = begin; pi != end && all_ok; ++pi) {
96 for (pj = begin; pj != pi && all_ok; ++pj) {
108 bool got_normal =
false;
109 for (
int i = 2; i < num_points && !got_normal; i++) {
110 LPlane plane(begin[0], begin[1], begin[i]);
111 LVector3 normal = plane.get_normal();
112 PN_stdfloat normal_length = normal.length();
113 got_normal = IS_THRESHOLD_EQUAL(normal_length, 1.0f, 0.001f);
130 return (_points.size() >= 3);
139 if (_points.size() < 3) {
144 LPoint2 p0 = _points[0]._p;
145 LPoint2 p1 = _points[1]._p;
146 PN_stdfloat dx1 = p1[0] - p0[0];
147 PN_stdfloat dy1 = p1[1] - p0[1];
151 PN_stdfloat dx2 = p1[0] - p0[0];
152 PN_stdfloat dy2 = p1[1] - p0[1];
153 int asum = ((dx1 * dy2 - dx2 * dy1 >= 0.0f) ? 1 : 0);
155 for (
size_t i = 0; i < _points.size() - 1; i++) {
157 p1 = _points[(i+3) % _points.size()]._p;
163 int csum = ((dx1 * dy2 - dx2 * dy1 >= 0.0f) ? 1 : 0);
179xform(
const LMatrix4 &mat) {
184 if (collide_cat.is_spam()) {
186 <<
"CollisionPolygon transformed by:\n";
187 mat.write(collide_cat.spam(
false), 2);
188 if (_points.empty()) {
189 collide_cat.spam(
false)
194 if (!_points.empty()) {
196 rederive_to_3d_mat(to_3d_mat);
198 epvector<LPoint3> verts;
199 verts.reserve(_points.size());
200 Points::const_iterator pi;
201 for (pi = _points.begin(); pi != _points.end(); ++pi) {
202 verts.push_back(to_3d((*pi)._p, to_3d_mat) * mat);
205 const LPoint3 *verts_begin = &verts[0];
206 const LPoint3 *verts_end = verts_begin + verts.size();
207 setup_points(verts_begin, verts_end);
221 rederive_to_3d_mat(to_3d_mat);
223 LPoint2 median = _points[0]._p;
224 for (
int n = 1; n < (int)_points.size(); n++) {
225 median += _points[n]._p;
227 median /= _points.size();
229 return to_3d(median, to_3d_mat);
239 bool bounds_only)
const {
241 if (cpa ==
nullptr) {
244 return CollisionSolid::get_viz(trav, data, bounds_only);
247 if (collide_cat.is_debug()) {
249 <<
"drawing polygon with clip plane " << *cpa <<
"\n";
258 if (apply_clip_plane(new_points, cpa, data.get_net_transform(trav))) {
260 return CollisionSolid::get_viz(trav, data, bounds_only);
263 if (new_points.empty()) {
271 draw_polygon(viz_geom_node, bounds_viz_geom_node, new_points);
274 return bounds_viz_geom_node;
276 return viz_geom_node;
286 return _volume_pcollector;
295 return _test_pcollector;
301void CollisionPolygon::
302output(std::ostream &out)
const {
303 out <<
"cpolygon, (" << get_plane()
304 <<
"), " << _points.size() <<
" vertices";
310void CollisionPolygon::
311write(std::ostream &out,
int indent_level)
const {
312 indent(out, indent_level) << (*this) <<
"\n";
313 Points::const_iterator pi;
314 for (pi = _points.begin(); pi != _points.end(); ++pi) {
315 indent(out, indent_level + 2) << (*pi)._p <<
"\n";
319 rederive_to_3d_mat(to_3d_mat);
320 out <<
"In 3-d space:\n";
321 for (pi = _points.begin(); pi != _points.end(); ++pi) {
322 LVertex vert = to_3d((*pi)._p, to_3d_mat);
323 indent(out, indent_level + 2) << vert <<
"\n";
331compute_internal_bounds()
const {
332 if (_points.empty()) {
333 return new BoundingBox;
337 rederive_to_3d_mat(to_3d_mat);
339 Points::const_iterator pi = _points.begin();
340 LPoint3 p = to_3d((*pi)._p, to_3d_mat);
345 for (++pi; pi != _points.end(); ++pi) {
346 p = to_3d((*pi)._p, to_3d_mat);
348 n.set(min(n[0], p[0]),
351 x.set(max(x[0], p[0]),
356 return new BoundingBox(n, x);
365 if (_points.size() < 3) {
369 const CollisionSphere *sphere;
370 DCAST_INTO_R(sphere, entry.
get_from(),
nullptr);
375 const LMatrix4 &wrt_mat = wrt_space->get_mat();
377 LPoint3 orig_center = sphere->get_center() * wrt_mat;
378 LPoint3 from_center = orig_center;
379 bool moved_from_center =
false;
380 PN_stdfloat t = 1.0f;
381 LPoint3 contact_point(from_center);
382 PN_stdfloat actual_t = 1.0f;
384 LVector3 from_radius_v =
385 LVector3(sphere->get_radius(), 0.0f, 0.0f) * wrt_mat;
386 PN_stdfloat from_radius_2 = from_radius_v.length_squared();
387 PN_stdfloat from_radius = csqrt(from_radius_2);
389 if (wrt_prev_space != wrt_space) {
393 LPoint3 b = from_center;
394 LPoint3 a = sphere->get_center() * wrt_prev_space->get_mat();
395 LVector3 delta = b - a;
399 PN_stdfloat dot = delta.dot(get_normal());
404 if (IS_NEARLY_ZERO(dot)) {
417 PN_stdfloat dist_to_p = dist_to_plane(a);
418 t = (dist_to_p / -dot);
422 actual_t = ((dist_to_p - from_radius) / -dot);
423 actual_t = min((PN_stdfloat)1.0, max((PN_stdfloat)0.0, actual_t));
424 contact_point = a + (actual_t * delta);
429 }
else if (t < 0.0f) {
431 moved_from_center =
true;
434 from_center = a + t * delta;
435 moved_from_center =
true;
442 if (!IS_THRESHOLD_EQUAL(normal.length_squared(), 1.0f, 0.001)) {
443 if (collide_cat.is_info()) {
446 <<
" has normal " << normal <<
" of length " << normal.length()
456 if (!get_plane().intersects_line(dist, from_center, -get_normal())) {
462 if (dist > from_radius || dist < -from_radius) {
467 LPoint2 p = to_2d(from_center - dist * get_normal());
468 PN_stdfloat edge_dist = 0.0f;
470 const ClipPlaneAttrib *cpa = entry.get_into_clip_planes();
471 if (cpa !=
nullptr) {
474 if (apply_clip_plane(new_points, cpa, entry.
get_into_node_path().get_net_transform())) {
476 edge_dist = dist_to_polygon(p, _points);
478 }
else if (new_points.empty()) {
484 edge_dist = dist_to_polygon(p, new_points);
489 edge_dist = dist_to_polygon(p, _points);
495 if (edge_dist > from_radius) {
505 PN_stdfloat max_dist = from_radius;
506 if (edge_dist >= 0.0f) {
507 PN_stdfloat max_dist_2 = max(from_radius_2 - edge_dist * edge_dist, (PN_stdfloat)0.0);
508 max_dist = csqrt(max_dist_2);
511 if (dist > max_dist || -dist > max_dist) {
516 if (collide_cat.is_debug()) {
521 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
523 PN_stdfloat into_depth = max_dist - dist;
524 if (moved_from_center) {
527 PN_stdfloat orig_dist;
528 get_plane().intersects_line(orig_dist, orig_center, -normal);
529 into_depth = max_dist - orig_dist;
532 new_entry->set_surface_normal(normal);
533 new_entry->set_surface_point(from_center - normal * dist);
534 new_entry->set_interior_point(from_center - normal * (dist + into_depth));
535 new_entry->set_contact_pos(contact_point);
536 new_entry->set_contact_normal(get_normal());
537 new_entry->set_t(actual_t);
548 if (_points.size() < 3) {
552 const CollisionLine *line;
553 DCAST_INTO_R(line, entry.
get_from(),
nullptr);
556 const LMatrix4 &wrt_mat = wrt_space->get_mat();
558 LPoint3 from_origin = line->get_origin() * wrt_mat;
559 LVector3 from_direction = line->get_direction() * wrt_mat;
562 if (!get_plane().intersects_line(t, from_origin, from_direction)) {
567 LPoint3 plane_point = from_origin + t * from_direction;
568 LPoint2 p = to_2d(plane_point);
570 const ClipPlaneAttrib *cpa = entry.get_into_clip_planes();
571 if (cpa !=
nullptr) {
574 if (apply_clip_plane(new_points, cpa, entry.
get_into_node_path().get_net_transform())) {
576 if (!point_is_inside(p, _points)) {
581 if (new_points.size() < 3) {
584 if (!point_is_inside(p, new_points)) {
591 if (!point_is_inside(p, _points)) {
596 if (collide_cat.is_debug()) {
601 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
605 new_entry->set_surface_normal(normal);
606 new_entry->set_surface_point(plane_point);
617 if (_points.size() < 3) {
621 const CollisionRay *ray;
622 DCAST_INTO_R(ray, entry.
get_from(),
nullptr);
625 const LMatrix4 &wrt_mat = wrt_space->get_mat();
627 LPoint3 from_origin = ray->get_origin() * wrt_mat;
628 LVector3 from_direction = ray->get_direction() * wrt_mat;
631 if (!get_plane().intersects_line(t, from_origin, from_direction)) {
641 LPoint3 plane_point = from_origin + t * from_direction;
642 LPoint2 p = to_2d(plane_point);
644 const ClipPlaneAttrib *cpa = entry.get_into_clip_planes();
645 if (cpa !=
nullptr) {
648 if (apply_clip_plane(new_points, cpa, entry.
get_into_node_path().get_net_transform())) {
650 if (!point_is_inside(p, _points)) {
655 if (new_points.size() < 3) {
658 if (!point_is_inside(p, new_points)) {
665 if (!point_is_inside(p, _points)) {
670 if (collide_cat.is_debug()) {
675 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
679 new_entry->set_surface_normal(normal);
680 new_entry->set_surface_point(plane_point);
690test_intersection_from_segment(
const CollisionEntry &entry)
const {
691 if (_points.size() < 3) {
695 const CollisionSegment *segment;
696 DCAST_INTO_R(segment, entry.
get_from(),
nullptr);
699 const LMatrix4 &wrt_mat = wrt_space->get_mat();
701 LPoint3 from_a = segment->get_point_a() * wrt_mat;
702 LPoint3 from_b = segment->get_point_b() * wrt_mat;
703 LPoint3 from_direction = from_b - from_a;
706 if (!get_plane().intersects_line(t, from_a, from_direction)) {
711 if (t < 0.0f || t > 1.0f) {
717 LPoint3 plane_point = from_a + t * from_direction;
718 LPoint2 p = to_2d(plane_point);
720 const ClipPlaneAttrib *cpa = entry.get_into_clip_planes();
721 if (cpa !=
nullptr) {
724 if (apply_clip_plane(new_points, cpa, entry.
get_into_node_path().get_net_transform())) {
726 if (!point_is_inside(p, _points)) {
731 if (new_points.size() < 3) {
734 if (!point_is_inside(p, new_points)) {
741 if (!point_is_inside(p, _points)) {
746 if (collide_cat.is_debug()) {
751 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
755 new_entry->set_surface_normal(normal);
756 new_entry->set_surface_point(plane_point);
765test_intersection_from_capsule(
const CollisionEntry &entry)
const {
766 const CollisionCapsule *capsule;
767 DCAST_INTO_R(capsule, entry.
get_from(),
nullptr);
770 const LMatrix4 &wrt_mat = wrt_space->get_mat();
772 LPoint3 from_a = capsule->get_point_a() * wrt_mat;
773 LPoint3 from_b = capsule->get_point_b() * wrt_mat;
774 LVector3 from_radius_v =
775 LVector3(capsule->get_radius(), 0.0f, 0.0f) * wrt_mat;
776 PN_stdfloat from_radius_2 = from_radius_v.length_squared();
777 PN_stdfloat from_radius = csqrt(from_radius_2);
779 PN_stdfloat dist_a = get_plane().dist_to_plane(from_a);
780 PN_stdfloat dist_b = get_plane().dist_to_plane(from_b);
783 if (dist_a >= from_radius && dist_b >= from_radius) {
788 if (dist_a <= -from_radius && dist_b <= -from_radius) {
794 rederive_to_3d_mat(to_3d_mat);
797 LPoint3 intersect_3d;
798 if (!get_plane().intersects_line(intersect_3d, from_a, from_b)) {
800 intersect_3d = (from_a + from_b) * 0.5f;
804 LPoint2 intersect_2d = to_2d(intersect_3d);
805 LPoint2 closest_p_2d = intersect_2d;
806 PN_stdfloat best_dist_2 = -1;
808 size_t num_points = _points.size();
809 for (
size_t i = 0; i < num_points; ++i) {
810 const LPoint2 &p1 = _points[i]._p;
811 const LPoint2 &p2 = _points[(i + 1) % num_points]._p;
814 LVector2 v = intersect_2d - p1;
815 LVector2 pv = p2 - p1;
816 if (is_right(v, pv)) {
817 PN_stdfloat t = v.dot(pv) / pv.length_squared();
818 t = max(min(t, (PN_stdfloat)1), (PN_stdfloat)0);
820 LPoint2 p = p1 + pv * t;
821 PN_stdfloat d = (p - intersect_2d).length_squared();
822 if (best_dist_2 < 0 || d < best_dist_2) {
829 LPoint3 closest_p_3d = to_3d(closest_p_2d, to_3d_mat);
832 LVector3 from_v = from_b - from_a;
834 PN_stdfloat t = (closest_p_3d - from_a).dot(from_v) / from_v.length_squared();
835 LPoint3 ref_point_3d = from_a + from_v * max(min(t, (PN_stdfloat)1), (PN_stdfloat)0);
842 if (!get_plane().intersects_line(dist, ref_point_3d, -get_normal())) {
848 if (dist > from_radius || dist < -from_radius) {
853 LPoint2 ref_point_2d = to_2d(ref_point_3d);
854 LPoint2 surface_point_2d = ref_point_2d;
855 PN_stdfloat edge_dist_2 = -1;
857 for (
size_t i = 0; i < num_points; ++i) {
858 const LPoint2 &p1 = _points[i]._p;
859 const LPoint2 &p2 = _points[(i + 1) % num_points]._p;
862 LVector2 v = ref_point_2d - p1;
863 LVector2 pv = p2 - p1;
864 if (is_right(v, pv)) {
865 PN_stdfloat t = v.dot(pv) / pv.length_squared();
866 t = max(min(t, (PN_stdfloat)1), (PN_stdfloat)0);
868 LPoint2 p = p1 + pv * t;
869 PN_stdfloat d = (p - ref_point_2d).length_squared();
870 if (edge_dist_2 < 0 || d < edge_dist_2) {
871 surface_point_2d = p;
881 if (edge_dist_2 > from_radius_2) {
891 PN_stdfloat max_dist = from_radius;
892 if (edge_dist_2 >= 0.0f) {
893 PN_stdfloat max_dist_2 = max(from_radius_2 - edge_dist_2, (PN_stdfloat)0.0);
894 max_dist = csqrt(max_dist_2);
897 if (dist > max_dist || -dist > max_dist) {
902 if (collide_cat.is_debug()) {
907 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
910 new_entry->set_surface_normal(normal);
912 if ((dist_a < 0 || dist_b < 0) && !IS_NEARLY_EQUAL(dist_a, dist_b)) {
915 LPoint3 deepest_3d = (dist_a < dist_b) ? from_a : from_b;
916 LPoint2 deepest_2d = to_2d(deepest_3d);
917 surface_point_2d = deepest_2d;
918 PN_stdfloat best_dist_2 = -1;
920 for (
size_t i = 0; i < num_points; ++i) {
921 const LPoint2 &p1 = _points[i]._p;
922 const LPoint2 &p2 = _points[(i + 1) % num_points]._p;
925 LVector2 v = deepest_2d - p1;
926 LVector2 pv = p2 - p1;
927 if (is_right(v, pv)) {
928 PN_stdfloat t = v.dot(pv) / pv.length_squared();
929 t = max(min(t, (PN_stdfloat)1), (PN_stdfloat)0);
931 LPoint2 p = p1 + pv * t;
932 PN_stdfloat d = (p - deepest_2d).length_squared();
933 if (best_dist_2 < 0 || d < best_dist_2) {
934 surface_point_2d = p;
940 if (best_dist_2 < 0) {
942 new_entry->set_surface_point(deepest_3d - normal * min(dist_a, dist_b));
943 new_entry->set_interior_point(deepest_3d - normal * from_radius);
949 LPoint3 surface_point = to_3d(surface_point_2d, to_3d_mat);
950 LPoint3 interior_point = ref_point_3d - normal * max_dist;
951 new_entry->set_surface_point(surface_point);
952 new_entry->set_interior_point((interior_point - surface_point).project(normal) + surface_point);
961test_intersection_from_parabola(
const CollisionEntry &entry)
const {
962 if (_points.size() < 3) {
966 const CollisionParabola *parabola;
967 DCAST_INTO_R(parabola, entry.
get_from(),
nullptr);
970 const LMatrix4 &wrt_mat = wrt_space->get_mat();
974 local_p.xform(wrt_mat);
977 if (!get_plane().intersects_parabola(t1, t2, local_p)) {
983 if (t1 >= parabola->
get_t1() && t1 <= parabola->get_t2()) {
984 if (t2 >= parabola->
get_t1() && t2 <= parabola->get_t2()) {
993 }
else if (t2 >= parabola->
get_t1() && t2 <= parabola->get_t2()) {
1002 LPoint3 plane_point = local_p.calc_point(t);
1003 LPoint2 p = to_2d(plane_point);
1005 const ClipPlaneAttrib *cpa = entry.get_into_clip_planes();
1006 if (cpa !=
nullptr) {
1009 if (apply_clip_plane(new_points, cpa, entry.
get_into_node_path().get_net_transform())) {
1011 if (!point_is_inside(p, _points)) {
1016 if (new_points.size() < 3) {
1019 if (!point_is_inside(p, new_points)) {
1026 if (!point_is_inside(p, _points)) {
1031 if (collide_cat.is_debug()) {
1036 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
1040 new_entry->set_surface_normal(normal);
1041 new_entry->set_surface_point(plane_point);
1052 const CollisionBox *box;
1053 DCAST_INTO_R(box, entry.
get_from(),
nullptr);
1058 const LMatrix4 &wrt_mat = wrt_space->get_mat();
1059 LMatrix4 plane_mat = wrt_mat * _to_2d_mat;
1061 LPoint3 from_center = box->get_center() * plane_mat;
1062 LVector3 from_extents = box->get_dimensions() * 0.5f;
1065 LVecBase3 box_x = plane_mat.get_row3(0) * from_extents[0];
1066 LVecBase3 box_y = plane_mat.get_row3(1) * from_extents[1];
1067 LVecBase3 box_z = plane_mat.get_row3(2) * from_extents[2];
1070 if (cabs(from_center[1]) > cabs(box_x[1]) + cabs(box_y[1]) + cabs(box_z[1])) {
1076 PN_stdfloat r1, center, r2;
1078 r1 = cabs(box_x.dot(box_x)) + cabs(box_y.dot(box_x)) + cabs(box_z.dot(box_x));
1079 project(box_x, center, r2);
1080 if (cabs(from_center.dot(box_x) - center) > r1 + r2) {
1084 r1 = cabs(box_x.dot(box_y)) + cabs(box_y.dot(box_y)) + cabs(box_z.dot(box_y));
1085 project(box_y, center, r2);
1086 if (cabs(from_center.dot(box_y) - center) > r1 + r2) {
1090 r1 = cabs(box_x.dot(box_z)) + cabs(box_y.dot(box_z)) + cabs(box_z.dot(box_z));
1091 project(box_z, center, r2);
1092 if (cabs(from_center.dot(box_z) - center) > r1 + r2) {
1098 Points::const_iterator pi;
1099 for (pi = _points.begin(); pi != _points.end(); ++pi) {
1100 const PointDef &pd = *pi;
1103 axis.set(-box_x[1] * pd._v[1],
1104 box_x[0] * pd._v[1] - box_x[2] * pd._v[0],
1105 box_x[1] * pd._v[0]);
1106 r1 = cabs(box_x.dot(axis)) + cabs(box_y.dot(axis)) + cabs(box_z.dot(axis));
1107 project(axis, center, r2);
1108 if (cabs(from_center.dot(axis) - center) > r1 + r2) {
1112 axis.set(-box_y[1] * pd._v[1],
1113 box_y[0] * pd._v[1] - box_y[2] * pd._v[0],
1114 box_y[1] * pd._v[0]);
1115 r1 = cabs(box_x.dot(axis)) + cabs(box_y.dot(axis)) + cabs(box_z.dot(axis));
1116 project(axis, center, r2);
1117 if (cabs(from_center.dot(axis) - center) > r1 + r2) {
1121 axis.set(-box_z[1] * pd._v[1],
1122 box_z[0] * pd._v[1] - box_z[2] * pd._v[0],
1123 box_z[1] * pd._v[0]);
1124 r1 = cabs(box_x.dot(axis)) + cabs(box_y.dot(axis)) + cabs(box_z.dot(axis));
1125 project(axis, center, r2);
1126 if (cabs(from_center.dot(axis) - center) > r1 + r2) {
1131 if (collide_cat.is_debug()) {
1136 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
1139 new_entry->set_surface_normal(normal);
1144 LPoint3 interior_point = box->get_center() * wrt_mat +
1145 wrt_mat.get_row3(0) * from_extents[0] * ((box_x[1] > 0) - (box_x[1] < 0)) +
1146 wrt_mat.get_row3(1) * from_extents[1] * ((box_y[1] > 0) - (box_y[1] < 0)) +
1147 wrt_mat.get_row3(2) * from_extents[2] * ((box_z[1] > 0) - (box_z[1] < 0));
1150 new_entry->set_surface_point(get_plane().project(interior_point));
1151 new_entry->set_interior_point(interior_point);
1160void CollisionPolygon::
1162 if (collide_cat.is_debug()) {
1164 <<
"Recomputing viz for " << *
this <<
"\n";
1166 nassertv(_viz_geom !=
nullptr && _bounds_viz_geom !=
nullptr);
1167 draw_polygon(_viz_geom, _bounds_viz_geom, _points);
1178PN_stdfloat CollisionPolygon::
1179dist_to_line_segment(
const LPoint2 &p,
1180 const LPoint2 &f,
const LPoint2 &t,
1181 const LVector2 &v) {
1182 LVector2 v1 = (p - f);
1183 PN_stdfloat d = (v1[0] * v[1] - v1[1] * v[0]);
1189 LPoint2 q = p + LVector2(-v[1], v[0]) * d;
1199 return (p - f).length();
1200 }
if (q[0] > t[0]) {
1201 return (p - t).length();
1208 return (p - f).length();
1209 }
if (q[1] > t[1]) {
1210 return (p - t).length();
1220 return (p - f).length();
1221 }
if (q[0] > t[0]) {
1222 return (p - t).length();
1229 return (p - f).length();
1230 }
if (q[1] < t[1]) {
1231 return (p - t).length();
1244 return (p - f).length();
1245 }
if (q[0] < t[0]) {
1246 return (p - t).length();
1253 return (p - f).length();
1254 }
if (q[1] > t[1]) {
1255 return (p - t).length();
1262 if (-v[0] > -v[1]) {
1265 return (p - f).length();
1266 }
if (q[0] < t[0]) {
1267 return (p - t).length();
1274 return (p - f).length();
1275 }
if (q[1] < t[1]) {
1276 return (p - t).length();
1290void CollisionPolygon::
1291compute_vectors(Points &points) {
1292 size_t num_points = points.size();
1293 for (
size_t i = 0; i < num_points; i++) {
1294 points[i]._v = points[(i + 1) % num_points]._p - points[i]._p;
1295 points[i]._v.normalize();
1303void CollisionPolygon::
1305 const CollisionPolygon::Points &points)
const {
1306 if (points.size() < 3) {
1307 if (collide_cat.is_debug()) {
1309 <<
"(Degenerate poly, ignoring.)\n";
1315 rederive_to_3d_mat(to_3d_mat);
1317 PT(GeomVertexData) vdata =
new GeomVertexData
1320 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
1322 Points::const_iterator pi;
1323 for (pi = points.begin(); pi != points.end(); ++pi) {
1324 vertex.add_data3(to_3d((*pi)._p, to_3d_mat));
1327 PT(GeomTrifans) body =
new GeomTrifans(Geom::UH_static);
1328 body->add_consecutive_vertices(0, points.size());
1329 body->close_primitive();
1331 PT(GeomLinestrips) border =
new GeomLinestrips(Geom::UH_static);
1332 border->add_consecutive_vertices(0, points.size());
1333 border->add_vertex(0);
1334 border->close_primitive();
1336 PT(Geom) geom1 =
new Geom(vdata);
1337 geom1->add_primitive(body);
1339 PT(Geom) geom2 =
new Geom(vdata);
1340 geom2->add_primitive(border);
1342 viz_geom_node->
add_geom(geom1, ((CollisionPolygon *)
this)->get_solid_viz_state());
1343 viz_geom_node->
add_geom(geom2, ((CollisionPolygon *)
this)->get_wireframe_viz_state());
1345 bounds_viz_geom_node->
add_geom(geom1, ((CollisionPolygon *)
this)->get_solid_bounds_viz_state());
1346 bounds_viz_geom_node->
add_geom(geom2, ((CollisionPolygon *)
this)->get_wireframe_bounds_viz_state());
1354bool CollisionPolygon::
1355point_is_inside(
const LPoint2 &p,
const CollisionPolygon::Points &points)
const {
1361 for (
int i = 0; i < (int)points.size() - 1; i++) {
1362 if (is_right(p - points[i]._p, points[i+1]._p - points[i]._p)) {
1366 if (is_right(p - points[points.size() - 1]._p,
1367 points[0]._p - points[points.size() - 1]._p)) {
1379PN_stdfloat CollisionPolygon::
1380dist_to_polygon(
const LPoint2 &p,
const CollisionPolygon::Points &points)
const {
1390 bool got_dist =
false;
1391 PN_stdfloat best_dist = -1.0f;
1393 size_t num_points = points.size();
1394 for (
size_t i = 0; i < num_points - 1; ++i) {
1395 PN_stdfloat d = dist_to_line_segment(p, points[i]._p, points[i + 1]._p,
1398 if (!got_dist || d < best_dist) {
1405 PN_stdfloat d = dist_to_line_segment(p, points[num_points - 1]._p, points[0]._p,
1406 points[num_points - 1]._v);
1408 if (!got_dist || d < best_dist) {
1421void CollisionPolygon::
1422project(
const LVector3 &axis, PN_stdfloat ¢er, PN_stdfloat &extent)
const {
1423 PN_stdfloat begin, end;
1425 Points::const_iterator pi;
1426 pi = _points.begin();
1428 const LPoint2 &point = (*pi)._p;
1429 begin = point[0] * axis[0] + point[1] * axis[2];
1432 for (; pi != _points.end(); ++pi) {
1433 const LPoint2 &point = (*pi)._p;
1435 PN_stdfloat t = point[0] * axis[0] + point[1] * axis[2];
1436 begin = min(begin, t);
1440 center = (end + begin) * 0.5f;
1441 extent = cabs((end - begin) * 0.5f);
1447void CollisionPolygon::
1448setup_points(
const LPoint3 *begin,
const LPoint3 *end) {
1449 int num_points = end - begin;
1450 nassertv(num_points >= 3);
1456 LVector3 normal = LVector3::zero();
1462 for (
int i = 0; i < num_points; i++) {
1463 const LPoint3 &p0 = begin[i];
1464 const LPoint3 &p1 = begin[(i + 1) % num_points];
1465 normal[0] += p0[1] * p1[2] - p0[2] * p1[1];
1466 normal[1] += p0[2] * p1[0] - p0[0] * p1[2];
1467 normal[2] += p0[0] * p1[1] - p0[1] * p1[0];
1470 if (normal.length_squared() == 0.0f) {
1479 collide_cat.error() <<
"Invalid points in CollisionPolygon:\n";
1481 for (pi = begin; pi != end; ++pi) {
1482 collide_cat.error(
false) <<
" " << (*pi) <<
"\n";
1484 collide_cat.error(
false)
1485 <<
" normal " << normal <<
" with length " << normal.length() <<
"\n";
1491 if (collide_cat.is_spam()) {
1493 <<
"CollisionPolygon defined with " << num_points <<
" vertices:\n";
1495 for (pi = begin; pi != end; ++pi) {
1496 collide_cat.spam(
false) <<
" " << (*pi) <<
"\n";
1501 set_plane(LPlane(normal, begin[0]));
1506 calc_to_3d_mat(to_3d_mat);
1509 _to_2d_mat.invert_from(to_3d_mat);
1514 for (pi = begin; pi != end; ++pi) {
1515 LPoint3 point = (*pi) * _to_2d_mat;
1516 _points.push_back(PointDef(point[0], point[2]));
1519 nassertv(_points.size() >= 3);
1537 compute_vectors(_points);
1544LPoint3 CollisionPolygon::
1545legacy_to_3d(
const LVecBase2 &point2d,
int axis)
const {
1546 nassertr(!point2d.is_nan(), LPoint3(0.0f, 0.0f, 0.0f));
1548 LVector3 normal = get_normal();
1549 PN_stdfloat D = get_plane()[3];
1551 nassertr(!normal.is_nan(), LPoint3(0.0f, 0.0f, 0.0f));
1552 nassertr(!cnan(D), LPoint3(0.0f, 0.0f, 0.0f));
1556 return LPoint3(-(normal[1]*point2d[0] + normal[2]*point2d[1] + D)/normal[0], point2d[0], point2d[1]);
1559 return LPoint3(point2d[0],
1560 -(normal[0]*point2d[0] + normal[2]*point2d[1] + D)/normal[1], point2d[1]);
1563 return LPoint3(point2d[0], point2d[1],
1564 -(normal[0]*point2d[0] + normal[1]*point2d[1] + D)/normal[2]);
1567 nassertr(
false, LPoint3(0.0f, 0.0f, 0.0f));
1568 return LPoint3(0.0f, 0.0f, 0.0f);
1579bool CollisionPolygon::
1580clip_polygon(CollisionPolygon::Points &new_points,
1581 const CollisionPolygon::Points &source_points,
1582 const LPlane &plane)
const {
1584 if (source_points.empty()) {
1590 if (!plane.intersects_plane(from3d, delta3d, get_plane())) {
1593 if (plane.dist_to_plane(get_plane().
get_point()) < 0.0) {
1596 new_points = source_points;
1604 LPoint2 from2d = to_2d(from3d);
1605 LVector2 delta2d = to_2d(delta3d);
1607 PN_stdfloat a = -delta2d[1];
1608 PN_stdfloat b = delta2d[0];
1609 PN_stdfloat c = from2d[0] * delta2d[1] - from2d[1] * delta2d[0];
1617 new_points.reserve(source_points.size() + 1);
1619 LPoint2 last_point = source_points.back()._p;
1620 bool last_is_in = !is_right(last_point - from2d, delta2d);
1621 bool all_in = last_is_in;
1622 Points::const_iterator pi;
1623 for (pi = source_points.begin(); pi != source_points.end(); ++pi) {
1624 const LPoint2 &this_point = (*pi)._p;
1625 bool this_is_in = !is_right(this_point - from2d, delta2d);
1629 bool crossed_over = (this_is_in != last_is_in);
1633 LVector2 d = this_point - last_point;
1634 PN_stdfloat denom = (a * d[0] + b * d[1]);
1636 PN_stdfloat t = -(a * last_point[0] + b * last_point[1] + c) / denom;
1637 LPoint2 p = last_point + t * d;
1639 new_points.push_back(PointDef(p[0], p[1]));
1640 last_is_in = this_is_in;
1646 new_points.push_back(PointDef(this_point[0], this_point[1]));
1651 last_point = this_point;
1664bool CollisionPolygon::
1665apply_clip_plane(CollisionPolygon::Points &new_points,
1671 bool first_plane =
true;
1673 for (
int i = 0; i < num_planes; i++) {
1675 PlaneNode *plane_node = DCAST(PlaneNode, plane_path.
node());
1678 net_transform->invert_compose(plane_path.get_net_transform());
1680 LPlane plane = plane_node->
get_plane() * new_transform->get_mat();
1682 first_plane =
false;
1683 if (!clip_polygon(new_points, _points, plane)) {
1688 last_points.swap(new_points);
1689 if (!clip_polygon(new_points, last_points, plane)) {
1697 compute_vectors(new_points);
1711 for (
size_t i = 0; i < _points.size(); i++) {
1712 _points[i]._p.write_datagram(me);
1713 _points[i]._v.write_datagram(me);
1715 _to_2d_mat.write_datagram(me);
1723void CollisionPolygon::
1725 CollisionPlane::fillin(scan, manager);
1728 for (
size_t i = 0; i < size; i++) {
1731 p.read_datagram(scan);
1732 v.read_datagram(scan);
1733 _points.push_back(PointDef(p, v));
1735 _to_2d_mat.read_datagram(scan);
1741 if (_points.size() >= 3) {
1743 rederive_to_3d_mat(to_3d_mat);
1745 epvector<LPoint3> verts;
1746 verts.reserve(_points.size());
1747 Points::const_iterator pi;
1748 for (pi = _points.begin(); pi != _points.end(); ++pi) {
1749 verts.push_back(to_3d((*pi)._p, to_3d_mat));
1752 const LPoint3 *verts_begin = &verts[0];
1753 const LPoint3 *verts_end = verts_begin + verts.size();
1754 setup_points(verts_begin, verts_end);
1765 CollisionPolygon *me =
new CollisionPolygon;
1770 me->fillin(scan, manager);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
This functions similarly to a LightAttrib.
get_on_plane
Returns the nth plane enabled by the attribute, sorted in render order.
get_num_on_planes
Returns the number of planes that are enabled by the attribute.
Defines a single collision event.
get_from_node_path
Returns the NodePath that represents the CollisionNode that contains the CollisionSolid that triggere...
get_into_node_path
Returns the NodePath that represents the specific CollisionNode or GeomNode instance that was collide...
get_from
Returns the CollisionSolid pointer for the particular solid that triggered this collision.
get_t1
Returns the starting point on the parabola.
get_parabola
Returns the parabola specified by this solid.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
static bool verify_points(const LPoint3 *begin, const LPoint3 *end)
Verifies that the indicated set of points will define a valid CollisionPolygon: that is,...
get_point
Returns the nth vertex of the CollisionPolygon, expressed in 3-D space.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
virtual LPoint3 get_collision_origin() const
Returns the point in space deemed to be the "origin" of the solid for collision purposes.
is_concave
Returns true if the CollisionPolygon appears to be concave, or false if it is safely convex.
virtual PStatCollector & get_test_pcollector()
Returns a PStatCollector that is used to count the number of intersection tests made against a solid ...
static void register_with_read_factory()
Factory method to generate a CollisionPolygon object.
virtual void xform(const LMatrix4 &mat)
Transforms the solid by the indicated matrix.
static TypedWritable * make_CollisionPolygon(const FactoryParams ¶ms)
Factory method to generate a CollisionPolygon object.
virtual PointerTo< PandaNode > get_viz(const CullTraverser *trav, const CullTraverserData &data, bool bounds_only) const
Returns a GeomNode that may be rendered to visualize the CollisionSolid.
is_valid
Returns true if the CollisionPolygon is valid (that is, it has at least three vertices),...
virtual PStatCollector & get_volume_pcollector()
Returns a PStatCollector that is used to count the number of bounding volume tests made against a sol...
The abstract base class for all things that can collide with other things in the world,...
bool has_effective_normal() const
Returns true if a special normal was set by set_effective_normal(), false otherwise.
const LVector3 & get_effective_normal() const
Returns the normal that was set by set_effective_normal().
virtual void xform(const LMatrix4 &mat)
Transforms the solid by the indicated matrix.
get_respect_effective_normal
See set_respect_effective_normal().
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
A class to retrieve the individual data elements previously stored in a Datagram.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
A node that holds Geom objects, renderable pieces of geometry.
void add_geom(Geom *geom, const RenderState *state=RenderState::make_empty())
Adds a new Geom to the node.
PandaNode * node() const
Returns the referenced node of the path.
A lightweight class that represents a single element that may be timed and/or counted via stats.
A basic node of the scene graph or data graph.
get_clip_effect
Returns the clip_effect bits for this clip plane.
get_plane
Returns the plane represented by the PlaneNode.
TypeHandle is the identifier used to differentiate C++ class types.
Base class for objects that can be written to and read from Bam files.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.