return edges;
}
-char gfxpoly_check(gfxpoly_t*poly)
+char gfxpoly_check(gfxpoly_t*poly, char updown)
{
current_polygon = poly;
- dict_t*d = dict_new2(&point_type);
+ dict_t*d1 = dict_new2(&point_type);
+ dict_t*d2 = dict_new2(&point_type);
int s,t;
gfxpolystroke_t*stroke = poly->strokes;
for(;stroke;stroke=stroke->next) {
that the endpoint multiplicity is two */
for(s=0;s<stroke->num_points;s++) {
point_t p = stroke->points[s];
- int num = (s>=1 && s<stroke->num_points-1)?2:1; // mid points are two points (start+end)
- if(!dict_contains(d, &p)) {
- dict_put(d, &p, (void*)(ptroff_t)num);
+ int num_xor = (s>=1 && s<stroke->num_points-1)?2:1; // mid points are two points (start+end)
+ int num_circ = (s>=1 && s<stroke->num_points-1)?0:(s==0?1:-1);
+ if(stroke->dir==DIR_UP)
+ num_circ=-num_circ;
+
+ if(!dict_contains(d1, &p)) {
+ dict_put(d1, &p, (void*)(ptroff_t)num_xor);
+ if(updown) {
+ assert(!dict_contains(d2, &p));
+ dict_put(d2, &p, (void*)(ptroff_t)num_circ);
+ }
} else {
- int count = (ptroff_t)dict_lookup(d, &p);
- dict_del(d, &p);
- count+=num;
- dict_put(d, &p, (void*)(ptroff_t)count);
+ int count = (ptroff_t)dict_lookup(d1, &p);
+ dict_del(d1, &p);
+ count+=num_xor;
+ dict_put(d1, &p, (void*)(ptroff_t)count);
+
+ if(updown) {
+ assert(dict_contains(d2, &p));
+ count = (ptroff_t)dict_lookup(d2, &p);
+ dict_del(d2, &p);
+ count+=num_circ;
+ dict_put(d2, &p, (void*)(ptroff_t)count);
+ }
}
}
}
- DICT_ITERATE_ITEMS(d, point_t*, p, void*, c) {
- int count = (ptroff_t)c;
+ DICT_ITERATE_ITEMS(d1, point_t*, p1, void*, c1) {
+ int count = (ptroff_t)c1;
if(count&1) {
- fprintf(stderr, "Point (%d,%d) occurs %d times\n", p->x, p->y, count);
- dict_destroy(d);
- assert(count%2 == 0);
+ fprintf(stderr, "Point (%d,%d) occurs %d times\n", p1->x, p1->y, count);
+ dict_destroy(d1);
+ return 0;
}
}
- dict_destroy(d);
+ if(updown) {
+ DICT_ITERATE_ITEMS(d2, point_t*, p2, void*, c2) {
+ int count = (ptroff_t)c2;
+ if(count!=0) {
+ if(count>0) fprintf(stderr, "Point (%d,%d) has %d more incoming than outgoing segments\n", p2->x, p2->y, count);
+ if(count<0) fprintf(stderr, "Point (%d,%d) has %d more outgoing than incoming segments\n", p2->x, p2->y, -count);
+ dict_destroy(d2);
+ return 0;
+ }
+ }
+ }
+ dict_destroy(d1);
+ dict_destroy(d2);
return 1;
}
fclose(fi);
}
+void gfxpoly_save_arrows(gfxpoly_t*poly, const char*filename)
+{
+ FILE*fi = fopen(filename, "wb");
+ fprintf(fi, "%% gridsize %f\n", poly->gridsize);
+ fprintf(fi, "%% begin\n");
+ int t;
+ double l = 5.0 / poly->gridsize;
+ double g = poly->gridsize;
+ gfxpolystroke_t*stroke = poly->strokes;
+ for(;stroke;stroke=stroke->next) {
+ fprintf(fi, "%g setgray\n", 0);
+
+ int s = stroke->dir==DIR_UP?stroke->num_points-1:0;
+ int end = stroke->dir==DIR_UP?-1:stroke->num_points;
+ int dir = stroke->dir==DIR_UP?-1:1;
+
+ point_t p = stroke->points[s];
+ s+=dir;
+ point_t o = p;
+ fprintf(fi, "%f %f moveto\n", p.x * g, p.y * g);
+ for(;s!=end;s+=dir) {
+ p = stroke->points[s];
+ int lx = p.x - o.x;
+ int ly = p.y - o.y;
+ double d = sqrt(lx*lx+ly*ly);
+ if(!d) d=1;
+ else d = l / d;
+ double d2 = d*1.5;
+ fprintf(fi, "%f %f lineto\n", (p.x - lx*d2) * g, (p.y - ly*d2) * g);
+ fprintf(fi, "%f %f lineto\n", (p.x - lx*d2 + (ly*d))*g,
+ (p.y - ly*d2 - (lx*d))*g);
+ fprintf(fi, "%f %f lineto\n", p.x * g, p.y * g);
+ fprintf(fi, "%f %f lineto\n", (p.x - lx*d2 - (ly*d))*g,
+ (p.y - ly*d2 + (lx*d))*g);
+ fprintf(fi, "%f %f lineto\n", (p.x - lx*d2) * g, (p.y - ly*d2) * g);
+ fprintf(fi, "%f %f moveto\n", p.x * g, p.y * g);
+ o = p;
+ }
+ fprintf(fi, "stroke\n");
+ }
+ fprintf(fi, "showpage\n");
+ fclose(fi);
+}
+
inline static event_t* event_new()
{
event_t*e = rfx_calloc(sizeof(event_t));
actlist_verify(actlist, y-1);
#endif
edgestyle_t*fill = 0;
- char dir_up = 0;
- char dir_down = 0;
+ int wind = 0;
do {
assert(e->s1->fs);
if(fill && x != e->p.x) {
- assert(!dir_up || !dir_down);
- assert(dir_up || dir_down);
-#ifdef DEBUG
- fprintf(stderr, "%d) draw horizontal line from %d to %d\n", y, x, e->p.x);
-#endif
+ assert(abs(wind)==1);
assert(x<e->p.x);
gfxpolystroke_t*stroke = rfx_calloc(sizeof(gfxpolystroke_t));
stroke->num_points = 2;
stroke->points = malloc(sizeof(point_t)*2);
- stroke->dir = dir_up?DIR_UP:DIR_DOWN;
+
+ if(wind>0) {
+ stroke->dir = DIR_DOWN;
+ } else {
+ stroke->dir = DIR_UP;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "%d) draw horizontal line from %d to %d (dir=%s)\n", y, x, e->p.x, stroke->dir==DIR_UP?"up":"down");
+#endif
+
stroke->fs = fill;
point_t a,b;
a.y = b.y = y;
- /* we draw from low x to high x so that left/right fillstyles add up
- (because the horizontal line's fill style controls the area *below* the line)
- */
- a.x = e->p.x;
- b.x = x;
+ a.x = x;
+ b.x = e->p.x;
stroke->points[0] = a;
stroke->points[1] = b;
#ifdef CHECKS
/* the output should always be intersection free polygons, so check this horizontal
line isn't puncturing any segments in the active list */
- segment_t* start = actlist_find(actlist, b, b);
- segment_t* s = actlist_find(actlist, a, a);
+ segment_t* start = actlist_find(actlist, a, a);
+ segment_t* s = actlist_find(actlist, b, b);
while(s!=start) {
assert(s->a.y == y || s->b.y == y);
s = s->left;
e->s2 = 0;
hqueue_put(&hqueue, e);
left = actlist_left(actlist, s);
- if(e->s1->dir==DIR_UP)
- dir_up^=1;
- else
- dir_down^=1;
+ wind += e->s1->dir==DIR_DOWN?-1:1;
break;
}
case EVENT_END: {
left = actlist_left(actlist, s);
actlist_delete(actlist, s);
advance_stroke(0, &hqueue, s->stroke, s->polygon_nr, s->stroke_pos);
- if(e->s1->dir==DIR_DOWN)
- dir_up^=1;
- else
- dir_down^=1;
+ wind += e->s1->dir==DIR_DOWN?1:-1;
break;
}
default: assert(0);
#endif
#ifdef DEBUG
- fprintf(stderr, "%d) event=%s[%d] left:[%d] x:%d\n",
+ fprintf(stderr, "%d) event=%s[%d] left:[%d] x:%d dir:%s\n",
y, e->type==EVENT_START?"start":"end",
s->nr,
left?left->nr:-1,
- x);
+ x, s->dir==DIR_UP?"up":"down");
#endif
if(e->type == EVENT_END)
#ifdef CHECKS
edgestyle_t*bleeding = fill;
assert(!bleeding);
+ segment_t*s = actlist_leftmost(actlist);
+ int dir = 0;
+ while(s) {
+ dir += s->dir==DIR_UP?-1:1;
+ s = actlist_right(actlist, s);
+ }
+ assert(!dir);
#endif
}