Math::...Octant(3pm)

๐Ÿ“ฆ
version 129 ยท 3 versions
, in debian bookworm, debian trixie, ubuntu jammy, ubuntu noble, ubuntu resolute, ubuntu stonking

๐ŸŒธ NAME ๐ŸŒธ

okay so welcome to the manual page for Math::...Octant(3pm), bestie ๐Ÿ’–

Math::PlanePath::DiagonalsOctant โ€” points in diagonal stripes for an eighth of the plane โœจ


๐Ÿฆ‹ SYNOPSIS ๐Ÿฆ‹

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

๐Ÿ’œ DESCRIPTION ๐Ÿ’œ

so the vibe is: this path walks successive diagonals downwards from the Y axis all the way down to the X=Y centre line, cruising through the eighth of the plane that sits on and above X=Y. it's giving orderly. it's giving diagonal. ๐Ÿ”ฅ

   8 |  21 27 33 40 47 55 63 72 81
     |    \  \  \  \  \  \  \
   7 |  17 22 28 34 41 48 56 64
     |    \  \  \  \  \  \
   6 |  13 18 23 29 35 42 49
     |    \  \  \  \  \
   5 |  10 14 19 24 30 36
     |    \  \  \  \
   4 |   7 11 15 20 25
     |    \  \  \
   3 |   5  8 12 16
     |    \  \
   2 |   3  6  9
     |    \
   1 |   2  4
     |
 Y=0 |   1
     + ----------------------------
       X=0  1  2  3  4  5  6  7  8

N=1,4,9,16,etc sitting right on the X=Y leading diagonal? those are the perfect squares ๐ŸŽ€ and N=2,6,12,20,etc chilling at the ends of the other diagonals are the pronic numbers k*(k+1). math ate, no cap ๐Ÿ’…

fun little aside: "octant" normally means an eighth of a 3-dimensional coordinate space. but since PlanePath is only 2 dimensions there's zero confusion, and at the risk of abusing nomenclature, half a quadrant gets reckoned as an "octant" here ๐Ÿ™ˆ

๐ŸŒˆ Pyramid Rows ๐ŸŒˆ

ok so take two diagonals running from k^2+1 to (k+1)^2 โ€” that's literally the same thing as a row of the step=2 PyramidRows (peep Math::PlanePath::PyramidRows). each endpoint is identical, except here it's two diagonals instead of one row. for example, in PyramidRows the Y=3 row runs from N=10 to N=16, ending at X=3,Y=3. here that same thing is two diagonals โ€” N=10 to N=12 and then N=13 to N=16 โ€” and that N=16 endpoint is the exact same X=3,Y=3. iconic parallel โœจ

๐Ÿงš Direction ๐Ÿงš

the option direction => 'up' flips the order inside each diagonal and counts upward from the centre out to the Y axis ๐Ÿ”„

   8 |  25 29 34 39 45 51 58 65 73
     |    \  \  \  \  \  \  \
   7 |  20 24 28 33 38 44 50 57
     |    \  \  \  \  \  \
   6 |  16 19 23 27 32 37 43
     |    \  \  \  \  \
   5 |  12 15 18 22 26 31
     |    \  \  \  \
   4 |   9 11 14 17 21             direction => "up"
     |    \  \  \
   3 |   6  8 10 13
     |    \  \
   2 |   4  5  7
     |    \
   1 |   2  3
     |
 Y=0 |   1
     +---------------------------
       X=0  1  2  3  4  5  6  7  8

in this arrangement N=1,2,4,6,9,etc on the Y axis are alternately the squares and the pronic numbers โ€” squares land on even Y and pronic on odd Y. alternating queen ๐Ÿ‘‘

๐Ÿ’– N Start ๐Ÿ’–

default behaviour is numbering points starting at N=1, just like the picture up there. but there's an optional n_start that lets you kick things off somewhere else, keeping the same diagonals sequence. for example, starting at 0:

   n_start => 0                    n_start=>0
   direction => "down"             direction=>"up"

     6  | 12                        | 15
     5  |  9 13                     | 11 14
     4  |  6 10 14                  |  8 10 13
     3  |  4  7 11 15               |  5  7  9 12
     2  |  2  5  8                  |  3  4  6
     1  |  1  3                     |  1  2
   Y=0  |  0                        |  0
        +--------------             +--------------
         X=0  1  2  3                X=0  1  2  3

๐Ÿ‘‘ FUNCTIONS ๐Ÿ‘‘

