=bmesh= fixed edge split modifier, and a bug in knifetool reported by letterrip. also brought back beautify-fill.

This commit is contained in:
Joseph Eagar 2011-04-22 23:37:58 +00:00
parent 2a24370bab
commit 133a1c2699
11 changed files with 177 additions and 265 deletions

@ -45,7 +45,11 @@ class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel):
# the mt.type enum is (ab)used for a lookup on function names
# ...to avoid lengthy if statements
# so each type must have a function here.
def NGONINTERP(self, layout, ob, md):
split = layout.split()
split.prop(md, "resolution")
def ARMATURE(self, layout, ob, md):
split = layout.split()

@ -2748,7 +2748,10 @@ void CDDM_tessfaces_to_faces(DerivedMesh *dm)
void CDDM_set_mvert(DerivedMesh *dm, MVert *mvert)
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
if (!CustomData_has_layer(&dm->vertData, CD_MVERT))
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, mvert, dm->numVertData);
cddm->mvert = mvert;
}
@ -2756,6 +2759,9 @@ void CDDM_set_medge(DerivedMesh *dm, MEdge *medge)
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE))
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, medge, dm->numEdgeData);
cddm->medge = medge;
}
@ -2763,5 +2769,8 @@ void CDDM_set_mface(DerivedMesh *dm, MFace *mface)
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
if (!CustomData_has_layer(&dm->faceData, CD_MFACE))
CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, mface, dm->numFaceData);
cddm->mface = mface;
}

