From 17be65cfea56a53dc3a9cb617895adf5300db099 Mon Sep 17 00:00:00 2001 From: scuri Date: Tue, 1 Jun 2010 22:31:45 +0000 Subject: *** empty log message *** --- html/en/func/filled.html | 24 +++--- html/en/func/lines.html | 22 +++--- html/en/func/polygon.html | 31 +++++--- include/cd_private.h | 23 +++--- src/cairo/cdcairo.c | 72 ++++++++++-------- src/cd.c | 4 + src/cd.def | 6 ++ src/cd_primitives.c | 169 ++++++++++++++++++++++++++++++++--------- src/cd_util.c | 1 + src/drv/cdirgb.c | 186 ++-------------------------------------------- src/drv/cdpdf.c | 28 +++---- src/drv/cdpicture.c | 12 +-- src/drv/cdps.c | 44 +++++------ src/gdiplus/cdwinp.cpp | 78 ++++++++----------- src/gdk/cdgdk.c | 2 +- src/sim/sim_primitives.c | 161 ++++++++++++++++++++++----------------- src/svg/cdsvg.c | 57 +++++++++----- src/win32/cdwin.c | 84 +++++++++++++-------- test/simple/simple.c | 20 +++-- 19 files changed, 522 insertions(+), 502 deletions(-) diff --git a/html/en/func/filled.html b/html/en/func/filled.html index 2ae1083..97a2e84 100644 --- a/html/en/func/filled.html +++ b/html/en/func/filled.html @@ -63,25 +63,29 @@ canvas:fSector(xc, yc, w, h, angle1, angle2: number) [in Lua] canvas:wSector(xc, yc, w, h, angle1, angle2: number) (WC) [in Lua]

Fills the arc of an ellipse aligned with the axis, according to the current - interior style, in the shape of a pie. It is drawn counter-clockwise. The + interior style, in the shape of a pie.

+

The coordinate (xc,yc) defines the center of the ellipse. Dimensions w and h define the elliptic axes X and Y, respectively.

-

Angles angle1 and angle2, in degrees, - define the arc's beginning and end, but they are not the angle relative to the +

Angles angle1 and angle2 are in degrees and oriented + counter-clockwise. They + define the arc start and end, but they are not the angle relative to the center, except when w==h and the ellipse is reduced to a circle. The arc - starts at the point (xc+(w/2)*cos(angle1),yc+(h/2)*sin(angle1)) - and ends at (xc+(w/2)*cos(angle2),yc+(h/2)*sin(angle2)). A - complete ellipse can be drawn using 0 and 360 as the angles.

+ starts at the point (xc+(w/2)*cos(angle1), yc+(h/2)*sin(angle1)) + and ends at (xc+(w/2)*cos(angle2), yc+(h/2)*sin(angle2)). A + complete ellipse can be drawn using 0 and 360 as the angles.  If angle2 + is less than angle1 it will be increased by 360 until it is greater + than angle1.

The angles are specified so if the size of the ellipse (w x h) is changed, its shape is preserved. So the angles relative to the center are dependent - from the ellipse size. The actual angle can be obtained using rangle = - atan2((h/2)*sin(angle),(w/2)*cos(angle)).

-

The angles are given in degrees. To specify the angle in radians, you can + from the ellipse size. The actual angle can be obtained using rangle = + atan2((h/2)*sin(angle), (w/2)*cos(angle)).

+

To specify the angle in radians, you can use the definition CD_RAD2DEG to multiply the value in radians before passing the angle to CD.

When the interior style CD_HOLLOW is defined, - the function behaves like its equivalent cdArc, + the function behaves like its equivalent cdCanvasArc, plus two lines connecting to the center.

Sector Parameters

diff --git a/html/en/func/lines.html b/html/en/func/lines.html index b748391..6ba78d7 100644 --- a/html/en/func/lines.html +++ b/html/en/func/lines.html @@ -1,5 +1,5 @@ - + @@ -64,21 +64,25 @@ canvas:fArc(xc, yc, w, h, angle1, angle2: number) [in Lua] canvas:wArc(xc, yc, w, h, angle1, angle2: number) (WC) [in Lua]

Draws the arc of an ellipse aligned with the axis, using the current - foreground color and line width and style. It is drawn counter-clockwise. The + foreground color and line width and style.

+

The coordinate (xc,yc) defines the center of the ellipse. Dimensions w and h define the elliptic axes X and Y, respectively.

-

Angles angle1 and angle2, in degrees define - the arc's beginning and end, but they are not the angle relative to the +

Angles angle1 and angle2 are in degrees and oriented + counter-clockwise. They define + the arc start and end, but they are not the angle relative to the center, except when w==h and the ellipse is reduced to a circle. The arc - starts at the point (xc+(w/2)*cos(angle1),yc+(h/2)*sin(angle1)) - and ends at (xc+(w/2)*cos(angle2),yc+(h/2)*sin(angle2)). A - complete ellipse can be drawn using 0 and 360 as the angles.

+ starts at the point (xc+(w/2)*cos(angle1), yc+(h/2)*sin(angle1)) + and ends at (xc+(w/2)*cos(angle2), yc+(h/2)*sin(angle2)). A + complete ellipse can be drawn using 0 and 360 as the angles. If angle2 + is less than angle1 it will be increased by 360 until it is greater + than angle1.

The angles are specified so if the size of the ellipse (w x h) is changed, its shape is preserved. So the angles relative to the center are dependent from the ellipse size. The actual angle can be obtained using rangle = - atan2((h/2)*sin(angle),(w/2)*cos(angle)).

-

The angles are given in degrees. To specify the angle in radians, you can + atan2((h/2)*sin(angle), (w/2)*cos(angle)).

+

To specify the angle in radians, you can use the definition CD_RAD2DEG to multiply the value in radians before passing the angle to CD.

Arc Parameters
diff --git a/html/en/func/polygon.html b/html/en/func/polygon.html index 3a0b9c0..c2acb9a 100644 --- a/html/en/func/polygon.html +++ b/html/en/func/polygon.html @@ -93,42 +93,43 @@ canvas:PathSet(action: number) [in Lua]

Configures the action between sequences of cdCanvasVertex. action can be:

