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> 47 using boost::filesystem::file_size;
57 namespace VarAccessors
69 void VariableBase::addPorts()
73 assert(i.use_count()==1);
77 m_ports.emplace_back(make_shared<Port>(*
this));
79 m_ports.emplace_back(make_shared<InputPort>(*
this));
84 if (
auto p=
ports(1).lock())
85 return !p->wires().empty();
91 if (
auto g=
group.lock())
92 return g->accessibleVars();
105 double hpy=-z*rv.
height();
107 const double dx=xx-
x(), dy=yy-
y();
108 if (
type()!=
constant && hypot(dx - r.
x(hpx,hpy), dy-r.
y(hpx,hpy)) < 5)
128 throw error(
"unknown variable type %s",
typeName(
type).c_str());
136 if (
type==vv->type())
137 if (
auto g=
group.lock())
138 for (
auto& i: g->items)
153 if (
auto g=
group.lock())
154 return g->edgeScale();
156 if (
auto g=dynamic_cast<GodleyIcon*>(
controller.lock().get()))
164 if (vv!=
minsky().variableValues.end())
169 vector<unsigned> VariableBase::dims()
const 173 if (
auto v=
vValue())
return v->hypercube().dims();
181 if (
auto v=
vValue())
return v->hypercube().dimLabels();
203 if (
m_name==
":_")
return "";
209 return utf_to_utf<char>(
m_name);
220 for (
auto p=x.find_first_of(
specialLatex); p!=string::npos;
223 if (p==0||x[p-1]!=
'\\')
224 quotedName+=x.substr(next,p-next)+
'\\'+x[p];
226 quotedName+=x.substr(next,p-next+1);
229 return quotedName+x.substr(next);
241 if (p==0||
name[p-1]!=
'\\')
254 controllingItem->updateBoundingBox();
266 if (valueId.length()>1 &&
valueId.substr(
valueId.length()-2)!=
":_" &&
294 if (!i && !
m_ports[1]->wires().empty())
295 i=dynamic_cast<IntOp*>(&(
m_ports[1]->wires()[0]->from()->item()));
296 if (i && i->portsSize()>2 && !i->ports(2).lock()->wires().empty())
297 if (
auto lhsVar=i->ports(2).lock()->wires()[0]->from()->item().variableCast())
299 if (
auto lhsVv=lhsVar->vValue())
301 if (vv->init()!=lhsVv->init()) vv->init(lhsVv->init());
303 return value->second->init();
336 if (v==vvs.end() || !v->second)
return 0;
337 return v->second->value();
356 return vv->detailedText;
363 return vv->detailedText=
x;
377 return vv->tooltip=
x;
398 if (it!=
minsky().variableValues.end())
401 if (vv->unitsCached)
return vv->units;
407 unique_ptr<IncrDecrCounter> svp;
416 if (
auto i=dynamic_cast<IntOp*>(
controller.lock().get()))
417 units=i->units(check);
418 else if (
auto g=dynamic_cast<GodleyIcon*>(
controller.lock().get()))
422 if (check &&
units.
str()!=vv->units.str())
425 i->throw_error(
"Inconsistent units "+
units.
str()+
"≠"+vv->units.str());
431 if (!fc.
name.empty())
438 if (
auto v=i->variableCast())
439 return v->valueId()==vid;
441 if (
units!=initVar->units(check))
442 throw_error(
"Inconsistent units in initial conditions");
451 assert(
m_ports[1]->wires()[0]->from());
452 vv->units=
m_ports[1]->wires()[0]->from()->item().units(check);
455 vv->units=v->units(check);
457 vv->units.normalise();
458 vv->unitsCached=
true;
476 value->second->exportAsCSV(filename,
name(), tabular);
482 v->csvDialog.spec=spec;
483 if (!filenames.empty())
484 v->csvDialog.url=filenames[0];
487 if (!v->hypercube().dimsAreDistinct())
488 throw_error(
"Axes of imported data should all have distinct names");
495 vv->csvDialog.destroyFrame();
519 if (tmp && tmp->type()!=type)
523 for (
size_t i=0; i<
get()->portsSize() && i< tmp->portsSize(); ++i)
524 for (
auto w: tmp->ports(i).lock()->wires())
526 if (
get()->ports(i).lock()->input())
527 w->moveToPorts(w->from(),
get()->ports(i).lock());
529 w->moveToPorts(
get()->ports(i).lock(), w->to());
531 get()->ensureValueExists(
nullptr,
"");
539 if ((!g || !g->group.lock()) && g==
controller.lock())
return true;
549 (vv && vv->size()==1 &&
558 vv->adjustSliderBounds();
565 case 0xff52:
case 0xff53:
566 if (
auto vv=
vValue()) vv->incrSlider(1);
569 case 0xff51:
case 0xff54:
570 if (
auto vv=
vValue()) vv->incrSlider(-1);
588 o << varDAG->rhs->latex();
599 miniPlot=make_shared<ecolab::Plot>();
600 miniPlot->plotType=ecolab::Plot::PlotType::bar;
619 const double sliderPos=(
x-this->
x())* (vv->sliderMax-vv->sliderMin)/rw+0.5*(vv->sliderMin+vv->sliderMax);
620 const double sliderHatch=sliderPos-fmod(sliderPos,vv->sliderStep);
621 vv->sliderSet(sliderHatch);
626 if (
minsky().reset_flag())
635 return vv->sliderMin;
643 return vv->sliderMin=
x;
650 return vv->sliderMax;
657 return vv->sliderMax=
x;
664 return vv->sliderStep;
671 return vv->sliderStep=
x;
678 return vv->sliderStepRel;
685 return vv->sliderStepRel=
x;
692 return vv->enableSlider;
699 return vv->enableSlider=
x;
715 l_cachedNameRender=
cachedNameRender=std::make_shared<RenderVariable>(*
this,cairo);
716 l_cachedNameRender->setFontSize(12.0);
725 const double w=std::max(l_cachedNameRender->width(), 0.5f*
iWidth());
726 const double h=std::max(l_cachedNameRender->height(), 0.5f*
iHeight());
727 const double hoffs=l_cachedNameRender->top();
729 unique_ptr<cairo::Path> clipPath;
731 const CairoSave cs(cairo);
732 cairo_scale(cairo, z,z);
733 cairo_move_to(cairo,r.
x(-w+1,-h-hoffs+2), r.
y(-w+1,-h-hoffs+2));
735 const CairoSave cs(cairo);
737 cairo_set_source_rgb(cairo,0,0,1);
738 l_cachedNameRender->show();
742 if (
miniPlot && vv && vv->size()==1)
751 const CairoSave cs(cairo);
752 cairo_translate(cairo,-w,-h);
764 if (!l_cachedMantissa || l_cachedMantissa->cairoContext()!=cairo)
767 l_cachedMantissa->setFontSize(6.0);
769 l_cachedExponent->setFontSize(6.0);
779 l_cachedMantissa->setMarkup
783 -log10(vv->maxSliderSteps()):
784 log10(vv->value()/vv->maxSliderSteps())
787 l_cachedMantissa->setMarkup(
mantissa(val));
790 if (signbit(
value())) l_cachedMantissa->setMarkup(
"-∞");
791 else l_cachedMantissa->setMarkup(
"∞");
794 l_cachedMantissa->setMarkup(
"???");
799 cairo_move_to(cairo,r.
x(w-l_cachedMantissa->width()-2,-h-hoffs+2),
800 r.
y(w-l_cachedMantissa->width()-2,-h-hoffs+2));
801 l_cachedMantissa->show();
805 cairo_move_to(cairo,r.
x(w-l_cachedExponent->width()-2,0),r.
y(w-l_cachedExponent->width()-2,0));
806 l_cachedExponent->show();
813 const cairo::CairoSave cs(cairo);
814 cairo_rotate(cairo, angle);
819 cairo_set_source_rgb(cairo,0,0,1);
822 cairo_set_source_rgb(cairo,1,0,0);
825 cairo_move_to(cairo,-w,-h);
827 cairo_line_to(cairo,-w+2,0);
828 cairo_line_to(cairo,-w,h);
829 cairo_line_to(cairo,w,h);
830 cairo_line_to(cairo,w+2,0);
831 cairo_line_to(cairo,w,-h);
832 cairo_close_path(cairo);
833 clipPath.reset(
new cairo::Path(cairo));
838 const CairoSave cs(cairo);
839 cairo_set_source_rgb(cairo,0,0,0);
844 catch (
const error&) {}
849 const double x0=z*w, y0=0, x1=-z*w+2, y1=0;
850 const double sa=
sin(angle), ca=
cos(angle);
862 const cairo::CairoSave cs(cairo);
868 cairo_new_path(cairo);
869 clipPath->appendToCurrent(cairo);
#define M_PI
some useful geometry types, defined from boost::geometry
std::string expMultiplier(int exp)
represents items that have been selected
bool onKeyPress(int, const std::string &, int) override
respond to key press events
bool miniPlotEnabled() const
void drawPorts(cairo_t *cairo) const
classdesc::Exclude< std::shared_ptr< ecolab::Pango > > cachedExponent
virtual void displayTooltip(cairo_t *, const std::string &) const
display tooltip text, eg on mouseover
virtual std::size_t numPorts() const =0
void destroyFrame() override
clean up popup window structures on window close
void resetValue(VariableValue &) const
reset a give variable value to it's initial condition, in this context
std::string valueIdInCurrentScope(const std::string &nm) const
returns valueId for nm. If nm is not qualified, this variable's scope is used
static int stockVarsPassed
for detecting reentrancy in units()
bool pushHistory()
push current model state onto history if it differs from previous
VariableValues variableValues
virtual bool visible() const
whether this item is visible on the canvas.
void makeConsistentWithValue()
make variable's type consistent with the type of the valueId
exception-safe increment/decrement of a counter in a block
string quoteLaTeX(const std::string &x)
bool onResizeHandles
set to true to indicate mouse is ovcaler resize handles
represents rectangular region of a lasso operation
virtual double value() const override
< set the initial value for this variable
float y(float x, float y) const
size_t scope(const string &name)
extract scope from a qualified variable name
std::vector< std::string > accessibleVars() const
return a list of existing variables this could be connected to
void retype(VariableBase::Type type)
changes type of variable to type
std::shared_ptr< Item > ItemPtr
constexpr float sliderHandleRadius
std::size_t numPorts() const override
const char specialLatex[]
std::pair< double, bool > rotationAsRadians() const
return the rotation as radians, and whether rotation should have additional straight angle added for ...
string valueId(const string &name)
construct a valueId from fully qualified name @ name should not be canonicalised
double sliderMax() const
slider parameters
rotate (x,y) by rot (in degrees) around the origin (x0, y0) can be used for rotating multiple points ...
const std::string & tooltip() const override
a shared_ptr that default constructs a default target, and is always valid
const std::string & init() const
virtual Type type() const =0
BoundingBox bb
canvas bounding box.
void exportAsCSV(const std::string &filename, bool tabular) const
export this variable as a CSV file
virtual float zoomFactor() const
bool flipped(double rotation)
returns if the angle (in degrees) is in the second or third quadrant
void resize(const LassoBox &b) override
resize this item on the canvas
void update(const Item &x)
static VariableBase * create(Type type)
int unitsCtr
for detecting reentrancy in units()
struct TCLcmd::trap::init_t init
static string emptyString
bool sliderVisible() const
returns true if slider is to be drawn
CLASSDESC_ACCESS_EXPLICIT_INSTANTIATION(minsky::VariablePtr)
virtual ClickType::Type clickType(float x, float y) const
returns the clicktype given a mouse click at x, y.
float zoomFactor() const override
bool visible() const override
whether this item is visible on the canvas.
static void drawSelected(cairo_t *cairo)
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky's state cha...
classdesc::Exclude< std::weak_ptr< Item > > controller
reference to a controlling item - eg GodleyIcon, IntOp or a Group if an IOVar.
void insertControlled(Selection &selection) override
bool ioVar() const override
indicates this is a group I/O variable
static int varsPassed
for caching units calculation factory method
std::vector< std::string > dimLabels() const
labels along each axis
virtual std::string valueId() const
string used to link to the VariableValue associated with this
represents the units (in sense of dimensional analysis) of a variable.
void adjustSliderBounds()
void ensureValueExists(VariableValue *vv, const std::string &name) const
ensure an associated variableValue exists
static std::string typeName(int t)
VariablePtr definingVar(const std::string &valueId) const
returns reference to variable defining (ie input wired) for valueId
std::string m_canonicalName
latex processed and active stripped version of name
std::string definition() const
formula defining this variable
const Minsky & cminsky()
const version to help in const correctness
EngNotation engExp() const
return formatted mantissa and exponent in engineering format
const std::string & detailedText() const override
void evalEquations(double result[], double, const double vars[])
void throw_error(const std::string &) const
mark item on canvas, then throw
void importFromCSV(const std::vector< std::string > &filenames, const DataSpecSchema &spec) const
import CSV files, using spec
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)
bool selected
true if selected for cut, copy or group operation
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)
std::string init() const
the initial value of this variable
ClickType::Type clickType(float x, float y) const override
returns the clicktype given a mouse click at x, y.
virtual std::string name() const
variable displayed name
bool enableSlider() const
slider parameters
void populateMissingDimensionsFromVariable(const VariableValue &, bool &incompatibleMessageDisplayed)
populate missing dimensions from a variableValue
bool mouseFocus
true if target of a mouseover
std::string mantissa(const EngNotation &e, int digits=3) const
bool sliderStepRel() const
slider parameters
classdesc::Exclude< std::shared_ptr< ecolab::Pango > > cachedMantissa
classdesc::Exclude< std::shared_ptr< RenderVariable > > cachedNameRender
cached Pango objects
void convertVarType(const std::string &name, VariableType::Type type)
Converts variable(s) named by name into a variable of type type.
void moveTo(float x, float y)
void updateBoundingBox() override
virtual std::weak_ptr< Port > ports(std::size_t i) const
callback to be run when item deleted from group
double sliderStep() const
slider parameters
void draw(cairo_t *) const override
Minsky & minsky()
global minsky object
ostringstream getDefFromIntVar(const VariableBase &v)
float x(float x, float y) const
bool lhs() const
variable is on left hand side of flow calculation
std::shared_ptr< VariableValue > vValue() const
variableValue associated with this. nullptr if not associated with a variableValue ...
classdesc::Exclude< std::shared_ptr< ecolab::Plot > > miniPlot
miniature plot feature
void drawResizeHandles(cairo_t *cairo) const override
double sliderMin() const
slider parameters
void retype(VariableType::Type type)
attempt to replace this variable with variable of type.
float height() const
half height of unrotated image
void setUnits(const std::string &) const
float width() const
half width of unrotated image
bool onMouseMotion(float x, float y) override
respond to mouse motion events with button pressed