图案的自动生成,不仅能为工艺设计、建筑设计、镭射线条提供资源,还能为加密、结构光设计等方面提供更多的方案。由于研究视觉算法需要,产品中要识别各种曲线,也要在仿真中生成各种曲线。在中学学习阶段,大家都学过无理数,如:π ,e,sinϕ,cosϕ 等等。只知道是无限不循环小数。现在将无理数中的某一段取出来,视作整数,我们可以发现并无规律,如下图:
接着,用一对无理数(sinϕ,cosϕ ),计算某一范围的函数值,也将某一段取出来,转为整数,在直角坐标系数中的图像如下:
正弦与余弦互为余角的特征,也即相位差,在上图中仍然显现了出来。
接着的算法思路是:对一个大圆,在圆周上取N个点,构成正N边形,正N边形的N个顶点坐标的(X,Y)重新计算,都对某一正整数K取模(相除,取出余数),即:
//无理数构图算法N67:---编程语言:C#,编程环境:Windows10 + VS2012
private void button67_Click(object sender, EventArgs e)
{
//绘图参数与工具:
int xOrg = pictureBox1.Width / 2;
int yOrg = pictureBox1.Height / 2;
Bitmap bmp = new Bitmap(boxWidth, boxHeight);
Graphics g = Graphics.FromImage(bmp);
g.Clear(Color.Black);
Brush bhRed = new SolidBrush(Color.Red);
Brush bhWhite = new SolidBrush(Color.White);
Pen penYellow = new Pen(Color.Yellow, 2);
Pen penLightPink = new Pen(Color.LightPink, 2);
//生成极坐标系下的数据集:
Random rd = new Random( (int)DateTime.Now.Ticks);//随机数据类
int R1 = (int)1E6 + rd.Next( 567);//用作倍数
int R2 = (int)1E3 + rd.Next( 321);//用作除数
int stp = 3 + 3*rd.Next(9);//细分程度
double maxR = 0;//记下最大半径
List<Point> pt3 = new List<Point>(); //点的集合
//算法构建---By daode1212,daode3056
for (float q = -PI; q <= PI; q += PI / stp)
{
int x = (int)(R1 * Math.Cos(q) % R2);//X坐标先扩大,再取余数
int y = (int)(R1 * Math.Sin(q) % R2);//Y坐标先扩大,再取余数
double R=Math.Sqrt((x * x + y * y));//当前半径
if ( R> maxR)maxR = R; //记下最大半径
pt3.Add(new Point(x, y));//添加到集合中
}
//控制大小,并实现平移:
var pt4 = pt3.Select(o => new Point((int)(xOrg + 300 * o.X / maxR), (int)(yOrg + 300 * o.Y / maxR))).ToArray();
//根据点的数目选择使用光滑曲线还是折线绘制:
if (pt3.Count % 3 == 1)
{
g.DrawBeziers(penYellow, pt4); //光滑Bezier曲线
}
else
{
g.DrawLines(penLightPink, pt4); //折线绘制
}
pt3.Clear(); pt4 = null; //内存回收
//生成文本与保存图片: ===============================
string txt = sender.ToString().Split(':')[1] +string.Format("_{0}`{1}`{2}", R1,R2,stp);
g.DrawString(txt, new Font("", 12), bhWhite, boxWidth / 2 - 150, boxHeight - 100);
pictureBox1.Image = bmp;
bmp.Save(txt + ".png"); this.Text = txt + ".png ---文件已经保存";
this.pictureBox1.Refresh();
}
用这个程序,并按各图片中的参数(R1`R2`stp),可以一一再现相应的图片。
对新的一系列坐标(Xnew,Ynew)画多边形,或画平滑的Bezier曲线,就得到下列各图:
奇迹就从这里开始,我们用极坐标来绘制与展示,如下图:
用Bezier平滑插值(需要3N+1个点)来描绘,就更美了:
以下为多边形配上了背景
下是各图片的缩略图(局部):
现在取PI小数点后1000位,自用它的无限不循环特性,进行序列化也可生成各种花式的图案:
//取自PI的图案,算法第N70: ---编程语言:C#,编程环境:Windows10 + VS2012
private void button70_Click(object sender, EventArgs e)
{
/*
要计算PI小数点后3000位的,链接: https://math.tools/numbers/pi/3000
*/
string strPI = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989";
//string s13= strPI.Substring(1, 3);//.14
//string s23= strPI.Substring(2, 3); //141
//string s999_3= strPI.Substring(999, 3);//898
//====================================
int[] sPI = new int[1000]; //可用范围:2---999
for (int i = 2; i < 1000;i++ )
{
sPI[i] =Int32.Parse(strPI.Substring(i, 3));
}
//=====================================
//绘图参数与工具:
int xOrg = pictureBox1.Width / 2;
int yOrg = pictureBox1.Height / 2;
Bitmap bmp = new Bitmap(boxWidth, boxHeight);
Graphics g = Graphics.FromImage(bmp);
g.Clear(Color.Black);
Brush bhBlue = new SolidBrush(Color.FromArgb(44,0,66));
Brush bhWhite = new SolidBrush(Color.White);
Pen penYellow = new Pen(Color.Yellow, 4);
Pen penLightPink = new Pen(Color.LightPink, 2);
//====================================
//生成极坐标系下的数据集:
Random rd = new Random((int)DateTime.Now.Ticks);//随机数据类
int R1 = 999*sPI[2 + rd.Next(1000-2)];//用作倍数
int R2 = sPI[2 + rd.Next(1000-2)]; ;//用作除数
int stp = 3 + 3 * rd.Next(9);//细分程度
double maxR = 0;//记下最大半径
List<Point> pt3 = new List<Point>(); //点的集合
//算法构建---By daode1212,daode3056
for (float q = -PI; q <= PI; q += PI / stp)
{
int x = (int)(R1 * Math.Cos(q) % R2);//X坐标先扩大,再取余数
int y = (int)(R1 * Math.Sin(q) % R2);//Y坐标先扩大,再取余数
double R = Math.Sqrt((x * x + y * y));//当前半径
if (R > maxR) maxR = R; //记下最大半径
pt3.Add(new Point(x, y));//压入集合中
}
//控制大小,并实现平移:
var pt4 = pt3.Select(o => new Point((int)(xOrg + 300 * o.X / maxR), (int)(yOrg + 300 * o.Y / maxR))).ToArray();
//根据点的数目选择使用光滑曲线还是折线簇绘制:
if (pt3.Count % 3 == 1)
{
g.FillPolygon(bhBlue, pt4);
g.DrawBeziers(penYellow, pt4);
}
else
{
g.FillClosedCurve(bhBlue, pt4);
g.DrawLines(penLightPink, pt4);
}
pt3.Clear(); pt4 = null;
//生成文本与保存图片: ===============================
string txt = sender.ToString().Split(':')[1] + string.Format("_{0}`{1}`{2}", R1, R2, stp);
g.DrawString(txt, new Font("", 12), bhWhite, boxWidth / 2 - 150, boxHeight - 50);
pictureBox1.Image = bmp;
bmp.Save(txt + ".png"); this.Text = txt + ".png ---文件已经保存";
this.pictureBox1.Refresh();
}
下是各图片的缩略图(局部):
二〇二二年八月二十六日