[Bf-blender-cvs] [04ec948] gsoc2016-improved_extrusion: Curves: Auxiliary functions for the Extend operator

João Araújo noreply at git.blender.org
Sat Jun 11 18:11:00 CEST 2016


Commit: 04ec948d475aacc936d284bc3e165ad721b3ef8d
Author: João Araújo
Date:   Sat Jun 11 17:05:01 2016 +0100
Branches: gsoc2016-improved_extrusion
https://developer.blender.org/rB04ec948d475aacc936d284bc3e165ad721b3ef8d

Curves: Auxiliary functions for the Extend operator

This commit contains part of the foundations for the Bezier curve Extend operator. This implementation is based on an addon created previously by a Blender user.

Some of the implemented functions may have use outside of the scope of the Extend operator. Therefore, they may be relocated and renamed in a future commit.

===================================================================

M	release/scripts/startup/bl_ui/space_view3d_toolbar.py
M	source/blender/editors/curve/curve_intern.h
M	source/blender/editors/curve/curve_ops.c
M	source/blender/editors/curve/editcurve.c

===================================================================

diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 49c7600..0b6ce5c 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -537,6 +537,7 @@ class VIEW3D_PT_tools_curveedit(View3DPanel, Panel):
         col.operator("curve.subdivide")
         col.operator("curve.smooth")
         col.operator("transform.vertex_random")
+        col.operator("curve.extend_curve")
 
 
 class VIEW3D_PT_tools_add_curve_edit(View3DPanel, Panel):
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 856573f..2fb7fc7 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -128,6 +128,8 @@ void CURVE_OT_cyclic_toggle(struct wmOperatorType *ot);
 
 void CURVE_OT_match_texture_space(struct wmOperatorType *ot);
 
+void CURVE_OT_extend_curve(struct wmOperatorType *ot);
+
 bool ED_curve_pick_vert(
         struct ViewContext *vc, short sel, const int mval[2],
         struct Nurb **r_nurb, struct BezTriple **r_bezt, struct BPoint **r_bp, short *r_handle);
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index fce6425..e158ba4 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -139,6 +139,7 @@ void ED_operatortypes_curve(void)
 	WM_operatortype_append(CURVE_OT_draw);
 	WM_operatortype_append(CURVE_OT_extrude);
 	WM_operatortype_append(CURVE_OT_cyclic_toggle);
