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

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

问题描述

我正在尝试使用 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 语句也会缩放线条的宽度,导致曲线形状奇怪.有两种简单的方法可以解决这个问题:

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

这导致:

  1. 删除您的比例声明并使用其幅度缩放曲线,即使用关于您的 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:

  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天全站免登陆