@@ 11,6 11,7 @@
#define absv(a) ((a)>0 ? (a) : -(a))
#define min(a, b) ((a)<(b) ? (a) : (b))
#define max(a, b) ((a)>(b) ? (a) : (b))
+#define feq(a,b) (absv((a)-(b))<1e-9)
#define x2i(c, a) (((a) - (c)->min.x)/dPx((c)->min, (c)->max)*(double)(c)->wd)
#define y2j(c, a) (((a) - (c)->min.y)/dPy((c)->min, (c)->max)*(double)(c)->ht)
@@ 20,12 21,13 @@
Ink *rawpx(Canvas *c, int i, int j);
Ink *rawpt(Canvas *c, double x, double y);
+void linew(Canvas *c, rPt p0, rPt p1, int sty, Ink ink, int nowrap);
void rawline(Canvas *c, double x0, double y0, double x1, double y1, int sty, Ink ink);
Font *font(int fid);
void rawglyph(Canvas *c, int i0, int j0, int wd, int ht, int stride, uchar max, uchar *data, Ink ink);
int
-initcvs(Canvas *c, rPt min, rPt max, int wd, int ht, Ink bg, rPt (*proj)(rPt,void*), void *prj) {
+initcvs(Canvas *c, rPt min, rPt max, int wd, int ht, Ink bg, rPt (*wrap)(rPt,void*), void *wrp, rPt (*proj)(rPt,void*), void *prj) {
int i;
long n;
Ink *in;
@@ 40,6 42,8 @@ initcvs(Canvas *c, rPt min, rPt max, int
c->wd = wd;
c->ht = ht;
c->bg = bg;
+ c->wrap = wrap;
+ c->wrp = wrp;
c->proj = proj;
c->prj = prj;
@@ 149,30 153,54 @@ closeicn(Icon *icn) {
Ink *
pt(Canvas *c, rPt p, Ink ink) {
+ if(c->wrap) p = (*c->wrap)(p, c->wrp);
if(c->proj) p = (*c->proj)(p, c->prj);
return rawpt(c, p.x, p.y);
}
void
line(Canvas *c, rPt p0, rPt p1, int sty, Ink ink) {
- int i, j, i0, j0, nsegx, nsegy, nseg;
- rPt p, pp0, pp;
+ linew(c, p0, p1, sty, ink, 0);
+}
+
+void
+linew(Canvas *c, rPt p0, rPt p1, int sty, Ink ink, int nowrap) {
+ int i, j, i0, j0, nsegx, nsegy, nseg, crosswrap;
+ rPt p, pp0, pp, p0w, p1w;
double dx, dy;
+ dx = dPx(p0, p1);
+ dy = dPy(p0, p1);
+
+ /* check if the line crosses wrap boundries */
+ p0w = c->wrap ? (*c->wrap)(p0, c->wrp) : p0;
+ p1w = c->wrap ? (*c->wrap)(p1, c->wrp) : p1;
+ crosswrap = (!feq(dPx(p0w, p1), dPx(p0, p1)) || !feq(dPy(p0w, p1w), dPy(p0, p1)));
+ if(!crosswrap) {
+ p0 = p0w;
+ p1 = p1w;
+ /* otherwise draw twice, once from p0w to p1 (by calling line again below) and once from p0 to p1w (in the remainder of the current call to line); this requires wrap to be idempotent to work correctly */
+ } else if(!nowrap && !(feq(p0w.x, p0.x) && feq(p0w.y, p0.y))) {
+ linew(c, p0w, (rPt){p0w.x+dx,p0w.y+dy}, sty, ink, 1);
+ } else if(!nowrap && !(feq(p1w.x, p1.x) && feq(p1w.y, p1.y))) {
+ linew(c, (rPt){p1w.x-dx,p1w.y-dy}, p1w, sty, ink, 1);
+ }
+
+ /* for efficiency at high zoom levels, skip lines where both ends fall outside visible boundaries, even though strictly speaking some segments of the line may fall within view */
pp0 = c->proj ? (*c->proj)(p0, c->prj) : p0;
- pp = c->proj ? (*c->proj)(p, c->prj) : p;
- /* for efficiency at high zoom levels, skip lines where both ends fall outside visible boundaries, even though strictly speaking some segments of the line may fall within view */
+ pp = c->proj ? (*c->proj)(p1, c->prj) : p1;
+
i0 = x2i(c,pp0.x); j0=y2j(c,pp0.y);
i = x2i(c,pp.x); j=y2j(c,pp.y);
if((i0<0 && i<0) || (i0>=c->wd && i>=c->wd) ||
(j0<0 && j<0) || (j0>=c->ht && j>=c->ht)) return;
- nsegx = absv(dPx(p0, p1)/dPx(c->min, c->max))*(double)c->wd / SEGMENT_FACTOR;
- nsegy = absv(dPy(p0, p1)/dPy(c->min, c->max))*(double)c->ht / SEGMENT_FACTOR;
- nseg = max(nsegx, nsegy);
+ nsegx = absv(dx/dPx(c->min, c->max))*(double)c->wd / SEGMENT_FACTOR;
+ nsegy = absv(dy/dPy(c->min, c->max))*(double)c->ht / SEGMENT_FACTOR;
+ nseg = max(nsegx, nsegy)+1;
- dx = dPx(p0, p1)/(double)nseg;
- dy = dPy(p0, p1)/(double)nseg;
+ dx /= (double)nseg;
+ dy /= (double)nseg;
p = p0;
p.x += dx;
@@ 193,6 221,7 @@ mark(Canvas *c, rPt p, int size, int typ
sx = size*resx(c);
sy = size*resy(c);
+ if(c->wrap) p = (*c->wrap)(p, c->wrp);
if(c->proj) p = (*c->proj)(p, c->prj);
switch(typ) {
case Mplus:
@@ 227,6 256,7 @@ icon(Canvas *c, rPt p, Icon *icn, int po
uchar ch, *data;
double d, r, g, b;
+ if(c->wrap) p = (*c->wrap)(p, c->wrp);
if(c->proj) p = (*c->proj)(p, c->prj);
i0 = x2i(c, p.x);
j0 = y2j(c, p.y);
@@ 272,6 302,7 @@ text(Canvas *c, rPt p, uchar *s, int fid
chp = ch;
}
+ if(c->wrap) p = (*c->wrap)(p, c->wrp);
if(c->proj) p = (*c->proj)(p, c->prj);
i0 = x2i(c, p.x);
j0 = y2j(c, p.y);
@@ 342,7 373,7 @@ void
rawline(Canvas *c, double x0, double y0, double x1, double y1, int sty, Ink ink) {
double dx, dy, r, u;
int sdx, sdy;
- Ink *in;
+ Ink *in0, *in;
int i;
x0 = x2i(c, x0); y0 = y2j(c, y0);
@@ 354,8 385,9 @@ rawline(Canvas *c, double x0, double y0,
sdx = dx > 0 ? 1 : -1;
sdy = dy > 0 ? 1 : -1;
- in = rawpx(c, (int)x0, (int)y0); if(in) *in = ink;
+ in0 = rawpx(c, (int)x0, (int)y0); if(in0) *in0 = ink;
in = rawpx(c, (int)x1, (int)y1); if(in) *in = ink;
+ if(in0==in) return;
if(dx*sdx > dy*sdy) {
if(x0>x1) {
u = x0; x0 = x1; x1 = u;
@@ 45,6 45,9 @@ struct Canvas {
int wd, ht;
Ink bg;
+ rPt (*wrap)(rPt,void*);
+ void *wrp;
+
rPt (*proj)(rPt,void*);
void *prj;
@@ 67,7 70,7 @@ struct Font {
#define dPx(p1,p2) ((p2).x-(p1).x)
#define dPy(p1,p2) ((p2).y-(p1).y)
-int initcvs(Canvas *c, rPt min, rPt max, int wd, int ht, Ink bg, rPt (*proj)(rPt,void*), void *prj);
+int initcvs(Canvas *c, rPt min, rPt max, int wd, int ht, Ink bg, rPt (*wrap)(rPt,void*), void *wrp, rPt (*proj)(rPt,void*), void *prj);
void closecvs(Canvas *c);
int initicn(Icon *icn, char *name, int wd, int ht, int depth, uchar *data);