using System;
using System.Linq;
namespace Bezier
{
/// <summary>
/// 計算されたベジェ曲線の座標データを保持するクラス
/// 点ベースと軸ベース、両方のアクセス方法を提供します。
/// </summary>
public class BezierCurveResult
{
/// <summary>
/// 点ベースの座標配列。
/// Points[点のインデックス][次元のインデックス]
/// (例: 3番目の点の座標配列全体が欲しい場合は Points[3])
/// </summary>
public double[][] Points { get; }
/// <summary>
/// 軸ベースの座標配列。
/// Axes[次元のインデックス][点のインデックス]
/// (例: X軸のすべての点の座標配列が欲しい場合は Axes[0])
/// </summary>
public double[][] Axes { get; }
public BezierCurveResult(int pointCount, int dimension)
{
// 点ベースのジャグ配列を初期化
Points = new double[pointCount][];
for (int i = 0; i < pointCount; i++)
{
Points[i] = new double[dimension];
}
// 軸ベースのジャグ配列を初期化
Axes = new double[dimension][];
for (int d = 0; d < dimension; d++)
{
Axes[d] = new double[pointCount];
}
}
}
/// <summary>
/// n次元に対応した3次ベジェ曲線クラス
/// </summary>
public class BezierCurve
{
public double[] Anchor1 { get; set; }
public double[] Handle1 { get; set; }
public double[] Handle2 { get; set; }
public double[] Anchor2 { get; set; }
public int Dimension
{
get { return Anchor1?.Length ?? 0; }
}
public BezierCurve(double[] anchor1, double[] handle1, double[] handle2, double[] anchor2)
{
int dim = anchor1.Length;
if (handle1.Length != dim || handle2.Length != dim || anchor2.Length != dim)
{
throw new ArgumentException("すべてのポイントは同じ次元数(配列の長さ)である必要があります。");
}
Anchor1 = anchor1;
Handle1 = handle1;
Handle2 = handle2;
Anchor2 = anchor2;
}
/// <summary>
/// 曲線を指定した数で分割し、点ベース・軸ベース両方の配列を持った結果オブジェクトを返します。
/// </summary>
public BezierCurveResult CalculatePoints(int segments)
{
if (segments <= 0)
{
throw new ArgumentException("分割数は1以上にしてください。", nameof(segments));
}
int dim = Dimension;
int pointCount = segments + 1;
// 戻り値用の専用オブジェクトを作成
var result = new BezierCurveResult(pointCount, dim);
for (int i = 0; i <= segments; i++)
{
double t = (double)i / segments;
double u = 1.0 - t;
double coeff0 = u * u * u;
double coeff1 = 3 * u * u * t;
double coeff2 = 3 * u * t * t;
double coeff3 = t * t * t;
for (int d = 0; d < dim; d++)
{
// 座標を計算
double val = coeff0 * Anchor1[d] +
coeff1 * Handle1[d] +
coeff2 * Handle2[d] +
coeff3 * Anchor2[d];
// 点ベースの配列に代入
result.Points[i][d] = val;
// 軸ベースの配列にも同じ値を代入
result.Axes[d][i] = val;
}
}
return result;
}
}
}