RNA: Spline.calc_length() utility function
authorCampbell Barton <ideasman42@gmail.com>
Mon, 20 Aug 2018 01:10:09 +0000 (11:10 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 20 Aug 2018 01:23:40 +0000 (11:23 +1000)
D1810 by @Matpi w/ edits

source/blender/blenkernel/BKE_curve.h
source/blender/blenkernel/intern/curve.c
source/blender/makesrna/intern/rna_curve.c
source/blender/makesrna/intern/rna_curve_api.c
source/blender/makesrna/intern/rna_internal.h

index fc6e86910cf9f4d1251c4a18de2e77a75bc4c73d..08cff0c369d11ab5ef7d58a16acec3dbd8e39ed7 100644 (file)
@@ -156,9 +156,14 @@ struct Nurb *BKE_nurb_copy(struct Nurb *src, int pntsu, int pntsv);
 
 void BKE_nurb_test2D(struct Nurb *nu);
 void BKE_nurb_minmax(struct Nurb *nu, bool use_radius, float min[3], float max[3]);
-
-void BKE_nurb_makeFaces(struct Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv);
-void BKE_nurb_makeCurve(struct Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array, int resolu, int stride);
+float BKE_nurb_calc_length(const struct Nurb *nu, int resolution);
+
+void BKE_nurb_makeFaces(
+        const struct Nurb *nu, float *coord_array,
+        int rowstride, int resolu, int resolv);
+void BKE_nurb_makeCurve(
+        const struct Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array,
+        int resolu, int stride);
 
 unsigned int BKE_curve_calc_coords_axis_len(
         const unsigned int bezt_array_len, const unsigned int resolu,
index 6d1d62f839c2d3b6d0107ca472cbee9cf85c6c8a..792ba08358e31cc91249ec73d1993d45991e7ed6 100644 (file)
@@ -632,6 +632,107 @@ void BKE_nurb_minmax(Nurb *nu, bool use_radius, float min[3], float max[3])
        }
 }
 
+float BKE_nurb_calc_length(const Nurb *nu, int resolution)
+{
+       BezTriple *bezt, *prevbezt;
+       BPoint *bp, *prevbp;
+       int a, b;
+       float length = 0.0f;
+       int resolu = resolution ? resolution : nu->resolu;
+       int pntsu = nu->pntsu;
+       float *points, *pntsit, *prevpntsit;
+
+       if (nu->type == CU_POLY) {
+               a = nu->pntsu - 1;
+               bp = nu->bp;
+               if (nu->flagu & CU_NURB_CYCLIC) {
+                       ++a;
+                       prevbp = nu->bp + (nu->pntsu - 1);
+               }
+               else {
+                       prevbp = bp;
+                       bp++;
+               }
+
+               while (a--) {
+                       length += len_v3v3(prevbp->vec, bp->vec);
+                       prevbp = bp;
+                       ++bp;
+               }
+       }
+       else if (nu->type == CU_BEZIER) {
+               points = MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier");
+               a = nu->pntsu - 1;
+               bezt = nu->bezt;
+               if (nu->flagu & CU_NURB_CYCLIC) {
+                       ++a;
+                       prevbezt = nu->bezt + (nu->pntsu - 1);
+               }
+               else {
+                       prevbezt = bezt;
+                       ++bezt;
+               }
+
+               while (a--) {
+                       if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
+                               length += len_v3v3(prevbezt->vec[1], bezt->vec[1]);
+                       }
+                       else {
+                               for (int j = 0; j < 3; j++) {
+                                       BKE_curve_forward_diff_bezier(
+                                               prevbezt->vec[1][j], prevbezt->vec[2][j],
+                                               bezt->vec[0][j], bezt->vec[1][j],
+                                               points + j, resolu, 3 * sizeof(float));
+                               }
+
+                               prevpntsit = pntsit = points;
+                               b = resolu;
+                               while (b--) {
+                                       pntsit += 3;
+                                       length += len_v3v3(prevpntsit, pntsit);
+                                       prevpntsit = pntsit;
+                               }
+                       }
+                       prevbezt = bezt;
+                       ++bezt;
+               }
+
+               MEM_freeN(points);
+       }
+       else if (nu->type == CU_NURBS) {
+               if (nu->pntsv == 1) {
+                       /* important to zero for BKE_nurb_makeCurve. */
+                       points = MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs");
+
+                       BKE_nurb_makeCurve(
+                               nu, points,
+                               NULL, NULL, NULL,
+                               resolu, sizeof(float[3]));
+
+                       if (nu->flagu & CU_NURB_CYCLIC) {
+                               b = pntsu * resolu + 1;
+                               prevpntsit = points + 3 * (pntsu * resolu - 1);
+                               pntsit = points;
+                       }
+                       else {
+                               b = (pntsu - 1) * resolu;
+                               prevpntsit = points;
+                               pntsit = points + 3;
+                       }
+
+                       while (--b) {
+                               length += len_v3v3(prevpntsit, pntsit);
+                               prevpntsit = pntsit;
+                               pntsit += 3;
+                       }
+
+                       MEM_freeN(points);
+               }
+       }
+
+       return length;
+}
+
 /* be sure to call makeknots after this */
 void BKE_nurb_points_add(Nurb *nu, int number)
 {
@@ -1080,9 +1181,10 @@ static void basisNurb(float t, short order, int pnts, float *knots, float *basis
        }
 }
 
