Skip to content

Instantly share code, notes, and snippets.

@Cranc
Created August 22, 2019 17:08
Show Gist options
  • Save Cranc/4516db74ffb5114d16f470bce6db8655 to your computer and use it in GitHub Desktop.
Save Cranc/4516db74ffb5114d16f470bce6db8655 to your computer and use it in GitHub Desktop.
namespace Spline_Engine.Splines
{
class NURBS : Interfaces.SplineInterface
{
//step size for drawing
private double increment = 0.01;
private int degree = 1;
public void Draw(Canvas panel, List<Vector3> points, Guid uid)
{
DrawNURBS(points, panel, uid);
DrawPoints(points, panel, uid);
DrawHelperLine(points, panel, uid);
}
private void DrawNURBS(List<Vector3> points, Canvas panel, Guid uid)
{
if (points.Count < 4)
return;
PointCollection draw_points = new PointCollection();
List<double> knotSequenz = CalculateKnotVector(degree, points.Count);
List<int> weights = new List<int>();
//generate weights
for(int i = 0; i < points.Count; i++)
{
weights.Add(1);
}
for (double u = 0; u <= 1; u += increment)
{
double x = 0;
double y = 0;
for (int i = 0; i < points.Count; i++)
{
double _base = NurbsBaseEquation(u, i, degree, knotSequenz, weights);
x += _base * points[i].X;
y += _base * points[i].Y;
}
draw_points.Add(new Point(x, y));
}
var polyLine = new Polyline();
polyLine.Uid = uid.ToString();
polyLine.Stroke = Brushes.Green;
polyLine.StrokeThickness = 2;
polyLine.FillRule = FillRule.EvenOdd;
polyLine.Points = draw_points;
panel.Children.Add(polyLine);
}
private List<double> CalculateKnotVector(int degree, int pointCount)
{
int len = pointCount + degree + 1;
int lower = len - 1 - 2 * degree;
List<double> knotSequenz = new List<double>();
knotSequenz.Add(0);
for (int i = 1; i < len; i++)
{
if(i <= degree)
{
knotSequenz.Add(0);
} else if(i >= len - degree - 1)
{
knotSequenz.Add(1);
}
else
{
int upper = i - degree;
knotSequenz.Add(upper / lower);
}
}
return knotSequenz;
}
private double NurbsBaseEquation(double u, int i, int n, List<double> knotSequenz, List<int> weights)
{
double upper = RecursiveBaseEquation(u, i, n, knotSequenz) * weights[i];
double lower = 0;
for(int j = 0; j < n; j++)
{
lower += RecursiveBaseEquation(u, j, n, knotSequenz) * weights[j];
}
return upper / lower;
}
private double RecursiveBaseEquation(double u, int i, int n, List<double> knotSequenz)
{
//return 0.0;
if(n == 0)
{
if(knotSequenz[i] <= u && u < knotSequenz[i + 1])
{
return 1.0;
} else
{
return 0.0;
}
}
return (u - knotSequenz[i]) / (knotSequenz[i + n] - knotSequenz[i]) * RecursiveBaseEquation(u, i, n - 1, knotSequenz) +
(knotSequenz[i + 1 + n] - u) / (knotSequenz[i + 1 + n] - knotSequenz[i + 1]) * RecursiveBaseEquation(u, i + 1, n - 1, knotSequenz);
}
private void DrawPoints(List<Vector3> points, Canvas panel, Guid uid)
{
foreach (var point in points)
{
var circle = new Ellipse();
circle.Uid = uid.ToString();
circle.Width = 10;
circle.Height = 10;
circle.Stroke = Brushes.Orange;
circle.Fill = Brushes.Orange;
panel.Children.Add(circle);
double left = point.X - (10 / 2);
double top = point.Y - (10 / 2);
Canvas.SetLeft(circle, left);
Canvas.SetTop(circle, top);
}
}
private void DrawHelperLine(List<Vector3> points, Canvas panel, Guid uid)
{
PointCollection draw_points = new PointCollection();
foreach (var point in points)
{
draw_points.Add(new Point(point.X, point.Y));
}
var polyLine = new Polyline();
polyLine.Uid = uid.ToString();
polyLine.Stroke = Brushes.Orange;
polyLine.StrokeThickness = 1;
polyLine.FillRule = FillRule.EvenOdd;
polyLine.Points = draw_points;
panel.Children.Add(polyLine);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment