573
577
if (lh1->l < lh2->l) return -1;
574
578
else if (lh1->l > lh2->l) return 1;
579
else if (lh1->v && lh2->v) {
580
/* want like verts to sort together; just compare pointers */
581
if (lh1->v < lh2->v) return -1;
582
else if (lh1->v > lh2->v) return 1;
578
588
/* If there's a linehit connected (same face) as testi in range [firsti, lasti], return the first such, else -1.
589
* It also counts as connected if both linehits are snapped to the same vertex.
579
590
* If testi is out of range, look for connection to f instead, if f is non-NULL */
580
591
static int find_connected_linehit(KnifeTool_OpData *kcd, int testi, BMFace *f, int firsti, int lasti)
594
ListBase *testfaces, *ifaces;
595
BMFace *testface, *iface;
599
if (testi >= 0 && testi < kcd->totlinehit) {
602
lh = &kcd->linehits[testi];
604
testfaces = &lh->v->faces;
606
testfaces = &lh->kfe->faces;
584
616
for (i = firsti; i <= lasti; i++) {
585
if (testi >= 0 && testi < kcd->totlinehit) {
586
if (knife_find_common_face(&kcd->linehits[testi].kfe->faces,
587
&kcd->linehits[i].kfe->faces))
593
if (find_ref(&kcd->linehits[i].kfe->faces, f))
618
lh = &kcd->linehits[i];
622
ifaces = &lh->v->faces;
624
ifaces = &lh->kfe->faces;
631
shareface = (knife_find_common_face(testfaces, ifaces) != NULL);
633
shareface = (find_ref(testfaces, iface) != NULL);
637
shareface = (find_ref(ifaces, testface) != NULL);
639
else if (testface && iface) {
640
shareface = (testface == iface);
600
/* Sort in order of distance along cut line, but take care when distances are equal */
601
static void knife_sort_linehits(KnifeTool_OpData *kcd)
648
/* Sort in order of distance along cut line.
649
* Remove any successive linehits that are snapped to the same vertex.
650
* If joinfaces, treat hits at same distance as follows: try to find
651
* ordering so that preceding and succeeding hits will share a face.
653
static void knife_sort_linehits(KnifeTool_OpData *kcd, bool joinfaces)
603
655
int i, j, k, nexti, nsame;
605
657
qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit);
659
/* Remove duplicated linehits snapped to same vertex */
660
i = j = 0; /* loop copies from j to i */
661
while (j < kcd->totlinehit) {
663
if (kcd->linehits[j].v) {
664
for (k = j + 1; k < kcd->totlinehit; k++) {
665
if (kcd->linehits[k].v != kcd->linehits[j].v)
671
kcd->linehits[i] = kcd->linehits[j];
607
680
/* for ranges of equal "l", swap if neccesary to make predecessor and
608
681
* successor faces connected to the linehits at either end of the range */
609
682
for (i = 0; i < kcd->totlinehit - 1; i = nexti) {
763
static void copy_hit_from_posdata(BMEdgeHit *lh, KnifePosData *pos, float lambda)
768
copy_v3_v3(lh->hit, pos->co);
769
copy_v3_v3(lh->cagehit, pos->cage);
770
copy_v3_v3(lh->realhit, pos->co);
772
/* perc and schit not used by callers of this function */
688
775
/* BMESH_TODO: add more functionality to cut-through:
689
776
* - cutting "in face" (e.g., holes) should cut in all faces, not just visible one
690
777
* - perhaps improve O(n^2) algorithm used here */
691
778
static void knife_cut_through(KnifeTool_OpData *kcd)
780
BMEdgeHit *lh, *lh2, *linehits;
695
KnifeEdge *kfe, *kfe2, *kfe3;
696
KnifeVert *v1, *v2, *firstv = NULL, *lastv = NULL;
697
ListBase firstfaces = {NULL, NULL}, lastfaces = {NULL, NULL};
782
KnifeEdge *kfe, *kfe2;
783
KnifeVert *v1, *v2, *lastv;
784
ListBase *faces1, *faces2;
699
785
KnifeEdge **splitkfe;
786
bool needprev, needcurr;
702
789
if (!kcd->totlinehit) {
703
790
/* if no linehits then no interesting back face stuff to do */
708
/* TODO: probably don't need to sort at all */
709
qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit);
710
splitkfe = MEM_callocN(kcd->totlinehit * sizeof(KnifeEdge *), "knife_cut_through");
712
if (kcd->prev.vert) {
713
if (kcd->prev.vert == kcd->curr.vert)
715
firstv = kcd->prev.vert;
716
knife_get_vert_faces(kcd, firstv, kcd->prev.bmface, &firstfaces);
718
else if (kcd->prev.edge) {
719
if (kcd->prev.edge == kcd->curr.edge)
721
firstv = knife_split_edge(kcd, kcd->prev.edge, kcd->prev.co, &kfe3);
722
knife_get_edge_faces(kcd, kcd->prev.edge, &firstfaces);
725
if (kcd->curr.vert) {
726
lastv = kcd->curr.vert;
727
knife_get_vert_faces(kcd, lastv, kcd->curr.bmface, &lastfaces);
729
else if (kcd->curr.edge) {
730
lastv = knife_split_edge(kcd, kcd->curr.edge, kcd->curr.co, &kfe3);
731
knife_get_edge_faces(kcd, kcd->curr.edge, &lastfaces);
735
/* For each face incident to firstv,
736
* find the first following linehit (if any) sharing that face and connect */
737
for (r = firstfaces.first; r; r = r->next) {
740
for (j = 0, lh2 = kcd->linehits; j < kcd->totlinehit && !found; j++, lh2++) {
742
for (r2 = kfe2->faces.first; r2; r2 = r2->next) {
744
v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
745
knife_add_single_cut_through(kcd, firstv, v2, f);
751
if (!found && lastv) {
752
for (r2 = lastfaces.first; r2; r2 = r2->next) {
754
knife_add_single_cut_through(kcd, firstv, lastv, f);
762
for (i = 0, lh = kcd->linehits; i < kcd->totlinehit; i++, lh++) {
795
/* sort eliminates hits on same vertices */
796
knife_sort_linehits(kcd, false);
798
/* code is cleaner if make prev and curr into hits (if they are on edges or verts) */
800
needprev = ((kcd->prev.vert && kcd->prev.vert != kcd->linehits[0].v) || kcd->prev.edge);
801
needcurr = ((kcd->curr.vert && kcd->curr.vert != kcd->linehits[n - 1].v) || kcd->curr.edge);
802
n += needprev + needcurr;
803
linehits = MEM_callocN(n * sizeof(BMEdgeHit), "knife_cut_through");
806
copy_hit_from_posdata(&linehits[0], &kcd->prev, 0.0f);
809
memcpy(linehits + i, kcd->linehits, kcd->totlinehit * sizeof(BMEdgeHit));
810
i += kcd->totlinehit;
812
copy_hit_from_posdata(&linehits[i], &kcd->curr, 1.0f);
815
splitkfe = MEM_callocN(n * sizeof(KnifeEdge *), "knife_cut_through");
818
for (i = 0, lh = linehits; i < n; i++, lh++) {
765
/* For each face attached to edge for this linehit,
766
* find the first following linehit (if any) sharing that face and connect */
767
for (r = kfe->faces.first; r; r = r->next) {
770
for (j = i + 1, lh2 = lh + 1; j < kcd->totlinehit && !found; j++, lh2++) {
772
for (r2 = kfe2->faces.first; r2; r2 = r2->next) {
774
v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]);
775
v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
776
knife_add_single_cut_through(kcd, v1, v2, f);
782
if (!found && lastv) {
783
for (r2 = lastfaces.first; r2; r2 = r2->next) {
785
v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]);
786
knife_add_single_cut_through(kcd, v1, lastv, f);
822
/* get faces incident on hit lh */
828
faces1 = &kfe->faces;
831
/* For each following hit, connect if lh1 an lh2 share a face */
832
for (j = i + 1, lh2 = lh + 1; j < n; j++, lh2++) {
840
faces2 = &kfe2->faces;
843
f = knife_find_common_face(faces1, faces2);
846
v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]);
848
v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
849
knife_add_single_cut_through(kcd, v1, v2, f);
794
855
MEM_freeN(splitkfe);
795
857
MEM_freeN(kcd->linehits);
796
858
kcd->linehits = NULL;
797
859
kcd->totlinehit = 0;
1171
1233
return sqrtf(max_fff(s1, s2, s3));
1237
* given a tri, return 3 planes aligned with the tri's normal.
1239
* If the triangle were extruded along its normal,
1240
* the planes calculated would be the 3 sides around the extrusion.
1242
static void plane_from_tri_clip3_v3(
1243
float tri_plane_clip[3][4],
1244
const float v0[3], const float v1[3], const float v2[3])
1247
float tvec[3], cross[3];
1249
normal_tri_v3(tri_norm, v0, v1, v2);
1251
sub_v3_v3v3(tvec, v0, v1);
1252
cross_v3_v3v3(cross, tvec, tri_norm);
1253
plane_from_point_normal_v3(tri_plane_clip[0], v0, cross);
1255
sub_v3_v3v3(tvec, v1, v2);
1256
cross_v3_v3v3(cross, tvec, tri_norm);
1257
plane_from_point_normal_v3(tri_plane_clip[1], v1, cross);
1259
sub_v3_v3v3(tvec, v2, v0);
1260
cross_v3_v3v3(cross, tvec, tri_norm);
1261
plane_from_point_normal_v3(tri_plane_clip[2], v2, cross);
1265
* Given a line that is planar with a tri, clip the segment by that tri.
1267
* This is needed so we end up with both points in the triangle.
1269
static bool isect_line_tri_coplanar_v3(
1270
const float p1[3], const float p2[3],
1271
const float v0[3], const float v1[3], const float v2[3],
1272
float r_isects[2][3],
1274
/* avoid re-calculating every time */
1275
float tri_plane[4], float tri_plane_clip[3][4])
1277
float p1_tmp[3] = {UNPACK3(p1)};
1278
float p2_tmp[3] = {UNPACK3(p2)};
1280
(void)v0, (void)v1, (void)v2;
1282
/* first check if the points are planar with the tri */
1283
if ((fabsf(dist_squared_to_plane_v3(p1, tri_plane)) < KNIFE_FLT_EPS_SQUARED) &&
1284
(fabsf(dist_squared_to_plane_v3(p2, tri_plane)) < KNIFE_FLT_EPS_SQUARED) &&
1285
/* clip the segment by planes around the triangle so we can be sure the points
1286
* aren't outside the triangle */
1287
(clip_segment_v3_plane_n(p1_tmp, p2_tmp, tri_plane_clip, 3)))
1289
copy_v3_v3(r_isects[0], p1_tmp);
1290
copy_v3_v3(r_isects[1], p2_tmp);
1174
1299
static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
1175
1300
const float v1[3], const float v2[3], const float v3[3],
1176
1301
SmallHash *ehash, bglMats *mats, int *count)
1216
1348
continue; /* We already found a hit on this knife edge */
1219
if (isect_line_tri_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, NULL)) {
1220
float p[3], no[3], view[3], sp[2];
1222
interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda);
1353
if (isect_line_tri_coplanar_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3,
1356
tri_plane, tri_plane_clip))
1358
/* both kfe ends are in cutting triangle */
1361
else if (isect_line_tri_epsilon_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3,
1362
&lambda, NULL, depsilon))
1364
/* kfe intersects cutting triangle lambda of the way along kfe */
1365
interp_v3_v3v3(isects[0], kfe->v1->cageco, kfe->v2->cageco, lambda);
1369
for (j = 0; j < n_isects; j++) {
1372
copy_v3_v3(p, isects[j]);
1224
1373
if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_sq) {
1241
knife_project_v2(kcd, p, sp);
1242
ED_view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
1243
mul_m4_v3(kcd->ob->imat, view);
1245
1390
if (kcd->cut_through) {
1249
1394
/* check if this point is visible in the viewport */
1250
float p1[3], lambda1;
1395
float p1[3], no[3], view[3], sp[2];
1398
/* screen projection */
1399
knife_project_v2(kcd, p, sp);
1400
ED_view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
1401
mul_m4_v3(kcd->ob->imat, view);
1252
1403
/* if face isn't planer, p may be behind the current tesselated tri,
1253
1404
* so move it onto that and then a little towards eye */
2654
2819
BLI_assert(i == nco);
2656
2821
if (nco == 0) {
2657
2822
/* Want to prevent creating two-sided polygons */
2658
if (BM_edge_exists(v1, v2)) {
2823
if (v1 == v2 || BM_edge_exists(v1, v2)) {
2662
*newface = BM_face_split(bm, f, v1, v2, &lnew, NULL, true);
2827
f_new = BM_face_split(bm, f, v1, v2, &l_new, NULL, true);
2666
fnew = BM_face_split_n(bm, f, v1, v2, cos, nco, &lnew, NULL);
2831
f_new = BM_face_split_n(bm, f, v1, v2, cos, nco, &l_new, NULL);
2670
2833
/* Now go through lnew chain matching up chain kv's and assign real v's to them */
2671
for (l_iter = lnew->next, i = 0; i < nco; l_iter = l_iter->next, i++) {
2834
for (l_iter = l_new->next, i = 0; i < nco; l_iter = l_iter->next, i++) {
2672
2835
BLI_assert(equals_v3v3(cos[i], l_iter->v->co));
2673
2836
if (kcd->select_result) {
2674
2837
BM_edge_select_set(bm, l_iter->e, true);
3098
3269
/* items for modal map */
3099
3270
WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CANCEL);
3271
WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_ANY, KM_ANY, 0, KNF_MODAL_PANNING);
3100
3272
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_ADD_CUT);
3101
3273
WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_CANCEL);
3102
3274
WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
3223
3395
ED_region_tag_redraw(kcd->ar);
3397
case KNF_MODAL_PANNING:
3398
if (event->val != KM_RELEASE) {
3399
if (kcd->mode != MODE_PANNING) {
3400
kcd->prevmode = kcd->mode;
3401
kcd->mode = MODE_PANNING;
3405
kcd->mode = kcd->prevmode;
3408
ED_region_tag_redraw(kcd->ar);
3409
return OPERATOR_PASS_THROUGH;
3227
3413
else { /* non-modal-mapped events */
3228
3414
switch (event->type) {
3229
3418
case WHEELUPMOUSE:
3230
3419
case WHEELDOWNMOUSE:
3231
3420
return OPERATOR_PASS_THROUGH;
3233
if (event->val != KM_RELEASE) {
3234
if (kcd->mode != MODE_PANNING)
3235
kcd->prevmode = kcd->mode;
3236
kcd->mode = MODE_PANNING;
3239
kcd->mode = kcd->prevmode;
3242
ED_region_tag_redraw(kcd->ar);
3243
return OPERATOR_PASS_THROUGH;
3245
3421
case MOUSEMOVE: /* mouse moved somewhere to select another loop */
3246
3422
if (kcd->mode != MODE_PANNING) {
3247
3423
knifetool_update_mval_i(kcd, event->mval);