工程相關領域的行業,通常少不了面對函式繪圖,現在有許多的軟體都可以使用更方便的功能來繪製複雜的函式圖形,如著名的Matlab。
在這邊介紹三維立體空間的函式繪製,將函式分為兩類:「顯函式」與「隱函式」。
顯函式
如果可以將函式表示為y = f(x, z) 的形式,這種函式稱之為顯函式,由於顯函式的(x,z)只會產生一個結果,所以顯函式所表示的圖形若使用一條與y軸平行的直線來與圖形相交,最多只有一個交點。繪製顯函式的方法就是分別對x與z進行迴圈計數,並帶入原方程式求出y值,然後在螢幕上繪出(x, y)的對應圖(z = f(x, y)或x = f(y, z)只是換個角度繪圖,方法一樣)。
隱函式
如果函式是f(x, y, z) = 0的形式,稱之為隱函式,雖然y - f(x, z) = 0也可以算是屬於此種形式,不過這邊所說的隱函式是指那些無法化為y = f(x, z)形式的函式;當畫上一條與y軸平行的直線時,可能會發生幾個情況,例如以球面函式x^2 + y^2 + z^2 - 1 = 0來說,可能沒有交點、一個交點或是兩個交點,如下圖所示:
由於一對(x, z)值可能會有兩個交點,所以我們必須將隱函式設法改變為以下的形式才能進行繪圖:
x = x(s, t)
y = y(s, t)
z = z(s, t)
      
      y = y(s, t)
z = z(s, t)
以上的形式稱之為參數式,之後我們就可以利用(s, t)進行迴圈計數並計算出(x, y, z)的值並進行繪圖,當然(x, y, z)的參數式代回原來的函式必須滿足原來的函式,以球面函式x2 + y2 + z2 - 1 = 0為例,較好的參數表示式當然就是極座標表示法。
大部份的隱函式都可以使用參數式來進行繪圖,不過不同的函式會需要不同的參數式,以下示範顯函式的繪圖:
- Demo.java
package cc.openhome;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JApplet;
import static java.lang.Math.*;
public class Demo extends JApplet {
    private int orgX;
    private int orgY;
    public void init() {
        super.init();
        setBackground(Color.black);
        setSize(640, 480);
        orgX = getWidth() / 2;
        orgY = getHeight() / 2;
    }
    public void paint(Graphics g) {
        g.setColor(Color.yellow);
        // 從斜角繪製
        // 繞 x 軸轉 30 度,繞 y 軸轉 -30 度
        double rotateX = toRadians(30);
        double rotateY = toRadians(-30);
        double sinRotateX = sin(rotateX);
        double cosRotateX = cos(rotateX);
        double sinRotateY = sin(rotateY);
        double cosRotateY = cos(rotateY);
                
        for(int z = 200; z >= -200; z-=10) {
            for(int x = -200; x <= 200; x++) {
                double y = 30*(cos(toRadians(sqrt(x * x + z * z)))
                         + cos(toRadians(3 * sqrt(x * x + z * z))));
                // 立體旋轉,從斜角繪製,調整繪圖中心至視窗中心
                int pointX = (int) (orgX + x * cosRotateY + z * sinRotateY);
                int pointY = (int) (orgY - (y * cosRotateX -
                           (-x * sinRotateY + z * cosRotateY) * sinRotateX));
                g.drawLine(pointX, pointY, pointX, pointY);
            }
        }
    }
}以下是使用HTML5 Canvas的方式(如果瀏覽器支援HTML5 Canvas,例如最新版的Firexfox、Chrome、IE9等,可以直接將下面的內容存為HTML或按下檔名連結,直接載入瀏覽器執行觀看結果:
<!DOCTYPE html>
<html>
    <head>
        <meta content="text/html; charset=Big5" http-equiv="content-type">
        <script type="text/javascript">
            window.onload = function() {
                function toRadians(angle) {
                    return angle * Math.PI / 180;
                }
                var sin = Math.sin;
                var cos = Math.cos;
                var sqrt = Math.sqrt;
                
                var canvas1 = document.getElementById('canvas1');
                var context = canvas1.getContext('2d');
                var orgX = canvas1.width / 2;
                var orgY = canvas1.height / 2;
                
                var rotateX = toRadians(30);
                var rotateY = toRadians(-30);
                
                var sinRotateX = Math.sin(rotateX);
                var cosRotateX = Math.cos(rotateX);
                var sinRotateY = Math.sin(rotateY);
                var cosRotateY = Math.cos(rotateY);
                
                context.beginPath();
                for(var z = 200; z >= -200; z-=10) {
                    for(var x = -200; x <= 200; x++) {
                        var y = 30*(cos(toRadians(sqrt(x * x + z * z)))
                               + cos(toRadians(3 * sqrt(x * x + z * z))));
                        // 立體旋轉,從斜角繪製,調整繪圖中心至視窗中心
                        var pointX = parseInt(
                              orgX + x * cosRotateY + z * sinRotateY);
                        var pointY = parseInt(orgY - (y * cosRotateX -
                           (-x * sinRotateY + z * cosRotateY) * sinRotateX));
                        context.moveTo(pointX, pointY);
                        context.lineTo(pointX + 1, pointY + 1);
                    }
                }
                context.stroke();
                context.closePath();
            };
        </script>
    </head>
    <body>       
        <canvas id="canvas1" width="640" height="480"></canvas>
    </body>
</html>
在Firefox下的效果如下:


