UNPKG

@zenghawtin/graph2d

Version:

Javascript library for 2d geometry

91 lines (79 loc) 3.44 kB
"use strict"; import Flatten from '../flatten'; const {Circle, Line, Point, Vector, Utils} = Flatten; /** * Class Inversion represent operator of inversion in circle * Inversion is a transformation of the Euclidean plane that maps generalized circles * (where line is considered as a circle with infinite radius) into generalized circles * See also https://en.wikipedia.org/wiki/Inversive_geometry and * http://mathworld.wolfram.com/Inversion.html <br/> * @type {Inversion} */ export class Inversion { /** * Inversion constructor * @param {Circle} inversion_circle inversion circle */ constructor(inversion_circle) { this.circle = inversion_circle; } get inversion_circle() { return this.circle; } static inversePoint(inversion_circle, point) { const v = new Vector(inversion_circle.pc, point); const k2 = inversion_circle.r * inversion_circle.r; const len2 = v.dot(v); const reflected_point = Utils.EQ_0(len2) ? new Point(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY) : inversion_circle.pc.translate(v.multiply(k2 / len2)); return reflected_point; } static inverseCircle(inversion_circle, circle) { const dist = inversion_circle.pc.distanceTo(circle.pc)[0]; if (Utils.EQ(dist, circle.r)) { // Circle passing through inversion center mapped into line let d = (inversion_circle.r * inversion_circle.r) / (2 * circle.r); let v = new Vector(inversion_circle.pc, circle.pc); v = v.normalize(); let pt = inversion_circle.pc.translate(v.multiply(d)); return new Line(pt, v); } else { // Circle not passing through inversion center - map into another circle */ /* Taken from http://mathworld.wolfram.com */ let v = new Vector(inversion_circle.pc, circle.pc); let s = inversion_circle.r * inversion_circle.r / (v.dot(v) - circle.r * circle.r); let pc = inversion_circle.pc.translate(v.multiply(s)); let r = Math.abs(s) * circle.r; return new Circle(pc, r); } } static inverseLine(inversion_circle, line) { const [dist, shortest_segment] = inversion_circle.pc.distanceTo(line); if (Utils.EQ_0(dist)) { // Line passing through inversion center, is mapping to itself return line.clone(); } else { // Line not passing through inversion center is mapping into circle let r = inversion_circle.r * inversion_circle.r / (2 * dist); let v = new Vector(inversion_circle.pc, shortest_segment.end); v = v.multiply(r / dist); return new Circle(inversion_circle.pc.translate(v), r); } } inverse(shape) { if (shape instanceof Point) { return Inversion.inversePoint(this.circle, shape); } else if (shape instanceof Circle) { return Inversion.inverseCircle(this.circle, shape); } else if (shape instanceof Line) { return Inversion.inverseLine(this.circle, shape); } } }; Flatten.Inversion = Inversion; /** * Shortcut to create inversion operator * @param circle * @returns {Inversion} */ export const inversion = (circle) => new Flatten.Inversion(circle); Flatten.inversion = inversion;