Blender V4.3
pbvh_uv_islands.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_map.hh"
6#include "BLI_math_geom.h"
7#include "BLI_math_matrix.hh"
8#include "BLI_math_vector.h"
9#include "BLI_ordered_edge.hh"
10
11#include "pbvh_uv_islands.hh"
12
13#include <iostream>
14#include <optional>
15#include <sstream>
16
18
20{
21 for (UVVertex *vertex : uv_edge.vertices) {
22 vertex->uv_edges.append_non_duplicates(&uv_edge);
23 }
24}
25
27{
28 for (UVEdge *uv_edge : uv_primitive.edges) {
29 uv_edge->uv_primitives.append_non_duplicates(&uv_primitive);
30 }
31}
32
34{
35 for (UVEdge *uv_edge : uv_primitive.edges) {
37 }
38}
39
40/* -------------------------------------------------------------------- */
44static int primitive_get_other_uv_vertex(const MeshData &mesh_data,
45 const int3 &tri,
46 const int v1,
47 const int v2)
48{
49 const Span<int> corner_verts = mesh_data.corner_verts;
50 BLI_assert(ELEM(v1, corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]));
51 BLI_assert(ELEM(v2, corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]));
52 for (const int loop : {tri[0], tri[1], tri[2]}) {
53 const int vert = corner_verts[loop];
54 if (!ELEM(vert, v1, v2)) {
55 return vert;
56 }
57 }
58 return -1;
59}
60
62 const int3 &tri,
63 const int3 &tri_other)
64{
65 int shared_uv_verts = 0;
66 for (const int loop : {tri[0], tri[1], tri[2]}) {
67 for (const int other_loop : {tri_other[0], tri_other[1], tri_other[2]}) {
68 if (uv_map[loop] == uv_map[other_loop]) {
69 shared_uv_verts += 1;
70 }
71 }
72 }
73 return shared_uv_verts >= 2;
74}
75
76static int get_uv_loop(const MeshData &mesh_data, const int3 &tri, const int vert)
77{
78 for (const int loop : {tri[0], tri[1], tri[2]}) {
79 if (mesh_data.corner_verts[loop] == vert) {
80 return loop;
81 }
82 }
84 return tri[0];
85}
86
87static rctf primitive_uv_bounds(const int3 &tri, const Span<float2> uv_map)
88{
90 BLI_rctf_init_minmax(&result);
91 for (const int loop : {tri[0], tri[1], tri[2]}) {
92 BLI_rctf_do_minmax_v(&result, uv_map[loop]);
93 }
94 return result;
95}
96
99/* -------------------------------------------------------------------- */
103static void mesh_data_init_edges(MeshData &mesh_data)
104{
105 mesh_data.edges.reserve(mesh_data.corner_tris.size() * 2);
107 eh.reserve(mesh_data.corner_tris.size() * 3);
108 for (int64_t i = 0; i < mesh_data.corner_tris.size(); i++) {
109 const int3 &tri = mesh_data.corner_tris[i];
110 Vector<int, 3> edges;
111 for (int j = 0; j < 3; j++) {
112 int v1 = mesh_data.corner_verts[tri[j]];
113 int v2 = mesh_data.corner_verts[tri[(j + 1) % 3]];
114
115 int64_t edge_index;
116 eh.add_or_modify(
117 {v1, v2},
118 [&](int *value) {
119 edge_index = mesh_data.edges.size();
120 *value = edge_index + 1;
121 mesh_data.edges.append({v1, v2});
122 mesh_data.vert_to_edge_map.add(edge_index, v1, v2);
123 },
124 [&](int *value) {
125 edge_index = *value - 1;
126 *value = edge_index;
127 });
128
129 edges.append(edge_index);
130 }
131 mesh_data.primitive_to_edge_map.add(edges, i);
132 }
133 /* Build edge to neighboring triangle map. */
134 mesh_data.edge_to_primitive_map = EdgeToPrimitiveMap(mesh_data.edges.size());
135 for (const int prim_i : mesh_data.corner_tris.index_range()) {
136 for (const int edge_i : mesh_data.primitive_to_edge_map[prim_i]) {
137 mesh_data.edge_to_primitive_map.add(prim_i, edge_i);
138 }
139 }
140}
141static constexpr int INVALID_UV_ISLAND_ID = -1;
146static void extract_uv_neighbors(const MeshData &mesh_data,
147 const Span<int> uv_island_ids,
148 const int primitive_i,
149 Vector<int> &prims_to_add)
150{
151 for (const int edge : mesh_data.primitive_to_edge_map[primitive_i]) {
152 for (const int other_primitive_i : mesh_data.edge_to_primitive_map[edge]) {
153 if (primitive_i == other_primitive_i) {
154 continue;
155 }
156 if (uv_island_ids[other_primitive_i] != INVALID_UV_ISLAND_ID) {
157 continue;
158 }
159
161 mesh_data.corner_tris[primitive_i],
162 mesh_data.corner_tris[other_primitive_i]))
163 {
164 prims_to_add.append(other_primitive_i);
165 }
166 }
167 }
168}
169
171{
172 mesh_data.uv_island_ids.reinitialize(mesh_data.corner_tris.size());
174
175 int uv_island_id = 0;
176 Vector<int> prims_to_add;
177 for (const int primitive_i : mesh_data.corner_tris.index_range()) {
178 /* Early exit when uv island id is already extracted during uv neighbor extractions. */
179 if (mesh_data.uv_island_ids[primitive_i] != INVALID_UV_ISLAND_ID) {
180 continue;
181 }
182
183 prims_to_add.append(primitive_i);
184 while (!prims_to_add.is_empty()) {
185 const int other_primitive_i = prims_to_add.pop_last();
186 mesh_data.uv_island_ids[other_primitive_i] = uv_island_id;
187 extract_uv_neighbors(mesh_data, mesh_data.uv_island_ids, other_primitive_i, prims_to_add);
188 }
189 uv_island_id++;
190 }
191
192 return uv_island_id;
193}
194
195static void mesh_data_init(MeshData &mesh_data)
196{
197 mesh_data_init_edges(mesh_data);
199}
200
202 const Span<int3> corner_tris,
203 const Span<int> corner_verts,
204 const Span<float2> uv_map,
205 const Span<float3> vert_positions)
206 : faces(faces),
207 corner_tris(corner_tris),
208 corner_verts(corner_verts),
209 uv_map(uv_map),
210 vert_positions(vert_positions),
211 vert_to_edge_map(vert_positions.size()),
212 edge_to_primitive_map(0),
213 primitive_to_edge_map(corner_tris.size())
214{
215 mesh_data_init(*this);
216}
217
220/* -------------------------------------------------------------------- */
224static void uv_vertex_init_flags(UVVertex &uv_vertex)
225{
226 uv_vertex.flags.is_border = false;
227 uv_vertex.flags.is_extended = false;
228}
229
234
235UVVertex::UVVertex(const MeshData &mesh_data, const int loop)
236 : vertex(mesh_data.corner_verts[loop]), uv(mesh_data.uv_map[loop])
237{
239}
240
246{
247 Vector<int> primitives_around_uv_vertex;
248 for (const UVEdge *uv_edge : uv_vertex.uv_edges) {
249 for (const UVPrimitive *uv_primitive : uv_edge->uv_primitives) {
250 primitives_around_uv_vertex.append_non_duplicates(uv_primitive->primitive_i);
251 }
252 }
253 return primitives_around_uv_vertex;
254}
255
258/* -------------------------------------------------------------------- */
262bool UVEdge::has_shared_edge(const Span<float2> uv_map, const int loop_1, const int loop_2) const
263{
264 return (vertices[0]->uv == uv_map[loop_1] && vertices[1]->uv == uv_map[loop_2]) ||
265 (vertices[0]->uv == uv_map[loop_2] && vertices[1]->uv == uv_map[loop_1]);
266}
267
268bool UVEdge::has_shared_edge(const UVVertex &v1, const UVVertex &v2) const
269{
270 return (vertices[0]->uv == v1.uv && vertices[1]->uv == v2.uv) ||
271 (vertices[0]->uv == v2.uv && vertices[1]->uv == v1.uv);
272}
273
274bool UVEdge::has_shared_edge(const UVEdge &other) const
275{
276 return has_shared_edge(*other.vertices[0], *other.vertices[1]);
277}
278
279bool UVEdge::has_same_vertices(const int vert1, const int vert2) const
280{
281 return (vertices[0]->vertex == vert1 && vertices[1]->vertex == vert2) ||
282 (vertices[0]->vertex == vert2 && vertices[1]->vertex == vert1);
283}
284
285bool UVEdge::has_same_uv_vertices(const UVEdge &other) const
286{
287 return has_shared_edge(other) &&
288 has_same_vertices(other.vertices[0]->vertex, other.vertices[1]->vertex);
289}
290
291bool UVEdge::has_same_vertices(const int2 &edge) const
292{
293 return has_same_vertices(edge[0], edge[1]);
294}
295
297{
298 return uv_primitives.size() == 1;
299}
300
302{
303 if (vertices[0]->vertex == vertex) {
304 return vertices[1];
305 }
306 return vertices[0];
307}
308
311/* -------------------------------------------------------------------- */
315{
316 const int vert_index = vertex.vertex;
317 const Vector<UVVertex *> &vertices = uv_vertex_lookup.lookup_or_add_default(vert_index);
318 for (UVVertex *v : vertices) {
319 if (v->uv == vertex.uv) {
320 return v;
321 }
322 }
323 return nullptr;
324}
325
327{
328 UVVertex *found_vertex = lookup(vertex);
329 if (found_vertex != nullptr) {
330 return found_vertex;
331 }
332
333 uv_vertices.append(vertex);
334 UVVertex *result = &uv_vertices.last();
335 result->uv_edges.clear();
336 /* v is already a key. Ensured by UVIsland::lookup in this method. */
337 uv_vertex_lookup.lookup(vertex.vertex).append(result);
338 return result;
339}
340
342{
343 UVVertex *found_vertex = lookup(*edge.vertices[0]);
344 if (found_vertex == nullptr) {
345 return nullptr;
346 }
347 for (UVEdge *e : found_vertex->uv_edges) {
348 UVVertex *other_vertex = e->get_other_uv_vertex(found_vertex->vertex);
349 if (other_vertex->vertex == edge.vertices[1]->vertex &&
350 other_vertex->uv == edge.vertices[1]->uv)
351 {
352 return e;
353 }
354 }
355 return nullptr;
356}
357
359{
360 UVEdge *found_edge = lookup(edge);
361 if (found_edge != nullptr) {
362 return found_edge;
363 }
364
365 uv_edges.append(edge);
366 UVEdge *result = &uv_edges.last();
367 result->uv_primitives.clear();
368 return result;
369}
370
371void UVIsland::append(const UVPrimitive &primitive)
372{
373 uv_primitives.append(primitive);
374 UVPrimitive *new_prim_ptr = &uv_primitives.last();
375 for (int i = 0; i < 3; i++) {
376 UVEdge *other_edge = primitive.edges[i];
377 UVEdge uv_edge_template;
378 uv_edge_template.vertices[0] = lookup_or_create(*other_edge->vertices[0]);
379 uv_edge_template.vertices[1] = lookup_or_create(*other_edge->vertices[1]);
380 new_prim_ptr->edges[i] = lookup_or_create(uv_edge_template);
381 uv_edge_append_to_uv_vertices(*new_prim_ptr->edges[i]);
382 new_prim_ptr->edges[i]->uv_primitives.append(new_prim_ptr);
383 }
384}
385
386bool UVIsland::has_shared_edge(const UVPrimitive &primitive) const
387{
389 for (const UVPrimitive &prim : prims) {
390 if (prim.has_shared_edge(primitive)) {
391 return true;
392 }
393 }
394 }
395 return false;
396}
397
398bool UVIsland::has_shared_edge(const MeshData &mesh_data, const int primitive_i) const
399{
400 for (const VectorList<UVPrimitive>::UsedVector &primitives : uv_primitives) {
401 for (const UVPrimitive &prim : primitives) {
402 if (prim.has_shared_edge(mesh_data, primitive_i)) {
403 return true;
404 }
405 }
406 }
407 return false;
408}
409
411{
412 for (const VectorList<UVPrimitive>::UsedVector &primitives : uv_primitives) {
413 for (const UVPrimitive &prim : primitives) {
414 if (prim.has_shared_edge(primitive)) {
415 this->append(primitive);
416 }
417 }
418 }
419}
420
421static UVPrimitive *add_primitive(const MeshData &mesh_data,
422 UVIsland &uv_island,
423 const int primitive_i)
424{
425 UVPrimitive uv_primitive(primitive_i);
426 const int3 &tri = mesh_data.corner_tris[primitive_i];
427 uv_island.uv_primitives.append(uv_primitive);
428 UVPrimitive *uv_primitive_ptr = &uv_island.uv_primitives.last();
429 for (const int edge_i : mesh_data.primitive_to_edge_map[primitive_i]) {
430 const int2 &edge = mesh_data.edges[edge_i];
431 const int loop_1 = get_uv_loop(mesh_data, tri, edge[0]);
432 const int loop_2 = get_uv_loop(mesh_data, tri, edge[1]);
433 UVEdge uv_edge_template;
434 uv_edge_template.vertices[0] = uv_island.lookup_or_create(UVVertex(mesh_data, loop_1));
435 uv_edge_template.vertices[1] = uv_island.lookup_or_create(UVVertex(mesh_data, loop_2));
436 UVEdge *uv_edge = uv_island.lookup_or_create(uv_edge_template);
437 uv_primitive_ptr->edges.append(uv_edge);
439 uv_edge->uv_primitives.append(uv_primitive_ptr);
440 }
441 return uv_primitive_ptr;
442}
443
445{
446 /* Lookup all borders of the island. */
449 for (UVPrimitive &prim : prims) {
450 for (UVEdge *edge : prim.edges) {
451 if (edge->is_border_edge()) {
452 edges.append(UVBorderEdge(edge, &prim));
453 }
454 }
455 }
456 }
457
458 while (true) {
459 std::optional<UVBorder> border = UVBorder::extract_from_edges(edges);
460 if (!border.has_value()) {
461 break;
462 }
463 if (!border->is_ccw()) {
464 border->flip_order();
465 }
466 borders.append(*border);
467 }
468}
469
470static std::optional<UVBorderCorner> sharpest_border_corner(UVBorder &border, float *r_angle)
471{
472 *r_angle = std::numeric_limits<float>::max();
473 std::optional<UVBorderCorner> result;
474 for (UVBorderEdge &edge : border.edges) {
475 const UVVertex *uv_vertex = edge.get_uv_vertex(0);
476 /* Only allow extending from tagged border vertices that have not been extended yet. During
477 * extending new borders are created, those are ignored as their is_border is set to false. */
478 if (!uv_vertex->flags.is_border || uv_vertex->flags.is_extended) {
479 continue;
480 }
481 float new_angle = border.outside_angle(edge);
482 if (new_angle < *r_angle) {
483 *r_angle = new_angle;
484 result = UVBorderCorner(&border.edges[edge.prev_index], &edge, new_angle);
485 }
486 }
487 return result;
488}
489
490static std::optional<UVBorderCorner> sharpest_border_corner(UVIsland &island)
491{
492 std::optional<UVBorderCorner> result;
493 float sharpest_angle = std::numeric_limits<float>::max();
494 for (UVBorder &border : island.borders) {
495 float new_angle;
496 std::optional<UVBorderCorner> new_result = sharpest_border_corner(border, &new_angle);
497 if (new_angle < sharpest_angle) {
498 sharpest_angle = new_angle;
499 result = new_result;
500 }
501 }
502 return result;
503}
504
509 /* UVs order are already applied. So `uvs[0]` matches `primitive->vertices[vert_order[0]]`. */
512
513 struct {
514 bool found : 1;
516
517 FanSegment(const MeshData &mesh_data, const int primitive_index, const int3 tri, int vertex)
519 {
520 flags.found = false;
521
522 /* Reorder so the first edge starts with the given vertex. */
523 if (mesh_data.corner_verts[tri[1]] == vertex) {
524 vert_order[0] = 1;
525 vert_order[1] = 2;
526 vert_order[2] = 0;
527 }
528 else if (mesh_data.corner_verts[tri[2]] == vertex) {
529 vert_order[0] = 2;
530 vert_order[1] = 0;
531 vert_order[2] = 1;
532 }
533 else {
534 BLI_assert(mesh_data.corner_verts[tri[0]] == vertex);
535 vert_order[0] = 0;
536 vert_order[1] = 1;
537 vert_order[2] = 2;
538 }
539 }
540
541 void print_debug(const MeshData &mesh_data) const
542 {
543 std::stringstream ss;
544 ss << " v1:" << mesh_data.corner_verts[tri[vert_order[0]]];
545 ss << " v2:" << mesh_data.corner_verts[tri[vert_order[1]]];
546 ss << " v3:" << mesh_data.corner_verts[tri[vert_order[2]]];
547 ss << " uv1:" << uvs[0];
548 ss << " uv2:" << uvs[1];
549 ss << " uv3:" << uvs[2];
550 if (flags.found) {
551 ss << " *found";
552 }
553 ss << "\n";
554 std::cout << ss.str();
555 }
556};
557
558struct Fan {
559 /* Blades of the fan. */
561
562 struct {
567 bool is_manifold : 1;
568
570
571 Fan(const MeshData &mesh_data, const int vertex)
572 {
573 flags.is_manifold = true;
574 int current_edge = mesh_data.vert_to_edge_map[vertex].first();
575 const int stop_primitive = mesh_data.edge_to_primitive_map[current_edge].first();
576 int previous_primitive = stop_primitive;
577 while (true) {
578 bool stop = false;
579 for (const int other_primitive_i : mesh_data.edge_to_primitive_map[current_edge]) {
580 if (stop) {
581 break;
582 }
583 if (other_primitive_i == previous_primitive) {
584 continue;
585 }
586
587 const int3 &other_tri = mesh_data.corner_tris[other_primitive_i];
588
589 for (const int edge_i : mesh_data.primitive_to_edge_map[other_primitive_i]) {
590 const int2 &edge = mesh_data.edges[edge_i];
591 if (edge_i == current_edge || (edge[0] != vertex && edge[1] != vertex)) {
592 continue;
593 }
594 segments.append(FanSegment(mesh_data, other_primitive_i, other_tri, vertex));
595 current_edge = edge_i;
596 previous_primitive = other_primitive_i;
597 stop = true;
598 break;
599 }
600 }
601 if (stop == false) {
602 flags.is_manifold = false;
603 break;
604 }
605 if (stop_primitive == previous_primitive) {
606 break;
607 }
608 }
609 }
610
612 {
613 int result = 0;
614 for (const FanSegment &fan_edge : segments) {
615 if (!fan_edge.flags.found) {
616 result++;
617 }
618 }
619 return result;
620 }
621
623 {
624 Vector<int> mesh_primitive_indices = connecting_mesh_primitive_indices(uv_vertex);
625
626 /* Go over all fan edges to find if they can be found as primitive around the uv vertex. */
627 for (FanSegment &fan_edge : segments) {
628 fan_edge.flags.found = mesh_primitive_indices.contains(fan_edge.primitive_index);
629 }
630 }
631
632 void init_uv_coordinates(const MeshData &mesh_data, UVVertex &uv_vertex)
633 {
634 for (FanSegment &fan_edge : segments) {
635 int other_v = mesh_data.corner_verts[fan_edge.tri[fan_edge.vert_order[0]]];
636 if (other_v == uv_vertex.vertex) {
637 other_v = mesh_data.corner_verts[fan_edge.tri[fan_edge.vert_order[1]]];
638 }
639
640 for (UVEdge *edge : uv_vertex.uv_edges) {
641 const UVVertex *other_uv_vertex = edge->get_other_uv_vertex(uv_vertex.vertex);
642 int64_t other_edge_v = other_uv_vertex->vertex;
643 if (other_v == other_edge_v) {
644 fan_edge.uvs[0] = uv_vertex.uv;
645 fan_edge.uvs[1] = other_uv_vertex->uv;
646 break;
647 }
648 }
649 }
650
651 segments.last().uvs[2] = segments.first().uvs[1];
652 for (int i = 0; i < segments.size() - 1; i++) {
653 segments[i].uvs[2] = segments[i + 1].uvs[1];
654 }
655 }
656
657#ifndef NDEBUG
662 bool contains_vertex_on_outside(const MeshData &mesh_data, const int vertex_index) const
663 {
664 for (const FanSegment &segment : segments) {
665 int v2 = mesh_data.corner_verts[segment.tri[segment.vert_order[1]]];
666 if (vertex_index == v2) {
667 return true;
668 }
669 }
670 return false;
671 }
672
673#endif
674
675 static bool is_path_valid(const Span<FanSegment *> path,
676 const MeshData &mesh_data,
677 const int from_vertex,
678 const int to_vertex)
679 {
680 int current_vert = from_vertex;
681 for (FanSegment *segment : path) {
682 int v1 = mesh_data.corner_verts[segment->tri[segment->vert_order[1]]];
683 int v2 = mesh_data.corner_verts[segment->tri[segment->vert_order[2]]];
684 if (!ELEM(current_vert, v1, v2)) {
685 return false;
686 }
687 current_vert = v1 == current_vert ? v2 : v1;
688 }
689 return current_vert == to_vertex;
690 }
691
699 const MeshData &mesh_data,
700 const int from_vertex,
701 const int to_vertex,
702 const bool reversed)
703 {
704 const int from_vert_order = 1;
705 const int to_vert_order = 2;
706 const int index_increment = reversed ? -1 : 1;
707
709 result.reserve(edge_order.size());
710 int index = 0;
711 while (true) {
712 FanSegment *segment = edge_order[index];
713 int v2 = mesh_data.corner_verts[segment->tri[segment->vert_order[from_vert_order]]];
714 if (v2 == from_vertex) {
715 break;
716 }
717 index = (index + index_increment + edge_order.size()) % edge_order.size();
718 }
719
720 while (true) {
721 FanSegment *segment = edge_order[index];
722 result.append(segment);
723
724 int v3 = mesh_data.corner_verts[segment->tri[segment->vert_order[to_vert_order]]];
725 if (v3 == to_vertex) {
726 break;
727 }
728
729 index = (index + index_increment + edge_order.size()) % edge_order.size();
730 }
731
732 return result;
733 }
734
741 static int64_t score(const Span<FanSegment *> solution)
742 {
743 int64_t not_visited_steps = 0;
744 for (FanSegment *segment : solution) {
745 if (!segment->flags.found) {
746 not_visited_steps++;
747 }
748 }
749 return solution.size() - not_visited_steps;
750 }
751
753 const int from_vertex,
754 const int to_vertex)
755 {
756 BLI_assert_msg(contains_vertex_on_outside(mesh_data, from_vertex),
757 "Inconsistency detected, `from_vertex` isn't part of the outside of the fan.");
758 BLI_assert_msg(contains_vertex_on_outside(mesh_data, to_vertex),
759 "Inconsistency detected, `to_vertex` isn't part of the outside of the fan.");
760 if (to_vertex == from_vertex) {
761 return Vector<FanSegment *>();
762 }
763
764 Array<FanSegment *> edges(segments.size());
765 for (int64_t index : segments.index_range()) {
766 edges[index] = &segments[index];
767 }
768
769 Vector<FanSegment *> winding_1 = path_between(edges, mesh_data, from_vertex, to_vertex, false);
770 Vector<FanSegment *> winding_2 = path_between(edges, mesh_data, from_vertex, to_vertex, true);
771
772 bool winding_1_valid = is_path_valid(winding_1, mesh_data, from_vertex, to_vertex);
773 bool winding_2_valid = is_path_valid(winding_2, mesh_data, from_vertex, to_vertex);
774
775 if (winding_1_valid && !winding_2_valid) {
776 return winding_1;
777 }
778 if (!winding_1_valid && winding_2_valid) {
779 return winding_2;
780 }
781 if (!winding_1_valid && !winding_2_valid) {
782 BLI_assert_msg(false, "Both solutions aren't valid.");
783 return Vector<FanSegment *>();
784 }
785 if (score(winding_1) < score(winding_2)) {
786 return winding_1;
787 }
788 return winding_2;
789 }
790
791 void print_debug(const MeshData &mesh_data) const
792 {
793 for (const FanSegment &segment : segments) {
794 segment.print_debug(mesh_data);
795 }
796 std::cout << "\n";
797 }
798};
799
800static void add_uv_primitive_shared_uv_edge(const MeshData &mesh_data,
801 UVIsland &island,
802 UVVertex *connected_vert_1,
803 UVVertex *connected_vert_2,
804 float2 uv_unconnected,
805 const int mesh_primitive_i)
806{
807 UVPrimitive prim1(mesh_primitive_i);
808 const int3 &tri = mesh_data.corner_tris[mesh_primitive_i];
809
810 const int other_vert_i = primitive_get_other_uv_vertex(
811 mesh_data, tri, connected_vert_1->vertex, connected_vert_2->vertex);
812 UVVertex vert_template;
813 vert_template.uv = uv_unconnected;
814 vert_template.vertex = other_vert_i;
815 UVVertex *vert_ptr = island.lookup_or_create(vert_template);
816
817 const int loop_1 = get_uv_loop(mesh_data, tri, connected_vert_1->vertex);
818 vert_template.uv = connected_vert_1->uv;
819 vert_template.vertex = mesh_data.corner_verts[loop_1];
820 UVVertex *vert_1_ptr = island.lookup_or_create(vert_template);
821
822 const int loop_2 = get_uv_loop(mesh_data, tri, connected_vert_2->vertex);
823 vert_template.uv = connected_vert_2->uv;
824 vert_template.vertex = mesh_data.corner_verts[loop_2];
825 UVVertex *vert_2_ptr = island.lookup_or_create(vert_template);
826
827 UVEdge edge_template;
828 edge_template.vertices[0] = vert_1_ptr;
829 edge_template.vertices[1] = vert_2_ptr;
830 prim1.edges.append(island.lookup_or_create(edge_template));
831 edge_template.vertices[0] = vert_2_ptr;
832 edge_template.vertices[1] = vert_ptr;
833 prim1.edges.append(island.lookup_or_create(edge_template));
834 edge_template.vertices[0] = vert_ptr;
835 edge_template.vertices[1] = vert_1_ptr;
836 prim1.edges.append(island.lookup_or_create(edge_template));
839 island.uv_primitives.append(prim1);
840}
845static int find_fill_primitive(const MeshData &mesh_data, UVBorderCorner &corner)
846{
847 if (corner.first->get_uv_vertex(1) != corner.second->get_uv_vertex(0)) {
848 return -1;
849 }
850 if (corner.first->get_uv_vertex(0) == corner.second->get_uv_vertex(1)) {
851 return -1;
852 }
853 const UVVertex *shared_vert = corner.second->get_uv_vertex(0);
854 for (const int edge_i : mesh_data.vert_to_edge_map[shared_vert->vertex]) {
855 const int2 &edge = mesh_data.edges[edge_i];
856 if (corner.first->edge->has_same_vertices(edge)) {
857 for (const int primitive_i : mesh_data.edge_to_primitive_map[edge_i]) {
858 const int3 &tri = mesh_data.corner_tris[primitive_i];
859 const int other_vert = primitive_get_other_uv_vertex(mesh_data, tri, edge[0], edge[1]);
860 if (other_vert == corner.second->get_uv_vertex(1)->vertex) {
861 return primitive_i;
862 }
863 }
864 }
865 }
866 return -1;
867}
868
869static void add_uv_primitive_fill(UVIsland &island,
870 UVVertex &uv_vertex1,
871 UVVertex &uv_vertex2,
872 UVVertex &uv_vertex3,
873 const int fill_primitive_i)
874{
875 UVPrimitive uv_primitive(fill_primitive_i);
876 UVEdge edge_template;
877 edge_template.vertices[0] = &uv_vertex1;
878 edge_template.vertices[1] = &uv_vertex2;
879 uv_primitive.edges.append(island.lookup_or_create(edge_template));
880 edge_template.vertices[0] = &uv_vertex2;
881 edge_template.vertices[1] = &uv_vertex3;
882 uv_primitive.edges.append(island.lookup_or_create(edge_template));
883 edge_template.vertices[0] = &uv_vertex3;
884 edge_template.vertices[1] = &uv_vertex1;
885 uv_primitive.edges.append(island.lookup_or_create(edge_template));
888 island.uv_primitives.append(uv_primitive);
889}
890
891static void extend_at_vert(const MeshData &mesh_data,
892 UVIsland &island,
893 UVBorderCorner &corner,
894 float min_uv_distance)
895{
896
897 int border_index = corner.first->border_index;
898 UVBorder &border = island.borders[border_index];
899 if (!corner.connected_in_mesh()) {
900 return;
901 }
902
903 UVVertex *uv_vertex = corner.second->get_uv_vertex(0);
904 Fan fan(mesh_data, uv_vertex->vertex);
905 if (!fan.flags.is_manifold) {
906 return;
907 }
908 fan.init_uv_coordinates(mesh_data, *uv_vertex);
909 fan.mark_already_added_segments(*uv_vertex);
910 int num_to_add = fan.count_edges_not_added();
911
912 /* In 3d space everything can connected, but in uv space it may not.
913 * in this case in the space between we should extract the primitives to be added
914 * from the fan. */
915 Vector<FanSegment *> winding_solution = fan.best_path_between(
916 mesh_data, corner.first->get_uv_vertex(0)->vertex, corner.second->get_uv_vertex(1)->vertex);
917
918 /*
919 * When all edges are already added and its winding solution contains one segment to be added,
920 * the segment should be split into two segments in order one for both sides.
921 *
922 * Although the tri_fill can fill the missing segment it could lead to a squashed
923 * triangle when the corner angle is near 180 degrees. In order to fix this we will
924 * always add two segments both using the same fill primitive.
925 */
926 if (winding_solution.size() < 2 && (num_to_add == 0 || corner.angle > 2.0f)) {
927 int fill_primitive_1_i = corner.second->uv_primitive->primitive_i;
928 int fill_primitive_2_i = corner.first->uv_primitive->primitive_i;
929
930 const int fill_primitive_i = winding_solution.size() == 1 ?
931 winding_solution[0]->primitive_index :
932 find_fill_primitive(mesh_data, corner);
933
934 if (fill_primitive_i != -1) {
935 fill_primitive_1_i = fill_primitive_i;
936 fill_primitive_2_i = fill_primitive_i;
937 }
938
939 float2 center_uv = corner.uv(0.5f, min_uv_distance);
941 island,
942 corner.first->get_uv_vertex(1),
943 corner.first->get_uv_vertex(0),
944 center_uv,
945 fill_primitive_1_i);
946 UVPrimitive &new_prim_1 = island.uv_primitives.last();
948 island,
949 corner.second->get_uv_vertex(0),
950 corner.second->get_uv_vertex(1),
951 center_uv,
952 fill_primitive_2_i);
953 UVPrimitive &new_prim_2 = island.uv_primitives.last();
954
955 /* Update border after adding the new geometry. */
956 {
957 UVBorderEdge *border_edge = corner.first;
958 border_edge->uv_primitive = &new_prim_1;
959 border_edge->edge = border_edge->uv_primitive->get_uv_edge(
960 corner.first->get_uv_vertex(0)->uv, center_uv);
961 border_edge->reverse_order = border_edge->edge->vertices[0]->uv == center_uv;
962 }
963 {
964 UVBorderEdge *border_edge = corner.second;
965 border_edge->uv_primitive = &new_prim_2;
966 border_edge->edge = border_edge->uv_primitive->get_uv_edge(
967 corner.second->get_uv_vertex(1)->uv, center_uv);
968 border_edge->reverse_order = border_edge->edge->vertices[1]->uv == center_uv;
969 }
970 }
971 else {
972 UVEdge *current_edge = corner.first->edge;
973 Vector<UVBorderEdge> new_border_edges;
974
975 num_to_add = winding_solution.size();
976 for (int64_t segment_index : winding_solution.index_range()) {
977
978 float2 old_uv = current_edge->get_other_uv_vertex(uv_vertex->vertex)->uv;
979 int shared_edge_vertex = current_edge->get_other_uv_vertex(uv_vertex->vertex)->vertex;
980
981 float factor = (segment_index + 1.0f) / num_to_add;
982 float2 new_uv = corner.uv(factor, min_uv_distance);
983
984 FanSegment &segment = *winding_solution[segment_index];
985
986 const int fill_primitive_i = segment.primitive_index;
987 const int3 &tri_fill = mesh_data.corner_tris[fill_primitive_i];
988 const int other_prim_vertex = primitive_get_other_uv_vertex(
989 mesh_data, tri_fill, uv_vertex->vertex, shared_edge_vertex);
990
991 UVVertex uv_vertex_template;
992 uv_vertex_template.vertex = uv_vertex->vertex;
993 uv_vertex_template.uv = uv_vertex->uv;
994 UVVertex *vertex_1_ptr = island.lookup_or_create(uv_vertex_template);
995 uv_vertex_template.vertex = shared_edge_vertex;
996 uv_vertex_template.uv = old_uv;
997 UVVertex *vertex_2_ptr = island.lookup_or_create(uv_vertex_template);
998 uv_vertex_template.vertex = other_prim_vertex;
999 uv_vertex_template.uv = new_uv;
1000 UVVertex *vertex_3_ptr = island.lookup_or_create(uv_vertex_template);
1001
1002 add_uv_primitive_fill(island, *vertex_1_ptr, *vertex_2_ptr, *vertex_3_ptr, fill_primitive_i);
1003
1004 UVPrimitive &new_prim = island.uv_primitives.last();
1005 current_edge = new_prim.get_uv_edge(uv_vertex->vertex, other_prim_vertex);
1006 UVBorderEdge new_border(new_prim.get_uv_edge(shared_edge_vertex, other_prim_vertex),
1007 &new_prim);
1008 new_border_edges.append(new_border);
1009 }
1010
1011 int border_insert = corner.first->index;
1012 border.remove(border_insert);
1013
1014 int border_next = corner.second->index;
1015 if (border_next < border_insert) {
1016 border_insert--;
1017 }
1018 else {
1019 border_next--;
1020 }
1021 border.remove(border_next);
1022 border.edges.insert(border_insert, new_border_edges);
1023
1024 border.update_indexes(border_index);
1025 }
1026}
1027
1028/* Marks vertices that can be extended. Only vertices that are part of a border can be extended. */
1030{
1031 for (VectorList<UVVertex>::UsedVector &uv_vertices : island.uv_vertices) {
1032 for (UVVertex &uv_vertex : uv_vertices) {
1033 uv_vertex.flags.is_border = false;
1034 uv_vertex.flags.is_extended = false;
1035 }
1036 }
1037 for (const UVBorder &border : island.borders) {
1038 for (const UVBorderEdge &border_edge : border.edges) {
1039 border_edge.edge->vertices[0]->flags.is_border = true;
1040 border_edge.edge->vertices[1]->flags.is_border = true;
1041 }
1042 }
1043}
1044
1045void UVIsland::extend_border(const MeshData &mesh_data,
1046 const UVIslandsMask &mask,
1047 const short island_index)
1048{
1050
1051 int64_t border_index = 0;
1052 for (UVBorder &border : borders) {
1053 border.update_indexes(border_index++);
1054 }
1055 while (true) {
1056 std::optional<UVBorderCorner> extension_corner = sharpest_border_corner(*this);
1057 if (!extension_corner.has_value()) {
1058 break;
1059 }
1060
1061 UVVertex *uv_vertex = extension_corner->second->get_uv_vertex(0);
1062
1063 /* Found corner is outside the mask, the corner should not be considered for extension. */
1064 const UVIslandsMask::Tile *tile = mask.find_tile(uv_vertex->uv);
1065 if (tile && tile->is_masked(island_index, uv_vertex->uv)) {
1067 mesh_data, *this, *extension_corner, tile->get_pixel_size_in_uv_space() * 2.0f);
1068 }
1069 /* Mark that the vert is extended. */
1070 uv_vertex->flags.is_extended = true;
1071 }
1072}
1073
1074void UVIsland::print_debug(const MeshData &mesh_data) const
1075{
1076 std::stringstream ss;
1077 ss << "#### Start UVIsland ####\n";
1078 ss << "import bpy\n";
1079 ss << "import bpy_extras.object_utils\n";
1080 ss << "import mathutils\n";
1081
1082 ss << "uvisland_vertices = [\n";
1083 for (const float3 &vertex_position : mesh_data.vert_positions) {
1084 ss << " mathutils.Vector((" << vertex_position.x << ", " << vertex_position.y << ", "
1085 << vertex_position.z << ")),\n";
1086 }
1087 ss << "]\n";
1088
1089 ss << "uvisland_edges = []\n";
1090
1091 ss << "uvisland_faces = [\n";
1092 for (const VectorList<UVPrimitive>::UsedVector &uvprimitives : uv_primitives) {
1093 for (const UVPrimitive &uvprimitive : uvprimitives) {
1094 ss << " [" << uvprimitive.edges[0]->vertices[0]->vertex << ", "
1095 << uvprimitive.edges[0]->vertices[1]->vertex << ", "
1096 << uvprimitive
1097 .get_other_uv_vertex(uvprimitive.edges[0]->vertices[0],
1098 uvprimitive.edges[0]->vertices[1])
1099 ->vertex
1100 << "],\n";
1101 }
1102 }
1103 ss << "]\n";
1104
1105 ss << "uvisland_uvs = [\n";
1106 for (const VectorList<UVPrimitive>::UsedVector &uvprimitives : uv_primitives) {
1107 for (const UVPrimitive &uvprimitive : uvprimitives) {
1108 float2 uv = uvprimitive.edges[0]->vertices[0]->uv;
1109 ss << " " << uv.x << ", " << uv.y << ",\n";
1110 uv = uvprimitive.edges[0]->vertices[1]->uv;
1111 ss << " " << uv.x << ", " << uv.y << ",\n";
1112 uv = uvprimitive
1113 .get_other_uv_vertex(uvprimitive.edges[0]->vertices[0],
1114 uvprimitive.edges[0]->vertices[1])
1115 ->uv;
1116 ss << " " << uv.x << ", " << uv.y << ",\n";
1117 }
1118 }
1119 ss << "]\n";
1120
1121 ss << "uvisland_mesh = bpy.data.meshes.new(name='UVIsland')\n";
1122 ss << "uvisland_mesh.from_pydata(uvisland_vertices, uvisland_edges, uvisland_faces)\n";
1123 ss << "uv_map = uvisland_mesh.attributes.new('UVMap', 'FLOAT2', 'CORNER')\n";
1124 ss << "uv_map.data.foreach_set('vector', uvisland_uvs)\n";
1125 ss << "bpy_extras.object_utils.object_data_add(bpy.context, uvisland_mesh)\n";
1126 ss << "#### End UVIsland ####\n\n\n";
1127
1128 std::cout << ss.str();
1129}
1130
1133/* -------------------------------------------------------------------- */
1138{
1139 /* Find a part of the border that haven't been extracted yet. */
1140 UVBorderEdge *starting_border_edge = nullptr;
1141 for (UVBorderEdge &edge : edges) {
1142 if (edge.tag == false) {
1143 starting_border_edge = &edge;
1144 break;
1145 }
1146 }
1147 if (starting_border_edge == nullptr) {
1148 return std::nullopt;
1149 }
1150 UVBorder border;
1151 border.edges.append(*starting_border_edge);
1152 starting_border_edge->tag = true;
1153
1154 float2 first_uv = starting_border_edge->get_uv_vertex(0)->uv;
1155 float2 current_uv = starting_border_edge->get_uv_vertex(1)->uv;
1156 while (current_uv != first_uv) {
1157 for (UVBorderEdge &border_edge : edges) {
1158 if (border_edge.tag == true) {
1159 continue;
1160 }
1161 int i;
1162 for (i = 0; i < 2; i++) {
1163 if (border_edge.edge->vertices[i]->uv == current_uv) {
1164 border_edge.reverse_order = i == 1;
1165 border_edge.tag = true;
1166 current_uv = border_edge.get_uv_vertex(1)->uv;
1167 border.edges.append(border_edge);
1168 break;
1169 }
1170 }
1171 if (i != 2) {
1172 break;
1173 }
1174 }
1175 }
1176 return border;
1177}
1178
1180{
1181 const UVBorderEdge &edge = edges.first();
1182 const UVVertex *uv_vertex1 = edge.get_uv_vertex(0);
1183 const UVVertex *uv_vertex2 = edge.get_uv_vertex(1);
1184 const UVVertex *uv_vertex3 = edge.get_other_uv_vertex();
1185 float poly[3][2];
1186 copy_v2_v2(poly[0], uv_vertex1->uv);
1187 copy_v2_v2(poly[1], uv_vertex2->uv);
1188 copy_v2_v2(poly[2], uv_vertex3->uv);
1189 const bool ccw = cross_poly_v2(poly, 3) > 0.0;
1190 return ccw;
1191}
1192
1194{
1195 uint64_t border_index = edges.first().border_index;
1196 for (UVBorderEdge &edge : edges) {
1197 edge.reverse_order = !edge.reverse_order;
1198 }
1199 std::reverse(edges.begin(), edges.end());
1200 update_indexes(border_index);
1201}
1202
1204{
1205 const UVBorderEdge &prev = edges[edge.prev_index];
1206 return M_PI - angle_signed_v2v2(prev.get_uv_vertex(1)->uv - prev.get_uv_vertex(0)->uv,
1207 edge.get_uv_vertex(1)->uv - edge.get_uv_vertex(0)->uv);
1208}
1209
1211{
1212 for (int64_t i = 0; i < edges.size(); i++) {
1213 int64_t prev = (i - 1 + edges.size()) % edges.size();
1214 int64_t next = (i + 1) % edges.size();
1215 edges[i].prev_index = prev;
1216 edges[i].index = i;
1217 edges[i].next_index = next;
1218 edges[i].border_index = border_index;
1219 }
1220}
1221
1223{
1224 /* Could read the border_index from any border edge as they are consistent. */
1225 uint64_t border_index = edges[0].border_index;
1226 edges.remove(index);
1227 update_indexes(border_index);
1228}
1229
1232/* -------------------------------------------------------------------- */
1237 : first(first), second(second), angle(angle)
1238{
1239}
1240
1241float2 UVBorderCorner::uv(float factor, float min_uv_distance)
1242{
1243 using namespace blender::math;
1244 float2 origin = first->get_uv_vertex(1)->uv;
1245 float angle_between = angle * factor;
1246 float desired_len = max_ff(second->length() * factor + first->length() * (1.0 - factor),
1247 min_uv_distance);
1248 float2 v = normalize(first->get_uv_vertex(0)->uv - origin);
1249
1250 float2x2 rot_mat = from_rotation<float2x2>(AngleRadian(angle_between));
1251 float2 rotated = rot_mat * v;
1252 float2 result = rotated * desired_len + first->get_uv_vertex(1)->uv;
1253 return result;
1254}
1255
1257{
1258 return first->get_uv_vertex(1) == second->get_uv_vertex(0);
1259}
1260
1262{
1263 std::stringstream ss;
1264 ss << "# ";
1265 if (connected_in_mesh()) {
1266 ss << first->get_uv_vertex(0)->vertex << "-";
1267 ss << first->get_uv_vertex(1)->vertex << "-";
1268 ss << second->get_uv_vertex(1)->vertex << "\n";
1269 }
1270 else {
1271 ss << first->get_uv_vertex(0)->vertex << "-";
1272 ss << first->get_uv_vertex(1)->vertex << ", ";
1273 ss << second->get_uv_vertex(0)->vertex << "-";
1274 ss << second->get_uv_vertex(1)->vertex << "\n";
1275 }
1276 std::cout << ss.str();
1277}
1278
1281/* -------------------------------------------------------------------- */
1285UVPrimitive::UVPrimitive(const int primitive_i) : primitive_i(primitive_i) {}
1286
1288{
1290 for (int i = 0; i < 3; i++) {
1291 for (int j = 0; j < 3; j++) {
1292 if (edges[i]->has_shared_edge(*other.edges[j])) {
1293 result.append(std::pair<UVEdge *, UVEdge *>(edges[i], other.edges[j]));
1294 }
1295 }
1296 }
1297 return result;
1298}
1299
1301{
1302 for (int i = 0; i < 3; i++) {
1303 for (int j = 0; j < 3; j++) {
1304 if (edges[i]->has_shared_edge(*other.edges[j])) {
1305 return true;
1306 }
1307 }
1308 }
1309 return false;
1310}
1311
1312bool UVPrimitive::has_shared_edge(const MeshData &mesh_data, const int primitive_i) const
1313{
1314 for (const UVEdge *uv_edge : edges) {
1315 const int3 &tri = mesh_data.corner_tris[primitive_i];
1316 int loop_1 = tri[2];
1317 for (int i = 0; i < 3; i++) {
1318 int loop_2 = tri[i];
1319 if (uv_edge->has_shared_edge(mesh_data.uv_map, loop_1, loop_2)) {
1320 return true;
1321 }
1322 loop_1 = loop_2;
1323 }
1324 }
1325 return false;
1326}
1327
1329 const uint8_t mesh_vert_index) const
1330{
1331 const int3 &tri = mesh_data.corner_tris[this->primitive_i];
1332 const int mesh_vertex = mesh_data.corner_verts[tri[mesh_vert_index]];
1333 for (const UVEdge *uv_edge : edges) {
1334 for (const UVVertex *uv_vert : uv_edge->vertices) {
1335 if (uv_vert->vertex == mesh_vertex) {
1336 return uv_vert;
1337 }
1338 }
1339 }
1341 return nullptr;
1342}
1343
1344UVEdge *UVPrimitive::get_uv_edge(const float2 uv1, const float2 uv2) const
1345{
1346 for (UVEdge *uv_edge : edges) {
1347 const float2 &e1 = uv_edge->vertices[0]->uv;
1348 const float2 &e2 = uv_edge->vertices[1]->uv;
1349 if ((e1 == uv1 && e2 == uv2) || (e1 == uv2 && e2 == uv1)) {
1350 return uv_edge;
1351 }
1352 }
1354 return nullptr;
1355}
1356
1357UVEdge *UVPrimitive::get_uv_edge(const int v1, const int v2) const
1358{
1359 for (UVEdge *uv_edge : edges) {
1360 const int e1 = uv_edge->vertices[0]->vertex;
1361 const int e2 = uv_edge->vertices[1]->vertex;
1362 if ((e1 == v1 && e2 == v2) || (e1 == v2 && e2 == v1)) {
1363 return uv_edge;
1364 }
1365 }
1367 return nullptr;
1368}
1369
1370bool UVPrimitive::contains_uv_vertex(const UVVertex *uv_vertex) const
1371{
1372 for (UVEdge *edge : edges) {
1373 if (std::find(edge->vertices.begin(), edge->vertices.end(), uv_vertex) != edge->vertices.end())
1374 {
1375 return true;
1376 }
1377 }
1378 return false;
1379}
1380
1382{
1385
1386 for (const UVEdge *edge : edges) {
1387 for (const UVVertex *uv_vertex : edge->vertices) {
1388 if (!ELEM(uv_vertex, v1, v2)) {
1389 return uv_vertex;
1390 }
1391 }
1392 }
1394 return nullptr;
1395}
1396
1398{
1399 Vector<UVBorderEdge> border_edges;
1400 for (UVEdge *edge : edges) {
1401 /* TODO remove const cast. only needed for debugging ATM. */
1402 UVBorderEdge border_edge(edge, const_cast<UVPrimitive *>(this));
1403 border_edges.append(border_edge);
1404 }
1405 return *UVBorder::extract_from_edges(border_edges);
1406}
1407
1410/* -------------------------------------------------------------------- */
1414 : edge(edge), uv_primitive(uv_primitive)
1415{
1416}
1417
1419{
1420 int actual_index = reverse_order ? 1 - index : index;
1421 return edge->vertices[actual_index];
1422}
1423
1425{
1426 int actual_index = reverse_order ? 1 - index : index;
1427 return edge->vertices[actual_index];
1428}
1429
1431{
1432 return uv_primitive->get_other_uv_vertex(edge->vertices[0], edge->vertices[1]);
1433}
1434
1436{
1437 return len_v2v2(edge->vertices[0]->uv, edge->vertices[1]->uv);
1438}
1439
1442/* -------------------------------------------------------------------- */
1447{
1448 islands.reserve(mesh_data.uv_island_len);
1449
1450 for (const int64_t uv_island_id : IndexRange(mesh_data.uv_island_len)) {
1451 islands.append_as(UVIsland());
1452 UVIsland *uv_island = &islands.last();
1453 uv_island->id = uv_island_id;
1454 for (const int primitive_i : mesh_data.corner_tris.index_range()) {
1455 if (mesh_data.uv_island_ids[primitive_i] == uv_island_id) {
1456 add_primitive(mesh_data, *uv_island, primitive_i);
1457 }
1458 }
1459 }
1460}
1461
1463{
1464 for (UVIsland &island : islands) {
1465 island.extract_borders();
1466 }
1467}
1468
1469void UVIslands::extend_borders(const MeshData &mesh_data, const UVIslandsMask &islands_mask)
1470{
1471 ushort index = 0;
1472 for (UVIsland &island : islands) {
1473 island.extend_border(mesh_data, islands_mask, index++);
1474 }
1475}
1476
1477void UVIslands::print_debug(const MeshData &mesh_data) const
1478{
1479 for (const UVIsland &island : islands) {
1480 island.print_debug(mesh_data);
1481 }
1482}
1483
1486/* -------------------------------------------------------------------- */
1491{
1492 return ushort2(max_ii(tile_resolution.x >> 2, 256), max_ii(tile_resolution.y >> 2, 256));
1493}
1494
1495UVIslandsMask::Tile::Tile(float2 udim_offset, ushort2 tile_resolution)
1496 : udim_offset(udim_offset),
1497 tile_resolution(tile_resolution),
1498 mask_resolution(mask_resolution_from_tile_resolution(tile_resolution)),
1499 mask(mask_resolution.x * mask_resolution.y)
1500{
1501 mask.fill(0xffff);
1502}
1503
1505{
1506 const float2 tile_uv = uv - udim_offset;
1507 return IN_RANGE(tile_uv.x, 0.0, 1.0f) && IN_RANGE(tile_uv.y, 0.0f, 1.0f);
1508}
1509
1511{
1512 return min_ff(1.0f / tile_resolution.x, 1.0f / tile_resolution.y);
1513}
1514
1515static void add_uv_island(const MeshData &mesh_data,
1517 const UVIsland &uv_island,
1518 int16_t island_index)
1519{
1520 for (const VectorList<UVPrimitive>::UsedVector &uv_primitives : uv_island.uv_primitives) {
1521 for (const UVPrimitive &uv_primitive : uv_primitives) {
1522 const int3 &tri = mesh_data.corner_tris[uv_primitive.primitive_i];
1523
1524 rctf uv_bounds = primitive_uv_bounds(tri, mesh_data.uv_map);
1525 rcti buffer_bounds;
1526 buffer_bounds.xmin = max_ii(
1527 floor((uv_bounds.xmin - tile.udim_offset.x) * tile.mask_resolution.x), 0);
1528 buffer_bounds.xmax = min_ii(
1529 ceil((uv_bounds.xmax - tile.udim_offset.x) * tile.mask_resolution.x),
1530 tile.mask_resolution.x - 1);
1531 buffer_bounds.ymin = max_ii(
1532 floor((uv_bounds.ymin - tile.udim_offset.y) * tile.mask_resolution.y), 0);
1533 buffer_bounds.ymax = min_ii(
1534 ceil((uv_bounds.ymax - tile.udim_offset.y) * tile.mask_resolution.y),
1535 tile.mask_resolution.y - 1);
1536
1537 for (int y = buffer_bounds.ymin; y < buffer_bounds.ymax + 1; y++) {
1538 for (int x = buffer_bounds.xmin; x < buffer_bounds.xmax + 1; x++) {
1539 float2 uv(float(x) / tile.mask_resolution.x, float(y) / tile.mask_resolution.y);
1540 float3 weights;
1541 barycentric_weights_v2(mesh_data.uv_map[tri[0]],
1542 mesh_data.uv_map[tri[1]],
1543 mesh_data.uv_map[tri[2]],
1544 uv + tile.udim_offset,
1545 weights);
1546 if (!barycentric_inside_triangle_v2(weights)) {
1547 continue;
1548 }
1549
1550 uint64_t offset = tile.mask_resolution.x * y + x;
1551 tile.mask[offset] = island_index;
1552 }
1553 }
1554 }
1555 }
1556}
1557
1558void UVIslandsMask::add(const MeshData &mesh_data, const UVIslands &uv_islands)
1559{
1560 for (Tile &tile : tiles) {
1561 for (const int i : uv_islands.islands.index_range()) {
1562 add_uv_island(mesh_data, tile, uv_islands.islands[i], i);
1563 }
1564 }
1565}
1566
1567void UVIslandsMask::add_tile(const float2 udim_offset, ushort2 resolution)
1568{
1569 tiles.append_as(Tile(udim_offset, resolution));
1570}
1571
1572static bool dilate_x(UVIslandsMask::Tile &islands_mask)
1573{
1574 bool changed = false;
1575 const Array<uint16_t> prev_mask = islands_mask.mask;
1576 for (int y = 0; y < islands_mask.mask_resolution.y; y++) {
1577 for (int x = 0; x < islands_mask.mask_resolution.x; x++) {
1578 uint64_t offset = y * islands_mask.mask_resolution.x + x;
1579 if (prev_mask[offset] != 0xffff) {
1580 continue;
1581 }
1582 if (x != 0 && prev_mask[offset - 1] != 0xffff) {
1583 islands_mask.mask[offset] = prev_mask[offset - 1];
1584 changed = true;
1585 }
1586 else if (x < islands_mask.mask_resolution.x - 1 && prev_mask[offset + 1] != 0xffff) {
1587 islands_mask.mask[offset] = prev_mask[offset + 1];
1588 changed = true;
1589 }
1590 }
1591 }
1592 return changed;
1593}
1594
1595static bool dilate_y(UVIslandsMask::Tile &islands_mask)
1596{
1597 bool changed = false;
1598 const Array<uint16_t> prev_mask = islands_mask.mask;
1599 for (int y = 0; y < islands_mask.mask_resolution.y; y++) {
1600 for (int x = 0; x < islands_mask.mask_resolution.x; x++) {
1601 uint64_t offset = y * islands_mask.mask_resolution.x + x;
1602 if (prev_mask[offset] != 0xffff) {
1603 continue;
1604 }
1605 if (y != 0 && prev_mask[offset - islands_mask.mask_resolution.x] != 0xffff) {
1606 islands_mask.mask[offset] = prev_mask[offset - islands_mask.mask_resolution.x];
1607 changed = true;
1608 }
1609 else if (y < islands_mask.mask_resolution.y - 1 &&
1610 prev_mask[offset + islands_mask.mask_resolution.x] != 0xffff)
1611 {
1612 islands_mask.mask[offset] = prev_mask[offset + islands_mask.mask_resolution.x];
1613 changed = true;
1614 }
1615 }
1616 }
1617 return changed;
1618}
1619
1620static void dilate_tile(UVIslandsMask::Tile &tile, int max_iterations)
1621{
1622 int index = 0;
1623 while (index < max_iterations) {
1624 bool changed = dilate_x(tile);
1625 changed |= dilate_y(tile);
1626 if (!changed) {
1627 break;
1628 }
1629 index++;
1630 }
1631}
1632
1633void UVIslandsMask::dilate(int max_iterations)
1634{
1635 for (Tile &tile : tiles) {
1636 dilate_tile(tile, max_iterations);
1637 }
1638}
1639
1640bool UVIslandsMask::Tile::is_masked(const uint16_t island_index, const float2 uv) const
1641{
1642 float2 local_uv = uv - udim_offset;
1643 if (local_uv.x < 0.0f || local_uv.y < 0.0f || local_uv.x >= 1.0f || local_uv.y >= 1.0f) {
1644 return false;
1645 }
1646 float2 pixel_pos_f = local_uv * float2(mask_resolution.x, mask_resolution.y);
1647 ushort2 pixel_pos = ushort2(pixel_pos_f.x, pixel_pos_f.y);
1648 uint64_t offset = pixel_pos.y * mask_resolution.x + pixel_pos.x;
1649 return mask[offset] == island_index;
1650}
1651
1653{
1654 for (const Tile &tile : tiles) {
1655 if (tile.contains(uv)) {
1656 return &tile;
1657 }
1658 }
1659 return nullptr;
1660}
1661
1662bool UVIslandsMask::is_masked(const uint16_t island_index, const float2 uv) const
1663{
1664 const Tile *tile = find_tile(uv);
1665 if (tile == nullptr) {
1666 return false;
1667 }
1668 return tile->is_masked(island_index, uv);
1669}
1670
1673} // namespace blender::bke::pbvh::uv_islands
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
#define M_PI
int barycentric_inside_triangle_v2(const float w[3])
void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
float cross_poly_v2(const float verts[][2], unsigned int nr)
Definition math_geom.cc:147
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
void BLI_rctf_do_minmax_v(struct rctf *rect, const float xy[2])
Definition rct.c:514
void BLI_rctf_init_minmax(struct rctf *rect)
Definition rct.c:484
unsigned short ushort
#define IN_RANGE(a, b, c)
#define ELEM(...)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
void fill(const T &value) const
Definition BLI_array.hh:261
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
void reserve(int64_t n)
Definition BLI_map.hh:979
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:457
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
int64_t size() const
bool contains(const T &value) const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
void reserve(const int64_t min_capacity)
void append_non_duplicates(const T &value)
void add(const int primitive_i, const int edge_i)
void add(const Span< int > edges, const int tri_i)
void add(const int edge_i, const int v1, const int v2)
append
ccl_global const KernelWorkTile * tile
ccl_device_inline float2 floor(const float2 a)
ccl_device_inline float3 ceil(const float3 a)
static ulong * next
static Vector< int > connecting_mesh_primitive_indices(const UVVertex &uv_vertex)
static int get_uv_loop(const MeshData &mesh_data, const int3 &tri, const int vert)
static void uv_primitive_append_to_uv_edges(UVPrimitive &uv_primitive)
static void dilate_tile(UVIslandsMask::Tile &tile, int max_iterations)
static void add_uv_island(const MeshData &mesh_data, UVIslandsMask::Tile &tile, const UVIsland &uv_island, int16_t island_index)
static bool dilate_x(UVIslandsMask::Tile &islands_mask)
static void uv_vertex_init_flags(UVVertex &uv_vertex)
static rctf primitive_uv_bounds(const int3 &tri, const Span< float2 > uv_map)
static void reset_extendability_flags(UVIsland &island)
static int find_fill_primitive(const MeshData &mesh_data, UVBorderCorner &corner)
static void uv_edge_append_to_uv_vertices(UVEdge &uv_edge)
static bool dilate_y(UVIslandsMask::Tile &islands_mask)
static std::optional< UVBorderCorner > sharpest_border_corner(UVBorder &border, float *r_angle)
static ushort2 mask_resolution_from_tile_resolution(ushort2 tile_resolution)
static void add_uv_primitive_fill(UVIsland &island, UVVertex &uv_vertex1, UVVertex &uv_vertex2, UVVertex &uv_vertex3, const int fill_primitive_i)
static void uv_primitive_append_to_uv_vertices(UVPrimitive &uv_primitive)
static int mesh_data_init_primitive_uv_island_ids(MeshData &mesh_data)
static constexpr int INVALID_UV_ISLAND_ID
static void add_uv_primitive_shared_uv_edge(const MeshData &mesh_data, UVIsland &island, UVVertex *connected_vert_1, UVVertex *connected_vert_2, float2 uv_unconnected, const int mesh_primitive_i)
static void extract_uv_neighbors(const MeshData &mesh_data, const Span< int > uv_island_ids, const int primitive_i, Vector< int > &prims_to_add)
static void extend_at_vert(const MeshData &mesh_data, UVIsland &island, UVBorderCorner &corner, float min_uv_distance)
static void mesh_data_init(MeshData &mesh_data)
static UVPrimitive * add_primitive(const MeshData &mesh_data, UVIsland &uv_island, const int primitive_i)
static int primitive_get_other_uv_vertex(const MeshData &mesh_data, const int3 &tri, const int v1, const int v2)
static bool primitive_has_shared_uv_edge(const Span< float2 > uv_map, const int3 &tri, const int3 &tri_other)
static void mesh_data_init_edges(MeshData &mesh_data)
VecBase< float, 2 > float2
VecBase< uint16_t, 2 > ushort2
signed short int16_t
Definition stdint.h:76
unsigned short uint16_t
Definition stdint.h:79
__int64 int64_t
Definition stdint.h:89
unsigned char uint8_t
Definition stdint.h:78
unsigned __int64 uint64_t
Definition stdint.h:90
FanSegment(const MeshData &mesh_data, const int primitive_index, const int3 tri, int vertex)
struct blender::bke::pbvh::uv_islands::FanSegment::@94 flags
void print_debug(const MeshData &mesh_data) const
Vector< FanSegment * > best_path_between(const MeshData &mesh_data, const int from_vertex, const int to_vertex)
void print_debug(const MeshData &mesh_data) const
struct blender::bke::pbvh::uv_islands::Fan::@95 flags
void mark_already_added_segments(const UVVertex &uv_vertex)
void init_uv_coordinates(const MeshData &mesh_data, UVVertex &uv_vertex)
bool contains_vertex_on_outside(const MeshData &mesh_data, const int vertex_index) const
static int64_t score(const Span< FanSegment * > solution)
static Vector< FanSegment * > path_between(const Span< FanSegment * > edge_order, const MeshData &mesh_data, const int from_vertex, const int to_vertex, const bool reversed)
static bool is_path_valid(const Span< FanSegment * > path, const MeshData &mesh_data, const int from_vertex, const int to_vertex)
Fan(const MeshData &mesh_data, const int vertex)
MeshData(OffsetIndices< int > faces, Span< int3 > corner_tris, Span< int > corner_verts, Span< float2 > uv_map, Span< float3 > vert_positions)
float2 uv(float factor, float min_uv_distance)
UVBorderCorner(UVBorderEdge *first, UVBorderEdge *second, float angle)
UVBorderEdge(UVEdge *edge, UVPrimitive *uv_primitive)
float outside_angle(const UVBorderEdge &edge) const
static std::optional< UVBorder > extract_from_edges(Vector< UVBorderEdge > &edges)
void update_indexes(uint64_t border_index)
Vector< UVPrimitive *, 2 > uv_primitives
bool has_same_vertices(const int2 &edge) const
bool has_shared_edge(Span< float2 > uv_map, const int loop_1, const int loop_2) const
std::array< UVVertex *, 2 > vertices
UVVertex * get_other_uv_vertex(const int vertex_index)
Map< int64_t, Vector< UVVertex * > > uv_vertex_lookup
void print_debug(const MeshData &mesh_data) const
bool has_shared_edge(const UVPrimitive &primitive) const
void extend_border(const MeshData &mesh_data, const UVIslandsMask &mask, const short island_index)
UVVertex * lookup_or_create(const UVVertex &vertex)
UVVertex * lookup(const UVVertex &vertex)
Tile(float2 udim_offset, ushort2 tile_resolution)
bool is_masked(const uint16_t island_index, const float2 uv) const
void add(const MeshData &mesh_data, const UVIslands &islands)
const Tile * find_tile(const float2 uv) const
bool is_masked(const uint16_t island_index, const float2 uv) const
void add_tile(float2 udim_offset, ushort2 resolution)
void extend_borders(const MeshData &mesh_data, const UVIslandsMask &islands_mask)
void print_debug(const MeshData &mesh_data) const
Vector< std::pair< UVEdge *, UVEdge * > > shared_edges(UVPrimitive &other)
UVEdge * get_uv_edge(const float2 uv1, const float2 uv2) const
bool has_shared_edge(const UVPrimitive &other) const
const UVVertex * get_other_uv_vertex(const UVVertex *v1, const UVVertex *v2) const
bool contains_uv_vertex(const UVVertex *uv_vertex) const
const UVVertex * get_uv_vertex(const MeshData &mesh_data, const uint8_t mesh_vert_index) const
struct blender::bke::pbvh::uv_islands::UVVertex::@96 flags
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax