diff --git a/Xr.h b/Xr.h index 8da186856..ab0e4e8df 100644 --- a/Xr.h +++ b/Xr.h @@ -143,6 +143,12 @@ XrScale(XrState *xrs, double sx, double sy); void XrRotate(XrState *xrs, double angle); +void +XrConcatMatrix(XrState *xrs, + double a, double b, + double c, double d, + double tx, double ty); + /* Path creation */ void XrNewPath(XrState *xrs); @@ -181,5 +187,15 @@ XrStroke(XrState *xrs); void XrFill(XrState *xrs); +/* Error status queries */ + +typedef enum _XrStatus { + XrStatusSuccess = 0, + XrStatusNoMemory +} XrStatus; + +XrStatus +XrGetStatus(XrState *xrs); + #endif diff --git a/src/Xr.h b/src/Xr.h index 8da186856..ab0e4e8df 100644 --- a/src/Xr.h +++ b/src/Xr.h @@ -143,6 +143,12 @@ XrScale(XrState *xrs, double sx, double sy); void XrRotate(XrState *xrs, double angle); +void +XrConcatMatrix(XrState *xrs, + double a, double b, + double c, double d, + double tx, double ty); + /* Path creation */ void XrNewPath(XrState *xrs); @@ -181,5 +187,15 @@ XrStroke(XrState *xrs); void XrFill(XrState *xrs); +/* Error status queries */ + +typedef enum _XrStatus { + XrStatusSuccess = 0, + XrStatusNoMemory +} XrStatus; + +XrStatus +XrGetStatus(XrState *xrs); + #endif diff --git a/src/xr.c b/src/xr.c index 4a7e23452..c68b52237 100644 --- a/src/xr.c +++ b/src/xr.c @@ -27,6 +27,11 @@ #define _XR_CURRENT_GSTATE(xrs) (xrs->stack) +#define XR_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */ + +static void +_XrClipValue(double *value, double min, double max); + XrState * XrCreate(Display *dpy) { @@ -85,18 +90,26 @@ XrSetOperator(XrState *xrs, XrOperator operator) void XrSetRGBColor(XrState *xrs, double red, double green, double blue) { + _XrClipValue(&red, 0.0, 1.0); + _XrClipValue(&green, 0.0, 1.0); + _XrClipValue(&blue, 0.0, 1.0); + _XrGStateSetRGBColor(_XR_CURRENT_GSTATE(xrs), red, green, blue); } void XrSetTolerance(XrState *xrs, double tolerance) { + _XrClipValue(&tolerance, XR_TOLERANCE_MINIMUM, tolerance); + _XrGStateSetTolerance(_XR_CURRENT_GSTATE(xrs), tolerance); } void XrSetAlpha(XrState *xrs, double alpha) { + _XrClipValue(&alpha, 0.0, 1.0); + _XrGStateSetAlpha(_XR_CURRENT_GSTATE(xrs), alpha); } @@ -151,6 +164,15 @@ XrRotate(XrState *xrs, double angle) _XrGStateRotate(_XR_CURRENT_GSTATE(xrs), angle); } +void +XrConcatMatrix(XrState *xrs, + double a, double b, + double c, double d, + double tx, double ty) +{ + _XrGStateConcatMatrix(_XR_CURRENT_GSTATE(xrs), a, b, c, d, tx, ty); +} + void XrNewPath(XrState *xrs) { @@ -269,3 +291,18 @@ XrFill(XrState *xrs) xrs->status = status; } } + +XrStatus +XrGetStatus(XrState *xrs) +{ + return xrs->status; +} + +static void +_XrClipValue(double *value, double min, double max) +{ + if (*value < min) + *value = min; + else if (*value > max) + *value = max; +} diff --git a/src/xrfiller.c b/src/xrfiller.c index 411e79eee..7b30d8126 100644 --- a/src/xrfiller.c +++ b/src/xrfiller.c @@ -60,7 +60,7 @@ _XrFillerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed * XrSpline spline; status = _XrSplineInit(&spline, a, b, c, d); - if (status == XrStatusDegenerate) + if (status == XrIntStatusDegenerate) return XrStatusSuccess; _XrSplineDecompose(&spline, gstate->tolerance); diff --git a/src/xrgstate.c b/src/xrgstate.c index 3f8e1c220..6541ced6e 100644 --- a/src/xrgstate.c +++ b/src/xrgstate.c @@ -76,6 +76,8 @@ _XrGStateInit(XrGState *gstate, Display *dpy) _XrPathInit(&gstate->path); _XrPenInitEmpty(&gstate->pen_regular); + + gstate->next = NULL; } XrStatus @@ -192,8 +194,6 @@ void _XrGStateSetTolerance(XrGState *gstate, double tolerance) { gstate->tolerance = tolerance; - if (gstate->tolerance < XR_GSTATE_TOLERANCE_MINIMUM) - gstate->tolerance = XR_GSTATE_TOLERANCE_MINIMUM; } void @@ -281,6 +281,21 @@ _XrGStateRotate(XrGState *gstate, double angle) _XrTransformMultiplyIntoLeft(&gstate->ctm_inverse, &tmp); } +void +_XrGStateConcatMatrix(XrGState *gstate, + double a, double b, + double c, double d, + double tx, double ty) +{ + XrTransform tmp; + + _XrTransformInitMatrix(&tmp, a, b, c, d, tx, ty); + _XrTransformMultiplyIntoRight(&tmp, &gstate->ctm); + + _XrTransformComputeInverse(&tmp); + _XrTransformMultiplyIntoLeft(&gstate->ctm_inverse, &tmp); +} + void _XrGStateNewPath(XrGState *gstate) { @@ -306,7 +321,7 @@ _XrGStateAddPathOp(XrGState *gstate, XrPathOp op, XPointDouble *pt, int num_pts) case XrPathOpRelLineTo: case XrPathOpRelCurveTo: for (i=0; i < num_pts; i++) { - _XrTransformPointWithoutTranslate(&gstate->ctm, &pt[i]); + _XrTransformDistance(&gstate->ctm, &pt[i]); } break; case XrPathOpClosePath: @@ -435,4 +450,3 @@ _XrGStateFill(XrGState *gstate) return XrStatusSuccess; } - diff --git a/src/xrint.h b/src/xrint.h index cbfbf7e0b..5a299af82 100644 --- a/src/xrint.h +++ b/src/xrint.h @@ -42,11 +42,12 @@ #define __attribute__(x) #endif -typedef enum _XrStatus { - XrStatusSuccess = 0, - XrStatusNoMemory, - XrStatusDegenerate -} XrStatus; +/* Sure wish C had a real enum type so that this would be distinct + from XrStatus. Oh well, without that, I'll use this bogus 1000 + offset */ +typedef enum _XrIntStatus { + XrIntStatusDegenerate = 1000 +} XrIntStatus; typedef enum _XrPathOp { XrPathOpMoveTo = 0, @@ -201,7 +202,6 @@ typedef struct _XrTraps { #define XR_GSTATE_OPERATOR_DEFAULT XrOperatorOver #define XR_GSTATE_TOLERANCE_DEFAULT 0.1 -#define XR_GSTATE_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */ #define XR_GSTATE_WINDING_DEFAULT 1 #define XR_GSTATE_LINE_WIDTH_DEFAULT 2.0 #define XR_GSTATE_LINE_CAP_DEFAULT XrLineCapButt @@ -362,6 +362,12 @@ _XrGStateScale(XrGState *gstate, double sx, double sy); void _XrGStateRotate(XrGState *gstate, double angle); +void +_XrGStateConcatMatrix(XrGState *gstate, + double a, double b, + double c, double d, + double tx, double ty); + void _XrGStateNewPath(XrGState *gstate); @@ -467,7 +473,7 @@ XrStatus _XrPolygonClose(XrPolygon *polygon); /* xrspline.c */ -XrStatus +XrIntStatus _XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d); XrStatus @@ -552,14 +558,14 @@ void _XrTransformMultiply(const XrTransform *t1, const XrTransform *t2, XrTransform *new); void -_XrTransformPointScaleOnly(XrTransform *transform, XPointDouble *pt); - -void -_XrTransformPointWithoutTranslate(XrTransform *transform, XPointDouble *pt); +_XrTransformDistance(XrTransform *transform, XPointDouble *pt); void _XrTransformPoint(XrTransform *transform, XPointDouble *pt); +void +_XrTransformComputeInverse(XrTransform *transform); + void _XrTransformEigenValues(XrTransform *transform, double *lambda1, double *lambda2); diff --git a/src/xrpen.c b/src/xrpen.c index d65fe2afd..038e6708f 100644 --- a/src/xrpen.c +++ b/src/xrpen.c @@ -90,7 +90,7 @@ _XrPenInit(XrPen *pen, double radius, XrGState *gstate) v->theta = 2 * M_PI * i / (double) pen->num_vertices; pt.x = radius * cos(v->theta); pt.y = radius * sin(v->theta); - _XrTransformPointWithoutTranslate(&gstate->ctm, &pt); + _XrTransformDistance(&gstate->ctm, &pt); v->pt.x = XDoubleToFixed(pt.x); v->pt.y = XDoubleToFixed(pt.y); v->flag = XrPenVertexFlagNone; diff --git a/src/xrspline.c b/src/xrspline.c index 5f5861130..d4e7c269b 100644 --- a/src/xrspline.c +++ b/src/xrspline.c @@ -45,7 +45,7 @@ _XrSplineDecomposeInto(XrSpline *spline, double tolerance_squared, XrSpline *res #define XR_SPLINE_GROWTH_INC 100 -XrStatus +XrIntStatus _XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d) { spline->a = *a; @@ -60,7 +60,7 @@ _XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c } else if (a->x != d->x || a->y != d->y) { _ComputeSlope(&spline->a, &spline->d, &spline->initial_slope); } else { - return XrStatusDegenerate; + return XrIntStatusDegenerate; } if (c->x != d->x || c->y != d->y) { diff --git a/src/xrstroker.c b/src/xrstroker.c index 1968b7a37..239e3c74c 100644 --- a/src/xrstroker.c +++ b/src/xrstroker.c @@ -150,14 +150,14 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out) x1 = XFixedToDouble(inpt->x); y1 = XFixedToDouble(inpt->y); v1 = in->vector; - _XrTransformPointWithoutTranslate(&gstate->ctm, &v1); + _XrTransformDistance(&gstate->ctm, &v1); dx1 = v1.x; dy1 = v1.y; x2 = XFixedToDouble(outpt->x); y2 = XFixedToDouble(outpt->y); v2 = out->vector; - _XrTransformPointWithoutTranslate(&gstate->ctm, &v2); + _XrTransformDistance(&gstate->ctm, &v2); dx2 = v2.x; dy2 = v2.y; @@ -213,7 +213,7 @@ _XrStrokerCap(XrStroker *stroker, XrStrokeFace *f) XPointFixed occw, ocw; vector.x *= gstate->line_width / 2.0; vector.y *= gstate->line_width / 2.0; - _XrTransformPointWithoutTranslate(&gstate->ctm, &vector); + _XrTransformDistance(&gstate->ctm, &vector); fvector.x = XDoubleToFixed(vector.x); fvector.y = XDoubleToFixed(vector.y); occw.x = f->ccw.x + fvector.x; @@ -249,7 +249,7 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac vector.x = XFixedToDouble(slope->dx); vector.y = XFixedToDouble(slope->dy); - _XrTransformPointWithoutTranslate(&gstate->ctm_inverse, &vector); + _XrTransformDistance(&gstate->ctm_inverse, &vector); mag = sqrt(vector.x * vector.x + vector.y * vector.y); if (mag == 0) { @@ -266,7 +266,7 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac vector.x = - vector.y * (gstate->line_width / 2.0); vector.y = tmp * (gstate->line_width / 2.0); - _XrTransformPointWithoutTranslate(&gstate->ctm, &vector); + _XrTransformDistance(&gstate->ctm, &vector); offset_ccw.x = XDoubleToFixed(vector.x); offset_ccw.y = XDoubleToFixed(vector.y); @@ -370,7 +370,7 @@ _XrStrokerAddEdgeDashed (void *closure, XPointFixed *p1, XPointFixed *p2) vector.x = XFixedToDouble(p2->x - p1->x); vector.y = XFixedToDouble(p2->y - p1->y); - _XrTransformPointWithoutTranslate(&gstate->ctm_inverse, &vector); + _XrTransformDistance(&gstate->ctm_inverse, &vector); mag = sqrt(vector.x * vector.x + vector.y * vector.y); remain = mag; @@ -382,7 +382,7 @@ _XrStrokerAddEdgeDashed (void *closure, XPointFixed *p1, XPointFixed *p2) remain -= tmp; d2.x = vector.x * (mag - remain)/mag; d2.y = vector.y * (mag - remain)/mag; - _XrTransformPointWithoutTranslate (&gstate->ctm, &d2); + _XrTransformDistance (&gstate->ctm, &d2); fd2.x = XDoubleToFixed (d2.x); fd2.y = XDoubleToFixed (d2.y); fd2.x += p1->x; @@ -472,7 +472,7 @@ _XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed XrPenFlaggedPoint extra_points[4]; status = _XrSplineInit(&spline, a, b, c, d); - if (status == XrStatusDegenerate) + if (status == XrIntStatusDegenerate) return XrStatusSuccess; status = _XrPenInitCopy(&pen, &gstate->pen_regular); diff --git a/src/xrtransform.c b/src/xrtransform.c index a6563a8f1..50b1d544e 100644 --- a/src/xrtransform.c +++ b/src/xrtransform.c @@ -36,6 +36,12 @@ static XrTransform XR_TRANSFORM_DEFAULT = { } }; +static void +_XrTransformScalarMultiply(XrTransform *transform, double scalar); + +static void +_XrTransformComputeAdjoint(XrTransform *transform); + void _XrTransformInit(XrTransform *transform) { @@ -130,7 +136,7 @@ _XrTransformMultiply(const XrTransform *t1, const XrTransform *t2, XrTransform * } void -_XrTransformPointWithoutTranslate(XrTransform *transform, XPointDouble *pt) +_XrTransformDistance(XrTransform *transform, XPointDouble *pt) { double new_x, new_y; @@ -146,12 +152,58 @@ _XrTransformPointWithoutTranslate(XrTransform *transform, XPointDouble *pt) void _XrTransformPoint(XrTransform *transform, XPointDouble *pt) { - _XrTransformPointWithoutTranslate(transform, pt); + _XrTransformDistance(transform, pt); pt->x += transform->m[2][0]; pt->y += transform->m[2][1]; } +static void +_XrTransformScalarMultiply(XrTransform *transform, double scalar) +{ + int row, col; + + for (row = 0; row < 3; row++) + for (col = 0; col < 2; col++) + transform->m[row][col] *= scalar; +} + +/* This function isn't a correct adjoint in that the implicit 1 in the + homogeneous result should actually be ad-bc instead. But, since this + adjoint is only used in the computation of the inverse, which + divides by det(A)=ad-bc anyway, everything works out in the end. */ +static void +_XrTransformComputeAdjoint(XrTransform *transform) +{ + /* adj(A) = transpose(C:cofactor(A,i,j)) */ + double a, b, c, d, tx, ty; + + a = transform->m[0][0]; b = transform->m[0][1]; + c = transform->m[1][0]; d = transform->m[1][1]; + tx = transform->m[2][0]; ty = transform->m[2][1]; + + _XrTransformInitMatrix(transform, + d, -b, + -c, a, + c*ty - d*tx, b*tx - a*ty); +} + +void +_XrTransformComputeInverse(XrTransform *transform) +{ + /* inv(A) = 1/det(A) * adj(A) */ + + double a, b, c, d, det; + + a = transform->m[0][0]; b = transform->m[0][1]; + c = transform->m[1][0]; d = transform->m[1][1]; + + det = a*d - b*c; + + _XrTransformComputeAdjoint(transform); + _XrTransformScalarMultiply(transform, 1 / det); +} + void _XrTransformEigenValues(XrTransform *transform, double *lambda1, double *lambda2) { @@ -159,12 +211,13 @@ _XrTransformEigenValues(XrTransform *transform, double *lambda1, double *lambda2 det(M - lI) = 0 - which for our 2x2 matrix: + The zeros in our homogeneous 3x3 matrix make this equation equal + to that formed by the sub-matrix: M = a b c d - gives: + by which: l^2 - (a+d)l + (ad - bc) = 0 @@ -182,4 +235,3 @@ _XrTransformEigenValues(XrTransform *transform, double *lambda1, double *lambda2 *lambda1 = (a + d + rad) / 2.0; *lambda2 = (a + d - rad) / 2.0; } - diff --git a/xr.c b/xr.c index 4a7e23452..c68b52237 100644 --- a/xr.c +++ b/xr.c @@ -27,6 +27,11 @@ #define _XR_CURRENT_GSTATE(xrs) (xrs->stack) +#define XR_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */ + +static void +_XrClipValue(double *value, double min, double max); + XrState * XrCreate(Display *dpy) { @@ -85,18 +90,26 @@ XrSetOperator(XrState *xrs, XrOperator operator) void XrSetRGBColor(XrState *xrs, double red, double green, double blue) { + _XrClipValue(&red, 0.0, 1.0); + _XrClipValue(&green, 0.0, 1.0); + _XrClipValue(&blue, 0.0, 1.0); + _XrGStateSetRGBColor(_XR_CURRENT_GSTATE(xrs), red, green, blue); } void XrSetTolerance(XrState *xrs, double tolerance) { + _XrClipValue(&tolerance, XR_TOLERANCE_MINIMUM, tolerance); + _XrGStateSetTolerance(_XR_CURRENT_GSTATE(xrs), tolerance); } void XrSetAlpha(XrState *xrs, double alpha) { + _XrClipValue(&alpha, 0.0, 1.0); + _XrGStateSetAlpha(_XR_CURRENT_GSTATE(xrs), alpha); } @@ -151,6 +164,15 @@ XrRotate(XrState *xrs, double angle) _XrGStateRotate(_XR_CURRENT_GSTATE(xrs), angle); } +void +XrConcatMatrix(XrState *xrs, + double a, double b, + double c, double d, + double tx, double ty) +{ + _XrGStateConcatMatrix(_XR_CURRENT_GSTATE(xrs), a, b, c, d, tx, ty); +} + void XrNewPath(XrState *xrs) { @@ -269,3 +291,18 @@ XrFill(XrState *xrs) xrs->status = status; } } + +XrStatus +XrGetStatus(XrState *xrs) +{ + return xrs->status; +} + +static void +_XrClipValue(double *value, double min, double max) +{ + if (*value < min) + *value = min; + else if (*value > max) + *value = max; +} diff --git a/xrfiller.c b/xrfiller.c index 411e79eee..7b30d8126 100644 --- a/xrfiller.c +++ b/xrfiller.c @@ -60,7 +60,7 @@ _XrFillerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed * XrSpline spline; status = _XrSplineInit(&spline, a, b, c, d); - if (status == XrStatusDegenerate) + if (status == XrIntStatusDegenerate) return XrStatusSuccess; _XrSplineDecompose(&spline, gstate->tolerance); diff --git a/xrgstate.c b/xrgstate.c index 3f8e1c220..6541ced6e 100644 --- a/xrgstate.c +++ b/xrgstate.c @@ -76,6 +76,8 @@ _XrGStateInit(XrGState *gstate, Display *dpy) _XrPathInit(&gstate->path); _XrPenInitEmpty(&gstate->pen_regular); + + gstate->next = NULL; } XrStatus @@ -192,8 +194,6 @@ void _XrGStateSetTolerance(XrGState *gstate, double tolerance) { gstate->tolerance = tolerance; - if (gstate->tolerance < XR_GSTATE_TOLERANCE_MINIMUM) - gstate->tolerance = XR_GSTATE_TOLERANCE_MINIMUM; } void @@ -281,6 +281,21 @@ _XrGStateRotate(XrGState *gstate, double angle) _XrTransformMultiplyIntoLeft(&gstate->ctm_inverse, &tmp); } +void +_XrGStateConcatMatrix(XrGState *gstate, + double a, double b, + double c, double d, + double tx, double ty) +{ + XrTransform tmp; + + _XrTransformInitMatrix(&tmp, a, b, c, d, tx, ty); + _XrTransformMultiplyIntoRight(&tmp, &gstate->ctm); + + _XrTransformComputeInverse(&tmp); + _XrTransformMultiplyIntoLeft(&gstate->ctm_inverse, &tmp); +} + void _XrGStateNewPath(XrGState *gstate) { @@ -306,7 +321,7 @@ _XrGStateAddPathOp(XrGState *gstate, XrPathOp op, XPointDouble *pt, int num_pts) case XrPathOpRelLineTo: case XrPathOpRelCurveTo: for (i=0; i < num_pts; i++) { - _XrTransformPointWithoutTranslate(&gstate->ctm, &pt[i]); + _XrTransformDistance(&gstate->ctm, &pt[i]); } break; case XrPathOpClosePath: @@ -435,4 +450,3 @@ _XrGStateFill(XrGState *gstate) return XrStatusSuccess; } - diff --git a/xrint.h b/xrint.h index cbfbf7e0b..5a299af82 100644 --- a/xrint.h +++ b/xrint.h @@ -42,11 +42,12 @@ #define __attribute__(x) #endif -typedef enum _XrStatus { - XrStatusSuccess = 0, - XrStatusNoMemory, - XrStatusDegenerate -} XrStatus; +/* Sure wish C had a real enum type so that this would be distinct + from XrStatus. Oh well, without that, I'll use this bogus 1000 + offset */ +typedef enum _XrIntStatus { + XrIntStatusDegenerate = 1000 +} XrIntStatus; typedef enum _XrPathOp { XrPathOpMoveTo = 0, @@ -201,7 +202,6 @@ typedef struct _XrTraps { #define XR_GSTATE_OPERATOR_DEFAULT XrOperatorOver #define XR_GSTATE_TOLERANCE_DEFAULT 0.1 -#define XR_GSTATE_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */ #define XR_GSTATE_WINDING_DEFAULT 1 #define XR_GSTATE_LINE_WIDTH_DEFAULT 2.0 #define XR_GSTATE_LINE_CAP_DEFAULT XrLineCapButt @@ -362,6 +362,12 @@ _XrGStateScale(XrGState *gstate, double sx, double sy); void _XrGStateRotate(XrGState *gstate, double angle); +void +_XrGStateConcatMatrix(XrGState *gstate, + double a, double b, + double c, double d, + double tx, double ty); + void _XrGStateNewPath(XrGState *gstate); @@ -467,7 +473,7 @@ XrStatus _XrPolygonClose(XrPolygon *polygon); /* xrspline.c */ -XrStatus +XrIntStatus _XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d); XrStatus @@ -552,14 +558,14 @@ void _XrTransformMultiply(const XrTransform *t1, const XrTransform *t2, XrTransform *new); void -_XrTransformPointScaleOnly(XrTransform *transform, XPointDouble *pt); - -void -_XrTransformPointWithoutTranslate(XrTransform *transform, XPointDouble *pt); +_XrTransformDistance(XrTransform *transform, XPointDouble *pt); void _XrTransformPoint(XrTransform *transform, XPointDouble *pt); +void +_XrTransformComputeInverse(XrTransform *transform); + void _XrTransformEigenValues(XrTransform *transform, double *lambda1, double *lambda2); diff --git a/xrpen.c b/xrpen.c index d65fe2afd..038e6708f 100644 --- a/xrpen.c +++ b/xrpen.c @@ -90,7 +90,7 @@ _XrPenInit(XrPen *pen, double radius, XrGState *gstate) v->theta = 2 * M_PI * i / (double) pen->num_vertices; pt.x = radius * cos(v->theta); pt.y = radius * sin(v->theta); - _XrTransformPointWithoutTranslate(&gstate->ctm, &pt); + _XrTransformDistance(&gstate->ctm, &pt); v->pt.x = XDoubleToFixed(pt.x); v->pt.y = XDoubleToFixed(pt.y); v->flag = XrPenVertexFlagNone; diff --git a/xrspline.c b/xrspline.c index 5f5861130..d4e7c269b 100644 --- a/xrspline.c +++ b/xrspline.c @@ -45,7 +45,7 @@ _XrSplineDecomposeInto(XrSpline *spline, double tolerance_squared, XrSpline *res #define XR_SPLINE_GROWTH_INC 100 -XrStatus +XrIntStatus _XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c, XPointFixed *d) { spline->a = *a; @@ -60,7 +60,7 @@ _XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c } else if (a->x != d->x || a->y != d->y) { _ComputeSlope(&spline->a, &spline->d, &spline->initial_slope); } else { - return XrStatusDegenerate; + return XrIntStatusDegenerate; } if (c->x != d->x || c->y != d->y) { diff --git a/xrstroker.c b/xrstroker.c index 1968b7a37..239e3c74c 100644 --- a/xrstroker.c +++ b/xrstroker.c @@ -150,14 +150,14 @@ _XrStrokerJoin(XrStroker *stroker, XrStrokeFace *in, XrStrokeFace *out) x1 = XFixedToDouble(inpt->x); y1 = XFixedToDouble(inpt->y); v1 = in->vector; - _XrTransformPointWithoutTranslate(&gstate->ctm, &v1); + _XrTransformDistance(&gstate->ctm, &v1); dx1 = v1.x; dy1 = v1.y; x2 = XFixedToDouble(outpt->x); y2 = XFixedToDouble(outpt->y); v2 = out->vector; - _XrTransformPointWithoutTranslate(&gstate->ctm, &v2); + _XrTransformDistance(&gstate->ctm, &v2); dx2 = v2.x; dy2 = v2.y; @@ -213,7 +213,7 @@ _XrStrokerCap(XrStroker *stroker, XrStrokeFace *f) XPointFixed occw, ocw; vector.x *= gstate->line_width / 2.0; vector.y *= gstate->line_width / 2.0; - _XrTransformPointWithoutTranslate(&gstate->ctm, &vector); + _XrTransformDistance(&gstate->ctm, &vector); fvector.x = XDoubleToFixed(vector.x); fvector.y = XDoubleToFixed(vector.y); occw.x = f->ccw.x + fvector.x; @@ -249,7 +249,7 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac vector.x = XFixedToDouble(slope->dx); vector.y = XFixedToDouble(slope->dy); - _XrTransformPointWithoutTranslate(&gstate->ctm_inverse, &vector); + _XrTransformDistance(&gstate->ctm_inverse, &vector); mag = sqrt(vector.x * vector.x + vector.y * vector.y); if (mag == 0) { @@ -266,7 +266,7 @@ _ComputeFace(XPointFixed *pt, XrSlopeFixed *slope, XrGState *gstate, XrStrokeFac vector.x = - vector.y * (gstate->line_width / 2.0); vector.y = tmp * (gstate->line_width / 2.0); - _XrTransformPointWithoutTranslate(&gstate->ctm, &vector); + _XrTransformDistance(&gstate->ctm, &vector); offset_ccw.x = XDoubleToFixed(vector.x); offset_ccw.y = XDoubleToFixed(vector.y); @@ -370,7 +370,7 @@ _XrStrokerAddEdgeDashed (void *closure, XPointFixed *p1, XPointFixed *p2) vector.x = XFixedToDouble(p2->x - p1->x); vector.y = XFixedToDouble(p2->y - p1->y); - _XrTransformPointWithoutTranslate(&gstate->ctm_inverse, &vector); + _XrTransformDistance(&gstate->ctm_inverse, &vector); mag = sqrt(vector.x * vector.x + vector.y * vector.y); remain = mag; @@ -382,7 +382,7 @@ _XrStrokerAddEdgeDashed (void *closure, XPointFixed *p1, XPointFixed *p2) remain -= tmp; d2.x = vector.x * (mag - remain)/mag; d2.y = vector.y * (mag - remain)/mag; - _XrTransformPointWithoutTranslate (&gstate->ctm, &d2); + _XrTransformDistance (&gstate->ctm, &d2); fd2.x = XDoubleToFixed (d2.x); fd2.y = XDoubleToFixed (d2.y); fd2.x += p1->x; @@ -472,7 +472,7 @@ _XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed XrPenFlaggedPoint extra_points[4]; status = _XrSplineInit(&spline, a, b, c, d); - if (status == XrStatusDegenerate) + if (status == XrIntStatusDegenerate) return XrStatusSuccess; status = _XrPenInitCopy(&pen, &gstate->pen_regular); diff --git a/xrtransform.c b/xrtransform.c index a6563a8f1..50b1d544e 100644 --- a/xrtransform.c +++ b/xrtransform.c @@ -36,6 +36,12 @@ static XrTransform XR_TRANSFORM_DEFAULT = { } }; +static void +_XrTransformScalarMultiply(XrTransform *transform, double scalar); + +static void +_XrTransformComputeAdjoint(XrTransform *transform); + void _XrTransformInit(XrTransform *transform) { @@ -130,7 +136,7 @@ _XrTransformMultiply(const XrTransform *t1, const XrTransform *t2, XrTransform * } void -_XrTransformPointWithoutTranslate(XrTransform *transform, XPointDouble *pt) +_XrTransformDistance(XrTransform *transform, XPointDouble *pt) { double new_x, new_y; @@ -146,12 +152,58 @@ _XrTransformPointWithoutTranslate(XrTransform *transform, XPointDouble *pt) void _XrTransformPoint(XrTransform *transform, XPointDouble *pt) { - _XrTransformPointWithoutTranslate(transform, pt); + _XrTransformDistance(transform, pt); pt->x += transform->m[2][0]; pt->y += transform->m[2][1]; } +static void +_XrTransformScalarMultiply(XrTransform *transform, double scalar) +{ + int row, col; + + for (row = 0; row < 3; row++) + for (col = 0; col < 2; col++) + transform->m[row][col] *= scalar; +} + +/* This function isn't a correct adjoint in that the implicit 1 in the + homogeneous result should actually be ad-bc instead. But, since this + adjoint is only used in the computation of the inverse, which + divides by det(A)=ad-bc anyway, everything works out in the end. */ +static void +_XrTransformComputeAdjoint(XrTransform *transform) +{ + /* adj(A) = transpose(C:cofactor(A,i,j)) */ + double a, b, c, d, tx, ty; + + a = transform->m[0][0]; b = transform->m[0][1]; + c = transform->m[1][0]; d = transform->m[1][1]; + tx = transform->m[2][0]; ty = transform->m[2][1]; + + _XrTransformInitMatrix(transform, + d, -b, + -c, a, + c*ty - d*tx, b*tx - a*ty); +} + +void +_XrTransformComputeInverse(XrTransform *transform) +{ + /* inv(A) = 1/det(A) * adj(A) */ + + double a, b, c, d, det; + + a = transform->m[0][0]; b = transform->m[0][1]; + c = transform->m[1][0]; d = transform->m[1][1]; + + det = a*d - b*c; + + _XrTransformComputeAdjoint(transform); + _XrTransformScalarMultiply(transform, 1 / det); +} + void _XrTransformEigenValues(XrTransform *transform, double *lambda1, double *lambda2) { @@ -159,12 +211,13 @@ _XrTransformEigenValues(XrTransform *transform, double *lambda1, double *lambda2 det(M - lI) = 0 - which for our 2x2 matrix: + The zeros in our homogeneous 3x3 matrix make this equation equal + to that formed by the sub-matrix: M = a b c d - gives: + by which: l^2 - (a+d)l + (ad - bc) = 0 @@ -182,4 +235,3 @@ _XrTransformEigenValues(XrTransform *transform, double *lambda1, double *lambda2 *lambda1 = (a + d + rad) / 2.0; *lambda2 = (a + d - rad) / 2.0; } -