/// <summary> /// 指定された頂点列の指定範囲にベジェ曲線をフィットさせる /// </summary> /// <param name="d">フィット元頂点列</param> /// <param name="first"><see cref="d"/>内の範囲開始インデックス</param> /// <param name="last"><see cref="d"/>内の範囲終了インデックス</param> /// <param name="tHat1">指定範囲開始点の長さ1の順方向ベクトル</param> /// <param name="tHat2">指定範囲終了点の長さ1の逆方向ベクトル</param> /// <param name="error">フィット時許容誤差の二乗</param> /// <param name="result">ここにベジェ曲線列が追加される</param> static void FitCubic(vector[] d, int first, int last, vector tHat1, vector tHat2, element error, List <cubicbezier> result) { cubicbezier bezCurve; /*Control points of fitted Bezier curve*/ var nPts = last - first + 1; /* Number of points in subset */ /* Use heuristic if region only has two points in it */ if (nPts == 2) { bezCurve = new cubicbezier(); bezCurve.P0 = d[first]; bezCurve.P3 = d[last]; var dist = (d[last] - d[first]).Length / 3; bezCurve.P1 = bezCurve.P0 + tHat1.Relength(dist); bezCurve.P2 = bezCurve.P3 + tHat2.Relength(dist); result.Add(bezCurve); return; } /* Parameterize points, and attempt to fit curve */ var u = ChordLengthParameterize(d, first, last); bezCurve = GenerateBezier(d, first, last, u, tHat1, tHat2); /* Find max deviation of points to fitted curve */ int splitPoint; /* Point to split point set at */ var maxError = ComputeMaxError(d, first, last, bezCurve, u, out splitPoint); if (maxError < error) { result.Add(bezCurve); return; } /* If error not too large, try some reparameterization */ /* and iteration */ var iterationError = error * error; /*Error below which you try iterating */ if (maxError < iterationError) { var maxIterations = 4; /* Max times to try iterating */ for (var i = 0; i < maxIterations; i++) { var uPrime = Reparameterize(d, first, last, u, bezCurve); bezCurve = GenerateBezier(d, first, last, uPrime, tHat1, tHat2); maxError = ComputeMaxError(d, first, last, bezCurve, uPrime, out splitPoint); if (maxError < error) { result.Add(bezCurve); return; } u = uPrime; } } /* Fitting failed -- split at max error point and fit recursively */ var tHatCenter = ((d[splitPoint - 1] - d[splitPoint + 1]) * (element)0.5).Normalize(); FitCubic(d, first, splitPoint, tHat1, tHatCenter, error, result); tHatCenter = -tHatCenter; FitCubic(d, splitPoint, last, tHatCenter, tHat2, error, result); }