/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.scenegraph.g2d.nodes; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import org.simantics.scenegraph.g2d.G2DNode; import org.simantics.scenegraph.utils.InitValueSupport; public class EdgeNode extends G2DNode implements InitValueSupport { private static final long serialVersionUID = 1294351381209071074L; public static enum ArrowType { None, Stroke, Fill, Both } protected Color color = null; protected Stroke stroke = null; protected Shape shape = null; protected Point2D firstdir = null; protected Point2D lastdir = null; protected Point2D first = null; protected Point2D last = null; protected double firstsize = 0; protected double lastsize = 0; protected ArrowType first_at = null; protected ArrowType last_at = null; protected Shape firstShape = null; protected Shape lastShape = null; private transient Rectangle2D bounds; @SyncField({"color", "stroke", "shape", "firstdir", "lastdir", "first", "last", "firstsize", "lastsize", "first_at", "last_at"}) public void init(Shape shape, Stroke stroke, Color color, Point2D firstdir, Point2D lastdir, Point2D first, Point2D last, double firstsize, double lastsize, ArrowType first_at, ArrowType last_at, Shape firstShape, Shape lastShape) { this.color = color; this.stroke = stroke; this.shape = shape; this.firstdir = firstdir; this.lastdir = lastdir; this.first = first; this.last = last; this.firstsize = firstsize; this.lastsize = lastsize; this.first_at = first_at; this.last_at = last_at; this.firstShape = firstShape; this.lastShape = lastShape; if (shape != null) { this.bounds = shape.getBounds2D(); } } @Override public void render(Graphics2D g) { if(color != null) g.setColor(color); if(stroke == null || shape == null) return; if(alphaComposite != null) { g.setComposite(alphaComposite); } Stroke effectiveStroke = stroke; if(dynamicStroke != null) { effectiveStroke = dynamicStroke; } Color effectiveColor = color; if(dynamicColor != null) { effectiveColor = dynamicColor; } g.setStroke(effectiveStroke); // NICENESS //g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //g.draw(shape); // Draw line "halo" // float f = ((BasicStroke)effectiveStroke).getLineWidth() * 3f; // Color background = Color.WHITE; // FIXME // g.setColor(background); // g.setStroke(new BasicStroke(f)); // g.draw(shape); // Draw line g.setColor(effectiveColor); g.setStroke(effectiveStroke); g.draw(shape); // Draw line ends if necessary. boolean drawArrows = first_at != ArrowType.None || last_at != ArrowType.None; if (!drawArrows) return; AffineTransform at = g.getTransform(); g.setStroke(ARROW_STROKE); if (first_at != ArrowType.None) { double theta = Math.atan2(firstdir.getY(), firstdir.getX()) - Math.PI/2; g.translate(first.getX(), first.getY()); g.rotate(theta); g.scale(firstsize, firstsize); if (first_at == ArrowType.Fill) g.fill(FILLED_ARROW); else if (first_at == ArrowType.Stroke) g.draw(NORMAL_ARROW); g.setTransform(at); } if (last_at != ArrowType.None) { double theta = Math.atan2(lastdir.getY(), lastdir.getX()) - Math.PI/2; g.translate(last.getX(), last.getY()); g.rotate(theta); g.scale(lastsize, lastsize); if (last_at == ArrowType.Fill) g.fill(FILLED_ARROW); else if (last_at == ArrowType.Stroke) g.draw(NORMAL_ARROW); g.setTransform(at); } } public transient final static GeneralPath NORMAL_ARROW; public transient final static GeneralPath FILLED_ARROW; public transient static final Stroke ARROW_STROKE = new BasicStroke(1.0f); static { FILLED_ARROW = new GeneralPath(); FILLED_ARROW.moveTo(-0.5f, 1f); FILLED_ARROW.lineTo( 0f, 0f); FILLED_ARROW.lineTo( 0.5f, 1f); FILLED_ARROW.closePath(); NORMAL_ARROW = new GeneralPath(); NORMAL_ARROW.moveTo(-0.5f, 1f); NORMAL_ARROW.lineTo( 0f, 0f); NORMAL_ARROW.lineTo( 0.5f, 1f); } @Override public Rectangle2D getBoundsInLocal() { return bounds; } protected Composite alphaComposite = null; protected Stroke dynamicStroke = null; protected Color dynamicColor = null; @PropertySetter("alpha") @SyncField("alphaComposite") public void setAlphaComposite(Composite alphaComposite) { this.alphaComposite = alphaComposite; } @PropertySetter("width") @SyncField("dynamicStroke") public void setDynamicStroke(Stroke stroke) { this.dynamicStroke = stroke; } @PropertySetter("color") @SyncField("dynamicColor") public void setDynamicColor(Color color) { this.dynamicColor = color; } // public void setValue(String key, Object value) { // // if ("alpha".equals(key)) { // Float val = Float.parseFloat((String)value); // alphaComposite = AlphaComposite.getInstance(AlphaComposite. SRC_OVER, val); // } else if ("width".equals(key)) { // dynamicStroke = new BasicStroke(Float.parseFloat((String)value)); // } else if ("color".equals(key)) { // try { // dynamicColor = new Color(Integer.parseInt(value.toString(), 16)); // } catch (Throwable t) { // t.printStackTrace(); // } // } // } @Override public void initValues() { dynamicStroke = null; dynamicColor = null; alphaComposite = null; } }