28 #include "dimension.rcd" 29 #include "engNotation.rcd" 30 #include "hypercube.xcd" 34 #include "tensorInterface.xcd" 35 #include "tensorVal.rcd" 36 #include "tensorVal.xcd" 37 #include "variable.rcd" 44 #include <boost/locale.hpp> 45 #include <boost/filesystem.hpp> 54 void VariableBase::addPorts()
57 for (
auto& i: m_ports)
58 assert(i.use_count()==1);
62 m_ports.emplace_back(make_shared<Port>(*
this));
63 for (
size_t i=1; i<numPorts(); ++i)
64 m_ports.emplace_back(make_shared<InputPort>(*
this));
67 bool VariableBase::inputWired()
const 69 if (
auto p=ports(1).lock())
70 return !p->wires().empty();
74 std::vector<std::string> VariableBase::accessibleVars()
const 76 if (
auto g=
group.lock())
77 return g->accessibleVars();
86 const double z=zoomFactor();
91 if (rv.
height()<0.5*iHeight()) hpy=-z*0.5*iHeight();
92 const double dx=xx-x(), dy=yy-y();
93 if (type()!=constant && hypot(dx - r.
x(hpx,hpy), dy-r.
y(hpx,hpy)) < 5)
94 return ClickType::inItem;
97 return Item::clickType(xx,yy);
113 throw error(
"unknown variable type %s", typeName(type).c_str());
119 if (type==this->type())
return;
120 if (
auto vv=vValue())
121 if (type==vv->type())
122 if (
auto g=
group.lock())
123 for (
auto& i: g->items)
135 float VariableBase::zoomFactor()
const 138 if (
auto g=
group.lock())
139 return g->edgeScale();
141 if (
auto g=dynamic_cast<GodleyIcon*>(controller.lock().get()))
142 return g->scaleFactor() * Item::zoomFactor();
143 return Item::zoomFactor();
146 shared_ptr<VariableValue> VariableBase::vValue()
const 149 if (vv!=
minsky().variableValues.end())
154 vector<unsigned> VariableBase::dims()
const 158 if (
auto v=vValue())
return v->hypercube().dims();
164 vector<string> VariableBase::dimLabels()
const 166 if (
auto v=vValue())
return v->hypercube().dimLabels();
176 std::string VariableBase::valueIdInCurrentScope(
const std::string& nm)
const 181 bool VariableBase::local()
const 186 string VariableBase::name()
const 188 if (m_name==
":_")
return "";
192 return m_name.substr(1);
194 return utf_to_utf<char>(m_name);
205 for (
auto p=x.find_first_of(
specialLatex); p!=string::npos;
208 if (p==0||x[p-1]!=
'\\')
209 quotedName+=x.substr(next,p-next)+
'\\'+x[p];
211 quotedName+=x.substr(next,p-next+1);
214 return quotedName+x.substr(next);
218 string VariableBase::name(
const std::string& name)
221 if (name.empty() || name==
":")
return name;
224 for (
auto p=name.find_first_of(
specialLatex); p!=string::npos;
226 if (p==0||name[p-1]!=
'\\')
233 ensureValueExists(tmpVV.get(),name);
235 cachedNameRender.reset();
237 if (
auto controllingItem=controller.lock())
239 controllingItem->updateBoundingBox();
243 bool VariableBase::ioVar()
const 244 {
return dynamic_cast<Group*
>(controller.lock().get());}
247 void VariableBase::ensureValueExists(
VariableValue* vv,
const std::string&)
const 251 if (valueId.length()>1 &&
valueId.substr(
valueId.length()-2)!=
":_" &&
270 string VariableBase::init()
const 273 if (value!=
minsky().variableValues.end()) {
275 if (type()==integral)
278 auto i=
dynamic_cast<IntOp*
>(controller.lock().get());
279 if (!i && !m_ports[1]->wires().empty())
280 i=dynamic_cast<IntOp*>(&(m_ports[1]->wires()[0]->from()->item()));
281 if (i && i->portsSize()>2 && !i->ports(2).lock()->wires().empty())
282 if (
auto lhsVar=i->ports(2).lock()->wires()[0]->from()->item().variableCast())
283 if (
auto vv=vValue())
284 if (
auto lhsVv=lhsVar->vValue())
286 if (vv->init()!=lhsVv->init()) vv->init(lhsVv->init());
288 return value->second->init();
293 string VariableBase::init(
const string& x)
295 ensureValueExists(
nullptr,
"");
303 if (type()==constant || type()==parameter ||
307 cachedNameRender.reset();
317 double VariableBase::value()
const 321 if (v==vvs.end() || !v->second)
return 0;
322 return v->second->value();
325 double VariableBase::value(
const double& x)
330 if (type()==constant)
331 cachedNameRender.
reset();
338 const std::string& VariableBase::detailedText()
const 340 if (
auto vv=vValue())
341 return vv->detailedText;
345 const std::string& VariableBase::detailedText(
const std::string& x)
347 if (
auto vv=vValue())
348 return vv->detailedText=x;
352 const std::string& VariableBase::tooltip()
const 354 if (
auto vv=vValue())
359 const std::string& VariableBase::tooltip(
const std::string& x)
361 if (
auto vv=vValue())
362 return vv->tooltip=x;
366 int VariableBase::stockVarsPassed=0;
367 int VariableBase::varsPassed=0;
369 Units VariableBase::units(
bool check)
const 374 if (unitsCtr-stockVarsPassed>=1)
377 throw_error(
"Cycle detected on wiring network");
383 if (it!=
minsky().variableValues.end())
386 if (vv->unitsCached)
return vv->units;
392 unique_ptr<IncrDecrCounter> svp;
401 if (
auto i=dynamic_cast<IntOp*>(controller.lock().get()))
402 units=i->units(check);
403 else if (
auto g=dynamic_cast<GodleyIcon*>(controller.lock().get()))
404 units=g->stockVarUnits(name(),check);
407 if (check && units.
str()!=vv->units.str())
409 if (
auto i=controller.lock())
410 i->throw_error(
"Inconsistent units "+units.
str()+
"≠"+vv->units.str());
413 if (check && controller.lock())
416 if (!fc.
name.empty())
422 (&GroupItems::items, [&vid](
const ItemPtr& i){
423 if (
auto v=i->variableCast())
424 return v->valueId()==vid;
426 if (units!=initVar->units(check))
427 throw_error(
"Inconsistent units in initial conditions");
434 if (m_ports.size()>1 && !m_ports[1]->wires().empty())
436 assert(m_ports[1]->wires()[0]->from());
437 vv->units=m_ports[1]->wires()[0]->from()->item().units(check);
440 vv->units=v->units(check);
442 vv->units.normalise();
443 vv->unitsCached=
true;
449 void VariableBase::setUnits(
const string& x)
const 457 void VariableBase::exportAsCSV(
const std::string& filename,
bool tabular)
const 460 if (value!=
minsky().variableValues.end())
461 value->second->exportAsCSV(filename, name(), tabular);
464 void VariableBase::importFromCSV(
const vector<string>& filenames,
const DataSpecSchema& spec)
const 466 if (
auto v=vValue()) {
467 v->csvDialog.spec=spec;
468 if (!filenames.empty())
469 v->csvDialog.url=filenames[0];
472 if (!v->hypercube().dimsAreDistinct())
473 throw_error(
"Axes of imported data should all have distinct names");
478 void VariableBase::reloadCSV()
481 if (!v->csvDialog.url.empty())
486 void VariableBase::destroyFrame()
488 if (
auto vv=vValue())
489 vv->csvDialog.destroyFrame();
492 void VariableBase::insertControlled(
Selection& selection)
513 if (tmp && tmp->type()!=type)
515 reset(VariableBase::create(type));
517 for (
size_t i=0; i<
get()->portsSize() && i< tmp->portsSize(); ++i)
518 for (
auto w: tmp->ports(i).lock()->wires())
520 if (
get()->ports(i).lock()->input())
521 w->moveToPorts(w->from(),
get()->ports(i).lock());
523 w->moveToPorts(
get()->ports(i).lock(), w->to());
525 get()->ensureValueExists(
nullptr,
"");
529 bool VariableBase::visible()
const 533 if ((!g || !g->group.lock()) && g==controller.lock())
return true;
534 if (controller.lock())
return false;
535 return Item::visible();
538 bool VariableBase::sliderVisible()
const 541 return enableSlider() &&
542 ((!vv && type()==parameter) ||
543 (vv && vv->size()==1 &&
544 (type()==parameter ||
549 void VariableBase::adjustSliderBounds()
const 551 if (
auto vv=vValue())
552 vv->adjustSliderBounds();
555 bool VariableBase::onKeyPress(
int keySym,
const std::string&,
int)
559 case 0xff52:
case 0xff53:
560 if (
auto vv=vValue()) vv->incrSlider(1);
563 case 0xff51:
case 0xff54:
564 if (
auto vv=vValue()) vv->incrSlider(-1);
572 std::string VariableBase::definition()
const 579 if (type()!=VariableType::parameter)
581 if (varDAG && varDAG->rhs && varDAG->type!=VariableType::constant && varDAG->type!=VariableType::integral)
582 o << varDAG->rhs->latex();
589 bool VariableBase::miniPlotEnabled(
bool enabled)
593 miniPlot=make_shared<ecolab::Plot>();
594 miniPlot->plotType=ecolab::Plot::PlotType::bar;
601 void VariableBase::resetMiniPlot()
603 if (miniPlotEnabled())
607 bool VariableBase::onMouseMotion(
float x,
float y)
609 if (
auto vv=vValue())
612 const double rw=fabs(zoomFactor()*(rv.
width()<iWidth()? 0.5*iWidth() : rv.
width())*
cos(rotation()*
M_PI/180));
613 const double sliderPos=(x-this->x())* (vv->sliderMax-vv->sliderMin)/rw+0.5*(vv->sliderMin+vv->sliderMax);
614 const double sliderHatch=sliderPos-fmod(sliderPos,vv->sliderStep);
615 vv->sliderSet(sliderHatch);
620 if (
minsky().reset_flag())
626 double VariableBase::sliderMin()
const 628 if (
auto vv=vValue())
629 return vv->sliderMin;
634 double VariableBase::sliderMin(
double x)
const 636 if (
auto vv=vValue())
637 return vv->sliderMin=x;
641 double VariableBase::sliderMax()
const 643 if (
auto vv=vValue())
644 return vv->sliderMax;
648 double VariableBase::sliderMax(
double x)
const 650 if (
auto vv=vValue())
651 return vv->sliderMax=x;
655 double VariableBase::sliderStep()
const 657 if (
auto vv=vValue())
658 return vv->sliderStep;
662 double VariableBase::sliderStep(
double x)
const 664 if (
auto vv=vValue())
665 return vv->sliderStep=x;
669 bool VariableBase::sliderStepRel()
const 671 if (
auto vv=vValue())
672 return vv->sliderStepRel;
676 bool VariableBase::sliderStepRel(
bool x)
const 678 if (
auto vv=vValue())
679 return vv->sliderStepRel=x;
683 bool VariableBase::enableSlider()
const 685 if (
auto vv=vValue())
686 return vv->enableSlider;
690 bool VariableBase::enableSlider(
bool x)
const 692 if (
auto vv=vValue())
693 return vv->enableSlider=x;
698 void VariableBase::draw(cairo_t *cairo)
const 700 auto [angle,
flipped]=rotationAsRadians();
701 const float z=zoomFactor();
706 auto l_cachedNameRender=cachedNameRender;
707 if (!l_cachedNameRender || cairo!=cachedNameRender->cairoContext())
709 l_cachedNameRender=cachedNameRender=std::make_shared<RenderVariable>(*
this,cairo);
710 l_cachedNameRender->setFontSize(12.0);
719 const double w=std::max(l_cachedNameRender->width(), 0.5f*iWidth());
720 const double h=std::max(l_cachedNameRender->height(), 0.5f*iHeight());
721 const double hoffs=l_cachedNameRender->top();
723 unique_ptr<cairo::Path> clipPath;
725 const CairoSave cs(cairo);
726 cairo_scale(cairo, z,z);
727 cairo_move_to(cairo,r.
x(-w+1,-h-hoffs+2), r.
y(-w+1,-h-hoffs+2));
729 const CairoSave cs(cairo);
731 cairo_set_source_rgb(cairo,0,0,1);
732 l_cachedNameRender->show();
736 if (miniPlot && vv && vv->size()==1)
742 miniPlot->addPt(0,cachedTime,vv->value());
743 miniPlot->setMinMax();
745 const CairoSave cs(cairo);
746 cairo_translate(cairo,-w,-h);
747 miniPlot->draw(cairo,2*w,2*h);
754 if (type()!=constant && !ioVar() && vv && vv->size()==1 && vv->idxInRange())
756 auto l_cachedMantissa=cachedMantissa;
757 auto l_cachedExponent=cachedExponent;
758 if (!l_cachedMantissa || l_cachedMantissa->cairoContext()!=cairo)
760 l_cachedMantissa=cachedMantissa=make_shared<Pango>(cairo);
761 l_cachedMantissa->setFontSize(6.0);
762 l_cachedExponent=cachedExponent=make_shared<Pango>(cairo);
763 l_cachedExponent->setFontSize(6.0);
768 if (value()!=cachedValue)
771 if (!
isnan(value())) {
773 l_cachedMantissa->setMarkup
777 -log10(vv->maxSliderSteps()):
778 log10(vv->value()/vv->maxSliderSteps())
781 l_cachedMantissa->setMarkup(
mantissa(val));
783 else if (
isinf(value())) {
784 if (signbit(value())) l_cachedMantissa->setMarkup(
"-∞");
785 else l_cachedMantissa->setMarkup(
"∞");
788 l_cachedMantissa->setMarkup(
"???");
793 cairo_move_to(cairo,r.
x(w-l_cachedMantissa->width()-2,-h-hoffs+2),
794 r.
y(w-l_cachedMantissa->width()-2,-h-hoffs+2));
795 l_cachedMantissa->show();
797 if (val.engExp!=0 && !
isnan(value()))
799 cairo_move_to(cairo,r.
x(w-l_cachedExponent->width()-2,0),r.
y(w-l_cachedExponent->width()-2,0));
800 l_cachedExponent->show();
807 const cairo::CairoSave cs(cairo);
808 cairo_rotate(cairo, angle);
812 case constant:
case parameter:
813 cairo_set_source_rgb(cairo,0,0,1);
816 cairo_set_source_rgb(cairo,1,0,0);
819 cairo_move_to(cairo,-w,-h);
821 cairo_line_to(cairo,-w+2,0);
822 cairo_line_to(cairo,-w,h);
823 cairo_line_to(cairo,w,h);
824 cairo_line_to(cairo,w+2,0);
825 cairo_line_to(cairo,w,-h);
826 cairo_close_path(cairo);
827 clipPath.reset(
new cairo::Path(cairo));
832 const CairoSave cs(cairo);
833 cairo_set_source_rgb(cairo,0,0,0);
838 catch (
const error&) {}
843 const double x0=z*w, y0=0, x1=-z*w+2, y1=0;
844 const double sa=
sin(angle), ca=
cos(angle);
845 if (!m_ports.empty())
846 m_ports[0]->moveTo(x()+(x0*ca-y0*sa),
848 if (m_ports.size()>1)
849 m_ports[1]->moveTo(x()+(x1*ca-y1*sa),
854 if (mouseFocus || (ioVar() && g && g->mouseFocus))
856 const cairo::CairoSave cs(cairo);
858 displayTooltip(cairo,tooltip());
859 if (onResizeHandles) drawResizeHandles(cairo);
862 cairo_new_path(cairo);
863 clipPath->appendToCurrent(cairo);
866 if (selected) drawSelected(cairo);
871 const float invZ=1/zoomFactor();
872 moveTo(0.5*(b.
x0+b.
x1), 0.5*(b.
y0+b.
y1));
873 iWidth(abs(b.
x1-b.
x0)*invZ);
874 iHeight(abs(b.
y1-b.
y0)*invZ);
877 void VariablePtr::makeConsistentWithValue()
882 int VarConstant::nextId=0;
#define M_PI
some useful geometry types, defined from boost::geometry
std::string expMultiplier(int exp)
represents items that have been selected
EngNotation engExp(double value)
return formatted mantissa and exponent in engineering format
void resetValue(VariableValue &) const
reset a give variable value to it's initial condition, in this context
bool pushHistory()
push current model state onto history if it differs from previous
VariableValues variableValues
exception-safe increment/decrement of a counter in a block
string quoteLaTeX(const std::string &x)
void reset()
reset all variableValues to their initial conditions
represents rectangular region of a lasso operation
float y(float x, float y) const
size_t scope(const string &name)
extract scope from a qualified variable name
void retype(VariableBase::Type type)
changes type of variable to type
std::shared_ptr< Item > ItemPtr
constexpr float sliderHandleRadius
const char specialLatex[]
string valueId(const string &name)
construct a valueId from fully qualified name @ name should not be canonicalised
rotate (x,y) by rot (in degrees) around the origin (x0, y0) can be used for rotating multiple points ...
a shared_ptr that default constructs a default target, and is always valid
const std::string & init() const
bool flipped(double rotation)
returns if the angle (in degrees) is in the second or third quadrant
static string emptyString
CLASSDESC_ACCESS_EXPLICIT_INSTANTIATION(minsky::VariablePtr)
represents the units (in sense of dimensional analysis) of a variable.
VariablePtr definingVar(const std::string &valueId) const
returns reference to variable defining (ie input wired) for valueId
const Minsky & cminsky()
const version to help in const correctness
std::string mantissa(double value, const EngNotation &, int digits=3)
void evalEquations(double result[], double, const double vars[])
void loadValueFromCSVFile(VariableValue &v, const vector< string > &filenames, const DataSpec &spec)
load a variableValue from a list of files according to data spec
string canonicalName(const string &name)
convert a raw name into a canonical name - this is not idempotent.
VariableDAGPtr getNodeFromVar(const VariableBase &v)
void ensureItemInserted(const ItemPtr &item)
check if item already present, and if not, inserts item delegates to ensureGroupInserted if passed a ...
represents a numerical coefficient times a variable (a "flow")
bool isValueId(const string &name)
check that name is a valid valueId (useful for assertions)
void populateMissingDimensionsFromVariable(const VariableValue &, bool &incompatibleMessageDisplayed)
populate missing dimensions from a variableValue
void convertVarType(const std::string &name, VariableType::Type type)
Converts variable(s) named by name into a variable of type type.
ostringstream getDefFromIntVar(const VariableBase &v)
float x(float x, float y) const
float height() const
half height of unrotated image
float width() const
half width of unrotated image