diff options
Diffstat (limited to 'src/drv/cddxf.c')
-rw-r--r-- | src/drv/cddxf.c | 1184 |
1 files changed, 1184 insertions, 0 deletions
diff --git a/src/drv/cddxf.c b/src/drv/cddxf.c new file mode 100644 index 0000000..b5c8854 --- /dev/null +++ b/src/drv/cddxf.c @@ -0,0 +1,1184 @@ +/** \file + * \brief DXF driver + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <limits.h> +#include "cd.h" +#include "cd_private.h" +#include "cddxf.h" + + +#ifndef ignore +#define ignore(x) (void)x +#endif + +#ifndef max +#define max(x, y) ((x > y)? x : y) +#endif + +#ifndef min +#define min(x, y) ((x < y)? x : y) +#endif + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + FILE *file; /* pointer to file */ + int layer; /* layer */ + + int tf; /* text font */ + double th; /* text height (in points) */ + int toa; /* text oblique angle (for italics) */ + int tha, tva; /* text horizontal and vertical alignment */ + + int fgcolor; /* foreground AutoCAD palette color */ + + int lt; /* line type */ + double lw; /* line width (in milimeters) */ +}; + + +static void wnamline (cdCtxCanvas* ctxcanvas, int t) /* write name of a line */ +{ + + static char *line[] = + {"CONTINUOUS", + "DASHED", + "HIDDEN", + "CENTER", + "PHANTOM", + "DOT", + "DASHDOT", + "BORDER", + "DIVIDE"}; + +/* + AutoCAD line styles ( see acad.lin ): + + 0 CONTINUOUS ____________________________________________ + 1 DASHED __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ + 2 HIDDEN _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 3 CENTER ____ _ ____ _ ____ _ ____ _ ____ _ ____ _ __ + 4 PHANTOM _____ _ _ _____ _ _ _____ _ _ _____ _ _ ____ + 5 DOT ............................................ + 6 DASHDOT __ . __ . __ . __ . __ . __ . __ . __ . __ . + 7 BORDER __ __ . __ __ . __ __ . __ __ . __ __ . __ _ + 8 DIVIDE __ . . __ . . __ . . __ . . __ . . __ . . __ + +*/ + + fprintf (ctxcanvas->file, "%s\n", line[t]); +} + + +static void wnamfont (cdCtxCanvas *ctxcanvas, int t) /* write name of a font */ +{ + static char *font[] = + { + "STANDARD", + "ROMAN", + "ROMAN_BOLD", + "ROMANTIC", + "ROMANTIC_BOLD", + "SANSSERIF", + "SANSSERIF_BOLD", + }; +/* + CD Fonts / Style AutoCAD Fonts + ------------------------------------------------------------------- + CD_SYSTEM 0 STANDARD + CD_COURIER / CD_PLAIN 1 ROMAN + CD_COURIER / CD_BOLD 2 ROMAN_BOLD + CD_COURIER / CD_ITALIC 1 ROMAN (ctxcanvas->toa = 15) + CD_COURIER / CD_BOLD_ITALIC 2 ROMAN_BOLD (ctxcanvas->toa = 15) + CD_TIMES_ROMAN / CD_PLAIN 3 ROMANTIC + CD_TIMES_ROMAN / CD_BOLD 4 ROMANTIC_BOLD + CD_TIMES_ROMAN / CD_ITALIC 3 ROMANTIC (ctxcanvas->toa = 15) + CD_TIMES_ROMAN / CD_BOLD_ITALIC 4 ROMANTIC_BOLD (ctxcanvas->toa = 15) + CD_HELVETICA / CD_PLAIN 5 SANSSERIF + CD_HELVETICA / CD_BOLD 6 SANSSERIF_BOLD + CD_HELVETICA / CD_ITALIC 5 SANSSERIF (ctxcanvas->toa = 15) + CD_HELVETICA / CD_BOLD_ITALIC 6 SANSSERIF_BOLD(ctxcanvas->toa = 15) +*/ + + fprintf (ctxcanvas->file, "%s\n", font[t]); +} + + +static void writepoly (cdCtxCanvas *ctxcanvas, cdPoint *poly, int nv) /* write polygon */ +{ + int i; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire polygon line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + for ( i=0; i<nv; i++ ) + { + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "VERTEX\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].x/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "20\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].y/ctxcanvas->canvas->xres ); + } + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void writepolyf (cdCtxCanvas *ctxcanvas, cdfPoint *poly, int nv) /* write polygon */ +{ + int i; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire polygon line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + for ( i=0; i<nv; i++ ) + { + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "VERTEX\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].x/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "20\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].y/ctxcanvas->canvas->xres ); + } + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void deflines (cdCtxCanvas *ctxcanvas) /* define lines */ +{ + int i, j; + static char *line[] = + {"Solid line", + "Dashed line", + "Hidden line", + "Center line", + "Phantom line", + "Dot line", + "Dashdot line", + "Border line", + "Divide Line"}; + +#define TABSIZE (sizeof(tab)/sizeof(tab[0])) + + static int tab[][8] = + { + { 0, 0, 0 , 0, 0, 0, 0, 0 }, + { 2, 15, 10, -5, 0, 0, 0, 0 }, + { 2, 10, 5 , -5, 0, 0, 0, 0 }, + { 4, 35, 20, -5, 5, -5, 0, 0 }, + { 6, 50, 25, -5, 5, -5, 5, -5 }, + { 2, 5, 0 , -5, 0, 0, 0, 0 }, + { 4, 20, 10, -5, 0, -5, 0, 0 }, + { 6, 35, 10, -5, 10, -5, 0, -5 }, + { 6, 25, 10, -5, 0, -5, 0, -5 } + }; + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "TABLE\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "LTYPE\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "5\n"); + for (j = 0; j < TABSIZE; j++) + { + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "LTYPE\n"); + fprintf (ctxcanvas->file, "2\n"); + + wnamline (ctxcanvas, j); /* line style */ + + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "64\n"); + fprintf (ctxcanvas->file, "3\n"); + fprintf (ctxcanvas->file, "%s\n", line[j]); /* line style */ + fprintf (ctxcanvas->file, "72\n"); + fprintf (ctxcanvas->file, "65\n"); + fprintf (ctxcanvas->file, "73\n"); + fprintf (ctxcanvas->file, "%d\n", tab[j][0]); /* number of parameters */ + fprintf (ctxcanvas->file, "40\n"); + fprintf (ctxcanvas->file, "%d\n", tab[j][1]); + for (i = 2; i < 2 + tab[j][0]; i++) + { + fprintf (ctxcanvas->file, "49\n"); + fprintf (ctxcanvas->file, "%d\n", tab[j][i]); /* parameters */ + } + } + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDTAB\n"); +} + + +static void deffonts (cdCtxCanvas *ctxcanvas) /* define fonts */ +{ + int i; + static char *font[] = + { + "romanc.shx" , + "romant.shx" , + "rom_____.pfb", + "romb____.pfb", + "sas_____.pfb", + "sasb____.pfb" + }; + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "TABLE\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "STYLE\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "5\n"); + for (i = 1; i < 7; i++) + { + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "STYLE\n"); + fprintf (ctxcanvas->file, "2\n"); + + wnamfont (ctxcanvas, i); /* font style name */ + + fprintf (ctxcanvas->file, "3\n"); + fprintf (ctxcanvas->file, "%s\n", font[i-1]); /* font style file */ + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "64\n"); + fprintf (ctxcanvas->file, "71\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "40\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "41\n"); + fprintf (ctxcanvas->file, "1\n"); + fprintf (ctxcanvas->file, "42\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "50\n"); + fprintf (ctxcanvas->file, "0\n"); + } + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDTAB\n"); +} + +static void cddeactivate (cdCtxCanvas *ctxcanvas) +{ + fflush (ctxcanvas->file); /* flush file */ +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDSEC\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "EOF\n"); /* fputs eof */ + fprintf (ctxcanvas->file, " \n"); + + fflush (ctxcanvas->file); /* flush file */ + fclose (ctxcanvas->file); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free (ctxcanvas); +} + +static void cdflush (cdCtxCanvas *ctxcanvas) +{ + ctxcanvas->layer++; +} + +/*==========================================================================*/ +/* Primitives */ +/*==========================================================================*/ +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + if (mode == CD_CLOSED_LINES || mode == CD_FILL) + { + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + } + + writepoly (ctxcanvas, poly, n); /* write polygon */ +} + +static void cdline (cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + cdPoint line[2]; /* uses new array of points to avoid */ + + line[0].x = x1; /* starting point */ + line[0].y = y1; + line[1].x = x2; /* ending point */ + line[1].y = y2; + writepoly (ctxcanvas, line, 2); /* draw line as a polygon */ +} + +static void cdboxrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdPoint rect[5]; /* uses new array of points to avoid */ + + rect[0].x = xmin; + rect[0].y = ymin; + rect[1].x = xmin; + rect[1].y = ymax; + rect[2].x = xmax; /* box edges */ + rect[2].y = ymax; + rect[3].x = xmax; + rect[3].y = ymin; + rect[4].x = xmin; + rect[4].y = ymin; + writepoly (ctxcanvas, rect, 5); /* draw box as a polygon */ +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + if (mode == CD_CLOSED_LINES || mode == CD_FILL) + { + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + } + + writepolyf (ctxcanvas, poly, n); /* write polygon */ +} + +static void cdfline (cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + cdfPoint line[2]; /* uses new array of points to avoid */ + + line[0].x = x1; /* starting point */ + line[0].y = y1; + line[1].x = x2; /* ending point */ + line[1].y = y2; + writepolyf (ctxcanvas, line, 2); /* draw line as a polygon */ +} + +static void cdfboxrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + cdfPoint rect[5]; /* uses new array of points to avoid */ + + rect[0].x = xmin; + rect[0].y = ymin; + rect[1].x = xmin; + rect[1].y = ymax; + rect[2].x = xmax; /* box edges */ + rect[2].y = ymax; + rect[3].x = xmax; + rect[3].y = ymin; + rect[4].x = xmin; + rect[4].y = ymin; + writepolyf (ctxcanvas, rect, 5); /* draw box as a polygon */ +} + +/*--------------------------------------------------------------------------*/ +/* gives radius of the circle most resembling elliptic arc at angle t */ +/*--------------------------------------------------------------------------*/ +static double calc_radius (double a, double b, double t) +{ + return (pow ((a*a*sin(t)*sin(t) + b*b*cos(t)*cos(t)), 1.5))/(a*b); +} + +/*--------------------------------------------------------------------------*/ +/* calculates bulge for a given circular arc segment (between points p1 and */ +/* p2, with radius r). Bulge is the tangent of 1/4 the angle theta of the */ +/* arc segment(a bulge of 1 is a semicircle, which has an angle of 180 deg) */ +/*--------------------------------------------------------------------------*/ +static double calc_bulge (double a, double b, double t1, double t2) +{ + cdfPoint p1, p2; /* initial and ending arc points */ + double r; /* radius most resembling arc at angle (t1+t2)/2 */ + double theta; /* angle of circular arc segment */ + double sin_theta; /* sine of theta */ + double dist_x; /* distance between two points along the x axis */ + double dist_y; /* distance between two points along the y axis */ + double halfdist; /* half distance between two points */ + + p1.x = a*cos(t1); + p1.y = b*sin(t1); + p2.x = a*cos(t2); + p2.y = b*sin(t2); + r = calc_radius (a, b, (t1+t2)/2); + + dist_x = p2.x - p1.x; + dist_y = p2.y - p1.y; + halfdist = (sqrt (dist_x*dist_x + dist_y*dist_y))/2; + sin_theta = halfdist/r; + if (sin_theta > 1) sin_theta = 1; + theta = 2*asin(sin_theta); + + return tan(theta/4); +} + +static void writevertex (cdCtxCanvas *ctxcanvas, int xc, int yc, double a, double b, double t, double bulge) +{ + cdfPoint p; + p.x = (xc + a*cos(t))/ctxcanvas->canvas->xres; + p.y = (yc + b*sin(t))/ctxcanvas->canvas->xres; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "VERTEX\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", p.x ); + fprintf ( ctxcanvas->file, "20\n" ); /* vertex coordinates */ + fprintf ( ctxcanvas->file, "%f\n", p.y ); + fprintf ( ctxcanvas->file, "42\n" ); /* bulge from this vertex */ + fprintf ( ctxcanvas->file, "%f\n", bulge ); /* to the next one */ +} + +static void cdarc (cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + double bulge; /* bulge is the tangent of 1/4 the angle for a given */ + /* circle arc segment (a bulge of 1 is a semicircle) */ + double t; /* current arc angle being calculated */ + double t1; /* a1 in radians */ + double t2; /* a2 in radians */ + double a; /* half horizontal axis */ + double b; /* half vertical axis */ + double seg_angle; /* angle of every arc segment */ + double diff; /* angle between a1 and a2 */ + int nseg; /* number of arc segments */ + int i; + + a = w/2; + b = h/2; + t1 = a1*CD_DEG2RAD; /* a1 in radians */ + t2 = a2*CD_DEG2RAD; /* a2 in radians */ + diff = fabs(a2 - a1); + nseg = cdRound(diff)/(360/32); /* 32 segments in closed ellipse */ + nseg = max(nseg, 1); + seg_angle = (t2-t1)/nseg; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "70\n" ); + fprintf ( ctxcanvas->file, "128\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire arc line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + + for (i=0, t=t1; i<nseg; i++, t+=seg_angle) + { /* calculate bulge between t */ + bulge = calc_bulge (a, b, t, t+seg_angle); /* and t+seg_angle and write */ + writevertex (ctxcanvas, xc, yc, a, b, t, bulge); /* vertex at t */ + } + writevertex (ctxcanvas, xc, yc, a, b, t2, 0); /* bulge of last vertex is useless */ + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void cdsector (cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + double bulge; /* bulge is the tangent of 1/4 the angle for a given */ + /* circle arc segment (a bulge of 1 is a semicircle) */ + double t; /* current arc angle being calculated */ + double t1; /* a1 in radians */ + double t2; /* a2 in radians */ + double a; /* half horizontal axis */ + double b; /* half vertical axis */ + double seg_angle; /* angle of every arc segment */ + double diff; /* angle between a1 and a2 */ + int nseg; /* number of arc segments */ + int i; + + a = w/2; + b = h/2; + t1 = a1*CD_DEG2RAD; /* a1 in radians */ + t2 = a2*CD_DEG2RAD; /* a2 in radians */ + diff = fabs(a2 - a1); + nseg = cdRound(diff)/(360/32); /* 32 segments in closed ellipse */ + nseg = max(nseg, 1); + seg_angle = (t2-t1)/nseg; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "70\n" ); + fprintf ( ctxcanvas->file, "128\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire arc line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + + if ((a2-a1) != 360) + writevertex (ctxcanvas, xc, yc, 0, 0, 0, 0); /* center */ + for (i=0, t=t1; i<nseg; i++, t+=seg_angle) + { /* calculate bulge between t */ + bulge = calc_bulge (a, b, t, t+seg_angle); /* and t+seg_angle and write */ + writevertex (ctxcanvas, xc, yc, a, b, t, bulge); /* vertex at t */ + } + writevertex (ctxcanvas, xc, yc, a, b, t2, 0); /* bulge of last vertex is useless */ + if ((a2-a1) != 360) + writevertex (ctxcanvas, xc, yc, 0, 0, 0, 0); /* center */ + + fprintf ( ctxcanvas->file, " 0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void cdtext (cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "TEXT\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "7\n" ); + wnamfont( ctxcanvas, ctxcanvas->tf ); /* current font */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* current position */ + fprintf ( ctxcanvas->file, "20\n" ); + fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "11\n" ); + fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* alignment point */ + fprintf ( ctxcanvas->file, "21\n" ); + fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->th ); /* text height */ + fprintf ( ctxcanvas->file, "50\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->canvas->text_orientation ); /* text orientation angle */ + fprintf ( ctxcanvas->file, "51\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->toa ); /* text oblique angle */ + fprintf ( ctxcanvas->file, "72\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->tha ); /* text horizontal alignment */ + fprintf ( ctxcanvas->file, "73\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->tva ); /* text vertical alignment */ + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "%s\n", s ); /* text */ +} + + +/*==========================================================================*/ +/* Attributes */ +/*==========================================================================*/ + +static int cdlinestyle (cdCtxCanvas *ctxcanvas, int style) +{ + switch (style) + { + case CD_CONTINUOUS: + ctxcanvas->lt = 0; + break; + case CD_DASHED: + ctxcanvas->lt = 1; + break; + case CD_DOTTED: + ctxcanvas->lt = 5; + break; + case CD_DASH_DOT: + ctxcanvas->lt = 6; + break; + case CD_DASH_DOT_DOT: + ctxcanvas->lt = 8; + break; + } + + return style; +} + +static int cdlinewidth (cdCtxCanvas *ctxcanvas, int width) +{ + ctxcanvas->lw = width/ctxcanvas->canvas->xres; + return width; +} + +static int cdfont (cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size) +{ + /* obs: DXF's text height (ctxcanvas->th) corresponds to CD ascent */ + + if (cdStrEqualNoCase(type_face, "System")) + { + ctxcanvas->tf = 0; + ctxcanvas->toa = 0; + ctxcanvas->th = 0.75; + } + else if (cdStrEqualNoCase(type_face, "Courier")) + { + switch (style&3) + { + case CD_PLAIN: + ctxcanvas->tf = 1; + ctxcanvas->toa = 0; + break; + + case CD_BOLD: + ctxcanvas->tf = 2; + ctxcanvas->toa = 0; + break; + + case CD_ITALIC: + ctxcanvas->tf = 1; + ctxcanvas->toa = 15; + break; + + case CD_BOLD_ITALIC: + ctxcanvas->tf = 2; + ctxcanvas->toa = 15; + break; + } + ctxcanvas->th = 0.75; + } + else if (cdStrEqualNoCase(type_face, "Times")) + { + switch (style&3) + { + case CD_PLAIN: + ctxcanvas->tf = 3; + ctxcanvas->toa = 0; + break; + + case CD_BOLD: + ctxcanvas->tf = 4; + ctxcanvas->toa = 0; + break; + + case CD_ITALIC: + ctxcanvas->tf = 3; + ctxcanvas->toa = 15; + break; + + case CD_BOLD_ITALIC: + ctxcanvas->tf = 4; + ctxcanvas->toa = 15; + break; + } + ctxcanvas->th = 1.125; + } + else if (cdStrEqualNoCase(type_face, "Helvetica")) + { + switch (style&3) + { + case CD_PLAIN: + ctxcanvas->tf = 5; + ctxcanvas->toa = 0; + break; + + case CD_BOLD: + ctxcanvas->tf = 6; + ctxcanvas->toa = 0; + break; + + case CD_ITALIC: + ctxcanvas->tf = 5; + ctxcanvas->toa = 15; + break; + + case CD_BOLD_ITALIC: + ctxcanvas->tf = 6; + ctxcanvas->toa = 15; + break; + } + ctxcanvas->th = 1.; + } + else + return 0; + + ctxcanvas->th = ctxcanvas->th * cdGetFontSizePoints(ctxcanvas->canvas, size); + + return 1; +} + +static void cdgetfontdim (cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + double tangent_ta; + double pixel_th; + + tangent_ta = tan(ctxcanvas->toa*CD_DEG2RAD); + pixel_th = (ctxcanvas->th*ctxcanvas->canvas->xres)/CD_MM2PT; /* points to pixels */ + switch (ctxcanvas->tf) + { + case 0: /* STANDARD font (CD_SYSTEM) */ + if (height) *height = cdRound(pixel_th*4/3); + if (ascent) *ascent = _cdRound(pixel_th); + if (descent) *descent = cdRound(pixel_th/3); + if (max_width) *max_width = _cdRound(pixel_th); + break; + + case 1: /* ROMAN fonts (CD_COURIER) */ + case 2: + if (height) *height = cdRound(pixel_th*4/3); + if (ascent) *ascent = _cdRound(pixel_th); + if (descent) *descent = cdRound(pixel_th/3); + if (max_width) *max_width = cdRound((pixel_th*21/20) + tangent_ta*(*ascent)); + break; + + case 3: /* ROMANTIC fonts (CD_TIMES_ROMAN) */ + if (height) *height = cdRound(pixel_th*8/9); + if (ascent) *ascent = cdRound(pixel_th*2/3); + if (descent) *descent = cdRound(pixel_th*2/9); + if (max_width) *max_width = cdRound((pixel_th*14/15) + tangent_ta*(*ascent)); + break; + + case 4: + if (height) *height = cdRound(pixel_th*8/9); + if (ascent) *ascent = cdRound(pixel_th*2/3); + if (descent) *descent = cdRound(pixel_th*2/9); + if (max_width) *max_width = cdRound((pixel_th*29/30) + tangent_ta*(*ascent)); + break; + + case 5: /* SANSSERIF fonts (CD_HELVETICA) */ + case 6: + if (height) *height = _cdRound(pixel_th); + if (ascent) *ascent = cdRound(pixel_th*3/4); + if (descent) *descent = cdRound(pixel_th/4); + if (max_width) *max_width = cdRound((pixel_th*15/16) + tangent_ta*(*ascent)); + break; + } +} + +static void cdgettextsize (cdCtxCanvas *ctxcanvas, const char *s, int *width, int *height) +{ + int i; + double tangent_ta; + double pixel_th; + + i = (int)strlen(s); + tangent_ta = tan(ctxcanvas->toa*CD_DEG2RAD); + pixel_th = (ctxcanvas->th*ctxcanvas->canvas->xres)/CD_MM2PT; /* points to pixels */ + + switch (ctxcanvas->tf) /* width return value based on maximum character width */ + { + case 0: /* STANDARD font (CD_SYSTEM) */ + if (height) *height = cdRound(pixel_th*4/3); + if (width) *width = cdRound(pixel_th*i + (pixel_th/3)*(i-1)); + break; + + case 1: /* ROMAN fonts (CD_COURIER) */ + case 2: + if (height) *height = cdRound(pixel_th*4/3); + if (width) *width = cdRound((pixel_th*21/20)*i + (pixel_th/10)*(i-1) + tangent_ta*pixel_th); + break; + + case 3: /* ROMANTIC fonts (CD_TIMES_ROMAN) */ + if (height) *height = cdRound(pixel_th*2/3 + pixel_th*2/9); + if (width) *width = cdRound((pixel_th*14/15)*i + (pixel_th/45)*(i-1) + tangent_ta*pixel_th*2/3); + break; + + case 4: + if (height) *height = cdRound(pixel_th*2/3 + pixel_th*2/9); + if (width) *width = cdRound((pixel_th*29/30)*i + (pixel_th*2/45)*(i-1) + tangent_ta*pixel_th*2/3); + break; + + case 5: /* SANSSERIF fonts (CD_HELVETICA) */ + case 6: + if (height) *height = _cdRound(pixel_th); + if (width) *width = cdRound((pixel_th*15/16)*i + (pixel_th/45)*(i-1) + tangent_ta*pixel_th*3/4); + break; + } +} + +static int cdtextalignment (cdCtxCanvas *ctxcanvas, int alignment) +{ + switch (alignment) /* convert alignment to DXF format */ + { + case CD_BASE_LEFT: + ctxcanvas->tva = 0; + ctxcanvas->tha = 0; + break; + + case CD_BASE_CENTER: + ctxcanvas->tva = 0; + ctxcanvas->tha = 1; + break; + + case CD_BASE_RIGHT: + ctxcanvas->tva = 0; + ctxcanvas->tha = 2; + break; + + case CD_SOUTH_WEST: + ctxcanvas->tva = 1; + ctxcanvas->tha = 0; + break; + + case CD_SOUTH: + ctxcanvas->tva = 1; + ctxcanvas->tha = 1; + break; + + case CD_SOUTH_EAST: + ctxcanvas->tva = 1; + ctxcanvas->tha = 2; + break; + + case CD_WEST: + ctxcanvas->tva = 2; + ctxcanvas->tha = 0; + break; + + case CD_CENTER: + ctxcanvas->tva = 2; + ctxcanvas->tha = 1; + break; + + case CD_EAST: + ctxcanvas->tva = 2; + ctxcanvas->tha = 2; + break; + + case CD_NORTH_WEST: + ctxcanvas->tva = 3; + ctxcanvas->tha = 0; + break; + + case CD_NORTH: + ctxcanvas->tva = 3; + ctxcanvas->tha = 1; + break; + + case CD_NORTH_EAST: + ctxcanvas->tva = 3; + ctxcanvas->tha = 2; + break; + } + + return alignment; +} + +/*==========================================================================*/ +/* Color */ +/*==========================================================================*/ + +static void RGB_to_HSB (unsigned char r, unsigned char g, unsigned char b, + double *hue, double *sat, double *bright) +{ + double maximum; + double minimum; + double delta; + double red = r/255.; /* red, green and blue range from 0 to 1 */ + double green = g/255.; + double blue = b/255.; + + maximum = max(max(red, green), blue); /* stores higher index */ + minimum = min(min(red, green), blue); /* stores lower index */ + delta = maximum - minimum; + + *bright = maximum*100; + *sat = 0; + + if (maximum != 0) /* sat from 0 to 100 */ + *sat = (delta*100)/maximum; + + if (*sat != 0) /* hue from 0 to 359 */ + { + if (red == maximum) *hue = (green - blue)/delta; + if (green == maximum) *hue = 2 + (blue - red)/delta; + if (blue == maximum) *hue = 4 + (red - green)/delta; + *hue *= 60; + if (*hue < 0) *hue += 360; + } + else + *hue = 0; /* color is greyscale (hue is meaningless) */ +} + +static int HSB_to_AutoCAD_Palette (double hue, double sat, double bright) +{ + int index; + int h, s, b; + + if (bright < 17) /* 5 levels of brightness in AutoCAD palette, 6 with */ + { /* black. If bright < 17, index is black (7). */ + index = 7; /* 17 is 100/6 (rounded up) */ + } + else if (sat < 10) /* low saturation makes color tend to */ + { /* grey/white. 6 levels of grey/white in */ + b = (int)floor(bright/14.3)-1;/* palette WITHOUT black. 14.3 is 100/7 */ + index = 250 + b; /* index is grey to white(255 in palette) */ + } + else + { + h = cdRound(hue/15.) + 1; + if (h > 24) h -= 24; /* 15 is 360/24 */ + h *= 10; /* h ranges from 10 to 240 in palette */ + s = (sat < 55) ? 1 : 0; /* s is 'high'(0) or 'low'(1) in palette */ + b = (int)floor(bright/16.7)-1;/* b is 0, 2, 4, 6 or 8 in palette */ + b = 2*(4 - b); /* (from brightest to dimmest) */ + index = h + s + b; /* index is simple sum of h, s and b */ + } + return index; +} + +static int get_palette_index (long int color) /* gives closest palette */ +{ /* index to RGB color */ + unsigned char red, green, blue; + double hue, sat, bright; + + cdDecodeColor (color, &red, &green, &blue); /* AutoCAD palette is */ + RGB_to_HSB (red, green, blue, &hue, &sat, &bright); /* based on HSB model */ + + return HSB_to_AutoCAD_Palette (hue, sat, bright); +} + +static long int cdforeground (cdCtxCanvas *ctxcanvas, long int color) +{ + ctxcanvas->fgcolor = get_palette_index (color); + return color; +} + + +/*==========================================================================*/ +/* Server Images */ +/*==========================================================================*/ + +static void cdpixel (cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + int oldcolor = ctxcanvas->fgcolor; /* put 'color' as current */ + cdforeground (ctxcanvas, color); /* foreground color */ + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POINT\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* position */ + fprintf ( ctxcanvas->file, " 20\n" ); + fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres ); + ctxcanvas->fgcolor = oldcolor; /* retrieve old fgcolor */ +} + +/******************************************************/ + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char filename[10240] = ""; + char* strdata = (char*)data; + cdCtxCanvas *ctxcanvas; + double param1, param2, param3; + + ctxcanvas = (cdCtxCanvas *) malloc (sizeof (cdCtxCanvas)); + + param1 = 0; + param2 = 0; + param3 = 0; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata, "%lfx%lf %lf", ¶m1, ¶m2, ¶m3); + + ctxcanvas->file = fopen (filename, "w"); + if (ctxcanvas->file == NULL) + { + free(ctxcanvas); + return; + } + + if (!param1) + { + canvas->w_mm = INT_MAX*3.78; + canvas->h_mm = INT_MAX*3.78; + canvas->xres = 3.78; + } + else if (!param2) + { + canvas->w_mm = INT_MAX*param1; + canvas->h_mm = INT_MAX*param1; + canvas->xres = param1; + } + else if (!param3) + { + canvas->w_mm = param1; + canvas->h_mm = param2; + canvas->xres = 3.78; + } + else + { + canvas->w_mm = param1; + canvas->h_mm = param2; + canvas->xres = param3; + } + + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + + canvas->bpp = 8; + + canvas->yres = canvas->xres; + + canvas->w = (int)(canvas->w_mm * canvas->xres); + canvas->h = (int)(canvas->h_mm * canvas->yres); + + ctxcanvas->layer = 0; /* reset layer */ + + ctxcanvas->tf = 0; /* text font (0 is STANDARD) */ + ctxcanvas->th = 9; /* text height */ + ctxcanvas->toa = 0; /* text oblique angle */ + ctxcanvas->tva = 0; /* text vertical alignment (0 is baseline) */ + ctxcanvas->tha = 0; /* text horizontal alignment (0 is left) */ + ctxcanvas->fgcolor = 7; /* foreground AutoCAD palette color */ + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "SECTION\n"); /* header maker */ + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "HEADER\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LIMCHECK\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "1\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LIMMIN\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LIMMAX\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->w_mm); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->h_mm); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$EXTMIN\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$EXTMAX\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->w_mm); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->h_mm); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$CLAYER\n"); + fprintf (ctxcanvas->file, "8\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LUNITS\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LUPREC\n"); + fprintf (ctxcanvas->file, "70\n"); /* precision (resolution dependant) */ + fprintf (ctxcanvas->file, "%d\n", (int)ceil(log10(ctxcanvas->canvas->xres))); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$AUNITS\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$AUPREC\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$TEXTSTYLE\n"); + fprintf (ctxcanvas->file, "7\n"); + fprintf (ctxcanvas->file, "STANDARD\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDSEC\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "SECTION\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "TABLES\n"); + + deflines (ctxcanvas); /* define lines */ + deffonts (ctxcanvas); /* define fonts */ + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDSEC\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "SECTION\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "ENTITIES\n"); +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdboxrect; + canvas->cxBox = cdboxrect; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfboxrect; + canvas->cxFBox = cdfboxrect; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxText = cdtext; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxFont = cdfont; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxForeground = cdforeground; + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxDeactivate = cddeactivate; +} + +/******************************************************/ + +static cdContext cdDXFContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_PALETTE | + CD_CAP_CLIPAREA | CD_CAP_CLIPPOLY | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | CD_CAP_CHORD | + CD_CAP_IMAGERGB | CD_CAP_IMAGEMAP | CD_CAP_IMAGESRV | + CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE | + CD_CAP_HATCH | CD_CAP_STIPPLE | CD_CAP_PATTERN | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextDXF(void) +{ + return &cdDXFContext; +} + |