Last active
February 19, 2022 17:03
-
-
Save hazpotts/ac0b6f872600ceb7f95d to your computer and use it in GitHub Desktop.
Small algorithm for calculating coordinates on a spiral
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* Calculates the coordinates from an Id. The counting starts from 0,0 and then spirals out | |
* like this: | |
* | |
* +--+--+--+--> | |
* | | |
* + +--+--+--+ | |
* | | | | |
* + + +--+ + | |
* | | | | | |
* + +--+--+ + | |
* | | | |
* +--+--+--+--+ | |
* | |
* Where id 24 would be 1,2 (x = 1, y = 2) | |
* Where id 18 would be -2,-1 (x = -2, y = -1) | |
* | |
* 21--22--23--24--15 | |
* | | |
* 20 7---8---9---10 | |
* | | | | |
* 19 6 1---2 11 | |
* | | | | | |
* 18 5---4---3 12 | |
* | | | |
* 17--16--15--14--13 | |
* | |
* This is calculated by finding the square root of the id, using that to get | |
* the closest odd whole (perfect) square roots above and below it, to get the | |
* start and end points of the ring of the spiral that it is on. | |
* From there the side of the ring is calculated and the position along that side. | |
*/ | |
function coordinates($id) { | |
if ($id == 1) { | |
$x = 0; | |
$y = 0; | |
} | |
else { | |
$idSqrt = sqrt($id); //find the square root of the id | |
$lowSqrt = floor($idSqrt); //round the square root down | |
$highSqrt = ceil($idSqrt); //round the square root up | |
if ($lowSqrt == $highSqrt) { //if they are the same it's the last position | |
$lowSqrt = $lowSqrt - 2; //to calculate previous odd square root | |
} | |
if ($lowSqrt % 2 == 0) { //if in the second half of the ring the low root is even, need to find the previous odd because centered rings are odd number sided squares | |
$lowSqrt--; | |
} | |
if ($highSqrt % 2 == 0) { //same but for first half and high root | |
$highSqrt++; | |
} | |
$previousRingEnd = pow($lowSqrt, 2); //square root rounded down and then squared finds the number at the end of the previous ring | |
$ringEnd = pow($highSqrt, 2); //the same but for the end of the current ring | |
$ringPosition = $id - $previousRingEnd; // (15-9 = 6) taking the previous ring from the id finds the position around the current ring | |
$ringTotal = $ringEnd - $previousRingEnd; // (25-9 = 16) taking the previous ring from the current finds the total count around the current ring | |
$sideLengthMinusOne = $ringTotal / 4; // 16/4 = 4 | |
$halfSideLengthMO = $sideLengthMinusOne / 2; // 4/2 = 2 | |
$side = $ringPosition/$ringTotal; | |
/* | |
* This calculates what side it's on | |
* and it's position along that side. | |
* Corner positions count as being the last on the side | |
* hence the minus 1 on side length, because the first | |
* corner of each side counted for the previous side. | |
* Corners could be calculated from either side that they | |
* are a part of. | |
*/ | |
switch (true) { | |
case $side <= 0.25: // right hand side | |
$x = $halfSideLengthMO; | |
$y = $halfSideLengthMO - $ringPosition; | |
break; | |
case $side <= 0.5: // bottom | |
$x = $halfSideLengthMO - ($ringPosition - $sideLengthMinusOne); | |
$y = -$halfSideLengthMO; | |
break; | |
case $side <= 0.75: // left hand side | |
$x = -$halfSideLengthMO; | |
$y = -$halfSideLengthMO + ($ringPosition - ($sideLengthMinusOne*2)); | |
break; | |
case $side > 0.75: // top | |
$x = -$halfSideLengthMO + ($ringPosition - ($sideLengthMinusOne*3)); | |
$y = $halfSideLengthMO; | |
break; | |
} | |
} | |
return compact('x','y'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment