Example #1
0
float (*BKE_mask_spline_feather_points(MaskSpline *spline, int *tot_feather_point))[2]
{
	MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);

	int i, tot = 0;
	float (*feather)[2], (*fp)[2];

	/* count */
	for (i = 0; i < spline->tot_point; i++) {
		MaskSplinePoint *point = &points_array[i];

		tot += point->tot_uw + 1;
	}

	/* create data */
	feather = fp = MEM_mallocN(tot * sizeof(*feather), "mask spline feather points");

	for (i = 0; i < spline->tot_point; i++) {
		MaskSplinePoint *point = &points_array[i];
		BezTriple *bezt = &point->bezt;
		float weight, n[2];
		int j;

		BKE_mask_point_normal(spline, point, 0.0f, n);
		weight = BKE_mask_point_weight(spline, point, 0.0f);

		madd_v2_v2v2fl(*fp, bezt->vec[1], n, weight);
		fp++;

		for (j = 0; j < point->tot_uw; j++) {
			float u = point->uw[j].u;
			float co[2];

			BKE_mask_point_segment_co(spline, point, u, co);
			BKE_mask_point_normal(spline, point, u, n);
			weight = BKE_mask_point_weight(spline, point, u);

			madd_v2_v2v2fl(*fp, co, n, weight);
			fp++;
		}
	}

	*tot_feather_point = tot;

	return feather;
}
Example #2
0
void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist)
{
	if (!equals_v2v2(v2, v1)) {
		float nor[2];

		sub_v2_v2v2(nor, v1, v2);
		normalize_v2(nor);
		madd_v2_v2v2fl(v1, v2, nor, dist);
	}
}
Example #3
0
/* reduced copy of garbled calchandleNurb() code in curve.c */
static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int UNUSED(mode))
{
	float *p1, *p2, *p3, pt[3];
	float len, len_a, len_b;
	float dvec_a[2], dvec_b[2];

	if (bezt->h1 == 0 && bezt->h2 == 0) {
		return;
	}
	
	p2 = bezt->vec[1];
	
	if (prev == NULL) {
		p3 = next->vec[1];
		pt[0] = 2.0f * p2[0] - p3[0];
		pt[1] = 2.0f * p2[1] - p3[1];
		p1 = pt;
	}
	else {
		p1 = prev->vec[1];
	}
	
	if (next == NULL) {
		p1 = prev->vec[1];
		pt[0] = 2.0f * p2[0] - p1[0];
		pt[1] = 2.0f * p2[1] - p1[1];
		p3 = pt;
	}
	else {
		p3 = next->vec[1];
	}

	sub_v2_v2v2(dvec_a, p2, p1);
	sub_v2_v2v2(dvec_b, p3, p2);

	len_a = len_v2(dvec_a);
	len_b = len_v2(dvec_b);

	if (len_a == 0.0f) len_a = 1.0f;
	if (len_b == 0.0f) len_b = 1.0f;

	if (bezt->h1 == HD_AUTO || bezt->h2 == HD_AUTO) { /* auto */
		float tvec[2];
		tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
		tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;

		len = len_v2(tvec) * 2.5614f;
		if (len != 0.0f) {
			
			if (bezt->h1 == HD_AUTO) {
				len_a /= len;
				madd_v2_v2v2fl(p2 - 3, p2, tvec, -len_a);
			}
			if (bezt->h2 == HD_AUTO) {
				len_b /= len;
				madd_v2_v2v2fl(p2 + 3, p2, tvec,  len_b);
			}
		}
	}

	if (bezt->h1 == HD_VECT) {    /* vector */
		madd_v2_v2v2fl(p2 - 3, p2, dvec_a, -1.0f / 3.0f);
	}
	if (bezt->h2 == HD_VECT) {
		madd_v2_v2v2fl(p2 + 3, p2, dvec_b,  1.0f / 3.0f);
	}
}
Example #4
0
static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event)
{
	ScrArea *sa = CTX_wm_area(C);
	ARegion *ar = CTX_wm_region(C);

	Mask *mask = CTX_data_edit_mask(C);
	SlidePointData *customdata = NULL;
	MaskLayer *masklay, *cv_masklay, *feather_masklay;
	MaskSpline *spline, *cv_spline, *feather_spline;
	MaskSplinePoint *point, *cv_point, *feather_point;
	MaskSplinePointUW *uw = NULL;
	int width, height, action = SLIDE_ACTION_NONE;
	bool is_handle = false;
	const bool slide_feather = RNA_boolean_get(op->ptr, "slide_feather");
	float co[2], cv_score, feather_score;
	const float threshold = 19;

	ED_mask_mouse_pos(sa, ar, event->mval, co);
	ED_mask_get_size(sa, &width, &height);

	cv_point = ED_mask_point_find_nearest(C, mask, co, threshold, &cv_masklay, &cv_spline, &is_handle, &cv_score);

	if (ED_mask_feather_find_nearest(C, mask, co, threshold, &feather_masklay, &feather_spline, &feather_point, &uw, &feather_score)) {
		if (slide_feather || !cv_point || feather_score < cv_score) {
			action = SLIDE_ACTION_FEATHER;

			masklay = feather_masklay;
			spline = feather_spline;
			point = feather_point;
		}
	}

	if (cv_point && action == SLIDE_ACTION_NONE) {
		if (is_handle)
			action = SLIDE_ACTION_HANDLE;
		else
			action = SLIDE_ACTION_POINT;

		masklay = cv_masklay;
		spline = cv_spline;
		point = cv_point;
	}

	if (action != SLIDE_ACTION_NONE) {
		customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data");

		customdata->mask = mask;
		customdata->masklay = masklay;
		customdata->spline = spline;
		customdata->point = point;
		customdata->width = width;
		customdata->height = height;
		customdata->action = action;
		customdata->uw = uw;

		if (uw) {
			float co_uw[2];
			float weight_scalar = BKE_mask_point_weight_scalar(spline, point, uw->u);

			customdata->weight = uw->w;
			customdata->weight_scalar = weight_scalar;
			BKE_mask_point_segment_co(spline, point, uw->u, co_uw);
			BKE_mask_point_normal(spline, point, uw->u, customdata->no);

			madd_v2_v2v2fl(customdata->feather, co_uw, customdata->no, uw->w * weight_scalar);
		}
		else {
			BezTriple *bezt = &point->bezt;

			customdata->weight = bezt->weight;
			customdata->weight_scalar = 1.0f;
			BKE_mask_point_normal(spline, point, 0.0f, customdata->no);

			madd_v2_v2v2fl(customdata->feather, bezt->vec[1], customdata->no, bezt->weight);
		}

		if (customdata->action == SLIDE_ACTION_FEATHER)
			customdata->initial_feather = slide_point_check_initial_feather(spline);

		copy_m3_m3(customdata->vec, point->bezt.vec);
		if (BKE_mask_point_has_handle(point))
			BKE_mask_point_handle(point, customdata->handle);
		ED_mask_mouse_pos(sa, ar, event->mval, customdata->co);
	}

	return customdata;
}
static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *arg)
{
	Scene *scene = CTX_data_scene(C);
	UnitSettings *unit = &scene->unit;
	RulerItem *ruler_item;
	RulerInfo *ruler_info = arg;
	RegionView3D *rv3d = ruler_info->ar->regiondata;
//	ARegion *ar = ruler_info->ar;
	const float cap_size = 4.0f;
	const float bg_margin = 4.0f * U.pixelsize;
	const float bg_radius = 4.0f * U.pixelsize;
	const float arc_size = 64.0f * U.pixelsize;
#define ARC_STEPS 24
	const int arc_steps = ARC_STEPS;
	int i;
	//unsigned int color_act = 0x666600;
	unsigned int color_act = 0xffffff;
	unsigned int color_base = 0x0;
	unsigned char color_back[4] = {0xff, 0xff, 0xff, 0x80};
	unsigned char color_text[3];
	unsigned char color_wire[3];

	/* anti-aliased lines for more consistent appearance */
	glEnable(GL_LINE_SMOOTH);

	BLF_enable(blf_mono_font, BLF_ROTATION);
	BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi);
	BLF_rotation(blf_mono_font, 0.0f);

	UI_GetThemeColor3ubv(TH_TEXT, color_text);
	UI_GetThemeColor3ubv(TH_WIRE, color_wire);

	for (ruler_item = ruler_info->items.first, i = 0; ruler_item; ruler_item = ruler_item->next, i++) {
		const bool is_act = (i == ruler_info->item_active);
		float dir_ruler[2];
		float co_ss[3][2];
		int j;

		/* should these be checked? - ok for now not to */
		for (j = 0; j < 3; j++) {
			ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
		}

		glEnable(GL_BLEND);

		cpack(is_act ? color_act : color_base);

		if (ruler_item->flag & RULERITEM_USE_ANGLE) {
			glBegin(GL_LINE_STRIP);
			for (j = 0; j < 3; j++) {
				glVertex2fv(co_ss[j]);
			}
			glEnd();
			cpack(0xaaaaaa);
			setlinestyle(3);
			glBegin(GL_LINE_STRIP);
			for (j = 0; j < 3; j++) {
				glVertex2fv(co_ss[j]);
			}
			glEnd();
			setlinestyle(0);

			/* arc */
			{
				float dir_tmp[3];
				float co_tmp[3];
				float arc_ss_coords[ARC_STEPS + 1][2];

				float dir_a[3];
				float dir_b[3];
				float quat[4];
				float axis[3];
				float angle;
				const float px_scale = (ED_view3d_pixel_size(rv3d, ruler_item->co[1]) *
				                        min_fff(arc_size,
				                                len_v2v2(co_ss[0], co_ss[1]) / 2.0f,
				                                len_v2v2(co_ss[2], co_ss[1]) / 2.0f));

				sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]);
				sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]);
				normalize_v3(dir_a);
				normalize_v3(dir_b);

				cross_v3_v3v3(axis, dir_a, dir_b);
				angle = angle_normalized_v3v3(dir_a, dir_b);

				axis_angle_to_quat(quat, axis, angle / arc_steps);

				copy_v3_v3(dir_tmp, dir_a);

				glColor3ubv(color_wire);

				for (j = 0; j <= arc_steps; j++) {
					madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale);
					ED_view3d_project_float_global(ar, co_tmp, arc_ss_coords[j], V3D_PROJ_TEST_NOP);
					mul_qt_v3(quat, dir_tmp);
				}

				glEnableClientState(GL_VERTEX_ARRAY);
				glVertexPointer(2, GL_FLOAT, 0, arc_ss_coords);
				glDrawArrays(GL_LINE_STRIP, 0, arc_steps + 1);
				glDisableClientState(GL_VERTEX_ARRAY);
			}

			/* text */
			{
				char numstr[256];
				float numstr_size[2];
				float pos[2];
				const int prec = 2;  /* XXX, todo, make optional */

				ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);

				BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);

				pos[0] = co_ss[1][0] + (cap_size * 2.0f);
				pos[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);

				/* draw text (bg) */
				glColor4ubv(color_back);
				uiSetRoundBox(UI_CNR_ALL);
				uiRoundBox(pos[0] - bg_margin,                  pos[1] - bg_margin,
				           pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1],
				           bg_radius);
				/* draw text */
				glColor3ubv(color_text);
				BLF_position(blf_mono_font, pos[0], pos[1], 0.0f);
				BLF_rotation(blf_mono_font, 0.0f);
				BLF_draw(blf_mono_font, numstr, sizeof(numstr));
			}

			/* capping */
			{
				float rot_90_vec_a[2];
				float rot_90_vec_b[2];
				float cap[2];

				sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]);
				rot_90_vec_a[0] = -dir_ruler[1];
				rot_90_vec_a[1] =  dir_ruler[0];
				normalize_v2(rot_90_vec_a);

				sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]);
				rot_90_vec_b[0] = -dir_ruler[1];
				rot_90_vec_b[1] =  dir_ruler[0];
				normalize_v2(rot_90_vec_b);

				glEnable(GL_BLEND);

				glColor3ubv(color_wire);

				glBegin(GL_LINES);

				madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
				glVertex2fv(cap);
				madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
				glVertex2fv(cap);

				madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
				glVertex2fv(cap);
				madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
				glVertex2fv(cap);

				/* angle vertex */
				glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
				glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
				glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
				glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
				glEnd();

				glDisable(GL_BLEND);
			}
		}
		else {
			glBegin(GL_LINE_STRIP);
			for (j = 0; j < 3; j += 2) {
				glVertex2fv(co_ss[j]);
			}
			glEnd();
			cpack(0xaaaaaa);
			setlinestyle(3);
			glBegin(GL_LINE_STRIP);
			for (j = 0; j < 3; j += 2) {
				glVertex2fv(co_ss[j]);
			}
			glEnd();
			setlinestyle(0);

			sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);

			/* text */
			{
				char numstr[256];
				float numstr_size[2];
				const int prec = 6;  /* XXX, todo, make optional */
				float pos[2];

				ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);

				BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);

				mid_v2_v2v2(pos, co_ss[0], co_ss[2]);

				/* center text */
				pos[0] -= numstr_size[0] / 2.0f;
				pos[1] -= numstr_size[1] / 2.0f;

				/* draw text (bg) */
				glColor4ubv(color_back);
				uiSetRoundBox(UI_CNR_ALL);
				uiRoundBox(pos[0] - bg_margin,                  pos[1] - bg_margin,
				           pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1],
				           bg_radius);
				/* draw text */
				glColor3ubv(color_text);
				BLF_position(blf_mono_font, pos[0], pos[1], 0.0f);
				BLF_draw(blf_mono_font, numstr, sizeof(numstr));
			}

			/* capping */
			{
				float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]};
				float cap[2];

				normalize_v2(rot_90_vec);

				glEnable(GL_BLEND);
				glColor3ubv(color_wire);

				glBegin(GL_LINES);
				madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
				glVertex2fv(cap);
				madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
				glVertex2fv(cap);

				madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
				glVertex2fv(cap);
				madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
				glVertex2fv(cap);
				glEnd();

				glDisable(GL_BLEND);
			}
		}
	}

	glDisable(GL_LINE_SMOOTH);

	BLF_disable(blf_mono_font, BLF_ROTATION);

