diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java index c17dbe5d15ea6d8176e885aa117d128cacaf43a7..49d587cf373cb7933e125e97704b7f35403b9570 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java @@ -11,6 +11,8 @@ */ package com.oracle.truffle.r.library.fastrGrid; +import static com.oracle.truffle.r.library.fastrGrid.GridUtils.asDouble; + import java.util.Arrays; import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; @@ -97,6 +99,10 @@ public final class GPar { return RDataFactory.createList(data, NAMES_VECTOR); } + public static double getCex(RList gpar) { + return asDouble(gpar.getDataAt(GP_CEX)); + } + public static DrawingContext asDrawingContext(RList gpar) { return new GParDrawingContext(gpar); } @@ -114,22 +120,40 @@ public final class GPar { @Override public String getColor() { - String result = RRuntime.asString(data[GP_COL]); - if (!result.startsWith("#")) { - result = ColorNames.findByName(result); - } - return result == null ? "#FFFFFF" : result; + return getHexColor(GP_COL); + } + + @Override + public void setColor(String hexCode) { + data[GP_COL] = hexCode; } @Override public double getFontSize() { - return GridUtils.asDouble(data[GP_FONTSIZE]) * GridUtils.asDouble(data[GP_CEX]); + return asDouble(data[GP_FONTSIZE]) * asDouble(data[GP_CEX]); } @Override public double getLineHeight() { - return GridUtils.asDouble(data[GP_LINEHEIGHT]); + return asDouble(data[GP_LINEHEIGHT]); } + @Override + public String getFillColor() { + return getHexColor(GP_FILL); + } + + @Override + public void setFillColor(String hexCode) { + data[GP_FILL] = hexCode; + } + + private String getHexColor(int index) { + String result = RRuntime.asString(data[index]); + if (!result.startsWith("#")) { + result = ColorNames.findByName(result); + } + return result == null ? "#FFFFFF" : result; + } } } 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 782150456ab9f823912270eed68a1e3a76e30792..0de2442c7b6c55ce38242daec0a3d6be4c9eefdf 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 @@ -19,8 +19,7 @@ import com.oracle.truffle.r.library.fastrGrid.Unit.UnitLengthNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.data.RAttributable; -import com.oracle.truffle.r.runtime.data.RDouble; -import com.oracle.truffle.r.runtime.data.RInteger; +import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; @@ -116,7 +115,7 @@ final class GridUtils { static RAbstractIntVector asIntVector(Object value) { if (value instanceof Integer) { - return RInteger.valueOf((Integer) value); + return RDataFactory.createIntVectorFromScalar((Integer) value); } else if (value instanceof RAbstractIntVector) { return (RAbstractIntVector) value; } @@ -125,7 +124,7 @@ final class GridUtils { public static RAbstractDoubleVector asDoubleVector(Object obj) { if (obj instanceof Double) { - return RDouble.valueOf((Double) obj); + return RDataFactory.createDoubleVectorFromScalar((Double) obj); } else if (obj instanceof RAbstractDoubleVector) { return (RAbstractDoubleVector) obj; } @@ -134,9 +133,9 @@ final class GridUtils { static RAbstractContainer asAbstractContainer(Object value) { if (value instanceof Integer) { - return RInteger.valueOf((Integer) value); + return RDataFactory.createIntVectorFromScalar((Integer) value); } else if (value instanceof Double) { - return RDouble.valueOf((Double) value); + return RDataFactory.createDoubleVectorFromScalar((Double) value); } else if (value instanceof RAbstractContainer) { return (RAbstractContainer) value; } 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 new file mode 100644 index 0000000000000000000000000000000000000000..5c40420695731eb0b9f2f03193bfab771dbac857 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java @@ -0,0 +1,141 @@ +/* + * 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-2015, 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.nodes.builtin.CastBuilder.Predef.abstractVectorValue; +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.UnitConversionContext; +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitLengthNode; +import com.oracle.truffle.r.library.fastrGrid.Unit.UnitToInchesNode; +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.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; +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; + +public abstract class LPoints extends RExternalBuiltinNode.Arg4 { + private static final double SMALL = 0.25; + private static final double RADIUS = 0.375; + private static final double SQRC = 0.88622692545275801364; /* sqrt(pi / 4) */ + private static final double DMDC = 1.25331413731550025119; /* sqrt(pi / 4) * sqrt(2) */ + private static final double TRC0 = 1.55512030155621416073; /* sqrt(4 * pi/(3 * sqrt(3))) */ + private static final double TRC1 = 1.34677368708859836060; /* TRC0 * sqrt(3) / 2 */ + private static final double TRC2 = 0.77756015077810708036; /* TRC0 / 2 */ + private static final String TRANSPARENT = "white"; // TODO: should be actually transparent + + @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); + @Child private VPContextFromVPNode vpContextFromVP = new VPContextFromVPNode(); + @Child private UnitLengthNode unitLength = Unit.createLengthNode(); + @Child private UnitToInchesNode unitToInches = Unit.createToInchesNode(); + + static { + Casts casts = new Casts(LPoints.class); + casts.arg(0).mustBe(abstractVectorValue()); + casts.arg(1).mustBe(abstractVectorValue()); + casts.arg(2).mustBe(numericValue(), Message.GENERIC, "grid.points: pch argument not implemented for characters yet").asIntegerVector(); + casts.arg(3).mustBe(abstractVectorValue()); + } + + public static LPoints create() { + return LPointsNodeGen.create(); + } + + @Specialization + public Object doPoints(RAbstractVector xVec, RAbstractVector yVec, RAbstractIntVector pchVec, RAbstractVector sizeVec) { + GridContext ctx = GridContext.getContext(); + GridDevice dev = ctx.getCurrentDevice(); + + RList currentVP = ctx.getGridState().getViewPort(); + RList gpar = ctx.getGridState().getGpar(); + DrawingContext drawingCtx = GPar.asDrawingContext(gpar); + double cex = GPar.getCex(gpar); + ViewPortTransform vpTransform = getViewPortTransform.execute(currentVP); + ViewPortContext vpContext = vpContextFromVP.execute(currentVP); + UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, drawingCtx); + + // Note: unlike in other drawing primitives, we only consider length of x + int length = unitLength.execute(xVec); + for (int i = 0; i < length; i++) { + Point loc = TransformMatrix.transLocation(Point.fromUnits(unitToInches, xVec, yVec, i, conversionCtx), vpTransform.transform); + double size = unitToInches.convertWidth(sizeVec, i, conversionCtx); + if (loc.isFinite() && Double.isFinite(size)) { + drawSymbol(drawingCtx, dev, cex, pchVec.getDataAt(i % pchVec.getLength()), size, loc.x, loc.y); + } + } + return RNull.instance; + } + + // transcribed from engine.c function GESymbol + + private void drawSymbol(DrawingContext drawingCtx, GridDevice dev, double cex, int pch, double size, double x, double y) { + // pch 0 - 25 are interpreted as geometrical shapes, pch from ascii code of ' ' are + // interpreted as corresponding ascii character, which should be drawn + switch (pch) { + case 46: + drawDot(drawingCtx, dev, cex, x, y); + break; + case 1: + drawOctahedron(drawingCtx, dev, GridColor.TRANSPARENT, size, x, y); + break; + case 16: + drawOctahedron(drawingCtx, dev, drawingCtx.getColor(), size, x, y); + break; + default: + throw RInternalError.unimplemented("grid.points unimplemented symbol " + pch); + } + } + + private static void drawOctahedron(DrawingContext drawingCtx, GridDevice dev, GridColor fill, double size, double x, double y) { + GridColor originalFill = drawingCtx.getFillColor(); + drawingCtx.setFillColor(fill); + dev.drawCircle(drawingCtx, x, y, RADIUS * size); + drawingCtx.setFillColor(originalFill); + } + + private static void drawDot(DrawingContext drawingCtx, GridDevice dev, double cex, double x, double y) { + // NOTE: we are *filling* a rect with the current colour (we are not drawing the border AND + // we are not using the current fill colour) + String originalFill = drawingCtx.getFillColor(); + drawingCtx.setFillColor(drawingCtx.getColor()); + drawingCtx.setColor(TRANSPARENT); + + /* + * The idea here is to use a 0.01" square, but to be of at least one device unit in each + * direction, assuming that corresponds to pixels. That may be odd if pixels are not square, + * but only on low resolution devices where we can do nothing better. + * + * For this symbol only, size is cex (see engine.c). + * + * Prior to 2.1.0 the offsets were always 0.5. + */ + double xc = cex * 0.005; + double yc = cex * 0.005; + if (cex > 0 && xc < 0.5) { + xc = 0.5; + } + if (cex > 0 && yc < 0.5) { + yc = 0.5; + } + dev.drawRect(drawingCtx, x - xc, y - yc, x + xc, y + yc); + + drawingCtx.setColor(drawingCtx.getFillColor()); + drawingCtx.setFillColor(originalFill); + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContext.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContext.java index facac095e99e7217f318bd2110c645f0d965b2b9..1cd94bdabf4384ebf90917e9ce5f86d12af7b3fd 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContext.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/DrawingContext.java @@ -34,6 +34,12 @@ public interface DrawingContext { */ String getColor(); + /** + * Alows to set the color. The parameter may also be a synonym defined in + * {@link com.oracle.truffle.r.library.fastrGrid.ColorNames}. + */ + void setColor(String hexCode); + /** * Gets the font size in points. * @@ -45,4 +51,16 @@ public interface DrawingContext { * Gets the height of a line in multiplies of the base line height. */ double getLineHeight(); + + /** + * @return Hexadecimal string of the color with leading '#', e.g. '#FFA8B2'. Never returns a + * synonym. + */ + String getFillColor(); + + /** + * Alows to set the fill color. The parameter may also be a synonym defined in + * {@link com.oracle.truffle.r.library.fastrGrid.ColorNames}. + */ + void setFillColor(String hexCode); } 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 9a10b92b977ab7968dc34fc0765fa0d3e12f47c0..6b0b5d88beed9b7238b8802637835e00132d6dcf 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 @@ -34,6 +34,7 @@ import com.oracle.truffle.r.library.fastrGrid.LInitGrid; 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.LRect; import com.oracle.truffle.r.library.fastrGrid.LSegments; import com.oracle.truffle.r.library.fastrGrid.LText; @@ -709,6 +710,8 @@ public class CallAndExternalFunctions { return LSegments.create(); case "L_circle": return LCircle.create(); + case "L_points": + return LPoints.create(); // Simple grid state access case "L_getGPar": diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index 8119e383c89cffe938e9d9ea2fec61c315c8f675..2ed282f563cbf7bbb51df5007804cadf27f655a7 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -767,6 +767,7 @@ com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/p com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/deriv/Deriv.java,gnu_r_gentleman_ihaka2.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/deriv/DerivVisitor.java,gnu_r_gentleman_ihaka2.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java,gnu_r_murrel_core.copyright +com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPoints.java,gnu_r_murrel_core.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java,gnu_r_murrel_core.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPortBuiltin.java,gnu_r_murrel_core.copyright com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LUpViewPort.java,gnu_r_murrel_core.copyright