#include <X11/Xos.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include "DviP.h"
#include <stdlib.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950
#endif
typedef struct Point {
double x;
double y;
struct Point *next;
} Point;
#define ITERATIONS 10
#define midx(p,q) ((p->x + q->x) / 2)
#define midy(p,q) ((p->y + q->y) / 2)
#define length(p,q) sqrt(((q->x - p->x)*(q->x - p->x)) \
+ ((q->y - p->y)*(q->y - p->y)))
Point *spline = (Point *)NULL;
static void ApproxSpline(int n);
static void DeletePoint(Point *p);
static void DrawSplineSegments(DviWidget dw);
static int GetSpline(char *s);
static void InsertPoint(Point *p, Point *q);
static void LineApprox(Point *p1, Point *p2, Point *p3);
static Point * MakePoint(double x, double y);
void
HorizontalMove(dw, delta)
DviWidget dw;
int delta;
{
dw->dvi.state->x += delta;
}
void
HorizontalGoto(dw, NewPosition)
DviWidget dw;
int NewPosition;
{
dw->dvi.state->x = NewPosition;
}
void
VerticalMove(dw, delta)
DviWidget dw;
int delta;
{
dw->dvi.state->y += delta;
}
void
VerticalGoto(dw, NewPosition)
DviWidget dw;
int NewPosition;
{
dw->dvi.state->y = NewPosition;
}
#ifdef USE_XFT
static void
DrawText (DviWidget dw)
{
int i;
XftFont *font;
font = dw->dvi.cache.font;
for (i = 0; i <= dw->dvi.cache.index; i++)
{
if (dw->dvi.cache.cache[i].font)
font = dw->dvi.cache.cache[i].font;
XftDrawString8 (dw->dvi.draw, &dw->dvi.black,
font,
dw->dvi.cache.cache[i].x,
dw->dvi.cache.start_y,
(unsigned char *) dw->dvi.cache.cache[i].chars,
dw->dvi.cache.cache[i].nchars);
}
}
#endif
void
FlushCharCache (dw)
DviWidget dw;
{
int xx, yx;
xx = ToX(dw, dw->dvi.state->x);
yx = ToX(dw, dw->dvi.state->y);
if (dw->dvi.cache.char_index != 0)
{
#ifdef USE_XFT
DrawText (dw);
#else
XDrawText (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
dw->dvi.cache.start_x, dw->dvi.cache.start_y,
dw->dvi.cache.cache, dw->dvi.cache.index + 1);
#endif
}
dw->dvi.cache.index = 0;
dw->dvi.cache.max = DVI_TEXT_CACHE_SIZE;
if (dw->dvi.noPolyText)
dw->dvi.cache.max = 1;
dw->dvi.cache.char_index = 0;
dw->dvi.cache.cache[0].nchars = 0;
dw->dvi.cache.start_x = dw->dvi.cache.x = xx;
dw->dvi.cache.start_y = dw->dvi.cache.y = yx;
}
#if 0
void
ClearPage (DviWidget dw)
{
if (dw->dvi.display_enable)
XClearWindow (XtDisplay (dw), XtWindow (dw));
}
#endif
void
SetGCForDraw (dw)
DviWidget dw;
{
int lw;
if (dw->dvi.state->line_style != dw->dvi.line_style ||
dw->dvi.state->line_width != dw->dvi.line_width)
{
lw = ToX(dw, dw->dvi.state->line_width);
if (lw <= 1)
lw = 0;
XSetLineAttributes (XtDisplay (dw), dw->dvi.normal_GC,
lw, LineSolid, CapButt, JoinMiter);
dw->dvi.line_style = dw->dvi.state->line_style;
dw->dvi.line_width = dw->dvi.state->line_width;
}
}
void
DrawLine (dw, x, y)
DviWidget dw;
int x, y;
{
if (dw->dvi.display_enable)
XDrawLine (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
ToX(dw, dw->dvi.state->x), ToX(dw, dw->dvi.state->y),
ToX(dw, dw->dvi.state->x + x), ToX(dw,dw->dvi.state->y + y));
dw->dvi.state->x += x;
dw->dvi.state->y += y;
}
void
DrawCircle (dw, diameter)
DviWidget dw;
int diameter;
{
if (dw->dvi.display_enable)
XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
ToX(dw, dw->dvi.state->x),
ToX(dw, dw->dvi.state->y - (diameter / 2)),
ToX(dw, diameter), ToX(dw, diameter), 0, 360 * 64);
dw->dvi.state->x += diameter;
}
void
DrawEllipse (dw, a, b)
DviWidget dw;
int a, b;
{
if (dw->dvi.display_enable)
XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
ToX(dw, dw->dvi.state->x), ToX(dw, dw->dvi.state->y - (b / 2)),
ToX(dw,a), ToX(dw,b), 0, 360 * 64);
dw->dvi.state->x += a;
}
static int
ConvertAngle(int theta)
{
return(theta * 64);
}
void
DrawArc (dw, x0, y0, x1, y1)
DviWidget dw;
int x0, y0, x1, y1;
{
int xc, yc, x2, y2, r;
int angle1, angle2;
xc = dw->dvi.state->x + x0;
yc = dw->dvi.state->y + y0;
x2 = xc + x1;
y2 = yc + y1;
dw->dvi.state->x = x2;
dw->dvi.state->y = y2;
if (dw->dvi.display_enable) {
r = (int)sqrt((float) x1 * x1 + (float) y1 * y1);
if (x0 == 0) {
if (y0 >= 0)
angle1 = 90;
else
angle1 = 270;
}
else {
angle1 = (int) (atan((double)(y0) / (double)(x0)) * 180 / M_PI);
if (x0 > 0)
angle1 = 180 - angle1;
else
angle1 = -angle1;
}
if (x1 == 0) {
if (y1 <= 0)
angle2 = 90;
else
angle2 = 270;
}
else {
angle2 = (int) (atan((double)(y1) / (double)(x1)) * 180 / M_PI);
if (x1 < 0)
angle2 = 180 - angle2;
else
angle2 = -angle2;
}
if (angle1 < 0)
angle1 += 360;
if (angle2 < 0)
angle2 += 360;
if (angle2 < angle1)
angle1 -= 360;
angle2 = angle2 - angle1;
angle1 = ConvertAngle(angle1);
angle2 = ConvertAngle(angle2);
XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
ToX(dw, xc - r), ToX(dw, yc - r),
ToX(dw, 2 * r), ToX(dw, 2 * r),
angle1, angle2);
}
}
static char *
getstr(char *p, char *temp)
{
while (*p == ' ' || *p == '\t' || *p == '\n')
p++;
if (*p == '\0') {
temp[0] = 0;
return((char *)NULL);
}
while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
*temp++ = *p++;
*temp = '\0';
return(p);
}
void
DrawSpline (dw, s, len)
DviWidget dw;
char *s;
int len;
{
int n;
if ((n = GetSpline(s)) <= 0)
return;
ApproxSpline(n);
DrawSplineSegments(dw);
}
static int
GetSpline(s)
char *s;
{
double x, y, x1, y1;
int n = 0;
Point *pt;
char *p = s, d[10];
if (!*p)
return(n);
pt = spline = MakePoint(0.0, 0.0);
n = 1;
x = y = 0.0;
p = s;
while (p && *p) {
if ((p = getstr(p, d)) == (char *)NULL)
break;
x1 = x + atof(d);
if ((p = getstr(p, d)) == (char *)NULL)
break;
y1 = y + atof(d);
pt->next = MakePoint(x1, y1);
pt = pt->next;
x = pt->x;
y = pt->y;
n++;
}
return(n);
}
static void
ApproxSpline(n)
int n;
{
int mid, j;
Point *p1, *p2, *p3, *p;
if (n < 3)
return;
mid = n - 3;
if (mid > 0) {
p = spline->next;
j = 1;
while (j < n-2) {
p1 = p;
p = p->next;
p2 = p;
InsertPoint(p1, MakePoint(midx(p1, p2), midy(p1, p2)));
j++;
}
}
p = spline;
while (p != (Point *)NULL) {
p1 = p;
if ((p = p->next) == (Point *)NULL)
break;
p2 = p;
if ((p = p->next) == (Point *)NULL)
break;
p3 = p;
LineApprox(p1, p2, p3);
}
}
static void
LineApprox(p1, p2, p3)
Point *p1, *p2, *p3;
{
Point *p4, *p;
int reps = ITERATIONS;
while (reps) {
for (p = p1; p != (Point *)NULL && p != p3; ) {
InsertPoint(p, p4 = MakePoint( midx(p,p->next), midy(p,p->next) ));
if (p != p1)
DeletePoint(p);
p = p4->next;
}
reps--;
}
}
static void
DrawSplineSegments(dw)
DviWidget dw;
{
Point *p, *q;
double x1, y1;
int dx, dy;
double xpos, ypos;
p = spline;
dx = dy = 0;
xpos = dw->dvi.state->x;
ypos = dw->dvi.state->y;
x1 = y1 = 0.0;
while (p != (Point *)NULL) {
dx = p->x - x1 + 0.5;
dy = p->y - y1 + 0.5;
DrawLine (dw, dx, dy);
x1 = p->x;
y1 = p->y;
dw->dvi.state->x = xpos + x1;
dw->dvi.state->y = ypos + y1;
q = p;
p = p->next;
XtFree((char *)q);
}
spline = (Point *)NULL;
}
static Point *
MakePoint(x, y)
double x, y;
{
Point *p;
p = (Point *) XtMalloc (sizeof (Point));
p->x = x;
p->y = y;
p->next = (Point *)NULL;
return(p);
}
static void
InsertPoint(p, q)
Point *p, *q;
{
q->next = p->next;
p->next = q;
}
static void
DeletePoint(p)
Point *p;
{
Point *tmp;
tmp = p->next;
p->x = p->next->x;
p->y = p->next->y;
p->next = p->next->next;
XtFree((char *)tmp);
}