如何尽可能准确地绘制蝴蝶曲线? [英] How to draw a butterfly curve as accurate as possible?
问题描述
我正在尝试使用 Java<绘制
根据我在大学时的记忆,接下来是使用 Java
绘制参数方程的方法:
public voidpaintComponent(Graphics g) {super.paintComponent(g);Graphics2D g2 = (Graphics2D)g;g2.translate(300,300);int x1,y1;整数 x0 = 0;int y0 = (int)(Math.E-2);//对于 x = 0,我们得到 y = Math.E - 2int nPoints = 1000;g2.scale(30,-30);for(int i=0;i<nPoints;i++) {双 t= 12*i*Math.PI/nPoints;//使其介于 0 和 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 voidpaintComponent(Graphics g) {super.paintComponent(g);Graphics2D g2 = (Graphics2D)g;g2.translate(300,300);双 x1,y1;双 x0 = 0;int nPoints = 500;g2.scale(30,-30);双 y0 = Math.E-2;for(int i=0;i<nPoints;i++) {双 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% 一样,而是最接近的.
你的 scale 语句也会缩放线条的宽度,导致曲线形状奇怪.有两种简单的方法可以解决这个问题:
减少线条的宽度,例如到 0.01f:
Graphics2D g2 = (Graphics2D)g;g2.translate(300,300);双 x1,y1;双 x0 = 0;int nPoints = 500;//备选方案 1 ---------------------g2.scale(30,-30);g2.setStroke(new BasicStroke(0.01f));//---------------------双 y0 = Math.E-2;for(int i=0;i<nPoints;i++) {双 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);双 x1,y1;双 x0 = 0;int nPoints = 500;//备选方案 2 ---------------------双安培 = -30.0;//---------------------双 y0 = Math.E-2;for(int i=0;i<nPoints;i++) {双 t= 12*i*Math.PI/nPoints;//备选方案 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;//优化 - - - - - - - - - - - - - - - - - -g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);int nPoints = 1500;//------------------------------------------------——g2.translate(300,300);双 x1,y1;双 x0 = 0;//备选方案 1 ---------------------g2.scale(50,-50);g2.setStroke(new BasicStroke(0.01f));//---------------------双 y0 = Math.E-2;for(int i=0;i<nPoints;i++) {双 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;}
这导致(看起来好多了):
到目前为止,两点之间的连接是一条直线.当然,您可以使用样条曲线(贝塞尔曲线等)进行进一步优化,但这可能并非易事.
I am trying to draw a butterfly curve using Java
.
Here's the parametric equation for the mentioned curve:
From what I remember from the college, the way to draw a parametric equation with Java
is the next:
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;
}
}
Now, this gave me the next result:
Okay, this is so far away from the expected result.
I then decided to try it using Line2D.Double
thinking that this would give a more accurate drawing.
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;
}
}
Which yielded the next result:
Okay, this surely looks better, but not the expected result for sure.
Hence I am asking, is there a way to draw the most accurate curve using this parametric equation with Java
?
It doesn't have to look 100% like the image above, but the closest.
Your scale-statement scales also the width of your line causing the strange shape of your curve. There are two easy ways to solve te problem:
Reduce the width of your line, e.g. to 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; }
This results in:
Remove your scale-statement and scale the curve using its amplitude i.e. use a constant prefactor concerning your x- and y-values, e.g. -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; }
This results in (which is more or less identical):
Moreover you can enhance the quality of your plot by using an antialiasing and an increase of 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;
}
This results in (which looks much better):
So far, the connection between two points is a straight line. Sure, you can use splines (Bezier etc.) for further optimization, but probably that is not trivial.
这篇关于如何尽可能准确地绘制蝴蝶曲线?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!