Complex coordinate to screen coordinate problem

affine-geometrycomplex numberscoordinate systemslinear-transformations

As an expansion to my fractal software, I've decided to add center plus width as an image location/definition. Which leads me to the question of how do I convert the complex number given to an x,y coordinate on the screen plane. Obviously, I do this when I calculate the image as I iterate a given function, but I do that in terms that are not applicable to the 'free-standing' number I want to deal with. I can go in the other direction with no problem but have not been able to figure this one out. The downside of doing mathematics without being a mathematician! In short, complex to screen conversion—how? As an example of screen to complex conversion her is the function I use for that:

scr2Pix = (pX, pY, pW, pH, minX, maxX, minY, maxY) ->
  xPercent = pX / pW
  yPercent = pY / pH
  newX = minX + (maxX - minX) * xPercent;
  newY = minY + (maxY - minY) * yPercent;
  [newX, newY]

The language is coffeescript. The parameters are better shown in this snippet:

x1 = -2.5 #! lower left X—complex
y1 = -1.5 #! lower left Y—complex
x2 = 1.5  #! upper right X—complex
y2 = 1.5  #! upper right Y—complex

console.log scr2Pix(320,240,640,480,x1,x2,y1,y2)

with a return value of [-0.5, 0], in effect asking for the conversion of 320,240 to a complex number. NB pW is screen width, pH is screen height, with pX and pY being the coordinates of the location I'd like to convert.

I believe what I'm looking for is pix2Scr() not so much as code, but as an algorithm that I can add to my collection.

The proposed answer coded inline as:

Sw = 640
w = 4
Sh = 480
x = -0.5
y = 0

nx = (Sw/(2*w)) * x + (-Sw/2)
ny = (Sw/(2*w)) * -y + (-Sh/2)

console.log nx,ny

produces -360 -240 which is correct except for sign so I've put in one too many minus signs somewhere?

Best Answer

First, let me clarify my interpretation of the problem. Your additional context was a great help in getting this far, but I may have misunderstood.

Let the location to be displayed be represented by $x_0+iy_0\in\mathbb C$ and $w\in\mathbb R$. My understanding is that $w$ represents a positive distance so that we want to map

  • from a rectangle lying between the vertical lines described by $x=x_0-w/2$ and $x=x_0+w/2$ centered on $x_0+iy_0$

  • to screen coordinates so that the image of $x_0+iy_0$ is centered in the screen and the picture fills the screen (aspect ratio preserved)


Three basic things need to happen

  1. Scale the plane;
  2. Reflect the plane over the $x$ axis, since the display uses left-handed coordinates; and
  3. translate the image of $x_0+iy_0$ to the center of the display.

Tackling 1) first: Let $S_w$ and $S_h$ denote the number of pixels in the width and height of the image, respectively. To make a rectangle that used to be $2w$ wide fit in a space that is $S_w$ pixels wide, we'll scale by a factor of $\lambda =\frac{S_w}{w}$.

Now 2): So far, we've mapped the complex plane into a (right-handed) pixel plane. To reverse the direction of the $y$ axis, we make the appropriate transformation. If you are thinking of things in terms of complex mappings, that is what the complex conjugate map does, and if you are thinking in terms of linear transformations on $\mathbb R\times\mathbb R$ then you would use the matrix $\begin{bmatrix}1&0\\0&-1\end{bmatrix}$ .

Now 3): If you were to use these transformations right now and map the whole plane to your screen, all you'd see is an image of quadrant $IV$ of the complex plane. The center that you want ($p_2=\lambda(x_0, -y_0)$ in the new coordinates) is probably nowhere in sight. Centered on your screen is the point $p_1=(S_w/2, S_h/2)$, by definition.

So the requisite translation is to add $p_1-p_2$ to each point of the screen plane.

I'll write out the whole transformation now, all in terms of $w,x_0, y_0, S_w,S_h$:

$$ (x,y)\mapsto \frac{S_w}{w}(x,-y)+(-\frac{S_w}{w}x_0+\frac{S_w}{2},\frac{S_w}{w}y_0+\frac{S_h}{2}) $$

In the example you gave with $w=4$, $x_0=-1/2$ and $y_0=0$, $S_w=640$ and $S_h=480$, this turns into

$$ (x,y)\mapsto 160(x,-y)+(400,240) $$

This maps $(-1/2,0)$ to $(320, 240)$,

and $(-5/2,0)$ to $(0, 240)$,

and $(3/2,0)$ to $(640, 240)$,

as expected.

Or, to rewrite it in terms of $z\in\mathbb C$ where $z_0=x_0+iy_0$:

$$ z\mapsto \frac{S_w}{w}\overline{(z-z_0)}+\frac{S_w}{2}+i\frac{S_h}{2} $$


Another way to do this would have been to use four-point correspondence to compute the affine transformation. It is a very general algorithm which can compute the affine transformation needed to map from one plane in $3$-space to another plane.

Actually for an affine transformation like this one, only three points are necessary because things simplify a little since you are moving around the same plane.

Related Question