1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.g2d.element.handler.impl;
14 import java.awt.geom.AffineTransform;
15 import java.awt.geom.Point2D;
16 import java.util.Collection;
18 import org.simantics.g2d.canvas.ICanvasContext;
19 import org.simantics.g2d.diagram.IDiagram;
20 import org.simantics.g2d.element.ElementHints;
21 import org.simantics.g2d.element.IElement;
22 import org.simantics.g2d.element.handler.LifeCycle;
23 import org.simantics.g2d.element.handler.Move;
24 import org.simantics.g2d.element.handler.Rotate;
25 import org.simantics.g2d.element.handler.Scale;
26 import org.simantics.g2d.element.handler.Transform;
27 import org.simantics.g2d.element.handler.Validator;
30 * This class implements Transform, Move, Rotate, and Scale.
31 * It maintains element position in element variable ElementHints.KEY_TRANSFORM.
33 * @author Toni Kalajainen
35 public class DefaultTransform implements Transform, Move, Rotate, Scale, Validator, LifeCycle {
37 private static final long serialVersionUID = -2394690413166528179L;
39 public static final DefaultTransform INSTANCE = new DefaultTransform(null);
43 public DefaultTransform() {
47 public DefaultTransform(Double aspectRatio) {
48 this.aspectRatio = aspectRatio;
52 public Double getFixedAspectRatio(IElement e) {
57 public Point2D getScale(IElement e) {
58 AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM);
63 public void setScale(IElement e, Point2D newScale) {
64 Point2D oldScale = getScale(e);
65 double sx = newScale.getX() / oldScale.getX();
66 double sy = newScale.getY() / oldScale.getY();
67 AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM);
68 at = new AffineTransform(at);
70 e.setHint(ElementHints.KEY_TRANSFORM, at);
74 public Point2D getMaximumScale(IElement e) {
79 public Point2D getMinimumScale(IElement e) {
83 private static Point2D _getScale(AffineTransform at) {
84 double m00 = at.getScaleX();
85 double m11 = at.getScaleY();
86 double m10 = at.getShearY();
87 double m01 = at.getShearX();
88 // Project unit vector to canvas
89 double sx = Math.sqrt(m00 * m00 + m10 * m10);
90 double sy = Math.sqrt(m01 * m01 + m11 * m11);
91 return new Point2D.Double(sx, sy);
95 public void validate(final IElement e, final ICanvasContext ctx, Collection<Issue> lst) {
97 if (aspectRatio != null) {
98 // Validate aspect ratio
99 final Point2D scale = getScale(e);
100 double currentRatio = scale.getX() / scale.getY();
101 if (Math.abs(currentRatio - aspectRatio) > 0.000001) {
102 lst.add(new Issue() {
104 public String getMessage() {
105 return "Aspect ratio is wrong";
109 public void addSuggestions(
110 Collection<Suggestion> suggestionList) {
111 suggestionList.add(new Suggestion() {
113 public boolean fix() {
114 double newSx = scale.getX();
115 double newSy = newSx * aspectRatio;
116 Point2D newScale = new Point2D.Double(newSx,
118 setScale(e, newScale);
124 public String getMessage() {
125 return "Scale height, keep width";
131 // TODO min scale validator
132 // TODO max scale validator
135 if (e.getHint(ElementHints.KEY_TRANSFORM) == null) {
136 Issue i = new Issue() {
138 public String getMessage() {
139 return "Transform is missing";
143 public void addSuggestions(Collection<Suggestion> suggestionList) {
144 Suggestion s = new Suggestion() {
146 public boolean fix() {
147 e.setHint(ElementHints.KEY_TRANSFORM,
148 new AffineTransform());
153 public String getMessage() {
154 return "Set default transform";
157 suggestionList.add(s);
166 public void rotate(IElement e, double theta, Point2D origo) {
167 if (Double.isNaN(theta)) return;
168 AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM);
169 at = (AffineTransform) at.clone();
170 Point2D localOrigo = at.transform(origo, null);
171 at.preConcatenate(AffineTransform.getRotateInstance(theta, localOrigo.getX(), localOrigo.getY()));
172 // This code concatenated the matrix from the wrong side
173 //at.rotate(theta, origo.getX(), origo.getY());
174 e.setHint(ElementHints.KEY_TRANSFORM, at);
178 public double getAngle(IElement e) {
179 AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM);
180 double m01 = at.getShearX();
181 double m11 = at.getScaleY();
182 return -Math.atan2(m01, m11);
186 public Point2D getPosition(IElement e) {
187 AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM);
188 Point2D p = new Point2D.Double(at.getTranslateX(), at.getTranslateY());
193 public void moveTo(IElement e, double x, double y) {
194 AffineTransform origAt = e.getHint(ElementHints.KEY_TRANSFORM);
196 AffineTransform result = new AffineTransform(origAt);
197 result.preConcatenate(AffineTransform.getTranslateInstance(x - origAt.getTranslateX(), y - origAt.getTranslateY()));
198 e.setHint(ElementHints.KEY_TRANSFORM, result);
202 public AffineTransform getTransform(IElement e) {
204 AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM);
206 IElement parentElement = e.getHint(ElementHints.KEY_PARENT_ELEMENT);
207 if(parentElement == null) return at;
209 Transform parentTransform = parentElement.getElementClass().getSingleItem(Transform.class);
210 assert(parentTransform!=null);
212 AffineTransform result = (AffineTransform)at.clone();
213 AffineTransform parentAT = parentTransform.getTransform(parentElement);
214 result.preConcatenate(AffineTransform.getTranslateInstance(parentAT.getTranslateX(), parentAT.getTranslateY()));
221 public void setTransform(IElement e, AffineTransform at) {
222 e.setHint(ElementHints.KEY_TRANSFORM, at.clone());
226 public void onElementActivated(IDiagram d, IElement e) {
230 public void onElementCreated(IElement e) {
231 e.setHint(ElementHints.KEY_TRANSFORM, new AffineTransform());
235 public void onElementDeactivated(IDiagram d, IElement e) {
239 public void onElementDestroyed(IElement e) {