package org.iplantc.phyloviewer.server.render; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import org.iplantc.phyloviewer.shared.math.Box2D; import org.iplantc.phyloviewer.shared.math.Matrix33; import org.iplantc.phyloviewer.shared.math.Vector2; import org.iplantc.phyloviewer.shared.render.Defaults; import org.iplantc.phyloviewer.shared.render.Graphics; import org.iplantc.phyloviewer.shared.render.style.IBranchStyle; import org.iplantc.phyloviewer.shared.render.style.IGlyphStyle; import org.iplantc.phyloviewer.shared.render.style.ILabelStyle; import org.iplantc.phyloviewer.shared.render.style.INodeStyle; import org.iplantc.phyloviewer.shared.scene.Text; public class Java2DGraphics extends Graphics { private Graphics2D g2d; private AffineTransform transform; // this is used to transform paths and shapes for drawing /** * Create a new Java2DGraphics that draws on the given Graphics2D * * @param graphics the drawing target. Note that the Graphics2D user clip <strong>must</strong> be * set for isCulled() to work. */ public Java2DGraphics(Graphics2D graphics) { this.g2d = graphics; this.transform = new AffineTransform(); g2d.setColor(new Color(1.0f, 1.0f, 1.0f, 1.0f)); this.setSize(1, 1); } protected Java2DGraphics() { } @Override protected void updateMatrix() { super.updateMatrix(); this.transform = affineTransformFrom(objectToScreenMatrix); } protected void setGraphics2D(Graphics2D graphics) { this.g2d = graphics; } @Override public void clear() { g2d.clearRect(0, 0, getWidth(), getHeight()); } @Override public void drawArc(Vector2 center, double radius, double startAngle, double endAngle) { // TODO implement circular rendering methods in Java2DGraphics throw new RuntimeException("drawArc not yet implemented"); } @Override public void drawPoint(Vector2 position) { Point2D point = point2DFrom(position); transform.transform(point, point); double radius = Defaults.POINT_SIZE / 2.0; double x = point.getX() - radius; double y = point.getY() - radius; double width = Defaults.POINT_SIZE; Ellipse2D.Double circle = new Ellipse2D.Double(x, y, width, width); g2d.fill(circle); } @Override public void drawText(Vector2 position, Vector2 offset, String text, double angle) { if(text != null) { Point2D point = point2DFrom(position); transform.transform(point, point); float x = (float)(point.getX() + offset.getX()); float y = (float)(point.getY() + offset.getY()); g2d.drawString(text, x, y); // TODO keep track of text bounds and don't write over previously drawn text } } @Override public void drawWedge(Vector2 center, Vector2 peak, double radius, double startAngle, double endAngle) { // TODO implement circular rendering methods in Java2DGraphics throw new RuntimeException("drawWedge not yet implemented"); } @Override public void setViewMatrix(Matrix33 matrix) { super.setViewMatrix(matrix); this.transform = affineTransformFrom(objectToScreenMatrix); } public static AffineTransform affineTransformFrom(Matrix33 m) { return new AffineTransform(m.getScaleX(), m.getShearY(), m.getShearX(), m.getScaleY(), m.getTranslationX(), m.getTranslationY()); } public static Matrix33 matrix33From(AffineTransform t) { return new Matrix33(t.getScaleX(), t.getShearX(), t.getTranslateX(), t.getShearY(), t.getScaleY(), t.getTranslateY(), 0, 0, 1); } public static Point2D point2DFrom(Vector2 v) { return new Point2D.Double(v.getX(), v.getY()); } public static Rectangle2D rectangle2DFrom(Box2D box) { return new Rectangle2D.Double(box.getMin().getX(), box.getMin().getY(), box.getWidth(), box.getHeight()); } @Override public void setStyle(IBranchStyle style) { if(style != null) { g2d.setColor(getColorFromHtmlString(style.getStrokeColor())); } } @Override public void setStyle(IGlyphStyle style) { if(style != null) { g2d.setColor(getColorFromHtmlString(style.getFillColor())); } } @Override public void setStyle(ILabelStyle style) { if(style != null) { g2d.setColor(getColorFromHtmlString(style.getColor())); } } @Override public void setStyle(INodeStyle style) { if(style != null) { g2d.setColor(getColorFromHtmlString(style.getColor())); } } public static Color getColorFromHtmlString(String colorString) { if(colorString != null) { // Do html strings have an alpha? if(colorString.startsWith("#") && colorString.length() == 7) { colorString = colorString.substring(1, colorString.length()); long colorInt = Long.parseLong(colorString, 16); float r = (float)(((colorInt & 0x00ff0000) >> 16) / 255.0); float g = (float)(((colorInt & 0x0000ff00) >> 8) / 255.0); float b = (float)(((colorInt & 0x000000ff)) / 255.0); return new Color(r, g, b, 1.0f); } } return new Color(0.0f, 0.0f, 0.0f, 1.0f); } private static Path2D createPath(Vector2[] vertices) { Path2D path = new Path2D.Double(); if(vertices.length > 2) { path.moveTo(vertices[0].getX(), vertices[0].getY()); for(int i = 1;i < vertices.length;++i) { path.lineTo(vertices[i].getX(), vertices[i].getY()); } } return path; } @Override public void drawLineStrip(Vector2[] vertices) { Path2D path = createPath(vertices); g2d.draw(transform.createTransformedShape(path)); } @Override public void drawPolygon(Vector2 vertices[]) { Path2D path = createPath(vertices); path.closePath(); Shape transformedPath = transform.createTransformedShape(path); g2d.fill(transformedPath); g2d.draw(transformedPath); } @Override public Box2D calculateBoundingBox(Text text) { return text.getBoundingBox(); } }