我正在尝试使用Java绘制butterfly curve

这是上述曲线的参数方程式:

java - 如何尽可能精确地绘制蝶形曲线?-LMLPHP

根据我在大学时记得的内容,接下来是用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;
    }
}


现在,这给了我下一个结果:

java - 如何尽可能精确地绘制蝶形曲线?-LMLPHP

好的,这与预期结果相去甚远。

然后,我决定使用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 - 如何尽可能精确地绘制蝶形曲线?-LMLPHP

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

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

java - 如何尽可能精确地绘制蝶形曲线?-LMLPHP

它不必看起来像上面的图像一样是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;
}



结果是:

java - 如何尽可能精确地绘制蝶形曲线?-LMLPHP


删除缩放比例陈述并使用其幅度缩放曲线,即对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;
}



结果(大致相同):

java - 如何尽可能精确地绘制蝶形曲线?-LMLPHP

此外,可以通过使用抗锯齿和增加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 - 如何尽可能精确地绘制蝶形曲线?-LMLPHP

到目前为止,两点之间的连接是一条直线。当然,可以使用样条曲线(贝塞尔曲线等)进行进一步的优化,但这可能并不简单。

关于java - 如何尽可能精确地绘制蝶形曲线?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53054837/

10-13 22:32