#undef ARC_STEPS

	/* draw snap */
	if ((ruler_info->snap_flag & RULER_SNAP_OK) && (ruler_info->state == RULER_STATE_DRAG)) {
		ruler_item = ruler_item_active_get(ruler_info);
		if (ruler_item) {
			/* size from drawSnapping */
			const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
			float co_ss[3];
			ED_view3d_project_float_global(ar, ruler_item->co[ruler_item->co_index], co_ss, V3D_PROJ_TEST_NOP);

			cpack(color_act);
			circ(co_ss[0], co_ss[1], size * U.pixelsize);
		}
	}

}
Example #6
0
/** only called from #BKE_mask_spline_feather_differentiated_points_with_resolution() ! */
static float (*mask_spline_feather_differentiated_points_with_resolution__even(
        MaskSpline *spline, unsigned int *tot_feather_point,
        const unsigned int resol, const bool do_feather_isect))[2]
{
	MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
	MaskSplinePoint *point_curr, *point_prev;
	float (*feather)[2], (*fp)[2];

	const int tot = BKE_mask_spline_differentiate_calc_total(spline, resol);
	int a;

	/* tot+1 because of 'forward_diff_bezier' function */
	feather = fp = MEM_mallocN((tot + 1) * sizeof(*feather), "mask spline feather diff points");

	a = spline->tot_point - 1;
	if (spline->flag & MASK_SPLINE_CYCLIC)
		a++;

	point_prev = points_array;
	point_curr = point_prev + 1;

	while (a--) {
		/* BezTriple *bezt_prev; */  /* UNUSED */
		/* BezTriple *bezt_curr; */      /* UNUSED */
		int j;

		if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC))
			point_curr = points_array;


		/* bezt_prev = &point_prev->bezt; */
		/* bezt_curr = &point_curr->bezt; */

		for (j = 0; j < resol; j++, fp++) {
			float u = (float) j / resol, weight;
			float co[2], n[2];

			/* TODO - these calls all calculate similar things
			 * could be unified for some speed */
			BKE_mask_point_segment_co(spline, point_prev, u, co);
			BKE_mask_point_normal(spline, point_prev, u, n);
			weight = BKE_mask_point_weight(spline, point_prev, u);

			madd_v2_v2v2fl(*fp, co, n, weight);
		}

		if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) {
			float u = 1.0f, weight;
			float co[2], n[2];

			BKE_mask_point_segment_co(spline, point_prev, u, co);
			BKE_mask_point_normal(spline, point_prev, u, n);
			weight = BKE_mask_point_weight(spline, point_prev, u);

			madd_v2_v2v2fl(*fp, co, n, weight);
		}

		point_prev = point_curr;
		point_curr++;
	}

	*tot_feather_point = tot;

	if ((spline->flag & MASK_SPLINE_NOINTERSECT) && do_feather_isect) {
		BKE_mask_spline_feather_collapse_inner_loops(spline, feather, tot);
	}

	return feather;
}
/**
 * reduced copy of #calchandleNurb_intern code in curve.c
 */
