// // VisADCanvasJ2D.java // /* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package visad.java2d; import visad.*; import visad.util.Delay; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; import java.awt.geom.Line2D; import java.awt.geom.AffineTransform; import java.awt.geom.NoninvertibleTransformException; import javax.swing.*; import java.rmi.RemoteException; import java.util.*; /** * <CODE>VisADCanvasJ2D</CODE> is the VisAD "Canvas" for Java2D. But * not really a <CODE>Canvas</CODE>, since <CODE>Canvas</CODE> is * heavyweight.<P> */ public class VisADCanvasJ2D extends JPanel implements Runnable { /** line patterns for use with BasicStroke */ private float[][] LINE_PATTERN = { null, {8}, {1, 7}, {7, 4, 1, 4} }; private DisplayRendererJ2D displayRenderer; private DisplayImplJ2D display; private Component component; Dimension prefSize = new Dimension(0, 0); // parent nodes of all data depictions private VisADGroup direct = null; private VisADGroup non_direct = null; // Shape to clip against, if any private Rectangle2D.Float clip_rectangle = null; private transient Thread renderThread; private BufferedImage[] images; // animation sequence private boolean[] valid_images; private int width, height; // size of images private int length; // length of images & valid_images private AffineTransform tgeometry; // transform for current display private Image aux_image; boolean captureFlag = false; BufferedImage captureImage = null; MouseHelper helper; // wake up flag for renderTrigger boolean wakeup = false; // flag set if images not created boolean timeout = false; public VisADCanvasJ2D(DisplayRendererJ2D renderer, Component c) { displayRenderer = renderer; display = (DisplayImplJ2D) renderer.getDisplay(); component = c; width = getSize().width; height = getSize().height; if (width <= 0) width = 1; if (height <= 0) height = 1; length = 1; images = new BufferedImage[] {(BufferedImage) createImage(width, height)}; aux_image = createImage(width, height); valid_images = new boolean[] {false}; int w = width; int h = height; AffineTransform trans = displayRenderer.getTrans(); tgeometry = new AffineTransform(); tgeometry.setToTranslation(0.5 * w, 0.5 * h); AffineTransform s1 = new AffineTransform(); int wh = (w < h) ? w : h; s1.setToScale(0.33 * wh, 0.33 * wh); tgeometry.concatenate(s1); tgeometry.concatenate(trans); ComponentListener cl = new ComponentAdapter() { public void componentResized(ComponentEvent e) { createImages(-1); } }; addComponentListener(cl); setBackground(Color.black); setForeground(Color.white); new Delay(); if (images[0] == null) { images = new BufferedImage[] {(BufferedImage) createImage(width, height)}; aux_image = createImage(width, height); valid_images = new boolean[] {false}; } renderThread = new Thread(this); renderThread.start(); } /** * Constructor for offscreen rendering. * @param renderer * @param w * @param h */ public VisADCanvasJ2D(DisplayRendererJ2D renderer, int w, int h) { displayRenderer = renderer; display = (DisplayImplJ2D) renderer.getDisplay(); component = null; width = w; height = h; length = 1; images = new BufferedImage[] {new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)}; aux_image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); valid_images = new boolean[] {false}; AffineTransform trans = displayRenderer.getTrans(); tgeometry = new AffineTransform(); tgeometry.setToTranslation(0.5 * w, 0.5 * h); AffineTransform s1 = new AffineTransform(); int wh = (w < h) ? w : h; s1.setToScale(0.33 * wh, 0.33 * wh); tgeometry.concatenate(s1); tgeometry.concatenate(trans); setBackground(Color.black); setForeground(Color.white); renderThread = new Thread(this); renderThread.start(); } /** * Return the background color. * @return A 3 element array of <CODE>float</CODE> values * in the range <CODE>[0.0f - 1.0f]</CODE> * in the order <I>(Red, Green, Blue)</I>. */ public float[] getBackgroundColor() { Color color = getBackground(); float[] list = new float[3]; list[0] = (float )color.getRed() / 255.0f; list[1] = (float )color.getGreen() / 255.0f; list[2] = (float )color.getBlue() / 255.0f; return list; } /** * Set the background color. All values should be in the range * <CODE>[0.0f - 1.0f]</CODE>. * @param r Red value. * @param g Green value. * @param b Blue value. */ public void setBackgroundColor(float r, float g, float b) { setBackground(new Color(r, g, b)); } void setDirect(VisADGroup d, VisADGroup nd) { direct = d; non_direct = nd; } void setClip(float xlow, float xhi, float ylow, float yhi) { if (xhi > xlow && yhi > ylow) { clip_rectangle = new Rectangle2D.Float(xlow, ylow, xhi-xlow, yhi-ylow); } } void unsetClip() { clip_rectangle = null; } /** * Add a <CODE>MouseBehavior</CODE> for mouse control of translation * and zoom. This adds <CODE>MouseListener</CODE>s to the VisADCanvasJ2D to * handle the behaviors for the mouse events. Do not use this in conjunction * with other <CODE>MouseListener</CODE>s that handle events for the default * VisAD mouse controls. * @param mouse mouse behavior to add */ public void addMouseBehavior(MouseBehaviorJ2D mouse) { helper = mouse.getMouseHelper(); MouseListener ml = new MouseAdapter() { public void mouseEntered(MouseEvent e) { helper.processEvent(e); } public void mouseExited(MouseEvent e) { helper.processEvent(e); } public void mousePressed(MouseEvent e) { helper.processEvent(e); } public void mouseReleased(MouseEvent e) { helper.processEvent(e); } public void mouseClicked(MouseEvent e) { requestFocus(); } }; addMouseListener(ml); MouseMotionListener mml = new MouseMotionAdapter() { public void mouseDragged(MouseEvent e) { helper.processEvent(e); } public void mouseMoved(MouseEvent e) { helper.processEvent(e); } }; addMouseMotionListener(mml); } /** * Add a <CODE>KeyboardBehavior</CODE> for keyboard control of translation * and zoom. This adds a <CODE>KeyListener</CODE> to the VisADCanvasJ2D to * handle the behaviors for the arrow keys. Do not use this in conjunction * with other <CODE>KeyListener</CODE>s that handle events for the arrow keys. * @param behavior keyboard behavior to add */ public void addKeyboardBehavior(final KeyboardBehaviorJ2D behavior) { KeyListener kl = new KeyAdapter() { public void keyPressed(KeyEvent e) { behavior.processKeyEvent(e); } public void keyReleased(KeyEvent e) { behavior.processKeyEvent(e); } }; addKeyListener(kl); } public void createImages(int len) { synchronized (images) { length = (len < 0) ? images.length : len; if (component != null) { width = getSize().width; height = getSize().height; } if (width <= 0) width = 1; if (height <= 0) height = 1; BufferedImage[] new_images = new BufferedImage[length]; boolean[] new_valid_images = new boolean[length]; for (int i=0; i<length; i++) { if (component != null) { new_images[i] = (BufferedImage) createImage(width, height); } else { new_images[i] = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); } new_valid_images[i] = false; } if (aux_image != null) aux_image.flush(); if (component != null) { aux_image = createImage(width, height); } else { aux_image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); } valid_images = new_valid_images; if (images != null) { for (int i=0; i<images.length; i++) { if (images[i] != null) images[i].flush(); } } images = new_images; /* System.out.println("VisADCanvasJ2D.createImages: len = " + len + " length = " + length + " width, height = " + width + " " + height); */ } renderTrigger(); } public void scratchImages() { synchronized (images) { for (int i=0; i<length; i++) valid_images[i] = false; } renderTrigger(); } /** trigger render to screen */ public void renderTrigger() { synchronized (this) { wakeup = true; notify(); } } public void stop() { renderThread = null; } public void run() { Thread me = Thread.currentThread(); while (renderThread == me) { timeout = false; if (component != null) { Graphics g = getGraphics(); if (g != null) { // paintComponent(g); repaint(); g.dispose(); } } else { paintComponent(null); } try { synchronized (this) { if (!wakeup) { if (timeout) { wait(1000); } else { wait(); } } } } catch(InterruptedException e) { // note notify generates a normal return from wait rather // than an Exception - control doesn't normally come here } synchronized (this) { wakeup = false; } } } public void paintComponent(Graphics g) { AffineTransform tsave = null; BufferedImage image = null; boolean valid = false; int w = 0, h = 0; int current_image = 0; AnimationControlJ2D animate_control = null; try { animate_control = (AnimationControlJ2D) display.getControl(AnimationControlJ2D.class); if (animate_control != null) { animate_control.setNoTick(true); current_image = animate_control.getCurrent(); } } catch (Exception e) { if (animate_control != null) animate_control.setNoTick(false); } /* System.out.println("VisADCanvasJ2D.paint: current = " + current_image + " (animate_control == null) = " + (animate_control == null)); */ synchronized (images) { if (0 <= current_image && current_image < length) { image = images[current_image]; if (image == null) { createImages(-1); image = images[current_image]; } valid = valid_images[current_image]; w = width; h = height; tsave = (tgeometry == null) ? null : new AffineTransform(tgeometry); if (image != null && !valid) { valid_images[current_image] = true; } } } /* System.out.println("VisADCanvasJ2D.paint: current_image = " + current_image + " length = " + length + " w, h = " + w + " " + h + " valid = " + valid + " image != null " + (image != null)); */ timeout = false; if (image != null) { if (!valid) { VisADGroup root = displayRenderer.getRoot(); AffineTransform trans = displayRenderer.getTrans(); Graphics ggg = image.createGraphics(); // ordinary Graphics for fast lines Graphics2D g2 = image.createGraphics(); // Graphics2D for the fancy stuff // System.out.println("(g2 == null) = " + (g2 == null)); g2.setBackground(getBackground()); g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); g2.clearRect(0, 0, width, height); // render into image; synchronized (images) { tgeometry = new AffineTransform(); tgeometry.setToTranslation(0.5 * w, 0.5 * h); AffineTransform s1 = new AffineTransform(); int wh = (w < h) ? w : h; s1.setToScale(0.33 * wh, 0.33 * wh); tgeometry.concatenate(s1); tgeometry.concatenate(trans); tsave = new AffineTransform(tgeometry); g2.setTransform(tgeometry); } try { if (animate_control != null) animate_control.init(); render(g2, ggg, root, 0, null); render(g2, ggg, root, 1, null); // draw Animation string in upper right corner of screen String[] animation_string = displayRenderer.getAnimationString(); if (animation_string[0] != null) { /* System.out.println("VisADCanvasJ2D.paint: " + animation_string[0] + " " + animation_string[1]); */ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setFont(new Font("Times New Roman", Font.PLAIN, 12)); g2.setTransform(new AffineTransform()); // hack for mystery NullPointerException try { int nchars = animation_string[0].length(); if (nchars < 12) nchars = 12; float x = w - 7 * nchars; float y = h - 12; g2.drawString(animation_string[0], x, y); g2.drawString(animation_string[1], x, y+10); } catch (NullPointerException e) { } } } catch (VisADException e) { } g2.dispose(); ggg.dispose(); } // end if (!valid) if (tsave == null || !displayRenderer.anyCursorStringVector()) { if (g != null) { g.drawImage(image, 0, 0, this); } if (captureFlag || display.hasSlaves()) { // System.out.println("image capture " + width + " " + height); captureFlag = false; if (component != null) { captureImage = (BufferedImage) createImage(width, height); } else { captureImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); } // CTR 2 June 2000 - captureImage can be null if (captureImage != null) { Graphics gc = captureImage.getGraphics(); gc.drawImage(image, 0, 0, this); gc.dispose(); captureImage.flush(); displayRenderer.notifyCapture(); // System.out.println("image capture end"); // CTR 21 Sep 99 - send BufferedImage to attached slaved displays if (display.hasSlaves()) display.updateSlaves(captureImage); } } } else { Image aux_copy = null; synchronized (images) { if (aux_image == null) { // if we got here before the image buffer was initialized, // skip this round of drawing return; } aux_copy = aux_image; } Graphics ga = aux_copy.getGraphics(); ga.drawImage(image, 0, 0, this); displayRenderer.drawCursorStringVector(ga, tsave, w, h); ga.dispose(); if (g != null) { g.drawImage(aux_copy, 0, 0, this); } if (captureFlag || display.hasSlaves()) { // System.out.println("aux_copy capture " + width + " " + height); captureFlag = false; if (component != null) { captureImage = (BufferedImage) createImage(width, height); } else { captureImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); } Graphics gc = captureImage.getGraphics(); gc.drawImage(aux_copy, 0, 0, this); gc.dispose(); captureImage.flush(); displayRenderer.notifyCapture(); // System.out.println("aux_copy capture end"); // WLH 14 Oct 99 - send BufferedImage to any attached slaved displays if (display.hasSlaves()) display.updateSlaves(captureImage); } } try { display.notifyListeners(DisplayEvent.FRAME_DONE, 0, 0); } catch (VisADException e) {} catch (RemoteException e) {} } // end if (image != null) else { // image == null timeout = true; } if (animate_control != null) animate_control.setNoTick(false); return; } private void render(Graphics2D g2, Graphics ggg, VisADSceneGraphObject scene, int pass, Rectangle2D.Float clip) throws VisADException { if (scene == null) return; if (scene instanceof VisADSwitch) { VisADSceneGraphObject child = ((VisADSwitch) scene).getSelectedChild(); if (child != null) render(g2, ggg, child, pass, clip); } else if (scene instanceof VisADGroup) { if (clip_rectangle != null && (scene.equals(direct) || scene.equals(non_direct))) { clip = clip_rectangle; } Vector children = ((VisADGroup) scene).getChildren(); for (int i=children.size()-1; i>=0; i--) { VisADSceneGraphObject child = (VisADSceneGraphObject) children.elementAt(i); if (child != null) render(g2, ggg, child, pass, clip); } } else { // scene instanceof VisADAppearance g2.setClip(clip); VisADAppearance appearance = (VisADAppearance) scene; VisADGeometryArray array = appearance.array; if (array == null) return; BufferedImage image = (BufferedImage) appearance.image; AffineTransform tg = g2.getTransform(); if (image != null) { if (pass != 0) return; // non-lines on first pass g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); if (!(array instanceof VisADQuadArray)) { throw new VisADError("VisADCanvasJ2D.render: array must be quad"); } float x00 = array.coordinates[0]; float y00 = array.coordinates[1]; float xw0 = array.coordinates[3]; float yw0 = array.coordinates[4]; float xwh = array.coordinates[6]; float ywh = array.coordinates[7]; float x0h = array.coordinates[9]; float y0h = array.coordinates[10]; int width = image.getWidth(); int height = image.getHeight(); /* now: x00 = m00 * 0 + m01 * 0 + m02 y00 = m10 * 0 + m11 * 0 + m12 xw0 = m00 * width + m01 * 0 + m02 yw0 = m10 * width + m11 * 0 + m12 xwh = m00 * width + m01 * height + m02 ywh = m10 * width + m11 * height + m12 x0h = m00 * 0 + m01 * height + m02 y0h = m10 * 0 + m11 * height + m12 so: */ float m02 = x00; float m12 = y00; float m00 = (xw0 - x00) / width; float m10 = (yw0 - y00) / width; float m01 = (x0h - x00) / height; float m11 = (y0h - y00) / height; float xerr = xwh - (m00 * width + m01 * height + m02); float yerr = ywh - (m10 * width + m11 * height + m12); AffineTransform timage = new AffineTransform(m00, m10, m01, m11, m02, m12); g2.transform(timage); // concatenate timage onto tg try { g2.drawImage(image, 0, 0, this); } catch (java.awt.image.ImagingOpException e) { } g2.setTransform(tg); // restore tg } else { // image == null if (array instanceof VisADPointArray || array instanceof VisADLineArray || array instanceof VisADLineStripArray) { if (pass != 1) return; // lines on second pass } else { if (pass != 0) return; // non-lines on first pass } int count = array.vertexCount; if (count == 0) return; float[] coordinates = array.coordinates; byte[] colors = array.colors; if (colors == null) { if (appearance.color_flag) { float red = (float) Math.max(Math.min(appearance.red, 1.0f), 0.0f); float green = (float) Math.max(Math.min(appearance.green, 1.0f), 0.0f); float blue = (float) Math.max(Math.min(appearance.blue, 1.0f), 0.0f); g2.setColor(new Color(red, green, blue)); } else { g2.setColor(new Color(1.0f, 1.0f, 1.0f)); } } else { } if (array instanceof VisADPointArray || array instanceof VisADLineArray || array instanceof VisADLineStripArray) { float fsize = (array instanceof VisADPointArray) ? appearance.pointSize : appearance.lineWidth; double dsize = fsize; if (dsize < 1.05) dsize = 1.05; // hack for Java2D problem double[] pts = {0.0, 0.0, 0.0, dsize, dsize, 0.0}; double[] newpts = new double[6]; double xx = 0.0, yy = 0.0; try { tg.inverseTransform(pts, 0, newpts, 0, 3); xx = (newpts[2] - newpts[0]) * (newpts[2] - newpts[0]) + (newpts[3] - newpts[1]) * (newpts[3] - newpts[1]); yy = (newpts[4] - newpts[0]) * (newpts[4] - newpts[0]) + (newpts[5] - newpts[1]) * (newpts[5] - newpts[1]); } catch (NoninvertibleTransformException e) { xx = 1.05; yy = 1.05; } float size = (float) (0.5 * (Math.sqrt(xx) + Math.sqrt(yy))); float hsize = 0.5f * size; float[] style = LINE_PATTERN[appearance.lineStyle]; float[] pattern = null; if (style != null) { pattern = new float[style.length]; float scale = size / appearance.lineWidth; for (int i=0; i<style.length; i++) pattern[i] = scale * style[i]; } g2.setStroke(new BasicStroke(size, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10, pattern, 0)); /* System.out.println("dsize = " + dsize + " size = " + size + " xx, yy = " + xx + " " + yy + (array instanceof VisADPointArray ? " point" : " line")); */ if (array instanceof VisADPointArray) { if (Math.abs(fsize - 1.0f) < 0.1f) { drawAppearance(ggg, appearance, tg, clip); } else { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); if (colors == null) { for (int i=0; i<3*count; i += 3) { if (coordinates[i] == coordinates[i] && coordinates[i+1] == coordinates[i+1]) { g2.fill(new Rectangle2D.Float(coordinates[i]-hsize, coordinates[i+1]-hsize, size, size)); } } } else { // colors != null int j = 0; int jinc = (colors.length == coordinates.length) ? 3 : 4; for (int i=0; i<3*count; i += 3) { if (coordinates[i] == coordinates[i] && coordinates[i+1] == coordinates[i+1]) { g2.setColor(new Color( ((colors[j] < 0) ? (((int) colors[j]) + 256) : ((int) colors[j]) ), ((colors[j+1] < 0) ? (((int) colors[j+1]) + 256) : ((int) colors[j+1]) ), ((colors[j+2] < 0) ? (((int) colors[j+2]) + 256) : ((int) colors[j+2]) ) )); g2.fill(new Rectangle2D.Float(coordinates[i]-hsize, coordinates[i+1]-hsize, size, size)); } j += jinc; } } } } else if (array instanceof VisADLineArray) { if (Math.abs(fsize - 1.0f) < 0.1f) { drawAppearance(ggg, appearance, tg, clip); } else { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (colors == null) { for (int i=0; i<3*count; i += 6) { g2.draw(new Line2D.Float(coordinates[i], coordinates[i+1], coordinates[i+3], coordinates[i+4])); } } else { // colors != null int j = 0; int jinc = (colors.length == coordinates.length) ? 3 : 4; for (int i=0; i<3*count; i += 6) { g2.setColor(new Color( (((colors[j] < 0) ? (((int) colors[j]) + 256) : ((int) colors[j]) ) + ((colors[j+jinc] < 0) ? (((int) colors[j+jinc]) + 256) : ((int) colors[j+jinc]) ) ) / 2, (((colors[j+1] < 0) ? (((int) colors[j+1]) + 256) : ((int) colors[j+1]) ) + ((colors[j+jinc+1] < 0) ? (((int) colors[j+jinc+1]) + 256) : ((int) colors[j+jinc+1]) ) ) / 2, (((colors[j+2] < 0) ? (((int) colors[j+2]) + 256) : ((int) colors[j+2]) ) + ((colors[j+jinc+2] < 0) ? (((int) colors[j+jinc+2]) + 256) : ((int) colors[j+jinc+2]) ) ) / 2 )); j += 2 * jinc; g2.draw(new Line2D.Float(coordinates[i], coordinates[i+1], coordinates[i+3], coordinates[i+4])); } } } } else { // (array instanceof VisADLineStripArray) g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int[] stripVertexCounts = ((VisADLineStripArray) array).stripVertexCounts; int base = 0; int basec = 0; int jinc = 0; if (colors != null) { jinc = (colors.length == coordinates.length) ? 3 : 4; } for (int strip=0; strip<stripVertexCounts.length; strip++) { count = stripVertexCounts[strip]; float lastx = coordinates[base]; float lasty = coordinates[base+1]; int lastr = 0, lastg = 0, lastb = 0; int thisr, thisg, thisb; if (colors != null) { lastr = (colors[basec] < 0) ? (((int) colors[basec]) + 256) : ((int) colors[basec]); lastg = (colors[basec+1] < 0) ? (((int) colors[basec+1]) + 256) : ((int) colors[basec+1]); lastb = (colors[basec+2] < 0) ? (((int) colors[basec+2]) + 256) : ((int) colors[basec+2]); } if (colors == null) { for (int i=3; i<3*count; i += 3) { g2.draw(new Line2D.Float(lastx, lasty, coordinates[base+i], coordinates[base+i+1])); lastx = coordinates[base+i]; lasty = coordinates[base+i+1]; } } else { int j = jinc; for (int i=3; i<3*count; i += 3) { thisr = (colors[basec+j] < 0) ? (((int) colors[basec+j]) + 256) : ((int) colors[basec+j]); thisg = (colors[basec+j+1] < 0) ? (((int) colors[basec+j+1]) + 256) : ((int) colors[basec+j+1]); thisb = (colors[basec+j+2] < 0) ? (((int) colors[basec+j+2]) + 256) : ((int) colors[basec+j+2]); g2.setColor(new Color((lastr + thisr) / 2, (lastg + thisg) / 2, (lastb + thisb) / 2)); lastr = thisr; lastg = thisg; lastb = thisb; j += jinc; g2.draw(new Line2D.Float(lastx, lasty, coordinates[base+i], coordinates[base+i+1])); lastx = coordinates[base+i]; lasty = coordinates[base+i+1]; } } base += 3 * count; basec += jinc * count; } // end for (int strip=0; strip<stripVertexCounts.length; strip++) } // end if (array instanceof VisADLineStripArray) } else if (array instanceof VisADTriangleArray) { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); if (colors == null) { for (int i=0; i<3*count; i += 9) { GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); path.moveTo(coordinates[i], coordinates[i+1]); path.lineTo(coordinates[i+3], coordinates[i+4]); path.lineTo(coordinates[i+6], coordinates[i+7]); path.closePath(); g2.fill(path); } } else { // colors != null int j = 0; int jinc = (colors.length == coordinates.length) ? 3 : 4; for (int i=0; i<3*count; i += 9) { g2.setColor(new Color( (((colors[j] < 0) ? (((int) colors[j]) + 256) : ((int) colors[j]) ) + ((colors[j+jinc] < 0) ? (((int) colors[j+jinc]) + 256) : ((int) colors[j+jinc]) ) + ((colors[j+2*jinc] < 0) ? (((int) colors[j+2*jinc]) + 256) : ((int) colors[j+2*jinc]) ) ) / 3, (((colors[j+1] < 0) ? (((int) colors[j+1]) + 256) : ((int) colors[j+1]) ) + ((colors[j+jinc+1] < 0) ? (((int) colors[j+jinc+1]) + 256) : ((int) colors[j+jinc+1]) ) + ((colors[j+2*jinc+1] < 0) ? (((int) colors[j+2*jinc+1]) + 256) : ((int) colors[j+2*jinc+1]) ) ) / 3, (((colors[j+2] < 0) ? (((int) colors[j+2]) + 256) : ((int) colors[j+2]) ) + ((colors[j+jinc+2] < 0) ? (((int) colors[j+jinc+2]) + 256) : ((int) colors[j+jinc+2]) ) + ((colors[j+2*jinc+2] < 0) ? (((int) colors[j+2*jinc+2]) + 256) : ((int) colors[j+2*jinc+2]) ) ) / 3 )); j += 3 * jinc; GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); path.moveTo(coordinates[i], coordinates[i+1]); path.lineTo(coordinates[i+3], coordinates[i+4]); path.lineTo(coordinates[i+6], coordinates[i+7]); path.closePath(); g2.fill(path); } } } else if (array instanceof VisADQuadArray) { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); if (colors == null) { for (int i=0; i<3*count; i += 12) { GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); path.moveTo(coordinates[i], coordinates[i+1]); path.lineTo(coordinates[i+3], coordinates[i+4]); path.lineTo(coordinates[i+6], coordinates[i+7]); path.lineTo(coordinates[i+9], coordinates[i+10]); path.closePath(); g2.fill(path); } } else { // colors != null int j = 0; int jinc = (colors.length == coordinates.length) ? 3 : 4; for (int i=0; i<3*count; i += 12) { g2.setColor(new Color( (((colors[j] < 0) ? (((int) colors[j]) + 256) : ((int) colors[j]) ) + ((colors[j+jinc] < 0) ? (((int) colors[j+jinc]) + 256) : ((int) colors[j+jinc]) ) + ((colors[j+2*jinc] < 0) ? (((int) colors[j+2*jinc]) + 256) : ((int) colors[j+2*jinc]) ) + ((colors[j+3*jinc] < 0) ? (((int) colors[j+3*jinc]) + 256) : ((int) colors[j+3*jinc]) ) ) / 4, (((colors[j+1] < 0) ? (((int) colors[j+1]) + 256) : ((int) colors[j+1]) ) + ((colors[j+jinc+1] < 0) ? (((int) colors[j+jinc+1]) + 256) : ((int) colors[j+jinc+1]) ) + ((colors[j+2*jinc+1] < 0) ? (((int) colors[j+2*jinc+1]) + 256) : ((int) colors[j+2*jinc+1]) ) + ((colors[j+3*jinc+1] < 0) ? (((int) colors[j+3*jinc+1]) + 256) : ((int) colors[j+3*jinc+1]) ) ) / 4, (((colors[j+2] < 0) ? (((int) colors[j+2]) + 256) : ((int) colors[j+2]) ) + ((colors[j+jinc+2] < 0) ? (((int) colors[j+jinc+2]) + 256) : ((int) colors[j+jinc+2]) ) + ((colors[j+2*jinc+2] < 0) ? (((int) colors[j+2*jinc+2]) + 256) : ((int) colors[j+2*jinc+2]) ) + ((colors[j+3*jinc+2] < 0) ? (((int) colors[j+3*jinc+2]) + 256) : ((int) colors[j+3*jinc+2]) ) ) / 4 )); j += 4 * jinc; GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); path.moveTo(coordinates[i], coordinates[i+1]); path.lineTo(coordinates[i+3], coordinates[i+4]); path.lineTo(coordinates[i+6], coordinates[i+7]); path.lineTo(coordinates[i+9], coordinates[i+10]); path.closePath(); g2.fill(path); } } } else if (array instanceof VisADIndexedTriangleStripArray) { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); int[] indices = ((VisADIndexedTriangleStripArray) array).indices; int indexCount = ((VisADIndexedTriangleStripArray) array).indexCount; int[] stripVertexCounts = ((VisADIndexedTriangleStripArray) array).stripVertexCounts; int base = 0; for (int strip=0; strip<stripVertexCounts.length; strip++) { count = stripVertexCounts[strip]; int index0 = indices[base]; int index1 = indices[base+1]; if (colors == null) { for (int i=base+2; i<base+count; i++) { int index2 = indices[i]; GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); path.moveTo(coordinates[3*index0], coordinates[3*index0+1]); path.lineTo(coordinates[3*index1], coordinates[3*index1+1]); path.lineTo(coordinates[3*index2], coordinates[3*index2+1]); path.closePath(); g2.fill(path); index0 = index1; index1 = index2; } } else { // colors != null int jinc = (colors.length == coordinates.length) ? 3 : 4; for (int i=base+2; i<base+count; i++) { int index2 = indices[i]; g2.setColor(new Color( (((colors[jinc*index0] < 0) ? (((int) colors[jinc*index0]) + 256) : ((int) colors[jinc*index0]) ) + ((colors[jinc*index1] < 0) ? (((int) colors[jinc*index1]) + 256) : ((int) colors[jinc*index1]) ) + ((colors[jinc*index2] < 0) ? (((int) colors[jinc*index2]) + 256) : ((int) colors[jinc*index2]) ) ) / 3, (((colors[jinc*index0+1] < 0) ? (((int) colors[jinc*index0+1]) + 256) : ((int) colors[jinc*index0+1]) ) + ((colors[jinc*index1+1] < 0) ? (((int) colors[jinc*index1+1]) + 256) : ((int) colors[jinc*index1+1]) ) + ((colors[jinc*index2+1] < 0) ? (((int) colors[jinc*index2+1]) + 256) : ((int) colors[jinc*index2+1]) ) ) / 3, (((colors[jinc*index0+2] < 0) ? (((int) colors[jinc*index0+2]) + 256) : ((int) colors[jinc*index0+2]) ) + ((colors[jinc*index1+2] < 0) ? (((int) colors[jinc*index1+2]) + 256) : ((int) colors[jinc*index1+2]) ) + ((colors[jinc*index2+2] < 0) ? (((int) colors[jinc*index2+2]) + 256) : ((int) colors[jinc*index2+2]) ) ) / 3 )); GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); path.moveTo(coordinates[3*index0], coordinates[3*index0+1]); path.lineTo(coordinates[3*index1], coordinates[3*index1+1]); path.lineTo(coordinates[3*index2], coordinates[3*index2+1]); path.closePath(); g2.fill(path); index0 = index1; index1 = index2; } } base += count; } } // end if (array instanceof VisADIndexedTriangleStripArray) else if (array instanceof VisADTriangleStripArray) { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); int[] stripVertexCounts = ((VisADTriangleStripArray) array).stripVertexCounts; int base = 0; int basec = 0; int jinc = 0; if (colors != null) { jinc = (colors.length == coordinates.length) ? 3 : 4; } for (int strip=0; strip<stripVertexCounts.length; strip++) { count = stripVertexCounts[strip]; float oldx = coordinates[base]; float oldy = coordinates[base+1]; float lastx = coordinates[base+3]; float lasty = coordinates[base+4]; int oldr = 0, oldg = 0, oldb = 0; int lastr = 0, lastg = 0, lastb = 0; int thisr, thisg, thisb; if (colors != null) { oldr = (colors[basec] < 0) ? (((int) colors[basec]) + 256) : ((int) colors[basec]); oldg = (colors[basec+1] < 0) ? (((int) colors[basec+1]) + 256) : ((int) colors[basec+1]); oldb = (colors[basec+2] < 0) ? (((int) colors[basec+2]) + 256) : ((int) colors[basec+2]); lastr = (colors[basec+jinc] < 0) ? (((int) colors[basec+jinc]) + 256) : ((int) colors[basec+jinc]); lastg = (colors[basec+jinc+1] < 0) ? (((int) colors[basec+jinc+1]) + 256) : ((int) colors[basec+jinc+1]); lastb = (colors[basec+jinc+2] < 0) ? (((int) colors[basec+jinc+2]) + 256) : ((int) colors[basec+jinc+2]); } if (colors == null) { for (int i=6; i<3*count; i+=3) { GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); path.moveTo(oldx, oldy); path.lineTo(lastx, lasty); path.lineTo(coordinates[base+i], coordinates[base+i+1]); path.closePath(); g2.fill(path); oldx = lastx; oldy = lasty; lastx = coordinates[base+i]; lasty = coordinates[base+i+1]; } // end for (int i=6; i<3*count; i+=3) } else { // colors != null int j = 2 * jinc; /* System.out.println(j + " " + jinc + " " + basec); */ for (int i=6; i<3*count; i+=3) { thisr = (colors[basec+j] < 0) ? (((int) colors[basec+j]) + 256) : ((int) colors[basec+j]); thisg = (colors[basec+j+1] < 0) ? (((int) colors[basec+j+1]) + 256) : ((int) colors[basec+j+1]); thisb = (colors[basec+j+2] < 0) ? (((int) colors[basec+j+2]) + 256) : ((int) colors[basec+j+2]); g2.setColor(new Color((thisr + lastr + oldr)/3, (thisg + lastg + oldg)/3, (thisb + lastb + oldb)/3)); /* System.out.println(i + " " + oldr + " " + oldg + " " + oldb + " " + lastr + " " + lastg + " " + lastb + " " + thisr + " " + thisg + " " + thisb); */ oldr = lastr; oldg = lastg; oldb = lastb; lastr = thisr; lastg = thisg; lastb = thisb; j += jinc; GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); path.moveTo(oldx, oldy); path.lineTo(lastx, lasty); path.lineTo(coordinates[base+i], coordinates[base+i+1]); path.closePath(); g2.fill(path); /* System.out.println(i + " " + oldx + " " + oldy + " " + lastx + " " + lasty + " " + coordinates[base+i] + " " + coordinates[base+i+1]); */ oldx = lastx; oldy = lasty; lastx = coordinates[base+i]; lasty = coordinates[base+i+1]; } // end for (int i=6; i<3*count; i+=3) } base += 3 * count; basec += jinc * count; } // end for (int strip=0; strip<stripVertexCounts.length; strip++) } // end if (array instanceof VisADTriangleStripArray) else { throw new VisADError("VisADCanvasJ2D.render: bad array class"); } } // end if (image == null) } // end if (scene instanceof VisADAppearance) } /** * This assumes only VisADPointArray or VisADLineArray. * @param graphics * @param appearance * @param t * @param clip */ public static void drawAppearance(Graphics graphics, VisADAppearance appearance, AffineTransform t, Rectangle2D.Float clip) { VisADGeometryArray array = appearance.array; if (array == null) return; byte[] colors = array.colors; if (colors == null) { if (appearance.color_flag) { graphics.setColor(new Color(appearance.red, appearance.green, appearance.blue)); /* System.out.println("drawAppearance: color = " + appearance.red + " " + appearance.green + " " + appearance.blue); */ } else { graphics.setColor(new Color(1.0f, 1.0f, 1.0f)); } } int count = array.vertexCount; float[] coordinates = array.coordinates; float[] oldcoords = new float[2*count]; int j = 0; for (int i=0; i<3*count; i += 3) { oldcoords[j++] = coordinates[i]; oldcoords[j++] = coordinates[i+1]; } float[] newcoords = new float[2 * count]; t.transform(oldcoords, 0, newcoords, 0, count); if (clip == null) { graphics.setClip(null); } else { // transform clip float x = (float) clip.getX(); float y = (float) clip.getY(); float width = (float) clip.getWidth(); float height = (float) clip.getHeight(); float[] oldclip = {x, y, x, y+height, x+width, y+height, x+width, y}; float[] newclip = new float[2 * 4]; t.transform(oldclip, 0, newclip, 0, 4); GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); path.moveTo(newclip[0], newclip[1]); path.lineTo(newclip[2], newclip[3]); path.lineTo(newclip[4], newclip[5]); path.lineTo(newclip[6], newclip[7]); path.closePath(); graphics.setClip(path); } if (array instanceof VisADPointArray) { /* System.out.println("drawAppearance: VisADPointArray, count = " + count); */ if (colors == null) { for (int i=0; i<2*count; i += 2) { graphics.drawLine((int) newcoords[i], (int) newcoords[i+1], (int) newcoords[i], (int) newcoords[i+1]); } } else { // colors != null int jinc = (colors.length == coordinates.length) ? 3 : 4; j = 0; for (int i=0; i<2*count; i += 2) { graphics.setColor(new Color( ((colors[j] < 0) ? (((int) colors[j]) + 256) : ((int) colors[j]) ), ((colors[j+1] < 0) ? (((int) colors[j+1]) + 256) : ((int) colors[j+1]) ), ((colors[j+2] < 0) ? (((int) colors[j+2]) + 256) : ((int) colors[j+2]) ) )); j += jinc; graphics.drawLine((int) newcoords[i], (int) newcoords[i+1], (int) newcoords[i], (int) newcoords[i+1]); } } } else if (array instanceof VisADLineArray) { /* System.out.println("drawAppearance: VisADLineArray, count = " + count + " colors == null " + (colors == null)); */ if (colors == null) { for (int i=0; i<2*count; i += 4) { int width = (int) appearance.lineWidth; int x1 = (int) newcoords[i]; int y1 = (int) newcoords[i+1]; int x2 = (int) newcoords[i+2]; int y2 = (int) newcoords[i+3]; if (width <= 1 || (x1 != x2 && y1 != y2)) { graphics.drawLine(x1, y1, x2, y2); } else { // (width > 1 && (x1 == x2 || y1 == y2)) int hw1 = width / 2; int hw2 = width - hw1; int[] xPoints = null; int[] yPoints = null; if (x1 == x2) { xPoints = new int[] {x1 - hw1, x1 + hw2, x1 + hw2, x1 - hw1}; yPoints = new int[] {y1, y1, y2, y2}; } else { // y1 == y2 xPoints = new int[] {x1, x1, x2, x2}; yPoints = new int[] {y1 - hw1, y1 + hw2, y1 + hw2, y1 - hw1}; } graphics.fillPolygon(xPoints, yPoints, 4); } /* graphics.drawLine((int) newcoords[i], (int) newcoords[i+1], (int) newcoords[i+2], (int) newcoords[i+3]); */ /* System.out.println(" " + newcoords[i] + " " + newcoords[i+1] + " " + newcoords[i+2] + " " + newcoords[i+3]); */ } } else { // colors != null int jinc = (colors.length == coordinates.length) ? 3 : 4; j = 0; for (int i=0; i<2*count; i += 4) { graphics.setColor(new Color( (((colors[j] < 0) ? (((int) colors[j]) + 256) : ((int) colors[j]) ) + ((colors[j+jinc] < 0) ? (((int) colors[j+jinc]) + 256) : ((int) colors[j+jinc]) ) ) / 2, (((colors[j+1] < 0) ? (((int) colors[j+1]) + 256) : ((int) colors[j+1]) ) + ((colors[j+jinc+1] < 0) ? (((int) colors[j+jinc+1]) + 256) : ((int) colors[j+jinc+1]) ) ) / 2, (((colors[j+2] < 0) ? (((int) colors[j+2]) + 256) : ((int) colors[j+2]) ) + ((colors[j+jinc+2] < 0) ? (((int) colors[j+jinc+2]) + 256) : ((int) colors[j+jinc+2]) ) ) / 2 )); j += 2 * jinc; int width = (int) appearance.lineWidth; int x1 = (int) newcoords[i]; int y1 = (int) newcoords[i+1]; int x2 = (int) newcoords[i+2]; int y2 = (int) newcoords[i+3]; if (width <= 1 || (x1 != x2 && y1 != y2)) { graphics.drawLine(x1, y1, x2, y2); } else { // (width > 1 && (x1 == x2 || y1 == y2)) int hw1 = width / 2; int hw2 = width - hw1; int[] xPoints = null; int[] yPoints = null; if (x1 == x2) { xPoints = new int[] {x1 - hw1, x1 + hw2, x1 + hw2, x1 - hw1}; yPoints = new int[] {y1, y1, y2, y2}; } else { // y1 == y2 xPoints = new int[] {x1, x1, x2, x2}; yPoints = new int[] {y1 - hw1, y1 + hw2, y1 + hw2, y1 - hw1}; } graphics.fillPolygon(xPoints, yPoints, 4); } /* graphics.drawLine((int) newcoords[i], (int) newcoords[i+1], (int) newcoords[i+2], (int) newcoords[i+3]); */ } } } else { throw new VisADError("DisplayRendererJ2D.drawAppearance: " + "bad VisADGeometryArray type"); } } public AffineTransform getTransform() { synchronized (images) { return tgeometry; } } public Dimension getPreferredSize() { return prefSize; } public void setPreferredSize(Dimension size) { prefSize = size; } // CTR 14 Nov 2000 - support for auto-aspect to canvas size private boolean autoAspect = false; public boolean getAutoAspect() { return autoAspect; } public void setAutoAspect(boolean auto) { autoAspect = auto; } public void setBounds(int x, int y, int width, int height) { if (width < 1 || height < 1) return; super.setBounds(x, y, width, height); if (autoAspect) { ProjectionControl pc = display.getProjectionControl(); try { double a, b; if (height > width) { a = 1.0; b = ((double) height) / ((double) width); } else { a = ((double) width) / ((double) height); b = 1.0; } pc.setAspectCartesian(new double[] {a, b}); } catch (VisADException exc) { } catch (RemoteException exc) { } } } }