読者です 読者をやめる 読者になる 読者になる

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

前回(1) の続きです。

反転変換した円を Illustrator で描く

反転変換は円を円に変換しますが、変換後の円をIllustratorでどう描けばよいでしょう。

前回の図で見たように、元の円の中心は写った先の円の中央には来ません。
円周上の点にアンカーポイントを置いていくのも非効率的です。

しかし基準円の中心から見て、元の円の最も近い点・遠い点は、 それぞれ変換後の円の最も遠い点・近い点になることは言えます。

そこで、この2点の中点を中心として、2点を通る円を描けばよいことになります。

f:id:shspage:20170411195629p:plain

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

// 半径 r, 中心 o の円に関する 円 circle の反転を返す。
// o: Point
// r2: float 半径の2乗
// circle: Circle
// return: Circle
function inverseCircle(o, r2, circle){
    var d = dist(circle.center, o);
    
    var v = d == 0
      ? new Point(circle.radius, 0)
        : circle.center.sub(o).mul(circle.radius / d);  // ※

    var p1 = circle.center.sub(v);
    var p2 = circle.center.add(v); 

    var i1 = inverse(o, r2, p1);
    var i2 = inverse(o, r2, p2);

    var c = new Circle(getMidPoint(i1, i2),
                       dist(i1, i2) / 2);
    return c;
}
// ----------------------------------------------
Point.prototype = {
    add : function(p){  // p : Point
        return new Point(this.x + p.x, this.y + p.y);
    },
    sub : function(p){  // p : Point
        return new Point(this.x - p.x, this.y - p.y);
    },
    mul : function(m){  // m : float
        return new Point(this.x * m, this.y * m);
    }
}
// ------------------------
// 円
// o : Point, 中心
// r : float, 半径
function Circle(o, r){
    this.center = o;
    this.radius = r;
}
// ------------------------
// Point p1, p2 の間の距離を返す
function dist(p1, p2) {
    return Math.sqrt(dist2(p1, p2));
}
// ------------------------
// Point p1, p2 の中点を返す
function getMidPoint(p1, p2){
    return new Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
}

inverse, dist2, Point(コンストラクタ) については前回載せたものになるので省略しています。

inverseCircle の
circle.center.sub(o).mul(circle.radius / d); の部分についてですが、

f:id:shspage:20170411195655p:plain

まず元の円の中心の座標値から基準円の中心の座標値を引くと、 基準円の中心を原点とした場合の、元の円の中心へのベクトルが得られます。

それを中心同士の距離 d で割ると単位ベクトル *1 になります。

ここではその単位ベクトルに元の円の半径を掛けたベクトルを作っています。

これを元の円の中心から引いたものを、基準円の中心に最も近い点(p1)、 足したものを最も遠い点(p2)としています。

反転変換しても接点は保たれる。

次のネタに行く前に、反転変換の性質をもう一つ挙げておきます。

接している円が共有している接点は1つの点です。 反転の仕組みから考えて、 1つの点を反転すると2つに分かれるというのはあり得ません。

なので接している2円を反転した場合、接している2円になります。

2円に交点があるなら、交点についても同じことが言えます。

これを踏まえて、

2円に接し1点を通る円を描く

これは前に書いた「 3つの円の隙間に円を描く 」で保留した説明にもなるのですが、単に面白い形を描く以外にも反転が役立つ例です。

下の図の点 P を通り2円に接する円を描きたいというときに、反転変換が利用できます。

f:id:shspage:20170411195734p:plain

Illustratorスクリプトは、長くなったのでGistに置きました。

Illustrator : 1点を通り2円に接する円を描く · GitHub

手順としては、まず点 P を中心とした適当な円を基準円として、2円を反転変換します。 そのうえで、変換後の2円に共通接線を引きます。 *2

f:id:shspage:20170411195751p:plain

前回書いたように、この直線は無限遠を通る円と考えられます。
そしてこの「円」は2円に接していますので、 反転すると元の2円に接する円になるはずです。

また、無限遠を反転変換すると基準円の中心になるのでした。

つまり、共通接線の接点を反転すると、
基準円の中心点 P と合わせて求める円の円周上の3点が決まります。

あとは3点を結ぶ三角形の外接円を描く要領で円を描くことができます。

f:id:shspage:20170411200139p:plain

考えてみると反転によって無限遠をはるばる点 P の位置に持ってきてるわけで、 無限遠が目の前に!おおっ!って感じです。

……ところで2円の共通接線は上の図に書いたものの他にも最大3本あります。 上の考え方からすると、これらも反転すると点Pを通り2円に接する円になるはずです。 この場合はいずれかまたは両方の円が描いた円の内側に接するような形になります。

円の内側に接するケースも考えると、共通接線が引けない場合でも 円が描けることがあります。 このためサンプルスクリプトは本当はもっと場合分けする必要があります。

詳しくは「 アポロニウスの問題 - Wikipedia 」を調べてみてください。

つづく

↓つづき

反転変換(円に関する反転)について(3) - s.h's page

*1:長さが1のベクトル

*2:スクリプトでの共通接線の書き方は以前の記事「2円をつなぐ線を描く」参照