static cdPoint* sPolyAddArc(cdCanvas* canvas, cdPoint* poly, int *n, int xc, int yc, int width, int height, double angle1, double angle2, cdPoint* current) { double c, s, sx, sy, x, y, prev_x, prev_y; double da; int i, K, k, p, new_n; cdPoint* old_poly = poly; sFixAngles(canvas, &angle1, &angle2); /* number of segments for the arc */ K = sCalcEllipseNumSegments(canvas, xc, yc, width, height, angle1, angle2); new_n = *n + K+1; /* add room for K+1 samples */ poly = (cdPoint*)realloc(poly, sizeof(cdPoint)*(new_n+2)); /* add room also for points at start and end */ if (!poly) {free(old_poly); return NULL;} i = *n; /* generates arc points at origin with axis x and y */ da = (angle2-angle1)/K; c = cos(da); s = sin(da); sx = -(width*s)/height; sy = (height*s)/width; x = (width/2.0f)*cos(angle1); y = (height/2.0f)*sin(angle1); prev_x = x; prev_y = y; if (current) { poly[i] = *current; i++; new_n++; /* no need to reallocate */ } poly[i].x = _cdRound(x)+xc; poly[i].y = _cdRound(y)+yc; p = i+1; for (k = 1; k < K+1; k++) { x = c*prev_x + sx*prev_y; y = sy*prev_x + c*prev_y; poly[p].x = _cdRound(x)+xc; poly[p].y = _cdRound(y)+yc; if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y) p++; prev_x = x; prev_y = y; } *n = new_n; return poly; }
static cdPoint* sPolyAddBezier(cdCanvas* canvas, cdPoint* poly, int *n, cdPoint start, const cdPoint* points) { int k, K, new_n, i; cdfPoint pt; cdfPoint bezier_control[4]; cdPoint* old_poly = poly; sBezierForm(start, points, bezier_control); K = sBezierNumSegments(canvas, start, points); new_n = *n + K+1; /* add room for K+1 samples */ poly = realloc(poly, sizeof(cdPoint)*new_n); if (!poly) {free(old_poly); return NULL;} i = *n; /* first segment */ sBezierCurve(bezier_control, &pt, 0); poly[i].x = _cdRound(pt.x); poly[i].y = _cdRound(pt.y); for(k = 1; k < K+1; k++) { sBezierCurve(bezier_control, &pt, (double)k/(double)K); poly[i+k].x = _cdRound(pt.x); poly[i+k].y = _cdRound(pt.y); } *n = new_n; return poly; }
void cdfCanvasArc(cdCanvas* canvas, double xc, double yc, double w, double h, double angle1, double angle2) { assert(canvas); if (!_cdCheckCanvas(canvas)) return; if (angle1 == angle2 || w == 0 || h == 0) return; sNormAngles(&angle1, &angle2); if (canvas->use_origin) { xc += canvas->forigin.x; yc += canvas->forigin.y; } if (canvas->invert_yaxis) yc = _cdInvertYAxis(canvas, yc); if (canvas->cxFArc) canvas->cxFArc(canvas->ctxcanvas, xc, yc, w, h, angle1, angle2); else canvas->cxArc(canvas->ctxcanvas, _cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), angle1, angle2); }
static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) { int i; tPrimNode *prim; if (mode == CD_CLIP || mode == CD_REGION) return; if (mode == CD_PATH) { cdfpath(ctxcanvas, poly, n); return; } prim = primCreate(CDPIC_FPOLY); if (mode == CD_FILL) primAddAttrib_Fill(prim, ctxcanvas->canvas); else primAddAttrib_Line(prim, ctxcanvas->canvas); prim->param.polyf.mode = mode; prim->param.polyf.n = n; prim->param.polyf.points = malloc(n * sizeof(cdfPoint)); memcpy(prim->param.polyf.points, poly, n * sizeof(cdfPoint)); prim->param_buffer = prim->param.polyf.points; picAddPrim(ctxcanvas, prim); for (i = 0; i < n; i++) { if (mode == CD_FILL) picUpdateBBox(ctxcanvas, _cdRound(poly[i].x), _cdRound(poly[i].y), 0); else picUpdateBBox(ctxcanvas, _cdRound(poly[i].x), _cdRound(poly[i].y), ctxcanvas->canvas->line_width); } }
void cdfCanvasBox(cdCanvas* canvas, double xmin, double xmax, double ymin, double ymax) { assert(canvas); if (!_cdCheckCanvas(canvas)) return; if (canvas->interior_style == CD_HOLLOW) { cdfCanvasRect(canvas, xmin, xmax, ymin, ymax); return; } if (!cdfCheckBoxSize(&xmin, &xmax, &ymin, &ymax)) return; if (canvas->use_origin) { xmin += canvas->forigin.x; xmax += canvas->forigin.x; ymin += canvas->forigin.y; ymax += canvas->forigin.y; } if (canvas->invert_yaxis) { ymin = _cdInvertYAxis(canvas, ymin); ymax = _cdInvertYAxis(canvas, ymax); _cdSwapDouble(ymin, ymax); } if (canvas->cxFBox) canvas->cxFBox(canvas->ctxcanvas, xmin, xmax, ymin, ymax); else canvas->cxBox(canvas->ctxcanvas, _cdRound(xmin), _cdRound(xmax), _cdRound(ymin), _cdRound(ymax)); }
static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *text, int len) { int xmin, xmax, ymin, ymax; tPrimNode *prim = primCreate(CDPIC_FTEXT); primAddAttrib_Text(prim, ctxcanvas->canvas); prim->param.textf.x = x; prim->param.textf.y = y; prim->param.textf.s = cdStrDupN(text, len); prim->param_buffer = prim->param.textf.s; picAddPrim(ctxcanvas, prim); cdCanvasGetTextBox(ctxcanvas->canvas, _cdRound(x), _cdRound(y), prim->param.text.s, &xmin, &xmax, &ymin, &ymax); picUpdateBBox(ctxcanvas, xmin, ymin, 0); picUpdateBBox(ctxcanvas, xmax, ymax, 0); }
static void cdfpath(cdCtxCanvas *ctxcanvas, cdfPoint* poly, int n) { int i, p, fill = -1; tPrimNode *prim; for (p=0; p<ctxcanvas->canvas->path_n; p++) { if (ctxcanvas->canvas->path[p] == CD_PATH_CLIP) return; else if (ctxcanvas->canvas->path[p] == CD_PATH_FILL || ctxcanvas->canvas->path[p] == CD_PATH_FILLSTROKE) /* no support for both in cdPicture */ { fill = 1; break; } else if (ctxcanvas->canvas->path[p] == CD_PATH_STROKE) { fill = -1; break; } } if (fill == -1) return; prim = primCreate(CDPIC_FPATH); prim->param.pathf.fill = fill; if (fill) primAddAttrib_Fill(prim, ctxcanvas->canvas); else primAddAttrib_Line(prim, ctxcanvas->canvas); prim->param_buffer = malloc(n * sizeof(cdfPoint) + ctxcanvas->canvas->path_n * sizeof(int)); prim->param.pathf.n = n; prim->param.pathf.points = (cdfPoint*)prim->param_buffer; memcpy(prim->param.pathf.points, poly, n * sizeof(cdfPoint)); prim->param.pathf.path = (int*)((unsigned char*)prim->param_buffer + n * sizeof(cdfPoint)); memcpy(prim->param.pathf.path, ctxcanvas->canvas->path, ctxcanvas->canvas->path_n * sizeof(int)); prim->param.pathf.path_n = ctxcanvas->canvas->path_n; picAddPrim(ctxcanvas, prim); for (i = 0; i < n; i++) { picUpdateBBox(ctxcanvas, _cdRound(poly[i].x), _cdRound(poly[i].y), 0); } }
static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) { int xmin, xmax, ymin, ymax; tPrimNode *prim = primCreate(CDPIC_FCHORD); primAddAttrib_Fill(prim, ctxcanvas->canvas); prim->param.arcsectorchordf.xc = xc; prim->param.arcsectorchordf.yc = yc; prim->param.arcsectorchordf.w = w; prim->param.arcsectorchordf.h = h; prim->param.arcsectorchordf.angle1 = a1; prim->param.arcsectorchordf.angle2 = a2; picAddPrim(ctxcanvas, prim); cdCanvasGetArcBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); picUpdateBBox(ctxcanvas, xmin, ymin, 0); picUpdateBBox(ctxcanvas, xmax, ymax, 0); }
void cdfCanvasSector(cdCanvas* canvas, double xc, double yc, double w, double h, double angle1, double angle2) { assert(canvas); if (!_cdCheckCanvas(canvas)) return; if (angle1 == angle2 || w == 0 || h == 0) return; sNormAngles(&angle1, &angle2); if (canvas->interior_style == CD_HOLLOW) { cdfCanvasArc(canvas, xc, yc, w, h, angle1, angle2); if (fabs(angle2-angle1) < 360) { double xi,yi,xf,yf; xi = xc + w*cos(CD_DEG2RAD*angle1)/2.0; yi = yc + h*sin(CD_DEG2RAD*angle1)/2.0; xf = xc + w*cos(CD_DEG2RAD*angle2)/2.0; yf = yc + h*sin(CD_DEG2RAD*angle2)/2.0; cdfCanvasLine(canvas, xi, yi, xc, yc); cdfCanvasLine(canvas, xc, yc, xf, yf); } return; } if (canvas->use_origin) { xc += canvas->forigin.x; yc += canvas->forigin.y; } if (canvas->invert_yaxis) yc = _cdInvertYAxis(canvas, yc); if (canvas->cxFSector) canvas->cxFSector(canvas->ctxcanvas, xc, yc, w, h, angle1, angle2); else canvas->cxSector(canvas->ctxcanvas, _cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), angle1, angle2); }
void cdfCanvasVertex(cdCanvas* canvas, double x, double y) { assert(canvas); if (!_cdCheckCanvas(canvas)) return; if (!canvas->cxFPoly) { cdCanvasVertex(canvas, _cdRound(x), _cdRound(y)); return; } if (canvas->use_fpoly == 0) return; /* real vertex inside a integer polygon */ if (!canvas->fpoly) { canvas->fpoly = (cdfPoint*)malloc(sizeof(cdfPoint)*(_CD_POLY_BLOCK+1)); canvas->fpoly_size = _CD_POLY_BLOCK; } canvas->use_fpoly = 1; if (!sCheckPathArc(canvas)) { if (canvas->use_origin) { x += canvas->forigin.x; y += canvas->forigin.y; } if (canvas->invert_yaxis) y = _cdInvertYAxis(canvas, y); } if (canvas->poly_n == canvas->fpoly_size) { canvas->fpoly_size += _CD_POLY_BLOCK; canvas->fpoly = (cdfPoint*)realloc(canvas->fpoly, sizeof(cdfPoint) * (canvas->fpoly_size+1)); } canvas->fpoly[canvas->poly_n].x = x; canvas->fpoly[canvas->poly_n].y = y; canvas->poly_n++; }
void cdfSimPutImageRectRGBA(cdCanvas* canvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, double x, double y, double w, double h, int xmin, int xmax, int ymin, int ymax) { int size, i, j, dst, src, *fx, *fy, rw, rh; unsigned char *ar, *ag, *ab, al; int zw = _cdRound(w); int zh = _cdRound(h); (void)ih; size = zw * zh; ar = (unsigned char*)malloc(size * 3); if (!ar) return; ag = ar + size; ab = ag + size; canvas->cxGetImageRGB(canvas->ctxcanvas, ar, ag, ab, _cdRound(x), _cdRound(y), zw, zh); rw = xmax - xmin + 1; rh = ymax - ymin + 1; fx = cdGetZoomTable(zw, rw, xmin); fy = cdGetZoomTable(zh, rh, ymin); for (j = 0; j < zh; j++) { for (i = 0; i < zw; i++) { dst = j * zw + i; src = fy[j] * iw + fx[i]; al = a[src]; ar[dst] = CD_ALPHA_BLEND(r[src], ar[dst], al); ag[dst] = CD_ALPHA_BLEND(g[src], ag[dst], al); ab[dst] = CD_ALPHA_BLEND(b[src], ab[dst], al); } } canvas->cxFPutImageRectRGB(canvas->ctxcanvas, zw, zh, ar, ag, ab, x, y, w, h, 0, 0, 0, 0); free(ar); free(fx); free(fy); }
void cdfCanvasLine(cdCanvas* canvas, double x1, double y1, double x2, double y2) { assert(canvas); if (!_cdCheckCanvas(canvas)) return; if (x1 == x2 && y1 == y2) { cdCanvasPixel(canvas, _cdRound(x1), _cdRound(y1), canvas->foreground); return; } if (canvas->use_origin) { x1 += canvas->forigin.x; y1 += canvas->forigin.y; x2 += canvas->forigin.x; y2 += canvas->forigin.y; } if (canvas->invert_yaxis) { y1 = _cdInvertYAxis(canvas, y1); y2 = _cdInvertYAxis(canvas, y2); } if (canvas->cxFLine) canvas->cxFLine(canvas->ctxcanvas, x1, y1, x2, y2); else canvas->cxLine(canvas->ctxcanvas, _cdRound(x1), _cdRound(y1), _cdRound(x2), _cdRound(y2)); }
static void cdSimElipse(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2, int sector) { cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; float c, s, sx, sy, x, y, prev_x, prev_y; double da; int i, p, yc2 = 2*yc; cdPoint* poly; /* number of segments of equivalent poligonal for a full ellipse */ int n = simCalcEllipseNumSegments(canvas, xc, yc, width, height); /* number of segments for the arc */ n = cdRound(((angle2-angle1)*n)/360); if (n < 1) n = 1; poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+2+1)); /* n+1 points +1 center */ /* converts degrees into radians */ angle1 *= CD_DEG2RAD; angle2 *= CD_DEG2RAD; /* generates arc points at origin with axis x and y */ da = (angle2-angle1)/n; c = (float)cos(da); s = (float)sin(da); sx = -(width*s)/height; sy = (height*s)/width; x = xc + (width/2.0f)*(float)cos(angle1); y = yc + (height/2.0f)*(float)sin(angle1); prev_x = x; prev_y = y; poly[0].x = _cdRound(x); poly[0].y = _cdRound(y); if (canvas->invert_yaxis) poly[0].y = yc2 - poly[0].y; p = 1; for (i = 1; i < n+1; i++) /* n+1 points */ { x = xc + c*(prev_x-xc) + sx*(prev_y-yc); y = yc + sy*(prev_x-xc) + c*(prev_y-yc); poly[p].x = _cdRound(x); poly[p].y = _cdRound(y); if (canvas->invert_yaxis) poly[p].y = yc2 - poly[p].y; if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y) p++; prev_x = x; prev_y = y; } if (poly[p-1].x != poly[0].x || poly[p-1].y != poly[0].y) { if (sector) /* cdSector */ { /* add center */ poly[p].x = xc; poly[p].y = yc; } else /* cdChord */ { /* add initial point */ poly[p].x = poly[0].x; poly[p].y = poly[0].y; } p++; } canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, p); free(poly); }
void cdarcSIM(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2) { cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; double c, s, sx, sy, x, y, prev_x, prev_y; double da; int i, yc2 = 2*yc, p, last_xi_a = -65535, last_yi_a = -65535, last_xi_b = -65535, last_yi_b = -65535; cdPoint* poly = NULL; /* number of segments of equivalent poligonal for a full ellipse */ int n = simCalcEllipseNumSegments(canvas, xc, yc, width, height); /* Use special floating point anti-alias line draw when line_width==1, and NOT using cdlineSIM. */ if (canvas->line_width > 1 || canvas->cxLine != cdlineSIM) { poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+1)); /* n+1 points */ if (!poly) return; } /* number of segments for the arc */ n = cdRound((fabs(angle2-angle1)*n)/360); if (n < 1) n = 1; /* converts degrees into radians */ angle1 *= CD_DEG2RAD; angle2 *= CD_DEG2RAD; /* generates arc points at origin with axis x and y */ da = (angle2-angle1)/n; c = cos(da); s = sin(da); sx = -(width*s)/height; sy = (height*s)/width; x = (width/2.0f)*cos(angle1); y = (height/2.0f)*sin(angle1); prev_x = x; prev_y = y; if (poly) { poly[0].x = _cdRound(x)+xc; poly[0].y = _cdRound(y)+yc; if (canvas->invert_yaxis) /* must invert because of the angle orientation */ poly[0].y = yc2 - poly[0].y; p = 1; } else simLineStyleNoReset = 1; for (i = 1; i < n+1; i++) /* n+1 points */ { x = c*prev_x + sx*prev_y; y = sy*prev_x + c*prev_y; if (poly) { poly[p].x = _cdRound(x)+xc; poly[p].y = _cdRound(y)+yc; if (canvas->invert_yaxis) /* must invert because of the angle orientation */ poly[p].y = yc2 - poly[p].y; if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y) p++; } else { int old_use_matrix = canvas->use_matrix; double x1 = prev_x+xc, y1 = prev_y+yc, x2 = x+xc, y2 = y+yc; if (canvas->use_matrix && !canvas->invert_yaxis) { cdfMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); cdfMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); } /* must disable transformation here, because line simulation use cxPixel */ canvas->use_matrix = 0; if (canvas->invert_yaxis) /* must invert because of the angle orientation */ { y1 = yc2 - y1; y2 = yc2 - y2; } simfLineThin(canvas, x1, y1, x2, y2, &last_xi_a, &last_yi_a, &last_xi_b, &last_yi_b); canvas->use_matrix = old_use_matrix; } prev_x = x; prev_y = y; } if (poly) { canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, p); free(poly); } else simLineStyleNoReset = 0; }
void cdfSimMark(cdCanvas* canvas, double x, double y) { int oldinteriorstyle = canvas->interior_style; int oldlinestyle = canvas->line_style; int oldlinewidth = canvas->line_width; double size, half_size, bottom, top, left, right; if (canvas->mark_type == CD_DIAMOND || canvas->mark_type == CD_HOLLOW_DIAMOND) { if (canvas->use_origin) { x += canvas->forigin.x; y += canvas->forigin.y; } if (canvas->invert_yaxis) y = _cdInvertYAxis(canvas, y); } size = (double)canvas->mark_size; half_size = size / 2; bottom = y - half_size; top = y + half_size; left = x - half_size; right = x + half_size; if (canvas->interior_style != CD_SOLID && (canvas->mark_type == CD_CIRCLE || canvas->mark_type == CD_BOX || canvas->mark_type == CD_DIAMOND)) cdCanvasInteriorStyle(canvas, CD_SOLID); if (canvas->line_style != CD_CONTINUOUS && (canvas->mark_type == CD_STAR || canvas->mark_type == CD_PLUS || canvas->mark_type == CD_X || canvas->mark_type == CD_HOLLOW_BOX || canvas->mark_type == CD_HOLLOW_CIRCLE || canvas->mark_type == CD_HOLLOW_DIAMOND)) cdCanvasLineStyle(canvas, CD_CONTINUOUS); if (canvas->line_width != 1 && (canvas->mark_type == CD_STAR || canvas->mark_type == CD_PLUS || canvas->mark_type == CD_X || canvas->mark_type == CD_HOLLOW_BOX || canvas->mark_type == CD_HOLLOW_CIRCLE || canvas->mark_type == CD_HOLLOW_DIAMOND)) cdCanvasLineWidth(canvas, 1); switch (canvas->mark_type) { case CD_STAR: cdfCanvasLine(canvas, left, bottom, right, top); cdfCanvasLine(canvas, left, top, right, bottom); /* continue */ case CD_PLUS: cdfCanvasLine(canvas, left, y, right, y); cdfCanvasLine(canvas, x, bottom, x, top); break; case CD_X: cdfCanvasLine(canvas, left, bottom, right, top); cdfCanvasLine(canvas, left, top, right, bottom); break; case CD_HOLLOW_CIRCLE: cdfCanvasArc(canvas, x, y, size, size, 0, 360); break; case CD_HOLLOW_BOX: cdfCanvasRect(canvas, left, right, bottom, top); break; case CD_CIRCLE: cdfCanvasSector(canvas, x, y, size, size, 0, 360); break; case CD_BOX: cdfCanvasBox(canvas, left, right, bottom, top); break; case CD_HOLLOW_DIAMOND: case CD_DIAMOND: /* Do not use Begin/End here so Mark can be used inside a regular BeginEnd loop */ if (!canvas->cxFPoly) { cdPoint poly[5]; /* leave room for one more point */ poly[0].x = _cdRound(left); poly[0].y = _cdRound(y); poly[1].x = _cdRound(x); poly[1].y = _cdRound(top); poly[2].x = _cdRound(right); poly[2].y = _cdRound(y); poly[3].x = _cdRound(x); poly[3].y = _cdRound(bottom); if (canvas->mark_type == CD_DIAMOND) cdPoly(canvas, CD_FILL, poly, 4); else cdPoly(canvas, CD_CLOSED_LINES, poly, 4); } else { cdfPoint poly[5]; /* leave room for one more point */ poly[0].x = left; poly[0].y = y; poly[1].x = x; poly[1].y = top; poly[2].x = right; poly[2].y = y; poly[3].x = x; poly[3].y = bottom; if (canvas->mark_type == CD_DIAMOND) canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, poly, 4); else canvas->cxFPoly(canvas->ctxcanvas, CD_CLOSED_LINES, poly, 4); } break; } if (canvas->interior_style != oldinteriorstyle && (canvas->mark_type == CD_CIRCLE || canvas->mark_type == CD_BOX || canvas->mark_type == CD_DIAMOND)) cdCanvasInteriorStyle(canvas, oldinteriorstyle); if (canvas->line_style != oldlinestyle && (canvas->mark_type == CD_STAR || canvas->mark_type == CD_PLUS || canvas->mark_type == CD_X || canvas->mark_type == CD_HOLLOW_BOX || canvas->mark_type == CD_HOLLOW_CIRCLE || canvas->mark_type == CD_HOLLOW_DIAMOND)) cdCanvasLineStyle(canvas, oldlinestyle); if (canvas->line_width != oldlinewidth && (canvas->mark_type == CD_STAR || canvas->mark_type == CD_PLUS || canvas->mark_type == CD_X || canvas->mark_type == CD_HOLLOW_BOX || canvas->mark_type == CD_HOLLOW_CIRCLE || canvas->mark_type == CD_HOLLOW_DIAMOND)) cdCanvasLineWidth(canvas, oldlinewidth); }