The Perl Toolchain Summit 2025 Needs You: You can help 🙏 Learn more

#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#define XX 0
#define YY 1
MODULE = Algorithm::Line::Lerp PACKAGE = Algorithm::Line::Lerp
SV *
bline(SV* sp1, SV* sp2)
PROTOTYPE: $$
PREINIT:
AV* ap1;
AV* ap2;
AV* theline;
AV* point;
long x0, y0, x1, y1, dx, dy, sx, sy, err, e2;
CODE:
if (!(SvROK(sp1) && SvTYPE(SvRV(sp1)) == SVt_PVAV))
croak("p1 must be array reference");
ap1 = (AV*)SvRV(sp1);
if (av_count(ap1) != 2) croak("p1 must only have two elements");
if (!(SvROK(sp2) && SvTYPE(SvRV(sp2)) == SVt_PVAV))
croak("p2 must be array reference");
ap2 = (AV*)SvRV(sp2);
if (av_count(ap2) != 2) croak("p2 must only have two elements");
x0 = SvIV(*av_fetch(ap1, XX, 0));
y0 = SvIV(*av_fetch(ap1, YY, 0));
x1 = SvIV(*av_fetch(ap2, XX, 0));
y1 = SvIV(*av_fetch(ap2, YY, 0));
dx = labs(x1 - x0);
dy = labs(y1 - y0);
sx = x0 < x1 ? 1 : -1;
sy = y0 < y1 ? 1 : -1;
err = (dx > dy ? dx : -dy) / 2;
theline = newAV();
while (1) {
point = newAV_alloc_x(2);
av_push(point, newSViv(x0));
av_push(point, newSViv(y0));
av_push(theline, newRV_noinc((SV*)point));
if (x0 == x1 && y0 == y1) break;
e2 = err;
if (e2 > -dx) {
err -= dy;
x0 += sx;
}
if (e2 < dy) {
err += dx;
y0 += sy;
}
}
RETVAL = newRV_noinc((SV*)theline);
OUTPUT:
RETVAL
SV *
line(SV* sp1, SV* sp2)
PROTOTYPE: $$
PREINIT:
AV* ap1;
AV* ap2;
AV* theline;
AV* point;
long dx, dy, ix, iy, n, m, step;
double divn, xstep, ystep, x, y;
CODE:
if (!(SvROK(sp1) && SvTYPE(SvRV(sp1)) == SVt_PVAV))
croak("p1 must be array reference");
ap1 = (AV*)SvRV(sp1);
if (av_count(ap1) != 2) croak("p1 must only have two elements");
if (!(SvROK(sp2) && SvTYPE(SvRV(sp2)) == SVt_PVAV))
croak("p2 must be array reference");
ap2 = (AV*)SvRV(sp2);
if (av_count(ap2) != 2) croak("p2 must only have two elements");
ix = SvIV(*av_fetch(ap1, XX, 0));
iy = SvIV(*av_fetch(ap1, YY, 0));
dx = SvIV(*av_fetch(ap2, XX, 0)) - ix;
dy = SvIV(*av_fetch(ap2, YY, 0)) - iy;
n = labs(dx); /* distance */
m = labs(dy);
if (m > n) n = m;
if (!n) {
theline = newAV_alloc_x(1);
point = newAV_alloc_x(2);
av_store(point, XX, newSViv(ix));
av_store(point, YY, newSViv(iy));
av_store(theline, 0, newRV_noinc((SV*)point));
} else {
theline = newAV_alloc_x(n);
divn = 1.0 / n;
xstep = dx * divn;
ystep = dy * divn;
x = ix;
y = iy;
for (step = 0; step <= n; ++step, x += xstep, y += ystep) {
point = newAV_alloc_x(2);
av_push(point, newSViv(lround(x)));
av_push(point, newSViv(lround(y)));
av_push(theline, newRV_noinc((SV*)point));
}
}
RETVAL = newRV_noinc((SV*)theline);
OUTPUT:
RETVAL