Пример #1
0
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;
							}
						}
					}
				}
			}
		}
	}
}
Пример #2
0
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;
							}
						}
					}
				}
			}
		}
	}
}
Пример #3
0
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);
	}
}
Пример #4
0
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;
}
Пример #5
0
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);
}
Пример #6
0
/**
 * \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 */
}
Пример #7
0
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;
}
Пример #8
0
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;
}