Commit cdf34aab authored by twanvl's avatar twanvl

Added color utilities; implemented more of Graph related classes

parent 06e03514
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <gfx/gfx.hpp>
// ----------------------------------------------------------------------------- : Color utility functions
Color lerp(const Color& a, const Color& b, double t) {
return Color(a.Red() + (b.Red() - a.Red() ) * t,
a.Green() + (b.Green() - a.Green()) * t,
a.Blue() + (b.Blue() - a.Blue() ) * t);
}
int hsl2rgbp(double t1, double t2, double t3) {
// adjust t3 to [0...1)
if (t3 < 0.0) t3 += 1;
else if (t3 > 1.0) t3 -= 1;
// determine color
if (6.0 * t3 < 1) return (int)(255 * (t1 + (t2-t1) * 6.0 * t3) );
if (2.0 * t3 < 1) return (int)(255 * (t2) );
if (3.0 * t3 < 2) return (int)(255 * (t1 + (t2-t1) * 6.0 * (2.0/3.0 - t3)) );
else return (int)(255 * (t1) );
}
Color hsl2rgb(double h, double s, double l) {
double t2 = l < 0.5 ? l * (1.0 + s) :
l * (1.0 - s) + s;
double t1 = 2.0 * l - t2;
return Color(
hsl2rgbp(t1, t2, h + 1.0/3.0),
hsl2rgbp(t1, t2, h) ,
hsl2rgbp(t1, t2, h - 1.0/3.0)
);
}
Color darken(const Color& c) {
return Color(
c.Red() * 8 / 10,
c.Green() * 8 / 10,
c.Blue() * 8 / 10
);
}
......@@ -144,7 +144,7 @@ class ContourMask {
UInt *lefts, *rights;
};
// ----------------------------------------------------------------------------- : Utility
// ----------------------------------------------------------------------------- : Color utility functions
inline int bot(int x) { return max(0, x); } ///< bottom range check for color values
inline int top(int x) { return min(255, x); } ///< top range check for color values
......@@ -153,5 +153,11 @@ inline int col(int x) { return top(bot(x)); } ///< top and bottom range check fo
/// Linear interpolation between colors
Color lerp(const Color& a, const Color& b, double t);
/// convert HSL to RGB, h,s,l must be in range [0...1)
Color hsl2rgb(double h, double s, double l);
/// A darker version of a color
Color darken(const Color& c);
// ----------------------------------------------------------------------------- : EOF
#endif
......@@ -7,6 +7,7 @@
// ----------------------------------------------------------------------------- : Includes
#include <gui/control/gallery_list.hpp>
#include <gfx/gfx.hpp>
// ----------------------------------------------------------------------------- : Events
......@@ -111,14 +112,6 @@ void GalleryList::onKeyDown(wxKeyEvent& ev) {
}
}
// Linear interpolation between colors
// MOVE ME, declared in gfx.hpp
Color lerp(const Color& a, const Color& b, double t) {
return Color(a.Red() + (b.Red() - a.Red() ) * t,
a.Green() + (b.Green() - a.Green()) * t,
a.Blue() + (b.Blue() - a.Blue() ) * t);
}
wxSize GalleryList::DoGetBestSize() const {
wxSize ws = GetSize(), cs = GetClientSize();
const int w = item_size.GetWidth() + 2 * MARGIN;
......
......@@ -7,19 +7,136 @@
// ----------------------------------------------------------------------------- : Includes
#include <gui/control/graph.hpp>
#include <gfx/gfx.hpp>
#include <wx/dcbuffer.h>
// ----------------------------------------------------------------------------- : Graph
DECLARE_TYPEOF_COLLECTION(GraphAxisP);
DECLARE_TYPEOF_COLLECTION(GraphElementP);
DECLARE_TYPEOF_COLLECTION(GraphGroup);
typedef map<String,UInt> map_String_UInt;
DECLARE_TYPEOF(map_String_UInt);
// ----------------------------------------------------------------------------- : GraphData
GraphElement::GraphElement(const String& v1) {
values.push_back(v1);
}
GraphElement::GraphElement(const String& v1, const String& v2) {
values.push_back(v1);
values.push_back(v2);
}
GraphData::GraphData(const GraphDataPre& d)
: axes(d.axes)
{
// total size
size = (UInt)d.elements.size();
// find groups on each axis
size_t value_count = 1;
size_t i = 0;
FOR_EACH(a, axes) {
map<String,UInt> counts; // note: default constructor for UInt() does initialize to 0
FOR_EACH_CONST(e, d.elements) {
counts[e->values[i]] += 1;
}
// TODO: allow some ordering in the groups, and allow colors to be passed
FOR_EACH(c, counts) {
a->groups.push_back(GraphGroup(c.first, c.second));
a->max = max(a->max, c.second);
}
// find some nice colors for the groups
if (a->auto_color) {
double hue = 0.6; // start hue
bool first = true;
FOR_EACH(g, a->groups) {
double amount = double(g.size) / size; // amount this group takes
if (!first) hue += amount/2;
g.color = hsl2rgb(hue, 1.0, 0.5);
hue += amount / 2;
first = false;
}
}
value_count *= a->groups.size();
++i;
}
// count elements in each position
values.clear();
values.resize(value_count, 0);
FOR_EACH_CONST(e, d.elements) {
// find index j in elements
size_t i = 0, j = 0;
FOR_EACH(a, axes) {
String v = e->values[i];
size_t k = 0, l = 0;
FOR_EACH(g, a->groups) {
if (v == g.name) {
k = l;
break;
}
l += 1;
}
j = j * a->groups.size() + k;
++i;
}
values[j] += 1;
}
}
// ----------------------------------------------------------------------------- : Graph1D
bool Graph1D::findItem(const RealPoint& pos, vector<int>& out) const {
int i = findItem(pos);
if (i == -1) return false;
else {
out.clear();
out.insert(out.begin(), data->axes.size(), -1);
out.at(axis) = i;
return true;
}
}
// ----------------------------------------------------------------------------- : Bar Graph
void BarGraph::draw(RotatedDC& dc) const {
// TODO
}
int BarGraph::findItem(const RealPoint& pos) const {
return -1; // TODO
}
// ----------------------------------------------------------------------------- : Pie Graph
// ----------------------------------------------------------------------------- : Graph Legend
// ----------------------------------------------------------------------------- : GraphControl
GraphControl::GraphControl(Window* parent, int id)
: wxControl(parent, id)
{}
{
graph = new_shared1<BarGraph>(0);
}
void GraphControl::setData(const GraphDataPre& data) {
setData(new_shared1<GraphData>(data));
}
void GraphControl::setData(const GraphDataP& data) {
if (graph) {
graph->setData(data);
current_item.clear(); // TODO : preserver selection
Refresh(false);
}
}
void GraphControl::onPaint(wxPaintEvent&) {
wxBufferedPaintDC dc(this);
wxSize cs = GetClientSize();
RotatedDC rdc(dc, 0, RealRect(RealPoint(0,0),cs), 1, false);
rdc.SetPen(*wxTRANSPARENT_PEN);
rdc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
rdc.DrawRectangle(rdc.getInternalRect());
if (graph) graph->draw(rdc);
}
void GraphControl::onSize(wxSizeEvent&) {
......
......@@ -23,25 +23,39 @@ DECLARE_POINTER_TYPE(Graph);
/** A group is rendered as a single bar or pie slice */
class GraphGroup {
public:
GraphGroup(const String& name, UInt size, const Color& color = *wxBLACK)
: name(name), color(color), size(size)
{}
String name; ///< Name of this position
Color color; ///< Associated color
int size; ///< Number of elements in this group
UInt size; ///< Number of elements in this group
};
/// An axis in a graph, consists of a list of groups
/** The sum of groups.sum = sum of all elements in the data */
class GraphAxis {
public:
GraphAxis(const String& name, bool auto_color = true)
: name(name)
, auto_color(auto_color)
, max(0)
{}
String name; ///< Name/label of this axis
bool auto_color; ///< Automatically assign colors to the groups on this axis
vector<GraphGroup> groups; ///< Groups along this axis
int max; ///< Maximum size of the groups
UInt max; ///< Maximum size of the groups
};
/// A single data point of a graph
class GraphElement {
public:
vector<String> axis_groups; ///< Group name for each axis
GraphElement() {}
GraphElement(const String& v1);
GraphElement(const String& v1, const String& v2);
vector<String> values; ///< Group name for each axis
};
/// Data to be displayed in a graph, not processed yet
......@@ -54,11 +68,11 @@ class GraphDataPre {
/// Data to be displayed in a graph
class GraphData {
public:
GraphData(GraphDataPre);
GraphData(const GraphDataPre&);
vector<GraphAxisP> axes; ///< The axes in the data
vector<int> values; ///< Multi dimensional (dim = axes.size()) array of values
int size; ///< Total number of elements
vector<UInt> values; ///< Multi dimensional (dim = axes.size()) array of values
UInt size; ///< Total number of elements
};
......@@ -69,7 +83,7 @@ class GraphData {
class Graph {
public:
/// Draw this graph, filling the internalRect() of the dc.
virtual void draw(RotatedDC& dc) = 0;
virtual void draw(RotatedDC& dc) const = 0;
/// Find the item at the given position, position is normalized to [0..1)
virtual bool findItem(const RealPoint& pos, vector<int>& out) const { return false; }
/// Change the data
......@@ -84,7 +98,7 @@ class Graph {
class Graph1D : public Graph {
public:
inline Graph1D(size_t axis) : axis(axis) {}
virtual bool findItem(const RealPoint& pos, vector<int>& out) const { return false; }
virtual bool findItem(const RealPoint& pos, vector<int>& out) const;
protected:
size_t axis;
/// Find an item, return the position along the axis, or -1 if not found
......
......@@ -1240,6 +1240,33 @@
<File
RelativePath=".\gfx\blend_image.cpp">
</File>
<File
RelativePath=".\gfx\color.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)3.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)3.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Debug Unicode|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)3.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Release Unicode|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)3.obj"/>
</FileConfiguration>
</File>
<File
RelativePath=".\gfx\combine_image.cpp">
<FileConfiguration
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment