Rev 44500 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* Copyright (C) 2001-3 Paul Murrell* 2003-5 The R Development Core Team** 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* http://www.r-project.org/Licenses/*/#include "grid.h"#include <string.h>extern int gridRegisterIndex;/* Some access methods for viewports */SEXP viewportX(SEXP vp) {return VECTOR_ELT(vp, VP_X);}SEXP viewportY(SEXP vp) {return VECTOR_ELT(vp, VP_Y);}SEXP viewportWidth(SEXP vp) {return VECTOR_ELT(vp, VP_WIDTH);}SEXP viewportHeight(SEXP vp) {return VECTOR_ELT(vp, VP_HEIGHT);}Rboolean viewportClip(SEXP vp) {return LOGICAL(VECTOR_ELT(vp, VP_CLIP))[0];}double viewportXScaleMin(SEXP vp) {return numeric(VECTOR_ELT(vp, VP_XSCALE), 0);}double viewportXScaleMax(SEXP vp) {return numeric(VECTOR_ELT(vp, VP_XSCALE), 1);}double viewportYScaleMin(SEXP vp) {return numeric(VECTOR_ELT(vp, VP_YSCALE), 0);}double viewportYScaleMax(SEXP vp) {return numeric(VECTOR_ELT(vp, VP_YSCALE), 1);}double viewportAngle(SEXP vp) {return numeric(VECTOR_ELT(vp, VP_ANGLE), 0);}SEXP viewportLayout(SEXP vp) {return VECTOR_ELT(vp, VP_LAYOUT);}double viewportHJust(SEXP vp) {return REAL(VECTOR_ELT(vp, VP_VALIDJUST))[0];}double viewportVJust(SEXP vp) {return REAL(VECTOR_ELT(vp, VP_VALIDJUST))[1];}SEXP viewportLayoutPosRow(SEXP vp) {return VECTOR_ELT(vp, VP_VALIDLPOSROW);}SEXP viewportLayoutPosCol(SEXP vp) {return VECTOR_ELT(vp, VP_VALIDLPOSCOL);}SEXP viewportgpar(SEXP vp) {return VECTOR_ELT(vp, PVP_GPAR);}const char* viewportFontFamily(SEXP vp) {return CHAR(STRING_ELT(VECTOR_ELT(VECTOR_ELT(vp, PVP_GPAR), GP_FONTFAMILY),0));}int viewportFont(SEXP vp) {return INTEGER(VECTOR_ELT(VECTOR_ELT(vp, PVP_GPAR), GP_FONT))[0];}double viewportFontSize(SEXP vp) {return REAL(VECTOR_ELT(VECTOR_ELT(vp, PVP_GPAR), GP_FONTSIZE))[0];}double viewportLineHeight(SEXP vp) {return REAL(VECTOR_ELT(VECTOR_ELT(vp, PVP_GPAR), GP_LINEHEIGHT))[0];}double viewportCex(SEXP vp) {return numeric(VECTOR_ELT(VECTOR_ELT(vp, PVP_GPAR), GP_CEX), 0);}SEXP viewportTransform(SEXP vp) {return VECTOR_ELT(vp, PVP_TRANS);}SEXP viewportLayoutWidths(SEXP vp) {return VECTOR_ELT(vp, PVP_WIDTHS);}SEXP viewportLayoutHeights(SEXP vp) {return VECTOR_ELT(vp, PVP_HEIGHTS);}SEXP viewportWidthCM(SEXP vp) {return VECTOR_ELT(vp, PVP_WIDTHCM);}SEXP viewportHeightCM(SEXP vp) {return VECTOR_ELT(vp, PVP_HEIGHTCM);}SEXP viewportRotation(SEXP vp) {return VECTOR_ELT(vp, PVP_ROTATION);}SEXP viewportClipRect(SEXP vp) {return VECTOR_ELT(vp, PVP_CLIPRECT);}SEXP viewportParent(SEXP vp) {return VECTOR_ELT(vp, PVP_PARENT);}SEXP viewportChildren(SEXP vp) {return VECTOR_ELT(vp, PVP_CHILDREN);}SEXP viewportDevWidthCM(SEXP vp) {return VECTOR_ELT(vp, PVP_DEVWIDTHCM);}SEXP viewportDevHeightCM(SEXP vp) {return VECTOR_ELT(vp, PVP_DEVHEIGHTCM);}SEXP viewportParentGPar(SEXP vp) {return VECTOR_ELT(vp, PVP_PARENTGPAR);}void fillViewportLocationFromViewport(SEXP vp, LViewportLocation *vpl){vpl->x = viewportX(vp);vpl->y = viewportY(vp);vpl->width = viewportWidth(vp);vpl->height = viewportHeight(vp);vpl->hjust = viewportHJust(vp);vpl->vjust = viewportVJust(vp);}void fillViewportContextFromViewport(SEXP vp,LViewportContext *vpc){vpc->xscalemin = viewportXScaleMin(vp);vpc->xscalemax = viewportXScaleMax(vp);vpc->yscalemin = viewportYScaleMin(vp);vpc->yscalemax = viewportYScaleMax(vp);}void copyViewportContext(LViewportContext vpc1, LViewportContext *vpc2){vpc2->xscalemin = vpc1.xscalemin;vpc2->xscalemax = vpc1.xscalemax;vpc2->yscalemin = vpc1.yscalemin;vpc2->yscalemax = vpc1.yscalemax;}void gcontextFromViewport(SEXP vp, const pGEcontext gc, pGEDevDesc dd) {gcontextFromgpar(viewportgpar(vp), 0, gc, dd);}/* The idea is to produce a transformation for this viewport which* will take any location in INCHES and turn it into a location on the* Device in INCHES.* The reason for working in INCHES is because we want to be able to* do rotations as part of the transformation.* If "incremental" is true, then we just work from the "current"* values of the parent. Otherwise, we have to recurse and recalculate* everything from scratch.*/void calcViewportTransform(SEXP vp, SEXP parent, Rboolean incremental,pGEDevDesc dd){int i, j;double vpWidthCM, vpHeightCM, rotationAngle;double parentWidthCM, parentHeightCM;double xINCHES, yINCHES;double xadj, yadj;double parentAngle;LViewportLocation vpl;LViewportContext vpc, parentContext;R_GE_gcontext gc, parentgc;LTransform thisLocation, thisRotation, thisJustification, thisTransform;LTransform tempTransform, parentTransform, transform;SEXP currentWidthCM, currentHeightCM, currentRotation;SEXP currentTransform;/* This should never be true when we are doing an incremental* calculation*/if (isNull(parent)) {/* We have a top-level viewport; the parent is the device*/getDeviceSize(dd, &parentWidthCM, &parentHeightCM);/* For a device the transform is the identity transform*/identity(parentTransform);/* For a device, xmin=0, ymin=0, xmax=1, ymax=1, and*/parentContext.xscalemin = 0;parentContext.yscalemin = 0;parentContext.xscalemax = 1;parentContext.yscalemax = 1;/* FIXME: How do I figure out the device fontsize ?* From ps.options etc, ... ?* FIXME: How do I figure out the device lineheight ??* FIXME: How do I figure out the device cex ??* FIXME: How do I figure out the device font ??* FIXME: How do I figure out the device fontfamily ??*/parentgc.ps = 10;parentgc.lineheight = 1.2;parentgc.cex = 1;parentgc.fontface = 1;parentgc.fontfamily[0] = '\0';/* The device is not rotated*/parentAngle = 0;fillViewportLocationFromViewport(vp, &vpl);} else {/* Get parent transform (etc ...)* If necessary, recalculate the parent transform (etc ...)*/if (!incremental)calcViewportTransform(parent, viewportParent(parent), 0, dd);/* Get information required to transform viewport location*/parentWidthCM = REAL(viewportWidthCM(parent))[0];parentHeightCM = REAL(viewportHeightCM(parent))[0];parentAngle = REAL(viewportRotation(parent))[0];for (i=0; i<3; i++)for (j=0; j<3; j++)parentTransform[i][j] =REAL(viewportTransform(parent))[i +3*j];fillViewportContextFromViewport(parent, &parentContext);/** Don't get gcontext from parent because the most recent* previous gpar setting may have come from a gTree* So we look at this viewport's parentgpar slot instead** WAS gcontextFromViewport(parent, &parentgc);*/gcontextFromgpar(viewportParentGPar(vp), 0, &parentgc, dd);/* In order for the vp to get its vpl from a layout* it must have specified a layout.pos and the parent* must have a layout* FIXME: Actually, in addition, layout.pos.row and* layout.pos.col must be valid for the layout*/if ((isNull(viewportLayoutPosRow(vp)) &&isNull(viewportLayoutPosCol(vp))) ||isNull(viewportLayout(parent)))fillViewportLocationFromViewport(vp, &vpl);else if (checkPosRowPosCol(vp, parent))calcViewportLocationFromLayout(viewportLayoutPosRow(vp),viewportLayoutPosCol(vp),parent,&vpl);}/* NOTE that we are not doing a transformLocn here because* we just want locations and dimensions (in INCHES) relative to* the parent, NOT relative to the device.*//* First, convert the location of the viewport into CM*/xINCHES = transformXtoINCHES(vpl.x, 0, parentContext, &parentgc,parentWidthCM, parentHeightCM,dd);yINCHES = transformYtoINCHES(vpl.y, 0, parentContext, &parentgc,parentWidthCM, parentHeightCM,dd);/* Calculate the width and height of the viewport in CM too* so that any viewports within this one can do transformations*/vpWidthCM = transformWidthtoINCHES(vpl.width, 0, parentContext, &parentgc,parentWidthCM, parentHeightCM,dd)*2.54;vpHeightCM = transformHeighttoINCHES(vpl.height, 0, parentContext,&parentgc,parentWidthCM,parentHeightCM,dd)*2.54;/* Fall out if location or size are non-finite*/if (!R_FINITE(xINCHES) ||!R_FINITE(yINCHES) ||!R_FINITE(vpWidthCM) ||!R_FINITE(vpHeightCM))error(_("Non-finite location and/or size for viewport"));/* Determine justification required*/justification(vpWidthCM, vpHeightCM, vpl.hjust, vpl.vjust,&xadj, &yadj);/* Next, produce the transformation to add the location of* the viewport to the location.*//* Produce transform for this viewport*/translation(xINCHES, yINCHES, thisLocation);if (viewportAngle(vp) != 0)rotation(viewportAngle(vp), thisRotation);elseidentity(thisRotation);translation(xadj/2.54, yadj/2.54, thisJustification);/* Position relative to origin of rotation THEN rotate.*/multiply(thisJustification, thisRotation, tempTransform);/* Translate to bottom-left corner.*/multiply(tempTransform, thisLocation, thisTransform);/* Combine with parent's transform*/multiply(thisTransform, parentTransform, transform);/* Sum up the rotation angles*/rotationAngle = parentAngle + viewportAngle(vp);/* Finally, allocate the rows and columns for this viewport's* layout if it has one*/if (!isNull(viewportLayout(vp))) {fillViewportContextFromViewport(vp, &vpc);gcontextFromViewport(vp, &gc, dd);calcViewportLayout(vp, vpWidthCM, vpHeightCM, vpc, &gc, dd);}/* Record all of the answers in the viewport* (the layout calculations are done within calcViewportLayout)*/PROTECT(currentWidthCM = ScalarReal(vpWidthCM));PROTECT(currentHeightCM = ScalarReal(vpHeightCM));PROTECT(currentRotation = ScalarReal(rotationAngle));PROTECT(currentTransform = allocMatrix(REALSXP, 3, 3));for (i=0; i<3; i++)for (j=0; j<3; j++)REAL(currentTransform)[i + 3*j] = transform[i][j];SET_VECTOR_ELT(vp, PVP_WIDTHCM, currentWidthCM);SET_VECTOR_ELT(vp, PVP_HEIGHTCM, currentHeightCM);SET_VECTOR_ELT(vp, PVP_ROTATION, currentRotation);SET_VECTOR_ELT(vp, PVP_TRANS, currentTransform);UNPROTECT(4);}void initVP(pGEDevDesc dd){SEXP vpfnname, vpfn, vp;SEXP xscale, yscale;SEXP currentgp = gridStateElement(dd, GSS_GPAR);SEXP gsd = (SEXP) dd->gesd[gridRegisterIndex]->systemSpecific;PROTECT(vpfnname = findFun(install("grid.top.level.vp"), R_gridEvalEnv));PROTECT(vpfn = lang1(vpfnname));PROTECT(vp = eval(vpfn, R_GlobalEnv));/** Set the "native" scale of the top viewport to be the* natural device coordinate system (e.g., points in* postscript, pixels in X11, ...)*/PROTECT(xscale = allocVector(REALSXP, 2));REAL(xscale)[0] = dd->dev->left;REAL(xscale)[1] = dd->dev->right;SET_VECTOR_ELT(vp, VP_XSCALE, xscale);PROTECT(yscale = allocVector(REALSXP, 2));REAL(yscale)[0] = dd->dev->bottom;REAL(yscale)[1] = dd->dev->top;SET_VECTOR_ELT(vp, VP_YSCALE, yscale);SET_VECTOR_ELT(vp, PVP_GPAR, currentgp);vp = doSetViewport(vp, TRUE, TRUE, dd);SET_VECTOR_ELT(gsd, GSS_VP, vp);UNPROTECT(5);}