use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.
the class Display method actionPerformed.
@Override
public void actionPerformed(final ActionEvent ae) {
dispatcher.exec(new Runnable() {
@Override
public void run() {
final String command = ae.getActionCommand();
if (command.startsWith("Job")) {
if (Utils.checkYN("Really cancel job?")) {
project.getLoader().quitJob(command);
repairGUI();
}
return;
} else if (command.equals("Move to top")) {
if (null == active)
return;
canvas.setUpdateGraphics(true);
getLayerSet().addUndoMoveStep(active);
layer.getParent().move(LayerSet.TOP, active);
getLayerSet().addUndoMoveStep(active);
Display.repaint(layer.getParent(), active, 5);
// Display.updatePanelIndex(layer, active);
} else if (command.equals("Move up")) {
if (null == active)
return;
canvas.setUpdateGraphics(true);
getLayerSet().addUndoMoveStep(active);
layer.getParent().move(LayerSet.UP, active);
getLayerSet().addUndoMoveStep(active);
Display.repaint(layer.getParent(), active, 5);
// Display.updatePanelIndex(layer, active);
} else if (command.equals("Move down")) {
if (null == active)
return;
canvas.setUpdateGraphics(true);
getLayerSet().addUndoMoveStep(active);
layer.getParent().move(LayerSet.DOWN, active);
getLayerSet().addUndoMoveStep(active);
Display.repaint(layer.getParent(), active, 5);
// Display.updatePanelIndex(layer, active);
} else if (command.equals("Move to bottom")) {
if (null == active)
return;
canvas.setUpdateGraphics(true);
getLayerSet().addUndoMoveStep(active);
layer.getParent().move(LayerSet.BOTTOM, active);
getLayerSet().addUndoMoveStep(active);
Display.repaint(layer.getParent(), active, 5);
// Display.updatePanelIndex(layer, active);
} else if (command.equals("Duplicate, link and send to next layer")) {
duplicateLinkAndSendTo(active, 1, layer.getParent().next(layer));
} else if (command.equals("Duplicate, link and send to previous layer")) {
duplicateLinkAndSendTo(active, 0, layer.getParent().previous(layer));
} else if (command.equals("Duplicate, link and send to...")) {
// fix non-scrolling popup menu
Utils.invokeLater(new Runnable() {
@Override
public void run() {
final GenericDialog gd = new GenericDialog("Send to");
gd.addMessage("Duplicate, link and send to...");
final String[] sl = new String[layer.getParent().size()];
int next = 0;
for (final Layer la : layer.getParent().getLayers()) {
sl[next++] = project.findLayerThing(la).toString();
}
gd.addChoice("Layer: ", sl, sl[layer.getParent().indexOf(layer)]);
gd.showDialog();
if (gd.wasCanceled())
return;
final Layer la = layer.getParent().getLayer(gd.getNextChoiceIndex());
if (layer == la) {
Utils.showMessage("Can't duplicate, link and send to the same layer.");
return;
}
duplicateLinkAndSendTo(active, 0, la);
}
});
} else if (-1 != command.indexOf("z = ")) {
// this is an item from the "Duplicate, link and send to" menu of layer z's
final Layer target_layer = layer.getParent().getLayer(Double.parseDouble(command.substring(command.lastIndexOf(' ') + 1)));
Utils.log2("layer: __" + command.substring(command.lastIndexOf(' ') + 1) + "__");
if (null == target_layer)
return;
duplicateLinkAndSendTo(active, 0, target_layer);
} else if (-1 != command.indexOf("z=")) {
// WARNING the indexOf is very similar to the previous one
// Send the linked group to the selected layer
final int iz = command.indexOf("z=") + 2;
Utils.log2("iz=" + iz + " other: " + command.indexOf(' ', iz + 2));
int end = command.indexOf(' ', iz);
if (-1 == end)
end = command.length();
final double lz = Double.parseDouble(command.substring(iz, end));
final Layer target = layer.getParent().getLayer(lz);
// TODO what happens when ZDisplayable are selected?
layer.getParent().move(selection.getAffected(), active.getLayer(), target);
} else if (command.equals("Unlink")) {
if (null == active || active instanceof Patch)
return;
active.unlink();
// selection.update();
updateSelection();
} else if (command.equals("Unlink from images")) {
if (null == active)
return;
try {
for (final Displayable displ : selection.getSelected()) {
displ.unlinkAll(Patch.class);
}
// selection.update();
updateSelection();
} catch (final Exception e) {
IJError.print(e);
}
} else if (command.equals("Unlink slices")) {
final YesNoCancelDialog yn = new YesNoCancelDialog(frame, "Attention", "Really unlink all slices from each other?\nThere is no undo.");
if (!yn.yesPressed())
return;
final ArrayList<Patch> pa = ((Patch) active).getStackPatches();
for (int i = pa.size() - 1; i > 0; i--) {
pa.get(i).unlink(pa.get(i - 1));
}
} else if (command.equals("Send to next layer")) {
final Rectangle box = selection.getBox();
try {
// unlink Patch instances
for (final Displayable displ : selection.getSelected()) {
displ.unlinkAll(Patch.class);
}
// selection.update();
updateSelection();
} catch (final Exception e) {
IJError.print(e);
}
// layer.getParent().moveDown(layer, active); // will repaint whatever appropriate layers
selection.moveDown();
repaint(layer.getParent(), box);
} else if (command.equals("Send to previous layer")) {
final Rectangle box = selection.getBox();
try {
// unlink Patch instances
for (final Displayable displ : selection.getSelected()) {
displ.unlinkAll(Patch.class);
}
// selection.update();
updateSelection();
} catch (final Exception e) {
IJError.print(e);
}
// layer.getParent().moveUp(layer, active); // will repaint whatever appropriate layers
selection.moveUp();
repaint(layer.getParent(), box);
} else if (command.equals("Show centered")) {
if (active == null)
return;
showCentered(active);
} else if (command.equals("Delete...")) {
// remove all selected objects
selection.deleteAll();
} else if (command.equals("Color...")) {
IJ.doCommand("Color Picker...");
} else if (command.equals("Revert")) {
if (null == active || active.getClass() != Patch.class)
return;
final Patch p = (Patch) active;
if (!p.revert()) {
if (null == p.getOriginalPath())
Utils.log("No editions to save for patch " + p.getTitle() + " #" + p.getId());
else
Utils.log("Could not revert Patch " + p.getTitle() + " #" + p.getId());
}
} else if (command.equals("Remove alpha mask")) {
Display.removeAlphaMasks(selection.get(Patch.class));
} else if (command.equals("Undo")) {
Bureaucrat.createAndStart(new Worker.Task("Undo") {
@Override
public void exec() {
layer.getParent().undoOneStep();
Display.repaint(layer.getParent());
}
}, project);
} else if (command.equals("Redo")) {
Bureaucrat.createAndStart(new Worker.Task("Redo") {
@Override
public void exec() {
layer.getParent().redoOneStep();
Display.repaint(layer.getParent());
}
}, project);
} else if (command.equals("Apply transform")) {
canvas.applyTransform();
} else if (command.equals("Apply transform propagating to last layer")) {
if (mode.getClass() == AffineTransformMode.class || mode.getClass() == NonLinearTransformMode.class) {
final LayerSet ls = getLayerSet();
// +1 to exclude current layer
final HashSet<Layer> subset = new HashSet<Layer>(ls.getLayers(ls.indexOf(Display.this.layer) + 1, ls.size() - 1));
if (mode.getClass() == AffineTransformMode.class)
((AffineTransformMode) mode).applyAndPropagate(subset);
else if (mode.getClass() == NonLinearTransformMode.class)
((NonLinearTransformMode) mode).apply(subset);
setMode(new DefaultMode(Display.this));
}
} else if (command.equals("Apply transform propagating to first layer")) {
if (mode.getClass() == AffineTransformMode.class || mode.getClass() == NonLinearTransformMode.class) {
final LayerSet ls = getLayerSet();
// -1 to exclude current layer
final HashSet<Layer> subset = new HashSet<Layer>(ls.getLayers(0, ls.indexOf(Display.this.layer) - 1));
if (mode.getClass() == AffineTransformMode.class)
((AffineTransformMode) mode).applyAndPropagate(subset);
else if (mode.getClass() == NonLinearTransformMode.class)
((NonLinearTransformMode) mode).apply(subset);
setMode(new DefaultMode(Display.this));
}
} else if (command.equals("Cancel transform")) {
// calls getMode().cancel()
canvas.cancelTransform();
} else if (command.equals("Specify transform...")) {
if (null == active)
return;
selection.specify();
} else if (command.equals("Exit inspection")) {
getMode().cancel();
setMode(new DefaultMode(Display.this));
} else if (command.equals("Inspect image mesh triangles")) {
setMode(new InspectPatchTrianglesMode(Display.this));
} else if (command.equals("Hide all but images")) {
final ArrayList<Class<?>> type = new ArrayList<Class<?>>();
type.add(Patch.class);
type.add(Stack.class);
final Collection<Displayable> col = layer.getParent().hideExcept(type, false);
selection.removeAll(col);
Display.updateCheckboxes(col, DisplayablePanel.VISIBILITY_STATE);
Display.update(layer.getParent(), false);
} else if (command.equals("Unhide all")) {
Display.updateCheckboxes(layer.getParent().setAllVisible(false), DisplayablePanel.VISIBILITY_STATE);
Display.update(layer.getParent(), false);
} else if (command.startsWith("Hide all ")) {
// skip the ending plural 's'
final String type = command.substring(9, command.length() - 1);
final Collection<Displayable> col = layer.getParent().setVisible(type, false, true);
selection.removeAll(col);
Display.updateCheckboxes(col, DisplayablePanel.VISIBILITY_STATE);
} else if (command.startsWith("Unhide all ")) {
// skip the ending plural 's'
String type = command.substring(11, command.length() - 1);
type = type.substring(0, 1).toUpperCase() + type.substring(1);
updateCheckboxes(layer.getParent().setVisible(type, true, true), DisplayablePanel.VISIBILITY_STATE);
} else if (command.equals("Hide deselected")) {
hideDeselected(0 != (ActionEvent.ALT_MASK & ae.getModifiers()));
} else if (command.equals("Hide deselected except images")) {
hideDeselected(true);
} else if (command.equals("Hide selected")) {
// TODO should deselect them too? I don't think so.
selection.setVisible(false);
Display.updateCheckboxes(selection.getSelected(), DisplayablePanel.VISIBILITY_STATE);
} else if (command.equals("Resize canvas/LayerSet...")) {
resizeCanvas();
} else if (command.equals("Autoresize canvas/LayerSet")) {
layer.getParent().setMinimumDimensions();
} else if (command.equals("Resize canvas/LayerSet to ROI")) {
final Roi roi = canvas.getFakeImagePlus().getRoi();
if (null == roi) {
Utils.log("No ROI present!");
return;
}
resizeCanvas(roi.getBounds());
} else if (command.equals("Import image")) {
importImage();
} else if (command.equals("Import next image")) {
importNextImage();
} else if (command.equals("Import stack...")) {
Display.this.getLayerSet().addChangeTreesStep();
final Rectangle sr = getCanvas().getSrcRect();
final Bureaucrat burro = project.getLoader().importStack(layer, sr.x + sr.width / 2, sr.y + sr.height / 2, null, true, null, false);
burro.addPostTask(new Runnable() {
@Override
public void run() {
Display.this.getLayerSet().addChangeTreesStep();
}
});
} else if (command.equals("Import stack with landmarks...")) {
// 1 - Find out if there's any other project open
final List<Project> pr = Project.getProjects();
if (1 == pr.size()) {
Utils.logAll("Need another project open!");
return;
}
// 2 - Ask for a "landmarks" type
final GenericDialog gd = new GenericDialog("Landmarks");
gd.addStringField("landmarks type:", "landmarks");
final String[] none = { "-- None --" };
final Hashtable<String, Project> mpr = new Hashtable<String, Project>();
for (final Project p : pr) {
if (p == project)
continue;
mpr.put(p.toString(), p);
}
final String[] project_titles = mpr.keySet().toArray(new String[0]);
final Hashtable<String, ProjectThing> map_target = findLandmarkNodes(project, "landmarks");
final String[] target_landmark_titles = map_target.isEmpty() ? none : map_target.keySet().toArray(new String[0]);
gd.addChoice("Landmarks node in this project:", target_landmark_titles, target_landmark_titles[0]);
gd.addMessage("");
gd.addChoice("Source project:", project_titles, project_titles[0]);
final Hashtable<String, ProjectThing> map_source = findLandmarkNodes(mpr.get(project_titles[0]), "landmarks");
final String[] source_landmark_titles = map_source.isEmpty() ? none : map_source.keySet().toArray(new String[0]);
gd.addChoice("Landmarks node in source project:", source_landmark_titles, source_landmark_titles[0]);
final List<Patch> stacks = Display.getPatchStacks(mpr.get(project_titles[0]).getRootLayerSet());
String[] stack_titles;
if (stacks.isEmpty()) {
if (1 == mpr.size()) {
IJ.showMessage("Project " + project_titles[0] + " does not contain any Stack.");
return;
}
stack_titles = none;
} else {
stack_titles = new String[stacks.size()];
int next = 0;
for (final Patch pa : stacks) stack_titles[next++] = pa.toString();
}
gd.addChoice("Stacks:", stack_titles, stack_titles[0]);
final Vector<?> vc = gd.getChoices();
final Choice choice_target_landmarks = (Choice) vc.get(0);
final Choice choice_source_projects = (Choice) vc.get(1);
final Choice choice_source_landmarks = (Choice) vc.get(2);
final Choice choice_stacks = (Choice) vc.get(3);
final TextField input = (TextField) gd.getStringFields().get(0);
input.addTextListener(new TextListener() {
@Override
public void textValueChanged(final TextEvent te) {
final String text = input.getText();
update(choice_target_landmarks, Display.this.project, text, map_target);
update(choice_source_landmarks, mpr.get(choice_source_projects.getSelectedItem()), text, map_source);
}
private void update(final Choice c, final Project p, final String type, final Hashtable<String, ProjectThing> table) {
table.clear();
table.putAll(findLandmarkNodes(p, type));
c.removeAll();
if (table.isEmpty())
c.add(none[0]);
else
for (final String t : table.keySet()) c.add(t);
}
});
choice_source_projects.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
final String item = (String) e.getItem();
final Project p = mpr.get(choice_source_projects.getSelectedItem());
// 1 - Update choice of landmark items
map_source.clear();
map_source.putAll(findLandmarkNodes(p, input.getText()));
choice_target_landmarks.removeAll();
if (map_source.isEmpty())
choice_target_landmarks.add(none[0]);
else
for (final String t : map_source.keySet()) choice_target_landmarks.add(t);
// 2 - Update choice of Stack items
stacks.clear();
choice_stacks.removeAll();
stacks.addAll(Display.getPatchStacks(mpr.get(project_titles[0]).getRootLayerSet()));
if (stacks.isEmpty())
choice_stacks.add(none[0]);
else
for (final Patch pa : stacks) choice_stacks.add(pa.toString());
}
});
gd.showDialog();
if (gd.wasCanceled())
return;
final String type = gd.getNextString();
if (null == type || 0 == type.trim().length()) {
Utils.log("Invalid landmarks node type!");
return;
}
final ProjectThing target_landmarks_node = map_target.get(gd.getNextChoice());
final Project source = mpr.get(gd.getNextChoice());
final ProjectThing source_landmarks_node = map_source.get(gd.getNextChoice());
final Patch stack_patch = stacks.get(gd.getNextChoiceIndex());
// Store current state
Display.this.getLayerSet().addLayerContentStep(layer);
// Insert stack
insertStack(target_landmarks_node, source, source_landmarks_node, stack_patch);
// Store new state
Display.this.getLayerSet().addChangeTreesStep();
} else if (command.equals("Import grid...")) {
Display.this.getLayerSet().addLayerContentStep(layer);
final Bureaucrat burro = project.getLoader().importGrid(layer);
if (null != burro)
burro.addPostTask(new Runnable() {
@Override
public void run() {
Display.this.getLayerSet().addLayerContentStep(layer);
}
});
} else if (command.equals("Import sequence as grid...")) {
Display.this.getLayerSet().addChangeTreesStep();
final Bureaucrat burro = project.getLoader().importSequenceAsGrid(layer);
if (null != burro)
burro.addPostTask(new Runnable() {
@Override
public void run() {
Display.this.getLayerSet().addChangeTreesStep();
}
});
} else if (command.equals("Import from text file...")) {
Display.this.getLayerSet().addChangeTreesStep();
final Bureaucrat burro = project.getLoader().importImages(layer);
if (null != burro)
burro.addPostTask(new Runnable() {
@Override
public void run() {
Display.this.getLayerSet().addChangeTreesStep();
}
});
} else if (command.equals("Import labels as arealists...")) {
Display.this.getLayerSet().addChangeTreesStep();
final Bureaucrat burro = project.getLoader().importLabelsAsAreaLists(layer, null, Double.MAX_VALUE, 0, 0.4f, false);
burro.addPostTask(new Runnable() {
@Override
public void run() {
Display.this.getLayerSet().addChangeTreesStep();
}
});
} else if (command.equals("Make flat image...")) {
// if there's a ROI, just use that as cropping rectangle
Rectangle srcRect = null;
final Roi roi = canvas.getFakeImagePlus().getRoi();
if (null != roi) {
srcRect = roi.getBounds();
} else {
// otherwise, whatever is visible
// srcRect = canvas.getSrcRect();
// The above is confusing. That is what ROIs are for. So paint all:
srcRect = new Rectangle(0, 0, (int) Math.ceil(layer.getParent().getLayerWidth()), (int) Math.ceil(layer.getParent().getLayerHeight()));
}
double scale = 1.0;
final String[] types = new String[] { "8-bit grayscale", "RGB Color" };
int the_type = ImagePlus.GRAY8;
final GenericDialog gd = new GenericDialog("Choose", frame);
gd.addSlider("Scale: ", 1, 100, 100);
gd.addNumericField("Width: ", srcRect.width, 0);
gd.addNumericField("height: ", srcRect.height, 0);
// connect the above 3 fields:
final Vector<?> numfields = gd.getNumericFields();
final UpdateDimensionField udf = new UpdateDimensionField(srcRect.width, srcRect.height, (TextField) numfields.get(1), (TextField) numfields.get(2), (TextField) numfields.get(0), (Scrollbar) gd.getSliders().get(0));
for (final Object ob : numfields) ((TextField) ob).addTextListener(udf);
gd.addChoice("Type: ", types, types[0]);
if (layer.getParent().size() > 1) {
// / $#%! where are my lisp macros
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.addCheckbox("Include non-empty layers only", true);
}
gd.addMessage("Background color:");
Utils.addRGBColorSliders(gd, Color.black);
gd.addCheckbox("Best quality", false);
gd.addMessage("");
final String[] choices = new String[] { "Show", "Save to file", "Save for web (CATMAID)" };
gd.addChoice("Export:", choices, choices[0]);
final String[] formats = Saver.formats();
gd.addChoice("Format:", formats, formats[0]);
gd.addNumericField("Tile_side", 256, 0);
final Choice cformats = (Choice) gd.getChoices().get(gd.getChoices().size() - 1);
cformats.setEnabled(false);
final Choice cchoices = (Choice) gd.getChoices().get(gd.getChoices().size() - 2);
final TextField tf = (TextField) gd.getNumericFields().get(gd.getNumericFields().size() - 1);
tf.setEnabled(false);
cchoices.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
cformats.setEnabled(cchoices.getSelectedIndex() > 0);
if (2 == cchoices.getSelectedIndex()) {
cformats.select(".jpg");
tf.setEnabled(true);
} else {
tf.setEnabled(false);
}
}
});
gd.addCheckbox("Use original images", true);
gd.showDialog();
if (gd.wasCanceled())
return;
scale = gd.getNextNumber() / 100;
the_type = (0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY8 : ImagePlus.COLOR_RGB);
if (Double.isNaN(scale) || scale <= 0.0) {
Utils.showMessage("Invalid scale.");
return;
}
// consuming and ignoring width and height:
gd.getNextNumber();
gd.getNextNumber();
Layer[] layer_array = null;
boolean non_empty_only = false;
if (layer.getParent().size() > 1) {
non_empty_only = gd.getNextBoolean();
final int i_start = gd.getNextChoiceIndex();
final int i_end = gd.getNextChoiceIndex();
final ArrayList<Layer> al = new ArrayList<Layer>();
final ArrayList<ZDisplayable> al_zd = layer.getParent().getZDisplayables();
final ZDisplayable[] zd = new ZDisplayable[al_zd.size()];
al_zd.toArray(zd);
for (int i = i_start, j = 0; i <= i_end; i++, j++) {
final Layer la = layer.getParent().getLayer(i);
// checks both the Layer and the ZDisplayable objects in the parent LayerSet
if (!la.isEmpty() || !non_empty_only)
al.add(la);
}
if (0 == al.size()) {
Utils.showMessage("All layers are empty!");
return;
}
layer_array = new Layer[al.size()];
al.toArray(layer_array);
} else {
layer_array = new Layer[] { Display.this.layer };
}
final Color background = new Color((int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber());
final boolean quality = gd.getNextBoolean();
final int choice = gd.getNextChoiceIndex();
final boolean save_to_file = 1 == choice;
final boolean save_for_web = 2 == choice;
final String format = gd.getNextChoice();
final Saver saver = new Saver(format);
final int tile_side = (int) gd.getNextNumber();
final boolean use_original_images = gd.getNextBoolean();
// in its own thread
if (save_for_web)
project.getLoader().makePrescaledTiles(layer_array, Patch.class, srcRect, scale, c_alphas, the_type, null, use_original_images, saver, tile_side);
else
project.getLoader().makeFlatImage(layer_array, srcRect, scale, c_alphas, the_type, save_to_file, format, quality, background);
} else if (command.equals("Lock")) {
selection.setLocked(true);
Utils.revalidateComponent(tabs.getSelectedComponent());
} else if (command.equals("Unlock")) {
selection.setLocked(false);
Utils.revalidateComponent(tabs.getSelectedComponent());
} else if (command.equals("Properties...")) {
switch(selection.getSelected().size()) {
case 0:
return;
case 1:
active.adjustProperties();
break;
default:
adjustGroupProperties(selection.getSelected());
break;
}
updateSelection();
} else if (command.equals("Measurement options...")) {
adjustMeasurementOptions();
} else if (command.equals("Show current 2D position in 3D")) {
final Point p = canvas.consumeLastPopupPoint();
if (null == p)
return;
Display3D.addFatPoint("Current 2D Position", getLayerSet(), p.x, p.y, layer.getZ(), 10, Color.magenta);
} else if (command.equals("Show layers as orthoslices in 3D")) {
final GenericDialog gd = new GenericDialog("Options");
final Roi roi = canvas.getFakeImagePlus().getRoi();
final Rectangle r = null == roi ? getLayerSet().get2DBounds() : roi.getBounds();
gd.addMessage("ROI 2D bounds:");
gd.addNumericField("x:", r.x, 0, 30, "pixels");
gd.addNumericField("y:", r.y, 0, 30, "pixels");
gd.addNumericField("width:", r.width, 0, 30, "pixels");
gd.addNumericField("height:", r.height, 0, 30, "pixels");
gd.addMessage("Layers to include:");
Utils.addLayerRangeChoices(layer, gd);
gd.addMessage("Constrain dimensions to:");
gd.addNumericField("max width and height:", getLayerSet().getPixelsMaxDimension(), 0, 30, "pixels");
gd.addMessage("Options:");
final String[] types = { "Greyscale", "Color RGB" };
gd.addChoice("Image type:", types, types[0]);
gd.addCheckbox("Invert images", false);
gd.showDialog();
if (gd.wasCanceled())
return;
final int x = (int) gd.getNextNumber(), y = (int) gd.getNextNumber(), width = (int) gd.getNextNumber(), height = (int) gd.getNextNumber();
final int first = gd.getNextChoiceIndex(), last = gd.getNextChoiceIndex();
final List<Layer> layers = getLayerSet().getLayers(first, last);
final int max_dim = Math.min((int) gd.getNextNumber(), Math.max(width, height));
float scale = 1;
if (max_dim < Math.max(width, height)) {
scale = max_dim / (float) Math.max(width, height);
}
final int type = 0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY8 : ImagePlus.COLOR_RGB;
final boolean invert = gd.getNextBoolean();
final LayerStack stack = new LayerStack(layers, new Rectangle(x, y, width, height), scale, type, Patch.class, max_dim, invert);
Display3D.showOrthoslices(stack.getImagePlus(), "LayerSet [" + x + "," + y + "," + width + "," + height + "] " + first + "--" + last, x, y, scale, layers.get(0));
} else if (command.equals("Align stack slices")) {
if (getActive() instanceof Patch) {
final Patch slice = (Patch) getActive();
if (slice.isStack()) {
// check linked group
final HashSet hs = slice.getLinkedGroup(new HashSet());
for (final Iterator it = hs.iterator(); it.hasNext(); ) {
if (it.next().getClass() != Patch.class) {
// labels should be fine, need to check that
Utils.showMessage("Images are linked to other objects, can't proceed to cross-correlate them.");
return;
}
}
final LayerSet ls = slice.getLayerSet();
final HashSet<Displayable> linked = slice.getLinkedGroup(null);
ls.addTransformStepWithData(linked);
// will repaint
final Bureaucrat burro = AlignTask.registerStackSlices((Patch) getActive());
burro.addPostTask(new Runnable() {
@Override
public void run() {
ls.enlargeToFit(linked);
// The current state when done
ls.addTransformStepWithData(linked);
}
});
} else {
Utils.log("Align stack slices: selected image is not part of a stack.");
}
}
} else if (command.equals("Align layers manually with landmarks")) {
setMode(new ManualAlignMode(Display.this));
} else if (command.equals("Align layers")) {
Roi roi = canvas.getFakeImagePlus().getRoi();
if (null != roi) {
final YesNoCancelDialog yn = new YesNoCancelDialog(frame, "Use ROI?", "Snapshot layers using the ROI bounds?\n" + roi.getBounds());
if (yn.cancelPressed())
return;
if (!yn.yesPressed()) {
roi = null;
}
}
// caching, since scroll wheel may change it
final Layer la = layer;
la.getParent().addTransformStep(la.getParent().getLayers());
final Bureaucrat burro = AlignLayersTask.alignLayersTask(la, null == roi ? null : roi.getBounds());
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().enlargeToFit(getLayerSet().getDisplayables(Patch.class));
la.getParent().addTransformStep(la.getParent().getLayers());
}
});
} else if (command.equals("Align multi-layer mosaic")) {
// caching, since scroll wheel may change it
final Layer la = layer;
la.getParent().addTransformStep();
final Bureaucrat burro = AlignTask.alignMultiLayerMosaicTask(la, active instanceof Patch ? (Patch) active : null);
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().enlargeToFit(getLayerSet().getDisplayables(Patch.class));
la.getParent().addTransformStep();
}
});
} else if (command.equals("Montage all images in this layer")) {
final Layer la = layer;
final List<Patch> patches = new ArrayList<Patch>((List<Patch>) (List) la.getDisplayables(Patch.class, true));
if (patches.size() < 2) {
Utils.showMessage("Montage needs 2 or more visible images");
return;
}
final Collection<Displayable> col = la.getParent().addTransformStepWithDataForAll(Arrays.asList(new Layer[] { la }));
// find any locked or selected patches
final HashSet<Patch> fixed = new HashSet<Patch>();
for (final Patch p : patches) {
if (p.isLocked2() || selection.contains(p))
fixed.add(p);
}
if (patches.size() == fixed.size()) {
Utils.showMessage("Can't do", "No montage possible: all images are selected,\nand hence all are considered locked.\nSelect only one image to be used as reference, or none.");
return;
}
Utils.log("Using " + fixed.size() + " image" + (fixed.size() == 1 ? "" : "s") + " as reference.");
final Bureaucrat burro = AlignTask.alignPatchesTask(patches, fixed);
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().enlargeToFit(patches);
la.getParent().addTransformStepWithData(col);
}
});
} else if (command.equals("Montage selected images")) {
final Layer la = layer;
if (selection.getSelected(Patch.class).size() < 2) {
Utils.showMessage("Montage needs 2 or more images selected");
return;
}
final Collection<Displayable> col = la.getParent().addTransformStepWithDataForAll(Arrays.asList(new Layer[] { la }));
final Bureaucrat burro = AlignTask.alignSelectionTask(selection);
if (null == burro)
return;
burro.addPostTask(new Runnable() {
@Override
public void run() {
la.getParent().enlargeToFit(selection.getAffected());
la.getParent().addTransformStepWithData(col);
}
});
} else if (command.equals("Montage multiple layers")) {
final GenericDialog gd = new GenericDialog("Choose range");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.showDialog();
if (gd.wasCanceled())
return;
final List<Layer> layers = getLayerSet().getLayers(gd.getNextChoiceIndex(), gd.getNextChoiceIndex());
final Collection<Displayable> col = getLayerSet().addTransformStepWithDataForAll(layers);
final Bureaucrat burro = AlignTask.montageLayersTask(layers);
burro.addPostTask(new Runnable() {
@Override
public void run() {
final Collection<Displayable> ds = new ArrayList<Displayable>();
for (final Layer la : layers) ds.addAll(la.getDisplayables(Patch.class));
getLayerSet().enlargeToFit(ds);
getLayerSet().addTransformStepWithData(col);
}
});
} else if (command.equals("Properties ...")) {
// NOTE the space before the dots, to distinguish from the "Properties..." command that works on Displayable objects.
adjustProperties();
} else if (command.equals("Adjust snapping parameters...")) {
AlignTask.p_snap.setup("Snap");
} else if (command.equals("Adjust fast-marching parameters...")) {
Segmentation.fmp.setup();
} else if (command.equals("Adjust arealist paint parameters...")) {
AreaWrapper.PP.setup();
} else if (command.equals("Fill ROI in alpha mask")) {
if (active.getClass() == Patch.class) {
((Patch) active).keyPressed(new KeyEvent(getCanvas(), -1, System.currentTimeMillis(), 0, KeyEvent.VK_F, 'f'));
}
} else if (command.equals("Fill inverse ROI in alpha mask")) {
if (active.getClass() == Patch.class) {
((Patch) active).keyPressed(new KeyEvent(getCanvas(), -1, System.currentTimeMillis(), Event.SHIFT_MASK, KeyEvent.VK_F, 'f'));
}
} else if (command.equals("Search...")) {
Search.showWindow();
} else if (command.equals("Select all")) {
selection.selectAll();
repaint(Display.this.layer, selection.getBox(), 0);
} else if (command.equals("Select all visible")) {
selection.selectAllVisible();
repaint(Display.this.layer, selection.getBox(), 0);
} else if (command.equals("Select all that match...")) {
final List<Displayable> ds = find();
selection.selectAll(ds);
Utils.showStatus("Added " + ds.size() + " to selection.");
} else if (command.equals("Select none")) {
final Rectangle box = selection.getBox();
selection.clear();
repaint(Display.this.layer, box, 0);
} else if (command.equals("Restore selection")) {
selection.restore();
} else if (command.equals("Select under ROI")) {
final Roi roi = canvas.getFakeImagePlus().getRoi();
if (null == roi)
return;
selection.selectAll(roi, true);
} else if (command.equals("Merge") || command.equals("Split")) {
final Bureaucrat burro = Bureaucrat.create(new Worker.Task(command + "ing AreaLists") {
@Override
public void exec() {
final ArrayList<Displayable> al_sel = selection.getSelected(AreaList.class);
// put active at the beginning, to work as the base on which other's will get merged
al_sel.remove(Display.this.active);
al_sel.add(0, Display.this.active);
final Set<DoStep> dataedits = new HashSet<DoStep>();
if (command.equals("Merge")) {
// Add data undo for active only, which will be edited
dataedits.add(new Displayable.DoEdit(Display.this.active).init(Display.this.active, new String[] { "data" }));
getLayerSet().addChangeTreesStep(dataedits);
final AreaList ali = AreaList.merge(al_sel);
if (null != ali) {
// remove all but the first from the selection
for (int i = 1; i < al_sel.size(); i++) {
final Object ob = al_sel.get(i);
if (ob.getClass() == AreaList.class) {
selection.remove((Displayable) ob);
}
}
selection.updateTransform(ali);
repaint(ali.getLayerSet(), ali, 0);
}
} else if (command.equals("Split")) {
// Add data undo for every AreaList
for (final Displayable d : al_sel) {
if (d.getClass() != AreaList.class)
continue;
dataedits.add(new Displayable.DoEdit(d).init(d, new String[] { "data" }));
}
getLayerSet().addChangeTreesStep(dataedits);
try {
List<AreaList> alis = AreaList.split(al_sel);
for (AreaList ali : alis) {
if (selection.contains(ali))
continue;
selection.add(ali);
}
} catch (Exception e) {
IJError.print(e);
getLayerSet().undoOneStep();
}
}
}
}, Display.this.project);
burro.addPostTask(new Runnable() {
@Override
public void run() {
final Set<DoStep> dataedits = new HashSet<DoStep>();
dataedits.add(new Displayable.DoEdit(Display.this.active).init(Display.this.active, new String[] { "data" }));
getLayerSet().addChangeTreesStep(dataedits);
}
});
burro.goHaveBreakfast();
} else if (command.equals("Reroot")) {
if (!(active instanceof Tree<?>))
return;
getLayerSet().addDataEditStep(active);
if (((Tree) active).reRoot(((Tree) active).getLastVisited())) {
getLayerSet().addDataEditStep(active);
Display.repaint(getLayerSet());
} else {
getLayerSet().removeLastUndoStep();
}
} else if (command.equals("Part subtree")) {
if (!(active instanceof Tree<?>))
return;
if (!Utils.check("Really part the subtree?"))
return;
final LayerSet.DoChangeTrees step = getLayerSet().addChangeTreesStep();
final Set<DoStep> deps = new HashSet<DoStep>();
// I hate java
deps.add(new Displayable.DoEdit(active).init(active, new String[] { "data" }));
step.addDependents(deps);
final List<ZDisplayable> ts = ((Tree) active).splitAt(((Tree) active).getLastVisited());
if (null == ts) {
getLayerSet().removeLastUndoStep();
return;
}
final Displayable elder = Display.this.active;
final HashSet<DoStep> deps2 = new HashSet<DoStep>();
for (final ZDisplayable t : ts) {
deps2.add(new Displayable.DoEdit(t).init(t, new String[] { "data" }));
if (t == elder)
continue;
// will change Display.this.active !
getLayerSet().add(t);
project.getProjectTree().addSibling(elder, t);
}
selection.clear();
selection.selectAll(ts);
selection.add(elder);
final LayerSet.DoChangeTrees step2 = getLayerSet().addChangeTreesStep();
step2.addDependents(deps2);
Display.repaint(getLayerSet());
} else if (command.equals("Show tabular view")) {
if (!(active instanceof Tree<?>))
return;
((Tree<?>) active).createMultiTableView();
} else if (command.equals("Mark")) {
if (!(active instanceof Tree<?>))
return;
final Point p = canvas.consumeLastPopupPoint();
if (null == p)
return;
if (((Tree<?>) active).markNear(p.x, p.y, layer, canvas.getMagnification())) {
Display.repaint(getLayerSet());
}
} else if (command.equals("Clear marks (selected Trees)")) {
for (final Tree<?> t : selection.get(Tree.class)) {
t.unmark();
}
Display.repaint(getLayerSet());
} else if (command.equals("Join")) {
if (!(active instanceof Tree<?>))
return;
final List<Tree<?>> tlines = (List<Tree<?>>) selection.get(active.getClass());
if (((Tree) active).canJoin(tlines)) {
final int nNodes_active = ((Tree) active).getRoot().getSubtreeNodes().size();
String warning = "";
for (final Tree<?> t : tlines) {
if (active == t)
continue;
if (null == t.getRoot()) {
Utils.log("Removed empty tree #" + t.getId() + " from those to join.");
tlines.remove(t);
continue;
}
if (t.getRoot().getSubtreeNodes().size() > nNodes_active) {
warning = "\nWARNING joining into a tree that is not the largest!";
break;
}
}
if (!Utils.check("Join these " + tlines.size() + " trees into the tree " + active + " ?" + warning))
return;
// Record current state
final Set<DoStep> dataedits = new HashSet<DoStep>(tlines.size());
for (final Tree<?> tl : tlines) {
dataedits.add(new Displayable.DoEdit(tl).init(tl, new String[] { "data" }));
}
getLayerSet().addChangeTreesStep(dataedits);
//
((Tree) active).join(tlines);
for (final Tree<?> tl : tlines) {
if (tl == active)
continue;
tl.remove2(false);
}
Display.repaint(getLayerSet());
// Again, to record current state (just the joined tree this time)
final Set<DoStep> dataedits2 = new HashSet<DoStep>(1);
dataedits2.add(new Displayable.DoEdit(active).init(active, new String[] { "data" }));
getLayerSet().addChangeTreesStep(dataedits2);
} else {
Utils.showMessage("Can't do", "Only one tree is selected.\nSelect more than one tree to perform a join operation!");
}
} else if (command.equals("Previous branch node or start")) {
if (!(active instanceof Tree<?>))
return;
final Point p = canvas.consumeLastPopupPoint();
if (null == p)
return;
center(((Treeline) active).findPreviousBranchOrRootPoint(p.x, p.y, layer, canvas));
} else if (command.equals("Next branch node or end")) {
if (!(active instanceof Tree<?>))
return;
final Point p = canvas.consumeLastPopupPoint();
if (null == p)
return;
center(((Tree<?>) active).findNextBranchOrEndPoint(p.x, p.y, layer, canvas));
} else if (command.equals("Root")) {
if (!(active instanceof Tree<?>))
return;
final Point p = canvas.consumeLastPopupPoint();
if (null == p)
return;
center(((Tree) active).createCoordinate(((Tree<?>) active).getRoot()));
} else if (command.equals("Last added node")) {
if (!(active instanceof Tree<?>))
return;
center(((Treeline) active).getLastAdded());
} else if (command.equals("Last edited node")) {
if (!(active instanceof Tree<?>))
return;
center(((Treeline) active).getLastEdited());
} else if (command.equals("Reverse point order")) {
if (!(active instanceof Pipe))
return;
getLayerSet().addDataEditStep(active);
((Pipe) active).reverse();
Display.repaint(Display.this.layer);
getLayerSet().addDataEditStep(active);
} else if (command.equals("View orthoslices")) {
if (!(active instanceof Patch))
return;
Display3D.showOrthoslices(((Patch) active));
} else if (command.equals("View volume")) {
if (!(active instanceof Patch))
return;
Display3D.showVolume(((Patch) active));
} else if (command.equals("Show in 3D")) {
for (final ZDisplayable zd : selection.get(ZDisplayable.class)) {
Display3D.show(zd.getProject().findProjectThing(zd));
}
// handle profile lists ...
final HashSet<ProjectThing> hs = new HashSet<ProjectThing>();
for (final Profile d : selection.get(Profile.class)) {
final ProjectThing profile_list = (ProjectThing) d.getProject().findProjectThing(d).getParent();
if (!hs.contains(profile_list)) {
Display3D.show(profile_list);
hs.add(profile_list);
}
}
} else if (command.equals("Snap")) {
// Take the active if it's a Patch
if (!(active instanceof Patch))
return;
Display.snap((Patch) active);
} else if (command.equals("Blend") || command.equals("Blend (selected images)...")) {
final HashSet<Patch> patches = new HashSet<Patch>(selection.get(Patch.class));
if (patches.size() > 1) {
final GenericDialog gd = new GenericDialog("Blending");
gd.addCheckbox("Respect current alpha mask", true);
gd.showDialog();
if (gd.wasCanceled())
return;
Blending.blend(patches, gd.getNextBoolean());
} else {
IJ.log("Please select more than one overlapping image.");
}
} else if (command.equals("Blend (layer-wise)...")) {
final GenericDialog gd = new GenericDialog("Blending");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.addCheckbox("Respect current alpha mask", true);
gd.addMessage("Filter:");
gd.addStringField("Use only images whose title matches:", "", 30);
gd.addCheckbox("Blend visible patches only", true);
gd.showDialog();
if (gd.wasCanceled())
return;
final boolean respect_alpha_mask = gd.getNextBoolean();
final String toMatch = gd.getNextString().trim();
final String regex = 0 == toMatch.length() ? null : ".*" + toMatch + ".*";
final boolean visible_only = gd.getNextBoolean();
Blending.blendLayerWise(getLayerSet().getLayers(gd.getNextChoiceIndex(), gd.getNextChoiceIndex()), respect_alpha_mask, new Filter<Patch>() {
@Override
public final boolean accept(final Patch patch) {
if (visible_only && !patch.isVisible())
return false;
if (null == regex)
return true;
return patch.getTitle().matches(regex);
}
});
} else if (command.equals("Match intensities (layer-wise)...")) {
Bureaucrat.createAndStart(new Worker.Task("Match intensities") {
@Override
public void exec() {
final MatchIntensities matching = new MatchIntensities();
matching.invoke(getActive());
}
}, project);
} else if (command.equals("Remove intensity maps (layer-wise)...")) {
final GenericDialog gd = new GenericDialog("Remove intensity maps");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.showDialog();
if (gd.wasCanceled())
return;
Bureaucrat.createAndStart(new Worker.Task("Match intensities") {
@Override
public void exec() {
for (final Layer layer : getLayerSet().getLayers(gd.getNextChoiceIndex(), gd.getNextChoiceIndex())) {
for (final Displayable p : layer.getDisplayables(Patch.class)) {
final Patch patch = (Patch) p;
if (patch.clearIntensityMap()) {
patch.updateMipMaps();
}
}
}
}
}, project);
} else if (command.equals("Montage")) {
final Set<Displayable> affected = new HashSet<Displayable>(selection.getAffected());
// make an undo step!
final LayerSet ls = layer.getParent();
ls.addTransformStepWithData(affected);
final Bureaucrat burro = AlignTask.alignSelectionTask(selection);
burro.addPostTask(new Runnable() {
@Override
public void run() {
ls.enlargeToFit(affected);
ls.addTransformStepWithData(affected);
}
});
} else if (command.equals("Lens correction")) {
final Layer la = layer;
la.getParent().addDataEditStep(new HashSet<Displayable>(la.getParent().getDisplayables()));
final Bureaucrat burro = DistortionCorrectionTask.correctDistortionFromSelection(selection);
burro.addPostTask(new Runnable() {
@Override
public void run() {
// no means to know which where modified and from which layers!
la.getParent().addDataEditStep(new HashSet<Displayable>(la.getParent().getDisplayables()));
}
});
} else if (command.equals("Link images...")) {
final GenericDialog gd = new GenericDialog("Options");
gd.addMessage("Linking images to images (within their own layer only):");
final String[] options = { "all images to all images", "each image with any other overlapping image" };
gd.addChoice("Link: ", options, options[1]);
final String[] options2 = { "selected images only", "all images in this layer", "all images in all layers, within the layer only", "all images in all layers, within and across consecutive layers" };
gd.addChoice("Apply to: ", options2, options2[0]);
gd.showDialog();
if (gd.wasCanceled())
return;
final Layer lay = layer;
final HashSet<Displayable> ds = new HashSet<Displayable>(lay.getParent().getDisplayables());
lay.getParent().addDataEditStep(ds, new String[] { "data" });
final boolean overlapping_only = 1 == gd.getNextChoiceIndex();
Collection<Displayable> coll = null;
switch(gd.getNextChoiceIndex()) {
case 0:
coll = selection.getSelected(Patch.class);
Patch.crosslink(coll, overlapping_only);
break;
case 1:
coll = lay.getDisplayables(Patch.class);
Patch.crosslink(coll, overlapping_only);
break;
case 2:
coll = new ArrayList<Displayable>();
for (final Layer la : lay.getParent().getLayers()) {
final Collection<Displayable> acoll = la.getDisplayables(Patch.class);
Patch.crosslink(acoll, overlapping_only);
coll.addAll(acoll);
}
break;
case 3:
final ArrayList<Layer> layers = lay.getParent().getLayers();
Collection<Displayable> lc1 = layers.get(0).getDisplayables(Patch.class);
if (lay == layers.get(0))
coll = lc1;
for (int i = 1; i < layers.size(); i++) {
final Collection<Displayable> lc2 = layers.get(i).getDisplayables(Patch.class);
if (null == coll && Display.this.layer == layers.get(i))
coll = lc2;
final Collection<Displayable> both = new ArrayList<Displayable>();
both.addAll(lc1);
both.addAll(lc2);
Patch.crosslink(both, overlapping_only);
lc1 = lc2;
}
break;
}
if (null != coll)
Display.updateCheckboxes(coll, DisplayablePanel.LINK_STATE, true);
lay.getParent().addDataEditStep(ds);
} else if (command.equals("Unlink all selected images")) {
if (Utils.check("Really unlink selected images?")) {
final Collection<Displayable> ds = selection.getSelected(Patch.class);
for (final Displayable d : ds) {
d.unlink();
}
Display.updateCheckboxes(ds, DisplayablePanel.LINK_STATE);
}
} else if (command.equals("Unlink all")) {
if (Utils.check("Really unlink all objects from all layers?")) {
final Collection<Displayable> ds = layer.getParent().getDisplayables();
for (final Displayable d : ds) {
d.unlink();
}
Display.updateCheckboxes(ds, DisplayablePanel.LINK_STATE);
}
} else if (command.equals("Calibration...")) {
try {
IJ.run(canvas.getFakeImagePlus(), "Properties...", "");
Display.updateTitle(getLayerSet());
// repaint layer names
project.getLayerTree().updateUILater();
} catch (final RuntimeException re) {
Utils.log2("Calibration dialog canceled.");
}
} else if (command.equals("Grid overlay...")) {
if (null == gridoverlay)
gridoverlay = new GridOverlay();
gridoverlay.setup(canvas.getFakeImagePlus().getRoi());
canvas.repaint(false);
} else if (command.equals("Enhance contrast (selected images)...")) {
final Layer la = layer;
final ArrayList<Displayable> selected = selection.getSelected(Patch.class);
final HashSet<Displayable> ds = new HashSet<Displayable>(selected);
la.getParent().addDataEditStep(ds);
final Displayable active = Display.this.getActive();
final Patch ref = active.getClass() == Patch.class ? (Patch) active : null;
final Bureaucrat burro = getProject().getLoader().enhanceContrast(selected, ref);
burro.addPostTask(new Runnable() {
@Override
public void run() {
la.getParent().addDataEditStep(ds);
}
});
} else if (command.equals("Enhance contrast layer-wise...")) {
// ask for range of layers
final GenericDialog gd = new GenericDialog("Choose range");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.showDialog();
if (gd.wasCanceled())
return;
// exclusive end
final java.util.List<Layer> layers = layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1);
final HashSet<Displayable> ds = new HashSet<Displayable>();
for (final Layer l : layers) ds.addAll(l.getDisplayables(Patch.class));
getLayerSet().addDataEditStep(ds);
final Bureaucrat burro = project.getLoader().enhanceContrast(layers);
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().addDataEditStep(ds);
}
});
} else if (command.equals("Adjust image filters (selected images)")) {
if (selection.isEmpty() || !(active instanceof Patch))
return;
FilterEditor.GUI(selection.get(Patch.class), (Patch) active);
} else if (command.equals("Set Min and Max layer-wise...")) {
final Displayable active = getActive();
double min = 0;
double max = 0;
if (null != active && active.getClass() == Patch.class) {
min = ((Patch) active).getMin();
max = ((Patch) active).getMax();
}
final GenericDialog gd = new GenericDialog("Min and Max");
gd.addMessage("Set min and max to all images in the layer range");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.addNumericField("min: ", min, 2);
gd.addNumericField("max: ", max, 2);
gd.showDialog();
if (gd.wasCanceled())
return;
//
min = gd.getNextNumber();
max = gd.getNextNumber();
final ArrayList<Displayable> al = new ArrayList<Displayable>();
for (final Layer la : layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1)) {
// exclusive end
al.addAll(la.getDisplayables(Patch.class));
}
final HashSet<Displayable> ds = new HashSet<Displayable>(al);
getLayerSet().addDataEditStep(ds);
final Bureaucrat burro = project.getLoader().setMinAndMax(al, min, max);
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().addDataEditStep(ds);
}
});
} else if (command.equals("Set Min and Max (selected images)...")) {
final Displayable active = getActive();
double min = 0;
double max = 0;
if (null != active && active.getClass() == Patch.class) {
min = ((Patch) active).getMin();
max = ((Patch) active).getMax();
}
final GenericDialog gd = new GenericDialog("Min and Max");
gd.addMessage("Set min and max to all selected images");
gd.addNumericField("min: ", min, 2);
gd.addNumericField("max: ", max, 2);
gd.showDialog();
if (gd.wasCanceled())
return;
//
min = gd.getNextNumber();
max = gd.getNextNumber();
final HashSet<Displayable> ds = new HashSet<Displayable>(selection.getSelected(Patch.class));
getLayerSet().addDataEditStep(ds);
final Bureaucrat burro = project.getLoader().setMinAndMax(selection.getSelected(Patch.class), min, max);
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().addDataEditStep(ds);
}
});
} else if (command.equals("Adjust min and max (selected images)...")) {
adjustMinAndMaxGUI();
} else if (command.equals("Mask image borders (layer-wise)...")) {
final GenericDialog gd = new GenericDialog("Mask borders");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.addMessage("Borders:");
gd.addNumericField("left: ", 6, 2);
gd.addNumericField("top: ", 6, 2);
gd.addNumericField("right: ", 6, 2);
gd.addNumericField("bottom: ", 6, 2);
gd.showDialog();
if (gd.wasCanceled())
return;
final Collection<Layer> layers = layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1);
final HashSet<Displayable> ds = new HashSet<Displayable>();
for (final Layer l : layers) ds.addAll(l.getDisplayables(Patch.class));
getLayerSet().addDataEditStep(ds);
final Bureaucrat burro = project.getLoader().maskBordersLayerWise(layers, (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber());
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().addDataEditStep(ds);
}
});
} else if (command.equals("Mask image borders (selected images)...")) {
final GenericDialog gd = new GenericDialog("Mask borders");
gd.addMessage("Borders:");
gd.addNumericField("left: ", 6, 2);
gd.addNumericField("top: ", 6, 2);
gd.addNumericField("right: ", 6, 2);
gd.addNumericField("bottom: ", 6, 2);
gd.showDialog();
if (gd.wasCanceled())
return;
final Collection<Displayable> patches = selection.getSelected(Patch.class);
final HashSet<Displayable> ds = new HashSet<Displayable>(patches);
getLayerSet().addDataEditStep(ds);
final Bureaucrat burro = project.getLoader().maskBorders(patches, (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber());
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().addDataEditStep(ds);
}
});
} else if (command.equals("Remove alpha masks (layer-wise)...")) {
final GenericDialog gd = new GenericDialog("Remove alpha masks");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.addCheckbox("Visible only", true);
gd.showDialog();
if (gd.wasCanceled())
return;
final Collection<Layer> layers = layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1);
final boolean visible_only = gd.getNextBoolean();
final Collection<Patch> patches = new ArrayList<Patch>();
for (final Layer l : layers) {
patches.addAll((Collection<Patch>) (Collection) l.getDisplayables(Patch.class, visible_only));
}
Display.removeAlphaMasks(patches);
} else if (command.equals("Remove alpha masks (selected images)...")) {
Display.removeAlphaMasks(selection.get(Patch.class));
} else if (command.equals("Split images under polyline ROI")) {
final Roi roi = canvas.getFakeImagePlus().getRoi();
if (null == roi)
return;
if (!(roi.getType() == Roi.POLYLINE || roi.getType() == Roi.FREELINE)) {
Utils.showMessage("Need a polyline or freeline ROI, not just any ROI!");
return;
}
if (!Utils.check("Really split images under the ROI?")) {
return;
}
// OK identify images whose contour intersects the ROI
final Set<Displayable> col = new HashSet<Displayable>();
// FreehandRoi is a subclass of PolygonRoi
final PolygonRoi proi = (PolygonRoi) roi;
final int[] x = proi.getXCoordinates(), y = proi.getYCoordinates();
final Rectangle b = proi.getBounds();
final Polygon[] pols = new Polygon[proi.getNCoordinates() - 1];
for (int i = 0; i < pols.length; i++) {
pols[i] = new Polygon(new int[] { b.x + x[i], b.x + x[i] + 1, b.x + x[i + 1], b.x + x[i + 1] + 1 }, new int[] { b.y + y[i], b.y + y[i], b.y + y[i + 1], b.y + y[i + 1] }, 4);
}
for (final Patch p : getLayer().getAll(Patch.class)) {
if (!p.isVisible())
continue;
final Area a = p.getArea();
for (int i = 0; i < pols.length; i++) {
final Area c = new Area(pols[i]);
c.intersect(a);
if (M.isEmpty(c))
continue;
// Else, add it:
col.add(p);
break;
}
}
if (col.isEmpty()) {
Utils.showMessage("No images intersect the ROI!");
return;
}
for (int i = 1; i < proi.getNCoordinates(); i++) {
for (int k = i + 2; k < proi.getNCoordinates(); k++) {
// check if the two segments intersect
if (null != M.computeSegmentsIntersection(x[i - 1], y[i - 1], x[i], y[i], x[k - 1], y[k - 1], x[k], y[k])) {
Utils.showMessage("Cannot split images with a polygon ROI that intersects itself!");
return;
}
}
}
final Area[] as = M.splitArea(new Area(getLayerSet().get2DBounds()), proi, getLayerSet().get2DBounds());
final Color[] c = new Color[] { Color.blue, Color.red };
int i = 0;
for (final Area a : as) {
// Utils.log2("Added overlay " + i + " with color " + c[i] + " and area " + AreaCalculations.area(a.getPathIterator(null)));
getLayer().getOverlay().add(a, c[i++], null, true, false, 0.4f);
}
Display.repaint(getLayer());
final YesNoDialog yn = new YesNoDialog(frame, "Check", "Does the splitting match your expectations?\nPush 'yes' to split the images.", false);
yn.setModal(false);
for (final WindowListener wl : yn.getWindowListeners()) yn.removeWindowListener(wl);
yn.setClosingTask(new Runnable() {
@Override
public void run() {
try {
// Remove overlay shapes
for (final Area a : as) {
getLayer().getOverlay().remove(a);
}
if (!yn.yesPressed()) {
Utils.log2("Pushed 'no'");
return;
}
// Split intersecting patches
// Duplicate each intersecting patch, and assign a[0] to the original and a[1] to the copy, as mask.
Bureaucrat.createAndStart(new Worker.Task("Spliting images") {
@Override
public void exec() {
final Roi r1 = new ShapeRoi(as[0]), r2 = new ShapeRoi(as[1]);
final ArrayList<Future<?>> fus = new ArrayList<Future<?>>();
for (final Patch p : (Collection<Patch>) (Collection) col) {
final Patch copy = (Patch) p.clone(p.getProject(), false);
p.addAlphaMask(r1, 0);
copy.addAlphaMask(r2, 0);
fus.add(p.updateMipMaps());
fus.add(copy.updateMipMaps());
// after submitting mipmaps, since it will get added to all Displays and repainted.
p.getLayer().add(copy);
}
Utils.wait(fus);
}
}, project);
} catch (final Throwable t) {
IJError.print(t);
} finally {
yn.dispose();
Display.repaint(getLayer());
}
}
});
yn.setVisible(true);
} else if (command.equals("Duplicate")) {
// only Patch and DLabel, i.e. Layer-only resident objects that don't exist in the Project Tree
final HashSet<Class> accepted = new HashSet<Class>();
accepted.add(Patch.class);
accepted.add(DLabel.class);
accepted.add(Stack.class);
final ArrayList<Displayable> originals = new ArrayList<Displayable>();
final ArrayList<Displayable> selected = selection.getSelected();
for (final Displayable d : selected) {
if (accepted.contains(d.getClass())) {
originals.add(d);
}
}
if (originals.size() > 0) {
getLayerSet().addChangeTreesStep();
for (final Displayable d : originals) {
if (d instanceof ZDisplayable) {
d.getLayerSet().add((ZDisplayable) d.clone());
} else {
d.getLayer().add(d.clone());
}
}
getLayerSet().addChangeTreesStep();
} else if (selected.size() > 0) {
Utils.log("Can only duplicate images and text labels.\nDuplicate *other* objects in the Project Tree.\n");
}
} else if (command.equals("Create subproject")) {
// Choose a 2D rectangle
final Roi roi = canvas.getFakeImagePlus().getRoi();
Rectangle bounds;
if (null != roi) {
if (!Utils.check("Use bounds as defined by the ROI:\n" + roi.getBounds() + " ?"))
return;
bounds = roi.getBounds();
} else
bounds = getLayerSet().get2DBounds();
// Choose a layer range, and whether to ignore hidden images
final GenericDialog gd = new GenericDialog("Choose layer range");
Utils.addLayerRangeChoices(layer, gd);
gd.addCheckbox("Ignore hidden images", true);
gd.showDialog();
if (gd.wasCanceled())
return;
final Layer first = layer.getParent().getLayer(gd.getNextChoiceIndex());
final Layer last = layer.getParent().getLayer(gd.getNextChoiceIndex());
final boolean ignore_hidden_patches = gd.getNextBoolean();
final Project sub = getProject().createSubproject(bounds, first, last, ignore_hidden_patches);
if (null == sub) {
Utils.log("ERROR: failed to create subproject.");
return;
}
final LayerSet subls = sub.getRootLayerSet();
Display.createDisplay(sub, subls.getLayer(0));
} else if (command.startsWith("Image stack under selected Arealist")) {
if (null == active || active.getClass() != AreaList.class)
return;
final GenericDialog gd = new GenericDialog("Stack options");
final String[] types = { "8-bit", "16-bit", "32-bit", "RGB" };
gd.addChoice("type:", types, types[0]);
gd.addSlider("Scale: ", 1, 100, 100);
gd.showDialog();
if (gd.wasCanceled())
return;
final int type;
switch(gd.getNextChoiceIndex()) {
case 0:
type = ImagePlus.GRAY8;
break;
case 1:
type = ImagePlus.GRAY16;
break;
case 2:
type = ImagePlus.GRAY32;
break;
case 3:
type = ImagePlus.COLOR_RGB;
break;
default:
type = ImagePlus.GRAY8;
break;
}
final ImagePlus imp = ((AreaList) active).getStack(type, gd.getNextNumber() / 100);
if (null != imp)
imp.show();
} else if (command.equals("Fly through selected Treeline/AreaTree")) {
if (null == active || !(active instanceof Tree<?>))
return;
Bureaucrat.createAndStart(new Worker.Task("Creating fly through", true) {
@Override
public void exec() {
final GenericDialog gd = new GenericDialog("Fly through");
gd.addNumericField("Width", 512, 0);
gd.addNumericField("Height", 512, 0);
final String[] types = new String[] { "8-bit gray", "Color RGB" };
gd.addChoice("Image type", types, types[0]);
gd.addSlider("scale", 0, 100, 100);
gd.addCheckbox("save to file", false);
gd.showDialog();
if (gd.wasCanceled())
return;
final int w = (int) gd.getNextNumber();
final int h = (int) gd.getNextNumber();
final int type = 0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY8 : ImagePlus.COLOR_RGB;
final double scale = gd.getNextNumber();
if (w <= 0 || h <= 0) {
Utils.log("Invalid width or height: " + w + ", " + h);
return;
}
if (0 == scale || Double.isNaN(scale)) {
Utils.log("Invalid scale: " + scale);
return;
}
String dir = null;
if (gd.getNextBoolean()) {
final DirectoryChooser dc = new DirectoryChooser("Target directory");
dir = dc.getDirectory();
// canceled
if (null == dir)
return;
dir = Utils.fixDir(dir);
}
final ImagePlus imp = ((Tree<?>) active).flyThroughMarked(w, h, scale / 100, type, dir);
if (null == imp) {
Utils.log("Mark a node first!");
return;
}
imp.show();
}
}, project);
} else if (command.startsWith("Arealists as labels")) {
final GenericDialog gd = new GenericDialog("Export labels");
gd.addSlider("Scale: ", 1, 100, 100);
final String[] options = { "All area list", "Selected area lists" };
gd.addChoice("Export: ", options, options[0]);
Utils.addLayerRangeChoices(layer, gd);
gd.addCheckbox("Visible only", true);
gd.showDialog();
if (gd.wasCanceled())
return;
final float scale = (float) (gd.getNextNumber() / 100);
final java.util.List<Displayable> al = (java.util.List<Displayable>) (0 == gd.getNextChoiceIndex() ? layer.getParent().getZDisplayables(AreaList.class) : selection.getSelectedSorted(AreaList.class));
if (null == al) {
Utils.log("No area lists found to export.");
return;
}
// Generics are ... a pain? I don't understand them? They fail when they shouldn't? And so easy to workaround that they are a shame?
final int first = gd.getNextChoiceIndex();
final int last = gd.getNextChoiceIndex();
final boolean visible_only = gd.getNextBoolean();
if (-1 != command.indexOf("(amira)")) {
AreaList.exportAsLabels(al, canvas.getFakeImagePlus().getRoi(), scale, first, last, visible_only, true, true);
} else if (-1 != command.indexOf("(tif)")) {
AreaList.exportAsLabels(al, canvas.getFakeImagePlus().getRoi(), scale, first, last, visible_only, false, false);
}
} else if (command.equals("Project properties...")) {
project.adjustProperties();
} else if (command.equals("Release memory...")) {
Bureaucrat.createAndStart(new Worker("Releasing memory") {
@Override
public void run() {
startedWorking();
try {
final GenericDialog gd = new GenericDialog("Release Memory");
final int max = (int) (IJ.maxMemory() / 1000000);
gd.addSlider("Megabytes: ", 0, max, max / 2);
gd.showDialog();
if (!gd.wasCanceled()) {
final int n_mb = (int) gd.getNextNumber();
project.getLoader().releaseToFit((long) n_mb * 1000000);
}
} catch (final Throwable e) {
IJError.print(e);
} finally {
finishedWorking();
}
}
}, project);
} else if (command.equals("Create sibling project with retiled layers")) {
final GenericDialog gd = new GenericDialog("Export flattened layers");
gd.addNumericField("Tile_width", 2048, 0);
gd.addNumericField("Tile_height", 2048, 0);
final String[] types = new String[] { "16-bit", "RGB color" };
gd.addChoice("Export_image_type", types, types[0]);
gd.addCheckbox("Create mipmaps", true);
gd.addNumericField("Number_of_threads_to_use", Runtime.getRuntime().availableProcessors(), 0);
gd.showDialog();
if (gd.wasCanceled())
return;
final DirectoryChooser dc = new DirectoryChooser("Choose target folder");
final String folder = dc.getDirectory();
if (null == folder)
return;
final int tileWidth = (int) gd.getNextNumber(), tileHeight = (int) gd.getNextNumber();
if (tileWidth < 0 || tileHeight < 0) {
Utils.showMessage("Invalid tile sizes: " + tileWidth + ", " + tileHeight);
return;
}
if (tileWidth != tileHeight) {
if (!Utils.check("The tile width (" + tileWidth + ") differs from the tile height (" + tileHeight + ").\nContinue anyway?")) {
return;
}
}
final int imageType = 0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY16 : ImagePlus.COLOR_RGB;
final boolean createMipMaps = gd.getNextBoolean();
final int nThreads = (int) gd.getNextNumber();
Bureaucrat.createAndStart(new Worker.Task("Export flattened sibling project") {
@Override
public void exec() {
try {
ProjectTiler.createRetiledSibling(project, folder, tileWidth, tileHeight, imageType, true, nThreads, createMipMaps);
} catch (final Throwable t) {
Utils.showMessage("ERROR: " + t);
IJError.print(t);
}
}
}, project);
} else if (command.equals("Flush image cache")) {
Loader.releaseAllCaches();
} else if (command.equals("Regenerate all mipmaps")) {
project.getLoader().regenerateMipMaps(getLayerSet().getDisplayables(Patch.class));
} else if (command.equals("Regenerate mipmaps (selected images)")) {
project.getLoader().regenerateMipMaps(selection.getSelected(Patch.class));
} else if (command.equals("Tags...")) {
// get a file first
final File f = Utils.chooseFile(null, "tags", ".xml");
if (null == f)
return;
if (!Utils.saveToFile(f, getLayerSet().exportTags())) {
Utils.logAll("ERROR when saving tags to file " + f.getAbsolutePath());
}
} else if (command.equals("Tags ...")) {
final String[] ff = Utils.selectFile("Import tags");
if (null == ff)
return;
final GenericDialog gd = new GenericDialog("Import tags");
final String[] modes = new String[] { "Append to current tags", "Replace current tags" };
gd.addChoice("Import tags mode:", modes, modes[0]);
gd.addMessage("Replacing current tags\nwill remove all tags\n from all nodes first!");
gd.showDialog();
if (gd.wasCanceled())
return;
getLayerSet().importTags(new StringBuilder(ff[0]).append('/').append(ff[1]).toString(), 1 == gd.getNextChoiceIndex());
} else if (command.equals("Connectivity graph...")) {
Bureaucrat.createAndStart(new Worker.Task("Connectivity graph") {
@Override
public void exec() {
Graph.extractAndShowGraph(getLayerSet());
}
}, getProject());
} else if (command.equals("NeuroML...")) {
final GenericDialog gd = new GenericDialog("Export NeuroML");
final String[] a = new String[] { "NeuroML (arbors and synapses)", "MorphML (arbors)" };
gd.addChoice("Type:", a, a[0]);
final String[] b = new String[] { "All treelines and areatrees", "Selected treelines and areatrees" };
gd.addChoice("Export:", b, b[0]);
gd.showDialog();
if (gd.wasCanceled())
return;
final int type = gd.getNextChoiceIndex();
final int export = gd.getNextChoiceIndex();
//
final SaveDialog sd = new SaveDialog("Choose .mml file", null, ".mml");
final String filename = sd.getFileName();
// canceled
if (null == filename)
return;
final File f = new File(sd.getDirectory() + filename);
//
Bureaucrat.createAndStart(new Worker.Task("Export NeuroML") {
@Override
public void exec() {
OutputStreamWriter w = null;
try {
final Set<Tree<?>> trees = new HashSet<Tree<?>>();
Collection<? extends Displayable> ds = null;
switch(export) {
case 0:
ds = getLayerSet().getZDisplayables();
break;
case 1:
ds = selection.getSelected();
break;
}
for (final Displayable d : ds) {
if (d.getClass() == Treeline.class || d.getClass() == AreaTree.class) {
trees.add((Tree<?>) d);
}
}
if (trees.isEmpty()) {
Utils.showMessage("No trees to export!");
return;
}
//
// encoding in Latin 1 (for macosx not to mess around
w = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(f), 65536), "8859_1");
//
switch(type) {
case 0:
NeuroML.exportNeuroML(trees, w);
break;
case 1:
NeuroML.exportMorphML(trees, w);
break;
}
//
w.flush();
w.close();
//
} catch (final Throwable t) {
IJError.print(t);
try {
if (null != w)
w.close();
} catch (final Exception ee) {
IJError.print(ee);
}
}
}
}, getProject());
} else if (command.equals("Measure")) {
if (selection.isEmpty()) {
Utils.log("Nothing selected to measure!");
return;
}
selection.measure();
} else if (command.equals("Area interpolation options...")) {
final GenericDialog gd = new GenericDialog("Area interpolation");
final boolean a = project.getBooleanProperty(AreaUtils.always_interpolate_areas_with_distance_map);
gd.addCheckbox("Always use distance map method", a);
gd.showDialog();
if (gd.wasCanceled())
return;
project.setProperty(AreaUtils.always_interpolate_areas_with_distance_map, gd.getNextBoolean() ? "true" : null);
} else {
Utils.log2("Display: don't know what to do with command " + command);
}
}
});
}
use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.
the class Display method addAreaListAreasMenu.
private void addAreaListAreasMenu(final JPopupMenu popup2, final Displayable active) {
final ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(final ActionEvent ae) {
final String command = ae.getActionCommand();
Bureaucrat.createAndStart(new Worker.Task(command) {
@Override
public void exec() {
if (command.equals("Copy area")) {
if (null == active || !(active instanceof AreaList))
return;
final AreaList ali = (AreaList) active;
final Area area = ali.getArea(getLayer());
if (null == area)
return;
DisplayCanvas.setCopyBuffer(ali.getClass(), area.createTransformedArea(ali.getAffineTransform()));
} else if (command.equals("Paste area")) {
if (null == active || !(active instanceof AreaList))
return;
final AreaList ali = (AreaList) active;
final Area wa = (Area) DisplayCanvas.getCopyBuffer(ali.getClass());
if (null == wa)
return;
try {
getLayerSet().addDataEditStep(ali);
ali.addArea(getLayer().getId(), wa.createTransformedArea(ali.getAffineTransform().createInverse()));
ali.calculateBoundingBox(getLayer());
getLayerSet().addDataEditStep(ali);
} catch (final NoninvertibleTransformException e) {
IJError.print(e);
getLayerSet().undoOneStep();
}
} else if (command.equals("Interpolate gaps towards previous area")) {
if (null == active || !(active instanceof AreaList))
return;
final AreaList ali = (AreaList) active;
// Is there an area in this layer?
final Layer current = getLayer();
if (null == ali.getArea(current))
return;
// Find a layer before the current that has an area
final LayerSet ls = getLayerSet();
// already at first
if (0 == ls.indexOf(current))
return;
Layer previous = null;
// Iterate layers towards the first layer
for (final ListIterator<Layer> it = ls.getLayers().listIterator(ls.indexOf(current)); it.hasPrevious(); ) {
final Layer la = it.previous();
if (null != ali.getArea(la)) {
previous = la;
break;
}
}
// all empty
if (null == previous)
return;
try {
ls.addDataEditStep(ali);
ali.interpolate(previous, current, project.getBooleanProperty(AreaUtils.always_interpolate_areas_with_distance_map));
ls.addDataEditStep(ali);
} catch (final Exception e) {
IJError.print(e);
ls.undoOneStep();
}
} else if (command.equals("Interpolate gaps towards next area")) {
if (null == active || !(active instanceof AreaList))
return;
final AreaList ali = (AreaList) active;
// Is there an area in this layer?
final Layer current = getLayer();
if (null == ali.getArea(current))
return;
// Find a layer after the current that has an area
final LayerSet ls = getLayerSet();
// already at the end
if (ls.size() - 1 == ls.indexOf(current))
return;
Layer next = null;
// Iterate towards the next layer
for (final ListIterator<Layer> it = ls.getLayers().listIterator(ls.indexOf(current) + 1); it.hasNext(); ) {
final Layer la = it.next();
if (null != ali.getArea(la)) {
next = la;
break;
}
}
// all empty
if (null == next)
return;
try {
ls.addDataEditStep(ali);
ali.interpolate(current, next, project.getBooleanProperty(AreaUtils.always_interpolate_areas_with_distance_map));
ls.addDataEditStep(ali);
} catch (final Exception e) {
IJError.print(e);
ls.undoOneStep();
}
} else if (command.equals("Interpolate all gaps")) {
if (null == active || !(active instanceof AreaList))
return;
final AreaList ali = (AreaList) active;
// find the first and last layers with areas
Layer first = null;
Layer last = null;
final LayerSet ls = getLayerSet();
final List<Layer> las = ls.getLayers();
for (final Layer la : las) {
if (null == first && null != ali.getArea(la)) {
first = la;
break;
}
}
for (final ListIterator<Layer> it = las.listIterator(las.size()); it.hasPrevious(); ) {
final Layer la = it.previous();
if (null == last && null != ali.getArea(la)) {
last = la;
break;
}
}
Utils.log2(first, last);
if (null != first && first != last) {
try {
ls.addDataEditStep(ali);
ali.interpolate(first, last, project.getBooleanProperty(AreaUtils.always_interpolate_areas_with_distance_map));
ls.addDataEditStep(ali);
} catch (final Exception e) {
IJError.print(e);
ls.undoOneStep();
}
}
}
Display.repaint(getLayer());
}
}, active.getProject());
}
};
final JMenu interpolate = new JMenu("Areas");
JMenuItem item = new JMenuItem("Interpolate gaps towards previous area");
item.addActionListener(listener);
interpolate.add(item);
item = new JMenuItem("Interpolate gaps towards next area");
item.addActionListener(listener);
interpolate.add(item);
item = new JMenuItem("Interpolate all gaps");
item.addActionListener(listener);
interpolate.add(item);
item = new JMenuItem("Area interpolation options...");
item.addActionListener(Display.this);
interpolate.add(item);
interpolate.addSeparator();
item = new JMenuItem("Copy area");
item.addActionListener(listener);
interpolate.add(item);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, 0, true));
item = new JMenuItem("Paste area");
item.addActionListener(listener);
interpolate.add(item);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, 0, true));
item.setEnabled(null != DisplayCanvas.getCopyBuffer(active.getClass()));
popup.add(interpolate);
}
use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.
the class Display method addAreaTreeAreasMenu.
private void addAreaTreeAreasMenu(final JPopupMenu popup, final AreaTree atree) {
final ActionListener listener = new ActionListener() {
private final Node<?> findNearestNode() {
final Layer la = getLayer();
final Point p = canvas.consumeLastPopupPoint();
final Node<?> lv = atree.getLastVisited();
boolean use_last_visited = false;
if (null != lv) {
final float[] xy = new float[] { lv.x, lv.y };
atree.getAffineTransform().transform(xy, 0, xy, 0, 1);
use_last_visited = lv.getLayer() == la && canvas.getSrcRect().contains((int) xy[0], (int) xy[1]);
}
// if no node lays near the clicked point.
return atree.findNodeNear(p.x, p.y, la, canvas, use_last_visited);
}
@Override
public void actionPerformed(final ActionEvent ae) {
final String command = ae.getActionCommand();
final LayerSet ls = atree.getLayerSet();
Bureaucrat.createAndStart(new Worker.Task(command) {
@Override
public void exec() {
final Node<?> nd = findNearestNode();
if (null == nd) {
Utils.log("No node found in the field of view!");
return;
}
if (command.equals("Copy area")) {
final Area area = (Area) nd.getData();
if (null == area)
return;
DisplayCanvas.setCopyBuffer(atree.getClass(), area.createTransformedArea(atree.getAffineTransform()));
} else if (command.equals("Paste area")) {
final Area wa = (Area) DisplayCanvas.getCopyBuffer(atree.getClass());
if (null == wa)
return;
try {
getLayerSet().addDataEditStep(atree);
atree.addWorldAreaTo(nd, wa);
atree.calculateBoundingBox(nd.getLayer());
getLayerSet().addDataEditStep(atree);
} catch (final Exception e) {
IJError.print(e);
getLayerSet().removeLastUndoStep();
}
} else if (command.equals("Interpolate gaps towards parent (node-centric)")) {
interpolate(nd, true);
} else if (command.equals("Interpolate gaps towards parent (absolute)")) {
interpolate(nd, false);
} else if (command.equals("Interpolate all gaps")) {
final GenericDialog gd = new GenericDialog("Interpolate");
final String[] a = new String[] { "node-centric", "absolute" };
gd.addChoice("Mode", a, a[0]);
gd.addCheckbox("Always use distance map", project.getBooleanProperty(AreaUtils.always_interpolate_areas_with_distance_map));
final String[] b = new String[] { "All selected AreaTrees", "Active AreaTree" };
gd.addChoice("Process", b, b[0]);
gd.showDialog();
if (gd.wasCanceled())
return;
final boolean node_centric = 0 == gd.getNextChoiceIndex();
final boolean use_distance_map = gd.getNextBoolean();
final boolean all = 0 == gd.getNextChoiceIndex();
final Set<Displayable> s = new HashSet<Displayable>();
if (all)
s.addAll(selection.get(AreaTree.class));
else
s.add(atree);
// Store current state for undo
ls.addDataEditStep(s);
try {
for (final Displayable d : s) {
((AreaTree) d).interpolateAllGaps(node_centric, use_distance_map);
}
ls.addDataEditStep(s);
} catch (final Exception e) {
IJError.print(e);
ls.undoOneStep();
}
Display.repaint();
}
}
private final void interpolate(final Node<?> nd, final boolean node_centric) {
if (null == nd.getDataCopy() || ((Area) nd.getData()).isEmpty()) {
Utils.log("Can't interpolate: node lacks an area!");
return;
}
ls.addDataEditStep(atree);
try {
if (atree.interpolateTowardsParent((AreaTree.AreaNode) nd, node_centric, project.getBooleanProperty(AreaUtils.always_interpolate_areas_with_distance_map))) {
ls.addDataEditStep(atree);
} else {
Utils.log("Nothing to interpolate: the parent node already has an area.");
ls.removeLastUndoStep();
}
} catch (final Exception e) {
IJError.print(e);
ls.undoOneStep();
}
Display.repaint();
}
}, atree.getProject());
}
};
final JMenu interpolate = new JMenu("Areas");
JMenuItem item = new JMenuItem("Interpolate gaps towards parent (node-centric)");
item.addActionListener(listener);
interpolate.add(item);
item = new JMenuItem("Interpolate gaps towards parent (absolute)");
item.addActionListener(listener);
interpolate.add(item);
item = new JMenuItem("Interpolate all gaps");
item.addActionListener(listener);
interpolate.add(item);
item = new JMenuItem("Area interpolation options...");
item.addActionListener(Display.this);
interpolate.add(item);
interpolate.addSeparator();
item = new JMenuItem("Copy area");
item.addActionListener(listener);
interpolate.add(item);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, 0, true));
item = new JMenuItem("Paste area");
item.addActionListener(listener);
interpolate.add(item);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, 0, true));
item.setEnabled(null != DisplayCanvas.getCopyBuffer(active.getClass()));
popup.add(interpolate);
}
use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.
the class Display method insertStack.
/**
* @param stack_patch is just a Patch of a series of Patch that make a stack of Patches.
*/
private boolean insertStack(final ProjectThing target_landmarks, final Project source, final ProjectThing source_landmarks, final Patch stack_patch) {
final List<Ball> l1 = new ArrayList<Ball>();
final List<Ball> l2 = new ArrayList<Ball>();
// source is the one that has the stack_patch
final Collection<ProjectThing> b1s = source_landmarks.findChildrenOfType("ball");
// target is this
final Collection<ProjectThing> b2s = target_landmarks.findChildrenOfType("ball");
final HashSet<String> seen = new HashSet<String>();
for (final ProjectThing b1 : b1s) {
final Ball ball1 = (Ball) b1.getObject();
if (null == ball1) {
Utils.log("ERROR: there's an empty 'ball' node in target project" + project.toString());
return false;
}
final String title1 = ball1.getTitle();
for (final ProjectThing b2 : b2s) {
final Ball ball2 = (Ball) b2.getObject();
if (null == ball2) {
Utils.log("ERROR: there's an empty 'ball' node in source project" + source.toString());
return false;
}
if (title1.equals(ball2.getTitle())) {
if (seen.contains(title1))
continue;
seen.add(title1);
l1.add(ball1);
l2.add(ball2);
}
}
}
if (l1.size() < 4) {
Utils.log("ERROR: found only " + l1.size() + " common landmarks: needs at least 4!");
return false;
}
// Extract coordinates of source project landmarks, in patch stack coordinate space
final List<double[]> c1 = new ArrayList<double[]>();
for (final Ball ball1 : l1) {
final Map<Layer, double[]> m = ball1.getRawBalls();
if (1 != m.size()) {
Utils.log("ERROR: ball object " + ball1 + " from target project " + project + " has " + m.size() + " balls instead of just 1.");
return false;
}
final Map.Entry<Layer, double[]> e = m.entrySet().iterator().next();
final Layer layer = e.getKey();
final double[] xyr = e.getValue();
final double[] fin = new double[] { xyr[0], xyr[1] };
final AffineTransform affine = ball1.getAffineTransformCopy();
try {
affine.preConcatenate(stack_patch.getAffineTransform().createInverse());
} catch (final Exception nite) {
IJError.print(nite);
return false;
}
final double[] fout = new double[2];
affine.transform(fin, 0, fout, 0, 1);
c1.add(new double[] { fout[0], fout[1], layer.getParent().indexOf(layer) });
}
// Extract coordinates of target (this) project landmarks, in calibrated world space
final List<double[]> c2 = new ArrayList<double[]>();
for (final Ball ball2 : l2) {
final double[][] b = ball2.getBalls();
if (1 != b.length) {
Utils.log("ERROR: ball object " + ball2 + " from source project " + source + " has " + b.length + " balls instead of just 1.");
return false;
}
final double[] fin = new double[] { b[0][0], b[0][1] };
final AffineTransform affine = ball2.getAffineTransformCopy();
final double[] fout = new double[2];
affine.transform(fin, 0, fout, 0, 1);
c2.add(new double[] { fout[0], fout[1], b[0][2] });
}
// Print landmarks:
Utils.log("Landmarks:");
for (Iterator<double[]> it1 = c1.iterator(), it2 = c2.iterator(); it1.hasNext(); ) {
Utils.log(Utils.toString(it1.next()) + " <--> " + Utils.toString(it2.next()));
}
// Create point matches
final List<PointMatch> pm = new ArrayList<PointMatch>();
for (Iterator<double[]> it1 = c1.iterator(), it2 = c2.iterator(); it1.hasNext(); ) {
pm.add(new mpicbg.models.PointMatch(new mpicbg.models.Point(it1.next()), new mpicbg.models.Point(it2.next())));
}
// Estimate AffineModel3D
final AffineModel3D aff3d = new AffineModel3D();
try {
aff3d.fit(pm);
} catch (final Exception e) {
IJError.print(e);
return false;
}
// Create and add the Stack
final String path = stack_patch.getImageFilePath();
final Stack st = new Stack(project, new File(path).getName(), 0, 0, getLayerSet().getLayers().get(0), path);
st.setInvertibleCoordinateTransform(aff3d);
getLayerSet().add(st);
return true;
}
use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.
the class Display method makeGUI.
private void makeGUI(final Layer layer, final Object[] props) {
// gather properties
final Point p;
double mag = 1.0D;
Rectangle srcRect = null;
if (null != props) {
p = (Point) props[0];
mag = ((Double) props[1]).doubleValue();
srcRect = (Rectangle) props[2];
} else {
p = null;
}
// transparency slider
this.transp_slider = new JSlider(javax.swing.SwingConstants.HORIZONTAL, 0, 100, 100);
this.transp_slider.setBackground(Color.white);
this.transp_slider.setMinimumSize(new Dimension(250, 20));
this.transp_slider.setMaximumSize(new Dimension(250, 20));
this.transp_slider.setPreferredSize(new Dimension(250, 20));
final TransparencySliderListener tsl = new TransparencySliderListener();
this.transp_slider.addChangeListener(tsl);
this.transp_slider.addMouseListener(tsl);
for (final KeyListener kl : this.transp_slider.getKeyListeners()) {
this.transp_slider.removeKeyListener(kl);
}
// Tabbed pane on the left
this.tabs = new JTabbedPane();
this.tabs.setMinimumSize(new Dimension(250, 300));
this.tabs.setBackground(Color.white);
this.tabs.addChangeListener(tabs_listener);
// Tab 1: Patches
this.panel_patches = new RollingPanel(this, Patch.class);
this.addTab("Patches", panel_patches);
// Tab 2: Profiles
this.panel_profiles = new RollingPanel(this, Profile.class);
this.addTab("Profiles", panel_profiles);
// Tab 3: ZDisplayables
this.panel_zdispl = new RollingPanel(this, ZDisplayable.class);
this.addTab("Z space", panel_zdispl);
// Tab 4: channels
this.panel_channels = makeTabPanel();
this.scroll_channels = makeScrollPane(panel_channels);
this.channels = new Channel[4];
this.channels[0] = new Channel(this, Channel.MONO);
this.channels[1] = new Channel(this, Channel.RED);
this.channels[2] = new Channel(this, Channel.GREEN);
this.channels[3] = new Channel(this, Channel.BLUE);
// this.panel_channels.add(this.channels[0]);
addGBRow(this.panel_channels, this.channels[1], null);
addGBRow(this.panel_channels, this.channels[2], this.channels[1]);
addGBRow(this.panel_channels, this.channels[3], this.channels[2]);
this.addTab("Opacity", scroll_channels);
// Tab 5: labels
this.panel_labels = new RollingPanel(this, DLabel.class);
this.addTab("Labels", panel_labels);
// Tab 6: layers
this.panel_layers = makeTabPanel();
this.scroll_layers = makeScrollPane(panel_layers);
recreateLayerPanels(layer);
this.scroll_layers.addMouseWheelListener(canvas);
this.addTab("Layers", scroll_layers);
// Tab 7: tool options
// empty
this.tool_options = new OptionPanel();
this.scroll_options = makeScrollPane(this.tool_options);
this.scroll_options.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.addTab("Tool options", this.scroll_options);
// Tab 8: annotations
this.annot_editor = new JEditorPane();
// by default, nothing is selected
this.annot_editor.setEnabled(false);
this.annot_editor.setMinimumSize(new Dimension(200, 50));
this.annot_label = new JLabel("(No selected object)");
this.annot_panel = makeAnnotationsPanel(this.annot_editor, this.annot_label);
this.addTab("Annotations", this.annot_panel);
// Tab 9: filter options
this.filter_options = createFilterOptionPanel();
this.scroll_filter_options = makeScrollPane(this.filter_options);
this.scroll_filter_options.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.addTab("Live filter", this.scroll_filter_options);
this.ht_tabs = new Hashtable<Class<?>, RollingPanel>();
this.ht_tabs.put(Patch.class, panel_patches);
this.ht_tabs.put(Profile.class, panel_profiles);
this.ht_tabs.put(ZDisplayable.class, panel_zdispl);
this.ht_tabs.put(AreaList.class, panel_zdispl);
this.ht_tabs.put(Pipe.class, panel_zdispl);
this.ht_tabs.put(Polyline.class, panel_zdispl);
this.ht_tabs.put(Treeline.class, panel_zdispl);
this.ht_tabs.put(AreaTree.class, panel_zdispl);
this.ht_tabs.put(Connector.class, panel_zdispl);
this.ht_tabs.put(Ball.class, panel_zdispl);
this.ht_tabs.put(Dissector.class, panel_zdispl);
this.ht_tabs.put(DLabel.class, panel_labels);
this.ht_tabs.put(Stack.class, panel_zdispl);
// channels not included
// layers not included
// tools not included
// annotations not included
// Navigator
this.navigator = new DisplayNavigator(this, layer.getLayerWidth(), layer.getLayerHeight());
// Layer scroller (to scroll slices)
int extent = (int) (250.0 / layer.getParent().size());
if (extent < 10)
extent = 10;
this.scroller = new JScrollBar(JScrollBar.HORIZONTAL);
this.scroller.setModel(new ScrollerModel(layer));
updateLayerScroller(layer);
this.scroller.addAdjustmentListener(scroller_listener);
// LAYOUT
final GridBagLayout layout = new GridBagLayout();
final GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.NONE;
c.weightx = 0;
c.weighty = 0;
c.gridx = 0;
c.gridy = 0;
c.ipadx = 0;
c.ipady = 0;
c.gridwidth = 1;
c.gridheight = 1;
Display.this.all = new JPanel();
all.setBackground(Color.white);
all.setLayout(layout);
c.insets = new Insets(0, 0, 0, 5);
// 1
// fixed dimensions
toolbar_panel = new ToolbarPanel();
layout.setConstraints(toolbar_panel, c);
all.add(toolbar_panel);
// 2
c.gridy++;
c.fill = GridBagConstraints.HORIZONTAL;
layout.setConstraints(transp_slider, c);
all.add(transp_slider);
// 3
c.gridy++;
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
layout.setConstraints(tabs, c);
all.add(tabs);
// 4
c.gridy++;
c.weighty = 0;
c.fill = GridBagConstraints.NONE;
layout.setConstraints(navigator, c);
all.add(navigator);
// 5
c.gridy++;
c.fill = GridBagConstraints.HORIZONTAL;
layout.setConstraints(scroller, c);
all.add(scroller);
// Canvas
this.canvas = new DisplayCanvas(this, (int) Math.ceil(layer.getLayerWidth()), (int) Math.ceil(layer.getLayerHeight()));
c.insets = new Insets(0, 0, 0, 0);
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.NORTHWEST;
c.gridx = 1;
c.gridy = 0;
c.gridheight = GridBagConstraints.REMAINDER;
c.weightx = 1;
c.weighty = 1;
layout.setConstraints(Display.this.canvas, c);
all.add(canvas);
// prevent new Displays from screwing up if input is globally disabled
if (!project.isInputEnabled())
Display.this.canvas.setReceivesInput(false);
this.canvas.addComponentListener(canvas_size_listener);
this.navigator.addMouseWheelListener(canvas);
this.transp_slider.addKeyListener(canvas);
// JFrame to show the split pane
this.frame = ControlWindow.createJFrame(layer.toString());
this.frame.setBackground(Color.white);
this.frame.getContentPane().setBackground(Color.white);
if (IJ.isMacintosh() && IJ.getInstance() != null) {
// may be needed for Java 1.4 on OS X
IJ.wait(10);
this.frame.setMenuBar(ij.Menus.getMenuBar());
}
this.frame.addWindowListener(window_listener);
// this.frame.addComponentListener(display_frame_listener);
this.frame.getContentPane().add(all);
if (null != props) {
// restore canvas
canvas.setup(mag, srcRect);
// restore visibility of each channel
// aka c_alphas_state
final int cs = ((Integer) props[5]).intValue();
final int[] sel = new int[4];
sel[0] = ((cs & 0xff000000) >> 24);
sel[1] = ((cs & 0xff0000) >> 16);
sel[2] = ((cs & 0xff00) >> 8);
sel[3] = (cs & 0xff);
// restore channel alphas
Display.this.c_alphas = ((Integer) props[4]).intValue();
channels[0].setAlpha((float) ((c_alphas & 0xff000000) >> 24) / 255.0f, 0 != sel[0]);
channels[1].setAlpha((float) ((c_alphas & 0xff0000) >> 16) / 255.0f, 0 != sel[1]);
channels[2].setAlpha((float) ((c_alphas & 0xff00) >> 8) / 255.0f, 0 != sel[2]);
channels[3].setAlpha((float) (c_alphas & 0xff) / 255.0f, 0 != sel[3]);
// restore visibility in the working c_alphas
Display.this.c_alphas = ((0 != sel[0] ? (int) (255 * channels[0].getAlpha()) : 0) << 24) + ((0 != sel[1] ? (int) (255 * channels[1].getAlpha()) : 0) << 16) + ((0 != sel[2] ? (int) (255 * channels[2].getAlpha()) : 0) << 8) + (0 != sel[3] ? (int) (255 * channels[3].getAlpha()) : 0);
}
if (null != active && null != layer) {
final Rectangle r = active.getBoundingBox();
r.x -= r.width / 2;
r.y -= r.height / 2;
r.width += r.width;
r.height += r.height;
if (r.x < 0)
r.x = 0;
if (r.y < 0)
r.y = 0;
if (r.width > layer.getLayerWidth())
r.width = (int) layer.getLayerWidth();
if (r.height > layer.getLayerHeight())
r.height = (int) layer.getLayerHeight();
final double magn = layer.getLayerWidth() / (double) r.width;
canvas.setup(magn, r);
}
// add keyListener to the whole frame
this.tabs.addKeyListener(canvas);
this.frame.addKeyListener(canvas);
// create a drag and drop listener
dnd = new DNDInsertImage(Display.this);
Utils.invokeLater(new Runnable() {
@Override
public void run() {
Display.this.frame.pack();
ij.gui.GUI.center(Display.this.frame);
Display.this.frame.setVisible(true);
// doesn't get it through events
ProjectToolbar.setProjectToolbar();
final Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
if (null != props) {
// fix positioning outside the screen (dual to single monitor)
if (p.x >= 0 && p.x < screen.width - 50 && p.y >= 0 && p.y <= screen.height - 50)
Display.this.frame.setLocation(p);
else
frame.setLocation(0, 0);
}
// fix excessive size
final Rectangle box = Display.this.frame.getBounds();
int x = box.x;
int y = box.y;
int width = box.width;
int height = box.height;
if (box.width > screen.width) {
x = 0;
width = screen.width;
}
if (box.height > screen.height) {
y = 0;
height = screen.height;
}
if (x != box.x || y != box.y) {
// added insets for bad window managers
Display.this.frame.setLocation(x, y + (0 == y ? 30 : 0));
}
if (width != box.width || height != box.height) {
// added insets for bad window managers
Display.this.frame.setSize(new Dimension(width - 10, height - 30));
}
if (null == props) {
// try to optimize canvas dimensions and magn
double magn = layer.getLayerHeight() / screen.height;
if (magn > 1.0)
magn = 1.0;
long size = 0;
// limit magnification if appropriate
for (final Displayable pa : layer.getDisplayables(Patch.class)) {
final Rectangle ba = pa.getBoundingBox();
size += (long) (ba.width * ba.height);
}
if (// 10 Mb
size > 10000000)
// 10 Mb
canvas.setInitialMagnification(0.25);
else {
Display.this.frame.setSize(new Dimension((int) (screen.width * 0.66), (int) (screen.height * 0.66)));
}
}
updateTab(panel_patches);
// re-layout:
tabs.validate();
// Set the calibration of the FakeImagePlus to that of the LayerSet
((FakeImagePlus) canvas.getFakeImagePlus()).setCalibrationSuper(layer.getParent().getCalibrationCopy());
updateFrameTitle(layer);
// Set the FakeImagePlus as the current image
setTempCurrentImage();
// start a repainting thread
if (null != props) {
// repaint() is unreliable
canvas.repaint(true);
}
ControlWindow.setLookAndFeel();
}
});
}
Aggregations