/******************************************************************************* * 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.g2d.element.handler.impl; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.util.Collection; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.diagram.IDiagram; import org.simantics.g2d.element.ElementHints; import org.simantics.g2d.element.IElement; import org.simantics.g2d.element.handler.LifeCycle; import org.simantics.g2d.element.handler.Move; import org.simantics.g2d.element.handler.Rotate; import org.simantics.g2d.element.handler.Scale; import org.simantics.g2d.element.handler.Transform; import org.simantics.g2d.element.handler.Validator; /** * This class implements Transform, Move, Rotate, and Scale. * It maintains element position in element variable ElementHints.KEY_TRANSFORM. * * @author Toni Kalajainen */ public class DefaultTransform implements Transform, Move, Rotate, Scale, Validator, LifeCycle { private static final long serialVersionUID = -2394690413166528179L; public static final DefaultTransform INSTANCE = new DefaultTransform(null); Double aspectRatio; public DefaultTransform() { this(null); } public DefaultTransform(Double aspectRatio) { this.aspectRatio = aspectRatio; } @Override public Double getFixedAspectRatio(IElement e) { return aspectRatio; } @Override public Point2D getScale(IElement e) { AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM); return _getScale(at); } @Override public void setScale(IElement e, Point2D newScale) { Point2D oldScale = getScale(e); double sx = newScale.getX() / oldScale.getX(); double sy = newScale.getY() / oldScale.getY(); AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM); at = new AffineTransform(at); at.scale(sx, sy); e.setHint(ElementHints.KEY_TRANSFORM, at); } @Override public Point2D getMaximumScale(IElement e) { return null; } @Override public Point2D getMinimumScale(IElement e) { return null; } private static Point2D _getScale(AffineTransform at) { double m00 = at.getScaleX(); double m11 = at.getScaleY(); double m10 = at.getShearY(); double m01 = at.getShearX(); // Project unit vector to canvas double sx = Math.sqrt(m00 * m00 + m10 * m10); double sy = Math.sqrt(m01 * m01 + m11 * m11); return new Point2D.Double(sx, sy); } @Override public void validate(final IElement e, final ICanvasContext ctx, Collection lst) { /* if (aspectRatio != null) { // Validate aspect ratio final Point2D scale = getScale(e); double currentRatio = scale.getX() / scale.getY(); if (Math.abs(currentRatio - aspectRatio) > 0.000001) { lst.add(new Issue() { @Override public String getMessage() { return "Aspect ratio is wrong"; } @Override public void addSuggestions( Collection suggestionList) { suggestionList.add(new Suggestion() { @Override public boolean fix() { double newSx = scale.getX(); double newSy = newSx * aspectRatio; Point2D newScale = new Point2D.Double(newSx, newSy); setScale(e, newScale); ctx.setDirty(); return true; } @Override public String getMessage() { return "Scale height, keep width"; } }); } }); } // TODO min scale validator // TODO max scale validator } if (e.getHint(ElementHints.KEY_TRANSFORM) == null) { Issue i = new Issue() { @Override public String getMessage() { return "Transform is missing"; } @Override public void addSuggestions(Collection suggestionList) { Suggestion s = new Suggestion() { @Override public boolean fix() { e.setHint(ElementHints.KEY_TRANSFORM, new AffineTransform()); return true; } @Override public String getMessage() { return "Set default transform"; } }; suggestionList.add(s); } }; lst.add(i); } */ } @Override public void rotate(IElement e, double theta, Point2D origo) { if (Double.isNaN(theta)) return; AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM); at = (AffineTransform) at.clone(); Point2D localOrigo = at.transform(origo, null); at.preConcatenate(AffineTransform.getRotateInstance(theta, localOrigo.getX(), localOrigo.getY())); // This code concatenated the matrix from the wrong side //at.rotate(theta, origo.getX(), origo.getY()); e.setHint(ElementHints.KEY_TRANSFORM, at); } @Override public double getAngle(IElement e) { AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM); double m01 = at.getShearX(); double m11 = at.getScaleY(); return -Math.atan2(m01, m11); } @Override public Point2D getPosition(IElement e) { AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM); Point2D p = new Point2D.Double(at.getTranslateX(), at.getTranslateY()); return p; } @Override public void moveTo(IElement e, double x, double y) { AffineTransform origAt = e.getHint(ElementHints.KEY_TRANSFORM); AffineTransform result = new AffineTransform(origAt); result.preConcatenate(AffineTransform.getTranslateInstance(x - origAt.getTranslateX(), y - origAt.getTranslateY())); e.setHint(ElementHints.KEY_TRANSFORM, result); } @Override public AffineTransform getTransform(IElement e) { AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM); IElement parentElement = e.getHint(ElementHints.KEY_PARENT_ELEMENT); if(parentElement == null) return at; Transform parentTransform = parentElement.getElementClass().getSingleItem(Transform.class); assert(parentTransform!=null); AffineTransform result = (AffineTransform)at.clone(); AffineTransform parentAT = parentTransform.getTransform(parentElement); result.preConcatenate(AffineTransform.getTranslateInstance(parentAT.getTranslateX(), parentAT.getTranslateY())); return result; } @Override public void setTransform(IElement e, AffineTransform at) { e.setHint(ElementHints.KEY_TRANSFORM, at.clone()); } @Override public void onElementActivated(IDiagram d, IElement e) { } @Override public void onElementCreated(IElement e) { e.setHint(ElementHints.KEY_TRANSFORM, new AffineTransform()); } @Override public void onElementDeactivated(IDiagram d, IElement e) { } @Override public void onElementDestroyed(IElement e) { } }