mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Scatter plots
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@363 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -112,10 +112,13 @@ help:
|
||||
redo: Redoes the last action
|
||||
cut: Move the selected text to the clipboard
|
||||
cut card: Move the selected card to the clipboard
|
||||
cut keyword: Move the selected keyword to the clipboard
|
||||
copy: Place the selected text on the clipboard
|
||||
copy card: Place the selected card on the clipboard
|
||||
copy keyword: Place the selected keyword on the clipboard
|
||||
paste: Inserts the text from the clipboard
|
||||
paste card: Inserts the card from the clipboard
|
||||
paste keyword: Inserts the keyword from the clipboard
|
||||
preferences: Change the configuration of Magic Set Editor
|
||||
|
||||
cards:
|
||||
@@ -273,6 +276,7 @@ tooltip:
|
||||
new set: New set
|
||||
open set: Open set
|
||||
save set: Save set
|
||||
export: Export set
|
||||
|
||||
cut: Cut
|
||||
copy: Copy
|
||||
|
||||
@@ -176,6 +176,7 @@ choice colors:
|
||||
artifact : rgb(188,192,195)
|
||||
multicolor : rgb(255,188,14)
|
||||
land : rgb(109,62,39)
|
||||
hybrid : rgb(243,26,136) # purple
|
||||
# Sub menus, same colors
|
||||
multicolor 2 color white / blue : rgb(255,188,14)
|
||||
multicolor 2 color blue / black : rgb(255,188,14)
|
||||
|
||||
+44
-33
@@ -971,31 +971,31 @@ card field:
|
||||
|
||||
############################################################## Statistics categories
|
||||
|
||||
statistics dimension:
|
||||
name: card color2
|
||||
script: primary_card_color(card.card_color)
|
||||
icon: stats/card_color.png
|
||||
colors:
|
||||
white : rgb(255,237,202)
|
||||
blue : rgb(42,141,255)
|
||||
black : rgb(33,33,33)
|
||||
red : rgb(255,52,0)
|
||||
green : rgb(138,230,0)
|
||||
colorless : rgb(122,85,85)
|
||||
artifact : rgb(188,192,195)
|
||||
multicolor : rgb(255,188,14)
|
||||
land : rgb(109,62,39)
|
||||
hybrid : rgb(243,26,136)
|
||||
group: white
|
||||
group: blue
|
||||
group: black
|
||||
group: red
|
||||
group: green
|
||||
group: colorless
|
||||
group: artifact
|
||||
group: multicolor
|
||||
group: land
|
||||
group: hybrid
|
||||
#statistics dimension:
|
||||
# name: card color2
|
||||
# script: primary_card_color(card.card_color)
|
||||
# icon: stats/card_color.png
|
||||
# colors:
|
||||
# white : rgb(255,237,202)
|
||||
# blue : rgb(42,141,255)
|
||||
# black : rgb(33,33,33)
|
||||
# red : rgb(255,52,0)
|
||||
# green : rgb(138,230,0)
|
||||
# colorless : rgb(122,85,85)
|
||||
# artifact : rgb(188,192,195)
|
||||
# multicolor : rgb(255,188,14)
|
||||
# land : rgb(109,62,39)
|
||||
# hybrid : rgb(243,26,136)
|
||||
# group: white
|
||||
# group: blue
|
||||
# group: black
|
||||
# group: red
|
||||
# group: green
|
||||
# group: colorless
|
||||
# group: artifact
|
||||
# group: multicolor
|
||||
# group: land
|
||||
# group: hybrid
|
||||
|
||||
statistics dimension:
|
||||
name: converted mana cost
|
||||
@@ -1010,11 +1010,16 @@ statistics dimension:
|
||||
icon: stats/colored_casting_cost.png
|
||||
|
||||
#statistics dimension:
|
||||
# name: power2
|
||||
# script: card.power
|
||||
# name: p/t
|
||||
# script: card.pt
|
||||
# numeric: true
|
||||
# icon: stats/power.png
|
||||
|
||||
#statistics dimension:
|
||||
# name: word count
|
||||
# type: word count
|
||||
# display: list
|
||||
|
||||
#statistics dimension:
|
||||
# name: toughness2
|
||||
# script: card.toughness
|
||||
@@ -1024,14 +1029,20 @@ statistics dimension:
|
||||
statistics category:
|
||||
name: color / rarity
|
||||
type: stack
|
||||
dimension: card color2
|
||||
dimension: card color
|
||||
dimension: rarity
|
||||
|
||||
#statistics category:
|
||||
# name: power / toughness
|
||||
# type: scatter
|
||||
# dimension: power2
|
||||
# dimension: toughness2
|
||||
statistics category:
|
||||
name: power / toughness
|
||||
type: scatter
|
||||
dimension: power
|
||||
dimension: toughness
|
||||
|
||||
statistics category:
|
||||
name: color / cost
|
||||
type: scatter
|
||||
dimension: card color
|
||||
dimension: converted mana cost
|
||||
|
||||
#statistics field:
|
||||
# name: creature type
|
||||
|
||||
+91
-17
@@ -18,6 +18,7 @@ DECLARE_TYPEOF_COLLECTION(GraphP);
|
||||
DECLARE_TYPEOF_COLLECTION(int);
|
||||
DECLARE_TYPEOF_COLLECTION(vector<int>);
|
||||
DECLARE_TYPEOF_COLLECTION(String);
|
||||
DECLARE_TYPEOF_COLLECTION(UInt);
|
||||
DECLARE_TYPEOF(map<String COMMA UInt>);
|
||||
|
||||
template <typename T> inline T sgn(T v) { return v < 0 ? -1 : 1; }
|
||||
@@ -200,7 +201,7 @@ int find_bar_graph_column(double width, double x, int count) {
|
||||
double width_space = width / count; // including spacing
|
||||
double space = width_space / 5;
|
||||
// Find column in which the point could be located
|
||||
int col = int(x / width_space);
|
||||
int col = floor(x / width_space);
|
||||
if (col < 0 || col >= count) return -1; // not a column
|
||||
double in_col = x - col * width_space;
|
||||
if (in_col < space / 2) return -1; // left
|
||||
@@ -254,14 +255,14 @@ void BarGraph2D::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer
|
||||
GraphAxis& axis1 = axis1_data(); // the major axis
|
||||
GraphAxis& axis2 = axis2_data(); // the stacked axis
|
||||
int count = int(axis1.groups.size());
|
||||
// Bar sizes
|
||||
// Draw
|
||||
if (layer == LAYER_SELECTION) {
|
||||
// Highlight current column
|
||||
Color bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
||||
int cur1 = this->axis1 < current.size() ? current[this->axis1] : -1;
|
||||
int cur2 = this->axis2 < current.size() ? current[this->axis2] : -1;
|
||||
if (cur1 >= 0) {
|
||||
// draw that bar
|
||||
// draw selected bar
|
||||
int start = 0;
|
||||
int j = 0;
|
||||
FOR_EACH_CONST(g2, axis2.groups) {
|
||||
@@ -278,8 +279,8 @@ void BarGraph2D::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer
|
||||
}
|
||||
} else if (cur2 >= 0) {
|
||||
// entire row
|
||||
// TODO
|
||||
}
|
||||
// TODO
|
||||
} else if (layer == LAYER_VALUES) {
|
||||
// Draw bars
|
||||
dc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
@@ -396,6 +397,72 @@ int PieGraph::findItem(const RealPoint& pos, const RealRect& rect) const {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Scatter Plot
|
||||
|
||||
void ScatterGraph::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer) const {
|
||||
if (!data || data->axes.size() <= max(axis1,axis2)) return;
|
||||
// Rectangle for bars
|
||||
RealRect rect = dc.getInternalRect();
|
||||
GraphAxis& axis1 = axis1_data(); // the major axis
|
||||
GraphAxis& axis2 = axis2_data(); // the stacked axis
|
||||
RealSize size(rect.width / axis1.groups.size(), rect.height / axis2.groups.size()); // size for a single cell
|
||||
double step = min(size.width, size.height) / sqrt((double)max_value) / 2.01;
|
||||
// Draw
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
if (layer == LAYER_SELECTION) {
|
||||
Color bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
||||
int cur1 = this->axis1 < current.size() ? current[this->axis1] : -1;
|
||||
int cur2 = this->axis2 < current.size() ? current[this->axis2] : -1;
|
||||
if (cur1 >= 0 && cur2 >= 0) {
|
||||
UInt value = values[cur1 * axis2.groups.size() + cur2];
|
||||
if (value) {
|
||||
dc.SetBrush(lerp(bg,lerp(axis1.groups[cur1].color, axis2.groups[cur2].color, 0.5),0.5));
|
||||
dc.DrawCircle(RealPoint(rect.left() + cur1 * size.width, rect.bottom() - (cur2+1) * size.height) + size/2, sqrt((double)value) * step + 5);
|
||||
}
|
||||
} else if (cur1 >= 0) {
|
||||
dc.SetBrush(lerp(bg,axis1.groups[cur1].color,0.3));
|
||||
dc.DrawRectangle(RealRect(rect.x + cur1 * size.width, rect.y, size.width, rect.height));
|
||||
} else if (cur2 >= 0) {
|
||||
dc.SetBrush(lerp(bg,axis2.groups[cur2].color,0.3));
|
||||
dc.DrawRectangle(RealRect(rect.x, rect.bottom() - (cur2+1) * size.height, rect.width, size.height));
|
||||
}
|
||||
} else {
|
||||
size_t i = 0;
|
||||
double x = rect.left();
|
||||
FOR_EACH_CONST(g1, axis1.groups) {
|
||||
double y = rect.bottom() - size.height;
|
||||
FOR_EACH_CONST(g2, axis2.groups) {
|
||||
UInt value = values[i++];
|
||||
dc.SetBrush(lerp(g1.color, g2.color, 0.5));
|
||||
dc.DrawCircle(RealPoint(x,y) + size/2, sqrt((double)value) * step);
|
||||
y -= size.height;
|
||||
}
|
||||
x += size.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool ScatterGraph::findItem(const RealPoint& pos, const RealRect& rect, vector<int>& out) const {
|
||||
if (!data || data->axes.size() <= max(axis1,axis2)) return false;
|
||||
// clicked item
|
||||
GraphAxis& axis1 = axis1_data();
|
||||
GraphAxis& axis2 = axis2_data();
|
||||
int col = floor((pos.x - rect.x) / rect.width * axis1.groups.size());
|
||||
int row = floor((rect.bottom() - pos.y) / rect.height * axis2.groups.size());
|
||||
if (col < 0 || col >= (int)axis1.groups.size()) return false;
|
||||
if (row < 0 || row >= (int)axis2.groups.size()) return false;
|
||||
// done
|
||||
out.clear();
|
||||
out.insert(out.begin(), data->axes.size(), -1);
|
||||
out.at(this->axis1) = col;
|
||||
out.at(this->axis2) = row;
|
||||
return true;
|
||||
}
|
||||
void ScatterGraph::setData(const GraphDataP& d) {
|
||||
Graph2D::setData(d);
|
||||
// find maximum
|
||||
max_value = 0;
|
||||
FOR_EACH(v, values) {
|
||||
max_value = max(max_value, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Graph Legend
|
||||
@@ -407,6 +474,7 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const {
|
||||
GraphAxis& axis = axis_data();
|
||||
int count = int(axis.groups.size());
|
||||
// Draw
|
||||
dc.SetFont(*wxNORMAL_FONT);
|
||||
if (layer == LAYER_SELECTION) {
|
||||
// highlight selection
|
||||
} else if (layer != LAYER_AXES) {
|
||||
@@ -427,15 +495,18 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const {
|
||||
Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
||||
if (draw_lines) {
|
||||
dc.SetPen(lerp(bg, fg, 0.5));
|
||||
for (int i = 1 ; i <= count ; ++i) {
|
||||
dc.DrawLine(RealPoint(rect.x + i*width, rect.top()), RealPoint(rect.x + i*width, rect.bottom()));
|
||||
for (int i = 0 ; i < count ; ++i) {
|
||||
if (draw_lines == DRAW_LINES_BETWEEN) {
|
||||
dc.DrawLine(RealPoint(rect.x + (i+1.0)*width, rect.top()), RealPoint(rect.x + (i+1.0)*width, rect.bottom()));
|
||||
} else {
|
||||
dc.DrawLine(RealPoint(rect.x + (i+0.5)*width, rect.top()), RealPoint(rect.x + (i+0.5)*width, rect.bottom() + 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
// always draw axis line
|
||||
dc.SetPen(fg);
|
||||
dc.DrawLine(rect.topLeft(), rect.bottomLeft());
|
||||
} else {
|
||||
// TODO
|
||||
double height = rect.height / count; // width of an item
|
||||
// Draw labels
|
||||
double y = rect.bottom();
|
||||
@@ -443,7 +514,7 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const {
|
||||
// draw label, aligned bottom center
|
||||
RealSize text_size = dc.GetTextExtent(g.name);
|
||||
//dc.SetClippingRegion(RealRect(x + 2, rect.bottom() + 3, width - 4, text_size.height));
|
||||
dc.DrawText(g.name, align_in_rect(ALIGN_MIDDLE_RIGHT, text_size, RealRect(-3, y, 0, -height)));
|
||||
dc.DrawText(g.name, align_in_rect(ALIGN_MIDDLE_RIGHT, text_size, RealRect(-4, y, 0, -height)));
|
||||
//dc.DestroyClippingRegion();
|
||||
y -= height;
|
||||
}
|
||||
@@ -452,8 +523,12 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const {
|
||||
Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
||||
if (draw_lines) {
|
||||
dc.SetPen(lerp(bg, fg, 0.5));
|
||||
for (int i = 1 ; i <= count ; ++i) {
|
||||
dc.DrawLine(RealPoint(rect.left(), rect.bottom() - i*height), RealPoint(rect.right(), rect.bottom() - i*height));
|
||||
for (int i = 0 ; i < count ; ++i) {
|
||||
if (draw_lines == DRAW_LINES_BETWEEN) {
|
||||
dc.DrawLine(RealPoint(rect.left(), rect.bottom() - (i+1.0)*height), RealPoint(rect.right(), rect.bottom() - (i+1.0)*height));
|
||||
} else {
|
||||
dc.DrawLine(RealPoint(rect.left() - 2, rect.bottom() - (i+0.5)*height), RealPoint(rect.right(), rect.bottom() - (i+0.5)*height));
|
||||
}
|
||||
}
|
||||
}
|
||||
// always draw axis line
|
||||
@@ -466,10 +541,10 @@ int GraphLabelAxis::findItem(const RealPoint& pos, const RealRect& rect) const {
|
||||
GraphAxis& axis = axis_data();
|
||||
int col;
|
||||
if (direction == HORIZONTAL) {
|
||||
col = (pos.x - rect.x) / rect.width * axis.groups.size();
|
||||
col = floor((pos.x - rect.x) / rect.width * axis.groups.size());
|
||||
if (pos.y < rect.bottom()) return -1;
|
||||
} else {
|
||||
col = (pos.y - rect.y) / rect.height * axis.groups.size();
|
||||
col = floor((rect.bottom() - pos.y) / rect.height * axis.groups.size());
|
||||
if (pos.x > rect.left()) return -1;
|
||||
}
|
||||
if (col < 0 || col >= (int)axis.groups.size()) return -1;
|
||||
@@ -582,12 +657,11 @@ void GraphControl::setLayout(GraphType type) {
|
||||
graph = new_intrusive5<GraphWithMargins>(combined, 23,8,7,20);
|
||||
break;
|
||||
} case GRAPH_TYPE_SCATTER: {
|
||||
// TODO
|
||||
intrusive_ptr<GraphContainer> combined(new GraphContainer());
|
||||
combined->add(new_intrusive4<GraphLabelAxis>(0, HORIZONTAL, false, true));
|
||||
combined->add(new_intrusive4<GraphLabelAxis>(1, VERTICAL, false, true));
|
||||
//combined->add(new_intrusive2<BarGraph2D>(0,1));
|
||||
graph = new_intrusive5<GraphWithMargins>(combined, 23,8,7,20);
|
||||
combined->add(new_intrusive4<GraphLabelAxis>(0, HORIZONTAL, false, DRAW_LINES_MID));
|
||||
combined->add(new_intrusive4<GraphLabelAxis>(1, VERTICAL, false, DRAW_LINES_MID));
|
||||
combined->add(new_intrusive2<ScatterGraph>(0,1));
|
||||
graph = new_intrusive5<GraphWithMargins>(combined, 80,8,7,20);
|
||||
break;
|
||||
} default:
|
||||
graph = GraphP();
|
||||
|
||||
@@ -181,6 +181,17 @@ class PieGraph : public Graph1D {
|
||||
virtual int findItem(const RealPoint& pos, const RealRect& rect) const;
|
||||
};
|
||||
|
||||
/// A scatter plot
|
||||
class ScatterGraph : public Graph2D {
|
||||
public:
|
||||
inline ScatterGraph(size_t axis1, size_t axis2) : Graph2D(axis1, axis2) {}
|
||||
virtual void draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer) const;
|
||||
virtual bool findItem(const RealPoint& pos, const RealRect& rect, vector<int>& out) const;
|
||||
virtual void setData(const GraphDataP& d);
|
||||
private:
|
||||
UInt max_value; ///< highest value
|
||||
};
|
||||
|
||||
/// The legend, used for pie graphs
|
||||
class GraphLegend : public Graph1D {
|
||||
public:
|
||||
@@ -192,11 +203,17 @@ class GraphLegend : public Graph1D {
|
||||
//class GraphTable {
|
||||
//};
|
||||
|
||||
enum DrawLines
|
||||
{ DRAW_LINES_NO
|
||||
, DRAW_LINES_BETWEEN
|
||||
, DRAW_LINES_MID
|
||||
};
|
||||
|
||||
/// Draws a horizontal/vertical axis for group labels
|
||||
class GraphLabelAxis : public Graph1D {
|
||||
public:
|
||||
inline GraphLabelAxis(size_t axis, Direction direction, bool rotate = false, bool draw_lines = false)
|
||||
: Graph1D(axis), direction(direction), rotate(rotate), draw_lines(draw_lines)
|
||||
inline GraphLabelAxis(size_t axis, Direction direction, bool rotate = false, DrawLines draw_lines = DRAW_LINES_NO, bool label = false)
|
||||
: Graph1D(axis), direction(direction), rotate(rotate), draw_lines(draw_lines), label(label)
|
||||
{}
|
||||
virtual void draw(RotatedDC& dc, int current, DrawLayer layer) const;
|
||||
virtual int findItem(const RealPoint& pos, const RealRect& rect) const;
|
||||
@@ -204,7 +221,8 @@ class GraphLabelAxis : public Graph1D {
|
||||
Direction direction;
|
||||
int levels;
|
||||
bool rotate;
|
||||
bool draw_lines;
|
||||
DrawLines draw_lines;
|
||||
bool label;
|
||||
};
|
||||
|
||||
/// Draws an a vertical axis for counts
|
||||
|
||||
@@ -172,6 +172,11 @@ void RotatedDC::DrawRoundedRectangle(const RealRect& r, double radius) {
|
||||
dc.DrawRoundedRectangle(r_ext.x, r_ext.y, r_ext.width, r_ext.height, trS(radius));
|
||||
}
|
||||
|
||||
void RotatedDC::DrawCircle(const RealPoint& center, double radius) {
|
||||
wxPoint p = tr(center);
|
||||
dc.DrawCircle(p.x + 1, p.y + 1, trS(radius));
|
||||
}
|
||||
|
||||
/// Convert radians to degrees
|
||||
double rad_to_deg(double rad) { return rad * (180.0 / M_PI); }
|
||||
/// Convert degrees to radians
|
||||
|
||||
@@ -146,6 +146,7 @@ class RotatedDC : public Rotation {
|
||||
void DrawLine (const RealPoint& p1, const RealPoint& p2);
|
||||
void DrawRectangle(const RealRect& r);
|
||||
void DrawRoundedRectangle(const RealRect& r, double radius);
|
||||
void DrawCircle(const RealPoint& center, double radius);
|
||||
/// Draw an arc of an ellipse, angles are in radians
|
||||
void DrawEllipticArc(const RealPoint& center, const RealSize& size, double start, double end);
|
||||
/// Draw spokes of an ellipse
|
||||
|
||||
Reference in New Issue
Block a user