1 /* SPDX-FileCopyrightText: 2023 Blender Authors
3 * SPDX-License-Identifier: GPL-2.0-or-later */
10 * Mesh intersection library functions.
11 * Uses exact arithmetic, so need GMP.
18 # include "BLI_array.hh"
19 # include "BLI_function_ref.hh"
20 # include "BLI_index_range.hh"
21 # include "BLI_map.hh"
22 # include "BLI_math_mpq.hh"
23 # include "BLI_math_vector_mpq_types.hh"
24 # include "BLI_math_vector_types.hh"
25 # include "BLI_span.hh"
26 # include "BLI_utility_mixins.hh"
28 namespace blender::meshintersect
{
30 constexpr int NO_INDEX
= -1;
33 * Vertex coordinates are stored both as #double3 and #mpq3, which should agree.
34 * Most calculations are done in exact arithmetic, using the mpq3 version,
35 * but some predicates can be sped up by operating on doubles and using error analysis
36 * to find the cases where that is good enough.
37 * Vertices also carry along an id, created on allocation. The id
38 * is useful for making algorithms that don't depend on pointers.
39 * Also, they are easier to read while debugging.
40 * They also carry an orig index, which can be used to tie them back to
41 * vertices that the caller may have in a different way (e.g., #BMVert).
42 * An orig index can be #NO_INDEX, indicating the Vert was created by
43 * the algorithm and doesn't match an original Vert.
44 * Vertices can be reliably compared for equality,
45 * and hashed (on their co_exact field).
54 Vert(const mpq3
&mco
, const double3
&dco
, int id
, int orig
);
57 /** Test equality on the co_exact field. */
58 bool operator==(const Vert
&other
) const;
60 /** Hash on the co_exact field. */
61 uint64_t hash() const;
64 std::ostream
&operator<<(std::ostream
&os
, const Vert
*v
);
67 * A Plane whose equation is `dot(norm, p) + d = 0`.
68 * The norm and d fields are always present, but the norm_exact
69 * and d_exact fields may be lazily populated. Since we don't
70 * store degenerate planes, we can tell if a the exact versions
71 * are not populated yet by having `norm_exact == 0`.
80 Plane(const mpq3
&norm_exact
, const mpq_class
&d_exact
);
81 Plane(const double3
&norm
, double d
);
83 /** Test equality on the exact fields. */
84 bool operator==(const Plane
&other
) const;
86 /** Hash on the exact fields. */
87 uint64_t hash() const;
89 void make_canonical();
91 * This is wrong for degenerate planes, but we don't expect to call it on those.
93 bool exact_populated() const;
94 void populate_exact();
97 std::ostream
&operator<<(std::ostream
&os
, const Plane
*plane
);
100 * A #Face has a sequence of Verts that for a CCW ordering around them.
101 * Faces carry an index, created at allocation time, useful for making
102 * pointer-independent algorithms, and for debugging.
103 * They also carry an original index, meaningful to the caller.
104 * And they carry original edge indices too: each is a number meaningful
105 * to the caller for the edge starting from the corresponding face position.
106 * A "face position" is the index of a vertex around a face.
107 * Faces don't own the memory pointed at by the vert array.
108 * Also indexed by face position, the is_intersect array says
109 * for each edge whether or not it is the result of intersecting
110 * with another face in the intersect algorithm.
111 * Since the intersect algorithm needs the plane for each face,
112 * a #Face also stores the Plane of the face, but this is only
113 * populate later because not all faces will be intersected.
115 struct Face
: NonCopyable
{
116 Array
<const Vert
*> vert
;
117 Array
<int> edge_orig
;
118 Array
<bool> is_intersect
;
119 Plane
*plane
= nullptr;
126 Face(Span
<const Vert
*> verts
, int id
, int orig
, Span
<int> edge_origs
, Span
<bool> is_intersect
);
127 Face(Span
<const Vert
*> verts
, int id
, int orig
);
132 return vert
.size() == 3;
135 /* Test equality of verts, in same positions. */
136 bool operator==(const Face
&other
) const;
138 /* Test equality faces allowing cyclic shifts. */
139 bool cyclic_equal(const Face
&other
) const;
141 FacePos
next_pos(FacePos p
) const
143 return (p
+ 1) % vert
.size();
146 FacePos
prev_pos(FacePos p
) const
148 return (p
+ vert
.size() - 1) % vert
.size();
151 const Vert
*const &operator[](int index
) const
161 const Vert
*const *begin() const
166 const Vert
*const *end() const
171 IndexRange
index_range() const
173 return IndexRange(vert
.size());
176 void populate_plane(bool need_exact
);
178 bool plane_populated() const
180 return plane
!= nullptr;
184 std::ostream
&operator<<(std::ostream
&os
, const Face
*f
);
187 * #IMeshArena is the owner of the Vert and Face resources used
188 * during a run of one of the mesh-intersect main functions.
189 * It also keeps has a hash table of all Verts created so that it can
190 * ensure that only one instance of a Vert with a given co_exact will
191 * exist. I.e., it de-duplicates the vertices.
193 class IMeshArena
: NonCopyable
, NonMovable
{
194 class IMeshArenaImpl
;
195 std::unique_ptr
<IMeshArenaImpl
> pimpl_
;
202 * Provide hints to number of expected Verts and Faces expected
205 void reserve(int vert_num_hint
, int face_num_hint
);
207 int tot_allocated_verts() const;
208 int tot_allocated_faces() const;
211 * These add routines find and return an existing Vert with the same
212 * co_exact, if it exists (the orig argument is ignored in this case),
213 * or else allocates and returns a new one. The index field of a
214 * newly allocated Vert will be the index in creation order.
216 const Vert
*add_or_find_vert(const mpq3
&co
, int orig
);
217 const Vert
*add_or_find_vert(const double3
&co
, int orig
);
218 const Vert
*add_or_find_vert(Vert
*vert
);
220 Face
*add_face(Span
<const Vert
*> verts
,
222 Span
<int> edge_origs
,
223 Span
<bool> is_intersect
);
224 Face
*add_face(Span
<const Vert
*> verts
, int orig
, Span
<int> edge_origs
);
225 Face
*add_face(Span
<const Vert
*> verts
, int orig
);
227 /** The following return #nullptr if not found. */
228 const Vert
*find_vert(const mpq3
&co
) const;
229 const Face
*find_face(Span
<const Vert
*> verts
) const;
233 * A #blender::meshintersect::IMesh is a self-contained mesh structure
234 * that can be used in `blenlib` without depending on the rest of Blender.
235 * The Vert and #Face resources used in the #IMesh should be owned by
237 * The Verts used by a #IMesh can be recovered from the Faces, so
238 * are usually not stored, but on request, the #IMesh can populate
239 * internal structures for indexing exactly the set of needed Verts,
240 * and also going from a Vert pointer to the index in that system.
243 Array
<Face
*> face_
; /* Not `const` so can lazily populate planes. */
244 Array
<const Vert
*> vert_
; /* Only valid if vert_populated_. */
245 Map
<const Vert
*, int> vert_to_index_
; /* Only valid if vert_populated_. */
246 bool vert_populated_
= false;
250 IMesh(Span
<Face
*> faces
) : face_(faces
) {}
252 void set_faces(Span
<Face
*> faces
);
253 Face
*face(int index
) const
258 int face_size() const
263 int vert_size() const
268 bool has_verts() const
270 return vert_populated_
;
273 void set_dirty_verts()
275 vert_populated_
= false;
276 vert_to_index_
.clear();
277 vert_
= Array
<const Vert
*>();
280 /* Pass `max_verts` if there is a good bound estimate on the maximum number of verts. */
281 void populate_vert();
282 void populate_vert(int max_verts
);
284 const Vert
*vert(int index
) const
286 BLI_assert(vert_populated_
);
290 /** Returns index in vert_ where v is, or #NO_INDEX. */
291 int lookup_vert(const Vert
*v
) const;
293 IndexRange
vert_index_range() const
295 BLI_assert(vert_populated_
);
296 return IndexRange(vert_
.size());
299 IndexRange
face_index_range() const
301 return IndexRange(face_
.size());
304 Span
<const Vert
*> vertices() const
306 BLI_assert(vert_populated_
);
307 return Span
<const Vert
*>(vert_
);
310 Span
<Face
*> faces() const
312 return Span
<Face
*>(face_
);
316 * Replace face at given index with one that elides the
317 * vertices at the positions in face_pos_erase that are true.
318 * Use arena to allocate the new face in.
319 * This may end up setting the face at f_index to NULL.
320 * Return true if that is so, else return false.
321 * The caller may want to use remove_null_faces if any face
322 * was removed, to avoid the need to check for null faces later.
324 bool erase_face_positions(int f_index
, Span
<bool> face_pos_erase
, IMeshArena
*arena
);
326 void remove_null_faces();
329 std::ostream
&operator<<(std::ostream
&os
, const IMesh
&mesh
);
332 * A Bounding Box using floats, and a routine to detect possible
336 float3 min
{FLT_MAX
, FLT_MAX
, FLT_MAX
};
337 float3 max
{-FLT_MAX
, -FLT_MAX
, -FLT_MAX
};
339 BoundingBox() = default;
340 BoundingBox(const float3
&min
, const float3
&max
) : min(min
), max(max
) {}
342 void combine(const float3
&p
)
344 math::min_max(p
, this->min
, this->max
);
347 void combine(const double3
&p
)
349 math::min_max(float3(p
), this->min
, this->max
);
352 void combine(const BoundingBox
&bb
)
354 min
= math::min(this->min
, bb
.min
);
355 max
= math::max(this->max
, bb
.max
);
358 void expand(float pad
)
366 * Assume bounding boxes have been expanded by a sufficient epsilon on all sides
367 * so that the comparisons against the bb bounds are sufficient to guarantee that
368 * if an overlap or even touching could happen, this will return true.
370 bool bbs_might_intersect(const BoundingBox
&bb_a
, const BoundingBox
&bb_b
);
373 * This is the main routine for calculating the self_intersection of a triangle mesh.
375 * The output will have duplicate vertices merged and degenerate triangles ignored.
376 * If the input has overlapping co-planar triangles, then there will be
377 * as many duplicates as there are overlaps in each overlapping triangular region.
378 * The orig field of each #IndexedTriangle will give the orig index in the input #IMesh
379 * that the output triangle was a part of (input can have -1 for that field and then
380 * the index in `tri[]` will be used as the original index).
381 * The orig structure of the output #IMesh gives the originals for vertices and edges.
382 * \note if the input tm_in has a non-empty orig structure, then it is ignored.
384 IMesh
trimesh_self_intersect(const IMesh
&tm_in
, IMeshArena
*arena
);
386 IMesh
trimesh_nary_intersect(const IMesh
&tm_in
,
388 FunctionRef
<int(int)> shape_fn
,
393 * Return an #IMesh that is a triangulation of a mesh with general
394 * polygonal faces, #IMesh.
395 * Added diagonals will be distinguishable by having edge original
396 * indices of #NO_INDEX.
398 IMesh
triangulate_polymesh(IMesh
&imesh
, IMeshArena
*arena
);
401 * Writing the obj_mesh has the side effect of populating verts in the #IMesh.
403 void write_obj_mesh(IMesh
&m
, const std::string
&objname
);
405 } /* namespace blender::meshintersect */
407 #endif /* WITH_GMP */