Alternate mask spline feather offset calculation method: now there are 2 [Even |...
authorCampbell Barton <ideasman42@gmail.com>
Mon, 27 Aug 2012 09:44:56 +0000 (09:44 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 27 Aug 2012 09:44:56 +0000 (09:44 +0000)
- Even preserves thickness but can give unsightly loops
- Smooth gives nicer shape but can give unsightly feather/spline mismatch for 'S' shapes created by beziers.

This is an example where smooth works much nicer.

http://www.graphicall.org/ftp/ideasman42/mask_compare.png

release/scripts/startup/bl_ui/properties_mask_common.py
source/blender/blenkernel/intern/mask.c
source/blender/blenkernel/intern/mask_evaluate.c
source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/intern/math_vector.c
source/blender/makesdna/DNA_mask_types.h
source/blender/makesrna/intern/rna_mask.c

index 67980c388b5d3a41a3d7cd7c143dd84f5ef71355..208b0a63075b0f30c48276d5e0f93241cb8dfb4b 100644 (file)
@@ -121,6 +121,7 @@ class MASK_PT_spline():
         spline = mask.layers.active.splines.active
 
         col = layout.column()
+        col.prop(spline, "offset_mode")
         col.prop(spline, "weight_interpolation")
 
         row = col.row()
index 5182c52605a156360630889087d3d9d764bff910..f73fb3879b81691d7be9c04dd860bc06b96f9ce9 100644 (file)
@@ -1194,17 +1194,6 @@ void BKE_mask_calc_handle_point(MaskSpline *spline, MaskSplinePoint *point)
        mask_calc_point_handle(point, point_prev, point_next);
 }
 
-static void enforce_dist_v2_v2fl(float v1[2], const float v2[2], const float dist)
-{
-       if (!equals_v2v2(v2, v1)) {
-               float nor[2];
-
-               sub_v2_v2v2(nor, v1, v2);
-               normalize_v2(nor);
-               madd_v2_v2v2fl(v1, v2, nor, dist);
-       }
-}
-
 void BKE_mask_calc_handle_adjacent_interp(MaskSpline *spline, MaskSplinePoint *point, const float u)
 {
        /* TODO! - make this interpolate between siblings - not always midpoint! */
@@ -1246,8 +1235,8 @@ void BKE_mask_calc_handle_adjacent_interp(MaskSpline *spline, MaskSplinePoint *p
                length_average /= (float)length_tot;
                weight_average /= (float)length_tot;
 
-               enforce_dist_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average);
-               enforce_dist_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average);
+               dist_ensure_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average);
+               dist_ensure_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average);
                point->bezt.weight = weight_average;
        }
 }
@@ -1279,8 +1268,8 @@ void BKE_mask_calc_handle_point_auto(MaskSpline *spline, MaskSplinePoint *point,
 
        /* preserve length by applying it back */
        if (do_recalc_length == FALSE) {
-               enforce_dist_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average);
-               enforce_dist_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average);
+               dist_ensure_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average);
+               dist_ensure_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average);
        }
 }
 