+	WM_operatortype_append(CURVE_OT_extend_curve);
 
 	WM_operatortype_append(CURVE_OT_match_texture_space);
 }
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 420f72f..4e76873 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -6303,3 +6303,271 @@ void CURVE_OT_match_texture_space(wmOperatorType *ot)
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
+
+
+
+/******************** Extend curve operator ********************/
+
+static ListBase *get_selected_splines(ListBase *nubase, int *r_number_splines, bool return_cyclic)
+{
+	/* receives a list with all splines in a "curve" object
+	 * returns the first spline of a linked list with all the selected splines,
+	 * along with the number of selected splines
+	 * if "return_cyclic" is false, it ignores cyclic splines */
+
+	Nurb *nu, *nu_copy;
+	BezTriple *bezt;
+	ListBase spline_list = {NULL, NULL};
+	int handles;
+
+	for(nu=nubase->first; nu; nu = nu->next) {
+		handles = nu->pntsu;
+		bezt = nu->bezt;
+		while (handles--) { /* cycle through all the handles. see if any is selected */
+			if (BEZT_ISSEL_ANY(bezt) && (!nu->flagu || return_cyclic)) { /* this expression was deduced using truth tables */
+				*r_number_splines += 1;
+				nu_copy = BKE_nurb_duplicate(nu);
+				nu_copy->next = NULL;
+				nu_copy->prev = NULL;
+				BLI_addtail(&spline_list, nu_copy);
+				break;
+			}
+			bezt++;
+		}
+	}
+	return &spline_list;
+}
+
+static void get_selected_handles(Nurb* nu, BezTriple **r_handle_list)
+{
+	/* Takes in the first element of a linked list of nurbs
+	 * and returns an array with the BezTriple of the selected handles. */
+	BezTriple *bezt;
+	int i = 0, a;
+
+	while (nu) {
+		a = nu->pntsu;
+		bezt = nu->bezt;
+		while (a--) {
+			if (BEZT_ISSEL_ANY(bezt)) {
+				r_handle_list[i] = bezt;
+				i++;
+			}
+			bezt++;
+		}
+		nu = nu->next;
+	}
+}
+
+static void get_selected_endpoints(Nurb* nu, BezTriple **r_handle_list)
+{
+	/* Takes in a nurb and returns an array with the selected endpoints BezTriple */
+	BezTriple *first_bezt, *last_bezt;
+	int a;
+
+	a = nu->pntsu - 1;
+	first_bezt = last_bezt = nu->bezt;
+
+	while (a--) {
+		last_bezt++;
+	}
+
+	if (BEZT_ISSEL_ANY(first_bezt) && BEZT_ISSEL_ANY(last_bezt)) {
+		r_handle_list[0] = first_bezt;
+		r_handle_list[1] = last_bezt;
+	}
+	else if (BEZT_ISSEL_ANY(first_bezt)) {
+		r_handle_list[0] = first_bezt;
+		r_handle_list[1] = NULL;
+	}
+	else if (BEZT_ISSEL_ANY(last_bezt)) {
+		r_handle_list[0] = NULL;
+		r_handle_list[1] = last_bezt;
+	}
+}
+
+static void get_nurb_shape_bounds(Object *obedit, float r_bound_box[4])
+{
+	/* returns the coordinates of the XY-bounding box of obedit */
+	r_bound_box[0] = obedit->bb->vec[0][0]; /* min X */
+	r_bound_box[1] = obedit->bb->vec[4][0]; /* max X */
+	r_bound_box[2] = obedit->bb->vec[0][1]; /* min Y */
+	r_bound_box[3] = obedit->bb->vec[3][1]; /* max Y */
+}
+
+static void get_max_extent_2d(float p1[2], float p2[2], float bb[4], float r_result[2])
+{
+	/* TODO: Find out what this actually does */
+	if (fabsf(p1[0]-p2[0])) {
+		if (p1[0] < p2[0]) {
+			r_result[0] = bb[0];
+			r_result[1] = (p2[1]-p1[1])/(p2[0]-p1[0])*(bb[0]-p1[0])+p1[1];
+		}
+		else {
+			r_result[0] = bb[1];
+			r_result[1] = (p2[1]-p1[1])/(p2[0]-p1[0])*(bb[1]-p1[0])+p1[1];
+		}
+	}
+	else {
+		if (p1[1] < p2[1]) {
+			r_result[0] = (p2[0]-p1[0])/(p2[1]-p1[1])*(bb[2]-p1[1])+p1[0];
+			r_result[1] = bb[2];
+		}
+		else {
+			r_result[0] = (p2[0]-p1[0])/(p2[1]-p1[1])*(bb[3]-p1[1])+p1[0];
+			r_result[1] = bb[3];
+		}
+	}
+}
+
+static void nearest_point(float p[2], float **p_list, int p_list_size, float r_near[2])
+{
+	/* return the point from p_list nearer to p */
+	if (p_list_size == 0) {
+		r_near = NULL;
+	}
+	else if (p_list_size == 1) {
+		copy_v2_v2(r_near, p_list[0]);
+	}
+	else {
+		int pos = 0, i = 1;
+		float distance = len_v2v2(p, p_list[0]), smallest_distance = distance;
+		while (i < p_list_size) {
+			distance = len_v2v2(p, p_list[i]);
+			if (distance < smallest_distance) {
+				distance = smallest_distance;
+				pos = i;
+			}
+			i++;
+		}
+		copy_v2_v2(r_near, p_list[pos]);
+	}
+}
+
+static ListBase *interpolate_all_segments(Nurb *nu)
+{
+	/* return a listbase with all the points in the Bezier curve. Each element
+	 * of the ListBase is a segment between two handles.
+	 * If the cuve only has two handles, the final result is only on list
+	 * Otherwise, there is an overlap between the last element of a list and
+	 * the first of the next one */
+	int i = 0, dims = 3;
+	float *coord_array;
+	ListBase pl = {NULL,NULL};
+	LinkData link;
+
+	/* number of BezTriples */
+	int bezier_points = nu->pntsu;
+
+	while (i < bezier_points-1+nu->flagu) {
+		coord_array = MEM_callocN(dims * (nu->resolu) * sizeof(float), "interpolate_bezier2");
+		link.data = coord_array;
+		for (int j = 0; j < dims; j++) {
+			BKE_curve_forward_diff_bezier(nu->bezt[i%bezier_points].vec[1][j],
+										  nu->bezt[i%bezier_points].vec[2][j],
+										  nu->bezt[(i+1)%bezier_points].vec[0][j],
+										  nu->bezt[(i+1)%bezier_points].vec[1][j],
+										  coord_array + j, nu->resolu - 1, sizeof(float) * dims);
+		}
+		BLI_addtail(&pl, &link);
+		i++;
+	}
+
+	return &pl;
+}
+
+/*
+def interpolate_all_segments(spline_ob):
+'''
+> spline_ob:     bezier spline object
+< returns interpolated splinepoints
+'''
+point_range = len(spline_ob.bezier_points)
+pl = []
+
+for i in range (0, point_range-1+spline_ob.use_cyclic_u):
+if len(pl) > 0:
+pl.pop()
+seg = (interpolate_bezier(spline_ob.bezier_points[i%point_range].co,
+						  spline_ob.bezier_points[i%point_range].handle_right,
+						  spline_ob.bezier_points[(i+1)%point_range].handle_left,
+						  spline_ob.bezier_points[(i+1)%point_range].co,
+						  spline_ob.resolution_u+1))
+pl += seg
+return pl */
+
+static ListBase *linear_spline_list(ListBase *nubase)
+{
+	/* return a list with all the points of a curve object */
+	ListBase spline_list = {NULL, NULL};
+	LinkData link;
+	Nurb *nu;
+
+	for (nu=nubase->first; nu; nu=nu->next) {
+		link.data = interpolate_all_segments(nu);
+		BLI_addtail(&spline_list, &link);
+	}
+
+	return &spline_list;
+}
+
+static int extend_curve_exec(bContext *C, wmOperator *op)
+{
+	Object *obedit = CTX_data_edit_object(C);
+	Nurb *first_spline, *second_spline;
+	ListBase *nubase = object_editcurve_get(obedit), *spline_list, *intersections_list;
+	BezTriple **selected_endpoints = NULL;
+	int n_selected_splines = 0, result;
+	float p1[3], p2[3], p1_handle[3], bound_box[4], p1_extend[2];
+
+	spline_list = get_selected_splines(nubase, &n_selected_splines, false);
+
+	if ((n_selected_splines == 0 || n_selected_splines > 2)) {
+		BKE_report(op->reports, RPT_ERROR, "Cannot extend current selection");
+		return OPERATOR_CANCELLED;
+	}
+
+	first_spline = (Nurb *)spline_list->first;
+	second_spline = (Nurb *)spline_list->last;
+
+	if (n_selected_splines == 1) { /* one spline selected */
+		selected_endpoints = MEM_callocN(2 * sizeof(BezTriple), "extendcurve1");
+		get_selected_endpoints(first_spline, selected_endpoints);
+
+		if (selected_endpoints[0] && selected_endpoints[1]) { /* both endpoints are selected */
+			result = isect_line_line_v3(selected_endpoints[0]->vec[1], selected_endpoints[0]->vec[0],
+										selected_endpoints[1]->vec[1], selected_endpoints[1]->vec[2],
+										p1, p2); /* result serves to check the existence of the intersection;
+												  * the intersection point is on variables p1 and p2 */
+		}
+		else { /* only one endpoint selected */
+			if (selected_endpoints[0]) {
+				copy_v3_v3(p1, selected_endpoints[0]->vec[1]);
+				copy_v3_v3(p1_handle, selected_endpoints[0]->vec[2]);
+			}
+			else {
+				copy_v3_v3(p1, selected_endpoints[1]->vec[1]);
+				copy_v3_v3(p1_handle, selected_endpoints[1]->vec[0]);
+			}
+			get_nurb_shape_bounds(obedit, bound_box);
+			get_max_extent_2d(p1, p1_handle, bound_box, p1_extend);
+		}
+	}
+
+	return OPERATOR_FINISHED;
+}
+
+void CURVE_OT_extend_curve(wmOperatorType *ot)
+{
+
+	/* identifiers */
+	ot->name = "Extend";
+	ot->description = "Extend selected vertex/vertices to nearest intersection";
+	ot->idname = "CURVE_OT_extend_curve";
+
+	/* api callbacks */
+	ot->exec = extend_curve_exec;
+
+	/* flags */
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}




More information about the Bf-blender-cvs mailing list