SeExpr
ExprCurve.cpp
Go to the documentation of this file.
1 /*
2 * Copyright Disney Enterprises, Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License
6 * and the following modification to it: Section 6 Trademarks.
7 * deleted and replaced with:
8 *
9 * 6. Trademarks. This License does not grant permission to use the
10 * trade names, trademarks, service marks, or product names of the
11 * Licensor and its affiliates, except as required for reproducing
12 * the content of the NOTICE file.
13 *
14 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * @file ExprCurve.cpp
18 * @brief Contains PyQt4 Ramp Widget to emulate Maya's ramp widget
19 * @author Arthur Shek
20 * @version ashek 05/04/09 Initial Version
21 */
22 #include <iostream>
23 #include <algorithm>
24 
25 #include <QtGui/QDialog>
26 #include <QtGui/QDoubleValidator>
27 #include <QtGui/QGraphicsSceneMouseEvent>
28 #include <QtGui/QHBoxLayout>
29 #include <QtGui/QLabel>
30 #include <QtGui/QVBoxLayout>
31 #include <QtGui/QPushButton>
32 #include <QtGui/QResizeEvent>
33 #include <QtGui/QDialogButtonBox>
34 #include <QtGui/QMenu>
35 
36 #include <SeExpr2/ExprBuiltins.h>
37 #include <cfloat>
38 
39 #include "ExprCurve.h"
40 
42 {
43  _cvs.clear();
44 }
45 
46 
47 void CurveGraphicsView::resizeEvent(QResizeEvent *event)
48 {
49  emit resizeSignal(event->size().width(), event->size().height());
50 }
51 
52 
53 CurveScene::CurveScene() : _curve(new T_CURVE),_width(320), _height(170), _interp(T_CURVE::kMonotoneSpline), _selectedItem(-1), _curvePoly(0), _baseRect(0), _lmb(false)
54 {
55  rebuildCurve();
57 }
58 
60 {
61  delete _curve;
62 }
63 
64 void CurveScene::resize(const int width, const int height)
65 {
66  // width and height already have the 8 px padding factored in
67  _width = width-16;
68  _height = height-16;
69  setSceneRect(-9, -7, width, height);
70  drawRect();
71  drawPoly();
72  drawPoints();
73 }
74 
76 {
77  delete _curve;
78  _curve=new T_CURVE;
79  for(unsigned int i=0;i<_cvs.size();i++)
80  _curve->addPoint(_cvs[i]._pos,_cvs[i]._val,_cvs[i]._interp);
82 }
83 
84 
85 void CurveScene::addPoint(double x, double y, const T_INTERP interp, const bool select)
86 {
87  x=SeExpr2::clamp(x,0,1);
88  y=SeExpr2::clamp(y,0,1);
89 
90  _cvs.push_back(T_CURVE::CV(x,y,T_INTERP(interp)));
91  int newIndex=_cvs.size()-1;
92 
93  rebuildCurve();
94 
95  if(select) _selectedItem = newIndex;
96  drawPoly();
97  drawPoints();
98 }
99 
100 
102 {
103  _cvs.erase(_cvs.begin()+index);
104  _selectedItem = -1;
105  rebuildCurve();
106 
107  drawPoly();
108  drawPoints();
110 }
111 
112 void CurveScene::keyPressEvent(QKeyEvent *event)
113 {
114  if (((event->key() == Qt::Key_Backspace) ||
115  (event->key() == Qt::Key_Delete)) && (_selectedItem >= 0)) {
116  // user hit delete with cv selected
118  }
119 }
120 
121 
122 void CurveScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
123 {
124  _lmb = true;
125  QPointF pos = mouseEvent->scenePos();
126  // get items under mouse click
127  QList<QGraphicsItem *> itemList = items(pos);
128  if (itemList.empty()) {
129  _selectedItem = -1;
130  emit cvSelected(-1, -1, _interp);
131  drawPoints();
132  } else if (itemList[0]->zValue() == 2) {
133  // getting here means we've selected a current point
134  const int numCircle = _circleObjects.size();
135  for (int i = 0; i < numCircle; i++ ) {
136  QGraphicsItem *obj = _circleObjects[i];
137  if (obj == itemList[0]) {
138  _selectedItem = i;
139  _interp = _cvs[i]._interp;
140  emit cvSelected(_cvs[i]._pos, _cvs[i]._val, _cvs[i]._interp);
141  }
142  }
143  drawPoints();
144  } else {
145  if(mouseEvent->buttons() == Qt::LeftButton){
146  // getting here means we want to create a new point
147  double myx=pos.x()/_width;
148  T_INTERP interpFromNearby=_curve->getLowerBoundCV(SeExpr2::clamp(myx,0,1))._interp;
149  if(interpFromNearby==T_CURVE::kNone)
150  interpFromNearby=T_CURVE::kMonotoneSpline;
151  addPoint(myx, pos.y()/_height, interpFromNearby);
153  }else{
154  _selectedItem=-1;
155  drawPoints();
156  }
157  }
158 }
159 
160 void CurveScene::contextMenuEvent(QGraphicsSceneContextMenuEvent* event){
161  if(_selectedItem>=0){
162  QMenu *menu = new QMenu(event->widget());
163  QAction *deleteAction = menu->addAction("Delete Point");
164  //menu->addAction("Cancel");
165  QAction *action = menu->exec(event->screenPos());
166  if (action == deleteAction) removePoint(_selectedItem);
167  }
168 }
169 
170 void CurveScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
171 {
172  if (_lmb) {
173  QPointF point = mouseEvent->scenePos();
174  if (_selectedItem >= 0) {
175  // clamp motion to inside curve area
176  double pos = SeExpr2::clamp(point.x()/_width,0,1);
177  double val = SeExpr2::clamp(point.y()/_height,0,1);
178  _cvs[_selectedItem]._pos=pos;
179  _cvs[_selectedItem]._val=val;
180  rebuildCurve();
181  emit cvSelected(pos, val, _cvs[_selectedItem]._interp);
182  drawPoly();
183  drawPoints();
185  }
186  }
187 }
188 
189 
190 void CurveScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
191 {
192  Q_UNUSED(mouseEvent);
193  _lmb = false;
194 }
195 
196 // user selected a different interpolation type, redraw
197 void CurveScene::interpChanged(const int interp)
198 {
199  _interp = T_INTERP(interp);
200  if (_selectedItem >= 0) {
201  _cvs[_selectedItem]._interp=_interp;
202  rebuildCurve();
203  drawPoly();
205  }
206 }
207 
208 // user entered a different point position, redraw
209 void CurveScene::selPosChanged(double posInput)
210 {
211  if (_selectedItem >= 0) {
212  double pos=SeExpr2::clamp(posInput,0,1);
213  _cvs[_selectedItem]._pos=pos;
214  rebuildCurve();
215  drawPoly();
216  drawPoints();
218  }
219 }
220 
221 // user entered a different point value, redraw
223 {
224  if (_selectedItem >= 0) {
225  val=SeExpr2::clamp(val,0,1);
226  _cvs[_selectedItem]._val=val;
227  rebuildCurve();
228  drawPoly();
229  drawPoints();
231  }
232 }
233 
234 // return points in reverse order in order to use same parsing in editor
236 {
237  emit curveChanged();
238 }
239 
240 // draws the base gray outline rectangle
242 {
243  if (_baseRect == 0) {
244  _baseRect = addRect(0, 0, _width, _height, QPen(Qt::black, 1.0), QBrush(Qt::gray));
245 
246  }
247  _baseRect->setRect(0, 0, _width, _height);
248  _baseRect->setZValue(0);
249 }
250 
251 
252 // draws the poly curve representation
254 {
255  if (_curvePoly == 0) {
256  _curvePoly = addPolygon(QPolygonF(), QPen(Qt::black, 1.0), QBrush(Qt::darkGray));
257  }
258 
259  QPolygonF poly;
260  poly.append(QPointF(_width, 0));
261  poly.append(QPointF(0, 0));
262  for (int i = 0; i < 1000; i++) {
263  double x = i/1000.0;
264  poly.append(QPointF(_width*x, _height*_curve->getValue(x)));
265  }
266  poly.append(QPointF(_width, 0));
267  _curvePoly->setPolygon(poly);
268  _curvePoly->setZValue(1);
269 }
270 
271 
272 // draws the cv points
274 {
275  while (_circleObjects.size()) {
276  delete _circleObjects[0];
277  _circleObjects.erase(_circleObjects.begin());
278  }
279  const int numCV = _cvs.size();
280  for (int i = 0; i < numCV; i++) {
281  const T_CURVE::CV& pt = _cvs[i];
282  QPen pen;
283  if (i == _selectedItem) {
284  pen = QPen(Qt::white,1.0);
285  } else {
286  pen = QPen(Qt::black,1.0);
287  }
288  _circleObjects.push_back(addEllipse(pt._pos*_width-4, pt._val*_height-4, 8, 8, pen, QBrush()));
289  QGraphicsEllipseItem *circle = _circleObjects.back();
290  circle->setFlag(QGraphicsItem::ItemIsMovable, true);
291  circle->setZValue(2);
292  }
293 }
294 
295 ExprCurve::ExprCurve(QWidget* parent, QString pLabel, QString vLabel, QString iLabel,
296  bool expandable) : QWidget(parent), _scene(0), _selPosEdit(0), _selValEdit(0), _interpComboBox(0)
297 {
298  Q_UNUSED(iLabel);
299  QHBoxLayout *mainLayout = new QHBoxLayout();
300  mainLayout->setSpacing(2);
301  mainLayout->setMargin(4);
302 
303  QWidget *edits = new QWidget;
304  QVBoxLayout *editsLayout = new QVBoxLayout;
305  editsLayout->setAlignment(Qt::AlignTop);
306  editsLayout->setSpacing(0);
307  editsLayout->setMargin(0);
308  edits->setLayout(editsLayout);
309 
310  QWidget *selPos = new QWidget;
311  QHBoxLayout *selPosLayout = new QHBoxLayout;
312  selPosLayout->setSpacing(1);
313  selPosLayout->setMargin(1);
314  selPos->setLayout(selPosLayout);
315  _selPosEdit = new QLineEdit;
316  QDoubleValidator *posValidator = new QDoubleValidator(0.0,1.0,6,_selPosEdit);
317  _selPosEdit->setValidator(posValidator);
318  int editwidth = QFontMetrics(font()).width("9.999")+8;
319  _selPosEdit->setFixedWidth(editwidth);
320  _selPosEdit->setFixedHeight(20);
321  selPosLayout->addStretch(50);
322  QLabel *posLabel;
323  if (pLabel.isEmpty()) {
324  posLabel = new QLabel("Selected Position: ");
325  } else {
326  posLabel = new QLabel(pLabel);
327  }
328  selPosLayout->addWidget(posLabel);
329  selPosLayout->addWidget(_selPosEdit);
330 
331  QWidget *selVal = new QWidget;
332  QBoxLayout *selValLayout = new QHBoxLayout;
333  selValLayout->setSpacing(1);
334  selValLayout->setMargin(1);
335  selVal->setLayout(selValLayout);
336  _selValEdit = new QLineEdit;
337  QDoubleValidator *valValidator = new QDoubleValidator(0.0,1.0,6,_selValEdit);
338  _selValEdit->setValidator(valValidator);
339  _selValEdit->setFixedWidth(editwidth);
340  _selValEdit->setFixedHeight(20);
341  selValLayout->addStretch(50);
342  QLabel *valLabel;
343  if (vLabel.isEmpty()) {
344  valLabel = new QLabel("Selected Value: ");
345  } else {
346  valLabel = new QLabel(vLabel);
347  }
348  selValLayout->addWidget(valLabel);
349  selValLayout->addWidget(_selValEdit);
350 
351  _interpComboBox = new QComboBox;
352  _interpComboBox->addItem("None");
353  _interpComboBox->addItem("Linear");
354  _interpComboBox->addItem("Smooth");
355  _interpComboBox->addItem("Spline");
356  _interpComboBox->addItem("MSpline");
357  _interpComboBox->setCurrentIndex(4);
358  _interpComboBox->setFixedWidth(70);
359  _interpComboBox->setFixedHeight(20);
360 
361 
362  editsLayout->addWidget(selPos);
363  editsLayout->addWidget(selVal);
364  editsLayout->addWidget(_interpComboBox);
365 
366  QFrame *curveFrame = new QFrame;
367  curveFrame->setFrameShape(QFrame::Panel);
368  curveFrame->setFrameShadow(QFrame::Sunken);
369  curveFrame->setLineWidth(1);
370  QHBoxLayout *curveFrameLayout = new QHBoxLayout;
371  curveFrameLayout->setMargin(0);
372  CurveGraphicsView *curveView = new CurveGraphicsView;
373  curveView->setFrameShape(QFrame::Panel);
374  curveView->setFrameShadow(QFrame::Sunken);
375  curveView->setLineWidth(1);
376  curveView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
377  curveView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
378  _scene = new CurveScene;
379  curveView->setScene(_scene);
380  curveView->setTransform(QTransform().scale(1, -1));
381  curveView->setRenderHints(QPainter::Antialiasing);
382  curveFrameLayout->addWidget(curveView);
383  curveFrame->setLayout(curveFrameLayout);
384 
385  mainLayout->addWidget(edits);
386  mainLayout->addWidget(curveFrame);
387  if(expandable){
388  QPushButton* expandButton=new QPushButton(">");
389  expandButton->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Expanding);
390  expandButton->setFixedWidth(15);
391  mainLayout->addWidget(expandButton);
392  // open a the detail widget when clicked
393  connect(expandButton, SIGNAL(clicked()), this, SLOT(openDetail()));
394  }
395  mainLayout->setStretchFactor(curveFrame,100);
396  setLayout(mainLayout);
397 
398  // SIGNALS
399 
400  // when a user selects a cv, update the fields on left
401  connect(_scene, SIGNAL(cvSelected(double, double, T_INTERP)), this, SLOT(cvSelectedSlot(double, double, T_INTERP)));
402  // when a user selects a different interp, the curve has to redraw
403  connect(_interpComboBox, SIGNAL(activated(int)), _scene, SLOT(interpChanged(int)));
404  // when a user types a different position, the curve has to redraw
405  connect(_selPosEdit, SIGNAL(returnPressed()), this, SLOT(selPosChanged()));
406  connect(this, SIGNAL(selPosChangedSignal(double)), _scene, SLOT(selPosChanged(double)));
407  // when a user types a different value, the curve has to redraw
408  connect(_selValEdit, SIGNAL(returnPressed()), this, SLOT(selValChanged()));
409  connect(this, SIGNAL(selValChangedSignal(double)), _scene, SLOT(selValChanged(double)));
410  // when the widget is resized, resize the curve widget
411  connect(curveView, SIGNAL(resizeSignal(int, int)), _scene, SLOT(resize(int, int)));
412 
413 }
414 
415 
416 // CV selected, update the user interface fields.
417 void ExprCurve::cvSelectedSlot(double pos, double val, T_INTERP interp)
418 {
419  QString posStr;
420  if (pos >= 0.0) posStr.setNum(pos, 'f', 3);
421  _selPosEdit->setText(posStr);
422  QString valStr;
423  if (val >= 0.0) valStr.setNum(val, 'f', 3);
424  _selValEdit->setText(valStr);
425  _interpComboBox->setCurrentIndex(interp);
426 }
427 
428 
429 // User entered new position, round and send signal to redraw curve.
431 {
432  double pos = QString(_selPosEdit->text()).toDouble();
433  _selPosEdit->setText(QString("%1").arg(pos, 0, 'f', 3));
434  emit selPosChangedSignal(pos);
435 }
436 
437 
438 // User entered new value, round and send signal to redraw curve.
440 {
441  double val = QString(_selValEdit->text()).toDouble();
442  val=SeExpr2::clamp(val,0,1);
443  _selValEdit->setText(QString("%1").arg(val, 0, 'f', 3));
444  emit selValChangedSignal(val);
445 }
446 
448 {
449  QDialog* dialog=new QDialog();
450  dialog->setMinimumWidth(1024);
451  dialog->setMinimumHeight(400);
452  ExprCurve* curve=new ExprCurve(0,"","","",false);
453 
454  // copy points into new data
455  const std::vector<T_CURVE::CV>& data=_scene->_cvs;
456  typedef std::vector<T_CURVE::CV>::const_iterator ITERATOR;
457  for(ITERATOR i=data.begin();i!=data.end();++i)
458  curve->addPoint(i->_pos,i->_val,i->_interp);
459 
460  QVBoxLayout* layout=new QVBoxLayout();
461  dialog->setLayout(layout);
462  layout->addWidget(curve);
463  QDialogButtonBox* buttonbar=new QDialogButtonBox();
464  buttonbar->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
465  connect(buttonbar,SIGNAL(accepted()),dialog,SLOT(accept()));
466  connect(buttonbar,SIGNAL(rejected()),dialog,SLOT(reject()));
467  layout->addWidget(buttonbar);
468 
469  if(dialog->exec()==QDialog::Accepted){
470  // copy points back from child
471  _scene->removeAll();
472  const std::vector<T_CURVE::CV>& dataNew=curve->_scene->_cvs;
473  typedef std::vector<T_CURVE::CV>::const_iterator ITERATOR;
474  for(ITERATOR i=dataNew.begin();i!=dataNew.end();++i)
475  addPoint(i->_pos,i->_val,i->_interp);
477  }
478 
479 
480  if(dialog->exec()==QDialog::Accepted){
481  // copy points back from child
482  _scene->removeAll();
483  const std::vector<T_CURVE::CV>& dataNew=curve->_scene->_cvs;
484  typedef std::vector<T_CURVE::CV>::const_iterator ITERATOR;
485  for(ITERATOR i=dataNew.begin();i!=dataNew.end();++i)
486  addPoint(i->_pos,i->_val,i->_interp);
488  }
489 }
490 
491 void ExprCurve::addPoint(const double x, const double y, T_INTERP interp, const bool select)
492 {
493  _scene->addPoint(x, y, interp, select);
494 }
495 
void selValChangedSignal(double val)
SeExpr2::CurveFuncX curve
void preparePoints()
Prepares points for evaluation (sorts and computes boundaries, clamps extrema)
Definition: Curve.cpp:56
std::vector< QGraphicsEllipseItem * > _circleObjects
Definition: ExprCurve.h:111
int _selectedItem
Definition: ExprCurve.h:112
Interpolation curve class for double-&gt;double and double-&gt;Vec3D.
Definition: Curve.h:38
void cvSelectedSlot(double pos, double val, T_INTERP interp)
Definition: ExprCurve.cpp:417
T_CURVE * _curve
Definition: ExprCurve.h:95
InterpType _interp
Definition: Curve.h:55
T getValue(const double param) const
Evaluates curve and returns full value.
Definition: Curve.cpp:104
void resize(const int width, const int height)
Definition: ExprCurve.cpp:64
void drawPoly()
Definition: ExprCurve.cpp:253
void removeAll()
Definition: ExprCurve.cpp:41
CV getLowerBoundCV(const double param) const
Definition: Curve.cpp:199
void resizeSignal(int width, int height)
QComboBox * _interpComboBox
Definition: ExprCurve.h:148
QLineEdit * _selValEdit
Definition: ExprCurve.h:147
double _pos
Definition: Curve.h:53
virtual void resizeEvent(QResizeEvent *event)
Definition: ExprCurve.cpp:47
virtual void keyPressEvent(QKeyEvent *event)
Definition: ExprCurve.cpp:112
void selValChanged(double val)
Definition: ExprCurve.cpp:222
SeExpr2::Curve< double > T_CURVE
Definition: ExprCurve.h:63
The result is computed int int< br >< divstyle="margin-left:40px;"> Picks values randomly between loRange and hiRange based on supplied index(which is automatically hashed).&nbsp
void addPoint(const double x, const double y, const T_INTERP interp, bool select=false)
Definition: ExprCurve.cpp:491
T_CURVE::InterpType T_INTERP
Definition: ExprCurve.h:64
virtual void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
Definition: ExprCurve.cpp:122
void selPosChangedSignal(double pos)
T_INTERP _interp
Definition: ExprCurve.h:110
int _height
Definition: ExprCurve.h:109
void addPoint(double x, double y, const T_INTERP interp, const bool select=true)
Definition: ExprCurve.cpp:85
void emitCurveChanged()
Definition: ExprCurve.cpp:235
</pre >< h3 > A simple variable reference</h3 > This is not a very interesting subclass of expression until we add some additional variables Variables on some applications may be very dynamic In this we only need x
Definition: tutorial.txt:108
virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
Definition: ExprCurve.cpp:160
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
Definition: ExprCurve.cpp:190
void interpChanged(const int interp)
Definition: ExprCurve.cpp:197
QLineEdit * _selPosEdit
Definition: ExprCurve.h:146
void selPosChanged(double pos)
Definition: ExprCurve.cpp:209
CurveScene * _scene
Definition: ExprCurve.h:133
void cvSelected(double x, double y, T_INTERP interp)
At the mid point
Definition: userdoc.txt:136
void removePoint(const int index)
Definition: ExprCurve.cpp:101
void curveChanged()
QGraphicsRectItem * _baseRect
Definition: ExprCurve.h:114
double clamp(double x, double lo, double hi)
Definition: ExprBuiltins.h:40
void drawPoints()
Definition: ExprCurve.cpp:273
QGraphicsPolygonItem * _curvePoly
Definition: ExprCurve.h:113
void rebuildCurve()
Definition: ExprCurve.cpp:75
ExprCurve(QWidget *parent=0, QString pLabel="", QString vLabel="", QString iLabel="", bool expandable=true)
Definition: ExprCurve.cpp:295
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
Definition: ExprCurve.cpp:170
void drawRect()
Definition: ExprCurve.cpp:241
void addPoint(double position, const T &val, InterpType type)
Adds a point to the curve.
Definition: Curve.cpp:50
int _width
Definition: ExprCurve.h:108
InterpType
Supported interpolation types.
Definition: Curve.h:43
void selValChanged()
Definition: ExprCurve.cpp:439
void openDetail()
Definition: ExprCurve.cpp:447
std::vector< T_CURVE::CV > _cvs
Definition: ExprCurve.h:90
void selPosChanged()
Definition: ExprCurve.cpp:430
This is the same as the prman cellnoise function< br ></div >< br > float< b > float y< br > float< b > float y
Definition: userdoc.txt:218
bool _lmb
Definition: ExprCurve.h:115