Beispiel #1
0
Rboolean checkPosRowPosCol(SEXP vp, SEXP parent) 
{
    int ncol = layoutNCol(viewportLayout(parent));
    int nrow = layoutNRow(viewportLayout(parent));
    if (!isNull(viewportLayoutPosRow(vp)) &&
	(INTEGER(viewportLayoutPosRow(vp))[0] < 1 ||
	 INTEGER(viewportLayoutPosRow(vp))[1] > nrow))
        error(_("invalid 'layout.pos.row'"));
    if (!isNull(viewportLayoutPosCol(vp)) &&
	(INTEGER(viewportLayoutPosCol(vp))[0] < 1 ||
	 INTEGER(viewportLayoutPosCol(vp))[1] > ncol))
        error(_("invalid 'layout.pos.col'"));
    return TRUE;
}
Beispiel #2
0
/* 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);
    else
	identity(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);
}