ベジェ曲線の書き方自体うろ覚えで、しかも寝起きで書いてるので変な所あるかも。
なんとなくそれっぽい感じに書けてるから、大丈夫じゃないかなぁって気がする。
今回はそれっぽい曲線が書ければ十分なので、これで大丈夫ということにしておく。
計算の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) { Listlist = 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 件のコメント:
コメントを投稿