如何尽可能精确地绘制蝶形曲线? [英] How to draw a butterfly curve as accurate as possible?

查看:105
本文介绍了如何尽可能精确地绘制蝶形曲线?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用

根据我在大学中记得的那样,用 Java 是下一个:

  public void paintComponent(图形g){
super.paintComponent( G);
Graphics2D g2 =(Graphics2D)g;
g2.translate(300,300);
int x1,y1;
int x0 = 0;
int y0 =(int)(数学E-2); //对于x = 0,我们得到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; //使其介于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 进行尝试,认为这样可以绘制出更准确的图形。 / p>

  public void paintComponent(图形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 =数学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(新Line2D.Double(x0,y0,x1,y1));
x0 = x1;
y0 = y1;
}
}

得出了下一个结果:





好的,这看起来确实更好,但肯定不是预期的结果。



因此,我要问的是,有没有一种方法可以使用此参数方程式和 Java 绘制最精确的曲线?





它不必看起来像100%

解决方案

您的比例尺语句也会缩放线条的宽度,从而导致线条的形状奇怪曲线。有两种简单的方法可以解决问题:


  1. 减小行的宽度,例如到0.01f:

      Graphics2D g2 =(Graphics2D)g; 
    g2.translate(300,300);
    double x1,y1;
    double x0 = 0;
    int nPoints = 500;
    //备选方案1 ---------------------
    g2.scale(30,-30);
    g2.setStroke(new BasicStroke(0.01f));
    // -----------------------------------
    double y0 =数学。 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(新Line2D.Double(x0,y0,x1,y1));
    x0 = x1;
    y0 = y1;
    }


结果如下:




  1. 删除比例尺陈述并使用其幅度比例尺缩放曲线,即使用与x值和y值相关的常数预因子,例如-30:

      Graphics2D g2 =(Graphics2D)g; 
    g2.translate(300,300);
    double x1,y1;
    double x0 = 0;
    int nPoints = 500;
    //替代2 ---------------------
    double amp = -30.0;
    // -----------------------------------
    double y0 =数学。 E-2;
    for(int i = 0; i< nPoints; i ++){
    double t = 12 * i * Math.PI / nPoints;
    //备选方案2 ------------------------------------------ ----------------------------------------
    x1 = amp *(数学.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(新的Line2D.Double(x0,y0,x1,y1));
    x0 = x1;
    y0 = y1;
    }


这导致(大致相同):





此外,可以通过使用抗锯齿和增加nPoint来提高绘图质量:

  Graphics2D g2 =(Graphics2D)g ; 
//优化------------------------------------
g2.setRenderingHint (RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int nPoints = 1500;
// -------------------------------------------- -----
g2.translate(300,300);
double x1,y1;
double x0 = 0;
//备选方案1 ---------------------
g2.scale(50,-50);
g2.setStroke(new BasicStroke(0.01f));
// -----------------------------------
double y0 =数学。 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(新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:

  1. 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:

  1. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