@ -70,6 +70,8 @@ void closest_to_line_segment_v3(float r[3], float p[3], float l1[3], float l2[3]
/* TODO int return value consistency */
int is_quad_convex_v3(float *v1, float *v2, float *v3, float *v4);
/* line-line */
#define ISECT_LINE_LINE_COLINEAR -1
#define ISECT_LINE_LINE_NONE 0

@ -2678,3 +2678,39 @@ float form_factor_hemi_poly(float p[3], float n[3], float v1[3], float v2[3], fl
return contrib;
}
/* evaluate if entire quad is a proper convex quad */
int is_quad_convex_v3(float *v1, float *v2, float *v3, float *v4)
{
float nor[3], nor1[3], nor2[3], vec[4][2];
/* define projection, do both trias apart, quad is undefined! */
normal_tri_v3( nor1,v1, v2, v3);
normal_tri_v3( nor2,v1, v3, v4);
nor[0]= ABS(nor1[0]) + ABS(nor2[0]);
nor[1]= ABS(nor1[1]) + ABS(nor2[1]);
nor[2]= ABS(nor1[2]) + ABS(nor2[2]);
if(nor[2] >= nor[0] && nor[2] >= nor[1]) {
vec[0][0]= v1[0]; vec[0][1]= v1[1];
vec[1][0]= v2[0]; vec[1][1]= v2[1];
vec[2][0]= v3[0]; vec[2][1]= v3[1];
vec[3][0]= v4[0]; vec[3][1]= v4[1];
}
else if(nor[1] >= nor[0] && nor[1]>= nor[2]) {
vec[0][0]= v1[0]; vec[0][1]= v1[2];
vec[1][0]= v2[0]; vec[1][1]= v2[2];
vec[2][0]= v3[0]; vec[2][1]= v3[2];
vec[3][0]= v4[0]; vec[3][1]= v4[2];
}
else {
vec[0][0]= v1[1]; vec[0][1]= v1[2];
vec[1][0]= v2[1]; vec[1][1]= v2[2];
vec[2][0]= v3[1]; vec[2][1]= v3[2];
vec[3][0]= v4[1]; vec[3][1]= v4[2];
}
/* linetests, the 2 diagonals have to instersect to be convex */
if( isect_line_line_v2(vec[0], vec[2], vec[1], vec[3]) > 0 ) return 1;
return 0;
}

@ -940,6 +940,21 @@ BMOpDefine def_bevel = {
BMOP_UNTAN_MULTIRES
};
/*
Beautify Fill
Makes triangle a bit nicer
*/
BMOpDefine def_beautify_fill = {
"beautify_fill",
{{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, /* input faces */
{BMOP_OPSLOT_ELEMENT_BUF, "constrain_edges"}, /* edges that can't be flipped */
{BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, /* new flipped faces and edges */
{0} /*null-terminating sentinel*/},
bmesh_beautify_fill_exec,
BMOP_UNTAN_MULTIRES
};
BMOpDefine *opdefines[] = {
&def_splitop,
&def_dupeop,
@ -1000,6 +1015,7 @@ BMOpDefine *opdefines[] = {
&def_create_cube,
&def_join_triangles,
&def_bevel,
&def_beautify_fill,
};
int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*));

@ -69,5 +69,6 @@ void bmesh_create_grid_exec(BMesh *bm, BMOperator *op);
void bmesh_create_cube_exec(BMesh *bm, BMOperator *op);
void bmesh_jointriangles_exec(BMesh *bm, BMOperator *op);
void bmesh_bevel_exec(BMesh *bm, BMOperator *op);
void bmesh_beautify_fill_exec(BMesh *bm, BMOperator *op);
#endif

@ -964,42 +964,6 @@ void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op)
MEM_freeN(vdata);
}
/* evaluate if entire quad is a proper convex quad */
static int convex(float *v1, float *v2, float *v3, float *v4)
{
float nor[3], nor1[3], nor2[3], vec[4][2];
/* define projection, do both trias apart, quad is undefined! */
normal_tri_v3( nor1,v1, v2, v3);
normal_tri_v3( nor2,v1, v3, v4);
nor[0]= ABS(nor1[0]) + ABS(nor2[0]);
nor[1]= ABS(nor1[1]) + ABS(nor2[1]);
nor[2]= ABS(nor1[2]) + ABS(nor2[2]);
if(nor[2] >= nor[0] && nor[2] >= nor[1]) {
vec[0][0]= v1[0]; vec[0][1]= v1[1];
vec[1][0]= v2[0]; vec[1][1]= v2[1];
vec[2][0]= v3[0]; vec[2][1]= v3[1];
vec[3][0]= v4[0]; vec[3][1]= v4[1];
}
else if(nor[1] >= nor[0] && nor[1]>= nor[2]) {
vec[0][0]= v1[0]; vec[0][1]= v1[2];
vec[1][0]= v2[0]; vec[1][1]= v2[2];
vec[2][0]= v3[0]; vec[2][1]= v3[2];
vec[3][0]= v4[0]; vec[3][1]= v4[2];
}
else {
vec[0][0]= v1[1]; vec[0][1]= v1[2];
vec[1][0]= v2[1]; vec[1][1]= v2[2];
vec[2][0]= v3[1]; vec[2][1]= v3[2];
vec[3][0]= v4[1]; vec[3][1]= v4[2];
}
/* linetests, the 2 diagonals have to instersect to be convex */
if( isect_line_line_v2(vec[0], vec[2], vec[1], vec[3]) > 0 ) return 1;
return 0;
}
BMEdge *edge_next(BMesh *bm, BMEdge *e)
{
BMIter iter;
@ -1257,22 +1221,22 @@ void bmesh_contextual_create_exec(BMesh *bm, BMOperator *op)
f = NULL;
/* the order of vertices can be anything, 6 cases to check */
if( convex(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co) ) {
if( is_quad_convex_v3(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co) ) {
f= BM_Make_QuadTri(bm, verts[0], verts[1], verts[2], verts[3], NULL, 1);
}
else if( convex(verts[0]->co, verts[2]->co, verts[3]->co, verts[1]->co) ) {
else if( is_quad_convex_v3(verts[0]->co, verts[2]->co, verts[3]->co, verts[1]->co) ) {
f= BM_Make_QuadTri(bm, verts[0], verts[2], verts[3], verts[1], NULL, 1);
}
else if( convex(verts[0]->co, verts[2]->co, verts[1]->co, verts[3]->co) ) {
else if( is_quad_convex_v3(verts[0]->co, verts[2]->co, verts[1]->co, verts[3]->co) ) {
f= BM_Make_QuadTri(bm, verts[0], verts[2], verts[1], verts[3], NULL, 1);
}
else if( convex(verts[0]->co, verts[1]->co, verts[3]->co, verts[2]->co) ) {
else if( is_quad_convex_v3(verts[0]->co, verts[1]->co, verts[3]->co, verts[2]->co) ) {
f= BM_Make_QuadTri(bm, verts[0], verts[1], verts[3], verts[2], NULL, 1);
}
else if( convex(verts[0]->co, verts[3]->co, verts[2]->co, verts[1]->co) ) {
else if( is_quad_convex_v3(verts[0]->co, verts[3]->co, verts[2]->co, verts[1]->co) ) {
f= BM_Make_QuadTri(bm, verts[0], verts[3], verts[2], verts[1], NULL, 1);
}
else if( convex(verts[0]->co, verts[3]->co, verts[1]->co, verts[2]->co) ) {
else if( is_quad_convex_v3(verts[0]->co, verts[3]->co, verts[1]->co, verts[2]->co) ) {
f= BM_Make_QuadTri(bm, verts[0], verts[3], verts[1], verts[2], NULL, 1);
}
else {

@ -14,6 +14,10 @@
#define EDGE_NEW 1
#define FACE_NEW 1
#define ELE_NEW 1
#define FACE_MARK 2
#define EDGE_MARK 4
void triangulate_exec(BMesh *bm, BMOperator *op)
{
BMOIter siter;
@ -54,3 +58,73 @@ void triangulate_exec(BMesh *bm, BMOperator *op)
BLI_array_free(projectverts);
BLI_array_free(newfaces);
}
void bmesh_beautify_fill_exec(BMesh *bm, BMOperator *op)
{
BMOIter siter;
BMIter iter;
BMFace *f;
BMEdge *e;
int stop=0;
BMO_Flag_Buffer(bm, op, "constrain_edges", EDGE_MARK, BM_EDGE);
BMO_ITER(f, &siter, bm, op, "faces", BM_FACE) {
if (f->len == 3)
BMO_SetFlag(bm, f, FACE_MARK);
}
while (!stop) {
stop = 1;
BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
BMVert *v1, *v2, *v3, *v4, *d1, *d2;
float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
int ok;
if (BM_Edge_FaceCount(e) != 2 || BMO_TestFlag(bm, e, EDGE_MARK))
continue;
if (!BMO_TestFlag(bm, e->l->f, FACE_MARK) || !BMO_TestFlag(bm, e->l->radial_next->f, FACE_MARK))
continue;
v1 = e->l->prev->v;
v2 = e->l->v;
v3 = e->l->radial_next->prev->v;
v4 = e->l->next->v;
if (is_quad_convex_v3(v1->co, v2->co, v3->co, v4->co)) {
/* testing rule:
* the area divided by the total edge lengths
*/
len1= len_v3v3(v1->co, v2->co);
len2= len_v3v3(v2->co, v3->co);
len3= len_v3v3(v3->co, v4->co);
len4= len_v3v3(v4->co, v1->co);
len5= len_v3v3(v1->co, v3->co);
len6= len_v3v3(v2->co, v4->co);
opp1= area_tri_v3(v1->co, v2->co, v3->co);
opp2= area_tri_v3(v1->co, v3->co, v4->co);
fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5);
opp1= area_tri_v3(v2->co, v3->co, v4->co);
opp2= area_tri_v3(v2->co, v4->co, v1->co);
fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6);
ok = 0;
if (fac1 > fac2) {
e = BM_Rotate_Edge(bm, e, 0);
BMO_SetFlag(bm, e, ELE_NEW);
BMO_SetFlag(bm, e->l->f, FACE_MARK|ELE_NEW);
BMO_SetFlag(bm, e->l->radial_next->f, FACE_MARK|ELE_NEW);
stop = 0;
}
}
}
}
BMO_Flag_To_Slot(bm, op, "geomout", ELE_NEW, BM_EDGE|BM_FACE);
}

@ -3884,19 +3884,16 @@ void MESH_OT_fill(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
static int beauty_fill_exec(bContext *C, wmOperator *op)
static int beautify_fill_exec(bContext *C, wmOperator *op)
{
#if 0
Object *obedit= CTX_data_edit_object(C);
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
beauty_fill(em);
BKE_mesh_end_editmesh(obedit->data, em);
if (!EDBM_CallOpf(em, op, "beautify_fill faces=%hf", BM_SELECT))
return OPERATOR_CANCELLED;
DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
#endif
return OPERATOR_FINISHED;
}
@ -3907,7 +3904,7 @@ void MESH_OT_beautify_fill(wmOperatorType *ot)
ot->idname= "MESH_OT_beautify_fill";
/* api callbacks */
ot->exec= beauty_fill_exec;
ot->exec= beautify_fill_exec;
ot->poll= ED_operator_editmesh;
/* flags */

@ -804,9 +804,10 @@ BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float
ls = (BMLoop**)kcd->em->looptris[result->indexA];
for (j=0; j<3; j++) {
BMLoop *l1 = ls[j];
BMLoop *l1 = ls[j];
BMFace *hitf;
ListBase *lst = knife_get_face_kedges(kcd, l1->f);
Ref *ref;
Ref *ref, *ref2;
for (ref=lst->first; ref; ref=ref->next) {
KnifeEdge *kfe = ref->ref;
@ -845,7 +846,13 @@ BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float
/*go backwards toward view a bit*/
add_v3_v3(p, no);
if (!BMBVH_RayCast(bmtree, p, no, NULL) && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
hitf = BMBVH_RayCast(bmtree, p, no, NULL);
for (ref2=kfe->faces.first; ref2; ref2=ref2->next) {
if (ref2->ref == hitf)
hitf = NULL;
}
if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
BMEdgeHit hit;
if (len_v3v3(p, kcd->vertco) < FLT_EPSILON*50 || len_v3v3(p, kcd->prevco) < FLT_EPSILON*50)
@ -1274,8 +1281,16 @@ static void remerge_faces(knifetool_opdata *kcd)
BLI_array_declare(stack);
BMFace **faces = NULL;
BLI_array_declare(faces);
BMOperator bmop;
int idx;
BMO_InitOpf(bm, &bmop, "beautify_fill faces=%ff constrain_edges=%fe", FACE_NEW, BOUNDARY);
BMO_Exec_Op(bm, &bmop);
BMO_Flag_Buffer(bm, &bmop, "geomout", FACE_NEW, BM_FACE);
BMO_Finish_Op(bm, &bmop);
BLI_smallhash_init(visit);
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
BMIter eiter;

@ -306,215 +306,6 @@ DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd)
if (!vu)
continue;
ml->v = vu->v;
#if 0 //BMESH_TODO should really handle edges here, but for now use cddm_calc_edges
/*ok, now we have to deal with edges. . .*/
if (etags[ml->e].tag) {
if (etags[ml->e].used) {
BLI_array_growone(medge);
BLI_array_growone(etags);
medge[cure] = medge[ml->e];
ml->e = cure;
etags[cure].used = 1;
cure++;
}
vu = etags[ml->e].v1user;
vu2 = etags[ml->e].v2user;
<<<<<<< .working
if (vu)
medge[ml->e].v1 = vu->v;
if (vu2)
medge[ml->e].v2 = vu2->v;
=======
/* finds another sharp edge which uses vert, by traversing faces around the
* vert until it does one of the following:
* - hits a loose edge (the edge is returned)
* - hits a sharp edge (the edge is returned)
* - returns to the start edge (NULL is returned)
*/
static SmoothEdge *find_other_sharp_edge(SmoothVert *vert, SmoothEdge *edge, LinkNode **visited_faces)
{
SmoothFace *face = NULL;
SmoothEdge *edge2 = NULL;
/* holds the edges we've seen so we can avoid looping indefinitely */
LinkNode *visited_edges = NULL;
#ifdef EDGESPLIT_DEBUG_1
printf("=== START === find_other_sharp_edge(edge = %4d, vert = %4d)\n",
edge->newIndex, vert->newIndex);
#endif
/* get a face on which to start */
if(edge->faces) face = edge->faces->link;
else return NULL;
/* record this edge as visited */
BLI_linklist_prepend(&visited_edges, edge);
/* get the next edge */
edge2 = other_edge(face, vert, edge);
/* record this face as visited */
if(visited_faces)
BLI_linklist_prepend(visited_faces, face);
/* search until we hit a loose edge or a sharp edge or an edge we've
* seen before
*/
while(face && !edge_is_sharp(edge2)
&& !linklist_contains(visited_edges, edge2)) {
#ifdef EDGESPLIT_DEBUG_3
printf("current face %4d; current edge %4d\n", face->newIndex,
edge2->newIndex);
#endif
/* get the next face */
face = other_face(edge2, face);
/* if face == NULL, edge2 is a loose edge */
if(face) {
/* record this face as visited */
if(visited_faces)
BLI_linklist_prepend(visited_faces, face);
/* record this edge as visited */
BLI_linklist_prepend(&visited_edges, edge2);
/* get the next edge */
edge2 = other_edge(face, vert, edge2);
#ifdef EDGESPLIT_DEBUG_3
printf("next face %4d; next edge %4d\n",
face->newIndex, edge2->newIndex);
} else {
printf("loose edge: %4d\n", edge2->newIndex);
#endif
}
}
/* either we came back to the start edge or we found a sharp/loose edge */
if(linklist_contains(visited_edges, edge2))
/* we came back to the start edge */
edge2 = NULL;
BLI_linklist_free(visited_edges, NULL);
#ifdef EDGESPLIT_DEBUG_1
printf("=== END === find_other_sharp_edge(edge = %4d, vert = %4d), "
"returning edge %d\n",
edge->newIndex, vert->newIndex, edge2 ? edge2->newIndex : -1);
#endif
return edge2;
}
static void split_single_vert(SmoothVert *vert, SmoothFace *face,
SmoothMesh *mesh)
{
SmoothVert *copy_vert;
ReplaceData repdata;
copy_vert = smoothvert_copy(vert, mesh);
if(copy_vert == NULL) {
/* bug [#26316], this prevents a segfault
* but this still needs fixing */
return;
}
repdata.find = vert;
repdata.replace = copy_vert;
face_replace_vert(face, &repdata);
}
typedef struct PropagateEdge {
struct PropagateEdge *next, *prev;
SmoothEdge *edge;
SmoothVert *vert;
} PropagateEdge;
static void push_propagate_stack(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh)
{
PropagateEdge *pedge = mesh->reusestack.first;
if(pedge) {
BLI_remlink(&mesh->reusestack, pedge);
}
else {
if(!mesh->arena) {
mesh->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "edgesplit arena");
BLI_memarena_use_calloc(mesh->arena);
}
pedge = BLI_memarena_alloc(mesh->arena, sizeof(PropagateEdge));
}
pedge->edge = edge;
pedge->vert = vert;
BLI_addhead(&mesh->propagatestack, pedge);
}
static void pop_propagate_stack(SmoothEdge **edge, SmoothVert **vert, SmoothMesh *mesh)
{
PropagateEdge *pedge = mesh->propagatestack.first;
if(pedge) {
*edge = pedge->edge;
*vert = pedge->vert;
BLI_remlink(&mesh->propagatestack, pedge);
BLI_addhead(&mesh->reusestack, pedge);
}
else {
*edge = NULL;
*vert = NULL;
}
}
static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh);
static void propagate_split(SmoothEdge *edge, SmoothVert *vert,
SmoothMesh *mesh)
{
SmoothEdge *edge2;
LinkNode *visited_faces = NULL;
#ifdef EDGESPLIT_DEBUG_1
printf("=== START === propagate_split(edge = %4d, vert = %4d)\n",
edge->newIndex, vert->newIndex);
#endif
edge2 = find_other_sharp_edge(vert, edge, &visited_faces);
if(!edge2) {
/* didn't find a sharp or loose edge, so we've hit a dead end */
} else if(!edge_is_loose(edge2)) {
/* edge2 is not loose, so it must be sharp */
if(edge_is_loose(edge)) {
/* edge is loose, so we can split edge2 at this vert */
split_edge(edge2, vert, mesh);
} else if(edge_is_sharp(edge)) {
/* both edges are sharp, so we can split the pair at vert */
split_edge(edge, vert, mesh);
} else {
/* edge is not sharp, so try to split edge2 at its other vert */
split_edge(edge2, other_vert(edge2, vert), mesh);
}
} else { /* edge2 is loose */
if(edge_is_loose(edge)) {
SmoothVert *vert2;
ReplaceData repdata;
/* can't split edge, what should we do with vert? */
if(linklist_subset(vert->faces, visited_faces)) {
/* vert has only one fan of faces attached; don't split it */
>>>>>>> .merge-right.r36153
} else {
etags[ml->e].used = 1;
if (vu->ov == etags[ml->e].v1)
medge[ml->e].v1 = vu->v;
else if (vu->ov == etags[ml->e].v2)
medge[ml->e].v2 = vu->v;
}
#endif
}
}
@ -544,7 +335,10 @@ static void propagate_split(SmoothEdge *edge, SmoothVert *vert,
CDDM_set_mvert(cddm, mvert);
CDDM_set_medge(cddm, medge);
CustomData_set_layer(&cddm->vertData, CD_MVERT, mvert);
CustomData_set_layer(&cddm->edgeData, CD_MEDGE, medge);
free_membase(membase);
MEM_freeN(etags);