index 9d9f1665a7babf6bcf09aa7b27d134ba292687ca..065dc38c81e97cdbfaa9b02ca41abd73da17d9bc 100644 (file)
@@ -507,15 +507,12 @@ void BKE_mask_spline_feather_collapse_inner_loops(MaskSpline *spline, float (*fe
 #undef BUCKET_INDEX
 }
 
-/**
- * values align with #BKE_mask_spline_differentiate_with_resolution_ex
- * when \a resol arguments match.
- */
-float (*BKE_mask_spline_feather_differentiated_points_with_resolution_ex(MaskSpline *spline,
-                                                                         int *tot_feather_point,
-                                                                         const unsigned int resol,
-                                                                         const int do_feather_isect
-                                                                         ))[2]
+/** only called from #BKE_mask_spline_feather_differentiated_points_with_resolution_ex() ! */
+static float (*mask_spline_feather_differentiated_points_with_resolution_ex__even(MaskSpline *spline,
+                                                                                  int *tot_feather_point,
+                                                                                  const unsigned int resol,
+                                                                                  const int do_feather_isect
+                                                                                  ))[2]
 {
        MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
        MaskSplinePoint *point_curr, *point_prev;
@@ -583,6 +580,161 @@ float (*BKE_mask_spline_feather_differentiated_points_with_resolution_ex(MaskSpl
        return feather;
 }
 
+/** only called from #BKE_mask_spline_feather_differentiated_points_with_resolution_ex() ! */
+static float (*mask_spline_feather_differentiated_points_with_resolution_ex__double(MaskSpline *spline,
+                                                                                    int *tot_feather_point,
+                                                                                    const unsigned int resol,
+                                                                                    const int do_feather_isect
+                                                                                    ))[2]
+{
+       MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
+
+       MaskSplinePoint *point_curr, *point_prev;
+       float (*feather)[2], (*fp)[2];
+       const int tot = BKE_mask_spline_differentiate_calc_total(spline, resol);
+       int a;
+
+       if (spline->tot_point <= 1) {
+               /* nothing to differentiate */
+               *tot_feather_point = 0;
+               return NULL;
+       }
+
+       /* len+1 because of 'forward_diff_bezier' function */
+       *tot_feather_point = tot;
+       feather = fp = MEM_mallocN((tot + 1) * sizeof(*feather), "mask spline vets");
+
+       a = spline->tot_point - 1;
+       if (spline->flag & MASK_SPLINE_CYCLIC)
+               a++;
+
+       point_prev = points_array;
+       point_curr = point_prev + 1;
+
+       while (a--) {
+               BezTriple local_prevbezt;
+               BezTriple local_bezt;
+               float point_prev_n[2], point_curr_n[2], tvec[2];
+               float weight_prev, weight_curr;
+               float len_base, len_feather, len_scalar;
+
+               BezTriple *bezt_prev;
+               BezTriple *bezt_curr;
+               int j;
+
+               if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC))
+                       point_curr = points_array;
+
+               bezt_prev = &point_prev->bezt;
+               bezt_curr = &point_curr->bezt;
+
+               /* modified copy for feather */
+               local_prevbezt = *bezt_prev;
+               local_bezt     = *bezt_curr;
+
+               bezt_prev = &local_prevbezt;
+               bezt_curr = &local_bezt;
+
+               /* calc the normals */
+               sub_v2_v2v2(tvec, bezt_prev->vec[1], bezt_prev->vec[0]);
+               normalize_v2(tvec);
+               point_prev_n[0] = -tvec[1];
+               point_prev_n[1] =  tvec[0];
+
+               sub_v2_v2v2(tvec, bezt_curr->vec[1], bezt_curr->vec[0]);
+               normalize_v2(tvec);
+               point_curr_n[0] = -tvec[1];
+               point_curr_n[1] =  tvec[0];
+
+               weight_prev = bezt_prev->weight;
+               weight_curr = bezt_curr->weight;
+
+               mul_v2_fl(point_prev_n, weight_prev);
+               mul_v2_fl(point_curr_n, weight_curr);
+
+               /* before we transform verts */
+               len_base = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]);
+
+               // add_v2_v2(bezt_prev->vec[0], point_prev_n);  // not needed
+               add_v2_v2(bezt_prev->vec[1], point_prev_n);
+               add_v2_v2(bezt_prev->vec[2], point_prev_n);
+
+               add_v2_v2(bezt_curr->vec[0], point_curr_n);
+               add_v2_v2(bezt_curr->vec[1], point_curr_n);
+               // add_v2_v2(bezt_curr->vec[2], point_curr_n); // not needed
+
+               len_feather = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]);
+
+               /* scale by chane in length */
+               len_scalar = len_feather / len_base;
+               dist_ensure_v2_v2fl(bezt_prev->vec[2], bezt_prev->vec[1], len_scalar * len_v2v2(bezt_prev->vec[2], bezt_prev->vec[1]));
+               dist_ensure_v2_v2fl(bezt_curr->vec[0], bezt_curr->vec[1], len_scalar * len_v2v2(bezt_curr->vec[0], bezt_curr->vec[1]));
+
+
+               for (j = 0; j < 2; j++) {
+                       BKE_curve_forward_diff_bezier(bezt_prev->vec[1][j], bezt_prev->vec[2][j],
+                                                     bezt_curr->vec[0][j], bezt_curr->vec[1][j],
+                                                     &(*fp)[j], resol, 2 * sizeof(float));
+               }
+
+
+               /* scale by the uw's */
+               if (point_prev->tot_uw) {
+                       for (j = 0; j < resol; j++, fp++) {
+                               float u = (float) j / resol;
+                               float weight_uw, weight_scalar;
+                               float co[2];
+
+                               /* TODO - these calls all calculate similar things
+                                * could be unified for some speed */
+                               BKE_mask_point_segment_co(spline, point_prev, u, co);
+
+                               weight_uw     = BKE_mask_point_weight(spline, point_prev, u);
+                               weight_scalar = BKE_mask_point_weight_scalar(spline, point_prev, u);
+
+                               dist_ensure_v2_v2fl(*fp, co, len_v2v2(*fp, co) * (weight_uw / weight_scalar));
+                       }
+               }
+               else {
+                       fp += resol;
+               }
+
+               if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) {
+                       copy_v2_v2(*fp, bezt_curr->vec[1]);
+               }
+
+               point_prev = point_curr;
+               point_curr++;
+       }
+
+       if ((spline->flag & MASK_SPLINE_NOINTERSECT) && do_feather_isect) {
+               BKE_mask_spline_feather_collapse_inner_loops(spline, feather, tot);
+       }
+
+       return feather;
+}
+
+/**
+ * values align with #BKE_mask_spline_differentiate_with_resolution_ex
+ * when \a resol arguments match.
+ */
+float (*BKE_mask_spline_feather_differentiated_points_with_resolution_ex(MaskSpline *spline,
+                                                                         int *tot_feather_point,
+                                                                         const unsigned int resol,
+                                                                         const int do_feather_isect
+                                                                         ))[2]
+{
+       switch (spline->offset_mode) {
+               case MASK_SPLINE_OFFSET_EVEN:
+                       return mask_spline_feather_differentiated_points_with_resolution_ex__even(spline, tot_feather_point, resol, do_feather_isect);
+                       break;
+               case MASK_SPLINE_OFFSET_SMOOTH:
+               default:
+                       return mask_spline_feather_differentiated_points_with_resolution_ex__double(spline, tot_feather_point, resol, do_feather_isect);
+                       break;
+       }
+}
+
 float (*BKE_mask_spline_feather_differentiated_points_with_resolution(MaskSpline *spline, int width, int height,
                                                                       int *tot_feather_point, const int do_feather_isect))[2]
 {
index 8499a7f219c9d1a137c8fd77e3a18c40da143eba..eef8c9daaef41ccd7e1d09884075fedacc39f52d 100644 (file)
@@ -220,6 +220,9 @@ MINLINE void normal_float_to_short_v3(short r[3], const float n[3]);
 
 void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]);
 
