diff options
author | Andrej Shadura <andrewsh@debian.org> | 2019-03-09 22:30:41 +0000 |
---|---|---|
committer | Andrej Shadura <andrewsh@debian.org> | 2019-03-09 22:30:41 +0000 |
commit | 38212b3127e90751fb39cda34250bc11be62b76c (patch) | |
tree | dc1397346030e9695bd763dddc93b3be527cd643 /addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/VisualizationTree.java | |
parent | 337087b668d3a54f3afee3a9adb597a32e9f7e94 (diff) |
Import Upstream version 0.7.0
Diffstat (limited to 'addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/VisualizationTree.java')
-rw-r--r-- | addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/VisualizationTree.java | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/VisualizationTree.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/VisualizationTree.java new file mode 100644 index 00000000..8e76716c --- /dev/null +++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/VisualizationTree.java @@ -0,0 +1,395 @@ +package de.lmu.ifi.dbs.elki.visualization; +/* + This file is part of ELKI: + Environment for Developing KDD-Applications Supported by Index-Structures + + Copyright (C) 2015 + Ludwig-Maximilians-Universität München + Lehr- und Forschungseinheit für Datenbanksysteme + ELKI Development Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import java.util.ArrayList; + +import de.lmu.ifi.dbs.elki.result.Result; +import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.FilteredIter; +import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.HashMapHierarchy; +import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.Hierarchy; +import de.lmu.ifi.dbs.elki.utilities.datastructures.hierarchy.StackedIter; + +/** + * Tree - actually a forest - to manage visualizations. + * + * @author Erich Schubert + * + * @apiviz.has Handler1 + * @apiviz.has Handler2 + * @apiviz.has Handler3 + */ +public class VisualizationTree extends HashMapHierarchy<Object> { + /** + * The event listeners for this context. + */ + private ArrayList<VisualizationListener> vlistenerList = new ArrayList<>(); + + /** + * Constructor. + */ + public VisualizationTree() { + super(); + } + + /** + * Add a listener. + * + * @param listener Listener to add + */ + public void addVisualizationListener(VisualizationListener listener) { + for(int i = 0; i < vlistenerList.size(); i++) { + if(vlistenerList.get(i) == listener) { + return; + } + } + vlistenerList.add(listener); + } + + /** + * Add a listener. + * + * @param listener Listener to remove + */ + public void removeVisualizationListener(VisualizationListener listener) { + vlistenerList.remove(listener); + } + + /** + * A visualization item has changed. + * + * @param item Item that has changed + */ + public void visChanged(VisualizationItem item) { + for(int i = vlistenerList.size(); --i >= 0;) { + vlistenerList.get(i).visualizationChanged(item); + } + } + + /** + * Handler for a single result. + * + * @author Erich Schubert + * + * @param <A> Object type + */ + public static interface Handler1<A> { + /** + * Process a new result. + * + * @param context Context + * @param result First result + */ + void process(VisualizerContext context, A result); + } + + /** + * Handler for two result. + * + * @author Erich Schubert + * + * @param <A> Object type + * @param <B> Object type + */ + public static interface Handler2<A, B> { + /** + * Process a new result. + * + * @param context Context + * @param result First result + * @param result2 Second result + */ + void process(VisualizerContext context, A result, B result2); + } + + /** + * Handler for three result. + * + * @author Erich Schubert + * + * @param <A> Object type + * @param <B> Object type + * @param <C> Object type + */ + public static interface Handler3<A, B, C> { + /** + * Process a new result. + * + * @param context Context + * @param result First result + * @param result2 Second result + * @param result3 Third result + */ + void process(VisualizerContext context, A result, B result2, C result3); + } + + /** + * Filtered iteration over a stacked hierarchy. + * + * This is really messy because the visualization hierarchy is typed Object. + * + * @param context Visualization context + * @param clazz Type filter + * @param <O> Object type + * @return Iterator of results. + */ + @SuppressWarnings("unchecked") + public static <O extends VisualizationItem> Hierarchy.Iter<O> filter(VisualizerContext context, Class<? super O> clazz) { + Hierarchy.Iter<Result> it1 = context.getHierarchy().iterAll(); + StackedIter<Object, Result> it2 = new StackedIter<>(it1, context.getVisHierarchy()); + if(!it2.valid()) { + return HashMapHierarchy.emptyIterator(); + } + return new FilteredIter<O>(it2, (Class<O>) clazz); + } + + /** + * Filtered iteration over a stacked hierarchy. + * + * This is really messy because the visualization hierarchy is typed Object. + * + * @param context Visualization context + * @param start Starting object (in primary hierarchy!) + * @param clazz Type filter + * @param <O> Object type + * @return Iterator of results. + */ + @SuppressWarnings("unchecked") + public static <O extends VisualizationItem> Hierarchy.Iter<O> filter(VisualizerContext context, Object start, Class<? super O> clazz) { + if(start instanceof Result) { // In first hierarchy. + Hierarchy.Iter<Result> it1 = context.getHierarchy().iterDescendantsSelf((Result) start); + StackedIter<Object, Result> it2 = new StackedIter<>(it1, context.getVisHierarchy()); + if(!it2.valid()) { + return HashMapHierarchy.emptyIterator(); + } + return new FilteredIter<O>(it2, (Class<O>) clazz); + } + Hierarchy.Iter<Object> it2 = context.getVisHierarchy().iterDescendantsSelf(start); + if(!it2.valid()) { + return HashMapHierarchy.emptyIterator(); + } + return new FilteredIter<O>(it2, (Class<O>) clazz); + } + + /** + * Filtered iteration over the primary result tree. + * + * @param context Visualization context + * @param start Starting object (in primary hierarchy!) + * @param clazz Type filter + * @param <O> Result type type + * @return Iterator of results. + */ + @SuppressWarnings("unchecked") + public static <O extends Result> Hierarchy.Iter<O> filterResults(VisualizerContext context, Object start, Class<? super O> clazz) { + if(start instanceof Result) { // In first hierarchy. + Hierarchy.Iter<Result> it1 = context.getHierarchy().iterDescendantsSelf((Result) start); + return new FilteredIter<O>(it1, (Class<O>) clazz); + } + return HashMapHierarchy.emptyIterator(); + } + + /** + * Process new results. + * + * This is a bit painful, because we have two hierarchies with different + * types: results, and visualizations. + * + * @param context Context + * @param start Starting point + * @param type1 First type + * @param handler Handler + */ + @SuppressWarnings("unchecked") + public static <A> void findNew(VisualizerContext context, Object start, Class<? super A> type1, Handler1<A> handler) { + final Hierarchy<Object> hier = context.getVisHierarchy(); + // Children of start in first hierarchy: + if(start instanceof Result) { + Hierarchy.Iter<Result> it1 = context.getHierarchy().iterDescendantsSelf((Result) start); + for(; it1.valid(); it1.advance()) { + final Result o1 = it1.get(); + if(!(type1.isInstance(o1))) { + continue; + } + handler.process(context, (A) o1); + } + } + // Children of start in second hierarchy: + if(start instanceof VisualizationItem) { + Iter<Object> it1 = hier.iterDescendantsSelf(start); + for(; it1.valid(); it1.advance()) { + final Object o1 = it1.get(); + if(!(type1.isInstance(o1))) { + continue; + } + handler.process(context, (A) start); + } + } + } + + /** + * Process new result combinations of an object type1 (in first hierarchy) and + * any child of type2 (in second hierarchy) + * + * This is a bit painful, because we have two hierarchies with different + * types: results, and visualizations. + * + * @param context Context + * @param start Starting point + * @param type1 First type, in first hierarchy + * @param type2 Second type, in second hierarchy + * @param handler Handler + */ + @SuppressWarnings("unchecked") + public static <A extends Result, B extends VisualizationItem> void findNewSiblings(VisualizerContext context, Object start, Class<? super A> type1, Class<? super B> type2, Handler2<A, B> handler) { + final Hierarchy<Object> vistree = context.getVisHierarchy(); + // Search start in first hierarchy: + if(start instanceof Result) { + Hierarchy.Iter<Result> it1 = context.getHierarchy().iterDescendantsSelf((Result) start); + for(; it1.valid(); it1.advance()) { + final Result o1 = it1.get(); + if(!(type1.isInstance(o1))) { + continue; + } + Iter<Object> it2 = vistree.iterDescendantsSelf(context.getBaseResult()); + for(; it2.valid(); it2.advance()) { + final Object o2 = it2.get(); + if(!(type2.isInstance(o2))) { + continue; + } + handler.process(context, (A) o1, (B) o2); + } + } + } + // Search start in second hierarchy: + if(start instanceof VisualizationItem) { + Iter<Object> it2 = vistree.iterDescendantsSelf(start); + for(; it2.valid(); it2.advance()) { + final Object o2 = it2.get(); + if(!(type2.isInstance(o2))) { + continue; + } + Iter<Result> it1 = context.getHierarchy().iterAll(); + for(; it1.valid(); it1.advance()) { + final Result o1 = it1.get(); + if(!(type1.isInstance(o1))) { + continue; + } + handler.process(context, (A) o1, (B) o2); + } + } + } + } + + /** + * Process new result combinations of an object type1 (in first hierarchy) + * having a child of type2 (in second hierarchy). + * + * This is a bit painful, because we have two hierarchies with different + * types: results, and visualizations. + * + * @param context Context + * @param start Starting point + * @param type1 First type, in first hierarchy + * @param type2 Second type, in second hierarchy + * @param handler Handler + */ + @SuppressWarnings("unchecked") + public static <A extends Result, B extends VisualizationItem> void findNewResultVis(VisualizerContext context, Object start, Class<? super A> type1, Class<? super B> type2, Handler2<A, B> handler) { + final Hierarchy<Object> hier = context.getVisHierarchy(); + // Search start in first hierarchy: + if(start instanceof Result) { + Hierarchy.Iter<Result> it1 = context.getHierarchy().iterDescendantsSelf((Result) start); + for(; it1.valid(); it1.advance()) { + final Result o1 = it1.get(); + if(!(type1.isInstance(o1))) { + continue; + } + // Nasty: we now need to search backwards for crossover points: + Iter<Result> it3 = context.getHierarchy().iterDescendantsSelf(o1); + for(; it3.valid(); it3.advance()) { + Iter<Object> it2 = hier.iterDescendantsSelf(it3.get()); + for(; it2.valid(); it2.advance()) { + final Object o2 = it2.get(); + if(!(type2.isInstance(o2))) { + continue; + } + handler.process(context, (A) o1, (B) o2); + } + } + } + } + // Search start in second hierarchy: + if(start instanceof VisualizationItem) { + Iter<Object> it2 = hier.iterDescendantsSelf(start); + for(; it2.valid(); it2.advance()) { + final Object o2 = it2.get(); + if(!(type2.isInstance(o2))) { + continue; + } + // Nasty: we now need to search backwards for crossover points: + Iter<Object> it3 = hier.iterAncestorsSelf(start); + for(; it3.valid(); it3.advance()) { + if(!(it3.get() instanceof Result)) { + continue; + } + // Now cross-over into primary hierarchy: + Iter<Result> it1 = context.getHierarchy().iterAncestorsSelf((Result) it3.get()); + for(; it1.valid(); it1.advance()) { + final Result o1 = it1.get(); + if(!(type1.isInstance(o1))) { + continue; + } + handler.process(context, (A) o1, (B) o2); + } + } + } + } + } + + /** + * Utility function to change Visualizer visibility. + * + * @param context Visualization context + * @param task Visualization task + * @param visibility Visibility value + */ + public static void setVisible(VisualizerContext context, VisualizationTask task, boolean visibility) { + // Hide other tools + if(visibility && task.tool) { + Hierarchy<Object> vistree = context.getVisHierarchy(); + for(Hierarchy.Iter<?> iter2 = vistree.iterAll(); iter2.valid(); iter2.advance()) { + if(!(iter2.get() instanceof VisualizationTask)) { + continue; + } + VisualizationTask other = (VisualizationTask) iter2.get(); + if(other != task && other.tool && other.visible) { + other.visible = false; + context.visChanged(other); + } + } + } + task.visible = visibility; + context.visChanged(task); + } +}
\ No newline at end of file |