21 "Keep non-manifold boundaries of the input mesh in place by avoiding the dual "
22 "transformation there");
76 const bool keep_boundaries)
78 if (keep_boundaries) {
80 for (
const int i :
data.index_range()) {
82 r_data[out_i] =
data[i];
89 for (
const int i :
data.index_range()) {
91 r_data[out_i] =
data[i];
101 const Span<std::pair<int, int>> new_to_old_map)
103 for (
const std::pair<int, int> &pair : new_to_old_map) {
104 r_data[pair.first] =
data[pair.second];
115 const int old_i = new_to_old_map[i];
116 r_data[i] =
data[old_i];
142 const bool keep_boundaries,
144 const Span<int> new_to_old_face_corners_map,
145 const Span<std::pair<int, int>> boundary_vertex_to_relevant_face_map,
152 if (!src_attribute) {
165 out_domain = src_attribute.
domain;
170 attribute_id, out_domain, data_type);
172 if (!dst_attribute) {
177 using T = decltype(dummy);
181 dst_span.
take_front(span.size()).copy_from(span);
182 if (keep_boundaries) {
225 const EdgeType edge_type = r_edge_types[i];
242 const EdgeType edge_type = r_edge_types[i];
264 r_vertex_poly_indices[loop.v].append(i);
325 const int vertex_index,
326 const bool boundary_vertex,
332 if (connected_polygons.
size() <= 2 && (!boundary_vertex || connected_polygons.
size() == 0)) {
338 for (
const int i : connected_polygons.
index_range()) {
340 bool first_edge_done =
false;
344 if (!first_edge_done) {
345 poly_vertex_corners[i].
first = loop_index;
346 first_edge_done =
true;
349 poly_vertex_corners[i].second = loop_index;
356 int shared_edge_i = -1;
360 if (boundary_vertex) {
362 for (
const int i : connected_polygons.
index_range()) {
364 const MLoop &second_loop =
mesh.
mloop[poly_vertex_corners[i].second];
366 shared_edge_i = second_loop.
e;
367 r_sorted_corners[0] = poly_vertex_corners[i].
first;
368 std::swap(connected_polygons[i], connected_polygons[0]);
369 std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
373 shared_edge_i = first_loop.
e;
374 r_sorted_corners[0] = poly_vertex_corners[i].second;
375 std::swap(connected_polygons[i], connected_polygons[0]);
376 std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
380 if (shared_edge_i == -1) {
383 for (
const int i : connected_polygons.
index_range()) {
385 const MLoop &second_loop =
mesh.
mloop[poly_vertex_corners[i].second];
387 shared_edge_i = second_loop.
e;
388 r_sorted_corners[0] = poly_vertex_corners[i].
first;
389 std::swap(connected_polygons[i], connected_polygons[0]);
390 std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
394 shared_edge_i = first_loop.
e;
395 r_sorted_corners[0] = poly_vertex_corners[i].second;
396 std::swap(connected_polygons[i], connected_polygons[0]);
397 std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
406 const MLoop &second_loop =
mesh.
mloop[poly_vertex_corners[0].second];
407 if (first_loop.
v == vertex_index) {
408 shared_edge_i = second_loop.
e;
409 r_sorted_corners[0] = poly_vertex_corners[0].
first;
412 r_sorted_corners[0] = poly_vertex_corners[0].second;
413 shared_edge_i = first_loop.
e;
419 r_shared_edges[i] = shared_edge_i;
423 for (; j < connected_polygons.
size(); ++j) {
425 const MLoop &second_loop =
mesh.
mloop[poly_vertex_corners[j].second];
426 if (first_loop.
e == shared_edge_i) {
427 r_sorted_corners[i + 1] = poly_vertex_corners[j].
first;
428 shared_edge_i = second_loop.
e;
431 if (second_loop.
e == shared_edge_i) {
432 r_sorted_corners[i + 1] = poly_vertex_corners[j].second;
433 shared_edge_i = first_loop.
e;
437 if (j == connected_polygons.
size()) {
443 std::swap(connected_polygons[i + 1], connected_polygons[j]);
444 std::swap(poly_vertex_corners[i + 1], poly_vertex_corners[j]);
447 if (!boundary_vertex) {
449 r_shared_edges.
last() = shared_edge_i;
459 const int vertex_index,
466 if (edge.v1 == vertex_index || edge.v2 == vertex_index) {
480 const int vertex_index,
485 bool edge1_done =
false;
488 bool needs_swap =
false;
492 if (edge.v1 == vertex_index || edge.v2 == vertex_index) {
505 if (loop.v == vertex_index) {
514 const int old_edge_i,
524 const int new_edge_i = new_edges.
size();
525 new_to_old_edges_map.
append(old_edge_i);
527 loop_edges.
append(new_edge_i);
532 const int first_poly_index,
533 const int second_poly_index,
540 vertex_poly_indices[vertex].
size() == 2 &&
541 vertex_poly_indices[vertex][0] == first_poly_index &&
542 vertex_poly_indices[vertex][1] == second_poly_index);
563 const int first_poly_index = vertex_poly_indices[vert_i][0];
564 const int second_poly_index = vertex_poly_indices[vert_i][1];
565 const int new_edge_index = new_edges.
size();
566 bool edge_created =
false;
570 const int v1 = edge.v1;
571 const int v2 = edge.v2;
572 bool mark_edge =
false;
574 v1, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
580 v2, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
591 new_to_old_edges_map.
append(loop.e);
595 old_to_new_edges_map[loop.e] = new_edge_index;
617 const bool keep_boundaries)
636 for (const int i : range) {
637 if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
638 (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
642 MutableSpan<int> loop_indices = vertex_poly_indices[i];
643 Array<int> sorted_corners(loop_indices.size());
644 bool vertex_ok = true;
645 if (vertex_types[i] == VertexType::Normal) {
646 Array<int> shared_edges(loop_indices.size());
647 vertex_ok = sort_vertex_polys(
648 mesh_in, i, false, edge_types, loop_indices, shared_edges, sorted_corners);
649 vertex_shared_edges[i] = std::move(shared_edges);
652 Array<int> shared_edges(loop_indices.size() - 1);
653 vertex_ok = sort_vertex_polys(
654 mesh_in, i, true, edge_types, loop_indices, shared_edges, sorted_corners);
655 vertex_shared_edges[i] = std::move(shared_edges);
660 vertex_types[i] = VertexType::NonManifold;
663 vertex_corners[i] = std::move(sorted_corners);
668 for (
const int i :
IndexRange(mesh_in.totpoly)) {
669 const MPoly poly = mesh_in.mpoly[i];
671 &poly, &mesh_in.mloop[poly.
loopstart], mesh_in.mvert, vertex_positions[i]);
675 if (keep_boundaries) {
677 boundary_edge_midpoint_index.
reinitialize(mesh_in.totedge);
679 for (
const int i :
IndexRange(mesh_in.totedge)) {
682 const MEdge &edge = mesh_in.medge[i];
683 mid_v3_v3v3(mid, mesh_in.mvert[edge.v1].co, mesh_in.mvert[edge.v2].co);
684 boundary_edge_midpoint_index[i] = vertex_positions.
size();
685 vertex_positions.append(mid);
690 Vector<int> loop_lengths;
692 Vector<int> loop_edges;
693 Vector<MEdge> new_edges;
695 Vector<int> new_to_old_face_corners_map;
696 Vector<int> new_to_old_edges_map;
698 Vector<std::pair<int, int>> boundary_vertex_to_relevant_face_map;
704 Array<int> old_to_new_edges_map(mesh_in.totedge);
705 old_to_new_edges_map.fill(-1);
712 old_to_new_edges_map,
714 new_to_old_edges_map);
716 for (
const int i : IndexRange(mesh_in.totvert)) {
723 Vector<int> loop_indices = vertex_poly_indices[i];
724 Span<int> shared_edges = vertex_shared_edges[i];
725 Span<int> sorted_corners = vertex_corners[i];
727 if (loop_indices.size() <= 2) {
733 for (
const int i : shared_edges.index_range()) {
734 const int old_edge_i = shared_edges[i];
735 if (old_to_new_edges_map[old_edge_i] == -1) {
739 new_edge.
v2 = loop_indices[(i + 1) % loop_indices.size()];
740 new_to_old_edges_map.append(old_edge_i);
741 old_to_new_edges_map[old_edge_i] = new_edges.size();
744 loop_edges.append(old_to_new_edges_map[old_edge_i]);
747 new_to_old_face_corners_map.extend(sorted_corners);
775 for (
const int i : shared_edges.index_range()) {
776 const int old_edge_i = shared_edges[i];
777 if (old_to_new_edges_map[old_edge_i] == -1) {
782 new_to_old_edges_map.append(old_edge_i);
783 old_to_new_edges_map[old_edge_i] = new_edges.size();
786 loop_edges.append(old_to_new_edges_map[old_edge_i]);
789 new_to_old_face_corners_map.extend(sorted_corners);
796 if (loop_indices.size() >= 2) {
804 mesh_in.mpoly[loop_indices[0]], mesh_in, i, edge_types, edge1, edge2);
807 const int last_face_center = loop_indices.last();
808 loop_indices.append(boundary_edge_midpoint_index[edge1]);
809 new_to_old_face_corners_map.append(sorted_corners.last());
810 const int first_midpoint = loop_indices.last();
811 if (old_to_new_edges_map[edge1] == -1) {
816 new_to_old_edges_map,
819 old_to_new_edges_map[edge1] = new_edges.size() - 1;
820 boundary_vertex_to_relevant_face_map.append(std::pair(first_midpoint, last_face_center));
823 loop_edges.append(old_to_new_edges_map[edge1]);
825 loop_indices.append(vertex_positions.size());
827 new_to_old_face_corners_map.append(sorted_corners.first());
828 boundary_vertex_to_relevant_face_map.append(
829 std::pair(loop_indices.last(), last_face_center));
830 vertex_positions.append(mesh_in.mvert[i].co);
831 const int boundary_vertex = loop_indices.last();
836 new_to_old_edges_map,
840 loop_indices.append(boundary_edge_midpoint_index[edge2]);
841 new_to_old_face_corners_map.append(sorted_corners.first());
842 const int second_midpoint = loop_indices.last();
847 new_to_old_edges_map,
851 if (old_to_new_edges_map[edge2] == -1) {
852 const int first_face_center = loop_indices.first();
857 new_to_old_edges_map,
860 old_to_new_edges_map[edge2] = new_edges.size() - 1;
861 boundary_vertex_to_relevant_face_map.append(std::pair(second_midpoint, first_face_center));
864 loop_edges.append(old_to_new_edges_map[edge2]);
868 loop_lengths.append(loop_indices.size());
869 for (
const int j : loop_indices) {
874 vertex_positions.size(), new_edges.size(), 0, loops.size(), loop_lengths.size());
878 new_to_old_edges_map,
879 new_to_old_face_corners_map,
880 boundary_vertex_to_relevant_face_map,
885 for (
const int i : IndexRange(mesh_out->
totpoly)) {
888 loop_start += loop_lengths[i];
890 for (
const int i : IndexRange(mesh_out->
totloop)) {
891 mesh_out->
mloop[i].
v = loops[i];
892 mesh_out->
mloop[i].
e = loop_edges[i];
894 for (
const int i : IndexRange(mesh_out->
totvert)) {
897 memcpy(mesh_out->
medge, new_edges.data(),
sizeof(
MEdge) * new_edges.size());
898 geometry_set.replace_mesh(mesh_out);
904 const bool keep_boundaries =
params.extract_input<
bool>(
"Keep Boundaries");
911 params.set_output(
"Dual Mesh", std::move(geometry_set));
@ GEO_COMPONENT_TYPE_MESH
void BKE_mesh_calc_poly_center(const struct MPoly *mpoly, const struct MLoop *loopstart, const struct MVert *mvarray, float r_cent[3])
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
#define NODE_CLASS_GEOMETRY
#define GEO_NODE_DUAL_MESH
void nodeRegisterType(struct bNodeType *ntype)
#define BLI_assert_unreachable()
MINLINE void copy_v3_v3(float r[3], const float a[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
static uint8 component(Color32 c, uint i)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
ATTR_WARN_UNUSED_RESULT const BMVert * v2
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
const Mesh * get_for_read() const
IndexRange index_range() const
void reinitialize(const int64_t new_size)
MutableSpan< T > typed() const
const CPPType & type() const
VArray< T > typed() const
ItemIterator items() const
constexpr int64_t size() const
constexpr void fill(const T &value)
constexpr T & last(const int64_t n=0) const
constexpr IndexRange index_range() const
constexpr MutableSpan take_front(const int64_t n) const
void append(const T &value)
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
StringRefNull description() const
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
AttributeAccessor mesh_attributes(const Mesh &mesh)
eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh)
static void node_geo_exec(GeoNodeExecParams params)
static void node_declare(NodeDeclarationBuilder &b)
static bool sort_vertex_polys(const Mesh &mesh, const int vertex_index, const bool boundary_vertex, const Span< EdgeType > edge_types, MutableSpan< int > connected_polygons, MutableSpan< int > r_shared_edges, MutableSpan< int > r_sorted_corners)
static void calc_boundaries(const Mesh &mesh, MutableSpan< VertexType > r_vertex_types, MutableSpan< EdgeType > r_edge_types)
static void copy_data_based_on_new_to_old_map(Span< T > data, MutableSpan< T > r_data, const Span< int > new_to_old_map)
static void copy_data_based_on_pairs(Span< T > data, MutableSpan< T > r_data, const Span< std::pair< int, int >> new_to_old_map)
static EdgeType get_edge_type_with_added_neighbor(EdgeType old_type)
static void boundary_edges_on_poly(const MPoly &poly, const Mesh &mesh, const int vertex_index, const Span< EdgeType > edge_types, int &r_edge1, int &r_edge2)
static void create_vertex_poly_map(const Mesh &mesh, MutableSpan< Vector< int >> r_vertex_poly_indices)
static void add_edge(const Mesh &mesh, const int old_edge_i, const int v1, const int v2, Vector< int > &new_to_old_edges_map, Vector< MEdge > &new_edges, Vector< int > &loop_edges)
static void dissolve_redundant_verts(const Mesh &mesh, const Span< Vector< int >> vertex_poly_indices, MutableSpan< VertexType > vertex_types, MutableSpan< int > old_to_new_edges_map, Vector< MEdge > &new_edges, Vector< int > &new_to_old_edges_map)
static void copy_data_based_on_vertex_types(Span< T > data, MutableSpan< T > r_data, const Span< VertexType > vertex_types, const bool keep_boundaries)
static void calc_dual_mesh(GeometrySet &geometry_set, const MeshComponent &in_component, const bool keep_boundaries)
static VertexType get_vertex_type_with_added_neighbor(VertexType old_type)
static void transfer_attributes(const Map< AttributeIDRef, AttributeKind > &attributes, const Span< VertexType > vertex_types, const bool keep_boundaries, const Span< int > new_to_old_edges_map, const Span< int > new_to_old_face_corners_map, const Span< std::pair< int, int >> boundary_vertex_to_relevant_face_map, const AttributeAccessor src_attributes, MutableAttributeAccessor dst_attributes)
static void boundary_edge_on_poly(const MPoly &poly, const Mesh &mesh, const int vertex_index, const Span< EdgeType > edge_types, int &r_edge)
static bool vertex_needs_dissolving(const int vertex, const int first_poly_index, const int second_poly_index, const Span< VertexType > vertex_types, const Span< Vector< int >> vertex_poly_indices)
static MEdge new_edge(const int v1, const int v2)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
void register_node_type_geo_dual_mesh()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
const GeometryComponent * get_component_for_read(GeometryComponentType component_type) const
void gather_attributes_for_propagation(blender::Span< GeometryComponentType > component_types, GeometryComponentType dst_component_type, bool include_instances, blender::Map< blender::bke::AttributeIDRef, blender::bke::AttributeKind > &r_attributes) const
void modify_geometry_sets(ForeachSubGeometryCallback callback)
NodeGeometryExecFunction geometry_node_execute
NodeDeclareFunction declare