SemiDiscreteOT 1.0
Semi-Discrete Optimal Transport Library
Loading...
Searching...
No Matches
PowerDiagramGeogram.cc
Go to the documentation of this file.
3#include <geogram/mesh/mesh.h>
4#include <geogram/mesh/mesh_AABB.h>
5#include <geogram/mesh/mesh_io.h>
6#include <geogram/delaunay/delaunay.h>
7#include <geogram/voronoi/RVD.h>
8#include <geogram/basic/command_line.h>
9#include <geogram/basic/command_line_args.h>
10#include <geogram/mesh/mesh_tetrahedralize.h>
11#include <filesystem>
12
13namespace PowerDiagramSpace {
14
15template <int dim, int spacedim>
17 : source_mesh(std::make_unique<GEO::Mesh>()),
18 dimension_voronoi(dim + 1),
19 RVD_mesh(std::make_unique<GEO::Mesh>())
20{
21 GEO::initialize();
22 using namespace GEO;
23
24 CmdLine::import_arg_group("standard");
25 CmdLine::import_arg_group("algo");
26 CmdLine::import_arg_group("opt");
27 CmdLine::declare_arg("nb_iter", 1000, "number of iterations for OTM");
28
29 CmdLine::declare_arg_group(
30 "RVD", "RVD output options", CmdLine::ARG_ADVANCED);
31 CmdLine::declare_arg("RVD", false, "save restricted Voronoi diagram");
32 CmdLine::declare_arg(
33 "RVD_iter", false, "save restricted Voronoi diagram at each iteration");
34 CmdLine::declare_arg(
35 "RVD:borders_only", false, "save only border of RVD");
36 CmdLine::declare_arg(
37 "RVD:integration_simplices", true, "export RVD as integration simplices");
38
39 CmdLine::declare_arg("multilevel", true, "use multilevel algorithm");
40 CmdLine::declare_arg("BRIO", true,
41 "use BRIO reordering to compute the levels");
42 CmdLine::declare_arg("ratio", 0.125, "ratio between levels");
43 CmdLine::declare_arg("epsilon", 0.01, "relative measure error in a cell");
44 CmdLine::declare_arg(
45 "lock", true, "Lock lower levels when sampling shape");
46 CmdLine::declare_arg(
47 "fitting_degree", 2, "degree for interpolating weights");
48 CmdLine::declare_arg(
49 "project", true, "project sampling on border");
50 CmdLine::declare_arg(
51 "feature_sensitive", true, "attempt to recover hard edges");
52 CmdLine::declare_arg(
53 "singular", false, "compute and save singular surface");
54 CmdLine::set_arg("algo:delaunay", "BPOW");
55 CmdLine::declare_arg(
56 "recenter", true, "recenter target onto source mesh");
57 CmdLine::declare_arg(
58 "rescale", true, "rescale target to match source volume");
59
60 if (!load_volume_mesh(source_mesh_file, *source_mesh)) {
61 throw std::runtime_error("Failed to load source mesh: " + source_mesh_file);
62 }
63
64 source_mesh->vertices.set_dimension(dimension_voronoi);
65}
66template <int dim, int spacedim>
68
69template <int dim, int spacedim>
71 const std::vector<Point<spacedim>> &points,
72 const Vector<double> &potentials)
73{
74 this->generator_points = points;
75 this->generator_potentials.resize(potentials.size());
76 for (unsigned int i = 0; i < potentials.size(); ++i) {
77 this->generator_potentials[i] = potentials[i];
78 }
79
80 // Convert points to Geogram format
81 points_mesh_target.clear();
82 points_mesh_target.reserve(points.size() * dim);
83 for (const auto& point : points) {
84 for (unsigned int d = 0; d < dim; ++d) {
85 points_mesh_target.push_back(point[d]);
86 }
87 }
88
89 init_power_diagram();
90}
91
92template <int dim, int spacedim>
94{
95 const size_t nb_points = this->generator_points.size();
96
97 // Initialize lifted points (dimension + 1)
98 points_mesh_target_lifted.resize(nb_points * dimension_voronoi);
99
100 // Copy first dim coordinates
101 for (size_t i = 0; i < nb_points; ++i) {
102 for (int d = 0; d < dim; ++d) {
103 points_mesh_target_lifted[i * dimension_voronoi + d] =
104 points_mesh_target[i * dim + d];
105 }
106 }
107
108 // Compute lifting coordinate based on potentials
109 double W = 0.0;
110 for (size_t i = 0; i < nb_points; ++i) {
111 W = std::max(W, this->generator_potentials[i]);
112 }
113
114 for (size_t i = 0; i < nb_points; ++i) {
115 points_mesh_target_lifted[dimension_voronoi * i + dim] =
116 ::sqrt(W - this->generator_potentials[i]);
117 }
118
119 // Create Delaunay triangulation
120 delaunay = GEO::Delaunay::create(GEO::coord_index_t(dimension_voronoi), "BPOW");
121
122 // Create Restricted Voronoi Diagram
123 RVD = GEO::RestrictedVoronoiDiagram::create(delaunay, source_mesh.get());
124
125 RVD->set_volumetric(true);
126 RVD->set_check_SR(true);
127 RVD->create_threads();
128}
129
130template <int dim, int spacedim>
132{
133 if (!delaunay || !RVD) {
134 throw std::runtime_error("Power diagram not initialized. Call set_generators first.");
135 }
136
137 delaunay->set_vertices(
138 this->generator_points.size(),
139 points_mesh_target_lifted.data()
140 );
141
142 RVD->compute_RVD(
143 *RVD_mesh,
144 0,
145 false, // cells_borders_only
146 true // integration_simplices
147 );
148
149 if (save_RVD) {
150 GEO::mesh_save(*RVD_mesh, "RVD.meshb");
151 }
152}
153
154template <int dim, int spacedim>
156{
157 if (!RVD_mesh) {
158 throw std::runtime_error("Power diagram not computed. Call compute_power_diagram first.");
159 }
160
161 GEO::Attribute<GEO::index_t> tet_region(RVD_mesh->cells.attributes(), "region");
162
163 const size_t nb_vertices = RVD->delaunay()->nb_vertices();
164 std::vector<GEO::vec3> centroids(nb_vertices, GEO::vec3(0.0, 0.0, 0.0));
165 std::vector<double> volumes(nb_vertices, 0.0);
166
167 // Compute weighted centroids
168 std::cout << "Computing centroids..." << std::endl;
169 for (GEO::index_t t = 0; t < RVD_mesh->cells.nb(); ++t) {
170 const GEO::index_t v = tet_region[t];
171 const GEO::index_t v0 = RVD_mesh->cells.tet_vertex(t, 0);
172 const GEO::index_t v1 = RVD_mesh->cells.tet_vertex(t, 1);
173 const GEO::index_t v2 = RVD_mesh->cells.tet_vertex(t, 2);
174 const GEO::index_t v3 = RVD_mesh->cells.tet_vertex(t, 3);
175
176 GEO::vec3 p0(RVD_mesh->vertices.point_ptr(v0));
177 GEO::vec3 p1(RVD_mesh->vertices.point_ptr(v1));
178 GEO::vec3 p2(RVD_mesh->vertices.point_ptr(v2));
179 GEO::vec3 p3(RVD_mesh->vertices.point_ptr(v3));
180
181 const double volume = GEO::Geom::tetra_signed_volume(p0, p1, p2, p3);
182 centroids[v] += (volume / 4.0) * (p0 + p1 + p2 + p3);
183 volumes[v] += volume;
184 }
185
186 // Normalize centroids and convert to Deal.II format
187 this->cell_centroids.clear();
188 for (size_t v = 0; v < nb_vertices; ++v) {
189 if (volumes[v] != 0.0) {
190 const double s = 1.0 / ::fabs(volumes[v]);
191 const GEO::vec3& c = centroids[v] * s;
192 this->cell_centroids.push_back(Point<spacedim>(c.x, c.y, c.z));
193 }
194 }
195}
196
197template <int dim, int spacedim>
198void GeogramPowerDiagram<dim, spacedim>::output_vtu(const std::string& /*filename*/) const
199{
200 // For now, we'll just save the RVD mesh if save_RVD is true
201 // TODO: Implement proper VTU output if needed
202}
203
204template <int dim, int spacedim>
206{
207 Utils::write_vector(this->cell_centroids, filename, "txt");
208}
209
210template <int dim, int spacedim>
211const std::vector<Point<spacedim>>& GeogramPowerDiagram<dim, spacedim>::get_cell_centroids() const
212{
213 return this->cell_centroids;
214}
215
216template <int dim, int spacedim>
217bool GeogramPowerDiagram<dim, spacedim>::load_volume_mesh(const std::string& filename, GEO::Mesh& mesh)
218{
219 GEO::MeshIOFlags flags;
220 flags.set_element(GEO::MESH_CELLS);
221 flags.set_attribute(GEO::MESH_CELL_REGION);
222
223 if (!GEO::mesh_load(filename, mesh, flags)) {
224 return false;
225 }
226
227 if (!mesh.cells.are_simplices()) {
228 std::cerr << "File " << filename
229 << " should only have tetrahedra" << std::endl;
230 return false;
231 }
232
233 if (mesh.cells.nb() == 0) {
234 std::cout << "File " << filename
235 << " does not contain a volume" << std::endl;
236 std::cout << "Trying to tetrahedralize..." << std::endl;
237 if (!GEO::mesh_tetrahedralize(mesh, true, false)) {
238 return false;
239 }
240 }
241 return true;
242}
243
244template class GeogramPowerDiagram<3, 3>;
245}
A class for computing power diagrams using Geogram.
void output_vtu(const std::string &filename) const override
Outputs the power diagram to a VTU file.
const std::vector< Point< spacedim > > & get_cell_centroids() const override
Returns the centroids of the power cells.
void compute_cell_centroids() override
Computes the centroids of the power cells.
GeogramPowerDiagram(const std::string &source_mesh_file)
Constructor for the GeogramPowerDiagram class.
void compute_power_diagram() override
Computes the power diagram.
void set_generators(const std::vector< Point< spacedim > > &points, const Vector< double > &potentials) override
Sets the generator points and their potentials.
void save_centroids_to_file(const std::string &filename) const override
Saves the centroids of the power cells to a file.
std::unique_ptr< GEO::Mesh > source_mesh
The source mesh.
bool load_volume_mesh(const std::string &filename, GEO::Mesh &mesh)
int dimension_voronoi
The dimension of the Voronoi diagram.
void write_vector(const VectorContainer &points, const std::string &filepath, const std::string &fileMode="txt")
Write a vector container to a file in binary or text format.
Definition utils.h:56