Minsky
operation.cc
Go to the documentation of this file.
1 /*
2  @copyright Steve Keen 2012
3  @author Russell Standish
4  This file is part of Minsky.
5 
6  Minsky is free software: you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Minsky is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with Minsky. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "minsky.h"
20 #include "geometry.h"
21 #include "operation.h"
22 #include "dataOp.h"
23 #include "userFunction.h"
24 #include "ravelWrap.h"
25 #include "str.h"
26 #include "cairoItems.h"
27 
28 #include <cairo_base.h>
29 #include <pango.h>
30 #include "minsky_epilogue.h"
31 
32 #include <math.h>
33 #include <sstream>
34 
35 #ifndef M_PI
36 #define M_PI 3.14159265358979323846
37 #endif
38 
39 using namespace ecolab;
40 using ecolab::cairo::CairoSave;
41 
42 namespace minsky
43 {
44  namespace
45  {
47  {
48  void combineInput(double& x, double y) const override {x+=y;}
50  };
51 
53  {
54  void combineInput(double& x, double y) const override {x*=y;}
56  double identity() const override {return 1;}
57  };
58 
60  {
61  void combineInput(double& x, double y) const override {if (y>x) x=y;}
63  double identity() const override {return -std::numeric_limits<double>::max();}
64  };
65 
67  {
68  void combineInput(double& x, double y) const override {if (y<x) x=y;}
70  double identity() const override {return std::numeric_limits<double>::min();}
71  };
73  {
74  void combineInput(double& x, double y) const override {x=(x>0.5)&&(y>0.5);}
76  double identity() const override {return 1;}
77  };
79  {
80  void combineInput(double& x, double y) const override {x=(x>0.5)||(y>0.5);}
82  };
83  }
84 
85  bool OperationBase::multiWire() const
86  {
87  switch (type())
88  {
89  case add: case subtract:
90  case multiply: case divide:
91  case min: case max:
92  case and_: case or_:
93  return true;
94  default:
95  return false;
96  }
97  }
98 
99  void OperationBase::addPorts()
100  {
101  m_ports.clear();
102  if (numPorts()>0)
103  m_ports.emplace_back(make_shared<Port>(*this));
104  for (size_t i=1; i<numPorts(); ++i)
105  switch (type())
106  {
107  case add: case subtract:
108  m_ports.emplace_back(make_shared<SumInputPort>(*this));
109  break;
110  case multiply: case divide:
111  m_ports.emplace_back(make_shared<MulInputPort>(*this));
112  break;
113  case min:
114  m_ports.emplace_back(make_shared<MinInputPort>(*this));
115  break;
116  case max:
117  m_ports.emplace_back(make_shared<MaxInputPort>(*this));
118  break;
119  case and_:
120  m_ports.emplace_back(make_shared<AndInputPort>(*this));
121  break;
122  case or_:
123  m_ports.emplace_back(make_shared<OrInputPort>(*this));
124  break;
125  case meld:
126  case merge:
127  m_ports.emplace_back(make_shared<MultiWireInputPort>(*this));
128  break;
129  default:
130  m_ports.emplace_back(make_shared<InputPort>(*this));
131  break;
132  }
133  }
134 
135  float OperationBase::scaleFactor() const
136  {
137  const float z=zoomFactor();
138  const float l=OperationBase::l*z, r=OperationBase::r*z,
139  h=OperationBase::h*z;
140  return std::max(1.0f,std::min(0.5f*iWidth()*z/std::max(l,r),0.5f*iHeight()*z/h));
141  }
142 
143  void OperationBase::drawUserFunction(cairo_t* cairo) const
144  {
145  // if rotation is in 1st or 3rd quadrant, rotate as
146  // normal, otherwise flip the text so it reads L->R
147  const double angle=rotation() * M_PI / 180.0;
148  const bool textFlipped=flipped(rotation());
149  const float z=zoomFactor();
150 
151  auto& c=dynamic_cast<const NamedOp&>(*this);
152 
153  Pango pango(cairo);
154  pango.setFontSize(10.0*scaleFactor()*z);
155  pango.setMarkup(latexToPango(c.description()));
156  pango.angle=angle + (textFlipped? M_PI: 0);
157  const Rotate r(rotation()+ (textFlipped? 180: 0),0,0);
158 
159  // parameters of icon in userspace (unscaled) coordinates
160  float w, h, hoffs;
161  w=0.5*pango.width()+2*z;
162  h=0.5*pango.height()+4*z;
163  hoffs=pango.top()/z;
164 
165  {
166  const cairo::CairoSave cs(cairo);
167  cairo_move_to(cairo,r.x(-w+1,-h-hoffs+2*z), r.y(-w+1,-h-hoffs+2*z));
168  pango.show();
169  }
170 
171  cairo_rotate(cairo, angle);
172 
173  cairo_set_source_rgb(cairo,0,0,1);
174  cairo_move_to(cairo,-w,-h);
175  cairo_line_to(cairo,-w,h);
176  cairo_line_to(cairo,w,h);
177 
178  cairo_line_to(cairo,w+2*z,0);
179  cairo_line_to(cairo,w,-h);
180  cairo_close_path(cairo);
181  cairo::Path clipPath(cairo);
182  cairo_stroke(cairo);
183 
184  cairo_rotate(cairo,-angle); // undo rotation
185 
186  // set the output ports coordinates
187  // compute port coordinates relative to the icon's
188  // point of reference
189  const Rotate rr(rotation(),0,0);
190 
191  m_ports[0]->moveTo(x()+rr.x(w+2,0), y()+rr.y(w+2,0));
192  switch (numPorts())
193  {
194  case 1: break;
195  case 2:
196  m_ports[1]->moveTo(x()+rr.x(-w,0), y()+rr.y(-w,0));
197  break;
198  case 3: default:
199  m_ports[1]->moveTo(x()+rr.x(-w,0), y()+rr.y(-w,textFlipped? h-3: -h+3));
200  m_ports[2]->moveTo(x()+rr.x(-w,0), y()+rr.y(-w,textFlipped? -h+3: h-3));
201  break;
202  }
203  if (type()==OperationType::userFunction)
204  {
205  cairo_set_source_rgb(cairo,0,0,0);
206  DrawBinOp drawBinOp(cairo, zoomFactor());
207  drawBinOp.drawPort([&](){drawBinOp.drawSymbol("x");},-1.1*w,-1.1*h,rotation());
208  drawBinOp.drawPort([&](){drawBinOp.drawSymbol("y");},-1.1*w,1.1*h,rotation());
209  }
210  if (mouseFocus)
211  {
212  drawPorts(cairo);
213  displayTooltip(cairo,tooltip());
214  if (onResizeHandles) drawResizeHandles(cairo);
215  }
216  clipPath.appendToCurrent(cairo);
217  cairo_clip(cairo);
218  if (selected) drawSelected(cairo);
219  }
220 
221  void OperationBase::setCachedText(cairo_t* cairo, const std::string& text, double size) const
222  {
223  if (cachedPango && cairo==cachedPango->cairoContext()) return;
224  cachedPango=make_shared<Pango>(cairo);
225  cachedPango->setMarkup(text);
226  cachedPango->setFontSize(size);
227  }
228 
229 
230  void OperationBase::draw(cairo_t* cairo) const
231  {
232  // if rotation is in 1st or 3rd quadrant, rotate as
233  // normal, otherwise flip the text so it reads L->R
234  const double angle=rotation() * M_PI / 180.0;
235  const bool textFlipped=flipped(rotation());
236  const float z=zoomFactor();
237 
238  {
239  const CairoSave cs(cairo);
240  cairo_scale(cairo,z,z);
241  iconDraw(cairo);
242  }
243 
244 
245  CairoSave cs(cairo);
246  cairo_rotate(cairo, angle);
247 
248  float l=OperationBase::l*z, r=OperationBase::r*z,
249  h=OperationBase::h*z;
250 
251  if (fabs(l)<0.5*iWidth()*z) l=-0.5*iWidth()*z;
252  if (r<0.5*iWidth()*z) r=0.5*iWidth()*z;
253  if (h<0.5*iHeight()*z) h=0.5*iHeight()*z;
254 
255  cairo_move_to(cairo,-r,-h);
256  cairo_line_to(cairo,-r,h);
257  cairo_line_to(cairo,r,h);
258  cairo_line_to(cairo,r+2*z,0);
259  cairo_line_to(cairo,r,-h);
260 
261  cairo_close_path(cairo);
262 
263  cairo_set_source_rgb(cairo,0,0,1);
264  cairo_stroke_preserve(cairo);
265 
266  cairo::Path clipPath(cairo);
267 
268  // compute port coordinates relative to the icon's
269  // point of reference. Move outport 2 pixels right for ticket For ticket 362.
270  double x0=r, y0=0, x1=l, y1=numPorts() > 2? -h+3: 0,
271  x2=l, y2=numPorts() > 2? h-3: 0;
272 
273  if (textFlipped) swap(y1,y2);
274 
275  {
276  const CairoSave cs(cairo);
277  cairo_identity_matrix(cairo);
278  cairo_translate(cairo, x(), y());
279  cairo_rotate(cairo, angle);
280  cairo_user_to_device(cairo, &x0, &y0);
281  cairo_user_to_device(cairo, &x1, &y1);
282  cairo_user_to_device(cairo, &x2, &y2);
283  }
284 
285  if (numPorts()>0)
286  m_ports[0]->moveTo(x0, y0);
287  if (numPorts()>1)
288  {
289 #ifdef DISPLAY_POW_UPSIDE_DOWN
290  if (type()==OperationType::pow)
291  ports[1]->moveTo(x2, y2);
292  else
293 #endif
294  m_ports[1]->moveTo(x1, y1);
295  }
296 
297  if (numPorts()>2)
298  {
299 #ifdef DISPLAY_POW_UPSIDE_DOWN
300  if (type()==OperationType::pow)
301  ports[2]->moveTo(x1, y1);
302  else
303 #endif
304  m_ports[2]->moveTo(x2, y2);
305  }
306 
307  cs.restore(); // undo rotation
308  if (mouseFocus)
309  {
310  drawPorts(cairo);
311  displayTooltip(cairo,tooltip());
312  if (onResizeHandles) drawResizeHandles(cairo);
313  }
314 
315  cairo_new_path(cairo);
316  clipPath.appendToCurrent(cairo);
317  cairo_clip(cairo);
318  if (selected) drawSelected(cairo);
319  }
320 
321  void OperationBase::resize(const LassoBox& b)
322  {
323  const float invZ=1/zoomFactor();
324  moveTo(0.5*(b.x0+b.x1), 0.5*(b.y0+b.y1));
325  iWidth(std::abs(b.x1-b.x0)*invZ);
326  iHeight(std::abs(b.y1-b.y0)*invZ);
327  }
328 
329  double OperationBase::value() const
330  {
331  try
332  {
333  unique_ptr<ScalarEvalOp> e(ScalarEvalOp::create(type(),itemPtrFromThis()));
334  if (e)
335  switch (e->numArgs())
336  {
337  case 0: return e->evaluate(0,0);
338  case 1: return e->evaluate(m_ports[1]->value());
339  case 2: return e->evaluate(m_ports[1]->value(),m_ports[2]->value());
340  }
341  }
342  catch (...)
343  {/* absorb exception here - some operators cannot be evaluated this way*/}
344  return nan("");
345  }
346 
347 
348  vector<string> OperationBase::dimensions() const
349  {
350  set<string> names;
351  for (size_t i=1; i<m_ports.size(); ++i)
352  if (auto vv=m_ports[i]->getVariableValue())
353  for (auto& xv: vv->hypercube().xvectors)
354  names.insert(xv.name);
355  else if (!m_ports[i]->wires().empty())
356  if (auto f=m_ports[i]->wires()[0]->from())
357  if (auto r=f->item().ravelCast())
358  for (auto& xv: r->hypercube().xvectors)
359  names.insert(xv.name);
360 
361  return {names.begin(), names.end()};
362  }
363 
364  namespace {
365  // return fractional part of x
366  inline double fracPart(double x) {
367  double dummy;
368  return modf(x,&dummy);
369  }
370 
371  // extract units from inputs, checking they're all consistent
372  struct CheckConsistent: public Units
373  {
374  CheckConsistent(const Item& item)
375  {
376  bool inputFound=false;
377  for (size_t i=1; i<item.portsSize(); ++i)
378  for (auto w: item.ports(i).lock()->wires())
379  if (inputFound)
380  {
381  auto tmp=w->units(true);
382  if (tmp!=*this)
383  item.throw_error("incompatible units: "+tmp.str()+"≠"+str());
384  }
385  else
386  {
387  inputFound=true;
388  Units::operator=(w->units(true));
389  }
390  }
391  };
392  }
393 
394  Units OperationBase::unitsBinOpCase(bool check) const
395  {
396  switch (type())
397  {
398  // these binops need to have dimensionless units
399  case log: case and_: case or_: case polygamma: case userFunction:
400 
401  if (check && !m_ports[1]->units(check).empty())
402  throw_error("function inputs not dimensionless");
403  return {};
404  case pow:
405  {
406  auto r=m_ports[1]->units(check);
407 
408  if (!r.empty())
409  {
410  if (!m_ports[2]->wires().empty())
411  if (auto v=dynamic_cast<VarConstant*>(&m_ports[2]->wires()[0]->from()->item()))
412  if (fracPart(v->value())==0)
413  {
414  for (auto& i: r) i.second*=v->value();
415  r.normalise();
416  return r;
417  }
418  if (check)
419  throw_error("dimensioned pow only possible if exponent is a constant integer");
420  }
421  return r;
422  }
423  // these binops must have compatible units
424  case le: case lt: case eq:
425  {
426  if (check)
427  CheckConsistent(*this);
428  return {};
429  }
430  case add: case subtract: case max: case min:
431  {
432  if (check)
433  return CheckConsistent(*this);
434  if (!m_ports[1]->wires().empty())
435  return m_ports[1]->wires()[0]->units(check);
436  if (!m_ports[2]->wires().empty())
437  return m_ports[2]->wires()[0]->units(check);
438  return {};
439  }
440  // multiply and divide are especially computed
441  case multiply: case divide:
442  {
443  Units units;
444  for (auto w: m_ports[1]->wires())
445  {
446  auto tmp=w->units(check);
447  for (auto& i: tmp)
448  units[i.first]+=i.second;
449  }
450  const int f=(type()==multiply)? 1: -1; //indices are negated for division
451  for (auto w: m_ports[2]->wires())
452  {
453  auto tmp=w->units(check);
454  for (auto& i: tmp)
455  units[i.first]+=f*i.second;
456  }
457  units.normalise();
458  return units;
459  }
460  default:
461  if (check)
462  throw_error("Operation<"+OperationType::typeName(type())+">::units() should be overridden");
463  return {};
464  }
465  }
466 
467  Units OperationBase::units(bool check) const
468  {
469  // default operations are dimensionless, but check that inputs are also
470  switch (classify(type()))
471  {
472  case function: case reduction: case scan: case tensor:
473  {
474  if (check && !m_ports[1]->units(check).empty())
475  throw_error("function input not dimensionless");
476  return {};
477  }
478  case constop:
479  // Add % sign to units from input to % operator. Need the first conditional otherwise Minsky crashes
480  if (type()==percent && !m_ports[1]->wires().empty()) {
481  auto r=m_ports[1]->units(check);
482  if (auto vV=dynamic_cast<VariableValue*>(&m_ports[1]->wires()[0]->from()->item()))
483  {
484  vV->setUnits("%"+r.str());
485  vV->units.normalise();
486  return vV->units;
487  }
488  return r;
489  }
490  return {};
491  case binop:
492  return unitsBinOpCase(check);
493  case statistics:
494  switch (type())
495  {
496  case mean: case median: case stdDev:
497  return m_ports[1]->units(check);
498  case moment:
499  {
500  auto argUnits=m_ports[1]->units(check);
501  for (auto& i: argUnits)
502  i.second*=arg;
503  return argUnits;
504  }
505  case histogram:
506  return {};
507  case covariance:
508  {
509  auto argUnits=m_ports[1]->units(check);
510  for (auto& i: m_ports[2]->units(check))
511  {
512  argUnits.emplace(i.first,1); // ensure base unit is present
513  argUnits[i.first]*=i.second;
514  }
515  return argUnits;
516  }
517  case linearRegression:
518  return m_ports[1]->units(check);
519  case correlation:
520  return {};
521  default:
522  throw_error("Statistics operation does not have units() defined");
523  }
524  default:
525  if (check)
526  throw_error("Operation<"+OperationType::typeName(type())+">::units() should be overridden");
527  return {};
528  }
529  }
530 
531  Units Time::units(bool) const {return cminsky().timeUnit;}
532  Units Derivative::units(bool check) const {
533  Units r=m_ports[1]->units(check);
534  if (!cminsky().timeUnit.empty())
535  r[cminsky().timeUnit]--;
536  r.normalise();
537  return r;
538  }
539 
540  namespace
541  {
543  }
544 
545  OperationBase* OperationBase::create(OperationType::Type type)
546  {
547  switch (type)
548  {
549  case time: return new Time;
550  case copy: return new Copy;
551  case integrate: return new IntOp;
552  case differentiate: return new Derivative;
553  case data: return new DataOp;
554  case ravel: return new Ravel;
555  case constant: throw error("Constant deprecated");
556  case userFunction: return new UserFunction;
557  default: return operationFactory.create(type);
558  }
559  }
560 
561  string OperationBase::portValues() const
562  {
563  string r="equations not yet constructed, please reset";
564  if (!m_ports.empty())
565  r="[out]="+str(m_ports[0]->value());
566  if (m_ports.size()>1)
567  r+=" [in1]="+ str(m_ports[1]->value());
568  if (m_ports.size()>2)
569  r+=" [in2]="+ str(m_ports[2]->value());
570  return r;
571  }
572 
573  string NamedOp::description() const
574  {
575  return m_description;
576  }
577 
578  string NamedOp::description(const std::string& x)
579  {
580  m_description=x;
581  updateBB(); // adjust icon bounding box - see ticket #1121
582  return m_description;
583  }
584 
585  // virtual draw methods for operations - defined here rather than
586  // operations.cc because it is more related to the functionality in
587  // this file.
588 
589  template <> void Operation<OperationType::constant>::iconDraw(cairo_t* cairo) const
590  {
591  assert(false); //shouldn't be here
592  }
593 
594  template <> void Operation<OperationType::ravel>::iconDraw(cairo_t* cairo) const
595  {
596  assert(false); //shouldn't be here
597  }
598 
599  template <> void Operation<OperationType::data>::iconDraw(cairo_t* cairo) const
600  {
601  const double sf = scaleFactor();
602  cairo_translate(cairo,-1,0);
603  cairo_scale(cairo,1.5*sf,0.75*sf);
604  cairo_arc(cairo,0,-3,3,0,2*M_PI);
605  cairo_arc(cairo,0,3,3,0,M_PI);
606  cairo_move_to(cairo,-3,3);
607  cairo_line_to(cairo,-3,-3);
608  cairo_move_to(cairo,3,3);
609  cairo_line_to(cairo,3,-3);
610  cairo_identity_matrix(cairo);
611  cairo_set_line_width(cairo,1.0);
612  cairo_stroke(cairo);
613  }
614 
615  template <> void Operation<OperationType::time>::iconDraw(cairo_t* cairo) const
616  {
617  const double sf = scaleFactor();
618  cairo_scale(cairo,sf,sf);
619  cairo_move_to(cairo,-4,2);
620  cairo_show_text(cairo,"t");
621  }
622 
623  template <> void Operation<OperationType::euler>::iconDraw(cairo_t* cairo) const
624  {
625  const double sf = scaleFactor();
626  cairo_scale(cairo,sf,sf);
627  cairo_move_to(cairo,-4,2);
628  cairo_show_text(cairo,"e");
629  }
630 
631  template <> void Operation<OperationType::pi>::iconDraw(cairo_t* cairo) const
632  {
633  const double sf = scaleFactor();
634  cairo_scale(cairo,sf,sf);
635  cairo_move_to(cairo,-4,2);
636  cairo_show_text(cairo,"π");
637  }
638 
639  template <> void Operation<OperationType::zero>::iconDraw(cairo_t* cairo) const
640  {
641  const double sf = scaleFactor();
642  cairo_scale(cairo,sf,sf);
643  cairo_move_to(cairo,-4,2);
644  cairo_show_text(cairo,"0");
645  }
646 
647  template <> void Operation<OperationType::one>::iconDraw(cairo_t* cairo) const
648  {
649  const double sf = scaleFactor();
650  cairo_scale(cairo,sf,sf);
651  cairo_move_to(cairo,-4,2);
652  cairo_show_text(cairo,"1");
653  }
654 
655  template <> void Operation<OperationType::inf>::iconDraw(cairo_t* cairo) const
656  {
657  const double sf = scaleFactor();
658  cairo_move_to(cairo,-4,-10);
659  setCachedText(cairo,"∞",9);
660  cairo_scale(cairo,sf,sf);
661  cachedPango->show();
662  }
663 
664  template <> void Operation<OperationType::percent>::iconDraw(cairo_t* cairo) const
665  {
666  const double sf = scaleFactor();
667  cairo_move_to(cairo,-4,-7);
668  setCachedText(cairo,"%",7);
669  cairo_scale(cairo,sf,sf);
670  cachedPango->show();
671  }
672 
673  template <> void Operation<OperationType::copy>::iconDraw(cairo_t* cairo) const
674  {
675  const double sf = scaleFactor();
676  cairo_move_to(cairo,-4,-5);
677  setCachedText(cairo, "→",7);
678  cairo_scale(cairo,sf,sf);
679  cachedPango->show();
680  }
681 
682  template <> void Operation<OperationType::integrate>::iconDraw(cairo_t* cairo) const
683  {/* moved to IntOp::draw() but needs to be here, and is actually called */}
684 
685  template <> void Operation<OperationType::differentiate>::iconDraw(cairo_t* cairo) const
686  {
687  const CairoSave cs(cairo);
688  const double sf = scaleFactor();
689  cairo_scale(cairo,sf,sf);
690  cairo_move_to(cairo,-7,-1);
691  cairo_set_font_size(cairo,8);
692  cairo_show_text(cairo,"d");
693  cairo_move_to(cairo,-7,0);cairo_line_to(cairo,2,0);
694  cairo_set_line_width(cairo,0.5);cairo_stroke(cairo);
695  cairo_move_to(cairo,-7,7);
696  cairo_show_text(cairo,"dt");
697  }
698 
699  template <> void Operation<OperationType::sqrt>::iconDraw(cairo_t* cairo) const
700  {
701  const CairoSave cs(cairo);
702  const double sf = scaleFactor();
703  cairo_scale(cairo,sf,sf);
704  cairo_set_font_size(cairo,10);
705  cairo_move_to(cairo,-7,6);
706  cairo_show_text(cairo,"\xE2\x88\x9a");
707  cairo_set_line_width(cairo,0.5);
708  cairo_rel_move_to(cairo,0,-9);
709  cairo_rel_line_to(cairo,5,0);
710  cairo_set_source_rgb(cairo,0,0,0);
711  cairo_stroke(cairo);
712  }
713 
714  template <> void Operation<OperationType::exp>::iconDraw(cairo_t* cairo) const
715  {
716  const double sf = scaleFactor();
717  cairo_scale(cairo,sf,sf);
718  cairo_move_to(cairo,-7,3);
719  cairo_show_text(cairo,"e");
720  cairo_rel_move_to(cairo,0,-4);
721  cairo_set_font_size(cairo,7);
722  cairo_show_text(cairo,"x");
723  }
724 
725  template <> void Operation<OperationType::pow>::iconDraw(cairo_t* cairo) const
726  {
727  const double sf = scaleFactor();
728  cairo_scale(cairo,sf,sf);
729  cairo_move_to(cairo,-6,3);
730  cairo_show_text(cairo,"x");
731  cairo_rel_move_to(cairo,0,-4);
732  cairo_set_font_size(cairo,7);
733  cairo_show_text(cairo,"y");
734  DrawBinOp d(cairo);
735 #ifdef DISPLAY_POW_UPSIDE_DOWN
736  d.drawPort([&](){d.drawSymbol("y");}, l, -h, rotation());
737  d.drawPort([&](){d.drawSymbol("x");}, l, h, rotation());
738 #else
739  d.drawPort([&](){d.drawSymbol("x");}, l, -h, rotation());
740  d.drawPort([&](){d.drawSymbol("y");}, l, h, rotation());
741 #endif
742  }
743 
744  template <> void Operation<OperationType::le>::iconDraw(cairo_t* cairo) const
745  {
746  const double sf = scaleFactor();
747  cairo_scale(cairo,sf,sf);
748  cairo_move_to(cairo,-9,3);
749  cairo_show_text(cairo,"x≤y");
750  DrawBinOp d(cairo);
751  d.drawPort([&](){d.drawSymbol("x");}, l, -h, rotation());
752  d.drawPort([&](){d.drawSymbol("y");}, l, h, rotation());
753  }
754 
755  template <> void Operation<OperationType::lt>::iconDraw(cairo_t* cairo) const
756  {
757  const double sf = scaleFactor();
758  cairo_scale(cairo,sf,sf);
759  cairo_move_to(cairo,-9,3);
760  cairo_show_text(cairo,"x<y");
761  DrawBinOp d(cairo);
762  d.drawPort([&](){d.drawSymbol("x");}, l, -h, rotation());
763  d.drawPort([&](){d.drawSymbol("y");}, l, h, rotation());
764  }
765 
766  template <> void Operation<OperationType::eq>::iconDraw(cairo_t* cairo) const
767  {
768  const double sf = scaleFactor();
769  cairo_scale(cairo,sf,sf);
770  cairo_move_to(cairo,-9,3);
771  cairo_show_text(cairo,"x=y");
772  DrawBinOp d(cairo);
773  d.drawPort([&](){d.drawSymbol("x");}, l, -h, rotation());
774  d.drawPort([&](){d.drawSymbol("y");}, l, h, rotation());
775  }
776 
777  template <> void Operation<OperationType::min>::iconDraw(cairo_t* cairo) const
778  {
779  const double sf = scaleFactor();
780  cairo_scale(cairo,sf,sf);
781  cairo_move_to(cairo,-9,3);
782  cairo_show_text(cairo,"min");
783  }
784 
785  template <> void Operation<OperationType::max>::iconDraw(cairo_t* cairo) const
786  {
787  const double sf = scaleFactor();
788  cairo_scale(cairo,sf,sf);
789  cairo_move_to(cairo,-9,3);
790  cairo_show_text(cairo,"max");
791  }
792 
793  template <> void Operation<OperationType::and_>::iconDraw(cairo_t* cairo) const
794  {
795  const CairoSave cs(cairo);
796  const double sf = scaleFactor();
797  cairo_scale(cairo,sf,sf);
798  cairo_set_source_rgb(cairo,0,0,0);
799  cairo_move_to(cairo,-4,3);
800  cairo_line_to(cairo,-1,-3);
801  cairo_line_to(cairo,2,3);
802  cairo_stroke(cairo);
803  }
804 
805  template <> void Operation<OperationType::or_>::iconDraw(cairo_t* cairo) const
806  {
807  const CairoSave cs(cairo);
808  const double sf = scaleFactor();
809  cairo_scale(cairo,sf,sf);
810  cairo_set_source_rgb(cairo,0,0,0);
811  cairo_move_to(cairo,-4,-3);
812  cairo_line_to(cairo,-1,3);
813  cairo_line_to(cairo,2,-3);
814  cairo_stroke(cairo);
815  }
816 
817  template <> void Operation<OperationType::not_>::iconDraw(cairo_t* cairo) const
818  {
819  const double sf = scaleFactor();
820  cairo_scale(cairo,sf,sf);
821  cairo_move_to(cairo,-6,3);
822  cairo_show_text(cairo,"¬");
823  }
824 
825  template <> void Operation<OperationType::covariance>::iconDraw(cairo_t* cairo) const
826  {
827  const double sf = scaleFactor();
828  cairo_scale(cairo,sf*.7,sf);
829  cairo_move_to(cairo,-16,3);
830  cairo_show_text(cairo,"<ΔxΔy>");
831  }
832 
833  template <> void Operation<OperationType::correlation>::iconDraw(cairo_t* cairo) const
834  {
835  const double sf = scaleFactor();
836  cairo_scale(cairo,sf,sf);
837  cairo_move_to(cairo,-3,3);
838  cairo_show_text(cairo,"ρ");
839  }
840 
841  template <> void Operation<OperationType::linearRegression>::iconDraw(cairo_t* cairo) const
842  {
843  const double sf = scaleFactor();
844  cairo_scale(cairo,sf,sf);
845  cairo_move_to(cairo,-7,7);
846  cairo_line_to(cairo,7,-7);
847  cairo_stroke(cairo);
848  cairo_arc(cairo,-4,0,0.2,0,2*M_PI);
849  cairo_stroke(cairo);
850  cairo_arc(cairo,3,3,0.2,0,2*M_PI);
851  cairo_stroke(cairo);
852  cairo_arc(cairo,4,-6,0.2,0,2*M_PI);
853  cairo_stroke(cairo);
854  }
855  template <> void Operation<OperationType::ln>::iconDraw(cairo_t* cairo) const
856  {
857  const double sf = scaleFactor();
858  cairo_scale(cairo,sf,sf);
859  cairo_move_to(cairo,-9,3);
860  cairo_show_text(cairo," ln");
861  }
862 
863  template <> void Operation<OperationType::log>::iconDraw(cairo_t* cairo) const
864  {
865  const double sf = scaleFactor();
866  cairo_scale(cairo,sf,sf);
867  cairo_move_to(cairo,-9,3);
868  cairo_show_text(cairo,"log");
869  DrawBinOp d(cairo);
870  d.drawPort([&](){d.drawSymbol("x");}, l, -h, rotation());
871  d.drawPort([&](){d.drawSymbol("b");}, l, h, rotation());
872  }
873 
874  template <> void Operation<OperationType::sin>::iconDraw(cairo_t* cairo) const
875  {
876  const double sf = scaleFactor();
877  cairo_scale(cairo,sf,sf);
878  cairo_set_font_size(cairo,10);
879  cairo_move_to(cairo,-9,3);
880  cairo_show_text(cairo,"sin");
881  }
882 
883  template <> void Operation<OperationType::cos>::iconDraw(cairo_t* cairo) const
884  {
885  const double sf = scaleFactor();
886  cairo_scale(cairo,sf,sf);
887  cairo_set_font_size(cairo,10);
888  cairo_move_to(cairo,-9,3);
889  cairo_show_text(cairo,"cos");
890  }
891 
892  template <> void Operation<OperationType::tan>::iconDraw(cairo_t* cairo) const
893  {
894  const double sf = scaleFactor();
895  cairo_scale(cairo,sf,sf);
896  cairo_set_font_size(cairo,10);
897  cairo_move_to(cairo,-9,3);
898  cairo_show_text(cairo,"tan");
899  }
900 
901  template <> void Operation<OperationType::asin>::iconDraw(cairo_t* cairo) const
902  {
903  const double sf = scaleFactor();
904  cairo_scale(cairo,sf,sf);
905  cairo_set_font_size(cairo,9);
906  cairo_move_to(cairo,-9,3);
907  cairo_show_text(cairo,"sin");
908  cairo_rel_move_to(cairo,0,-3);
909  cairo_set_font_size(cairo,7);
910  cairo_show_text(cairo,"-1");
911  cairo_rel_move_to(cairo,0,-2);
912  }
913 
914  template <> void Operation<OperationType::acos>::iconDraw(cairo_t* cairo) const
915  {
916  const double sf = scaleFactor();
917  cairo_scale(cairo,sf,sf);
918  cairo_set_font_size(cairo,9);
919  cairo_move_to(cairo,-9,3);
920  cairo_show_text(cairo,"cos");
921  cairo_rel_move_to(cairo,0,-3);
922  cairo_set_font_size(cairo,7);
923  cairo_show_text(cairo,"-1");
924  cairo_rel_move_to(cairo,0,-2);
925  }
926 
927  template <> void Operation<OperationType::atan>::iconDraw(cairo_t* cairo) const
928  {
929  const double sf = scaleFactor();
930  cairo_scale(cairo,sf,sf);
931  cairo_set_font_size(cairo,9);
932  cairo_move_to(cairo,-9,3);
933  cairo_show_text(cairo,"tan");
934  cairo_rel_move_to(cairo,0,-3);
935  cairo_set_font_size(cairo,7);
936  cairo_show_text(cairo,"-1");
937  cairo_rel_move_to(cairo,0,-2);
938  }
939 
940  template <> void Operation<OperationType::sinh>::iconDraw(cairo_t* cairo) const
941  {
942  const double sf = scaleFactor();
943  cairo_scale(cairo,sf,sf);
944  cairo_set_font_size(cairo,8);
945  cairo_move_to(cairo,-9,3);
946  cairo_show_text(cairo,"sinh");
947  }
948 
949  template <> void Operation<OperationType::cosh>::iconDraw(cairo_t* cairo) const
950  {
951  const double sf = scaleFactor();
952  cairo_scale(cairo,sf,sf);
953  cairo_set_font_size(cairo,8);
954  cairo_move_to(cairo,-9,3);
955  cairo_show_text(cairo,"cosh");
956  }
957 
958  template <> void Operation<OperationType::tanh>::iconDraw(cairo_t* cairo) const
959  {
960  const double sf = scaleFactor();
961  cairo_scale(cairo,sf,sf);
962  cairo_set_font_size(cairo,8);
963  cairo_move_to(cairo,-9,3);
964  cairo_show_text(cairo,"tanh");
965  }
966 
967  template <> void Operation<OperationType::abs>::iconDraw(cairo_t* cairo) const
968  {
969  const double sf = scaleFactor();
970  cairo_scale(cairo,sf,sf);
971  cairo_set_font_size(cairo,9);
972  cairo_move_to(cairo,-6,3);
973  cairo_show_text(cairo,"|x|");
974  }
975  template <> void Operation<OperationType::floor>::iconDraw(cairo_t* cairo) const
976  {
977  const double sf = scaleFactor();
978  cairo_move_to(cairo,-5,-5);
979  // what we're trying to draw, but Windows' deficient fontsets don't allow it
980  //setCachedText(cairo, "⌊x⌋",7);
981  setCachedText(cairo, "x",7);
982  cairo_scale(cairo,sf,sf);
983  cachedPango->show();
984  cairo_move_to(cairo,-5,-4);
985  cairo_rel_line_to(cairo,0,cachedPango->height()-2);
986  cairo_rel_line_to(cairo,1,0);
987  cairo_move_to(cairo,-5+cachedPango->width(),-4);
988  cairo_rel_line_to(cairo,0,cachedPango->height()-2);
989  cairo_rel_line_to(cairo,-1,0);
990  cairo_stroke(cairo);
991  }
992  template <> void Operation<OperationType::frac>::iconDraw(cairo_t* cairo) const
993  {
994  const double sf = scaleFactor();
995  cairo_scale(cairo,sf,sf);
996  cairo_set_font_size(cairo,8);
997  cairo_move_to(cairo,-9,3);
998  cairo_show_text(cairo,"frac");
999  }
1000  template <> void Operation<OperationType::Gamma>::iconDraw(cairo_t* cairo) const
1001  {
1002  const double sf = scaleFactor();
1003  cairo_scale(cairo,sf,sf);
1004  cairo_move_to(cairo,-6,3);
1005  cairo_show_text(cairo,"Γ");
1006  }
1007  template <> void Operation<OperationType::polygamma>::iconDraw(cairo_t* cairo) const
1008  {
1009  const double sf = scaleFactor();
1010  cairo_scale(cairo,sf,sf);
1011  cairo_move_to(cairo,-7,3);
1012  cairo_show_text(cairo,"ψ");
1013  cairo_rel_move_to(cairo,0,-3);
1014  cairo_set_font_size(cairo,7);
1015  // show order of polygamma function. 0 is default.
1016  const std::string order="("+to_string(static_cast<unsigned>(m_ports[2]->value()))+")";
1017  cairo_show_text(cairo,order.c_str());
1018  cairo_rel_move_to(cairo,0,-2);
1019  DrawBinOp d(cairo);
1020  d.drawPort([&](){d.drawSymbol("x");}, l, -h, rotation());
1021  d.drawPort([&](){d.drawSymbol("n");}, l, h, rotation());
1022  }
1023  template <> void Operation<OperationType::fact>::iconDraw(cairo_t* cairo) const
1024  {
1025  const double sf = scaleFactor();
1026  cairo_scale(cairo,sf,sf);
1027  cairo_move_to(cairo,-3,3);
1028  cairo_show_text(cairo,"!");
1029  }
1030  template <> void Operation<OperationType::add>::iconDraw(cairo_t* cairo) const
1031  {
1032  const double sf = scaleFactor();
1033  cairo_scale(cairo,sf,sf);
1034  DrawBinOp d(cairo);
1035  d.drawPlus();
1036  d.drawPort([&](){d.drawPlus();}, l, h, rotation());
1037  d.drawPort([&](){d.drawPlus();}, l, -h, rotation());
1038  }
1039 
1040  template <> void Operation<OperationType::subtract>::iconDraw(cairo_t* cairo) const
1041  {
1042  const double sf = scaleFactor();
1043  cairo_scale(cairo,sf,sf);
1044  DrawBinOp d(cairo);
1045  d.drawMinus();
1046  d.drawPort([&](){d.drawPlus();}, l, -h, rotation());
1047  d.drawPort([&](){d.drawMinus();}, l, h, rotation());
1048  }
1049 
1050  template <> void Operation<OperationType::multiply>::iconDraw(cairo_t* cairo) const
1051  {
1052  const double sf = scaleFactor();
1053  cairo_scale(cairo,sf,sf);
1054  DrawBinOp d(cairo);
1055  d.drawMultiply();
1056  d.drawPort([&](){d.drawMultiply();}, l, h, rotation());
1057  d.drawPort([&](){d.drawMultiply();}, l, -h, rotation());
1058  }
1059 
1060  template <> void Operation<OperationType::divide>::iconDraw(cairo_t* cairo) const
1061  {
1062  const double sf = scaleFactor();
1063  cairo_scale(cairo,sf,sf);
1064  DrawBinOp d(cairo);
1065  d.drawDivide();
1066  d.drawPort([&](){d.drawMultiply();}, l, -h, rotation());
1067  d.drawPort([&](){d.drawDivide();}, l, h, rotation());
1068  }
1069 
1070  template <> void Operation<OperationType::sum>::iconDraw(cairo_t* cairo) const
1071  {
1072  const double sf = scaleFactor();
1073  cairo_move_to(cairo,-4,-7);
1074  setCachedText(cairo, "∑", 7);
1075  cairo_scale(cairo,sf,sf);
1076  cachedPango->show();
1077  }
1078 
1079  template <> void Operation<OperationType::product>::iconDraw(cairo_t* cairo) const
1080  {
1081  const double sf = scaleFactor();
1082  cairo_move_to(cairo,-4,-7);
1083  setCachedText(cairo, "∏",7);
1084  cairo_scale(cairo,sf,sf);
1085  cachedPango->show();
1086  }
1087 
1088  template <> void Operation<OperationType::infimum>::iconDraw(cairo_t* cairo) const
1089  {
1090  const double sf = scaleFactor();
1091  cairo_scale(cairo,sf,sf);
1092  cairo_set_font_size(cairo,10);
1093  cairo_move_to(cairo,-9,3);
1094  cairo_show_text(cairo,"inf");
1095  }
1096 
1097  template <> void Operation<OperationType::supremum>::iconDraw(cairo_t* cairo) const
1098  {
1099  const double sf = scaleFactor();
1100  cairo_scale(cairo,sf,sf);
1101  cairo_set_font_size(cairo,10);
1102  cairo_move_to(cairo,-9,3);
1103  cairo_show_text(cairo,"sup");
1104  }
1105 
1106  template <> void Operation<OperationType::infIndex>::iconDraw(cairo_t* cairo) const
1107  {
1108  const double sf = scaleFactor();
1109  cairo_scale(cairo,sf,sf);
1110  cairo_set_font_size(cairo,10);
1111  cairo_move_to(cairo,-9,3);
1112  cairo_show_text(cairo,"infi");
1113  }
1114 
1115  template <> void Operation<OperationType::supIndex>::iconDraw(cairo_t* cairo) const
1116  {
1117  const double sf = scaleFactor();
1118  cairo_scale(cairo,sf,sf);
1119  cairo_set_font_size(cairo,10);
1120  cairo_move_to(cairo,-9,3);
1121  cairo_show_text(cairo,"supi");
1122  }
1123 
1124  template <> void Operation<OperationType::any>::iconDraw(cairo_t* cairo) const
1125  {
1126  const double sf = scaleFactor();
1127  cairo_scale(cairo,sf,sf);
1128  cairo_set_font_size(cairo,10);
1129  cairo_move_to(cairo,-9,3);
1130  cairo_show_text(cairo,"any");
1131  }
1132 
1133  template <> void Operation<OperationType::all>::iconDraw(cairo_t* cairo) const
1134  {
1135  const double sf = scaleFactor();
1136  cairo_scale(cairo,sf,sf);
1137  cairo_set_font_size(cairo,10);
1138  cairo_move_to(cairo,-9,3);
1139  cairo_show_text(cairo,"all");
1140  }
1141 
1142 
1143 
1144  template <> void Operation<OperationType::size>::iconDraw(cairo_t* cairo) const
1145  {
1146  const double sf = scaleFactor();
1147  cairo_scale(cairo,sf,sf);
1148  cairo_set_font_size(cairo,10);
1149  cairo_move_to(cairo,-9,3);
1150  cairo_show_text(cairo,"nᵢ");
1151  }
1152 
1153  template <> void Operation<OperationType::shape>::iconDraw(cairo_t* cairo) const
1154  {
1155  const double sf = scaleFactor();
1156  cairo_scale(cairo,sf,sf);
1157  cairo_set_font_size(cairo,10);
1158  cairo_move_to(cairo,-9,3);
1159  cairo_show_text(cairo,"{nᵢ}");
1160  }
1161 
1162  template <> void Operation<OperationType::mean>::iconDraw(cairo_t* cairo) const
1163  {
1164  const double sf = scaleFactor();
1165  cairo_scale(cairo,sf,sf);
1166  cairo_set_font_size(cairo,10);
1167  cairo_move_to(cairo,-8,3);
1168  cairo_show_text(cairo,"<x>");
1169  }
1170 
1171  template <> void Operation<OperationType::median>::iconDraw(cairo_t* cairo) const
1172  {
1173  const double sf = scaleFactor();
1174  cairo_scale(cairo,sf,sf);
1175  cairo_set_font_size(cairo,10);
1176  cairo_move_to(cairo,-3,3);
1177  cairo_show_text(cairo,"x");
1178  cairo_move_to(cairo,-4,-1);
1179  cairo_show_text(cairo,"~");
1180  }
1181 
1182  template <> void Operation<OperationType::stdDev>::iconDraw(cairo_t* cairo) const
1183  {
1184  const double sf = scaleFactor();
1185  cairo_scale(cairo,sf,sf);
1186  cairo_set_font_size(cairo,10);
1187  cairo_move_to(cairo,-3,3);
1188  cairo_show_text(cairo,"σ");
1189  }
1190 
1191  template <> void Operation<OperationType::moment>::iconDraw(cairo_t* cairo) const
1192  {
1193  const double sf = scaleFactor();
1194  cairo_scale(cairo,sf*.85,sf);
1195  cairo_set_font_size(cairo,10);
1196  cairo_move_to(cairo,-12,3);
1197  cairo_show_text(cairo,"<Δxᵏ>");
1198  }
1199 
1200  template <> void Operation<OperationType::histogram>::iconDraw(cairo_t* cairo) const
1201  {
1202  const double sf = scaleFactor();
1203  cairo_translate(cairo,-sf*iWidth(), -sf*iHeight());
1204  cairo_scale(cairo,2*sf*iWidth()/cminsky().histogramResource.width(),2*sf*iHeight()/cminsky().histogramResource.height());
1205  cminsky().histogramResource.render(cairo);
1206  }
1207 
1208 
1209 
1210  template <> void Operation<OperationType::runningSum>::iconDraw(cairo_t* cairo) const
1211  {
1212  const double sf = scaleFactor();
1213  cairo_move_to(cairo,-7,-7);
1214  setCachedText(cairo, "∑+",7);
1215  cairo_scale(cairo,sf,sf);
1216  cachedPango->show();
1217  }
1218 
1219  template <> void Operation<OperationType::runningProduct>::iconDraw(cairo_t* cairo) const
1220  {
1221  const double sf = scaleFactor();
1222  cairo_move_to(cairo,-6,-7);
1223  setCachedText(cairo, "∏×",7);
1224  cairo_scale(cairo,sf,sf);
1225  cachedPango->show();
1226  }
1227 
1228  template <> void Operation<OperationType::difference>::iconDraw(cairo_t* cairo) const
1229  {
1230  const double sf = scaleFactor();
1231  cairo_move_to(cairo,-4,-7);
1232  setCachedText(cairo, "Δ<sup>-</sup>",7);
1233  cairo_scale(cairo,sf,sf);
1234  cachedPango->show();
1235  }
1236 
1237  template <> void Operation<OperationType::differencePlus>::iconDraw(cairo_t* cairo) const
1238  {
1239  const double sf = scaleFactor();
1240  cairo_move_to(cairo,-4,-7);
1241  setCachedText(cairo, "Δ<sup>+</sup>",7);
1242  cairo_scale(cairo,sf,sf);
1243  cachedPango->show();
1244  }
1245 
1246  template <> void Operation<OperationType::innerProduct>::iconDraw(cairo_t* cairo) const
1247  {
1248  const double sf = scaleFactor();
1249  cairo_move_to(cairo,-4,-10);
1250  setCachedText(cairo, "·",14);
1251  cairo_scale(cairo,sf,sf);
1252  cachedPango->show();
1253  }
1254 
1255  template <> void Operation<OperationType::outerProduct>::iconDraw(cairo_t* cairo) const
1256  {
1257  const double sf = scaleFactor();
1258  cairo_move_to(cairo,-4,-10);
1259  // this is the character we want, but draw it explicitly because
1260  //of Windows' deficient fontsets.
1261  // setCachedText(cairo, "⊗",10);
1262  cairo_scale(cairo,sf,sf);
1263  constexpr const double r=6;
1264  static const double d=0.5*r*std::sqrt(2);
1265  cairo_move_to(cairo,d,d);
1266  cairo_line_to(cairo,-d,-d);
1267  cairo_move_to(cairo,-d,d);
1268  cairo_line_to(cairo,d,-d);
1269  cairo_move_to(cairo,r,0);
1270  cairo_arc(cairo,0,0,r,0,2*M_PI);
1271  cairo_stroke(cairo);
1272  }
1273 
1274  template <> void Operation<OperationType::index>::iconDraw(cairo_t* cairo) const
1275  {
1276  const double sf = scaleFactor();
1277  cairo_scale(cairo,sf,sf);
1278  cairo_set_font_size(cairo,10);
1279  cairo_move_to(cairo,-9,3);
1280  cairo_show_text(cairo,"idx");
1281  }
1282 
1283  template <> void Operation<OperationType::gather>::iconDraw(cairo_t* cairo) const
1284  {
1285  const double sf = scaleFactor();
1286  cairo_scale(cairo,sf,sf);
1287  cairo_set_font_size(cairo,8);
1288  cairo_move_to(cairo,-7,3);
1289  cairo_show_text(cairo,"x[i]");
1290  DrawBinOp drawBinOp(cairo);
1291  drawBinOp.drawPort([&](){drawBinOp.drawSymbol("x");},l,-h,rotation());
1292  drawBinOp.drawPort([&](){drawBinOp.drawSymbol("i");},l,h,rotation());
1293  }
1294 
1295  template <> void Operation<OperationType::meld>::iconDraw(cairo_t* cairo) const
1296  {
1297  const double sf = scaleFactor();
1298  cairo_move_to(cairo,-4,-5);
1299  //setCachedText(cairo, "⭄",10);
1300  cairo_scale(cairo,sf,sf);
1301  cairo_rel_line_to(cairo,4,0);
1302  cairo_rel_line_to(cairo,2,5);
1303  cairo_rel_line_to(cairo,-2,5);
1304  cairo_rel_line_to(cairo,-4,0);
1305  cairo_move_to(cairo,-4,0);
1306  cairo_rel_line_to(cairo,10,0);
1307  cairo_stroke(cairo);
1308  }
1309 
1310  template <> void Operation<OperationType::merge>::iconDraw(cairo_t* cairo) const
1311  {
1312  const double sf = scaleFactor();
1313  cairo_move_to(cairo,-4,-3);
1314  //setCachedText(cairo, "⫤",10);
1315  cairo_scale(cairo,sf,sf);
1316  cairo_rel_line_to(cairo,8,0);
1317  cairo_move_to(cairo,-4,3);
1318  cairo_rel_line_to(cairo,8,0);
1319  cairo_rel_move_to(cairo,0,-10);
1320  cairo_rel_line_to(cairo,0,14);
1321  cairo_stroke(cairo);
1322  }
1323 
1324  template <> void Operation<OperationType::slice>::iconDraw(cairo_t* cairo) const
1325  {
1326  const double sf = scaleFactor();
1327  cairo_move_to(cairo,-10,-10);
1328  setCachedText(cairo, "[...",10);
1329  cairo_scale(cairo,sf,sf);
1330  cachedPango->show();
1331  cairo_move_to(cairo,-10+cachedPango->width(),-9);
1332  cairo_rel_line_to(cairo,0,cachedPango->height()-2);
1333  cairo_stroke(cairo);
1334  }
1335 
1336 
1337 
1338  template <> void Operation<OperationType::numOps>::iconDraw(cairo_t* cairo) const
1339  {/* needs to be here, and is actually called */}
1340 
1341 }
1342 
function f
Definition: canvas.m:1
void drawDivide() const
Definition: operation.h:151
std::string latexToPango(const char *s)
Definition: latexMarkup.h:30
double identity() const override
input port value if no wire attached
Definition: operation.cc:63
std::size_t portsSize() const
number of ports
Definition: item.h:184
Expr polygamma(const Expr &x, const Expr &y)
Definition: expr.h:166
void drawPort(F f, float x, float y, float rotation) const
Definition: operation.h:172
UnitsExpressionWalker pow(const UnitsExpressionWalker &x, const UnitsExpressionWalker &y)
Expr sqrt(const Expr &x)
Definition: expr.h:154
double identity() const override
input port value if no wire attached
Definition: operation.cc:70
represents rectangular region of a lasso operation
Definition: lasso.h:28
float y(float x, float y) const
Definition: geometry.h:60
void drawMultiply() const
Definition: operation.h:142
rotate (x,y) by rot (in degrees) around the origin (x0, y0) can be used for rotating multiple points ...
Definition: geometry.h:44
OperationFactory< OperationBase, Operation > operationFactory
Definition: operation.cc:542
base class for operations that have names
Definition: operation.h:101
bool flipped(double rotation)
returns if the angle (in degrees) is in the second or third quadrant
Definition: geometry.h:102
void combineInput(double &x, double y) const override
combine two input wires
Definition: operation.cc:68
double identity() const override
input port value if no wire attached
Definition: operation.cc:56
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
double height() const
Definition: SVGItem.h:45
std::string timeUnit
Definition: simulation.h:35
void drawSymbol(const char *s) const
Definition: operation.h:162
#define M_PI
Definition: operation.cc:36
represents the units (in sense of dimensional analysis) of a variable.
Definition: units.h:34
std::string str(T x)
utility function to create a string representation of a numeric type
Definition: str.h:33
factory class template, for creating objects of type T<O>. N is the maximum value of O ...
Definition: operationType.h:76
const Minsky & cminsky()
const version to help in const correctness
Definition: minsky.h:549
void throw_error(const std::string &) const
mark item on canvas, then throw
Definition: item.cc:86
SVGRenderer histogramResource
Definition: minsky.h:225
void combineInput(double &x, double y) const override
combine two input wires
Definition: operation.cc:54
void combineInput(double &x, double y) const override
combine two input wires
Definition: operation.cc:48
void combineInput(double &x, double y) const override
combine two input wires
Definition: operation.cc:74
float x0
Definition: lasso.h:30
void render(cairo_t *) const
Definition: SVGItem.cc:82
void normalise()
Definition: units.h:42
float y1
Definition: lasso.h:30
float x1
Definition: lasso.h:30
void drawPlus() const
Definition: operation.h:126
void combineInput(double &x, double y) const override
combine two input wires
Definition: operation.cc:80
UnitsExpressionWalker timeUnit
virtual std::weak_ptr< Port > ports(std::size_t i) const
callback to be run when item deleted from group
Definition: item.h:180
float y0
Definition: lasso.h:30
legacy data importer object
Definition: dataOp.h:28
string to_string(CONST84 char *x)
Definition: minskyTCLObj.h:33
void drawMinus() const
Definition: operation.h:135
float x(float x, float y) const
Definition: geometry.h:59
helper class to draw port label symbols
Definition: operation.h:120
double identity() const override
input port value if no wire attached
Definition: operation.cc:76
Expr log(const Expr &x)
Definition: expr.h:120
void combineInput(double &x, double y) const override
combine two input wires
Definition: operation.cc:61