static void calchandle_curvemap(
        BezTriple *bezt, const BezTriple *prev, const BezTriple *next)
{
	/* defines to avoid confusion */
#define p2_h1 ((p2) - 3)
#define p2_h2 ((p2) + 3)

	const float *p1, *p3;
	float *p2;
	float pt[3];
	float len, len_a, len_b;
	float dvec_a[2], dvec_b[2];

	if (bezt->h1 == 0 && bezt->h2 == 0) {
		return;
	}
	
	p2 = bezt->vec[1];
	
	if (prev == NULL) {
		p3 = next->vec[1];
		pt[0] = 2.0f * p2[0] - p3[0];
		pt[1] = 2.0f * p2[1] - p3[1];
		p1 = pt;
	}
	else {
		p1 = prev->vec[1];
	}
	
	if (next == NULL) {
		p1 = prev->vec[1];
		pt[0] = 2.0f * p2[0] - p1[0];
		pt[1] = 2.0f * p2[1] - p1[1];
		p3 = pt;
	}
	else {
		p3 = next->vec[1];
	}

	sub_v2_v2v2(dvec_a, p2, p1);
	sub_v2_v2v2(dvec_b, p3, p2);

	len_a = len_v2(dvec_a);
	len_b = len_v2(dvec_b);

	if (len_a == 0.0f) len_a = 1.0f;
	if (len_b == 0.0f) len_b = 1.0f;

	if (bezt->h1 == HD_AUTO || bezt->h2 == HD_AUTO) { /* auto */
		float tvec[2];
		tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
		tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;

		len = len_v2(tvec) * 2.5614f;
		if (len != 0.0f) {
			
			if (bezt->h1 == HD_AUTO) {
				len_a /= len;
				madd_v2_v2v2fl(p2_h1, p2, tvec, -len_a);
			}
			if (bezt->h2 == HD_AUTO) {
				len_b /= len;
				madd_v2_v2v2fl(p2_h2, p2, tvec,  len_b);
			}
		}
	}

	if (bezt->h1 == HD_VECT) {    /* vector */
		madd_v2_v2v2fl(p2_h1, p2, dvec_a, -1.0f / 3.0f);
	}
	if (bezt->h2 == HD_VECT) {
		madd_v2_v2v2fl(p2_h2, p2, dvec_b,  1.0f / 3.0f);
	}

#undef p2_h1
#undef p2_h2
}
Example #8
0
/**
 * reduced copy of #calchandleNurb_intern code in curve.c
 */
