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