static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
                                float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
                                const bool add_end_point, tGpTimingData *gtd)
{
	bGPDspoint *pt;
	Nurb *nu = (curnu) ? *curnu : NULL;
	BezTriple *bezt, *prev_bezt = NULL;
	int i, tot, old_nbezt = 0;
	const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
	float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3];
	const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
	
	/* create new 'nurb' or extend current one within the curve */
	if (nu) {
		old_nbezt = nu->pntsu;
		/* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke,
		 * so no need to add it.
		 * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes.
		 */
		BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2) + add_start_end_points);
	}
	else {
		nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
		
		nu->pntsu = gps->totpoints + add_start_end_points;
		nu->resolu = 12;
		nu->resolv = 12;
		nu->type = CU_BEZIER;
		nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts");
		
		stitch = false; /* Security! */
	}
	
	if (do_gtd) {
		gp_timing_data_set_nbr(gtd, nu->pntsu);
	}
	
	tot = gps->totpoints;
	
	/* get initial coordinates */
	pt = gps->points;
	if (tot) {
		gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
		if (tot > 1) {
			gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
		}
		if (stitch && tot > 2) {
			gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
		}
	}
	
	/* If needed, make the link between both strokes with two zero-radius additional points */
	if (curnu && old_nbezt) {
		BLI_assert(gps->prev != NULL);
		
		/* Update last point's second handle */
		if (stitch) {
			bezt = &nu->bezt[old_nbezt - 1];
			interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC);
			copy_v3_v3(bezt->vec[2], h2);
			pt++;
		}
		
		/* Create "link points" */
		/* About "zero-radius" point interpolations:
		 * - If we have at least two points in current curve (most common case), we linearly extrapolate
		 *   the last segment to get the first point (p1) position and timing.
		 * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
		 *   with the first point of the current stroke.
		 * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
		 * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
		 */
		else {
			float p1[3], p2[3];
			float dt1 = 0.0f, dt2 = 0.0f;
			
			prev_bezt = NULL;
			if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) {
				/* Only use last curve segment if previous stroke was not a single-point one! */
				prev_bezt = &nu->bezt[old_nbezt - 2];
			}
			bezt = &nu->bezt[old_nbezt - 1];
			
			/* First point */
			if (prev_bezt) {
				interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC);
				if (do_gtd) {
					const int idx = gps->prev->totpoints - 1;
					dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
				}
			}
			else {
				interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC);
				if (do_gtd) {
					dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
				}
			}
			
			/* Second point */
			/* Note dt2 is always negative, which marks the gap. */
			if (tot > 1) {
				interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC);
				if (do_gtd) {
					dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
				}
			}
			else {
				interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC);
				if (do_gtd) {
					dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
				}
			}
			
			/* Second handle of last point of previous stroke. */
			interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC);
			copy_v3_v3(bezt->vec[2], h2);
			
			/* First point */
			interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
			interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
			bezt++;
			gp_stroke_to_bezier_add_point(gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1,
			                              0.0f, rad_fac, minmax_weights);
			
			/* Second point */
			interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
			interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
			bezt++;
			gp_stroke_to_bezier_add_point(gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2,
			                              0.0f, rad_fac, minmax_weights);
			
			old_nbezt += 2;
			copy_v3_v3(p3d_prev, p2);
		}
	}
	else if (add_start_point) {
		float p[3];
		float dt = 0.0f;
		
		if (gps->totpoints > 1) {
			interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC);
			if (do_gtd) {
				dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
			}
		}
		else {
			copy_v3_v3(p, p3d_cur);
			p[0] -= GAP_DFAC;  /* Rather arbitrary... */
			dt = -GAP_DFAC;  /* Rather arbitrary too! */
		}
		interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC);
		interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC);
		bezt = &nu->bezt[old_nbezt];
		gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt,
		                              0.0f, rad_fac, minmax_weights);
		
		old_nbezt++;
		copy_v3_v3(p3d_prev, p);
	}
	
	if (old_nbezt) {
		prev_bezt = &nu->bezt[old_nbezt - 1];
	}
	
	/* add points */
	for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
		float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
		
		if (i || old_nbezt) {
			interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
		}
		else {
			interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC);
		}
		
		if (i < tot - 1) {
			interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC);
		}
		else {
			interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
		}
		
		gp_stroke_to_bezier_add_point(gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur,
		                              do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights);
		
		/* shift coord vects */
		copy_v3_v3(p3d_prev, p3d_cur);
		copy_v3_v3(p3d_cur, p3d_next);
		
		if (i + 2 < tot) {
			gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
		}
		
		prev_bezt = bezt;
	}

	if (add_end_point) {
		float p[3];
		float dt = 0.0f;
		
		if (gps->totpoints > 1) {
			interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC);
			if (do_gtd) {
				const int idx = gps->totpoints - 1;
				dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
			}
		}
		else {
			copy_v3_v3(p, prev_bezt->vec[1]);
			p[0] += GAP_DFAC;  /* Rather arbitrary... */
			dt = GAP_DFAC;  /* Rather arbitrary too! */
		}
		
		/* Second handle of last point of this stroke. */
		interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC);
		copy_v3_v3(prev_bezt->vec[2], h2);
		
		/* The end point */
		interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC);
		interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC);
		/* Note bezt has already been incremented in main loop above, so it points to the right place. */
		gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt,
		                              0.0f, rad_fac, minmax_weights);
	}
	
	/* must calculate handles or else we crash */
	BKE_nurb_handles_calc(nu);
	
	if (!curnu || !*curnu) {
		BLI_addtail(&cu->nurb, nu);
	}
	if (curnu) {
		*curnu = nu;
	}
}
Example #2
0
Nurb *ED_curve_add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type, int newob)
{
	static int xzproj = 0;   /* this function calls itself... */
	ListBase *editnurb = object_editcurve_get(obedit);
	RegionView3D *rv3d = ED_view3d_context_rv3d(C);
	Nurb *nu = NULL;
	BezTriple *bezt;
	BPoint *bp;
	Curve *cu = (Curve *)obedit->data;
	float vec[3], zvec[3] = {0.0f, 0.0f, 1.0f};
	float umat[4][4], viewmat[4][4];
	float fac;
	int a, b;
	const float grid = 1.0f;
	const int cutype = (type & CU_TYPE); // poly, bezier, nurbs, etc
	const int stype = (type & CU_PRIMITIVE);

	unit_m4(umat);
	unit_m4(viewmat);

	if (rv3d) {
		copy_m4_m4(viewmat, rv3d->viewmat);
		copy_v3_v3(zvec, rv3d->viewinv[2]);
	}

	BKE_nurbList_flag_set(editnurb, 0);

	/* these types call this function to return a Nurb */
	if (stype != CU_PRIM_TUBE && stype != CU_PRIM_DONUT) {
		nu = (Nurb *)MEM_callocN(sizeof(Nurb), "addNurbprim");
		nu->type = cutype;
		nu->resolu = cu->resolu;
		nu->resolv = cu->resolv;
	}

	switch (stype) {
		case CU_PRIM_CURVE: /* curve */
			nu->resolu = cu->resolu;
			if (cutype == CU_BEZIER) {
				nu->pntsu = 2;
				nu->bezt = (BezTriple *)MEM_callocN(2 * sizeof(BezTriple), "addNurbprim1");
				bezt = nu->bezt;
				bezt->h1 = bezt->h2 = HD_ALIGN;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->radius = 1.0;

				bezt->vec[1][0] += -grid;
				bezt->vec[0][0] += -1.5f * grid;
				bezt->vec[0][1] += -0.5f * grid;
				bezt->vec[2][0] += -0.5f * grid;
				bezt->vec[2][1] +=  0.5f * grid;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);

				bezt++;
				bezt->h1 = bezt->h2 = HD_ALIGN;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->radius = bezt->weight = 1.0;

				bezt->vec[0][0] = 0;
				bezt->vec[0][1] = 0;
				bezt->vec[1][0] = grid;
				bezt->vec[1][1] = 0;
				bezt->vec[2][0] = grid * 2;
				bezt->vec[2][1] = 0;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);

				BKE_nurb_handles_calc(nu);
			}
			else {

				nu->pntsu = 4;
				nu->pntsv = 1;
				nu->orderu = 4;
				nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 4, "addNurbprim3");

				bp = nu->bp;
				for (a = 0; a < 4; a++, bp++) {
					bp->vec[3] = 1.0;
					bp->f1 = SELECT;
					bp->radius = bp->weight = 1.0;
				}

				bp = nu->bp;
				bp->vec[0] += -1.5f * grid;
				bp++;
				bp->vec[0] += -grid;
				bp->vec[1] +=  grid;
				bp++;
				bp->vec[0] += grid;
				bp->vec[1] += grid;
				bp++;
				bp->vec[0] += 1.5f * grid;

				bp = nu->bp;
				for (a = 0; a < 4; a++, bp++) mul_m4_v3(mat, bp->vec);

				if (cutype == CU_NURBS) {
					nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */
					BKE_nurb_knot_calc_u(nu);
				}

			}
			break;
		case CU_PRIM_PATH: /* 5 point path */
			nu->pntsu = 5;
			nu->pntsv = 1;
			nu->orderu = 5;
			nu->flagu = CU_NURB_ENDPOINT; /* endpoint */
			nu->resolu = cu->resolu;
			nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim3");

			bp = nu->bp;
			for (a = 0; a < 5; a++, bp++) {
				bp->vec[3] = 1.0;
				bp->f1 = SELECT;
				bp->radius = bp->weight = 1.0;
			}

			bp = nu->bp;
			bp->vec[0] += -2.0f * grid;
			bp++;
			bp->vec[0] += -grid;
			bp++; bp++;
			bp->vec[0] += grid;
			bp++;
			bp->vec[0] += 2.0f * grid;

			bp = nu->bp;
			for (a = 0; a < 5; a++, bp++) mul_m4_v3(mat, bp->vec);

			if (cutype == CU_NURBS) {
				nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */
				BKE_nurb_knot_calc_u(nu);
			}

			break;
		case CU_PRIM_CIRCLE: /* circle */
			nu->resolu = cu->resolu;

			if (cutype == CU_BEZIER) {
				nu->pntsu = 4;
				nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * 4, "addNurbprim1");
				nu->flagu = CU_NURB_CYCLIC;
				bezt = nu->bezt;

				bezt->h1 = bezt->h2 = HD_AUTO;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->vec[1][0] += -grid;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);
				bezt->radius = bezt->weight = 1.0;

				bezt++;
				bezt->h1 = bezt->h2 = HD_AUTO;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->vec[1][1] += grid;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);
				bezt->radius = bezt->weight = 1.0;

				bezt++;
				bezt->h1 = bezt->h2 = HD_AUTO;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->vec[1][0] += grid;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);
				bezt->radius = bezt->weight = 1.0;

				bezt++;
				bezt->h1 = bezt->h2 = HD_AUTO;
				bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
				bezt->vec[1][1] += -grid;
				for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]);
				bezt->radius = bezt->weight = 1.0;

				BKE_nurb_handles_calc(nu);
			}
			else if (cutype == CU_NURBS) { /* nurb */
				nu->pntsu = 8;
				nu->pntsv = 1;
				nu->orderu = 4;
				nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 8, "addNurbprim6");
				nu->flagu = CU_NURB_CYCLIC;
				bp = nu->bp;

				for (a = 0; a < 8; a++) {
					bp->f1 = SELECT;
					if (xzproj == 0) {
						bp->vec[0] += nurbcircle[a][0] * grid;
						bp->vec[1] += nurbcircle[a][1] * grid;
					}
					else {
						bp->vec[0] += 0.25f * nurbcircle[a][0] * grid - 0.75f * grid;
						bp->vec[2] += 0.25f * nurbcircle[a][1] * grid;
					}
					if (a & 1) bp->vec[3] = 0.25 * M_SQRT2;
					else bp->vec[3] = 1.0;
					mul_m4_v3(mat, bp->vec);
					bp->radius = bp->weight = 1.0;

					bp++;
				}

				BKE_nurb_knot_calc_u(nu);
			}
			break;
		case CU_PRIM_PATCH: /* 4x4 patch */
			if (cutype == CU_NURBS) { /* nurb */

				nu->pntsu = 4;
				nu->pntsv = 4;
				nu->orderu = 4;
				nu->orderv = 4;
				nu->flag = CU_SMOOTH;
				nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * (4 * 4), "addNurbprim6");
				nu->flagu = 0;
				nu->flagv = 0;
				bp = nu->bp;

				for (a = 0; a < 4; a++) {
					for (b = 0; b < 4; b++) {
						bp->f1 = SELECT;
						fac = (float)a - 1.5f;
						bp->vec[0] += fac * grid;
						fac = (float)b - 1.5f;
						bp->vec[1] += fac * grid;
						if ((a == 1 || a == 2) && (b == 1 || b == 2)) {
							bp->vec[2] += grid;
						}
						mul_m4_v3(mat, bp->vec);
						bp->vec[3] = 1.0;
						bp++;
					}
				}

				BKE_nurb_knot_calc_u(nu);
				BKE_nurb_knot_calc_v(nu);
			}
			break;
		case CU_PRIM_TUBE: /* Cylinder */
			if (cutype == CU_NURBS) {
				nu = ED_curve_add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */
				nu->resolu = cu->resolu;
				nu->flag = CU_SMOOTH;
				BLI_addtail(editnurb, nu); /* temporal for extrude and translate */
				vec[0] = vec[1] = 0.0;
				vec[2] = -grid;

				mul_mat3_m4_v3(mat, vec);

				ed_editnurb_translate_flag(editnurb, SELECT, vec);
				ed_editnurb_extrude_flag(cu->editnurb, SELECT);
				mul_v3_fl(vec, -2.0f);
				ed_editnurb_translate_flag(editnurb, SELECT, vec);

				BLI_remlink(editnurb, nu);

				a = nu->pntsu * nu->pntsv;
				bp = nu->bp;
				while (a-- > 0) {
					bp->f1 |= SELECT;
					bp++;
				}
			}
			break;
		case CU_PRIM_SPHERE: /* sphere */
			if (cutype == CU_NURBS) {
				float tmp_cent[3] = {0.f, 0.f, 0.f};
				float tmp_vec[3] = {0.f, 0.f, 1.f};

				nu->pntsu = 5;
				nu->pntsv = 1;
				nu->orderu = 3;
				nu->resolu = cu->resolu;
				nu->resolv = cu->resolv;
				nu->flag = CU_SMOOTH;
				nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim6");
				nu->flagu = 0;
				bp = nu->bp;

				for (a = 0; a < 5; a++) {
					bp->f1 = SELECT;
					bp->vec[0] += nurbcircle[a][0] * grid;
					bp->vec[2] += nurbcircle[a][1] * grid;
					if (a & 1) bp->vec[3] = 0.5 * M_SQRT2;
					else bp->vec[3] = 1.0;
					mul_m4_v3(mat, bp->vec);
					bp++;
				}
				nu->flagu = CU_NURB_BEZIER;
				BKE_nurb_knot_calc_u(nu);

				BLI_addtail(editnurb, nu); /* temporal for spin */

				if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0)
					ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent);
				else if ((U.flag & USER_ADD_VIEWALIGNED))
					ed_editnurb_spin(viewmat, obedit, zvec, mat[3]);
				else
					ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]);

				BKE_nurb_knot_calc_v(nu);

				a = nu->pntsu * nu->pntsv;
				bp = nu->bp;
				while (a-- > 0) {
					bp->f1 |= SELECT;
					bp++;
				}
				BLI_remlink(editnurb, nu);
			}
			break;
		case CU_PRIM_DONUT: /* torus */
			if (cutype == CU_NURBS) {
				float tmp_cent[3] = {0.f, 0.f, 0.f};
				float tmp_vec[3] = {0.f, 0.f, 1.f};

				xzproj = 1;
				nu = ED_curve_add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */
				xzproj = 0;
				nu->resolu = cu->resolu;
				nu->resolv = cu->resolv;
				nu->flag = CU_SMOOTH;
				BLI_addtail(editnurb, nu); /* temporal for spin */

				/* same as above */
				if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0)
					ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent);
				else if ((U.flag & USER_ADD_VIEWALIGNED))
					ed_editnurb_spin(viewmat, obedit, zvec, mat[3]);
				else
					ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]);


				BLI_remlink(editnurb, nu);

				a = nu->pntsu * nu->pntsv;
				bp = nu->bp;
				while (a-- > 0) {
					bp->f1 |= SELECT;
					bp++;
				}

			}
			break;

		default: /* should never happen */
			BLI_assert(!"invalid nurbs type");
			return NULL;
	}

	BLI_assert(nu != NULL);

	if (nu) { /* should always be set */
		if ((obedit->type != OB_SURF) && ((cu->flag & CU_3D) == 0)) {
			nu->flag |= CU_2D;
		}

		nu->flag |= CU_SMOOTH;
		cu->actnu = BLI_listbase_count(editnurb);
		cu->actvert = CU_ACT_NONE;

		BKE_nurb_test2D(nu);
	}

	return nu;
}
static int apply_objects_internal(bContext *C, ReportList *reports, int apply_loc, int apply_rot, int apply_scale)
{
	Main *bmain = CTX_data_main(C);
	Scene *scene = CTX_data_scene(C);
	float rsmat[3][3], tmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale;
	int a, change = 1;
	
	/* first check if we can execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{

		if (ob->type == OB_MESH) {
			if (ID_REAL_USERS(ob->data) > 1) {
				BKE_report(reports, RPT_ERROR, "Can't apply to a multi user mesh, doing nothing");
				change = 0;
			}
		}
		else if (ob->type == OB_ARMATURE) {
			if (ID_REAL_USERS(ob->data) > 1) {
				BKE_report(reports, RPT_ERROR, "Can't apply to a multi user armature, doing nothing");
				change = 0;
			}
		}
		else if (ob->type == OB_LATTICE) {
			if (ID_REAL_USERS(ob->data) > 1) {
				BKE_report(reports, RPT_ERROR, "Can't apply to a multi user lattice, doing nothing");
				change = 0;
			}
		}
		else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			Curve *cu;

			if (ID_REAL_USERS(ob->data) > 1) {
				BKE_report(reports, RPT_ERROR, "Can't apply to a multi user curve, doing nothing");
				change = 0;
			}

			cu = ob->data;

			if (!(cu->flag & CU_3D) && (apply_rot || apply_loc)) {
				BKE_report(reports, RPT_ERROR, "Neither rotation nor location could be applied to a 2d curve, doing nothing");
				change = 0;
			}
			if (cu->key) {
				BKE_report(reports, RPT_ERROR, "Can't apply to a curve with vertex keys, doing nothing");
				change = 0;
			}
		}
	}
	CTX_DATA_END;
	
	if (!change)
		return OPERATOR_CANCELLED;

	change = 0;

	/* now execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{

		/* calculate rotation/scale matrix */
		if (apply_scale && apply_rot)
			BKE_object_to_mat3(ob, rsmat);
		else if (apply_scale)
			BKE_object_scale_to_mat3(ob, rsmat);
		else if (apply_rot) {
			float tmat[3][3], timat[3][3];

			/* simple rotation matrix */
			BKE_object_rot_to_mat3(ob, rsmat);

			/* correct for scale, note mul_m3_m3m3 has swapped args! */
			BKE_object_scale_to_mat3(ob, tmat);
			invert_m3_m3(timat, tmat);
			mul_m3_m3m3(rsmat, timat, rsmat);
			mul_m3_m3m3(rsmat, rsmat, tmat);
		}
		else
			unit_m3(rsmat);

		copy_m4_m3(mat, rsmat);

		/* calculate translation */
		if (apply_loc) {
			copy_v3_v3(mat[3], ob->loc);

			if (!(apply_scale && apply_rot)) {
				/* correct for scale and rotation that is still applied */
				BKE_object_to_mat3(ob, obmat);
				invert_m3_m3(iobmat, obmat);
				mul_m3_m3m3(tmat, rsmat, iobmat);
				mul_m3_v3(tmat, mat[3]);
			}
		}

		/* apply to object data */
		if (ob->type == OB_MESH) {
			Mesh *me = ob->data;
			MVert *mvert;

			multiresModifier_scale_disp(scene, ob);
			
			/* adjust data */
			mvert = me->mvert;
			for (a = 0; a < me->totvert; a++, mvert++)
				mul_m4_v3(mat, mvert->co);
			
			if (me->key) {
				KeyBlock *kb;
				
				for (kb = me->key->block.first; kb; kb = kb->next) {
					float *fp = kb->data;
					
					for (a = 0; a < kb->totelem; a++, fp += 3)
						mul_m4_v3(mat, fp);
				}
			}
			
			/* update normals */
			BKE_mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
		}
		else if (ob->type == OB_ARMATURE) {
			ED_armature_apply_transform(ob, mat);
		}
		else if (ob->type == OB_LATTICE) {
			Lattice *lt = ob->data;
			BPoint *bp = lt->def;
			int a = lt->pntsu * lt->pntsv * lt->pntsw;
			
			while (a--) {
				mul_m4_v3(mat, bp->vec);
				bp++;
			}
		}
		else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			Curve *cu = ob->data;

			Nurb *nu;
			BPoint *bp;
			BezTriple *bezt;

			scale = mat3_to_scale(rsmat);

			for (nu = cu->nurb.first; nu; nu = nu->next) {
				if (nu->type == CU_BEZIER) {
					a = nu->pntsu;
					for (bezt = nu->bezt; a--; bezt++) {
						mul_m4_v3(mat, bezt->vec[0]);
						mul_m4_v3(mat, bezt->vec[1]);
						mul_m4_v3(mat, bezt->vec[2]);
						bezt->radius *= scale;
					}
					BKE_nurb_handles_calc(nu);
				}
				else {
					a = nu->pntsu * nu->pntsv;
					for (bp = nu->bp; a--; bp++)
						mul_m4_v3(mat, bp->vec);
				}
			}
		}
		else
			continue;

		if (apply_loc)
			zero_v3(ob->loc);
		if (apply_scale)
			ob->size[0] = ob->size[1] = ob->size[2] = 1.0f;
		if (apply_rot) {
			zero_v3(ob->rot);
			unit_qt(ob->quat);
			unit_axis_angle(ob->rotAxis, &ob->rotAngle);
		}

		BKE_object_where_is_calc(scene, ob);
		if (ob->type == OB_ARMATURE) {
			BKE_pose_where_is(scene, ob); /* needed for bone parents */
		}

		ignore_parent_tx(bmain, scene, ob);

		DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);

		change = 1;
	}
	CTX_DATA_END;

	if (!change)
		return OPERATOR_CANCELLED;

	WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
	return OPERATOR_FINISHED;
}
Example #4
0
/* convert stroke to 3d bezier */
static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
                                float minmax_weights[2], float rad_fac, int stitch, tGpTimingData *gtd)
{
	bGPDspoint *pt;
	Nurb *nu = (curnu) ? *curnu : NULL;
	BezTriple *bezt, *prev_bezt = NULL;
	int i, tot, old_nbezt = 0;
	float p3d_cur[3], p3d_prev[3], p3d_next[3];
	const int do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
	
	/* create new 'nurb' or extend current one within the curve */
	if (nu) {
		old_nbezt = nu->pntsu;
		/* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke,
		 * so no need to add it.
		 * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes.
		 */
		BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2));
	}
	else {
		nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
		
		nu->pntsu = gps->totpoints;
		nu->resolu = 12;
		nu->resolv = 12;
		nu->type = CU_BEZIER;
		nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints * sizeof(BezTriple), "bezts");
		
		stitch = FALSE; /* Security! */
	}

	if (do_gtd) {
		_gp_timing_data_set_nbr(gtd, nu->pntsu);
	}

	tot = gps->totpoints;

	/* get initial coordinates */
	pt = gps->points;
	if (tot) {
		gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
		if (tot > 1) {
			gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
		}
		if (stitch && tot > 2) {
			gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
		}
	}

	/* If needed, make the link between both strokes with two zero-radius additional points */
	if (curnu && old_nbezt) {
		/* Update last point's second handle */
		if (stitch) {
			float h2[3];
			bezt = nu->bezt + old_nbezt - 1;
			interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC);
			copy_v3_v3(bezt->vec[2], h2);
			pt++;
		}
		
		/* Create "link points" */
		/* About "zero-radius" point interpolations:
		 * - If we have at least two points in current curve (most common case), we linearly extrapolate
		 *   the last segment to get the first point (p1) position and timing.
		 * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
		 *   with the first point of the current stroke.
		 * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
		 * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
		 */
		else {
			float h1[3], h2[3], p1[3], p2[3];
			float delta_time;
			
			prev_bezt = NULL;
			if (old_nbezt > 1 && gps->prev && gps->prev->totpoints > 1) {
				/* Only use last curve segment if previous stroke was not a single-point one! */
				prev_bezt = nu->bezt + old_nbezt - 2;
			}
			bezt = nu->bezt + old_nbezt - 1;
			if (prev_bezt) {
				interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC);
			}
			else {
				interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC);
			}
			if (tot > 1) {
				interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC);
			}
			else {
				interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC);
			}
			
			/* Second handle of last point */
			interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC);
			copy_v3_v3(bezt->vec[2], h2);
			
			/* First point */
			interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
			interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
			
			bezt++;
			copy_v3_v3(bezt->vec[0], h1);
			copy_v3_v3(bezt->vec[1], p1);
			copy_v3_v3(bezt->vec[2], h2);
			bezt->h1 = bezt->h2 = HD_FREE;
			bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
			minmax_weights[0] = bezt->radius = bezt->weight = 0.0f;
			
			if (do_gtd) {
				if (prev_bezt) {
					delta_time = gtd->tot_time + (gtd->tot_time - gtd->times[gtd->cur_point - 1]) * GAP_DFAC;
				}
				else {
					delta_time = gtd->tot_time + (((float)(gps->inittime - gtd->inittime)) - gtd->tot_time) * GAP_DFAC;
				}
				gp_timing_data_add_point(gtd, gtd->inittime, delta_time, len_v3v3((bezt - 1)->vec[1], p1));
			}
			
			/* Second point */
			interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
			interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
			
			bezt++;
			copy_v3_v3(bezt->vec[0], h1);
			copy_v3_v3(bezt->vec[1], p2);
			copy_v3_v3(bezt->vec[2], h2);
			bezt->h1 = bezt->h2 = HD_FREE;
			bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
			minmax_weights[0] = bezt->radius = bezt->weight = 0.0f;
			
			if (do_gtd) {
				/* This negative delta_time marks the gap! */
				if (tot > 1) {
					delta_time = ((gps->points + 1)->time - gps->points->time) * -GAP_DFAC;
				}
				else {
					delta_time = -(((float)(gps->inittime - gtd->inittime)) - gtd->tot_time) * GAP_DFAC;
				}
				gp_timing_data_add_point(gtd, gps->inittime, delta_time, len_v3v3(p1, p2));
			}
			
			old_nbezt += 2;
			copy_v3_v3(p3d_prev, p2);
		}
	}
	if (old_nbezt && do_gtd) {
		prev_bezt = nu->bezt + old_nbezt - 1;
	}
	
	/* add points */
	for (i = stitch ? 1 : 0, bezt = nu->bezt + old_nbezt; i < tot; i++, pt++, bezt++) {
		float h1[3], h2[3];
		float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
		
		if (i || old_nbezt) {
			interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
		}
		else {
			interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC);
		}
		
		if (i < tot - 1) {
			interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC);
		}
		else {
			interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
		}
		
		copy_v3_v3(bezt->vec[0], h1);
		copy_v3_v3(bezt->vec[1], p3d_cur);
		copy_v3_v3(bezt->vec[2], h2);
		
		/* set settings */
		bezt->h1 = bezt->h2 = HD_FREE;
		bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
		bezt->radius = width * rad_fac;
		bezt->weight = width;
		CLAMP(bezt->weight, 0.0f, 1.0f);
		if (bezt->weight < minmax_weights[0]) {
			minmax_weights[0] = bezt->weight;
		}
		else if (bezt->weight > minmax_weights[1]) {
			minmax_weights[1] = bezt->weight;
		}
		
		/* Update timing data */
		if (do_gtd) {
			gp_timing_data_add_point(gtd, gps->inittime, pt->time, prev_bezt ? len_v3v3(prev_bezt->vec[1], p3d_cur) : 0.0f);
		}
		
		/* shift coord vects */
		copy_v3_v3(p3d_prev, p3d_cur);
		copy_v3_v3(p3d_cur, p3d_next);
		
		if (i + 2 < tot) {
			gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
		}
		
		prev_bezt = bezt;
	}
	
	/* must calculate handles or else we crash */
	BKE_nurb_handles_calc(nu);

	if (!curnu || !*curnu) {
		BLI_addtail(&cu->nurb, nu);
	}
	if (curnu) {
		*curnu = nu;
	}
}
Example #5
0
static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_loc, bool apply_rot, bool apply_scale)
{
	Main *bmain = CTX_data_main(C);
	Scene *scene = CTX_data_scene(C);
	float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale;
	bool changed = true;
	
	/* first check if we can execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{
		if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) {
			ID *obdata = ob->data;
			if (ID_REAL_USERS(obdata) > 1) {
				BKE_reportf(reports, RPT_ERROR,
				            "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}

			if (obdata->lib) {
				BKE_reportf(reports, RPT_ERROR,
				            "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
		}

		if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			ID *obdata = ob->data;
			Curve *cu;

			cu = ob->data;

			if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) {
				BKE_reportf(reports, RPT_ERROR,
				            "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
			if (cu->key) {
				BKE_reportf(reports, RPT_ERROR,
				            "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting",
				            ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2);
				changed = false;
			}
		}
	}
	CTX_DATA_END;
	
	if (!changed)
		return OPERATOR_CANCELLED;

	changed = false;

	/* now execute */
	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
	{

		/* calculate rotation/scale matrix */
		if (apply_scale && apply_rot)
			BKE_object_to_mat3(ob, rsmat);
		else if (apply_scale)
			BKE_object_scale_to_mat3(ob, rsmat);
		else if (apply_rot) {
			float tmat[3][3], timat[3][3];

			/* simple rotation matrix */
			BKE_object_rot_to_mat3(ob, rsmat, true);

			/* correct for scale, note mul_m3_m3m3 has swapped args! */
			BKE_object_scale_to_mat3(ob, tmat);
			invert_m3_m3(timat, tmat);
			mul_m3_m3m3(rsmat, timat, rsmat);
			mul_m3_m3m3(rsmat, rsmat, tmat);
		}
		else
			unit_m3(rsmat);

		copy_m4_m3(mat, rsmat);

		/* calculate translation */
		if (apply_loc) {
			copy_v3_v3(mat[3], ob->loc);

			if (!(apply_scale && apply_rot)) {
				float tmat[3][3];
				/* correct for scale and rotation that is still applied */
				BKE_object_to_mat3(ob, obmat);
				invert_m3_m3(iobmat, obmat);
				mul_m3_m3m3(tmat, rsmat, iobmat);
				mul_m3_v3(tmat, mat[3]);
			}
		}

		/* apply to object data */
		if (ob->type == OB_MESH) {
			Mesh *me = ob->data;
			MVert *mvert;
			int a;

			if (apply_scale)
				multiresModifier_scale_disp(scene, ob);
			
			/* adjust data */
			mvert = me->mvert;
			for (a = 0; a < me->totvert; a++, mvert++)
				mul_m4_v3(mat, mvert->co);
			
			if (me->key) {
				KeyBlock *kb;
				
				for (kb = me->key->block.first; kb; kb = kb->next) {
					float *fp = kb->data;
					
					for (a = 0; a < kb->totelem; a++, fp += 3)
						mul_m4_v3(mat, fp);
				}
			}
			
			/* update normals */
			BKE_mesh_calc_normals(me);
		}
		else if (ob->type == OB_ARMATURE) {
			ED_armature_apply_transform(ob, mat);
		}
		else if (ob->type == OB_LATTICE) {
			Lattice *lt = ob->data;
			BPoint *bp = lt->def;
			int a = lt->pntsu * lt->pntsv * lt->pntsw;
			
			while (a--) {
				mul_m4_v3(mat, bp->vec);
				bp++;
			}
		}
		else if (ob->type == OB_MBALL) {
			MetaBall *mb = ob->data;
			ED_mball_transform(mb, mat);
		}
		else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
			Curve *cu = ob->data;

			Nurb *nu;
			BPoint *bp;
			BezTriple *bezt;
			int a;

			scale = mat3_to_scale(rsmat);

			for (nu = cu->nurb.first; nu; nu = nu->next) {
				if (nu->type == CU_BEZIER) {
					a = nu->pntsu;
					for (bezt = nu->bezt; a--; bezt++) {
						mul_m4_v3(mat, bezt->vec[0]);
						mul_m4_v3(mat, bezt->vec[1]);
						mul_m4_v3(mat, bezt->vec[2]);
						bezt->radius *= scale;
					}
					BKE_nurb_handles_calc(nu);
				}
				else {
					a = nu->pntsu * nu->pntsv;
					for (bp = nu->bp; a--; bp++)
						mul_m4_v3(mat, bp->vec);
				}
			}
		}
		else if (ob->type == OB_CAMERA) {
			MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);

			/* applying scale on camera actually scales clip's reconstruction.
			 * of there's clip assigned to camera nothing to do actually.
			 */
			if (!clip)
				continue;

			if (apply_scale)
				BKE_tracking_reconstruction_scale(&clip->tracking, ob->size);
		}
		else if (ob->type == OB_EMPTY) {
			/* It's possible for empties too, even though they don't 
			 * really have obdata, since we can simply apply the maximum
			 * scaling to the empty's drawsize.
			 *
			 * Core Assumptions:
			 * 1) Most scaled empties have uniform scaling 
			 *    (i.e. for visibility reasons), AND/OR
			 * 2) Preserving non-uniform scaling is not that important,
			 *    and is something that many users would be willing to
			 *    sacrifice for having an easy way to do this.
			 */

			if ((apply_loc == false) &&
			    (apply_rot == false) &&
			    (apply_scale == true))
			{
				float max_scale = max_fff(fabsf(ob->size[0]), fabsf(ob->size[1]), fabsf(ob->size[2]));
				ob->empty_drawsize *= max_scale;
			}
		}
		else {
			continue;
		}

		if (apply_loc)
			zero_v3(ob->loc);
		if (apply_scale)
			ob->size[0] = ob->size[1] = ob->size[2] = 1.0f;
		if (apply_rot) {
			zero_v3(ob->rot);
			unit_qt(ob->quat);
			unit_axis_angle(ob->rotAxis, &ob->rotAngle);
		}

		BKE_object_where_is_calc(scene, ob);
		if (ob->type == OB_ARMATURE) {
			BKE_pose_where_is(scene, ob); /* needed for bone parents */
		}

		ignore_parent_tx(bmain, scene, ob);

		DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);

		changed = true;
	}
	CTX_DATA_END;

	if (!changed) {
		BKE_report(reports, RPT_WARNING, "Objects have no data to transform");
		return OPERATOR_CANCELLED;
	}

	WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
	return OPERATOR_FINISHED;
}
Example #6
0
/* convert stroke to 3d bezier */
static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect)
{
	bGPDspoint *pt;
	Nurb *nu;
	BezTriple *bezt;
	int i, tot;
	float p3d_cur[3], p3d_prev[3], p3d_next[3];

	/* create new 'nurb' within the curve */
	nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");

	nu->pntsu = gps->totpoints;
	nu->resolu = 12;
	nu->resolv = 12;
	nu->type = CU_BEZIER;
	nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints * sizeof(BezTriple), "bezts");

	tot = gps->totpoints;

	/* get initial coordinates */
	pt = gps->points;
	if (tot) {
		gp_strokepoint_convertcoords(C, gps, pt, p3d_cur, subrect);
		if (tot > 1) {
			gp_strokepoint_convertcoords(C, gps, pt + 1, p3d_next, subrect);
		}
	}

	/* add points */
	for (i = 0, bezt = nu->bezt; i < tot; i++, pt++, bezt++) {
		float h1[3], h2[3];
		
		if (i) interp_v3_v3v3(h1, p3d_cur, p3d_prev, 0.3);
		else interp_v3_v3v3(h1, p3d_cur, p3d_next, -0.3);
		
		if (i < tot - 1) interp_v3_v3v3(h2, p3d_cur, p3d_next, 0.3);
		else interp_v3_v3v3(h2, p3d_cur, p3d_prev, -0.3);
		
		copy_v3_v3(bezt->vec[0], h1);
		copy_v3_v3(bezt->vec[1], p3d_cur);
		copy_v3_v3(bezt->vec[2], h2);
		
		/* set settings */
		bezt->h1 = bezt->h2 = HD_FREE;
		bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
		bezt->radius = bezt->weight = pt->pressure * gpl->thickness * 0.1f;
		
		/* shift coord vects */
		copy_v3_v3(p3d_prev, p3d_cur);
		copy_v3_v3(p3d_cur, p3d_next);
		
		if (i + 2 < tot) {
			gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
		}
	}

	/* must calculate handles or else we crash */
	BKE_nurb_handles_calc(nu);

	/* add nurb to curve */
	BLI_addtail(&cu->nurb, nu);
}