Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2012-12-22 22:25:01 +0400
committerTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2012-12-22 22:25:01 +0400
commitfa0211df269a3398dd70467982f9e129c79e501b (patch)
tree404ee267890602b49470cb640986b50d2c2055c1 /source/blender/freestyle/intern/geometry/FitCurve.cpp
parent8b57a67f3eb57366c2b3abcb8f3b04403d339e1a (diff)
Another "insanely" big code clean-up patch by Bastien Montagne, many thanks!
Diffstat (limited to 'source/blender/freestyle/intern/geometry/FitCurve.cpp')
-rw-r--r--source/blender/freestyle/intern/geometry/FitCurve.cpp763
1 files changed, 381 insertions, 382 deletions
diff --git a/source/blender/freestyle/intern/geometry/FitCurve.cpp b/source/blender/freestyle/intern/geometry/FitCurve.cpp
index f71af130d7f..4eae543c9f9 100644
--- a/source/blender/freestyle/intern/geometry/FitCurve.cpp
+++ b/source/blender/freestyle/intern/geometry/FitCurve.cpp
@@ -1,33 +1,49 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
-//
-// Copyright (C) : Please refer to the COPYRIGHT file distributed
-// with this source distribution.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-//
-///////////////////////////////////////////////////////////////////////////////
+/** \file blender/freestyle/intern/geometry/FitCurve.cpp
+ * \ingroup freestyle
+ * \brief An Algorithm for Automatically Fitting Digitized Curves by Philip J. Schneider,
+ * \brief from "Graphics Gems", Academic Press, 1990
+ * \author Stephane Grabli
+ * \date 06/06/2003
+ */
#include <cstdlib> // for malloc and free
#include <stdio.h>
#include <math.h>
+
#include "FitCurve.h"
using namespace std;
typedef Vector2 *BezierCurve;
+// XXX Do we need "#ifdef __cplusplus" at all here???
#ifdef __cplusplus
extern "C"
{
@@ -46,379 +62,367 @@ static Vector2 ComputeLeftTangent(Vector2 *d, int end);
static Vector2 ComputeLeftTangent(Vector2 *d, int end);
static double ComputeMaxError(Vector2 *d, int first, int last, BezierCurve bezCurve, double *u, int *splitPoint);
static double *ChordLengthParameterize(Vector2 *d, int first, int last);
-static BezierCurve GenerateBezier(Vector2 *d, int first, int last, double *uPrime, Vector2 tHat1, Vector2 tHat2);
+static BezierCurve GenerateBezier(Vector2 *d, int first, int last, double *uPrime, Vector2 tHat1, Vector2 tHat2);
static Vector2 V2AddII(Vector2 a, Vector2 b);
static Vector2 V2ScaleIII(Vector2 v, double s);
static Vector2 V2SubII(Vector2 a, Vector2 b);
+#define MAXPOINTS 1000 /* The most points you can have */
-#define MAXPOINTS 1000 /* The most points you can have */
-
-/* returns squared length of input vector */
-static double V2SquaredLength(Vector2 *a)
-{ return(((*a)[0] * (*a)[0])+((*a)[1] * (*a)[1]));
+/* returns squared length of input vector */
+static double V2SquaredLength(Vector2 *a)
+{
+ return (((*a)[0] * (*a)[0]) + ((*a)[1] * (*a)[1]));
}
-
+
/* returns length of input vector */
static double V2Length(Vector2 *a)
{
- return(sqrt(V2SquaredLength(a)));
+ return (sqrt(V2SquaredLength(a)));
}
-static Vector2 *V2Scale(Vector2 *v, double newlen)
+static Vector2 *V2Scale(Vector2 *v, double newlen)
{
- double len = V2Length(v);
- if (len != 0.0) { (*v)[0] *= newlen/len; (*v)[1] *= newlen/len; }
- return(v);
+ double len = V2Length(v);
+ if (len != 0.0) {
+ (*v)[0] *= newlen / len;
+ (*v)[1] *= newlen / len;
+ }
+ return v;
}
/* return the dot product of vectors a and b */
-static double V2Dot(Vector2 *a, Vector2 *b)
+static double V2Dot(Vector2 *a, Vector2 *b)
{
- return(((*a)[0]*(*b)[0])+((*a)[1]*(*b)[1]));
+ return (((*a)[0] * (*b)[0]) + ((*a)[1] * (*b)[1]));
}
/* return the distance between two points */
static double V2DistanceBetween2Points(Vector2 *a, Vector2 *b)
{
-double dx = (*a)[0] - (*b)[0];
-double dy = (*a)[1] - (*b)[1];
- return(sqrt((dx*dx)+(dy*dy)));
+ double dx = (*a)[0] - (*b)[0];
+ double dy = (*a)[1] - (*b)[1];
+ return (sqrt((dx * dx) + (dy * dy)));
}
/* return vector sum c = a+b */
static Vector2 *V2Add(Vector2 *a, Vector2 *b, Vector2 *c)
{
- (*c)[0] = (*a)[0]+(*b)[0]; (*c)[1] = (*a)[1]+(*b)[1];
- return(c);
+ (*c)[0] = (*a)[0] + (*b)[0];
+ (*c)[1] = (*a)[1] + (*b)[1];
+ return c;
}
/* normalizes the input vector and returns it */
-static Vector2 *V2Normalize(Vector2 *v)
+static Vector2 *V2Normalize(Vector2 *v)
{
-double len = V2Length(v);
- if (len != 0.0) { (*v)[0] /= len; (*v)[1] /= len; }
- return(v);
+ double len = V2Length(v);
+ if (len != 0.0) {
+ (*v)[0] /= len;
+ (*v)[1] /= len;
+ }
+ return v;
}
/* negates the input vector and returns it */
-static Vector2 *V2Negate(Vector2 *v)
+static Vector2 *V2Negate(Vector2 *v)
{
- (*v)[0] = -(*v)[0]; (*v)[1] = -(*v)[1];
- return(v);
+ (*v)[0] = -(*v)[0];
+ (*v)[1] = -(*v)[1];
+ return v;
}
-
-/*
- * GenerateBezier :
+/* GenerateBezier:
* Use least-squares method to find Bezier control points for region.
- *
+ * Vector2 *d; Array of digitized points
+ * int first, last; Indices defining region
+ * double *uPrime; Parameter values for region
+ * Vector2 tHat1, tHat2; Unit tangents at endpoints
*/
static BezierCurve GenerateBezier(Vector2 *d, int first, int last, double *uPrime, Vector2 tHat1, Vector2 tHat2)
-// Vector2 *d; /* Array of digitized points */
-// int first, last; /* Indices defining region */
-// double *uPrime; /* Parameter values for region */
-// Vector2 tHat1, tHat2; /* Unit tangents at endpoints */
{
- int i;
- Vector2 A[MAXPOINTS][2]; /* Precomputed rhs for eqn */
- int nPts; /* Number of pts in sub-curve */
- double C[2][2]; /* Matrix C */
- double X[2]; /* Matrix X */
- double det_C0_C1, /* Determinants of matrices */
- det_C0_X,
- det_X_C1;
- double alpha_l, /* Alpha values, left and right */
- alpha_r;
- Vector2 tmp; /* Utility variable */
- BezierCurve bezCurve; /* RETURN bezier curve ctl pts */
-
- bezCurve = (Vector2 *)malloc(4 * sizeof(Vector2));
- nPts = last - first + 1;
-
-
- /* Compute the A's */
- for (i = 0; i < nPts; i++) {
- Vector2 v1, v2;
+ int i;
+ Vector2 A[MAXPOINTS][2]; /* Precomputed rhs for eqn */
+ int nPts; /* Number of pts in sub-curve */
+ double C[2][2]; /* Matrix C */
+ double X[2]; /* Matrix X */
+ double det_C0_C1; /* Determinants of matrices */
+ double det_C0_X;
+ double det_X_C1;
+ double alpha_l; /* Alpha values, left and right */
+ double alpha_r;
+ Vector2 tmp; /* Utility variable */
+ BezierCurve bezCurve; /* RETURN bezier curve ctl pts */
+
+ bezCurve = (Vector2*)malloc(4 * sizeof(Vector2));
+ nPts = last - first + 1;
+
+ /* Compute the A's */
+ for (i = 0; i < nPts; i++) {
+ Vector2 v1, v2;
v1 = tHat1;
v2 = tHat2;
V2Scale(&v1, B1(uPrime[i]));
V2Scale(&v2, B2(uPrime[i]));
A[i][0] = v1;
A[i][1] = v2;
- }
-
- /* Create the C and X matrices */
- C[0][0] = 0.0;
- C[0][1] = 0.0;
- C[1][0] = 0.0;
- C[1][1] = 0.0;
- X[0] = 0.0;
- X[1] = 0.0;
-
- for (i = 0; i < nPts; i++) {
- C[0][0] += V2Dot(&A[i][0], &A[i][0]);
+ }
+
+ /* Create the C and X matrices */
+ C[0][0] = 0.0;
+ C[0][1] = 0.0;
+ C[1][0] = 0.0;
+ C[1][1] = 0.0;
+ X[0] = 0.0;
+ X[1] = 0.0;
+ for (i = 0; i < nPts; i++) {
+ C[0][0] += V2Dot(&A[i][0], &A[i][0]);
C[0][1] += V2Dot(&A[i][0], &A[i][1]);
-/* C[1][0] += V2Dot(&A[i][0], &A[i][1]);*/
+// C[1][0] += V2Dot(&A[i][0], &A[i][1]);
C[1][0] = C[0][1];
C[1][1] += V2Dot(&A[i][1], &A[i][1]);
tmp = V2SubII(d[first + i],
- V2AddII(
- V2ScaleIII(d[first], B0(uPrime[i])),
- V2AddII(
- V2ScaleIII(d[first], B1(uPrime[i])),
- V2AddII(
- V2ScaleIII(d[last], B2(uPrime[i])),
- V2ScaleIII(d[last], B3(uPrime[i]))))));
-
-
- X[0] += V2Dot(&((A[i])[0]), &tmp);
- X[1] += V2Dot(&((A[i])[1]), &tmp);
- }
-
- /* Compute the determinants of C and X */
- det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1];
- det_C0_X = C[0][0] * X[1] - C[0][1] * X[0];
- det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1];
-
- /* Finally, derive alpha values */
- if (det_C0_C1 == 0.0) {
- det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12;
- }
- alpha_l = det_X_C1 / det_C0_C1;
- alpha_r = det_C0_X / det_C0_C1;
-
-
- /* If alpha negative, use the Wu/Barsky heuristic (see text) */
- /* (if alpha is 0, you get coincident control points that lead to
- * divide by zero in any subsequent NewtonRaphsonRootFind() call. */
- if (alpha_l < 1.0e-6 || alpha_r < 1.0e-6) {
- double dist = V2DistanceBetween2Points(&d[last], &d[first]) /
- 3.0;
+ V2AddII(V2ScaleIII(d[first], B0(uPrime[i])),
+ V2AddII(V2ScaleIII(d[first], B1(uPrime[i])),
+ V2AddII(V2ScaleIII(d[last], B2(uPrime[i])),
+ V2ScaleIII(d[last], B3(uPrime[i]))
+ )
+ )
+ )
+ );
+
+ X[0] += V2Dot(&((A[i])[0]), &tmp);
+ X[1] += V2Dot(&((A[i])[1]), &tmp);
+ }
+
+ /* Compute the determinants of C and X */
+ det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1];
+ det_C0_X = C[0][0] * X[1] - C[0][1] * X[0];
+ det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1];
+
+ /* Finally, derive alpha values */
+ if (det_C0_C1 == 0.0) {
+ det_C0_C1 = (C[0][0] * C[1][1]) * 10.0e-12;
+ }
+ alpha_l = det_X_C1 / det_C0_C1;
+ alpha_r = det_C0_X / det_C0_C1;
+
+
+ /* If alpha negative, use the Wu/Barsky heuristic (see text) (if alpha is 0, you get coincident control points
+ * that lead to divide by zero in any subsequent NewtonRaphsonRootFind() call).
+ */
+ if (alpha_l < 1.0e-6 || alpha_r < 1.0e-6) {
+ double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0;
bezCurve[0] = d[first];
bezCurve[3] = d[last];
V2Add(&(bezCurve[0]), V2Scale(&(tHat1), dist), &(bezCurve[1]));
V2Add(&(bezCurve[3]), V2Scale(&(tHat2), dist), &(bezCurve[2]));
- return (bezCurve);
- }
-
- /* First and last control points of the Bezier curve are */
- /* positioned exactly at the first and last data points */
- /* Control points 1 and 2 are positioned an alpha distance out */
- /* on the tangent vectors, left and right, respectively */
- bezCurve[0] = d[first];
- bezCurve[3] = d[last];
- V2Add(&bezCurve[0], V2Scale(&tHat1, alpha_l), &bezCurve[1]);
- V2Add(&bezCurve[3], V2Scale(&tHat2, alpha_r), &bezCurve[2]);
- return (bezCurve);
-}
+ return bezCurve;
+ }
+ /* First and last control points of the Bezier curve are positioned exactly at the first and last data points
+ * Control points 1 and 2 are positioned an alpha distance out on the tangent vectors, left and right, respectively
+ */
+ bezCurve[0] = d[first];
+ bezCurve[3] = d[last];
+ V2Add(&bezCurve[0], V2Scale(&tHat1, alpha_l), &bezCurve[1]);
+ V2Add(&bezCurve[3], V2Scale(&tHat2, alpha_r), &bezCurve[2]);
+ return (bezCurve);
+}
/*
* Reparameterize:
- * Given set of points and their parameterization, try to find
- * a better parameterization.
- *
+ * Given set of points and their parameterization, try to find a better parameterization.
+ * Vector2 *d; Array of digitized points
+ * int first, last; Indices defining region
+ * double *u; Current parameter values
+ * BezierCurve bezCurve; Current fitted curve
*/
static double *Reparameterize(Vector2 *d, int first, int last, double *u, BezierCurve bezCurve)
-// Vector2 *d; /* Array of digitized points */
-// int first, last; /* Indices defining region */
-// double *u; /* Current parameter values */
-// BezierCurve bezCurve; /* Current fitted curve */
{
- int nPts = last-first+1;
- int i;
- double *uPrime; /* New parameter values */
-
- uPrime = (double *)malloc(nPts * sizeof(double));
- for (i = first; i <= last; i++) {
- uPrime[i-first] = NewtonRaphsonRootFind(bezCurve, d[i], u[i-
- first]);
- }
- return (uPrime);
-}
-
+ int nPts = last - first + 1;
+ int i;
+ double *uPrime; /* New parameter values */
+ uPrime = (double*)malloc(nPts * sizeof(double));
+ for (i = first; i <= last; i++) {
+ uPrime[i-first] = NewtonRaphsonRootFind(bezCurve, d[i], u[i - first]);
+ }
+ return (uPrime);
+}
/*
- * NewtonRaphsonRootFind :
- * Use Newton-Raphson iteration to find better root.
+ * NewtonRaphsonRootFind:
+ * Use Newton-Raphson iteration to find better root.
+ * BezierCurve Q; Current fitted curve
+ * Vector2 P; Digitized point
+ * double u; Parameter value for "P"
*/
static double NewtonRaphsonRootFind(BezierCurve Q, Vector2 P, double u)
-// BezierCurve Q; /* Current fitted curve */
-// Vector2 P; /* Digitized point */
-// double u; /* Parameter value for "P" */
{
- double numerator, denominator;
- Vector2 Q1[3], Q2[2]; /* Q' and Q'' */
- Vector2 Q_u, Q1_u, Q2_u; /*u evaluated at Q, Q', & Q'' */
- double uPrime; /* Improved u */
- int i;
-
- /* Compute Q(u) */
- Q_u = BezierII(3, Q, u);
-
- /* Generate control vertices for Q' */
- for (i = 0; i <= 2; i++) {
- Q1[i][0] = (Q[i+1][0] - Q[i][0]) * 3.0;
- Q1[i][1] = (Q[i+1][1] - Q[i][1]) * 3.0;
- }
-
- /* Generate control vertices for Q'' */
- for (i = 0; i <= 1; i++) {
- Q2[i][0] = (Q1[i+1][0] - Q1[i][0]) * 2.0;
- Q2[i][1] = (Q1[i+1][1] - Q1[i][1]) * 2.0;
- }
-
- /* Compute Q'(u) and Q''(u) */
- Q1_u = BezierII(2, Q1, u);
- Q2_u = BezierII(1, Q2, u);
-
- /* Compute f(u)/f'(u) */
- numerator = (Q_u[0] - P[0]) * (Q1_u[0]) + (Q_u[1] - P[1]) * (Q1_u[1]);
- denominator = (Q1_u[0]) * (Q1_u[0]) + (Q1_u[1]) * (Q1_u[1]) +
- (Q_u[0] - P[0]) * (Q2_u[0]) + (Q_u[1] - P[1]) * (Q2_u[1]);
-
- /* u = u - f(u)/f'(u) */
- if(denominator == 0) // FIXME
- return u;
- uPrime = u - (numerator/denominator);
- return (uPrime);
+ double numerator, denominator;
+ Vector2 Q1[3], Q2[2]; /* Q' and Q'' */
+ Vector2 Q_u, Q1_u, Q2_u; /* u evaluated at Q, Q', & Q'' */
+ double uPrime; /* Improved u */
+ int i;
+
+ /* Compute Q(u) */
+ Q_u = BezierII(3, Q, u);
+
+ /* Generate control vertices for Q' */
+ for (i = 0; i <= 2; i++) {
+ Q1[i][0] = (Q[i + 1][0] - Q[i][0]) * 3.0;
+ Q1[i][1] = (Q[i + 1][1] - Q[i][1]) * 3.0;
+ }
+
+ /* Generate control vertices for Q'' */
+ for (i = 0; i <= 1; i++) {
+ Q2[i][0] = (Q1[i + 1][0] - Q1[i][0]) * 2.0;
+ Q2[i][1] = (Q1[i + 1][1] - Q1[i][1]) * 2.0;
+ }
+
+ /* Compute Q'(u) and Q''(u) */
+ Q1_u = BezierII(2, Q1, u);
+ Q2_u = BezierII(1, Q2, u);
+
+ /* Compute f(u)/f'(u) */
+ numerator = (Q_u[0] - P[0]) * (Q1_u[0]) + (Q_u[1] - P[1]) * (Q1_u[1]);
+ denominator = (Q1_u[0]) * (Q1_u[0]) + (Q1_u[1]) * (Q1_u[1]) +
+ (Q_u[0] - P[0]) * (Q2_u[0]) + (Q_u[1] - P[1]) * (Q2_u[1]);
+
+ /* u = u - f(u)/f'(u) */
+ if (denominator == 0) // FIXME
+ return u;
+ uPrime = u - (numerator / denominator);
+ return uPrime;
}
-
-
/*
- * Bezier :
- * Evaluate a Bezier curve at a particular parameter value
- *
+ * Bezier:
+ * Evaluate a Bezier curve at a particular parameter value
+ * int degree; The degree of the bezier curve
+ * Vector2 *V; Array of control points
+ * double t; Parametric value to find point for
*/
static Vector2 BezierII(int degree, Vector2 *V, double t)
-// int degree; /* The degree of the bezier curve */
-// Vector2 *V; /* Array of control points */
-// double t; /* Parametric value to find point for */
{
- int i, j;
- Vector2 Q; /* Point on curve at parameter t */
- Vector2 *Vtemp; /* Local copy of control points */
-
- /* Copy array */
- Vtemp = (Vector2 *)malloc((unsigned)((degree+1)
- * sizeof (Vector2)));
- for (i = 0; i <= degree; i++) {
+ int i, j;
+ Vector2 Q; /* Point on curve at parameter t */
+ Vector2 *Vtemp; /* Local copy of control points */
+
+ /* Copy array */
+ Vtemp = (Vector2*)malloc((unsigned)((degree + 1) * sizeof (Vector2)));
+ for (i = 0; i <= degree; i++) {
Vtemp[i] = V[i];
- }
+ }
- /* Triangle computation */
- for (i = 1; i <= degree; i++) {
+ /* Triangle computation */
+ for (i = 1; i <= degree; i++) {
for (j = 0; j <= degree-i; j++) {
- Vtemp[j][0] = (1.0 - t) * Vtemp[j][0] + t * Vtemp[j+1][0];
- Vtemp[j][1] = (1.0 - t) * Vtemp[j][1] + t * Vtemp[j+1][1];
+ Vtemp[j][0] = (1.0 - t) * Vtemp[j][0] + t * Vtemp[j + 1][0];
+ Vtemp[j][1] = (1.0 - t) * Vtemp[j][1] + t * Vtemp[j + 1][1];
}
- }
+ }
- Q = Vtemp[0];
- free((void *)Vtemp);
- return Q;
+ Q = Vtemp[0];
+ free((void*)Vtemp);
+ return Q;
}
-
/*
- * B0, B1, B2, B3 :
- * Bezier multipliers
+ * B0, B1, B2, B3:
+ * Bezier multipliers
*/
static double B0(double u)
{
- double tmp = 1.0 - u;
- return (tmp * tmp * tmp);
+ double tmp = 1.0 - u;
+ return (tmp * tmp * tmp);
}
static double B1(double u)
{
- double tmp = 1.0 - u;
- return (3 * u * (tmp * tmp));
+ double tmp = 1.0 - u;
+ return (3 * u * (tmp * tmp));
}
static double B2(double u)
{
- double tmp = 1.0 - u;
- return (3 * u * u * tmp);
+ double tmp = 1.0 - u;
+ return (3 * u * u * tmp);
}
static double B3(double u)
{
- return (u * u * u);
+ return (u * u * u);
}
-
-
/*
- * ComputeLeftTangent, ComputeRightTangent, ComputeCenterTangent :
- *Approximate unit tangents at endpoints and "center" of digitized curve
+ * ComputeLeftTangent, ComputeRightTangent, ComputeCenterTangent:
+ * Approximate unit tangents at endpoints and "center" of digitized curve
+ */
+/* Vector2 *d; Digitized points
+ * int end; Index to "left" end of region
*/
static Vector2 ComputeLeftTangent(Vector2 *d, int end)
-// Vector2 *d; /* Digitized points*/
-// int end; /* Index to "left" end of region */
{
- Vector2 tHat1;
- tHat1 = V2SubII(d[end+1], d[end]);
- tHat1 = *V2Normalize(&tHat1);
- return tHat1;
+ Vector2 tHat1;
+ tHat1 = V2SubII(d[end + 1], d[end]);
+ tHat1 = *V2Normalize(&tHat1);
+ return tHat1;
}
+/* Vector2 *d; Digitized points
+ * int end; Index to "right" end of region
+ */
static Vector2 ComputeRightTangent(Vector2 *d, int end)
-// Vector2 *d; /* Digitized points */
-// int end; /* Index to "right" end of region */
{
- Vector2 tHat2;
- tHat2 = V2SubII(d[end-1], d[end]);
- tHat2 = *V2Normalize(&tHat2);
- return tHat2;
+ Vector2 tHat2;
+ tHat2 = V2SubII(d[end - 1], d[end]);
+ tHat2 = *V2Normalize(&tHat2);
+ return tHat2;
}
+/* Vector2 *d; Digitized points
+ * int end; Index to point inside region
+ */
static Vector2 ComputeCenterTangent(Vector2 *d, int center)
-// Vector2 *d; /* Digitized points */
-// int center; /* Index to point inside region */
{
- Vector2 V1, V2, tHatCenter;
-
- V1 = V2SubII(d[center-1], d[center]);
- V2 = V2SubII(d[center], d[center+1]);
- tHatCenter[0] = (V1[0] + V2[0])/2.0;
- tHatCenter[1] = (V1[1] + V2[1])/2.0;
- tHatCenter = *V2Normalize(&tHatCenter);
- return tHatCenter;
+ Vector2 V1, V2, tHatCenter;
+
+ V1 = V2SubII(d[center - 1], d[center]);
+ V2 = V2SubII(d[center], d[center + 1]);
+ tHatCenter[0] = (V1[0] + V2[0]) / 2.0;
+ tHatCenter[1] = (V1[1] + V2[1]) / 2.0;
+ tHatCenter = *V2Normalize(&tHatCenter);
+ return tHatCenter;
}
-
/*
- * ChordLengthParameterize :
- * Assign parameter values to digitized points
- * using relative distances between points.
+ * ChordLengthParameterize:
+ * Assign parameter values to digitized points using relative distances between points.
+ * Vector2 *d; Array of digitized points
+ * int first, last; Indices defining region
*/
static double *ChordLengthParameterize(Vector2 *d, int first, int last)
-// Vector2 *d; /* Array of digitized points */
-// int first, last; /* Indices defining region */
{
- int i;
- double *u; /* Parameterization */
+ int i;
+ double *u; /* Parameterization */
- u = (double *)malloc((unsigned)(last-first+1) * sizeof(double));
+ u = (double*)malloc((unsigned)(last - first + 1) * sizeof(double));
- u[0] = 0.0;
- for (i = first+1; i <= last; i++) {
- u[i-first] = u[i-first-1] +
- V2DistanceBetween2Points(&d[i], &d[i-1]);
- }
+ u[0] = 0.0;
+ for (i = first + 1; i <= last; i++) {
+ u[i - first] = u[i - first - 1] + V2DistanceBetween2Points(&d[i], &d[i - 1]);
+ }
- for (i = first + 1; i <= last; i++) {
- u[i-first] = u[i-first] / u[last-first];
- }
+ for (i = first + 1; i <= last; i++) {
+ u[i - first] = u[i - first] / u[last - first];
+ }
- return(u);
+ return u;
}
@@ -426,53 +430,57 @@ static double *ChordLengthParameterize(Vector2 *d, int first, int last)
/*
* ComputeMaxError :
- * Find the maximum squared distance of digitized points
- * to fitted curve.
-*/
+ * Find the maximum squared distance of digitized points to fitted curve.
+ * Vector2 *d; Array of digitized points
+ * int first, last; Indices defining region
+ * BezierCurve bezCurve; Fitted Bezier curve
+ * double *u; Parameterization of points
+ * int *splitPoint; Point of maximum error
+ */
static double ComputeMaxError(Vector2 *d, int first, int last, BezierCurve bezCurve, double *u, int *splitPoint)
-// Vector2 *d; /* Array of digitized points */
-// int first, last; /* Indices defining region */
-// BezierCurve bezCurve; /* Fitted Bezier curve */
-// double *u; /* Parameterization of points */
-// int *splitPoint; /* Point of maximum error */
{
- int i;
- double maxDist; /* Maximum error */
- double dist; /* Current error */
- Vector2 P; /* Point on curve */
- Vector2 v; /* Vector from point to curve */
-
- *splitPoint = (last - first + 1)/2;
- maxDist = 0.0;
- for (i = first + 1; i < last; i++) {
- P = BezierII(3, bezCurve, u[i-first]);
+ int i;
+ double maxDist; /* Maximum error */
+ double dist; /* Current error */
+ Vector2 P; /* Point on curve */
+ Vector2 v; /* Vector from point to curve */
+
+ *splitPoint = (last - first + 1) / 2;
+ maxDist = 0.0;
+ for (i = first + 1; i < last; i++) {
+ P = BezierII(3, bezCurve, u[i - first]);
v = V2SubII(P, d[i]);
dist = V2SquaredLength(&v);
if (dist >= maxDist) {
- maxDist = dist;
- *splitPoint = i;
+ maxDist = dist;
+ *splitPoint = i;
}
- }
- return (maxDist);
+ }
+ return maxDist;
}
+
static Vector2 V2AddII(Vector2 a, Vector2 b)
{
- Vector2 c;
- c[0] = a[0] + b[0]; c[1] = a[1] + b[1];
- return (c);
+ Vector2 c;
+ c[0] = a[0] + b[0];
+ c[1] = a[1] + b[1];
+ return c;
}
+
static Vector2 V2ScaleIII(Vector2 v, double s)
{
- Vector2 result;
- result[0] = v[0] * s; result[1] = v[1] * s;
- return (result);
+ Vector2 result;
+ result[0] = v[0] * s;
+ result[1] = v[1] * s;
+ return result;
}
static Vector2 V2SubII(Vector2 a, Vector2 b)
{
- Vector2 c;
- c[0] = a[0] - b[0]; c[1] = a[1] - b[1];
- return (c);
+ Vector2 c;
+ c[0] = a[0] - b[0];
+ c[1] = a[1] - b[1];
+ return c;
}
#ifdef __cplusplus
@@ -488,116 +496,107 @@ FitCurveWrapper::FitCurveWrapper()
FitCurveWrapper::~FitCurveWrapper()
{
- _vertices.clear();
+ _vertices.clear();
}
-void FitCurveWrapper::DrawBezierCurve(int n, Vector2 *curve )
+void FitCurveWrapper::DrawBezierCurve(int n, Vector2 *curve)
{
- for(int i=0; i<n+1; ++i)
- _vertices.push_back(curve[i]);
+ for (int i = 0; i < n + 1; ++i)
+ _vertices.push_back(curve[i]);
}
void FitCurveWrapper::FitCurve(vector<Vec2d>& data, vector<Vec2d>& oCurve, double error)
{
- int size = data.size();
- Vector2 *d = new Vector2[size];
- for(int i=0; i<size; ++i)
- {
- d[i][0] = data[i][0];
- d[i][1] = data[i][1];
- }
-
- FitCurve(d,size,error);
-
- // copy results
- for(vector<Vector2>::iterator v=_vertices.begin(), vend=_vertices.end();
- v!=vend;
- ++v)
- {
- oCurve.push_back(Vec2d(v->x(), v->y())) ;
- }
-
+ int size = data.size();
+ Vector2 *d = new Vector2[size];
+ for (int i = 0; i < size; ++i) {
+ d[i][0] = data[i][0];
+ d[i][1] = data[i][1];
+ }
+
+ FitCurve(d, size, error);
+
+ // copy results
+ for (vector<Vector2>::iterator v = _vertices.begin(), vend = _vertices.end(); v != vend; ++v) {
+ oCurve.push_back(Vec2d(v->x(), v->y())) ;
+ }
}
void FitCurveWrapper::FitCurve(Vector2 *d, int nPts, double error)
{
- Vector2 tHat1, tHat2; /* Unit tangent vectors at endpoints */
+ Vector2 tHat1, tHat2; /* Unit tangent vectors at endpoints */
- tHat1 = ComputeLeftTangent(d, 0);
- tHat2 = ComputeRightTangent(d, nPts - 1);
- FitCubic(d, 0, nPts - 1, tHat1, tHat2, error);
+ tHat1 = ComputeLeftTangent(d, 0);
+ tHat2 = ComputeRightTangent(d, nPts - 1);
+ FitCubic(d, 0, nPts - 1, tHat1, tHat2, error);
}
void FitCurveWrapper::FitCubic(Vector2 *d, int first, int last, Vector2 tHat1, Vector2 tHat2, double error)
{
- BezierCurve bezCurve; /*Control points of fitted Bezier curve*/
- double *u; /* Parameter values for point */
- double *uPrime; /* Improved parameter values */
- double maxError; /* Maximum fitting error */
- int splitPoint; /* Point to split point set at */
- int nPts; /* Number of points in subset */
- double iterationError; /*Error below which you try iterating */
- int maxIterations = 4; /* Max times to try iterating */
- Vector2 tHatCenter; /* Unit tangent vector at splitPoint */
- int i;
-
- iterationError = error * error;
- nPts = last - first + 1;
-
- /* Use heuristic if region only has two points in it */
- if (nPts == 2) {
- double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0;
-
- bezCurve = (Vector2 *)malloc(4 * sizeof(Vector2));
+ BezierCurve bezCurve; /* Control points of fitted Bezier curve */
+ double *u; /* Parameter values for point */
+ double *uPrime; /* Improved parameter values */
+ double maxError; /* Maximum fitting error */
+ int splitPoint; /* Point to split point set at */
+ int nPts; /* Number of points in subset */
+ double iterationError; /* Error below which you try iterating */
+ int maxIterations = 4; /* Max times to try iterating */
+ Vector2 tHatCenter; /* Unit tangent vector at splitPoint */
+ int i;
+
+ iterationError = error * error;
+ nPts = last - first + 1;
+
+ /* Use heuristic if region only has two points in it */
+ if (nPts == 2) {
+ double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0;
+
+ bezCurve = (Vector2*)malloc(4 * sizeof(Vector2));
bezCurve[0] = d[first];
bezCurve[3] = d[last];
V2Add(&bezCurve[0], V2Scale(&tHat1, dist), &bezCurve[1]);
V2Add(&bezCurve[3], V2Scale(&tHat2, dist), &bezCurve[2]);
DrawBezierCurve(3, bezCurve);
- free((void *)bezCurve);
+ free((void*)bezCurve);
return;
- }
+ }
- /* Parameterize points, and attempt to fit curve */
- u = ChordLengthParameterize(d, first, last);
- bezCurve = GenerateBezier(d, first, last, u, tHat1, tHat2);
+ /* Parameterize points, and attempt to fit curve */
+ u = ChordLengthParameterize(d, first, last);
+ bezCurve = GenerateBezier(d, first, last, u, tHat1, tHat2);
- /* Find max deviation of points to fitted curve */
- maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint);
- if (maxError < error) {
+ /* Find max deviation of points to fitted curve */
+ maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint);
+ if (maxError < error) {
DrawBezierCurve(3, bezCurve);
- free((void *)u);
- free((void *)bezCurve);
+ free((void*)u);
+ free((void*)bezCurve);
return;
- }
-
+ }
- /* If error not too large, try some reparameterization */
- /* and iteration */
- if (maxError < iterationError) {
+ /* If error not too large, try some reparameterization and iteration */
+ if (maxError < iterationError) {
for (i = 0; i < maxIterations; i++) {
- uPrime = Reparameterize(d, first, last, u, bezCurve);
- bezCurve = GenerateBezier(d, first, last, uPrime, tHat1, tHat2);
- maxError = ComputeMaxError(d, first, last,
- bezCurve, uPrime, &splitPoint);
- if (maxError < error) {
- DrawBezierCurve(3, bezCurve);
- free((void *)u);
- free((void *)bezCurve);
- return;
- }
- free((void *)u);
- u = uPrime;
+ uPrime = Reparameterize(d, first, last, u, bezCurve);
+ bezCurve = GenerateBezier(d, first, last, uPrime, tHat1, tHat2);
+ maxError = ComputeMaxError(d, first, last,
+ bezCurve, uPrime, &splitPoint);
+ if (maxError < error) {
+ DrawBezierCurve(3, bezCurve);
+ free((void*)u);
+ free((void*)bezCurve);
+ return;
+ }
+ free((void*)u);
+ u = uPrime;
+ }
}
- }
-
- /* Fitting failed -- split at max error point and fit recursively */
- free((void *)u);
- free((void *)bezCurve);
- tHatCenter = ComputeCenterTangent(d, splitPoint);
- FitCubic(d, first, splitPoint, tHat1, tHatCenter, error);
- V2Negate(&tHatCenter);
- FitCubic(d, splitPoint, last, tHatCenter, tHat2, error);
+ /* Fitting failed -- split at max error point and fit recursively */
+ free((void*)u);
+ free((void*)bezCurve);
+ tHatCenter = ComputeCenterTangent(d, splitPoint);
+ FitCubic(d, first, splitPoint, tHat1, tHatCenter, error);
+ V2Negate(&tHatCenter);
+ FitCubic(d, splitPoint, last, tHatCenter, tHat2, error);
}
-