/* convert stroke to 3d path */
static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect)
{
	bGPDspoint *pt;
	Nurb *nu;
	BPoint *bp;
	int i;

	/* create new 'nurb' within the curve */
	nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
	
	nu->pntsu = gps->totpoints;
	nu->pntsv = 1;
	nu->orderu = gps->totpoints;
	nu->flagu = CU_NURB_ENDPOINT;
	nu->resolu = 32;
	
	nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * gps->totpoints, "bpoints");
	
	/* add points */
	for (i = 0, pt = gps->points, bp = nu->bp; i < gps->totpoints; i++, pt++, bp++) {
		float p3d[3];
		
		/* get coordinates to add at */
		gp_strokepoint_convertcoords(C, gps, pt, p3d, subrect);
		copy_v3_v3(bp->vec, p3d);
		
		/* set settings */
		bp->f1 = SELECT;
		bp->radius = bp->weight = pt->pressure * gpl->thickness;
	}
	
	/* add nurb to curve */
	BLI_addtail(&cu->nurb, nu);
}
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;
	}
}
static void gp_stroke_to_path(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;
	BPoint *bp, *prev_bp = NULL;
	const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
	const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
	int i, old_nbp = 0;
	
	/* create new 'nurb' or extend current one within the curve */
	if (nu) {
		old_nbp = nu->pntsu;

		/* If stitch, the first point of this stroke is already present in current nu.
		 * Else, we have to add two additional points to make the zero-radius link between strokes.
		 */
		BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2) + add_start_end_points);
	}
	else {
		nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
		
		nu->pntsu = gps->totpoints + add_start_end_points;
		nu->pntsv = 1;
		nu->orderu = 2; /* point-to-point! */
		nu->type = CU_NURBS;
		nu->flagu = CU_NURB_ENDPOINT;
		nu->resolu = cu->resolu;
		nu->resolv = cu->resolv;
		nu->knotsu = NULL;
		
		nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints");
		
		stitch = false; /* Security! */
	}
	
	if (do_gtd) {
		gp_timing_data_set_nbr(gtd, nu->pntsu);
	}
	
	/* If needed, make the link between both strokes with two zero-radius additional 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...
	 */
	if (curnu && !stitch && old_nbp) {
		float p1[3], p2[3], p[3], next_p[3];
		float dt1 = 0.0f, dt2 = 0.0f;
		
		BLI_assert(gps->prev != NULL);
		
		prev_bp = NULL;
		if ((old_nbp > 1) && (gps->prev->totpoints > 1)) {
			/* Only use last curve segment if previous stroke was not a single-point one! */
			prev_bp = &nu->bp[old_nbp - 2];
		}
		bp = &nu->bp[old_nbp - 1];
		
		/* First point */
		gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
		if (prev_bp) {
			interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -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, bp->vec, p, GAP_DFAC);
			if (do_gtd) {
				dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
			}
		}
		bp++;
		gp_stroke_to_path_add_point(gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1,
		                            0.0f, rad_fac, minmax_weights);
		
		/* Second point */
		/* Note dt2 is always negative, which marks the gap. */
		if (gps->totpoints > 1) {
			gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
			interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
			if (do_gtd) {
				dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
			}
		}
		else {
			interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC);
			if (do_gtd) {
				dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
			}
		}
		bp++;
		gp_stroke_to_path_add_point(gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
		
		old_nbp += 2;
	}
	else if (add_start_point) {
		float p[3], next_p[3];
		float dt = 0.0f;
		
		gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
		if (gps->totpoints > 1) {
			gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
			interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
			if (do_gtd) {
				dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
			}
		}
		else {
			p[0] -= GAP_DFAC;  /* Rather arbitrary... */
			dt = -GAP_DFAC;  /* Rather arbitrary too! */
		}
		bp = &nu->bp[old_nbp];
		/* Note we can't give anything else than 0.0 as time here, since a negative one (which would be expected value)
		 * would not work (it would be *before* gtd->inittime, which is not supported currently).
		 */
		gp_stroke_to_path_add_point(gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
		
		old_nbp++;
	}
	
	if (old_nbp) {
		prev_bp = &nu->bp[old_nbp - 1];
	}
	
	/* add points */
	for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp];
	     i < gps->totpoints;
	     i++, pt++, bp++)
	{
		float p[3];
		float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
		
		/* get coordinates to add at */
		gp_strokepoint_convertcoords(C, gps, pt, p, subrect);
		
		gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time,
		                            width, rad_fac, minmax_weights);
		
		prev_bp = bp;
	}

	if (add_end_point) {
		float p[3];
		float dt = 0.0f;
		
		if (gps->totpoints > 1) {
			interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -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_bp->vec);
			p[0] += GAP_DFAC;  /* Rather arbitrary... */
			dt = GAP_DFAC;  /* Rather arbitrary too! */
		}
		/* Note bp has already been incremented in main loop above, so it points to the right place. */
		gp_stroke_to_path_add_point(gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
	}
	
	/* add nurb to curve */
	if (!curnu || !*curnu) {
		BLI_addtail(&cu->nurb, nu);
	}
	if (curnu) {
		*curnu = nu;
	}
	
	BKE_nurb_knot_calc_u(nu);
}
Exemple #4
0
/* convert stroke to 3d path */
static void gp_stroke_to_path(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;
	BPoint *bp, *prev_bp = NULL;
	const int do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
	int i, old_nbp = 0;

	/* create new 'nurb' or extend current one within the curve */
	if (nu) {
		old_nbp = nu->pntsu;
		
		/* If stitch, the first point of this stroke is already present in current nu.
		 * Else, we have to add to additional points to make the zero-radius link between strokes.
		 */
		BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2));
	}
	else {
		nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
		
		nu->pntsu = gps->totpoints;
		nu->pntsv = 1;
		nu->orderu = 2; /* point-to-point! */
		nu->type = CU_NURBS;
		nu->flagu = CU_NURB_ENDPOINT;
		nu->resolu = cu->resolu;
		nu->resolv = cu->resolv;
		nu->knotsu = NULL;
		
		nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints");
		
		stitch = FALSE; /* Security! */
	}

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

	/* If needed, make the link between both strokes with two zero-radius additional 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...
	 */
	if (curnu && !stitch && old_nbp) {
		float p1[3], p2[3], p[3], next_p[3];
		float delta_time;

		prev_bp = NULL;
		if ((old_nbp > 1) && gps->prev && (gps->prev->totpoints > 1)) {
			/* Only use last curve segment if previous stroke was not a single-point one! */
			prev_bp = nu->bp + old_nbp - 2;
		}
		bp = nu->bp + old_nbp - 1;
		
		/* XXX We do this twice... Not sure it's worth to bother about this! */
		gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
		if (prev_bp) {
			interp_v3_v3v3(p1, prev_bp->vec, bp->vec, 1.0f + GAP_DFAC);
		}
		else {
			interp_v3_v3v3(p1, bp->vec, p, GAP_DFAC);
		}
		
		if (gps->totpoints > 1) {
			/* XXX We do this twice... Not sure it's worth to bother about this! */
			gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
			interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
		}
		else {
			interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC);
		}
		
		/* First point */
		bp++;
		copy_v3_v3(bp->vec, p1);
		bp->vec[3] = 1.0f;
		bp->f1 = SELECT;
		minmax_weights[0] = bp->radius = bp->weight = 0.0f;
		if (do_gtd) {
			if (prev_bp) {
				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((bp - 1)->vec, p1));
		}
		
		/* Second point */
		bp++;
		copy_v3_v3(bp->vec, p2);
		bp->vec[3] = 1.0f;
		bp->f1 = SELECT;
		minmax_weights[0] = bp->radius = bp->weight = 0.0f;
		if (do_gtd) {
			/* This negative delta_time marks the gap! */
			if (gps->totpoints > 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_nbp += 2;
	}
	if (old_nbp && do_gtd) {
		prev_bp = nu->bp + old_nbp - 1;
	}
	
	/* add points */
	for (i = (stitch) ? 1 : 0, pt = gps->points + ((stitch) ? 1 : 0), bp = nu->bp + old_nbp;
	     i < gps->totpoints;
	     i++, pt++, bp++)
	{
		float p3d[3];
		float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
		
		/* get coordinates to add at */
		gp_strokepoint_convertcoords(C, gps, pt, p3d, subrect);
		copy_v3_v3(bp->vec, p3d);
		bp->vec[3] = 1.0f;
		
		/* set settings */
		bp->f1 = SELECT;
		bp->radius = width * rad_fac;
		bp->weight = width;
		CLAMP(bp->weight, 0.0f, 1.0f);
		if (bp->weight < minmax_weights[0]) {
			minmax_weights[0] = bp->weight;
		}
		else if (bp->weight > minmax_weights[1]) {
			minmax_weights[1] = bp->weight;
		}
		
		/* Update timing data */
		if (do_gtd) {
			gp_timing_data_add_point(gtd, gps->inittime, pt->time, (prev_bp) ? len_v3v3(prev_bp->vec, p3d) : 0.0f);
		}
		prev_bp = bp;
	}
	
	/* add nurb to curve */
	if (!curnu || !*curnu) {
		BLI_addtail(&cu->nurb, nu);
	}
	if (curnu) {
		*curnu = nu;
	}
	
	BKE_nurb_knot_calc_u(nu);
}
Exemple #5
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;
	}
}
/* 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);
}