Provided by: libmath-planepath-perl_129-1_all bug

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);

DESCRIPTION

       This path puts points in layers working outwards from the corner of the first quadrant.

             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

       The horizontal 1,4,9,16,etc along Y=0 is the perfect squares.  This is since each further
       row/column "gnomon" added to a square makes 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

       N=2,6,12,20,etc on the diagonal X=Y-1 up from X=0,Y=1 is the pronic numbers k*(k+1) which
       are half way between the squares.

       Each gnomon is 2 longer than the previous.  This is similar to the "PyramidRows",
       "PyramidSides" and "SacksSpiral" paths.  The "Corner" and the "PyramidSides" are the same
       but "PyramidSides" is stretched to two quadrants instead of one for the "Corner" here.

   Wider
       An optional "wider => $integer" makes the path wider horizontally, becoming a rectangle.
       For example

           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

       Each gnomon has the horizontal part "wider" many steps longer.  Each gnomon is still 2
       longer than the previous since this widening is a constant amount in each.

   N Start
       The default is to number points starting N=1 as shown above.  An optional "n_start" can
       give a different start with the same shape etc.  For example to start 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

       In Nstart=0, the squares are on the Y axis and the pronic numbers are on the X=Y leading
       diagonal.

FUNCTIONS

       See "FUNCTIONS" in Math::PlanePath for behaviour common to all path classes.

       "$path = Math::PlanePath::Corner->new ()"
       "$path = Math::PlanePath::Corner->new (wider => $w, n_start => $n)"
           Create and return a new path object.

       "($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.

       "$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 has the effect of treating
           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 in
           the rectangle.

FORMULAS

   N to X,Y
       Counting d=0 for the first L-shaped gnomon at Y=0, then 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 for
       example N=9.5 is at X=-0.5,Y=3.  With this the starting N for each gnomon d is

           StartNfrac(d) = d^2 + 0.5

       Inverting gives the gnomon d number for an N,

           d = floor(sqrt(N - 0.5))

       Subtracting the gnomon start gives an offset into that gnomon

           OffStart = N - StartNfrac(d)

       The corner point 1,3,7,13,etc where the gnomon turns down is at d+0.5 into that remainder,
       and it's convenient to subtract that so 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 have N=StartN(d) per the Start(N)
       formula above, and any further X is 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 is increasing N so the smallest N is in
       the leftmost column and the biggest N in the rightmost column.

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

       Going up a column, N values are increasing 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
           |/
            -----------------------

       This means the biggest N is the top right corner if that corner is Y>=X, otherwise the
       bottom right corner.

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

       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), ie. either the Y=X
       diagonal if it's in 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 is 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/>.