static void calchandle_curvemap(
        BezTriple *bezt, const BezTriple *prev, const BezTriple *next)
{
	/* defines to avoid confusion */
#define p2_h1 ((p2) - 3)
#define p2_h2 ((p2) + 3)

	const float *p1, *p3;
	float *p2;
	float pt[3];
	float len, len_a, len_b;
	float dvec_a[2], dvec_b[2];

	if (bezt->h1 == 0 && bezt->h2 == 0) {
		return;
	}

	p2 = bezt->vec[1];

	if (prev == NULL) {
		p3 = next->vec[1];
		pt[0] = 2.0f * p2[0] - p3[0];
		pt[1] = 2.0f * p2[1] - p3[1];
		p1 = pt;
	}
	else {
		p1 = prev->vec[1];
	}

	if (next == NULL) {
		p1 = prev->vec[1];
		pt[0] = 2.0f * p2[0] - p1[0];
		pt[1] = 2.0f * p2[1] - p1[1];
		p3 = pt;
	}
	else {
		p3 = next->vec[1];
	}

	sub_v2_v2v2(dvec_a, p2, p1);
	sub_v2_v2v2(dvec_b, p3, p2);

	len_a = len_v2(dvec_a);
	len_b = len_v2(dvec_b);

	if (len_a == 0.0f) len_a = 1.0f;
	if (len_b == 0.0f) len_b = 1.0f;

	if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {    /* auto */
		float tvec[2];
		tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
		tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;

		len = len_v2(tvec) * 2.5614f;
		if (len != 0.0f) {

			if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
				len_a /= len;
				madd_v2_v2v2fl(p2_h1, p2, tvec, -len_a);

				if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
					const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
					const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
					if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) ||
					    (ydiff1 >= 0.0f && ydiff2 >= 0.0f))
					{
						bezt->vec[0][1] = bezt->vec[1][1];
					}
					else { /* handles should not be beyond y coord of two others */
						if (ydiff1 <= 0.0f) {
							if (prev->vec[1][1] > bezt->vec[0][1]) {
								bezt->vec[0][1] = prev->vec[1][1];
							}
						}
						else {
							if (prev->vec[1][1] < bezt->vec[0][1]) {
								bezt->vec[0][1] = prev->vec[1][1];
							}
						}
					}
				}
			}
			if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
				len_b /= len;
				madd_v2_v2v2fl(p2_h2, p2, tvec,  len_b);

				if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
					const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
					const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
					if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) ||
					    (ydiff1 >= 0.0f && ydiff2 >= 0.0f))
					{
						bezt->vec[2][1] = bezt->vec[1][1];
					}
					else { /* handles should not be beyond y coord of two others */
						if (ydiff1 <= 0.0f) {
							if (next->vec[1][1] < bezt->vec[2][1]) {
								bezt->vec[2][1] = next->vec[1][1];
							}
						}
						else {
							if (next->vec[1][1] > bezt->vec[2][1]) {
								bezt->vec[2][1] = next->vec[1][1];
							}
						}
					}
				}
			}
		}
	}

	if (bezt->h1 == HD_VECT) {    /* vector */
		madd_v2_v2v2fl(p2_h1, p2, dvec_a, -1.0f / 3.0f);
	}
	if (bezt->h2 == HD_VECT) {
		madd_v2_v2v2fl(p2_h2, p2, dvec_b,  1.0f / 3.0f);
	}

#undef p2_h1
#undef p2_h2
}