ベジェ曲線の書き方自体うろ覚えで、しかも寝起きで書いてるので変な所あるかも。
なんとなくそれっぽい感じに書けてるから、大丈夫じゃないかなぁって気がする。
今回はそれっぽい曲線が書ければ十分なので、これで大丈夫ということにしておく。
計算のpublic関数で、intとdoubleで多重定義しているので、そこだけ注意。
それぞれの線の最大長さを指定する方法と、分割数を指定する方法の2種類がある。
前者は計算量が多い代わりに、なめらかな曲線になる。後者は計算量が少ない代わりに、ガタガタした曲線になりやすい。
上画像では、黒や白は前者で、緑は後者で計算している。
readonly PictureBox picture_box = null;
public Form1()
{
InitializeComponent();
picture_box = new PictureBox();
picture_box.Dock = DockStyle.Fill;
picture_box.Paint += Picture_box_Paint;
picture_box.Click += delegate (object sender, EventArgs e) { ((PictureBox)sender).Refresh(); };
Controls.Add(picture_box);
MaximumSize = MinimumSize = Size = Size + new Size(1200, 1200) - picture_box.Size;
StartPosition = FormStartPosition.CenterScreen;
}
private void Picture_box_Paint(Object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.Clear(Color.Gray);
g.TranslateTransform(100, 100);
g.DrawRectangle(Pens.Black, 0, 0, 1000, 1000);
g.DrawLines(Pens.Black, PointD.convert_to_PointF(new Bezier()
{
points = new[]
{
new PointD(0, 0),
new PointD(0, 500),
new PointD(1000, 500),
new PointD(1000, 1000),
}
}.calc(Math.Sqrt(2))));
g.DrawLines(Pens.White, PointD.convert_to_PointF(new Bezier()
{
points = new[]
{
new PointD(0,0),
new PointD(1000, 1000),
}
}.calc(Math.Sqrt(2))));
g.DrawLines(Pens.White, PointD.convert_to_PointF(new Bezier()
{
points = new[]
{
new PointD(0,0),
new PointD(1000, 0),
new PointD(1000, 1000),
}
}.calc(Math.Sqrt(2))));
g.DrawLines(Pens.White, PointD.convert_to_PointF(new Bezier()
{
points = new[]
{
new PointD(0,0),
new PointD(1000, 0),
new PointD(1000, 0),
new PointD(1000, 1000),
}
}.calc(Math.Sqrt(2))));
g.DrawLines(Pens.White, PointD.convert_to_PointF(new Bezier()
{
points = new[]
{
new PointD(0,0),
new PointD(1000, 0),
new PointD(1000, 0),
new PointD(1000, 0),
new PointD(1000, 1000),
}
}.calc(Math.Sqrt(2))));
g.DrawLines(Pens.White, PointD.convert_to_PointF(new Bezier()
{
points = new[]
{
new PointD(0,0),
new PointD(1000, 0),
new PointD(1000, 0),
new PointD(1000, 0),
new PointD(1000, 0),
new PointD(1000, 1000),
}
}.calc(Math.Sqrt(2))));
g.DrawLines(Pens.White, PointD.convert_to_PointF(new Bezier()
{
points = new[]
{
new PointD(0,0),
new PointD(1000, 0),
new PointD(1000, 0),
new PointD(1000, 0),
new PointD(1000, 0),
new PointD(1000, 0),
new PointD(1000, 1000),
}
}.calc(Math.Sqrt(2))));
g.DrawLines(Pens.Lime, PointD.convert_to_PointF(new Bezier()
{
points = new[]
{
new PointD(0,0),
new PointD(0, 1000),
new PointD(1000, 1000),
new PointD(1000, 0),
}
}.calc(10)));
}
class Bezier
{
public PointD[] points { get; set; }
public PointD[] calc(int number_of_points)
{
PointD[] result = new PointD[number_of_points];
for (int i = 0; i < result.Length; i++)
{
result[i] = calc(points, (double)i / (result.Length - 1));
}
return (result);
}
public PointD[] calc(double P2P_max_distance)
{
return (calc(points, P2P_max_distance, 0, 1));
}
protected PointD[] calc(PointD[] points, double P2P_max_distance, double start_point, double end_point)
{
List list = new List();
PointD p1 = calc(points, start_point);
PointD p2 = calc(points, end_point);
double distance = (p1 - p2).length;
list.Add(p1);
if (distance > P2P_max_distance)
{
double center = start_point + (end_point - start_point) * 0.5;
list.AddRange(calc(points, P2P_max_distance, start_point, center));
list.AddRange(calc(points, P2P_max_distance, center, end_point));
}
list.Add(p2);
return (list.ToArray());
}
protected PointD calc(PointD[] points, double point)
{
if (points.Length < 2)
{
throw (new Exception());
}
else if (points.Length == 2)
{
return (calc(points, 0, point));
}
else
{
PointD[] new_points = new PointD[points.Length - 1];
for (int i = 0; i < new_points.Length; i++)
{
new_points[i] = calc(points, i, point);
}
return (calc(new_points, point));
}
}
protected PointD calc(PointD[] points, int start_index, double point)
{
int i = start_index;
int j = i + 1;
return (points[i] + (points[j] - points[i]) * point);
}
}
struct PointD
{
public double x { get; set; }
public double y { get; set; }
public PointD(double x, double y)
{
this.x = x;
this.y = y;
}
public PointF convert_to_PointF()
{
return (new PointF((float)x, (float)y));
}
public static PointF[] convert_to_PointF(PointD[] points)
{
PointF[] result = new PointF[points.Length];
for (int i = 0; i < result.Length; i++)
{
result[i] = points[i].convert_to_PointF();
}
return (result);
}
public double length
{
get
{
return (Math.Sqrt(x * x + y * y));
}
}
public static PointD operator +(PointD p1, PointD p2)
{
return (new PointD(p1.x + p2.x, p1.y + p2.y));
}
public static PointD operator -(PointD p1, PointD p2)
{
return (new PointD(p1.x - p2.x, p1.y - p2.y));
}
public static PointD operator *(PointD p1, PointD p2)
{
return (new PointD(p1.x * p2.x, p1.y * p2.y));
}
public static PointD operator *(PointD p, double d)
{
return (new PointD(p.x * d, p.y * d));
}
public static PointD operator *(double d, PointD p)
{
return (p * d);
}
public static PointD operator /(PointD p1, PointD p2)
{
return (new PointD(p1.x / p2.x, p1.y / p2.y));
}
public static PointD operator /(PointD p, double d)
{
return (new PointD(p.x / d, p.y / d));
}
}
0 件のコメント:
コメントを投稿