8 #include <vtestbed/base/constants.hh> 9 #include <vtestbed/base/mean.hh> 10 #include <vtestbed/config/real_type.hh> 11 #include <vtestbed/core/bisection.hh> 13 #include <vtestbed/geometry/inertia_tensor.hh> 14 #include <vtestbed/geometry/math.hh> 15 #include <vtestbed/geometry/polyhedron.hh> 16 #include <vtestbed/geometry/tetrahedron.hh> 17 #include <vtestbed/geometry/vertex.hh> 24 inline blitz::Array<T,1>
26 const auto n = src.size();
27 blitz::Array<T,1> result(blitz::shape(n));
28 for (
size_t i=0; i<n; ++i) {
37 for (
auto& v : vertices) {
45 const auto nvertices = vertices.size();
46 vertices.resize(nvertices*2);
47 for (
size_t i=0; i<nvertices; ++i) {
50 vertices[nvertices + i] = v;
54 template <
class Vertices,
class Normals,
class Rotate>
56 rotate_vertices(Vertices& vertices, Normals& normals, Rotate rotate) {
57 for (
auto& v : vertices) {
60 for (
auto& v : normals) {
71 operator()(value_type lhs, value_type rhs)
const {
72 lhs.sort(), rhs.sort();
80 return f[0] == f[1] || f[1] == f[2] || f[2] == f[0];
83 template <
class T,
int N>
84 struct CompareTriangles {
89 operator()(
const value_type& lhs,
const value_type& rhs)
const {
90 const auto y0 = std::min({lhs[0][1], lhs[1][1], lhs[2][1]});
91 const auto y1 = std::min({rhs[0][1], rhs[1][1], rhs[2][1]});
97 template <
class T,
int N>
99 gnuplot(
std::ostream& out,
const vtb::geometry::Vertex<T,N>& v) {
101 for (
int i=1; i<N; ++i) { out <<
' ' << v(i); }
106 template <
class T,
int N>
108 const blitz_vertex_array& vertices,
109 const blitz_face_array& faces
111 _vertices(vertices.data(), vertices.data() + vertices.size()),
112 _faces(faces.data(), faces.data() + faces.size()) {}
115 template <
class T,
int N>
117 auto& vertices = this->_vertices;
118 auto& faces = this->_faces;
120 const auto n = tree.nodes().size();
121 vertices.reserve(n*3);
123 for (
const auto& node : tree.nodes()) {
124 for (
const auto& tr : node.polygons()) {
125 vertices.emplace_back(tr[0]);
126 vertices.emplace_back(tr[1]);
127 vertices.emplace_back(tr[2]);
128 faces.emplace_back(idx, idx+1, idx+2);
134 template <
class T,
int N>
136 auto& vertices = this->_vertices;
137 auto& faces = this->_faces;
139 vertices.reserve(triangles.size()*3);
140 faces.reserve(triangles.size());
141 for (
const auto& tr : triangles) {
142 vertices.emplace_back(tr[0]);
143 vertices.emplace_back(tr[1]);
144 vertices.emplace_back(tr[2]);
145 faces.emplace_back(idx, idx+1, idx+2);
150 template <
class T,
int N>
153 const auto& vertices = this->_vertices;
154 const auto& faces = this->_faces;
155 const auto nfaces = faces.size();
156 auto& vnormals = this->_vertex_normals;
157 vnormals.assign(vertices.size(), T{0});
158 auto& fnormals = this->_face_normals;
159 fnormals.assign(faces.size(), T{0});
160 for (size_type i=0; i<nfaces; ++i) {
161 const auto& face = this->_faces[i];
162 const auto i0 = face[0];
163 const auto i1 = face[1];
164 const auto i2 = face[2];
165 const auto& v0 = vertices[i0];
166 const auto& v1 = vertices[i1];
167 const auto& v2 = vertices[i2];
168 vertex_type a = v1-v0, b = v2-v0;
169 vertex_type n = cross(a, b);
170 vnormals[i0] += n, vnormals[i1] += n, vnormals[i2] += n;
171 fnormals[i] = unit(n);
173 for (
auto& n : vnormals) {
178 template <
class T,
int N>
181 const auto& vertices = this->_vertices;
182 const auto& faces = this->_faces;
183 const auto nfaces = faces.size();
184 auto& fnormals = this->_face_normals;
185 fnormals.assign(faces.size(), T{0});
186 for (size_type i=0; i<nfaces; ++i) {
187 const auto& face = this->_faces[i];
188 const auto i0 = face[0];
189 const auto i1 = face[1];
190 const auto i2 = face[2];
191 const auto& v0 = vertices[i0];
192 const auto& v1 = vertices[i1];
193 const auto& v2 = vertices[i2];
194 vertex_type a = v1-v0, b = v2-v0;
195 vertex_type n = cross(a, b);
196 fnormals[i] = unit(n);
200 template <
class T,
int N>
203 using vtb::geometry::centroid;
204 const auto& vf = this->vertex_faces();
205 const auto& cf = this->component_faces(vf);
206 auto& faces = this->_faces;
207 const auto& origin = centroid(vertices());
208 index_type nfaces = faces.size();
209 for (
const auto& face_indices : cf) {
210 index_type rfi = this->reference_face_index(face_indices, origin);
212 this->reorder(rfi, origin);
216 computed[rfi] =
true;
217 while (!queue.empty()) {
218 const auto& face_a = faces[queue.front()];
220 for (index_type vertex_index : face_a){
221 for (index_type i : vf[vertex_index]){
222 if (computed[i]) {
continue; }
223 if (!faces[i].reorder(face_a, vertex_index)) {
continue; }
232 template <
class T,
int N>
235 #if defined(VTB_DEBUG_DEDUPLICATE) 236 size_type old_nfaces = this->_faces.size();
237 size_type old_nvertices = this->_vertices.size();
239 this->remove_duplicate_vertices();
240 this->remove_duplicate_faces();
241 #if defined(VTB_DEBUG_DEDUPLICATE) 242 size_type new_nfaces = this->_faces.size();
243 size_type new_nvertices = this->_vertices.size();
244 std::clog <<
"removed " << (old_nfaces-new_nfaces)
245 <<
" faces and " << (old_nvertices-new_nvertices)
246 <<
" vertices" << std::endl;
250 template <
class T,
int N>
254 using iterator =
typename map_type::iterator;
255 auto& vertices = this->_vertices;
256 auto& vertex_normals = this->_vertex_normals;
257 auto& faces = this->_faces;
258 if (!vertex_normals.empty()) {
261 map_type unique_vertices;
262 vertex_array new_vertex_normals;
263 auto insert = [&] (
const index_type& i) -> index_type {
264 const auto& v = vertices[i];
265 iterator it;
bool success;
266 index_type index = unique_vertices.size();
267 std::tie(it,success) = unique_vertices.insert({v, index});
268 return !success ? it->second : index;
270 for (
auto& f : faces) {
271 auto i0 = insert(f[0]);
272 auto i1 = insert(f[1]);
273 auto i2 = insert(f[2]);
274 f = face_type(i0,i1,i2);
276 vertices.resize(unique_vertices.size());
277 for (
const auto& entry : unique_vertices) {
278 vertices[entry.second] = entry.first;
282 template <
class T,
int N>
285 auto& faces = this->_faces;
287 for (
const auto& f : faces) {
288 if (face_has_duplicate_indices(f)) {
continue; }
289 unique_faces.insert(f);
291 faces.assign(unique_faces.begin(), unique_faces.end());
294 template <
class T,
int N>
297 auto& faces = this->_faces;
299 for (
const auto& f : faces) {
300 if (face_has_duplicate_indices(f)) {
continue; }
301 auto result = unique_faces.insert(f);
302 if (!result.second) { trash.insert(*result.first); }
304 auto end = trash.end();
305 auto first = unique_faces.begin();
306 while (first != unique_faces.end()) {
307 if (trash.find(*first) !=
end) { first = unique_faces.erase(first); }
310 faces.assign(unique_faces.begin(), unique_faces.end());
313 template <
class T,
int N>
316 auto& vertices = this->_vertices;
317 auto first = vertices.begin();
318 Equal_vertex<T,N> eq;
319 while (first != vertices.end()) {
320 if (eq(*first, vertex)) {
321 index_type idx = first - vertices.begin();
328 template <
class T,
int N>
331 auto& faces = this->_faces;
334 faces.begin(), faces.end(),
335 [vertex] (
const face_type& f) {
return f.contains(vertex); }
341 template <
class T,
int N>
344 auto& vertices = this->_vertices;
345 auto& vertex_normals = this->_vertex_normals;
346 auto& faces = this->_faces;
347 auto& face_normals = this->_face_normals;
348 const auto offset = vertices.size();
349 for (
const auto& v : rhs.vertices()) { vertices.emplace_back(v); }
350 for (
const auto& n : rhs.vertex_normals()) {
351 vertex_normals.emplace_back(n);
353 for (
auto f : rhs.faces()) { faces.emplace_back(f += offset); }
354 for (
const auto& n : rhs.face_normals()) {
355 face_normals.emplace_back(n);
359 template <
class T,
int N>
362 index_array_2d vf(this->_vertices.size());
363 const auto& faces = this->_faces;
364 int nfaces = faces.size();
365 for (
int i=0; i<nfaces; ++i) {
366 const auto& face = faces[i];
367 vf[face[0]].push_back(i);
368 vf[face[1]].push_back(i);
369 vf[face[2]].push_back(i);
374 template <
class T,
int N>
377 const index_array_2d& vf
378 )
const -> index_array_2d {
379 const auto& faces = this->_faces;
380 index_type nfaces = faces.size();
384 for (index_type i=0; i<nfaces; ++i) {
385 if (computed[i]) {
continue; }
389 auto& face_indices = cf.back();
390 while (!queue.empty()) {
391 auto face_index = queue.front();
393 face_indices.push_back(face_index);
394 for (index_type vertex_index : faces[face_index]) {
395 for (index_type face : vf[vertex_index]){
396 if (computed[face]) {
continue; }
397 computed[face] =
true;
406 template <
class T,
int N>
409 const index_array& indices,
410 const vertex_type& origin
411 )
const -> index_type {
412 const auto& vertices = this->_vertices;
413 const auto& faces = this->_faces;
425 for (index_type i : indices) {
426 const auto& face = faces[i];
427 const auto& v0 = vertices[face[0]];
428 const auto& v1 = vertices[face[1]];
429 const auto& v2 = vertices[face[2]];
430 vertex_type face_centre = (v0+v1+v2) / 3;
431 T new_length =
distance(face_centre, origin);
433 if (new_length < min_length) {
434 min_length = new_length;
435 face_with_min_length = i;
438 return face_with_min_length;
441 template <
class T,
int N>
444 index_type reference_face_index,
445 const vertex_type& geometry_centre
447 const auto& vertices = this->_vertices;
448 auto& faces = this->_faces;
449 auto& face = faces[reference_face_index];
450 const auto& v0 = vertices[face[0]];
451 const auto& v1 = vertices[face[1]];
452 const auto& v2 = vertices[face[2]];
453 vertex_type face_centre = (v0+v1+v2) / 3;
454 vertex_type n = surface_normal(v0,v1,v2);
455 if (dot(n, face_centre-geometry_centre) < 0) {
460 template <
class T,
int N>
463 this->_vertices.clear();
464 this->_vertex_normals.clear();
465 this->_faces.clear();
466 this->_face_normals.clear();
469 template <
class T,
int N>
472 this->_vertex_normals.clear();
473 this->_face_normals.clear();
476 template <
class T,
int N>
479 this->_vertices.shrink_to_fit();
480 this->_vertex_normals.shrink_to_fit();
481 this->_faces.shrink_to_fit();
482 this->_face_normals.shrink_to_fit();
485 template <
class T,
int N>
489 swap(this->_vertices, rhs._vertices);
490 swap(this->_vertex_normals, rhs._vertex_normals);
491 swap(this->_faces, rhs._faces);
492 swap(this->_face_normals, rhs._face_normals);
495 template <
class T,
int N>
500 const auto& v = this->_vertices;
501 for (
const auto& f : this->_faces) {
502 sum.update(area(Triangle<T,3>{v[f[0]], v[f[1]], v[f[2]]}));
507 template <
class T,
int N>
510 using vtb::geometry::signed_volume;
511 vertex_type origin = this->centre();
513 const auto& v = this->_vertices;
514 const auto& faces = this->_faces;
515 for (
const auto& f : faces) {
516 Tetrahedron<T,N> t{origin, v[f[0]], v[f[1]], v[f[2]]};
517 volume += signed_volume(t);
522 template <
class T,
int N>
525 using vtb::geometry::signed_volume;
526 vertex_type origin = this->centre();
529 const auto& v = this->_vertices;
530 const auto& faces = this->_faces;
531 for (
const auto& f : faces) {
532 const auto v0 = v[f[0]];
533 const auto v1 = v[f[1]];
534 const auto v2 = v[f[2]];
535 if (v0(d) > level || v1(d) > level || v2(d) > level) {
continue; }
536 Tetrahedron<T,N> t{origin,v0,v1,v2};
537 volume += signed_volume(t);
542 template <
class T,
int N>
545 vertex_type origin{T{}};
546 for (
const auto& v : vertices()) { origin += v; }
547 const auto nvertices = vertices().size();
548 if (nvertices > 0) { origin /= nvertices; }
552 template <
class T,
int N>
558 template <
class T,
int N>
563 for (
const auto& v : this->_vertices) {
564 for (
int i=0; i<N; ++i) {
574 return Rectangle<T,N>{
min,
max};
577 template <
class T,
int N>
582 for (
const auto& v : this->_vertices) {
584 if (m < min) {
min = m; }
585 if (max < m) {
max = m; }
587 return Bounds<T>{
min,
max};
590 template <
class T,
int N>
593 triangle_array triangles;
594 const auto& v = this->_vertices;
595 const auto& faces = this->_faces;
596 for (
const auto& f : faces) {
597 triangles.emplace_back(v[f[0]], v[f[1]], v[f[2]]);
602 template <
class T,
int N>
605 return to_blitz_array(this->_vertices);
608 template <
class T,
int N>
611 return to_blitz_array(this->_vertex_normals);
614 template <
class T,
int N>
617 return to_blitz_array(this->_faces);
620 template <
class T,
int N>
626 template <
class T,
int N>
632 using vtb::geometry::centroid;
633 using vtb::geometry::signed_volume;
634 using bool3 = Vertex<bool,3>;
635 using vec3 = Vertex<T,3>;
636 auto level = bounding_box().min()(2) + draught;
637 auto mass = std::abs(signed_volume_below(2, level)) * constants<T>::water_density();
638 auto goal_function = [&] (T delta) -> T {
640 poly.move({0,0,delta});
641 vec3 centre_of_gravity = T{};
642 vec3 origin = centre_of_gravity;
644 vec3 centre_of_floatation{T{}}, centre_of_buoyancy{T{}}, centre_of_wind{T{}};
645 vec3 wind_force{T{}}, buoyancy_force{T{}};
646 T waterline_length = 0, total_dry_volume = 0, total_wet_volume = 0;
647 const auto& vertices = poly._vertices;
648 const auto& faces = poly._faces;
649 constexpr
auto p0 = constants<T>::atmospheric_pressure();
650 constexpr
auto g = constants<T>::g();
651 constexpr
auto air_density = constants<T>::air_density();
652 constexpr
auto water_density = constants<T>::water_density();
653 for (
const auto& f : faces) {
654 Triangle<T,3> tr{vertices[f[0]],vertices[f[1]],vertices[f[2]]};
655 auto n = surface_normal(tr);
656 auto area = vtb::geometry::area(tr);
658 auto centre = centroid(tr);
659 T wet_area = 0, dry_area = 0;
660 T wet_volume = 0, dry_volume = 0;
661 bool3 above{tr[0][2] > 0, tr[1][2] > 0, tr[2][2] > 0};
662 vec3 wet_centre{T{}}, dry_centre{T{}};
663 bool all_dry = all(above);
664 bool all_wet = !any(above);
665 if (!all_wet && !all_dry) {
667 bool x01 = above(0) ^ above(1);
668 bool x02 = above(0) ^ above(2);
669 bool x12 = above(1) ^ above(2);
671 if (x01 && x02) { outstanding = 0, a = tr[1], b = tr[2]; }
672 else if (x01 && x12) { outstanding = 1, a = tr[0], b = tr[2]; }
673 else { outstanding = 2, a = tr[0], b = tr[1]; }
674 const auto& outstanding_vertex = tr[outstanding];
677 a + (0-a(2))/(outstanding_vertex(2)-a(2))*(outstanding_vertex-a),
678 b + (0-b(2))/(outstanding_vertex(2)-b(2))*(outstanding_vertex-b),
680 auto subarea = vtb::geometry::area(subtr);
683 T segment_length = waterline_segment.length();
684 centre_of_floatation += waterline_segment.centre()*segment_length;
685 waterline_length += segment_length;
688 if (outstanding_vertex(2) > 0) {
689 wet_area = area - subarea;
690 wet_volume = volume - new_volume;
691 wet_centre = T{0.25} * (subtr[1] + subtr[2] + a + b);
693 dry_volume = new_volume;
694 dry_centre = centroid(subtr);
697 wet_volume = new_volume;
698 wet_centre = centroid(subtr);
699 dry_area = area - subarea;
700 dry_volume = volume - new_volume;
701 dry_centre = T{0.25} * (subtr[1] + subtr[2] + a + b);
705 dry_centre = centre, dry_area = area, dry_volume = volume;
708 wet_centre = centre, wet_area = area, wet_volume = volume;
712 auto z = dry_centre(2);
713 centre_of_wind += dry_centre*dry_volume;
714 total_dry_volume += dry_volume;
715 wind_force += (p0 - air_density*g*z) * (-n) * dry_area;
718 auto z = wet_centre(2);
719 centre_of_buoyancy += wet_centre*wet_volume;
720 total_wet_volume += wet_volume;
721 buoyancy_force += (p0 - water_density*g*z) * (-n) * wet_area;
724 buoyancy_force /= mass, wind_force /= mass;
725 if (waterline_length != 0) { centre_of_floatation /= waterline_length; }
726 if (total_wet_volume != 0) { centre_of_buoyancy /= total_wet_volume; }
727 if (total_dry_volume != 0) { centre_of_wind /= total_dry_volume; }
728 vec3 gravity_force{0,0,-g};
729 vec3 force = gravity_force + buoyancy_force + wind_force;
739 Bisection<T,1> bisection;
740 bisection.max_iterations(100);
741 bisection.argument_precision(T{1e-5});
742 bisection.function_precision(T{1e-5});
743 auto bounds = bounding_box();
744 auto delta = bisection(bounds.min()(2), bounds.max()(2), goal_function);
748 template <
class T,
int N>
751 using vtb::geometry::centroid;
752 move(-centroid(bounding_box()));
755 template <
class T,
int N>
758 for (
auto& v : this->_vertices) { v += delta; }
761 template <
class T,
int N>
764 for (
auto& v : this->_vertices) { v *= amount; }
767 template <
class T,
int N>
770 if (vertices().empty()) {
return; }
771 for (
auto& v : this->_vertices) {
772 auto v_length = length(v);
773 auto s = std::max(T{}, (v_length-thickness)/v_length);
778 template <
class T,
int N>
781 flip_vertices(this->_vertices, dim);
782 flip_vertices(this->_vertex_normals, dim);
785 template <
class T,
int N>
788 auto& vertices = this->_vertices;
789 const auto nvertices = vertices.size();
790 if (nvertices == 0) {
794 for (
const auto& v : vertices) {
800 mirror_vertices(vertices, dim);
801 auto& faces = this->_faces;
802 const auto nfaces = faces.size();
804 faces.resize(nfaces*2);
805 for (
size_t i=0; i<nfaces; ++i) {
808 faces[nfaces + i] = f;
811 if (!this->_vertex_normals.empty()) {
812 mirror_vertices(this->_vertex_normals, dim);
816 template <
class T,
int N>
819 using vtb::geometry::rotate;
820 if (dim < 0 || dim > 2) {
823 if (degrees % 90 != 0) {
833 auto& vertices = this->_vertices;
834 auto& normals = this->_vertex_normals;
837 rotate_vertices(vertices, normals, rotate<0,90,T,N>);
838 }
else if (dim == 1) {
839 rotate_vertices(vertices, normals, rotate<1,90,T,N>);
841 rotate_vertices(vertices, normals, rotate<2,90,T,N>);
843 }
else if (degrees == 180) {
845 rotate_vertices(vertices, normals, rotate<0,180,T,N>);
846 }
else if (dim == 1) {
847 rotate_vertices(vertices, normals, rotate<1,180,T,N>);
849 rotate_vertices(vertices, normals, rotate<2,180,T,N>);
853 rotate_vertices(vertices, normals, rotate<0,270,T,N>);
854 }
else if (dim == 1) {
855 rotate_vertices(vertices, normals, rotate<1,270,T,N>);
857 rotate_vertices(vertices, normals, rotate<2,270,T,N>);
862 template <
class T,
int N>
866 #define VTB_GEOMETRY_SUBEXPRESSIONS(w0,w1,w2, f1,f2,f3, g0,g1,g2) \ 867 tmp0 = w0+w1; f1 = tmp0+w2; \ 868 tmp1 = w0*w0; tmp2 = tmp1+w1*tmp0; f2 = tmp2+w2*f1; \ 869 f3 = w0*tmp1 + w1*tmp2 + w2*f2; \ 870 g0 = f2+w0*(f1+w0); g1 = f2+w1*(f1+w1); g2 = f2+w2*(f1+w2) 871 static const T mult[10] = {
873 T{1}/T{24}, T{1}/T{24}, T{1}/T{24},
874 T{1}/T{60}, T{1}/T{60}, T{1}/T{60},
875 T{1}/T{120}, T{1}/T{120}, T{1}/T{120},
878 const auto& v = this->_vertices;
879 const auto& faces = this->_faces;
880 for (
const auto& f : faces) {
882 Triangle<T,N> t{v[f[0]], v[f[1]], v[f[2]]};
883 if (t[0][d] > level || t[1][d] > level || t[2][d] > level) {
continue; }
884 auto x0 = t[0][0], y0 = t[0][1], z0 = t[0][2];
885 auto x1 = t[1][0], y1 = t[1][1], z1 = t[1][2];
886 auto x2 = t[2][0], y2 = t[2][1], z2 = t[2][2];
888 auto a1 = x1-x0, b1 = y1-y0, c1 = z1-z0;
889 auto a2 = x2-x0, b2 = y2-y0, c2 = z2-z0;
891 auto d0 = b1*c2-b2*c1, d1 = a2*c1-a1*c2, d2 = a1*b2-a2*b1;
894 T f1x, f2x, f3x, f1y, f2y, f3y, f1z, f2z, f3z;
895 T g0x, g1x, g2x, g0y, g1y, g2y, g0z, g1z, g2z;
896 VTB_GEOMETRY_SUBEXPRESSIONS(x0,x1,x2, f1x,f2x,f3x, g0x,g1x,g2x);
897 VTB_GEOMETRY_SUBEXPRESSIONS(y0,y1,y2, f1y,f2y,f3y, g0y,g1y,g2y);
898 VTB_GEOMETRY_SUBEXPRESSIONS(z0,z1,z2, f1z,f2z,f3z, g0z,g1z,g2z);
901 intg[1] += d0*f2x; intg[2] += d1*f2y; intg[3] += d2*f2z;
902 intg[4] += d0*f3x; intg[5] += d1*f3y; intg[6] += d2*f3z;
903 intg[7] += d0*(y0*g0x + y1*g1x + y2*g2x);
904 intg[8] += d1*(z0*g0y + z1*g1y + z2*g2y);
905 intg[9] += d2*(x0*g0z + x1*g1z + x2*g2z);
907 for (
int i=0; i<10; ++i) { intg[i] *= mult[i]; }
908 Mass_moments<T,N> prop;
909 auto& cm = prop.centre;
910 auto& mass = prop.volume;
915 if (mass != 0) { cm /= mass; }
916 prop.inertia.xx = intg[5] + intg[6] - mass*(cm(1)*cm(1)+cm(2)*cm(2));
917 prop.inertia.yy = intg[4] + intg[6] - mass*(cm(2)*cm(2)+cm(0)*cm(0));
918 prop.inertia.zz = intg[4] + intg[5] - mass*(cm(0)*cm(0)+cm(1)*cm(1));
919 prop.inertia.xy = (intg[7] - mass*cm(0)*cm(1));
920 prop.inertia.yz = (intg[8] - mass*cm(1)*cm(2));
921 prop.inertia.xz = (intg[9] - mass*cm(2)*cm(0));
923 prop.inertia.xx /= mass; prop.inertia.yy /= mass; prop.inertia.zz /= mass;
924 prop.inertia.xy /= mass; prop.inertia.yz /= mass; prop.inertia.xz /= mass;
927 #undef VTB_GEOMETRY_SUBEXPRESSIONS 930 template <
class T,
int N>
934 const auto& vertices = this->_vertices;
935 const auto& faces = this->_faces;
936 for (
const auto& f : faces) {
937 const auto& v0 = vertices[f[0]];
938 const auto& v1 = vertices[f[1]];
939 const auto& v2 = vertices[f[2]];
940 triangles.emplace_back(v0,v1,v2);
942 std::sort(triangles.begin(), triangles.end(), CompareTriangles<T,N>{});
943 std::reverse(triangles.begin(), triangles.end());
944 for (
const auto& t : triangles) {
945 const auto& v0 = t[0];
946 const auto& v1 = t[1];
947 const auto& v2 = t[2];
948 ::gnuplot(out, v0); out <<
'\n';
949 ::gnuplot(out, v1); out <<
"\n\n";
950 ::gnuplot(out, v2); out <<
'\n';
951 ::gnuplot(out, v2); out <<
"\n\n\n";
955 template <
class T,
int N>
958 const auto& geometry = *
this;
959 for (
const auto& v : geometry.vertices()) {
960 out <<
"v " << v(0) <<
' ' << v(1) <<
' ' << v(2) <<
'\n';
962 for (
const auto& v : geometry.vertex_normals()) {
963 out <<
"vn " << v(0) <<
' ' << v(1) <<
' ' << v(2) <<
'\n';
965 for (
const auto& face : geometry.faces()) {
967 for (
const auto& idx : face) {
968 out <<
' ' << (idx + 1);
976 template <
class T,
int N>
979 out << rhs.vertices();
980 out << rhs.vertex_normals();
982 out << rhs.face_normals();
987 vtb::geometry::operator<<(
989 const Polyhedron<VTB_REAL_TYPE,3>& rhs
992 template <
class T,
int N>
996 in >> rhs._vertex_normals;
998 in >> rhs._face_normals;
1003 vtb::geometry::operator>>(
1005 Polyhedron<VTB_REAL_TYPE,3>& rhs
1008 template <
class T,
int N>
1010 vtb::geometry::winding_number(
const Polyhedron<T,N>& geometry,
const Vertex<T,N>& origin) {
1011 const auto& v = geometry.vertices();
1012 const auto& faces = geometry.faces();
1014 for (
const auto& f : faces) {
1015 Tetrahedron<T,N> t{origin, v[f[0]], v[f[1]], v[f[2]]};
1016 wn += solid_angle(t);
1021 template VTB_REAL_TYPE
1022 vtb::geometry::winding_number(
const Polyhedron<VTB_REAL_TYPE,3>&,
const Vertex<VTB_REAL_TYPE,3>&);
1024 template <
class T,
int N>
1029 Inertia_tensor<T,N> I;
1030 const auto& v = body.vertices();
1031 const auto& faces = body.faces();
1032 const auto& origin = centroid(body);
1034 for (
const auto& f : faces) {
1035 Tetrahedron<T,3> t{origin, v[f[0]], v[f[1]], v[f[2]]};
1036 auto t_signed_volume = signed_volume(t);
1037 auto t_volume = abs(t_signed_volume);
1038 #define x(i) t[i-1][0] 1039 #define y(i) t[i-1][1] 1040 #define z(i) t[i-1][2] 1042 pow2(y(1)) + y(1)*y(2) +
1043 pow2(y(2)) + y(1)*y(3) + y(2)*y(3) +
1044 pow2(y(3)) + y(1)*y(4) + y(2)*y(4) + y(3)*y(4) +
1046 pow2(z(1)) + z(1)*z(2) +
1047 pow2(z(2)) + z(1)*z(3) + z(2)*z(3) +
1048 pow2(z(3)) + z(1)*z(4) + z(2)*z(4) + z(3)*z(4) +
1051 pow2(x(1)) + x(1)*x(2) +
1052 pow2(x(2)) + x(1)*x(3) + x(2)*x(3) +
1053 pow2(x(3)) + x(1)*x(4) + x(2)*x(4) + x(3)*x(4) +
1055 pow2(z(1)) + z(1)*z(2) +
1056 pow2(z(2)) + z(1)*z(3) + z(2)*z(3) +
1057 pow2(z(3)) + z(1)*z(4) + z(2)*z(4) + z(3)*z(4) +
1060 pow2(x(1)) + x(1)*x(2) +
1061 pow2(x(2)) + x(1)*x(3) + x(2)*x(3) +
1062 pow2(x(3)) + x(1)*x(4) + x(2)*x(4) + x(3)*x(4) +
1064 pow2(y(1)) + y(1)*y(2) +
1065 pow2(y(2)) + y(1)*y(3) + y(2)*y(3) +
1066 pow2(y(3)) + y(1)*y(4) + y(2)*y(4) + y(3)*y(4) +
1069 2*y(1)*z(1) + y(2)*z(1) + y(3)*z(1) + y(4)*z(1) + y(1)*z(2) +
1070 2*y(2)*z(2) + y(3)*z(2) + y(4)*z(2) + y(1)*z(3) + y(2)*z(3) +
1071 2*y(3)*z(3) + y(4)*z(3) + y(1)*z(4) + y(2)*z(4) + y(3)*z(4) +
1074 2*x(1)*z(1) + x(2)*z(1) + x(3)*z(1) + x(4)*z(1) + x(1)*z(2) +
1075 2*x(2)*z(2) + x(3)*z(2) + x(4)*z(2) + x(1)*z(3) + x(2)*z(3) +
1076 2*x(3)*z(3) + x(4)*z(3) + x(1)*z(4) + x(2)*z(4) + x(3)*z(4) +
1079 2*x(1)*y(1) + x(2)*y(1) + x(3)*y(1) + x(4)*y(1) + x(1)*y(2) +
1080 2*x(2)*y(2) + x(3)*y(2) + x(4)*y(2) + x(1)*y(3) + x(2)*y(3) +
1081 2*x(3)*y(3) + x(4)*y(3) + x(1)*y(4) + x(2)*y(4) + x(3)*y(4) +
1086 total_volume += t_signed_volume;
1088 if (total_volume != T{}) { I.scale(T{1}/total_volume); }
void flip(int dimension)
Flip the geometry over specified axis.
Mass_moments< T, N > mass_moments(const Polyline< T, N > &polyline)
Calculate area, centroid and inertia tensor.
void reorder()
Fix face indices winding order.
Inertia_tensor< T, N > inertia_tensor(const Polyhedron< T, N > &body)
Calculate inertia tensor (matrix) of a body as a sum of inertia tensors for tetrahedrons.
void normalise_faces()
Compute face normals only.
Binary space partitioning trees.
void move_to_centre_of_bounding_box()
Move origin to centre of bounding box.
void unique()
Remove duplicate vertices and faces.
void scale(const vertex_type &ratio)
Scale the geometry by specified ratio over each dimension.
Estimates sample mean without overflows.
static constexpr const T pi()
void move_to_centre_of_mass()
Move origin to centre of mass.
Three-dimensional polyhedron.
void normalise()
Compute face and vertex normals in one loop.
void wall(scalar_type thickness)
Shrink or extend the geometry by thickness in the direction of centroid.
void mirror(int dimension)
Extend the geometry by mirroring it over the specified axis.
void merge(const Polyhedron &rhs)
Add all vertices, faces and normals from rhs.
void rotate(int dimension, int degrees)
Rotate the geometry by angle which is multiple of 90 degrees.