X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fhandler%2FMouseScaleMode.java;h=32df540eec5a10ea41da8062652b30d16002d4dd;hp=8ba0ba7095c0aa3eac80ceff4b36c845fedf3acc;hb=668112002bdc3a7f35e4f0f865a437c91f7dce10;hpb=969bd23cab98a79ca9101af33334000879fb60c5 diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/MouseScaleMode.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/MouseScaleMode.java index 8ba0ba709..32df540ee 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/MouseScaleMode.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/MouseScaleMode.java @@ -1,370 +1,370 @@ -/******************************************************************************* - * 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.diagram.handler; - -import java.awt.AlphaComposite; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.simantics.Simantics; -import org.simantics.db.Resource; -import org.simantics.diagram.elements.ElementTransforms; -import org.simantics.diagram.elements.ElementTransforms.TransformedObject; -import org.simantics.g2d.canvas.ICanvasContext; -import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; -import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup; -import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit; -import org.simantics.g2d.diagram.DiagramHints; -import org.simantics.g2d.diagram.participant.ElementPainter; -import org.simantics.g2d.diagram.participant.pointertool.AbstractMode; -import org.simantics.g2d.element.ElementClass; -import org.simantics.g2d.element.ElementUtils; -import org.simantics.g2d.element.IElement; -import org.simantics.g2d.element.SceneGraphNodeKey; -import org.simantics.g2d.element.handler.Scale; -import org.simantics.g2d.element.handler.Transform; -import org.simantics.g2d.element.impl.MutatedElement; -import org.simantics.g2d.participant.MouseUtil.MouseInfo; -import org.simantics.scenegraph.INode; -import org.simantics.scenegraph.g2d.G2DParentNode; -import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; -import org.simantics.scenegraph.g2d.events.KeyEvent; -import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent; -import org.simantics.scenegraph.g2d.events.command.CommandEvent; -import org.simantics.scenegraph.g2d.events.command.Commands; -import org.simantics.scenegraph.g2d.nodes.SingleElementNode; -import org.simantics.scenegraph.g2d.snap.ISnapAdvisor; -import org.simantics.utils.datastructures.hints.IHintContext.Key; - -/** - * @author Tuukka Lehtonen - */ -public class MouseScaleMode extends AbstractMode { - - private static final Key KEY_SCALE_NODE = new SceneGraphNodeKey(INode.class, "SCALE_NODE"); - - private static final boolean DEBUG = false; - - @Dependency ElementPainter painter; - - /** - * The set of elements that are being scaled. - */ - Set selection; - - Map originalScales = new HashMap(); - Map scaledElements = new HashMap(); - - Point2D initialMousePos; - Point2D pivotPosition; - AffineTransform pivot; - AffineTransform pivotInverse; - Point2D lastMousePos = new Point2D.Double(); - Point2D newScale = new Point2D.Double(); - - final ISnapAdvisor snapAdvisor; - - final static public ISnapAdvisor DEFAULT_SNAP = new ISnapAdvisor() { - - @Override - public void snap(Point2D point) { - double resolution = 0.1; - point.setLocation( - Math.round(point.getX() / resolution) * resolution, - Math.round(point.getY() / resolution) * resolution); - } - - @Override - public void snap(Point2D point, Point2D[] features) { - snap(point); - } - - }; - - public MouseScaleMode(int mouseId, MouseInfo mi, Set selection) { - this(mouseId, mi, selection, DEFAULT_SNAP); - } - - public MouseScaleMode(int mouseId, MouseInfo mi, Set selection, ISnapAdvisor snapAdvisor) { - super(mouseId); - this.snapAdvisor = snapAdvisor; - this.selection = selection; - this.selection = new HashSet(selection); - for (IElement e : selection) - if (!e.getElementClass().containsClass(Scale.class)) - this.selection.remove(e); - - if (this.selection.size() == 1) { - AffineTransform at = ElementUtils.getTransform(this.selection.iterator().next()); - this.pivotPosition = new Point2D.Double(at.getTranslateX(), at.getTranslateY()); - } else if (this.selection.size() > 1) { - this.pivotPosition = ElementUtils.getElementBoundsCenter(this.selection, null); - } else { - this.pivotPosition = new Point2D.Double(); - } - this.pivot = AffineTransform.getTranslateInstance(pivotPosition.getX(), pivotPosition.getY()); - this.pivotInverse = AffineTransform.getTranslateInstance(-pivotPosition.getX(), -pivotPosition.getY()); - this.initialMousePos = mi != null ? (Point2D) mi.canvasPosition.clone() : null; - - for (IElement e : this.selection) { - Scale scale = e.getElementClass().getAtMostOneItemOfClass(Scale.class); - if (scale != null) { - Point2D s = scale.getScale(e); - System.out.println(""); - originalScales.put(e, s); - scaledElements.put(e, new MutatedElement(e)); - } - } - } - - protected SingleElementNode node = null; - - @SGInit - public void initSG(G2DParentNode parent) { - // Using SingleElementNode for AlphaComposite. - node = parent.addNode("mouse scale ghost", SingleElementNode.class); - node.setZIndex(Integer.MAX_VALUE - 1000); - node.setComposite(AlphaComposite.SrcOver.derive(0.30f)); - } - - @SGCleanup - public void cleanupSG() { - node.remove(); - node = null; - } - - @Override - public void addedToContext(ICanvasContext ctx) { - super.addedToContext(ctx); - - if (selection.isEmpty()) - asyncExec(new Runnable() { - @Override - public void run() { - if (!isRemoved()) - remove(); - } - }); - else - update(); - } - - @Override - public void removedFromContext(ICanvasContext ctx) { - for (MutatedElement me : scaledElements.values()) - me.dispose(); - - super.removedFromContext(ctx); - } - - public boolean handleCommand(CommandEvent ce) { - if (Commands.CANCEL.equals(ce.command)) { - cancel(); - return true; - } - return true; - } - - @EventHandler(priority = Integer.MAX_VALUE) - public boolean handleKeys(KeyEvent event) { - if (event instanceof KeyPressedEvent) { - if (event.keyCode == java.awt.event.KeyEvent.VK_ESCAPE) { - cancel(); - } else if (event.keyCode == java.awt.event.KeyEvent.VK_ENTER) { - commit(); - } - } - return true; - } - - @EventHandler(priority = Integer.MAX_VALUE) - public boolean handleMouse(MouseEvent event) { - //System.out.println("scale mouse event: " + event); - if (event instanceof MouseButtonPressedEvent) { - MouseButtonPressedEvent mbpe = (MouseButtonPressedEvent) event; - if (mbpe.button == MouseEvent.LEFT_BUTTON) { - commit(); - } - } else if (event instanceof MouseMovedEvent) { - MouseMovedEvent mme = (MouseMovedEvent) event; - ElementUtils.controlToCanvasCoordinate(getContext(), mme.controlPosition, lastMousePos); - - ISnapAdvisor snapAdvisor = getContext().getDefaultHintContext().getHint(DiagramHints.SNAP_ADVISOR); - - double d = 0; - if (DEBUG) { - System.out.println("initialpos: " + initialMousePos); - System.out.println("pivot: " + pivotPosition); - } - if (initialMousePos != null) { - double dx = initialMousePos.getX() - pivotPosition.getX(); - double dy = initialMousePos.getY() - pivotPosition.getY(); - d = Math.sqrt(dx*dx + dy*dy); - } - - double lx = lastMousePos.getX() - pivotPosition.getX(); - double ly = lastMousePos.getY() - pivotPosition.getY(); - double l = Math.sqrt(lx*lx + ly*ly); - - // Safety measures. - double s = l; - if (d > 1e-9) - s /= d; - else if (d == 0) - s *= .01; - else - return true; - if(DEBUG) { - System.out.println("l: " + l); - System.out.println("d: " + d); - System.out.println("s: " + s); - } - - for (Map.Entry entry : originalScales.entrySet()) { - IElement e = entry.getKey(); - Point2D originalScale = entry.getValue(); - ElementClass ec = e.getElementClass(); - IElement me = scaledElements.get(e); - - newScale.setLocation(originalScale.getX() * s, originalScale.getY() * s); - - // Limit downwards scale to 1/10000 just to keep unwanted 0 - // determinant problems away easily. - if (newScale.getX() < 2e-4 || newScale.getY() < 2e-4) { - if(DEBUG) { - System.out.println("DISCARD new scale:" + newScale); - } - continue; - } - //System.out.println("SET new scale:" + newScale); - - // Try to snap to grid. - if (snapAdvisor != null) { - this.snapAdvisor.snap(newScale); - } - - double sx = newScale.getX() / originalScale.getX(); - double sy = newScale.getY() / originalScale.getY(); - - // Reset transform - - // localAt <- local transform(e) - // worldAt <- world transform(e) - AffineTransform localAt = ElementUtils.getLocalTransform(e, new AffineTransform()); - Point2D localPos = ElementUtils.getPos(e, new Point2D.Double()); - Point2D worldPos = ElementUtils.getAbsolutePos(e, new Point2D.Double()); - Point2D worldToLocal = new Point2D.Double(localPos.getX() - worldPos.getX(), localPos.getY() - worldPos.getY()); - if (DEBUG) { - System.out.println("pivot: " + pivot); - System.out.println("pivot^-1: " + pivotInverse); - System.out.println("localAt: " + localAt); - System.out.println("sx: " + sx); - } - - // Prevent singular transforms from being created. - if (sx == 0 || sy == 0) - continue; - - // Scale local transform. - // The translation part of localAt is useless. - localAt.scale(sx, sy); - - // Figure out the scaled element position after - // scaling about pivotPosition. - // - // L = element local coordinate system - // W = world coordinate system - // P = pivot coordinate system - // X(p): point p is in coordinate system X - - // W(p) -> P(p) -> scale p -> W(p) -> L(p) - Point2D p = (Point2D) worldPos.clone(); - if (DEBUG) - System.out.println("Wp: " + p); - // -> P(p) - pivotInverse.transform(p, p); - if (DEBUG) - System.out.println("Pp: " + p); - // scale(p) - p.setLocation(p.getX() * sx, p.getY() * sy); - // -> W(p) - pivot.transform(p, p); - if (DEBUG) - System.out.println("Wp: " + p); - // -> L(p) - p.setLocation(p.getX() + worldToLocal.getX(), p.getY() + worldToLocal.getY()); - if (DEBUG) - System.out.println("Lp: " + p); - - localAt.setTransform( - localAt.getScaleX(), localAt.getShearX(), - localAt.getShearY(), localAt.getScaleY(), - p.getX(), p.getY()); - - if (DEBUG) - System.out.println(" -> " + localAt); - - ec.getSingleItem(Transform.class).setTransform(me, localAt); - } - - update(); - } - return true; - } - - private void update() { - for (IElement me : scaledElements.values()) - painter.updateElement(node, me, KEY_SCALE_NODE, false); - setDirty(); - } - - private void cancel() { - setDirty(); - remove(); - } - - private void commit() { - Collection transformed = new ArrayList(); - for (IElement e : scaledElements.values()) { - Object obj = ElementUtils.getObject(e); - if (obj instanceof Resource) { - AffineTransform at = ElementUtils.getLocalTransform(e, new AffineTransform()); - transformed.add( new TransformedObject((Resource) obj, at) ); - } - } - - Simantics.getSession().asyncRequest( - ElementTransforms.setTransformRequest(transformed) - ); - - setDirty(); - remove(); - } - -// private static AffineTransform uncheckedInverse(AffineTransform at) { -// try { -// return at.createInverse(); -// } catch (NoninvertibleTransformException e) { -// throw new RuntimeException(e); -// } -// } - +/******************************************************************************* + * 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.diagram.handler; + +import java.awt.AlphaComposite; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.simantics.Simantics; +import org.simantics.db.Resource; +import org.simantics.diagram.elements.ElementTransforms; +import org.simantics.diagram.elements.ElementTransforms.TransformedObject; +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; +import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup; +import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit; +import org.simantics.g2d.diagram.DiagramHints; +import org.simantics.g2d.diagram.participant.ElementPainter; +import org.simantics.g2d.diagram.participant.pointertool.AbstractMode; +import org.simantics.g2d.element.ElementClass; +import org.simantics.g2d.element.ElementUtils; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.SceneGraphNodeKey; +import org.simantics.g2d.element.handler.Scale; +import org.simantics.g2d.element.handler.Transform; +import org.simantics.g2d.element.impl.MutatedElement; +import org.simantics.g2d.participant.MouseUtil.MouseInfo; +import org.simantics.scenegraph.INode; +import org.simantics.scenegraph.g2d.G2DParentNode; +import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; +import org.simantics.scenegraph.g2d.events.KeyEvent; +import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent; +import org.simantics.scenegraph.g2d.events.MouseEvent; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent; +import org.simantics.scenegraph.g2d.events.command.CommandEvent; +import org.simantics.scenegraph.g2d.events.command.Commands; +import org.simantics.scenegraph.g2d.nodes.SingleElementNode; +import org.simantics.scenegraph.g2d.snap.ISnapAdvisor; +import org.simantics.utils.datastructures.hints.IHintContext.Key; + +/** + * @author Tuukka Lehtonen + */ +public class MouseScaleMode extends AbstractMode { + + private static final Key KEY_SCALE_NODE = new SceneGraphNodeKey(INode.class, "SCALE_NODE"); + + private static final boolean DEBUG = false; + + @Dependency ElementPainter painter; + + /** + * The set of elements that are being scaled. + */ + Set selection; + + Map originalScales = new HashMap(); + Map scaledElements = new HashMap(); + + Point2D initialMousePos; + Point2D pivotPosition; + AffineTransform pivot; + AffineTransform pivotInverse; + Point2D lastMousePos = new Point2D.Double(); + Point2D newScale = new Point2D.Double(); + + final ISnapAdvisor snapAdvisor; + + final static public ISnapAdvisor DEFAULT_SNAP = new ISnapAdvisor() { + + @Override + public void snap(Point2D point) { + double resolution = 0.1; + point.setLocation( + Math.round(point.getX() / resolution) * resolution, + Math.round(point.getY() / resolution) * resolution); + } + + @Override + public void snap(Point2D point, Point2D[] features) { + snap(point); + } + + }; + + public MouseScaleMode(int mouseId, MouseInfo mi, Set selection) { + this(mouseId, mi, selection, DEFAULT_SNAP); + } + + public MouseScaleMode(int mouseId, MouseInfo mi, Set selection, ISnapAdvisor snapAdvisor) { + super(mouseId); + this.snapAdvisor = snapAdvisor; + this.selection = selection; + this.selection = new HashSet(selection); + for (IElement e : selection) + if (!e.getElementClass().containsClass(Scale.class)) + this.selection.remove(e); + + if (this.selection.size() == 1) { + AffineTransform at = ElementUtils.getTransform(this.selection.iterator().next()); + this.pivotPosition = new Point2D.Double(at.getTranslateX(), at.getTranslateY()); + } else if (this.selection.size() > 1) { + this.pivotPosition = ElementUtils.getElementBoundsCenter(this.selection, null); + } else { + this.pivotPosition = new Point2D.Double(); + } + this.pivot = AffineTransform.getTranslateInstance(pivotPosition.getX(), pivotPosition.getY()); + this.pivotInverse = AffineTransform.getTranslateInstance(-pivotPosition.getX(), -pivotPosition.getY()); + this.initialMousePos = mi != null ? (Point2D) mi.canvasPosition.clone() : null; + + for (IElement e : this.selection) { + Scale scale = e.getElementClass().getAtMostOneItemOfClass(Scale.class); + if (scale != null) { + Point2D s = scale.getScale(e); + System.out.println(""); + originalScales.put(e, s); + scaledElements.put(e, new MutatedElement(e)); + } + } + } + + protected SingleElementNode node = null; + + @SGInit + public void initSG(G2DParentNode parent) { + // Using SingleElementNode for AlphaComposite. + node = parent.addNode("mouse scale ghost", SingleElementNode.class); + node.setZIndex(Integer.MAX_VALUE - 1000); + node.setComposite(AlphaComposite.SrcOver.derive(0.30f)); + } + + @SGCleanup + public void cleanupSG() { + node.remove(); + node = null; + } + + @Override + public void addedToContext(ICanvasContext ctx) { + super.addedToContext(ctx); + + if (selection.isEmpty()) + asyncExec(new Runnable() { + @Override + public void run() { + if (!isRemoved()) + remove(); + } + }); + else + update(); + } + + @Override + public void removedFromContext(ICanvasContext ctx) { + for (MutatedElement me : scaledElements.values()) + me.dispose(); + + super.removedFromContext(ctx); + } + + public boolean handleCommand(CommandEvent ce) { + if (Commands.CANCEL.equals(ce.command)) { + cancel(); + return true; + } + return true; + } + + @EventHandler(priority = Integer.MAX_VALUE) + public boolean handleKeys(KeyEvent event) { + if (event instanceof KeyPressedEvent) { + if (event.keyCode == java.awt.event.KeyEvent.VK_ESCAPE) { + cancel(); + } else if (event.keyCode == java.awt.event.KeyEvent.VK_ENTER) { + commit(); + } + } + return true; + } + + @EventHandler(priority = Integer.MAX_VALUE) + public boolean handleMouse(MouseEvent event) { + //System.out.println("scale mouse event: " + event); + if (event instanceof MouseButtonPressedEvent) { + MouseButtonPressedEvent mbpe = (MouseButtonPressedEvent) event; + if (mbpe.button == MouseEvent.LEFT_BUTTON) { + commit(); + } + } else if (event instanceof MouseMovedEvent) { + MouseMovedEvent mme = (MouseMovedEvent) event; + ElementUtils.controlToCanvasCoordinate(getContext(), mme.controlPosition, lastMousePos); + + ISnapAdvisor snapAdvisor = getContext().getDefaultHintContext().getHint(DiagramHints.SNAP_ADVISOR); + + double d = 0; + if (DEBUG) { + System.out.println("initialpos: " + initialMousePos); + System.out.println("pivot: " + pivotPosition); + } + if (initialMousePos != null) { + double dx = initialMousePos.getX() - pivotPosition.getX(); + double dy = initialMousePos.getY() - pivotPosition.getY(); + d = Math.sqrt(dx*dx + dy*dy); + } + + double lx = lastMousePos.getX() - pivotPosition.getX(); + double ly = lastMousePos.getY() - pivotPosition.getY(); + double l = Math.sqrt(lx*lx + ly*ly); + + // Safety measures. + double s = l; + if (d > 1e-9) + s /= d; + else if (d == 0) + s *= .01; + else + return true; + if(DEBUG) { + System.out.println("l: " + l); + System.out.println("d: " + d); + System.out.println("s: " + s); + } + + for (Map.Entry entry : originalScales.entrySet()) { + IElement e = entry.getKey(); + Point2D originalScale = entry.getValue(); + ElementClass ec = e.getElementClass(); + IElement me = scaledElements.get(e); + + newScale.setLocation(originalScale.getX() * s, originalScale.getY() * s); + + // Limit downwards scale to 1/10000 just to keep unwanted 0 + // determinant problems away easily. + if (newScale.getX() < 2e-4 || newScale.getY() < 2e-4) { + if(DEBUG) { + System.out.println("DISCARD new scale:" + newScale); + } + continue; + } + //System.out.println("SET new scale:" + newScale); + + // Try to snap to grid. + if (snapAdvisor != null) { + this.snapAdvisor.snap(newScale); + } + + double sx = newScale.getX() / originalScale.getX(); + double sy = newScale.getY() / originalScale.getY(); + + // Reset transform + + // localAt <- local transform(e) + // worldAt <- world transform(e) + AffineTransform localAt = ElementUtils.getLocalTransform(e, new AffineTransform()); + Point2D localPos = ElementUtils.getPos(e, new Point2D.Double()); + Point2D worldPos = ElementUtils.getAbsolutePos(e, new Point2D.Double()); + Point2D worldToLocal = new Point2D.Double(localPos.getX() - worldPos.getX(), localPos.getY() - worldPos.getY()); + if (DEBUG) { + System.out.println("pivot: " + pivot); + System.out.println("pivot^-1: " + pivotInverse); + System.out.println("localAt: " + localAt); + System.out.println("sx: " + sx); + } + + // Prevent singular transforms from being created. + if (sx == 0 || sy == 0) + continue; + + // Scale local transform. + // The translation part of localAt is useless. + localAt.scale(sx, sy); + + // Figure out the scaled element position after + // scaling about pivotPosition. + // + // L = element local coordinate system + // W = world coordinate system + // P = pivot coordinate system + // X(p): point p is in coordinate system X + + // W(p) -> P(p) -> scale p -> W(p) -> L(p) + Point2D p = (Point2D) worldPos.clone(); + if (DEBUG) + System.out.println("Wp: " + p); + // -> P(p) + pivotInverse.transform(p, p); + if (DEBUG) + System.out.println("Pp: " + p); + // scale(p) + p.setLocation(p.getX() * sx, p.getY() * sy); + // -> W(p) + pivot.transform(p, p); + if (DEBUG) + System.out.println("Wp: " + p); + // -> L(p) + p.setLocation(p.getX() + worldToLocal.getX(), p.getY() + worldToLocal.getY()); + if (DEBUG) + System.out.println("Lp: " + p); + + localAt.setTransform( + localAt.getScaleX(), localAt.getShearY(), + localAt.getShearX(), localAt.getScaleY(), + p.getX(), p.getY()); + + if (DEBUG) + System.out.println(" -> " + localAt); + + ec.getSingleItem(Transform.class).setTransform(me, localAt); + } + + update(); + } + return true; + } + + private void update() { + for (IElement me : scaledElements.values()) + painter.updateElement(node, me, KEY_SCALE_NODE, false); + setDirty(); + } + + private void cancel() { + setDirty(); + remove(); + } + + private void commit() { + Collection transformed = new ArrayList(); + for (IElement e : scaledElements.values()) { + Object obj = ElementUtils.getObject(e); + if (obj instanceof Resource) { + AffineTransform at = ElementUtils.getLocalTransform(e, new AffineTransform()); + transformed.add( new TransformedObject((Resource) obj, at) ); + } + } + + Simantics.getSession().asyncRequest( + ElementTransforms.setTransformRequest(transformed) + ); + + setDirty(); + remove(); + } + +// private static AffineTransform uncheckedInverse(AffineTransform at) { +// try { +// return at.createInverse(); +// } catch (NoninvertibleTransformException e) { +// throw new RuntimeException(e); +// } +// } + } \ No newline at end of file