Math::...:Corner(3pm)

πŸ“¦
version 129 Β· 3 versions
, in debian bookworm, debian trixie, ubuntu jammy, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– Math::...:Corner(3pm) β€” the corner path bestie πŸ’–

okay so. this is Math::PlanePath::Corner, a little Perl module from the User Contributed Perl Documentation collection, and it's lowkey one of the cutest paths in the whole PlanePath family. it's in the Math::PlanePath::Corner namespace and it does exactly one thing: it lays points out in layers spiralling outwards from the corner of the first quadrant. iconic behaviour, no notes. πŸŽ€


✨ NAME ✨

Math::PlanePath::Corner β€” points shaped around in a corner πŸ’…


🌸 SYNOPSIS 🌸

use Math::PlanePath::Corner;
my $path = Math::PlanePath::Corner->new;
my ($x, $y) = $path->n_to_xy (123);

that's it. that's the whole vibe. create the path, ask it where point 123 lives, get coordinates back. πŸ¦‹


🫢 DESCRIPTION 🫢

so the way this works: points get dropped in layers that work outwards from the corner of the first quadrant. like nesting L-shapes, one inside the other, getting bigger. main character energy fr fr.

    5 | 26--...
      |
    4 | 17--18--19--20--21
      |                  |
    3 | 10--11--12--13  22
      |              |   |
    2 |  5-- 6-- 7  14  23
      |          |   |   |
    1 |  2-- 3   8  15  24
      |  |   |   |   |   |
  Y=0 |  1   4   9  16  25
      +---------------------
       X=0   1   2   3   4

see that horizontal run 1,4,9,16,etc along Y=0? those are the perfect squares. obviously. and it's not a coincidence, it's because every further row/column "gnomon" you slap onto a square makes it a one-bigger square:

                            10 11 12 13
               5  6  7       5  6  7 14
    2  3       2  3  8       2  3  8 15
    1  4       1  4  9       1  4  9 16

     2x2        3x3           4x4

and the points N=2,6,12,20,etc sitting on the diagonal X=Y-1 (going up from X=0,Y=1) are the pronic numbers k*(k+1) β€” the ones that are literally half way between the squares. cute lil in-betweeners. πŸ“

each gnomon is 2 longer than the one before it. this whole setup is similar to the "PyramidRows", "PyramidSides" and "SacksSpiral" paths. and heads up: "Corner" and "PyramidSides" are actually the same thing β€” the difference is that "PyramidSides" is stretched to two quadrants instead of one like the "Corner" here. same girl, different pose. πŸ’…

🌈 Wider

there's an optional wider => $integer that makes the path wider horizontally, so it turns into a rectangle. like so:

wider => 3

 4  |  29--30--31--...
    |
 3  |  19--20--21--22--23--24--25
    |                           |
 2  |  11--12--13--14--15--16  26
    |                       |   |
 1  |   5---6---7---8---9  17  27
    |                   |   |   |
Y=0 |   1---2---3---4  10  18  28
    |
     -----------------------------
        ^
       X=0  1   2   3   4   5   6

so each gnomon's horizontal part is wider many steps longer. and it's still 2 longer than the previous one, because this widening is a constant amount every time. consistent queen. πŸ‘‘

⭐ N Start

by default, numbering starts at N=1 like we showed above. but you can pass an optional n_start to start somewhere else while keeping the same shape and everything. for example, starting at 0:

n_start => 0

  5  |  25 ...
  4  |  16 17 18 19 20
  3  |   9 10 11 12 21
  2  |   4  5  6 13 22
  1  |   1  2  7 14 23
Y=0  |   0  3  8 15 24
      -----------------
       X=0   1   2   3

with Nstart=0, the squares end up on the Y axis and the pronic numbers end up on the X=Y leading diagonal. shakeup! πŸ”₯


πŸ’œ FUNCTIONS πŸ’œ

there are shared behaviours common to all path classes β€” go peek at "FUNCTIONS" in Math::PlanePath for those. here's what's specific to this babe:

  • "$path = Math::PlanePath::Corner->new ()"
  • "$path = Math::PlanePath::Corner->new (wider => $w, n_start => $n)" β€” create and return a brand new path object. yes you can pass wider and n_start right there. go off. ✨
  • "($x,$y) = $path->n_to_xy ($n)" β€” return the X,Y coordinates of point number $n on the path.
for "$n < n_start()-0.5" the return is an empty list. there's an extra 0.5 before Nstart, but nothing further before there. so don't come looking, nothing's home. πŸ™ˆ
  • "$n = $path->xy_to_n ($x,$y)" β€” return the point number for coordinates "$x,$y".

$x and $y are each rounded to the nearest integer, which basically treats each point as a square of side 1, so the quadrant x>=-0.5 and y>=-0.5 is entirely covered.

  • "($n_lo, $n_hi) = $path->rect_to_n_range ($x1,$y1, $x2,$y2)" β€” the returned range is exact, meaning $n_lo and $n_hi are the smallest and biggest values in the rectangle. no guesswork, we're precise here. 🎯

🧚 FORMULAS 🧚

πŸ’« N to X,Y

counting d=0 for the first L-shaped gnomon at Y=0, the start of the gnomon is:

StartN(d) = d^2 + 1 = 1,2,5,10,17,etc

the current "n_to_xy()" code extends to the left by an extra 0.5 for fractional N, so like N=9.5 sits at X=-0.5,Y=3. with that, the starting N for each gnomon d is:

StartNfrac(d) = d^2 + 0.5

inverting that gives you the gnomon d number for an N:

d = floor(sqrt(N - 0.5))

subtracting the gnomon start gives you an offset into that gnomon:

