Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/mesh/editmesh_knife.c
| Show First 20 Lines • Show All 1,568 Lines • ▼ Show 20 Lines | static void knife_find_line_hits(KnifeTool_OpData *kcd) | ||||
| void **val_p; | void **val_p; | ||||
| float plane_cos[12]; | float plane_cos[12]; | ||||
| float s[2], se1[2], se2[2], sint[2]; | float s[2], se1[2], se2[2], sint[2]; | ||||
| float r1[3], r2[3]; | float r1[3], r2[3]; | ||||
| float d, d1, d2, lambda; | float d, d1, d2, lambda; | ||||
| float vert_tol, vert_tol_sq; | float vert_tol, vert_tol_sq; | ||||
| float line_tol, line_tol_sq; | float line_tol, line_tol_sq; | ||||
| float face_tol, face_tol_sq; | float face_tol, face_tol_sq; | ||||
| int isect_kind; | |||||
| unsigned int tot; | unsigned int tot; | ||||
| int i; | int i; | ||||
| const bool use_hit_prev = true; | const bool is_drag_hold = kcd->is_drag_hold; | ||||
| const bool use_hit_curr = (kcd->is_drag_hold == false); | const bool use_hit_prev = (kcd->prev.vert == NULL) && (kcd->prev.edge == NULL); | ||||
| const bool use_hit_curr = (is_drag_hold == false) && (kcd->curr.vert == NULL) && | |||||
| (kcd->curr.edge == NULL); | |||||
| if (kcd->linehits) { | if (kcd->linehits) { | ||||
| MEM_freeN(kcd->linehits); | MEM_freeN(kcd->linehits); | ||||
| kcd->linehits = NULL; | kcd->linehits = NULL; | ||||
| kcd->totlinehit = 0; | kcd->totlinehit = 0; | ||||
| } | } | ||||
| copy_v3_v3(v1, kcd->prev.cage); | copy_v3_v3(v1, kcd->prev.cage); | ||||
| Show All 18 Lines | static void knife_find_line_hits(KnifeTool_OpData *kcd) | ||||
| ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->ar, kcd->vc.v3d, s1, v1, v3, true); | ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->ar, kcd->vc.v3d, s1, v1, v3, true); | ||||
| ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->ar, kcd->vc.v3d, s2, v2, v4, true); | ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->ar, kcd->vc.v3d, s2, v2, v4, true); | ||||
| mul_m4_v3(kcd->ob->imat, v1); | mul_m4_v3(kcd->ob->imat, v1); | ||||
| mul_m4_v3(kcd->ob->imat, v2); | mul_m4_v3(kcd->ob->imat, v2); | ||||
| mul_m4_v3(kcd->ob->imat, v3); | mul_m4_v3(kcd->ob->imat, v3); | ||||
| mul_m4_v3(kcd->ob->imat, v4); | mul_m4_v3(kcd->ob->imat, v4); | ||||
| /* TODO: [Optimization], intersect segments v1-v3, v2-v4 with the editcage boundbox. | |||||
| * This would greatly reduces the number of false positives in the overlap. */ | |||||
| /* Numeric error, 'v1' -> 'v2', 'v2' -> 'v4' | /* Numeric error, 'v1' -> 'v2', 'v2' -> 'v4' | ||||
| * can end up being ~2000 units apart with an orthogonal perspective. | * can end up being ~2000 units apart with an orthogonal perspective. | ||||
| * | * | ||||
| * (from ED_view3d_win_to_segment_clipped() above) | * (from ED_view3d_win_to_segment_clipped() above) | ||||
| * this gives precision error; rather then solving properly | * this gives precision error; rather then solving properly | ||||
| * (which may involve using doubles everywhere!), | * (which may involve using doubles everywhere!), | ||||
| * limit the distance between these points */ | * limit the distance between these points */ | ||||
| if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) { | if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) { | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | static void knife_find_line_hits(KnifeTool_OpData *kcd) | ||||
| /* Assume these tolerances swamp floating point rounding errors in calculations below */ | /* Assume these tolerances swamp floating point rounding errors in calculations below */ | ||||
| /* first look for vertex hits */ | /* first look for vertex hits */ | ||||
| for (val_p = BLI_smallhash_iternew_p(&kfvs, &hiter, (uintptr_t *)&v); val_p; | for (val_p = BLI_smallhash_iternew_p(&kfvs, &hiter, (uintptr_t *)&v); val_p; | ||||
| val_p = BLI_smallhash_iternext_p(&hiter, (uintptr_t *)&v)) { | val_p = BLI_smallhash_iternext_p(&hiter, (uintptr_t *)&v)) { | ||||
| KnifeEdge *kfe_hit = NULL; | KnifeEdge *kfe_hit = NULL; | ||||
| bool is_in_cut = false; | |||||
| if ((is_drag_hold == false) && ELEM(v, kcd->prev.vert, kcd->curr.vert)) { | |||||
| bm_elem_from_knife_vert(v, &kfe_hit); | |||||
| is_in_cut = true; | |||||
| } | |||||
| else { | |||||
| knife_project_v2(kcd, v->cageco, s); | knife_project_v2(kcd, v->cageco, s); | ||||
| d = dist_squared_to_line_segment_v2(s, s1, s2); | d = dist_squared_to_line_segment_v2(s, s1, s2); | ||||
| if ((d <= vert_tol_sq) && | if ((d <= vert_tol_sq) && | ||||
| (point_is_visible(kcd, v->cageco, s, bm_elem_from_knife_vert(v, &kfe_hit)))) { | (point_is_visible(kcd, v->cageco, s, bm_elem_from_knife_vert(v, &kfe_hit)))) { | ||||
| is_in_cut = true; | |||||
| } | |||||
| } | |||||
| if (is_in_cut) { | |||||
| memset(&hit, 0, sizeof(hit)); | memset(&hit, 0, sizeof(hit)); | ||||
| hit.v = v; | hit.v = v; | ||||
| /* If this isn't from an existing BMVert, it may have been added to a BMEdge originally. | /* 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 | * 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 */ | * see: #knife_add_single_cut -> #knife_verts_edge_in_face, T42611 */ | ||||
| if (kfe_hit) { | if (kfe_hit) { | ||||
| hit.kfe = kfe_hit; | hit.kfe = kfe_hit; | ||||
| Show All 9 Lines | else { | ||||
| /* note that these vertes aren't used */ | /* note that these vertes aren't used */ | ||||
| *val_p = NULL; | *val_p = NULL; | ||||
| } | } | ||||
| } | } | ||||
| /* now edge hits; don't add if a vertex at end of edge should have hit */ | /* now edge hits; don't add if a vertex at end of edge should have hit */ | ||||
| for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val; | for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val; | ||||
| val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe)) { | val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe)) { | ||||
| int kfe_verts_in_cut; | bool kfe_v1_in_cut = BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) != NULL; | ||||
| /* if we intersect both verts, don't attempt to intersect the edge */ | bool kfe_v2_in_cut = BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2) != NULL; | ||||
| kfe_verts_in_cut = (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) != NULL) + | |||||
| (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2) != NULL); | |||||
| if (kfe_verts_in_cut == 2) { | /* if we intersect both verts, don't attempt to intersect the edge */ | ||||
| if (kfe_v1_in_cut && kfe_v2_in_cut) { | |||||
| continue; | continue; | ||||
| } | } | ||||
| knife_project_v2(kcd, kfe->v1->cageco, se1); | knife_project_v2(kcd, kfe->v1->cageco, se1); | ||||
| knife_project_v2(kcd, kfe->v2->cageco, se2); | knife_project_v2(kcd, kfe->v2->cageco, se2); | ||||
| isect_kind = (kfe_verts_in_cut) ? -1 : isect_seg_seg_v2_point(s1, s2, se1, se2, sint); | int isect_kind = 1; | ||||
| if ((is_drag_hold == false) && (kfe == kcd->prev.edge)) { | |||||
| copy_v2_v2(sint, kcd->prev.mval); | |||||
| } | |||||
| else if ((is_drag_hold == false) && (kfe == kcd->curr.edge)) { | |||||
| copy_v2_v2(sint, kcd->curr.mval); | |||||
| } | |||||
| else if (kfe_v1_in_cut) { | |||||
| copy_v3_v3(sint, se1); | |||||
| } | |||||
| else if (kfe_v2_in_cut) { | |||||
| copy_v3_v3(sint, se2); | |||||
| } | |||||
| else { | |||||
| isect_kind = isect_seg_seg_v2_point_ex(s1, s2, se1, se2, 0.0f, sint); | |||||
| if (isect_kind == -1) { | if (isect_kind == -1) { | ||||
| /* isect_seg_seg_v2_simple doesn't do tolerance test around ends of s1-s2 */ | /* isect_seg_seg_v2_point doesn't do tolerance test around ends of s1-s2 */ | ||||
| closest_to_line_segment_v2(sint, s1, se1, se2); | closest_to_line_segment_v2(sint, s1, se1, se2); | ||||
| if (len_squared_v2v2(sint, s1) <= line_tol_sq) { | if (len_squared_v2v2(sint, s1) <= line_tol_sq) { | ||||
| isect_kind = 1; | isect_kind = 1; | ||||
| } | } | ||||
| else { | else { | ||||
| closest_to_line_segment_v2(sint, s2, se1, se2); | closest_to_line_segment_v2(sint, s2, se1, se2); | ||||
| if (len_squared_v2v2(sint, s2) <= line_tol_sq) { | if (len_squared_v2v2(sint, s2) <= line_tol_sq) { | ||||
| isect_kind = 1; | isect_kind = 1; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| if (isect_kind == 1) { | if (isect_kind == 1) { | ||||
| d1 = len_v2v2(sint, se1); | d1 = len_v2v2(sint, se1); | ||||
| d2 = len_v2v2(se2, se1); | d2 = len_v2v2(se2, se1); | ||||
| if (!(d1 <= line_tol || d2 <= line_tol || fabsf(d1 - d2) <= line_tol)) { | if (!(d1 <= line_tol || d2 <= line_tol || fabsf(d1 - d2) <= line_tol)) { | ||||
| float p_cage[3], p_cage_tmp[3]; | float p_cage[3], p_cage_tmp[3]; | ||||
| lambda = d1 / d2; | lambda = d1 / d2; | ||||
| /* Can't just interpolate between ends of kfe because | /* Can't just interpolate between ends of kfe because | ||||
| * that doesn't work with perspective transformation. | * that doesn't work with perspective transformation. | ||||
| ▲ Show 20 Lines • Show All 1,462 Lines • Show Last 20 Lines | |||||