using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Collections.Generic;
namespace Autospline {
public struct Segment {
public double previous;
public double current;
public double next;
public double nextnext;
public static double get(double s, double p0, double pm, double p1) {
return p0*(1.0-s)*(1.0-s) + 2.0*pm*(1.0-s)*s + p1*s*s;
}
public static double get(double s, double p0, double p1, double t0, double t1) {
double h0 = 2.0*s*s*s - 3.0*s*s + 1.0;
double h1 = -2.0*s*s*s + 3.0*s*s;
double h2 = s*s*s - 2.0*s*s + s;
double h3 = s*s*s - s*s;
double p = h0*p0 + h1*p1 + h2*t0 + h3*t1;
return p;
}
public double get(double s) {
return get(s, current, next, current - previous, next - current);
}
public double getCool(double s) {
return get(s, current, next, 0.5*(next - previous), 0.5*(nextnext - current));
}
public double getCool2(double s) {
return get(s, 0.5*(previous + current), current, 0.5*(current + next));
}
}
public struct Segment2d {
public Segment x;
public Segment y;
}
public class MainWindow : Form {
static public void Main() { Application.Run(new MainWindow()); }
bool pressed = false;
List<Segment2d> segments = new List<Segment2d>();
Bitmap buffer;
void newCurve(double x, double y) {
Segment2d segment;
segment.x.previous = segment.x.current = segment.x.next = segment.x.nextnext = x;
segment.y.previous = segment.y.current = segment.y.next = segment.y.nextnext = y;
segments.Add(segment);
}
void addPoint(double x, double y) {
Segment2d previous = segments[segments.Count - 1];
previous.x.nextnext = x;
previous.y.nextnext = y;
segments[segments.Count - 1] = previous;
Segment2d segment;
segment.y.nextnext = y;
segment.x.next = segment.x.nextnext = x;
segment.y.next = segment.y.nextnext = y;
segment.x.current = previous.x.next;
segment.y.current = previous.y.next;
segment.x.previous = previous.x.current;
segment.y.previous = previous.y.current;
segments.Add(segment);
}
public MainWindow() {
OnResize(this, new EventArgs());
Paint += OnPaint;
MouseMove += OnMouseMove;
MouseDown += OnMouseDown;
MouseUp += OnMouseUp;
Resize += OnResize;
WindowState = FormWindowState.Maximized;
}
public void OnResize(Object sender, EventArgs e) {
buffer = new Bitmap(ClientSize.Width, ClientSize.Height);
}
public void OnPaint(Object sender, PaintEventArgs e) {
Graphics g = Graphics.FromImage(buffer);
Draw(g);
g.Flush();
e.Graphics.DrawImageUnscaled(buffer, 0, 0);
}
public void OnMouseDown(Object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
newCurve(e.X, e.Y);
pressed = true;
Invalidate();
} else
if (e.Button == MouseButtons.Right) {
segments.Clear();
if (pressed) newCurve(e.X, e.Y);
Invalidate();
}
}
public void OnMouseUp(Object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left && pressed) {
addPoint(e.X, e.Y);
pressed = false;
Invalidate();
}
}
public void OnMouseMove(Object sender, MouseEventArgs e) {
if (pressed) {
addPoint(e.X, e.Y);
Invalidate();
}
}
public void Draw(Graphics g) {
g.Clear(Color.White);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
int count = 100;
double r = 2.0;
double l = 2.0;
Pen pen = new Pen(Color.FromArgb(128, 128, 128, 128));
Pen cool = new Pen(Color.FromArgb(128, 0, 0, 255));
foreach(Segment2d segment in segments) {
double x0 = segment.x.get(0.0);
double y0 = segment.y.get(0.0);
for(int i = 1; i <= count; ++i) {
double x1 = segment.x.get((double)i/(double)count);
double y1 = segment.y.get((double)i/(double)count);
if (i == count || (x1 - x0)*(x1 - x0) + (y1 - y0)*(y1 - y0) > l*l) {
g.DrawLine(pen, (float)x0, (float)y0, (float)x1, (float)y1);
x0 = x1;
y0 = y1;
}
}
x0 = segment.x.getCool2(0.0);
y0 = segment.y.getCool2(0.0);
for(int i = 1; i <= count; ++i) {
double x1 = segment.x.getCool2((double)i/(double)count);
double y1 = segment.y.getCool2((double)i/(double)count);
if (i == count || (x1 - x0)*(x1 - x0) + (y1 - y0)*(y1 - y0) > l*l) {
g.DrawLine(cool, (float)x0, (float)y0, (float)x1, (float)y1);
x0 = x1;
y0 = y1;
}
}
g.FillEllipse(
Brushes.Black,
(float)(segment.x.current - r), (float)(segment.y.current - r),
(float)(2.0*r), (float)(2.0*r) );
g.FillEllipse(
Brushes.Black,
(float)(segment.x.next - r), (float)(segment.y.next - r),
(float)(2.0*r), (float)(2.0*r) );
}
}
}
}