地球儀の描き方  2002.08.10(初版)アップロードしたのは 2004.01.02


 前ページで述べた、平面の世界地図から地球儀を描く方法を簡単に解説します。

 x-z 平面を y軸から眺めることを考えます(下図を参照)。このとき x-z 平面
の矩形領域(ここでは正方形領域)
矩形領域の範囲 を半径ρの半球面(y > 0 の領域)に貼り付けます。貼り付けるとは、元の平面図形 を縦に糸状に切り刻んだものを端から順に半球面の円弧に沿って貼り付けてゆく作 業を想像するとよいでしょう。つまり、そのように頭の中で考えます。 直角座標と極座標  このとき矩形領域内の座標点を(X,Z)とすると、対応する球面上の角度(極座標 の角度成分)(θ,φ)との関係は角度を y軸に対して測るとして
角度の関係式 となります。平面の地図で X は経度を表し、Z は緯度を表します。角度(θ,φ)の 範囲は
極座標角度成分の範囲 です。ただし、x軸の向きを反転しています(xの符号を反対にする)。  また、球面上の座標点(x,y,z)から極座標(ρ,θ,φ)への変換の式は
極座標の変換式 で表されます。角度θ(地図の経度に対応)とφ(緯度に対応)は y軸から測って いることに注意しましょう。この座標変換の逆変換は
逆変換 となります。  y軸から見た球面上の角度(θ,φ)の射影は、x-z平面上の座標点(x,z)になるので、 座標(X,Z)から(x,z)への座標変換の逆変換の式は
座標変換の逆変換の式 となります。これが求める変換式です。次に、完全なプログラム コードを示しま す。
// txtmap.cpp
// テキスチャマッピング
//   読み込んだ画像を球面に貼り付けて、それを背景画面に射影する。
//   ここでは平面の世界地図 worldmap.bmp から地球儀を描く
//
//         【注意】 このプログラムは単独では動きません。
//          worldmap.bmp を同じディレクトリに置いて実行ください
#include <math.h>
#include "glibw32.h"

const int Xsize = 198, Ysize = 198; // ビットマップのサイズ
COLORREF crf[Xsize][Ysize];
void mapping(GRAPH&);
void table(int, int, int [2][2], int [2][2], int [2][2]);

int main()
{
    ginit(Xsize, Ysize);
    if( loadbmp("worldmap.bmp") ){ // ビットマップのロード
        gend();
        exit(1);
    }

    GRAPH g;
    g.window(0, 0, Xsize-1, Ysize-1); // ロードした画像の座標

    // gのピクセルをスキャンして配列に格納
    for(int i = 0; i < Xsize; i++)
        for(int j = 0; j < Ysize; j++)
            g.getpixel(i, j, crf[i][j]);

    g.cls(); // 画面をクリア
    mapping(g);

    gend();

    return 0;
}

// 画像を球面に貼り付けて、それを画面に射影する
void mapping(GRAPH& g1)
{
    double PI = 4.0*atan(1.0); // 円周率
    int m,n;
    int R[2][2], G[2][2], B[2][2], r, g, b;
    double x, z, p, q, rho;
    int xs = Xsize/2;
    int zs = Ysize/2;
    rho = 2.0*xs/PI;      // 球の半径ρの値

    for(int j = -(int)rho; j < (int)rho; j++){
        z = rho*asin(j/rho);
        if(z > 0) n = (int)z;
        else n = (int)(z-1);
        q = z - n;
        if(q==1){ q=0; n=n+1; }

        for(int i = -(int)rho; i < (int)rho; i++){
            if(i*i + j*j > rho*rho) continue;

            double y = sqrt(fabs(rho*rho - i*i -j*j));
            x = rho*atan2(i,y);
            if(x > 0) m = (int)x;
            else m = (int)(x-1);
            p = x - m;
            if(p==1){ p=0; m=m+1; }

            // 線形補間
            table(m+xs, n+zs, R, G, B);
            r = (int)((1.0-q)*( (1.0-p)*R[0][0]+p*R[1][0] )
                          + q*( (1.0-p)*R[0][1] + p*R[1][1]) );
            g = (int)((1.0-q)*( (1.0-p)*G[0][0]+p*G[1][0] )
                          + q*( (1.0-p)*G[0][1] + p*G[1][1]) );
            b = (int)((1.0-q)*( (1.0-p)*B[0][0]+p*B[1][0] )
                          + q*( (1.0-p)*B[0][1] + p*B[1][1]) );
            g1.pset(i+xs, j+zs, RGB(r,g,b));
        }
    }
}

// (x,y)の周辺4画素の色を求める
void table(int x, int y, int R[2][2], int G[2][2], int B[2][2])    
{
    for(int i = 0; i < 2; i++)
        for(int j = 0; j < 2; j++){
            R[i][j] = GetRValue(crf[x+i][y+j]);
            G[i][j] = GetGValue(crf[x+i][y+j]);
            B[i][j] = GetBValue(crf[x+i][y+j]);
        }
}

 実行ファイルとソースファイルのダウンロードはこちらです。

地球儀の描き方
実行ファイルとソース ファイル及び必要な画像ファイル
Windows 95/98/2000上で動作します。
  ダウンロード
  txtmap.lzh (37KB)

 * このソフトウェアは、ウィルス検査を行っています。 
 * ファイルは吉崎栄泰氏による LHA (Copyright(c)1988-92 H.Yoshizaki)を 
  使って圧縮しています。 

| 目次 | 前のページ |

Copyright(c) 2002-2004 Yamada,K