Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Trickey <howard.trickey@gmail.com>2020-07-01 19:42:04 +0300
committerHoward Trickey <howard.trickey@gmail.com>2020-07-01 19:42:04 +0300
commit777690902663f3dc820f183329e404a6388485f4 (patch)
tree7429a08f1e506dcd85501dad9bca0595efb661be
parent590ce6817d76b01d1eff0a54bf2f5240596ccefa (diff)
Change boolean blenlib interface to be purely C++.
-rw-r--r--source/blender/blenlib/BLI_boolean.hh (renamed from source/blender/blenlib/BLI_boolean.h)56
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/boolean.cc231
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.cc7
-rw-r--r--tests/gtests/blenlib/BLI_boolean_test.cc258
5 files changed, 171 insertions, 383 deletions
diff --git a/source/blender/blenlib/BLI_boolean.h b/source/blender/blenlib/BLI_boolean.hh
index 55155afc1d4..1ced075a907 100644
--- a/source/blender/blenlib/BLI_boolean.h
+++ b/source/blender/blenlib/BLI_boolean.hh
@@ -14,48 +14,13 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_BOOLEAN_H__
-#define __BLI_BOOLEAN_H__
+#ifndef __BLI_BOOLEAN_HH__
+#define __BLI_BOOLEAN_HH__
/** \file
* \ingroup bli
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum bool_optype {
- BOOLEAN_NONE = -1,
- /* Aligned with BooleanModifierOp. */
- BOOLEAN_ISECT = 0,
- BOOLEAN_UNION = 1,
- BOOLEAN_DIFFERENCE = 2,
-} bool_optype;
-
-typedef struct Boolean_trimesh_input {
- int vert_len;
- int tri_len;
- float (*vert_coord)[3];
- int (*tri)[3];
-} Boolean_trimesh_input;
-
-typedef struct Boolean_trimesh_output {
- int vert_len;
- int tri_len;
- float (*vert_coord)[3];
- int (*tri)[3];
-} Boolean_trimesh_output;
-
-Boolean_trimesh_output *BLI_boolean_trimesh(const Boolean_trimesh_input *in0,
- const Boolean_trimesh_input *in1,
- int bool_optype);
-
-void BLI_boolean_trimesh_free(Boolean_trimesh_output *output);
-
-#ifdef __cplusplus
-}
-
# include "BLI_array.hh"
# include "BLI_math_mpq.hh"
# include "BLI_mesh_intersect.hh"
@@ -64,6 +29,15 @@ void BLI_boolean_trimesh_free(Boolean_trimesh_output *output);
namespace blender {
namespace meshintersect {
+/* Enum values after BOOLEAN_NONE need to match BMESH_ISECT_BOOLEAN_... values in editmesh_intersect.c. */
+enum bool_optype {
+ BOOLEAN_NONE = -1,
+ /* Aligned with BooleanModifierOp. */
+ BOOLEAN_ISECT = 0,
+ BOOLEAN_UNION = 1,
+ BOOLEAN_DIFFERENCE = 2,
+};
+
struct PolyMeshOrig {
Array<int> vert_orig;
Array<Array<int>> face_orig;
@@ -79,7 +53,9 @@ struct PolyMesh {
PolyMeshOrig orig;
};
-PolyMesh boolean(PolyMesh &pm, int bool_optype, int nshapes, std::function<int(int)> shape_fn);
+PolyMesh boolean(PolyMesh &pm, bool_optype op, int nshapes, std::function<int(int)> shape_fn);
+
+TriMesh boolean_trimesh(const TriMesh &tm, bool_optype op, int nshapes, std::function<int(int)> shape_fn);
void write_obj_polymesh(const Array<mpq3> &vert,
const Array<Array<int>> &face,
@@ -88,6 +64,4 @@ void write_obj_polymesh(const Array<mpq3> &vert,
} // namespace meshintersect
} // namespace blender
-#endif
-
-#endif /* __BLI_BOOLEAN_H__ */
+#endif /* __BLI_BOOLEAN_HH__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 8d5d370df3d..52cdd6ca1af 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -157,7 +157,7 @@ set(SRC
BLI_bitmap.h
BLI_bitmap_draw_2d.h
BLI_blenlib.h
- BLI_boolean.h
+ BLI_boolean.hh
BLI_boxpack_2d.h
BLI_buffer.h
BLI_color.hh
diff --git a/source/blender/blenlib/intern/boolean.cc b/source/blender/blenlib/intern/boolean.cc
index 55f969c1b81..bdf9b56dda6 100644
--- a/source/blender/blenlib/intern/boolean.cc
+++ b/source/blender/blenlib/intern/boolean.cc
@@ -33,7 +33,7 @@
#include "BLI_vector.hh"
#include "BLI_vector_set.hh"
-#include "BLI_boolean.h"
+#include "BLI_boolean.hh"
namespace blender {
@@ -987,7 +987,7 @@ static int find_ambient_cell(const TriMesh &tm,
static void propagate_windings_and_flag(PatchesInfo &pinfo,
CellsInfo &cinfo,
int c_ambient,
- int bool_optype,
+ bool_optype op,
int nshapes,
std::function<int(int)> shape_fn)
{
@@ -1025,7 +1025,7 @@ static void propagate_windings_and_flag(PatchesInfo &pinfo,
if (dbg_level > 1) {
std::cout << " representative tri " << t << ": in shape " << shape << "\n";
}
- cell_neighbor.set_winding_and_flag(cell, shape, winding_delta, bool_optype);
+ cell_neighbor.set_winding_and_flag(cell, shape, winding_delta, op);
if (dbg_level > 1) {
std::cout << " now cell_neighbor = " << cell_neighbor << "\n";
}
@@ -1177,9 +1177,9 @@ static TriMesh extract_from_flag_diffs(const TriMesh &tm_subdivided,
return tm_out;
}
-static const char *bool_optype_name(int bool_optype)
+static const char *bool_optype_name(bool_optype op)
{
- switch (bool_optype) {
+ switch (op) {
case BOOLEAN_NONE:
return "none";
break;
@@ -1196,72 +1196,6 @@ static const char *bool_optype_name(int bool_optype)
}
}
-/*
- * This function does a boolean operation on nshapes inputs.
- * All the shapes are combined in tm_in.
- * The shape_fn function should take a triangle index in tm_in and return
- * a number in the range 0 to nshapes-1, to say which shape that triangle is in.
- */
-static TriMesh nary_boolean(const TriMesh &tm_in,
- int bool_optype,
- int nshapes,
- std::function<int(int)> shape_fn)
-{
- constexpr int dbg_level = 0;
- if (dbg_level > 0) {
- std::cout << "BOOLEAN of " << nshapes << " operand" << (nshapes == 1 ? "" : "s")
- << " op=" << bool_optype_name(bool_optype) << "\n";
- }
- if (tm_in.vert.size() == 0 || tm_in.tri.size() == 0) {
- return TriMesh(tm_in);
- }
- TriMesh tm_si = trimesh_self_intersect(tm_in);
- /* It is possible for tm_si to be empty if all the input triangles are bogus/degenerate. */
- if (tm_si.tri.size() == 0 || bool_optype == BOOLEAN_NONE) {
- return tm_si;
- }
- auto si_shape_fn = [shape_fn, tm_si](int t) { return shape_fn(tm_si.tri[t].orig()); };
- if (dbg_level > 1) {
- write_obj_trimesh(tm_si.vert, tm_si.tri, "boolean_tm_input");
- std::cout << "boolean tm input:\n";
- for (int t = 0; t < static_cast<int>(tm_si.tri.size()); ++t) {
- std::cout << "tri " << t << " = " << tm_si.tri[t] << " shape " << si_shape_fn(t) << "\n";
- }
- }
- TriMeshTopology tm_si_topo(&tm_si);
- PatchesInfo pinfo = find_patches(tm_si, tm_si_topo);
- CellsInfo cinfo = find_cells(tm_si, tm_si_topo, pinfo);
- cinfo.init_windings(nshapes);
- int c_ambient = find_ambient_cell(tm_si, tm_si_topo, pinfo);
- if (c_ambient == -1) {
- /* TODO: find a way to propagate this error to user properly. */
- std::cout << "Could not find an ambient cell; input not valid?\n";
- return TriMesh(tm_si);
- }
- propagate_windings_and_flag(pinfo, cinfo, c_ambient, bool_optype, nshapes, si_shape_fn);
- TriMesh tm_out = extract_from_flag_diffs(tm_si, pinfo, cinfo);
- if (dbg_level > 1) {
- write_obj_trimesh(tm_out.vert, tm_out.tri, "boolean_tm_output");
- }
- return tm_out;
-}
-
-static TriMesh self_boolean(const TriMesh &tm_in, int bool_optype)
-{
- return nary_boolean(tm_in, bool_optype, 1, [](int UNUSED(t)) { return 0; });
-}
-
-static TriMesh binary_boolean(const TriMesh &tm_in_a, const TriMesh &tm_in_b, int bool_optype)
-{
- /* Just combine the two pieces. We can tell by original triangle number which side it came
- * from.
- */
- TriMesh tm_in = concat_trimeshes(tm_in_a, tm_in_b);
- int b_tri_start = static_cast<int>(tm_in_a.tri.size());
- auto shape_fn = [b_tri_start](int t) { return (t >= b_tri_start ? 1 : 0); };
- return nary_boolean(tm_in, bool_optype, 2, shape_fn);
-}
-
static Array<IndexedTriangle> triangulate_poly(int orig_face,
const Array<int> &face,
const Array<mpq3> &vert)
@@ -1985,7 +1919,57 @@ static PolyMesh polymesh_from_trimesh_with_dissolve(const TriMesh &tm_out, const
return pm_out;
}
-/* Do the boolean operation bool_optype on the polygon mesh pm_in.
+/*
+ * This function does a boolean operation on a TriMesh with nshapes inputs.
+ * All the shapes are combined in tm_in.
+ * The shape_fn function should take a triangle index in tm_in and return
+ * a number in the range 0 to nshapes-1, to say which shape that triangle is in.
+ */
+TriMesh boolean_trimesh(const TriMesh &tm_in,
+ bool_optype op,
+ int nshapes,
+ std::function<int(int)> shape_fn)
+{
+ constexpr int dbg_level = 0;
+ if (dbg_level > 0) {
+ std::cout << "BOOLEAN of " << nshapes << " operand" << (nshapes == 1 ? "" : "s")
+ << " op=" << bool_optype_name(op) << "\n";
+ }
+ if (tm_in.vert.size() == 0 || tm_in.tri.size() == 0) {
+ return TriMesh(tm_in);
+ }
+ TriMesh tm_si = trimesh_self_intersect(tm_in);
+ /* It is possible for tm_si to be empty if all the input triangles are bogus/degenerate. */
+ if (tm_si.tri.size() == 0 || op == BOOLEAN_NONE) {
+ return tm_si;
+ }
+ auto si_shape_fn = [shape_fn, tm_si](int t) { return shape_fn(tm_si.tri[t].orig()); };
+ if (dbg_level > 1) {
+ write_obj_trimesh(tm_si.vert, tm_si.tri, "boolean_tm_input");
+ std::cout << "boolean tm input:\n";
+ for (int t = 0; t < static_cast<int>(tm_si.tri.size()); ++t) {
+ std::cout << "tri " << t << " = " << tm_si.tri[t] << " shape " << si_shape_fn(t) << "\n";
+ }
+ }
+ TriMeshTopology tm_si_topo(&tm_si);
+ PatchesInfo pinfo = find_patches(tm_si, tm_si_topo);
+ CellsInfo cinfo = find_cells(tm_si, tm_si_topo, pinfo);
+ cinfo.init_windings(nshapes);
+ int c_ambient = find_ambient_cell(tm_si, tm_si_topo, pinfo);
+ if (c_ambient == -1) {
+ /* TODO: find a way to propagate this error to user properly. */
+ std::cout << "Could not find an ambient cell; input not valid?\n";
+ return TriMesh(tm_si);
+ }
+ propagate_windings_and_flag(pinfo, cinfo, c_ambient, op, nshapes, si_shape_fn);
+ TriMesh tm_out = extract_from_flag_diffs(tm_si, pinfo, cinfo);
+ if (dbg_level > 1) {
+ write_obj_trimesh(tm_out.vert, tm_out.tri, "boolean_tm_output");
+ }
+ return tm_out;
+}
+
+/* Do the boolean operation op on the polygon mesh pm_in.
* The boolean operation has nshapes input shapes. Each is a disjoint subset of the input polymesh.
* The shape_fn argument, when applied to an input face argument, says which shape it is in
* (should be a value from -1 to nshapes - 1: if -1, it is not part of any shape).
@@ -1993,111 +1977,12 @@ static PolyMesh polymesh_from_trimesh_with_dissolve(const TriMesh &tm_out, const
* optional triangulation: parallel to each face, it gives a set of IndexedTriangles that
* triangulate that face.
* pm arg isn't const because we will add triangulation if it is not there. */
-PolyMesh boolean(PolyMesh &pm_in, int bool_optype, int nshapes, std::function<int(int)> shape_fn)
+PolyMesh boolean(PolyMesh &pm_in, bool_optype op, int nshapes, std::function<int(int)> shape_fn)
{
TriMesh tm_in = trimesh_from_polymesh(pm_in);
- TriMesh tm_out = nary_boolean(tm_in, bool_optype, nshapes, shape_fn);
+ TriMesh tm_out = boolean_trimesh(tm_in, op, nshapes, shape_fn);
return polymesh_from_trimesh_with_dissolve(tm_out, pm_in);
}
} // namespace meshintersect
} // namespace blender
-
-/*
- * Convert the C-style Boolean_trimesh_input into our internal C++ class for triangle meshes,
- * TriMesh.
- */
-static blender::meshintersect::TriMesh trimesh_from_input(const Boolean_trimesh_input *in,
- int side)
-{
- constexpr int dbg_level = 0;
- BLI_assert(in != nullptr);
- blender::meshintersect::TriMesh tm_in;
- tm_in.vert = blender::Array<blender::mpq3>(in->vert_len);
- for (int v = 0; v < in->vert_len; ++v) {
- tm_in.vert[v] = blender::mpq3(
- in->vert_coord[v][0], in->vert_coord[v][1], in->vert_coord[v][2]);
- }
- tm_in.tri = blender::Array<blender::meshintersect::IndexedTriangle>(in->tri_len);
- for (int t = 0; t < in->tri_len; ++t) {
- tm_in.tri[t] = blender::meshintersect::IndexedTriangle(
- in->tri[t][0], in->tri[t][1], in->tri[t][2], t);
- }
- if (dbg_level > 0) {
- /* Output in format that can be pasted into test spec. */
- std::cout << "Input side " << side << "\n";
- std::cout << tm_in.vert.size() << " " << tm_in.tri.size() << "\n";
- for (uint v = 0; v < tm_in.vert.size(); ++v) {
- std::cout << " " << tm_in.vert[v][0].get_d() << " " << tm_in.vert[v][1].get_d() << " "
- << tm_in.vert[v][2].get_d() << "\n";
- }
- for (uint t = 0; t < tm_in.tri.size(); ++t) {
- std::cout << " " << tm_in.tri[t].v0() << " " << tm_in.tri[t].v1() << " "
- << tm_in.tri[t].v2() << "\n";
- }
- std::cout << "\n";
- blender::meshintersect::write_obj_trimesh(
- tm_in.vert, tm_in.tri, "boolean_input" + std::to_string(side));
- }
- return tm_in;
-}
-
-/* Do a boolean operation between one or two triangle meshes, and return the answer as another
- * triangle mesh. The in_b argument may be NULL, meaning that the caller wants a unary boolean
- * operation. If the bool_optype is BOOLEAN_NONE, this function just does the self intersection of
- * the one or two meshes. This is a C interface. The caller must call BLI_boolean_trimesh_free() on
- * the returned value when done with it.
- */
-extern "C" Boolean_trimesh_output *BLI_boolean_trimesh(const Boolean_trimesh_input *in_a,
- const Boolean_trimesh_input *in_b,
- int bool_optype)
-{
- constexpr int dbg_level = 0;
- bool is_binary = in_b != NULL;
- if (dbg_level > 0) {
- std::cout << "BLI_BOOLEAN_TRIMESH op=" << blender::meshintersect::bool_optype_name(bool_optype)
- << (is_binary ? " binary" : " unary") << "\n";
- }
- blender::meshintersect::TriMesh tm_in_a = trimesh_from_input(in_a, 0);
- blender::meshintersect::TriMesh tm_out;
- if (is_binary) {
- blender::meshintersect::TriMesh tm_in_b = trimesh_from_input(in_b, 1);
- tm_out = blender::meshintersect::binary_boolean(tm_in_a, tm_in_b, bool_optype);
- }
- else {
- tm_out = blender::meshintersect::self_boolean(tm_in_a, bool_optype);
- }
- if (dbg_level > 1) {
- blender::meshintersect::write_html_trimesh(
- tm_out.vert, tm_out.tri, "mesh_boolean_test.html", "after self_boolean");
- }
- int nv = tm_out.vert.size();
- int nt = tm_out.tri.size();
- Boolean_trimesh_output *output = static_cast<Boolean_trimesh_output *>(
- MEM_mallocN(sizeof(*output), __func__));
- output->vert_len = nv;
- output->tri_len = nt;
- output->vert_coord = static_cast<decltype(output->vert_coord)>(
- MEM_malloc_arrayN(nv, sizeof(output->vert_coord[0]), __func__));
- output->tri = static_cast<decltype(output->tri)>(
- MEM_malloc_arrayN(nt, sizeof(output->tri[0]), __func__));
- for (int v = 0; v < nv; ++v) {
- output->vert_coord[v][0] = static_cast<float>(tm_out.vert[v][0].get_d());
- output->vert_coord[v][1] = static_cast<float>(tm_out.vert[v][1].get_d());
- output->vert_coord[v][2] = static_cast<float>(tm_out.vert[v][2].get_d());
- }
- for (int t = 0; t < nt; ++t) {
- output->tri[t][0] = tm_out.tri[t].v0();
- output->tri[t][1] = tm_out.tri[t].v1();
- output->tri[t][2] = tm_out.tri[t].v2();
- }
- return output;
-}
-
-/* Free the memory used in the return value of BLI_boolean_trimesh. */
-extern "C" void BLI_boolean_trimesh_free(Boolean_trimesh_output *output)
-{
- MEM_freeN(output->vert_coord);
- MEM_freeN(output->tri);
- MEM_freeN(output);
-}
diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc
index 56385f741b5..40f893005ee 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.cc
+++ b/source/blender/bmesh/tools/bmesh_boolean.cc
@@ -21,7 +21,7 @@
*/
#include "BLI_array.hh"
-#include "BLI_boolean.h"
+#include "BLI_boolean.hh"
#include "BLI_math.h"
#include "BLI_math_mpq.hh"
#include "BLI_mesh_intersect.hh"
@@ -169,7 +169,8 @@ static int bmesh_boolean(BMesh *bm,
}
};
}
- PolyMesh pm_out = boolean(pm_in, boolean_mode, nshapes, shape_fn);
+ bool_optype op = static_cast<bool_optype>(boolean_mode);
+ PolyMesh pm_out = boolean(pm_in, op, nshapes, shape_fn);
apply_polymesh_output_to_bmesh(bm, pm_out);
return pm_in.vert.size() != pm_out.vert.size() || pm_in.face.size() != pm_out.face.size();
}
@@ -221,7 +222,7 @@ bool BM_mesh_boolean_knife(BMesh *bm,
const bool use_self,
const bool use_separate_all)
{
- return blender::meshintersect::bmesh_boolean(bm, looptris, looptris_tot, test_fn, user_data, use_self, use_separate_all, BOOLEAN_NONE);
+ return blender::meshintersect::bmesh_boolean(bm, looptris, looptris_tot, test_fn, user_data, use_self, use_separate_all, blender::meshintersect::BOOLEAN_NONE);
}
} /* extern "C" */
diff --git a/tests/gtests/blenlib/BLI_boolean_test.cc b/tests/gtests/blenlib/BLI_boolean_test.cc
index 6503d9ca946..5e542ef0f73 100644
--- a/tests/gtests/blenlib/BLI_boolean_test.cc
+++ b/tests/gtests/blenlib/BLI_boolean_test.cc
@@ -9,62 +9,65 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
-#include "BLI_boolean.h"
+#include "BLI_boolean.hh"
#include "BLI_math_mpq.hh"
#include "BLI_mpq3.hh"
#include "BLI_vector.hh"
-/* Class that can make a Boolean_trimesh_input from a string spec.
+using blender::Array;
+using blender::Vector;
+using blender::mpq3;
+using blender::meshintersect::TriMesh;
+using blender::meshintersect::PolyMesh;
+using blender::meshintersect::IndexedTriangle;
+using blender::meshintersect::BOOLEAN_NONE;
+using blender::meshintersect::BOOLEAN_ISECT;
+using blender::meshintersect::BOOLEAN_UNION;
+using blender::meshintersect::BOOLEAN_DIFFERENCE;
+using blender::meshintersect::boolean;
+using blender::meshintersect::boolean_trimesh;
+using blender::meshintersect::write_obj_trimesh;
+using blender::meshintersect::write_obj_polymesh;
+
+/* Class that can make a TriMesh from a string spec.
* The spec has #verts #tris on the first line, then all the vert coords,
* then all the tris as vert index triples.
*/
class BT_input {
public:
+ TriMesh trimesh;
BT_input(const char *spec)
{
std::istringstream ss(spec);
std::string line;
getline(ss, line);
std::istringstream hdrss(line);
- m_bti.vert_coord = nullptr;
- m_bti.tri = nullptr;
- hdrss >> m_bti.vert_len >> m_bti.tri_len;
- if (m_bti.vert_len > 0 && m_bti.tri_len > 0) {
- m_bti.vert_coord = new float[m_bti.vert_len][3];
- m_bti.tri = new int[m_bti.tri_len][3];
+ int nv, nt;
+ hdrss >> nv >> nt;
+ trimesh.vert = Array<mpq3>(nv);
+ trimesh.tri = Array<IndexedTriangle>(nt);
+ if (nv > 0 && nt > 0) {
int i = 0;
- while (i < m_bti.vert_len && getline(ss, line)) {
+ while (i < nv && getline(ss, line)) {
std::istringstream iss(line);
- iss >> m_bti.vert_coord[i][0] >> m_bti.vert_coord[i][1] >> m_bti.vert_coord[i][2];
+ iss >> trimesh.vert[i][0] >> trimesh.vert[i][1] >> trimesh.vert[i][2];
++i;
}
i = 0;
- while (i < m_bti.tri_len && getline(ss, line)) {
+ while (i < nt && getline(ss, line)) {
std::istringstream tss(line);
- tss >> m_bti.tri[i][0] >> m_bti.tri[i][1] >> m_bti.tri[i][2];
+ int v0, v1, v2;
+ tss >> v0 >> v1 >> v2;
+ trimesh.tri[i] = IndexedTriangle(v0, v1, v2, i);
++i;
}
}
}
-
- ~BT_input()
- {
- delete[] m_bti.vert_coord;
- delete[] m_bti.tri;
- }
-
- Boolean_trimesh_input *input()
- {
- return &m_bti;
- }
-
- private:
- Boolean_trimesh_input m_bti;
};
class BP_input {
public:
- blender::meshintersect::PolyMesh polymesh;
+ PolyMesh polymesh;
BP_input(const char *spec)
{
@@ -74,8 +77,8 @@ class BP_input {
std::istringstream hdrss(line);
int nv, nf;
hdrss >> nv >> nf;
- polymesh.vert = blender::Array<blender::mpq3>(nv);
- polymesh.face = blender::Array<blender::Array<int>>(nf);
+ polymesh.vert = Array<mpq3>(nv);
+ polymesh.face = Array<Array<int>>(nf);
if (nv > 0 && nf > 0) {
int i = 0;
while (i < nv && getline(ss, line)) {
@@ -86,12 +89,12 @@ class BP_input {
i = 0;
while (i < nf && getline(ss, line)) {
std::istringstream tss(line);
- blender::Vector<int> f;
+ Vector<int> f;
int v;
while (tss >> v) {
f.append(v);
}
- polymesh.face[i] = blender::Array<int>(f.size());
+ polymesh.face[i] = Array<int>(f.size());
std::copy(f.begin(), f.end(), polymesh.face[i].begin());
++i;
}
@@ -99,96 +102,28 @@ class BP_input {
}
};
-/* Some contrasting colors to use for distinguishing triangles. */
-static const char *drawcolor[] = {
- "0.67 0.14 0.14", /* red */
- "0.16 0.29 0.84", /* blue */
- "0.11 0.41 0.08", /* green */
- "0.50 0.29 0.10", /* brown */
- "0.50 0.15 0.75", /* purple */
- "0.62 0.62 0.62", /* light grey */
- "0.50 0.77 0.49", /* light green */
- "0.61 0.68 1.00", /* light blue */
- "0.16 0.82 0.82", /* cyan */
- "1.00 0.57 0.20", /* orange */
- "1.00 0.93 0.20", /* yellow */
- "0.91 0.87 0.73", /* tan */
- "1.00 0.80 0.95", /* pink */
- "0.34 0.34 0.34" /* dark grey */
-};
-static constexpr int numcolors = sizeof(drawcolor) / sizeof(drawcolor[0]);
-
-static void write_obj(const Boolean_trimesh_output *out, const std::string objname)
-{
- constexpr const char *objdir = "/tmp/";
- if (out->tri_len == 0) {
- return;
- }
-
- std::string fname = std::string(objdir) + objname + std::string(".obj");
- std::string matfname = std::string(objdir) + std::string("dumpobj.mtl");
- std::ofstream f;
- f.open(fname);
- if (!f) {
- std::cout << "Could not open file " << fname << "\n";
- return;
- }
-
- f << "mtllib dumpobj.mtl\n";
-
- for (int v = 0; v < out->vert_len; ++v) {
- float *co = out->vert_coord[v];
- f << "v " << co[0] << " " << co[1] << " " << co[2] << "\n";
- }
-
- for (int i = 0; i < out->tri_len; ++i) {
- int matindex = i % numcolors;
- f << "usemtl mat" + std::to_string(matindex) + "\n";
- /* OBJ files use 1-indexing for vertices. */
- int *tri = out->tri[i];
- f << "f " << tri[0] + 1 << " " << tri[1] + 1 << " " << tri[2] + 1 << "\n";
- }
- f.close();
-
- /* Could check if it already exists, but why bother. */
- std::ofstream mf;
- mf.open(matfname);
- if (!mf) {
- std::cout << "Could not open file " << matfname << "\n";
- return;
- }
- for (int c = 0; c < numcolors; ++c) {
- mf << "newmtl mat" + std::to_string(c) + "\n";
- mf << "Kd " << drawcolor[c] << "\n";
- }
-}
constexpr bool DO_OBJ = true;
TEST(eboolean, Empty)
{
- Boolean_trimesh_input in;
- in.vert_len = 0;
- in.tri_len = 0;
- in.vert_coord = NULL;
- in.tri = NULL;
- Boolean_trimesh_output *out = BLI_boolean_trimesh(&in, nullptr, BOOLEAN_NONE);
- EXPECT_EQ(out->vert_len, 0);
- EXPECT_EQ(out->tri_len, 0);
- BLI_boolean_trimesh_free(out);
+ TriMesh in;
+ TriMesh out = boolean_trimesh(in, BOOLEAN_NONE, 1, [](int){return 0;});
+ EXPECT_EQ(out.vert.size(), 0);
+ EXPECT_EQ(out.tri.size(), 0);
}
TEST(eboolean, TetTet)
{
const char *spec = R"(8 8
- 0.0 0.0 0.0
- 2.0 0.0 0.0
- 1.0 2.0 0.0
- 1.0 1.0 2.0
- 0.0 0.0 1.0
- 2.0 0.0 1.0
- 1.0 2.0 1.0
- 1.0 1.0 3.0
+ 0 0 0
+ 2 0 0
+ 1 2 0
+ 1 1 2
+ 0 0 1
+ 2 0 1
+ 1 2 1
+ 1 1 3
0 2 1
0 1 3
1 2 3
@@ -198,35 +133,34 @@ TEST(eboolean, TetTet)
5 6 7
6 4 7
)";
+
BT_input bti(spec);
- Boolean_trimesh_output *out = BLI_boolean_trimesh(bti.input(), nullptr, BOOLEAN_NONE);
- EXPECT_EQ(out->vert_len, 11);
- EXPECT_EQ(out->tri_len, 20);
+ TriMesh out = boolean_trimesh(bti.trimesh, BOOLEAN_NONE, 1, [](int){return 0;});
+ EXPECT_EQ(out.vert.size(), 11);
+ EXPECT_EQ(out.tri.size(), 20);
if (DO_OBJ) {
- write_obj(out, "tettet");
+ write_obj_trimesh(out.vert, out.tri, "tettet");
}
- BLI_boolean_trimesh_free(out);
- Boolean_trimesh_output *out2 = BLI_boolean_trimesh(bti.input(), nullptr, BOOLEAN_UNION);
- EXPECT_EQ(out2->vert_len, 10);
- EXPECT_EQ(out2->tri_len, 16);
+ TriMesh out2 =boolean_trimesh(bti.trimesh, BOOLEAN_UNION, 1, [](int){return 0;});
+ EXPECT_EQ(out2.vert.size(), 10);
+ EXPECT_EQ(out2.tri.size(), 16);
if (DO_OBJ) {
- write_obj(out2, "tettet_union");
+ write_obj_trimesh(out2.vert, out2.tri, "tettet_union");
}
- BLI_boolean_trimesh_free(out2);
}
TEST(eboolean, TetTet2)
{
const char *spec = R"(8 8
- 0.0 1.0 -1.0
- 0.875 -0.5 -1.0
- -0.875 -0.5 -1.0
- 0.0 0.0 1.0
- 0.0 1.0 0.0
- 0.875 -0.5 0.0
- -0.875 -0.5 0.0
- 0.0 0.0 2.0
+ 0 1 -1
+ 7/8 -1/2 -1
+ -7/8 -1/2 -1
+ 0 0 1
+ 0 1 0
+ 7/8 -1/2 0
+ -7/8 -1/2 0
+ 0 0 2
0 3 1
0 1 2
1 3 2
@@ -238,13 +172,12 @@ TEST(eboolean, TetTet2)
)";
BT_input bti(spec);
- Boolean_trimesh_output *out = BLI_boolean_trimesh(bti.input(), nullptr, BOOLEAN_UNION);
- EXPECT_EQ(out->vert_len, 10);
- EXPECT_EQ(out->tri_len, 16);
+ TriMesh out =boolean_trimesh(bti.trimesh, BOOLEAN_UNION, 1, [](int){return 0;});
+ EXPECT_EQ(out.vert.size(), 10);
+ EXPECT_EQ(out.tri.size(), 16);
if (DO_OBJ) {
- write_obj(out, "tettet2_union");
+ write_obj_trimesh(out.vert, out.tri, "tettet2_union");
}
- BLI_boolean_trimesh_free(out);
}
TEST(eboolean, CubeTet)
@@ -258,10 +191,10 @@ TEST(eboolean, CubeTet)
1 -1 1
1 1 -1
1 1 1
- 0 0.5 0.5
- 0.5 -0.25 0.5
- -0.5 -0.25 0.5
- 0 0 1.5
+ 0 1/2 1/2
+ 1/2 -1/4 1/2
+ -1/2 -1/4 1/2
+ 0 0 3/2
0 1 3
0 3 2
2 3 7
@@ -281,47 +214,42 @@ TEST(eboolean, CubeTet)
)";
BT_input bti(spec);
- Boolean_trimesh_output *out = BLI_boolean_trimesh(bti.input(), nullptr, BOOLEAN_UNION);
- EXPECT_EQ(out->vert_len, 14);
- EXPECT_EQ(out->tri_len, 24);
+ TriMesh out = boolean_trimesh(bti.trimesh, BOOLEAN_UNION, 1, [](int){return 0;});
+ EXPECT_EQ(out.vert.size(), 14);
+ EXPECT_EQ(out.tri.size(), 24);
if (DO_OBJ) {
- write_obj(out, "cubetet_union");
+ write_obj_trimesh(out.vert, out.tri, "cubetet_union");
}
- BLI_boolean_trimesh_free(out);
}
TEST(eboolean, BinaryTetTet)
{
- const char *spec_a = R"(4 4
- 0.0 0.0 0.0
- 2.0 0.0 0.0
- 1.0 2.0 0.0
- 1.0 1.0 2.0
- 0 2 1
- 0 1 3
- 1 2 3
- 2 0 3
- )";
- const char *spec_b = R"(4 4
- 0.0 0.0 1.0
- 2.0 0.0 1.0
- 1.0 2.0 1.0
- 1.0 1.0 3.0
+ const char *spec = R"(8 8
+ 0 0 0
+ 2 0 0
+ 1 2 0
+ 1 1 2
+ 0 0 1
+ 2 0 1
+ 1 2 1
+ 1 1 3
0 2 1
0 1 3
1 2 3
2 0 3
+ 4 6 5
+ 4 5 7
+ 5 6 7
+ 6 4 7
)";
- BT_input bti_a(spec_a);
- BT_input bti_b(spec_b);
- Boolean_trimesh_output *out = BLI_boolean_trimesh(bti_a.input(), bti_b.input(), BOOLEAN_ISECT);
- EXPECT_EQ(out->vert_len, 4);
- EXPECT_EQ(out->tri_len, 4);
+ BT_input bti(spec);
+ TriMesh out = boolean_trimesh(bti.trimesh, BOOLEAN_ISECT, 2, [](int t){return t < 4 ? 0 : 1;});
+ EXPECT_EQ(out.vert.size(), 4);
+ EXPECT_EQ(out.tri.size(), 4);
if (DO_OBJ) {
- write_obj(out, "binary_tettet_isect");
+ write_obj_trimesh(out.vert, out.tri, "binary_tettet_isect");
}
- BLI_boolean_trimesh_free(out);
}
TEST(eboolean, PolyCubeCube)