Fix to knife: would sometimes miss cuts on non-planar faces.

Also, there was a needless loop through all three loops of
a tesselation triangle, which all share the same original face.
Also, made an early out for case where an edge cut had already
been discovered on a Knife edge.
This commit is contained in:
2012-08-06 13:37:25 +00:00
parent 244714d53e
commit 21a137471d

View File

@@ -1092,9 +1092,9 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
BLI_array_declare(edges);
BVHTreeOverlap *results, *result;
BMLoop **ls;
float cos[9], uv[3], lambda;
float cos[9], lambda;
unsigned int tot = 0;
int i, j;
int i;
/* for comparing distances, error of intersection depends on triangle scale.
* need to scale down before squaring for accurate comparison */
@@ -1112,105 +1112,107 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
for (i = 0; i < tot; i++, result++) {
float p[3];
BMLoop *l1;
BMFace *hitf;
ListBase *lst;
Ref *ref;
ls = (BMLoop **)kcd->em->looptris[result->indexA];
for (j = 0; j < 3; j++) {
BMLoop *l1 = ls[j];
BMFace *hitf;
ListBase *lst = knife_get_face_kedges(kcd, l1->f);
Ref *ref;
l1 = ls[0];
lst = knife_get_face_kedges(kcd, l1->f);
for (ref = lst->first; ref; ref = ref->next) {
KnifeEdge *kfe = ref->ref;
for (ref = lst->first; ref; ref = ref->next) {
KnifeEdge *kfe = ref->ref;
//if (kfe == kcd->cur.edge || kfe == kcd->prev.edge)
// continue;
if (BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
continue; // We already found a hit on this knife edge
}
if (isect_line_tri_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, uv)) {
float no[3], view[3], sp[3];
if (isect_line_tri_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, NULL)) {
float no[3], view[3], sp[3];
interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda);
interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda);
if (kcd->cur.vert && len_squared_v3v3(kcd->cur.vert->cageco, p) < depsilon_squared)
continue;
if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_squared)
continue;
if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_squared ||
len_squared_v3v3(kcd->cur.cage, p) < depsilon_squared)
{
continue;
if (kcd->cur.vert && len_squared_v3v3(kcd->cur.vert->cageco, p) < depsilon_squared)
continue;
if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_squared)
continue;
if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_squared ||
len_squared_v3v3(kcd->cur.cage, p) < depsilon_squared)
continue;
knife_project_v3(kcd, p, sp);
view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
mul_m4_v3(kcd->ob->imat, view);
if (kcd->cut_through) {
hitf = FALSE;
} else {
/* check if this point is visible in the viewport */
float p1[3], lambda1;
/* if face isn't planer, p may be behind the current tesselated tri,
so move it onto that and then a little towards eye */
if (isect_line_tri_v3(p, view, ls[0]->v->co, ls[1]->v->co, ls[2]->v->co, &lambda1, NULL)) {
interp_v3_v3v3(p1, p, view, lambda1);
} else {
copy_v3_v3(p1, p);
}
sub_v3_v3(view, p1);
normalize_v3(view);
knife_project_v3(kcd, p, sp);
view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
mul_m4_v3(kcd->ob->imat, view);
copy_v3_v3(no, view);
mul_v3_fl(no, 0.003);
if (kcd->cut_through) {
hitf = FALSE;
}
else {
/* check if this point is visible in the viewport */
sub_v3_v3(view, p);
normalize_v3(view);
copy_v3_v3(no, view);
mul_v3_fl(no, 0.003);
/* go towards view a bit */
add_v3_v3(p, no);
/* ray cast */
hitf = BMBVH_RayCast(bmtree, p, no, NULL, NULL);
}
/* ok, if visible add the new point */
if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
BMEdgeHit hit;
/* go towards view a bit */
add_v3_v3(p1, no);
if (len_squared_v3v3(p, kcd->cur.co) < depsilon_squared ||
len_squared_v3v3(p, kcd->prev.co) < depsilon_squared)
{
continue;
/* ray cast */
hitf = BMBVH_RayCast(bmtree, p1, no, NULL, NULL);
}
/* ok, if visible add the new point */
if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
BMEdgeHit hit;
if (len_squared_v3v3(p, kcd->cur.co) < depsilon_squared ||
len_squared_v3v3(p, kcd->prev.co) < depsilon_squared)
continue;
hit.kfe = kfe;
hit.v = NULL;
knife_find_basef(kfe);
hit.f = kfe->basef;
hit.perc = len_v3v3(p, kfe->v1->cageco) / len_v3v3(kfe->v1->cageco, kfe->v2->cageco);
copy_v3_v3(hit.cagehit, p);
interp_v3_v3v3(p, kfe->v1->co, kfe->v2->co, hit.perc);
copy_v3_v3(hit.realhit, p);
/* BMESH_TODO: should also snap to vertices */
if (kcd->snap_midpoints) {
float perc = hit.perc;
/* select the closest from the edge endpoints or the midpoint */
if (perc < 0.25f) {
perc = 0.0f;
} else if (perc < 0.75f) {
perc = 0.5f;
} else {
perc = 1.0f;
}
hit.kfe = kfe;
hit.v = NULL;
knife_find_basef(kfe);
hit.f = kfe->basef;
hit.perc = len_v3v3(p, kfe->v1->cageco) / len_v3v3(kfe->v1->cageco, kfe->v2->cageco);
copy_v3_v3(hit.cagehit, p);
interp_v3_v3v3(p, kfe->v1->co, kfe->v2->co, hit.perc);
copy_v3_v3(hit.realhit, p);
/* BMESH_TODO: should also snap to vertices */
if (kcd->snap_midpoints) {
float perc = hit.perc;
/* select the closest from the edge endpoints or the midpoint */
if (perc < 0.25f) {
perc = 0.0f;
}
else if (perc < 0.75f) {
perc = 0.5f;
}
else {
perc = 1.0f;
}
interp_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co, perc);
interp_v3_v3v3(hit.cagehit, kfe->v1->cageco, kfe->v2->cageco, perc);
}
else {
copy_v3_v3(hit.hit, p);
}
knife_project_v3(kcd, hit.cagehit, hit.schit);
BLI_array_append(edges, hit);
BLI_smallhash_insert(ehash, (intptr_t)kfe, NULL);
interp_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co, perc);
interp_v3_v3v3(hit.cagehit, kfe->v1->cageco, kfe->v2->cageco, perc);
} else {
copy_v3_v3(hit.hit, p);
}
knife_project_v3(kcd, hit.cagehit, hit.schit);
BLI_array_append(edges, hit);
BLI_smallhash_insert(ehash, (intptr_t)kfe, NULL);
}
}
}