| 
						
						
							
								
							
						
						
					 | 
					@ -44,18 +44,18 @@ void compute_patch_edges(const stl_vector_mp<polygon_face_t>&    patch_faces, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					void compute_patches(const stl_vector_mp<stl_vector_mp<uint32_t>>& edges_of_face, | 
					 | 
					 | 
					void compute_patches(const stl_vector_mp<stl_vector_mp<uint32_t>>& edges_of_face, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                     const stl_vector_mp<iso_edge_t>&              patch_edges, | 
					 | 
					 | 
					                     const stl_vector_mp<iso_edge_t>&              patch_edges, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                     const stl_vector_mp<polygon_face_t>&          patch_faces, | 
					 | 
					 | 
					                     const stl_vector_mp<polygon_face_t>&          patch_faces, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                     stl_vector_mp<stl_vector_mp<uint32_t>>&       patches, | 
					 | 
					 | 
					                     flat_index_group_t&                           patches, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                     stl_vector_mp<uint32_t>&                      patch_of_face_mapping) | 
					 | 
					 | 
					                     stl_vector_mp<uint32_t>&                      patch_of_face_mapping) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					{ | 
					 | 
					 | 
					{ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    stl_vector_mp<bool> visited_face(edges_of_face.size(), false); | 
					 | 
					 | 
					    stl_vector_mp<bool> visited_face(edges_of_face.size(), false); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for (uint32_t i = 0; i < edges_of_face.size(); i++) { | 
					 | 
					 | 
					    for (uint32_t i = 0; i < edges_of_face.size(); i++) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        if (!visited_face[i]) { | 
					 | 
					 | 
					        if (!visited_face[i]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // new patch
 | 
					 | 
					 | 
					            // new patch
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            auto&                patch    = patches.emplace_back(); | 
					 | 
					 | 
					            const auto patch_id = static_cast<uint32_t>(patches.size()); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            const auto           patch_id = static_cast<uint32_t>(patches.size() - 1); | 
					 | 
					 | 
					            patches.start_indices.emplace_back(patch_id); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            std::queue<uint32_t> Q{}; | 
					 | 
					 | 
					            std::queue<uint32_t> Q{}; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Q.emplace(i); | 
					 | 
					 | 
					            Q.emplace(i); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            patch.emplace_back(i); | 
					 | 
					 | 
					            patches.index_group.emplace_back(i); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            visited_face[i]          = true; | 
					 | 
					 | 
					            visited_face[i]          = true; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            patch_of_face_mapping[i] = patch_id; | 
					 | 
					 | 
					            patch_of_face_mapping[i] = patch_id; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            while (!Q.empty()) { | 
					 | 
					 | 
					            while (!Q.empty()) { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -68,7 +68,7 @@ void compute_patches(const stl_vector_mp<stl_vector_mp<uint32_t>>& edges_of_face | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                                                   : patch_edges[eId].headers[0].face_index; | 
					 | 
					 | 
					                                                   : patch_edges[eId].headers[0].face_index; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        if (!visited_face[other_fId]) { | 
					 | 
					 | 
					                        if (!visited_face[other_fId]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                            Q.emplace(other_fId); | 
					 | 
					 | 
					                            Q.emplace(other_fId); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                            patch.emplace_back(other_fId); | 
					 | 
					 | 
					                            patches.index_group.emplace_back(other_fId); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                            patch_of_face_mapping[other_fId] = patch_id; | 
					 | 
					 | 
					                            patch_of_face_mapping[other_fId] = patch_id; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                            visited_face[other_fId]          = true; | 
					 | 
					 | 
					                            visited_face[other_fId]          = true; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        } | 
					 | 
					 | 
					                        } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -77,11 +77,13 @@ void compute_patches(const stl_vector_mp<stl_vector_mp<uint32_t>>& edges_of_face | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    patches.start_indices.emplace_back(static_cast<uint32_t>(patches.index_group.size())); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					void compute_chains(size_t                                  iso_vert_count, | 
					 | 
					 | 
					void compute_chains(size_t                     iso_vert_count, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					                    stl_vector_mp<iso_edge_t>&              patch_edges, | 
					 | 
					 | 
					                    stl_vector_mp<iso_edge_t>& patch_edges, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					                    stl_vector_mp<stl_list_mp<iso_edge_t>>& chains) | 
					 | 
					 | 
					                    flat_index_group_t&        chains, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    stl_vector_mp<iso_edge_t>& chain_representative_headers) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					{ | 
					 | 
					 | 
					{ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    stl_vector_mp<stl_vector_mp<uint32_t>> non_manifold_edges_of_vert{}; | 
					 | 
					 | 
					    stl_vector_mp<stl_vector_mp<uint32_t>> non_manifold_edges_of_vert{}; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    stl_vector_mp<uint32_t>                non_manifold_edges{}; | 
					 | 
					 | 
					    stl_vector_mp<uint32_t>                non_manifold_edges{}; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -98,16 +100,32 @@ void compute_chains(size_t                                  iso_vert_count, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // NOTE: the rule of building chains here in brief:
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // HINT: the chains can be seen as intersection edges of patches
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // CONCEPT: the non-manifold edges where vertices do not have branches are called 'trivial';
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //          the non-manifold edges where vertices have branches (i.e. intersection of chains) are called 'singular', and the
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //          vertices are also called 'singular'.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // 1. each chain can start from arbitary vertex of a non-manifold edge, and end at visited edge (i.e. a ring is built) or
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // singular vertex;
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // 2. along each chain, the neighboring patch does not change, otherwise a new chain is raised.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    stl_vector_mp<bool> visited_edge(patch_edges.size(), false); | 
					 | 
					 | 
					    stl_vector_mp<bool> visited_edge(patch_edges.size(), false); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    std::list<uint32_t> chain_edges{}; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    chains.index_group.reserve(non_manifold_edges.size() * 2); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    chains.start_indices.reserve(8); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    chain_representative_headers.reserve(8); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for (const auto& i : non_manifold_edges) { | 
					 | 
					 | 
					    for (const auto& i : non_manifold_edges) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        if (!visited_edge[i]) { | 
					 | 
					 | 
					        if (!visited_edge[i]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // unvisited non-manifold iso-edge (not a boundary edge)
 | 
					 | 
					 | 
					            // unvisited non-manifold iso-edge (not a boundary edge)
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // new chain
 | 
					 | 
					 | 
					            // new chain
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            auto&                chain = chains.emplace_back(); | 
					 | 
					 | 
					            chains.start_indices.emplace_back(static_cast<uint32_t>(chains.index_group.size())); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            auto&                edge = patch_edges[i]; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            std::queue<uint32_t> Q{}; | 
					 | 
					 | 
					            std::queue<uint32_t> Q{}; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Q.emplace(i); | 
					 | 
					 | 
					            Q.emplace(i); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            chain.emplace_back(std::move(patch_edges[i])); | 
					 | 
					 | 
					            chain_edges.emplace_back(edge.v1); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            chain_edges.emplace_back(edge.v2); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            chain_representative_headers.emplace_back(edge); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            visited_edge[i] = true; | 
					 | 
					 | 
					            visited_edge[i] = true; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            chain_edges.clear(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            while (!Q.empty()) { | 
					 | 
					 | 
					            while (!Q.empty()) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                const auto eId = Q.front(); | 
					 | 
					 | 
					                const auto eId = Q.front(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                Q.pop(); | 
					 | 
					 | 
					                Q.pop(); | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -116,9 +134,21 @@ void compute_chains(size_t                                  iso_vert_count, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                if (non_manifold_edges_of_vert[v].size() == 2) { | 
					 | 
					 | 
					                if (non_manifold_edges_of_vert[v].size() == 2) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    const auto other_eId = (non_manifold_edges_of_vert[v][0] == eId) ? non_manifold_edges_of_vert[v][1] | 
					 | 
					 | 
					                    const auto other_eId = (non_manifold_edges_of_vert[v][0] == eId) ? non_manifold_edges_of_vert[v][1] | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                                                                                     : non_manifold_edges_of_vert[v][0]; | 
					 | 
					 | 
					                                                                                     : non_manifold_edges_of_vert[v][0]; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    edge = patch_edges[other_eId]; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    if (!visited_edge[other_eId]) { | 
					 | 
					 | 
					                    if (!visited_edge[other_eId]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        Q.emplace(other_eId); | 
					 | 
					 | 
					                        Q.emplace(other_eId); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                        chain.emplace_back(std::move(patch_edges[other_eId])); | 
					 | 
					 | 
					                        if (v == chain_edges.front()) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                            if (v == edge.v1) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                                chain_edges.emplace_front(edge.v2); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                            else | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                                chain_edges.emplace_front(edge.v1); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                        } else { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                            if (v == edge.v1) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                                chain_edges.emplace_front(edge.v2); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                            else | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                                chain_edges.emplace_front(edge.v1); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        visited_edge[other_eId] = true; | 
					 | 
					 | 
					                        visited_edge[other_eId] = true; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    } | 
					 | 
					 | 
					                    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                } | 
					 | 
					 | 
					                } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -127,21 +157,40 @@ void compute_chains(size_t                                  iso_vert_count, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                if (non_manifold_edges_of_vert[v].size() == 2) { | 
					 | 
					 | 
					                if (non_manifold_edges_of_vert[v].size() == 2) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    const auto other_eId = (non_manifold_edges_of_vert[v][0] == eId) ? non_manifold_edges_of_vert[v][1] | 
					 | 
					 | 
					                    const auto other_eId = (non_manifold_edges_of_vert[v][0] == eId) ? non_manifold_edges_of_vert[v][1] | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                                                                                     : non_manifold_edges_of_vert[v][0]; | 
					 | 
					 | 
					                                                                                     : non_manifold_edges_of_vert[v][0]; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    edge                 = patch_edges[other_eId]; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    if (!visited_edge[other_eId]) { | 
					 | 
					 | 
					                    if (!visited_edge[other_eId]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        Q.emplace(other_eId); | 
					 | 
					 | 
					                        Q.emplace(other_eId); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                        chain.emplace_back(std::move(patch_edges[other_eId])); | 
					 | 
					 | 
					                        if (v == chain_edges.front()) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                            if (v == edge.v1) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                                chain_edges.emplace_front(edge.v2); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                            else | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                                chain_edges.emplace_front(edge.v1); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                        } else { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                            if (v == edge.v1) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                                chain_edges.emplace_front(edge.v2); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                            else | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                                chain_edges.emplace_front(edge.v1); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        visited_edge[other_eId] = true; | 
					 | 
					 | 
					                        visited_edge[other_eId] = true; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    } | 
					 | 
					 | 
					                    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                } | 
					 | 
					 | 
					                } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            // add chain edges to chains.index_group
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            chains.index_group.insert(chains.index_group.end(), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                                      std::make_move_iterator(chain_edges.begin()), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                                      std::make_move_iterator(chain_edges.end())); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    chains.start_indices.emplace_back(static_cast<uint32_t>(chains.index_group.size())); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    chains.start_indices.shrink_to_fit(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    chains.index_group.shrink_to_fit(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& half_patch_adj_list, | 
					 | 
					 | 
					void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& half_patch_adj_list, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                                   stl_vector_mp<stl_vector_mp<uint32_t>>&       shells, | 
					 | 
					 | 
					                                   flat_index_group_t&                           shells, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                                   stl_vector_mp<uint32_t>&                      shell_of_half_patch, | 
					 | 
					 | 
					                                   stl_vector_mp<uint32_t>&                      shell_of_half_patch, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                                   stl_vector_mp<stl_vector_mp<uint32_t>>&       components, | 
					 | 
					 | 
					                                   flat_index_group_t&                           components, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                                   stl_vector_mp<uint32_t>&                      component_of_patch) | 
					 | 
					 | 
					                                   stl_vector_mp<uint32_t>&                      component_of_patch) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					{ | 
					 | 
					 | 
					{ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    const auto          num_patch = half_patch_adj_list.size() / 2; | 
					 | 
					 | 
					    const auto          num_patch = half_patch_adj_list.size() / 2; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -152,11 +201,11 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for (uint32_t i = 0; i < 2 * num_patch; i++) { | 
					 | 
					 | 
					    for (uint32_t i = 0; i < 2 * num_patch; i++) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        if (!visited_flags[i]) { | 
					 | 
					 | 
					        if (!visited_flags[i]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // create new component
 | 
					 | 
					 | 
					            // create new component
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            const uint32_t       shell_Id = static_cast<uint32_t>(shells.size()); | 
					 | 
					 | 
					            const auto shell_Id = static_cast<uint32_t>(shells.size()); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            auto&                shell    = shells.emplace_back(); | 
					 | 
					 | 
					            shells.start_indices.emplace_back(shell_Id); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            std::queue<uint32_t> Q{}; | 
					 | 
					 | 
					            std::queue<uint32_t> Q{}; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Q.emplace(i); | 
					 | 
					 | 
					            Q.emplace(i); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            shell.emplace_back(i); | 
					 | 
					 | 
					            shells.index_group.emplace_back(i); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            shell_of_half_patch[i] = shell_Id; | 
					 | 
					 | 
					            shell_of_half_patch[i] = shell_Id; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            visited_flags[i]       = true; | 
					 | 
					 | 
					            visited_flags[i]       = true; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            while (!Q.empty()) { | 
					 | 
					 | 
					            while (!Q.empty()) { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -164,7 +213,7 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                Q.pop(); | 
					 | 
					 | 
					                Q.pop(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                for (auto hp : half_patch_adj_list[half_patch]) { | 
					 | 
					 | 
					                for (auto hp : half_patch_adj_list[half_patch]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    if (!visited_flags[hp]) { | 
					 | 
					 | 
					                    if (!visited_flags[hp]) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                        shell.emplace_back(hp); | 
					 | 
					 | 
					                        shells.index_group.emplace_back(hp); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                        shell_of_half_patch[hp] = shell_Id; | 
					 | 
					 | 
					                        shell_of_half_patch[hp] = shell_Id; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        Q.emplace(hp); | 
					 | 
					 | 
					                        Q.emplace(hp); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        visited_flags[hp] = true; | 
					 | 
					 | 
					                        visited_flags[hp] = true; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -173,20 +222,21 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    shells.start_indices.emplace_back(static_cast<uint32_t>(shells.index_group.size())); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // find connected component of patch-adjacency graph
 | 
					 | 
					 | 
					    // find connected component of patch-adjacency graph
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // each component is an iso-surface component
 | 
					 | 
					 | 
					    // each component is an iso-surface component
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    visited_flags.clear(); | 
					 | 
					 | 
					    visited_flags.clear(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    visited_flags.resize(num_patch, false); | 
					 | 
					 | 
					    visited_flags.resize(num_patch, false); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    components.clear(); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    component_of_patch.resize(num_patch); | 
					 | 
					 | 
					    component_of_patch.resize(num_patch); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for (uint32_t i = 0; i < num_patch; i++) { | 
					 | 
					 | 
					    for (uint32_t i = 0; i < num_patch; i++) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        if (!visited_flags[i]) { | 
					 | 
					 | 
					        if (!visited_flags[i]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // create new component
 | 
					 | 
					 | 
					            // create new component
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            const uint32_t       component_Id = static_cast<uint32_t>(components.size()); | 
					 | 
					 | 
					            const auto component_Id = static_cast<uint32_t>(components.size()); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            auto&                component    = components.emplace_back(); | 
					 | 
					 | 
					            components.start_indices.emplace_back(component_Id); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            std::queue<uint32_t> Q{}; | 
					 | 
					 | 
					            std::queue<uint32_t> Q{}; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Q.emplace(i); | 
					 | 
					 | 
					            Q.emplace(i); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            component.emplace_back(i); | 
					 | 
					 | 
					            components.index_group.emplace_back(i); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            component_of_patch[i] = component_Id; | 
					 | 
					 | 
					            component_of_patch[i] = component_Id; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            visited_flags[i]      = true; | 
					 | 
					 | 
					            visited_flags[i]      = true; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            while (!Q.empty()) { | 
					 | 
					 | 
					            while (!Q.empty()) { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -196,7 +246,7 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                for (auto hp : half_patch_adj_list[2 * patch]) { | 
					 | 
					 | 
					                for (auto hp : half_patch_adj_list[2 * patch]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    if (!visited_flags[hp / 2]) { | 
					 | 
					 | 
					                    if (!visited_flags[hp / 2]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        const auto p = hp / 2; | 
					 | 
					 | 
					                        const auto p = hp / 2; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                        component.emplace_back(p); | 
					 | 
					 | 
					                        components.index_group.emplace_back(p); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                        component_of_patch[p] = component_Id; | 
					 | 
					 | 
					                        component_of_patch[p] = component_Id; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        Q.emplace(p); | 
					 | 
					 | 
					                        Q.emplace(p); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        visited_flags[p] = true; | 
					 | 
					 | 
					                        visited_flags[p] = true; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -206,7 +256,7 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                for (auto hp : half_patch_adj_list[2 * patch + 1]) { | 
					 | 
					 | 
					                for (auto hp : half_patch_adj_list[2 * patch + 1]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    if (!visited_flags[hp / 2]) { | 
					 | 
					 | 
					                    if (!visited_flags[hp / 2]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        const auto p = hp / 2; | 
					 | 
					 | 
					                        const auto p = hp / 2; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                        component.emplace_back(p); | 
					 | 
					 | 
					                        components.index_group.emplace_back(p); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                        component_of_patch[p] = component_Id; | 
					 | 
					 | 
					                        component_of_patch[p] = component_Id; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        Q.emplace(p); | 
					 | 
					 | 
					                        Q.emplace(p); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        visited_flags[p] = true; | 
					 | 
					 | 
					                        visited_flags[p] = true; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -215,6 +265,8 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    components.start_indices.emplace_back(static_cast<uint32_t>(components.index_group.size())); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // get shells as list of patch indices
 | 
					 | 
					 | 
					    // get shells as list of patch indices
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    //    for (auto& shell : shells) {
 | 
					 | 
					 | 
					    //    for (auto& shell : shells) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    //        for (auto& pId : shell) {
 | 
					 | 
					 | 
					    //        for (auto& pId : shell) {
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -225,7 +277,7 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					void compute_arrangement_cells(uint32_t                                            num_shell, | 
					 | 
					 | 
					void compute_arrangement_cells(uint32_t                                            num_shell, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                               const stl_vector_mp<std::pair<uint32_t, uint32_t>>& shell_links, | 
					 | 
					 | 
					                               const stl_vector_mp<std::pair<uint32_t, uint32_t>>& shell_links, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                               stl_vector_mp<stl_vector_mp<uint32_t>>&             arrangement_cells) | 
					 | 
					 | 
					                               flat_index_group_t&                                 arrangement_cells) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					{ | 
					 | 
					 | 
					{ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // build shell adjacency list
 | 
					 | 
					 | 
					    // build shell adjacency list
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uint32_t                                          sink_shell = num_shell; | 
					 | 
					 | 
					    uint32_t                                          sink_shell = num_shell; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -250,17 +302,17 @@ void compute_arrangement_cells(uint32_t | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for (uint32_t i = 0; i < num_shell + 1; ++i) { | 
					 | 
					 | 
					    for (uint32_t i = 0; i < num_shell + 1; ++i) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        if (!visited_shell[i]) { | 
					 | 
					 | 
					        if (!visited_shell[i]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // create new component
 | 
					 | 
					 | 
					            // create new component
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            auto&                arr_cell = arrangement_cells.emplace_back(); | 
					 | 
					 | 
					            arrangement_cells.start_indices.emplace_back(static_cast<uint32_t>(arrangement_cells.size())); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            std::queue<uint32_t> Q{}; | 
					 | 
					 | 
					            std::queue<uint32_t> Q{}; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Q.emplace(i); | 
					 | 
					 | 
					            Q.emplace(i); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            arr_cell.emplace_back(i); | 
					 | 
					 | 
					            arrangement_cells.index_group.emplace_back(i); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            visited_shell[i] = true; | 
					 | 
					 | 
					            visited_shell[i] = true; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            while (!Q.empty()) { | 
					 | 
					 | 
					            while (!Q.empty()) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                const auto shell_id = Q.front(); | 
					 | 
					 | 
					                const auto shell_id = Q.front(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                Q.pop(); | 
					 | 
					 | 
					                Q.pop(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                for (const auto s : adjacent_shells[shell_id]) { | 
					 | 
					 | 
					                for (const auto s : adjacent_shells[shell_id]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    if (!visited_shell[s]) { | 
					 | 
					 | 
					                    if (!visited_shell[s]) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                        arr_cell.emplace_back(s); | 
					 | 
					 | 
					                        arrangement_cells.index_group.emplace_back(s); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                        Q.emplace(s); | 
					 | 
					 | 
					                        Q.emplace(s); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        visited_shell[s] = true; | 
					 | 
					 | 
					                        visited_shell[s] = true; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    } | 
					 | 
					 | 
					                    } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -270,13 +322,21 @@ void compute_arrangement_cells(uint32_t | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // remove sink shell from arrangement cells
 | 
					 | 
					 | 
					    // remove sink shell from arrangement cells
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    stl_vector_mp<uint32_t> sink_free_shell_list{}; | 
					 | 
					 | 
					    flat_index_group_t sink_free_cells{}; | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    for (auto& arr_cell : arrangement_cells) { | 
					 | 
					 | 
					    sink_free_cells.index_group.reserve(arrangement_cells.index_group.size()); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        sink_free_shell_list.clear(); | 
					 | 
					 | 
					    sink_free_cells.start_indices.reserve(arrangement_cells.size() + 1); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        for (const auto s : arr_cell) { | 
					 | 
					 | 
					    sink_free_cells.start_indices.emplace_back(0); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            if (s < num_shell) { sink_free_shell_list.emplace_back(s); } | 
					 | 
					 | 
					    sink_free_cells.group_foreach([&](uint32_t group_idx, uint32_t range_start, uint32_t range_end) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        if (sink_free_cells.index_group.size() > sink_free_cells.start_indices.back()) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            sink_free_cells.start_indices.emplace_back(static_cast<uint32_t>(sink_free_cells.index_group.size())); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        // arr_cell = sink_free_shell_list;
 | 
					 | 
					 | 
					        for (auto i = range_start; i < range_end; ++i) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        std::swap(arr_cell, sink_free_shell_list); | 
					 | 
					 | 
					            if (arrangement_cells.index_group[i] < num_shell) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    } | 
					 | 
					 | 
					                sink_free_cells.index_group.emplace_back(arrangement_cells.index_group[i]); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    }); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    sink_free_cells.index_group.shrink_to_fit(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    sink_free_cells.start_indices.shrink_to_fit(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    std::swap(arrangement_cells, sink_free_cells); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} |