mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-02 17:48:01 +02:00
Fixed spline error calculation. New effort to compute spline initial/final slopes even for degenerate splines, (degenerate splines are still broken somewhere though).
This commit is contained in:
parent
44ca388c90
commit
5f1938f26f
17 changed files with 348 additions and 116 deletions
|
|
@ -26,6 +26,7 @@ SRCS = xr.c \
|
|||
xrcolor.c \
|
||||
xrfiller.c \
|
||||
xrgstate.c \
|
||||
xrmisc.c \
|
||||
xrpath.c \
|
||||
xrpen.c \
|
||||
xrpolygon.c \
|
||||
|
|
@ -40,6 +41,7 @@ OBJS = xr.o \
|
|||
xrcolor.o \
|
||||
xrfiller.o \
|
||||
xrgstate.o \
|
||||
xrmisc.o \
|
||||
xrpath.o \
|
||||
xrpen.o \
|
||||
xrpolygon.o \
|
||||
|
|
|
|||
|
|
@ -95,12 +95,21 @@ XrGStateInitCopy(XrGState *gstate, XrGState *other)
|
|||
XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat);
|
||||
|
||||
err = XrPathInitCopy(&gstate->path, &other->path);
|
||||
if (err) {
|
||||
if (gstate->dashes) {
|
||||
free (gstate->dashes);
|
||||
gstate->dashes = 0;
|
||||
}
|
||||
}
|
||||
if (err)
|
||||
goto CLEANUP_DASHES;
|
||||
|
||||
err = XrPenInitCopy(&gstate->pen_regular, &other->pen_regular);
|
||||
if (err)
|
||||
goto CLEANUP_PATH;
|
||||
|
||||
return err;
|
||||
|
||||
CLEANUP_PATH:
|
||||
XrPathDeinit(&gstate->path);
|
||||
CLEANUP_DASHES:
|
||||
free (gstate->dashes);
|
||||
gstate->dashes = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -117,8 +126,10 @@ XrGStateDeinit(XrGState *gstate)
|
|||
|
||||
XrPenDeinit(&gstate->pen_regular);
|
||||
|
||||
if (gstate->dashes)
|
||||
if (gstate->dashes) {
|
||||
free (gstate->dashes);
|
||||
gstate->dashes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
24
src/xrint.h
24
src/xrint.h
|
|
@ -122,20 +122,23 @@ typedef struct _XrPolygon {
|
|||
int closed;
|
||||
} XrPolygon;
|
||||
|
||||
typedef struct _XrSpline {
|
||||
XPointFixed a, b, c, d;
|
||||
|
||||
int num_pts;
|
||||
int pts_size;
|
||||
XPointFixed *pts;
|
||||
} XrSpline;
|
||||
|
||||
typedef struct _XrSlopeFixed
|
||||
{
|
||||
XFixed dx;
|
||||
XFixed dy;
|
||||
} XrSlopeFixed;
|
||||
|
||||
typedef struct _XrSpline {
|
||||
XPointFixed a, b, c, d;
|
||||
|
||||
XrSlopeFixed initial_slope;
|
||||
XrSlopeFixed final_slope;
|
||||
|
||||
int num_pts;
|
||||
int pts_size;
|
||||
XPointFixed *pts;
|
||||
} XrSpline;
|
||||
|
||||
typedef enum _XrPenVertexTag {
|
||||
XrPenVertexTagNone,
|
||||
XrPenVertexTagForward,
|
||||
|
|
@ -580,5 +583,10 @@ XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4]);
|
|||
XrError
|
||||
XrTrapsTessellatePolygon (XrTraps *traps, XrPolygon *poly, int winding);
|
||||
|
||||
/* xrmisc.c */
|
||||
|
||||
void
|
||||
ComputeSlope(XPointFixed *a, XPointFixed *b, XrSlopeFixed *slope);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
34
src/xrmisc.c
Normal file
34
src/xrmisc.c
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* $XFree86: $
|
||||
*
|
||||
* Copyright © 2002 Carl D. Worth
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of Carl
|
||||
* D. Worth not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Carl D. Worth makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "xrint.h"
|
||||
|
||||
void
|
||||
ComputeSlope(XPointFixed *a, XPointFixed *b, XrSlopeFixed *slope)
|
||||
{
|
||||
slope->dx = b->x - a->x;
|
||||
slope->dy = b->y - a->y;
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +221,6 @@ _XrPathOpBufCreate(void)
|
|||
static void
|
||||
_XrPathOpBufDestroy(XrPathOpBuf *op)
|
||||
{
|
||||
op->num_ops = 0;
|
||||
free(op);
|
||||
}
|
||||
|
||||
|
|
@ -249,7 +248,6 @@ _XrPathArgBufCreate(void)
|
|||
static void
|
||||
_XrPathArgBufDestroy(XrPathArgBuf *arg)
|
||||
{
|
||||
arg->num_pts = 0;
|
||||
free(arg);
|
||||
}
|
||||
|
||||
|
|
|
|||
22
src/xrpen.c
22
src/xrpen.c
|
|
@ -31,9 +31,6 @@ _XrPenVerticesNeeded(double radius, double tolerance, XrTransform *matrix);
|
|||
static void
|
||||
_XrPenComputeSlopes(XrPen *pen);
|
||||
|
||||
static void
|
||||
_FindSlope(XPointFixed *a, XPointFixed *b, XrSlopeFixed *slope);
|
||||
|
||||
static int
|
||||
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b);
|
||||
|
||||
|
|
@ -231,18 +228,11 @@ _XrPenComputeSlopes(XrPen *pen)
|
|||
v = &pen->vertex[i];
|
||||
next = &pen->vertex[(i + 1) % pen->num_vertices];
|
||||
|
||||
_FindSlope(&prev->pt, &v->pt, &v->slope_cw);
|
||||
_FindSlope(&v->pt, &next->pt, &v->slope_ccw);
|
||||
ComputeSlope(&prev->pt, &v->pt, &v->slope_cw);
|
||||
ComputeSlope(&v->pt, &next->pt, &v->slope_ccw);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_FindSlope(XPointFixed *a, XPointFixed *b, XrSlopeFixed *slope)
|
||||
{
|
||||
slope->dx = b->x - a->x;
|
||||
slope->dy = b->y - a->y;
|
||||
}
|
||||
|
||||
static int
|
||||
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
|
||||
{
|
||||
|
|
@ -283,12 +273,14 @@ _XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenVertexTag dir, XrPolyg
|
|||
start = 0;
|
||||
stop = num_pts;
|
||||
step = 1;
|
||||
_FindSlope(&spline->c, &spline->d, &final_slope);
|
||||
final_slope = spline->final_slope;
|
||||
} else {
|
||||
start = num_pts - 1;
|
||||
stop = -1;
|
||||
step = -1;
|
||||
_FindSlope(&spline->b, &spline->a, &final_slope);
|
||||
final_slope = spline->initial_slope;
|
||||
final_slope.dx = -final_slope.dx;
|
||||
final_slope.dy = -final_slope.dy;
|
||||
}
|
||||
|
||||
i = start;
|
||||
|
|
@ -302,7 +294,7 @@ _XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenVertexTag dir, XrPolyg
|
|||
if (i + step == stop)
|
||||
slope = final_slope;
|
||||
else
|
||||
_FindSlope(&pt[i], &pt[i+step], &slope);
|
||||
ComputeSlope(&pt[i], &pt[i+step], &slope);
|
||||
if (_SlopeCounterClockwise(&slope, &pen->vertex[active].slope_ccw)) {
|
||||
if (++active == pen->num_vertices)
|
||||
active = 0;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ XrPolygonDeinit(XrPolygon *polygon)
|
|||
{
|
||||
if (polygon->edges_size) {
|
||||
free(polygon->edges);
|
||||
polygon->edges = NULL;
|
||||
polygon->edges_size = 0;
|
||||
polygon->num_edges = 0;
|
||||
}
|
||||
|
|
|
|||
122
src/xrspline.c
122
src/xrspline.c
|
|
@ -38,7 +38,7 @@ static void
|
|||
_DeCastlejau(XrSpline *spline, XrSpline *s1, XrSpline *s2);
|
||||
|
||||
static double
|
||||
_XrSplineErrorSquared(XrSpline *spline, XPointFixed *p);
|
||||
_XrSplineErrorSquared(XrSpline *spline);
|
||||
|
||||
static XrError
|
||||
_XrSplineDecomposeInto(XrSpline *spline, double tolerance_squared, XrSpline *result);
|
||||
|
|
@ -53,6 +53,30 @@ XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c,
|
|||
spline->c = *c;
|
||||
spline->d = *d;
|
||||
|
||||
if (a->x != b->x || a->y != b->y) {
|
||||
ComputeSlope(&spline->a, &spline->b, &spline->initial_slope);
|
||||
} else if (a->x != c->x || a->y != c->y) {
|
||||
ComputeSlope(&spline->a, &spline->c, &spline->initial_slope);
|
||||
} else if (a->x != d->x || a->y != d->y) {
|
||||
ComputeSlope(&spline->a, &spline->d, &spline->initial_slope);
|
||||
} else {
|
||||
/* XXX: Completely degenerate spline (single point). I'm still
|
||||
not sure what the fallout from this is. */
|
||||
spline->initial_slope.dx = 0;
|
||||
spline->initial_slope.dy = 0;
|
||||
}
|
||||
|
||||
if (c->x != d->x || c->y != d->y) {
|
||||
ComputeSlope(&spline->c, &spline->d, &spline->final_slope);
|
||||
} else if (b->x != d->x || b->y != d->y) {
|
||||
ComputeSlope(&spline->b, &spline->b, &spline->final_slope);
|
||||
} else if (a->x != d->x || a->y != d->y) {
|
||||
ComputeSlope(&spline->a, &spline->d, &spline->final_slope);
|
||||
} else {
|
||||
spline->final_slope.dx = 0;
|
||||
spline->final_slope.dy = 0;
|
||||
}
|
||||
|
||||
spline->num_pts = 0;
|
||||
spline->pts_size = 0;
|
||||
spline->pts = NULL;
|
||||
|
|
@ -64,6 +88,7 @@ XrSplineDeinit(XrSpline *spline)
|
|||
spline->num_pts = 0;
|
||||
spline->pts_size = 0;
|
||||
free(spline->pts);
|
||||
spline->pts = NULL;
|
||||
}
|
||||
|
||||
static XrError
|
||||
|
|
@ -139,44 +164,89 @@ _DeCastlejau(XrSpline *spline, XrSpline *s1, XrSpline *s2)
|
|||
}
|
||||
|
||||
static double
|
||||
_XrSplineErrorSquared(XrSpline *spline, XPointFixed *p)
|
||||
_PointDistanceSquaredToPoint(XPointFixed *a, XPointFixed *b)
|
||||
{
|
||||
XPointFixed mid;
|
||||
double dx, dy;
|
||||
|
||||
_LerpHalf(&spline->a, &spline->d, &mid);
|
||||
|
||||
dx = XFixedToDouble(mid.x - p->x);
|
||||
dy = XFixedToDouble(mid.y - p->y);
|
||||
double dx = XFixedToDouble(b->x - a->x);
|
||||
double dy = XFixedToDouble(b->y - a->y);
|
||||
|
||||
return dx*dx + dy*dy;
|
||||
}
|
||||
|
||||
static double
|
||||
_PointDistanceSquaredToSegment(XPointFixed *p, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
double u;
|
||||
double dx, dy;
|
||||
double pdx, pdy;
|
||||
XPointFixed px;
|
||||
|
||||
/* intersection point (px):
|
||||
|
||||
px = p1 + u(p2 - p1)
|
||||
(p - px) . (p2 - p1) = 0
|
||||
|
||||
Thus:
|
||||
|
||||
u = ((p - p1) . (p2 - p1)) / (||(p2 - p1)|| ^ 2);
|
||||
*/
|
||||
|
||||
dx = XFixedToDouble(p2->x - p1->x);
|
||||
dy = XFixedToDouble(p2->y - p1->y);
|
||||
|
||||
if (dx == 0 && dy == 0)
|
||||
return _PointDistanceSquaredToPoint(p, p1);
|
||||
|
||||
pdx = XFixedToDouble(p->x - p1->x);
|
||||
pdy = XFixedToDouble(p->y - p1->y);
|
||||
|
||||
u = (pdx * dx + pdy * dy) / (dx*dx + dy*dy);
|
||||
|
||||
if (u <= 0)
|
||||
return _PointDistanceSquaredToPoint(p, p1);
|
||||
else if (u >= 1)
|
||||
return _PointDistanceSquaredToPoint(p, p2);
|
||||
|
||||
px.x = p1->x + u * (p2->x - p1->x);
|
||||
px.y = p1->y + u * (p2->y - p1->y);
|
||||
|
||||
return _PointDistanceSquaredToPoint(p, &px);
|
||||
}
|
||||
|
||||
/* Return an upper bound on the error (squared) that could result from approximating
|
||||
a spline as a line segment connecting the two endpoints */
|
||||
static double
|
||||
_XrSplineErrorSquared(XrSpline *spline)
|
||||
{
|
||||
double berr, cerr;
|
||||
|
||||
berr = _PointDistanceSquaredToSegment(&spline->b, &spline->a, &spline->d);
|
||||
cerr = _PointDistanceSquaredToSegment(&spline->c, &spline->a, &spline->d);
|
||||
|
||||
if (berr > cerr)
|
||||
return berr;
|
||||
else
|
||||
return cerr;
|
||||
}
|
||||
|
||||
static XrError
|
||||
_XrSplineDecomposeInto(XrSpline *spline, double tolerance_squared, XrSpline *result)
|
||||
{
|
||||
XrError err;
|
||||
XrSpline s1, s2;
|
||||
|
||||
if (_XrSplineErrorSquared(spline) < tolerance_squared) {
|
||||
return _XrSplineAddPoint(result, &spline->a);
|
||||
}
|
||||
|
||||
_DeCastlejau(spline, &s1, &s2);
|
||||
|
||||
if (_XrSplineErrorSquared(spline, &s1.d) < tolerance_squared) {
|
||||
err = _XrSplineAddPoint(result, &s1.a);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = _XrSplineAddPoint(result, &s1.d);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
err = _XrSplineDecomposeInto(&s1, tolerance_squared, result);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = _XrSplineDecomposeInto(&s2, tolerance_squared, result);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
err = _XrSplineDecomposeInto(&s1, tolerance_squared, result);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = _XrSplineDecomposeInto(&s2, tolerance_squared, result);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return XrErrorSuccess;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ XrTrapsDeinit(XrTraps *traps)
|
|||
{
|
||||
if (traps->xtraps_size) {
|
||||
free(traps->xtraps);
|
||||
traps->xtraps = NULL;
|
||||
traps->xtraps_size = 0;
|
||||
traps->num_xtraps = 0;
|
||||
}
|
||||
|
|
|
|||
25
xrgstate.c
25
xrgstate.c
|
|
@ -95,12 +95,21 @@ XrGStateInitCopy(XrGState *gstate, XrGState *other)
|
|||
XrSurfaceSetSolidColor(&gstate->src, &gstate->color, gstate->solidFormat);
|
||||
|
||||
err = XrPathInitCopy(&gstate->path, &other->path);
|
||||
if (err) {
|
||||
if (gstate->dashes) {
|
||||
free (gstate->dashes);
|
||||
gstate->dashes = 0;
|
||||
}
|
||||
}
|
||||
if (err)
|
||||
goto CLEANUP_DASHES;
|
||||
|
||||
err = XrPenInitCopy(&gstate->pen_regular, &other->pen_regular);
|
||||
if (err)
|
||||
goto CLEANUP_PATH;
|
||||
|
||||
return err;
|
||||
|
||||
CLEANUP_PATH:
|
||||
XrPathDeinit(&gstate->path);
|
||||
CLEANUP_DASHES:
|
||||
free (gstate->dashes);
|
||||
gstate->dashes = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -117,8 +126,10 @@ XrGStateDeinit(XrGState *gstate)
|
|||
|
||||
XrPenDeinit(&gstate->pen_regular);
|
||||
|
||||
if (gstate->dashes)
|
||||
if (gstate->dashes) {
|
||||
free (gstate->dashes);
|
||||
gstate->dashes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
24
xrint.h
24
xrint.h
|
|
@ -122,20 +122,23 @@ typedef struct _XrPolygon {
|
|||
int closed;
|
||||
} XrPolygon;
|
||||
|
||||
typedef struct _XrSpline {
|
||||
XPointFixed a, b, c, d;
|
||||
|
||||
int num_pts;
|
||||
int pts_size;
|
||||
XPointFixed *pts;
|
||||
} XrSpline;
|
||||
|
||||
typedef struct _XrSlopeFixed
|
||||
{
|
||||
XFixed dx;
|
||||
XFixed dy;
|
||||
} XrSlopeFixed;
|
||||
|
||||
typedef struct _XrSpline {
|
||||
XPointFixed a, b, c, d;
|
||||
|
||||
XrSlopeFixed initial_slope;
|
||||
XrSlopeFixed final_slope;
|
||||
|
||||
int num_pts;
|
||||
int pts_size;
|
||||
XPointFixed *pts;
|
||||
} XrSpline;
|
||||
|
||||
typedef enum _XrPenVertexTag {
|
||||
XrPenVertexTagNone,
|
||||
XrPenVertexTagForward,
|
||||
|
|
@ -580,5 +583,10 @@ XrTrapsTessellateRectangle (XrTraps *traps, XPointFixed q[4]);
|
|||
XrError
|
||||
XrTrapsTessellatePolygon (XrTraps *traps, XrPolygon *poly, int winding);
|
||||
|
||||
/* xrmisc.c */
|
||||
|
||||
void
|
||||
ComputeSlope(XPointFixed *a, XPointFixed *b, XrSlopeFixed *slope);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
34
xrmisc.c
Normal file
34
xrmisc.c
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* $XFree86: $
|
||||
*
|
||||
* Copyright © 2002 Carl D. Worth
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of Carl
|
||||
* D. Worth not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Carl D. Worth makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* CARL D. WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL CARL D. WORTH BE LIABLE FOR ANY SPECIAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "xrint.h"
|
||||
|
||||
void
|
||||
ComputeSlope(XPointFixed *a, XPointFixed *b, XrSlopeFixed *slope)
|
||||
{
|
||||
slope->dx = b->x - a->x;
|
||||
slope->dy = b->y - a->y;
|
||||
}
|
||||
|
||||
2
xrpath.c
2
xrpath.c
|
|
@ -221,7 +221,6 @@ _XrPathOpBufCreate(void)
|
|||
static void
|
||||
_XrPathOpBufDestroy(XrPathOpBuf *op)
|
||||
{
|
||||
op->num_ops = 0;
|
||||
free(op);
|
||||
}
|
||||
|
||||
|
|
@ -249,7 +248,6 @@ _XrPathArgBufCreate(void)
|
|||
static void
|
||||
_XrPathArgBufDestroy(XrPathArgBuf *arg)
|
||||
{
|
||||
arg->num_pts = 0;
|
||||
free(arg);
|
||||
}
|
||||
|
||||
|
|
|
|||
22
xrpen.c
22
xrpen.c
|
|
@ -31,9 +31,6 @@ _XrPenVerticesNeeded(double radius, double tolerance, XrTransform *matrix);
|
|||
static void
|
||||
_XrPenComputeSlopes(XrPen *pen);
|
||||
|
||||
static void
|
||||
_FindSlope(XPointFixed *a, XPointFixed *b, XrSlopeFixed *slope);
|
||||
|
||||
static int
|
||||
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b);
|
||||
|
||||
|
|
@ -231,18 +228,11 @@ _XrPenComputeSlopes(XrPen *pen)
|
|||
v = &pen->vertex[i];
|
||||
next = &pen->vertex[(i + 1) % pen->num_vertices];
|
||||
|
||||
_FindSlope(&prev->pt, &v->pt, &v->slope_cw);
|
||||
_FindSlope(&v->pt, &next->pt, &v->slope_ccw);
|
||||
ComputeSlope(&prev->pt, &v->pt, &v->slope_cw);
|
||||
ComputeSlope(&v->pt, &next->pt, &v->slope_ccw);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_FindSlope(XPointFixed *a, XPointFixed *b, XrSlopeFixed *slope)
|
||||
{
|
||||
slope->dx = b->x - a->x;
|
||||
slope->dy = b->y - a->y;
|
||||
}
|
||||
|
||||
static int
|
||||
_SlopeClockwise(XrSlopeFixed *a, XrSlopeFixed *b)
|
||||
{
|
||||
|
|
@ -283,12 +273,14 @@ _XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenVertexTag dir, XrPolyg
|
|||
start = 0;
|
||||
stop = num_pts;
|
||||
step = 1;
|
||||
_FindSlope(&spline->c, &spline->d, &final_slope);
|
||||
final_slope = spline->final_slope;
|
||||
} else {
|
||||
start = num_pts - 1;
|
||||
stop = -1;
|
||||
step = -1;
|
||||
_FindSlope(&spline->b, &spline->a, &final_slope);
|
||||
final_slope = spline->initial_slope;
|
||||
final_slope.dx = -final_slope.dx;
|
||||
final_slope.dy = -final_slope.dy;
|
||||
}
|
||||
|
||||
i = start;
|
||||
|
|
@ -302,7 +294,7 @@ _XrPenStrokeSplineHalf(XrPen *pen, XrSpline *spline, XrPenVertexTag dir, XrPolyg
|
|||
if (i + step == stop)
|
||||
slope = final_slope;
|
||||
else
|
||||
_FindSlope(&pt[i], &pt[i+step], &slope);
|
||||
ComputeSlope(&pt[i], &pt[i+step], &slope);
|
||||
if (_SlopeCounterClockwise(&slope, &pen->vertex[active].slope_ccw)) {
|
||||
if (++active == pen->num_vertices)
|
||||
active = 0;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ XrPolygonDeinit(XrPolygon *polygon)
|
|||
{
|
||||
if (polygon->edges_size) {
|
||||
free(polygon->edges);
|
||||
polygon->edges = NULL;
|
||||
polygon->edges_size = 0;
|
||||
polygon->num_edges = 0;
|
||||
}
|
||||
|
|
|
|||
122
xrspline.c
122
xrspline.c
|
|
@ -38,7 +38,7 @@ static void
|
|||
_DeCastlejau(XrSpline *spline, XrSpline *s1, XrSpline *s2);
|
||||
|
||||
static double
|
||||
_XrSplineErrorSquared(XrSpline *spline, XPointFixed *p);
|
||||
_XrSplineErrorSquared(XrSpline *spline);
|
||||
|
||||
static XrError
|
||||
_XrSplineDecomposeInto(XrSpline *spline, double tolerance_squared, XrSpline *result);
|
||||
|
|
@ -53,6 +53,30 @@ XrSplineInit(XrSpline *spline, XPointFixed *a, XPointFixed *b, XPointFixed *c,
|
|||
spline->c = *c;
|
||||
spline->d = *d;
|
||||
|
||||
if (a->x != b->x || a->y != b->y) {
|
||||
ComputeSlope(&spline->a, &spline->b, &spline->initial_slope);
|
||||
} else if (a->x != c->x || a->y != c->y) {
|
||||
ComputeSlope(&spline->a, &spline->c, &spline->initial_slope);
|
||||
} else if (a->x != d->x || a->y != d->y) {
|
||||
ComputeSlope(&spline->a, &spline->d, &spline->initial_slope);
|
||||
} else {
|
||||
/* XXX: Completely degenerate spline (single point). I'm still
|
||||
not sure what the fallout from this is. */
|
||||
spline->initial_slope.dx = 0;
|
||||
spline->initial_slope.dy = 0;
|
||||
}
|
||||
|
||||
if (c->x != d->x || c->y != d->y) {
|
||||
ComputeSlope(&spline->c, &spline->d, &spline->final_slope);
|
||||
} else if (b->x != d->x || b->y != d->y) {
|
||||
ComputeSlope(&spline->b, &spline->b, &spline->final_slope);
|
||||
} else if (a->x != d->x || a->y != d->y) {
|
||||
ComputeSlope(&spline->a, &spline->d, &spline->final_slope);
|
||||
} else {
|
||||
spline->final_slope.dx = 0;
|
||||
spline->final_slope.dy = 0;
|
||||
}
|
||||
|
||||
spline->num_pts = 0;
|
||||
spline->pts_size = 0;
|
||||
spline->pts = NULL;
|
||||
|
|
@ -64,6 +88,7 @@ XrSplineDeinit(XrSpline *spline)
|
|||
spline->num_pts = 0;
|
||||
spline->pts_size = 0;
|
||||
free(spline->pts);
|
||||
spline->pts = NULL;
|
||||
}
|
||||
|
||||
static XrError
|
||||
|
|
@ -139,44 +164,89 @@ _DeCastlejau(XrSpline *spline, XrSpline *s1, XrSpline *s2)
|
|||
}
|
||||
|
||||
static double
|
||||
_XrSplineErrorSquared(XrSpline *spline, XPointFixed *p)
|
||||
_PointDistanceSquaredToPoint(XPointFixed *a, XPointFixed *b)
|
||||
{
|
||||
XPointFixed mid;
|
||||
double dx, dy;
|
||||
|
||||
_LerpHalf(&spline->a, &spline->d, &mid);
|
||||
|
||||
dx = XFixedToDouble(mid.x - p->x);
|
||||
dy = XFixedToDouble(mid.y - p->y);
|
||||
double dx = XFixedToDouble(b->x - a->x);
|
||||
double dy = XFixedToDouble(b->y - a->y);
|
||||
|
||||
return dx*dx + dy*dy;
|
||||
}
|
||||
|
||||
static double
|
||||
_PointDistanceSquaredToSegment(XPointFixed *p, XPointFixed *p1, XPointFixed *p2)
|
||||
{
|
||||
double u;
|
||||
double dx, dy;
|
||||
double pdx, pdy;
|
||||
XPointFixed px;
|
||||
|
||||
/* intersection point (px):
|
||||
|
||||
px = p1 + u(p2 - p1)
|
||||
(p - px) . (p2 - p1) = 0
|
||||
|
||||
Thus:
|
||||
|
||||
u = ((p - p1) . (p2 - p1)) / (||(p2 - p1)|| ^ 2);
|
||||
*/
|
||||
|
||||
dx = XFixedToDouble(p2->x - p1->x);
|
||||
dy = XFixedToDouble(p2->y - p1->y);
|
||||
|
||||
if (dx == 0 && dy == 0)
|
||||
return _PointDistanceSquaredToPoint(p, p1);
|
||||
|
||||
pdx = XFixedToDouble(p->x - p1->x);
|
||||
pdy = XFixedToDouble(p->y - p1->y);
|
||||
|
||||
u = (pdx * dx + pdy * dy) / (dx*dx + dy*dy);
|
||||
|
||||
if (u <= 0)
|
||||
return _PointDistanceSquaredToPoint(p, p1);
|
||||
else if (u >= 1)
|
||||
return _PointDistanceSquaredToPoint(p, p2);
|
||||
|
||||
px.x = p1->x + u * (p2->x - p1->x);
|
||||
px.y = p1->y + u * (p2->y - p1->y);
|
||||
|
||||
return _PointDistanceSquaredToPoint(p, &px);
|
||||
}
|
||||
|
||||
/* Return an upper bound on the error (squared) that could result from approximating
|
||||
a spline as a line segment connecting the two endpoints */
|
||||
static double
|
||||
_XrSplineErrorSquared(XrSpline *spline)
|
||||
{
|
||||
double berr, cerr;
|
||||
|
||||
berr = _PointDistanceSquaredToSegment(&spline->b, &spline->a, &spline->d);
|
||||
cerr = _PointDistanceSquaredToSegment(&spline->c, &spline->a, &spline->d);
|
||||
|
||||
if (berr > cerr)
|
||||
return berr;
|
||||
else
|
||||
return cerr;
|
||||
}
|
||||
|
||||
static XrError
|
||||
_XrSplineDecomposeInto(XrSpline *spline, double tolerance_squared, XrSpline *result)
|
||||
{
|
||||
XrError err;
|
||||
XrSpline s1, s2;
|
||||
|
||||
if (_XrSplineErrorSquared(spline) < tolerance_squared) {
|
||||
return _XrSplineAddPoint(result, &spline->a);
|
||||
}
|
||||
|
||||
_DeCastlejau(spline, &s1, &s2);
|
||||
|
||||
if (_XrSplineErrorSquared(spline, &s1.d) < tolerance_squared) {
|
||||
err = _XrSplineAddPoint(result, &s1.a);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = _XrSplineAddPoint(result, &s1.d);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
err = _XrSplineDecomposeInto(&s1, tolerance_squared, result);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = _XrSplineDecomposeInto(&s2, tolerance_squared, result);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
err = _XrSplineDecomposeInto(&s1, tolerance_squared, result);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = _XrSplineDecomposeInto(&s2, tolerance_squared, result);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return XrErrorSuccess;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ XrTrapsDeinit(XrTraps *traps)
|
|||
{
|
||||
if (traps->xtraps_size) {
|
||||
free(traps->xtraps);
|
||||
traps->xtraps = NULL;
|
||||
traps->xtraps_size = 0;
|
||||
traps->num_xtraps = 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue