diff options
Diffstat (limited to 'source/blender/editors/mesh/editmesh_knife.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_knife.c | 119 |
1 files changed, 100 insertions, 19 deletions
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index ea974fc76f5..9d8b283fe1a 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -628,13 +628,13 @@ static int find_connected_linehit(KnifeTool_OpData *kcd, int testi, BMFace *f, i } if (testfaces) { if (ifaces) - shareface = knife_find_common_face(testfaces, ifaces); + shareface = (knife_find_common_face(testfaces, ifaces) != NULL); else if (iface) - shareface = find_ref(testfaces, iface); + shareface = (find_ref(testfaces, iface) != NULL); } else if (ifaces) { if (testface) - shareface = find_ref(ifaces, testface); + shareface = (find_ref(ifaces, testface) != NULL); } else if (testface && iface) { shareface = (testface == iface); @@ -1233,6 +1233,69 @@ static float len_v3_tri_side_max(const float v1[3], const float v2[3], const flo return sqrtf(max_fff(s1, s2, s3)); } +/** + * given a tri, return 3 planes aligned with the tri's normal. + * + * If the triangle were extruded along its normal, + * the planes calculated would be the 3 sides around the extrusion. + */ +static void plane_from_tri_clip3_v3( + float tri_plane_clip[3][4], + const float v0[3], const float v1[3], const float v2[3]) +{ + float tri_norm[3]; + float tvec[3], cross[3]; + + normal_tri_v3(tri_norm, v0, v1, v2); + + sub_v3_v3v3(tvec, v0, v1); + cross_v3_v3v3(cross, tvec, tri_norm); + plane_from_point_normal_v3(tri_plane_clip[0], v0, cross); + + sub_v3_v3v3(tvec, v1, v2); + cross_v3_v3v3(cross, tvec, tri_norm); + plane_from_point_normal_v3(tri_plane_clip[1], v1, cross); + + sub_v3_v3v3(tvec, v2, v0); + cross_v3_v3v3(cross, tvec, tri_norm); + plane_from_point_normal_v3(tri_plane_clip[2], v2, cross); +} + +/** + * Given a line that is planar with a tri, clip the segment by that tri. + * + * This is needed so we end up with both points in the triangle. + */ +static bool isect_line_tri_coplanar_v3( + const float p1[3], const float p2[3], + const float v0[3], const float v1[3], const float v2[3], + float r_isects[2][3], + + /* avoid re-calculating every time */ + float tri_plane[4], float tri_plane_clip[3][4]) +{ + float p1_tmp[3] = {UNPACK3(p1)}; + float p2_tmp[3] = {UNPACK3(p2)}; + + (void)v0, (void)v1, (void)v2; + + /* first check if the points are planar with the tri */ + if ((fabsf(dist_squared_to_plane_v3(p1, tri_plane)) < KNIFE_FLT_EPS_SQUARED) && + (fabsf(dist_squared_to_plane_v3(p2, tri_plane)) < KNIFE_FLT_EPS_SQUARED) && + /* clip the segment by planes around the triangle so we can be sure the points + * aren't outside the triangle */ + (clip_segment_v3_plane_n(p1_tmp, p2_tmp, tri_plane_clip, 3))) + { + copy_v3_v3(r_isects[0], p1_tmp); + copy_v3_v3(r_isects[1], p2_tmp); + + return true; + } + else { + return false; + } +} + static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, const float v1[3], const float v2[3], const float v3[3], SmallHash *ehash, bglMats *mats, int *count) @@ -1243,9 +1306,11 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, BVHTreeOverlap *results, *result; BMLoop **ls; float cos[9], tri_norm[3], tri_plane[4], isects[2][3], lambda; + float tri_plane_clip[3][4]; unsigned int tot = 0; int i, j, n_isects; + /* for comparing distances, error of intersection depends on triangle scale. * need to scale down before squaring for accurate comparison */ const float depsilon = (FLT_EPSILON / 2.0f) * len_v3_tri_side_max(v1, v2, v3); @@ -1255,8 +1320,10 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, copy_v3_v3(cos + 3, v2); copy_v3_v3(cos + 6, v3); + /* avoid re-calculation in #isect_line_tri_coplanar_v3 */ normal_tri_v3(tri_norm, v1, v2, v3); plane_from_point_normal_v3(tri_plane, v1, tri_norm); + plane_from_tri_clip3_v3(tri_plane_clip, v1, v2, v3); BLI_bvhtree_insert(tree2, 0, cos, 3); BLI_bvhtree_balance(tree2); @@ -1282,21 +1349,25 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, } n_isects = 0; - if (fabsf(dist_to_plane_v3(kfe->v1->cageco, tri_plane)) < KNIFE_FLT_EPS && - fabsf(dist_to_plane_v3(kfe->v2->cageco, tri_plane)) < KNIFE_FLT_EPS) + + if (isect_line_tri_coplanar_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, + isects, + /* cached values */ + tri_plane, tri_plane_clip)) { /* 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)) { + 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]; + float p[3]; copy_v3_v3(p, isects[j]); if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_sq) { @@ -1316,16 +1387,18 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, continue; } - knife_project_v2(kcd, p, sp); - ED_view3d_unproject(mats, view, sp[0], sp[1], 0.0f); - mul_m4_v3(kcd->ob->imat, view); - if (kcd->cut_through) { f_hit = NULL; } else { /* check if this point is visible in the viewport */ - float p1[3], lambda1; + float p1[3], no[3], view[3], sp[2]; + float lambda1; + + /* screen projection */ + knife_project_v2(kcd, p, sp); + ED_view3d_unproject(mats, view, sp[0], sp[1], 0.0f); + mul_m4_v3(kcd->ob->imat, view); /* if face isn't planer, p may be behind the current tesselated tri, * so move it onto that and then a little towards eye */ @@ -1473,8 +1546,16 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) knife_project_v2(kcd, v1, s1); knife_project_v2(kcd, v2, s2); - if (len_squared_v2v2(s1, s2) < 1) - return; + if (kcd->is_interactive) { + if (len_squared_v2v2(s1, s2) < 1.0f) { + return; + } + } + else { + if (len_squared_v2v2(s1, s2) < KNIFE_FLT_EPS_SQUARED) { + return; + } + } /* unproject screen line */ ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s1, v1, v3, true); @@ -2050,7 +2131,7 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd) facenet_entry *entry; ListBase *face_nets = MEM_callocN(sizeof(ListBase) * bm->totface, "face_nets"); BMFace **faces = MEM_callocN(sizeof(BMFace *) * bm->totface, "faces knife"); - MemArena *arena = BLI_memarena_new(1 << 16, "knifenet_fill_faces"); + MemArena *arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "knifenet_fill_faces"); SmallHash shash; RNG *rng; int i, j, k = 0, totface = bm->totface; @@ -3078,7 +3159,7 @@ static void knifetool_init(bContext *C, KnifeTool_OpData *kcd, (only_select ? BMBVH_RESPECT_SELECT : BMBVH_RESPECT_HIDDEN), kcd->cagecos, false); - kcd->arena = BLI_memarena_new(1 << 15, "knife"); + kcd->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), "knife"); kcd->vthresh = KMAXDIST - 1; kcd->ethresh = KMAXDIST; @@ -3444,7 +3525,7 @@ static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, while (p) { const float (*mval_fl)[2] = p->link; const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); - isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1); + isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1, false); p = p->next; } |