89{
90 if (argc < 2) {
91 std::printf("usage: texture_unwrap_dump <project.3mf>\n");
92 return 2;
93 }
94
99 std::vector<Preset *> project_presets;
100 bool is_bbl_3mf = false, is_orca_3mf = false;
102
103 const boost::filesystem::path tmp = boost::filesystem::temp_directory_path() / "texture_unwrap_dump";
104 boost::filesystem::create_directories(tmp);
106
107
108
109 if (!
load_bbs_3mf(argv[1], &config, &ctx, &model, &plate_data, &project_presets, &is_bbl_3mf, &is_orca_3mf,
110 &file_version, nullptr,
111 LoadStrategy::LoadModel | LoadStrategy::LoadConfig | LoadStrategy::AddDefaultInstances |
112 LoadStrategy::Silence)) {
113 std::printf("failed to load %s\n", argv[1]);
114 return 1;
115 }
116
117 std::printf(
"loaded: %zu object(s)\n", model.
objects.size());
118
122 std::printf("volume \"%s\": no texture displacement layers; paint masks per slot:",
123 volume->
name.c_str());
126 std::printf("\n");
127 continue;
128 }
129 std::printf(
"volume \"%s\": %zu base triangles, %zu layer(s)\n", volume->
name.c_str(),
131
133 std::printf("\n layer %d \"%s\" mapping=%d seam_angle=%.1f connect=%d islands_stored=%zu\n",
137 continue;
138
139 const indexed_triangle_set patch =
141 std::printf(" patch: %zu vertices, %zu triangles\n", patch.vertices.size(), patch.indices.size());
142 if (patch.indices.empty())
143 continue;
144
145 const auto t0 = std::chrono::steady_clock::now();
148 const auto t1 = std::chrono::steady_clock::now();
149 std::printf(" TIMING compute_patch_unwrap: %.0f ms\n",
150 std::chrono::duration<double, std::milli>(t1 - t0).
count());
151 std::printf(
" unwrap: %d charts, %zu unwrapped triangles\n", unwrap.
chart_count,
153
154
155 std::vector<std::vector<int>> chart_faces(
size_t(std::max(unwrap.
chart_count, 0)));
156 for (
size_t i = 0; i < unwrap.
indices.size(); ++i) {
158 if (chart >= 0 && size_t(chart) < chart_faces.size())
159 chart_faces[size_t(chart)].push_back(unwrap.
source_face[i]);
160 }
161
162 int bad_charts = 0;
163 for (size_t c = 0; c < chart_faces.size(); ++c) {
164 int loops = 0, euler = 0;
166
167
168
169 int pos = 0, neg = 0;
170 for (
size_t i = 0; i < unwrap.
indices.size(); ++i) {
171 const stl_triangle_vertex_indices &t = unwrap.
indices[i];
173 continue;
175 unwrap.
uvs[
size_t(t[2])]);
176 if (a > 0.f) ++
pos;
else if (a < 0.f) ++neg;
177 }
178 const int flipped = std::min(pos, neg);
179 const bool disk = loops == 1 && euler == 1;
180 if (!disk || flipped > 0) {
181 ++bad_charts;
182 std::printf(" chart %2zu: %4zu faces loops=%d euler=%d%s flipped=%d/%d%s\n", c,
183 chart_faces[c].size(), loops, euler, disk ? "" : " NOT A DISK", flipped,
184 pos + neg, flipped ? " FOLDED" : "");
185 }
186 }
187 std::printf(
" charts with a defect: %d / %d\n", bad_charts, unwrap.
chart_count);
188
189
190
191
192
193 {
194 const auto n0 = std::chrono::steady_clock::now();
196 const auto n1 = std::chrono::steady_clock::now();
197 std::printf(" TIMING compute_connected_net: %.0f ms (%zu islands)\n",
198 std::chrono::duration<double, std::milli>(n1 - n0).
count(),
net.size());
199 }
200 const auto t2 = std::chrono::steady_clock::now();
202 const auto t3 = std::chrono::steady_clock::now();
203 std::printf(" TIMING compute_lscm_uvs: %.0f ms (called on every preview, overlay and bake)\n",
204 std::chrono::duration<double, std::milli>(t3 - t2).
count());
205 if (uv.size() != patch.vertices.size()) {
206 std::printf(" compute_lscm_uvs returned %zu uvs for %zu vertices\n", uv.size(),
207 patch.vertices.size());
208 continue;
209 }
210
211
212
213 const auto t4 = std::chrono::steady_clock::now();
215 const auto t5 = std::chrono::steady_clock::now();
216 std::printf(" TIMING compute_lscm_corner_uvs: %.0f ms\n",
217 std::chrono::duration<double, std::milli>(t5 - t4).
count());
218
219
220
221
222 std::unordered_map<uint64_t, std::vector<Vec2f>> edge_seen;
223 if (corner.size() == patch.indices.size() * 3)
224 for (
size_t f = 0;
f < patch.indices.size(); ++
f) {
225 const stl_triangle_vertex_indices &t = patch.indices[
f];
226 for (int k = 0; k < 3; ++k) {
227 const int a = t[k], b = t[(k + 1) % 3];
228 const int probe = std::min(a, b);
229 const int local = (a == probe) ? k : (k + 1) % 3;
230 edge_seen[
edge_key(a, b)].push_back(corner[
f * 3 +
size_t(local)]);
231 }
232 }
233
234 std::vector<int> chart_of_face(patch.indices.size(), -1);
235 for (
size_t i = 0; i < unwrap.
indices.size(); ++i)
237
238 std::unordered_map<uint64_t, std::vector<int>> edge_faces;
239 for (
size_t f = 0;
f < patch.indices.size(); ++
f) {
240 const stl_triangle_vertex_indices &t = patch.indices[
f];
241 for (int k = 0; k < 3; ++k)
242 edge_faces[
edge_key(t[k], t[(k + 1) % 3])].push_back(
int(
f));
243 }
244
245 int adjacent = 0, broken = 0, broken_same_chart = 0;
246 float worst = 0.f;
247 std::map<std::pair<int, int>, std::pair<int, float>> by_pair;
248 for (const auto &[key, seen] : edge_seen) {
249 if (seen.size() != 2)
250 continue;
251 ++adjacent;
252 const float d = (seen[0] - seen[1]).norm();
253 if (d <= 1e-4f)
254 continue;
255 ++broken;
256 worst = std::max(worst, d);
257 const auto &faces_here = edge_faces[key];
258 int c1 = -1, c2 = -1;
259 if (faces_here.size() == 2) {
260 c1 = chart_of_face[size_t(faces_here[0])];
261 c2 = chart_of_face[size_t(faces_here[1])];
262 }
263 if (c1 == c2)
264 ++broken_same_chart;
265 auto &slot = by_pair[{ std::min(c1, c2), std::max(c1, c2) }];
266 ++slot.first;
267 slot.second = std::max(slot.second, d);
268 }
269 std::printf(" broken edges inside a single chart: %d\n", broken_same_chart);
270 std::printf(" broken by chart pair:");
271 for (const auto &[pk, v] : by_pair)
272 std::printf(" (%d,%d)x%d/%.1f", pk.first, pk.second, v.first, v.second);
273 std::printf("\n");
274
275
276
277 float seam_mm = 0.f;
278 for (const auto &[key, seen] : edge_seen) {
279 if (seen.size() != 2 || (seen[0] - seen[1]).norm() <= 1e-4f)
280 continue;
281 seam_mm += (patch.vertices[size_t(key >> 32)] - patch.vertices[size_t(uint32_t(key))]).norm();
282 }
283 std::printf(" interior edges: %d, discontinuous: %d, total torn seam: %.2f mm (worst jump %.3f)\n",
284 adjacent, broken, seam_mm, worst);
285 std::printf(
" stored islands %zu vs charts %d -> %s\n", layer.
islands.size(),
288 : "net rebuilt");
289 }
290 }
291 return 0;
292}
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
Definition PrintConfig.hpp:915
const TriangleSelector::TriangleSplittingData & get_data() const noexcept
Definition Model.hpp:763
ModelVolumePtrs volumes
Definition Model.hpp:393
const TriangleMesh & mesh() const
Definition Model.hpp:892
FacetsAnnotation & texture_displacement_facet(int slot)
Definition Model.hpp:937
std::vector< TextureDisplacementLayer > texture_displacement_layers
Definition Model.hpp:974
std::string name
Definition Model.hpp:834
Definition Model.hpp:1696
ModelObjectPtrs objects
Definition Model.hpp:1702
indexed_triangle_set its
Definition TriangleMesh.hpp:164
@ local
Definition Time.hpp:13
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16
std::vector< PlateData * > PlateDataPtrs
Definition bbs_3mf.hpp:278
void set_data_dir(const std::string &dir)
Definition utils.cpp:353
PatchUnwrap compute_patch_unwrap(const indexed_triangle_set &patch, float seam_angle_deg, float padding_mm, const std::vector< std::pair< int, int > > &seam_edges)
Definition TextureDisplacement.cpp:1230
std::vector< Vec2f > compute_lscm_uvs(const indexed_triangle_set &patch, const TextureDisplacementLayer &layer)
Definition TextureDisplacement.cpp:1993
std::vector< TextureIsland > compute_connected_net(const PatchUnwrap &unwrap)
Definition TextureDisplacement.cpp:1673
static constexpr size_t TEXTURE_DISPLACEMENT_MAX_LAYERS
Definition TextureDisplacement.hpp:44
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:124
indexed_triangle_set extract_painted_patch(const indexed_triangle_set &base_mesh, const TriangleSelector::TriangleSplittingData &facet_data)
Definition TextureDisplacement.cpp:2457
std::vector< Vec2f > compute_lscm_corner_uvs(const indexed_triangle_set &patch, const TextureDisplacementLayer &layer)
Definition TextureDisplacement.cpp:2024
bool load_bbs_3mf(const char *path, DynamicPrintConfig *config, ConfigSubstitutionContext *config_substitutions, Model *model, PlateDataPtrs *plate_data_list, std::vector< Preset * > *project_presets, bool *is_bbl_3mf, bool *is_orca_3mf, Semver *file_version, Import3mfProgressFn proFn, LoadStrategy strategy, BBLProject *project, int plate_id)
Definition bbs_3mf.cpp:9569
float signed_area_2d(const Vec2f &a, const Vec2f &b, const Vec2f &c)
Definition texture_unwrap_dump.cpp:81
void chart_topology(const indexed_triangle_set &mesh, const std::vector< int > &faces, int &loops, int &euler)
Definition texture_unwrap_dump.cpp:46
uint64_t edge_key(int a, int b)
Definition texture_unwrap_dump.cpp:37
Definition BonjourDialog.hpp:16
Definition Config.hpp:274
Definition TextureDisplacement.hpp:771
std::vector< stl_triangle_vertex_indices > indices
Definition TextureDisplacement.hpp:779
std::vector< Vec2f > uvs
Definition TextureDisplacement.hpp:772
std::vector< int > vertex_chart
Definition TextureDisplacement.hpp:774
int chart_count
Definition TextureDisplacement.hpp:786
std::vector< int > source_face
Definition TextureDisplacement.hpp:780
Definition TextureDisplacement.hpp:210
int slot
Definition TextureDisplacement.hpp:214
std::vector< TextureIsland > islands
Definition TextureDisplacement.hpp:308
std::vector< std::pair< int, int > > lscm_seam_edges
Definition TextureDisplacement.hpp:280
float lscm_seam_angle_deg
Definition TextureDisplacement.hpp:271
TextureProjectionMethod projection_method
Definition TextureDisplacement.hpp:269
bool auto_connect_islands
Definition TextureDisplacement.hpp:262
std::string name
Definition TextureDisplacement.hpp:216
std::vector< TriangleBitStreamMapping > triangles_to_split
Definition TriangleSelector.hpp:289