//
// GDInterface.java
// Java Graphics Device
//
// Created by Simon Urbanek on Thu Aug 05 2004.
// Copyright (c) 2004-2016 Simon Urbanek. All rights reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation;
// version 2.1 of the License.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
package org.rosuda.javaGD;
/** <code>CGInterface</code> defines an interface (and provides a simple implementation) between the JavaGD R device and the Java code. Any back-end that desires to display R graphics in Java can subclass this class are provide its name to JavaGD package via JAVAGD_CLASS_NAME environment variable. The default implementation handles most callbacks, but subclasses should override at least {@link #gdOpen} to create an instance of {@link GDContainer} {@link #c} which will be used for all subsequent drawing.
<p>
<b>external API: those methods are called via JNI from the GD C code</b>
<p>
<pre>
public void gdOpen(int devNr);
public void gdActivate();
public void gdCircle(double x, double y, double r);
public void gdClip(double x0, double x1, double y0, double y1);
public void gdClose();
public void gdDeactivate();
public void gdFlush(boolean flush);
public double[] gdInit(double width, double height, int unit, double xpi, double ypi)
public double[] gdLocator();
public void gdLine(double x1, double y1, double x2, double y2);
public double[] gdMetricInfo(int ch);
public void gdMode(int mode);
public void gdNewPage();
public boolean gdNewPageConfirm();
public void gdPath(int npoly, int[] nper, double[] x, double[] y, int mode);
public void gdPolygon(int n, double[] x, double[] y);
public void gdPolyline(int n, double[] x, double[] y);
public void gdRect(double x0, double y0, double x1, double y1);
public double[] gdSize();
public double gdStrWidth(String str);
public void gdText(double x, double y, String str, double rot, double hadj);
public void gdRaster(byte[] rgb, boolean hasAlpha, int img_w, int img_h, double x, double y, double w, double h, double rot, boolean interpolate);
public int[] gdCap(int[] dim);
</pre>
<p>
<b>GDC - manipulation of the current graphics state</b>
<p>
<pre>
public void gdcSetColor(int cc);
public void gdcSetFill(int cc);
public void gdcSetLine(double lwd, int lty);
public void gdcSetFont(double cex, double ps, double lineheight, int fontface, String fontfamily);
</pre>
*/
public abstract class GDInterface {
public static final int IN = 0;
public static final int PX = 1;
/**
* Flag indicating whether this device is active (current) in R
**/
private boolean active = false;
/**
* Flag indicating whether this device has currently an open instance
**/
private boolean open = false;
/**
* Flag indicating whether hold is in progress
**/
private boolean holding = false;
/**
* The device number as supplied by R in {@link #gdOpen(int, double, double)}
* (-1 if undefined)
**/
private int devNr = -1;
private double width = 672.0;
private double height = 672.0;
private double xpi = 96.0;
private double ypi = 96.0;
private int canvasColor;
/**
* Returns the device number
*
* @return the device number or -1 is unknown
**/
public final int getDeviceNumber() {
return this.devNr;
}
public final boolean isActive() {
return this.active;
}
public final boolean isOpen() {
return this.open;
}
public final boolean isHolding() {
return this.holding;
}
public void setSize(double width, double height, int unit) {
switch (unit) {
case IN:
this.width = width * this.xpi;
this.height = height * this.ypi;
break;
default:
this.width = width;
this.height = height;
break;
}
}
public double getWidth() {
return this.width;
}
public double getHeight() {
return this.height;
}
protected int getCanvasColor() {
return this.canvasColor;
}
/**
* Returns the raster point per inch (dpi)
*
* @param width initial width of the device
* @param height initial height of the device
* @param unit constant for unit of width and height ({@link #IN}, {@link #PX})
* @param xpi
* @param ypi
* @return array with factor for x (horizontal) and y (vertical)
*/
public double[] gdInit(double width, double height, int unit, double xpi, double ypi,
final int canvasColor) {
if (xpi > 0 && ypi > 0) {
this.xpi = xpi;
this.ypi = ypi;
}
setSize(width, height, unit);
this.canvasColor = canvasColor;
return new double[] { this.width, this.height };
}
/**
* Returns the raster point per inch (dpi)
*
* @return array with factor for x (horizontal) and y (vertical)
*/
public double[] gdPPI() {
return new double[] { this.xpi, this.ypi };
}
/**
* Opens the new device with the specified size
* @param devNr device number
*/
public void gdOpen(int devNr) {
if (isOpen()) {
gdClose();
}
this.devNr = devNr;
this.open = true;
}
/** the device became active (current) */
public void gdActivate() {
this.active = true;
}
/** draw a circle
* @param x x coordinate of the center
* @param y y coordinate of the center
* @param r radius */
public abstract void gdCircle(double x, double y, double r);
/** clip drawing to the specified region
* @param x0 left coordinate
* @param x1 right coordinate
* @param y0 top coordinate
* @param y1 bottom coordinate */
public abstract void gdClip(double x0, double x1, double y0, double y1);
/** close the display */
public void gdClose() {
this.open = false;
}
/** the device became inactive (i.e. another device is now current) */
public void gdDeactivate() {
this.active = false;
}
/** hold/flush
* @param flush if <code>false</code> then the device started holding and no
* updates should be shown on screen, if <code>true</code> then the device should
* flush right away and resume normal operation after than. Note that
* the flush must either be synchronous, or it must be guaranteed that
* shown content will be identical to the state up till now, otherwise
* the device will break animations. */
public void gdFlush(boolean flush) {
this.holding = !flush;
}
/** invoke the locator
* @return array of indices or <code>null</code> is cancelled */
public abstract double[] gdLocator();
/** draw a line
* @param x1 x coordinate of the origin
* @param y1 y coordinate of the origin
* @param x2 x coordinate of the end
* @param y2 y coordinate of the end */
public abstract void gdLine(double x1, double y1, double x2, double y2);
/** retrieve font metrics info for the given unicode character
* @param ch character (encoding may depend on the font type)
* @return an array consisting for three doubles: ascent, descent and width */
public abstract double[] gdMetricInfo(int ch);
/** R signalled a mode change
* @param mode mode as signalled by R (currently 0=R stopped drawing, 1=R started drawing, 2=graphical input exists) */
public abstract void gdMode(int mode);
/** create a new, blank page
* @param devNr device number assigned to this device by R */
public void gdNewPage() {
}
public boolean gdNewPageConfirm() {
return false;
}
public abstract void gdPath(int nPoly, int[] nPer, double[] x, double[] y, int mode);
public abstract void gdPolygon(int n, double[] x, double[] y);
public abstract void gdPolyline(int n, double[] x, double[] y);
public abstract void gdRect(double x0, double y0, double x1, double y1);
/** retrieve the current size of the device
* @return an array of four doubles: 0, width, height, 0 */
public abstract double[] gdSize();
/** retrieve width of the given text when drawn in the current font
* @param str text
* @return width of the text */
public abstract double gdStrWidth(String str);
/** draw text
* @param x x coordinate of the origin
* @param y y coordinate of the origin
* @param str text to draw
* @param rot rotation (in degrees)
* @param hadj horizontal adjustment with respect to the text size (0=left-aligned wrt origin, 0.5=centered, 1=right-aligned wrt origin) */
public abstract void gdText(double x, double y, String str, double rot, double hadj);
public abstract void gdRaster(byte[] img, boolean imgAlpha, int img_w, int img_h,
double x, double y, double w, double h, double rot, boolean interpolate);
public abstract byte[] gdCap(int[] dim);
/*-- GDC - manipulation of the current graphics state */
/** set drawing color
* @param cc color */
public abstract void gdcSetColor(int cc);
/** set fill color
* @param cc color */
public abstract void gdcSetFill(int cc);
/** set line width and type
* @param lwd line width (see <code>lwd</code> parameter in R)
* @param lty line type (see <code>lty</code> parameter in R)
* @param cap line cap (see <code>lend</code> parameter in R)
* @param join line join (see <code>ljoin</code> parameter in R)
* @param joinMiterLimit limit for mitered line joins (see <code>lmitre</code> parameter in R)
*/
public abstract void gdcSetLine(double lwd, int lty, byte cap, byte join, float joinMiterLimit);
/** set current font
* @param cex character expansion (see <code>cex</code> parameter in R)
* @param ps point size (see <code>ps</code> parameter in R - for all practical purposes the requested font size in points is <code>cex * ps</code>)
* @param lineheight line height
* @param fontface font face (see <code>font</code> parameter in R: 1=plain, 2=bold, 3=italic, 4=bold-italic, 5=symbol)
* @param fontfamily font family (see <code>family</code> parameter in R) */
public abstract void gdcSetFont(double cex, double ps, double lineheight, int fontface, String fontfamily);
}