static int trim_rgb(gstack_t* stack) { size_t n = gstack_size(stack); rgb_stop_t stop; gstack_t *stack0; if ((stack0 = gstack_new(sizeof(rgb_stop_t), n, n)) == NULL) return 1; while (! gstack_empty(stack)) { gstack_pop(stack, &stop); gstack_push(stack0, &stop); if (stop.z >= 409600) { while (! gstack_empty(stack)) gstack_pop(stack, &stop); } } while (! gstack_empty(stack0)) { gstack_pop(stack0, &stop); gstack_push(stack, &stop); } gstack_destroy(stack0); return 0; }
extern int paths_serialise(gstack_t* paths, size_t* nA, arrow_t** pA) { size_t n = paths_count(paths); if (n>0) { arrow_t *A = malloc(n*sizeof(arrow_t)); *pA = A; gstack_t *path; if (!A) return 1; while (gstack_pop(paths, &path) == 0) { corner_t corner; while (gstack_pop(path, &corner) == 0) { *A = corner.A; A++; } } } *nA = n; return 0; }
static int merged_svg(gstack_t *ross, svg_t *svg) { svg_stop_t ss; rgbop_stop_t ros; while (gstack_pop(ross, &ros) == 0) { ss.colour.red = svg_it_rgb(ros.r); ss.colour.green = svg_it_rgb(ros.g); ss.colour.blue = svg_it_rgb(ros.b); ss.opacity = svg_it_op(ros.op); ss.value = svg_it_z(ros.z); svg_append(ss,svg); } return 0; }
static int pssvg_convert(grd5_t *grd5, svgset_t *svgset, pssvg_opt_t opt) { int n = grd5->n; gstack_t *gstack; if ((gstack = gstack_new(sizeof(svg_t*), n, 1)) == NULL) return 1; int err = pssvg_convert_all(grd5, svgset, gstack, opt); if (! err) { size_t m = gstack_size(gstack); if (m == 0) { btrace("no gradients converted"); err++; } else { if (m < n) btrace("only %zd/%d gradient converted", m, n); if (gstack_reverse(gstack) != 0) err++; else { svgset->n = m; if ((svgset->svg = malloc(m*sizeof(svg_t*))) == NULL) err++; else { for (size_t i = 0 ; i < m ; i++) gstack_pop(gstack, svgset->svg+i); } } } } gstack_destroy(gstack); return err; }
static gstack_t* merge(gstack_t *rss, gstack_t *oss) { gstack_t *ross; int err = 0; size_t n = gstack_size(rss) + gstack_size(oss); /* get the first two of each type of stop */ rgb_stop_t rs0, rs1; err += gstack_pop(rss, &rs0); err += gstack_pop(rss, &rs1); if (err) { btrace("%i errors rgb", err); return NULL; } op_stop_t os0, os1; err += gstack_pop(oss, &os0); err += gstack_pop(oss, &os1); if (err) { btrace("%i errors op", err); return NULL; } if ((rs0.z != 0) || (os0.z != 0)) { btrace("nonzero initial stop"); btrace("RGB %.3f", svg_it_z(rs0.z)); btrace("Opacity %.3f", svg_it_z(os0.z)); return NULL; } /* merged stack to return */ if ((ross = gstack_new(sizeof(rgbop_stop_t), n, n)) == NULL) return NULL; rgbop_stop_t ros; while (1) { ros = stop_merge(rs0, os0); gstack_push(ross, &ros); if (rs1.z > os1.z) { rs0 = rgb_stop_interp(rs0, rs1, os1.z); os0 = os1; if (gstack_pop(oss, &os1) != 0) { btrace("early termination of opacity channel"); break; } } else if (rs1.z < os1.z) { os0 = op_stop_interp(os0, os1, rs1.z); rs0 = rs1; if (gstack_pop(rss, &rs1) != 0) { btrace("early termination of rgb channel"); break; } } else { rs0 = rs1; os0 = os1; int odone = gstack_pop(oss, &os1), rdone = gstack_pop(rss, &rs1); if (odone && rdone) { ros = stop_merge(rs0, os0); gstack_push(ross, &ros); gstack_reverse(ross); return ross; } else if (odone && !rdone) { btrace("early termination of opacity channel"); break; } else if (rdone && ! odone) { btrace("early termination of rgb channel"); break; } else { /* OK, so now we continue */ } } } /* something has gone pear-shaped */ gstack_destroy(ross); btrace("merge failed"); return NULL; }
static int path_decimate(gstack_t** path, double* Dmin) { size_t n = gstack_size(*path); double xmin = pow(*Dmin, 2); corner_t cns[n]; /* empty the stack into a corners array - we do this in reverse order so the gstack_push below gives us a gstack_t in the same order (needed due to an assumed orientation of the boundaries) */ for (int i = 0 ; i < n ; i++) { if (gstack_pop(*path, (void*)(cns+(n-1-i))) != 0) return -1; } /* cache metric tensor and ellipse centres */ vector_t e[n]; m2_t mt[n]; for (int i = 0 ; i < n ; i++) { ellipse_t E; arrow_ellipse(&(cns[i].A), &E); mt[i] = ellipse_mt(E); e[i] = E.centre; } /* create ellipse intersection graph */ graph_t G; if (graph_init(n,&G) != 0) return -1; size_t err = 0; for (int i = 0 ; i < n-1 ; i++) { for (int j = i+1 ; j < n ; j++) { double x = contact_mt(vsub(e[j], e[i]), mt[i], mt[j]); /* failed contact() results in edge not being included in the graph so possible intesection survives - save the number for a warning (below) */ if (x<0) { err++; continue; } /* weight of each node is the maximum of the contact-distances of the incoming edges */ if (x < xmin) { double w1 = graph_get_weight(G, i), w2 = graph_get_weight(G, j); graph_set_weight(G, i, MAX(w1, x)); graph_set_weight(G, j, MAX(w2, x)); if (graph_add_edge(G, i, j) != 0) return -1; } } } if (err) fprintf(stderr,"failed contact distance for %i pairs\n", (int)err); /* greedy node deletion to obtain non-intersecting subset */ size_t maxi; while (graph_maxedge(G, &maxi) > 0) if (graph_del_node(G, maxi) != 0) return -1; /* dump back into gstack */ for (int i = 0 ; i < n ; i++) if ( !graph_node_flag(G, i, NODE_STALE) ) gstack_push(*path, (void*)(cns+i)); graph_clean(&G); return 1; }