如何画出尽可能准确的蝴蝶曲线?

问题描述 投票:0回答:2

我正在尝试使用 Java 绘制一条

蝴蝶曲线

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

Butterfly Curve Parametric equation

根据我在大学时的记忆,用

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;
    }
}

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

first try curve

好吧,这离预期的结果太远了。

然后我决定使用

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;
    }
}

这产生了下一个结果:

Better curve

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

因此我想问,有没有办法使用这个带有

Java
的参数方程来绘制最准确的曲线?

best curve

它不必看起来 100% 像上图,但最接近。

java 2d graphics2d java-2d
2个回答
1
投票

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

  1. 减少线条的宽度,例如至 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;
    }  
    

这会导致:

enter image description here

  1. 删除缩放语句并使用其幅度缩放曲线,即使用关于 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;
    }  
    

这会导致(或多或少相同):

enter image description here

此外,您可以通过使用抗锯齿和增加 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;
    }  

结果(看起来好多了):

enter image description here

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


0
投票

蝴蝶的参数方程如下:

编写一段java代码段来适当地绘制这个函数

© www.soinside.com 2019 - 2024. All rights reserved.