summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/visualization/visualizers/pairsegments/SegmentsStylingPolicy.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/visualization/visualizers/pairsegments/SegmentsStylingPolicy.java')
-rw-r--r--src/de/lmu/ifi/dbs/elki/visualization/visualizers/pairsegments/SegmentsStylingPolicy.java287
1 files changed, 287 insertions, 0 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/visualization/visualizers/pairsegments/SegmentsStylingPolicy.java b/src/de/lmu/ifi/dbs/elki/visualization/visualizers/pairsegments/SegmentsStylingPolicy.java
new file mode 100644
index 00000000..99ecf081
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/visualization/visualizers/pairsegments/SegmentsStylingPolicy.java
@@ -0,0 +1,287 @@
+package de.lmu.ifi.dbs.elki.visualization.visualizers.pairsegments;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2012
+ 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 java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import de.lmu.ifi.dbs.elki.database.ids.DBID;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
+import de.lmu.ifi.dbs.elki.database.ids.ModifiableDBIDs;
+import de.lmu.ifi.dbs.elki.evaluation.clustering.pairsegments.Segment;
+import de.lmu.ifi.dbs.elki.evaluation.clustering.pairsegments.Segments;
+import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
+import de.lmu.ifi.dbs.elki.visualization.style.ClassStylingPolicy;
+import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
+import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
+
+/**
+ * Styling policy to communicate the segment selection to other visualizers.
+ *
+ * @author Sascha Goldhofer
+ * @author Erich Schubert
+ */
+public class SegmentsStylingPolicy implements ClassStylingPolicy {
+ /**
+ * The segments we use for visualization
+ */
+ protected final Segments segments;
+
+ /**
+ * Selected segments
+ */
+ protected ArrayList<Segment> selectedSegments = new ArrayList<Segment>();
+
+ /**
+ * Segments indirectly selected
+ */
+ protected TreeMap<Segment, Segment> indirectSelections = new TreeMap<Segment, Segment>();
+
+ /**
+ * Not selected IDs that will be drawn in default colors.
+ */
+ protected ModifiableDBIDs unselectedObjects = DBIDUtil.newHashSet();
+
+ /**
+ * Color library (only used in compatibility mode)
+ */
+ // TODO: move to abstract super class?
+ ColorLibrary colorset;
+
+ /**
+ * Constructor.
+ *
+ * @param segments Segments
+ */
+ public SegmentsStylingPolicy(Segments segments, StyleLibrary style) {
+ super();
+ this.segments = segments;
+ this.colorset = style.getColorSet(StyleLibrary.PLOT);
+
+ // get all selectable segments
+ for(Segment segment : segments) {
+ // store segmentID
+ if(!segment.isUnpaired()) {
+ // and store their get all objects
+ if(segment.getDBIDs() != null) {
+ unselectedObjects.addDBIDs(segment.getDBIDs());
+ }
+ }
+ }
+ }
+
+ /**
+ * Test whether a segment is selected.
+ *
+ * @param segment Segment to test
+ * @return true when selected
+ */
+ public boolean isSelected(Segment segment) {
+ return selectedSegments.contains(segment) || indirectSelections.containsValue(segment);
+ }
+
+ @Override
+ public int getStyleForDBID(DBID id) {
+ Iterator<Segment> s = selectedSegments.iterator();
+ for(int i = 0; s.hasNext(); i++) {
+ Segment seg = s.next();
+ DBIDs ids = seg.getDBIDs();
+ if(ids != null && ids.contains(id)) {
+ return i;
+ }
+ }
+ return -2;
+ }
+
+ @Override
+ public int getColorForDBID(DBID id) {
+ int style = getStyleForDBID(id);
+ // FIXME: slow
+ return SVGUtil.stringToColor(colorset.getColor(style)).getRGB();
+ }
+
+ @Override
+ // -2=grau, -1=schwarz, 0+=farben
+ public int getMinStyle() {
+ return -2;
+ }
+
+ @Override
+ public int getMaxStyle() {
+ return selectedSegments.size();
+ }
+
+ @Override
+ public Iterator<DBID> iterateClass(int cnum) {
+ // unselected
+ if(cnum == -2) {
+ return unselectedObjects.iterator();
+ }
+ else if(cnum == -1) {
+ return DBIDUtil.EMPTYDBIDS.iterator();
+ }
+ // colors
+ DBIDs ids = selectedSegments.get(cnum).getDBIDs();
+ return (ids != null) ? ids.iterator() : DBIDUtil.EMPTYDBIDS.iterator();
+ }
+
+ /**
+ * Adds or removes the given segment to the selection. Depending on the
+ * clustering and cluster selected and the addToSelection option given, the
+ * current selection will be modified. This method is called by clicking on a
+ * segment and ring and the CTRL-button status.
+ *
+ * Adding selections does only work on the same clustering and cluster, else a
+ * new selection will be added.
+ *
+ * @param segment the selected element representing a segment ring (specific
+ * clustering)
+ * @param addToSelection flag for adding segment to current selection
+ */
+ public void select(Segment segment, boolean addToSelection) {
+ // abort if segment represents pairs inNone. Would select all segments...
+ if(segment.isNone()) {
+ return;
+ }
+ if(!addToSelection) {
+ deselectAllSegments();
+ }
+
+ // get selected segments
+ if(segment.isUnpaired()) {
+ // check if all segments are selected
+ if(addToSelection) {
+ boolean allSegmentsSelected = true;
+ for(Segment other : segments.getPairedSegments(segment)) {
+ if(!isSelected(other)) {
+ allSegmentsSelected = false;
+ break;
+ }
+ }
+
+ // if all are selected, deselect all
+ if(allSegmentsSelected) {
+ deselectSegment(segment);
+ return;
+ }
+ }
+ if(isSelected(segment)) {
+ deselectSegment(segment);
+ }
+ else {
+ selectSegment(segment);
+ }
+ }
+ else {
+ // an object segment was selected
+ if(isSelected(segment)) {
+ deselectSegment(segment);
+ }
+ else {
+ selectSegment(segment);
+ }
+ }
+ }
+
+ /**
+ * Deselect all currently selected segments
+ */
+ public void deselectAllSegments() {
+ while(selectedSegments.size() > 0) {
+ deselectSegment(selectedSegments.get(selectedSegments.size() - 1));
+ }
+ }
+
+ /**
+ * Deselect a segment
+ *
+ * @param segment Segment to deselect
+ */
+ protected void deselectSegment(Segment segment) {
+ if(segment.isUnpaired()) {
+ ArrayList<Segment> remove = new ArrayList<Segment>();
+ // remove all object segments associated with unpaired segment from
+ // selection list
+ for(Entry<Segment, Segment> entry : indirectSelections.entrySet()) {
+ if(entry.getValue() == segment) {
+ remove.add(entry.getKey());
+ }
+ }
+
+ for(Segment other : remove) {
+ indirectSelections.remove(other);
+ deselectSegment(other);
+ }
+ }
+ else {
+ // check if deselected object Segment has a unpaired segment highlighted
+ Segment unpaired = indirectSelections.get(segment);
+ if(unpaired != null) {
+ // remove highlight
+ deselectSegment(unpaired);
+ }
+ if(selectedSegments.remove(segment)) {
+ if(segment.getDBIDs() != null) {
+ unselectedObjects.addDBIDs(segment.getDBIDs());
+ }
+ }
+ }
+ }
+
+ /**
+ * Select a segment
+ *
+ * @param segment Segment to select
+ */
+ protected void selectSegment(Segment segment) {
+ if(segment.isUnpaired()) {
+ // remember selected unpaired segment
+ for(Segment other : segments.getPairedSegments(segment)) {
+ indirectSelections.put(other, segment);
+ selectSegment(other);
+ }
+ }
+ else {
+ if(!selectedSegments.contains(segment)) {
+ selectedSegments.add(segment);
+ if(segment.getDBIDs() != null) {
+ unselectedObjects.removeDBIDs(segment.getDBIDs());
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the index of a selected segment.
+ *
+ * @param segment Segment to find
+ * @return Index, or -1
+ */
+ public int indexOfSegment(Segment segment) {
+ return selectedSegments.indexOf(segment);
+ }
+} \ No newline at end of file