1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/akwkevin-aistudio.-wpf.-diagram

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Это зеркальный репозиторий, синхронизируется ежедневно с исходного репозитория.
Клонировать/Скачать
BezierSpline.cs 8.1 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
艾竹 Отправлено 2 лет назад 6a4c311
using System;
namespace AIStudio.Wpf.DiagramDesigner.Geometrys
{
/// <summary>
/// Bezier Spline methods
/// </summary>
/// <remarks>
/// Modified: Peter Lee (peterlee.com.cn < at > gmail.com)
/// Update: 2009-03-16
///
/// see also:
/// Draw a smooth curve through a set of 2D points with Bezier primitives
/// http://www.codeproject.com/KB/graphics/BezierSpline.aspx
/// By Oleg V. Polikarpotchkin
///
/// Algorithm Descripition:
///
/// To make a sequence of individual Bezier curves to be a spline, we
/// should calculate Bezier control points so that the spline curve
/// has two continuous derivatives at knot points.
///
/// Note: `[]` denotes subscript
/// `^` denotes supscript
/// `'` denotes first derivative
/// `''` denotes second derivative
///
/// A Bezier curve on a single interval can be expressed as:
///
/// B(t) = (1-t)^3 P0 + 3(1-t)^2 t P1 + 3(1-t)t^2 P2 + t^3 P3 (*)
///
/// where t is in [0,1], and
/// 1. P0 - first knot point
/// 2. P1 - first control point (close to P0)
/// 3. P2 - second control point (close to P3)
/// 4. P3 - second knot point
///
/// The first derivative of (*) is:
///
/// B'(t) = -3(1-t)^2 P0 + 3(3t^2–4t+1) P1 + 3(2–3t)t P2 + 3t^2 P3
///
/// The second derivative of (*) is:
///
/// B''(t) = 6(1-t) P0 + 6(3t-2) P1 + 6(1–3t) P2 + 6t P3
///
/// Considering a set of piecewise Bezier curves with n+1 points
/// (Q[0..n]) and n subintervals, the (i-1)-th curve should connect
/// to the i-th one:
///
/// Q[0] = P0[1],
/// Q[1] = P0[2] = P3[1], ... , Q[i-1] = P0[i] = P3[i-1] (i = 1..n) (@)
///
/// At the i-th subinterval, the Bezier curve is:
///
/// B[i](t) = (1-t)^3 P0[i] + 3(1-t)^2 t P1[i] +
/// 3(1-t)t^2 P2[i] + t^3 P3[i] (i = 1..n)
///
/// applying (@):
///
/// B[i](t) = (1-t)^3 Q[i-1] + 3(1-t)^2 t P1[i] +
/// 3(1-t)t^2 P2[i] + t^3 Q[i] (i = 1..n) (i)
///
/// From (i), the first derivative at the i-th subinterval is:
///
/// B'[i](t) = -3(1-t)^2 Q[i-1] + 3(3t^2–4t+1) P1[i] +
/// 3(2–3t)t P2[i] + 3t^2 Q[i] (i = 1..n)
///
/// Using the first derivative continuity condition:
///
/// B'[i-1](1) = B'[i](0)
///
/// we get:
///
/// P1[i] + P2[i-1] = 2Q[i-1] (i = 2..n) (1)
///
/// From (i), the second derivative at the i-th subinterval is:
///
/// B''[i](t) = 6(1-t) Q[i-1] + 6(3t-2) P1[i] +
/// 6(1-3t) P2[i] + 6t Q[i] (i = 1..n)
///
/// Using the second derivative continuity condition:
///
/// B''[i-1](1) = B''[i](0)
///
/// we get:
///
/// P1[i-1] + 2P1[i] = P2[i] + 2P2[i-1] (i = 2..n) (2)
///
/// Then, using the so-called "natural conditions":
///
/// B''[1](0) = 0
///
/// B''[n](1) = 0
///
/// to the second derivative equations, and we get:
///
/// 2P1[1] - P2[1] = Q[0] (3)
///
/// 2P2[n] - P1[n] = Q[n] (4)
///
/// From (1)(2)(3)(4), we have 2n conditions for n first control points
/// P1[1..n], and n second control points P2[1..n].
///
/// Eliminating P2[1..n], we get (be patient to get :-) a set of n
/// equations for solving P1[1..n]:
///
/// 2P1[1] + P1[2] + = Q[0] + 2Q[1]
/// P1[1] + 4P1[2] + P1[3] = 4Q[1] + 2Q[2]
/// ...
/// P1[i-1] + 4P1[i] + P1[i+1] = 4Q[i-1] + 2Q[i]
/// ...
/// P1[n-2] + 4P1[n-1] + P1[n] = 4Q[n-2] + 2Q[n-1]
/// P1[n-1] + 3.5P1[n] = (8Q[n-1] + Q[n]) / 2
///
/// From this set of equations, P1[1..n] are easy but tedious to solve.
/// </remarks>
public static class BezierSpline
{
/// <summary>
/// Get open-ended Bezier Spline Control Points.
/// </summary>
/// <param name="knots">Input Knot Bezier spline points.</param>
/// <param name="firstControlPoints">Output First Control points array of knots.Length - 1 length.</param>
/// <param name="secondControlPoints">Output Second Control points array of knots.Length - 1 length.</param>
/// <exception cref="ArgumentNullException"><paramref name="knots"/> parameter must be not null.</exception>
/// <exception cref="ArgumentException"><paramref name="knots"/> array must containg at least two points.</exception>
public static void GetCurveControlPoints(PointBase[] knots, out PointBase[] firstControlPoints, out PointBase[] secondControlPoints)
{
if (knots == null)
throw new ArgumentNullException("knots");
int n = knots.Length - 1;
if (n < 1)
throw new ArgumentException("At least two knot points required", "knots");
if (n == 1)
{ // Special case: Bezier curve should be a straight line.
firstControlPoints = new PointBase[1];
// 3P1 = 2P0 + P3
firstControlPoints[0] = new PointBase((2 * knots[0].X + knots[1].X) / 3, (2 * knots[0].Y + knots[1].Y) / 3);
secondControlPoints = new PointBase[1];
// P2 = 2P1 – P0
secondControlPoints[0] = new PointBase(2 * firstControlPoints[0].X - knots[0].X, 2 * firstControlPoints[0].Y - knots[0].Y);
return;
}
// Calculate first Bezier control points
// Right hand side vector
double[] rhs = new double[n];
// Set right hand side X values
for (int i = 1; i < n - 1; ++i)
rhs[i] = 4 * knots[i].X + 2 * knots[i + 1].X;
rhs[0] = knots[0].X + 2 * knots[1].X;
rhs[n - 1] = (8 * knots[n - 1].X + knots[n].X) / 2.0;
// Get first control points X-values
double[] x = GetFirstControlPoints(rhs);
// Set right hand side Y values
for (int i = 1; i < n - 1; ++i)
rhs[i] = 4 * knots[i].Y + 2 * knots[i + 1].Y;
rhs[0] = knots[0].Y + 2 * knots[1].Y;
rhs[n - 1] = (8 * knots[n - 1].Y + knots[n].Y) / 2.0;
// Get first control points Y-values
double[] y = GetFirstControlPoints(rhs);
// Fill output arrays.
firstControlPoints = new PointBase[n];
secondControlPoints = new PointBase[n];
for (int i = 0; i < n; ++i)
{
// First control point
firstControlPoints[i] = new PointBase(x[i], y[i]);
// Second control point
if (i < n - 1)
secondControlPoints[i] = new PointBase(2 * knots[i + 1].X - x[i + 1], 2 * knots[i + 1].Y - y[i + 1]);
else
secondControlPoints[i] = new PointBase((knots[n].X + x[n - 1]) / 2, (knots[n].Y + y[n - 1]) / 2);
}
}
/// <summary>
/// Solves a tridiagonal system for one of coordinates (x or y) of first Bezier control points.
/// </summary>
/// <param name="rhs">Right hand side vector.</param>
/// <returns>Solution vector.</returns>
private static double[] GetFirstControlPoints(double[] rhs)
{
int n = rhs.Length;
double[] x = new double[n]; // Solution vector.
double[] tmp = new double[n]; // Temp workspace.
double b = 2.0;
x[0] = rhs[0] / b;
for (int i = 1; i < n; i++) // Decomposition and forward substitution.
{
tmp[i] = 1 / b;
b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
x[i] = (rhs[i] - x[i - 1]) / b;
}
for (int i = 1; i < n; i++)
x[n - i - 1] -= tmp[n - i] * x[n - i]; // Backsubstitution.
return x;
}
}
}

Комментарий ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/akwkevin-aistudio.-wpf.-diagram.git
git@gitlife.ru:oschina-mirror/akwkevin-aistudio.-wpf.-diagram.git
oschina-mirror
akwkevin-aistudio.-wpf.-diagram
akwkevin-aistudio.-wpf.-diagram
1.0.7Demo