use of ini.trakem2.display.Stack in project TrakEM2 by trakem2.
the class LayerTree method actionPerformed.
public void actionPerformed(ActionEvent ae) {
try {
String command = ae.getActionCommand();
// commands for multiple selections:
TreePath[] paths = this.getSelectionPaths();
if (null != paths && paths.length > 1) {
if (command.equals("Reverse layer Z coords")) {
// check that all layers belong to the same layer set
// just do it
Layer[] layer = new Layer[paths.length];
LayerSet ls = null;
for (int i = 0; i < paths.length; i++) {
layer[i] = (Layer) ((LayerThing) ((DefaultMutableTreeNode) paths[i].getLastPathComponent()).getUserObject()).getObject();
if (null == ls)
ls = layer[i].getParent();
else if (!ls.equals(layer[i].getParent())) {
Utils.showMessage("To reverse, all layers must belong to the same layer set");
return;
}
}
final ArrayList<Layer> al = new ArrayList<Layer>();
for (int i = 0; i < layer.length; i++) al.add(layer[i]);
ls.addLayerEditedStep(al);
// ASSSUMING layers are already Z ordered! CHECK
for (int i = 0, j = layer.length - 1; i < layer.length / 2; i++, j--) {
double z = layer[i].getZ();
layer[i].setZ(layer[j].getZ());
layer[j].setZ(z);
}
updateList(ls);
ls.addLayerEditedStep(al);
Display.updateLayerScroller(ls);
} else if (command.equals("Translate layers in Z...")) {
GenericDialog gd = ControlWindow.makeGenericDialog("Range");
gd.addMessage("Translate selected range in the Z axis:");
gd.addNumericField("by: ", 0, 4);
gd.showDialog();
if (gd.wasCanceled())
return;
// else, displace
double dz = gd.getNextNumber();
if (Double.isNaN(dz)) {
Utils.showMessage("Invalid number");
return;
}
HashSet<LayerSet> hs_parents = new HashSet<LayerSet>();
for (int i = 0; i < paths.length; i++) {
Layer layer = (Layer) ((LayerThing) ((DefaultMutableTreeNode) paths[i].getLastPathComponent()).getUserObject()).getObject();
layer.setZ(layer.getZ() + dz);
hs_parents.add(layer.getParent());
}
for (LayerSet ls : hs_parents) {
updateList(ls);
}
// now update all profile's Z ordering in the ProjectTree
ProjectThing root_pt = project.getRootProjectThing();
for (final ProjectThing pt : root_pt.findChildrenOfType("profile_list")) {
pt.fixZOrdering();
project.getProjectTree().updateList(pt);
}
project.getProjectTree().updateUILater();
// Display.updateLayerScroller((LayerSet)((DefaultMutableTreeNode)getModel().getRoot()).getUserObject());
} else if (command.equals("Delete...")) {
if (!Utils.check("Really remove all selected layers?"))
return;
for (int i = 0; i < paths.length; i++) {
DefaultMutableTreeNode lnode = (DefaultMutableTreeNode) paths[i].getLastPathComponent();
LayerThing lt = (LayerThing) lnode.getUserObject();
Layer layer = (Layer) lt.getObject();
if (!layer.remove(false)) {
Utils.showMessage("Could not delete layer " + layer);
this.updateUILater();
return;
}
if (lt.remove(false)) {
((DefaultTreeModel) this.getModel()).removeNodeFromParent(lnode);
}
}
this.updateUILater();
} else if (command.equals("Scale Z and thickness...")) {
GenericDialog gd = new GenericDialog("Scale Z");
gd.addNumericField("scale: ", 1.0, 2);
gd.showDialog();
double scale = gd.getNextNumber();
if (Double.isNaN(scale) || 0 == scale) {
Utils.showMessage("Imvalid scaling factor: " + scale);
return;
}
for (int i = 0; i < paths.length; i++) {
DefaultMutableTreeNode lnode = (DefaultMutableTreeNode) paths[i].getLastPathComponent();
LayerThing lt = (LayerThing) lnode.getUserObject();
Layer layer = (Layer) lt.getObject();
layer.setZ(layer.getZ() * scale);
layer.setThickness(layer.getThickness() * scale);
}
this.updateUILater();
} else {
Utils.showMessage("Don't know what to do with command " + command + " for multiple selected nodes");
}
return;
}
// commands for single selection:
if (null == selected_node)
return;
LayerThing thing = (LayerThing) selected_node.getUserObject();
LayerThing new_thing = null;
TemplateThing tt = null;
Object ob = null;
int i_position = -1;
if (command.startsWith("new ")) {
String name = command.substring(4).toLowerCase();
if (name.equals("layer")) {
// Create new Layer and add it to the selected node
LayerSet set = (LayerSet) thing.getObject();
Layer new_layer = Layer.create(thing.getProject(), set);
if (null == new_layer)
return;
tt = thing.getChildTemplate("layer");
ob = new_layer;
Display.updateTitle(set);
} else if (name.equals("layer set")) {
// with space in the middle
// Create a new LayerSet and add it in the middle
Layer layer = (Layer) thing.getObject();
LayerSet new_set = layer.getParent().create(layer);
if (null == new_set)
return;
layer.add(new_set);
// add it at the end of the list
// with space, not underscore
tt = thing.getChildTemplate("layer set");
ob = new_set;
i_position = selected_node.getChildCount();
Display.update(layer);
} else {
Utils.log("LayerTree.actionPerformed: don't know what to do with the command: " + command);
return;
}
} else if (command.equals("many new layers...")) {
LayerSet set = (LayerSet) thing.getObject();
List<Layer> layers = Layer.createMany(set.getProject(), set);
// add them to the tree as LayerThing
if (null == layers)
return;
for (Layer la : layers) {
// null layers will be skipped
addLayer(set, la);
}
Display.updateTitle(set);
return;
} else if (command.equals("Show")) {
// create a new Display
DBObject dbo = (DBObject) thing.getObject();
// the top level LayerSet
if (thing.getType().equals("layer_set") && null == ((LayerSet) dbo).getParent())
return;
Display.createDisplay(dbo.getProject(), thing.getType().equals("layer") ? (Layer) dbo : ((LayerSet) dbo).getParent());
return;
} else if (command.equals("Show centered in Display")) {
LayerSet ls = (LayerSet) thing.getObject();
Display.showCentered(ls.getParent(), ls, false, false);
} else if (command.equals("Delete...")) {
remove(true, thing, selected_node);
return;
} else if (command.equals("Import stack...")) {
if (thing.getObject() instanceof LayerSet) {
LayerSet set = (LayerSet) thing.getObject();
Layer layer = null;
if (0 == set.getLayers().size()) {
layer = Layer.create(set.getProject(), set);
if (null == layer)
return;
tt = thing.getChildTemplate("Layer");
ob = layer;
} else
// click on a desired, existing layer.
return;
layer.getProject().getLoader().importStack(layer, null, true);
} else if (thing.getObject() instanceof Layer) {
Layer layer = (Layer) thing.getObject();
layer.getProject().getLoader().importStack(layer, null, true);
return;
}
} else if (command.equals("Import grid...")) {
if (thing.getObject() instanceof Layer) {
Layer layer = (Layer) thing.getObject();
layer.getProject().getLoader().importGrid(layer);
}
} else if (command.equals("Import sequence as grid...")) {
if (thing.getObject() instanceof Layer) {
Layer layer = (Layer) thing.getObject();
layer.getProject().getLoader().importSequenceAsGrid(layer);
}
} else if (command.equals("Import from text file...")) {
if (thing.getObject() instanceof Layer) {
Layer layer = (Layer) thing.getObject();
layer.getProject().getLoader().importImages(layer);
}
} else if (command.equals("Resize LayerSet...")) {
if (thing.getObject() instanceof LayerSet) {
LayerSet ls = (LayerSet) thing.getObject();
ij.gui.GenericDialog gd = ControlWindow.makeGenericDialog("Resize LayerSet");
gd.addNumericField("new width: ", ls.getLayerWidth(), 3);
gd.addNumericField("new height: ", ls.getLayerHeight(), 3);
gd.addChoice("Anchor: ", LayerSet.ANCHORS, LayerSet.ANCHORS[0]);
gd.showDialog();
if (gd.wasCanceled())
return;
float new_width = (float) gd.getNextNumber(), new_height = (float) gd.getNextNumber();
// will complain and prevent cropping existing Displayable objects
ls.setDimensions(new_width, new_height, gd.getNextChoiceIndex());
}
} else if (command.equals("Autoresize LayerSet")) {
if (thing.getObject() instanceof LayerSet) {
LayerSet ls = (LayerSet) thing.getObject();
ls.setMinimumDimensions();
}
} else if (command.equals("Adjust...")) {
if (thing.getObject() instanceof Layer) {
Layer layer = (Layer) thing.getObject();
ij.gui.GenericDialog gd = ControlWindow.makeGenericDialog("Adjust Layer");
gd.addNumericField("new z: ", layer.getZ(), 4);
gd.addNumericField("new thickness: ", layer.getThickness(), 4);
gd.showDialog();
if (gd.wasCanceled())
return;
double new_z = gd.getNextNumber();
layer.setThickness(gd.getNextNumber());
if (new_z != layer.getZ()) {
layer.setZ(new_z);
// move in the tree
/*
DefaultMutableTreeNode child = findNode(thing, this);
DefaultMutableTreeNode parent = (DefaultMutableTreeNode)child.getParent();
parent.remove(child);
// reinsert
int n = parent.getChildCount();
int i = 0;
for (; i < n; i++) {
DefaultMutableTreeNode child_node = (DefaultMutableTreeNode)parent.getChildAt(i);
LayerThing child_thing = (LayerThing)child_node.getUserObject();
if (!child_thing.getType().equals("Layer")) continue;
double iz = ((Layer)child_thing.getObject()).getZ();
if (iz < new_z) continue;
// else, add the layer here, after this one
break;
}
((DefaultTreeModel)this.getModel()).insertNodeInto(child, parent, i);
*/
// fix tree crappiness (empty slot ?!?)
/* // the fix doesn't work. ARGH TODO
Enumeration e = parent.children();
parent.removeAllChildren();
i = 0;
while (e.hasMoreElements()) {
//parent.add((DefaultMutableTreeNode)e.nextElement());
((DefaultTreeModel)this.getModel()).insertNodeInto(child, parent, i);
i++;
}*/
// easier and correct: overkill
updateList(layer.getParent());
// set selected
DefaultMutableTreeNode child = findNode(thing, this);
TreePath treePath = new TreePath(child.getPath());
this.scrollPathToVisible(treePath);
this.setSelectionPath(treePath);
}
}
return;
} else if (command.equals("Rename...")) {
GenericDialog gd = ControlWindow.makeGenericDialog("Rename");
gd.addStringField("new name: ", thing.getTitle());
gd.showDialog();
if (gd.wasCanceled())
return;
project.getRootLayerSet().addUndoStep(new RenameThingStep(thing));
thing.setTitle(gd.getNextString());
project.getRootLayerSet().addUndoStep(new RenameThingStep(thing));
} else if (command.equals("Translate layers in Z...")) {
// / TODO: this method should use multiple selections directly on the tree
if (thing.getObject() instanceof LayerSet) {
LayerSet ls = (LayerSet) thing.getObject();
ArrayList<Layer> al_layers = ls.getLayers();
String[] layer_names = new String[al_layers.size()];
for (int i = 0; i < layer_names.length; i++) {
layer_names[i] = ls.getProject().findLayerThing(al_layers.get(i)).toString();
}
GenericDialog gd = ControlWindow.makeGenericDialog("Range");
gd.addMessage("Translate selected range in the Z axis:");
gd.addChoice("from: ", layer_names, layer_names[0]);
gd.addChoice("to: ", layer_names, layer_names[layer_names.length - 1]);
gd.addNumericField("by: ", 0, 4);
gd.showDialog();
if (gd.wasCanceled())
return;
// else, displace
double dz = gd.getNextNumber();
if (Double.isNaN(dz)) {
Utils.showMessage("Invalid number");
return;
}
int i_start = gd.getNextChoiceIndex();
int i_end = gd.getNextChoiceIndex();
for (int i = i_start; i <= i_end; i++) {
Layer layer = (Layer) al_layers.get(i);
layer.setZ(layer.getZ() + dz);
}
// update node labels and position
updateList(ls);
}
} else if (command.equals("Reverse layer Z coords...")) {
// / TODO: this method should use multiple selections directly on the tree
if (thing.getObject() instanceof LayerSet) {
LayerSet ls = (LayerSet) thing.getObject();
ArrayList<Layer> al_layers = ls.getLayers();
String[] layer_names = new String[al_layers.size()];
for (int i = 0; i < layer_names.length; i++) {
layer_names[i] = ls.getProject().findLayerThing(al_layers.get(i)).toString();
}
GenericDialog gd = ControlWindow.makeGenericDialog("Range");
gd.addMessage("Reverse Z coordinates of selected range:");
gd.addChoice("from: ", layer_names, layer_names[0]);
gd.addChoice("to: ", layer_names, layer_names[layer_names.length - 1]);
gd.showDialog();
if (gd.wasCanceled())
return;
int i_start = gd.getNextChoiceIndex();
int i_end = gd.getNextChoiceIndex();
for (int i = i_start, j = i_end; i < i_end / 2; i++, j--) {
Layer layer1 = (Layer) al_layers.get(i);
double z1 = layer1.getZ();
Layer layer2 = (Layer) al_layers.get(j);
layer1.setZ(layer2.getZ());
layer2.setZ(z1);
}
// update node labels and position
updateList(ls);
}
} else if (command.equals("Search...")) {
Search.showWindow();
} else if (command.equals("Reset layer Z and thickness")) {
LayerSet ls = ((LayerSet) thing.getObject());
List<Layer> layers = ls.getLayers();
ls.addLayerEditedStep(layers);
int i = 0;
for (final Layer la : ls.getLayers()) {
la.setZ(i++);
la.setThickness(1);
}
ls.addLayerEditedStep(layers);
} else {
Utils.log("LayerTree.actionPerformed: don't know what to do with the command: " + command);
return;
}
if (null == tt)
return;
new_thing = new LayerThing(tt, thing.getProject(), ob);
if (-1 == i_position && new_thing.getType().equals("layer")) {
// find the node whose 'z' is larger than z, and add the Layer before that.
// (just because there could be objects other than LayerThing with a Layer in it in the future, so set.getLayers().indexOf(layer) may not be useful)
double z = ((Layer) ob).getZ();
int n = selected_node.getChildCount();
int i = 0;
for (; i < n; i++) {
DefaultMutableTreeNode child_node = (DefaultMutableTreeNode) selected_node.getChildAt(i);
LayerThing child_thing = (LayerThing) child_node.getUserObject();
if (!child_thing.getType().equals("layer")) {
continue;
}
double iz = ((Layer) child_thing.getObject()).getZ();
if (iz < z) {
continue;
}
// else, add the layer here, after this one
break;
}
i_position = i;
}
thing.addChild(new_thing);
DefaultMutableTreeNode new_node = new DefaultMutableTreeNode(new_thing);
((DefaultTreeModel) this.getModel()).insertNodeInto(new_node, selected_node, i_position);
TreePath treePath = new TreePath(new_node.getPath());
this.scrollPathToVisible(treePath);
this.setSelectionPath(treePath);
if (new_thing.getType().equals("layer set")) {
// add the first layer to it, and open it in a Display
LayerSet newls = (LayerSet) new_thing.getObject();
Layer la = new Layer(newls.getProject(), 0, 1, newls);
addLayer(newls, la);
new Display(newls.getProject(), la);
}
} catch (Exception e) {
IJError.print(e);
}
}
use of ini.trakem2.display.Stack in project TrakEM2 by trakem2.
the class DBLoader method fetchLayer.
/**
* Load all objects into the Layer: Profile and Pipe from the hs_pt (full of ProjectThing wrapping them), and Patch, LayerSet, DLabel, etc from the database.
*/
private Layer fetchLayer(Project project, long id, HashMap hs_pt) throws Exception {
ResultSet r = connection.prepareStatement("SELECT * FROM ab_layers WHERE id=" + id).executeQuery();
Layer layer = null;
if (r.next()) {
long layer_id = r.getLong("id");
layer = new Layer(project, layer_id, r.getDouble("z"), r.getDouble("thickness"));
// find the Layer's parent
long parent_id = r.getLong("layer_set_id");
Object set = hs_pt.get(new Long(parent_id));
if (null != set) {
((LayerSet) set).addSilently(layer);
} else {
Utils.log("Loader.fetchLayer: WARNING no parent for layer " + layer);
}
// add the displayables from hs_pt that correspond to this layer (and all other objects that belong to the layer)
HashMap hs_d = new HashMap();
ResultSet rd = connection.prepareStatement("SELECT ab_displayables.id, ab_profiles.id, layer_id, stack_index FROM ab_displayables,ab_profiles WHERE ab_displayables.id=ab_profiles.id AND layer_id=" + layer_id).executeQuery();
while (rd.next()) {
Long idd = new Long(rd.getLong("id"));
Object ob = hs_pt.get(idd);
// Utils.log("Found profile with id=" + idd + " and ob = " + ob);
if (null != ob) {
hs_d.put(new Integer(rd.getInt("stack_index")), ob);
}
}
rd.close();
// fetch LayerSet objects (which are also Displayable), and put them in the hs_pt (this is hackerous)
ResultSet rls = connection.prepareStatement("SELECT * FROM ab_layer_sets, ab_displayables WHERE ab_layer_sets.id=ab_displayables.id AND ab_layer_sets.parent_layer_id=" + id).executeQuery();
while (rls.next()) {
long ls_id = rls.getLong("id");
LayerSet layer_set = new LayerSet(project, ls_id, rls.getString("title"), (float) rls.getDouble("width"), (float) rls.getDouble("height"), rls.getDouble("rot_x"), rls.getDouble("rot_y"), rls.getDouble("rot_z"), (float) rls.getDouble("layer_width"), (float) rls.getDouble("layer_height"), rls.getBoolean("locked"), rls.getInt("snapshots_mode"), new AffineTransform(rls.getDouble("m00"), rls.getDouble("m10"), rls.getDouble("m01"), rls.getDouble("m11"), rls.getDouble("m02"), rls.getDouble("m12")));
hs_pt.put(new Long(ls_id), layer_set);
hs_d.put(new Integer(rls.getInt("stack_index")), layer_set);
layer_set.setLayer(layer, false);
// find the pipes (or other possible ZDisplayable objects) in the hs_pt that belong to this LayerSet and add them silently
ResultSet rpi = connection.prepareStatement("SELECT ab_displayables.id, ab_zdisplayables.id, layer_id, layer_set_id, stack_index FROM ab_displayables,ab_zdisplayables WHERE ab_displayables.id=ab_zdisplayables.id AND layer_set_id=" + ls_id + " ORDER BY stack_index ASC").executeQuery();
while (rpi.next()) {
Long idd = new Long(rpi.getLong("id"));
Object ob = hs_pt.get(idd);
if (null != ob && ob instanceof ZDisplayable) {
layer_set.addSilently((ZDisplayable) ob);
} else {
Utils.log("fetchLayer: failed to add a ZDisplayable to the layer_set. zdispl id = " + idd);
}
}
rpi.close();
}
rls.close();
// add Patch objects from ab_patches joint-called with ab_displayables
ResultSet rp = connection.prepareStatement("SELECT ab_patches.id, ab_displayables.id, layer_id, title, width, height, stack_index, imp_type, locked, min, max, m00, m10, m01, m11, m02, m12 FROM ab_patches,ab_displayables WHERE ab_patches.id=ab_displayables.id AND ab_displayables.layer_id=" + layer_id).executeQuery();
while (rp.next()) {
long patch_id = rp.getLong("id");
Patch patch = new Patch(project, patch_id, rp.getString("title"), (float) rp.getDouble("width"), (float) rp.getDouble("height"), rp.getInt("o_width"), rp.getInt("o_height"), rp.getInt("imp_type"), rp.getBoolean("locked"), rp.getDouble("min"), rp.getDouble("max"), new AffineTransform(rp.getDouble("m00"), rp.getDouble("m10"), rp.getDouble("m01"), rp.getDouble("m11"), rp.getDouble("m02"), rp.getDouble("m12")));
// collecting all Displayable objects to reconstruct links
hs_pt.put(new Long(patch_id), patch);
hs_d.put(new Integer(rp.getInt("stack_index")), patch);
}
rp.close();
// add DLabel objects
ResultSet rl = connection.prepareStatement("SELECT ab_labels.id, ab_displayables.id, layer_id, title, width, height, m00, m10, m01, m11, m02, m12, stack_index, font_name, font_style, font_size, ab_labels.type, locked FROM ab_labels,ab_displayables WHERE ab_labels.id=ab_displayables.id AND ab_displayables.layer_id=" + layer_id).executeQuery();
while (rl.next()) {
long label_id = rl.getLong("id");
DLabel label = new DLabel(project, label_id, rl.getString("title"), (float) rl.getDouble("width"), (float) rl.getDouble("height"), rl.getInt("type"), rl.getString("font_name"), rl.getInt("font_style"), rl.getInt("font_size"), rl.getBoolean("locked"), new AffineTransform(rl.getDouble("m00"), rl.getDouble("m10"), rl.getDouble("m01"), rl.getDouble("m11"), rl.getDouble("m02"), rl.getDouble("m12")));
// collecting all Displayable objects to reconstruct links
hs_pt.put(new Long(label_id), label);
hs_d.put(new Integer(rl.getInt("stack_index")), label);
}
rl.close();
// Add silently to the Layer ordered by stack index
Set e = hs_d.keySet();
Object[] si = new Object[hs_d.size()];
si = e.toArray(si);
// will it sort an array of integers correctly? Who knows!
Arrays.sort(si);
for (int i = 0; i < si.length; i++) {
// Utils.log("Loader layer.addSilently: adding " + (DBObject)hs_d.get(si[i]));
layer.addSilently((DBObject) hs_d.get(si[i]));
}
// find displays and open later, when fully loaded.
ResultSet rdi = connection.prepareStatement("SELECT * FROM ab_displays WHERE layer_id=" + layer.getId()).executeQuery();
while (rdi.next()) {
fetchDisplay(rdi, layer);
}
rdi.close();
}
r.close();
return layer;
}
use of ini.trakem2.display.Stack in project TrakEM2 by trakem2.
the class FilePathRepair method fixStack.
private static int fixStack(final PathTableModel data, final Set<Patch> fixed, final Collection<Patch> slices, final String wrong_path, final String new_path, final boolean update_mipmaps) {
int n_fixed = 0;
Dimension dim = null;
Loader loader = null;
for (final Patch ps : slices) {
if (fixed.contains(ps))
continue;
final String slicepath = ps.getFilePath();
final int isl = slicepath.lastIndexOf("-----#slice=");
if (-1 == isl) {
Utils.log2("Not a stack path: " + slicepath);
// someone linked an image...
continue;
}
// same: // ps.getImageFilePath();
final String ps_path = slicepath.substring(0, isl);
if (!ps_path.substring(0, isl).equals(wrong_path)) {
Utils.log2("Not the same stack path:\n i=" + ps_path + "\n ref=" + wrong_path);
// not the same stack!
continue;
}
if (null == dim) {
loader = ps.getProject().getLoader();
loader.releaseToFit(Math.max(Loader.MIN_FREE_BYTES, ps.getOWidth() * ps.getOHeight() * 10));
dim = loader.getDimensions(new_path);
if (null == dim) {
// preserving backslashes
Utils.log(new StringBuilder("ERROR: could not open image at ").append(new_path).toString());
return n_fixed;
}
// Check dimensions
if (dim.width != ps.getOWidth() || dim.height != ps.getOHeight()) {
Utils.log("ERROR different o_width,o_height for patch " + ps + "\n at new path " + new_path + "\nold o_width,o_height: " + ps.getOWidth() + "," + ps.getOHeight() + "\nnew o_width,o_height: " + dim.width + "," + dim.height);
return n_fixed;
}
}
// flag as good
fixed.add(ps);
loader.removeFromUnloadable(ps);
// Assign new image path with slice info appended
loader.addedPatchFrom(new_path + slicepath.substring(isl), ps);
// submit job to regenerate mipmaps in the background
if (update_mipmaps)
loader.regenerateMipMaps(ps);
//
data.remove(ps);
n_fixed++;
}
return n_fixed;
}
use of ini.trakem2.display.Stack in project TrakEM2 by trakem2.
the class AreaUtils method generateTriangles.
/**
* Expects areas in local coordinates to the Displayable @param d.
* @param d
* @param scale The scaling of the entire universe, to limit the overall box
* @param resample_ The optimization parameter for marching cubes (i.e. a value of 2 will scale down to half, then apply marching cubes, then scale up by 2 the vertices coordinates).
* @param areas
* @return The List of triangles involved, specified as three consecutive vertices. A list of Point3f vertices.
*/
public static List<Point3f> generateTriangles(final Displayable d, final double scale, final int resample_, final Map<Layer, Area> areas) {
// in the LayerSet, layers are ordered by Z already.
try {
int n = areas.size();
if (0 == n)
return null;
final int resample;
if (resample_ <= 0) {
resample = 1;
Utils.log2("Fixing zero or negative resampling value to 1.");
} else
resample = resample_;
final LayerSet layer_set = d.getLayerSet();
final AffineTransform aff = d.getAffineTransformCopy();
final Rectangle r = d.getBoundingBox(null);
// remove translation from a copy of the Displayable's AffineTransform
final AffineTransform at_translate = new AffineTransform();
at_translate.translate(-r.x, -r.y);
aff.preConcatenate(at_translate);
// incorporate resampling scaling into the transform
final AffineTransform atK = new AffineTransform();
// Utils.log("resample: " + resample + " scale: " + scale);
// 'scale' is there to limit gigantic universes
final double K = (1.0 / resample) * scale;
atK.scale(K, K);
aff.preConcatenate(atK);
final Calibration cal = layer_set.getCalibrationCopy();
// Find first layer, compute depth, and fill in the depth vs area map
Layer first_layer = null, last_layer = null;
final int w = (int) Math.ceil(r.width * K);
final int h = (int) Math.ceil(r.height * K);
int depth = 0;
final Map<Integer, Area> ma = new HashMap<Integer, Area>();
for (final Layer la : layer_set.getLayers()) {
// layers sorted by Z ASC
final Area area = areas.get(la);
if (null != area) {
ma.put(depth, area);
if (null == first_layer) {
first_layer = la;
}
// Utils.log("area at depth " + depth + " for layer " + la);
depth++;
n--;
} else if (0 != depth) {
// Utils.log("Empty area at depth " + depth);
// an empty layer
depth++;
}
if (0 == n) {
last_layer = la;
// no more areas to paint
break;
}
}
if (0 == depth) {
Utils.log("ERROR could not find any areas for " + d);
return null;
}
if (0 != n) {
Utils.log("WARNING could not find all areas for " + d);
}
// No zero-padding: Marching Cubes now can handle edges
final ShapeList<ByteType> shapeList = new ShapeListCached<ByteType>(new int[] { w, h, depth }, new ByteType(), 32);
final Image<ByteType> shapeListImage = new Image<ByteType>(shapeList, shapeList.getBackground(), "ShapeListContainer");
// 255 or -1 don't work !? So, giving the highest value (127) that is both a byte and an int.
final ByteType intensity = new ByteType((byte) 127);
for (final Map.Entry<Integer, Area> e : ma.entrySet()) {
Area a = e.getValue();
if (!aff.isIdentity()) {
a = M.areaInIntsByRounding(a.createTransformedArea(aff));
}
shapeList.addShape(a, intensity, new int[] { e.getKey() });
}
// debug:
// ImagePlus imp = ImageJFunctions.displayAsVirtualStack(shapeListImage);
// imp.getProcessor().setMinAndMax( 0, 255 );
// imp.show();
// Utils.log2("Using imglib Shape List Image Container");
// Now marching cubes
// origins at 0,0,0: uncalibrated
final List<Point3f> list = new MCTriangulator().getTriangles(shapeListImage, 1, new float[3]);
// The list of triangles has coordinates:
// - in x,y: in pixels, scaled by K = (1 / resample) * scale,
// translated by r.x, r.y (the top-left coordinate of this AreaList bounding box)
// - in z: in stack slice indices
// So all x,y,z must be corrected in x,y and z of the proper layer
// final double offset = first_layer.getZ();
final int i_first_layer = layer_set.indexOf(first_layer);
// The x,y translation to correct each point by:
final float dx = (float) (r.x * scale * cal.pixelWidth);
final float dy = (float) (r.y * scale * cal.pixelHeight);
// Correct x,y by resampling and calibration, but not scale
// scale is already in the pixel coordinates
final float rsw = (float) (resample * cal.pixelWidth);
final float rsh = (float) (resample * cal.pixelHeight);
// no resampling in Z. and Uses pixelWidth, not pixelDepth.
final double sz = scale * cal.pixelWidth;
// debug:
/*
// which p.z types exist?
final TreeSet<Float> ts = new TreeSet<Float>();
for (final Iterator it = list.iterator(); it.hasNext(); ) {
ts.add(((Point3f)it.next()).z);
}
for (final Float pz : ts) Utils.log2("A z: " + pz);
*/
// debug: How many different Z?
/*
HashSet<Float> zs = new HashSet<Float>();
for (Point3f p : list) {
zs.add(p.z);
}
ArrayList<Float> a = new ArrayList<Float>(zs);
java.util.Collections.sort(a);
for (Float f : a) {
Utils.log("f: " + f);
}
*/
// Utils.log2("Number of slices: " + imp.getNSlices());
// Fix all points:
// Read from list, modify and put into verts
// and don't modify it if the verts already has it (it's just coincident)
final Point3f[] verts = new Point3f[list.size()];
// Utils.log("number of verts: " + verts.length + " mod 3: " + (verts.length % 3));
final TreeMap<Integer, Point3f> output = new TreeMap<Integer, Point3f>();
// The first section generates vertices at -1 and 0
// The last section generates them at last_section_index and last_section_index +1
// Capture from -1 to 0
fix3DPoints(list, output, verts, first_layer.getZ(), 0, -1, dx, dy, rsw, rsh, sz, 1);
int slice_index = 0;
for (final Layer la : layer_set.getLayers().subList(i_first_layer, i_first_layer + depth)) {
// If layer is empty, continue
/* // YEAH don't! At least the immediate next layer would have points, like the extra Z level after last layer, to account for the thickness of the layer!
if (empty_layers.contains(la)) {
slice_index++;
continue;
}
*/
fix3DPoints(list, output, verts, la.getZ(), la.getThickness(), slice_index, dx, dy, rsw, rsh, sz, 1);
slice_index++;
}
// Do the last layer again. The last layer has two Z planes in which it has pixels:
try {
// Capture from last_section_index to last_section_index+1, inclusive
fix3DPoints(list, output, verts, last_layer.getZ() + last_layer.getThickness(), 0, slice_index, dx, dy, rsw, rsh, sz, 2);
} catch (final Exception ee) {
IJError.print(ee);
}
// Handle potential errors:
if (0 != list.size() - output.size()) {
Utils.log2("Unprocessed/unused points: " + (list.size() - output.size()));
for (int i = 0; i < verts.length; i++) {
if (null == verts[i]) {
final Point3f p = (Point3f) list.get(i);
Utils.log2("verts[" + i + "] = " + p.x + ", " + p.y + ", " + p.z + " p.z as int: " + ((int) (p.z + 0.05f)));
}
}
return new ArrayList<Point3f>(output.values());
} else {
return java.util.Arrays.asList(verts);
}
} catch (final Exception e) {
e.printStackTrace();
}
return null;
}
use of ini.trakem2.display.Stack in project TrakEM2 by trakem2.
the class Polyline method mousePressed.
@Override
public void mousePressed(final MouseEvent me, final Layer layer, int x_p, int y_p, final double mag) {
// transform the x_p, y_p to the local coordinates
final int x_pd = x_p;
final int y_pd = y_p;
if (!this.at.isIdentity()) {
final Point2D.Double po = inverseTransformPoint(x_p, y_p);
x_p = (int) po.x;
y_p = (int) po.y;
}
final int tool = ProjectToolbar.getToolId();
final Display display = ((DisplayCanvas) me.getSource()).getDisplay();
final long layer_id = layer.getId();
index = findPoint(x_p, y_p, layer_id, mag);
if (ProjectToolbar.PENCIL == tool && n_points > 0 && -1 == index && !me.isShiftDown() && !Utils.isControlDown(me)) {
// Check that there are any images -- otherwise may hang. TODO
if (layer_set.getDisplayables(Patch.class).isEmpty()) {
Utils.log("No images are present!");
return;
}
final double scale = layer_set.getVirtualizationScale();
// Ok now with all found images, create a virtual stack that provides access to them all, with caching.
final Worker[] worker = new Worker[2];
final TraceParameters tr_ = tr_map.get(layer_set);
final TraceParameters tr = null == tr_ ? new TraceParameters() : tr_;
if (null == tr_) {
synchronized (tr_map) {
tr_map.put(layer_set, tr);
}
}
if (tr.update) {
worker[0] = new Worker("Preparing Hessian...") {
@Override
public void run() {
startedWorking();
try {
Utils.log("Push ESCAPE key to cancel autotrace anytime.");
final ImagePlus virtual = new LayerStack(layer_set, scale, ImagePlus.GRAY8, Patch.class, display.getDisplayChannelAlphas(), Segmentation.fmp.SNT_invert_image).getImagePlus();
// virtual.show();
final Calibration cal = virtual.getCalibration();
double minimumSeparation = 1;
if (cal != null)
minimumSeparation = Math.min(cal.pixelWidth, Math.min(cal.pixelHeight, cal.pixelDepth));
final ComputeCurvatures hessian = new ComputeCurvatures(virtual, minimumSeparation, null, cal != null);
hessian.run();
tr.virtual = virtual;
// tr.scale = scale;
tr.hessian = hessian;
tr.update = false;
} catch (final Exception e) {
IJError.print(e);
}
finishedWorking();
}
};
Bureaucrat.createAndStart(worker[0], project);
}
final Point2D.Double po = transformPoint(p[0][n_points - 1], p[1][n_points - 1]);
final int start_x = (int) po.x;
final int start_y = (int) po.y;
// 0-based
final int start_z = layer_set.indexOf(layer_set.getLayer(p_layer[n_points - 1]));
// must transform into virtual space
final int goal_x = (int) (x_pd * scale);
final int goal_y = (int) (y_pd * scale);
final int goal_z = layer_set.indexOf(layer);
/*
Utils.log2("x_pd, y_pd : " + x_pd + ", " + y_pd);
Utils.log2("scale: " + scale);
Utils.log2("start: " + start_x + "," + start_y + ", " + start_z);
Utils.log2("goal: " + goal_x + "," + goal_y + ", " + goal_z);
Utils.log2("virtual: " + tr.virtual);
*/
final boolean simplify = me.isAltDown();
worker[1] = new Worker("Tracer - waiting on hessian") {
@Override
public void run() {
startedWorking();
try {
if (null != worker[0]) {
// Wait until hessian is ready
worker[0].join();
}
setTaskName("Tracing path");
final int reportEveryMilliseconds = 2000;
tr.tracer = new TracerThread(tr.virtual, 0, 255, // timeout seconds
120, reportEveryMilliseconds, start_x, start_y, start_z, goal_x, goal_y, goal_z, // reciproal pix values at start and goal
true, tr.virtual.getStackSize() == 1, tr.hessian, null == tr.hessian ? 1 : 4, null, null != tr.hessian);
tr.tracer.addProgressListener(new SearchProgressCallback() {
@Override
public void pointsInSearch(final SearchInterface source, final int inOpen, final int inClosed) {
worker[1].setTaskName("Tracing path: open=" + inOpen + " closed=" + inClosed);
}
@Override
public void finished(final SearchInterface source, final boolean success) {
if (!success) {
Utils.logAll("Could NOT trace a path");
}
}
@Override
public void threadStatus(final SearchInterface source, final int currentStatus) {
// This method gets called every reportEveryMilliseconds
if (worker[1].hasQuitted()) {
source.requestStop();
}
}
});
tr.tracer.run();
final Path result = tr.tracer.getResult();
tr.tracer = null;
if (null == result) {
// : "+
Utils.log("Finding a path failed");
// not public //SearchThread.exitReasonStrings[tracer.getExitReason()]);
return;
}
// TODO: precise_x_positions etc are likely to be broken (calibrated or something)
// Remove bogus points: those at the end with 0,0 coords
int len = result.points;
final double[][] pos = result.getXYZUnscaled();
for (int i = len - 1; i > -1; i--) {
if (0 == pos[0][i] && 0 == pos[1][i]) {
len--;
} else
break;
}
// Transform points: undo scale, and bring to this Polyline AffineTransform:
final AffineTransform aff = new AffineTransform();
/* Inverse order: */
/* 2 */
aff.concatenate(Polyline.this.at.createInverse());
/* 1 */
aff.scale(1 / scale, 1 / scale);
final double[] po = new double[len * 2];
for (int i = 0, j = 0; i < len; i++, j += 2) {
po[j] = pos[0][i];
po[j + 1] = pos[1][i];
}
final double[] po2 = new double[len * 2];
// what a stupid format: consecutive x,y pairs
aff.transform(po, 0, po2, 0, len);
long[] p_layer_ids = new long[len];
double[] pox = new double[len];
double[] poy = new double[len];
for (int i = 0, j = 0; i < len; i++, j += 2) {
// z_positions in 0-(N-1), not in 1-N like slices!
p_layer_ids[i] = layer_set.getLayer((int) pos[2][i]).getId();
pox[i] = po2[j];
poy[i] = po2[j + 1];
}
// Simplify path: to steps of 5 calibration units, or 5 pixels when not calibrated.
if (simplify) {
setTaskName("Simplifying path");
final Object[] ob = Polyline.simplify(pox, poy, p_layer_ids, 10000, layer_set);
pox = (double[]) ob[0];
poy = (double[]) ob[1];
p_layer_ids = (long[]) ob[2];
len = pox.length;
}
// Record the first newly-added autotraced point index:
last_autotrace_start = Polyline.this.n_points;
Polyline.this.appendPoints(pox, poy, p_layer_ids, len);
Polyline.this.repaint(true, null);
Utils.logAll("Added " + len + " new points.");
} catch (final Exception e) {
IJError.print(e);
}
finishedWorking();
}
};
Bureaucrat.createAndStart(worker[1], project);
index = -1;
return;
}
if (ProjectToolbar.PEN == tool || ProjectToolbar.PENCIL == tool) {
if (Utils.isControlDown(me) && me.isShiftDown()) {
final long lid = Display.getFrontLayer(this.project).getId();
if (-1 == index || lid != p_layer[index]) {
index = findNearestPoint(x_p, y_p, layer_id);
}
if (-1 != index) {
// delete point
removePoint(index);
index = -1;
repaint(false, null);
}
// In any case, terminate
return;
}
if (// disable!
-1 != index && layer_id != p_layer[index])
// disable!
index = -1;
else // if no conditions are met, attempt to add point
if (-1 == index && !me.isShiftDown() && !me.isAltDown()) {
// add a new point
index = addPoint(x_p, y_p, layer_id, mag);
is_new_point = true;
repaint(false, null);
return;
}
}
}
Aggregations