if you want the behaviour that every path class shares, go read "FUNCTIONS" in Math::PlanePath ๐Ÿซถ

  • $path = Math::PlanePath::DiagonalsOctant->new ()
  • $path = Math::PlanePath::DiagonalsOctant->new (direction => $str, n_start => $n) โ€” creates and returns a brand new path object. fresh out the box ๐ŸŽ
  • ($x,$y) = $path->n_to_xy ($n) โ€” returns the X,Y coordinates of point number $n on the path. โ€” heads up tho: for "$n < 0.5" the return is an empty list, because the path is considered to begin at 1. no point number 0 energy here ๐Ÿ’€
  • $n = $path->xy_to_n ($x,$y) โ€” returns the point number for coordinates "$x,$y". both $x and $y get rounded to the nearest integer, which has the effect of treating each point $n as a square of side 1. squares within squares, we love a fractal moment ๐Ÿฆ‹
  • ($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 genuinely the smallest and biggest values in the rectangle. no approximations, we don't do that here โœจ

๐Ÿ’… FORMULAS ๐Ÿ’…

๐ŸŒธ N to X,Y ๐ŸŒธ

to break N into X,Y it's convenient to take two diagonals at a time, since the length then changes by 1 each pair, which makes a quadratic. starting at each X=0,Y=odd just after a perfect square N lets you get away with just a sqrt ๐Ÿ˜Œ

Nstart = d*d+1

where d numbers diagonal pairs, eg. d=3 for X=0,Y=5 going down. and this reverses super easily as:

d = floor sqrt(N-1)

the code reckons the start of the diagonal as 0.5 further back, so that N=9.5 sits at X=-.5,Y=5.5. to do that, d gets formed as:

d = floor sqrt(N-0.5)
  = int( sqrt(int(4*$n)-2)/2 )

taking the /2 out of the sqrt helps with "Math::BigInt" which circa Perl 5.14 doesn't inter-operate with flonums very well. it's giving compatibility struggles ๐Ÿ˜ญ

in any case N-Nstart is an offset into two diagonals โ€” the first one of length d many points, the second one d+1. for example d=3 starting Y=5 covers points N=10,11,12 followed by Y=6 N=13,14,15,16.

the formulas get simplified by calculating a remainder relative to the second diagonal, so it's negative for the first and positive for the second:

Nrem = N - (d*(d+1)+1)

d*(d+1)+1 is 1 past the pronic numbers when ending each first diagonal, as described above. anyway, for example d=3 is relative to N=13, making Nrem=-3,-2,-1 or Nrem=0,1,2,3.

to include that preceding 0.5 in the second diagonal, it simply means reckoning Nrem>=-0.5 as belonging to the second. in that base:

if Nrem >= -0.5
  X = Nrem            # direction="down"
  Y = 2*d - Nrem
else
  X = Nrem + d
  Y = d - Nrem - 1

for example N=15 gives Nrem=1 which is the first case, so X=1, Y=2*3-1=5. or N=11 gives Nrem=-2 which is the second case, so X=-2+3=1, Y=3-(-2)-1=4. math checks out bestie ๐Ÿงฎ

for "up" direction the Nrem and d are the same, but the coordinate directions reverse:

if Nrem >= -0.5
  X = d - Nrem        # direction="up"
  Y = d + Nrem
else
  X = -Nrem - 1
  Y = 2d + Nrem

another way is to reckon Nstart from the X=0,Y=even diagonals, which then gives two diagonals of the same length, and d gets formed by a sqrt inverting a pronic Nstart=d*(d+1). two ways to slay the same problem ๐Ÿ’…

๐ŸŒˆ Rectangle to N Range ๐ŸŒˆ

within each row, increasing X is increasing N. within each column, increasing Y is increasing N. and this holds true in both the "down" and "up" arrangements. on that basis, in a rectangle the lower left corner is the minimum N and the upper right is the maximum N โœจ

if the rectangle is partly outside the covered octant then the corners have to be shifted to put them in range, ie. trim off any rows or columns entirely outside the rectangle. for the lower left this means:

     |  |    /
     |  |   /
     +--------          if x1 < 0 then x1 = 0
   x1   | /             increase x1 to within octant
        |/
        +

        |  |/
        |  |            if y1 < x1 then y1 = x1
        | /|            increase y1 to bottom-left within octant
        |/ +----y1
        +  x1

and for the top right:

        |    /  x2
        | ------+ y2    if x2 > y2 then x2 = y2
        |  /    |       decrease x2 so top-right within octant
        | /     |         (the end of the y2 row)
        |/
        +

๐Ÿ”ฅ OEIS ๐Ÿ”ฅ

entries in Sloane's Online Encyclopedia of Integer Sequences related to this path include:

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

direction=down
  A002620    N at end each run X=k,Y=k and X=k,Y=k+1
direction=down, n_start=0
  A055087    X coord, runs 0 to k twice
  A082375    Y-X, runs k to 0 or 1 stepping by 2
  A005563    N on X=Y diagonal, X*(X+2)

direction=up
  A002620    N on Y axis, end of each run, quarter squares
direction=up, n_start=0
  A024206    N on Y axis (starting from n=1 is Y=0, so Y=n-1)
  A014616    N in column X=1 (is Y axis N-1, from N=3)
  A002378    N on X=Y diagonal, pronic X*(X+1)

either direction, n_start=0
  A055086    X+Y, k repeating floor(k/2)+1 times

A004652      N start and end of each even-numbered diagonal
A274427      map to N of full Diagonals

permutations
  A056536     N of PyramidRows in DiagonalsOctant order
  A091995      with DiagonalsOctant direction=up
  A091018      N-1, ie. starting from 0
  A090894      N-1 and DiagonalsOctant direction=up

  A056537     N of DiagonalsOctant at X,Y in PyramidRows order
               inverse of A056536

sequence cataloguing is such a mood ๐ŸŽ€


โญ SEE ALSO โญ

Math::PlanePath, Math::PlanePath::Diagonals, Math::PlanePath::DiagonalsAlternating, Math::PlanePath::PyramidRows


๐ŸŒˆ HOME PAGE ๐ŸŒˆ

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


๐Ÿ’– LICENSE ๐Ÿ’–

Copyright 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/>.

legal bestie moment: that "no warranty" bit is real and it matters, so don't come for anyone if it breaks ๐Ÿ’€

and that's a wrap!! this page was living its best life as perl v5.32.0, dated 2021-01-23, and it's the Math::...Octant(3pm) manual. go build some diagonal stripes, you absolute icon ๐Ÿซถโœจ๐Ÿ’