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.