132 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			132 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * ***** BEGIN GPL LICENSE BLOCK *****
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This program is free software; you can redistribute it and/or
							 | 
						||
| 
								 | 
							
								 * modify it under the terms of the GNU General Public License
							 | 
						||
| 
								 | 
							
								 * as published by the Free Software Foundation; either version 2
							 | 
						||
| 
								 | 
							
								 * of the License, or (at your option) any later version.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This program is distributed in the hope that it will be useful,
							 | 
						||
| 
								 | 
							
								 * but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						||
| 
								 | 
							
								 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						||
| 
								 | 
							
								 * GNU General Public License for more details.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * You should have received a copy of the GNU General Public License
							 | 
						||
| 
								 | 
							
								 * along with this program; if not, write to the Free Software Foundation,
							 | 
						||
| 
								 | 
							
								 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * ***** END GPL LICENSE BLOCK *****
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** \file blender/bmesh/tools/bmesh_separate.c
							 | 
						||
| 
								 | 
							
								 *  \ingroup bmesh
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * BMesh separate, disconnects a set of faces from all others,
							 | 
						||
| 
								 | 
							
								 * so they don't share any vertices/edges with other faces.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <limits.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "MEM_guardedalloc.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "BLI_utildefines.h"
							 | 
						||
| 
								 | 
							
								#include "BLI_buffer.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "bmesh.h"
							 | 
						||
| 
								 | 
							
								#include "intern/bmesh_private.h"
							 | 
						||
| 
								 | 
							
								#include "bmesh_separate.h"  /* own include */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Split all faces that match `filter_fn`.
							 | 
						||
| 
								 | 
							
								 * \note
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								void BM_mesh_separate_faces(
							 | 
						||
| 
								 | 
							
								        BMesh *bm,
							 | 
						||
| 
								 | 
							
								        BMFaceFilterFunc filter_fn, void *user_data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									BMFace **faces_array_all = MEM_mallocN(bm->totface * sizeof(BMFace *), __func__);
							 | 
						||
| 
								 | 
							
									/*
							 | 
						||
| 
								 | 
							
									 * - Create an array of faces based on 'filter_fn'.
							 | 
						||
| 
								 | 
							
									 *   First part of array for match, for non-match.
							 | 
						||
| 
								 | 
							
									 *
							 | 
						||
| 
								 | 
							
									 * - Clear all vertex tags, then tag all vertices from 'faces_b'.
							 | 
						||
| 
								 | 
							
									 *
							 | 
						||
| 
								 | 
							
									 * - Loop over 'faces_a', checking each vertex,
							 | 
						||
| 
								 | 
							
									 *   splitting out any which are tagged (and therefor shared).
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									BMFace *f;
							 | 
						||
| 
								 | 
							
									BMIter iter;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									unsigned int faces_a_len = 0;
							 | 
						||
| 
								 | 
							
									unsigned int faces_b_len = 0;
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										int i_a = 0;
							 | 
						||
| 
								 | 
							
										int i_b = bm->totface;
							 | 
						||
| 
								 | 
							
										BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
							 | 
						||
| 
								 | 
							
											faces_array_all[filter_fn(f, user_data) ? i_a++ : --i_b] = f;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										faces_a_len = i_a;
							 | 
						||
| 
								 | 
							
										faces_b_len = bm->totface - i_a;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									BMFace **faces_a = faces_array_all;
							 | 
						||
| 
								 | 
							
									BMFace **faces_b = faces_array_all + faces_a_len;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Enable for all  */
							 | 
						||
| 
								 | 
							
									BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Disable vert tag on faces_b */
							 | 
						||
| 
								 | 
							
									for (unsigned int i = 0; i < faces_b_len; i++) {
							 | 
						||
| 
								 | 
							
										BMLoop *l_iter, *l_first;
							 | 
						||
| 
								 | 
							
										l_iter = l_first = BM_FACE_FIRST_LOOP(faces_b[i]);
							 | 
						||
| 
								 | 
							
										do {
							 | 
						||
| 
								 | 
							
											BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG);
							 | 
						||
| 
								 | 
							
										} while ((l_iter = l_iter->next) != l_first);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									BLI_buffer_declare_static(BMLoop **, loop_split, 0, 128);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Check shared verts ('faces_a' tag and disable) */
							 | 
						||
| 
								 | 
							
									for (unsigned int i = 0; i < faces_a_len; i++) {
							 | 
						||
| 
								 | 
							
										BMLoop *l_iter, *l_first;
							 | 
						||
| 
								 | 
							
										l_iter = l_first = BM_FACE_FIRST_LOOP(faces_a[i]);
							 | 
						||
| 
								 | 
							
										do {
							 | 
						||
| 
								 | 
							
											if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
							 | 
						||
| 
								 | 
							
												BMVert *v = l_iter->v;
							 | 
						||
| 
								 | 
							
												/* Disable, since we may visit this vertex again on other faces */
							 | 
						||
| 
								 | 
							
												BM_elem_flag_disable(v, BM_ELEM_TAG);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												/* We know the vertex is shared, collect all vertices and split them off. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												/* Fill 'loop_split' */
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													BMEdge *e_first, *e_iter;
							 | 
						||
| 
								 | 
							
													e_iter = e_first = l_iter->e;
							 | 
						||
| 
								 | 
							
													do {
							 | 
						||
| 
								 | 
							
														BMLoop *l_radial_first, *l_radial_iter;
							 | 
						||
| 
								 | 
							
														l_radial_first = l_radial_iter = e_iter->l;
							 | 
						||
| 
								 | 
							
														do {
							 | 
						||
| 
								 | 
							
															if (l_radial_iter->v == v) {
							 | 
						||
| 
								 | 
							
																if (filter_fn(l_radial_iter->f, user_data)) {
							 | 
						||
| 
								 | 
							
																	BLI_buffer_append(&loop_split, BMLoop *, l_radial_iter);
							 | 
						||
| 
								 | 
							
																}
							 | 
						||
| 
								 | 
							
															}
							 | 
						||
| 
								 | 
							
														} while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
							 | 
						||
| 
								 | 
							
													} while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												/* Perform the split */
							 | 
						||
| 
								 | 
							
												bmesh_urmv_loop_multi(bm, loop_split.data, loop_split.count);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												BLI_buffer_empty(&loop_split);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										} while ((l_iter = l_iter->next) != l_first);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									BLI_buffer_free(&loop_split);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									MEM_freeN(faces_array_all);
							 | 
						||
| 
								 | 
							
								}
							 |