implement a color mapper class
authorDiane Trout <diane@caltech.edu>
Sun, 12 Mar 2006 09:16:10 +0000 (09:16 +0000)
committerDiane Trout <diane@caltech.edu>
Sun, 12 Mar 2006 09:16:10 +0000 (09:16 +0000)
So I was deeply inspired by my habit of using nested python dictionaries
This provides the semantics of a hierarchy of 3 different colors.
A generic default, a per annotation "type" default, and an "instance" default.

it does assume there's only those 3 levels and nothing else, though it
probably is possible to make it more recursive and capable of supporting
arbitrary depths. However I don't need that.

alg/annotation_colors.cpp [new file with mode: 0644]
alg/annotation_colors.hpp [new file with mode: 0644]
alg/module.mk
alg/test/module.mk
alg/test/test_annotation_color.cpp [new file with mode: 0644]
mussagl.pro

diff --git a/alg/annotation_colors.cpp b/alg/annotation_colors.cpp
new file mode 100644 (file)
index 0000000..aab22d1
--- /dev/null
@@ -0,0 +1,97 @@
+#include "annotation_colors.hpp"
+
+using namespace std;
+
+DefaultColorMap::DefaultColorMap()
+  : defaultColor(Color(0.0, 0.0, 0.0)) // set default color to black
+{
+}
+
+DefaultColorMap::DefaultColorMap(const Color &c) 
+  : defaultColor(c)
+{
+}
+
+DefaultColorMap::DefaultColorMap(const DefaultColorMap &dcm)
+  : defaultColor(dcm.defaultColor),
+    cm(dcm.cm)
+{
+}
+
+AnnotationColors::AnnotationColors()
+{
+}
+
+AnnotationColors::AnnotationColors(AnnotationColors &ac)
+  : root_map(ac.root_map)
+{
+}
+
+void AnnotationColors::setColor(Color &c)
+{
+  root_map.defaultColor = c;
+}
+
+Color AnnotationColors::color() 
+{
+  return root_map.defaultColor;
+}
+
+void AnnotationColors::appendTypeColor(const string &type, const Color &c)
+{
+  root_map.cm[type].defaultColor = c;
+}
+
+Color AnnotationColors::typeColor(const string &type)
+{
+  return root_map.cm[type].defaultColor;
+}
+
+void AnnotationColors::erase(const string &type)
+{
+  root_map.cm.erase(type);
+}
+
+void AnnotationColors::appendInstanceColor(const string &type, 
+                                           const string &instance,
+                                           const Color &c)
+{
+  root_map.cm[type].cm[instance].defaultColor = c;
+}
+
+Color AnnotationColors::instanceColor(const string &type,
+                                      const string &instance) 
+{
+  return root_map.cm[type].cm[instance].defaultColor;
+}
+
+void AnnotationColors::erase(const string &type, 
+                             const string& instance)
+{
+  root_map.cm[type].cm.erase(instance);
+}
+
+Color AnnotationColors::lookup(const annot &a)
+{
+  return lookup(a.type, a.name);
+}
+
+Color AnnotationColors::lookup(const string &type, const string &instance)
+{
+  // Yeah, there's probably a nicer looking recursive solution
+  // to this problem.
+  DefaultColorMap::iterator type_map = root_map.cm.find(type);
+  if (type_map != root_map.cm.end() ) {
+    // found lookup instance
+    DefaultColorMap::iterator instance_map = type_map->second.cm.find(instance);
+    if (instance_map != type_map->second.cm.end() ) {
+      return instance_map->second.defaultColor;
+    } else {
+      return type_map->second.defaultColor;
+    }
+  } else {
+    // not found
+    return root_map.defaultColor;
+  }
+}
+
diff --git a/alg/annotation_colors.hpp b/alg/annotation_colors.hpp
new file mode 100644 (file)
index 0000000..96efa25
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef ANNOTATION_COLOR_H
+#define ANNOTATION_COLOR_H
+
+#include <map>
+#include <string>
+
+#include "alg/color.hpp"
+#include "alg/sequence.hpp"
+
+struct DefaultColorMap;
+struct DefaultColorMap
+{
+  typedef std::map<std::string, DefaultColorMap> color_map_type;
+  typedef color_map_type::iterator iterator;
+  DefaultColorMap();
+  //! initialize color map with a default color
+  DefaultColorMap(const Color &);
+  DefaultColorMap(const color_map_type&);
+  DefaultColorMap(const DefaultColorMap&);
+
+  Color defaultColor;
+  //! color map
+  color_map_type cm;
+};
+
+class AnnotationColors
+{
+public:
+  AnnotationColors();
+  AnnotationColors(AnnotationColors &);
+
+  //! set default color
+  void setColor(Color &);
+  //! retreive default color
+  Color color();
+
+  //! add default color for a particular type
+  void appendTypeColor(const std::string &, const Color &);
+  //! get default color for a type
+  Color typeColor(const std::string &);
+  //! remove a type (and all of its instances)
+  void erase(const std::string &);
+
+  //! add default color for a particular type
+  void appendInstanceColor(const std::string &type, 
+                           const std::string &instance, 
+                           const Color &);
+  //! get color for a particular type
+  Color instanceColor(const std::string &type, 
+                      const std::string &instance);
+  //! remove an instance of particular type
+  void erase(const std::string &type, const std::string& instance);
+
+  //! lookup an annotation color
+  Color lookup(const annot &);
+  Color lookup(const std::string &, const std::string &);
+private:
+  // nested maps, with default?
+  DefaultColorMap root_map;
+};
+#endif
index ba925db0e88b316673fd1d6100eba1c7dd1212ee..0d157ce034aa29411a23fb6dd4f4f5cc759ef0ad 100644 (file)
@@ -1,6 +1,7 @@
 CURDIR := $(BASEDIR)alg/
 
