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:
authorCampbell Barton <ideasman42@gmail.com>2015-01-13 17:28:33 +0300
committerCampbell Barton <ideasman42@gmail.com>2015-01-13 17:36:03 +0300
commita97c5d1f9f7ec71807763c2f28f095bf37f0c230 (patch)
tree71ea0119c44071a672d6bd6b4a835e5b46f4805b /source/blender/editors/mesh
parenta2a7260915633eda8a3d26aa678baba49b2429ce (diff)
Fix T42459: Knife fails at small scale
Occluding geometry failed when near overlapping (or cutting small objects).
Diffstat (limited to 'source/blender/editors/mesh')
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c120
1 files changed, 99 insertions, 21 deletions
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 10541a6d02e..093ad02b2da 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1227,9 +1227,81 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
kcd->ortho_extent = max_xyz;
}
-/* Check if p is visible (not clipped, not occluded by another face).
- * s in screen projection of p. */
-static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const float s[2], bglMats *mats)
+static BMElem *bm_elem_from_knife_vert(KnifeVert *kfv, KnifeEdge **r_kfe)
+{
+ BMElem *ele_test;
+ KnifeEdge *kfe = NULL;
+
+ if (r_kfe || ele_test == NULL) {
+ if (kfv->v == NULL) {
+ Ref *ref;
+ for (ref = kfv->edges.first; ref; ref = ref->next) {
+ kfe = ref->ref;
+ if (kfe->e) {
+ *r_kfe = kfe;
+ break;
+ }
+ }
+ }
+ }
+
+ /* vert? */
+ ele_test = (BMElem *)kfv->v;
+
+ /* edge? */
+ if (ele_test == NULL) {
+ if (kfe) {
+ ele_test = (BMElem *)kfe->e;
+ }
+ }
+
+ if (ele_test == NULL) {
+ if (BLI_listbase_is_single(&kfe->faces)) {
+ ele_test = ((Ref *)kfe->faces.first)->ref;
+ }
+ }
+
+ return ele_test;
+}
+
+static BMElem *bm_elem_from_knife_edge(KnifeEdge *kfe)
+{
+ BMElem *ele_test;
+
+ ele_test = (BMElem *)kfe->e;
+
+ if (ele_test == NULL) {
+ ele_test = (BMElem *)kfe->basef;
+ }
+
+ return ele_test;
+}
+
+static bool bm_ray_cast_cb_elem_not_in_face_check(BMFace *f, void *user_data)
+{
+ switch (((BMElem *)user_data)->head.htype) {
+ case BM_FACE:
+ return (BMFace *)user_data != f;
+ case BM_EDGE:
+ return !BM_edge_in_face((BMEdge *)user_data, f);
+ case BM_VERT:
+ return !BM_vert_in_face((BMVert *)user_data, f);
+ default:
+ return true;
+ }
+}
+
+
+/**
+ * Check if \a p is visible (not clipped, not occluded by another face).
+ * s in screen projection of p.
+ *
+ * \param ele_test Optional vert/edge/face to use when \a p is on the surface of the geometry,
+ * intersecting faces matching this face (or connected when an vert/edge) will be ignored.
+ */
+static bool point_is_visible(
+ KnifeTool_OpData *kcd, const float p[3], const float s[2], bglMats *mats,
+ BMElem *ele_test)
{
BMFace *f_hit;
@@ -1253,7 +1325,7 @@ static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const floa
/* make p_ofs a little towards view, so ray doesn't hit p's face. */
sub_v3_v3(view, p);
dist = normalize_v3(view);
- madd_v3_v3v3fl(p_ofs, p, view, KNIFE_FLT_EPSBIG * 3.0f);
+ copy_v3_v3(p_ofs, p);
/* avoid projecting behind the viewpoint */
if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) {
@@ -1272,9 +1344,19 @@ static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const floa
}
/* see if there's a face hit between p1 and the view */
- f_hit = BKE_bmbvh_ray_cast(kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL);
- if (f_hit)
+ if (ele_test) {
+ f_hit = BKE_bmbvh_ray_cast_filter(
+ kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL,
+ bm_ray_cast_cb_elem_not_in_face_check, ele_test);
+ }
+ else {
+ f_hit = BKE_bmbvh_ray_cast(
+ kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL);
+ }
+
+ if (f_hit) {
return false;
+ }
}
return true;
@@ -1446,25 +1528,21 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
for (val_p = BLI_smallhash_iternew_p(&kfvs, &hiter, (uintptr_t *)&v); val_p;
val_p = BLI_smallhash_iternext_p(&hiter, (uintptr_t *)&v))
{
+ KnifeEdge *kfe_hit = NULL;
+
knife_project_v2(kcd, v->cageco, s);
d = dist_squared_to_line_segment_v2(s, s1, s2);
if ((d <= vert_tol_sq) &&
- point_is_visible(kcd, v->cageco, s, &mats))
+ (point_is_visible(kcd, v->cageco, s, &mats, bm_elem_from_knife_vert(v, &kfe_hit))))
{
memset(&hit, 0, sizeof(hit));
hit.v = v;
/* If this isn't from an existing BMVert, it may have been added to a BMEdge originally.
- * knowing if the hit comes from an edge is important for edge-in-face checks later on
- * see: #knife_add_single_cut -> #knife_verts_edge_in_face, T42611 */
- if (v->v == NULL) {
- for (ref = v->edges.first; ref; ref = ref->next) {
- kfe = ref->ref;
- if (kfe->e) {
- hit.kfe = kfe;
- break;
- }
- }
+ * knowing if the hit comes from an edge is important for edge-in-face checks later on
+ * see: #knife_add_single_cut -> #knife_verts_edge_in_face, T42611 */
+ if (kfe_hit) {
+ hit.kfe = kfe_hit;
}
copy_v3_v3(hit.hit, v->co);
@@ -1518,7 +1596,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
* Need to find 3d intersection of ray through sint */
knife_input_ray_segment(kcd, sint, 1.0f, r1, r2);
isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p_cage, p_cage_tmp);
- if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, &mats)) {
+ if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, &mats, bm_elem_from_knife_edge(kfe))) {
memset(&hit, 0, sizeof(hit));
if (kcd->snap_midpoints) {
/* choose intermediate point snap too */
@@ -1547,7 +1625,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
float p[3], p_cage[3];
if (use_hit_prev && knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) {
- if (point_is_visible(kcd, p_cage, s1, &mats)) {
+ if (point_is_visible(kcd, p_cage, s1, &mats, (BMElem *)f)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
copy_v3_v3(hit.hit, p);
@@ -1559,7 +1637,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
if (use_hit_curr && knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) {
- if (point_is_visible(kcd, p_cage, s2, &mats)) {
+ if (point_is_visible(kcd, p_cage, s2, &mats, (BMElem *)f)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
copy_v3_v3(hit.hit, p);
@@ -3341,7 +3419,7 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
float cent[3], cent_ss[2];
edbm_mesh_knife_face_point(f, cent);
knife_project_v2(kcd, cent, cent_ss);
- if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, &mats)) &&
+ if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, &mats, (BMElem *)f)) &&
edbm_mesh_knife_point_isect(polys, cent_ss))
{
BM_elem_flag_enable(f, BM_ELEM_TAG);