/* 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); }
/* 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); }
/* 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); }