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>2013-08-30 20:34:44 +0400
committerHoward Trickey <howard.trickey@gmail.com>2013-08-30 20:34:44 +0400
commit86f8470a5da2efbd8d521df2759b3a0d06160667 (patch)
treee183951f3140f9634fb2f82228b329c748886f60 /source
parent03a8b4f180900bb9b2c35669fe963a23ae29cf32 (diff)
Some knife fixes. Avoids duplicating verts; better handling of cut-through ortho.
Now cut lines detect vertices that they pass (almost) exactly over and snap to them, to avoid making verts vert close to other ones. Added radius arg to BKE_bmbvh_ray_cast so that can detect an obscuring face when the ray might otherwise go exactly between two triangles. Needed an isect_line_tri_epsilon function for similar reason. Fixes last part of bug #35002. Other knife bugs still present but getting this commit in now before continuing bug fixing.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_editmesh_bvh.h2
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c2
-rw-r--r--source/blender/blenkernel/intern/editmesh_bvh.c11
-rw-r--r--source/blender/blenlib/BLI_math_geom.h3
-rw-r--r--source/blender/blenlib/intern/math_geom.c39
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c240
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c2
7 files changed, 193 insertions, 106 deletions
diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h
index 6750ee1ff3e..7b4ad4284c6 100644
--- a/source/blender/blenkernel/BKE_editmesh_bvh.h
+++ b/source/blender/blenkernel/BKE_editmesh_bvh.h
@@ -44,7 +44,7 @@ typedef struct BMBVHTree BMBVHTree;
BMBVHTree *BKE_bmbvh_new(struct BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free);
void BKE_bmbvh_free(BMBVHTree *tree);
struct BVHTree *BKE_bmbvh_tree_get(BMBVHTree *tree);
-struct BMFace *BKE_bmbvh_ray_cast(BMBVHTree *tree, const float co[3], const float dir[3],
+struct BMFace *BKE_bmbvh_ray_cast(BMBVHTree *tree, const float co[3], const float dir[3], const float radius,
float *r_dist, float r_hitout[3], float r_cagehit[3]);
/* find a face intersecting a segment (but not apart of the segment) */
struct BMFace *BKE_bmbvh_find_face_segment(BMBVHTree *tree, const float co_a[3], const float co_b[3],
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index e8e56c6f17b..caa5bf90584 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -1872,7 +1872,7 @@ static void statvis_calc_thickness(
normal_tri_v3(ray_no, cos[2], cos[1], cos[0]);
#define FACE_RAY_TEST_ANGLE \
- f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, \
+ f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, \
&dist, NULL, NULL); \
if (f_hit && dist < face_dists[index]) { \
float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no)); \
diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c
index fced3472566..ab8d223dd71 100644
--- a/source/blender/blenkernel/intern/editmesh_bvh.c
+++ b/source/blender/blenkernel/intern/editmesh_bvh.c
@@ -193,11 +193,14 @@ static void bmbvh_ray_cast_cb(void *userdata, int index, const BVHTreeRay *ray,
const BMLoop **ltri = bmcb_data->looptris[index];
float dist, uv[2];
const float *tri_cos[3];
+ bool isect;
bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
- if (isect_ray_tri_v3(ray->origin, ray->direction, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv) &&
- (dist < hit->dist))
+ isect = ray->radius > 0.0f ?
+ isect_ray_tri_epsilon_v3(ray->origin, ray->direction, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv, ray->radius) :
+ isect_ray_tri_v3(ray->origin, ray->direction, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv);
+ if (isect && dist < hit->dist)
{
hit->dist = dist;
hit->index = index;
@@ -213,7 +216,7 @@ static void bmbvh_ray_cast_cb(void *userdata, int index, const BVHTreeRay *ray,
}
}
-BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree, const float co[3], const float dir[3],
+BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree, const float co[3], const float dir[3], const float radius,
float *r_dist, float r_hitout[3], float r_cagehit[3])
{
BVHTreeRayHit hit;
@@ -229,7 +232,7 @@ BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree, const float co[3], const float dir
bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->em->looptris;
bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage;
- BLI_bvhtree_ray_cast(bmtree->tree, co, dir, 0.0f, &hit, bmbvh_ray_cast_cb, &bmcb_data);
+ BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb, &bmcb_data);
if (hit.index != -1 && hit.dist != dist) {
if (r_hitout) {
if (bmtree->flag & BMBVH_RETURN_ORIG) {
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 02db0885163..4307645bb91 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -139,6 +139,9 @@ void isect_plane_plane_v3(float r_isect_co[3], float r_isect_no[3],
/* line/ray triangle */
bool isect_line_tri_v3(const float p1[3], const float p2[3],
const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2]);
+bool isect_line_tri_epsilon_v3(const float p1[3], const float p2[3],
+ const float v0[3], const float v1[3], const float v2[3],
+ float *r_lambda, float r_uv[2], const float epsilon);
bool isect_ray_tri_v3(const float p1[3], const float d[3],
const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2]);
bool isect_ray_tri_threshold_v3(const float p1[3], const float d[3],
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 6ca4b4b6095..375b258acf9 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -894,6 +894,45 @@ bool isect_line_tri_v3(const float p1[3], const float p2[3],
return 1;
}
+/* like isect_line_tri_v3, but allows epsilon tolerance around triangle */
+bool isect_line_tri_epsilon_v3(const float p1[3], const float p2[3],
+ const float v0[3], const float v1[3], const float v2[3],
+ float *r_lambda, float r_uv[2], const float epsilon)
+{
+
+ float p[3], s[3], d[3], e1[3], e2[3], q[3];
+ float a, f, u, v;
+
+ sub_v3_v3v3(e1, v1, v0);
+ sub_v3_v3v3(e2, v2, v0);
+ sub_v3_v3v3(d, p2, p1);
+
+ cross_v3_v3v3(p, d, e2);
+ a = dot_v3v3(e1, p);
+ if ((a > -0.000001f) && (a < 0.000001f)) return 0;
+ f = 1.0f / a;
+
+ sub_v3_v3v3(s, p1, v0);
+
+ u = f * dot_v3v3(s, p);
+ if ((u < -epsilon) || (u > 1.0f + epsilon)) return 0;
+
+ cross_v3_v3v3(q, s, e1);
+
+ v = f * dot_v3v3(d, q);
+ if ((v < -epsilon) || ((u + v) > 1.0f + epsilon)) return 0;
+
+ *r_lambda = f * dot_v3v3(e2, q);
+ if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return 0;
+
+ if (r_uv) {
+ r_uv[0] = u;
+ r_uv[1] = v;
+ }
+
+ return 1;
+}
+
/* moved from effect.c
* test if the ray starting at p1 going in d direction intersects the triangle v0..v2
* return non zero if it does
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index e94411053cc..5fe0019281f 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -499,10 +499,11 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd)
{
KnifeEdge *kfe = new_knife_edge(kcd), *kfe2 = NULL, *kfe3 = NULL;
- if (kcd->prev.vert && kcd->prev.vert == kcd->curr.vert)
- return;
- if (kcd->prev.edge && kcd->prev.edge == kcd->curr.edge)
+ if ((kcd->prev.vert && kcd->prev.vert == kcd->curr.vert) ||
+ (kcd->prev.edge && kcd->prev.edge == kcd->curr.edge)) {
+ kcd->prev = kcd->curr;
return;
+ }
kfe->draw = true;
@@ -573,10 +574,17 @@ static int verge_linehit(const void *vlh1, const void *vlh2)
if (lh1->l < lh2->l) return -1;
else if (lh1->l > lh2->l) return 1;
+ else if (lh1->v && lh2->v) {
+ /* want like verts to sort together; just compare pointers */
+ if (lh1->v < lh2->v) return -1;
+ else if (lh1->v > lh2->v) return 1;
+ else return 0;
+ }
else return 0;
}
/* If there's a linehit connected (same face) as testi in range [firsti, lasti], return the first such, else -1.
+ * It also counts as connected if both linehits are snapped to the same vertex.
* If testi is out of range, look for connection to f instead, if f is non-NULL */
static int find_connected_linehit(KnifeTool_OpData *kcd, int testi, BMFace *f, int firsti, int lasti)
{
@@ -586,9 +594,10 @@ static int find_connected_linehit(KnifeTool_OpData *kcd, int testi, BMFace *f, i
if (testi >= 0 && testi < kcd->totlinehit) {
if (knife_find_common_face(&kcd->linehits[testi].kfe->faces,
&kcd->linehits[i].kfe->faces))
- {
return i;
- }
+ else if (kcd->linehits[testi].v &&
+ kcd->linehits[testi].v == kcd->linehits[i].v)
+ return i;
}
else if (f) {
if (find_ref(&kcd->linehits[i].kfe->faces, f))
@@ -598,13 +607,38 @@ static int find_connected_linehit(KnifeTool_OpData *kcd, int testi, BMFace *f, i
return -1;
}
-/* Sort in order of distance along cut line, but take care when distances are equal */
-static void knife_sort_linehits(KnifeTool_OpData *kcd)
+/* Sort in order of distance along cut line.
+ * Remove any successive linehits that are snapped to the same vertex.
+ * If joinfaces, treat hits at same distance as follows: try to find
+ * ordering so that preceding and succeeding hits will share a face.
+ */
+static void knife_sort_linehits(KnifeTool_OpData *kcd, bool joinfaces)
{
int i, j, k, nexti, nsame;
qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit);
+ /* Remove duplicated linehits snapped to same vertex */
+ i = j = 0; /* loop copies from j to i */
+ while (j < kcd->totlinehit) {
+ nsame = 0;
+ if (kcd->linehits[j].v) {
+ for (k = j + 1; k < kcd->totlinehit; k++) {
+ if (kcd->linehits[k].v != kcd->linehits[j].v)
+ break;
+ nsame++;
+ }
+ }
+ if (i != j)
+ kcd->linehits[i] = kcd->linehits[j];
+ i++;
+ j += 1 + nsame;
+ }
+ kcd->totlinehit = i;
+
+ if (!joinfaces)
+ return;
+
/* for ranges of equal "l", swap if neccesary to make predecessor and
* successor faces connected to the linehits at either end of the range */
for (i = 0; i < kcd->totlinehit - 1; i = nexti) {
@@ -653,6 +687,7 @@ static void knife_add_single_cut_through(KnifeTool_OpData *kcd, KnifeVert *v1, K
knife_edge_append_face(kcd, kfenew, f);
}
+#if 0
static void knife_get_vert_faces(KnifeTool_OpData *kcd, KnifeVert *kfv, BMFace *facef, ListBase *lst)
{
BMIter bmiter;
@@ -685,20 +720,32 @@ static void knife_get_edge_faces(KnifeTool_OpData *kcd, KnifeEdge *kfe, ListBase
}
}
}
+#endif
+
+static void copy_hit_from_posdata(BMEdgeHit *lh, KnifePosData *pos, float lambda) {
+ lh->kfe = pos->edge;
+ lh->v = pos->vert;
+ lh->f = pos->bmface;
+ copy_v3_v3(lh->hit, pos->co);
+ copy_v3_v3(lh->cagehit, pos->cage);
+ copy_v3_v3(lh->realhit, pos->co);
+ lh->l = lambda;
+ /* perc and schit not used by callers of this function */
+}
/* BMESH_TODO: add more functionality to cut-through:
* - cutting "in face" (e.g., holes) should cut in all faces, not just visible one
* - perhaps improve O(n^2) algorithm used here */
static void knife_cut_through(KnifeTool_OpData *kcd)
{
- BMEdgeHit *lh, *lh2;
+ BMEdgeHit *lh, *lh2, *linehits;
BMFace *f;
- KnifeEdge *kfe, *kfe2, *kfe3;
- KnifeVert *v1, *v2, *firstv = NULL, *lastv = NULL;
- ListBase firstfaces = {NULL, NULL}, lastfaces = {NULL, NULL};
- Ref *r, *r2;
+ KnifeEdge *kfe, *kfe2;
+ KnifeVert *v1, *v2, *lastv;
+ ListBase *faces1, *faces2;
KnifeEdge **splitkfe;
- int i, j;
+ bool needprev, needcurr;
+ int i, j, n;
if (!kcd->totlinehit) {
/* if no linehits then no interesting back face stuff to do */
@@ -706,93 +753,68 @@ static void knife_cut_through(KnifeTool_OpData *kcd)
return;
}
- /* TODO: probably don't need to sort at all */
- qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit);
- splitkfe = MEM_callocN(kcd->totlinehit * sizeof(KnifeEdge *), "knife_cut_through");
+ /* sort eliminates hits on same vertices */
+ knife_sort_linehits(kcd, false);
- if (kcd->prev.vert) {
- if (kcd->prev.vert == kcd->curr.vert)
- return;
- firstv = kcd->prev.vert;
- knife_get_vert_faces(kcd, firstv, kcd->prev.bmface, &firstfaces);
- }
- else if (kcd->prev.edge) {
- if (kcd->prev.edge == kcd->curr.edge)
- return;
- firstv = knife_split_edge(kcd, kcd->prev.edge, kcd->prev.co, &kfe3);
- knife_get_edge_faces(kcd, kcd->prev.edge, &firstfaces);
+ /* code is cleaner if make prev and curr into hits (if they are on edges or verts) */
+ n = kcd->totlinehit;
+ needprev = ((kcd->prev.vert && kcd->prev.vert != kcd->linehits[0].v) || kcd->prev.edge);
+ needcurr = ((kcd->curr.vert && kcd->curr.vert != kcd->linehits[n - 1].v) || kcd->curr.edge);
+ n += needprev + needcurr;
+ linehits = MEM_callocN(n * sizeof(BMEdgeHit), "knife_cut_through");
+ i = 0;
+ if (needprev) {
+ copy_hit_from_posdata(&linehits[0], &kcd->prev, 0.0f);
+ i++;
}
+ memcpy(linehits + i, kcd->linehits, kcd->totlinehit * sizeof(BMEdgeHit));
+ i += kcd->totlinehit;
+ if (needcurr)
+ copy_hit_from_posdata(&linehits[i], &kcd->curr, 1.0f);
- if (kcd->curr.vert) {
- lastv = kcd->curr.vert;
- knife_get_vert_faces(kcd, lastv, kcd->curr.bmface, &lastfaces);
- }
- else if (kcd->curr.edge) {
- lastv = knife_split_edge(kcd, kcd->curr.edge, kcd->curr.co, &kfe3);
- knife_get_edge_faces(kcd, kcd->curr.edge, &lastfaces);
- }
-
- if (firstv) {
- /* For each face incident to firstv,
- * find the first following linehit (if any) sharing that face and connect */
- for (r = firstfaces.first; r; r = r->next) {
- bool found = false;
- f = r->ref;
- for (j = 0, lh2 = kcd->linehits; j < kcd->totlinehit && !found; j++, lh2++) {
- kfe2 = lh2->kfe;
- for (r2 = kfe2->faces.first; r2; r2 = r2->next) {
- if (r2->ref == f) {
- v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
- knife_add_single_cut_through(kcd, firstv, v2, f);
- found = true;
- break;
- }
- }
- }
- if (!found && lastv) {
- for (r2 = lastfaces.first; r2; r2 = r2->next) {
- if (r2->ref == f) {
- knife_add_single_cut_through(kcd, firstv, lastv, f);
- break;
- }
- }
- }
- }
- }
- for (i = 0, lh = kcd->linehits; i < kcd->totlinehit; i++, lh++) {
+ splitkfe = MEM_callocN(n * sizeof(KnifeEdge *), "knife_cut_through");
+
+ lastv = NULL;
+ for (i = 0, lh = linehits; i < n; i++, lh++) {
kfe = lh->kfe;
+ v1 = NULL;
- /* For each face attached to edge for this linehit,
- * find the first following linehit (if any) sharing that face and connect */
- for (r = kfe->faces.first; r; r = r->next) {
- bool found = false;
- f = r->ref;
- for (j = i + 1, lh2 = lh + 1; j < kcd->totlinehit && !found; j++, lh2++) {
- kfe2 = lh2->kfe;
- for (r2 = kfe2->faces.first; r2; r2 = r2->next) {
- if (r2->ref == f) {
- v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]);
- v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
- knife_add_single_cut_through(kcd, v1, v2, f);
- found = true;
- break;
- }
- }
+ /* get faces incident on hit lh */
+ if (lh->v) {
+ v1 = lh->v;
+ faces1 = &v1->faces;
+ }
+ else if (kfe) {
+ faces1 = &kfe->faces;
+ }
+
+ /* For each following hit, connect if lh1 an lh2 share a face */
+ for (j = i + 1, lh2 = lh + 1; j < n; j++, lh2++) {
+ kfe2 = lh2->kfe;
+ v2 = NULL;
+ if (lh2->v) {
+ v2 = lh2->v;
+ faces2 = &v2->faces;
}
- if (!found && lastv) {
- for (r2 = lastfaces.first; r2; r2 = r2->next) {
- if (r2->ref == f) {
- v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]);
- knife_add_single_cut_through(kcd, v1, lastv, f);
- break;
- }
- }
+ else if (kfe2) {
+ faces2 = &kfe2->faces;
+ }
+
+ f = knife_find_common_face(faces1, faces2);
+ if (f) {
+ if (!v1)
+ v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]);
+ if (!v2)
+ v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
+ knife_add_single_cut_through(kcd, v1, v2, f);
+ lastv = v2;
}
}
}
MEM_freeN(splitkfe);
+ MEM_freeN(linehits);
MEM_freeN(kcd->linehits);
kcd->linehits = NULL;
kcd->totlinehit = 0;
@@ -816,7 +838,7 @@ static void knife_add_cut(KnifeTool_OpData *kcd)
BMEdgeHit *lh, *lastlh, *firstlh;
int i;
- knife_sort_linehits(kcd);
+ knife_sort_linehits(kcd, true);
lh = kcd->linehits;
lastlh = firstlh = NULL;
@@ -848,14 +870,14 @@ static void knife_add_cut(KnifeTool_OpData *kcd)
continue;
/* first linehit may be down face parallel to view */
- if (!lastlh && fabsf(lh->l) < KNIFE_FLT_EPS)
+ if (!lastlh && !lh->v && fabsf(lh->l) < KNIFE_FLT_EPS)
continue;
if (kcd->prev.is_space) {
kcd->prev.is_space = 0;
copy_v3_v3(kcd->prev.co, lh->hit);
copy_v3_v3(kcd->prev.cage, lh->cagehit);
- kcd->prev.vert = NULL;
+ kcd->prev.vert = lh->v;
kcd->prev.edge = lh->kfe;
kcd->prev.bmface = lh->f;
continue;
@@ -1181,9 +1203,9 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
BLI_array_declare(edges);
BVHTreeOverlap *results, *result;
BMLoop **ls;
- float cos[9], lambda;
+ float cos[9], tri_norm[3], tri_plane[4], isects[2][3], lambda;
unsigned int tot = 0;
- int i;
+ int i, j, n_isects;
/* for comparing distances, error of intersection depends on triangle scale.
* need to scale down before squaring for accurate comparison */
@@ -1194,6 +1216,9 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
copy_v3_v3(cos + 3, v2);
copy_v3_v3(cos + 6, v3);
+ normal_tri_v3(tri_norm, v1, v2, v3);
+ plane_from_point_normal_v3(tri_plane, v1, tri_norm);
+
BLI_bvhtree_insert(tree2, 0, cos, 3);
BLI_bvhtree_balance(tree2);
@@ -1217,11 +1242,23 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
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, NULL)) {
+ n_isects = 0;
+ if (fabs(dist_to_plane_v3(kfe->v1->cageco, tri_plane)) < KNIFE_FLT_EPS &&
+ fabs(dist_to_plane_v3(kfe->v2->cageco, tri_plane)) < KNIFE_FLT_EPS) {
+ /* both kfe ends are in cutting triangle */
+ copy_v3_v3(isects[0], kfe->v1->cageco);
+ copy_v3_v3(isects[1], kfe->v2->cageco);
+ n_isects = 2;
+ }
+ else if (isect_line_tri_epsilon_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, NULL, depsilon)) {
+ /* kfe intersects cutting triangle lambda of the way along kfe */
+ interp_v3_v3v3(isects[0], kfe->v1->cageco, kfe->v2->cageco, lambda);
+ n_isects = 1;
+ }
+ for (j = 0; j < n_isects; j++) {
float p[3], no[3], view[3], sp[2];
- interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda);
-
+ copy_v3_v3(p, isects[j]);
if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_sq) {
continue;
}
@@ -1268,7 +1305,7 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
add_v3_v3(p1, no);
/* ray cast */
- f_hit = BKE_bmbvh_ray_cast(bmtree, p1, no, NULL, NULL, NULL);
+ f_hit = BKE_bmbvh_ray_cast(bmtree, p1, no, KNIFE_FLT_EPS, NULL, NULL, NULL);
}
/* ok, if visible add the new point */
@@ -1292,7 +1329,6 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
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;
@@ -1310,6 +1346,12 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
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 if (hit.perc < KNIFE_FLT_EPS || hit.perc > 1.0f - KNIFE_FLT_EPS) {
+ /* snap to vert */
+ hit.v = (hit.perc < KNIFE_FLT_EPS) ? kfe->v1 : kfe->v2;
+ copy_v3_v3(hit.hit, hit.v->co);
+ copy_v3_v3(hit.cagehit, hit.v->co);
+ }
else {
copy_v3_v3(hit.hit, p);
}
@@ -1502,7 +1544,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float
knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
sub_v3_v3v3(ray, origin_ofs, origin);
- f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray, NULL, co, cageco);
+ f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray, 0.0f, NULL, co, cageco);
if (is_space)
*is_space = !f;
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 46cab3b4416..a64a23a9f4a 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -1481,7 +1481,7 @@ int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d)
static BMFace *edge_ray_cast(struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e)
{
- BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, NULL, r_hitout, NULL);
+ BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL);
if (f && BM_edge_in_face(e, f))
return NULL;