@@ -139,6 +140,14 @@ cdCanvasPathSet(canvas, CD_PATH_MOVETO); cdCanvasVertex(canvas, x1, y1); cdCanvasPathSet(canvas, CD_PATH_LINETO); cdCanvasVertex(canvas, x2, y2); +cdCanvasPathSet(canvas, CD_PATH_CURVETO); +cdCanvasVertex(canvas, x3, y3); /* control point for start point */ +cdCanvasVertex(canvas, x4, y4); /* control point for end point */ +cdCanvasVertex(canvas, x5, y5); /* end point */ +cdCanvasPathSet(canvas, CD_PATH_ARC); +cdCanvasVertex(canvas, x6, y6); /* center */ +cdCanvasVertex(canvas, x7, y7); /* width, height */ +cdCanvasVertex(canvas, x8, y8); /* start angle, end angle (degrees / 1000) */ cdCanvasPathSet(canvas, CD_PATH_STROKE); cdCanvasEnd(canvas); diff --git a/include/cd_private.h b/include/cd_private.h index 28b92d8..1410126 100644 --- a/include/cd_private.h +++ b/include/cd_private.h @@ -222,7 +222,6 @@ struct _cdCanvas /* simulation flags */ int sim_mode; - int sim_poly; /* WC */ double s, sx, tx, sy, ty; /* Transformacao Window -> Viewport (scale+translation)*/ @@ -269,7 +268,6 @@ enum{CD_CTX_NATIVEWINDOW, CD_CTX_IMAGE, CD_CTX_DBUFFER, CD_CTX_PRINTER, CD_CTX_E /* utilities */ /*************/ int cdRound(double x); -void cdCanvasGetEllipseBox(int xc, int yc, int w, int h, double a1, double a2, int *xmin, int *xmax, int *ymin, int *ymax); int cdCheckBoxSize(int *xmin, int *xmax, int *ymin, int *ymax); int cdfCheckBoxSize(double *xmin, double *xmax, double *ymin, double *ymax); void cdNormalizeLimits(int w, int h, int *xmin, int *xmax, int *ymin, int *ymax); @@ -280,6 +278,14 @@ char* cdStrDup(const char* str); char* cdStrDupN(const char* str, int len); void cdSetPaperSize(int size, double *w_pt, double *h_pt); +void cdCanvasPoly(cdCanvas* canvas, int mode, cdPoint* points, int n); +void cdCanvasGetArcBox(int xc, int yc, int w, int h, double a1, double a2, int *xmin, int *xmax, int *ymin, int *ymax); +int cdCanvasGetArcPathF(cdCanvas* canvas, const cdPoint* poly, double *xc, double *yc, double *w, double *h, double *a1, double *a2); +int cdfCanvasGetArcPath(cdCanvas* canvas, const cdfPoint* poly, double *xc, double *yc, double *w, double *h, double *a1, double *a2); +int cdCanvasGetArcPath(cdCanvas* canvas, const cdPoint* poly, int *xc, int *yc, int *w, int *h, double *a1, double *a2); +void cdCanvasGetArcStartEnd(int xc, int yc, int w, int h, double a1, double a2, int *x1, int *y1, int *x2, int *y2); +void cdfCanvasGetArcStartEnd(double xc, double yc, double w, double h, double a1, double a2, double *x1, double *y1, double *x2, double *y2); + #define _cdCheckCanvas(_canvas) (_canvas!=NULL && ((unsigned char*)_canvas)[0] == 'C' && ((unsigned char*)_canvas)[1] == 'D') #define _cdInvertYAxis(_canvas, _y) (_canvas->h - (_y) - 1) #define _cdSwapInt(_a,_b) {int _c=_a;_a=_b;_b=_c;} @@ -351,11 +357,6 @@ void cdSimGetTextSizeFT(cdCtxCanvas* ctxcanvas, const char *s, int len, int *wid /* sim_primitives.c */ -/* Simulation functions that depend on the simulation base driver. */ -void cdSimPolyFill(cdCanvas* canvas, cdPoint* poly, int n); -void cdSimPolyLine(cdCanvas* canvas, const cdPoint* poly, int n); -void cdfSimPolyLine(cdCanvas* canvas, const cdfPoint* poly, int n); - /* Simulation functions that are >> independent << of the simulation base driver. */ void cdSimMark(cdCanvas* canvas, int x, int y); void cdSimPutImageRectRGBA(cdCanvas* canvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax); @@ -368,6 +369,8 @@ void cdSimBox(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax); void cdSimArc(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2); void cdSimSector(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2); void cdSimChord(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2); +void cdSimPoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* points, int n); + void cdSimPolyBezier(cdCanvas* canvas, const cdPoint* points, int n); void cdSimPolyPath(cdCanvas* canvas, const cdPoint* points, int n); @@ -379,13 +382,11 @@ void cdfSimBox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, do void cdfSimArc(cdCtxCanvas *ctxcanvas, double xc, double yc, double width, double height, double angle1, double angle2); void cdfSimSector(cdCtxCanvas *ctxcanvas, double xc, double yc, double width, double height, double angle1, double angle2); void cdfSimChord(cdCtxCanvas *ctxcanvas, double xc, double yc, double width, double height, double angle1, double angle2); +void cdfSimPoly(cdCtxCanvas* ctxcanvas, int mode, cdfPoint* fpoly, int n); + void cdfSimPolyBezier(cdCanvas* canvas, const cdfPoint* points, int n); void cdfSimPolyPath(cdCanvas* canvas, const cdfPoint* points, int n); -/* Utilities */ -void cdSimPoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* points, int n); -int cdSimCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height); - #ifdef __cplusplus } diff --git a/src/cairo/cdcairo.c b/src/cairo/cdcairo.c index 55f8b51..9589d74 100644 --- a/src/cairo/cdcairo.c +++ b/src/cairo/cdcairo.c @@ -592,24 +592,28 @@ static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) cdfline(ctxcanvas, (double)x1, (double)y1, (double)x2, (double)y2); } -static void sFixAngles(cdCtxCanvas* ctxcanvas, double *a1, double *a2) +static void sFixAngles(cdCanvas* canvas, double *a1, double *a2, int swap) { - if (ctxcanvas->canvas->invert_yaxis) - { - double t; + /* Cairo angles are clock-wise by default, in radians */ + + /* if NOT inverted means a transformation is set, + so the angle will follow the transformation that includes the axis invertion, + then it is already counter-clockwise */ - /* Cairo angles are clock-wise by default */ + if (canvas->invert_yaxis) + { + /* change orientation */ *a1 *= -1; *a2 *= -1; /* swap, so the start angle is the smaller */ - t = *a1; - *a1 = *a2; - *a2 = t; + if (swap) + { + double t = *a1; + *a1 = *a2; + *a2 = t; + } } - /* if NOT inverted means a transformation is set, - so the angle will follow the transformation that includes the axis invertion, - then it is counter-clockwise */ /* convert to radians */ *a1 *= CD_DEG2RAD; @@ -620,7 +624,7 @@ static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, doubl { sUpdateFill(ctxcanvas, 0); - sFixAngles(ctxcanvas, &a1, &a2); + sFixAngles(ctxcanvas->canvas, &a1, &a2, 1); if (w == h) { @@ -651,7 +655,7 @@ static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, do { sUpdateFill(ctxcanvas, 1); - sFixAngles(ctxcanvas, &a1, &a2); + sFixAngles(ctxcanvas->canvas, &a1, &a2, 1); if (w == h) { @@ -685,7 +689,7 @@ static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, dou { sUpdateFill(ctxcanvas, 1); - sFixAngles(ctxcanvas, &a1, &a2); + sFixAngles(ctxcanvas->canvas, &a1, &a2, 1); if (w == h) { @@ -883,18 +887,17 @@ static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) if (i+3 > n) return; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x/1000.0, - a2 = poly[i+2].y/1000.0; + if (!cdCanvasGetArcPathF(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; - sFixAngles(ctxcanvas, &a1, &a2); + sFixAngles(ctxcanvas->canvas, &a1, &a2, 0); /* do not swap because we handle negative arcs here */ if (w == h) { - cairo_arc(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2); + if ((a2-a1)<0) + cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2); + else + cairo_arc(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2); } else /* Ellipse: change the scale to create from the circle */ { @@ -904,7 +907,10 @@ static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) cairo_scale(ctxcanvas->cr, w/h, 1.0); cairo_translate(ctxcanvas->cr, -xc, -yc); - cairo_arc(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2); + if ((a2-a1)<0) + cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2); + else + cairo_arc(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2); cairo_restore(ctxcanvas->cr); /* restore from local */ } @@ -1036,18 +1042,17 @@ static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) if (i+3 > n) return; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x, - a2 = poly[i+2].y; + if (!cdfCanvasGetArcPath(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; - sFixAngles(ctxcanvas, &a1, &a2); + sFixAngles(ctxcanvas->canvas, &a1, &a2, 0); /* do not swap because we handle negative arcs here */ if (w == h) { - cairo_arc(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2); + if ((a2-a1)<0) + cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2); + else + cairo_arc(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2); } else /* Ellipse: change the scale to create from the circle */ { @@ -1057,7 +1062,10 @@ static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) cairo_scale(ctxcanvas->cr, w/h, 1.0); cairo_translate(ctxcanvas->cr, -xc, -yc); - cairo_arc(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2); + if ((a2-a1)<0) + cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2); + else + cairo_arc(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2); cairo_restore(ctxcanvas->cr); /* restore from local */ } diff --git a/src/cd.c b/src/cd.c index 1c64def..13d2541 100644 --- a/src/cd.c +++ b/src/cd.c @@ -327,7 +327,11 @@ int cdCanvasSimulate(cdCanvas* canvas, int mode) canvas->cxFont(canvas->ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size); if (mode & CD_SIM_POLYLINE || mode & CD_SIM_POLYGON) + { + /* can NOT replace canvas->cxPoly because it will be used by the simulation, + handle polygon simulation in Begin/End */ canvas->cxFPoly = NULL; + } return sim_mode; } diff --git a/src/cd.def b/src/cd.def index eda5beb..da6938c 100644 --- a/src/cd.def +++ b/src/cd.def @@ -220,6 +220,12 @@ EXPORTS cdGetFontSizePoints cdStrEqualNoCase cdSetPaperSize + cdCanvasGetArcPath + cdfCanvasGetArcPath + cdCanvasGetArcPathF + cdCanvasGetArcBox + cdCanvasGetArcStartEnd + cdfCanvasGetArcStartEnd wdCanvasLineWidth wdCanvasMarkSize diff --git a/src/cd_primitives.c b/src/cd_primitives.c index ca6ad6d..8714e70 100644 --- a/src/cd_primitives.c +++ b/src/cd_primitives.c @@ -136,20 +136,9 @@ void cdCanvasBegin(cdCanvas* canvas, int mode) return; } - canvas->sim_poly = 0; - if (canvas->interior_style == CD_HOLLOW && mode == CD_FILL) mode = CD_CLOSED_LINES; - /* simulacao de linhas */ - if ((mode == CD_CLOSED_LINES || mode == CD_OPEN_LINES || mode == CD_BEZIER) && - canvas->sim_mode & CD_SIM_POLYLINE) - canvas->sim_poly = 1; - - /* simulacao de poligonos preenchidos */ - if (mode == CD_FILL && canvas->sim_mode & CD_SIM_POLYGON) - canvas->sim_poly = 1; - canvas->poly_mode = mode; } @@ -182,7 +171,7 @@ void cdCanvasVertex(cdCanvas* canvas, int x, int y) canvas->poly = (cdPoint*)realloc(canvas->poly, sizeof(cdPoint) * (canvas->poly_size+1)); } - if (canvas->poly_mode != CD_BEZIER && + if (canvas->poly_mode != CD_BEZIER && canvas->poly_mode != CD_PATH && canvas->poly_n > 0 && canvas->poly[canvas->poly_n-1].x == x && canvas->poly[canvas->poly_n-1].y == y) @@ -258,6 +247,27 @@ void cdCanvasPathSet(cdCanvas* canvas, int action) canvas->path_n++; } +void cdCanvasPoly(cdCanvas* canvas, int mode, cdPoint* points, int n) +{ + int sim_poly = 0; + + /* simulacao de linhas */ + if ((mode == CD_CLOSED_LINES || mode == CD_OPEN_LINES || + mode == CD_BEZIER || mode == CD_PATH) && + canvas->sim_mode & CD_SIM_POLYLINE) + sim_poly = 1; + + /* simulacao de poligonos preenchidos */ + if ((mode == CD_FILL || mode == CD_PATH) && + canvas->sim_mode & CD_SIM_POLYGON) + sim_poly = 1; + + if (sim_poly) + cdSimPoly(canvas->ctxcanvas, mode, points, n); + else + canvas->cxPoly(canvas->ctxcanvas, mode, points, n); +} + void cdCanvasEnd(cdCanvas* canvas) { assert(canvas); @@ -297,15 +307,10 @@ void cdCanvasEnd(cdCanvas* canvas) return; } - if (canvas->sim_poly) - cdSimPoly(canvas->ctxcanvas, canvas->poly_mode, canvas->poly, canvas->poly_n); + if (canvas->use_fpoly) + canvas->cxFPoly(canvas->ctxcanvas, canvas->poly_mode, canvas->fpoly, canvas->poly_n); else - { - if (canvas->use_fpoly) - canvas->cxFPoly(canvas->ctxcanvas, canvas->poly_mode, canvas->fpoly, canvas->poly_n); - else - canvas->cxPoly(canvas->ctxcanvas, canvas->poly_mode, canvas->poly, canvas->poly_n); - } + cdCanvasPoly(canvas, canvas->poly_mode, canvas->poly, canvas->poly_n); if (canvas->poly_mode == CD_CLIP) { @@ -462,7 +467,7 @@ void cdfCanvasBox(cdCanvas* canvas, double xmin, double xmax, double ymin, doubl canvas->cxBox(canvas->ctxcanvas, _cdRound(xmin), _cdRound(xmax), _cdRound(ymin), _cdRound(ymax)); } -static void normAngles(double *angle1, double *angle2) +static void sNormAngles(double *angle1, double *angle2) { *angle1 = fmod(*angle1,360); *angle2 = fmod(*angle2,360); @@ -477,7 +482,7 @@ void cdCanvasArc(cdCanvas* canvas, int xc, int yc, int w, int h, double angle1, if (angle1 == angle2 || w == 0 || h == 0) return; - normAngles(&angle1, &angle2); + sNormAngles(&angle1, &angle2); if (canvas->use_origin) { @@ -499,7 +504,7 @@ void cdfCanvasArc(cdCanvas* canvas, double xc, double yc, double w, double h, do if (angle1 == angle2 || w == 0 || h == 0) return; - normAngles(&angle1, &angle2); + sNormAngles(&angle1, &angle2); if (canvas->use_origin) { @@ -525,7 +530,7 @@ void cdCanvasSector(cdCanvas* canvas, int xc, int yc, int w, int h, double angle if (angle1 == angle2 || w == 0 || h == 0) return; - normAngles(&angle1, &angle2); + sNormAngles(&angle1, &angle2); if (canvas->interior_style == CD_HOLLOW) { @@ -568,7 +573,7 @@ void cdfCanvasSector(cdCanvas* canvas, double xc, double yc, double w, double h, if (angle1 == angle2 || w == 0 || h == 0) return; - normAngles(&angle1, &angle2); + sNormAngles(&angle1, &angle2); if (canvas->interior_style == CD_HOLLOW) { @@ -614,7 +619,7 @@ void cdCanvasChord(cdCanvas* canvas, int xc, int yc, int w, int h, double angle1 if (angle1 == angle2 || w == 0 || h == 0) return; - normAngles(&angle1, &angle2); + sNormAngles(&angle1, &angle2); if (canvas->interior_style == CD_HOLLOW) { @@ -654,7 +659,7 @@ void cdfCanvasChord(cdCanvas* canvas, double xc, double yc, double w, double h, if (angle1 == angle2 || w == 0 || h == 0) return; - normAngles(&angle1, &angle2); + sNormAngles(&angle1, &angle2); if (canvas->interior_style == CD_HOLLOW) { @@ -689,23 +694,43 @@ void cdfCanvasChord(cdCanvas* canvas, double xc, double yc, double w, double h, canvas->cxChord(canvas->ctxcanvas, _cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), angle1, angle2); } -void cdCanvasGetEllipseBox(int xc, int yc, int w, int h, double a1, double a2, int *xmin, int *xmax, int *ymin, int *ymax) +void cdCanvasGetArcStartEnd(int xc, int yc, int w, int h, double a1, double a2, int *x1, int *y1, int *x2, int *y2) { + /* computation is done as if the angles are counterclockwise, + and yaxis is NOT inverted. */ + + /* leave xc and yc outside the round, so the center will be always the same */ + + if (x1) *x1 = xc + cdRound((w/2.0)*cos(a1*CD_DEG2RAD)); + if (y1) *y1 = yc + cdRound((h/2.0)*sin(a1*CD_DEG2RAD)); + if (x2) *x2 = xc + cdRound((w/2.0)*cos(a2*CD_DEG2RAD)); + if (y2) *y2 = yc + cdRound((h/2.0)*sin(a2*CD_DEG2RAD)); +} + +void cdfCanvasGetArcStartEnd(double xc, double yc, double w, double h, double a1, double a2, double *x1, double *y1, double *x2, double *y2) +{ + if (x1) *x1 = xc + (w/2.0)*cos(a1*CD_DEG2RAD); + if (y1) *y1 = yc + (h/2.0)*sin(a1*CD_DEG2RAD); + if (x2) *x2 = xc + (w/2.0)*cos(a2*CD_DEG2RAD); + if (y2) *y2 = yc + (h/2.0)*sin(a2*CD_DEG2RAD); +} + +void cdCanvasGetArcBox(int xc, int yc, int w, int h, double a1, double a2, int *xmin, int *xmax, int *ymin, int *ymax) +{ + int x, y; + + /* computation is done as if the angles are counterclockwise, + and yaxis is NOT inverted. */ + #define _BBOX() \ if (x > *xmax) *xmax = x; \ if (y > *ymax) *ymax = y; \ if (x < *xmin) *xmin = x; \ if (y < *ymin) *ymin = y; - int x, y; - - *xmin = (int)(xc+w/2*cos(a1*CD_DEG2RAD)); - *ymin = (int)(yc+h/2*sin(a1*CD_DEG2RAD)); + cdCanvasGetArcStartEnd(xc, yc, w, h, a1, a2, xmin, ymin, &x, &y); *xmax = *xmin; *ymax = *ymin; - - x = (int)(xc+w/2*cos(a2*CD_DEG2RAD)); - y = (int)(yc+h/2*sin(a2*CD_DEG2RAD)); _BBOX() if (a1 > a2) @@ -733,3 +758,77 @@ void cdCanvasGetEllipseBox(int xc, int yc, int w, int h, double a1, double a2, i _BBOX() } } + +int cdCanvasGetArcPath(cdCanvas* canvas, const cdPoint* poly, int *xc, int *yc, int *w, int *h, double *a1, double *a2) +{ + *xc = poly[0].x; + *yc = poly[0].y; + *w = poly[1].x; + *h = poly[1].y; + *a1 = poly[2].x; + *a2 = poly[2].y; + + if (canvas->invert_yaxis) /* undo axis invertion */ + { + *h = _cdInvertYAxis(canvas, *h); + *a2 = _cdInvertYAxis(canvas, *a2); + } + + /* fix integer scale */ + *a1 /= 1000.0; + *a2 /= 1000.0; + + if (*a1 == *a2 || *w == 0 || *h == 0) + return 0; + + /* path angles can be counter-clockwise (a1a2) */ + return 1; +} + +int cdfCanvasGetArcPath(cdCanvas* canvas, const cdfPoint* poly, double *xc, double *yc, double *w, double *h, double *a1, double *a2) +{ + *xc = poly[0].x; + *yc = poly[0].y; + *w = poly[1].x; + *h = poly[1].y; + *a1 = poly[2].x; + *a2 = poly[2].y; + + if (canvas->invert_yaxis) /* undo axis invertion */ + { + *h = _cdInvertYAxis(canvas, *h); + *a2 = _cdInvertYAxis(canvas, *a2); + } + + if (*a1 == *a2 || *w == 0 || *h == 0) + return 0; + + /* path angles can be counter-clockwise (a1a2) */ + return 1; +} + +int cdCanvasGetArcPathF(cdCanvas* canvas, const cdPoint* poly, double *xc, double *yc, double *w, double *h, double *a1, double *a2) +{ + *xc = poly[0].x; + *yc = poly[0].y; + *w = poly[1].x; + *h = poly[1].y; + *a1 = poly[2].x; + *a2 = poly[2].y; + + if (canvas->invert_yaxis) /* undo axis invertion */ + { + *h = _cdInvertYAxis(canvas, *h); + *a2 = _cdInvertYAxis(canvas, *a2); + } + + /* fix integer scale */ + *a1 /= 1000.0; + *a2 /= 1000.0; + + if (*a1 == *a2 || *w == 0 || *h == 0) + return 0; + + /* path angles can be counter-clockwise (a1a2) */ + return 1; +} diff --git a/src/cd_util.c b/src/cd_util.c index 39d491d..b278dfc 100644 --- a/src/cd_util.c +++ b/src/cd_util.c @@ -397,3 +397,4 @@ void cdSetPaperSize(int size, double *w_pt, double *h_pt) *w_pt = (double)paper[size].w_pt; *h_pt = (double)paper[size].h_pt; } + diff --git a/src/drv/cdirgb.c b/src/drv/cdirgb.c index e6cb4b5..9f367e0 100644 --- a/src/drv/cdirgb.c +++ b/src/drv/cdirgb.c @@ -580,7 +580,7 @@ static void irgbClipPoly(cdCtxCanvas* ctxcanvas, unsigned char* clip_region, cdP memcpy(t_poly, poly, sizeof(cdPoint)*n); poly = t_poly; - for(i = 0; i < n; i++) + for(i = 0; i < n; i++) /* must duplicate because clip poly is stored */ cdMatrixTransformPoint(canvas->matrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y); } @@ -642,79 +642,6 @@ static void irgbClipPoly(cdCtxCanvas* ctxcanvas, unsigned char* clip_region, cdP irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h); } -static void irgbClipElipse(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2, int sector) -{ - float c, s, sx, sy, x, y, prev_x, prev_y; - double da; - int i, p; - cdPoint* poly; - - /* number of segments of equivalent poligonal for a full ellipse */ - int n = cdSimCalcEllipseNumSegments(ctxcanvas->canvas, xc, yc, width, height); - - /* number of segments for the arc */ - n = cdRound((fabs(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); - poly[0].x = _cdRound(x); - poly[0].y = _cdRound(y); - prev_x = x; - prev_y = 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 (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++; - } - - irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, p, ctxcanvas->canvas->combine_mode); - - free(poly); -} - static void irgbClipBox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) { int combine_mode = ctxcanvas->canvas->combine_mode; @@ -952,54 +879,6 @@ static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin cdfSimBox(ctxcanvas, xmin, xmax, ymin, ymax); } -static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) -{ - if (ctxcanvas->canvas->new_region) - { - /* matrix transformation is done inside irgbClip* if necessary */ - irgbClipElipse(ctxcanvas, xc, yc, w, h, a1, a2, 1); - return; - } - - cdSimSector(ctxcanvas, xc, yc, w, h, a1, a2); -} - -static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) -{ - if (ctxcanvas->canvas->new_region) - { - /* matrix transformation is done inside irgbClip* if necessary */ - irgbClipElipse(ctxcanvas, xc, yc, w, h, a1, a2, 0); - return; - } - - cdSimChord(ctxcanvas, xc, yc, w, h, a1, a2); -} - -static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) -{ - if (ctxcanvas->canvas->new_region) - { - /* matrix transformation is done inside irgbClip* if necessary */ - irgbClipElipse(ctxcanvas, _cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, 1); - return; - } - - cdfSimSector(ctxcanvas, xc, yc, w, h, a1, a2); -} - -static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) -{ - if (ctxcanvas->canvas->new_region) - { - /* matrix transformation is done inside irgbClip* if necessary */ - irgbClipElipse(ctxcanvas, _cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, 0); - return; - } - - cdfSimChord(ctxcanvas, xc, yc, w, h, a1, a2); -} - static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s, int len) { if (ctxcanvas->canvas->new_region) @@ -1035,59 +914,6 @@ static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) cdSimPoly(ctxcanvas, mode, poly, n); } -static void cdfpoly(cdCtxCanvas* ctxcanvas, int mode, cdfPoint* fpoly, int n) -{ - int i; - - switch(mode) - { - case CD_CLOSED_LINES: - fpoly[n] = fpoly[0]; - n++; - /* continue */ - case CD_OPEN_LINES: - cdfSimPolyLine(ctxcanvas->canvas, fpoly, n); - break; - case CD_BEZIER: - cdfSimPolyBezier(ctxcanvas->canvas, fpoly, n); - break; - case CD_PATH: - cdfSimPolyPath(ctxcanvas->canvas, fpoly, n); - break; - case CD_FILL: - { - cdPoint* poly = malloc(sizeof(cdPoint)*n); - - for (i = 0; icanvas->clip_mode == CD_CLIPPOLYGON) cdclip(ctxcanvas, CD_CLIPPOLYGON); - } - break; - } -} - static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h) { int dst_offset, src_offset, l, xsize, ysize, xpos, ypos; @@ -2031,8 +1857,8 @@ static void cdinittable(cdCanvas* canvas) canvas->cxRect = cdSimRect; canvas->cxBox = cdbox; canvas->cxArc = cdSimArc; - canvas->cxSector = cdsector; - canvas->cxChord = cdchord; + canvas->cxSector = cdSimSector; + canvas->cxChord = cdSimChord; canvas->cxPoly = cdpoly; canvas->cxText = cdtext; @@ -2040,9 +1866,9 @@ static void cdinittable(cdCanvas* canvas) canvas->cxFRect = cdfSimRect; canvas->cxFBox = cdfbox; canvas->cxFArc = cdfSimArc; - canvas->cxFSector = cdfsector; - canvas->cxFChord = cdfchord; - canvas->cxFPoly = cdfpoly; + canvas->cxFSector = cdfSimSector; + canvas->cxFChord = cdfSimChord; + canvas->cxFPoly = cdfSimPoly; canvas->cxKillCanvas = cdkillcanvas; diff --git a/src/drv/cdpdf.c b/src/drv/cdpdf.c index 2c48d50..f6621d3 100644 --- a/src/drv/cdpdf.c +++ b/src/drv/cdpdf.c @@ -570,15 +570,16 @@ static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) if (i+3 > n) return; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x/1000.0, - a2 = poly[i+2].y/1000.0; + if (!cdCanvasGetArcPathF(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; if (w==h) - PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); + { + if ((a2-a1)<0) + PDF_arcn(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); + else + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); + } else /* Ellipse: change the scale to create from the circle */ { PDF_save(ctxcanvas->pdf); /* save to use the local transform */ @@ -587,7 +588,10 @@ static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) PDF_scale(ctxcanvas->pdf, w/h, 1); PDF_translate(ctxcanvas->pdf, -xc, -yc); - PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*h, a1, a2); + if ((a2-a1)<0) + PDF_arcn(ctxcanvas->pdf, xc, yc, 0.5*h, a1, a2); + else + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*h, a1, a2); PDF_restore(ctxcanvas->pdf); /* restore from local */ } @@ -716,12 +720,8 @@ static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) if (i+3 > n) return; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x, - a2 = poly[i+2].y; + if (!cdfCanvasGetArcPath(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; if (w==h) PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); diff --git a/src/drv/cdpicture.c b/src/drv/cdpicture.c index f1d089a..4cbc5d5 100644 --- a/src/drv/cdpicture.c +++ b/src/drv/cdpicture.c @@ -508,7 +508,7 @@ static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a prim->param.arcsectorchord.angle1 = a1; prim->param.arcsectorchord.angle2 = a2; picAddPrim(ctxcanvas, prim); - cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + cdCanvasGetArcBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); picUpdateBBox(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width); picUpdateBBox(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width); } @@ -525,7 +525,7 @@ static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, doubl prim->param.arcsectorchordf.angle1 = a1; prim->param.arcsectorchordf.angle2 = a2; picAddPrim(ctxcanvas, prim); - cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + cdCanvasGetArcBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); picUpdateBBox(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width); picUpdateBBox(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width); } @@ -542,7 +542,7 @@ static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, doubl prim->param.arcsectorchord.angle1 = a1; prim->param.arcsectorchord.angle2 = a2; picAddPrim(ctxcanvas, prim); - cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + cdCanvasGetArcBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); picUpdateBBox(ctxcanvas, xmin, ymin, 0); picUpdateBBox(ctxcanvas, xmax, ymax, 0); picUpdateBBox(ctxcanvas, xc, yc, 0); @@ -560,7 +560,7 @@ static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, do prim->param.arcsectorchordf.angle1 = a1; prim->param.arcsectorchordf.angle2 = a2; picAddPrim(ctxcanvas, prim); - cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + 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); picUpdateBBox(ctxcanvas, _cdRound(xc), _cdRound(yc), 0); @@ -578,7 +578,7 @@ static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double prim->param.arcsectorchord.angle1 = a1; prim->param.arcsectorchord.angle2 = a2; picAddPrim(ctxcanvas, prim); - cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + cdCanvasGetArcBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); picUpdateBBox(ctxcanvas, xmin, ymin, 0); picUpdateBBox(ctxcanvas, xmax, ymax, 0); } @@ -595,7 +595,7 @@ static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, dou prim->param.arcsectorchordf.angle1 = a1; prim->param.arcsectorchordf.angle2 = a2; picAddPrim(ctxcanvas, prim); - cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + 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); } diff --git a/src/drv/cdps.c b/src/drv/cdps.c index b651994..357abf4 100644 --- a/src/drv/cdps.c +++ b/src/drv/cdps.c @@ -648,7 +648,7 @@ static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a if (ctxcanvas->eps) { int xmin, xmax, ymin, ymax; - cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + cdCanvasGetArcBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); bbox(ctxcanvas, xmin, ymin); bbox(ctxcanvas, xmax, ymax); } @@ -680,7 +680,7 @@ static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, doubl if (ctxcanvas->eps) { int xmin, xmax, ymin, ymax; - cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + cdCanvasGetArcBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); bbox(ctxcanvas, xmin, ymin); bbox(ctxcanvas, xmax, ymax); } @@ -720,7 +720,7 @@ static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, doubl if (ctxcanvas->eps) { int xmin, xmax, ymin, ymax; - cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + cdCanvasGetArcBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); bbox(ctxcanvas, xmin, ymin); bbox(ctxcanvas, xmax, ymax); bbox(ctxcanvas, xc, yc); @@ -761,7 +761,7 @@ static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, do if (ctxcanvas->eps) { int xmin, xmax, ymin, ymax; - cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + cdCanvasGetArcBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); bbox(ctxcanvas, xmin, ymin); bbox(ctxcanvas, xmax, ymax); fbbox(ctxcanvas, xc, yc); @@ -800,7 +800,7 @@ static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double if (ctxcanvas->eps) { int xmin, xmax, ymin, ymax; - cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + cdCanvasGetArcBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); bbox(ctxcanvas, xmin, ymin); bbox(ctxcanvas, xmax, ymax); } @@ -838,7 +838,7 @@ static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, dou if (ctxcanvas->eps) { int xmin, xmax, ymin, ymax; - cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + cdCanvasGetArcBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); bbox(ctxcanvas, xmin, ymin); bbox(ctxcanvas, xmax, ymax); } @@ -1110,19 +1110,19 @@ static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) case CD_PATH_ARC: { double xc, yc, w, h, a1, a2; + char* arc = "arc"; if (i+3 > n) return; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x/1000.0, - a2 = poly[i+2].y/1000.0; + if (!cdCanvasGetArcPathF(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; + + if ((a2-a1)<0) + arc = "arcn"; if (w==h) /* Circulo: PS implementa direto */ { - fprintf(ctxcanvas->file, "N %d %d %g %g %g arc\n", xc, yc, 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "N %d %d %g %g %g %s\n", xc, yc, 0.5*w, a1, a2, arc); } else /* Elipse: mudar a escala p/ criar a partir do circulo */ { @@ -1130,7 +1130,7 @@ static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) fprintf(ctxcanvas->file, "%d %d translate\n", xc, yc); fprintf(ctxcanvas->file, "1 %g scale\n", ((double)h)/w); fprintf(ctxcanvas->file, "N\n"); - fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "0 0 %g %g %g %s\n", 0.5*w, a1, a2, arc); fprintf(ctxcanvas->file, "setmatrix\n"); /* back to CTM */ } @@ -1303,19 +1303,19 @@ static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) case CD_PATH_ARC: { double xc, yc, w, h, a1, a2; + char* arc = "arc"; if (i+3 > n) return; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x, - a2 = poly[i+2].y; + if (!cdfCanvasGetArcPath(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; + + if ((a2-a1)<0) + arc = "arcn"; if (w==h) /* Circulo: PS implementa direto */ { - fprintf(ctxcanvas->file, "N %g %g %g %g %g arc\n", xc, yc, 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "N %g %g %g %g %g %s\n", xc, yc, 0.5*w, a1, a2, arc); } else /* Elipse: mudar a escala p/ criar a partir do circulo */ { @@ -1323,7 +1323,7 @@ static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) fprintf(ctxcanvas->file, "%g %g translate\n", xc, yc); fprintf(ctxcanvas->file, "1 %g scale\n", ((double)h)/w); fprintf(ctxcanvas->file, "N\n"); - fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "0 0 %g %g %g %s\n", 0.5*w, a1, a2, arc); fprintf(ctxcanvas->file, "setmatrix\n"); /* back to CTM */ } diff --git a/src/gdiplus/cdwinp.cpp b/src/gdiplus/cdwinp.cpp index a2eec55..52c19a1 100644 --- a/src/gdiplus/cdwinp.cpp +++ b/src/gdiplus/cdwinp.cpp @@ -626,15 +626,21 @@ static void cdfbox(cdCtxCanvas* ctxcanvas, double xmin, double xmax, double ymin } } -static void cdwpFixAngles(cdCtxCanvas* ctxcanvas, double *angle1, double *angle2) +static void sFixAngles(cdCanvas* canvas, double *a1, double *a2) { - if (ctxcanvas->canvas->invert_yaxis) + // GDI+ angles are clock-wise by default, in degrees + + /* if NOT inverted means a transformation is set, + so the angle will follow the transformation that includes the axis invertion, + then it is already counter-clockwise */ + + if (canvas->invert_yaxis) { - // GDI+ angles are clock-wise by default, in degrees - *angle1 *= -1; - *angle2 *= -1; + /* change orientation */ + *a1 *= -1; + *a2 *= -1; - // no need to swap, because we will use (angle2-angle1) + /* no need to swap, because we will use (angle2-angle1) */ } } @@ -645,7 +651,7 @@ static void cdarc(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double a ctxcanvas->graphics->DrawEllipse(ctxcanvas->linePen, rect); else { - cdwpFixAngles(ctxcanvas, &angle1, &angle2); + sFixAngles(ctxcanvas->canvas, &angle1, &angle2); ctxcanvas->graphics->DrawArc(ctxcanvas->linePen, rect, (REAL)angle1, (REAL)(angle2-angle1)); } ctxcanvas->dirty = 1; @@ -658,7 +664,7 @@ static void cdfarc(cdCtxCanvas* ctxcanvas, double xc, double yc, double w, doubl ctxcanvas->graphics->DrawEllipse(ctxcanvas->linePen, rect); else { - cdwpFixAngles(ctxcanvas, &angle1, &angle2); + sFixAngles(ctxcanvas->canvas, &angle1, &angle2); ctxcanvas->graphics->DrawArc(ctxcanvas->linePen, rect, (REAL)angle1, (REAL)(angle2-angle1)); } ctxcanvas->dirty = 1; @@ -674,7 +680,7 @@ static void cdsector(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, doubl path.AddEllipse(rect); else { - cdwpFixAngles(ctxcanvas, &angle1, &angle2); + sFixAngles(ctxcanvas->canvas, &angle1, &angle2); path.AddPie(rect, (REAL)angle1, (REAL)(angle2-angle1)); } Region region(&path); @@ -692,7 +698,7 @@ static void cdsector(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, doubl } else { - cdwpFixAngles(ctxcanvas, &angle1, &angle2); + sFixAngles(ctxcanvas->canvas, &angle1, &angle2); ctxcanvas->graphics->FillPie(ctxcanvas->fillBrush, rect, (REAL)angle1, (REAL)(angle2-angle1)); ctxcanvas->graphics->DrawArc(&pen, rect, (REAL)angle1, (REAL)(angle2-angle1)); } @@ -710,7 +716,7 @@ static void cdfsector(cdCtxCanvas* ctxcanvas, double xc, double yc, double w, do path.AddEllipse(rect); else { - cdwpFixAngles(ctxcanvas, &angle1, &angle2); + sFixAngles(ctxcanvas->canvas, &angle1, &angle2); path.AddPie(rect, (REAL)angle1, (REAL)(angle2-angle1)); } Region region(&path); @@ -728,7 +734,7 @@ static void cdfsector(cdCtxCanvas* ctxcanvas, double xc, double yc, double w, do } else { - cdwpFixAngles(ctxcanvas, &angle1, &angle2); + sFixAngles(ctxcanvas->canvas, &angle1, &angle2); ctxcanvas->graphics->FillPie(ctxcanvas->fillBrush, rect, (REAL)angle1, (REAL)(angle2-angle1)); ctxcanvas->graphics->DrawArc(&pen, rect, (REAL)angle1, (REAL)(angle2-angle1)); } @@ -746,7 +752,7 @@ static void cdchord(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double path.AddEllipse(rect); else { - cdwpFixAngles(ctxcanvas, &angle1, &angle2); + sFixAngles(ctxcanvas->canvas, &angle1, &angle2); path.AddArc(rect, (REAL)angle1, (REAL)(angle2-angle1)); path.CloseFigure(); } @@ -760,7 +766,7 @@ static void cdchord(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double else { GraphicsPath path; - cdwpFixAngles(ctxcanvas, &angle1, &angle2); + sFixAngles(ctxcanvas->canvas, &angle1, &angle2); path.AddArc(rect, (REAL)angle1, (REAL)(angle2-angle1)); ctxcanvas->graphics->FillPath(ctxcanvas->fillBrush, &path); } @@ -780,7 +786,7 @@ static void cdfchord(cdCtxCanvas* ctxcanvas, double xc, double yc, double w, dou path.AddEllipse(rect); else { - cdwpFixAngles(ctxcanvas, &angle1, &angle2); + sFixAngles(ctxcanvas->canvas, &angle1, &angle2); path.AddArc(rect, (REAL)angle1, (REAL)(angle2-angle1)); path.CloseFigure(); } @@ -794,7 +800,7 @@ static void cdfchord(cdCtxCanvas* ctxcanvas, double xc, double yc, double w, dou else { GraphicsPath path; - cdwpFixAngles(ctxcanvas, &angle1, &angle2); + sFixAngles(ctxcanvas->canvas, &angle1, &angle2); path.AddArc(rect, (REAL)angle1, (REAL)(angle2-angle1)); ctxcanvas->graphics->FillPath(ctxcanvas->fillBrush, &path); } @@ -850,27 +856,17 @@ static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) if (i+3 > n) break; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x/1000.0, - a2 = poly[i+2].y/1000.0; + if (!cdCanvasGetArcPath(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; if (current_set) { int StartX, StartY; if (ctxcanvas->canvas->invert_yaxis) - { - StartX = xc + cdRound(w * cos(CD_DEG2RAD * a1) / 2.0); - StartY = yc - cdRound(h * sin(CD_DEG2RAD * a1) / 2.0); - } + cdCanvasGetArcStartEnd(xc, yc, w, h, -a1, -a2, &StartX, &StartY, NULL, NULL); else - { - StartX = xc + cdRound(w * cos(CD_DEG2RAD * a2) / 2.0); - StartY = yc + cdRound(h * sin(CD_DEG2RAD * a2) / 2.0); - } + cdCanvasGetArcStartEnd(xc, yc, w, h, a1, a2, &StartX, &StartY, NULL, NULL); graphics_path->AddLine(current_x, current_y, StartX, StartY); } @@ -880,7 +876,7 @@ static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) graphics_path->AddEllipse(rect); else { - cdwpFixAngles(ctxcanvas, &a1, &a2); + sFixAngles(ctxcanvas->canvas, &a1, &a2); graphics_path->AddArc(rect, (REAL)a1, (REAL)(a2-a1)); } @@ -1084,27 +1080,17 @@ static void cdfpoly(cdCtxCanvas* ctxcanvas, int mode, cdfPoint* poly, int n) if (i+3 > n) break; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x, - a2 = poly[i+2].y; + if (!cdfCanvasGetArcPath(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; if (current_set) { double StartX, StartY; if (ctxcanvas->canvas->invert_yaxis) - { - StartX = xc + w * cos(CD_DEG2RAD * a1) / 2.0; - StartY = yc - h * sin(CD_DEG2RAD * a1) / 2.0; - } + cdfCanvasGetArcStartEnd(xc, yc, w, h, -a1, -a2, &StartX, &StartY, NULL, NULL); else - { - StartX = xc + w * cos(CD_DEG2RAD * a2) / 2.0; - StartY = yc + h * sin(CD_DEG2RAD * a2) / 2.0; - } + cdfCanvasGetArcStartEnd(xc, yc, w, h, a1, a2, &StartX, &StartY, NULL, NULL); graphics_path->AddLine((REAL)current_x, (REAL)current_y, (REAL)StartX, (REAL)StartY); } @@ -1114,7 +1100,7 @@ static void cdfpoly(cdCtxCanvas* ctxcanvas, int mode, cdfPoint* poly, int n) graphics_path->AddEllipse(rect); else { - cdwpFixAngles(ctxcanvas, &a1, &a2); + sFixAngles(ctxcanvas->canvas, &a1, &a2); graphics_path->AddArc(rect, (REAL)a1, (REAL)(a2-a1)); } diff --git a/src/gdk/cdgdk.c b/src/gdk/cdgdk.c index 56055a7..d5236c7 100644 --- a/src/gdk/cdgdk.c +++ b/src/gdk/cdgdk.c @@ -890,7 +890,7 @@ static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) { int i; - if (mode != CD_BEZIER) + if (mode != CD_BEZIER && mode != CD_PATH) { for (i = 0; i < n; i++) { diff --git a/src/sim/sim_primitives.c b/src/sim/sim_primitives.c index 9470b21..4b3ebf3 100644 --- a/src/sim/sim_primitives.c +++ b/src/sim/sim_primitives.c @@ -19,7 +19,7 @@ void cdSimLine(cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2) cdPoint poly[2]; poly[0].x = x1; poly[0].y = y1; poly[1].x = x2; poly[1].y = y2; - canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, 2); + cdCanvasPoly(canvas, CD_OPEN_LINES, poly, 2); } void cdfSimLine(cdCtxCanvas* ctxcanvas, double x1, double y1, double x2, double y2) @@ -39,7 +39,7 @@ void cdSimRect(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) poly[1].x = xmin; poly[1].y = ymax; poly[2].x = xmax; poly[2].y = ymax; poly[3].x = xmax; poly[3].y = ymin; - canvas->cxPoly(canvas->ctxcanvas, CD_CLOSED_LINES, poly, 4); + cdCanvasPoly(canvas, CD_CLOSED_LINES, poly, 4); } void cdfSimRect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) @@ -62,7 +62,7 @@ void cdSimBox(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) poly[1].x = xmin; poly[1].y = ymax; poly[2].x = xmax; poly[2].y = ymax; poly[3].x = xmax; poly[3].y = ymin; - canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, 4); + cdCanvasPoly(canvas, CD_FILL, poly, 4); } void cdfSimBox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) @@ -77,9 +77,9 @@ void cdfSimBox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, do canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, poly, 4); } -int cdSimCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height) +static int sCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height, double angle1, double angle2) { - int n, dx, dy, hd; + int K, dx, dy, hd; int w2 = width/2; int h2 = height/2; int x1 = xc-w2, @@ -93,6 +93,8 @@ int cdSimCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int cdMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); } + /* first calculate the number of segments of equivalent poligonal for a full ellipse */ + dx = (x1-x2); dy = (y1-y2); hd = (int)(sqrt(dx*dx + dy*dy)/2); @@ -104,40 +106,39 @@ int cdSimCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int The number of segments will be 360 / min_angle. */ - n = (int)((360.0*CD_DEG2RAD) / acos((double)hd / (hd + 1.0)) + 0.5); /* round up */ + K = (int)((360.0*CD_DEG2RAD) / acos((double)hd / (hd + 1.0)) + 0.5); /* round up */ /* multiple of 4 */ - n = ((n + 3)/4)*4; + K = ((K + 3)/4)*4; /* minimum number is 4 */ - if (n < 4) n = 4; + if (K < 4) K = 4; + + + /* finally, calculate the number of segments for the arc */ + K = cdRound((fabs(angle2-angle1)*K)/(360*CD_DEG2RAD)); + if (K < 1) K = 1; - return n; + return K; } -static void sFixAngles(cdCanvas* canvas, double *angle1, double *angle2) +static void sFixAngles(cdCanvas* canvas, double *a1, double *a2) { + /* computation in PolyAddArc is done as if the angles are counterclockwise, + and yaxis is NOT inverted. */ + if (canvas->invert_yaxis) { - double t; - - /* computation is done as if the angles are counterclockwise, - and yaxis is NOT inverted. */ - - /* if yaxis is inverted then must orient clockwise */ - /* change angle orientation */ - *angle1 = 360 - *angle1; - *angle2 = 360 - *angle2; + /* change orientation */ + *a1 *= -1; + *a2 *= -1; - /* swap, so the start angle is the smaller */ - t = *angle1; - *angle1 = *angle2; - *angle2 = t; + /* no need to swap, because we will use (angle2-angle1) */ } /* convert to radians */ - *angle1 *= CD_DEG2RAD; - *angle2 *= CD_DEG2RAD; + *a1 *= CD_DEG2RAD; + *a2 *= CD_DEG2RAD; } static cdPoint* sPolyAddArc(cdCanvas* canvas, cdPoint* poly, int *n, int xc, int yc, int width, int height, double angle1, double angle2, cdPoint* current) @@ -147,14 +148,10 @@ static cdPoint* sPolyAddArc(cdCanvas* canvas, cdPoint* poly, int *n, int xc, int int i, K, k, p, new_n; cdPoint* old_poly = poly; - /* number of segments of equivalent poligonal for a full ellipse */ - K = cdSimCalcEllipseNumSegments(canvas, xc, yc, width, height); - sFixAngles(canvas, &angle1, &angle2); /* number of segments for the arc */ - K = cdRound((fabs(angle2-angle1)*K)/(360*CD_DEG2RAD)); - if (K < 1) K = 1; + 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 */ @@ -208,17 +205,13 @@ static cdPoint* sPolyAddArc(cdCanvas* canvas, cdPoint* poly, int *n, int xc, int static cdfPoint* sfPolyAddArc(cdCanvas* canvas, cdfPoint* poly, int *n, double xc, double yc, double width, double height, double angle1, double angle2, cdfPoint* current) { double c, s, sx, sy, x, y, prev_x, prev_y, da; - int i, k, p, new_n; + int i, k, K, p, new_n; cdfPoint* old_poly = poly; - /* number of segments of equivalent poligonal for a full ellipse */ - int K = cdSimCalcEllipseNumSegments(canvas, (int)xc, (int)yc, (int)width, (int)height); - sFixAngles(canvas, &angle1, &angle2); /* number of segments for the arc */ - K = cdRound((fabs(angle2-angle1)*K)/(360*CD_DEG2RAD)); - if (K < 1) K = 1; + K = sCalcEllipseNumSegments(canvas, (int)xc, (int)yc, (int)width, (int)height, angle1, angle2); new_n = *n + K+1; /* add room for K+1 samples */ poly = (cdfPoint*)realloc(poly, sizeof(cdfPoint)*(new_n+2)); /* add room also for points at start and end */ @@ -284,7 +277,7 @@ void cdSimArc(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, dou if (poly) { - canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, n); + cdCanvasPoly(canvas, CD_OPEN_LINES, poly, n); free(poly); } } @@ -336,7 +329,7 @@ static void sElipse(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int heigh if (poly) { - canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, n); + cdCanvasPoly(canvas, CD_FILL, poly, n); free(poly); } } @@ -684,7 +677,7 @@ void cdSimPolyBezier(cdCanvas* canvas, const cdPoint* points, int n) if (poly) { - canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, poly_n); + cdCanvasPoly(canvas, CD_OPEN_LINES, poly, poly_n); free(poly); } } @@ -789,12 +782,8 @@ void cdfSimPolyPath(cdCanvas* canvas, const cdfPoint* poly, int n) if (i+3 > n) break; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x, - a2 = poly[i+2].y; + if (!cdfCanvasGetArcPath(canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; if (current_set) path_poly = sfPolyAddArc(canvas, path_poly, &path_poly_n, xc, yc, w, h, a1, a2, ¤t); @@ -909,12 +898,8 @@ static void sSimPolyFPath(cdCanvas* canvas, const cdPoint* poly, int n) if (i+3 > n) break; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x/1000.0, - a2 = poly[i+2].y/1000.0; + if (!cdCanvasGetArcPathF(canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; if (current_set) path_poly = sfPolyAddArc(canvas, path_poly, &path_poly_n, xc, yc, w, h, a1, a2, ¤t); @@ -1043,12 +1028,8 @@ void cdSimPolyPath(cdCanvas* canvas, const cdPoint* poly, int n) if (i+3 > n) break; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x/1000.0, - a2 = poly[i+2].y/1000.0; + if (!cdCanvasGetArcPath(canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; if (current_set) path_poly = sPolyAddArc(canvas, path_poly, &path_poly_n, xc, yc, w, h, a1, a2, ¤t); @@ -1091,22 +1072,22 @@ void cdSimPolyPath(cdCanvas* canvas, const cdPoint* poly, int n) break; case CD_PATH_FILL: if (poly) - canvas->cxPoly(canvas->ctxcanvas, CD_FILL, path_poly, path_poly_n); + cdCanvasPoly(canvas, CD_FILL, path_poly, path_poly_n); break; case CD_PATH_STROKE: if (poly) - canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, path_poly, path_poly_n); + cdCanvasPoly(canvas, CD_OPEN_LINES, path_poly, path_poly_n); break; case CD_PATH_FILLSTROKE: if (poly) { - canvas->cxPoly(canvas->ctxcanvas, CD_FILL, path_poly, path_poly_n); - canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, path_poly, path_poly_n); + cdCanvasPoly(canvas, CD_FILL, path_poly, path_poly_n); + cdCanvasPoly(canvas, CD_OPEN_LINES, path_poly, path_poly_n); } break; case CD_PATH_CLIP: if (poly) - canvas->cxPoly(canvas->ctxcanvas, CD_CLIP, path_poly, path_poly_n); + cdCanvasPoly(canvas, CD_CLIP, path_poly, path_poly_n); break; } } @@ -1117,6 +1098,11 @@ void cdSimPolyPath(cdCanvas* canvas, const cdPoint* poly, int n) /************************************************************************/ +/* Simulation functions that depend on the simulation base driver. */ +static void cdSimPolyFill(cdCanvas* canvas, cdPoint* poly, int n); +static void cdSimPolyLine(cdCanvas* canvas, const cdPoint* poly, int n); +static void cdfSimPolyLine(cdCanvas* canvas, const cdfPoint* poly, int n); + void cdSimPoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) { cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; @@ -1142,6 +1128,45 @@ void cdSimPoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) } } +void cdfSimPoly(cdCtxCanvas* ctxcanvas, int mode, cdfPoint* fpoly, int n) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + + switch(mode) + { + case CD_CLOSED_LINES: + fpoly[n] = fpoly[0]; + n++; + /* continue */ + case CD_OPEN_LINES: + cdfSimPolyLine(canvas, fpoly, n); + break; + case CD_BEZIER: + cdfSimPolyBezier(canvas, fpoly, n); + break; + case CD_PATH: + cdfSimPolyPath(canvas, fpoly, n); + break; + case CD_CLIP: + case CD_FILL: + { + cdPoint* poly = malloc(sizeof(cdPoint)*n); + int i; + + for (i = 0; iinterior_style; @@ -1218,9 +1243,9 @@ void cdSimMark(cdCanvas* canvas, int x, int y) poly[3].y = bottom; if (canvas->mark_type == CD_DIAMOND) - canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, 4); + cdCanvasPoly(canvas, CD_FILL, poly, 4); else - canvas->cxPoly(canvas->ctxcanvas, CD_CLOSED_LINES, poly, 4); + cdCanvasPoly(canvas, CD_CLOSED_LINES, poly, 4); } break; } @@ -1296,7 +1321,7 @@ void cdSimPutImageRectRGBA(cdCanvas* canvas, int iw, int ih, const unsigned char #include "cd_truetype.h" #include "sim.h" -void cdSimPolyLine(cdCanvas* canvas, const cdPoint* poly, int n) +static void cdSimPolyLine(cdCanvas* canvas, const cdPoint* poly, int n) { int i, reset = 1, transform = 0; int old_use_matrix = canvas->use_matrix; @@ -1342,7 +1367,7 @@ void cdSimPolyLine(cdCanvas* canvas, const cdPoint* poly, int n) canvas->use_matrix = old_use_matrix; } -void cdfSimPolyLine(cdCanvas* canvas, const cdfPoint* poly, int n) +static void cdfSimPolyLine(cdCanvas* canvas, const cdfPoint* poly, int n) { int i, reset = 1, transform = 0; int old_use_matrix = canvas->use_matrix; @@ -1429,14 +1454,14 @@ static void sGetBox(cdPoint* poly, int *xmin, int *xmax, int *ymin, int *ymax) } } -void cdSimPolyFill(cdCanvas* canvas, cdPoint* poly, int n) +static void cdSimPolyFill(cdCanvas* canvas, cdPoint* poly, int n) { int old_use_matrix = canvas->use_matrix; if (canvas->use_matrix) { int i; - for(i = 0; i < n; i++) /* can do that because poly is internal of the CD */ + for(i = 0; i < n; i++) /* can do that because poly is internal of the CD, and it will NOT be stored */ cdMatrixTransformPoint(canvas->matrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y); } diff --git a/src/svg/cdsvg.c b/src/svg/cdsvg.c index f84e4b5..789ece3 100644 --- a/src/svg/cdsvg.c +++ b/src/svg/cdsvg.c @@ -215,9 +215,36 @@ static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax cdfbox(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); } -static void sCalcArc(cdCtxCanvas* ctxcanvas, double xc, double yc, double w, double h, double a1, double a2, double *arcStartX, double *arcStartY, double *arcEndX, double *arcEndY, int *largeArc) +static void sCalcArc(cdCanvas* canvas, double xc, double yc, double w, double h, double a1, double a2, double *arcStartX, double *arcStartY, double *arcEndX, double *arcEndY, int *largeArc) { - if (ctxcanvas->canvas->invert_yaxis==0) + /* computation is done as if the angles are counterclockwise, + and yaxis is NOT inverted. */ + + if (canvas->invert_yaxis) + { + double t; + + /* change orientation */ + a1 *= -1; + a2 *= -1; + + /* swap, so the start angle is the smaller */ + t = a1; + a1 = a2; + a2 = t; + } + + cdfCanvasGetArcStartEnd(xc, yc, w, h, a1, a2, arcStartX, arcStartY, arcEndX, arcEndY); + + if (fabs(a2-a1) > 180.0) + *largeArc = 1; + else + *largeArc = 0; +} + +static void sCalcArc_OLD(cdCanvas* canvas, double xc, double yc, double w, double h, double a1, double a2, double *arcStartX, double *arcStartY, double *arcEndX, double *arcEndY, int *largeArc) +{ + if (canvas->invert_yaxis==0) { double t; @@ -263,7 +290,7 @@ static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, doubl return; } - sCalcArc(ctxcanvas, xc, yc, w, h, a1, a2, &arcStartX, &arcStartY, &arcEndX, &arcEndY, &largeArc); + sCalcArc(ctxcanvas->canvas, xc, yc, w, h, a1, a2, &arcStartX, &arcStartY, &arcEndX, &arcEndY, &largeArc); fprintf(ctxcanvas->file, "\n", arcStartX, arcStartY, w/2, h/2, largeArc, arcEndX, arcEndY, ctxcanvas->fgColor, ctxcanvas->canvas->line_width, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->opacity); @@ -286,7 +313,7 @@ static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, do return; } - sCalcArc(ctxcanvas, xc, yc, w, h, a1, a2, &arcStartX, &arcStartY, &arcEndX, &arcEndY, &largeArc); + sCalcArc(ctxcanvas->canvas, xc, yc, w, h, a1, a2, &arcStartX, &arcStartY, &arcEndX, &arcEndY, &largeArc); fprintf(ctxcanvas->file, "\n", xc, yc, arcStartX, arcStartY, w/2, h/2, largeArc, arcEndX, arcEndY, (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor: ctxcanvas->pattern, ctxcanvas->opacity); @@ -302,7 +329,7 @@ static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, dou double arcStartX, arcStartY, arcEndX, arcEndY; int largeArc; - sCalcArc(ctxcanvas, xc, yc, w, h, a1, a2, &arcStartX, &arcStartY, &arcEndX, &arcEndY, &largeArc); + sCalcArc(ctxcanvas->canvas, xc, yc, w, h, a1, a2, &arcStartX, &arcStartY, &arcEndX, &arcEndY, &largeArc); fprintf(ctxcanvas->file, "\n", arcStartX, arcStartY, w/2, h/2, largeArc, arcEndX, arcEndY, (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor: ctxcanvas->pattern, ctxcanvas->opacity); @@ -477,14 +504,10 @@ static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) if (i+3 > n) return; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x, - a2 = poly[i+2].y; + if (!cdfCanvasGetArcPath(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; - sCalcArc(ctxcanvas, xc, yc, w, h, a1, a2, &arcStartX, &arcStartY, &arcEndX, &arcEndY, &largeArc); + sCalcArc(ctxcanvas->canvas, xc, yc, w, h, a1, a2, &arcStartX, &arcStartY, &arcEndX, &arcEndY, &largeArc); fprintf(ctxcanvas->file, "M %g %g A %g %g 0 %d 0 %g %g ", arcStartX, arcStartY, w/2, h/2, largeArc, arcEndX, arcEndY); @@ -636,14 +659,10 @@ static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) if (i+3 > n) return; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x/1000.0, - a2 = poly[i+2].y/1000.0; + if (!cdCanvasGetArcPath(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; - sCalcArc(ctxcanvas, xc, yc, w, h, a1, a2, &arcStartX, &arcStartY, &arcEndX, &arcEndY, &largeArc); + sCalcArc(ctxcanvas->canvas, xc, yc, w, h, a1, a2, &arcStartX, &arcStartY, &arcEndX, &arcEndY, &largeArc); fprintf(ctxcanvas->file, "M %g %g A %d %d 0 %d 0 %g %g ", arcStartX, arcStartY, w/2, h/2, largeArc, arcEndX, arcEndY); diff --git a/src/win32/cdwin.c b/src/win32/cdwin.c index 37c4c0d..246ea5e 100644 --- a/src/win32/cdwin.c +++ b/src/win32/cdwin.c @@ -710,41 +710,45 @@ typedef struct _winArcParam YEndArc; /* second radial ending point */ } winArcParam; -static void sCalcArc(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2, winArcParam* arc) +static void sCalcArc(cdCanvas* canvas, int xc, int yc, int w, int h, double a1, double a2, winArcParam* arc, int swap) { - /* convert to radians */ - angle1 *= CD_DEG2RAD; - angle2 *= CD_DEG2RAD; + /* computation is done as if the angles are counter-clockwise, + and yaxis is NOT inverted. */ - arc->LeftRect = xc - w/2; - arc->RightRect = xc + w/2 + 1; - arc->XStartArc = xc + cdRound(w * cos(angle1) / 2.0); - arc->XEndArc = xc + cdRound(w * cos(angle2) / 2.0); + arc->LeftRect = xc - w/2; + arc->TopRect = yc - h/2; + arc->RightRect = xc + w/2 + 1; + arc->BottomRect = yc + h/2 + 1; - if (ctxcanvas->canvas->invert_yaxis) + /* GDI orientation is the same as CD */ + + if (!canvas->invert_yaxis) + _cdSwapInt(arc->BottomRect, arc->TopRect); /* not necessary, but done for clarity */ + + cdCanvasGetArcStartEnd(xc, yc, w, h, a1, a2, &(arc->XStartArc), &(arc->YStartArc), &(arc->XEndArc), &(arc->YEndArc)); + + if (canvas->invert_yaxis) { - arc->TopRect = yc - h/2; - arc->BottomRect = yc + h/2 + 1; - arc->YStartArc = yc - cdRound(h * sin(angle1) / 2.0); - arc->YEndArc = yc - cdRound(h * sin(angle2) / 2.0); + /* fix axis orientation only, because angle orientation is the same */ + arc->YStartArc = 2*yc - arc->YStartArc; + arc->YEndArc = 2*yc - arc->YEndArc; } else { - arc->BottomRect = yc - h/2; - arc->TopRect = yc + h/2 + 1; - arc->YStartArc = yc + cdRound(h * sin(angle1) / 2.0); - arc->YEndArc = yc + cdRound(h * sin(angle2) / 2.0); - + /* Arc behave diferent when GM_ADVANCED is set */ /* it is clock-wise when axis NOT inverted */ - _cdSwapInt(arc->XStartArc, arc->XEndArc); - _cdSwapInt(arc->YStartArc, arc->YEndArc); + if (swap) + { + _cdSwapInt(arc->XStartArc, arc->XEndArc); + _cdSwapInt(arc->YStartArc, arc->YEndArc); + } } } static void cdarc(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) { winArcParam arc; - sCalcArc(ctxcanvas, xc, yc, w, h, angle1, angle2, &arc); + sCalcArc(ctxcanvas->canvas, xc, yc, w, h, angle1, angle2, &arc, 1); sUpdateFill(ctxcanvas, 0); @@ -754,7 +758,7 @@ static void cdarc(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double a static void cdsector(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) { winArcParam arc; - sCalcArc(ctxcanvas, xc, yc, w, h, angle1, angle2, &arc); + sCalcArc(ctxcanvas->canvas, xc, yc, w, h, angle1, angle2, &arc, 1); sUpdateFill(ctxcanvas, 1); @@ -796,7 +800,7 @@ static void cdsector(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, doubl static void cdchord(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) { winArcParam arc; - sCalcArc(ctxcanvas, xc, yc, w, h, angle1, angle2, &arc); + sCalcArc(ctxcanvas->canvas, xc, yc, w, h, angle1, angle2, &arc, 1); sUpdateFill(ctxcanvas, 1); @@ -843,10 +847,11 @@ static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) if (mode == CD_PATH) { - int p; + int p, current_set; /* if there is any current path, remove it */ BeginPath(ctxcanvas->hDC); + current_set = 0; i = 0; for (p=0; pcanvas->path_n; p++) @@ -856,42 +861,57 @@ static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) case CD_PATH_NEW: EndPath(ctxcanvas->hDC); BeginPath(ctxcanvas->hDC); + current_set = 0; break; case CD_PATH_MOVETO: if (i+1 > n) return; MoveToEx(ctxcanvas->hDC, poly[i].x, poly[i].y, NULL); + current_set = 1; i++; break; case CD_PATH_LINETO: if (i+1 > n) return; LineTo(ctxcanvas->hDC, poly[i].x, poly[i].y); + current_set = 1; i++; break; case CD_PATH_ARC: { - int xc, yc, w, h; + int xc, yc, w, h, old_arcmode = 0; double a1, a2; winArcParam arc; if (i+3 > n) return; - xc = poly[i].x, - yc = poly[i].y, - w = poly[i+1].x, - h = poly[i+1].y, - a1 = poly[i+2].x/1000.0, - a2 = poly[i+2].y/1000.0; + if (!cdCanvasGetArcPath(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) + return; + + sCalcArc(ctxcanvas->canvas, xc, yc, w, h, a1, a2, &arc, 0); - sCalcArc(ctxcanvas, xc, yc, w, h, a1, a2, &arc); + if (current_set) + LineTo(ctxcanvas->hDC, arc.XStartArc, arc.YStartArc); + if ((a2-a1)<0) /* can be clockwise */ + { + /* Arc behave diferent when GM_ADVANCED is set */ + old_arcmode = SetArcDirection(ctxcanvas->hDC, ctxcanvas->canvas->invert_yaxis? AD_CLOCKWISE: AD_COUNTERCLOCKWISE); + } + Arc(ctxcanvas->hDC, arc.LeftRect, arc.TopRect, arc.RightRect, arc.BottomRect, arc.XStartArc, arc.YStartArc, arc.XEndArc, arc.YEndArc); + if (old_arcmode) /* restore */ + SetArcDirection(ctxcanvas->hDC, old_arcmode); + + MoveToEx(ctxcanvas->hDC, arc.XEndArc, arc.YEndArc, NULL); + current_set = 1; + i += 3; } break; case CD_PATH_CURVETO: if (i+3 > n) return; PolyBezierTo(ctxcanvas->hDC, (POINT*)(poly + i), 3); + current_set = 1; i += 3; break; case CD_PATH_CLOSE: diff --git a/test/simple/simple.c b/test/simple/simple.c index eb7acab..891caef 100644 --- a/test/simple/simple.c +++ b/test/simple/simple.c @@ -705,18 +705,26 @@ int SimpleDrawAll(void) cdCanvasPathSet(canvas, CD_PATH_MOVETO); cdVertex(w/2 + 200, h/2); cdCanvasPathSet(canvas, CD_PATH_LINETO); + cdVertex(w/2 + 230, h/2 + 50); + cdCanvasPathSet(canvas, CD_PATH_LINETO); cdVertex(w/2 + 250, h/2 + 50); cdCanvasPathSet(canvas, CD_PATH_CURVETO); - cdVertex(w/2+150+150, h/2+200-50); - cdVertex(w/2+150+180, h/2+250-50); - cdVertex(w/2+150+180, h/2+200-50); + cdVertex(w/2+150+150, h/2+200-50); /* control point for start */ + cdVertex(w/2+150+180, h/2+250-50); /* control point for end */ + cdVertex(w/2+150+180, h/2+200-50); /* end point */ cdCanvasPathSet(canvas, CD_PATH_CURVETO); cdVertex(w/2+150+180, h/2+150-50); cdVertex(w/2+150+150, h/2+100-50); cdVertex(w/2+150+300, h/2+100-50); - cdCanvasPathSet(canvas, CD_PATH_CLOSE); -// cdCanvasPathSet(canvas, CD_PATH_STROKE); - cdCanvasPathSet(canvas, CD_PATH_FILL); + cdCanvasPathSet(canvas, CD_PATH_LINETO); + cdVertex(w/2+150+300, h/2-50); + cdCanvasPathSet(canvas, CD_PATH_ARC); + cdVertex(w/2+300, h/2); /* center */ + cdVertex(200, 100); /* width, height */ + cdVertex(-30*1000, -170*1000); /* start angle, end angle (degrees / 1000) */ +// cdCanvasPathSet(canvas, CD_PATH_CLOSE); + cdCanvasPathSet(canvas, CD_PATH_STROKE); +// cdCanvasPathSet(canvas, CD_PATH_FILL); // cdCanvasPathSet(canvas, CD_PATH_FILLSTROKE); cdEnd(); -- cgit v1.2.3