22 #include "phillipsDiagram.rcd" 23 #include "phillipsDiagram.xcd" 26 using ecolab::cairo::CairoSave;
35 const CairoSave cs(cairo);
42 const double lw=5*abs(
value)/maxV;
43 lineWidth=std::max(1.0, lw);
44 static const double dashLength=3;
46 cairo_set_dash(cairo,&dashLength,1,0);
48 cairo_set_line_width(cairo, lineWidth);
60 const CairoSave cs(cairo);
66 cairo_set_source_rgba(cairo,0,0,1,0.3);
67 cairo_rectangle(cairo,-0.6*w,0.5*h,1.2*w,-
f*h);
71 cairo_set_source_rgba(cairo,1,0,0,0.3);
72 cairo_rectangle(cairo,-0.6*w,-0.5*h,1.2*w,-
f*h);
81 if (!surface.get())
return false;
82 auto cairo=surface->cairo();
83 const CairoSave cs(cairo);
84 cairo_translate(cairo,
x,
y);
87 const CairoSave cs(cairo);
88 cairo_identity_matrix(cairo);
89 cairo_translate(cairo,i.second.x()+
x, i.second.y()+
y);
99 decltype(
stocks) newStocks;
100 decltype(
flows) newFlows;
103 if (
auto g=dynamic_cast<GodleyIcon*>(it->get())) {
104 for (
auto& v: g->stockVars())
107 auto oldStock=
stocks.find(v->valueId());
108 if (oldStock!=
stocks.end())
110 newStock->second.moveTo(oldStock->second.x(), oldStock->second.y());
111 newStock->second.rotation(oldStock->second.rotation());
114 for (
unsigned r=1; r<g->table.rows(); ++r) {
115 if (g->table.initialConditionRow(r))
continue;
116 map<string, vector<pair<FlowCoef, string>>> sources, destinations;
117 for (
size_t c=1; c<g->table.cols(); c++)
119 const FlowCoef fc(g->table.cell(r,c));
122 auto payload=make_pair(
FlowCoef(fc.coef,g->table.cell(0,c)),g->table.cell(r,0));
123 if ((fc.coef>0 && !g->table.signConventionReversed(c))
124 || (fc.coef<0 && g->table.signConventionReversed(c)))
125 sources[fc.name].emplace_back(payload);
127 destinations[fc.name].emplace_back(payload);
130 for (
auto& i: sources)
131 for (
auto& [s,sd]: i.second)
132 for (
auto& [d,description]: destinations[i.first])
135 if (s.coef*d.coef<0) swap(ss,dd);
136 auto& source=newStocks[g->valueId(ss.name)];
137 auto& dest=newStocks[g->valueId(dd.name)];
138 auto flow=newFlows.emplace(make_pair(g->valueId(dd.name),g->valueId(ss.name)),
PhillipsFlow(dest.ports(0), source.ports(1))).first;
139 flow->second.addTerm(abs(s.coef*d.coef), i.first);
140 flow->second.tooltip((!flow->second.tooltip().empty()?
";":
"")+description);
141 if (
auto oldFlow=
flows.find(flow->first); oldFlow!=
flows.end())
142 flow->second.coords(oldFlow->second.coords());
150 if (newStocks.empty())
158 double angle=0, delta=2*
M_PI/newStocks.size();
161 auto h=newStocks.begin()->second.height();
162 auto maxW=newStocks.begin()->second.width();
163 for (
auto& i: newStocks) maxW=max(maxW,i.second.width());
165 auto r=h/delta + 0.5*maxW;
167 for (
auto& i: newStocks)
169 if (!
stocks.contains(i.first))
171 i.second.moveTo(r*(
cos(angle)+1)+maxW+50,r*(
sin(angle)+1)+maxW+50);
172 i.second.rotation(angle*180.0/
M_PI);
177 flows.swap(newFlows);
185 x-=this->
x; y-=this->
y;
187 if (i.second.contains(
x,
y))
194 if (i.second.near(
x,
y))
214 x-=this->
x; y-=this->
y;
235 const bool mf=i.second.near(
x,
y);
236 if (mf!=i.second.mouseFocus)
238 i.second.mouseFocus=mf;
246 x-=this->
x; y-=this->
y;
248 if (i.second.contains(
x,
y))
#define M_PI
some useful geometry types, defined from boost::geometry
PhillipsFlow * flowBeingEdited
bool pushHistory()
push current model state onto history if it differs from previous
void draw(cairo_t *cairo) const override
draw this item into a cairo context
virtual double value() const override
< set the initial value for this variable
PhillipsStock * stockBeingRotated
static std::map< Units, double > maxFlow
static std::map< Units, double > maxStock
void mouseMove(float x, float y) override
float zoomFactor() const override
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky's state cha...
bool redraw(int, int, int width, int height) override
std::vector< ItemPtr > Items
void mouseDown(float x, float y) override
std::map< std::pair< std::string, std::string >, PhillipsFlow > flows
std::map< std::string, PhillipsStock > stocks
boost::geometry::model::d2::point_xy< float > Point
const Minsky & cminsky()
const version to help in const correctness
represents a numerical coefficient times a variable (a "flow")
void init() override
populate phillips diagram from Godley tables in model
PhillipsStock * stockBeingMoved
void startRotatingItem(float x, float y)
bool mouseFocus
true if target of a mouseover
Exclude< Point > rotateOrigin
void draw(cairo_t *cairo, bool reverseArrow=false) const
draw this item into a cairo context
void moveTo(float x, float y)
CLASSDESC_ACCESS_EXPLICIT_INSTANTIATION(minsky::PhillipsDiagram)
void mouseUp(float x, float y) override
void draw(cairo_t *) const override
Minsky & minsky()
global minsky object
void editHandle(unsigned position, float x, float y)
float y
position for panning