Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorHoward Trickey <howard.trickey@gmail.com>2012-03-12 15:27:59 +0400
committerHoward Trickey <howard.trickey@gmail.com>2012-03-12 15:27:59 +0400
commitca5fd21bb5c43d605c8fef270e397184ec73d480 (patch)
tree47e3ec3f6daee7dc3f0c92ad863910b435dd0f29 /source
parent30907594b6bcbc8c401d425a57bf7eadefdcaf61 (diff)
Make knifetool more robust against crashes. Fix some hole problems.
Sometimes split would fail to make a face - make sure it doesn't crash if that happens. Chain finding code for holes would sometimes go back to same vertex on the face, which causes problems, so fixe that. Also, disallowed a cut that starts at a vertex or edge and cycles back to that same point in a face - this would make a face with a repeated vertex, which may not be handled by the rest of the system properly.
Diffstat (limited to 'source')
-rw-r--r--source/blender/editors/mesh/knifetool.c67
1 files changed, 49 insertions, 18 deletions
diff --git a/source/blender/editors/mesh/knifetool.c b/source/blender/editors/mesh/knifetool.c
index e1380e6f1e1..0231fa4ade3 100644
--- a/source/blender/editors/mesh/knifetool.c
+++ b/source/blender/editors/mesh/knifetool.c
@@ -2099,6 +2099,8 @@ static int find_hole_search(knifetool_opdata *kcd, KnifeVert *kfvfirst, KnifeVer
kfe = r->ref;
if (kfe == kfelast)
continue;
+ if (kfe->v1->v || kfe->v2->v)
+ continue;
kfv_other = NULL;
if (kfe->v1 == kfv)
kfv_other = kfe->v2;
@@ -2165,7 +2167,7 @@ static int find_hole_chains(knifetool_opdata *kcd, ListBase *hole, BMFace *f,
KnifeVert **hv;
KnifeEdge **he;
Ref *r;
- KnifeVert *kfv;
+ KnifeVert *kfv, *kfvother;
KnifeEdge *kfe;
ListBase *chain;
BMVert *v;
@@ -2190,14 +2192,21 @@ static int find_hole_chains(knifetool_opdata *kcd, ListBase *hole, BMFace *f,
i = 0;
kfv = NULL;
+ kfvother = NULL;
for (r = hole->first; r; r = r->next) {
kfe = r->ref;
he[i] = kfe;
- kfv = (kfv == kfe->v1)? kfe->v2 : kfe->v1;
+ if (kfvother == NULL) {
+ kfv = kfe->v1;
+ } else {
+ kfv = kfvother;
+ BLI_assert(kfv == kfe->v1 || kfv == kfe->v2);
+ }
hco[i] = BLI_memarena_alloc(kcd->arena, 2*sizeof(float));
hco[i][0] = kfv->co[ax];
hco[i][1] = kfv->co[ay];
hv[i] = kfv;
+ kfvother = (kfe->v1 == kfv) ? kfe->v2 : kfe->v1;
i++;
}
@@ -2213,7 +2222,7 @@ static int find_hole_chains(knifetool_opdata *kcd, ListBase *hole, BMFace *f,
/* For first diagonal (m==0), want shortest length.
* For second diagonal (m==1), want max separation of index of hole
* vertex from the hole vertex used in the first diagonal, and from there
- * want the one with shortest length. */
+ * want the one with shortest length not to the same vertex as the first diagonal. */
for (m = 0; m < 2; m++) {
besti[m] = -1;
bestj[m] = -1;
@@ -2230,6 +2239,8 @@ static int find_hole_chains(knifetool_opdata *kcd, ListBase *hole, BMFace *f,
bestd = FLT_MAX;
}
for (j = 0; j < nf; j++) {
+ if (m == 1 && j == bestj[0])
+ continue;
d = len_squared_v2v2(hco[i], fco[j]);
if (d > bestd)
continue;
@@ -2261,6 +2272,7 @@ static int find_hole_chains(knifetool_opdata *kcd, ListBase *hole, BMFace *f,
}
if (besti[0] != -1 && besti[1] != -1) {
+ BLI_assert(besti[0] != besti[1] && bestj[0] != bestj[1]);
kfe = new_knife_edge(kcd);
kfe->v1 = get_bm_knife_vert(kcd, fv[bestj[0]]);
kfe->v2 = hv[besti[0]];
@@ -2291,10 +2303,14 @@ static int find_hole_chains(knifetool_opdata *kcd, ListBase *hole, BMFace *f,
static int knife_edge_in_face(knifetool_opdata *kcd, KnifeEdge *kfe, BMFace *f) {
BMesh *bm = kcd->em->bm;
BMVert *v1, *v2;
- BMLoop *l1, *l2, *l, *loops[2];
+ BMLoop *l1, *l2, *l;
+ float mid[3];
BMIter iter;
int v1inside, v2inside;
+ if (!f)
+ return FALSE;
+
v1 = kfe->v1->v;
v2 = kfe->v2->v;
l1 = NULL;
@@ -2315,11 +2331,11 @@ static int knife_edge_in_face(knifetool_opdata *kcd, KnifeEdge *kfe, BMFace *f)
return TRUE;
if (l1 && l2) {
/* Can have case where v1 and v2 are on shared chain between two faces.
- * BM_face_legal_splits does visibility and self-intersection tests. */
- loops[0] = l1;
- loops[1] = l2;
- BM_face_legal_splits(bm, f, (BMLoop *(*)[2])loops, 1);
- return (loops[0] != NULL);
+ * BM_face_legal_splits does visibility and self-intersection tests,
+ * but it is expensive and maybe a bit buggy, so use a simple
+ * "is the midpoint in the face" test */
+ mid_v3_v3v3(mid, kfe->v1->co, kfe->v2->co);
+ return BM_face_point_inside_test(bm, f, mid);
}
return FALSE;
}
@@ -2356,13 +2372,20 @@ static void knife_make_chain_cut(knifetool_opdata *kcd, BMFace *f, ListBase *cha
kfvprev = kfv;
}
BLI_assert(i == nco);
- fnew = BM_face_split_n(bm, f, v1, v2, cos, nco, &lnew, NULL);
- *newface = fnew;
-
- /* Now go through lnew chain matching up chain kv's and assign real v's to them */
- for (l_iter = lnew->next, i = 0; i < nco; l_iter = l_iter->next, i++) {
- BLI_assert(equals_v3v3(cos[i], l_iter->v->co));
- kverts[i]->v = l_iter->v;
+ lnew = NULL;
+ if (nco == 0) {
+ *newface = BM_face_split(bm, f, v1, v2, &lnew, NULL, TRUE);
+ } else {
+ fnew = BM_face_split_n(bm, f, v1, v2, cos, nco, &lnew, NULL);
+ *newface = fnew;
+
+ if (fnew) {
+ /* Now go through lnew chain matching up chain kv's and assign real v's to them */
+ for (l_iter = lnew->next, i = 0; i < nco; l_iter = l_iter->next, i++) {
+ BLI_assert(equals_v3v3(cos[i], l_iter->v->co));
+ kverts[i]->v = l_iter->v;
+ }
+ }
}
BLI_array_fixedstack_free(cos);
@@ -2381,6 +2404,10 @@ static void knife_make_face_cuts(knifetool_opdata *kcd, BMFace *f, ListBase *kfe
oldcount = BLI_countlist(kfedges);
while ((chain = find_chain(kcd, kfedges)) != NULL) {
knife_make_chain_cut(kcd, f, chain, &fnew);
+ if (!fnew) {
+ BLI_assert("!knife failed chain cut");
+ return;
+ }
/* Move kfedges to fnew_kfedges if they are now in fnew.
* The chain edges were removed already */
@@ -2413,6 +2440,10 @@ static void knife_make_face_cuts(knifetool_opdata *kcd, BMFace *f, ListBase *kfe
* from the second last vertex to the second vertex.
*/
knife_make_chain_cut(kcd, f, chain, &fnew);
+ if (!fnew) {
+ BLI_assert(!"knife failed hole cut");
+ return;
+ }
kfe = ((Ref *)sidechain->first)->ref;
if (knife_edge_in_face(kcd, kfe, f)) {
knife_make_chain_cut(kcd, f, sidechain, &fnew2);
@@ -2423,8 +2454,8 @@ static void knife_make_face_cuts(knifetool_opdata *kcd, BMFace *f, ListBase *kfe
fhole = fnew2;
}
else {
- /* shouldn't happen */
- BLI_assert(0);
+ /* shouldn't happen except in funny edge cases */
+ return;
}
BM_face_kill(bm, fhole);
/* Move kfedges to either fnew or fnew2 if appropriate.