OffStart = N - StartNfrac(d)

the corner point 1,3,7,13,etc β€” the spot where the gnomon turns down β€” is at d+0.5 into that remainder, and it's convenient to subtract that, so you get negative for the horizontal and positive for the vertical:

Off = OffStart - (d+0.5)
    = N - (d*(d+1) + 1)

then the X,Y coordinates are:

if (Off < 0)  then  X=d+Off, Y=d
if (Off >= 0) then  X=d,     Y=d-Off

πŸ’« X,Y to N

for a given X,Y, the bigger of X or Y determines the d gnomon.

if Y>=X then X,Y is on the horizontal part. at X=0 you have N=StartN(d) per the Start(N) formula above, and any further X is just an offset from there:

if Y >= X then
  d=Y
  N = StartN(d) + X
    = Y^2 + 1 + X

otherwise, if Y<X, then X,Y is on the vertical part. at Y=0, N is the last point on the gnomon, and one back from the start of the following gnomon:

if Y <= X then
  d=X
  LastN(d) = StartN(d+1) - 1
           = (d+1)^2
  N = LastN(d) - Y
    = (X+1)^2 - Y

πŸ’« Rectangle N Range

for "rect_to_n_range()", in each row, increasing X means increasing N, so the smallest N is in the leftmost column and the biggest N is in the rightmost column.

|
|  ------>  N increasing
|
 -----------------------

going up a column, N values increase away from the X=Y diagonal, up or down, and all N values above X=Y are bigger than the ones below.

|    ^  N increasing up from X=Y diagonal
|    |
|    |/
|    /
|   /|
|  / |  N increasing down from X=Y diagonal
| /  v
|/
 -----------------------

which means the biggest N is the top right corner if that corner is Y>=X, otherwise it's the bottom right corner.

                                       max N at top right
|      /                          | --+     if corner Y>=X
|     / --+                       |   | /
|    /    |                       |   |/
|   /     |                       |   |
|  /  ----v                       |  /|
| /     max N at bottom right     | --+
|/        if corner Y<=X          |/
 ----------                        -------

and for the smallest N: if the bottom left corner has Y>X then it's in the "increasing" part and that bottom left corner is the smallest N. otherwise Y<=X means some of the "decreasing" part is covered, and the smallest N is at Y=min(X,Ymax) β€” i.e. either the Y=X diagonal if it's inside the rectangle, or the top right corner otherwise.

|      /
| |   /
| |  /  min N at bottom left
| +----  if corner Y>X
|  /
| /
|/
 ----------

|      /                           |      /
|   | /                            |     /
|   |/  min N at X=Y               |    /
|   *    if diagonal crossed       |   / +-- min N at top left
|  /|                              |  /  |    if corner Y<X
| / +-----                         | /   |
|/                                 |/
 ----------                         ----------

min N at Xmin,Ymin            if Ymin >= Xmin
         Xmin,min(Xmin,Ymax)  if Ymin <= Xmin

🌟 OEIS 🌟

this path shows up in Sloane's Online Encyclopedia of Integer Sequences, as:

<http://oeis.org/A196199> (etc)

wider=0, n_start=1 (the defaults)
  A213088    X+Y sum
  A196199    X-Y diff, being runs -n to +n
  A053615    abs(X-Y), runs n to 0 to n, distance to next pronic

  A000290    N on X axis, perfect squares starting from 1
  A002522    N on Y axis, Y^2+1
  A002061    N on X=Y diagonal, extra initial 1
  A004201    N on and below X=Y diagonal, so X>=Y

  A020703    permutation N at transpose Y,X
  A060734    permutation N by diagonals up from X axis
  A064790     inverse
  A060736    permutation N by diagonals down from Y axis
  A064788     inverse

  A027709    boundary length of N unit squares
  A078633    grid sticks of N points

n_start=0
  A000196    max(X,Y), being floor(sqrt(N))

  A005563    N on X axis, n*(n+2)
  A000290    N on Y axis, perfect squares
  A002378    N on X=Y diagonal, pronic numbers

n_start=2
  A059100    N on Y axis, Y^2+2
  A014206    N on X=Y diagonal, pronic+2

wider=1
  A053188    abs(X-Y), dist to nearest square, extra initial 0
wider=1, n_start=0
  A002378    N on Y axis, pronic numbers
  A005563    N on X=Y diagonal, n*(n+2)
wider=1, n_start=2
  A014206    N on Y axis, pronic+2

wider=2, n_start=1
  A028387    N on X=Y diagonal, k*(k+3) + 1
wider=2, n_start=0
  A005563    N on Y axis, (Y+1)^2-1
  A028552    N on X=Y diagonal, k*(k+3)

wider=3, n_start=0
  A028552    N on Y axis, k*(k+3)

πŸ‘‘ SEE ALSO πŸ‘‘

Math::PlanePath, Math::PlanePath::PyramidSides, Math::PlanePath::PyramidRows, Math::PlanePath::SacksSpiral, Math::PlanePath::Diagonals


🌈 HOME PAGE 🌈

<http://user42.tuxfamily.org/math-planepath/index.html>


πŸŽ€ LICENSE πŸŽ€

Copyright 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Kevin Ryde

this file is part of Math-PlanePath.

Math-PlanePath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.

Math-PlanePath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. see the GNU General Public License for more details.

you should have received a copy of the GNU General Public License along with Math-PlanePath. if not, see <http://www.gnu.org/licenses/>.

fr fr read the license, bestie. no warranty is no warranty. πŸ’€

and that's the whole page!! this was perl v5.32.0, dated 2021-01-23, from Math::...:Corner(3pm). stay cornered, stay iconic, mwah πŸ’–βœ¨