+void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist);
+void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
+
 /***************************** Array Functions *******************************/
 /* attempted to follow fixed length vertex functions. names could be improved*/
 double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size);
index 5cda1c0b81f5b1c3fc80c6abd56c0765fe6bd832..4196bab0474b037f95005089d2a17956b384c0bc 100644 (file)
@@ -451,6 +451,29 @@ void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
        if (max[2] < vec[2]) max[2] = vec[2];
 }
 
+/** ensure \a v1 is \a dist from \a v2 */
+void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist)
+{
+       if (!equals_v3v3(v2, v1)) {
+               float nor[3];
+
+               sub_v3_v3v3(nor, v1, v2);
+               normalize_v3(nor);
+               madd_v3_v3v3fl(v1, v2, nor, dist);
+       }
+}
+
+void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist)
+{
+       if (!equals_v2v2(v2, v1)) {
+               float nor[2];
+
+               sub_v2_v2v2(nor, v1, v2);
+               normalize_v2(nor);
+               madd_v2_v2v2fl(v1, v2, nor, dist);
+       }
+}
+
 /***************************** Array Functions *******************************/
 
 double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size)
index 6c7f7aa2471e3f09bfd5c944857d4b8008f81691..bf388d8c0181381c3872e48dc654a1b36fae860d 100644 (file)
@@ -82,13 +82,14 @@ typedef struct MaskSplinePoint {
 typedef struct MaskSpline {
        struct MaskSpline *next, *prev;
 
-       int flag;                /* defferent spline flag (closed, ...) */
+       short flag;              /* defferent spline flag (closed, ...) */
+       char offset_mode;        /* feather offset method */
+       char weight_interp;      /* weight interpolation */
+
        int tot_point;           /* total number of points */
        MaskSplinePoint *points; /* points which defines spline itself */
        MaskParent parent;       /* parenting information of the whole spline */
 
-       int weight_interp, pad;  /* weight interpolation */
-
        MaskSplinePoint *points_deform; /* deformed copy of 'points' BezTriple data - not saved */
 } MaskSpline;
 
@@ -146,8 +147,17 @@ enum {
 };
 
 /* MaskSpline->weight_interp */
-#define MASK_SPLINE_INTERP_LINEAR   1
-#define MASK_SPLINE_INTERP_EASE     2
+enum {
+       MASK_SPLINE_INTERP_LINEAR  = 1,
+       MASK_SPLINE_INTERP_EASE    = 2
+};
+
+/* MaskSpline->offset_mode */
+enum {
+       MASK_SPLINE_OFFSET_EVEN   = 0,
+       MASK_SPLINE_OFFSET_SMOOTH = 1
+};
+
 
 /* ob->restrictflag */
 #define MASK_RESTRICT_VIEW      1
index a6571a2db4f42067ef9b34ead54f4917d1282b72..719baed8edb998266f1df61c6d5fc425b8e9fcfd 100644 (file)
@@ -540,6 +540,12 @@ static void rna_def_maskSpline(BlenderRNA *brna)
                {0, NULL, 0, NULL, NULL}
        };
 
+       static EnumPropertyItem spline_offset_mode_items[] = {
+               {MASK_SPLINE_OFFSET_EVEN, "EVEN", 0, "Even", "Calculate even feather offset"},
+               {MASK_SPLINE_OFFSET_SMOOTH, "SMOOTH", 0, "Smooth", "Calculate feather offset as a second curve"},
+               {0, NULL, 0, NULL, NULL}
+       };
+
        StructRNA *srna;
        PropertyRNA *prop;
 
@@ -548,6 +554,13 @@ static void rna_def_maskSpline(BlenderRNA *brna)
        srna = RNA_def_struct(brna, "MaskSpline", NULL);
        RNA_def_struct_ui_text(srna, "Mask spline", "Single spline used for defining mask shape");
 
+       /* offset mode */
+       prop = RNA_def_property(srna, "offset_mode", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "offset_mode");
+       RNA_def_property_enum_items(prop, spline_offset_mode_items);
+       RNA_def_property_ui_text(prop, "Feather Offset", "The method used for calculating the feather offset");
+       RNA_def_property_update(prop, 0, "rna_Mask_update_data");
+
        /* weight interpolation */
        prop = RNA_def_property(srna, "weight_interpolation", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_sdna(prop, NULL, "weight_interp");