docs: function inverse(shape, inversion_circle) {
      let dist, shortest_segment;
      let dx, dy;
      let s;
      let v;
      let r;
      let d;
      let pt;
  
      if (shape instanceof Flatten.Line) {
          [dist, shortest_segment] = inversion_circle.pc.distanceTo(shape);
          if (EQ_0(dist)) {            // Line passing through inversion center, is mapping to itself
              return shape.clone();
          } else {                           // Line not passing through inversion center is mapping into circle
              r = inversion_circle.r * inversion_circle.r / (2 * dist);
              v = new Flatten.Vector(inversion_circle.pc, shortest_segment.end);
              v = v.multiply(r / dist);
              return new Flatten.Circle(inversion_circle.pc.translate(v), r);
          }
      } else if (shape instanceof Flatten.Circle) {
          [dist, shortest_segment] = inversion_circle.pc.distanceTo(shape.pc);
          if (EQ(dist, shape.r)) {     // Circle passing through inversion center mapped into line
              d = inversion_circle.r * inversion_circle.r / (2 * shape.r);
              v = new Flatten.Vector(shape.pc, inversion_circle.pc);
              v = v.normalize();
              pt = inversion_circle.pc.translate(v.multiply(d));
              return new Flatten.Line(pt, v);
          } else {                           // Circle not passing through inversion center - map into another circle */
              /* Taken from http://mathworld.wolfram.com */
  
              dx = shape.pc.x - inversion_circle.pc.x;
              dy = shape.pc.y - inversion_circle.pc.y;
  
              s = inversion_circle.r * inversion_circle.r / (dx * dx + dy * dy - shape.r * shape.r);
  
              let pc = new Flatten.Point(inversion_circle.pc.x + s * dx, inversion_circle.pc.y + s * dy);
  
              return new Flatten.Circle(pc, Math.abs(s) * shape.r);
          }
      }
  }