<li>Insertion of deal.II points in CGAL triangulation types</li>
<li>Conversion from CGAL::Triangulation_2 to Triangulation<dim, 2></li>
<li>Conversion from CGAL::Triangulation_3 to Triangulation<dim, 3></li>
+ <li>Conversion from CGAL::Surface_mesh or CGAL::Polyhedron_3 to Triangulation<2, 3></li>
</ul>
<br>
(Marco Feder, Luca Heltai, 2022/04/26)
# include <boost/hana.hpp>
+# include <CGAL/Polyhedron_3.h>
# include <CGAL/Surface_mesh.h>
+# include <CGAL/Triangulation_2.h>
# include <CGAL/Triangulation_3.h>
# include <deal.II/cgal/utilities.h>
const CGALTriangulation & cgal_triangulation,
Triangulation<dim, spacedim> &dealii_triangulation);
+ /**
+ * Construct a deal.II surface triangulation starting from a
+ * CGAL::Surface_mesh or a CGAL::Polyhedron_3.
+ *
+ * These types can both represent a polyhedral surface made of general
+ * polygons. deal.II only supports triangle or quadrilateral triangulations,
+ * and this function will throw an exception if the input surface mesh
+ * contains polygonal faces with more than 4 vertices per face.
+ *
+ * CGAL orients the faces of a polyhedral surface in a counter clock-wise
+ * w.r.t. to the material side of the surface, i.e., the normal is directed
+ * towards the outside of the surface if the surface is closed and represents
+ * a bounded domain. The opposite orientation is also perfectly valid, and
+ * would represent an unbounded domain complementary to the region
+ * represented by the surface. This function does not change the orientation
+ * of the surface mesh and will produce a triangulation with the same
+ * orientation of the input mesh.
+ *
+ * @param[in] cgal_mesh The input CGAL surface mesh.
+ * @param[out] triangulation The output deal.II triangulation.
+ */
+ template <typename CGAL_MeshType>
+ void
+ cgal_surface_mesh_to_dealii_triangulation(const CGAL_MeshType &cgal_mesh,
+ Triangulation<2, 3> &triangulation);
+
# ifndef DOXYGEN
// This is a degenerate Triangulation_2, made of edges
for (const auto &e : cgal_triangulation.finite_edges())
{
- // An edge is idenfied by a face and a vertex index in the face
+ // An edge is idendified by a face and a vertex index in the face
const auto & f = e.first;
const auto & i = e.second;
CellData<dim> cell(ReferenceCells::Line.n_vertices());
}
dealii_triangulation.create_triangulation(vertices, cells, subcell_data);
}
+
+
+
+ template <typename CGAL_MeshType>
+ void
+ cgal_surface_mesh_to_dealii_triangulation(const CGAL_MeshType &cgal_mesh,
+ Triangulation<2, 3> &triangulation)
+ {
+ Assert(triangulation.n_cells() == 0,
+ ExcMessage(
+ "Triangulation must be empty upon calling this function."));
+
+ const auto is_surface_mesh =
+ boost::hana::is_valid([](auto &&obj) -> decltype(obj.faces()) {});
+
+ const auto is_polyhedral =
+ boost::hana::is_valid([](auto &&obj) -> decltype(obj.facets_begin()) {});
+
+ // Collect Vertices and cells
+ std::vector<dealii::Point<3>> vertices;
+ std::vector<CellData<2>> cells;
+ SubCellData subcell_data;
+
+ // Different loops for Polyhedron or Surface_mesh types
+ if constexpr (decltype(is_surface_mesh(cgal_mesh)){})
+ {
+ AssertThrow(cgal_mesh.num_vertices() > 0,
+ ExcMessage("CGAL surface mesh is empty."));
+ vertices.reserve(cgal_mesh.num_vertices());
+ std::map<typename CGAL_MeshType::Vertex_index, unsigned int> vertex_map;
+ {
+ unsigned int i = 0;
+ for (const auto &v : cgal_mesh.vertices())
+ {
+ vertices.emplace_back(CGALWrappers::cgal_point_to_dealii_point<3>(
+ cgal_mesh.point(v)));
+ vertex_map[v] = i++;
+ }
+ }
+
+ // Collect CellData
+ for (const auto &face : cgal_mesh.faces())
+ {
+ const auto face_vertices =
+ CGAL::vertices_around_face(cgal_mesh.halfedge(face), cgal_mesh);
+
+ AssertThrow(face_vertices.size() == 3 || face_vertices.size() == 4,
+ ExcMessage("Only triangle or quadrilateral surface "
+ "meshes are supported in deal.II"));
+
+ CellData<2> c(face_vertices.size());
+ auto it_vertex = c.vertices.begin();
+ for (const auto &v : face_vertices)
+ *(it_vertex++) = vertex_map[v];
+
+ // Make sure the numberfing is consistent with the one in deal.II
+ if (face_vertices.size() == 4)
+ std::swap(c.vertices[3], c.vertices[2]);
+
+ cells.emplace_back(c);
+ }
+ }
+ else if constexpr (decltype(is_polyhedral(cgal_mesh)){})
+ {
+ AssertThrow(cgal_mesh.size_of_vertices() > 0,
+ ExcMessage("CGAL surface mesh is empty."));
+ vertices.reserve(cgal_mesh.size_of_vertices());
+ std::map<decltype(cgal_mesh.vertices_begin()), unsigned int> vertex_map;
+ {
+ unsigned int i = 0;
+ for (auto it = cgal_mesh.vertices_begin();
+ it != cgal_mesh.vertices_end();
+ ++it)
+ {
+ vertices.emplace_back(
+ CGALWrappers::cgal_point_to_dealii_point<3>(it->point()));
+ vertex_map[it] = i++;
+ }
+ }
+
+ // Loop over faces of Polyhedron, fill CellData
+ for (auto face = cgal_mesh.facets_begin();
+ face != cgal_mesh.facets_end();
+ ++face)
+ {
+ auto j = face->facet_begin();
+ const unsigned int vertices_per_face = CGAL::circulator_size(j);
+ AssertThrow(vertices_per_face == 3 || vertices_per_face == 4,
+ ExcMessage("Only triangle or quadrilateral surface "
+ "meshes are supported in deal.II. You "
+ "tried to read a mesh where a face has " +
+ std::to_string(vertices_per_face) +
+ " vertices per face."));
+
+ CellData<2> c(vertices_per_face);
+ auto it = c.vertices.begin();
+ for (unsigned int i = 0; i < vertices_per_face; ++i)
+ {
+ *(it++) = vertex_map[j->vertex()];
+ ++j;
+ }
+
+ if (vertices_per_face == 4)
+ std::swap(c.vertices[3], c.vertices[2]);
+
+ cells.emplace_back(c);
+ }
+ }
+ else
+ {
+ AssertThrow(false,
+ ExcInternalError(
+ "Unsupported CGAL surface triangulation type."));
+ }
+ triangulation.create_triangulation(vertices, cells, subcell_data);
+ }
# endif
} // namespace CGALWrappers
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+// Convert a closed CGAL::Surface_mesh or a closed CGAL::Polyhedron_3 to a
+// deal.II triangulation. The input mesh is a quad torus.
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_out.h>
+#include <deal.II/grid/tria.h>
+
+#include <CGAL/IO/io.h>
+#include <deal.II/cgal/triangulation.h>
+
+#include <fstream>
+
+#include "../tests.h"
+
+using namespace CGALWrappers;
+using Kernel = CGAL::Simple_cartesian<double>;
+using CGALPoint = CGAL::Point_3<Kernel>;
+using Mesh = CGAL::Surface_mesh<CGALPoint>;
+using Polyhedron = CGAL::Polyhedron_3<Kernel>;
+
+int
+main()
+{
+ initlog();
+ Triangulation<2, 3> tria;
+ GridOut go;
+ {
+ deallog << "Surface mesh" << std::endl;
+ Mesh sm;
+ std::ifstream input_sm(SOURCE_DIR "/input_grids/torus_quad.off");
+ input_sm >> sm;
+ cgal_surface_mesh_to_dealii_triangulation(sm, tria);
+ go.write_msh(tria, deallog.get_file_stream());
+ }
+ tria.clear();
+
+ // Now do the same with a Polyhedron
+ deallog << "Polyhedron test" << std::endl;
+ {
+ Polyhedron P;
+ std::ifstream input_p(SOURCE_DIR "/input_grids/torus_quad.off");
+ input_p >> P;
+ cgal_surface_mesh_to_dealii_triangulation(P, tria);
+ go.write_msh(tria, deallog.get_file_stream());
+ }
+}
--- /dev/null
+
+DEAL::Surface mesh
+$NOD
+25
+1 0.107677 -1.54743e-18 -0.331395
+2 -0.281902 -1.54743e-18 -0.204814
+3 -0.281902 -1.54743e-18 0.204814
+4 0.107676 -1.54743e-18 0.331395
+5 0.348450 -1.54743e-18 8.92032e-08
+6 0.182080 0.331395 -0.560383
+7 -0.476691 0.331395 -0.346336
+8 -0.476691 0.331395 0.346336
+9 0.182080 0.331395 0.560384
+10 0.589223 0.331395 8.92032e-08
+11 0.302466 0.204814 -0.930895
+12 -0.791866 0.204814 -0.575325
+13 -0.791866 0.204814 0.575324
+14 0.302466 0.204814 0.930895
+15 0.978801 0.204814 8.92032e-08
+16 0.302466 -0.204814 -0.930895
+17 -0.791866 -0.204814 -0.575325
+18 -0.791866 -0.204814 0.575324
+19 0.302466 -0.204814 0.930895
+20 0.978801 -0.204814 8.92032e-08
+21 0.182080 -0.331395 -0.560383
+22 -0.476691 -0.331395 -0.346336
+23 -0.476691 -0.331395 0.346336
+24 0.182080 -0.331395 0.560384
+25 0.589222 -0.331395 8.92032e-08
+$ENDNOD
+$ELM
+25
+1 3 0 0 4 6 7 2 1
+2 3 0 0 4 7 8 3 2
+3 3 0 0 4 8 9 4 3
+4 3 0 0 4 9 10 5 4
+5 3 0 0 4 10 6 1 5
+6 3 0 0 4 11 12 7 6
+7 3 0 0 4 12 13 8 7
+8 3 0 0 4 13 14 9 8
+9 3 0 0 4 14 15 10 9
+10 3 0 0 4 15 11 6 10
+11 3 0 0 4 16 17 12 11
+12 3 0 0 4 17 18 13 12
+13 3 0 0 4 18 19 14 13
+14 3 0 0 4 19 20 15 14
+15 3 0 0 4 20 16 11 15
+16 3 0 0 4 21 22 17 16
+17 3 0 0 4 22 23 18 17
+18 3 0 0 4 23 24 19 18
+19 3 0 0 4 24 25 20 19
+20 3 0 0 4 25 21 16 20
+21 3 0 0 4 1 2 22 21
+22 3 0 0 4 2 3 23 22
+23 3 0 0 4 3 4 24 23
+24 3 0 0 4 4 5 25 24
+25 3 0 0 4 5 1 21 25
+$ENDELM
+DEAL::Polyhedron test
+$NOD
+25
+1 0.107677 -1.54743e-18 -0.331395
+2 -0.281902 -1.54743e-18 -0.204814
+3 -0.281902 -1.54743e-18 0.204814
+4 0.107676 -1.54743e-18 0.331395
+5 0.348450 -1.54743e-18 8.92032e-08
+6 0.182080 0.331395 -0.560383
+7 -0.476691 0.331395 -0.346336
+8 -0.476691 0.331395 0.346336
+9 0.182080 0.331395 0.560384
+10 0.589223 0.331395 8.92032e-08
+11 0.302466 0.204814 -0.930895
+12 -0.791866 0.204814 -0.575325
+13 -0.791866 0.204814 0.575324
+14 0.302466 0.204814 0.930895
+15 0.978801 0.204814 8.92032e-08
+16 0.302466 -0.204814 -0.930895
+17 -0.791866 -0.204814 -0.575325
+18 -0.791866 -0.204814 0.575324
+19 0.302466 -0.204814 0.930895
+20 0.978801 -0.204814 8.92032e-08
+21 0.182080 -0.331395 -0.560383
+22 -0.476691 -0.331395 -0.346336
+23 -0.476691 -0.331395 0.346336
+24 0.182080 -0.331395 0.560384
+25 0.589222 -0.331395 8.92032e-08
+$ENDNOD
+$ELM
+25
+1 3 0 0 4 6 7 2 1
+2 3 0 0 4 7 8 3 2
+3 3 0 0 4 8 9 4 3
+4 3 0 0 4 9 10 5 4
+5 3 0 0 4 10 6 1 5
+6 3 0 0 4 11 12 7 6
+7 3 0 0 4 12 13 8 7
+8 3 0 0 4 13 14 9 8
+9 3 0 0 4 14 15 10 9
+10 3 0 0 4 15 11 6 10
+11 3 0 0 4 16 17 12 11
+12 3 0 0 4 17 18 13 12
+13 3 0 0 4 18 19 14 13
+14 3 0 0 4 19 20 15 14
+15 3 0 0 4 20 16 11 15
+16 3 0 0 4 21 22 17 16
+17 3 0 0 4 22 23 18 17
+18 3 0 0 4 23 24 19 18
+19 3 0 0 4 24 25 20 19
+20 3 0 0 4 25 21 16 20
+21 3 0 0 4 1 2 22 21
+22 3 0 0 4 2 3 23 22
+23 3 0 0 4 3 4 24 23
+24 3 0 0 4 4 5 25 24
+25 3 0 0 4 5 1 21 25
+$ENDELM
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+// Convert a closed CGAL::Surface_mesh or a closed CGAL::Polyhedron_3 to a
+// deal.II triangulation. The input mesh is a tripod.
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_out.h>
+#include <deal.II/grid/tria.h>
+
+#include <CGAL/IO/io.h>
+#include <deal.II/cgal/triangulation.h>
+
+#include <fstream>
+
+#include "../tests.h"
+
+using namespace CGALWrappers;
+using Kernel = CGAL::Simple_cartesian<double>;
+using CGALPoint = CGAL::Point_3<Kernel>;
+using Mesh = CGAL::Surface_mesh<CGALPoint>;
+using Polyhedron = CGAL::Polyhedron_3<Kernel>;
+
+int
+main()
+{
+ initlog();
+ Triangulation<2, 3> tria;
+ GridOut go;
+ {
+ deallog << "Surface mesh" << std::endl;
+ Mesh sm;
+ std::ifstream input_sm(SOURCE_DIR "/input_grids/tripod.off");
+ input_sm >> sm;
+ cgal_surface_mesh_to_dealii_triangulation(sm, tria);
+ go.write_msh(tria, deallog.get_file_stream());
+ }
+ tria.clear();
+
+ // Now do the same with a Polyhedron
+ deallog << "Polyhedron test" << std::endl;
+ {
+ Polyhedron P;
+ std::ifstream input_p(SOURCE_DIR "/input_grids/tripod.off");
+ input_p >> P;
+ cgal_surface_mesh_to_dealii_triangulation(P, tria);
+ go.write_msh(tria, deallog.get_file_stream());
+ }
+}
--- /dev/null
+
+DEAL::Surface mesh
+$NOD
+24
+1 -0.462837 0.0205318 -0.140203
+2 -0.174333 0.0412215 -0.151981
+3 -0.144255 0.368209 -0.146404
+4 0.0936504 0.361854 -0.147855
+5 0.141347 0.0412215 -0.151981
+6 0.450915 -0.165801 -0.163699
+7 0.357073 -0.405901 -0.137953
+8 0.141347 -0.274458 -0.151981
+9 -0.174333 -0.274458 -0.151981
+10 -0.461176 -0.217462 -0.108519
+11 -0.450778 -0.0217283 0.159384
+12 -0.174333 0.0412215 0.163699
+13 -0.174333 0.356901 0.163699
+14 0.106877 0.340470 0.155338
+15 0.141347 0.0412215 0.163699
+16 0.452244 -0.184928 0.145632
+17 0.379439 -0.433293 0.144635
+18 0.141347 -0.274458 0.163699
+19 -0.174333 -0.274458 0.163699
+20 -0.413695 -0.363559 0.134658
+21 -0.500000 -0.0816885 0.0513155
+22 -0.0364476 -0.274458 0.0120900
+23 0.500000 -0.344000 -0.0556357
+24 0.00831896 0.433293 0.0305898
+$ENDNOD
+$ELM
+44
+1 2 0 0 3 1 2 10
+2 2 0 0 3 2 5 9
+3 2 0 0 3 2 3 5
+4 2 0 0 3 5 6 8
+5 2 0 0 3 2 1 12
+6 2 0 0 3 3 2 13
+7 2 0 0 3 5 4 15
+8 2 0 0 3 6 5 16
+9 2 0 0 3 8 7 18
+10 2 0 0 3 10 9 20
+11 2 0 0 3 20 19 11
+12 2 0 0 3 19 18 12
+13 2 0 0 3 15 14 12
+14 2 0 0 3 18 17 15
+15 2 0 0 3 9 10 2
+16 2 0 0 3 8 9 5
+17 2 0 0 3 4 5 3
+18 2 0 0 3 7 8 6
+19 2 0 0 3 11 12 1
+20 2 0 0 3 12 13 2
+21 2 0 0 3 14 15 4
+22 2 0 0 3 15 16 5
+23 2 0 0 3 17 18 7
+24 2 0 0 3 19 20 9
+25 2 0 0 3 12 11 19
+26 2 0 0 3 15 12 18
+27 2 0 0 3 13 12 14
+28 2 0 0 3 16 15 17
+29 2 0 0 3 1 21 11
+30 2 0 0 3 10 21 1
+31 2 0 0 3 20 21 10
+32 2 0 0 3 11 21 20
+33 2 0 0 3 8 22 9
+34 2 0 0 3 18 22 8
+35 2 0 0 3 19 22 18
+36 2 0 0 3 9 22 19
+37 2 0 0 3 16 23 6
+38 2 0 0 3 17 23 16
+39 2 0 0 3 7 23 17
+40 2 0 0 3 6 23 7
+41 2 0 0 3 4 24 14
+42 2 0 0 3 3 24 4
+43 2 0 0 3 13 24 3
+44 2 0 0 3 14 24 13
+$ENDELM
+DEAL::Polyhedron test
+$NOD
+24
+1 -0.462837 0.0205318 -0.140203
+2 -0.174333 0.0412215 -0.151981
+3 -0.144255 0.368209 -0.146404
+4 0.0936504 0.361854 -0.147855
+5 0.141347 0.0412215 -0.151981
+6 0.450915 -0.165801 -0.163699
+7 0.357073 -0.405901 -0.137953
+8 0.141347 -0.274458 -0.151981
+9 -0.174333 -0.274458 -0.151981
+10 -0.461176 -0.217462 -0.108519
+11 -0.450778 -0.0217283 0.159384
+12 -0.174333 0.0412215 0.163699
+13 -0.174333 0.356901 0.163699
+14 0.106877 0.340470 0.155338
+15 0.141347 0.0412215 0.163699
+16 0.452244 -0.184928 0.145632
+17 0.379439 -0.433293 0.144635
+18 0.141347 -0.274458 0.163699
+19 -0.174333 -0.274458 0.163699
+20 -0.413695 -0.363559 0.134658
+21 -0.500000 -0.0816885 0.0513155
+22 -0.0364476 -0.274458 0.0120900
+23 0.500000 -0.344000 -0.0556357
+24 0.00831896 0.433293 0.0305898
+$ENDNOD
+$ELM
+44
+1 2 0 0 3 1 2 10
+2 2 0 0 3 2 5 9
+3 2 0 0 3 2 3 5
+4 2 0 0 3 5 6 8
+5 2 0 0 3 2 1 12
+6 2 0 0 3 3 2 13
+7 2 0 0 3 5 4 15
+8 2 0 0 3 6 5 16
+9 2 0 0 3 8 7 18
+10 2 0 0 3 10 9 20
+11 2 0 0 3 20 19 11
+12 2 0 0 3 19 18 12
+13 2 0 0 3 15 14 12
+14 2 0 0 3 18 17 15
+15 2 0 0 3 9 10 2
+16 2 0 0 3 8 9 5
+17 2 0 0 3 4 5 3
+18 2 0 0 3 7 8 6
+19 2 0 0 3 11 12 1
+20 2 0 0 3 12 13 2
+21 2 0 0 3 14 15 4
+22 2 0 0 3 15 16 5
+23 2 0 0 3 17 18 7
+24 2 0 0 3 19 20 9
+25 2 0 0 3 12 11 19
+26 2 0 0 3 15 12 18
+27 2 0 0 3 13 12 14
+28 2 0 0 3 16 15 17
+29 2 0 0 3 1 21 11
+30 2 0 0 3 10 21 1
+31 2 0 0 3 20 21 10
+32 2 0 0 3 11 21 20
+33 2 0 0 3 8 22 9
+34 2 0 0 3 18 22 8
+35 2 0 0 3 19 22 18
+36 2 0 0 3 9 22 19
+37 2 0 0 3 16 23 6
+38 2 0 0 3 17 23 16
+39 2 0 0 3 7 23 17
+40 2 0 0 3 6 23 7
+41 2 0 0 3 4 24 14
+42 2 0 0 3 3 24 4
+43 2 0 0 3 13 24 3
+44 2 0 0 3 14 24 13
+$ENDELM
--- /dev/null
+OFF
+25 25 50
+0.107677 -1.54743e-018 -0.331395
+-0.281902 -1.54743e-018 -0.204814
+-0.281902 -1.54743e-018 0.204814
+0.107676 -1.54743e-018 0.331395
+0.34845 -1.54743e-018 8.92032e-008
+0.18208 0.331395 -0.560383
+-0.476691 0.331395 -0.346336
+-0.476691 0.331395 0.346336
+0.18208 0.331395 0.560384
+0.589223 0.331395 8.92032e-008
+0.302466 0.204814 -0.930895
+-0.791866 0.204814 -0.575325
+-0.791866 0.204814 0.575324
+0.302466 0.204814 0.930895
+0.978801 0.204814 8.92032e-008
+0.302466 -0.204814 -0.930895
+-0.791866 -0.204814 -0.575325
+-0.791866 -0.204814 0.575324
+0.302466 -0.204814 0.930895
+0.978801 -0.204814 8.92032e-008
+0.18208 -0.331395 -0.560383
+-0.476691 -0.331395 -0.346336
+-0.476691 -0.331395 0.346336
+0.18208 -0.331395 0.560384
+0.589222 -0.331395 8.92032e-008
+4 5 6 1 0
+4 6 7 2 1
+4 7 8 3 2
+4 8 9 4 3
+4 9 5 0 4
+4 10 11 6 5
+4 11 12 7 6
+4 12 13 8 7
+4 13 14 9 8
+4 14 10 5 9
+4 15 16 11 10
+4 16 17 12 11
+4 17 18 13 12
+4 18 19 14 13
+4 19 15 10 14
+4 20 21 16 15
+4 21 22 17 16
+4 22 23 18 17
+4 23 24 19 18
+4 24 20 15 19
+4 0 1 21 20
+4 1 2 22 21
+4 2 3 23 22
+4 3 4 24 23
+4 4 0 20 24
--- /dev/null
+OFF
+24 44 0
+
+-0.462837 0.0205318 -0.140203
+-0.174333 0.0412215 -0.151981
+-0.144255 0.368209 -0.146404
+0.0936504 0.361854 -0.147855
+0.141347 0.0412215 -0.151981
+0.450915 -0.165801 -0.163699
+0.357073 -0.405901 -0.137953
+0.141347 -0.274458 -0.151981
+-0.174333 -0.274458 -0.151981
+-0.461176 -0.217462 -0.108519
+-0.450778 -0.0217283 0.159384
+-0.174333 0.0412215 0.163699
+-0.174333 0.356901 0.163699
+0.106877 0.34047 0.155338
+0.141347 0.0412215 0.163699
+0.452244 -0.184928 0.145632
+0.379439 -0.433293 0.144635
+0.141347 -0.274458 0.163699
+-0.174333 -0.274458 0.163699
+-0.413695 -0.363559 0.134658
+-0.5 -0.0816885 0.0513155
+-0.0364476 -0.274458 0.01209
+0.5 -0.344 -0.0556357
+0.00831896 0.433293 0.0305898
+3 0 1 9
+3 1 4 8
+3 1 2 4
+3 4 5 7
+3 1 0 11
+3 2 1 12
+3 4 3 14
+3 5 4 15
+3 7 6 17
+3 9 8 19
+3 19 18 10
+3 18 17 11
+3 14 13 11
+3 17 16 14
+3 8 9 1
+3 7 8 4
+3 3 4 2
+3 6 7 5
+3 10 11 0
+3 11 12 1
+3 13 14 3
+3 14 15 4
+3 16 17 6
+3 18 19 8
+3 11 10 18
+3 14 11 17
+3 12 11 13
+3 15 14 16
+3 0 20 10
+3 9 20 0
+3 19 20 9
+3 10 20 19
+3 7 21 8
+3 17 21 7
+3 18 21 17
+3 8 21 18
+3 15 22 5
+3 16 22 15
+3 6 22 16
+3 5 22 6
+3 3 23 13
+3 2 23 3
+3 12 23 2
+3 13 23 12
+