Mercurial > hg > ccmieditor
view java/src/uk/ac/qmul/eecs/ccmi/simpletemplate/TriangularNode.java @ 8:ea7885bd9bff tip
fixed bug : render solid line as dotted/dashed when moving the stylus from dotted/dashed to solid
author | ccmi-guest |
---|---|
date | Thu, 03 Jul 2014 16:12:20 +0100 |
parents | 9418ab7b7f3f |
children |
line wrap: on
line source
/* CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package uk.ac.qmul.eecs.ccmi.simpletemplate; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D.Double; import java.io.InputStream; import java.util.List; import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeProperties; import uk.ac.qmul.eecs.ccmi.gui.Direction; import uk.ac.qmul.eecs.ccmi.sound.SoundFactory; /** * * A triangular shaped diagram node. * */ @SuppressWarnings("serial") public class TriangularNode extends SimpleShapeNode { public TriangularNode(String typeName, NodeProperties properties) { super(typeName, properties); Rectangle2D dataBounds = getMinBounds(); dataDisplayBounds.setFrame(dataBounds); tShape = getOutShape(dataBounds); /* by building the shape around dataBounds which was at (0,0) the new bounds */ /* are now negative, so we need to bring the new bounds back at (0,0) */ Rectangle2D bounds = getBounds(); translateImplementation(new Point2D.Double(),0-bounds.getX(),0-bounds.getY()); } @Override protected Rectangle2D getMinBounds(){ Rectangle2D minBounds = super.getMinBounds(); return new Rectangle2D.Double(minBounds.getX(),minBounds.getY(),minBounds.getWidth()/2,minBounds.getHeight()/2); } @Override public ShapeType getShapeType() { return ShapeType.Triangle; } @Override protected void translateImplementation(Point2D p, double dx, double dy){ /* if we clicked on a property node, just move that one */ for(List<PropertyNode> pnList : propertyNodesMap.values()) for(PropertyNode pn : pnList) if(pn.contains(p)){ pn.translate(dx, dy); return; } super.translateImplementation(p,dx, dy); tShape.transform(AffineTransform.getTranslateInstance(dx, dy)); } public static Path2D.Double getOutShape(Rectangle2D r){ Path2D.Double triangle = new Path2D.Double(GeneralPath.WIND_EVEN_ODD,3); double minEdge = Math.min(r.getWidth(), r.getHeight()); triangle.moveTo(r.getCenterX(), r.getY()-minEdge); double angle = Math.atan(minEdge/(r.getWidth()/2)); double w = r.getHeight()/ Math.tan(angle); triangle.lineTo(r.getX()-w, r.getMaxY()); triangle.lineTo(r.getMaxX()+w, r.getMaxY()); triangle.closePath(); return triangle; } @Override protected void reshapeInnerProperties(List<String> insidePropertyTypes){ nameLabel = new MultiLineString(); nameLabel.setText(getName().isEmpty() ? " " : getName()); nameLabel.setBold(true); if(!super.anyInsideProperties()){ dataDisplayBounds.setFrame(dataDisplayBounds.getX(), dataDisplayBounds.getY(), nameLabel.getBounds().getWidth(), nameLabel.getBounds().getHeight()); Rectangle2D minBounds = getMinBounds(); dataDisplayBounds.add(new Rectangle2D.Double(dataDisplayBounds.getX(), dataDisplayBounds.getY(), minBounds.getWidth(),minBounds.getHeight())); tShape = getOutShape(dataDisplayBounds); }else { Rectangle2D r = nameLabel.getBounds(); for(int i=0; i<insidePropertyTypes.size();i++){ propertyLabels[i] = new MultiLineString(); if(getProperties().getValues(insidePropertyTypes.get(i)).size() == 0){ propertyLabels[i].setText(" "); }else{ propertyLabels[i].setJustification(MultiLineString.LEFT); String[] a = new String[getProperties().getValues(insidePropertyTypes.get(i)).size()]; propertyLabels[i].setText(getProperties().getValues(insidePropertyTypes.get(i)).toArray(a), getProperties().getModifiers(insidePropertyTypes.get(i))); } r.add(new Rectangle2D.Double(r.getX(),r.getMaxY(),propertyLabels[i].getBounds().getWidth(),propertyLabels[i].getBounds().getHeight())); } /* set a gap to uniformly distribute the extra space among property rectangles to reach the minimum bound's height */ boundsGap = 0; Rectangle2D.Double minBounds = (Rectangle2D.Double)getMinBounds(); if(r.getHeight() < minBounds.height){ boundsGap = minBounds.height - r.getHeight(); boundsGap /= insidePropertyTypes.size(); } r.add(minBounds); dataDisplayBounds.setFrame(new Rectangle2D.Double(dataDisplayBounds.x,dataDisplayBounds.y,r.getWidth(),r.getHeight())); tShape = getOutShape(dataDisplayBounds); } } @Override public Double getBounds() { return (Double)tShape.getBounds2D(); } @Override public InputStream getSound(){ return sound; } @Override public Point2D getConnectionPoint(Direction d) { return calculateConnectionPoint(d,getBounds()); } public static Point2D calculateConnectionPoint(Direction d, Rectangle2D bounds) { if(d.getX() == 0){ return new Point2D.Double(bounds.getCenterX(), d.getY() > 0 ? bounds.getY() : bounds.getMaxY()); } boolean left = false; boolean right = false; double dirTan = d.getY()/d.getX(); double boundsTan = bounds.getHeight()/bounds.getWidth(); double alfa = Math.atan(dirTan); double alfaDegrees = Math.toDegrees(alfa); if(d.getY() < 0){ //from the top if(alfaDegrees < 0) right = true; else left = true; }else{ //from the bottom if(dirTan < boundsTan && d.getX() > 0) right = true; else if(dirTan > -boundsTan && d.getX() < 0) left = true; } if(right){ double beta = Math.atan(bounds.getHeight()/(bounds.getWidth()/2)); double py = bounds.getHeight()/2; double x = py/ (Math.tan(alfa)-Math.tan(beta)); double y = x * Math.tan(alfa); return new Point2D.Double(bounds.getCenterX()-x, bounds.getCenterY()-y); } else if(left){ double beta = - Math.atan(bounds.getHeight()/(bounds.getWidth()/2)); double py = bounds.getHeight()/2; double x = py/ (Math.tan(alfa)-Math.tan(beta)); double y = x * Math.tan(alfa); return new Point2D.Double(bounds.getCenterX()-x, bounds.getCenterY()-y); } else{ return new Point2D.Double( bounds.getCenterX() + ((bounds.getHeight()/2) * (d.getX()/d.getY()) ), bounds.getMaxY()); } } @Override public Shape getShape() { return tShape; } public Object clone(){ return new TriangularNode(getType(),(NodeProperties)getProperties().clone()); } private Path2D.Double tShape; private static InputStream sound; static { sound = TriangularNode.class.getResourceAsStream("audio/Triangle.mp3"); SoundFactory.getInstance().loadSound(sound); } }