import * as Utils from '../utils/utils' import { Circle, Line, Point, Vector } from './index' /** * 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
* @type {Inversion} */ export class Inversion { circle: Circle /** * 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) } } } /** * Shortcut to create inversion operator * @param circle * @returns {Inversion} */ export const inversion = (circle) => new Inversion(circle)