1076
1084
glBegin(GL_POINTS);
1077
1085
lh = kcd->linehits;
1078
1086
for (i = 0; i < kcd->totlinehit; i++, lh++) {
1079
float sv1[3], sv2[3];
1081
knife_project_v3(kcd, lh->kfe->v1->cageco, sv1);
1082
knife_project_v3(kcd, lh->kfe->v2->cageco, sv2);
1083
knife_project_v3(kcd, lh->cagehit, lh->schit);
1085
if (len_squared_v2v2(lh->schit, sv1) < vthresh4_squared) {
1087
float sv1[2], sv2[2];
1089
knife_project_v2(kcd, lh->kfe->v1->cageco, sv1);
1090
knife_project_v2(kcd, lh->kfe->v2->cageco, sv2);
1091
knife_project_v2(kcd, lh->cagehit, lh->schit);
1093
if (len_squared_v2v2(lh->schit, sv1) < vthresh4_sq) {
1086
1094
copy_v3_v3(lh->cagehit, lh->kfe->v1->cageco);
1087
1095
glVertex3fv(lh->cagehit);
1088
1096
lh->v = lh->kfe->v1;
1090
else if (len_squared_v2v2(lh->schit, sv2) < vthresh4_squared) {
1098
else if (len_squared_v2v2(lh->schit, sv2) < vthresh4_sq) {
1091
1099
copy_v3_v3(lh->cagehit, lh->kfe->v2->cageco);
1092
1100
glVertex3fv(lh->cagehit);
1093
1101
lh->v = lh->kfe->v2;
1204
1212
for (ref = lst->first; ref; ref = ref->next) {
1205
1213
KnifeEdge *kfe = ref->ref;
1207
if (BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
1215
if (BLI_smallhash_haskey(ehash, (uintptr_t)kfe)) {
1208
1216
continue; /* We already found a hit on this knife edge */
1211
1219
if (isect_line_tri_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, NULL)) {
1212
float p[3], no[3], view[3], sp[3];
1220
float p[3], no[3], view[3], sp[2];
1214
1222
interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda);
1216
if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_squared) {
1219
if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_squared) {
1222
if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_squared ||
1223
len_squared_v3v3(kcd->curr.cage, p) < depsilon_squared)
1224
if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_sq) {
1227
if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_sq) {
1230
if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_sq ||
1231
len_squared_v3v3(kcd->curr.cage, p) < depsilon_sq)
1227
1235
if ((kcd->vc.rv3d->rflag & RV3D_CLIPPING) &&
1228
ED_view3d_clipping_test(kcd->vc.rv3d, p, TRUE))
1236
ED_view3d_clipping_test(kcd->vc.rv3d, p, true))
1233
knife_project_v3(kcd, p, sp);
1241
knife_project_v2(kcd, p, sp);
1234
1242
ED_view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
1235
1243
mul_m4_v3(kcd->ob->imat, view);
1237
1245
if (kcd->cut_through) {
1241
1249
/* check if this point is visible in the viewport */
1378
1386
copy_v3_v3(v2, kcd->curr.cage);
1380
1388
/* project screen line's 3d coordinates back into 2d */
1381
knife_project_v3(kcd, v1, s1);
1382
knife_project_v3(kcd, v2, s2);
1389
knife_project_v2(kcd, v1, s1);
1390
knife_project_v2(kcd, v2, s2);
1384
if (len_v2v2(s1, s2) < 1)
1392
if (len_squared_v2v2(s1, s2) < 1)
1387
1395
/* unproject screen line */
1388
ED_view3d_win_to_segment_clip(kcd->ar, kcd->vc.v3d, s1, v1, v3);
1389
ED_view3d_win_to_segment_clip(kcd->ar, kcd->vc.v3d, s2, v2, v4);
1396
ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s1, v1, v3, true);
1397
ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s2, v2, v4, true);
1391
1399
mul_m4_v3(kcd->ob->imat, v1);
1392
1400
mul_m4_v3(kcd->ob->imat, v2);
1493
1501
knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
1494
1502
sub_v3_v3v3(ray, origin_ofs, origin);
1496
f = BMBVH_RayCast(kcd->bmbvh, origin, ray, co, cageco);
1504
f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray, NULL, co, cageco);
1499
1507
*is_space = !f;
1502
/* try to use backbuffer selection method if ray casting failed */
1503
f = EDBM_face_find_nearest(&kcd->vc, &dist);
1510
if (kcd->is_interactive) {
1511
/* try to use backbuffer selection method if ray casting failed */
1512
f = EDBM_face_find_nearest(&kcd->vc, &dist);
1505
/* cheat for now; just put in the origin instead
1506
* of a true coordinate on the face.
1507
* This just puts a point 1.0f infront of the view. */
1508
add_v3_v3v3(co, origin, ray);
1514
/* cheat for now; just put in the origin instead
1515
* of a true coordinate on the face.
1516
* This just puts a point 1.0f infront of the view. */
1517
add_v3_v3v3(co, origin, ray);
1603
1625
KnifeEdge *kfe = ref->ref;
1605
1627
/* project edge vertices into screen space */
1606
knife_project_v3(kcd, kfe->v1->cageco, kfe->v1->sco);
1607
knife_project_v3(kcd, kfe->v2->cageco, kfe->v2->sco);
1628
knife_project_v2(kcd, kfe->v1->cageco, kfe->v1->sco);
1629
knife_project_v2(kcd, kfe->v2->cageco, kfe->v2->sco);
1609
dis = dist_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
1610
if (dis < curdis && dis < maxdist) {
1631
dis_sq = dist_squared_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
1632
if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
1611
1633
if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
1612
1634
float lambda = line_point_factor_v2(sco, kfe->v1->sco, kfe->v2->sco);
1615
1637
interp_v3_v3v3(vec, kfe->v1->cageco, kfe->v2->cageco, lambda);
1617
if (ED_view3d_clipping_test(kcd->vc.rv3d, vec, TRUE) == 0) {
1639
if (ED_view3d_clipping_test(kcd->vc.rv3d, vec, true) == 0) {
2064
2086
BLI_scanfill_begin(&sf_ctx);
2066
2088
for (entry = face_nets[i].first; entry; entry = entry->next) {
2067
if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v1)) {
2089
if (!BLI_smallhash_haskey(hash, (uintptr_t)entry->kfe->v1)) {
2068
2090
sf_vert = BLI_scanfill_vert_add(&sf_ctx, entry->kfe->v1->v->co);
2069
2091
sf_vert->poly_nr = 0;
2070
rnd_offset_co(sf_vert->co, rndscale);
2092
rnd_offset_co(rng, sf_vert->co, rndscale);
2071
2093
sf_vert->tmp.p = entry->kfe->v1->v;
2072
BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v1, sf_vert);
2094
BLI_smallhash_insert(hash, (uintptr_t)entry->kfe->v1, sf_vert);
2075
if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v2)) {
2097
if (!BLI_smallhash_haskey(hash, (uintptr_t)entry->kfe->v2)) {
2076
2098
sf_vert = BLI_scanfill_vert_add(&sf_ctx, entry->kfe->v2->v->co);
2077
2099
sf_vert->poly_nr = 0;
2078
rnd_offset_co(sf_vert->co, rndscale);
2100
rnd_offset_co(rng, sf_vert->co, rndscale);
2079
2101
sf_vert->tmp.p = entry->kfe->v2->v;
2080
BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v2, sf_vert);
2102
BLI_smallhash_insert(hash, (uintptr_t)entry->kfe->v2, sf_vert);
2084
2106
for (j = 0, entry = face_nets[i].first; entry; entry = entry->next, j++) {
2085
sf_vert_last = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1);
2086
sf_vert = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2);
2107
sf_vert_last = BLI_smallhash_lookup(hash, (uintptr_t)entry->kfe->v1);
2108
sf_vert = BLI_smallhash_lookup(hash, (uintptr_t)entry->kfe->v2);
2088
2110
sf_vert->poly_nr++;
2089
2111
sf_vert_last->poly_nr++;
2092
2114
for (j = 0, entry = face_nets[i].first; entry; entry = entry->next, j++) {
2093
sf_vert_last = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1);
2094
sf_vert = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2);
2115
sf_vert_last = BLI_smallhash_lookup(hash, (uintptr_t)entry->kfe->v1);
2116
sf_vert = BLI_smallhash_lookup(hash, (uintptr_t)entry->kfe->v2);
2096
2118
if (sf_vert->poly_nr > 1 && sf_vert_last->poly_nr > 1) {
2097
2119
ScanFillEdge *sf_edge;
2098
2120
sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert);
2121
if (entry->kfe->e_old)
2100
2122
sf_edge->f = SF_EDGE_BOUNDARY; /* mark as original boundary edge */
2102
2124
BMO_elem_flag_disable(bm, entry->kfe->e->v1, DEL);
2183
2205
MEM_freeN(faces);
2184
2206
BLI_memarena_free(arena);
2186
2209
BMO_error_clear(bm); /* remerge_faces sometimes raises errors, so make sure to clear them */
2188
bmesh_edit_end(bm, BMO_OP_FLAG_UNTAN_MULTIRES);
2211
bmesh_edit_end(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH);
2192
2215
#else /* use direct (non-scanfill) method for cuts */
2194
/* assuming v is on line ab, what fraction of the way is v from a to b? */
2195
static float frac_along(const float a[3], const float b[3], const float v[3])
2199
lab = len_v3v3(a, b);
2204
return len_v3v3(a, v) / lab;
2208
2217
/* sort list of kverts by fraction along edge e */
2209
2218
static void sort_by_frac_along(ListBase *lst, BMEdge *e)
2211
KnifeVert *vcur, *vprev;
2220
/* note, since we know the point is along the edge, sort from distance to v1co */
2221
const float *v1co = e->v1->co;
2222
// const float *v2co = e->v2->co;
2213
2223
Ref *cur = NULL, *prev = NULL, *next = NULL;
2215
2225
if (lst->first == lst->last)
2221
2228
for (cur = ((Ref *)lst->first)->next; cur; cur = next) {
2229
KnifeVert *vcur = cur->ref;
2231
const float vcur_fac = line_point_factor_v3(vcur->co, v1co, v2co);
2233
const float vcur_fac = len_squared_v3v3(v1co, vcur->co);
2222
2236
next = cur->next;
2223
2237
prev = cur->prev;
2225
2239
BLI_remlink(lst, cur);
2230
if (frac_along(v1co, v2co, vprev->co) <= frac_along(v1co, v2co, vcur->co))
2242
KnifeVert *vprev = prev->ref;
2244
if (line_point_factor_v3(vprev->co, v1co, v2co) <= vcur_fac)
2247
if (len_squared_v3v3(v1co, vprev->co) <= vcur_fac)
2232
2250
prev = prev->prev;
2866
2890
EDBM_mesh_normals_update(kcd->em);
2867
EDBM_update_generic(kcd->em, TRUE, TRUE);
2891
EDBM_update_generic(kcd->em, true, true);
2870
/* copied from paint_image.c */
2871
static int project_knife_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
2893
static void knifetool_finish(wmOperator *op)
2873
int orth = ED_view3d_clip_range_get(v3d, rv3d, clipsta, clipend);
2875
if (orth) { /* only needed for ortho */
2876
float fac = 2.0f / ((*clipend) - (*clipsta));
2895
KnifeTool_OpData *kcd = op->customdata;
2896
knifetool_finish_ex(kcd);
2884
2899
static void knife_recalc_projmat(KnifeTool_OpData *kcd)
2886
2901
invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
2887
2902
ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, kcd->projmat);
2888
//mult_m4_m4m4(kcd->projmat, kcd->vc.rv3d->winmat, kcd->vc.rv3d->viewmat);
2903
//mul_m4_m4m4(kcd->projmat, kcd->vc.rv3d->winmat, kcd->vc.rv3d->viewmat);
2890
kcd->is_ortho = project_knife_view_clip(kcd->vc.v3d, kcd->vc.rv3d,
2891
&kcd->clipsta, &kcd->clipend);
2905
kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d,
2906
&kcd->clipsta, &kcd->clipend, true);
2894
2909
/* called when modal loop selection is done... */
2895
static void knifetool_exit(bContext *C, wmOperator *op)
2910
static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd)
2897
KnifeTool_OpData *kcd = op->customdata;
2902
WM_cursor_restore(CTX_wm_window(C));
2915
if (kcd->is_interactive) {
2916
WM_cursor_restore(CTX_wm_window(C));
2904
/* deactivate the extra drawing stuff in 3D-View */
2905
ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle);
2918
/* deactivate the extra drawing stuff in 3D-View */
2919
ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle);
2907
2922
/* free the custom data */
2908
2923
BLI_mempool_destroy(kcd->refs);
2913
2928
BLI_ghash_free(kcd->origvertmap, NULL, NULL);
2914
2929
BLI_ghash_free(kcd->kedgefacemap, NULL, NULL);
2916
BMBVH_FreeBVH(kcd->bmbvh);
2931
BKE_bmbvh_free(kcd->bmbvh);
2917
2932
BLI_memarena_free(kcd->arena);
2919
2934
/* tag for redraw */
2920
2935
ED_region_tag_redraw(kcd->ar);
2922
2937
if (kcd->cagecos)
2923
MEM_freeN(kcd->cagecos);
2938
MEM_freeN((void *)kcd->cagecos);
2925
2940
if (kcd->linehits)
2926
2941
MEM_freeN(kcd->linehits);
2928
2943
/* destroy kcd itself */
2929
2944
MEM_freeN(kcd);
2946
static void knifetool_exit(bContext *C, wmOperator *op)
2948
KnifeTool_OpData *kcd = op->customdata;
2949
knifetool_exit_ex(C, kcd);
2930
2950
op->customdata = NULL;
2933
static void cage_mapped_verts_callback(void *userData, int index, const float co[3],
2934
const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2936
void **data = userData;
2937
BMEditMesh *em = data[0];
2938
float (*cagecos)[3] = data[1];
2939
SmallHash *hash = data[2];
2941
if (index >= 0 && index < em->bm->totvert && !BLI_smallhash_haskey(hash, index)) {
2942
BLI_smallhash_insert(hash, index, NULL);
2943
copy_v3_v3(cagecos[index], co);
2947
static void knifetool_update_mval(KnifeTool_OpData *kcd, int mval_i[2])
2953
static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2])
2949
2955
knife_recalc_projmat(kcd);
2950
kcd->vc.mval[0] = mval_i[0];
2951
kcd->vc.mval[1] = mval_i[1];
2956
copy_v2_v2(kcd->mval, mval);
2953
2958
if (knife_update_active(kcd)) {
2954
2959
ED_region_tag_redraw(kcd->ar);
2963
static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2])
2965
float mval[2] = {UNPACK2(mval_i)};
2966
knifetool_update_mval(kcd, mval);
2958
2969
/* called when modal loop selection gets set up... */
2959
static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut))
2970
static void knifetool_init(bContext *C, KnifeTool_OpData *kcd,
2971
const bool only_select, const bool cut_through, const bool is_interactive)
2961
KnifeTool_OpData *kcd;
2962
2973
Scene *scene = CTX_data_scene(C);
2963
2974
Object *obedit = CTX_data_edit_object(C);
2964
DerivedMesh *cage, *final;
2967
const short only_select = RNA_boolean_get(op->ptr, "only_selected");
2969
/* alloc new customdata */
2970
kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), "knifetool Modal Op Data");
2972
2976
/* assign the drawing handle for drawing preview line... */
2973
2977
kcd->ob = obedit;
2974
2978
kcd->ar = CTX_wm_region(C);
2975
kcd->draw_handle = ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW);
2976
2980
em_setup_viewcontext(C, &kcd->vc);
2978
kcd->em = BMEdit_FromObject(kcd->ob);
2982
kcd->em = BKE_editmesh_from_object(kcd->ob);
2980
2984
BM_mesh_elem_index_ensure(kcd->em->bm, BM_VERT);
2982
cage = editbmesh_get_derived_cage_and_final(scene, obedit, kcd->em, &final, CD_MASK_DERIVEDMESH);
2983
kcd->cagecos = MEM_callocN(sizeof(float) * 3 * kcd->em->bm->totvert, "knife cagecos");
2985
data[1] = kcd->cagecos;
2988
BLI_smallhash_init(&shash);
2989
cage->foreachMappedVert(cage, cage_mapped_verts_callback, data);
2990
BLI_smallhash_release(&shash);
2992
kcd->bmbvh = BMBVH_NewBVH(kcd->em,
2993
(BMBVH_USE_CAGE | BMBVH_RETURN_ORIG) |
2986
kcd->cagecos = (const float (*)[3])BKE_editmesh_vertexCos_get(kcd->em, scene, NULL);
2988
kcd->bmbvh = BKE_bmbvh_new(kcd->em,
2994
2990
(only_select ? BMBVH_RESPECT_SELECT : BMBVH_RESPECT_HIDDEN),
2991
kcd->cagecos, false);
2997
2993
kcd->arena = BLI_memarena_new(1 << 15, "knife");
2998
2994
kcd->vthresh = KMAXDIST - 1;
2999
2995
kcd->ethresh = KMAXDIST;
3003
2999
knife_recalc_projmat(kcd);
3034
3033
return OPERATOR_CANCELLED;
3037
static int knifetool_invoke(bContext *C, wmOperator *op, wmEvent *evt)
3036
static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3038
const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
3039
const bool cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry");
3039
3041
KnifeTool_OpData *kcd;
3041
3043
view3d_operator_needs_opengl(C);
3043
if (!knifetool_init(C, op, 0))
3044
return OPERATOR_CANCELLED;
3045
/* alloc new customdata */
3046
kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
3048
knifetool_init(C, kcd, only_select, cut_through, true);
3046
3050
/* add a modal handler for this operator - handles loop selection */
3047
3051
WM_cursor_modal(CTX_wm_window(C), BC_KNIFECURSOR);
3048
3052
WM_event_add_modal_handler(C, op);
3050
kcd = op->customdata;
3051
knifetool_update_mval(kcd, evt->mval);
3054
knifetool_update_mval_i(kcd, event->mval);
3053
3056
knife_update_header(C, kcd);
3159
3162
return OPERATOR_FINISHED;
3160
3163
case KNF_MODAL_MIDPOINT_ON:
3161
kcd->snap_midpoints = 1;
3164
kcd->snap_midpoints = true;
3163
3166
knife_recalc_projmat(kcd);
3164
3167
knife_update_active(kcd);
3165
3168
knife_update_header(C, kcd);
3166
3169
ED_region_tag_redraw(kcd->ar);
3169
3172
case KNF_MODAL_MIDPOINT_OFF:
3170
kcd->snap_midpoints = 0;
3173
kcd->snap_midpoints = false;
3172
3175
knife_recalc_projmat(kcd);
3173
3176
knife_update_active(kcd);
3174
3177
knife_update_header(C, kcd);
3175
3178
ED_region_tag_redraw(kcd->ar);
3178
3181
case KNF_MODEL_IGNORE_SNAP_ON:
3179
3182
ED_region_tag_redraw(kcd->ar);
3180
kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 1;
3183
kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = true;
3181
3184
knife_update_header(C, kcd);
3184
3187
case KNF_MODEL_IGNORE_SNAP_OFF:
3185
3188
ED_region_tag_redraw(kcd->ar);
3186
kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 0;
3189
kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = false;
3187
3190
knife_update_header(C, kcd);
3190
3193
case KNF_MODAL_ANGLE_SNAP_TOGGLE:
3191
3194
kcd->angle_snapping = !kcd->angle_snapping;
3192
3195
knife_update_header(C, kcd);
3195
3198
case KNF_MODAL_CUT_THROUGH_TOGGLE:
3196
3199
kcd->cut_through = !kcd->cut_through;
3197
3200
knife_update_header(C, kcd);
3200
3203
case KNF_MODAL_NEW_CUT:
3201
3204
ED_region_tag_redraw(kcd->ar);
3275
3278
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
3277
RNA_def_boolean(ot->srna, "use_occlude_geometry", TRUE, "Occlude Geometry", "Only cut the front most geometry");
3278
RNA_def_boolean(ot->srna, "only_selected", FALSE, "Only Selected", "Only cut selected geometry");
3280
RNA_def_boolean(ot->srna, "use_occlude_geometry", true, "Occlude Geometry", "Only cut the front most geometry");
3281
RNA_def_boolean(ot->srna, "only_selected", false, "Only Selected", "Only cut selected geometry");
3285
/* -------------------------------------------------------------------- */
3286
/* Knife tool as a utility function
3287
* that can be used for internal slicing operations */
3290
* Return a point inside the face.
3292
* tessellation here seems way overkill,
3293
* but without this its very hard to know of a point is inside the face
3295
static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3])
3297
int tottri = f->len - 2;
3298
BMLoop **loops = BLI_array_alloca(loops, f->len);
3299
int (*index)[3] = BLI_array_alloca(index, tottri);
3302
float const *best_co[3] = {NULL};
3303
float best_area = -1.0f;
3306
tottri = BM_face_calc_tessellation(f, loops, index);
3307
BLI_assert(tottri <= f->len - 2);
3309
for (j = 0; j < tottri; j++) {
3310
const float *p1 = loops[index[j][0]]->v->co;
3311
const float *p2 = loops[index[j][1]]->v->co;
3312
const float *p3 = loops[index[j][2]]->v->co;
3316
cross_v3_v3v3(cross, p2, p3);
3317
area = fabsf(dot_v3v3(p1, cross));
3318
if (area > best_area) {
3328
mid_v3_v3v3v3(r_cent, best_co[0], best_co[1], best_co[2]);
3331
mid_v3_v3v3v3(r_cent, loops[0]->v->co, loops[1]->v->co, loops[2]->v->co);
3335
static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, float projmat[4][4])
3340
edvm_mesh_knife_face_point(f, cent);
3342
ED_view3d_project_float_v2_m4(ar, cent, cent_ss, projmat);
3346
LinkNode *p = polys;
3350
const float (*mval_fl)[2] = p->link;
3351
const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
3352
isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1);
3365
* \param use_tag When set, tag all faces inside the polylines.
3367
void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag)
3369
KnifeTool_OpData *kcd;
3371
view3d_operator_needs_opengl(C);
3375
const bool only_select = false;
3376
const bool cut_through = false;
3377
const bool is_interactive = false; /* can enable for testing */
3379
kcd = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
3381
knifetool_init(C, kcd, only_select, cut_through, is_interactive);
3383
kcd->ignore_edge_snapping = true;
3384
kcd->ignore_vert_snapping = true;
3387
BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false);
3393
LinkNode *p = polys;
3395
knife_recalc_projmat(kcd);
3398
const float (*mval_fl)[2] = p->link;
3399
const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
3402
for (i = 0; i < mval_tot; i++) {
3403
knifetool_update_mval(kcd, mval_fl[i]);
3405
knife_start_cut(kcd);
3406
kcd->mode = MODE_DRAGGING;
3412
knife_finish_cut(kcd);
3413
kcd->mode = MODE_IDLE;
3420
knifetool_finish_ex(kcd);
3422
/* tag faces inside! */
3424
BMesh *bm = kcd->em->bm;
3425
float projmat[4][4];
3432
ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, projmat);
3434
/* use face-loop tag to store if we have intersected */
3435
#define F_ISECT_IS_UNKNOWN(f) BM_elem_flag_test(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG)
3436
#define F_ISECT_SET_UNKNOWN(f) BM_elem_flag_enable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG)
3437
#define F_ISECT_SET_OUTSIDE(f) BM_elem_flag_disable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG)
3440
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3441
F_ISECT_SET_UNKNOWN(f);
3442
BM_elem_flag_disable(f, BM_ELEM_TAG);
3446
/* tag all faces linked to cut edges */
3447
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
3448
/* check are we tagged?, then we are an original face */
3449
if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) {
3452
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
3453
if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) {
3454
BM_elem_flag_enable(f, BM_ELEM_TAG);
3460
/* expand tags for faces which are not cut, but are inside the polys */
3463
keep_search = false;
3464
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3465
if (BM_elem_flag_test(f, BM_ELEM_TAG) == false && (F_ISECT_IS_UNKNOWN(f))) {
3466
/* am I connected to a tagged face via an un-tagged edge (ie, not across a cut) */
3467
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
3468
BMLoop *l_iter = l_first;
3472
if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) {
3473
/* now check if the adjacent faces is tagged */
3474
BMLoop *l_radial_iter = l_iter->radial_next;
3475
if (l_radial_iter != l_iter) {
3477
if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) {
3480
} while ((l_radial_iter = l_radial_iter->radial_next) != l_iter && (found == false));
3483
} while ((l_iter = l_iter->next) != l_first && (found == false));
3486
if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) {
3487
BM_elem_flag_enable(f, BM_ELEM_TAG);
3491
/* don't loose time on this face again, set it as outside */
3492
F_ISECT_SET_OUTSIDE(f);
3497
} while (keep_search);
3499
#undef F_ISECT_IS_UNKNOWN
3500
#undef F_ISECT_SET_UNKNOWN
3501
#undef F_ISECT_SET_OUTSIDE
3505
knifetool_exit_ex(C, kcd);