# Exponential grids / mobius transformations

**URL:** <https://discourse.processing.org/t/exponential-grids-mobius-transformations/1347>\
**Category:** Beginners\
**Created:** [June 28, 2018, 8:09pm UTC](https://discourse.processing.org/t/exponential-grids-mobius-transformations/1347 "2018-06-28T20:09:34Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![jc2046](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jc2046/32/610_2.png) [@jc2046](https://discourse.processing.org/u/jc2046)\
**Post date:** [June 28, 2018, 8:09pm UTC](https://discourse.processing.org/t/exponential-grids-mobius-transformations/1347/1 "2018-06-28T20:09:35Z")

</div>

Hi,

I want my sketch to draw this kind of things

 ![svg%20-%20Copy](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/3/31e65aeedfee99f0686023a3b093caaefcb4d42c.png)

But Im not sure where to start, what kind of maths are involved nor some seudocode examples. If you have some info, tips, suggestion, intuition, whatever it would be more than welcome

Thanks!

---

<div class="post-metadata">

**Author:** ![TfGuy44](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/tfguy44/32/41_2.png) [@TfGuy44](https://discourse.processing.org/u/TfGuy44)\
**Post date:** [June 28, 2018, 8:28pm UTC](https://discourse.processing.org/t/exponential-grids-mobius-transformations/1347/2 "2018-06-28T20:28:20Z")

</div>

It’s tough to know the values that generated that exact image, but this is pretty close:

```auto
void setup(){
  size(600,600);
  strokeWeight(2);
}
void draw(){
  background(0);
  noFill();
  translate(20,300);
  
  stroke(255,0,0);
  line(0,-height,0,height);
  float rad = 100;
  for( int i = 0; i < 15; i++){
    ellipse(rad/2,0,rad,rad);
    rad*=1.3;
  }
  stroke(0,0,255);
  line(-20,0,width,0);
  rad = 200;
  for( int i = 0; i < 6; i++){
    ellipse(0,rad/2,rad,rad);
    ellipse(0,-rad/2,rad,rad);
    rad*=1.4;
  }
}

```

You can fiddle with the initial values for `rad` and the amount it increases by each time a loop happens.

---

<div class="post-metadata">

**Author:** ![jc2046](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jc2046/32/610_2.png) [@jc2046](https://discourse.processing.org/u/jc2046)\
**Post date:** [June 29, 2018, 2:50am UTC](https://discourse.processing.org/t/exponential-grids-mobius-transformations/1347/3 "2018-06-29T02:50:23Z")

</div>

Another example

![text22](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/1X/2b1502f11a3966e6d1b1d0951ffdedfd7ba40699.gif)

---

<div class="post-metadata">

**Author:** ![TfGuy44](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/tfguy44/32/41_2.png) [@TfGuy44](https://discourse.processing.org/u/TfGuy44)\
**Post date:** [June 29, 2018, 5:18am UTC](https://discourse.processing.org/t/exponential-grids-mobius-transformations/1347/4 "2018-06-29T05:18:10Z")

</div>

Well, that’s a little more involved. You’ll probably want to draw grid lines deformed via some equations. Start with a sketch that just draws normal grid lines:

```auto
int mapX( inX, inY){
  return inX;
}

int mapY( inX, inY){
  return inY;
}

for( each horizontal line ){
for( each pair of points along that line, call them (Ax,Ay) (Bx,By) ){
actually draw a line from (mapX(Ax,Ay), mapY(Ax,Ay)) to (mapX(Bx,By), mapB(Bx,By));
}
}
Do the same for vertical lines.

```

Once you have that working you can have `mapX()` and `mapY()` return values that result from mapping one input point to one output point.

---

<div class="post-metadata">

**Author:** ![behreajj](https://avatars.discourse-cdn.com/v4/letter/b/b5a626/32.png) [@behreajj](https://discourse.processing.org/u/behreajj)\
**Post date:** [July 5, 2018, 2:15pm UTC](https://discourse.processing.org/t/exponential-grids-mobius-transformations/1347/5 "2018-07-05T14:15:48Z")

</div>

Hi jc2046,

Maths are not my strong point, so take the following with caution; going by the formula at the top of the Wikipedia entry on [Mobius transformation](https://en.wikipedia.org/wiki/M%C3%B6bius_transformation), the code might look like

```auto
Complex mobius(Complex a, Complex b, Complex c, Complex d, 
  Complex z) {
  return mobius(a, b, c, d, z, new Complex());
}

Complex mobius(Complex a, Complex b, Complex c, Complex d, 
  Complex z, Complex out) {
  return div(add(mult(a, z), b), add(mult(c, z), d), out);
}

```

There are all sorts of implementations for a [complex number](https://en.wikipedia.org/wiki/Complex_number) in Java; you can reference this [Stack Overflow discussion](https://stackoverflow.com/questions/2997053/does-java-have-a-class-for-complex-numbers) for developed and tested implementations. For now, a basic class

```auto
class Complex {
  float real = 0.0;
  float imaginary = 0.0;

  Complex() {
  }

  Complex(float real, float imaginary) {
    set(real, imaginary);
  }

  String toString() {
    return String.format("(%.2f, %.2f)", real, imaginary);
  }

  Complex clone() {
    return new Complex(real, imaginary);
  }

  Complex set(float real, float imaginary) {
    this.real = real;
    this.imaginary = imaginary;
    return this;
  }
}

```

with some basic operations ([+, -](https://en.wikipedia.org/wiki/Complex_number#Addition_and_subtraction), [\*, /](https://en.wikipedia.org/wiki/Complex_number#Multiplication_and_division)):

```auto
Complex add(Complex a, Complex b) {
  return add(a, b, new Complex());
}

Complex add(Complex a, Complex b, Complex out) {
  return out.set(a.real + b.real, 
    a.imaginary + b.imaginary);
}

Complex div(Complex a, Complex b) {
  return div(a, b, new Complex());
}

Complex div(Complex a, Complex b, Complex out) {
  return mult(a, reciprocal(b), out);
}

Complex mult(Complex a, Complex b) {
  return mult(a, b, new Complex());
}

Complex mult(Complex a, Complex b, Complex out) {
  return out.set(
    a.real * b.real - a.imaginary * b.imaginary, 
    a.real * b.imaginary + a.imaginary * b.real);
}

Complex reciprocal(Complex a) {
  return reciprocal(a, new Complex());
}

Complex reciprocal(Complex a, Complex out) {
  final float modulusSq = a.real * a.real + a.imaginary * a.imaginary;
  return out.set(a.real / modulusSq, -a.imaginary / modulusSq);
}

Complex sub(Complex a, Complex b) {
  return sub(a, b, new Complex());
}

Complex sub(Complex a, Complex b, Complex out) {
  return out.set(a.real - b.real, 
    a.imaginary - b.imaginary);
}

```

(`static` functions are not available to classes created within the Processing IDE, so I just placed the above under `draw` in the main sketch. You could also create instance methods for in-place operations a += b, a -= b, a \*= b, a /= b .)

Messing around with the four inputs to the formula (a, b, c, d and e) gave me the following  
 ![complex](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/1X/819f5a49933164090b0d4418a08abe4f51c4e047.gif)

```auto
// Number of iterations of mobius transformation.
int transformations = 20;

// Smoothness of convex polygons approximating a circle.
int detail = 200;

// For display.
float x, y, scale, animIncr = 1 / 30.0;

// Four inputs to mobius function.
Complex a = new Complex(1.0, 0.0);
Complex b = new Complex(0.0, 0.0);
Complex c = new Complex(0.0, 0.0);
Complex d = new Complex(1.0, 0.0);

// Reference circle.
Complex[] circle = new Complex[detail];

// Transformations.
Complex[][] transformed = new Complex[transformations][detail];

void setup() {
  size(512, 256);
  smooth(8);
  noFill();
  strokeWeight(1.5);
  strokeCap(ROUND);
  strokeJoin(ROUND);

  // Translate and scale circles
  // to make them fit in the sketch's center.
  x = width * 0.5;
  y = height * 0.5;
  scale = min(width, height) * 0.25;

  // Calculate points on reference circle.
  // The y-axis represents imaginary numbers.
  float iToTheta = TWO_PI / float(detail);
  for (int i = 0; i < detail; ++i) {
    float theta = i * iToTheta;
    circle[i] = new Complex(cos(theta), sin(theta));
  }

  // Create transformations.
  float jToStep = 1.0 / float(transformations - 1);
  for (int j = 0; j < transformations; ++j) {
    for (int i = 0; i < detail; ++i) {
      float step = j * jToStep;
      c.real = lerp(-1.0, 1.0, step);
      d.imaginary = lerp(-1.0, 1.0, step);
      transformed[j][i] = mobius(a, b, c, d, circle[i]);
    }
  }
}

void draw() {
  surface.setTitle(String.format("%.2f", frameRate));
  background(0xff000000);

  // Manipulate inputs arbitrarily.
  a.real = map(mouseX, 0, width, -1.0, 1.0);
  b.real = map(mouseY, 0, height, -1.0, 1.0);

  float animStep = frameCount * animIncr;
  a.imaginary = cos(animStep);
  b.imaginary = sin(animStep);

  // Draw reference circle.
  stroke(0xff404040);
  beginShape(POLYGON);
  for (int i = 0; i < detail; ++i) {
    vertex(x + circle[i].real * scale, 
      y + circle[i].imaginary * scale);
  }
  endShape(CLOSE);

  // Draw transformations.
  float iToStep = 1.0 / float(detail - 1);
  float jToStep = 1.0 / float(transformations - 1);
  for (int j = 0; j < transformations; ++j) {

    // Manipulate inputs arbitrarily.
    float jStep = j * jToStep;
    c.imaginary = lerp(-1.0, 1.0, jStep);
    d.imaginary = lerp(-1.0, 1.0, jStep);

    stroke(lerpColor(0xffff0000, 0xff00ffff, jStep, HSB));
    beginShape(POLYGON);
    for (int i = 0; i < detail; ++i) {

      // Manipulate inputs arbitrarily.
      float iStep = i * iToStep;
      c.real = lerp(0.0, 2.0, iStep);
      d.real = lerp(-2.0, 0.0, iStep);

      // Mobius transformation, where z is reference circle.
      mobius(a, b, c, d, circle[i], transformed[j][i]);

      vertex(x + transformed[j][i].real * scale, 
        y + transformed[j][i].imaginary * scale);
    }
    
    // Depending on how inputs are manipulated,
    // the resultant shape may or may not be a
    // closed circle.
    // endShape(CLOSE);
    endShape();
  }
}

```

I’ve assumed that the y-axis represents the imaginary component of the complex number. I imagine you’ll have to move beyond the out-of-the-box primitives (`ellipse`, `rect`, etc.). You could use `point`, then draw points at a high enough density to create a continuous form; use `beginShape`, `vertex` and `endShape` as above; or dig into the [pixels](https://processing.org/reference/pixels.html) array. I find it helpful to keep function inputs and outputs in the range -1 to 1 (or the valid ranges specified by the given formula), then for display purposes translate, rotate and scale them in a separate part of the code.

Adam J. Murray has a [gist](https://gist.github.com/adamjmurray/621594) exploring a Mobius tranformation in Processing as well (he uses a float array with two elements rather than define a Complex class).

Can’t speak to exponential grids or the second image posted, I’m afraid.

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [July 5, 2018, 5:11pm UTC](https://discourse.processing.org/t/exponential-grids-mobius-transformations/1347/6 "2018-07-05T17:11:53Z")

</div>

> [@behreajj](#):
>
> ( `static` functions are not available to classes created within the Processing IDE, …

Actually we can have `static` members inside nested classes as long as we declare those classes as `static` as well! ☕

For further info about that, go to this discussion thread: 🙋‍♂️

> [@Deeply-layered nested classes](https://discourse.processing.org/t/deeply-layered-nested-classes/805):
>
> Hello. I’m trying to make nested classes to make some sort of system in my classes. I am working insode Visual Studio Code, where you can hide lines of code. When I try: static class A{ static class B{ class C{ C(){} } } } A.B.C ins = new A.B.C(); it gives me an error: …\*\* No enclosing instance of type Test.A.B is accessible. Must qualify the allocation with an enclosing instance of type Test.A.B (e.g. x.new A() where x is an instance of Test.A.B).\* Whe…

---

<div class="post-metadata">

**Author:** ![jc2046](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jc2046/32/610_2.png) [@jc2046](https://discourse.processing.org/u/jc2046)\
**Post date:** [July 9, 2018, 7:25pm UTC](https://discourse.processing.org/t/exponential-grids-mobius-transformations/1347/7 "2018-07-09T19:25:09Z")

</div>

Wow. Thanks for the repplies, and for be so supportive, guys. Currently Im overflowing with a totally non related Processing project. In some time (maybe months) I will recover this thread and produce some output to show here.

That rotating rainbow sketch is delicious, by the way.

Thanks again and let the Mobius transfos be a party

---

<div class="post-metadata">

**Author:** ![jc2046](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jc2046/32/610_2.png) [@jc2046](https://discourse.processing.org/u/jc2046)\
**Post date:** [July 9, 2018, 7:36pm UTC](https://discourse.processing.org/t/exponential-grids-mobius-transformations/1347/8 "2018-07-09T19:36:38Z")

</div>

By the way, The second example that looks so convoluted is really quite simple. You only have to plot cosines or simple functions. Been in this expo plane instead of tipical linear is what does the magic. Wolfram has a lot of this ideas to explore:

[http://functions.wolfram.com/ElementaryFunctions/Cos/visualizations/7/ShowAll.html](http://functions.wolfram.com/ElementaryFunctions/Cos/visualizations/7/ShowAll.html)

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [September 1, 2018, 3:03am UTC](https://discourse.processing.org/t/exponential-grids-mobius-transformations/1347/9 "2018-09-01T03:03:37Z")

</div>

I recently saw a related github repo of a processing sketch by @alexmiller for the [Superformula](https://en.wikipedia.org/wiki/Superformula):

> **[alexdmiller/superformula-processing](https://github.com/alexdmiller/superformula-processing)**
>
> An implementation of the "Superformula" in Processing - alexdmiller/superformula-processing

People interested in similar geometric creations might want to check it out. It uses cp5 sliders.
