Cleanup: Remove unnecessary C API for delaunay triangulation
The only user was the Python API. Convert that to use the C++ API. That simplifies things a bit even, since the encoding of "arrays of arrays" is a fair amount simpler with the C++ data structures. The motivation is to simplify the changes from #111061.
This commit is contained in:
@@ -50,10 +50,46 @@
|
||||
* for dynamically maintaining a triangulation.
|
||||
*/
|
||||
|
||||
/** What triangles and edges of CDT are desired when getting output? */
|
||||
enum CDT_output_type {
|
||||
/** All triangles, outer boundary is convex hull. */
|
||||
CDT_FULL,
|
||||
/** All triangles fully enclosed by constraint edges or faces. */
|
||||
CDT_INSIDE,
|
||||
/** Like previous, but detect holes and omit those from output. */
|
||||
CDT_INSIDE_WITH_HOLES,
|
||||
/** Only point, edge, and face constraints, and their intersections. */
|
||||
CDT_CONSTRAINTS,
|
||||
/**
|
||||
* Like CDT_CONSTRAINTS, but keep enough
|
||||
* edges so that any output faces that came from input faces can be made as valid
|
||||
* #BMesh faces in Blender: that is,
|
||||
* no vertex appears more than once and no isolated holes in faces.
|
||||
*/
|
||||
CDT_CONSTRAINTS_VALID_BMESH,
|
||||
/** Like previous, but detect holes and omit those from output. */
|
||||
CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES,
|
||||
};
|
||||
|
||||
namespace blender::meshintersect {
|
||||
|
||||
/** #vec2<Arith_t> is a 2d vector with #Arith_t as the type for coordinates. */
|
||||
template<typename Arith_t> struct vec2_impl;
|
||||
template<> struct vec2_impl<double> {
|
||||
typedef double2 type;
|
||||
};
|
||||
|
||||
#ifdef WITH_GMP
|
||||
template<> struct vec2_impl<mpq_class> {
|
||||
typedef mpq2 type;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename Arith_t> using vec2 = typename vec2_impl<Arith_t>::type;
|
||||
|
||||
/**
|
||||
* Input to Constrained Delaunay Triangulation.
|
||||
* There are verts_len vertices, whose coordinates
|
||||
* are given by vert_coords. For the rest of the input,
|
||||
* Input vertex coordinates are stored in `vert`. For the rest of the input,
|
||||
* vertices are referred to by indices into that array.
|
||||
* Edges and Faces are optional. If provided, they will
|
||||
* appear in the output triangulation ("constraints").
|
||||
@@ -61,11 +97,7 @@
|
||||
* implied by the faces will be inferred.
|
||||
*
|
||||
* The edges are given by pairs of vertex indices.
|
||||
* The faces are given in a triple `(faces, faces_start_table, faces_len_table)`
|
||||
* to represent a list-of-lists as follows:
|
||||
* the vertex indices for a counterclockwise traversal of
|
||||
* face number `i` starts at `faces_start_table[i]` and has `faces_len_table[i]`
|
||||
* elements.
|
||||
* The faces are given as groups of vertex indices, in counterclockwise order.
|
||||
*
|
||||
* The edges implied by the faces are automatically added
|
||||
* and need not be put in the edges array, which is intended
|
||||
@@ -105,18 +137,14 @@
|
||||
* If this is not needed, set need_ids to false and the execution may be much
|
||||
* faster in some circumstances.
|
||||
*/
|
||||
typedef struct CDT_input {
|
||||
int verts_len;
|
||||
int edges_len;
|
||||
int faces_len;
|
||||
float (*vert_coords)[2];
|
||||
int (*edges)[2];
|
||||
int *faces;
|
||||
int *faces_start_table;
|
||||
int *faces_len_table;
|
||||
float epsilon;
|
||||
bool need_ids;
|
||||
} CDT_input;
|
||||
template<typename Arith_t> class CDT_input {
|
||||
public:
|
||||
Array<vec2<Arith_t>> vert;
|
||||
Array<std::pair<int, int>> edge;
|
||||
Array<Vector<int>> face;
|
||||
Arith_t epsilon{0};
|
||||
bool need_ids{true};
|
||||
};
|
||||
|
||||
/**
|
||||
* A representation of the triangulation for output.
|
||||
@@ -131,101 +159,15 @@ typedef struct CDT_input {
|
||||
* The output faces may be pieces of some input faces, or they
|
||||
* may be new.
|
||||
*
|
||||
* In the same way that faces lists-of-lists were represented by
|
||||
* a run-together array and a "start" and "len" extra array,
|
||||
* similar triples are used to represent the output to input
|
||||
* Extra outputs are used to represent the output to input
|
||||
* mapping of vertices, edges, and faces.
|
||||
* These are only set if need_ids is true in the input.
|
||||
*
|
||||
* Those triples are:
|
||||
* - verts_orig, verts_orig_start_table, verts_orig_len_table
|
||||
* - edges_orig, edges_orig_start_table, edges_orig_len_table
|
||||
* - faces_orig, faces_orig_start_table, faces_orig_len_table
|
||||
*
|
||||
* For edges, the edges_orig triple can also say which original face
|
||||
* edge is part of a given output edge. See the comment below
|
||||
* on the C++ interface for how to decode the entries in the edges_orig
|
||||
* table.
|
||||
* For edges, the edge_orig triple can also say which original face
|
||||
* edge is part of a given output edge. See the comment below for how
|
||||
* to decode the entries in the edge_orig table.
|
||||
*/
|
||||
typedef struct CDT_result {
|
||||
int verts_len;
|
||||
int edges_len;
|
||||
int faces_len;
|
||||
int face_edge_offset;
|
||||
float (*vert_coords)[2];
|
||||
int (*edges)[2];
|
||||
int *faces;
|
||||
int *faces_start_table;
|
||||
int *faces_len_table;
|
||||
int *verts_orig;
|
||||
int *verts_orig_start_table;
|
||||
int *verts_orig_len_table;
|
||||
int *edges_orig;
|
||||
int *edges_orig_start_table;
|
||||
int *edges_orig_len_table;
|
||||
int *faces_orig;
|
||||
int *faces_orig_start_table;
|
||||
int *faces_orig_len_table;
|
||||
} CDT_result;
|
||||
|
||||
/** What triangles and edges of CDT are desired when getting output? */
|
||||
typedef enum CDT_output_type {
|
||||
/** All triangles, outer boundary is convex hull. */
|
||||
CDT_FULL,
|
||||
/** All triangles fully enclosed by constraint edges or faces. */
|
||||
CDT_INSIDE,
|
||||
/** Like previous, but detect holes and omit those from output. */
|
||||
CDT_INSIDE_WITH_HOLES,
|
||||
/** Only point, edge, and face constraints, and their intersections. */
|
||||
CDT_CONSTRAINTS,
|
||||
/**
|
||||
* Like CDT_CONSTRAINTS, but keep enough
|
||||
* edges so that any output faces that came from input faces can be made as valid
|
||||
* #BMesh faces in Blender: that is,
|
||||
* no vertex appears more than once and no isolated holes in faces.
|
||||
*/
|
||||
CDT_CONSTRAINTS_VALID_BMESH,
|
||||
/** Like previous, but detect holes and omit those from output. */
|
||||
CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES,
|
||||
} CDT_output_type;
|
||||
|
||||
/**
|
||||
* API interface to CDT.
|
||||
* This returns a pointer to an allocated CDT_result.
|
||||
* When the caller is finished with it, the caller
|
||||
* should use #BLI_delaunay_2d_cdt_free() to free it.
|
||||
*/
|
||||
CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_type output_type);
|
||||
|
||||
void BLI_delaunay_2d_cdt_free(CDT_result *result);
|
||||
|
||||
/* C++ Interface. */
|
||||
|
||||
namespace blender::meshintersect {
|
||||
|
||||
/** #vec2<Arith_t> is a 2d vector with #Arith_t as the type for coordinates. */
|
||||
template<typename Arith_t> struct vec2_impl;
|
||||
template<> struct vec2_impl<double> {
|
||||
typedef double2 type;
|
||||
};
|
||||
|
||||
#ifdef WITH_GMP
|
||||
template<> struct vec2_impl<mpq_class> {
|
||||
typedef mpq2 type;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename Arith_t> using vec2 = typename vec2_impl<Arith_t>::type;
|
||||
|
||||
template<typename Arith_t> class CDT_input {
|
||||
public:
|
||||
Array<vec2<Arith_t>> vert;
|
||||
Array<std::pair<int, int>> edge;
|
||||
Array<Vector<int>> face;
|
||||
Arith_t epsilon{0};
|
||||
bool need_ids{true};
|
||||
};
|
||||
|
||||
template<typename Arith_t> class CDT_result {
|
||||
public:
|
||||
Array<vec2<Arith_t>> vert;
|
||||
|
||||
@@ -2810,167 +2810,3 @@ blender::meshintersect::CDT_result<mpq_class> delaunay_2d_calc(const CDT_input<m
|
||||
#endif
|
||||
|
||||
} /* namespace blender::meshintersect */
|
||||
|
||||
/* C interface. */
|
||||
|
||||
/**
|
||||
* This function uses the double version of #CDT::delaunay_calc.
|
||||
* Almost all of the work here is to convert between C++ #Arrays<Vector<int>>
|
||||
* and a C version that linearizes all the elements and uses a "start"
|
||||
* and "len" array to say where the individual vectors start and how
|
||||
* long they are.
|
||||
*/
|
||||
::CDT_result *BLI_delaunay_2d_cdt_calc(const ::CDT_input *input, const CDT_output_type output_type)
|
||||
{
|
||||
blender::meshintersect::CDT_input<double> in;
|
||||
in.vert = blender::Array<blender::meshintersect::vec2<double>>(input->verts_len);
|
||||
in.edge = blender::Array<std::pair<int, int>>(input->edges_len);
|
||||
in.face = blender::Array<blender::Vector<int>>(input->faces_len);
|
||||
for (int v = 0; v < input->verts_len; ++v) {
|
||||
double x = double(input->vert_coords[v][0]);
|
||||
double y = double(input->vert_coords[v][1]);
|
||||
in.vert[v] = blender::meshintersect::vec2<double>(x, y);
|
||||
}
|
||||
for (int e = 0; e < input->edges_len; ++e) {
|
||||
in.edge[e] = std::pair<int, int>(input->edges[e][0], input->edges[e][1]);
|
||||
}
|
||||
for (int f = 0; f < input->faces_len; ++f) {
|
||||
in.face[f] = blender::Vector<int>(input->faces_len_table[f]);
|
||||
int fstart = input->faces_start_table[f];
|
||||
for (int j = 0; j < input->faces_len_table[f]; ++j) {
|
||||
in.face[f][j] = input->faces[fstart + j];
|
||||
}
|
||||
}
|
||||
in.epsilon = double(input->epsilon);
|
||||
in.need_ids = input->need_ids;
|
||||
|
||||
blender::meshintersect::CDT_result<double> res = blender::meshintersect::delaunay_2d_calc(
|
||||
in, output_type);
|
||||
|
||||
::CDT_result *output = static_cast<::CDT_result *>(MEM_mallocN(sizeof(*output), __func__));
|
||||
int nv = output->verts_len = res.vert.size();
|
||||
int ne = output->edges_len = res.edge.size();
|
||||
int nf = output->faces_len = res.face.size();
|
||||
int tot_v_orig = 0;
|
||||
int tot_e_orig = 0;
|
||||
int tot_f_orig = 0;
|
||||
int tot_f_lens = 0;
|
||||
if (input->need_ids) {
|
||||
for (int v = 0; v < nv; ++v) {
|
||||
tot_v_orig += res.vert_orig[v].size();
|
||||
}
|
||||
for (int e = 0; e < ne; ++e) {
|
||||
tot_e_orig += res.edge_orig[e].size();
|
||||
}
|
||||
}
|
||||
for (int f = 0; f < nf; ++f) {
|
||||
if (input->need_ids) {
|
||||
tot_f_orig += res.face_orig[f].size();
|
||||
}
|
||||
tot_f_lens += res.face[f].size();
|
||||
}
|
||||
|
||||
output->vert_coords = static_cast<decltype(output->vert_coords)>(
|
||||
MEM_malloc_arrayN(nv, sizeof(output->vert_coords[0]), __func__));
|
||||
output->edges = static_cast<decltype(output->edges)>(
|
||||
MEM_malloc_arrayN(ne, sizeof(output->edges[0]), __func__));
|
||||
output->faces = static_cast<int *>(MEM_malloc_arrayN(tot_f_lens, sizeof(int), __func__));
|
||||
output->faces_start_table = static_cast<int *>(MEM_malloc_arrayN(nf, sizeof(int), __func__));
|
||||
output->faces_len_table = static_cast<int *>(MEM_malloc_arrayN(nf, sizeof(int), __func__));
|
||||
if (input->need_ids) {
|
||||
output->verts_orig = static_cast<int *>(MEM_malloc_arrayN(tot_v_orig, sizeof(int), __func__));
|
||||
output->verts_orig_start_table = static_cast<int *>(
|
||||
MEM_malloc_arrayN(nv, sizeof(int), __func__));
|
||||
output->verts_orig_len_table = static_cast<int *>(
|
||||
MEM_malloc_arrayN(nv, sizeof(int), __func__));
|
||||
output->edges_orig = static_cast<int *>(MEM_malloc_arrayN(tot_e_orig, sizeof(int), __func__));
|
||||
output->edges_orig_start_table = static_cast<int *>(
|
||||
MEM_malloc_arrayN(ne, sizeof(int), __func__));
|
||||
output->edges_orig_len_table = static_cast<int *>(
|
||||
MEM_malloc_arrayN(ne, sizeof(int), __func__));
|
||||
output->faces_orig = static_cast<int *>(MEM_malloc_arrayN(tot_f_orig, sizeof(int), __func__));
|
||||
output->faces_orig_start_table = static_cast<int *>(
|
||||
MEM_malloc_arrayN(nf, sizeof(int), __func__));
|
||||
output->faces_orig_len_table = static_cast<int *>(
|
||||
MEM_malloc_arrayN(nf, sizeof(int), __func__));
|
||||
}
|
||||
else {
|
||||
output->verts_orig = nullptr;
|
||||
output->verts_orig_start_table = nullptr;
|
||||
output->verts_orig_len_table = nullptr;
|
||||
output->edges_orig = nullptr;
|
||||
output->edges_orig_start_table = nullptr;
|
||||
output->edges_orig_len_table = nullptr;
|
||||
output->faces_orig = nullptr;
|
||||
output->faces_orig_start_table = nullptr;
|
||||
output->faces_orig_len_table = nullptr;
|
||||
}
|
||||
|
||||
int v_orig_index = 0;
|
||||
for (int v = 0; v < nv; ++v) {
|
||||
output->vert_coords[v][0] = float(res.vert[v][0]);
|
||||
output->vert_coords[v][1] = float(res.vert[v][1]);
|
||||
if (input->need_ids) {
|
||||
int this_start = v_orig_index;
|
||||
output->verts_orig_start_table[v] = this_start;
|
||||
for (int j : res.vert_orig[v].index_range()) {
|
||||
output->verts_orig[v_orig_index++] = res.vert_orig[v][j];
|
||||
}
|
||||
output->verts_orig_len_table[v] = v_orig_index - this_start;
|
||||
}
|
||||
}
|
||||
int e_orig_index = 0;
|
||||
for (int e = 0; e < ne; ++e) {
|
||||
output->edges[e][0] = res.edge[e].first;
|
||||
output->edges[e][1] = res.edge[e].second;
|
||||
if (input->need_ids) {
|
||||
int this_start = e_orig_index;
|
||||
output->edges_orig_start_table[e] = this_start;
|
||||
for (int j : res.edge_orig[e].index_range()) {
|
||||
output->edges_orig[e_orig_index++] = res.edge_orig[e][j];
|
||||
}
|
||||
output->edges_orig_len_table[e] = e_orig_index - this_start;
|
||||
}
|
||||
}
|
||||
int f_orig_index = 0;
|
||||
int f_index = 0;
|
||||
for (int f = 0; f < nf; ++f) {
|
||||
|
||||
output->faces_start_table[f] = f_index;
|
||||
int flen = res.face[f].size();
|
||||
output->faces_len_table[f] = flen;
|
||||
for (int j = 0; j < flen; ++j) {
|
||||
output->faces[f_index++] = res.face[f][j];
|
||||
}
|
||||
if (input->need_ids) {
|
||||
int this_start = f_orig_index;
|
||||
output->faces_orig_start_table[f] = this_start;
|
||||
for (int k : res.face_orig[f].index_range()) {
|
||||
output->faces_orig[f_orig_index++] = res.face_orig[f][k];
|
||||
}
|
||||
output->faces_orig_len_table[f] = f_orig_index - this_start;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
void BLI_delaunay_2d_cdt_free(::CDT_result *result)
|
||||
{
|
||||
MEM_freeN(result->vert_coords);
|
||||
MEM_freeN(result->edges);
|
||||
MEM_freeN(result->faces);
|
||||
MEM_freeN(result->faces_start_table);
|
||||
MEM_freeN(result->faces_len_table);
|
||||
if (result->verts_orig) {
|
||||
MEM_freeN(result->verts_orig);
|
||||
MEM_freeN(result->verts_orig_start_table);
|
||||
MEM_freeN(result->verts_orig_len_table);
|
||||
MEM_freeN(result->edges_orig);
|
||||
MEM_freeN(result->edges_orig_start_table);
|
||||
MEM_freeN(result->edges_orig_len_table);
|
||||
MEM_freeN(result->faces_orig);
|
||||
MEM_freeN(result->faces_orig_start_table);
|
||||
MEM_freeN(result->faces_orig_len_table);
|
||||
}
|
||||
MEM_freeN(result);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <type_traits>
|
||||
|
||||
#define DO_CPP_TESTS 1
|
||||
#define DO_C_TESTS 1
|
||||
#define DO_TEXT_TESTS 0
|
||||
#define DO_RANDOM_TESTS 0
|
||||
|
||||
@@ -1735,56 +1734,6 @@ TEST(delaunay_m, RepeatTri)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if DO_C_TESTS
|
||||
|
||||
TEST(delaunay_d, CintTwoFace)
|
||||
{
|
||||
float vert_coords[][2] = {
|
||||
{0.0, 0.0}, {1.0, 0.0}, {0.5, 1.0}, {1.1, 1.0}, {1.1, 0.0}, {1.6, 1.0}};
|
||||
int faces[] = {0, 1, 2, 3, 4, 5};
|
||||
int faces_len[] = {3, 3};
|
||||
int faces_start[] = {0, 3};
|
||||
|
||||
::CDT_input input;
|
||||
input.verts_len = 6;
|
||||
input.edges_len = 0;
|
||||
input.faces_len = 2;
|
||||
input.vert_coords = vert_coords;
|
||||
input.edges = nullptr;
|
||||
input.faces = faces;
|
||||
input.faces_len_table = faces_len;
|
||||
input.faces_start_table = faces_start;
|
||||
input.epsilon = 1e-5f;
|
||||
input.need_ids = false;
|
||||
::CDT_result *output = BLI_delaunay_2d_cdt_calc(&input, CDT_FULL);
|
||||
BLI_delaunay_2d_cdt_free(output);
|
||||
}
|
||||
|
||||
TEST(delaunay_d, CintTwoFaceNoIds)
|
||||
{
|
||||
float vert_coords[][2] = {
|
||||
{0.0, 0.0}, {1.0, 0.0}, {0.5, 1.0}, {1.1, 1.0}, {1.1, 0.0}, {1.6, 1.0}};
|
||||
int faces[] = {0, 1, 2, 3, 4, 5};
|
||||
int faces_len[] = {3, 3};
|
||||
int faces_start[] = {0, 3};
|
||||
|
||||
::CDT_input input;
|
||||
input.verts_len = 6;
|
||||
input.edges_len = 0;
|
||||
input.faces_len = 2;
|
||||
input.vert_coords = vert_coords;
|
||||
input.edges = nullptr;
|
||||
input.faces = faces;
|
||||
input.faces_len_table = faces_len;
|
||||
input.faces_start_table = faces_start;
|
||||
input.epsilon = 1e-5f;
|
||||
input.need_ids = true;
|
||||
::CDT_result *output = BLI_delaunay_2d_cdt_calc(&input, CDT_FULL);
|
||||
BLI_delaunay_2d_cdt_free(output);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if DO_TEXT_TESTS
|
||||
template<typename T>
|
||||
void text_test(
|
||||
|
||||
@@ -369,71 +369,40 @@ int mathutils_array_parse_alloc_vi(int **array,
|
||||
return size;
|
||||
}
|
||||
|
||||
int mathutils_array_parse_alloc_viseq(
|
||||
int **array, int **start_table, int **len_table, PyObject *value, const char *error_prefix)
|
||||
bool mathutils_array_parse_alloc_viseq(PyObject *value,
|
||||
const char *error_prefix,
|
||||
blender::Array<blender::Vector<int>> &r_data)
|
||||
{
|
||||
PyObject *value_fast, *subseq;
|
||||
int i, size, start, subseq_len;
|
||||
int *ip;
|
||||
|
||||
*array = nullptr;
|
||||
*start_table = nullptr;
|
||||
*len_table = nullptr;
|
||||
PyObject *value_fast;
|
||||
if (!(value_fast = PySequence_Fast(value, error_prefix))) {
|
||||
/* PySequence_Fast sets the error */
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
size = PySequence_Fast_GET_SIZE(value_fast);
|
||||
|
||||
const int size = PySequence_Fast_GET_SIZE(value_fast);
|
||||
if (size != 0) {
|
||||
PyObject **value_fast_items = PySequence_Fast_ITEMS(value_fast);
|
||||
|
||||
*start_table = static_cast<int *>(PyMem_Malloc(size * sizeof(int)));
|
||||
*len_table = static_cast<int *>(PyMem_Malloc(size * sizeof(int)));
|
||||
|
||||
/* First pass to set starts and len, and calculate size of array needed */
|
||||
start = 0;
|
||||
for (i = 0; i < size; i++) {
|
||||
subseq = value_fast_items[i];
|
||||
if ((subseq_len = int(PySequence_Size(subseq))) == -1) {
|
||||
r_data.reinitialize(size);
|
||||
for (const int64_t i : r_data.index_range()) {
|
||||
PyObject *subseq = value_fast_items[i];
|
||||
const int subseq_len = int(PySequence_Size(subseq));
|
||||
if (subseq_len == -1) {
|
||||
PyErr_Format(
|
||||
PyExc_ValueError, "%.200s: sequence expected to have subsequences", error_prefix);
|
||||
PyMem_Free(*start_table);
|
||||
PyMem_Free(*len_table);
|
||||
Py_DECREF(value_fast);
|
||||
*start_table = nullptr;
|
||||
*len_table = nullptr;
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
(*start_table)[i] = start;
|
||||
(*len_table)[i] = subseq_len;
|
||||
start += subseq_len;
|
||||
}
|
||||
|
||||
ip = *array = static_cast<int *>(PyMem_Malloc(start * sizeof(int)));
|
||||
|
||||
/* Second pass to parse the subsequences into array */
|
||||
for (i = 0; i < size; i++) {
|
||||
subseq = value_fast_items[i];
|
||||
subseq_len = (*len_table)[i];
|
||||
|
||||
if (mathutils_int_array_parse(ip, subseq_len, subseq, error_prefix) == -1) {
|
||||
PyMem_Free(*array);
|
||||
PyMem_Free(*start_table);
|
||||
PyMem_Free(*len_table);
|
||||
*array = nullptr;
|
||||
*len_table = nullptr;
|
||||
*start_table = nullptr;
|
||||
size = -1;
|
||||
break;
|
||||
r_data[i].resize(subseq_len);
|
||||
blender::MutableSpan<int> group = r_data[i];
|
||||
if (mathutils_int_array_parse(group.data(), group.size(), subseq, error_prefix) == -1) {
|
||||
Py_DECREF(value_fast);
|
||||
return false;
|
||||
}
|
||||
ip += subseq_len;
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(value_fast);
|
||||
return size;
|
||||
return true;
|
||||
}
|
||||
|
||||
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
|
||||
/* Can cast different mathutils types to this, use for generic functions. */
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
struct DynStr;
|
||||
|
||||
@@ -187,14 +189,11 @@ int mathutils_array_parse_alloc_vi(int **array,
|
||||
PyObject *value,
|
||||
const char *error_prefix);
|
||||
/**
|
||||
* Parse sequence of variable-length sequences of int and return allocated
|
||||
* triple of arrays to represent the result:
|
||||
* The flattened sequences are put into *array.
|
||||
* The start index of each sequence goes into start_table.
|
||||
* The length of each index goes into len_table.
|
||||
* Parse sequence of variable-length sequences of integers and fill r_data with their values.
|
||||
*/
|
||||
int mathutils_array_parse_alloc_viseq(
|
||||
int **array, int **start_table, int **len_table, PyObject *value, const char *error_prefix);
|
||||
bool mathutils_array_parse_alloc_viseq(PyObject *value,
|
||||
const char *error_prefix,
|
||||
blender::Array<blender::Vector<int>> &r_data);
|
||||
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix);
|
||||
|
||||
/**
|
||||
|
||||
@@ -1536,25 +1536,17 @@ static PyObject *M_Geometry_convex_hull_2d(PyObject * /*self*/, PyObject *pointl
|
||||
* to fill values, with start_table and len_table giving the start index
|
||||
* and length of the toplevel_len sub-lists.
|
||||
*/
|
||||
static PyObject *list_of_lists_from_arrays(const int *array,
|
||||
const int *start_table,
|
||||
const int *len_table,
|
||||
int toplevel_len)
|
||||
static PyObject *list_of_lists_from_arrays(const blender::Span<blender::Vector<int>> data)
|
||||
{
|
||||
PyObject *ret, *sublist;
|
||||
int i, j, sublist_len, sublist_start, val;
|
||||
|
||||
if (array == nullptr) {
|
||||
if (data.is_empty()) {
|
||||
return PyList_New(0);
|
||||
}
|
||||
ret = PyList_New(toplevel_len);
|
||||
for (i = 0; i < toplevel_len; i++) {
|
||||
sublist_len = len_table[i];
|
||||
sublist = PyList_New(sublist_len);
|
||||
sublist_start = start_table[i];
|
||||
for (j = 0; j < sublist_len; j++) {
|
||||
val = array[sublist_start + j];
|
||||
PyList_SET_ITEM(sublist, j, PyLong_FromLong(val));
|
||||
PyObject *ret = PyList_New(data.size());
|
||||
for (const int i : data.index_range()) {
|
||||
const blender::Span<int> group = data[i];
|
||||
PyObject *sublist = PyList_New(group.size());
|
||||
for (const int j : group.index_range()) {
|
||||
PyList_SET_ITEM(sublist, j, PyLong_FromLong(group[j]));
|
||||
}
|
||||
PyList_SET_ITEM(ret, i, sublist);
|
||||
}
|
||||
@@ -1606,19 +1598,15 @@ PyDoc_STRVAR(
|
||||
"\n");
|
||||
static PyObject *M_Geometry_delaunay_2d_cdt(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
using namespace blender;
|
||||
const char *error_prefix = "delaunay_2d_cdt";
|
||||
PyObject *vert_coords, *edges, *faces, *item;
|
||||
PyObject *vert_coords, *edges, *faces;
|
||||
int output_type;
|
||||
float epsilon;
|
||||
bool need_ids = true;
|
||||
float(*in_coords)[2] = nullptr;
|
||||
int(*in_edges)[2] = nullptr;
|
||||
int *in_faces = nullptr;
|
||||
int *in_faces_start_table = nullptr;
|
||||
int *in_faces_len_table = nullptr;
|
||||
Py_ssize_t vert_coords_len, edges_len, faces_len;
|
||||
CDT_input in;
|
||||
CDT_result *res = nullptr;
|
||||
Py_ssize_t vert_coords_len, edges_len;
|
||||
PyObject *out_vert_coords = nullptr;
|
||||
PyObject *out_edges = nullptr;
|
||||
PyObject *out_faces = nullptr;
|
||||
@@ -1626,7 +1614,6 @@ static PyObject *M_Geometry_delaunay_2d_cdt(PyObject * /*self*/, PyObject *args)
|
||||
PyObject *out_orig_edges = nullptr;
|
||||
PyObject *out_orig_faces = nullptr;
|
||||
PyObject *ret_value = nullptr;
|
||||
int i;
|
||||
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"OOOif|p:delaunay_2d_cdt",
|
||||
@@ -1640,6 +1627,15 @@ static PyObject *M_Geometry_delaunay_2d_cdt(PyObject * /*self*/, PyObject *args)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BLI_SCOPED_DEFER([&]() {
|
||||
if (in_coords != nullptr) {
|
||||
PyMem_Free(in_coords);
|
||||
}
|
||||
if (in_edges != nullptr) {
|
||||
PyMem_Free(in_edges);
|
||||
}
|
||||
});
|
||||
|
||||
vert_coords_len = mathutils_array_parse_alloc_v(
|
||||
(float **)&in_coords, 2, vert_coords, error_prefix);
|
||||
if (vert_coords_len == -1) {
|
||||
@@ -1648,86 +1644,65 @@ static PyObject *M_Geometry_delaunay_2d_cdt(PyObject * /*self*/, PyObject *args)
|
||||
|
||||
edges_len = mathutils_array_parse_alloc_vi((int **)&in_edges, 2, edges, error_prefix);
|
||||
if (edges_len == -1) {
|
||||
goto exit_cdt;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
faces_len = mathutils_array_parse_alloc_viseq(
|
||||
&in_faces, &in_faces_start_table, &in_faces_len_table, faces, error_prefix);
|
||||
if (faces_len == -1) {
|
||||
goto exit_cdt;
|
||||
Array<Vector<int>> in_faces;
|
||||
if (!mathutils_array_parse_alloc_viseq(faces, error_prefix, in_faces)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
in.verts_len = int(vert_coords_len);
|
||||
in.vert_coords = in_coords;
|
||||
in.edges_len = edges_len;
|
||||
in.faces_len = faces_len;
|
||||
in.edges = in_edges;
|
||||
in.faces = in_faces;
|
||||
in.faces_start_table = in_faces_start_table;
|
||||
in.faces_len_table = in_faces_len_table;
|
||||
Array<double2> verts(vert_coords_len);
|
||||
for (const int i : verts.index_range()) {
|
||||
verts[i] = {double(in_coords[i][0]), double(in_coords[i][1])};
|
||||
}
|
||||
|
||||
meshintersect::CDT_input<double> in;
|
||||
in.vert = std::move(verts);
|
||||
in.edge = Span(reinterpret_cast<std::pair<int, int> *>(in_edges), edges_len);
|
||||
in.face = std::move(in_faces);
|
||||
in.epsilon = epsilon;
|
||||
in.need_ids = need_ids;
|
||||
|
||||
res = BLI_delaunay_2d_cdt_calc(&in, CDT_output_type(output_type));
|
||||
const meshintersect::CDT_result<double> res = meshintersect::delaunay_2d_calc(
|
||||
in, CDT_output_type(output_type));
|
||||
|
||||
ret_value = PyTuple_New(6);
|
||||
|
||||
out_vert_coords = PyList_New(res->verts_len);
|
||||
for (i = 0; i < res->verts_len; i++) {
|
||||
item = Vector_CreatePyObject(res->vert_coords[i], 2, nullptr);
|
||||
out_vert_coords = PyList_New(res.vert.size());
|
||||
for (const int i : res.vert.index_range()) {
|
||||
const float2 vert_float(res.vert[i]);
|
||||
PyObject *item = Vector_CreatePyObject(vert_float, 2, nullptr);
|
||||
if (item == nullptr) {
|
||||
Py_DECREF(ret_value);
|
||||
Py_DECREF(out_vert_coords);
|
||||
goto exit_cdt;
|
||||
return nullptr;
|
||||
}
|
||||
PyList_SET_ITEM(out_vert_coords, i, item);
|
||||
}
|
||||
PyTuple_SET_ITEM(ret_value, 0, out_vert_coords);
|
||||
|
||||
out_edges = PyList_New(res->edges_len);
|
||||
for (i = 0; i < res->edges_len; i++) {
|
||||
item = PyTuple_New(2);
|
||||
PyTuple_SET_ITEM(item, 0, PyLong_FromLong(long(res->edges[i][0])));
|
||||
PyTuple_SET_ITEM(item, 1, PyLong_FromLong(long(res->edges[i][1])));
|
||||
out_edges = PyList_New(res.edge.size());
|
||||
for (const int i : res.edge.index_range()) {
|
||||
PyObject *item = PyTuple_New(2);
|
||||
PyTuple_SET_ITEM(item, 0, PyLong_FromLong(long(res.edge[i].first)));
|
||||
PyTuple_SET_ITEM(item, 1, PyLong_FromLong(long(res.edge[i].second)));
|
||||
PyList_SET_ITEM(out_edges, i, item);
|
||||
}
|
||||
PyTuple_SET_ITEM(ret_value, 1, out_edges);
|
||||
|
||||
out_faces = list_of_lists_from_arrays(
|
||||
res->faces, res->faces_start_table, res->faces_len_table, res->faces_len);
|
||||
out_faces = list_of_lists_from_arrays(res.face);
|
||||
PyTuple_SET_ITEM(ret_value, 2, out_faces);
|
||||
|
||||
out_orig_verts = list_of_lists_from_arrays(
|
||||
res->verts_orig, res->verts_orig_start_table, res->verts_orig_len_table, res->verts_len);
|
||||
out_orig_verts = list_of_lists_from_arrays(res.vert_orig);
|
||||
PyTuple_SET_ITEM(ret_value, 3, out_orig_verts);
|
||||
|
||||
out_orig_edges = list_of_lists_from_arrays(
|
||||
res->edges_orig, res->edges_orig_start_table, res->edges_orig_len_table, res->edges_len);
|
||||
out_orig_edges = list_of_lists_from_arrays(res.edge_orig);
|
||||
PyTuple_SET_ITEM(ret_value, 4, out_orig_edges);
|
||||
|
||||
out_orig_faces = list_of_lists_from_arrays(
|
||||
res->faces_orig, res->faces_orig_start_table, res->faces_orig_len_table, res->faces_len);
|
||||
out_orig_faces = list_of_lists_from_arrays(res.face_orig);
|
||||
PyTuple_SET_ITEM(ret_value, 5, out_orig_faces);
|
||||
|
||||
exit_cdt:
|
||||
if (in_coords != nullptr) {
|
||||
PyMem_Free(in_coords);
|
||||
}
|
||||
if (in_edges != nullptr) {
|
||||
PyMem_Free(in_edges);
|
||||
}
|
||||
if (in_faces != nullptr) {
|
||||
PyMem_Free(in_faces);
|
||||
}
|
||||
if (in_faces_start_table != nullptr) {
|
||||
PyMem_Free(in_faces_start_table);
|
||||
}
|
||||
if (in_faces_len_table != nullptr) {
|
||||
PyMem_Free(in_faces_len_table);
|
||||
}
|
||||
if (res) {
|
||||
BLI_delaunay_2d_cdt_free(res);
|
||||
}
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user