From 3db13457b8a9e332b67c6fc50dec849ddaed3181 Mon Sep 17 00:00:00 2001 From: Albert Cardona Date: Mon, 13 Apr 2009 13:31:56 +0200 Subject: [PATCH] Added ability to propagate manual transformation to all previous or next layers. --- ini/trakem2/display/Display.java | 14 +++++++ ini/trakem2/display/Displayable.java | 16 ++++++++ ini/trakem2/display/Selection.java | 75 ++++++++++++++++++++++++++++++++---- 3 files changed, 97 insertions(+), 8 deletions(-) diff --git a/ini/trakem2/display/Display.java b/ini/trakem2/display/Display.java index aae2210e..6fa9818f 100644 --- a/ini/trakem2/display/Display.java +++ b/ini/trakem2/display/Display.java @@ -2119,6 +2119,10 @@ public final class Display extends DBObject implements ActionListener, ImageList if (canvas.isTransforming()) { item = new JMenuItem("Apply transform"); item.addActionListener(this); popup.add(item); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true)); // dummy, for I don't add a MenuKeyListener, but "works" through the normal key listener. It's here to provide a visual cue + item = new JMenuItem("Apply transform propagating to last layer"); item.addActionListener(this); popup.add(item); + if (layer.getParent().indexOf(layer) == layer.getParent().size() -1) item.setEnabled(false); + item = new JMenuItem("Apply transform propagating to first layer"); item.addActionListener(this); popup.add(item); + if (0 == layer.getParent().indexOf(layer)) item.setEnabled(false); } else { item = new JMenuItem("Transform"); item.addActionListener(this); popup.add(item); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0, true)); @@ -2891,6 +2895,16 @@ public final class Display extends DBObject implements ActionListener, ImageList } else if (command.equals("Apply transform")) { if (null == active) return; canvas.setTransforming(false); + } else if (command.equals("Apply transform propagating to last layer")) { + if (selection.isTransforming()) { + final java.util.List layers = layer.getParent().getLayers(); + selection.applyAndPropagate(new HashSet(layers.subList(layers.indexOf(Display.this.layer)+1, layers.size()))); // +1 to exclude current layer + } + } else if (command.equals("Apply transform propagating to first layer")) { + if (selection.isTransforming()) { + final java.util.List layers = layer.getParent().getLayers(); + selection.applyAndPropagate(new HashSet(layers.subList(0, layers.indexOf(Display.this.layer)))); + } } else if (command.equals("Cancel transform")) { if (null == active) return; canvas.cancelTransform(); diff --git a/ini/trakem2/display/Displayable.java b/ini/trakem2/display/Displayable.java index 7183aa68..c3606562 100644 --- a/ini/trakem2/display/Displayable.java +++ b/ini/trakem2/display/Displayable.java @@ -1876,4 +1876,20 @@ public abstract class Displayable extends DBObject { /** Set the subclass specific data fields. */ abstract boolean to2(final Displayable d); } + + /** Returns true if any Displayable objects of different layers in sublist are linked to each other. + * If ignore_stacks is true, then image links across layers are ignored. */ + static public final boolean areThereLayerCrossLinks(final Set sublist, final boolean ignore_stacks) { + if (null == sublist || 0 == sublist.size()) return false; + for (final Layer l : sublist) { + for (final Displayable d : l.getDisplayables(Patch.class)) { + if (d.isLinked()) { + for (final Displayable other : d.getLinked()) { + final Class c = other.getClass(); + if ( (!ignore_stacks && Patch.class == c && other.layer != d.layer) + || (Profile.class == c && other.getLinked(Profile.class).size() > 0) + || ZDisplayable.class.isAssignableFrom(c)) { + return true; }}}}} + return false; + } } diff --git a/ini/trakem2/display/Selection.java b/ini/trakem2/display/Selection.java index 3099ed60..8906db5d 100644 --- a/ini/trakem2/display/Selection.java +++ b/ini/trakem2/display/Selection.java @@ -345,6 +345,8 @@ public class Selection { addUndoStep(); + if (null != accum_affine) accum_affine.preConcatenate(at); + for (final Displayable d : hs) { //d.scale(px, py, anchor_x, anchor_y, false); // false because the linked ones are already included in the HashSet d.preTransform(at, false); @@ -379,6 +381,8 @@ public class Selection { // store the current state if at end: Utils.log2("index at end: " + history.indexAtEnd()); if (history.indexAtEnd()) history.append(new TransformationStep(getTransformationsCopy())); + // disable application to other layers (too big a headache) + accum_affine = null; // undo one step TransformationStep step = (TransformationStep)history.undoOneStep(); if (null == step) return; // no more steps @@ -868,6 +872,8 @@ public class Selection { private History history = null; + private AffineTransform accum_affine = null; + synchronized public void setTransforming(final boolean b) { if (b == transforming) { Utils.log2("Selection.setTransforming warning: trying to set the same mode"); @@ -879,6 +885,7 @@ public class Selection { history.add(new TransformationStep(getTransformationsCopy())); transforming = true; floater.center(); + accum_affine = new AffineTransform(); } else { if (null != history) { history.clear(); @@ -886,10 +893,49 @@ public class Selection { } // the transform is already applied, just forget it: transforming = false; + accum_affine = null; forgetAffine(); // store current state for undo/redo: - if (null != display) display.getLayerSet().addTransformStep(active.getLinkedGroup(null)); + if (null != display) display.getLayerSet().addTransformStep(hs); + } + } + + /** Skips current layer, since its done already. */ + synchronized protected void applyAndPropagate(final Set sublist) { + if (!transforming) return; + if (null == accum_affine) { + Utils.log2("Cannot apply to other layers: undo/redo was used."); + return; + } + if (0 == sublist.size()) { + Utils.logAll("No layers to apply to!"); + return; + } + // Check if there are links across affected layers + if (Displayable.areThereLayerCrossLinks(sublist, false)) { + Utils.log("Can't apply: some images may be linked across layers.\n Unlink them by removing segmentation objects like arealists, pipes, profiles, etc. that cross these layers."); + return; + } + // Add undo step + final ArrayList al = new ArrayList(); + for (final Layer l : sublist) { + al.addAll(l.getDisplayables()); } + display.getLayer().getParent().addTransformStep(al); + + + if (null != free_affine && null != model) { + accum_affine.preConcatenate(free_affine); + accum_affine.preConcatenate(model.createAffine()); + } + + // Apply! + for (final Layer l : sublist) { + if (display.getLayer() == l) continue; // already applied + l.apply(Displayable.class, accum_affine); + } + + setTransforming(false); } synchronized public void cancelTransform() { @@ -957,6 +1003,13 @@ public class Selection { } private void initializeModel() { + + // Store current "initial" state in the accumulated affine + if (null != free_affine && null != model && null != accum_affine) { + accum_affine.preConcatenate(free_affine); + accum_affine.preConcatenate(model.createAffine()); + } + free_affine = new AffineTransform(); initial_affines = getTransformationsCopy(); @@ -1000,11 +1053,11 @@ public class Selection { model.fit(matches); } catch (Exception e) {} - AffineTransform model_affine = model.createAffine(); - for (Iterator it = initial_affines.entrySet().iterator(); it.hasNext(); ) { - Map.Entry e = (Map.Entry)it.next(); - Displayable d = (Displayable)e.getKey(); - AffineTransform at = new AffineTransform((AffineTransform)e.getValue()); + final AffineTransform model_affine = model.createAffine(); + for (final Iterator it = initial_affines.entrySet().iterator(); it.hasNext(); ) { + final Map.Entry e = (Map.Entry)it.next(); + final Displayable d = (Displayable)e.getKey(); + final AffineTransform at = new AffineTransform((AffineTransform)e.getValue()); at.preConcatenate(free_affine); at.preConcatenate(model_affine); d.setAffineTransform(at); @@ -1033,8 +1086,8 @@ public class Selection { grabbed = null; // reset Utils.log2("transforming: " + transforming); if (!transforming) { - if (display.getLayerSet().prepareStep(new ArrayList(queue))) { - display.getLayerSet().addTransformStep(new ArrayList(queue)); + if (display.getLayerSet().prepareStep(new ArrayList(hs))) { + display.getLayerSet().addTransformStep(new ArrayList(hs)); } } else { if (me.isShiftDown()) { @@ -1403,6 +1456,8 @@ public class Selection { addUndoStep(); + if (null != accum_affine) accum_affine.preConcatenate(at); + for (final Displayable d : hs) { d.preTransform(at, false); // all linked ones included in the hashset } @@ -1416,6 +1471,8 @@ public class Selection { addUndoStep(); + if (null != accum_affine) accum_affine.preConcatenate(at); + for (final Displayable d : hs) { d.preTransform(at, false); // all linked ones already included in the hashset } @@ -1436,6 +1493,8 @@ public class Selection { addUndoStep(); + if (null != accum_affine) accum_affine.preConcatenate(at); + for (final Displayable d : hs) { d.preTransform(at, false); // all linked ones already included in the hashset } -- 2.11.4.GIT