Library of Assembled Shared Sources
triangle_mesh_3d.h
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2024 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43
44
45/** @class lass::prim::TriangleMesh3D
46 * @brief One of the simplier meshes
47 * @author Bram de Greve [BdG]
48 */
49
50#ifndef LASS_GUARDIAN_OF_INCLUSION_PRIM_TRIANGLE_MESH_3D_H
51#define LASS_GUARDIAN_OF_INCLUSION_PRIM_TRIANGLE_MESH_3D_H
52
53#include "prim_common.h"
54#include "aabb_3d.h"
55#include "point_2d.h"
56#include "ray_3d.h"
57#include "triangle_3d.h"
63
64namespace lass
65{
66namespace prim
67{
68
69struct IndexTriangle
70{
71 size_t vertices[3];
72 size_t normals[3];
73 size_t uvs[3];
74
75 size_t size() const { return 3; }
76 static size_t null() { return static_cast<size_t>(-1); }
77};
78
79LASS_DLL bool LASS_CALL operator==(const IndexTriangle& a, const IndexTriangle& b);
80
81template
82<
83 typename T,
84 template <typename TT, typename OT, typename SH> class BoundingVolumeHierarchy,
85 typename SplitHeuristics
86>
87class TriangleMesh3D
88{
89public:
90
91 typedef TriangleMesh3D<T, BoundingVolumeHierarchy, SplitHeuristics> TSelf;
92
93 typedef Point3D<T> TPoint;
94 typedef typename TPoint::TVector TVector;
95 typedef Point2D<T> TUv;
96 typedef Aabb3D<T> TAabb;
98
99 typedef typename TPoint::TValue TValue;
100 typedef typename TPoint::TParam TParam;
101 typedef typename TPoint::TReference TReference;
102 typedef typename TPoint::TConstReference TConstReference;
103 typedef typename TPoint::TNumTraits TNumTraits;
104
105 typedef impl::IntersectTriangle3DWoop<TPoint> TIntersectTriangleWoop;
106
107
108 enum
109 {
110 dimension = TPoint::dimension,
111 };
112
113 template <typename U> struct Rebind
114 {
115 typedef TriangleMesh3D<U, BoundingVolumeHierarchy, SplitHeuristics> Type;
116 };
117
118 struct IntersectionContext
119 {
120 TPoint point;
121 TVector normal;
122 TVector dPoint_dU;
123 TVector dPoint_dV;
124 TVector dNormal_dU;
125 TVector dNormal_dV;
126 TVector geometricNormal;
127 TUv uv;
128 };
129
130 struct Triangle
131 {
132 typedef typename TPoint::TVector TVector;
133
134 const TPoint* vertices[3];
135 const TVector* normals[3];
136 const TUv* uvs[3];
137 Triangle* others[3]; /**< triangle on other side of vertices k,k+1 */
138 unsigned creaseLevel[3]; /**< crease level of side k,k+1 */
139 size_t attribute;
140
141 Result intersect(const TRay& ray, TReference t, TParam tMin = 0, IntersectionContext* context = 0) const;
142 Result intersect(const TIntersectTriangleWoop& intersectWoop, TReference t, TParam tMin = 0, IntersectionContext* context = 0) const;
143 size_t side(const TPoint* v) const;
144 TValue area() const;
145 TVector geometricNormal() const;
146 };
147
148 typedef IntersectionContext TIntersectionContext;
149 typedef Triangle TTriangle;
150 typedef IndexTriangle TIndexTriangle;
151
152 // we need to use std::vector as we're going to rely on some pointer arithmetic ...
153 typedef std::vector<Triangle> TTriangles;
154 typedef std::vector<TPoint> TVertices;
155 typedef std::vector<TVector> TNormals;
156 typedef std::vector<TUv> TUvs;
157
158 typedef typename TTriangles::const_iterator TTriangleIterator;
159 typedef typename TVertices::const_iterator TVertexIterator;
160 typedef typename TNormals::const_iterator TNormalIterator;
161 typedef typename TUvs::const_iterator TUvIterator;
162
163 typedef std::vector<TTriangleIterator> TTriangleIterators;
164
165 TriangleMesh3D(const SplitHeuristics& heuristics = SplitHeuristics(defaultMaxObjectsPerLeaf, defaultMaxDepth));
166
167 template <typename VertexInputRange, typename IndexTriangleInputRange>
168 TriangleMesh3D(
169 const VertexInputRange& vertices, const IndexTriangleInputRange& triangles,
170 const SplitHeuristics& heuristics = SplitHeuristics(defaultMaxObjectsPerLeaf, defaultMaxDepth));
171
172 template <typename VertexInputRange, typename NormalInputRange, typename UvInputRange, typename IndexTriangleInputRange>
173 TriangleMesh3D(
174 const VertexInputRange& vertices, const NormalInputRange& normals, const UvInputRange& uvs, const IndexTriangleInputRange& triangles,
175 const SplitHeuristics& heuristics = SplitHeuristics(defaultMaxObjectsPerLeaf, defaultMaxDepth));
176
177 template <typename IndexTriangleInputRange>
178 TriangleMesh3D(
179 TVertices&& vertices, const IndexTriangleInputRange& triangles,
180 const SplitHeuristics& heuristics = SplitHeuristics(defaultMaxObjectsPerLeaf, defaultMaxDepth)
181 );
182
183 template <typename IndexTriangleInputRange>
184 TriangleMesh3D(
185 TVertices&& vertices, TNormals&& normals, TUvs&& uvs, const IndexTriangleInputRange& triangles,
186 const SplitHeuristics& heuristics = SplitHeuristics(defaultMaxObjectsPerLeaf, defaultMaxDepth)
187 );
188
189 TriangleMesh3D(const TriangleMesh3D& other);
190 TriangleMesh3D(TriangleMesh3D&& other);
191
192 TriangleMesh3D& operator=(const TriangleMesh3D& other);
193 TriangleMesh3D& operator=(TriangleMesh3D&& other);
194
195 const TTriangles& triangles() const;
196 const TVertices& vertices() const;
197 const TNormals& normals() const;
198 const TUvs& uvs() const;
199 template <typename OutputIterator>
200 OutputIterator indexTriangles(OutputIterator triangles) const;
201
202 const TAabb aabb() const;
203 const TValue area() const;
204
205 void smoothNormals();
206 void flatFaces();
207
208 void loopSubdivision(unsigned level);
209 template <typename Func> void subdivisionWithLimitSurface(unsigned level, Func snapToLimitSurface);
210 template <typename Func> void subdivisionWithLimitSurface(unsigned level, Func snapToLimitSurface, TTriangleIterators& selected);
211
212 void autoSew();
213 void autoCrease(unsigned level);
214 void autoCrease(unsigned level, TParam maxAngleInRadians);
215
216 using TFilter = std::function<bool(TTriangleIterator, TValue t)>;
217
218 Result intersect(const TRay& ray, TTriangleIterator& triangle, TReference t, TParam tMin = 0, IntersectionContext* context = 0) const;
219 bool intersects(const TRay& ray, TParam tMin, TParam tMax) const;
220
221 Result intersectFilter(const TRay& ray, TTriangleIterator& triangle, TReference t, TParam tMin, TFilter filter, IntersectionContext* context = 0) const;
222 bool intersectsFilter(const TRay& ray, TParam tMin, TParam tMax, TFilter filter) const;
223
224 void swap(TSelf& other);
225
226private:
227
228 typedef spat::DefaultAabbRayTraits<TAabb, TRay> TAabbRayTraits;
229
230 struct IntersectInfo
231 {
232 const TIntersectTriangleWoop woop;
233 const TFilter filter;
234
235 IntersectInfo(const TRay& ray, TFilter filter):
236 woop(ray.support(), ray.direction()),
237 filter(filter) {}
238 };
239
240 struct TriangleTraits: public TAabbRayTraits
241 {
242 typedef typename TSelf::TTriangle TObject;
243 typedef typename TSelf::TTriangleIterator TObjectIterator;
244 typedef const TTriangle& TObjectReference;
245 typedef void TInfo;
246
247 typedef typename TAabbRayTraits::TAabb TAabb;
248 typedef typename TAabbRayTraits::TRay TRay;
249 typedef typename TAabbRayTraits::TPoint TPoint;
250 typedef typename TAabbRayTraits::TVector TVector;
251 typedef typename TAabbRayTraits::TValue TValue;
252 typedef typename TAabbRayTraits::TParam TParam;
253 typedef typename TAabbRayTraits::TReference TReference;
254 typedef typename TAabbRayTraits::TConstReference TConstReference;
255
256 static const TAabb objectAabb(TObjectIterator triangle)
257 {
258 TAabb result;
259 result += *(triangle->vertices[0]);
260 result += *(triangle->vertices[1]);
261 result += *(triangle->vertices[2]);
262 return result;
263 }
264 static bool objectIntersect(TObjectIterator triangle, const TRay& /*ray*/, TReference t, TParam tMin, const TInfo* info)
265 {
266 LASS_ASSERT(info);
267 const IntersectInfo* myInfo = static_cast<const IntersectInfo*>(info);
268 const bool hit = triangle->intersect(myInfo->woop, t, tMin) == rOne;
269 if (!hit)
270 {
271 return false;
272 }
273 if (myInfo->filter && !myInfo->filter(triangle, t))
274 {
275 return false;
276 }
277 return true;
278 }
279 static bool objectIntersects(TObjectIterator triangle, const TRay& /*ray*/, TParam tMin, TParam tMax, const TInfo* info)
280 {
281 LASS_ASSERT(info);
282 const IntersectInfo* myInfo = static_cast<const IntersectInfo*>(info);
283 TValue t;
284 const bool hit = triangle->intersect(myInfo->woop, t, tMin) == rOne;
285 if (!hit || t >= tMax)
286 {
287 return false;
288 }
289 if (myInfo->filter && !myInfo->filter(triangle, t))
290 {
291 return false;
292 }
293 return true;
294 }
295 static bool objectIntersects(TObjectIterator triangle, const TAabb& aabb, const TInfo*)
296 {
297 const prim::Triangle3D<T> temp(
298 *(triangle->vertices[0]),
299 *(triangle->vertices[1]),
300 *(triangle->vertices[2]));
301 return prim::intersects(temp, aabb);
302 }
303 };
304
305 typedef BoundingVolumeHierarchy<TTriangle, TriangleTraits, SplitHeuristics> TTriangleTree;
306
307 enum {
308 defaultMaxObjectsPerLeaf = TTriangleTree::defaultMaxObjectsPerLeaf,
309 defaultMaxDepth = TTriangleTree::defaultMaxDepth,
310 };
311
312 struct LogicalEdge
313 {
314 Triangle* triangle;
315 const TPoint* tail;
316 const TPoint* head;
317 LogicalEdge(Triangle* triangle, const TPoint* tail, const TPoint* head):
318 triangle(triangle), tail(tail), head(head) {}
319 bool operator==(const LogicalEdge& other) const
320 {
321 return tail == other.tail && head == other.head;
322 }
323 bool operator<(const LogicalEdge& other) const
324 {
325 return tail < other.tail || (tail == other.tail && head < other.head);
326 }
327 };
328
329 struct PositionalEdge
330 {
331 Triangle* triangle;
332 size_t k1;
333 size_t k2;
334 PositionalEdge(Triangle* triangle, size_t k1, size_t k2):
335 triangle(triangle), k1(k1), k2(k2)
336 {
337 const TPoint& v1 = *triangle->vertices[k1];
338 x_[ 0] = v1.x;
339 x_[ 1] = v1.y;
340 x_[ 2] = v1.z;
341 const TPoint& v2 = *triangle->vertices[k2];
342 x_[ 3] = v2.x;
343 x_[ 4] = v2.y;
344 x_[ 5] = v2.z;
345 }
346 bool operator<(const PositionalEdge& other) const
347 {
348 for (size_t i = 0; i < size_; ++i)
349 {
350 if (x_[i] < other.x_[i]) return true;
351 if (x_[i] > other.x_[i]) return false;
352 }
353 return false;
354 }
355 private:
356 enum { size_ = 6 };
357 TValue x_[size_];
358 };
359
360 class HalfEdge
361 {
362 public:
363 typedef typename TPoint::TVector TVector;
364
365 HalfEdge(const Triangle* triangle, size_t edge): triangle_(triangle), edge_(edge) { LASS_ASSERT(edge_ < 3); }
366 HalfEdge(const Triangle* triangle, const TPoint* tail): triangle_(triangle), edge_(triangle->side(tail)) { LASS_ASSERT(edge_ < 3); }
367 const Triangle* triangle() const { return triangle_; }
368 size_t edge() const { return edge_; }
369
370 const TPoint* vertex() const { return triangle_->vertices[edge_]; }
371 const TVector* normal() const { return triangle_->normals[edge_]; }
372 const TUv* uv() const { return triangle_->uvs[edge_]; }
373 unsigned creaseLevel() const { return triangle_->creaseLevel[edge_]; }
374 void setNormal(const TVector* normal) { const_cast<Triangle*>(triangle_)->normals[edge_] = normal; } // oops ...
375 const TVector vector() const { return *oNext().vertex() - *vertex(); }
376
377 HalfEdge oPrev() const { return HalfEdge(triangle_, (edge_ + 2) % 3); } // previous edge within triangle, clock wise
378 HalfEdge oNext() const { return HalfEdge(triangle_, (edge_ + 1) % 3); } // next edge within triangle, counter clock wise
379 HalfEdge rPrev() const { return sym().oNext(); } // previous edge around vertex, clock wise
380 HalfEdge rNext() const { return oPrev().sym(); } // next edge around vertex, counter clock wise
381 HalfEdge sym() const // same edge, but on other side.
382 {
383 const Triangle* other = triangle_->others[edge_];
384 if (!other || other->others[0] == triangle_)
385 {
386 return HalfEdge(other, size_t(0));
387 }
388 if (other->others[1] == triangle_)
389 {
390 return HalfEdge(other, 1);
391 }
392 LASS_ASSERT(other->others[2] == triangle_);
393 return HalfEdge(other, 2);
394 }
395
396 bool isCrease() const
397 {
398 return creaseLevel() > 0 || sym().sym() != *this; // it's safe to do a sym of a "null" edge.
399 }
400
401 bool operator!() const { return !triangle_; }
402 explicit operator bool() const { return triangle_ != 0; }
403 private:
404 const Triangle* triangle_;
405 size_t edge_;
406 };
407
408 typedef std::vector<const Triangle*> TVertexTriangles;
409 typedef std::vector<const TPoint*> TVertexRing;
410 typedef std::vector<const TUv*> TUvRing;
411
412 typedef std::pair<Triangle*, Triangle*> TWing;
413 typedef std::map<const TPoint*, TWing> TOddVertexWings;
414
415 template <typename IndexTriangleInputIterator> void buildMesh(IndexTriangleInputIterator first, IndexTriangleInputIterator last);
416 void connectTriangles();
417 void findVertexTriangles(TVertexTriangles& vertexTriangles) const;
418 void findVertexRing(const TPoint& vertex, const Triangle* vertexTriangle, TVertexRing& ring, TVertexRing& creases, TUvRing& uvs) const;
419 void subdivide();
420 void subdivide(TTriangleIterators& selected, TOddVertexWings& oddVertexWings);
421
422 TTriangleTree tree_;
423 TTriangles triangles_;
424 TVertices vertices_;
425 TNormals normals_;
426 TUvs uvs_;
427 size_t numBoundaryEdges_;
428};
429
430}
431
432}
433
434#include "triangle_mesh_3d.inl"
435
436#define LASS_PRIM_HAVE_PY_EXPORT_TRAITS_TRIANGLE_MESH_3D
437#ifdef LASS_GUARDIAN_OF_INCLUSION_UTIL_PYOBJECT_PLUS_H
439#endif
440
441#ifdef LASS_GUARDIAN_OF_INCLUSION_PRIM_HALF_EDGE_MESH_3D_H
442# include "half_edge_mesh_3d_triangle_mesh_3d.h"
443#endif
444
445#ifdef LASS_GUARDIAN_OF_INCLUSION_PRIM_SPHERE_3D_H
447#endif
448
449#endif
450
451// EOF
your momma's axis aligned bounding box.
Definition aabb_3d.h:89
Result intersectFilter(const TRay &ray, TTriangleIterator &triangle, TReference t, TParam tMin, TFilter filter, IntersectionContext *context=0) const
Find nearest intersection with ray that passes the filter, and with t > tMin.
void flatFaces()
remove all normals, so that faces become flat
bool intersectsFilter(const TRay &ray, TParam tMin, TParam tMax, TFilter filter) const
Checks if the ray has any intersection that passes the filter, and with t > tMin and t < tMax.
bool intersects(const TRay &ray, TParam tMin, TParam tMax) const
Checks if the ray has any intersection with the mesh, with t > tMin and t < tMax.
void subdivisionWithLimitSurface(unsigned level, Func snapToLimitSurface)
global subdivision with function to resnap new vertices.
Result intersect(const TRay &ray, TTriangleIterator &triangle, TReference t, TParam tMin=0, IntersectionContext *context=0) const
Find nearest intersection with ray with t > tMin.
void autoCrease(unsigned level, TParam maxAngleInRadians)
automatically assign crease levels to edges with discontinued normals
void autoSew()
automatically sews (unconnected) triangles by comparing geometrical vertices and normals
#define LASS_DLL
DLL interface: import or export symbols?
set of geometrical primitives
Definition aabb_2d.h:81
Result
meta information on the result you have from an operation like an intersection ...
Definition result.h:74
@ rOne
there's exactly one answer, 1 output argument contains the answer
Definition result.h:77
Library for Assembled Shared Sources.
Definition config.h:53