Library of Assembled Shared Sources
triangle_mesh_3d.inl
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#ifndef LASS_GUARDIAN_OF_INCLUSION_PRIM_SIMPLE_TRIANGLE_MESH_3D_INL
46#define LASS_GUARDIAN_OF_INCLUSION_PRIM_SIMPLE_TRIANGLE_MESH_3D_INL
47
48#include "prim_common.h"
49#include "triangle_mesh_3d.h"
52#include "point_3dh.h"
53#include "point_2dh.h"
54#include <algorithm>
55#include <cstddef>
56
57namespace lass
58{
59namespace prim
60{
61
62// --- public --------------------------------------------------------------------------------------
63
64template <typename T, template <typename, typename, typename> class BHV, typename SH>
65TriangleMesh3D<T, BHV, SH>::TriangleMesh3D(const SH& heuristics):
66 tree_(heuristics)
67{
68}
69
70
71
72template <typename T, template <typename, typename, typename> class BHV, typename SH>
73template
74<
75 typename VertexInputRange, typename IndexTriangleInputRange
76>
77TriangleMesh3D<T, BHV, SH>::TriangleMesh3D(
78 const VertexInputRange& vertices, const IndexTriangleInputRange& triangles, const SH& heuristics):
79 tree_(heuristics),
80 vertices_(vertices.begin(), vertices.end()),
81 normals_(),
82 uvs_()
83{
84 buildMesh(triangles);
85}
86
87
88
89template <typename T, template <typename, typename, typename> class BHV, typename SH>
90template
91<
92 typename VertexInputRange, typename NormalInputRange,
93 typename UvInputRange, typename IndexTriangleInputRange
94>
95TriangleMesh3D<T, BHV, SH>::TriangleMesh3D(
96 const VertexInputRange& vertices, const NormalInputRange& normals,
97 const UvInputRange& uvs, const IndexTriangleInputRange& triangles,
98 const SH& heuristics):
99 tree_(heuristics),
100 vertices_(vertices.begin(), vertices.end()),
101 normals_(normals.begin(), normals.end()),
102 uvs_(uvs.begin(), uvs.end())
103{
104 buildMesh(triangles.begin(), triangles.end());
105}
106
107
108
109template <typename T, template <typename, typename, typename> class BHV, typename SH>
110template <typename IndexTriangleInputRange>
111TriangleMesh3D<T, BHV, SH>::TriangleMesh3D(
112 TVertices&& vertices, const IndexTriangleInputRange& triangles, const SH& heuristics):
113 tree_(heuristics),
114 vertices_(std::move(vertices))
115{
116 buildMesh(triangles.begin(), triangles.end());
117}
118
119
120
121template <typename T, template <typename, typename, typename> class BHV, typename SH>
122template <typename IndexTriangleInputRange>
123TriangleMesh3D<T, BHV, SH>::TriangleMesh3D(
124 TVertices&& vertices, TNormals&& normals,TUvs&& uvs, const IndexTriangleInputRange& triangles, const SH& heuristics):
125 tree_(heuristics),
126 vertices_(std::move(vertices)),
127 normals_(std::move(normals)),
128 uvs_(std::move(uvs))
129{
130 buildMesh(triangles.begin(), triangles.end());
131}
132
133
134
135template <typename T, template <typename, typename, typename> class BHV, typename SH>
136TriangleMesh3D<T, BHV, SH>::TriangleMesh3D(const TriangleMesh3D& other):
137 tree_(static_cast<const SH&>(other.tree_)),
138 vertices_(other.vertices_),
139 normals_(other.normals_),
140 uvs_(other.uvs_)
141{
142 std::vector<IndexTriangle> triangles;
143 other.indexTriangles(std::back_inserter(triangles));
144 buildMesh(triangles.begin(), triangles.end());
145}
146
147
148
149template <typename T, template <typename, typename, typename> class BHV, typename SH>
150TriangleMesh3D<T, BHV, SH>::TriangleMesh3D(TriangleMesh3D&& other):
151 tree_(std::move(static_cast<SH&&>(other.tree_))),
152 triangles_(std::move(other.triangles_)),
153 vertices_(std::move(other.vertices_)),
154 normals_(std::move(other.normals_)),
155 uvs_(std::move(other.uvs_)),
156 numBoundaryEdges_(other.numBoundaryEdges_)
157{
158}
159
160
161
162template <typename T, template <typename, typename, typename> class BHV, typename SH>
163TriangleMesh3D<T, BHV, SH>& TriangleMesh3D<T, BHV, SH>::operator=(const TriangleMesh3D& other)
164{
165 TriangleMesh3D temp(other);
166 swap(temp);
167 return *this;
168}
169
170
171
172template <typename T, template <typename, typename, typename> class BHV, typename SH>
173TriangleMesh3D<T, BHV, SH>& TriangleMesh3D<T, BHV, SH>::operator=(TriangleMesh3D&& other)
174{
175 swap(other);
176 return *this;
177}
178
179
180
181template <typename T, template <typename, typename, typename> class BHV, typename SH>
182const typename TriangleMesh3D<T, BHV, SH>::TTriangles&
183TriangleMesh3D<T, BHV, SH>::triangles() const
184{
185 return triangles_;
186}
187
188
189
190template <typename T, template <typename, typename, typename> class BHV, typename SH>
191const typename TriangleMesh3D<T, BHV, SH>::TVertices&
192TriangleMesh3D<T, BHV, SH>::vertices() const
193{
194 return vertices_;
195}
196
197
198
199template <typename T, template <typename, typename, typename> class BHV, typename SH>
200const typename TriangleMesh3D<T, BHV, SH>::TNormals&
201TriangleMesh3D<T, BHV, SH>::normals() const
202{
203 return normals_;
204}
205
207
208template <typename T, template <typename, typename, typename> class BHV, typename SH>
209const typename TriangleMesh3D<T, BHV, SH>::TUvs&
210TriangleMesh3D<T, BHV, SH>::uvs() const
211{
212 return uvs_;
213}
215
216
217template <typename T, template <typename, typename, typename> class BHV, typename SH>
218template <typename OutputIterator>
219OutputIterator TriangleMesh3D<T, BHV, SH>::indexTriangles(OutputIterator triangles) const
220{
221 typename TTriangles::const_iterator triangle;
222 for (triangle = triangles_.begin(); triangle != triangles_.end(); ++triangle)
223 {
224 TIndexTriangle indexTriangle;
225 for (std::size_t k = 0; k < 3; ++k)
226 {
227 LASS_ASSERT(triangle->vertices[k]);
228 indexTriangle.vertices[k] = static_cast<size_t>(triangle->vertices[k] - &vertices_.front());
229 indexTriangle.normals[k] = triangle->normals[k] ? static_cast<size_t>(triangle->normals[k] - &normals_.front()) : IndexTriangle::null();
230 indexTriangle.uvs[k] = triangle->uvs[k] ? static_cast<size_t>(triangle->uvs[k] - &uvs_.front()) : IndexTriangle::null();
231 }
232 *triangles++ = indexTriangle;
233 }
234 return triangles;
235}
236
237
238
239template <typename T, template <typename, typename, typename> class BHV, typename SH>
240const typename TriangleMesh3D<T, BHV, SH>::TAabb
241TriangleMesh3D<T, BHV, SH>::aabb() const
242{
243 LASS_ASSERT(tree_.isEmpty() == triangles_.empty());
244 return tree_.aabb();
245}
246
247
248
249template <typename T, template <typename, typename, typename> class BHV, typename SH>
250const typename TriangleMesh3D<T, BHV, SH>::TValue
251TriangleMesh3D<T, BHV, SH>::area() const
252{
253 TValue result = 0;
254 typename TTriangles::const_iterator triangle;
255 for (triangle = triangles_.begin(); triangle != triangles_.end(); ++triangle)
256 {
257 result += triangle->area();
258 }
259 return result;
260}
261
262namespace impl
263{
264 template <typename HalfEdgeType>
265 typename HalfEdgeType::TVector computeWeightedNormal(const HalfEdgeType& edge)
266 {
267 typedef typename HalfEdgeType::TVector TVector;
268 const TVector a = edge.vector();
269 const TVector b = -edge.oPrev().vector();
270 const TVector n = cross(a, b);
271 if (n.isZero() || n.isNaN())
272 {
273 return TVector();
274 }
275 return n.normal() * num::acos(dot(a.normal(), b.normal()));
276 }
277}
278
279
280template <typename T, template <typename, typename, typename> class BHV, typename SH>
281void TriangleMesh3D<T, BHV, SH>::smoothNormals()
282{
283 const size_t numTriangles = triangles_.size();
284
285 for (size_t i = 0; i < numTriangles; ++i)
286 {
287 std::fill_n(triangles_[i].normals, 3, static_cast<TVector*>(0));
288 }
289 normals_.clear();
290 normals_.reserve(3 * triangles_.size()); // let's waste some memory, we must make sure it's never going to reallocate!
291
292 for (size_t i = 0; i < numTriangles; ++i)
293 {
294 Triangle& triangle = triangles_[i];
295 for (size_t k = 0; k < 3; ++k)
296 {
297 HalfEdge edge(&triangle, k);
298 if (edge.normal())
299 {
300 continue;
301 }
302
303 // start a fresh normal.
304 LASS_ENFORCE(normals_.size() < normals_.capacity());
305 normals_.push_back(impl::computeWeightedNormal(edge));
306 TVector& normal = normals_.back();
307 edge.setNormal(&normal);
308
309 // rotate left, until you hit a crease, an edge with a normal already.
310 // No need to check if you hit yourself, as you have a normal already.
311 for (HalfEdge left = edge.rNext(); left && !left.normal() && !left.creaseLevel(); left = left.rNext())
312 {
313 normal += impl::computeWeightedNormal(left);
314 left.setNormal(&normal);
315 }
316
317 // rotate right, until ...
318 for (HalfEdge right = edge.rPrev(); right && !right.normal() && !right.oPrev().creaseLevel(); right = right.rPrev())
319 {
320 normal += impl::computeWeightedNormal(right);
321 right.setNormal(&normal);
322 }
323
324 normal.normalize();
325 }
326 }
327}
328
329
330
331/** remove all normals, so that faces become flat
332 */
333template <typename T, template <typename, typename, typename> class BHV, typename SH>
335{
336 normals_.clear();
337 for (typename TTriangles::iterator triangle = triangles_.begin();
338 triangle != triangles_.end(); ++triangle)
339 {
340 std::fill(triangle->normals, triangle->normals + 3, static_cast<TVector*>(0));
341 }
342}
343
344
345template <typename T, template <typename, typename, typename> class BHV, typename SH>
346void TriangleMesh3D<T, BHV, SH>::loopSubdivision(unsigned level)
347{
348 if (triangles_.empty())
349 {
350 return;
351 }
352
353 while (level-- > 0)
354 {
355 // step I: subdivide triangles with simple interpolation
356 //
357 subdivide();
358
359 // copying should "reduce" the extra reserve we don't need
360 TVertices newVertices = vertices_;
361 TNormals newNormals = normals_;
362 TUvs newUvs = uvs_;
363 const TPoint* const firstVertex = &vertices_[0];
364 const TVector* const firstNormal = normals_.empty() ? 0 : &normals_[0];
365 const TUv* const firstUv = uvs_.empty() ? 0 : &uvs_[0];
366
367 // step II: smooth mesh
368 //
369 //*
370 TVertexTriangles vertexTriangles;
371 findVertexTriangles(vertexTriangles);
372 TVertexRing ring;
373 TVertexRing creases;
374 TUvRing uvRing;
375 const size_t numVertices = vertices_.size();
376 for (size_t i = 0; i < numVertices; ++i)
377 {
378 const Triangle* const vertexTriangle = vertexTriangles[i];
379 if (!vertexTriangle)
380 {
381 continue;
382 }
383 const TPoint& vertex = vertices_[i];
384 findVertexRing(vertex, vertexTriangle, ring, creases, uvRing);
385 const size_t nRing = ring.size();
386 const size_t nCreases = creases.size();
387 LASS_ASSERT(nRing >= 2);
388 if (nCreases == 2)
389 {
390 // crease or boundary (boundary edges count as creases)
391 newVertices[i] = TPoint(.75f * vertex.position() + .125f * (creases[0]->position() + creases[1]->position()));
392 }
393 else if (nRing > 2 && nCreases == 0)
394 {
395 // interior vertex
396 const TValue alpha = num::inv(static_cast<TValue>(nRing));
397 const TValue beta = nRing == 6
398 ? .125f
399 : 2.f * (.625f - num::sqr(.375f + .25f * num::cos(2.f * TNumTraits::pi * alpha))) * alpha;
400 TVector newVertex = (1.f - static_cast<TValue>(nRing) * beta) * vertex.position();
401 for (size_t j = 0; j < nRing; ++j)
402 {
403 newVertex += beta * ring[j]->position();
404 }
405 newVertices[i] = TPoint(newVertex);
406 if (!uvRing.empty())
407 {
408 LASS_ASSERT(uvRing.size() == nRing);
409 const size_t k = vertexTriangle->side(&vertex);
410 LASS_ASSERT(k < 3 && vertexTriangle->uvs[k]);
411 const TUv& uv = *vertexTriangle->uvs[k];
412 typename TUv::TVector newUv = (1.f - static_cast<TValue>(nRing) * beta) * uv.position();
413 for (size_t j = 0; j < nRing; ++j)
414 {
415 newUv += beta * uvRing[j]->position();
416 }
417 newUvs[static_cast<size_t>(&uv - firstUv)] = TUv(newUv);
418 }
419 }
420 }
421 /**/
422
423 // step III: adjust pointers and decrease crease levels
424 //
425 for (typename TTriangles::iterator triangle = triangles_.begin();
426 triangle != triangles_.end(); ++triangle)
427 {
428 for (size_t k = 0; k < 3; ++k)
429 {
430 triangle->vertices[k] = &newVertices[static_cast<size_t>(triangle->vertices[k] - firstVertex)];
431 triangle->normals[k] = triangle->normals[k] ? &newNormals[static_cast<size_t>(triangle->normals[k] - firstNormal)] : 0;
432 triangle->uvs[k] = triangle->uvs[k] ? &newUvs[static_cast<size_t>(triangle->uvs[k] - firstUv)] : 0;
433 triangle->creaseLevel[k] = triangle->creaseLevel[k] > 0 ? triangle->creaseLevel[k] - 1 : 0;
434 }
435 }
436 vertices_.swap(newVertices);
437 normals_.swap(newNormals);
438 uvs_.swap(newUvs);
439 }
440 tree_.reset(triangles_.begin(), triangles_.end());
441}
442
443
444/** global subdivision with function to resnap new vertices.
445 *
446 * void snapToLimitSurface(TPoint& vert, TVector* n1, TVector* n2, TUv* uv1, TUv* uv2, const size_t* attr1, const size_t* attr2)
447 */
448template <typename T, template <typename, typename, typename> class BHV, typename SH>
449template <typename Func>
450void TriangleMesh3D<T, BHV, SH>::subdivisionWithLimitSurface(unsigned level, Func snapToLimitSurface)
451{
452 if (triangles_.empty())
453 {
454 return;
455 }
456
457 while (level-- > 0)
458 {
459 // step I: subdivide triangles with simple interpolation
460 //
461 subdivide();
462
463 // step II: gather the pairs of odd triangles sharing an odd vertex.
464 //
465 TOddVertexWings oddVertexWings;
466 const size_t numTriangles = triangles_.size();
467 for (size_t i = 3; i < numTriangles; i += 4)
468 {
469 Triangle& oddTriangle = triangles_[i];
470 for (size_t k = 0; k < 3; ++k)
471 {
472 const TPoint* oddVertex = oddTriangle.vertices[k];
473 typename TOddVertexWings::iterator w = oddVertexWings.find(oddVertex);
474 if (w == oddVertexWings.end())
475 {
476 oddVertexWings[oddVertex] = std::make_pair(&oddTriangle, (Triangle*) 0);
477 }
478 else
479 {
480 TWing& wing = w->second;
481 LASS_ASSERT(wing.first && !wing.second);
482 wing.second = &oddTriangle;
483 }
484 }
485 }
486
487 // loop over all odd vertices, and snap them to the limit surface.
488 // also, allow normals and uvs to be adjusted.
489 // attributes cannot be adjusted, as they are triangles properties. They are not interpolated either, just inherited from the original triangle.
490 //
491 for (typename TOddVertexWings::const_iterator i = oddVertexWings.begin(), end = oddVertexWings.end(); i != end; ++i)
492 {
493 const TPoint* vertex = i->first;
494 const Triangle* wing1 = i->second.first;
495 const Triangle* wing2 = i->second.second;
496 LASS_ASSERT(wing1);
497 const size_t k1 = wing1->side(vertex);
498 const size_t k2 = wing2 ? wing2->side(vertex) : IndexTriangle::null();
499
500 // What's up with all the const_casts, doc?
501 // Well, you see, Triangle has const pointers to its vertices, normals and other goodies.
502 // That's no good if we want to adjust these values, is it? We can get around it by computing indices of said vertex, normal or uv
503 // in vertices_, normals_ or uvs_ respectively, and then adjust the value there, as these tables are non-const,
504 // but that's just a convoluted hidden const_cast. Better to be explicit about it. And it's faster too =)
505 // Maybe we should devise a Triangle without all the const things. But not today...
506 //
507 snapToLimitSurface(
508 *const_cast<TPoint*>(vertex),
509 const_cast<TVector*>(wing1->normals[k1]), const_cast<TVector*>(wing2 ? wing2->normals[k2] : 0),
510 const_cast<TUv*>(wing1->uvs[k1]), const_cast<TUv*>(wing2 ? wing2->uvs[k2] : 0),
511 &(wing1->attribute), wing2 ? &(wing2->attribute) : 0);
512 }
513 }
514}
515
516
517template <typename T, template <typename, typename, typename> class BHV, typename SH>
518template <typename Func>
519void TriangleMesh3D<T, BHV, SH>::subdivisionWithLimitSurface(unsigned level, Func snapToLimitSurface, TTriangleIterators& selected)
520{
521 if (triangles_.empty())
522 {
523 return;
524 }
525
526 TOddVertexWings oddVertexWings;
527 while (level-- > 0)
528 {
529 // step I: subdivide triangles with simple interpolation
530 //
531 subdivide(selected, oddVertexWings);
532
533 // loop over all odd vertices, and snap them to the limit surface.
534 // also, allow normals and uvs to be adjusted.
535 // attributes cannot be adjusted, as they are triangles properties. They are not interpolated either, just inherited from the original triangle.
536 //
537 for (typename TOddVertexWings::const_iterator i = oddVertexWings.begin(), end = oddVertexWings.end(); i != end; ++i)
538 {
539 const TPoint* vertex = i->first;
540 const Triangle* wing1 = i->second.first;
541 const Triangle* wing2 = i->second.second;
542 LASS_ASSERT(wing1);
543 const size_t k1 = wing1->side(vertex);
544 const size_t k2 = wing2 ? wing2->side(vertex) : IndexTriangle::null();
545
546 // What's up with all the const_casts, doc?
547 // Well, you see, Triangle has const pointers to its vertices, normals and other goodies.
548 // That's no good if we want to adjust these values, is it? We can get around it by computing indices of said vertex, normal or uv
549 // in vertices_, normals_ or uvs_ respectively, and then adjust the value there, as these tables are non-const,
550 // but that's just a convoluted hidden const_cast. Better to be explicit about it. And it's faster too =)
551 // Maybe we should devise a Triangle without all the const things. But not today...
552 //
553 snapToLimitSurface(
554 *const_cast<TPoint*>(vertex),
555 const_cast<TVector*>(wing1->normals[k1]), const_cast<TVector*>(wing2 ? wing2->normals[k2] : 0),
556 const_cast<TUv*>(wing1->uvs[k1]), const_cast<TUv*>(wing2 ? wing2->uvs[k2] : 0),
557 &(wing1->attribute), wing2 ? &(wing2->attribute) : 0);
558 }
559 }
560}
561
562
563/** automatically sews (unconnected) triangles by comparing geometrical vertices and normals
564 */
565template <typename T, template <typename, typename, typename> class BHV, typename SH>
567{
568 typedef std::vector<PositionalEdge> TEdges;
569
570 // I. make list of all boundary edges
571 //
572 const size_t numTriangles = triangles_.size();
573 TEdges edges;
574 edges.reserve(numBoundaryEdges_);
575 for (size_t i = 0; i < numTriangles; ++i)
576 {
577 Triangle& triangle = triangles_[i];
578 for (size_t k1 = 2, k2 = 0; k2 < 3; k1 = k2++)
579 {
580 if (triangle.others[k1] == 0)
581 {
582 edges.push_back(PositionalEdge(&triangle, k1, k2));
583 }
584 }
585 }
586 LASS_ASSERT(edges.size() == numBoundaryEdges_);
587 std::sort(edges.begin(), edges.end());
588
589 // II. go over all boundary edges, and search one to sew with ...
590 //
591 for (size_t i = 0; i < numTriangles; ++i)
592 {
593 Triangle& triangle = triangles_[i];
594 for (size_t k1 = 2, k2 = 0; k2 < 3; k1 = k2++)
595 {
596 if (triangle.others[k1] == 0)
597 {
598 const PositionalEdge bait(&triangle, k2, k1); // reversed edge
599 const typename TEdges::const_iterator haul = std::lower_bound(edges.begin(), edges.end(), bait);
600 if (haul != edges.end() && !(bait < *haul) && haul->triangle->others[haul->k1] == 0)
601 {
602 triangle.others[k1] = haul->triangle;
603 haul->triangle->others[haul->k1] = &triangle;
604 LASS_ASSERT(numBoundaryEdges_ >= 2);
605 numBoundaryEdges_ -= 2;
606 for (size_t s = 1; s <= 2; ++s)
607 {
608 // turn right/left, and replace all otherV by v
609 Triangle* other = haul->triangle;
610 size_t k = s == 1 ? haul->k2 : haul->k1;
611 const TPoint* const v =
612 triangle.vertices[s == 1 ? k1 : k2];
613 const TPoint* const otherV = other->vertices[k];
614 LASS_ASSERT(*v == *otherV);
615 if (v != otherV)
616 {
617 do
618 {
619 LASS_ASSERT(other->vertices[k] == otherV);
620 other->vertices[k] = v;
621 other = other->others[
622 (k + (s == 1 ? 0 : 2)) % 3];
623 k = other ? other->side(otherV) : 3;
624 }
625 while (other && k < 3);
626 }
627 }
628 }
629 }
630 }
631 }
632}
633
634
635namespace impl
636{
637 template <typename TriangleType>
638 typename TriangleType::TVector computeFaceNormal(const TriangleType& triangle)
639 {
640 typedef typename TriangleType::TVector TVector;
641 const TVector a = *triangle.vertices[1] - *triangle.vertices[0];
642 const TVector b = *triangle.vertices[2] - *triangle.vertices[0];
643 const TVector n = cross(a, b);
644 if (n.isZero() || n.isNaN())
645 {
646 return TVector();
647 }
648 return n.normal();
649 }
650}
651
652/** automatically assign crease levels to edges with discontinued normals
653 */
654template <typename T, template <typename, typename, typename> class BHV, typename SH>
655void TriangleMesh3D<T, BHV, SH>::autoCrease(unsigned level, TParam maxAngleInRadians)
656{
657 const TValue minDot = num::cos(maxAngleInRadians);
658 const size_t numTriangles = triangles_.size();
659 for (size_t i = 0; i < numTriangles; ++i)
660 {
661 Triangle& triangle = triangles_[i];
662 const TVector faceNormal = impl::computeFaceNormal(triangle);
663 for (size_t k1 = 2, k2 = 0; k2 < 3; k1 = k2++)
664 {
665 triangle.creaseLevel[k1] = level; // it's a crease by default, smooth it under conditions.
666
667 Triangle* other = triangle.others[k1];
668 if (!other)
669 {
670 continue;
671 }
672 const size_t otherK1 = other->side(triangle.vertices[k1]);
673 const size_t otherK2 = (otherK1 + 2) % 3;
674 LASS_ASSERT(otherK1 < 3 && otherK2 == other->side(triangle.vertices[k2]));
675 const TVector otherNormal = impl::computeFaceNormal(*other);
676
677 const TVector a1 = (triangle.normals[k1] ? *triangle.normals[k1] : faceNormal).normal();
678 const TVector a2 = (triangle.normals[k2] ? *triangle.normals[k2] : faceNormal).normal();
679 const TVector b1 = (other->normals[otherK1] ? *other->normals[otherK1] : otherNormal).normal();
680 const TVector b2 = (other->normals[otherK2] ? *other->normals[otherK2] : otherNormal).normal();
681
682 if (maxAngleInRadians == 0)
683 {
684 if (a1 == b1 && a2 == b2)
685 {
686 triangle.creaseLevel[k1] = 0;
687 }
688 }
689 else
690 {
691 if (dot(a1, b1) >= minDot && dot(a2, b2) >= minDot)
692 {
693 triangle.creaseLevel[k1] = 0;
694 }
695 }
696 }
697 }
698}
699
700
701
702/** Find nearest intersection with ray with t > tMin.
703 *
704 * Of all triangles that intersect with the ray, return the one that is nearest to the
705 * ray origin while still being further away than tMin. The distance along the ray to
706 * the intersection point is returned in t. If an intersection was found, the context
707 * (if provided) is filled with intersection information.
708 *
709 * @param[in] ray the ray to intersect with
710 * @param[out] triangle the triangle that was hit
711 * @param[out] t the distance along the ray to the intersection point, with t > tMin
712 * @param[in] tMin the minimum distance along the ray to consider, so that t > tMin
713 * @param[out] context the context to be filled with intersection information (optional)
714 *
715 * @return rOne if an intersection was found, rNone otherwise
716 */
717template <typename T, template <typename, typename, typename> class BHV, typename SH>
719 const TRay& ray, TTriangleIterator& triangle,
720 TReference t, TParam tMin, IntersectionContext* context) const
721{
722 return intersectFilter(ray, triangle, t, tMin, nullptr, context);
723}
724
725
726
727/** Find nearest intersection with ray that passes the filter, and with t > tMin.
728 *
729 * Similar to intersect, but the filter function is evaluated for each candidate
730 * intersection point. If the filter returns true, the intersection is accepted.
731 * If the filter returns false, the next candidate is evaluated. This allows for
732 * implementing an alpha mask on the triangle mesh, for example.
733 *
734 * @param[in] ray the ray to intersect with
735 * @param[out] triangle the triangle that was hit
736 * @param[out] t the distance along the ray to the intersection point, with t > tMin
737 * @param[in] tMin the minimum distance along the ray to consider, so that t > tMin
738 * @param[in] filter the filter to apply to the intersection points
739 * @param[out] context the context to be filled with intersection information (optional)
740 *
741 * @return rOne if an intersection was found, rNone otherwise
742 */
743template <typename T, template <typename, typename, typename> class BHV, typename SH>
745 const TRay& ray, TTriangleIterator& triangle,
746 TReference t, TParam tMin, TFilter filter, IntersectionContext* context) const
747{
748 LASS_ASSERT(tree_.isEmpty() == triangles_.empty());
749
750 IntersectInfo info(ray, filter);
751 const TTriangleIterator candidate = tree_.intersect(ray, t, tMin, &info);
752 if (candidate == triangles_.end())
753 {
754 return rNone;
755 }
756 triangle = candidate;
757
758 if (context)
759 {
760 TValue temp;
761 [[maybe_unused]] const Result r = triangle->intersect(info.woop, temp, tMin, context);
762 LASS_ASSERT(r == rOne && t == temp);
763 }
764
765 return rOne;
766}
767
768
769
770/** Checks if the ray has any intersection with the mesh, with t > tMin and t < tMax.
771 *
772 * @param[in] ray the ray to intersect with
773 * @param[in] tMin the minimum distance along the ray to consider, so that t > tMin
774 * @param[in] tMax the maximum distance along the ray to consider, so that t < tMax
775 *
776 * @return true if an intersection was found, false otherwise
777 */
778template <typename T, template <typename, typename, typename> class BHV, typename SH>
779bool TriangleMesh3D<T, BHV, SH>::intersects(const TRay& ray, TParam tMin, TParam tMax) const
780{
781 return intersectsFilter(ray, tMin, tMax, nullptr);
782}
783
784
785
786/** Checks if the ray has any intersection that passes the filter, and with t > tMin and t < tMax.
787 *
788 * Similar to intersects, but the filter function is evaluated for each candidate
789 * intersection point. Only if it returns true, it's considered as a valid
790 * intersection. This allows for implementing an alpha mask on the triangle mesh,
791 * for example.
792 *
793 * @param[in] ray the ray to intersect with
794 * @param[in] tMin the minimum distance along the ray to consider, so that t > tMin
795 * @param[in] tMax the maximum distance along the ray to consider, so that t < tMax
796 * @param[in] filter the filter to apply to the intersection points
797 *
798 * @return true if an intersection was found, false otherwise
799 */
800template <typename T, template <typename, typename, typename> class BHV, typename SH>
801bool TriangleMesh3D<T, BHV, SH>::intersectsFilter(const TRay& ray, TParam tMin, TParam tMax, TFilter filter) const
802{
803 LASS_ASSERT(tree_.isEmpty() == triangles_.empty());
804 IntersectInfo info(ray, filter);
805 return tree_.intersects(ray, tMin, tMax, &info);
806}
807
808
809
810template <typename T, template <typename, typename, typename> class BHV, typename SH>
811void TriangleMesh3D<T, BHV, SH>::swap(TSelf& other)
812{
813 tree_.swap(other.tree_);
814 triangles_.swap(other.triangles_);
815 vertices_.swap(other.vertices_);
816 normals_.swap(other.normals_);
817 uvs_.swap(other.uvs_);
818 std::swap(numBoundaryEdges_, other.numBoundaryEdges_);
819}
820
821
822
823// --- Triangle ------------------------------------------------------------------------------------
824
825template <typename T, template <typename, typename, typename> class BHV, typename SH>
826Result TriangleMesh3D<T, BHV, SH>::Triangle::intersect(const TRay& ray,
827 TReference t, TParam tMin, IntersectionContext* context) const
828{
829 const TIntersectTriangleWoop intersectWoop(ray.support(), ray.direction());
830 return intersect(intersectWoop, t, tMin, context);
831}
832
833
834
835template <typename T, template <typename, typename, typename> class BHV, typename SH>
836Result TriangleMesh3D<T, BHV, SH>::Triangle::intersect(
837 const TIntersectTriangleWoop& intersectWoop,
838 TReference t, TParam tMin, IntersectionContext* context) const
839{
840 LASS_ASSERT(vertices[0] && vertices[1] && vertices[2]);
841 const TPoint point0 = *vertices[0];
842 const TPoint point1 = *vertices[1];
843 const TPoint point2 = *vertices[2];
844
845 TValue b[3];
846 const Result hit = intersectWoop(point0, point1, point2, b, t, tMin);
847 if (hit != rOne)
848 {
849 return hit;
850 }
851
852 if (context)
853 {
854 LASS_ASSERT(b[0] >= 0 && b[1] >= 0 && b[2] >= 0 && num::abs(b[0] + b[1] + b[2] - 1) < TNumTraits::gamma(10));
855 context->point = TPoint(b[0] * point0.position() + b[1] * point1.position() + b[2] * point2.position());
856
857 const TVector dPoint_dR = *vertices[1] - point0;
858 const TVector dPoint_dS = *vertices[2] - point0;
859 const TValue r = b[1];
860 const TValue s = b[2];
861 TUv dRs_dU(1, 0);
862 TUv dRs_dV(0, 1);
863 if (uvs[0])
864 {
865 LASS_ASSERT(uvs[1] && uvs[2]);
866 const TUv uv0 = *uvs[0];
867 const TUv uv1 = *uvs[1];
868 const TUv uv2 = *uvs[2];
869 context->uv = TUv(b[0] * uv0.position() + b[1] * uv1.position() + b[2] * uv2.position());
870
871 // Invert dUv_dR and dUv_dS by solving the following system of equations:
872 // [ du/dr du/ds ] [ dr/du dr/dv ] = [ 1 0 ]
873 // [ dv/dr dv/ds ] [ ds/du ds/dv ] [ 0 1 ]
874 //
875 // matrix is row major, but solution is column major
876 //
877 const typename TUv::TVector dUv_dR = uv1 - uv0;
878 const typename TUv::TVector dUv_dS = uv2 - uv0;
879 const TValue matrix[4] = { dUv_dR.x, dUv_dS.x, dUv_dR.y, dUv_dS.y };
880 TValue solution[4] = { 1, 0, 0, 1 };
881 num::impl::cramer2<TValue>(matrix, solution, solution + 4);
882 dRs_dU = TUv(solution[0], solution[1]);
883 dRs_dV = TUv(solution[2], solution[3]);
884
885 context->dPoint_dU = dPoint_dR * dRs_dU.x + dPoint_dS * dRs_dU.y;
886 context->dPoint_dV = dPoint_dR * dRs_dV.x + dPoint_dS * dRs_dV.y;
887 }
888 else
889 {
890 context->uv = TUv(r, s);
891 context->dPoint_dU = dPoint_dR;
892 context->dPoint_dV = dPoint_dS;
893 }
894
895 context->geometricNormal = cross(dPoint_dR, dPoint_dS).normal();
896 if (normals[0])
897 {
898 LASS_ASSERT(normals[1] && normals[2]);
899 const TVector normal0 = *normals[0];
900 const TVector normal1 = *normals[1];
901 const TVector normal2 = *normals[2];
902 context->normal = (b[0] * normal0 + b[1] * normal1 + b[2] * normal2).normal();
903 const TVector dNormal_dR = normal1 - normal0;
904 const TVector dNormal_dS = normal2 - normal0;
905 context->dNormal_dU = dNormal_dR * dRs_dU.x + dNormal_dS * dRs_dU.y;
906 context->dNormal_dV = dNormal_dR * dRs_dV.x + dNormal_dS * dRs_dV.y;
907 }
908 else
909 {
910 context->normal = context->geometricNormal;
911 context->dNormal_dU = TVector();
912 context->dNormal_dV = TVector();
913 }
914 }
915 return rOne;
916}
917
918
919
920template <typename T, template <typename, typename, typename> class BHV, typename SH> inline
921size_t TriangleMesh3D<T, BHV, SH>::Triangle::side(const TPoint* vertex) const
922{
923 return vertices[0] == vertex ? 0 : (vertices[1] == vertex ? 1 : (vertices[2] == vertex ? 2 : size_t(-1)));
924}
925
926
927
928template <typename T, template <typename, typename, typename> class BHV, typename SH> inline
929typename TriangleMesh3D<T, BHV, SH>::TValue TriangleMesh3D<T, BHV, SH>::Triangle::area() const
930{
931 const TVector a = *vertices[1] - *vertices[0];
932 const TVector b = *vertices[2] - *vertices[0];
933 const TVector n = cross(a, b);
934 return n.norm() / 2;
935}
936
937
938
939template <typename T, template <typename, typename, typename> class BHV, typename SH> inline
940typename TriangleMesh3D<T, BHV, SH>::TVector TriangleMesh3D<T, BHV, SH>::Triangle::geometricNormal() const
941{
942 const TVector a = *vertices[1] - *vertices[0];
943 const TVector b = *vertices[2] - *vertices[0];
944 const TVector n = cross(a, b);
945 return n.normal();
946}
947
948
949
950// --- private -------------------------------------------------------------------------------------
951
952template <typename T, template <typename, typename, typename> class BHV, typename SH>
953template <typename IndexTriangleInputIterator>
954void TriangleMesh3D<T, BHV, SH>::buildMesh(IndexTriangleInputIterator first, IndexTriangleInputIterator last)
955{
956 const size_t sizeVertices = vertices_.size();
957 const size_t sizeNormals = normals_.size();
958 const size_t sizeUvs = uvs_.size();
959
960 for (; first != last; ++first)
961 {
962 TTriangle triangle;
963 size_t numNormals = 0;
964 size_t numUvs = 0;
965 for (std::size_t k = 0; k < 3; ++k)
966 {
967 triangle.others[k] = 0;
968 triangle.creaseLevel[k] = 0;
969
970 const size_t vertex = first->vertices[k];
971 triangle.vertices[k] = &vertices_[LASS_ENFORCE_INDEX(vertex, sizeVertices)];
972
973 const size_t normal = first->normals[k];
974 if (normal != IndexTriangle::null())
975 {
976 triangle.normals[k] = &normals_[LASS_ENFORCE_INDEX(normal, sizeNormals)];
977 ++numNormals;
978 }
979 else
980 {
981 triangle.normals[k] = 0;
982 }
983
984 const size_t uv = first->uvs[k];
985 if (uv != IndexTriangle::null())
986 {
987 triangle.uvs[k] = &uvs_[LASS_ENFORCE_INDEX(uv, sizeUvs)];
988 ++numUvs;
989 }
990 else
991 {
992 triangle.uvs[k] = 0;
993 }
994 }
995
996 if (!(numNormals == 0 || numNormals == 3))
997 {
998 LASS_THROW("Each triangle must have either zero or three normals vectors");
999 }
1000 if (!(numUvs == 0 || numUvs == 3))
1001 {
1002 LASS_THROW("Each triangle must have either zero or three uv coordinates");
1003 }
1004
1005 triangles_.push_back(triangle);
1006 }
1007
1008 connectTriangles();
1009 tree_.reset(triangles_.begin(), triangles_.end());
1010}
1011
1012
1013
1014template <typename T, template <typename, typename, typename> class BHV, typename SH>
1015void TriangleMesh3D<T, BHV, SH>::findVertexTriangles(TVertexTriangles& vertexTriangles) const
1016{
1017 TVertexTriangles result(vertices_.size(), 0);
1018 const TPoint* const firstVertex = &vertices_[0];
1019 for (typename TTriangles::const_iterator i = triangles_.begin(); i != triangles_.end(); ++i)
1020 {
1021 const Triangle& triangle = *i;
1022 for (size_t k = 0; k < 3; ++k)
1023 {
1024 const size_t j = static_cast<size_t>(triangle.vertices[k] - firstVertex);
1025 LASS_ASSERT(j < result.size());
1026 result[j] = &triangle;
1027 }
1028 }
1029 vertexTriangles.swap(result);
1030}
1031
1032
1033
1034template <typename T, template <typename, typename, typename> class BHV, typename SH>
1035void TriangleMesh3D<T, BHV, SH>::connectTriangles()
1036{
1037 typedef std::vector<LogicalEdge> TEdges;
1038
1039 numBoundaryEdges_ = 0;
1040 const size_t numTriangles = triangles_.size();
1041 if (numTriangles == 0)
1042 {
1043 return;
1044 }
1045
1046 // step 1: build list of edges and sort.
1047 //
1048 TEdges edges;
1049 edges.reserve(3 * numTriangles);
1050 for (size_t i = 0; i < numTriangles; ++i)
1051 {
1052 Triangle& triangle = triangles_[i];
1053 for (std::size_t k1 = 2, k2 = 0; k2 < 3; k1 = k2++)
1054 {
1055 edges.push_back(LogicalEdge(
1056 &triangle, triangle.vertices[k1], triangle.vertices[k2]));
1057 }
1058 }
1059 std::sort(edges.begin(), edges.end());
1060
1061 // step 2: build topological information of triangles
1062 //
1063 for (size_t i = 0; i < numTriangles; ++i)
1064 {
1065 Triangle& triangle = triangles_[i];
1066 for (std::size_t k1 = 2, k2 = 0; k2 < 3; k1 = k2++)
1067 {
1068 const LogicalEdge bait(0, triangle.vertices[k2], triangle.vertices[k1]); // reversed edge
1069 const typename TEdges::const_iterator haul = std::lower_bound(edges.begin(), edges.end(), bait);
1070 if (haul != edges.end() && *haul == bait)
1071 {
1072 if (stde::next(haul) != edges.end() && *stde::next(haul) == bait)
1073 {
1074 std::ostringstream buffer;
1075 buffer << "multiple half edges detected from " << *bait.tail << " to " << *bait.head << ". Triangles:\n";
1076 const typename TEdges::const_iterator last = std::upper_bound(edges.begin(), edges.end(), bait);
1077 for (typename TEdges::const_iterator e = haul; e != last; ++e)
1078 {
1079 const Triangle& t = *e->triangle;
1080 buffer << *t.vertices[0] << ", " << *t.vertices[1] << ", " << *t.vertices[2] << "\n";
1081 }
1082 LASS_THROW(buffer.str());
1083 }
1084 triangle.others[k1] = haul->triangle;
1085 }
1086 else
1087 {
1088 triangle.others[k1] = 0;
1089 ++numBoundaryEdges_;
1090 }
1091 }
1092 }
1093}
1094
1095
1096
1097template <typename T, template <typename, typename, typename> class BHV, typename SH>
1098void TriangleMesh3D<T, BHV, SH>::findVertexRing(
1099 const TPoint& vertex, const Triangle* vertexTriangle, TVertexRing& ring,
1100 TVertexRing& creases, TUvRing& uvs) const
1101{
1102 ring.resize(0); // normaly, this should not shrink memory (*)
1103 creases.resize(0);
1104 uvs.resize(0);
1105
1106 bool hasUvRing = true;
1107 const TUv* vertexUv = 0;
1108 const Triangle* triangle = vertexTriangle;
1109 do
1110 {
1111 const size_t k = triangle->side(&vertex);
1112 LASS_ASSERT(k < 3);
1113 const size_t kCcw = (k + 2) % 3;
1114 const TPoint* neighbour = triangle->vertices[kCcw];
1115 const Triangle* const other = triangle->others[kCcw];
1116 if (triangle->creaseLevel[kCcw] > 0 || !other)
1117 {
1118 //LASS_ASSERT(triangle->others[kCcw]);
1119 creases.push_back(neighbour);
1120 }
1121
1122 if (!vertexUv)
1123 {
1124 vertexUv = triangle->uvs[k];
1125 }
1126 hasUvRing &= vertexUv && vertexUv == triangle->uvs[k];
1127 if (hasUvRing)
1128 {
1129 LASS_ASSERT(triangle->uvs[kCcw]);
1130 uvs.push_back(triangle->uvs[kCcw]);
1131 }
1132
1133 if (!other)
1134 {
1135 // we've hit a boundary edge, turn back to other "end".
1136 // ring will only consist of that one + this neighbour
1137 //
1138 const Triangle* triangle2 = vertexTriangle;
1139 const TPoint* neighbour2 = 0;
1140 while (triangle2)
1141 {
1142 const size_t k2 = triangle2->side(&vertex);
1143 LASS_ASSERT(k2 < 3);
1144 const size_t k2Cw = (k2 + 1) % 3;
1145 neighbour2 = triangle2->vertices[k2Cw];
1146 const Triangle* other2 = triangle2->others[k2];
1147 if (triangle2->creaseLevel[k2Cw] > 0 || !other2)
1148 {
1149 //LASS_ASSERT(triangle2->others[k2Cw]);
1150 creases.push_back(neighbour2);
1151 }
1152 triangle2 = other2;
1153 }
1154 ring.resize(1, neighbour2);
1155 hasUvRing = false;
1156 }
1157 ring.push_back(neighbour);
1158 triangle = other;
1159 }
1160 while (triangle && triangle != vertexTriangle);
1161
1162 if (!hasUvRing)
1163 {
1164 uvs.resize(0);
1165 }
1166 // (*) so says the standard, as as we all know, _every_ compiler follows the standard, don't they?
1167}
1168
1169
1170
1171/** subdivide every triangle in 4 new ones by splitting the edges
1172 * @warning tree_ will be reset and must be recreated manually after calling this function!
1173 */
1174template <typename T, template <typename, typename, typename> class BHV, typename SH>
1175void TriangleMesh3D<T, BHV, SH>::subdivide()
1176{
1177 if (triangles_.empty())
1178 {
1179 return;
1180 }
1181
1182 const size_t numTriangles = triangles_.size();
1183 const size_t numVertices = vertices_.size();
1184 const size_t numNormals = normals_.size();
1185 const size_t numUvs = uvs_.size();
1186 LASS_ASSERT((3 * numTriangles + numBoundaryEdges_) % 2 == 0);
1187 const size_t numOddVertices = (3 * numTriangles + numBoundaryEdges_) / 2;
1188
1189 // count the number of normals and uvs to be added.
1190 // odd normals/uvs may be shared and counted double. to compensate, count them all as double, but shared ones only half so.
1191 size_t numOddNormals = 0;
1192 size_t numOddUvs = 0;
1193 if (numNormals || numUvs)
1194 {
1195 for (size_t i = 0; i < numTriangles; ++i)
1196 {
1197 const Triangle& triangle = triangles_[i];
1198 for (size_t k0 = 2, k1 = 0; k1 < 3; k0 = k1++)
1199 {
1200 LASS_ASSERT((!triangle.normals[k0]) == (!triangle.normals[k1]));
1201 LASS_ASSERT((!triangle.uvs[k0]) == (!triangle.uvs[k1]));
1202 if (const Triangle* const other = triangle.others[k0])
1203 {
1204 const size_t h0 = other->side(triangle.vertices[k1]);
1205 const size_t h1 = other->side(triangle.vertices[k0]);
1206 LASS_ASSERT(h0 < 3 && h1 == (h0 + 1) % 3);
1207 if (triangle.normals[k0])
1208 {
1209 numOddNormals += other->normals[h0] == triangle.normals[k0] && other->normals[h1] == triangle.normals[k1] ? 1 : 2; // if shared, count as "half double"
1210 }
1211 if (triangle.uvs[k0])
1212 {
1213 numOddUvs += other->uvs[h0] == triangle.uvs[k0] && other->uvs[h1] == triangle.uvs[k1] ? 1 : 2; // if shared, count as "half double"
1214 }
1215 }
1216 else
1217 {
1218 numOddNormals += triangle.normals[k0] ? 2 : 0;
1219 numOddUvs += triangle.uvs[k0] ? 2 : 0;
1220 }
1221 }
1222 }
1223 LASS_ASSERT((numOddNormals % 2) == 0 && (numOddUvs % 2) == 0);
1224 numOddNormals /= 2;
1225 numOddUvs /= 2;
1226 }
1227
1228
1229 TTriangles newTriangles(4 * numTriangles);
1230 TVertices newVertices = vertices_;
1231 TNormals newNormals = normals_;
1232 TUvs newUvs = uvs_;
1233 newVertices.reserve(numVertices + numOddVertices);
1234 newNormals.reserve(numNormals + numOddNormals);
1235 newUvs.reserve(numUvs + numOddUvs);
1236
1237 const Triangle* const firstTriangle = &triangles_[0];
1238 const TPoint* const firstVertex = &vertices_[0];
1239 const TVector* const firstNormal = normals_.empty() ? 0 : &normals_[0];
1240 const TUv* const firstUv = uvs_.empty() ? 0 : &uvs_[0];
1241
1242 /*
1243 2 - original vertex numbers are on outside
1244 * - new vertex numbers are on inside
1245 /2\ - triangle numbers are between braces: (#)
1246 / \ - as always everything is counter clockwise
1247 / (2) \ - number of edges (for 'others'): same number as it tail.
1248 /0 1\ - triangle (3) is called the oddTriangle
1249 *---------*
1250 /2\2 1/2\
1251 / \ (3) / \
1252 / (0) \ / (1) \
1253 /0 1\0/0 1\
1254 *---------*---------*
1255 0 1
1256 */
1257 for (size_t i = 0; i < numTriangles; ++i)
1258 {
1259 const Triangle& triangle = triangles_[i];
1260 Triangle* const newTris = &newTriangles[4 * i];
1261 Triangle& oddTriangle = newTris[3];
1262
1263 // compute new vertices, normals and Uvs, and store in odd triangle
1264 //
1265 for (size_t k0 = 2, k1 = 0; k1 < 3; k0 = k1++)
1266 {
1267 const Triangle* const other = triangle.others[k0];
1268 Triangle* const oddOther = other ? &newTriangles[4 * static_cast<size_t>(other - firstTriangle) + 3] : 0;
1269 const size_t h0 = other ? other->side(triangle.vertices[k1]) : IndexTriangle::null();
1270 const size_t h1 = other ? other->side(triangle.vertices[k0]) : IndexTriangle::null();
1271 LASS_ASSERT((h0 < 3 && h1 == (h0 + 1) % 3) || other == 0);
1272
1273 if (!oddTriangle.vertices[k0])
1274 {
1275 LASS_ASSERT(newVertices.size() < newVertices.capacity());
1276 newVertices.push_back(TPoint(.5 * (triangle.vertices[k0]->position() + triangle.vertices[k1]->position())));
1277 oddTriangle.vertices[k0] = &newVertices.back();
1278 if (other)
1279 {
1280 oddOther->vertices[h0] = &newVertices.back();
1281 }
1282 }
1283 if (triangle.normals[k0] && !oddTriangle.normals[k0])
1284 {
1285 LASS_ASSERT(triangle.normals[k1]);
1286 LASS_ASSERT(newNormals.size() < newNormals.capacity());
1287 newNormals.push_back(.5 * (*triangle.normals[k0] + *triangle.normals[k1]));
1288 oddTriangle.normals[k0] = &newNormals.back();
1289 if (other && triangle.normals[k0] == other->normals[h1] && triangle.normals[k1] == other->normals[h0])
1290 {
1291 oddOther->normals[h0] = &newNormals.back();
1292 }
1293 }
1294 if (triangle.uvs[k0] && !oddTriangle.uvs[k0])
1295 {
1296 LASS_ASSERT(newUvs.size() < newUvs.capacity());
1297 LASS_ASSERT(triangle.uvs[k1]);
1298 newUvs.push_back(TUv(.5 * (triangle.uvs[k0]->position() + triangle.uvs[k1]->position())));
1299 oddTriangle.uvs[k0] = &newUvs.back();
1300 if (other && triangle.uvs[k0] == other->uvs[h1] && triangle.uvs[k1] == other->uvs[h0])
1301 {
1302 oddOther->uvs[h0] = &newUvs.back();
1303 }
1304 }
1305 oddTriangle.others[k0] = &newTris[k1];
1306 oddTriangle.creaseLevel[k0] = 0;
1307 }
1308 oddTriangle.attribute = triangle.attribute;
1309
1310 // connect other triangles
1311 //
1312 for (size_t k0 = 0, k1 = 1, k2 = 2; k0 < 3; k1 = k2, k2 = k0, ++k0)
1313 {
1314 Triangle& newTriangle = newTris[k0];
1315 newTriangle.vertices[k0] = &newVertices.begin()[triangle.vertices[k0] - firstVertex];
1316 newTriangle.vertices[k1] = oddTriangle.vertices[k0];
1317 newTriangle.vertices[k2] = oddTriangle.vertices[k2];
1318 newTriangle.normals[k0] = triangle.normals[k0] ? &newNormals.begin()[triangle.normals[k0] - firstNormal] : 0;
1319 newTriangle.normals[k1] = oddTriangle.normals[k0];
1320 newTriangle.normals[k2] = oddTriangle.normals[k2];
1321 newTriangle.uvs[k0] = triangle.uvs[k0] ? &newUvs.begin()[triangle.uvs[k0] - firstUv] : 0;
1322 newTriangle.uvs[k1] = oddTriangle.uvs[k0];
1323 newTriangle.uvs[k2] = oddTriangle.uvs[k2];
1324 if (const Triangle* other0 = triangle.others[k0])
1325 {
1326 const size_t j = static_cast<size_t>(other0 - firstTriangle);
1327 const size_t h = other0->side(triangle.vertices[k0]);
1328 LASS_ASSERT(h < 3);
1329 Triangle& newOther = newTriangles[4 * j + h];
1330 LASS_ASSERT(newOther.others[(h + 2) % 3] == 0 || newOther.others[(h + 2) % 3] == &newTriangle);
1331 newTriangle.others[k0] = &newOther;
1332 }
1333 newTriangle.others[k1] = &oddTriangle;
1334 if (const Triangle* other2 = triangle.others[k2])
1335 {
1336 const size_t j = static_cast<size_t>(other2 - firstTriangle);
1337 const size_t h = other2->side(triangle.vertices[k0]);
1338 LASS_ASSERT(h < 3);
1339 Triangle& newOther = newTriangles[4 * j + h];
1340 LASS_ASSERT(newOther.others[h] == 0 || newOther.others[h] == &newTriangle);
1341 newTriangle.others[k2] = &newOther;
1342 }
1343 newTriangle.creaseLevel[k0] = triangle.creaseLevel[k0];
1344 newTriangle.creaseLevel[k1] = 0;
1345 newTriangle.creaseLevel[k2] = triangle.creaseLevel[k2];
1346 newTriangle.attribute = triangle.attribute;
1347 }
1348 }
1349
1350 triangles_.swap(newTriangles);
1351 vertices_.swap(newVertices);
1352 normals_.swap(newNormals);
1353 uvs_.swap(newUvs);
1354 tree_.reset();
1355 numBoundaryEdges_ *= 2;
1356}
1357
1358
1359
1360/** subdivide every triangle in selected in 4 new ones by splitting the edges
1361 * @warning tree_ will be reset and must be recreated manually after calling this function!
1362 */
1363template <typename T, template <typename, typename, typename> class BHV, typename SH>
1364void TriangleMesh3D<T, BHV, SH>::subdivide(TTriangleIterators& selected, TOddVertexWings& oddVertexWings)
1365{
1366 if (triangles_.empty())
1367 {
1368 return;
1369 }
1370
1371 enum VertexTag
1372 {
1373 Unselected = 0,
1374 Progressive = 1,
1375 Selected = 3, // also contains Progressive mask so that a (Selected | Progressive) is still Selected
1376 };
1377 typedef std::vector<unsigned> TVertexTags;
1378
1379 const Triangle* const firstTriangle = &triangles_[0];
1380 const TPoint* const firstVertex = &vertices_[0];
1381 const TVector* const firstNormal = normals_.empty() ? 0 : &normals_[0];
1382 const TUv* const firstUv = uvs_.empty() ? 0 : &uvs_[0];
1383
1384 // tag all vertices attached to selected triangles as selected
1385 //
1386 TVertexTags vertexTags(vertices_.size(), Unselected);
1387 const size_t numSelected = selected.size();
1388 for (size_t i = 0; i < numSelected; ++i)
1389 {
1390 const TTriangleIterator triangle = selected[i];
1391 for (size_t k = 0; k < 3; ++k)
1392 {
1393 const TPoint* vertex = triangle->vertices[k];
1394 vertexTags.begin()[vertex - firstVertex] = Selected;
1395 }
1396 }
1397
1398 // this may be a bit blunt if the number of selected faces is very smal compared to a huge triangle mesh.
1399 // Because, we're gonna loop through _all_ triangles.
1400 // Each triangle that has at least one Selected vertex but have all its vertices at least set Progressive.
1401 const size_t numTriangles = triangles_.size();
1402 std::vector<size_t> triangleSplits(numTriangles, 1);
1403 for (size_t i = 0; i < numTriangles; ++i)
1404 {
1405 const Triangle& triangle = triangles_[i];
1406 unsigned& tag0 = vertexTags.begin()[triangle.vertices[0] - firstVertex];
1407 unsigned& tag1 = vertexTags.begin()[triangle.vertices[1] - firstVertex];
1408 unsigned& tag2 = vertexTags.begin()[triangle.vertices[2] - firstVertex];
1409 if (tag0 == Selected || tag1 == Selected || tag2 == Selected)
1410 {
1411 tag0 = static_cast<VertexTag>(tag0 | Progressive);
1412 tag1 = static_cast<VertexTag>(tag1 | Progressive);
1413 tag2 = static_cast<VertexTag>(tag2 | Progressive);
1414 }
1415 }
1416
1417 // let's again loop through all triangles.
1418 // Only triangles with none of their vertices Unselected will be split in four
1419 // The others we'll mark as not to be split (for now).
1420 std::vector<size_t> offspringCount(numTriangles, 4);
1421 for (size_t i = 0; i < numTriangles; ++i)
1422 {
1423 const Triangle& triangle = triangles_[i];
1424 for (size_t k = 0; k < 3; ++k)
1425 {
1426 if (vertexTags.begin()[triangle.vertices[k] - firstVertex] == Unselected)
1427 {
1428 offspringCount[i] = 1;
1429 break;
1430 }
1431 }
1432 }
1433
1434 // and again ...
1435 // Some of the triangles marked not to be split, have neighbours that are split in four.
1436 // They never can have more than one such neighbour, but if they do, the triangle must be split in two.
1437 for (size_t i = 0; i < numTriangles; ++i)
1438 {
1439 if (offspringCount[i] == 4)
1440 {
1441 continue;
1442 }
1443 const Triangle& triangle = triangles_[i];
1444 for (size_t k = 0; k < 3; ++k)
1445 {
1446 const Triangle* other = triangle.others[k];
1447 if (other && offspringCount.begin()[other - firstTriangle] == 4)
1448 {
1449#ifndef NDEBUG
1450 const TPoint* v0 = triangle.vertices[k];
1451 const TPoint* v1 = triangle.vertices[(k + 1) % 3];
1452 const TPoint* v2 = triangle.vertices[(k + 2) % 3];
1453 LASS_ASSERT(other->side(v0) < 3 && other->side(v1) < 3);
1454 LASS_ASSERT(vertexTags.begin()[v0 - firstVertex] != Unselected && vertexTags.begin()[v1 - firstVertex] != Unselected);
1455 LASS_ASSERT(vertexTags.begin()[v2 - firstVertex] == Unselected);
1456#endif
1457 offspringCount[i] = 2;
1458 break;
1459 }
1460 }
1461 }
1462
1463 // accumulate the number of offspring to get a position into the new triangle list.
1464 std::vector<size_t> newTriangleOffsets(numTriangles + 1, 0); // one more
1465 std::partial_sum(offspringCount.begin(), offspringCount.end(), newTriangleOffsets.begin() + 1);
1466 const size_t numNewTriangles = newTriangleOffsets.back();
1467
1468 // count the number of odd verts, normals and uvs to be added.
1469 // odd verts, normals and uvs may be shared and counted double. to compensate, count them all as double, but shared ones only half so.
1470 size_t numOddVertices = 0;
1471 size_t numOddNormals = 0;
1472 size_t numOddUvs = 0;
1473 size_t numOddBoundaryEdges = 0;
1474 for (size_t i = 0; i < numTriangles; ++i)
1475 {
1476 if (offspringCount[i] != 4)
1477 {
1478 continue;
1479 }
1480 const Triangle& triangle = triangles_[i];
1481 for (size_t k = 0; k < 3; ++k)
1482 {
1483 const HalfEdge edge1(&triangle, k);
1484 if (const HalfEdge other1 = edge1.sym())
1485 {
1486 const bool otherIsFourSplit = offspringCount.begin()[other1.triangle() - firstTriangle] == 4;
1487 numOddVertices += otherIsFourSplit ? 1 : 2; // if shared, count as "half double"
1488
1489 const HalfEdge edge2 = edge1.oNext();
1490 const HalfEdge other2 = other1.oNext();
1491 LASS_ASSERT(!edge1.normal() == !edge2.normal() && !edge1.uv() == !edge2.uv());
1492 LASS_ASSERT(!other1.normal() == !other2.normal() && !other1.uv() == !other2.uv());
1493 if (edge1.normal())
1494 {
1495 numOddNormals += (otherIsFourSplit && edge1.normal() == other2.normal() && edge2.normal() == other1.normal()) ? 1 : 2; // if shared, count as "half double"
1496 }
1497 if (edge1.uv())
1498 {
1499 numOddUvs += (otherIsFourSplit && edge1.uv() == other2.uv() && edge2.uv() == other1.uv()) ? 1 : 2; // if shared, count as "half double"
1500 }
1501 }
1502 else
1503 {
1504 numOddVertices += 2;
1505 numOddNormals += edge1.normal() ? 2 : 0;
1506 numOddUvs += edge1.uv() ? 2 : 0;
1507 numOddBoundaryEdges += 1;
1508 }
1509 }
1510 }
1511 LASS_ASSERT((numOddVertices % 2) == 0 && (numOddNormals % 2) == 0 && (numOddUvs % 2) == 0);
1512 numOddVertices /= 2;
1513 numOddNormals /= 2;
1514 numOddUvs /= 2;
1515
1516 TTriangles newTriangles(numNewTriangles);
1517 TVertices newVertices = vertices_;
1518 TNormals newNormals = normals_;
1519 TUvs newUvs = uvs_;
1520 newVertices.reserve(vertices_.size() + numOddVertices);
1521 newNormals.reserve(normals_.size() + numOddNormals);
1522 newUvs.reserve(uvs_.size() + numOddUvs);
1523 oddVertexWings.clear();
1524 //oddVertexWings.reserve(numOddVertices);
1525
1526 // now it's time to do the real triangle splitting.
1527 // first, let's run over all four splits.
1528 for (size_t i = 0; i < numTriangles; ++i)
1529 {
1530 if (offspringCount[i] != 4)
1531 {
1532 continue;
1533 }
1534 const Triangle& triangle = triangles_[i];
1535 Triangle* const newTris = &newTriangles[newTriangleOffsets[i]];
1536
1537 Triangle& oddTriangle = newTris[3];
1538
1539 // compute new vertices, normals and Uvs, and store in odd triangle
1540 //
1541 for (size_t k0 = 2, k1 = 0; k1 < 3; k0 = k1++)
1542 {
1543 const Triangle* const other = triangle.others[k0];
1544 const size_t j = other ? static_cast<size_t>(other - firstTriangle) : IndexTriangle::null();
1545 const size_t h0 = other ? other->side(triangle.vertices[k1]) : IndexTriangle::null();
1546 const size_t h1 = other ? other->side(triangle.vertices[k0]) : IndexTriangle::null();
1547 LASS_ASSERT((h0 < 3 && h1 == (h0 + 1) % 3) || other == 0);
1548 Triangle* const oddOther = (other && offspringCount[j] == 4) ? &newTriangles[newTriangleOffsets[j] + 3] : 0;
1549
1550 if (!oddTriangle.vertices[k0])
1551 {
1552 LASS_ASSERT(newVertices.size() < newVertices.capacity());
1553 newVertices.push_back(TPoint(.5 * (triangle.vertices[k0]->position() + triangle.vertices[k1]->position())));
1554 oddTriangle.vertices[k0] = &newVertices.back();
1555 if (oddOther)
1556 {
1557 oddOther->vertices[h0] = &newVertices.back();
1558 }
1559 oddVertexWings[&newVertices.back()] = TWing(&oddTriangle, const_cast<Triangle*>(oddOther));
1560 }
1561 if (triangle.normals[k0] && !oddTriangle.normals[k0])
1562 {
1563 LASS_ASSERT(triangle.normals[k1]);
1564 LASS_ASSERT(newNormals.size() < newNormals.capacity());
1565 newNormals.push_back(.5 * (*triangle.normals[k0] + *triangle.normals[k1]));
1566 oddTriangle.normals[k0] = &newNormals.back();
1567 if (oddOther && triangle.normals[k0] == other->normals[h1] && triangle.normals[k1] == other->normals[h0])
1568 {
1569 oddOther->normals[h0] = &newNormals.back();
1570 }
1571 }
1572 if (triangle.uvs[k0] && !oddTriangle.uvs[k0])
1573 {
1574 LASS_ASSERT(newUvs.size() < newUvs.capacity());
1575 LASS_ASSERT(triangle.uvs[k1]);
1576 newUvs.push_back(TUv(.5 * (triangle.uvs[k0]->position() + triangle.uvs[k1]->position())));
1577 oddTriangle.uvs[k0] = &newUvs.back();
1578 if (oddOther && triangle.uvs[k0] == other->uvs[h1] && triangle.uvs[k1] == other->uvs[h0])
1579 {
1580 oddOther->uvs[h0] = &newUvs.back();
1581 }
1582 }
1583 oddTriangle.others[k0] = &newTris[k1];
1584 oddTriangle.creaseLevel[k0] = 0;
1585 }
1586 oddTriangle.attribute = triangle.attribute;
1587
1588 // connect other triangles
1589 //
1590 for (size_t k0 = 0, k1 = 1, k2 = 2; k0 < 3; k1 = k2, k2 = k0, ++k0)
1591 {
1592 Triangle& newTriangle = newTris[k0];
1593 newTriangle.vertices[k0] = &newVertices.begin()[triangle.vertices[k0] - firstVertex];
1594 newTriangle.vertices[k1] = oddTriangle.vertices[k0];
1595 newTriangle.vertices[k2] = oddTriangle.vertices[k2];
1596 newTriangle.normals[k0] = triangle.normals[k0] ? &newNormals.begin()[triangle.normals[k0] - firstNormal] : 0;
1597 newTriangle.normals[k1] = oddTriangle.normals[k0];
1598 newTriangle.normals[k2] = oddTriangle.normals[k2];
1599 newTriangle.uvs[k0] = triangle.uvs[k0] ? &newUvs.begin()[triangle.uvs[k0] - firstUv] : 0;
1600 newTriangle.uvs[k1] = oddTriangle.uvs[k0];
1601 newTriangle.uvs[k2] = oddTriangle.uvs[k2];
1602 if (const Triangle* other0 = triangle.others[k0])
1603 {
1604 const size_t j = static_cast<size_t>(other0 - firstTriangle);
1605 LASS_ASSERT(offspringCount[j] == 4 || offspringCount[j] == 2);
1606 if (offspringCount[j] == 4)
1607 {
1608 const size_t h = other0->side(triangle.vertices[k0]);
1609 LASS_ASSERT(h < 3);
1610 Triangle& newOther = newTriangles[newTriangleOffsets[j] + h];
1611 LASS_ASSERT(newOther.others[(h + 2) % 3] == 0 || newOther.others[(h + 2) % 3] == &newTriangle);
1612 newTriangle.others[k0] = &newOther;
1613 }
1614 }
1615 newTriangle.others[k1] = &oddTriangle;
1616 if (const Triangle* other2 = triangle.others[k2])
1617 {
1618 const size_t j = static_cast<size_t>(other2 - firstTriangle);
1619 LASS_ASSERT(offspringCount[j] == 4 || offspringCount[j] == 2);
1620 if (offspringCount[j] == 4)
1621 {
1622 const size_t h = other2->side(triangle.vertices[k0]);
1623 LASS_ASSERT(h < 3);
1624 Triangle& newOther = newTriangles[newTriangleOffsets[j] + h];
1625 LASS_ASSERT(newOther.others[h] == 0 || newOther.others[h] == &newTriangle);
1626 newTriangle.others[k2] = &newOther;
1627 }
1628 }
1629 newTriangle.creaseLevel[k0] = triangle.creaseLevel[k0];
1630 newTriangle.creaseLevel[k1] = 0;
1631 newTriangle.creaseLevel[k2] = triangle.creaseLevel[k2];
1632 newTriangle.attribute = triangle.attribute;
1633 }
1634 }
1635
1636 // by now, all new arrays should be filled.
1637 LASS_ASSERT(newVertices.size() == vertices_.size() + numOddVertices);
1638 LASS_ASSERT(newNormals.size() == normals_.size() + numOddNormals);
1639 LASS_ASSERT(newUvs.size() == uvs_.size() + numOddUvs);
1640
1641 // now do the no-splits and two-splits.
1642 //
1643 for (size_t i = 0; i < numTriangles; ++i)
1644 {
1645 const Triangle& triangle = triangles_[i];
1646 Triangle* const newTris = &newTriangles[newTriangleOffsets[i]];
1647
1648 switch (offspringCount[i])
1649 {
1650 case 1:
1651 for (size_t k = 0; k < 3; ++k)
1652 {
1653 newTris[0].vertices[k] = &newVertices.begin()[triangle.vertices[k] - firstVertex];
1654 newTris[0].normals[k] = triangle.normals[k] ? &newNormals.begin()[triangle.normals[k] - firstNormal] : 0;
1655 newTris[0].uvs[k] = triangle.uvs[k] ? &newUvs.begin()[triangle.uvs[k] - firstUv] : 0;
1656 if (const Triangle* const other = triangle.others[k])
1657 {
1658 const size_t j = static_cast<size_t>(other - firstTriangle);
1659 LASS_ASSERT(offspringCount[j] == 1 || offspringCount[j] == 2);
1660 const size_t dj = (offspringCount[j] == 2 && vertexTags.begin()[triangle.vertices[k] - firstVertex] == Unselected) ? 1 : 0;
1661 newTris[0].others[k] = &newTriangles[newTriangleOffsets[j] + dj];
1662 }
1663 else
1664 {
1665 newTris[0].others[k] = 0;
1666 }
1667 }
1668 newTris[0].attribute = triangle.attribute;
1669 break;
1670
1671 case 2:
1672 {
1673 size_t k1 = IndexTriangle::null(), k2 = IndexTriangle::null();
1674 for (size_t k = 0; k < 3; ++k)
1675 {
1676 newTris[0].vertices[k] = newTris[1].vertices[k] = &newVertices.begin()[triangle.vertices[k] - firstVertex];
1677 newTris[0].normals[k] = newTris[1].normals[k] = triangle.normals[k] ? &newNormals.begin()[triangle.normals[k] - firstNormal] : 0;
1678 newTris[0].uvs[k] = newTris[1].uvs[k] = triangle.uvs[k] ? &newUvs.begin()[triangle.uvs[k] - firstUv] : 0;
1679 if (const Triangle* const other = triangle.others[k])
1680 {
1681 // this may be wrong for the splitted side, but it'll be corrected in a split second. got it? split second ... nevermind.
1682 const size_t j = static_cast<size_t>(other - firstTriangle);
1683 const size_t dj = (offspringCount[j] == 2 && vertexTags.begin()[triangle.vertices[k] - firstVertex] == Unselected) ? 1 : 0;
1684 newTris[0].others[k] = newTris[1].others[k] = &newTriangles[newTriangleOffsets[j] + dj];
1685 }
1686 else
1687 {
1688 newTris[0].others[k] = newTris[1].others[k] = 0;
1689 }
1690 if (vertexTags[static_cast<size_t>(triangle.vertices[k] - firstVertex)] == Unselected)
1691 {
1692 LASS_ASSERT(k1 == IndexTriangle::null() && k2 == IndexTriangle::null());
1693 k1 = (k + 1) % 3;
1694 k2 = (k + 2) % 3;
1695 LASS_ASSERT(vertexTags[static_cast<size_t>(triangle.vertices[k1] - firstVertex)] != Unselected);
1696 LASS_ASSERT(vertexTags[static_cast<size_t>(triangle.vertices[k2] - firstVertex)] != Unselected);
1697 newTris[1].others[k] = &newTris[0];
1698 }
1699 }
1700 LASS_ASSERT(k1 < 3 && k2 < 3);
1701 newTris[0].others[k2] = &newTris[1];
1702
1703 const Triangle* other = triangle.others[k1];
1704 LASS_ASSERT(other);
1705 const size_t j = static_cast<size_t>(other - firstTriangle);
1706 LASS_ASSERT(offspringCount[j] == 4);
1707 const size_t offJ = newTriangleOffsets[j];
1708 Triangle& oddOther = newTriangles[offJ + 3];
1709 const size_t h1 = other->side(triangle.vertices[k2]);
1710 const size_t h2 = other->side(triangle.vertices[k1]);
1711 LASS_ASSERT((h1 < 3 && h2 == (h1 + 1) % 3));
1712 Triangle& other1 = newTriangles[offJ + h1];
1713 Triangle& other2 = newTriangles[offJ + h2];
1714
1715 newTris[0].vertices[k2] = newTris[1].vertices[k1] = oddOther.vertices[h1];
1716 newTris[0].normals[k2] = newTris[1].normals[k1] = oddOther.normals[h1];
1717 newTris[0].uvs[k2] = newTris[1].uvs[k1] = oddOther.uvs[h1];
1718
1719 LASS_ASSERT(newTris[0].vertices[k1] == other2.vertices[h2] && newTris[0].vertices[k2] == other2.vertices[h1]);
1720 newTris[0].others[k1] = &other2;
1721 other2.others[h1] = &newTris[0];
1722 LASS_ASSERT(newTris[1].vertices[k1] == other1.vertices[h2] && newTris[1].vertices[k2] == other1.vertices[h1]);
1723 newTris[1].others[k1] = &other1;
1724 other1.others[h1] = &newTris[1];
1725
1726 newTris[0].attribute = newTris[1].attribute = triangle.attribute;
1727
1728 LASS_ASSERT(oddVertexWings.find(oddOther.vertices[h1]) != oddVertexWings.end());
1729 TWing& wing = oddVertexWings[oddOther.vertices[h1]];
1730 LASS_ASSERT(wing.first && !wing.second);
1731 wing.second = &newTris[1];
1732 }
1733 break;
1734
1735 default:
1736 LASS_ASSERT(offspringCount[i] == 4);
1737 break;
1738 };
1739 }
1740
1741 std::vector<size_t> selectedIndices;
1742 selectedIndices.reserve(numSelected);
1743 for (size_t i = 0; i < numSelected; ++i)
1744 {
1745 selectedIndices.push_back(static_cast<size_t>(selected[i] - triangles_.begin()));
1746 }
1747
1748 triangles_.swap(newTriangles);
1749 vertices_.swap(newVertices);
1750 normals_.swap(newNormals);
1751 uvs_.swap(newUvs);
1752 tree_.reset();
1753 numBoundaryEdges_ += numOddBoundaryEdges;
1754
1755 TTriangleIterators newSelected;
1756 newSelected.reserve(4 * numSelected);
1757 for (size_t i = 0; i < numSelected; ++i)
1758 {
1759 const TTriangleIterator t = triangles_.begin() + static_cast<std::ptrdiff_t>(newTriangleOffsets[selectedIndices[i]]);
1760 for (int dt = 0; dt < 4; ++dt)
1761 {
1762 newSelected.push_back(t + dt);
1763 }
1764 }
1765 selected.swap(newSelected);
1766}
1767
1768
1769
1770
1771
1772// --- free ----------------------------------------------------------------------------------------
1773
1774
1775
1776}
1777
1778}
1779
1780#endif
1781
1782// EOF
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 autoSew()
automatically sews (unconnected) triangles by comparing geometrical vertices and normals
implementation details of lass::prim
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
@ rNone
operation has no answer, output arguments are meaningless
Definition result.h:76
@ 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