diff options
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.java | 287 |
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 |