1

I've made a solar system animation some time ago and I'm rewriting it now. I'll be adding gravity effect to masses, and to make the effect visible, I've turned the background into a grid.

I'll be adding two different effects; pinch and twirl. I'm following the tutorial on Geek Office Dog: Hello swirl! (A swirl effect tutorial in javascript). Going step by step, first, I want to understand how rotation works.

This is the simple rotation demo excerpt form the site: jsFiddle. The code seemed chaotic to me, so I modified and simplified it: jsFiddle.

var canvas  = document.getElementById("canvas");
var context = canvas.getContext("2d");

var img = new Image();
img.src = document.getElementById("test-image").src;

img.onload = function () {
  context.drawImage(img, 0, 0);

  originalImageData    = context.getImageData(0, 0, canvas.width, canvas.height);
  originalPixels       = originalImageData.data;
  transformedImageData = context.createImageData(originalImageData);
  transformedPixels    = transformedImageData.data;

  originX = 100;
  originY = 100;
  radius  = 50;

  // copying the original pixels into transformed pixels
  for (var y = 0; y < originalImageData.height; y++) {
    for (var x = 0; x < originalImageData.width; x++) {
      var position = (y * originalImageData.width + x) * 4;
      transformedPixels[position + 0] = originalPixels[position + 0];
      transformedPixels[position + 1] = originalPixels[position + 1];
      transformedPixels[position + 2] = originalPixels[position + 2];
      transformedPixels[position + 3] = originalPixels[position + 3];
    }
  }

  // Iterate over the interest square region
  for (var y = -radius; y < radius; y++) {
    for (var x = -radius; x < radius; x++) {

      // Check if the pixel is inside the effect circle
      if (x * x + y * y <= radius * radius) {

        // Get the pixel array position
        var sourcePosition = (y + originY) * originalImageData.width + x + originX;
        sourcePosition *= 4;

        // Transform the pixel cartesian coordinates (x, y) to polar coordinates (r, angle)
        var r = Math.sqrt(x * x + y * y);
        var angle = Math.atan2(y, x);
        // convert the angle from radian to degree 
        var degrees = (angle * 180.0) / Math.PI;
        // rotate the pixels
        degrees -= 30.0;
        // Transform back from polar coordinates to cartesian 
        angle = (degrees * Math.PI) / 180.0;
        var newY = Math.floor(r * Math.sin(angle));
        var newX = Math.floor(r * Math.cos(angle));

        // Get the new pixel location 
        var destPosition = (newY + originY) * originalImageData.width + newX + originX;
        destPosition *= 4;

        transformedPixels[destPosition + 0] = originalPixels[sourcePosition + 0];
        transformedPixels[destPosition + 1] = originalPixels[sourcePosition + 1];
        transformedPixels[destPosition + 2] = originalPixels[sourcePosition + 2];
        transformedPixels[destPosition + 3] = originalPixels[sourcePosition + 3];
      }
    }
  }
  context.putImageData(transformedImageData, 0, 0);
};
<table>
 <tr>
  <td>image</td>
  <td>image</td>
  <td>canvas</td>
 </tr>
 <tr>
  <td><img id="test-image" border="1" src="data:image/png;base64,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"></td>
  <td><img id="image-area" border="1" src="http://i1115.photobucket.com/albums/k544/akinuri/download%201.png"></td>
  <td><canvas id="canvas" style="border: 1px solid blue" width="227" height="213"></canvas></td>
 </tr>
</table>

I didn't understand the // Iterate over the interest square region part. Why is it looping between -radius and radius and how exactly does x * x + y * y <= radius * radius check if the pixel is inside the circle?

I can't visualize what's going on in that part of the code in my mind. Yet.


Update: Okay, so after giving it some thought, I'm thinking that at the loops:

// Iterate over the interest square region
    for (var y = -radius; y < radius; y++) {
        for (var x = -radius; x < radius; x++) {

            // Check if the pixel is inside the effect circle
            if (x * x + y * y <= radius * radius) {

we're not actually iterating the area on the image, but a theoretical area.

enter image description here

and checking if the current (x,y) is inside the circle. And if it is, in the next line of code, we calculate the actual position of (x,y) on the image:

// Get the pixel array position
var sourcePosition = (y + originY) * originalImageData.width + x + originX;
sourcePosition *= 4;

Loops (+ if) just give us the coordinates of every pixel inside the circle, and then we shift these (x,y) coordinates by (originX, originY) values so that we can get the actual coordinates on the image.

Am I correct? Am I? (excuse my excitement :)

akinuri
  • 10,690
  • 10
  • 65
  • 102
  • 1
    On a circle the point at x,y is always 1 radius from the origin. Pythagoras gives us x^2 + y^2 = radius^2 for all points on the circle. So less-than yields points inside the circle and greater than yields points outside. – James Nov 01 '15 at 19:27

1 Answers1

3

Easy part first :)

x * x + y * y <= radius * radius

this is just Pythagoras:

enter image description here

And now if you look at that picture it's also somewhat obvious that x and y oscillate between -r and r right? :) Just imagine what those coordinates would be at every topmost leftmost ... point of the circle :)

Armin Braun
  • 3,645
  • 1
  • 17
  • 33
  • You answer gave me some thoughts and I've updated the question. Can you check if it is correct, and advise if it's not? – akinuri Nov 02 '15 at 17:23
  • 1
    Read the update :) Looks good, I think you got it right. What I would suggest to you, is take this up as a learning opportunity and rather than ask me, check yourself ;)! You got a bunch of code there and were clearly able to identify each part of it doing a certain specific task. Just take the individual parts ( say converting coordinates from real to imaginary, converting the other way around, looping over the iterations on the position) and turn them into proper functions each! – Armin Braun Nov 02 '15 at 18:59