-
-void BKE_nurb_makeFaces(Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv)
-/* coord_array  has to be (3 * 4 * resolu * resolv) in size, and zero-ed */
+/**
+ * \param coord_array: has to be (3 * 4 * resolu * resolv) in size, and zero-ed.
+ */
+void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv)
 {
        BPoint *bp;
        float *basisu, *basis, *basisv, *sum, *fp, *in;
@@ -1258,8 +1360,9 @@ void BKE_nurb_makeFaces(Nurb *nu, float *coord_array, int rowstride, int resolu,
  * \param tilt_array   set when non-NULL
  * \param radius_array set when non-NULL
  */
-void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array,
-                        int resolu, int stride)
+void BKE_nurb_makeCurve(
+        const Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array,
+        int resolu, int stride)
 {
        const float eps = 1e-6f;
        BPoint *bp;
index 59fbde13ee362e2ad908f601f2156d9ab4970674..233303ef613c8997ae49cb74a64b876d70fb24ee 100644 (file)
@@ -1759,6 +1759,8 @@ static void rna_def_curve_nurb(BlenderRNA *brna)
        RNA_def_property_update(prop, 0, "rna_Curve_update_data");
 
        RNA_def_struct_path_func(srna, "rna_Curve_spline_path");
+
+       RNA_api_curve_nurb(srna);
 }
 
 void RNA_def_curve(BlenderRNA *brna)
index 695f1f75c16708bf67fd43dc82b26860afcfe7f5..d83a843c5c158cca902af8e335f41ec20ae7b331 100644 (file)
@@ -49,6 +49,11 @@ static void rna_Curve_transform(Curve *cu, float *mat, bool shape_keys)
 
        DAG_id_tag_update(&cu->id, 0);
 }
+static float rna_Nurb_calc_length(Nurb *nu, int resolution_u)
+{
+       return BKE_nurb_calc_length(nu, resolution_u);
+}
+
 #else
 
 void RNA_api_curve(StructRNA *srna)
@@ -69,4 +74,20 @@ void RNA_api_curve(StructRNA *srna)
        RNA_def_function_return(func, parm);
 }
 
+void RNA_api_curve_nurb(StructRNA *srna)
+{
+       FunctionRNA *func;
+       PropertyRNA *parm;
+
+       func = RNA_def_function(srna, "calc_length", "rna_Nurb_calc_length");
+       RNA_def_function_ui_description(func, "Calculate spline length");
+       RNA_def_int(
+               func, "resolution", 0, 0, 1024, "Resolution",
+               "Spline resolution to be used, 0 defaults to the resolution_u", 0, 64);
+       parm = RNA_def_float_distance(
+               func, "length", 0.0f, 0.0f, FLT_MAX, "Length",
+               "Length of the polygonaly approximated spline", 0.0f, FLT_MAX);
+       RNA_def_function_return(func, parm);
+}
+
 #endif
index 67fbee8d0ef2e230780acfceffb611a658b7915f..c3ccdc6f446febc0e63a1e5d6832b3398bf83ad2 100644 (file)
@@ -261,6 +261,7 @@ void RNA_api_armature_edit_bone(StructRNA *srna);
 void RNA_api_bone(StructRNA *srna);
 void RNA_api_camera(StructRNA *srna);
 void RNA_api_curve(StructRNA *srna);
+void RNA_api_curve_nurb(StructRNA *srna);
 void RNA_api_fcurves(StructRNA *srna);
 void RNA_api_drivers(StructRNA *srna);
 void RNA_api_image_packed_file(struct StructRNA *srna);