blob: 5ea18c7b29a5c23359bdc6e9714b220408e06b67 [file] [log] [blame]
/*
* A PicTeX device, (C) 1996 Valerio Aimale, for
* R : A Computer Language for Statistical Data Analysis
* Copyright (C) 2001--2017 The R Core Team
* Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, a copy is available at
* https://www.R-project.org/Licenses/
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <Defn.h>
# include <rlocale.h> /* includes wchar.h */
#define R_USE_PROTOTYPES 1
#include <R_ext/GraphicsEngine.h>
#include "Fileio.h"
#include "grDevices.h"
/* device-specific information per picTeX device */
#define DOTSperIN 72.27
#define in2dots(x) (DOTSperIN * x)
typedef struct {
FILE *texfp;
char filename[128];
int pageno;
int landscape;
double width;
double height;
double pagewidth;
double pageheight;
double xlast;
double ylast;
double clipleft, clipright, cliptop, clipbottom;
double clippedx0, clippedy0, clippedx1, clippedy1;
int lty;
rcolor col;
rcolor fill;
int fontsize;
int fontface;
Rboolean debug;
} picTeXDesc;
/* Global device information */
static const double charwidth[4][128] = {
{
0.5416690, 0.8333360, 0.7777810, 0.6111145, 0.6666690, 0.7083380, 0.7222240,
0.7777810, 0.7222240, 0.7777810, 0.7222240, 0.5833360, 0.5361130, 0.5361130,
0.8138910, 0.8138910, 0.2388900, 0.2666680, 0.5000020, 0.5000020, 0.5000020,
0.5000020, 0.5000020, 0.6666700, 0.4444460, 0.4805580, 0.7222240, 0.7777810,
0.5000020, 0.8611145, 0.9722260, 0.7777810, 0.2388900, 0.3194460, 0.5000020,
0.8333360, 0.5000020, 0.8333360, 0.7583360, 0.2777790, 0.3888900, 0.3888900,
0.5000020, 0.7777810, 0.2777790, 0.3333340, 0.2777790, 0.5000020, 0.5000020,
0.5000020, 0.5000020, 0.5000020, 0.5000020, 0.5000020, 0.5000020, 0.5000020,
0.5000020, 0.5000020, 0.2777790, 0.2777790, 0.3194460, 0.7777810, 0.4722240,
0.4722240, 0.6666690, 0.6666700, 0.6666700, 0.6388910, 0.7222260, 0.5972240,
0.5694475, 0.6666690, 0.7083380, 0.2777810, 0.4722240, 0.6944480, 0.5416690,
0.8750050, 0.7083380, 0.7361130, 0.6388910, 0.7361130, 0.6458360, 0.5555570,
0.6805570, 0.6875050, 0.6666700, 0.9444480, 0.6666700, 0.6666700, 0.6111130,
0.2888900, 0.5000020, 0.2888900, 0.5000020, 0.2777790, 0.2777790, 0.4805570,
0.5166680, 0.4444460, 0.5166680, 0.4444460, 0.3055570, 0.5000020, 0.5166680,
0.2388900, 0.2666680, 0.4888920, 0.2388900, 0.7944470, 0.5166680, 0.5000020,
0.5166680, 0.5166680, 0.3416690, 0.3833340, 0.3611120, 0.5166680, 0.4611130,
0.6833360, 0.4611130, 0.4611130, 0.4347230, 0.5000020, 1.0000030, 0.5000020,
0.5000020, 0.5000020
},
{
0.5805590, 0.9166720, 0.8555600, 0.6722260, 0.7333370, 0.7944490, 0.7944490,
0.8555600, 0.7944490, 0.8555600, 0.7944490, 0.6416700, 0.5861150, 0.5861150,
0.8916720, 0.8916720, 0.2555570, 0.2861130, 0.5500030, 0.5500030, 0.5500030,
0.5500030, 0.5500030, 0.7333370, 0.4888920, 0.5652800, 0.7944490, 0.8555600,
0.5500030, 0.9472275, 1.0694500, 0.8555600, 0.2555570, 0.3666690, 0.5583360,
0.9166720, 0.5500030, 1.0291190, 0.8305610, 0.3055570, 0.4277800, 0.4277800,
0.5500030, 0.8555600, 0.3055570, 0.3666690, 0.3055570, 0.5500030, 0.5500030,
0.5500030, 0.5500030, 0.5500030, 0.5500030, 0.5500030, 0.5500030, 0.5500030,
0.5500030, 0.5500030, 0.3055570, 0.3055570, 0.3666690, 0.8555600, 0.5194470,
0.5194470, 0.7333370, 0.7333370, 0.7333370, 0.7027820, 0.7944490, 0.6416700,
0.6111145, 0.7333370, 0.7944490, 0.3305570, 0.5194470, 0.7638930, 0.5805590,
0.9777830, 0.7944490, 0.7944490, 0.7027820, 0.7944490, 0.7027820, 0.6111145,
0.7333370, 0.7638930, 0.7333370, 1.0388950, 0.7333370, 0.7333370, 0.6722260,
0.3430580, 0.5583360, 0.3430580, 0.5500030, 0.3055570, 0.3055570, 0.5250030,
0.5611140, 0.4888920, 0.5611140, 0.5111140, 0.3361130, 0.5500030, 0.5611140,
0.2555570, 0.2861130, 0.5305590, 0.2555570, 0.8666720, 0.5611140, 0.5500030,
0.5611140, 0.5611140, 0.3722250, 0.4216690, 0.4041690, 0.5611140, 0.5000030,
0.7444490, 0.5000030, 0.5000030, 0.4763920, 0.5500030, 1.1000060, 0.5500030,
0.5500030, 0.550003 },
{
0.5416690, 0.8333360, 0.7777810, 0.6111145, 0.6666690, 0.7083380, 0.7222240,
0.7777810, 0.7222240, 0.7777810, 0.7222240, 0.5833360, 0.5361130, 0.5361130,
0.8138910, 0.8138910, 0.2388900, 0.2666680, 0.5000020, 0.5000020, 0.5000020,
0.5000020, 0.5000020, 0.7375210, 0.4444460, 0.4805580, 0.7222240, 0.7777810,
0.5000020, 0.8611145, 0.9722260, 0.7777810, 0.2388900, 0.3194460, 0.5000020,
0.8333360, 0.5000020, 0.8333360, 0.7583360, 0.2777790, 0.3888900, 0.3888900,
0.5000020, 0.7777810, 0.2777790, 0.3333340, 0.2777790, 0.5000020, 0.5000020,
0.5000020, 0.5000020, 0.5000020, 0.5000020, 0.5000020, 0.5000020, 0.5000020,
0.5000020, 0.5000020, 0.2777790, 0.2777790, 0.3194460, 0.7777810, 0.4722240,
0.4722240, 0.6666690, 0.6666700, 0.6666700, 0.6388910, 0.7222260, 0.5972240,
0.5694475, 0.6666690, 0.7083380, 0.2777810, 0.4722240, 0.6944480, 0.5416690,
0.8750050, 0.7083380, 0.7361130, 0.6388910, 0.7361130, 0.6458360, 0.5555570,
0.6805570, 0.6875050, 0.6666700, 0.9444480, 0.6666700, 0.6666700, 0.6111130,
0.2888900, 0.5000020, 0.2888900, 0.5000020, 0.2777790, 0.2777790, 0.4805570,
0.5166680, 0.4444460, 0.5166680, 0.4444460, 0.3055570, 0.5000020, 0.5166680,
0.2388900, 0.2666680, 0.4888920, 0.2388900, 0.7944470, 0.5166680, 0.5000020,
0.5166680, 0.5166680, 0.3416690, 0.3833340, 0.3611120, 0.5166680, 0.4611130,
0.6833360, 0.4611130, 0.4611130, 0.4347230, 0.5000020, 1.0000030, 0.5000020,
0.5000020, 0.5000020 },
{
0.5805590, 0.9166720, 0.8555600, 0.6722260, 0.7333370, 0.7944490, 0.7944490,
0.8555600, 0.7944490, 0.8555600, 0.7944490, 0.6416700, 0.5861150, 0.5861150,
0.8916720, 0.8916720, 0.2555570, 0.2861130, 0.5500030, 0.5500030, 0.5500030,
0.5500030, 0.5500030, 0.8002530, 0.4888920, 0.5652800, 0.7944490, 0.8555600,
0.5500030, 0.9472275, 1.0694500, 0.8555600, 0.2555570, 0.3666690, 0.5583360,
0.9166720, 0.5500030, 1.0291190, 0.8305610, 0.3055570, 0.4277800, 0.4277800,
0.5500030, 0.8555600, 0.3055570, 0.3666690, 0.3055570, 0.5500030, 0.5500030,
0.5500030, 0.5500030, 0.5500030, 0.5500030, 0.5500030, 0.5500030, 0.5500030,
0.5500030, 0.5500030, 0.3055570, 0.3055570, 0.3666690, 0.8555600, 0.5194470,
0.5194470, 0.7333370, 0.7333370, 0.7333370, 0.7027820, 0.7944490, 0.6416700,
0.6111145, 0.7333370, 0.7944490, 0.3305570, 0.5194470, 0.7638930, 0.5805590,
0.9777830, 0.7944490, 0.7944490, 0.7027820, 0.7944490, 0.7027820, 0.6111145,
0.7333370, 0.7638930, 0.7333370, 1.0388950, 0.7333370, 0.7333370, 0.6722260,
0.3430580, 0.5583360, 0.3430580, 0.5500030, 0.3055570, 0.3055570, 0.5250030,
0.5611140, 0.4888920, 0.5611140, 0.5111140, 0.3361130, 0.5500030, 0.5611140,
0.2555570, 0.2861130, 0.5305590, 0.2555570, 0.8666720, 0.5611140, 0.5500030,
0.5611140, 0.5611140, 0.3722250, 0.4216690, 0.4041690, 0.5611140, 0.5000030,
0.7444490, 0.5000030, 0.5000030, 0.4763920, 0.5500030, 1.1000060, 0.5500030,
0.5500030, 0.550003
}
};
static const char * const fontname[] = {
"cmss10",
"cmssbx10",
"cmssi10",
"cmssxi10"
};
/* Device driver actions */
static void PicTeX_Circle(double x, double y, double r,
const pGEcontext gc,
pDevDesc dd);
static void PicTeX_Clip(double x0, double x1, double y0, double y1,
pDevDesc dd);
static void PicTeX_Close(pDevDesc dd);
static void PicTeX_Line(double x1, double y1, double x2, double y2,
const pGEcontext gc,
pDevDesc dd);
static void PicTeX_MetricInfo(int c,
const pGEcontext gc,
double* ascent, double* descent,
double* width, pDevDesc dd);
static void PicTeX_NewPage(const pGEcontext gc, pDevDesc dd);
static void PicTeX_Polygon(int n, double *x, double *y,
const pGEcontext gc,
pDevDesc dd);
static void PicTeX_Rect(double x0, double y0, double x1, double y1,
const pGEcontext gc,
pDevDesc dd);
static void PicTeX_Size(double *left, double *right,
double *bottom, double *top,
pDevDesc dd);
static double PicTeX_StrWidth(const char *str,
const pGEcontext gc,
pDevDesc dd);
static void PicTeX_Text(double x, double y, const char *str,
double rot, double hadj,
const pGEcontext gc,
pDevDesc dd);
/* Support routines */
static void SetLinetype(int newlty, double newlwd, pDevDesc dd)
{
picTeXDesc *ptd = (picTeXDesc *) dd->deviceSpecific;
int i, templty;
ptd->lty = newlty;
if (ptd->lty) {
fprintf(ptd->texfp,"\\setdashpattern <");
for(i=0 ; i<8 && newlty&15 ; i++) {
int lwd = (int)newlwd * newlty;
fprintf(ptd->texfp,"%dpt", lwd & 15);
templty = newlty>>4;
if ((i+1)<8 && templty&15) fprintf(ptd->texfp,", ");
newlty = newlty>>4;
}
fprintf(ptd->texfp,">\n");
} else fprintf(ptd->texfp,"\\setsolid\n");
}
static void SetFont(int face, int size, picTeXDesc *ptd)
{
int lface=face, lsize= size;
if(lface < 1 || lface > 4 ) lface = 1;
if(lsize < 1 || lsize > 24) lsize = 10;
if(lsize != ptd->fontsize || lface != ptd->fontface) {
fprintf(ptd->texfp, "\\font\\picfont %s at %dpt\\picfont\n",
fontname[lface-1], lsize);
ptd->fontsize = lsize;
ptd->fontface = lface;
}
}
static void PicTeX_MetricInfo(int c,
const pGEcontext gc,
double* ascent, double* descent,
double* width, pDevDesc dd)
{
/* metric information not available => return 0,0,0 */
*ascent = 0.0;
*descent = 0.0;
*width = 0.0;
}
/* Initialize the device */
/* Interactive Resize */
static void PicTeX_Size(double *left, double *right,
double *bottom, double *top,
pDevDesc dd)
{
*left = dd->left; /* left */
*right = dd->right;/* right */
*bottom = dd->bottom; /* bottom */
*top = dd->top;/* top */
}
static void PicTeX_Clip(double x0, double x1, double y0, double y1,
pDevDesc dd)
{
picTeXDesc *ptd = (picTeXDesc *) dd->deviceSpecific;
if(ptd->debug)
fprintf(ptd->texfp, "%% Setting Clip Region to %.2f %.2f %.2f %.2f\n",
x0, y0, x1, y1);
ptd->clipleft = x0;
ptd->clipright = x1;
ptd->clipbottom = y0;
ptd->cliptop = y1;
}
/* Start a new page */
static void PicTeX_NewPage(const pGEcontext gc,
pDevDesc dd)
{
picTeXDesc *ptd = (picTeXDesc *) dd->deviceSpecific;
int face, size;
if (ptd->pageno) {
fprintf(ptd->texfp, "\\endpicture\n}\n\n\n");
fprintf(ptd->texfp, "\\hbox{\\beginpicture\n");
fprintf(ptd->texfp, "\\setcoordinatesystem units <1pt,1pt>\n");
fprintf(ptd->texfp,
"\\setplotarea x from 0 to %.2f, y from 0 to %.2f\n",
in2dots(ptd->width), in2dots(ptd->height));
fprintf(ptd->texfp,"\\setlinear\n");
fprintf(ptd->texfp, "\\font\\picfont cmss10\\picfont\n");
}
ptd->pageno++;
face = ptd->fontface;
size = ptd->fontsize;
ptd->fontface = 0;
ptd->fontsize = 0;
SetFont(face, size, ptd);
}
/* Close down the driver */
static void PicTeX_Close(pDevDesc dd)
{
picTeXDesc *ptd = (picTeXDesc *) dd->deviceSpecific;
fprintf(ptd->texfp, "\\endpicture\n}\n");
fclose(ptd->texfp);
free(ptd);
}
/* Draw To */
static void PicTeX_ClipLine(double x0, double y0, double x1, double y1,
picTeXDesc *ptd)
{
ptd->clippedx0 = x0; ptd->clippedx1 = x1;
ptd->clippedy0 = y0; ptd->clippedy1 = y1;
if ((ptd->clippedx0 < ptd->clipleft &&
ptd->clippedx1 < ptd->clipleft) ||
(ptd->clippedx0 > ptd->clipright &&
ptd->clippedx1 > ptd->clipright) ||
(ptd->clippedy0 < ptd->clipbottom &&
ptd->clippedy1 < ptd->clipbottom) ||
(ptd->clippedy0 > ptd->cliptop &&
ptd->clippedy1 > ptd->cliptop)) {
ptd->clippedx0 = ptd->clippedx1;
ptd->clippedy0 = ptd->clippedy1;
return;
}
/*Clipping Left */
if (ptd->clippedx1 >= ptd->clipleft && ptd->clippedx0 < ptd->clipleft) {
ptd->clippedy0 = ((ptd->clippedy1-ptd->clippedy0) /
(ptd->clippedx1-ptd->clippedx0) *
(ptd->clipleft-ptd->clippedx0)) +
ptd->clippedy0;
ptd->clippedx0 = ptd->clipleft;
}
if (ptd->clippedx1 <= ptd->clipleft && ptd->clippedx0 > ptd->clipleft) {
ptd->clippedy1 = ((ptd->clippedy1-ptd->clippedy0) /
(ptd->clippedx1-ptd->clippedx0) *
(ptd->clipleft-ptd->clippedx0)) +
ptd->clippedy0;
ptd->clippedx1 = ptd->clipleft;
}
/* Clipping Right */
if (ptd->clippedx1 >= ptd->clipright &&
ptd->clippedx0 < ptd->clipright) {
ptd->clippedy1 = ((ptd->clippedy1-ptd->clippedy0) /
(ptd->clippedx1-ptd->clippedx0) *
(ptd->clipright-ptd->clippedx0)) +
ptd->clippedy0;
ptd->clippedx1 = ptd->clipright;
}
if (ptd->clippedx1 <= ptd->clipright &&
ptd->clippedx0 > ptd->clipright) {
ptd->clippedy0 = ((ptd->clippedy1-ptd->clippedy0) /
(ptd->clippedx1-ptd->clippedx0) *
(ptd->clipright-ptd->clippedx0)) +
ptd->clippedy0;
ptd->clippedx0 = ptd->clipright;
}
/*Clipping Bottom */
if (ptd->clippedy1 >= ptd->clipbottom &&
ptd->clippedy0 < ptd->clipbottom ) {
ptd->clippedx0 = ((ptd->clippedx1-ptd->clippedx0) /
(ptd->clippedy1-ptd->clippedy0) *
(ptd->clipbottom -ptd->clippedy0)) +
ptd->clippedx0;
ptd->clippedy0 = ptd->clipbottom ;
}
if (ptd->clippedy1 <= ptd->clipbottom &&
ptd->clippedy0 > ptd->clipbottom ) {
ptd->clippedx1 = ((ptd->clippedx1-ptd->clippedx0) /
(ptd->clippedy1-ptd->clippedy0) *
(ptd->clipbottom -ptd->clippedy0)) +
ptd->clippedx0;
ptd->clippedy1 = ptd->clipbottom ;
}
/*Clipping Top */
if (ptd->clippedy1 >= ptd->cliptop && ptd->clippedy0 < ptd->cliptop ) {
ptd->clippedx1 = ((ptd->clippedx1-ptd->clippedx0) /
(ptd->clippedy1-ptd->clippedy0) *
(ptd->cliptop -ptd->clippedy0)) +
ptd->clippedx0;
ptd->clippedy1 = ptd->cliptop ;
}
if (ptd->clippedy1 <= ptd->cliptop && ptd->clippedy0 > ptd->cliptop ) {
ptd->clippedx0 = ((ptd->clippedx1-ptd->clippedx0) /
(ptd->clippedy1-ptd->clippedy0) *
(ptd->cliptop -ptd->clippedy0)) +
ptd->clippedx0;
ptd->clippedy0 = ptd->cliptop ;
}
}
static void PicTeX_Line(double x1, double y1, double x2, double y2,
const pGEcontext gc,
pDevDesc dd)
{
picTeXDesc *ptd = (picTeXDesc *) dd->deviceSpecific;
if (x1 != x2 || y1 != y2) {
SetLinetype(gc->lty, gc->lwd, dd);
if(ptd->debug)
fprintf(ptd->texfp,
"%% Drawing line from %.2f, %.2f to %.2f, %.2f\n",
x1, y1, x2, y2);
PicTeX_ClipLine(x1, y1, x2, y2, ptd);
if (ptd->debug)
fprintf(ptd->texfp,
"%% Drawing clipped line from %.2f, %.2f to %.2f, %.2f\n",
ptd->clippedx0, ptd->clippedy0,
ptd->clippedx1, ptd->clippedy1);
fprintf(ptd->texfp, "\\plot %.2f %.2f %.2f %.2f /\n",
ptd->clippedx0, ptd->clippedy0,
ptd->clippedx1, ptd->clippedy1);
}
}
static void PicTeX_Polyline(int n, double *x, double *y,
const pGEcontext gc,
pDevDesc dd)
{
double x1, y1, x2, y2;
int i;
picTeXDesc *ptd = (picTeXDesc *) dd->deviceSpecific;
SetLinetype(gc->lty, gc->lwd, dd);
x1 = x[0];
y1 = y[0];
for (i = 1; i < n; i++) {
x2 = x[i];
y2 = y[i];
PicTeX_ClipLine(x1, y1, x2, y2, ptd);
fprintf(ptd->texfp, "\\plot %.2f %.2f %.2f %.2f /\n",
ptd->clippedx0, ptd->clippedy0,
ptd->clippedx1, ptd->clippedy1);
x1 = x2;
y1 = y2;
}
}
/* String Width in Rasters */
/* For the current font in pointsize fontsize */
static double PicTeX_StrWidth(const char *str,
const pGEcontext gc,
pDevDesc dd)
{
picTeXDesc *ptd = (picTeXDesc *) dd->deviceSpecific;
const char *p;
int size;
double sum;
size = (int)(gc->cex * gc->ps + 0.5);
SetFont(gc->fontface, size, ptd);
sum = 0;
if(mbcslocale && ptd->fontface != 5) {
/* This version at least uses the state of the MBCS */
size_t i, ucslen = mbcsToUcs2(str, NULL, 0, CE_NATIVE);
if (ucslen != (size_t)-1) {
ucs2_t ucs[ucslen];
int status = (int) mbcsToUcs2(str, ucs, (int)ucslen, CE_NATIVE);
if (status >= 0)
for (i = 0; i < ucslen; i++)
if(ucs[i] < 128) sum += charwidth[ptd->fontface-1][ucs[i]];
else sum += (double) Ri18n_wcwidth(ucs[i]) * 0.5; /* A guess */
else
warning(_("invalid string in '%s'"), "PicTeX_StrWidth");
} else
warning(_("invalid string in '%s'"), "PicTeX_StrWidth");
} else
for(p = str; *p; p++)
sum += charwidth[ptd->fontface-1][(int)*p];
return sum * ptd->fontsize;
}
/* Possibly Filled Rectangle */
static void PicTeX_Rect(double x0, double y0, double x1, double y1,
const pGEcontext gc,
pDevDesc dd)
{
double x[4], y[4];
x[0] = x0; y[0] = y0;
x[1] = x0; y[1] = y1;
x[2] = x1; y[2] = y1;
x[3] = x1; y[3] = y0;
PicTeX_Polygon(4, x, y, gc, dd);
}
static void PicTeX_Circle(double x, double y, double r,
const pGEcontext gc,
pDevDesc dd)
{
picTeXDesc *ptd = (picTeXDesc *) dd->deviceSpecific;
fprintf(ptd->texfp,
"\\circulararc 360 degrees from %.2f %.2f center at %.2f %.2f\n",
x, (y + r), x, y);
}
static void PicTeX_Polygon(int n, double *x, double *y,
const pGEcontext gc,
pDevDesc dd)
{
double x1, y1, x2, y2;
int i;
picTeXDesc *ptd = (picTeXDesc *) dd->deviceSpecific;
SetLinetype(gc->lty, gc->lwd, dd);
x1 = x[0];
y1 = y[0];
for (i=1; i<n; i++) {
x2 = x[i];
y2 = y[i];
PicTeX_ClipLine(x1, y1, x2, y2, ptd);
fprintf(ptd->texfp, "\\plot %.2f %.2f %.2f %.2f /\n",
ptd->clippedx0, ptd->clippedy0,
ptd->clippedx1, ptd->clippedy1);
x1 = x2;
y1 = y2;
}
x2 = x[0];
y2 = y[0];
PicTeX_ClipLine(x1, y1, x2, y2, ptd);
fprintf(ptd->texfp, "\\plot %.2f %.2f %.2f %.2f /\n",
ptd->clippedx0, ptd->clippedy0,
ptd->clippedx1, ptd->clippedy1);
}
/* TeX Text Translations */
static void textext(const char *str, picTeXDesc *ptd)
{
fputc('{', ptd->texfp);
for( ; *str ; str++)
switch(*str) {
case '$':
fprintf(ptd->texfp, "\\$");
break;
case '%':
fprintf(ptd->texfp, "\\%%");
break;
case '{':
fprintf(ptd->texfp, "\\{");
break;
case '}':
fprintf(ptd->texfp, "\\}");
break;
case '^':
fprintf(ptd->texfp, "\\^{}");
break;
default:
fputc(*str, ptd->texfp);
break;
}
fprintf(ptd->texfp,"} ");
}
/* Rotated Text */
static void PicTeX_Text(double x, double y, const char *str,
double rot, double hadj,
const pGEcontext gc,
pDevDesc dd)
{
int size;
double xoff = 0.0, yoff = 0.0;
picTeXDesc *ptd = (picTeXDesc *) dd->deviceSpecific;
size = (int)(gc->cex * gc->ps + 0.5);
SetFont(gc->fontface, size, ptd);
if(ptd->debug)
fprintf(ptd->texfp,
"%% Writing string of length %.2f, at %.2f %.2f, xc = %.2f yc = %.2f\n",
(double)PicTeX_StrWidth(str, gc, dd),
x, y, 0.0, 0.0);
#if 0 /* Original */
fprintf(ptd->texfp,"\\put ");
textext(str, ptd);
if (rot == 90 )
fprintf(ptd->texfp," [rB] <%.2fpt,%.2fpt>", xoff, yoff);
else fprintf(ptd->texfp," [lB] <%.2fpt,%.2fpt>", xoff, yoff);
#else /* use rotatebox */
if (rot == 90 ){
fprintf(ptd->texfp,"\\put {\\rotatebox{%d}",(int)rot);
textext(str, ptd);
fprintf(ptd->texfp,"} [rB] <%.2fpt,%.2fpt>", xoff, yoff);
} else {
fprintf(ptd->texfp,"\\put ");
textext(str, ptd);
fprintf(ptd->texfp," [lB] <%.2fpt,%.2fpt>", xoff, yoff);
}
#endif
fprintf(ptd->texfp," at %.2f %.2f\n", x, y);
}
static
Rboolean PicTeXDeviceDriver(pDevDesc dd, const char *filename,
const char *bg, const char *fg,
double width, double height,
Rboolean debug)
{
picTeXDesc *ptd;
if (!(ptd = (picTeXDesc *) malloc(sizeof(picTeXDesc))))
return FALSE;
if (!(ptd->texfp = R_fopen(R_ExpandFileName(filename), "w"))) {
free(ptd);
return FALSE;
}
strcpy(ptd->filename, filename);
dd->startfill = R_GE_str2col(bg);
dd->startcol = R_GE_str2col(fg);
dd->startps = 10;
dd->startlty = 0;
dd->startfont = 1;
dd->startgamma = 1;
dd->close = PicTeX_Close;
dd->clip = PicTeX_Clip;
dd->size = PicTeX_Size;
dd->newPage = PicTeX_NewPage;
dd->line = PicTeX_Line;
dd->text = PicTeX_Text;
dd->strWidth = PicTeX_StrWidth;
dd->rect = PicTeX_Rect;
dd->circle = PicTeX_Circle;
/* dd->path = PicTeX_Path; not implemented */
dd->polygon = PicTeX_Polygon;
dd->polyline = PicTeX_Polyline;
dd->metricInfo = PicTeX_MetricInfo;
dd->hasTextUTF8 = FALSE;
dd->useRotatedTextInContour = FALSE;
/* Screen Dimensions in Pixels */
dd->left = 0; /* left */
dd->right = in2dots(width);/* right */
dd->bottom = 0; /* bottom */
dd->top = in2dots(height);/* top */
dd->clipLeft = dd->left; dd->clipRight = dd->right;
dd->clipBottom = dd->bottom; dd->clipTop = dd->top;
ptd->width = width;
ptd->height = height;
// PicTeX_Open():
ptd->fontsize = 0;
ptd->fontface = 0;
ptd->debug = FALSE;
fprintf(ptd->texfp, "\\hbox{\\beginpicture\n");
fprintf(ptd->texfp, "\\setcoordinatesystem units <1pt,1pt>\n");
fprintf(ptd->texfp,
"\\setplotarea x from 0 to %.2f, y from 0 to %.2f\n",
in2dots(ptd->width), in2dots(ptd->height));
fprintf(ptd->texfp,"\\setlinear\n");
fprintf(ptd->texfp, "\\font\\picfont cmss10\\picfont\n");
SetFont(1, 10, ptd);
ptd->pageno++;
/* Base Pointsize */
/* Nominal Character Sizes in Pixels */
dd->cra[0] = 9;
dd->cra[1] = 12;
/* Character Addressing Offsets */
/* These offsets should center a single */
/* plotting character over the plotting point. */
/* Pure guesswork and eyeballing ... */
dd->xCharOffset = 0; /*0.4900;*/
dd->yCharOffset = 0; /*0.3333;*/
dd->yLineBias = 0; /*0.1;*/
/* Inches per Raster Unit */
/* We use printer points, i.e. 72.27 dots per inch : */
dd->ipr[0] = dd->ipr[1] = 1./DOTSperIN;
dd->canClip = TRUE;
dd->canHAdj = 0;
dd->canChangeGamma = FALSE;
ptd->lty = 1;
ptd->pageno = 0;
ptd->debug = debug;
dd->haveTransparency = 1;
dd->haveTransparentBg = 2;
dd->deviceSpecific = (void *) ptd;
dd->displayListOn = FALSE;
return TRUE;
}
/* PicTeX Device Driver Parameters
* --------------------
* file = output filename
* bg = background color
* fg = foreground color
* width = width in inches
* height = height in inches
* debug = Rboolean; if TRUE, write TeX-Comments into output.
*/
SEXP PicTeX(SEXP args)
{
pGEDevDesc dd;
const char *file, *bg, *fg;
double height, width;
Rboolean debug;
const void *vmax = vmaxget();
args = CDR(args); /* skip entry point name */
file = translateChar(asChar(CAR(args))); args = CDR(args);
bg = CHAR(asChar(CAR(args))); args = CDR(args);
fg = CHAR(asChar(CAR(args))); args = CDR(args);
width = asReal(CAR(args)); args = CDR(args);
height = asReal(CAR(args)); args = CDR(args);
debug = asLogical(CAR(args)); args = CDR(args);
if(debug == NA_LOGICAL) debug = FALSE;
R_CheckDeviceAvailable();
BEGIN_SUSPEND_INTERRUPTS {
pDevDesc dev;
if (!(dev = (pDevDesc) calloc(1, sizeof(DevDesc))))
return 0;
if(!PicTeXDeviceDriver(dev, file, bg, fg, width, height, debug)) {
free(dev);
error(_("unable to start %s() device"), "pictex");
}
dd = GEcreateDevDesc(dev);
GEaddDevice2f(dd, "pictex", file);
} END_SUSPEND_INTERRUPTS;
vmaxset(vmax);
return R_NilValue;
}