Math-PlanePath
view release on metacpan or search on metacpan
lib/Math/PlanePath/Corner.pm view on Meta::CPAN
Return the X,Y coordinates of point number C<$n> on the path.
For C<$n < n_start()-0.5> the return is an empty list. There's an extra 0.5
before Nstart, but nothing further before there.
=item C<$n = $path-E<gt>xy_to_n ($x,$y)>
Return the point number for coordinates C<$x,$y>.
C<$x> and C<$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.
=item C<($n_lo, $n_hi) = $path-E<gt>rect_to_n_range ($x1,$y1, $x2,$y2)>
The returned range is exact, meaning C<$n_lo> and C<$n_hi> are the smallest
and biggest in the rectangle.
=back
=head1 FORMULAS
=head2 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 C<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
=head2 X,Y to N
For a given X,Y the bigger of X or Y determines the d gnomon.
If YE<gt>=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 YE<lt>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
=head2 Rectangle N Range
For C<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 YE<gt>=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 YE<gt>X then it's in the
"increasing" part and that bottom left corner is the smallest N. Otherwise
YE<lt>=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.
| /
( run in 2.677 seconds using v1.01-cache-2.11-cpan-df04353d9ac )