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
diff options
context:
space:
mode:
-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;