diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java index 7134c501c43cd9307bc0493796c3d8e3b26026ae..ec20b0d423e149c5f6586dab80eeee192e20bdad 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java @@ -107,7 +107,7 @@ class DoSetViewPort extends RBaseNode { } } - UnitConversionContext conversionCtx = new UnitConversionContext(parentSize, parentContext, drawingContext); + UnitConversionContext conversionCtx = new UnitConversionContext(parentSize, parentContext, device, drawingContext); double xInches = unitsToInches.convertX(vpl.x, 0, conversionCtx); double yInches = unitsToInches.convertY(vpl.y, 0, conversionCtx); double width = unitsToInches.convertWidth(vpl.width, 0, conversionCtx); @@ -141,7 +141,7 @@ class DoSetViewPort extends RBaseNode { if (!isNull(viewPort.getDataAt(ViewPort.VP_LAYOUT))) { ViewPortContext vpCtx = vpContextFromVP.execute(viewPort); DrawingContext drawingCtx = GPar.asDrawingContext(asList(viewPort.getDataAt(ViewPort.PVP_GPAR))); - calcViewPortLayout(viewPort, new Size(width, height), vpCtx, drawingCtx); + calcViewPortLayout(viewPort, new Size(width, height), vpCtx, device, drawingCtx); } Object[] viewPortData = viewPort.getDataWithoutCopying(); @@ -151,13 +151,13 @@ class DoSetViewPort extends RBaseNode { viewPortData[ViewPort.PVP_TRANS] = RDataFactory.createDoubleVector(flatten(transform), RDataFactory.COMPLETE_VECTOR, new int[]{3, 3}); } - private void calcViewPortLayout(RList viewPort, Size size, ViewPortContext parentVPCtx, DrawingContext drawingCtx) { + private void calcViewPortLayout(RList viewPort, Size size, ViewPortContext parentVPCtx, GridDevice device, DrawingContext drawingCtx) { LayoutSize layoutSize = LayoutSize.fromViewPort(viewPort); double[] npcWidths = new double[layoutSize.ncol]; double[] npcHeights = new double[layoutSize.nrow]; boolean[] relativeWidths = new boolean[layoutSize.ncol]; boolean[] relativeHeights = new boolean[layoutSize.nrow]; - UnitConversionContext conversionCtx = new UnitConversionContext(size, parentVPCtx, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(size, parentVPCtx, device, drawingCtx); // For both dimensions we find out which units are other than "null" for those we can // immediately calculate the physical size in npcWidth/npcHeights. The reducedWidth/Height @@ -178,8 +178,8 @@ class DoSetViewPort extends RBaseNode { int respect = RRuntime.asInteger(layoutAsList.getDataAt(ViewPort.LAYOUT_VRESPECT)); int[] layoutRespectMat = ((RAbstractIntVector) layoutAsList.getDataAt(ViewPort.LAYOUT_MRESPECT)).materialize().getDataWithoutCopying(); if ((reducedHeight > 0 || reducedWidth > 0) && respect > 0) { - double sumRelWidth = sumRelativeDimension(layoutSize, layoutWidths, relativeWidths, parentVPCtx, drawingCtx, true); - double sumRelHeight = sumRelativeDimension(layoutSize, layoutHeights, relativeHeights, parentVPCtx, drawingCtx, false); + double sumRelWidth = sumRelativeDimension(layoutSize, layoutWidths, relativeWidths, parentVPCtx, device, drawingCtx, true); + double sumRelHeight = sumRelativeDimension(layoutSize, layoutHeights, relativeHeights, parentVPCtx, device, drawingCtx, false); double tempWidth = reducedWidth; double tempHeight = reducedHeight; double denom; @@ -233,8 +233,8 @@ class DoSetViewPort extends RBaseNode { } // Secondly, allocate remaining relative widths and heights in the remaining space - allocateRelativeDim(layoutSize, layoutWidths, npcWidths, relativeWidths, reducedWidth, respect, layoutRespectMat, drawingCtx, parentVPCtx, true); - allocateRelativeDim(layoutSize, layoutHeights, npcHeights, relativeHeights, reducedHeight, respect, layoutRespectMat, drawingCtx, parentVPCtx, false); + allocateRelativeDim(layoutSize, layoutWidths, npcWidths, relativeWidths, reducedWidth, respect, layoutRespectMat, device, drawingCtx, parentVPCtx, true); + allocateRelativeDim(layoutSize, layoutHeights, npcHeights, relativeHeights, reducedHeight, respect, layoutRespectMat, device, drawingCtx, parentVPCtx, false); // Create the result Object[] vpData = viewPort.getDataWithoutCopying(); @@ -243,8 +243,8 @@ class DoSetViewPort extends RBaseNode { } private void allocateRelativeDim(LayoutSize layoutSize, RAbstractContainer layoutItems, double[] npcItems, boolean[] relativeItems, double reducedDim, int respect, int[] layoutRespectMat, - DrawingContext drawingCtx, ViewPortContext parentVPCtx, boolean isWidth) { - UnitConversionContext layoutModeCtx = new UnitConversionContext(new Size(0, 0), parentVPCtx, drawingCtx, 1, 0); + GridDevice device, DrawingContext drawingCtx, ViewPortContext parentVPCtx, boolean isWidth) { + UnitConversionContext layoutModeCtx = new UnitConversionContext(new Size(0, 0), parentVPCtx, device, drawingCtx, 1, 0); double totalUnrespectedSize = 0; if (reducedDim > 0) { for (int i = 0; i < layoutSize.ncol; i++) { @@ -293,8 +293,9 @@ class DoSetViewPort extends RBaseNode { return false; } - private double sumRelativeDimension(LayoutSize layoutSize, RAbstractContainer layoutItems, boolean[] relativeItems, ViewPortContext parentVPCtx, DrawingContext drawingCtx, boolean isWidth) { - UnitConversionContext layoutModeCtx = new UnitConversionContext(new Size(0, 0), parentVPCtx, drawingCtx, 0, 1); + private double sumRelativeDimension(LayoutSize layoutSize, RAbstractContainer layoutItems, boolean[] relativeItems, ViewPortContext parentVPCtx, GridDevice device, DrawingContext drawingCtx, + boolean isWidth) { + UnitConversionContext layoutModeCtx = new UnitConversionContext(new Size(0, 0), parentVPCtx, device, drawingCtx, 0, 1); double totalWidth = 0; for (int i = 0; i < layoutSize.ncol; i++) { if (relativeItems[i]) { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridLinesNode.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridLinesNode.java new file mode 100644 index 0000000000000000000000000000000000000000..695175e7c26b926c6ce2c47c78c524cd69208b63 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridLinesNode.java @@ -0,0 +1,119 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (C) 2001-3 Paul Murrell + * Copyright (c) 1998-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asIntVector; + +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; +import com.oracle.truffle.r.library.fastrGrid.ViewPortContext.VPContextFromVPNode; +import com.oracle.truffle.r.library.fastrGrid.ViewPortTransform.GetViewPortTransformNode; +import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; +import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +/** + * Common code shared between {@code L_lines} and {@code L_polygon} externals. Both draw a series of + * lines, but only the later connects the last point with the first point and only the former draws + * arrows (which is not implemented yet). Note: the third parameter contains sequences + * {@code 1:max(length(x),length(y))}, where the 'length' dispatches to S3 method giving us unit + * length like {@link com.oracle.truffle.r.library.fastrGrid.Unit.UnitLengthNode}. This means that + * we do not have to use the {@link com.oracle.truffle.r.library.fastrGrid.Unit.UnitLengthNode} to + * get the length. + */ +public abstract class GridLinesNode extends Node { + public static GridLinesNode createLines() { + return new GridLinesImpl(); + } + + public static GridLinesNode createPolygon() { + return new GridLinesPolygon(); + } + + @Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode(); + @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); + @Child private VPContextFromVPNode vpContextFromVP = new VPContextFromVPNode(); + + void execute(RAbstractVector x, RAbstractVector y, RList lengths) { + GridContext ctx = GridContext.getContext(); + GridDevice dev = ctx.getCurrentDevice(); + + RList currentVP = ctx.getGridState().getViewPort(); + DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); + ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP); + ViewPortContext vpContext = vpContextFromVP.execute(currentVP); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); + + // Convert the list of vectors of indexes to type-safe array and calculate the max length of + // the vectors. + RAbstractIntVector[] unitIndexesList = new RAbstractIntVector[lengths.getLength()]; + int maxIndexesLen = 0; + for (int i = 0; i < lengths.getLength(); i++) { + unitIndexesList[i] = asIntVector(lengths.getDataAt(i)); + maxIndexesLen = Math.max(maxIndexesLen, unitIndexesList[i].getLength()); + } + + double[] xx = new double[maxIndexesLen + 1]; // plus one for polygons + double[] yy = new double[maxIndexesLen + 1]; + for (RAbstractIntVector unitIndexes : unitIndexesList) { + boolean oldIsFinite = false; + int start = 0; + int unitIndexesLen = unitIndexes.getLength(); + // following loop finds series of valid points (finite x and y values) and draws each + // such series as a polyline + for (int i = 0; i < unitIndexesLen; i++) { + int unitIndex = unitIndexes.getDataAt(i) - 1; // coverting R's 1-based index + Point origLoc = Point.fromUnits(unitToInches, x, y, unitIndex, conversionCtx); + Point loc = TransformMatrix.transLocation(origLoc, vpTransform.transform); + xx[i] = loc.x; + yy[i] = loc.y; + boolean currIsFinite = loc.isFinite(); + boolean lastIter = i == (unitIndexesLen - 1); + if (currIsFinite && !oldIsFinite) { + start = i; // start a new series + } else if (oldIsFinite && (!currIsFinite || lastIter)) { + // draw the previous points series because + // (1) current is invalid point. Note: in (one of) the next iteration(s), the + // oldIsFinite will be false and we will update the start and start a new series + // (2) we are in the last iteration + if (lastIter || i - start > 1) { + // we draw only if the previous series of points was at least of length 3 or + // it's last iteration. This seems slightly weird, but that's how GnuR seems + // to work + drawPolylines(dev, drawingCtx, yy, xx, start, (i - start) + 1); + } + } + oldIsFinite = currIsFinite; + } + } + } + + abstract void drawPolylines(GridDevice dev, DrawingContext drawingCtx, double[] yy, double[] xx, int start, int length); + + private static final class GridLinesImpl extends GridLinesNode { + @Override + void drawPolylines(GridDevice dev, DrawingContext drawingCtx, double[] yy, double[] xx, int start, int length) { + dev.drawPolyLines(drawingCtx, xx, yy, start, length); + } + } + + private static final class GridLinesPolygon extends GridLinesNode { + @Override + void drawPolylines(GridDevice dev, DrawingContext drawingCtx, double[] yy, double[] xx, int start, int length) { + xx[start + length] = xx[start]; + yy[start + length] = yy[start]; + dev.drawPolyLines(drawingCtx, xx, yy, start, length + 1); + } + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridTextNode.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridTextNode.java index 8fbbe300af3a8ffa4d06306f45c38402604c92dc..13e52dfc66885702da15fcee914f19de9291ce4c 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridTextNode.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridTextNode.java @@ -97,7 +97,7 @@ public final class GridTextNode extends RBaseNode { DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP); ViewPortContext vpContext = vpContextFromVP.execute(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); int length = GridUtils.maxLength(unitLength, x, y); diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridUtils.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridUtils.java index 0de2442c7b6c55ce38242daec0a3d6be4c9eefdf..1b7ff9197a90621615f2628037cd26df56593c6b 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridUtils.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridUtils.java @@ -21,6 +21,7 @@ import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; @@ -89,6 +90,16 @@ final class GridUtils { return false; } + static RList asListOrNull(Object value) { + if (value == null || value == RNull.instance) { + return null; + } + if (!(value instanceof RList)) { + throw RError.error(RError.NO_CALLER, Message.GENERIC, "Expected list"); + } + return (RList) value; + } + static RList asList(Object value) { if (!(value instanceof RList)) { throw RError.error(RError.NO_CALLER, Message.GENERIC, "Expected list"); diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LCircle.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LCircle.java index 60448d3fa71cfa21343359505fc0c9a635a4a0be..c5262bd3ff8b07d7bf2db368fb117cd930dcad56 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LCircle.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LCircle.java @@ -51,7 +51,7 @@ public abstract class LCircle extends RExternalBuiltinNode.Arg3 { DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP); ViewPortContext vpContext = vpContextFromVP.execute(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); int length = GridUtils.maxLength(unitLength, xVec, yVec, radiusVec); for (int i = 0; i < length; i++) { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LConvert.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LConvert.java index 04f325f4853d495702f376c79e16f2c606e33fa4..3703c83baa9d98587184cef5cc43f1dae7d81b64 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LConvert.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LConvert.java @@ -19,6 +19,7 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVect import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.library.fastrGrid.Unit.AxisOrDimension; import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; import com.oracle.truffle.r.library.fastrGrid.ViewPortContext.VPContextFromVPNode; import com.oracle.truffle.r.library.fastrGrid.ViewPortTransform.GetViewPortTransformNode; @@ -59,7 +60,7 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 { DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP); ViewPortContext vpContext = vpContextFromVP.execute(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); int length = unitLength.execute(units); double[] result = new double[length]; @@ -69,15 +70,11 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 { for (int i = 0; i < length; i++) { // scalar values used in current iteration - int axisFrom = axisFromVec.getDataAt(i % axisFromVec.getLength()); - int axisTo = axisToVec.getDataAt(i % axisToVec.getLength()); - boolean compatibleAxes = axisFrom == axisTo || - (axisFrom == 0 && axisTo == 2) || - (axisFrom == 2 && axisTo == 0) || - (axisFrom == 1 && axisTo == 3) || - (axisFrom == 3 && axisTo == 1); - double vpToSize = isXAxis(axisTo) ? vpTransform.size.getWidth() : vpTransform.size.getHeight(); - double vpFromSize = isXAxis(axisFrom) ? vpTransform.size.getWidth() : vpTransform.size.getHeight(); + AxisOrDimension axisFrom = AxisOrDimension.fromInt(axisFromVec.getDataAt(i % axisFromVec.getLength())); + AxisOrDimension axisTo = AxisOrDimension.fromInt(axisToVec.getDataAt(i % axisToVec.getLength())); + boolean compatibleAxes = axisFrom.isHorizontal() == axisTo.isHorizontal(); + double vpToSize = axisTo.isHorizontal() ? vpTransform.size.getWidth() : vpTransform.size.getHeight(); + double vpFromSize = axisFrom.isHorizontal() ? vpTransform.size.getWidth() : vpTransform.size.getHeight(); int unitTo = unitToVec.getDataAt(i % unitToVec.getLength()); int fromUnitId = unitIds.getDataAt(i % unitIds.getLength()); @@ -94,26 +91,26 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 { result[i] = transformFromNPC(tranfromToNPC(fromValue, fromUnitId, axisFrom, vpContext), unitTo, axisTo, vpContext); } else { double inches = toInches(units, i, axisFrom, conversionCtx); - boolean isX = isXAxis(axisTo); + boolean isX = axisTo.isHorizontal(); double scalemin = isX ? vpContext.xscalemin : vpContext.yscalemin; double scalemax = isX ? vpContext.xscalemax : vpContext.yscalemax; - result[i] = Unit.convertFromInches(inches, unitTo, vpToSize, scalemin, scalemax, isDimension(axisTo), drawingCtx); + result[i] = Unit.convertFromInches(inches, unitTo, vpToSize, scalemin, scalemax, axisTo.isDimension(), drawingCtx); } } return RDataFactory.createDoubleVector(result, RDataFactory.COMPLETE_VECTOR); } - private double toInches(RAbstractVector units, int index, int axisFrom, UnitConversionContext conversionCtx) { + private double toInches(RAbstractVector units, int index, AxisOrDimension axisFrom, UnitConversionContext conversionCtx) { double inches; - if (isXAxis(axisFrom)) { - if (isDimension(axisFrom)) { + if (axisFrom.isHorizontal()) { + if (axisFrom.isDimension()) { inches = unitToInches.convertWidth(units, index, conversionCtx); } else { inches = unitToInches.convertX(units, index, conversionCtx); } } else { - if (isDimension(axisFrom)) { + if (axisFrom.isDimension()) { inches = unitToInches.convertHeight(units, index, conversionCtx); } else { inches = unitToInches.convertY(units, index, conversionCtx); @@ -122,30 +119,30 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 { return inches; } - private static double tranfromToNPC(double value, int fromUnitId, int axisFrom, ViewPortContext vpContext) { + private static double tranfromToNPC(double value, int fromUnitId, AxisOrDimension axisFrom, ViewPortContext vpContext) { if (fromUnitId == Unit.NPC) { return value; } assert fromUnitId == Unit.NATIVE : "relative conversion should only happen when units are NPC or NATIVE"; - boolean isX = isXAxis(axisFrom); + boolean isX = axisFrom.isHorizontal(); double min = isX ? vpContext.xscalemin : vpContext.yscalemin; double max = isX ? vpContext.xscalemax : vpContext.yscalemax; - if (isDimension(axisFrom)) { + if (axisFrom.isDimension()) { return value / (max - min); } else { return (value - min) / (max - min); } } - private static double transformFromNPC(double value, int unitTo, int axisTo, ViewPortContext vpContext) { + private static double transformFromNPC(double value, int unitTo, AxisOrDimension axisTo, ViewPortContext vpContext) { if (unitTo == Unit.NPC) { return value; } assert unitTo == Unit.NATIVE : "relative conversion should only happen when units are NPC or NATIVE"; - boolean isX = isXAxis(axisTo); + boolean isX = axisTo.isHorizontal(); double min = isX ? vpContext.xscalemin : vpContext.yscalemin; double max = isX ? vpContext.xscalemax : vpContext.yscalemax; - if (isDimension(axisTo)) { + if (axisTo.isDimension()) { return value * (max - min); } else { return min + value * (max - min); @@ -157,13 +154,4 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 { private static boolean isRelative(int unitId) { return unitId == NPC || unitId == NATIVE; } - - // what = 0 means x, 1 means y, 2 means width, 3 means height - private static boolean isXAxis(int what) { - return what % 2 == 0; - } - - private static boolean isDimension(int what) { - return what >= 2; - } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LLines.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LLines.java index 0f429081b6cc99c8f4a9cd88e349e107acf55af6..de270734525fa83add0e666a969031c40c1ec98d 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LLines.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LLines.java @@ -1,40 +1,37 @@ /* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright (C) 2001-3 Paul Murrell - * Copyright (c) 1998-2013, The R Core Team - * Copyright (c) 2017, Oracle and/or its affiliates + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. * - * All rights reserved. + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. */ package com.oracle.truffle.r.library.fastrGrid; -import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asIntVector; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; -import com.oracle.truffle.r.library.fastrGrid.ViewPortContext.VPContextFromVPNode; -import com.oracle.truffle.r.library.fastrGrid.ViewPortTransform.GetViewPortTransformNode; -import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; -import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; -/** - * Note: the third parameter contains sequences {@code 1:max(length(x),length(y))}, where the - * 'length' dispatches to S3 method giving us unit length like - * {@link com.oracle.truffle.r.library.fastrGrid.Unit.UnitLengthNode}. - */ public abstract class LLines extends RExternalBuiltinNode.Arg4 { - @Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode(); - @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); - @Child private VPContextFromVPNode vpContextFromVP = new VPContextFromVPNode(); + @Child private GridLinesNode gridLinesNode = GridLinesNode.createLines(); static { Casts casts = new Casts(LLines.class); @@ -48,59 +45,9 @@ public abstract class LLines extends RExternalBuiltinNode.Arg4 { } @Specialization - Object doLines(RAbstractVector x, RAbstractVector y, RList lengths, Object arrowIgnored) { - GridContext ctx = GridContext.getContext(); - GridDevice dev = ctx.getCurrentDevice(); - - RList currentVP = ctx.getGridState().getViewPort(); - DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); - ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP); - ViewPortContext vpContext = vpContextFromVP.execute(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, drawingCtx); - - // Convert the list of vectors of indexes to type-safe array and calculate the max length of - // the vectors. - RAbstractIntVector[] unitIndexesList = new RAbstractIntVector[lengths.getLength()]; - int maxIndexesLen = 0; - for (int i = 0; i < lengths.getLength(); i++) { - unitIndexesList[i] = asIntVector(lengths.getDataAt(i)); - maxIndexesLen = Math.max(maxIndexesLen, unitIndexesList[i].getLength()); - } - - double[] xx = new double[maxIndexesLen]; - double[] yy = new double[maxIndexesLen]; - for (RAbstractIntVector unitIndexes : unitIndexesList) { - boolean oldIsFinite = false; - int start = 0; - int unitIndexesLen = unitIndexes.getLength(); - // following loop finds series of valid points (finite x and y values) and draws each - // such series as a polyline - for (int i = 0; i < unitIndexesLen; i++) { - int unitIndex = unitIndexes.getDataAt(i) - 1; // coverting R's 1-based index - Point origLoc = Point.fromUnits(unitToInches, x, y, unitIndex, conversionCtx); - Point loc = TransformMatrix.transLocation(origLoc, vpTransform.transform); - xx[i] = loc.x; - yy[i] = loc.y; - boolean currIsFinite = loc.isFinite(); - boolean lastIter = i == (unitIndexesLen - 1); - if (currIsFinite && !oldIsFinite) { - start = i; // start a new series - } else if (oldIsFinite && (!currIsFinite || lastIter)) { - // draw the previous points series because - // (1) current is invalid point. Note: in (one of) the next iteration(s), the - // oldIsFinite will be false and we will update the start and start a new series - // (2) we are in the last iteration - if (lastIter || i - start > 1) { - // we draw only if the previous series of points was at least of length 3 or - // it's last iteration. This seems slightly weird, but that's how GnuR seems - // to work - dev.drawPolyLines(drawingCtx, xx, yy, start, (i - start) + 1); - } - } - oldIsFinite = currIsFinite; - } - } - + Object doLines(RAbstractVector x, RAbstractVector y, RList lengths, @SuppressWarnings("unused") Object arrowIgnored) { + // TODO: implement arrows + gridLinesNode.execute(x, y, lengths); return RNull.instance; } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java index 040c72660f91850bbe93a56306fde72aff4c0345..67604044ec4ba6305f9429280680d2daf7e8d8ed 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java @@ -68,7 +68,7 @@ public abstract class LPoints extends RExternalBuiltinNode.Arg4 { double cex = GPar.getCex(gpar); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP); ViewPortContext vpContext = vpContextFromVP.execute(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); // Note: unlike in other drawing primitives, we only consider length of x int length = unitLength.execute(xVec); diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPolygon.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPolygon.java new file mode 100644 index 0000000000000000000000000000000000000000..8d4343e9ab8267fb2732e90a6fa6568f8bb14376 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPolygon.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; + +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +public abstract class LPolygon extends RExternalBuiltinNode.Arg3 { + @Child private GridLinesNode gridLinesNode = GridLinesNode.createPolygon(); + + static { + Casts casts = new Casts(LPolygon.class); + casts.arg(0).mustBe(abstractVectorValue()); + casts.arg(1).mustBe(abstractVectorValue()); + casts.arg(2).mustBe(RList.class); + } + + public static LPolygon create() { + return LPolygonNodeGen.create(); + } + + @Specialization + Object doLines(RAbstractVector x, RAbstractVector y, RList lengths) { + gridLinesNode.execute(x, y, lengths); + return RNull.instance; + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java index a7557972f356b4ffb2222996a75a3078ce376da0..e79c9dcd67cd90dba367f726de114c2dfb310ad3 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java @@ -56,7 +56,7 @@ public abstract class LRect extends RExternalBuiltinNode.Arg6 { DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP); ViewPortContext vpContext = vpContextFromVP.execute(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); int length = GridUtils.maxLength(unitLength, xVec, yVec, wVec, hVec); for (int i = 0; i < length; i++) { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LSegments.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LSegments.java index 3aca3f3afc573ff7ecbffdd36790bb2c506d18cf..426234d0fbf5b1a9ae978f84f4d4ffc45a3731ad 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LSegments.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LSegments.java @@ -55,7 +55,7 @@ public abstract class LSegments extends RExternalBuiltinNode.Arg5 { DrawingContext drawingCtx = GPar.asDrawingContext(ctx.getGridState().getGpar()); ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP); ViewPortContext vpContext = vpContextFromVP.execute(currentVP); - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, drawingCtx); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, drawingCtx); int length = GridUtils.maxLength(unitLength, x0, y0, x1, y1); double[] xx = new double[2]; diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Unit.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Unit.java index 06952fdba756c381d8ce11f23b25e645625e2fa3..a9dd76013ca467a1189d3bcefbdad1c519d3c010 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Unit.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Unit.java @@ -15,6 +15,7 @@ import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asAbstractContain import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asDouble; import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asIntVector; import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asList; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asListOrNull; import static com.oracle.truffle.r.library.fastrGrid.GridUtils.fmax; import static com.oracle.truffle.r.library.fastrGrid.GridUtils.fmin; import static com.oracle.truffle.r.library.fastrGrid.GridUtils.hasRClass; @@ -34,6 +35,7 @@ import com.oracle.truffle.r.library.fastrGrid.UnitFactory.UnitToInchesNodeGen; import com.oracle.truffle.r.library.fastrGrid.ViewPortContext.VPContextFromVPNode; import com.oracle.truffle.r.library.fastrGrid.ViewPortTransform.GetViewPortTransformNode; import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; +import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode; import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode; import com.oracle.truffle.r.nodes.unary.CastNode; @@ -177,13 +179,14 @@ public class Unit { } } - private static double convertToInches(double value, int unitId, double vpSize, double scalemin, double scalemax, int nullLMode, int nullAMode, boolean isDimension, DrawingContext drawingCtx) { + private static double convertToInches(double value, int unitId, RList data, UnitConversionContext ctx, AxisOrDimension axisOrDim) { + double vpSize = ctx.getViewPortSize(axisOrDim); switch (unitId) { case INCHES: return value; case NATIVE: - double tmp = isDimension ? value : (value - scalemin); - return (tmp / (scalemax - scalemin)) * vpSize; + double tmp = axisOrDim.isDimension() ? value : (value - ctx.getScaleMin(axisOrDim)); + return (tmp / (ctx.getScaleMax(axisOrDim) - ctx.getScaleMin(axisOrDim))) * vpSize; case NPC: return value * vpSize; case POINTS: @@ -194,12 +197,18 @@ public class Unit { return value / (CM_IN_INCH * 10); case CHAR: case MYCHAR: - return (value * drawingCtx.getFontSize()) / INCH_TO_POINTS_FACTOR; + return (value * ctx.drawingContext.getFontSize()) / INCH_TO_POINTS_FACTOR; case LINES: case MYLINES: - return (value * drawingCtx.getFontSize() * drawingCtx.getLineHeight()) / INCH_TO_POINTS_FACTOR; + return (value * ctx.drawingContext.getFontSize() * ctx.drawingContext.getLineHeight()) / INCH_TO_POINTS_FACTOR; + case STRINGWIDTH: + case MYSTRINGWIDTH: + return ctx.device.getStringWidth(ctx.drawingContext, RRuntime.asString(data.getDataAt(0))); + case STRINGHEIGHT: + case MYSTRINGHEIGHT: + return ctx.device.getStringHeight(ctx.drawingContext, RRuntime.asString(data.getDataAt(0))); case NULL: - return evaluateNullUnit(value, vpSize, nullLMode, nullAMode); + return evaluateNullUnit(value, vpSize, ctx.nullLayoutMode, ctx.nullArithmeticMode); default: throw RInternalError.unimplemented("unit type " + unitId + " in convertToInches"); } @@ -387,6 +396,33 @@ public class Unit { } } + /** + * Used to discriminate between x axis, y axis, width, and height when doing unit conversions. + * The order should be the same as used in e.g. {@code L_convert}, which is 0 means x, 1 means + * y, 2 means width, 3 means height. + */ + public enum AxisOrDimension { + X, + Y, + WIDTH, + HEIGHT; + + private static final AxisOrDimension[] enumValues = values(); + + static AxisOrDimension fromInt(int value) { + assert value >= 0 && value < 4; + return enumValues[value]; + } + + public boolean isHorizontal() { + return this == X || this == WIDTH; + } + + public boolean isDimension() { + return this == WIDTH || this == HEIGHT; + } + } + /** * Wraps the data necessary for converting a unit to another unit. Note: {@code nullLMode} and * {@code nullAMode} is only used for converting 'NULL' units and is only explicitly set when @@ -397,20 +433,34 @@ public class Unit { public final Size viewPortSize; public final ViewPortContext viewPortContext; public final DrawingContext drawingContext; + public final GridDevice device; public final int nullLayoutMode; public final int nullArithmeticMode; - public UnitConversionContext(Size viewPortSize, ViewPortContext viewPortContext, DrawingContext drawingContext) { - this(viewPortSize, viewPortContext, drawingContext, 0, 0); + public UnitConversionContext(Size viewPortSize, ViewPortContext viewPortContext, GridDevice device, DrawingContext drawingContext) { + this(viewPortSize, viewPortContext, device, drawingContext, 0, 0); } - public UnitConversionContext(Size viewPortSize, ViewPortContext viewPortContext, DrawingContext drawingContext, int nullLMode, int nullAMode) { + public UnitConversionContext(Size viewPortSize, ViewPortContext viewPortContext, GridDevice device, DrawingContext drawingContext, int nullLMode, int nullAMode) { this.viewPortSize = viewPortSize; this.viewPortContext = viewPortContext; + this.device = device; this.drawingContext = drawingContext; this.nullLayoutMode = nullLMode; this.nullArithmeticMode = nullAMode; } + + public double getViewPortSize(AxisOrDimension forAxisOrDim) { + return forAxisOrDim.isHorizontal() ? viewPortSize.getWidth() : viewPortSize.getHeight(); + } + + public double getScaleMin(AxisOrDimension forAxisOrDim) { + return forAxisOrDim.isHorizontal() ? viewPortContext.xscalemin : viewPortContext.yscalemin; + } + + public double getScaleMax(AxisOrDimension forAxisOrDim) { + return forAxisOrDim.isHorizontal() ? viewPortContext.xscalemax : viewPortContext.yscalemax; + } } /** @@ -425,34 +475,29 @@ public class Unit { } public double convertX(RAbstractContainer vector, int index, UnitConversionContext ctx) { - return execute(vector, index, ctx.viewPortSize.getWidth(), ctx.viewPortContext.xscalemin, ctx.viewPortContext.xscalemax, ctx.nullLayoutMode, ctx.nullArithmeticMode, false, - ctx.drawingContext); + return execute(vector, index, ctx, AxisOrDimension.X); } public double convertY(RAbstractContainer vector, int index, UnitConversionContext ctx) { - return execute(vector, index, ctx.viewPortSize.getHeight(), ctx.viewPortContext.yscalemin, ctx.viewPortContext.yscalemax, ctx.nullLayoutMode, ctx.nullArithmeticMode, false, - ctx.drawingContext); + return execute(vector, index, ctx, AxisOrDimension.Y); } public double convertWidth(RAbstractContainer vector, int index, UnitConversionContext ctx) { - return execute(vector, index, ctx.viewPortSize.getWidth(), ctx.viewPortContext.xscalemin, ctx.viewPortContext.xscalemax, ctx.nullLayoutMode, ctx.nullArithmeticMode, true, - ctx.drawingContext); + return execute(vector, index, ctx, AxisOrDimension.WIDTH); } public double convertHeight(RAbstractContainer vector, int index, UnitConversionContext ctx) { - return execute(vector, index, ctx.viewPortSize.getHeight(), ctx.viewPortContext.yscalemin, ctx.viewPortContext.yscalemax, ctx.nullLayoutMode, ctx.nullArithmeticMode, true, - ctx.drawingContext); + return execute(vector, index, ctx, AxisOrDimension.HEIGHT); } public double convertDimension(RAbstractContainer vector, int index, UnitConversionContext ctx, boolean isWidth) { return isWidth ? convertWidth(vector, index, ctx) : convertHeight(vector, index, ctx); } - public abstract double execute(RAbstractContainer vector, int index, double vpSize, double scalemin, double scalemax, int nullLMode, int nullAMode, boolean isDimension, - DrawingContext drawingCtx); + public abstract double execute(RAbstractContainer vector, int index, UnitConversionContext ctx, AxisOrDimension axisOrDim); @Specialization(guards = "isSimple(value)") - double doNormal(RAbstractContainer value, int index, double vpSize, double scalemin, double scalemax, int nullLMode, int nullAMode, boolean isDimension, DrawingContext drawingCtx, + double doNormal(RAbstractContainer value, int index, UnitConversionContext ctx, AxisOrDimension axisOrDim, @Cached("createAsDoubleCast()") CastNode asDoubleCast, @Cached("create()") UnitUnitIdNode unitUnitId) { int unitId = unitUnitId.execute(value, index); @@ -460,29 +505,27 @@ public class Unit { double scalarValue = vector.getDataAt(index % vector.getLength()); if (isGrobUnit(unitId)) { RList grobList = asList(vector.getAttr("data")); - return grobUnitToInches.execute(scalarValue, unitId, grobList.getDataAt(index % grobList.getLength()), nullLMode, nullAMode); + return grobUnitToInches.execute(scalarValue, unitId, grobList.getDataAt(index % grobList.getLength()), ctx); } - return convertToInches(scalarValue, unitId, vpSize, scalemin, scalemax, nullLMode, nullAMode, isDimension, drawingCtx); + return convertToInches(scalarValue, unitId, asListOrNull(vector.getAttr("data")), ctx, axisOrDim); } @Specialization(guards = "isUnitList(value)") - double doList(RList value, int index, double vpSize, double scalemin, double scalemax, int nullLMode, int nullAMode, boolean isDimension, DrawingContext drawingCtx, + double doList(RList value, int index, UnitConversionContext ctx, AxisOrDimension axisOrDim, @Cached("create()") UnitToInchesNode recursiveNode) { Object unwrapped = value.getDataAt(index % value.getLength()); if (unwrapped instanceof RAbstractVector) { - return recursiveNode.execute((RAbstractContainer) unwrapped, 0, vpSize, scalemin, scalemax, nullLMode, nullAMode, isDimension, drawingCtx); + return recursiveNode.execute((RAbstractContainer) unwrapped, 0, ctx, axisOrDim); } throw error(Message.GENERIC, "Unexpected unit list with non-vector like element at index " + index); } @Specialization(guards = "isArithmetic(list)") - double doArithmetic(RList list, int index, double vpSize, double scalemin, double scalemax, int nullLMode, int nullAMode, boolean isDimension, DrawingContext drawingCtx, + double doArithmetic(RList list, int index, UnitConversionContext ctx, AxisOrDimension axisOrDim, @Cached("create()") UnitLengthNode unitLengthNode, @Cached("create()") UnitToInchesNode recursiveNode) { ArithmeticUnit expr = ArithmeticUnit.asArithmeticUnit(list); - // Note the catch: newNullAMode is applied only if isDimension == true - BiFunction<RAbstractContainer, Integer, Double> recursive = (x, newNullAMode) -> recursiveNode.execute(x, index, vpSize, scalemin, scalemax, nullLMode, - isDimension ? newNullAMode : nullAMode, isDimension, drawingCtx); + BiFunction<RAbstractContainer, Integer, Double> recursive = (x, newNullAMode) -> recursiveNode.execute(x, index, getNewCtx(ctx, axisOrDim, newNullAMode), axisOrDim); switch (expr.op) { case "+": return recursive.apply(expr.arg1, L_adding) + recursive.apply(expr.arg2, L_adding); @@ -496,11 +539,11 @@ public class Unit { } // must be aggregate operation - int newNullAMode = isDimension ? getNullAMode(expr.op) : nullAMode; + UnitConversionContext newCtx = getNewCtx(ctx, axisOrDim, getNullAMode(expr.op)); int len = unitLengthNode.execute(expr.arg1); double[] values = new double[len]; for (int i = 0; i < len; i++) { - values[i] = recursiveNode.execute(expr.arg1, i, vpSize, scalemin, scalemax, nullLMode, newNullAMode, isDimension, drawingCtx); + values[i] = recursiveNode.execute(expr.arg1, i, newCtx, axisOrDim); } switch (expr.op) { @@ -515,6 +558,12 @@ public class Unit { } } + // Note the catch: newNullAMode is applied only if the axisOrDim is dimension + private static UnitConversionContext getNewCtx(UnitConversionContext ctx, AxisOrDimension axisOrDim, int newNullAMode) { + return new UnitConversionContext(ctx.viewPortSize, ctx.viewPortContext, ctx.device, ctx.drawingContext, ctx.nullLayoutMode, + axisOrDim.isDimension() ? newNullAMode : ctx.nullArithmeticMode); + } + private static int getNullAMode(String op) { switch (op) { case "min": @@ -543,7 +592,7 @@ public class Unit { // transcribed from unit.c function evaluateGrobUnit - public double execute(double value, int unitId, Object grob, int nullLMode, int nullAMode) { + public double execute(double value, int unitId, Object grob, UnitConversionContext conversionCtx) { GridContext ctx = GridContext.getContext(); RList currentVP = ctx.getGridState().getViewPort(); getViewPortTransform.execute(currentVP); @@ -571,10 +620,10 @@ public class Unit { case GROBY: if (unitId == GROBY && isRelativeUnit.execute(unitxy.getDataAt(1), 0)) { double nullUnitValue = pureNullUnitValue((RAbstractContainer) unitxy.getDataAt(1), 0); - result = evaluateNullUnit(nullUnitValue, vpTransform.size.getHeight(), nullLMode, nullAMode); + result = evaluateNullUnit(nullUnitValue, vpTransform.size.getHeight(), conversionCtx.nullLayoutMode, conversionCtx.nullArithmeticMode); } else if (isRelativeUnit.execute(unitxy.getDataAt(0), 0)) { double nullUnitValue = pureNullUnitValue((RAbstractContainer) unitxy.getDataAt(0), 0); - result = evaluateNullUnit(nullUnitValue, vpTransform.size.getWidth(), nullLMode, nullAMode); + result = evaluateNullUnit(nullUnitValue, vpTransform.size.getWidth(), conversionCtx.nullLayoutMode, conversionCtx.nullArithmeticMode); } else { throw RInternalError.unimplemented("GrobUnitToInches from unit.c: 610"); } @@ -585,16 +634,16 @@ public class Unit { // Note: GnuR uses equivalent of vpTransform.size.getWidth() even for // GROBHEIGHT, bug? double nullUnitValue = pureNullUnitValue((RAbstractContainer) unitxy.getDataAt(0), 0); - result = evaluateNullUnit(nullUnitValue, vpTransform.size.getWidth(), nullLMode, nullAMode); + result = evaluateNullUnit(nullUnitValue, vpTransform.size.getWidth(), conversionCtx.nullLayoutMode, conversionCtx.nullArithmeticMode); } else { - UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, GPar.asDrawingContext(currentGP)); + UnitConversionContext newConversionCtx = new UnitConversionContext(vpTransform.size, vpContext, conversionCtx.device, GPar.asDrawingContext(currentGP)); initUnitToInchesNode(); if (unitId == GROBWIDTH) { - result = unitToInchesNode.convertWidth((RAbstractContainer) unitxy.getDataAt(0), 0, conversionCtx); + result = unitToInchesNode.convertWidth((RAbstractContainer) unitxy.getDataAt(0), 0, newConversionCtx); } else { // Note: GnuR uses height transform for both grobascent, grobdescent and // for height - result = unitToInchesNode.convertHeight((RAbstractContainer) unitxy.getDataAt(0), 0, conversionCtx); + result = unitToInchesNode.convertHeight((RAbstractContainer) unitxy.getDataAt(0), 0, newConversionCtx); } } break; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java index 6b0b5d88beed9b7238b8802637835e00132d6dcf..ba396e0f39fc1d68144c2a87f676b6cb71d0cf4b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java @@ -35,6 +35,7 @@ import com.oracle.truffle.r.library.fastrGrid.LInitViewPortStack; import com.oracle.truffle.r.library.fastrGrid.LLines; import com.oracle.truffle.r.library.fastrGrid.LNewPage; import com.oracle.truffle.r.library.fastrGrid.LPoints; +import com.oracle.truffle.r.library.fastrGrid.LPolygon; import com.oracle.truffle.r.library.fastrGrid.LRect; import com.oracle.truffle.r.library.fastrGrid.LSegments; import com.oracle.truffle.r.library.fastrGrid.LText; @@ -702,6 +703,8 @@ public class CallAndExternalFunctions { return LRect.create(); case "L_lines": return LLines.create(); + case "L_polygon": + return LPolygon.create(); case "L_text": return LText.create(); case "L_textBounds": diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index 8cef96974b030c84f4d8b3c6f076da0f399fe32d..0095ec54be32afb7dde5f2cff0b1a5d62c8bf2d8 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -783,7 +783,7 @@ com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridUtil com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/Unit.java,gnu_r_murrel_core.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortLocation.java,gnu_r_murrel_core.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortContext.java,gnu_r_murrel_core.copyright -com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LLines.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridLinesNode.java,gnu_r_murrel_core.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/ViewPortTransform.java,gnu_r_murrel_core.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LGridDirty.java,gnu_r_murrel_core.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java,gnu_r.copyright