Fixed pen to transform user-space radius to device space, (vertices_needed computation still broken). Pen now behaves well when an extra point is coincident with an original vertex point.

This commit is contained in:
Carl Worth 2002-09-04 07:28:56 +00:00
parent cf6f2e67d9
commit 13216da122
10 changed files with 124 additions and 64 deletions

4
Xr.h
View file

@ -145,8 +145,6 @@ XrScale(XrState *xrs, double sx, double sy);
void
XrRotate(XrState *xrs, double angle);
/* XXX: NYI: XrSetDash, ... */
/* Path creation */
void
XrNewPath(XrState *xrs);
@ -178,8 +176,6 @@ XrRelCurveTo(XrState *xrs,
void
XrClosePath(XrState *xrs);
/* XXX: NYI: XrArcTo, XrCurveTo, XrRelCurveTo, ... */
/* Render current path */
void
XrStroke(XrState *xrs);

View file

@ -145,8 +145,6 @@ XrScale(XrState *xrs, double sx, double sy);
void
XrRotate(XrState *xrs, double angle);
/* XXX: NYI: XrSetDash, ... */
/* Path creation */
void
XrNewPath(XrState *xrs);
@ -178,8 +176,6 @@ XrRelCurveTo(XrState *xrs,
void
XrClosePath(XrState *xrs);
/* XXX: NYI: XrArcTo, XrCurveTo, XrRelCurveTo, ... */
/* Render current path */
void
XrStroke(XrState *xrs);

View file

@ -114,6 +114,9 @@ XrGStateDeinit(XrGState *gstate)
XrTransformDeinit(&gstate->ctm_inverse);
XrPathDeinit(&gstate->path);
XrPenDeinit(&gstate->pen_regular);
if (gstate->dashes)
free (gstate->dashes);
}
@ -354,7 +357,7 @@ XrGStateStroke(XrGState *gstate)
XrStroker stroker;
XrTraps traps;
XrPenInit(&gstate->pen_regular, gstate->line_width / 2.0, gstate->tolerance);
XrPenInit(&gstate->pen_regular, gstate->line_width / 2.0, gstate);
XrTrapsInit(&traps);
XrStrokerInit(&stroker, gstate, &traps);

View file

@ -434,7 +434,7 @@ XrSurfaceSetFormat(XrSurface *surface, XrFormat format);
/* xrpen.c */
XrError
XrPenInit(XrPen *pen, double radius, double tolerance);
XrPenInit(XrPen *pen, double radius, XrGState *gstate);
XrError
XrPenInitEmpty(XrPen *pen);

View file

@ -58,21 +58,26 @@ XrPenInitEmpty(XrPen *pen)
}
XrError
XrPenInit(XrPen *pen, double radius, double tolerance)
XrPenInit(XrPen *pen, double radius, XrGState *gstate)
{
int i;
XrPenVertex *v;
XPointDouble pt;
if (pen->num_vertices) {
/* XXX: It would be nice to notice that the pen is already properly constructed.
However, this test would also have to account for possible changes in the transformation
matrix.
if (pen->radius == radius && pen->tolerance == tolerance)
return XrErrorSuccess;
*/
XrPenDeinit(pen);
}
pen->radius = radius;
pen->tolerance = tolerance;
pen->tolerance = gstate->tolerance;
pen->num_vertices = _XrPenVerticesNeeded(radius, tolerance);
pen->num_vertices = _XrPenVerticesNeeded(radius, gstate->tolerance);
pen->vertex = malloc(pen->num_vertices * sizeof(XrPenVertex));
if (pen->vertex == NULL) {
@ -82,8 +87,11 @@ XrPenInit(XrPen *pen, double radius, double tolerance)
for (i=0; i < pen->num_vertices; i++) {
v = &pen->vertex[i];
v->theta = 2 * M_PI * i / (double) pen->num_vertices;
v->pt.x = XDoubleToFixed(radius * cos(v->theta));
v->pt.y = XDoubleToFixed(radius * sin(v->theta));
pt.x = radius * cos(v->theta);
pt.y = radius * sin(v->theta);
XrTransformPointWithoutTranslate(&gstate->ctm, &pt);
v->pt.x = XDoubleToFixed(pt.x);
v->pt.y = XDoubleToFixed(pt.y);
v->tag = XrPenVertexTagNone;
}
@ -126,7 +134,7 @@ _XrPenVertexCompareByTheta(const void *a, const void *b)
XrError
XrPenAddPoints(XrPen *pen, XrPenTaggedPoint *pt, int num_pts)
{
int i;
int i, j;
XrPenVertex *v, *new_vertex;
XrPenVertex *vi, *pi;
@ -159,11 +167,21 @@ XrPenAddPoints(XrPen *pen, XrPenTaggedPoint *pt, int num_pts)
/* merge new vertices into original */
pi = pen->vertex + pen->num_vertices - num_pts - 1;
vi = v + num_pts - 1;
for (i = pen->num_vertices - 1; i >= 0; i--) {
if (vi >= v && vi->theta > pi->theta)
for (i = pen->num_vertices - 1; vi >= v; i--) {
if (pi >= pen->vertex
&& vi->pt.x == pi->pt.x && vi->pt.y == pi->pt.y) {
/* Eliminate the duplicate vertex */
for (j=i; j < pen->num_vertices - 1; j++)
pen->vertex[j] = pen->vertex[j+1];
pen->vertex[--i] = *vi;
pen->num_vertices--;
pi--;
vi--;
} else if (pi < pen->vertex || vi->theta >= pi->theta) {
pen->vertex[i] = *vi--;
else
} else {
pen->vertex[i] = *pi--;
}
}
free(v);

View file

@ -338,6 +338,14 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
XrError err;
XrStroker *stroker = closure;
XrStrokeFace start, end;
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
here and in XrStrokerAddSubEdge and in _ComputeFace). The
key behavior is that degenerate paths should draw as much
as possible. */
return XrErrorSuccess;
}
err = XrStrokerAddSubEdge (stroker, p1, p2, &start, &end);
if (err)
@ -478,7 +486,7 @@ XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *
XrSpline spline;
XrPolygon polygon;
XrPen pen;
XrStrokeFace face1, face2;
XrStrokeFace start, end;
XrPenTaggedPoint extra_points[4];
XrSplineInit(&spline, a, b, c, d);
@ -492,30 +500,35 @@ XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *
if (err)
goto CLEANUP_POLYGON;
_ComputeInitialFace(a, b, gstate, &face1);
_ComputeFinalFace(c, d, gstate, &face2);
_ComputeInitialFace(a, b, gstate, &start);
_ComputeFinalFace(c, d, gstate, &end);
if (stroker->have_prev) {
err = _XrStrokerJoin(stroker, &stroker->prev, &face1);
err = _XrStrokerJoin (stroker, &stroker->prev, &start);
if (err)
return err;
} else {
stroker->have_prev = 1;
stroker->first = face1;
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = start;
}
}
stroker->prev = end;
stroker->is_first = 0;
extra_points[0].pt = face1.cw;
extra_points[0].pt.x -= face1.pt.x;
extra_points[0].pt.y -= face1.pt.y;
extra_points[1].pt = face1.ccw; extra_points[1].tag = XrPenVertexTagNone;
extra_points[1].pt.x -= face1.pt.x;
extra_points[1].pt.y -= face1.pt.y;
extra_points[2].pt = face2.cw; extra_points[2].tag = XrPenVertexTagNone;
extra_points[2].pt.x -= face2.pt.x;
extra_points[2].pt.y -= face2.pt.y;
extra_points[3].pt = face2.ccw; extra_points[3].tag = XrPenVertexTagReverse;
extra_points[3].pt.x -= face2.pt.x;
extra_points[3].pt.y -= face2.pt.y;
extra_points[0].pt = start.cw; extra_points[0].tag = XrPenVertexTagForward;
extra_points[0].pt.x -= start.pt.x;
extra_points[0].pt.y -= start.pt.y;
extra_points[1].pt = start.ccw; extra_points[1].tag = XrPenVertexTagNone;
extra_points[1].pt.x -= start.pt.x;
extra_points[1].pt.y -= start.pt.y;
extra_points[2].pt = end.cw; extra_points[2].tag = XrPenVertexTagNone;
extra_points[2].pt.x -= end.pt.x;
extra_points[2].pt.y -= end.pt.y;
extra_points[3].pt = end.ccw; extra_points[3].tag = XrPenVertexTagReverse;
extra_points[3].pt.x -= end.pt.x;
extra_points[3].pt.y -= end.pt.y;
err = XrPenAddPoints(&pen, extra_points, 4);
if (err)

View file

@ -114,6 +114,9 @@ XrGStateDeinit(XrGState *gstate)
XrTransformDeinit(&gstate->ctm_inverse);
XrPathDeinit(&gstate->path);
XrPenDeinit(&gstate->pen_regular);
if (gstate->dashes)
free (gstate->dashes);
}
@ -354,7 +357,7 @@ XrGStateStroke(XrGState *gstate)
XrStroker stroker;
XrTraps traps;
XrPenInit(&gstate->pen_regular, gstate->line_width / 2.0, gstate->tolerance);
XrPenInit(&gstate->pen_regular, gstate->line_width / 2.0, gstate);
XrTrapsInit(&traps);
XrStrokerInit(&stroker, gstate, &traps);

