如何尽可能准确地绘制蝴蝶曲线?
How to draw a butterfly curve as accurate as possible?
我正在尝试使用 Java
绘制 butterfly curve。
这是上述曲线的参数方程:
我记得大学时,用Java
画参数方程的方法是下一个:
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.translate(300,300);
int x1,y1;
int x0 = 0;
int y0 = (int)(Math.E-2); //for x = 0, we get y = Math.E - 2
int nPoints = 1000;
g2.scale(30,-30);
for(int i=0;i<nPoints;i++) {
double t= 12*i*Math.PI/nPoints; //to make it between 0 and 12*PI.
x1=(int)(Math.sin(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
y1 = (int)(Math.cos(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
g2.drawLine(x0,y0,x1,y1);
x0=x1;
y0=y1;
}
}
现在,这给了我下一个结果:
好吧,这和预期的结果相差太远了。
然后我决定使用 Line2D.Double
进行尝试,认为这样可以提供更准确的绘图。
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.translate(300,300);
double x1,y1;
double x0 = 0;
int nPoints = 500;
g2.scale(30,-30);
double y0 = Math.E-2;
for(int i=0;i<nPoints;i++) {
double t= 12*i*Math.PI/nPoints;
x1=(Math.sin(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
y1 = (Math.cos(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
g2.draw(new Line2D.Double(x0,y0,x1,y1));
x0=x1;
y0=y1;
}
}
产生下一个结果:
好的,这确实看起来更好,但肯定不是预期的结果。
所以我想问一下,有没有办法用Java
这个参数方程画出最准确的曲线?
不一定要 100% 像上图,但最接近。
你的缩放语句也会缩放你的线的宽度,导致你的曲线形状奇怪。有两种简单的方法可以解决这个问题:
减小线条的宽度,例如到 0.01f:
Graphics2D g2 = (Graphics2D)g;
g2.translate(300,300);
double x1,y1;
double x0 = 0;
int nPoints = 500;
// Alternative 1 ---------------------
g2.scale(30,-30);
g2.setStroke(new BasicStroke(0.01f ));
// -----------------------------------
double y0 = Math.E-2;
for(int i=0;i<nPoints;i++) {
double t= 12*i*Math.PI/nPoints;
x1= (Math.sin(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
y1 = (Math.cos(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
g2.draw(new Line2D.Double(x0,y0,x1,y1));
x0=x1;
y0=y1;
}
这导致:
删除比例语句并使用其幅度缩放曲线,即使用关于 x 和 y 值的常数预因子,例如-30:
Graphics2D g2 = (Graphics2D)g;
g2.translate(300,300);
double x1,y1;
double x0 = 0;
int nPoints = 500;
// Alternative 2 ---------------------
double amp = -30.0;
// -----------------------------------
double y0 = Math.E-2;
for(int i=0;i<nPoints;i++) {
double t= 12*i*Math.PI/nPoints;
// Alternative 2 ----------------------------------------------------------------------------------
x1=amp*(Math.sin(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
y1=amp*(Math.cos(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
// ------------------------------------------------------------------------------------------------
g2.draw(new Line2D.Double(x0,y0,x1,y1));
x0=x1;
y0=y1;
}
这导致(或多或少相同):
此外,您可以通过使用抗锯齿和增加 nPoints 来提高绘图质量:
Graphics2D g2 = (Graphics2D)g;
// Optimization ------------------------------------
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int nPoints = 1500;
// -------------------------------------------------
g2.translate(300,300);
double x1,y1;
double x0 = 0;
// Alternative 1 ---------------------
g2.scale(50,-50);
g2.setStroke(new BasicStroke(0.01f ));
// -----------------------------------
double y0 = Math.E-2;
for(int i=0;i<nPoints;i++) {
double t= 12*i*Math.PI/nPoints;
x1= (Math.sin(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
y1 = (Math.cos(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
g2.draw(new Line2D.Double(x0,y0,x1,y1));
x0=x1;
y0=y1;
}
结果(看起来好多了):
至此,两点之间的连接是一条直线。当然,您可以使用样条曲线(贝塞尔曲线等)进行进一步优化,但这可能并不简单。
我正在尝试使用 Java
绘制 butterfly curve。
这是上述曲线的参数方程:
我记得大学时,用Java
画参数方程的方法是下一个:
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.translate(300,300);
int x1,y1;
int x0 = 0;
int y0 = (int)(Math.E-2); //for x = 0, we get y = Math.E - 2
int nPoints = 1000;
g2.scale(30,-30);
for(int i=0;i<nPoints;i++) {
double t= 12*i*Math.PI/nPoints; //to make it between 0 and 12*PI.
x1=(int)(Math.sin(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
y1 = (int)(Math.cos(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
g2.drawLine(x0,y0,x1,y1);
x0=x1;
y0=y1;
}
}
现在,这给了我下一个结果:
好吧,这和预期的结果相差太远了。
然后我决定使用 Line2D.Double
进行尝试,认为这样可以提供更准确的绘图。
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.translate(300,300);
double x1,y1;
double x0 = 0;
int nPoints = 500;
g2.scale(30,-30);
double y0 = Math.E-2;
for(int i=0;i<nPoints;i++) {
double t= 12*i*Math.PI/nPoints;
x1=(Math.sin(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
y1 = (Math.cos(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
g2.draw(new Line2D.Double(x0,y0,x1,y1));
x0=x1;
y0=y1;
}
}
产生下一个结果:
好的,这确实看起来更好,但肯定不是预期的结果。
所以我想问一下,有没有办法用Java
这个参数方程画出最准确的曲线?
不一定要 100% 像上图,但最接近。
你的缩放语句也会缩放你的线的宽度,导致你的曲线形状奇怪。有两种简单的方法可以解决这个问题:
减小线条的宽度,例如到 0.01f:
Graphics2D g2 = (Graphics2D)g; g2.translate(300,300); double x1,y1; double x0 = 0; int nPoints = 500; // Alternative 1 --------------------- g2.scale(30,-30); g2.setStroke(new BasicStroke(0.01f )); // ----------------------------------- double y0 = Math.E-2; for(int i=0;i<nPoints;i++) { double t= 12*i*Math.PI/nPoints; x1= (Math.sin(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5))); y1 = (Math.cos(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5))); g2.draw(new Line2D.Double(x0,y0,x1,y1)); x0=x1; y0=y1; }
这导致:
删除比例语句并使用其幅度缩放曲线,即使用关于 x 和 y 值的常数预因子,例如-30:
Graphics2D g2 = (Graphics2D)g; g2.translate(300,300); double x1,y1; double x0 = 0; int nPoints = 500; // Alternative 2 --------------------- double amp = -30.0; // ----------------------------------- double y0 = Math.E-2; for(int i=0;i<nPoints;i++) { double t= 12*i*Math.PI/nPoints; // Alternative 2 ---------------------------------------------------------------------------------- x1=amp*(Math.sin(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5))); y1=amp*(Math.cos(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5))); // ------------------------------------------------------------------------------------------------ g2.draw(new Line2D.Double(x0,y0,x1,y1)); x0=x1; y0=y1; }
这导致(或多或少相同):
此外,您可以通过使用抗锯齿和增加 nPoints 来提高绘图质量:
Graphics2D g2 = (Graphics2D)g;
// Optimization ------------------------------------
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int nPoints = 1500;
// -------------------------------------------------
g2.translate(300,300);
double x1,y1;
double x0 = 0;
// Alternative 1 ---------------------
g2.scale(50,-50);
g2.setStroke(new BasicStroke(0.01f ));
// -----------------------------------
double y0 = Math.E-2;
for(int i=0;i<nPoints;i++) {
double t= 12*i*Math.PI/nPoints;
x1= (Math.sin(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
y1 = (Math.cos(t)*(Math.pow(Math.E,Math.cos(t))-2*Math.cos(4*t)-Math.pow(Math.sin(t/12),5)));
g2.draw(new Line2D.Double(x0,y0,x1,y1));
x0=x1;
y0=y1;
}
结果(看起来好多了):
至此,两点之间的连接是一条直线。当然,您可以使用样条曲线(贝塞尔曲线等)进行进一步优化,但这可能并不简单。