static void testvertexnearedge(ScanFillContext *sf_ctx) { /* only vertices with (->h == 1) are being tested for * being close to an edge, if true insert */ ScanFillVert *eve; ScanFillEdge *eed, *ed1; for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { if (eve->edge_tot == 1) { /* find the edge which has vertex eve, * note: we _know_ this will crash if 'ed1' becomes NULL * but this will never happen. */ for (ed1 = sf_ctx->filledgebase.first; !(ed1->v1 == eve || ed1->v2 == eve); ed1 = ed1->next) { /* do nothing */ } if (ed1->v1 == eve) { ed1->v1 = ed1->v2; ed1->v2 = eve; } for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { if (eve != eed->v1 && eve != eed->v2 && eve->poly_nr == eed->poly_nr) { if (compare_v2v2(eve->xy, eed->v1->xy, SF_EPSILON)) { ed1->v2 = eed->v1; eed->v1->edge_tot++; eve->edge_tot = 0; break; } else if (compare_v2v2(eve->xy, eed->v2->xy, SF_EPSILON)) { ed1->v2 = eed->v2; eed->v2->edge_tot++; eve->edge_tot = 0; break; } else { if (boundinsideEV(eed, eve)) { const float dist = dist_to_line_v2(eed->v1->xy, eed->v2->xy, eve->xy); if (dist < SF_EPSILON) { /* new edge */ ed1 = BLI_scanfill_edge_add(sf_ctx, eed->v1, eve); /* printf("fill: vertex near edge %x\n", eve); */ ed1->f = 0; ed1->poly_nr = eed->poly_nr; eed->v1 = eve; eve->edge_tot = 3; break; } } } } } } } }
static void testvertexnearedge(ScanFillContext *sf_ctx) { /* only vertices with ->h==1 are being tested for * being close to an edge, if true insert */ ScanFillVert *eve; ScanFillEdge *eed, *ed1; for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { if (eve->h == 1) { /* find the edge which has vertex eve */ ed1 = sf_ctx->filledgebase.first; while (ed1) { if (ed1->v1 == eve || ed1->v2 == eve) break; ed1 = ed1->next; } if (ed1->v1 == eve) { ed1->v1 = ed1->v2; ed1->v2 = eve; } for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { if (eve != eed->v1 && eve != eed->v2 && eve->poly_nr == eed->poly_nr) { if (compare_v3v3(eve->co, eed->v1->co, SF_EPSILON)) { ed1->v2 = eed->v1; eed->v1->h++; eve->h = 0; break; } else if (compare_v3v3(eve->co, eed->v2->co, SF_EPSILON)) { ed1->v2 = eed->v2; eed->v2->h++; eve->h = 0; break; } else { if (boundinsideEV(eed, eve)) { const float dist = dist_to_line_v2(eed->v1->xy, eed->v2->xy, eve->xy); if (dist < SF_EPSILON) { /* new edge */ ed1 = BLI_scanfill_edge_add(sf_ctx, eed->v1, eve); /* printf("fill: vertex near edge %x\n",eve); */ ed1->f = 0; ed1->poly_nr = eed->poly_nr; eed->v1 = eve; eve->h = 3; break; } } } } } } } }
static void draw_filled_lasso(wmGesture *gt) { ScanFillContext sf_ctx; ScanFillVert *sf_vert = NULL, *sf_vert_last = NULL, *sf_vert_first = NULL; ScanFillFace *sf_tri; short *lasso = (short *)gt->customdata; int i; BLI_scanfill_begin(&sf_ctx); for (i = 0; i < gt->points; i++, lasso += 2) { float co[3]; co[0] = (float)lasso[0]; co[1] = (float)lasso[1]; co[2] = 0.0f; sf_vert = BLI_scanfill_vert_add(&sf_ctx, co); if (sf_vert_last) /* e = */ /* UNUSED */ BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert); sf_vert_last = sf_vert; if (sf_vert_first == NULL) sf_vert_first = sf_vert; } /* highly unlikely this will fail, but could crash if (gt->points == 0) */ if (sf_vert_first) { const float zvec[3] = {0.0f, 0.0f, 1.0f}; BLI_scanfill_edge_add(&sf_ctx, sf_vert_first, sf_vert); BLI_scanfill_calc_ex(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES | BLI_SCANFILL_CALC_HOLES, zvec); glEnable(GL_BLEND); glColor4f(1.0, 1.0, 1.0, 0.05); glBegin(GL_TRIANGLES); for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { glVertex2fv(sf_tri->v1->co); glVertex2fv(sf_tri->v2->co); glVertex2fv(sf_tri->v3->co); } glEnd(); glDisable(GL_BLEND); BLI_scanfill_end(&sf_ctx); } }
static unsigned int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) { ScanFillVertLink *scdata; ScanFillVertLink *sc = NULL, *sc1; ScanFillVert *eve, *v1, *v2, *v3; ScanFillEdge *eed, *eed_next, *ed1, *ed2, *ed3; unsigned int a, b, verts, maxface, totface; const unsigned short nr = pf->nr; bool twoconnected = false; /* PRINTS */ #if 0 verts = pf->verts; for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { printf("vert: %x co: %f %f\n", eve, eve->xy[0], eve->xy[1]); } for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { printf("edge: %x verts: %x %x\n", eed, eed->v1, eed->v2); } #endif /* STEP 0: remove zero sized edges */ if (flag & BLI_SCANFILL_CALC_REMOVE_DOUBLES) { for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { if (equals_v2v2(eed->v1->xy, eed->v2->xy)) { if (eed->v1->f == SF_VERT_ZERO_LEN && eed->v2->f != SF_VERT_ZERO_LEN) { eed->v2->f = SF_VERT_ZERO_LEN; eed->v2->tmp.v = eed->v1->tmp.v; } else if (eed->v2->f == SF_VERT_ZERO_LEN && eed->v1->f != SF_VERT_ZERO_LEN) { eed->v1->f = SF_VERT_ZERO_LEN; eed->v1->tmp.v = eed->v2->tmp.v; } else if (eed->v2->f == SF_VERT_ZERO_LEN && eed->v1->f == SF_VERT_ZERO_LEN) { eed->v1->tmp.v = eed->v2->tmp.v; } else { eed->v2->f = SF_VERT_ZERO_LEN; eed->v2->tmp.v = eed->v1; } } } } /* STEP 1: make using FillVert and FillEdge lists a sorted * ScanFillVertLink list */ sc = scdata = MEM_mallocN(sizeof(*scdata) * pf->verts, "Scanfill1"); verts = 0; for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { if (eve->poly_nr == nr) { if (eve->f != SF_VERT_ZERO_LEN) { verts++; eve->f = SF_VERT_NEW; /* flag for connectedges later on */ sc->vert = eve; sc->edge_first = sc->edge_last = NULL; /* if (even->tmp.v == NULL) eve->tmp.u = verts; */ /* Note, debug print only will work for curve polyfill, union is in use for mesh */ sc++; } } } qsort(scdata, verts, sizeof(ScanFillVertLink), vergscdata); if (flag & BLI_SCANFILL_CALC_REMOVE_DOUBLES) { for (eed = sf_ctx->filledgebase.first; eed; eed = eed_next) { eed_next = eed->next; BLI_remlink(&sf_ctx->filledgebase, eed); /* This code is for handling zero-length edges that get * collapsed in step 0. It was removed for some time to * fix trunk bug #4544, so if that comes back, this code * may need some work, or there will have to be a better * fix to #4544. * * warning, this can hang on un-ordered edges, see: [#33281] * for now disable 'BLI_SCANFILL_CALC_REMOVE_DOUBLES' for ngons. */ if (eed->v1->f == SF_VERT_ZERO_LEN) { v1 = eed->v1; while ((eed->v1->f == SF_VERT_ZERO_LEN) && (eed->v1->tmp.v != v1) && (eed->v1 != eed->v1->tmp.v)) eed->v1 = eed->v1->tmp.v; } if (eed->v2->f == SF_VERT_ZERO_LEN) { v2 = eed->v2; while ((eed->v2->f == SF_VERT_ZERO_LEN) && (eed->v2->tmp.v != v2) && (eed->v2 != eed->v2->tmp.v)) eed->v2 = eed->v2->tmp.v; } if (eed->v1 != eed->v2) { addedgetoscanlist(scdata, eed, verts); } } } else { for (eed = sf_ctx->filledgebase.first; eed; eed = eed_next) { eed_next = eed->next; BLI_remlink(&sf_ctx->filledgebase, eed); if (eed->v1 != eed->v2) { addedgetoscanlist(scdata, eed, verts); } } } #if 0 sc = sf_ctx->_scdata; for (a = 0; a < verts; a++) { printf("\nscvert: %x\n", sc->vert); for (eed = sc->edge_first; eed; eed = eed->next) { printf(" ed %x %x %x\n", eed, eed->v1, eed->v2); } sc++; } #endif /* STEP 2: FILL LOOP */ if (pf->f == SF_POLY_NEW) twoconnected = true; /* (temporal) security: never much more faces than vertices */ totface = 0; if (flag & BLI_SCANFILL_CALC_HOLES) { maxface = 2 * verts; /* 2*verts: based at a filled circle within a triangle */ } else { maxface = verts - 2; /* when we don't calc any holes, we assume face is a non overlapping loop */ } sc = scdata; for (a = 0; a < verts; a++) { /* printf("VERTEX %d index %d\n", a, sc->vert->tmp.u); */ /* set connectflags */ for (ed1 = sc->edge_first; ed1; ed1 = eed_next) { eed_next = ed1->next; if (ed1->v1->edge_tot == 1 || ed1->v2->edge_tot == 1) { BLI_remlink((ListBase *)&(sc->edge_first), ed1); BLI_addtail(&sf_ctx->filledgebase, ed1); if (ed1->v1->edge_tot > 1) ed1->v1->edge_tot--; if (ed1->v2->edge_tot > 1) ed1->v2->edge_tot--; } else { ed1->v2->f = SF_VERT_AVAILABLE; } } while (sc->edge_first) { /* for as long there are edges */ ed1 = sc->edge_first; ed2 = ed1->next; /* commented out... the ESC here delivers corrupted memory (and doesnt work during grab) */ /* if (callLocalInterruptCallBack()) break; */ if (totface >= maxface) { /* printf("Fill error: endless loop. Escaped at vert %d, tot: %d.\n", a, verts); */ a = verts; break; } if (ed2 == NULL) { sc->edge_first = sc->edge_last = NULL; /* printf("just 1 edge to vert\n"); */ BLI_addtail(&sf_ctx->filledgebase, ed1); ed1->v2->f = SF_VERT_NEW; ed1->v1->edge_tot--; ed1->v2->edge_tot--; } else { /* test rest of vertices */ ScanFillVertLink *best_sc = NULL; float best_angle = 3.14f; float miny; bool firsttime = false; v1 = ed1->v2; v2 = ed1->v1; v3 = ed2->v2; /* this happens with a serial of overlapping edges */ if (v1 == v2 || v2 == v3) break; /* printf("test verts %d %d %d\n", v1->tmp.u, v2->tmp.u, v3->tmp.u); */ miny = min_ff(v1->xy[1], v3->xy[1]); sc1 = sc + 1; for (b = a + 1; b < verts; b++, sc1++) { if (sc1->vert->f == SF_VERT_NEW) { if (sc1->vert->xy[1] <= miny) break; if (testedgeside(v1->xy, v2->xy, sc1->vert->xy)) { if (testedgeside(v2->xy, v3->xy, sc1->vert->xy)) { if (testedgeside(v3->xy, v1->xy, sc1->vert->xy)) { /* point is in triangle */ /* because multiple points can be inside triangle (concave holes) */ /* we continue searching and pick the one with sharpest corner */ if (best_sc == NULL) { /* even without holes we need to keep checking [#35861] */ best_sc = sc1; } else { float angle; /* prevent angle calc for the simple cases only 1 vertex is found */ if (firsttime == false) { best_angle = angle_v2v2v2(v2->xy, v1->xy, best_sc->vert->xy); firsttime = true; } angle = angle_v2v2v2(v2->xy, v1->xy, sc1->vert->xy); if (angle < best_angle) { best_sc = sc1; best_angle = angle; } } } } } } } if (best_sc) { /* make new edge, and start over */ /* printf("add new edge %d %d and start again\n", v2->tmp.u, best_sc->vert->tmp.u); */ ed3 = BLI_scanfill_edge_add(sf_ctx, v2, best_sc->vert); BLI_remlink(&sf_ctx->filledgebase, ed3); BLI_insertlinkbefore((ListBase *)&(sc->edge_first), ed2, ed3); ed3->v2->f = SF_VERT_AVAILABLE; ed3->f = SF_EDGE_INTERNAL; ed3->v1->edge_tot++; ed3->v2->edge_tot++; } else { /* new triangle */ /* printf("add face %d %d %d\n", v1->tmp.u, v2->tmp.u, v3->tmp.u); */ addfillface(sf_ctx, v1, v2, v3); totface++; BLI_remlink((ListBase *)&(sc->edge_first), ed1); BLI_addtail(&sf_ctx->filledgebase, ed1); ed1->v2->f = SF_VERT_NEW; ed1->v1->edge_tot--; ed1->v2->edge_tot--; /* ed2 can be removed when it's a boundary edge */ if (((ed2->f == SF_EDGE_NEW) && twoconnected) /* || (ed2->f == SF_EDGE_BOUNDARY) */) { BLI_remlink((ListBase *)&(sc->edge_first), ed2); BLI_addtail(&sf_ctx->filledgebase, ed2); ed2->v2->f = SF_VERT_NEW; ed2->v1->edge_tot--; ed2->v2->edge_tot--; } /* new edge */ ed3 = BLI_scanfill_edge_add(sf_ctx, v1, v3); BLI_remlink(&sf_ctx->filledgebase, ed3); ed3->f = SF_EDGE_INTERNAL; ed3->v1->edge_tot++; ed3->v2->edge_tot++; /* printf("add new edge %x %x\n", v1, v3); */ sc1 = addedgetoscanlist(scdata, ed3, verts); if (sc1) { /* ed3 already exists: remove if a boundary */ /* printf("Edge exists\n"); */ ed3->v1->edge_tot--; ed3->v2->edge_tot--; for (ed3 = sc1->edge_first; ed3; ed3 = ed3->next) { if ((ed3->v1 == v1 && ed3->v2 == v3) || (ed3->v1 == v3 && ed3->v2 == v1)) { if (twoconnected /* || (ed3->f == SF_EDGE_BOUNDARY) */) { BLI_remlink((ListBase *)&(sc1->edge_first), ed3); BLI_addtail(&sf_ctx->filledgebase, ed3); ed3->v1->edge_tot--; ed3->v2->edge_tot--; } break; } } } } } /* test for loose edges */ for (ed1 = sc->edge_first; ed1; ed1 = eed_next) { eed_next = ed1->next; if (ed1->v1->edge_tot < 2 || ed1->v2->edge_tot < 2) { BLI_remlink((ListBase *)&(sc->edge_first), ed1); BLI_addtail(&sf_ctx->filledgebase, ed1); if (ed1->v1->edge_tot > 1) ed1->v1->edge_tot--; if (ed1->v2->edge_tot > 1) ed1->v2->edge_tot--; } } /* done with loose edges */ } sc++; } MEM_freeN(scdata); BLI_assert(totface <= maxface); return totface; }
void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mask, const int width, const int height, const bool do_aspect_correct, const bool do_mask_aa, const bool do_feather) { const rctf default_bounds = {0.0f, 1.0f, 0.0f, 1.0f}; const float pixel_size = 1.0f / (float)min_ii(width, height); const float asp_xy[2] = {(do_aspect_correct && width > height) ? (float)height / (float)width : 1.0f, (do_aspect_correct && width < height) ? (float)width / (float)height : 1.0f}; const float zvec[3] = {0.0f, 0.0f, 1.0f}; MaskLayer *masklay; unsigned int masklay_index; MemArena *sf_arena; mr_handle->layers_tot = (unsigned int)BLI_countlist(&mask->masklayers); mr_handle->layers = MEM_mallocN(sizeof(MaskRasterLayer) * mr_handle->layers_tot, "MaskRasterLayer"); BLI_rctf_init_minmax(&mr_handle->bounds); sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__); for (masklay = mask->masklayers.first, masklay_index = 0; masklay; masklay = masklay->next, masklay_index++) { /* we need to store vertex ranges for open splines for filling */ unsigned int tot_splines; MaskRasterSplineInfo *open_spline_ranges; unsigned int open_spline_index = 0; MaskSpline *spline; /* scanfill */ ScanFillContext sf_ctx; ScanFillVert *sf_vert = NULL; ScanFillVert *sf_vert_next = NULL; ScanFillFace *sf_tri; unsigned int sf_vert_tot = 0; unsigned int tot_feather_quads = 0; #ifdef USE_SCANFILL_EDGE_WORKAROUND unsigned int tot_boundary_used = 0; unsigned int tot_boundary_found = 0; #endif if (masklay->restrictflag & MASK_RESTRICT_RENDER) { /* skip the layer */ mr_handle->layers_tot--; masklay_index--; continue; } tot_splines = (unsigned int)BLI_countlist(&masklay->splines); open_spline_ranges = MEM_callocN(sizeof(*open_spline_ranges) * tot_splines, __func__); BLI_scanfill_begin_arena(&sf_ctx, sf_arena); for (spline = masklay->splines.first; spline; spline = spline->next) { const bool is_cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0; const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0; float (*diff_points)[2]; unsigned int tot_diff_point; float (*diff_feather_points)[2]; float (*diff_feather_points_flip)[2]; unsigned int tot_diff_feather_points; const unsigned int resol_a = BKE_mask_spline_resolution(spline, width, height) / 4; const unsigned int resol_b = BKE_mask_spline_feather_resolution(spline, width, height) / 4; const unsigned int resol = CLAMPIS(MAX2(resol_a, resol_b), 4, 512); diff_points = BKE_mask_spline_differentiate_with_resolution( spline, &tot_diff_point, resol); if (do_feather) { diff_feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution( spline, &tot_diff_feather_points, resol, FALSE); BLI_assert(diff_feather_points); } else { tot_diff_feather_points = 0; diff_feather_points = NULL; } if (tot_diff_point > 3) { ScanFillVert *sf_vert_prev; unsigned int j; float co[3]; co[2] = 0.0f; sf_ctx.poly_nr++; if (do_aspect_correct) { if (width != height) { float *fp; float *ffp; unsigned int i; float asp; if (width < height) { fp = &diff_points[0][0]; ffp = tot_diff_feather_points ? &diff_feather_points[0][0] : NULL; asp = (float)width / (float)height; } else { fp = &diff_points[0][1]; ffp = tot_diff_feather_points ? &diff_feather_points[0][1] : NULL; asp = (float)height / (float)width; } for (i = 0; i < tot_diff_point; i++, fp += 2) { (*fp) = (((*fp) - 0.5f) / asp) + 0.5f; } if (tot_diff_feather_points) { for (i = 0; i < tot_diff_feather_points; i++, ffp += 2) { (*ffp) = (((*ffp) - 0.5f) / asp) + 0.5f; } } } } /* fake aa, using small feather */ if (do_mask_aa == TRUE) { if (do_feather == FALSE) { tot_diff_feather_points = tot_diff_point; diff_feather_points = MEM_mallocN(sizeof(*diff_feather_points) * (size_t)tot_diff_feather_points, __func__); /* add single pixel feather */ maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points, tot_diff_point, pixel_size, FALSE); } else { /* ensure single pixel feather, on any zero feather areas */ maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points, tot_diff_point, pixel_size, TRUE); } } if (is_fill) { /* applt intersections depending on fill settings */ if (spline->flag & MASK_SPLINE_NOINTERSECT) { BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points, tot_diff_feather_points); } copy_v2_v2(co, diff_points[0]); sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co); sf_vert_prev->tmp.u = sf_vert_tot; sf_vert_prev->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */ sf_vert_tot++; /* TODO, an alternate functions so we can avoid double vector copy! */ for (j = 1; j < tot_diff_point; j++) { copy_v2_v2(co, diff_points[j]); sf_vert = BLI_scanfill_vert_add(&sf_ctx, co); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */ sf_vert_tot++; } sf_vert = sf_vert_prev; sf_vert_prev = sf_ctx.fillvertbase.last; for (j = 0; j < tot_diff_point; j++) { ScanFillEdge *sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_prev, sf_vert); #ifdef USE_SCANFILL_EDGE_WORKAROUND if (diff_feather_points) { sf_edge->tmp.c = SF_EDGE_IS_BOUNDARY; tot_boundary_used++; } #else (void)sf_edge; #endif sf_vert_prev = sf_vert; sf_vert = sf_vert->next; } if (diff_feather_points) { float co_feather[3]; co_feather[2] = 1.0f; BLI_assert(tot_diff_feather_points == tot_diff_point); /* note: only added for convenience, we don't infact use these to scanfill, * only to create feather faces after scanfill */ for (j = 0; j < tot_diff_feather_points; j++) { copy_v2_v2(co_feather, diff_feather_points[j]); sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); /* no need for these attrs */ #if 0 sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */ #endif sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; } tot_feather_quads += tot_diff_point; } } else { /* unfilled spline */ if (diff_feather_points) { float co_diff[2]; float co_feather[3]; co_feather[2] = 1.0f; if (spline->flag & MASK_SPLINE_NOINTERSECT) { diff_feather_points_flip = MEM_mallocN(sizeof(float) * 2 * tot_diff_feather_points, "diff_feather_points_flip"); for (j = 0; j < tot_diff_point; j++) { sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]); add_v2_v2v2(diff_feather_points_flip[j], diff_points[j], co_diff); } BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points, tot_diff_feather_points); BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points_flip, tot_diff_feather_points); } else { diff_feather_points_flip = NULL; } open_spline_ranges[open_spline_index].vertex_offset = sf_vert_tot; open_spline_ranges[open_spline_index].vertex_total = tot_diff_point; /* TODO, an alternate functions so we can avoid double vector copy! */ for (j = 0; j < tot_diff_point; j++) { /* center vert */ copy_v2_v2(co, diff_points[j]); sf_vert = BLI_scanfill_vert_add(&sf_ctx, co); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; /* feather vert A */ copy_v2_v2(co_feather, diff_feather_points[j]); sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; /* feather vert B */ if (diff_feather_points_flip) { copy_v2_v2(co_feather, diff_feather_points_flip[j]); } else { sub_v2_v2v2(co_diff, co, co_feather); add_v2_v2v2(co_feather, co, co_diff); } sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; tot_feather_quads += 2; } if (!is_cyclic) { tot_feather_quads -= 2; } if (diff_feather_points_flip) { MEM_freeN(diff_feather_points_flip); diff_feather_points_flip = NULL; } /* cap ends */ /* dummy init value */ open_spline_ranges[open_spline_index].vertex_total_cap_head = 0; open_spline_ranges[open_spline_index].vertex_total_cap_tail = 0; if (!is_cyclic) { float *fp_cent; float *fp_turn; unsigned int k; fp_cent = diff_points[0]; fp_turn = diff_feather_points[0]; #define CALC_CAP_RESOL \ clampis_uint((unsigned int )(len_v2v2(fp_cent, fp_turn) / \ (pixel_size * SPLINE_RESOL_CAP_PER_PIXEL)), \ SPLINE_RESOL_CAP_MIN, SPLINE_RESOL_CAP_MAX) { const unsigned int vertex_total_cap = CALC_CAP_RESOL; for (k = 1; k < vertex_total_cap; k++) { const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI; rotate_point_v2(co_feather, fp_turn, fp_cent, angle, asp_xy); sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; } tot_feather_quads += vertex_total_cap; open_spline_ranges[open_spline_index].vertex_total_cap_head = vertex_total_cap; } fp_cent = diff_points[tot_diff_point - 1]; fp_turn = diff_feather_points[tot_diff_point - 1]; { const unsigned int vertex_total_cap = CALC_CAP_RESOL; for (k = 1; k < vertex_total_cap; k++) { const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI; rotate_point_v2(co_feather, fp_turn, fp_cent, -angle, asp_xy); sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; } tot_feather_quads += vertex_total_cap; open_spline_ranges[open_spline_index].vertex_total_cap_tail = vertex_total_cap; } } open_spline_ranges[open_spline_index].is_cyclic = is_cyclic; open_spline_index++; #undef CALC_CAP_RESOL /* end capping */ } } } if (diff_points) { MEM_freeN(diff_points); } if (diff_feather_points) { MEM_freeN(diff_feather_points); } } { unsigned int (*face_array)[4], *face; /* access coords */ float (*face_coords)[3], *cos; /* xy, z 0-1 (1.0 == filled) */ unsigned int sf_tri_tot; rctf bounds; unsigned int face_index; int scanfill_flag = 0; bool is_isect = false; ListBase isect_remvertbase = {NULL, NULL}; ListBase isect_remedgebase = {NULL, NULL}; /* now we have all the splines */ face_coords = MEM_mallocN((sizeof(float) * 3) * sf_vert_tot, "maskrast_face_coords"); /* init bounds */ BLI_rctf_init_minmax(&bounds); /* coords */ cos = (float *)face_coords; for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert_next) { sf_vert_next = sf_vert->next; copy_v3_v3(cos, sf_vert->co); /* remove so as not to interfere with fill (called after) */ if (sf_vert->keyindex == SF_KEYINDEX_TEMP_ID) { BLI_remlink(&sf_ctx.fillvertbase, sf_vert); } /* bounds */ BLI_rctf_do_minmax_v(&bounds, cos); cos += 3; } /* --- inefficient self-intersect case --- */ /* if self intersections are found, its too trickty to attempt to map vertices * so just realloc and add entirely new vertices - the result of the self-intersect check */ if ((masklay->flag & MASK_LAYERFLAG_FILL_OVERLAP) && (is_isect = BLI_scanfill_calc_self_isect(&sf_ctx, &isect_remvertbase, &isect_remedgebase))) { unsigned int sf_vert_tot_isect = (unsigned int)BLI_countlist(&sf_ctx.fillvertbase); unsigned int i = sf_vert_tot; face_coords = MEM_reallocN(face_coords, sizeof(float[3]) * (sf_vert_tot + sf_vert_tot_isect)); cos = (float *)&face_coords[sf_vert_tot][0]; for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert->next) { copy_v3_v3(cos, sf_vert->co); sf_vert->tmp.u = i++; cos += 3; } sf_vert_tot += sf_vert_tot_isect; /* we need to calc polys after self intersect */ scanfill_flag |= BLI_SCANFILL_CALC_POLYS; } /* --- end inefficient code --- */ /* main scan-fill */ if ((masklay->flag & MASK_LAYERFLAG_FILL_DISCRETE) == 0) scanfill_flag |= BLI_SCANFILL_CALC_HOLES; sf_tri_tot = (unsigned int)BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, zvec); if (is_isect) { /* add removed data back, we only need edges for feather, * but add verts back so they get freed along with others */ BLI_movelisttolist(&sf_ctx.fillvertbase, &isect_remvertbase); BLI_movelisttolist(&sf_ctx.filledgebase, &isect_remedgebase); } face_array = MEM_mallocN(sizeof(*face_array) * ((size_t)sf_tri_tot + (size_t)tot_feather_quads), "maskrast_face_index"); face_index = 0; /* faces */ face = (unsigned int *)face_array; for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { *(face++) = sf_tri->v3->tmp.u; *(face++) = sf_tri->v2->tmp.u; *(face++) = sf_tri->v1->tmp.u; *(face++) = TRI_VERT; face_index++; FACE_ASSERT(face - 4, sf_vert_tot); } /* start of feather faces... if we have this set, * 'face_index' is kept from loop above */ BLI_assert(face_index == sf_tri_tot); if (tot_feather_quads) { ScanFillEdge *sf_edge; for (sf_edge = sf_ctx.filledgebase.first; sf_edge; sf_edge = sf_edge->next) { if (sf_edge->tmp.c == SF_EDGE_IS_BOUNDARY) { *(face++) = sf_edge->v1->tmp.u; *(face++) = sf_edge->v2->tmp.u; *(face++) = sf_edge->v2->keyindex; *(face++) = sf_edge->v1->keyindex; face_index++; FACE_ASSERT(face - 4, sf_vert_tot); #ifdef USE_SCANFILL_EDGE_WORKAROUND tot_boundary_found++; #endif } } } #ifdef USE_SCANFILL_EDGE_WORKAROUND if (tot_boundary_found != tot_boundary_used) { BLI_assert(tot_boundary_found < tot_boundary_used); } #endif /* feather only splines */ while (open_spline_index > 0) { const unsigned int vertex_offset = open_spline_ranges[--open_spline_index].vertex_offset; unsigned int vertex_total = open_spline_ranges[ open_spline_index].vertex_total; unsigned int vertex_total_cap_head = open_spline_ranges[ open_spline_index].vertex_total_cap_head; unsigned int vertex_total_cap_tail = open_spline_ranges[ open_spline_index].vertex_total_cap_tail; unsigned int k, j; j = vertex_offset; /* subtract one since we reference next vertex triple */ for (k = 0; k < vertex_total - 1; k++, j += 3) { BLI_assert(j == vertex_offset + (k * 3)); *(face++) = j + 3; /* next span */ /* z 1 */ *(face++) = j + 0; /* z 1 */ *(face++) = j + 1; /* z 0 */ *(face++) = j + 4; /* next span */ /* z 0 */ face_index++; FACE_ASSERT(face - 4, sf_vert_tot); *(face++) = j + 0; /* z 1 */ *(face++) = j + 3; /* next span */ /* z 1 */ *(face++) = j + 5; /* next span */ /* z 0 */ *(face++) = j + 2; /* z 0 */ face_index++; FACE_ASSERT(face - 4, sf_vert_tot); } if (open_spline_ranges[open_spline_index].is_cyclic) { *(face++) = vertex_offset + 0; /* next span */ /* z 1 */ *(face++) = j + 0; /* z 1 */ *(face++) = j + 1; /* z 0 */ *(face++) = vertex_offset + 1; /* next span */ /* z 0 */ face_index++; FACE_ASSERT(face - 4, sf_vert_tot); *(face++) = j + 0; /* z 1 */ *(face++) = vertex_offset + 0; /* next span */ /* z 1 */ *(face++) = vertex_offset + 2; /* next span */ /* z 0 */ *(face++) = j + 2; /* z 0 */ face_index++; FACE_ASSERT(face - 4, sf_vert_tot); } else { unsigned int midvidx = vertex_offset; /*************** * cap end 'a' */ j = midvidx + (vertex_total * 3); for (k = 0; k < vertex_total_cap_head - 2; k++, j++) { *(face++) = midvidx + 0; /* z 1 */ *(face++) = midvidx + 0; /* z 1 */ *(face++) = j + 0; /* z 0 */ *(face++) = j + 1; /* z 0 */ face_index++; FACE_ASSERT(face - 4, sf_vert_tot); } j = vertex_offset + (vertex_total * 3); /* 2 tris that join the original */ *(face++) = midvidx + 0; /* z 1 */ *(face++) = midvidx + 0; /* z 1 */ *(face++) = midvidx + 1; /* z 0 */ *(face++) = j + 0; /* z 0 */ face_index++; FACE_ASSERT(face - 4, sf_vert_tot); *(face++) = midvidx + 0; /* z 1 */ *(face++) = midvidx + 0; /* z 1 */ *(face++) = j + vertex_total_cap_head - 2; /* z 0 */ *(face++) = midvidx + 2; /* z 0 */ face_index++; FACE_ASSERT(face - 4, sf_vert_tot); /*************** * cap end 'b' */ /* ... same as previous but v 2-3 flipped, and different initial offsets */ j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1); midvidx = vertex_offset + (vertex_total * 3) - 3; for (k = 0; k < vertex_total_cap_tail - 2; k++, j++) { *(face++) = midvidx; /* z 1 */ *(face++) = midvidx; /* z 1 */ *(face++) = j + 1; /* z 0 */ *(face++) = j + 0; /* z 0 */ face_index++; FACE_ASSERT(face - 4, sf_vert_tot); } j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1); /* 2 tris that join the original */ *(face++) = midvidx + 0; /* z 1 */ *(face++) = midvidx + 0; /* z 1 */ *(face++) = j + 0; /* z 0 */ *(face++) = midvidx + 1; /* z 0 */ face_index++; FACE_ASSERT(face - 4, sf_vert_tot); *(face++) = midvidx + 0; /* z 1 */ *(face++) = midvidx + 0; /* z 1 */ *(face++) = midvidx + 2; /* z 0 */ *(face++) = j + vertex_total_cap_tail - 2; /* z 0 */ face_index++; FACE_ASSERT(face - 4, sf_vert_tot); } } MEM_freeN(open_spline_ranges); // fprintf(stderr, "%u %u (%u %u), %u\n", face_index, sf_tri_tot + tot_feather_quads, sf_tri_tot, tot_feather_quads, tot_boundary_used - tot_boundary_found); #ifdef USE_SCANFILL_EDGE_WORKAROUND BLI_assert(face_index + (tot_boundary_used - tot_boundary_found) == sf_tri_tot + tot_feather_quads); #else BLI_assert(face_index == sf_tri_tot + tot_feather_quads); #endif { MaskRasterLayer *layer = &mr_handle->layers[masklay_index]; if (BLI_rctf_isect(&default_bounds, &bounds, &bounds)) { #ifdef USE_SCANFILL_EDGE_WORKAROUND layer->face_tot = (sf_tri_tot + tot_feather_quads) - (tot_boundary_used - tot_boundary_found); #else layer->face_tot = (sf_tri_tot + tot_feather_quads); #endif layer->face_coords = face_coords; layer->face_array = face_array; layer->bounds = bounds; layer_bucket_init(layer, pixel_size); BLI_rctf_union(&mr_handle->bounds, &bounds); } else { MEM_freeN(face_coords); MEM_freeN(face_array); layer_bucket_init_dummy(layer); } /* copy as-is */ layer->alpha = masklay->alpha; layer->blend = masklay->blend; layer->blend_flag = masklay->blend_flag; layer->falloff = masklay->falloff; } /* printf("tris %d, feather tris %d\n", sf_tri_tot, tot_feather_quads); */ } /* add trianges */ BLI_scanfill_end_arena(&sf_ctx, sf_arena); } BLI_memarena_free(sf_arena); }
/** * \param normal_proj Optional normal thats used to project the scanfill verts into 2d coords. * Pass this along if known since it saves time calculating the normal. * \param flipnormal Flip the normal (same as passing \a normal_proj negated) */ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj[3], const bool flipnormal) { ScanFillContext sf_ctx; ScanFillVert *sf_vert, *sf_vert_new, *sf_vert_last; ScanFillFace *sf_tri; MemArena *sf_arena; DispList *dlnew = NULL, *dl; float *f1; int colnr = 0, charidx = 0, cont = 1, tot, a, *index, nextcol = 0; int totvert; const int scanfill_flag = BLI_SCANFILL_CALC_REMOVE_DOUBLES | BLI_SCANFILL_CALC_POLYS | BLI_SCANFILL_CALC_HOLES; if (dispbase == NULL) return; if (BLI_listbase_is_empty(dispbase)) return; sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__); while (cont) { int dl_flag_accum = 0; cont = 0; totvert = 0; nextcol = 0; BLI_scanfill_begin_arena(&sf_ctx, sf_arena); dl = dispbase->first; while (dl) { if (dl->type == DL_POLY) { if (charidx < dl->charidx) cont = 1; else if (charidx == dl->charidx) { /* character with needed index */ if (colnr == dl->col) { sf_ctx.poly_nr++; /* make editverts and edges */ f1 = dl->verts; a = dl->nr; sf_vert = sf_vert_new = NULL; while (a--) { sf_vert_last = sf_vert; sf_vert = BLI_scanfill_vert_add(&sf_ctx, f1); totvert++; if (sf_vert_last == NULL) sf_vert_new = sf_vert; else { BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert); } f1 += 3; } if (sf_vert != NULL && sf_vert_new != NULL) { BLI_scanfill_edge_add(&sf_ctx, sf_vert, sf_vert_new); } } else if (colnr < dl->col) { /* got poly with next material at current char */ cont = 1; nextcol = 1; } } dl_flag_accum |= dl->flag; } dl = dl->next; } /* XXX (obedit && obedit->actcol) ? (obedit->actcol - 1) : 0)) { */ if (totvert && (tot = BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal_proj))) { if (tot) { dlnew = MEM_callocN(sizeof(DispList), "filldisplist"); dlnew->type = DL_INDEX3; dlnew->flag = (dl_flag_accum & (DL_BACK_CURVE | DL_FRONT_CURVE)); dlnew->col = colnr; dlnew->nr = totvert; dlnew->parts = tot; dlnew->index = MEM_mallocN(tot * 3 * sizeof(int), "dlindex"); dlnew->verts = MEM_mallocN(totvert * 3 * sizeof(float), "dlverts"); /* vert data */ f1 = dlnew->verts; totvert = 0; for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert->next) { copy_v3_v3(f1, sf_vert->co); f1 += 3; /* index number */ sf_vert->tmp.i = totvert; totvert++; } /* index data */ index = dlnew->index; for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { index[0] = sf_tri->v1->tmp.i; index[1] = sf_tri->v2->tmp.i; index[2] = sf_tri->v3->tmp.i; if (flipnormal) SWAP(int, index[0], index[2]); index += 3; } } BLI_addhead(to, dlnew); } BLI_scanfill_end_arena(&sf_ctx, sf_arena); if (nextcol) { /* stay at current char but fill polys with next material */ colnr++; } else { /* switch to next char and start filling from first material */ charidx++; colnr = 0; } } BLI_memarena_free(sf_arena); /* do not free polys, needed for wireframe display */ }
static bool scanfill_preprocess_self_isect( ScanFillContext *sf_ctx, PolyInfo *poly_info, const unsigned short poly_nr, ListBase *filledgebase) { PolyInfo *pi = &poly_info[poly_nr]; GHash *isect_hash = NULL; ListBase isect_lb = {NULL}; /* warning, O(n2) check here, should use spatial lookup */ { ScanFillEdge *eed; for (eed = pi->edge_first; eed; eed = (eed == pi->edge_last) ? NULL : eed->next) { ScanFillEdge *eed_other; for (eed_other = eed->next; eed_other; eed_other = (eed_other == pi->edge_last) ? NULL : eed_other->next) { if (!ELEM(eed->v1, eed_other->v1, eed_other->v2) && !ELEM(eed->v2, eed_other->v1, eed_other->v2) && (eed != eed_other)) { /* check isect */ float pt[2]; BLI_assert(eed != eed_other); if (isect_seg_seg_v2_point(eed->v1->co, eed->v2->co, eed_other->v1->co, eed_other->v2->co, pt) == 1) { ScanFillIsect *isect; if (UNLIKELY(isect_hash == NULL)) { isect_hash = BLI_ghash_ptr_new(__func__); } isect = MEM_mallocN(sizeof(ScanFillIsect), __func__); BLI_addtail(&isect_lb, isect); copy_v2_v2(isect->co, pt); isect->co[2] = eed->v1->co[2]; isect->v = BLI_scanfill_vert_add(sf_ctx, isect->co); isect->v->poly_nr = eed->v1->poly_nr; /* NOTE: vert may belong to 2 polys now */ VFLAG_SET(isect->v, V_ISISECT); edge_isect_ls_add(isect_hash, eed, isect); edge_isect_ls_add(isect_hash, eed_other, isect); } } } } } if (isect_hash == NULL) { return false; } /* now subdiv the edges */ { ScanFillEdge *eed; for (eed = pi->edge_first; eed; eed = (eed == pi->edge_last) ? NULL : eed->next) { if (eed->user_flag & E_ISISECT) { ListBase *e_ls = BLI_ghash_lookup(isect_hash, eed); LinkData *isect_link; /* maintain coorect terminating edge */ if (pi->edge_last == eed) { pi->edge_last = NULL; } if (BLI_listbase_is_single(e_ls) == false) { BLI_sortlist_r(e_ls, eed->v2->co, edge_isect_ls_sort_cb); } /* move original edge to filledgebase and add replacement * (which gets subdivided next) */ { ScanFillEdge *eed_tmp; eed_tmp = BLI_scanfill_edge_add(sf_ctx, eed->v1, eed->v2); BLI_remlink(&sf_ctx->filledgebase, eed_tmp); BLI_insertlinkafter(&sf_ctx->filledgebase, eed, eed_tmp); BLI_remlink(&sf_ctx->filledgebase, eed); BLI_addtail(filledgebase, eed); if (pi->edge_first == eed) { pi->edge_first = eed_tmp; } eed = eed_tmp; } for (isect_link = e_ls->first; isect_link; isect_link = isect_link->next) { ScanFillIsect *isect = isect_link->data; ScanFillEdge *eed_subd; eed_subd = BLI_scanfill_edge_add(sf_ctx, isect->v, eed->v2); eed_subd->poly_nr = poly_nr; eed->v2 = isect->v; BLI_remlink(&sf_ctx->filledgebase, eed_subd); BLI_insertlinkafter(&sf_ctx->filledgebase, eed, eed_subd); /* step to the next edge and continue dividing */ eed = eed_subd; } BLI_freelistN(e_ls); MEM_freeN(e_ls); if (pi->edge_last == NULL) { pi->edge_last = eed; } } } } BLI_freelistN(&isect_lb); BLI_ghash_free(isect_hash, NULL, NULL); { ScanFillEdge *e_init; ScanFillEdge *e_curr; ScanFillEdge *e_next; ScanFillVert *v_prev; ScanFillVert *v_curr; int inside = false; /* first vert */ #if 0 e_init = pi->edge_last; e_curr = e_init; e_next = pi->edge_first; v_prev = e_curr->v1; v_curr = e_curr->v2; #else /* find outside vertex */ { ScanFillEdge *eed; ScanFillEdge *eed_prev; float min_x = FLT_MAX; e_curr = pi->edge_last; e_next = pi->edge_first; eed_prev = pi->edge_last; for (eed = pi->edge_first; eed; eed = (eed == pi->edge_last) ? NULL : eed->next) { if (eed->v2->co[0] < min_x) { min_x = eed->v2->co[0]; e_curr = eed_prev; e_next = eed; } eed_prev = eed; } e_init = e_curr; v_prev = e_curr->v1; v_curr = e_curr->v2; } #endif BLI_assert(e_curr->poly_nr == poly_nr); BLI_assert(pi->edge_last->poly_nr == poly_nr); do { ScanFillVert *v_next; v_next = (e_next->v1 == v_curr) ? e_next->v2 : e_next->v1; BLI_assert(ELEM(v_curr, e_next->v1, e_next->v2)); /* track intersections */ if (inside) { EFLAG_SET(e_next, E_ISDELETE); } if (v_next->user_flag & V_ISISECT) { inside = !inside; } /* now step... */ v_prev = v_curr; v_curr = v_next; e_curr = e_next; e_next = edge_step(poly_info, poly_nr, v_prev, v_curr, e_curr); } while (e_curr != e_init); } return true; }
static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf) { ScanFillVertLink *sc = NULL, *sc1; ScanFillVert *eve, *v1, *v2, *v3; ScanFillEdge *eed, *nexted, *ed1, *ed2, *ed3; int a, b, verts, maxface, totface; short nr, test, twoconnected = 0; nr = pf->nr; /* PRINTS */ #if 0 verts = pf->verts; eve = sf_ctx->fillvertbase.first; while (eve) { printf("vert: %x co: %f %f\n", eve, eve->xy[0], eve->xy[1]); eve = eve->next; } eed = sf_ctx->filledgebase.first; while (eed) { printf("edge: %x verts: %x %x\n", eed, eed->v1, eed->v2); eed = eed->next; } #endif /* STEP 0: remove zero sized edges */ eed = sf_ctx->filledgebase.first; while (eed) { if (equals_v2v2(eed->v1->xy, eed->v2->xy)) { if (eed->v1->f == SF_VERT_ZERO_LEN && eed->v2->f != SF_VERT_ZERO_LEN) { eed->v2->f = SF_VERT_ZERO_LEN; eed->v2->tmp.v = eed->v1->tmp.v; } else if (eed->v2->f == SF_VERT_ZERO_LEN && eed->v1->f != SF_VERT_ZERO_LEN) { eed->v1->f = SF_VERT_ZERO_LEN; eed->v1->tmp.v = eed->v2->tmp.v; } else if (eed->v2->f == SF_VERT_ZERO_LEN && eed->v1->f == SF_VERT_ZERO_LEN) { eed->v1->tmp.v = eed->v2->tmp.v; } else { eed->v2->f = SF_VERT_ZERO_LEN; eed->v2->tmp.v = eed->v1; } } eed = eed->next; } /* STEP 1: make using FillVert and FillEdge lists a sorted * ScanFillVertLink list */ sc = sf_ctx->_scdata = (ScanFillVertLink *)MEM_callocN(pf->verts * sizeof(ScanFillVertLink), "Scanfill1"); eve = sf_ctx->fillvertbase.first; verts = 0; while (eve) { if (eve->poly_nr == nr) { if (eve->f != SF_VERT_ZERO_LEN) { verts++; eve->f = 0; /* flag for connectedges later on */ sc->vert = eve; sc++; } } eve = eve->next; } qsort(sf_ctx->_scdata, verts, sizeof(ScanFillVertLink), vergscdata); eed = sf_ctx->filledgebase.first; while (eed) { nexted = eed->next; BLI_remlink(&sf_ctx->filledgebase, eed); /* This code is for handling zero-length edges that get * collapsed in step 0. It was removed for some time to * fix trunk bug #4544, so if that comes back, this code * may need some work, or there will have to be a better * fix to #4544. */ if (eed->v1->f == SF_VERT_ZERO_LEN) { v1 = eed->v1; while ((eed->v1->f == SF_VERT_ZERO_LEN) && (eed->v1->tmp.v != v1) && (eed->v1 != eed->v1->tmp.v)) eed->v1 = eed->v1->tmp.v; } if (eed->v2->f == SF_VERT_ZERO_LEN) { v2 = eed->v2; while ((eed->v2->f == SF_VERT_ZERO_LEN) && (eed->v2->tmp.v != v2) && (eed->v2 != eed->v2->tmp.v)) eed->v2 = eed->v2->tmp.v; } if (eed->v1 != eed->v2) addedgetoscanlist(sf_ctx, eed, verts); eed = nexted; } #if 0 sc = scdata; for (a = 0; a < verts; a++) { printf("\nscvert: %x\n", sc->v1); eed = sc->first; while (eed) { printf(" ed %x %x %x\n", eed, eed->v1, eed->v2); eed = eed->next; } sc++; } #endif /* STEP 2: FILL LOOP */ if (pf->f == 0) twoconnected = 1; /* (temporal) security: never much more faces than vertices */ totface = 0; maxface = 2 * verts; /* 2*verts: based at a filled circle within a triangle */ sc = sf_ctx->_scdata; for (a = 0; a < verts; a++) { /* printf("VERTEX %d %x\n",a,sc->v1); */ ed1 = sc->edge_first; while (ed1) { /* set connectflags */ nexted = ed1->next; if (ed1->v1->h == 1 || ed1->v2->h == 1) { BLI_remlink((ListBase *)&(sc->edge_first), ed1); BLI_addtail(&sf_ctx->filledgebase, ed1); if (ed1->v1->h > 1) ed1->v1->h--; if (ed1->v2->h > 1) ed1->v2->h--; } else ed1->v2->f = SF_VERT_UNKNOWN; ed1 = nexted; } while (sc->edge_first) { /* for as long there are edges */ ed1 = sc->edge_first; ed2 = ed1->next; /* commented out... the ESC here delivers corrupted memory (and doesnt work during grab) */ /* if (callLocalInterruptCallBack()) break; */ if (totface > maxface) { /* printf("Fill error: endless loop. Escaped at vert %d, tot: %d.\n", a, verts); */ a = verts; break; } if (ed2 == 0) { sc->edge_first = sc->edge_last = NULL; /* printf("just 1 edge to vert\n"); */ BLI_addtail(&sf_ctx->filledgebase, ed1); ed1->v2->f = 0; ed1->v1->h--; ed1->v2->h--; } else { /* test rest of vertices */ float miny; v1 = ed1->v2; v2 = ed1->v1; v3 = ed2->v2; /* this happens with a serial of overlapping edges */ if (v1 == v2 || v2 == v3) break; /* printf("test verts %x %x %x\n",v1,v2,v3); */ miny = minf(v1->xy[1], v3->xy[1]); /* miny= MIN2(v1->xy[1],v3->xy[1]); */ sc1 = sc + 1; test = 0; for (b = a + 1; b < verts; b++) { if (sc1->vert->f == 0) { if (sc1->vert->xy[1] <= miny) break; if (testedgeside(v1->xy, v2->xy, sc1->vert->xy)) if (testedgeside(v2->xy, v3->xy, sc1->vert->xy)) if (testedgeside(v3->xy, v1->xy, sc1->vert->xy)) { /* point in triangle */ test = 1; break; } } sc1++; } if (test) { /* make new edge, and start over */ /* printf("add new edge %x %x and start again\n",v2,sc1->vert); */ ed3 = BLI_scanfill_edge_add(sf_ctx, v2, sc1->vert); BLI_remlink(&sf_ctx->filledgebase, ed3); BLI_insertlinkbefore((ListBase *)&(sc->edge_first), ed2, ed3); ed3->v2->f = SF_VERT_UNKNOWN; ed3->f = SF_EDGE_UNKNOWN; ed3->v1->h++; ed3->v2->h++; } else { /* new triangle */ /* printf("add face %x %x %x\n",v1,v2,v3); */ addfillface(sf_ctx, v1, v2, v3); totface++; BLI_remlink((ListBase *)&(sc->edge_first), ed1); BLI_addtail(&sf_ctx->filledgebase, ed1); ed1->v2->f = 0; ed1->v1->h--; ed1->v2->h--; /* ed2 can be removed when it's a boundary edge */ if ((ed2->f == 0 && twoconnected) || (ed2->f == SF_EDGE_BOUNDARY)) { BLI_remlink((ListBase *)&(sc->edge_first), ed2); BLI_addtail(&sf_ctx->filledgebase, ed2); ed2->v2->f = 0; ed2->v1->h--; ed2->v2->h--; } /* new edge */ ed3 = BLI_scanfill_edge_add(sf_ctx, v1, v3); BLI_remlink(&sf_ctx->filledgebase, ed3); ed3->f = SF_EDGE_UNKNOWN; ed3->v1->h++; ed3->v2->h++; /* printf("add new edge %x %x\n",v1,v3); */ sc1 = addedgetoscanlist(sf_ctx, ed3, verts); if (sc1) { /* ed3 already exists: remove if a boundary */ /* printf("Edge exists\n"); */ ed3->v1->h--; ed3->v2->h--; ed3 = sc1->edge_first; while (ed3) { if ( (ed3->v1 == v1 && ed3->v2 == v3) || (ed3->v1 == v3 && ed3->v2 == v1) ) { if (twoconnected || ed3->f == SF_EDGE_BOUNDARY) { BLI_remlink((ListBase *)&(sc1->edge_first), ed3); BLI_addtail(&sf_ctx->filledgebase, ed3); ed3->v1->h--; ed3->v2->h--; } break; } ed3 = ed3->next; } } } } /* test for loose edges */ ed1 = sc->edge_first; while (ed1) { nexted = ed1->next; if (ed1->v1->h < 2 || ed1->v2->h < 2) { BLI_remlink((ListBase *)&(sc->edge_first), ed1); BLI_addtail(&sf_ctx->filledgebase, ed1); if (ed1->v1->h > 1) ed1->v1->h--; if (ed1->v2->h > 1) ed1->v2->h--; } ed1 = nexted; } } sc++; } MEM_freeN(sf_ctx->_scdata); sf_ctx->_scdata = NULL; return totface; }