//
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
namespace ImageSharp.Drawing.Paths
{
using System.Numerics;
///
/// Represents a line segment that conistst of control points that will be rendered as a cubic bezier curve
///
///
public class BezierLineSegment : ILineSegment
{
///
/// The segments per curve.
/// code for this taken from
///
private const int SegmentsPerCurve = 50;
///
/// The line points.
///
private readonly Vector2[] linePoints;
///
/// Initializes a new instance of the class.
///
/// The points.
public BezierLineSegment(params Vector2[] points)
{
Guard.NotNull(points, nameof(points));
Guard.MustBeGreaterThanOrEqualTo(points.Length, 4, nameof(points));
this.linePoints = this.GetDrawingPoints(points);
}
///
/// Returns the current a simple linear path.
///
///
/// Returns the current as simple linear path.
///
public Vector2[] AsSimpleLinearPath()
{
return this.linePoints;
}
///
/// Returns the drawing points along the line.
///
/// The control points.
///
/// The .
///
private Vector2[] GetDrawingPoints(Vector2[] controlPoints)
{
// TODO we need to calculate an optimal SegmentsPerCurve value
// depending on the calcualted length of this curve
int curveCount = (controlPoints.Length - 1) / 3;
int finalPointCount = (SegmentsPerCurve * curveCount) + 1; // we have SegmentsPerCurve for each curve plus the origon point;
Vector2[] drawingPoints = new Vector2[finalPointCount];
int position = 0;
int targetPoint = controlPoints.Length - 3;
for (int i = 0; i < targetPoint; i += 3)
{
Vector2 p0 = controlPoints[i];
Vector2 p1 = controlPoints[i + 1];
Vector2 p2 = controlPoints[i + 2];
Vector2 p3 = controlPoints[i + 3];
// only do this for the first end point. When i != 0, this coincides with the end point of the previous segment,
if (i == 0)
{
drawingPoints[position++] = this.CalculateBezierPoint(0, p0, p1, p2, p3);
}
for (int j = 1; j <= SegmentsPerCurve; j++)
{
float t = j / (float)SegmentsPerCurve;
drawingPoints[position++] = this.CalculateBezierPoint(t, p0, p1, p2, p3);
}
}
return drawingPoints;
}
///
/// Calculates the bezier point along the line.
///
/// The position within the line.
/// The p 0.
/// The p 1.
/// The p 2.
/// The p 3.
///
/// The .
///
private Vector2 CalculateBezierPoint(float t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
{
float u = 1 - t;
float tt = t * t;
float uu = u * u;
float uuu = uu * u;
float ttt = tt * t;
Vector2 p = uuu * p0; // first term
p += 3 * uu * t * p1; // second term
p += 3 * u * tt * p2; // third term
p += ttt * p3; // fourth term
return p;
}
}
}