---
name: "Math::PlanePath::Corner"
section: "3pm"
platform: "linux"
package: "libmath-planepath-perl"
version: "129-1"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/Math::PlanePath::Corner"
---

# Math::PlanePath::Corner(3pm)

## 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/\>.