View file

@ -434,7 +434,7 @@ XrSurfaceSetFormat(XrSurface *surface, XrFormat format);
/* xrpen.c */
XrError
XrPenInit(XrPen *pen, double radius, double tolerance);
XrPenInit(XrPen *pen, double radius, XrGState *gstate);
XrError
XrPenInitEmpty(XrPen *pen);

36
xrpen.c
View file

@ -58,21 +58,26 @@ XrPenInitEmpty(XrPen *pen)
}
XrError
XrPenInit(XrPen *pen, double radius, double tolerance)
XrPenInit(XrPen *pen, double radius, XrGState *gstate)
{
int i;
XrPenVertex *v;
XPointDouble pt;
if (pen->num_vertices) {
/* XXX: It would be nice to notice that the pen is already properly constructed.
However, this test would also have to account for possible changes in the transformation
matrix.
if (pen->radius == radius && pen->tolerance == tolerance)
return XrErrorSuccess;
*/
XrPenDeinit(pen);
}
pen->radius = radius;
pen->tolerance = tolerance;
pen->tolerance = gstate->tolerance;
pen->num_vertices = _XrPenVerticesNeeded(radius, tolerance);
pen->num_vertices = _XrPenVerticesNeeded(radius, gstate->tolerance);
pen->vertex = malloc(pen->num_vertices * sizeof(XrPenVertex));
if (pen->vertex == NULL) {
@ -82,8 +87,11 @@ XrPenInit(XrPen *pen, double radius, double tolerance)
for (i=0; i < pen->num_vertices; i++) {
v = &pen->vertex[i];
v->theta = 2 * M_PI * i / (double) pen->num_vertices;
v->pt.x = XDoubleToFixed(radius * cos(v->theta));
v->pt.y = XDoubleToFixed(radius * sin(v->theta));
pt.x = radius * cos(v->theta);
pt.y = radius * sin(v->theta);
XrTransformPointWithoutTranslate(&gstate->ctm, &pt);
v->pt.x = XDoubleToFixed(pt.x);
v->pt.y = XDoubleToFixed(pt.y);
v->tag = XrPenVertexTagNone;
}
@ -126,7 +134,7 @@ _XrPenVertexCompareByTheta(const void *a, const void *b)
XrError
XrPenAddPoints(XrPen *pen, XrPenTaggedPoint *pt, int num_pts)
{
int i;
int i, j;
XrPenVertex *v, *new_vertex;
XrPenVertex *vi, *pi;
@ -159,11 +167,21 @@ XrPenAddPoints(XrPen *pen, XrPenTaggedPoint *pt, int num_pts)
/* merge new vertices into original */
pi = pen->vertex + pen->num_vertices - num_pts - 1;
vi = v + num_pts - 1;
for (i = pen->num_vertices - 1; i >= 0; i--) {
if (vi >= v && vi->theta > pi->theta)
for (i = pen->num_vertices - 1; vi >= v; i--) {
if (pi >= pen->vertex
&& vi->pt.x == pi->pt.x && vi->pt.y == pi->pt.y) {
/* Eliminate the duplicate vertex */
for (j=i; j < pen->num_vertices - 1; j++)
pen->vertex[j] = pen->vertex[j+1];
pen->vertex[--i] = *vi;
pen->num_vertices--;
pi--;
vi--;
} else if (pi < pen->vertex || vi->theta >= pi->theta) {
pen->vertex[i] = *vi--;
else
} else {
pen->vertex[i] = *pi--;
}
}
free(v);

View file

@ -338,6 +338,14 @@ XrStrokerAddEdge(void *closure, XPointFixed *p1, XPointFixed *p2)
XrError err;
XrStroker *stroker = closure;
XrStrokeFace start, end;
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
here and in XrStrokerAddSubEdge and in _ComputeFace). The
key behavior is that degenerate paths should draw as much
as possible. */
return XrErrorSuccess;
}
err = XrStrokerAddSubEdge (stroker, p1, p2, &start, &end);
if (err)
@ -478,7 +486,7 @@ XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *
XrSpline spline;
XrPolygon polygon;
XrPen pen;
XrStrokeFace face1, face2;
XrStrokeFace start, end;
XrPenTaggedPoint extra_points[4];
XrSplineInit(&spline, a, b, c, d);
@ -492,30 +500,35 @@ XrStrokerAddSpline (void *closure, XPointFixed *a, XPointFixed *b, XPointFixed *
if (err)
goto CLEANUP_POLYGON;
_ComputeInitialFace(a, b, gstate, &face1);
_ComputeFinalFace(c, d, gstate, &face2);
_ComputeInitialFace(a, b, gstate, &start);
_ComputeFinalFace(c, d, gstate, &end);
if (stroker->have_prev) {
err = _XrStrokerJoin(stroker, &stroker->prev, &face1);
err = _XrStrokerJoin (stroker, &stroker->prev, &start);
if (err)
return err;
} else {
stroker->have_prev = 1;
stroker->first = face1;
if (stroker->is_first) {
stroker->have_first = 1;
stroker->first = start;
}
}
stroker->prev = end;
stroker->is_first = 0;
extra_points[0].pt = face1.cw;
extra_points[0].pt.x -= face1.pt.x;
extra_points[0].pt.y -= face1.pt.y;
extra_points[1].pt = face1.ccw; extra_points[1].tag = XrPenVertexTagNone;
extra_points[1].pt.x -= face1.pt.x;
extra_points[1].pt.y -= face1.pt.y;
extra_points[2].pt = face2.cw; extra_points[2].tag = XrPenVertexTagNone;
extra_points[2].pt.x -= face2.pt.x;
extra_points[2].pt.y -= face2.pt.y;
extra_points[3].pt = face2.ccw; extra_points[3].tag = XrPenVertexTagReverse;
extra_points[3].pt.x -= face2.pt.x;
extra_points[3].pt.y -= face2.pt.y;
extra_points[0].pt = start.cw; extra_points[0].tag = XrPenVertexTagForward;
extra_points[0].pt.x -= start.pt.x;
extra_points[0].pt.y -= start.pt.y;
extra_points[1].pt = start.ccw; extra_points[1].tag = XrPenVertexTagNone;
extra_points[1].pt.x -= start.pt.x;
extra_points[1].pt.y -= start.pt.y;
extra_points[2].pt = end.cw; extra_points[2].tag = XrPenVertexTagNone;
extra_points[2].pt.x -= end.pt.x;
extra_points[2].pt.y -= end.pt.y;
extra_points[3].pt = end.ccw; extra_points[3].tag = XrPenVertexTagReverse;
extra_points[3].pt.x -= end.pt.x;
extra_points[3].pt.y -= end.pt.y;
err = XrPenAddPoints(&pen, extra_points, 4);
if (err)