-SOURCES.cpp := color.cpp \
+SOURCES.cpp := annotation_colors.cpp \
+               color.cpp \
                conserved_path.cpp \
                flp.cpp \
                flp_seqcomp.cpp \
index c02382de73689279c535505c98339cbe5fc42bf3..a23177fba56a02d7a66fa5899a7bf58403f12bef 100644 (file)
@@ -1,6 +1,7 @@
 CURDIR := $(BASEDIR)alg/test/
 
-SOURCES.cpp := test_conserved_path.cpp \
+SOURCES.cpp := test_annotation_color.cpp \
+               test_conserved_path.cpp \
                test_flp.cpp \
                test_glsequence.cpp \
                                                         test_color.cpp \
diff --git a/alg/test/test_annotation_color.cpp b/alg/test/test_annotation_color.cpp
new file mode 100644 (file)
index 0000000..af7035b
--- /dev/null
@@ -0,0 +1,40 @@
+#include <boost/test/auto_unit_test.hpp>
+
+#include "alg/annotation_colors.hpp"
+#include "alg/color.hpp"
+
+BOOST_AUTO_TEST_CASE( simple_annot_colors )
+{
+  Color black(0.0, 0.0, 0.0);
+  Color white(1.0, 1.0, 1.0);
+  Color red(1.0, 0.0, 0.0);
+
+  AnnotationColors ac;
+
+  ac.setColor(white);
+  BOOST_CHECK_EQUAL( ac.color(), white);
+
+  ac.appendTypeColor("bleem", black);
+  BOOST_CHECK_EQUAL( ac.typeColor("bleem"), black );
+  // FIXME: it'd be nice if something like this worked?
+  //BOOST_CHECK_RAISES( ac.typeColor("not found"), not_found );
+  ac.appendInstanceColor("bleem", "a", red);
+  BOOST_CHECK_EQUAL( ac.instanceColor("bleem", "a"), red);
+  BOOST_CHECK_EQUAL( ac.lookup("bleem", "a"), red );
+  BOOST_CHECK_EQUAL( ac.lookup("bleem", "foo"), black );
+  BOOST_CHECK_EQUAL( ac.lookup("venchent", "a"), white );
+
+  annot a;
+  a.start = 30;
+  a.end = 45;
+  a.type = "bleem";
+  a.name = "a";
+  
+  BOOST_CHECK_EQUAL( ac.lookup(a), red );
+  a.name = "b";
+  BOOST_CHECK_EQUAL( ac.lookup(a), black );
+  a.type = "venchent";
+  BOOST_CHECK_EQUAL( ac.lookup(a), white );
+}
+
index 24e1124c31ba625bd0c68c70cb5f5c85b56e32e9..82b4fd768e7474d9cb582a34cd4b40f27bf1496b 100644 (file)
@@ -18,6 +18,7 @@ HEADERS += mussa_exceptions.hpp \
            qui/ThresholdWidget.hpp \
            qui/ImageScaler.hpp \
            qui/ImageSaveDialog.hpp \
+           alg/annotation_colors.hpp \
            alg/color.hpp \
            alg/conserved_path.hpp \
            alg/flp.hpp \
@@ -33,6 +34,7 @@ SOURCES += mussagl.cpp \
            qui/ThresholdWidget.cpp \
            qui/ImageScaler.cpp \
            qui/ImageSaveDialog.cpp \
+           alg/annotation_colors.cpp \
            alg/color.cpp \
            alg/conserved_path.cpp \
            alg/flp.cpp \