summaryrefslogtreecommitdiff
path: root/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/VisualizationTree.java
diff options
context:
space:
mode:
authorAndrej Shadura <andrewsh@debian.org>2019-03-09 22:30:41 +0000
committerAndrej Shadura <andrewsh@debian.org>2019-03-09 22:30:41 +0000
commit38212b3127e90751fb39cda34250bc11be62b76c (patch)
treedc1397346030e9695bd763dddc93b3be527cd643 /addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/VisualizationTree.java
parent337087b668d3a54f3afee3a9adb597a32e9f7e94 (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.java395
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