collide: Expose CollisionPolygon's setup_points and verify_points to Python

Closes #1035
This commit is contained in:
Daniel 2020-11-22 17:44:59 +01:00 committed by rdb
parent 3d5f0b7fe1
commit ac6a1a7874
7 changed files with 188 additions and 2 deletions

View File

@ -3829,6 +3829,7 @@ OPTS=['DIR:panda/src/collide']
IGATEFILES=GetDirectoryContents('panda/src/collide', ["*.h", "*_composite*.cxx"])
TargetAdd('libp3collide.in', opts=OPTS, input=IGATEFILES)
TargetAdd('libp3collide.in', opts=['IMOD:panda3d.core', 'ILIB:libp3collide', 'SRCDIR:panda/src/collide'])
PyTargetAdd('p3collide_ext_composite.obj', opts=OPTS, input='p3collide_ext_composite.cxx')
#
# DIRECTORY: panda/src/parametrics/
@ -4073,6 +4074,7 @@ PyTargetAdd('core.pyd', input='p3event_pythonTask.obj')
PyTargetAdd('core.pyd', input='p3gobj_ext_composite.obj')
PyTargetAdd('core.pyd', input='p3pgraph_ext_composite.obj')
PyTargetAdd('core.pyd', input='p3display_ext_composite.obj')
PyTargetAdd('core.pyd', input='p3collide_ext_composite.obj')
PyTargetAdd('core.pyd', input='core_module.obj')
if not GetLinkAllStatic() and GetTarget() != 'emscripten':

View File

@ -65,11 +65,16 @@ set(P3COLLIDE_SOURCES
config_collide.cxx
)
set(P3COLLIDE_IGATEEXT
collisionPolygon_ext.cxx
collisionPolygon_ext.h
)
composite_sources(p3collide P3COLLIDE_SOURCES)
add_component_library(p3collide SYMBOL BUILDING_PANDA_COLLIDE
${P3COLLIDE_HEADERS} ${P3COLLIDE_SOURCES})
target_link_libraries(p3collide p3tform)
target_interrogate(p3collide ALL)
target_interrogate(p3collide ALL EXTENSIONS ${P3COLLIDE_IGATEEXT})
if(NOT BUILD_METALIBS)
install(TARGETS p3collide

View File

@ -59,6 +59,9 @@ PUBLISHED:
bool is_valid() const;
bool is_concave() const;
EXTENSION(static bool verify_points(PyObject *points));
EXTENSION(void setup_points(PyObject *points));
PUBLISHED:
MAKE_SEQ_PROPERTY(points, get_num_points, get_point);
MAKE_PROPERTY(valid, is_valid);
@ -71,6 +74,8 @@ public:
const CullTraverserData &data,
bool bounds_only) const;
void setup_points(const LPoint3 *begin, const LPoint3 *end);
virtual PStatCollector &get_volume_pcollector();
virtual PStatCollector &get_test_pcollector();
@ -128,7 +133,6 @@ private:
PN_stdfloat dist_to_polygon(const LPoint2 &p, LPoint2 &edge_p, const Points &points) const;
void project(const LVector3 &axis, PN_stdfloat &center, PN_stdfloat &extent) const;
void setup_points(const LPoint3 *begin, const LPoint3 *end);
INLINE LPoint2 to_2d(const LVecBase3 &point3d) const;
INLINE void calc_to_3d_mat(LMatrix4 &to_3d_mat) const;
INLINE void rederive_to_3d_mat(LMatrix4 &to_3d_mat) const;

View File

