反転変換(円に関する反転)について(1)

反転変換は、下の図で、点  P d \times d' = r^2 になるような点  Q に写す座標変換です。

f:id:shspage:20170409123323p:plain

 P が円の中心に近いほど、 Qは中心から遠ざかり、
 P が円の中心と同じ位置の場合、 Q までの距離は無限遠になります。

反転に使った半径  r の円を基準円と呼びます。

Illustratorスクリプトの関数として書くと以下のようになります。

var Point = function(x, y){
    this.x = x;
    this.y = y;
}
// --------------------------------------
// Point p1, p2 の間の距離の2乗を返す
function dist2(p1, p2) {
    var dx = p1.x - p2.x;
    var dy = p1.y - p2.y;
    return dx*dx + dy*dy;
}
// --------------------------------------
// 半径 r, 中心 o の円に関して点 p を反転変換する。
// r2: float 半径 r の2乗
// o, p: Point
function inverse(o, r2, p){
    var d2 = dist2(o, p);
    if(d2 == 0){
        return Infinity;
    }

    var m = r2 / d2;  // ※

    var q = new Point((p.x - o.x) * m + o.x,
                      (p.y - o.y) * m + o.y);
    return q;
}

var m = r2 / d2; の部分についてですが、

 Q(x', y') の位置は、 P(x, y) x, y をそれぞれ  d で割って  d' を掛ければ求められますので、 *1

 \displaystyle
\displaystyle
Q = P \frac{d'}{d}

最初の式から  \displaystyle
d' = \frac{r^2}{d}
ですので、

 \displaystyle
Q = P \frac{\frac{r^2}{d}}{d}

分数の分母と分子に d を掛けると

 \displaystyle
Q = P \frac{r^2}{d^2}

となります。

たいていは多くの点について繰り返し使うような用途になるので、 半径をあらかじめ2乗しておき、距離も2乗として使い、 無駄な乗算や平方根の計算による処理時間のロスを減らしています。

で?

って感じですが、
これを図形に適用するとだんだん面白くなってきます。

1. 反転変換は円を円にする

下の図で基準円の内側にある、円周に沿って並べた点は、それぞれ基準円の外側にある点のように反転変換されます。

f:id:shspage:20170409164022p:plain

点が等間隔でなくなって、中心も変なところに行っていますが、変換された点も円を描いているようではありますね。

もっと点を増やすと、明らかに円を描いているのがわかります。

f:id:shspage:20170409164029p:plain

反転変換には「円を円に写す」という性質があります。

2. 反転変換は中心を通る円を直線にする

下の図で基準円の内側にある、中心を通る円に沿って並べた点は、 それぞれ外側にある直線に沿って並んだ点に変換されます。

f:id:shspage:20170409164039p:plain

「1」と矛盾するようですが、実はこれは同じことで、
私のイメージとしては、
と、下のような図を描くと数学のできる人がブチ切れそうですが、

f:id:shspage:20170409164044p:plain

前述のように、基準円の中心に置いた点は反転変換によって無限遠に飛ばされます。
つまり中心を通る円を反転すると、無限遠を通る円になります。
直線とは、無限遠を通る円の円周と考えることもできるのですね。

3. 反転変換の結果を反転変換すると元に戻る

反転変換の式、  d \times d' = r^2 は、  d' \times d = r^2 としても同じことですので、これは当然ですが、
この性質にしたがって言えば、「2」の「中心を通る円を直線にする」は「直線を中心を通る円にする」とも言えます。

※ 図を描くのに使用したスクリプトを記事の最後に掲載します。

活用例

円の外に描いた六角形(辺上にアンカーポイントをたくさん追加している)を 円を使って反転変換して、赤い線の形状にしました。

f:id:shspage:20170409170252p:plain

何か面白い形ができそうな感じがしないでしょうか。

記事の最後に掲載しているスクリプトはオブジェクトの中心座標を移動していますが、 この例ではアンカーポイントを反転変換しています。 スクリプトはほとんど似た感じなので Gist に置きました。

Illustrator:最背面のパス(円)に関して残りの選択パスのアンカーポイントを反転変換した座標に移動する · GitHub

つづく

今回はここまで。

たぶん(3)まで続く予定。

付録:図を描くのに使用したスクリプト

「で?」の節の図の作成に使用したスクリプトです。

// 最背面のパス(円)に関して残りの選択オブジェクトを
// それぞれの中心を反転変換した座標に移動する
// --------------------------------------
var Point = function(x, y){
    this.x = x;
    this.y = y;
}
// --------------------------------------
// 半径 r, 中心 o の円に関して点 p を反転変換する
// r2: float, 半径 r の2乗
// o, p: Point
function inverse(o, r2, p){
    var d2 = dist2(o, p);
    if(d2 == 0){
        return Infinity;
    }
    var m = r2 / d2;
    var q = new Point((p.x - o.x) * m + o.x,
                       (p.y - o.y) * m + o.y);
    return q;
}
// --------------------------------------
// Point p1, p2 の間の距離の2乗を返す
function dist2(p1, p2) {
    var dx = p1.x - p2.x;
    var dy = p1.y - p2.y;
    return dx*dx + dy*dy;
}
// --------------------------------------
// PageItem item の中心の座標を返す
function getCenter(item){
    var gb = item.geometricBounds;  // [left, top, right, bottom]
    return new Point((gb[0] + gb[2]) / 2,
                     (gb[1] + gb[3]) / 2);
}
// --------------------------------------
function main(){
    // 選択範囲を取得。最背面は反転に使用する円
    var sel = activeDocument.selection;
    
    var circle = sel.pop();
    var o = getCenter(circle);
    var r = circle.width / 2;
    var r2 = r * r;

    for(var si = 0; si < sel.length; si++){
        var p = getCenter(sel[si]);
        var q = inverse(o, r2, p);
        
        if(q != Infinity){  // 無限遠は無視
            sel[si].translate(q.x - p.x, q.y - p.y);
        }
    }
}
main();

*1:Oが原点の場合