@ -0,0 +1,86 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file collisionPolygon_ext.cxx
* @author Derzsi Daniel
* @date 2020-10-13
*/
#include "collisionPolygon_ext.h"
#ifdef HAVE_PYTHON
#include "collisionPolygon.h"
#ifdef STDFLOAT_DOUBLE
extern struct Dtool_PyTypedObject Dtool_LPoint3d;
#else
extern struct Dtool_PyTypedObject Dtool_LPoint3f;
#endif
/**
* Verifies that the indicated Python list of points will define a
* CollisionPolygon.
*/
bool Extension<CollisionPolygon>::
verify_points(PyObject *points) {
const pvector<LPoint3> vec = convert_points(points);
const LPoint3 *verts_begin = &vec[0];
const LPoint3 *verts_end = verts_begin + vec.size();
return CollisionPolygon::verify_points(verts_begin, verts_end);
}
/**
* Initializes this CollisionPolygon with the given Python list of
* points.
*/
void Extension<CollisionPolygon>::
setup_points(PyObject *points) {
const pvector<LPoint3> vec = convert_points(points);
const LPoint3 *verts_begin = &vec[0];
const LPoint3 *verts_end = verts_begin + vec.size();
_this->setup_points(verts_begin, verts_end);
}
/**
* Converts a Python sequence to a list of LPoint3 objects.
*/
pvector<LPoint3> Extension<CollisionPolygon>::
convert_points(PyObject *points) {
pvector<LPoint3> vec;
PyObject *seq = PySequence_Fast(points, "function expects a sequence");
if (!seq) {
return vec;
}
PyObject **items = PySequence_Fast_ITEMS(seq);
Py_ssize_t len = PySequence_Fast_GET_SIZE(seq);
void *ptr;
vec.reserve(len);
for (Py_ssize_t i = 0; i < len; ++i) {
#ifdef STDFLOAT_DOUBLE
if (ptr = DtoolInstance_UPCAST(items[i], Dtool_LPoint3d)) {
#else
if (ptr = DtoolInstance_UPCAST(items[i], Dtool_LPoint3f)) {
#endif
vec.push_back(*(LPoint3 *)ptr);
} else {
collide_cat.warning() << "Argument must be of LPoint3 type.\n";
}
}
Py_DECREF(seq);
return vec;
}
#endif

View File

@ -0,0 +1,43 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file collisionPolygon_ext.h
* @author Derzsi Daniel
* @date 2020-10-13
*/
#ifndef COLLISIONPOLYGON_EXT_H
#define COLLISIONPOLYGON_EXT_H
#include "pandabase.h"
#ifdef HAVE_PYTHON
#include "extension.h"
#include "collisionPolygon.h"
#include "py_panda.h"
/**
* This class defines the extension methods for CollisionPolygon, which are called
* instead of any C++ methods with the same prototype.
*
* @since 1.11.0
*/
template<>
class Extension<CollisionPolygon> : public ExtensionBase<CollisionPolygon> {
public:
static bool verify_points(PyObject *points);
void setup_points(PyObject *points);
private:
static pvector<LPoint3> convert_points(PyObject *points);
};
#endif // HAVE_PYTHON
#endif

View File

@ -0,0 +1 @@
#include "collisionPolygon_ext.cxx"

View File

@ -0,0 +1,45 @@
from panda3d import core
def test_collision_polygon_verify_not_enough_points():
# Less than 3 points cannot create a polygon
assert not core.CollisionPolygon.verify_points([])
assert not core.CollisionPolygon.verify_points([core.LPoint3(1, 0, 0)])
assert not core.CollisionPolygon.verify_points([core.LPoint3(1, 0, 0), core.LPoint3(0, 0, 1)])
def test_collision_polygon_verify_repeating_points():
# Repeating points cannot create a polygon
assert not core.CollisionPolygon.verify_points([core.LPoint3(1, 0, 0), core.LPoint3(1, 0, 0), core.LPoint3(0, 0, 1)])
assert not core.CollisionPolygon.verify_points([core.LPoint3(3, 6, 1), core.LPoint3(1, 3, 5), core.LPoint3(9, 1, 2), core.LPoint3(1, 3, 5)])
def test_collision_polygon_verify_colinear_points():
# Colinear points cannot create a polygon
assert not core.CollisionPolygon.verify_points([core.LPoint3(1, 2, 3), core.LPoint3(2, 3, 4), core.LPoint3(3, 4, 5)])
assert not core.CollisionPolygon.verify_points([core.LPoint3(2, 1, 1), core.LPoint3(3, 2, 1), core.LPoint3(4, 3, 1)])
def test_collision_polygon_verify_points():
# Those should be regular, colinear points
assert core.CollisionPolygon.verify_points([core.LPoint3(1, 0, 0), core.LPoint3(0, 1, 0), core.LPoint3(0, 0, 1)])
assert core.CollisionPolygon.verify_points([core.LPoint3(10, 2, 8), core.LPoint3(7, 1, 3), core.LPoint3(5, 9, 6)])
assert core.CollisionPolygon.verify_points([core.LPoint3(3, -8, -7), core.LPoint3(9, 10, 8), core.LPoint3(7, 0, 10), core.LPoint3(-6, -2, 3)])
assert core.CollisionPolygon.verify_points([core.LPoint3(-1, -3, -5), core.LPoint3(10, 3, -10), core.LPoint3(-10, 10, -4), core.LPoint3(0, 1, -4), core.LPoint3(-9, -2, 0)])
def test_collision_polygon_setup_points():
# Create empty collision polygon
polygon = core.CollisionPolygon(core.LVecBase3(0, 0, 0), core.LVecBase3(0, 0, 0), core.LVecBase3(0, 0, 0))
assert not polygon.is_valid()
# Test our setup method against a few test cases
for points in [
[core.LPoint3(-1, -3, -5), core.LPoint3(10, 3, -10), core.LPoint3(-10, 10, -4), core.LPoint3(0, 1, -4), core.LPoint3(-9, -2, 0)],
[core.LPoint3(3, -8, -7), core.LPoint3(9, 10, 8), core.LPoint3(7, 0, 10), core.LPoint3(-6, -2, 3)],
[core.LPoint3(1, 0, 0), core.LPoint3(0, 1, 0), core.LPoint3(0, 0, 1)],
[core.LPoint3(10, 2, 8), core.LPoint3(7, 1, 3), core.LPoint3(5, 9, 6)]
]:
polygon.setup_points(points)
assert polygon.is_valid()
assert polygon.get_num_points() == len(points)