00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <iostream>
00016 #include <algorithm>
00017
00018 #include <QtGui/QDialog>
00019 #include <QtGui/QDoubleValidator>
00020 #include <QtGui/QGraphicsSceneMouseEvent>
00021 #include <QtGui/QHBoxLayout>
00022 #include <QtGui/QLabel>
00023 #include <QtGui/QVBoxLayout>
00024 #include <QtGui/QPushButton>
00025 #include <QtGui/QResizeEvent>
00026 #include <QtGui/QDialogButtonBox>
00027
00028 #include <SeVec3d.h>
00029 #include <SeExprBuiltins.h>
00030 #include <cfloat>
00031
00032 #include "SeExprEdCurve.h"
00033
00034 void CurveScene::removeAll()
00035 {
00036 _cvs.clear();
00037 }
00038
00039
00040 void CurveGraphicsView::resizeEvent(QResizeEvent *event)
00041 {
00042 emit resizeSignal(event->size().width(), event->size().height());
00043 }
00044
00045
00046 CurveScene::CurveScene() : _curve(new T_CURVE),_width(320), _height(170), _interp(T_CURVE::kMonotoneSpline), _selectedItem(-1), _curvePoly(0), _baseRect(0), _lmb(false)
00047 {
00048 rebuildCurve();
00049 resize(_width, _height);
00050 }
00051
00052 CurveScene::~CurveScene()
00053 {
00054 delete _curve;
00055 }
00056
00057 void CurveScene::resize(const int width, const int height)
00058 {
00059
00060 _width = width-16;
00061 _height = height-16;
00062 setSceneRect(-9, -7, width, height);
00063 drawRect();
00064 drawPoly();
00065 drawPoints();
00066 }
00067
00068 void CurveScene::rebuildCurve()
00069 {
00070 delete _curve;
00071 _curve=new T_CURVE;
00072 for(unsigned int i=0;i<_cvs.size();i++)
00073 _curve->addPoint(_cvs[i]._pos,_cvs[i]._val,_cvs[i]._interp);
00074 _curve->preparePoints();
00075 }
00076
00077
00078 void CurveScene::addPoint(double x, double y, const T_INTERP interp, const bool select)
00079 {
00080 x=SeExpr::clamp(x,0,1);
00081 y=SeExpr::clamp(y,0,1);
00082
00083 _cvs.push_back(T_CURVE::CV(x,y,T_INTERP(interp)));
00084 int newIndex=_cvs.size()-1;
00085
00086 rebuildCurve();
00087
00088 if(select) _selectedItem = newIndex;
00089 drawPoly();
00090 drawPoints();
00091 }
00092
00093
00094 void CurveScene::removePoint(const int index)
00095 {
00096 _cvs.erase(_cvs.begin()+index);
00097 _selectedItem = -1;
00098 rebuildCurve();
00099
00100 drawPoly();
00101 drawPoints();
00102 emitCurveChanged();
00103 }
00104
00105 void CurveScene::keyPressEvent(QKeyEvent *event)
00106 {
00107 if (((event->key() == Qt::Key_Backspace) ||
00108 (event->key() == Qt::Key_Delete)) && (_selectedItem >= 0)) {
00109
00110 removePoint(_selectedItem);
00111 }
00112 }
00113
00114
00115 void CurveScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
00116 {
00117 _lmb = true;
00118 QPointF pos = mouseEvent->scenePos();
00119
00120 QList<QGraphicsItem *> itemList = items(pos);
00121 if (itemList.empty()) {
00122 _selectedItem = -1;
00123 emit cvSelected(-1, -1, _interp);
00124 drawPoints();
00125 } else if (itemList[0]->zValue() == 2) {
00126
00127 const int numCircle = _circleObjects.size();
00128 for (int i = 0; i < numCircle; i++ ) {
00129 QGraphicsItem *obj = _circleObjects[i];
00130 if (obj == itemList[0]) {
00131 _selectedItem = i;
00132 _interp = _cvs[i]._interp;
00133 emit cvSelected(_cvs[i]._pos, _cvs[i]._val, _cvs[i]._interp);
00134 }
00135 }
00136 drawPoints();
00137 } else {
00138
00139 double myx=pos.x()/_width;
00140 T_INTERP interpFromNearby=_curve->getLowerBoundCV(SeExpr::clamp(myx,0,1))._interp;
00141 if(interpFromNearby==T_CURVE::kNone) interpFromNearby=T_CURVE::kMonotoneSpline;
00142
00143 addPoint(myx, pos.y()/_height, interpFromNearby);
00144 emitCurveChanged();
00145 }
00146 }
00147
00148
00149 void CurveScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
00150 {
00151 if (_lmb) {
00152 QPointF point = mouseEvent->scenePos();
00153 if (_selectedItem >= 0) {
00154
00155 double pos = SeExpr::clamp(point.x()/_width,0,1);
00156 double val = SeExpr::clamp(point.y()/_height,0,1);
00157 _cvs[_selectedItem]._pos=pos;
00158 _cvs[_selectedItem]._val=val;
00159 rebuildCurve();
00160 emit cvSelected(pos, val, _cvs[_selectedItem]._interp);
00161 drawPoly();
00162 drawPoints();
00163 emitCurveChanged();
00164 }
00165 }
00166 }
00167
00168
00169 void CurveScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
00170 {
00171 Q_UNUSED(mouseEvent);
00172 _lmb = false;
00173 }
00174
00175
00176 void CurveScene::interpChanged(const int interp)
00177 {
00178 _interp = T_INTERP(interp);
00179 if (_selectedItem >= 0) {
00180 _cvs[_selectedItem]._interp=_interp;
00181 rebuildCurve();
00182 drawPoly();
00183 emitCurveChanged();
00184 }
00185 }
00186
00187
00188 void CurveScene::selPosChanged(double posInput)
00189 {
00190 if (_selectedItem >= 0) {
00191 double pos=SeExpr::clamp(posInput,0,1);
00192 _cvs[_selectedItem]._pos=pos;
00193 rebuildCurve();
00194 drawPoly();
00195 drawPoints();
00196 emitCurveChanged();
00197 }
00198 }
00199
00200
00201 void CurveScene::selValChanged(double val)
00202 {
00203 if (_selectedItem >= 0) {
00204 val=SeExpr::clamp(val,0,1);
00205 _cvs[_selectedItem]._val=val;
00206 rebuildCurve();
00207 drawPoly();
00208 drawPoints();
00209 emitCurveChanged();
00210 }
00211 }
00212
00213
00214 void CurveScene::emitCurveChanged()
00215 {
00216 emit curveChanged();
00217 }
00218
00219
00220 void CurveScene::drawRect()
00221 {
00222 if (_baseRect == 0) {
00223 _baseRect = addRect(0, 0, _width, _height, QPen(Qt::black, 1.0), QBrush(Qt::gray));
00224
00225 }
00226 _baseRect->setRect(0, 0, _width, _height);
00227 _baseRect->setZValue(0);
00228 }
00229
00230
00231
00232 void CurveScene::drawPoly()
00233 {
00234 if (_curvePoly == 0) {
00235 _curvePoly = addPolygon(QPolygonF(), QPen(Qt::black, 1.0), QBrush(Qt::darkGray));
00236 }
00237
00238 QPolygonF poly;
00239 poly.append(QPointF(_width, 0));
00240 poly.append(QPointF(0, 0));
00241 for (int i = 0; i < 1000; i++) {
00242 double x = i/1000.0;
00243 poly.append(QPointF(_width*x, _height*_curve->getValue(x)));
00244 }
00245 poly.append(QPointF(_width, 0));
00246 _curvePoly->setPolygon(poly);
00247 _curvePoly->setZValue(1);
00248 }
00249
00250
00251
00252 void CurveScene::drawPoints()
00253 {
00254 while (_circleObjects.size()) {
00255 delete _circleObjects[0];
00256 _circleObjects.erase(_circleObjects.begin());
00257 }
00258 const int numCV = _cvs.size();
00259 for (int i = 0; i < numCV; i++) {
00260 const T_CURVE::CV& pt = _cvs[i];
00261 QPen pen;
00262 if (i == _selectedItem) {
00263 pen = QPen(Qt::white,1.0);
00264 } else {
00265 pen = QPen(Qt::black,1.0);
00266 }
00267 _circleObjects.push_back(addEllipse(pt._pos*_width-4, pt._val*_height-4, 8, 8, pen, QBrush()));
00268 QGraphicsEllipseItem *circle = _circleObjects.back();
00269 circle->setFlag(QGraphicsItem::ItemIsMovable, true);
00270 circle->setZValue(2);
00271 }
00272 }
00273
00274 SeExprEdCurve::SeExprEdCurve(QWidget* parent, QString pLabel, QString vLabel, QString iLabel,
00275 bool expandable) : QWidget(parent), _scene(0), _selPosEdit(0), _selValEdit(0), _interpComboBox(0)
00276 {
00277 Q_UNUSED(iLabel);
00278 QHBoxLayout *mainLayout = new QHBoxLayout();
00279 mainLayout->setSpacing(2);
00280 mainLayout->setMargin(4);
00281
00282 QWidget *edits = new QWidget;
00283 QVBoxLayout *editsLayout = new QVBoxLayout;
00284 editsLayout->setAlignment(Qt::AlignTop);
00285 editsLayout->setSpacing(0);
00286 editsLayout->setMargin(0);
00287 edits->setLayout(editsLayout);
00288
00289 QWidget *selPos = new QWidget;
00290 QHBoxLayout *selPosLayout = new QHBoxLayout;
00291 selPosLayout->setSpacing(1);
00292 selPosLayout->setMargin(1);
00293 selPos->setLayout(selPosLayout);
00294 _selPosEdit = new QLineEdit;
00295 QDoubleValidator *posValidator = new QDoubleValidator(0.0,1.0,6,_selPosEdit);
00296 _selPosEdit->setValidator(posValidator);
00297 int editwidth = QFontMetrics(font()).width("9.999")+8;
00298 _selPosEdit->setFixedWidth(editwidth);
00299 _selPosEdit->setFixedHeight(20);
00300 selPosLayout->addStretch(50);
00301 QLabel *posLabel;
00302 if (pLabel.isEmpty()) {
00303 posLabel = new QLabel("Selected Position: ");
00304 } else {
00305 posLabel = new QLabel(pLabel);
00306 }
00307 selPosLayout->addWidget(posLabel);
00308 selPosLayout->addWidget(_selPosEdit);
00309
00310 QWidget *selVal = new QWidget;
00311 QBoxLayout *selValLayout = new QHBoxLayout;
00312 selValLayout->setSpacing(1);
00313 selValLayout->setMargin(1);
00314 selVal->setLayout(selValLayout);
00315 _selValEdit = new QLineEdit;
00316 QDoubleValidator *valValidator = new QDoubleValidator(0.0,1.0,6,_selValEdit);
00317 _selValEdit->setValidator(valValidator);
00318 _selValEdit->setFixedWidth(editwidth);
00319 _selValEdit->setFixedHeight(20);
00320 selValLayout->addStretch(50);
00321 QLabel *valLabel;
00322 if (vLabel.isEmpty()) {
00323 valLabel = new QLabel("Selected Value: ");
00324 } else {
00325 valLabel = new QLabel(vLabel);
00326 }
00327 selValLayout->addWidget(valLabel);
00328 selValLayout->addWidget(_selValEdit);
00329
00330 _interpComboBox = new QComboBox;
00331 _interpComboBox->addItem("None");
00332 _interpComboBox->addItem("Linear");
00333 _interpComboBox->addItem("Smooth");
00334 _interpComboBox->addItem("Spline");
00335 _interpComboBox->addItem("MSpline");
00336 _interpComboBox->setCurrentIndex(4);
00337 _interpComboBox->setFixedWidth(70);
00338 _interpComboBox->setFixedHeight(20);
00339
00340
00341 editsLayout->addWidget(selPos);
00342 editsLayout->addWidget(selVal);
00343 editsLayout->addWidget(_interpComboBox);
00344
00345 QFrame *curveFrame = new QFrame;
00346 curveFrame->setFrameShape(QFrame::Panel);
00347 curveFrame->setFrameShadow(QFrame::Sunken);
00348 curveFrame->setLineWidth(1);
00349 QHBoxLayout *curveFrameLayout = new QHBoxLayout;
00350 curveFrameLayout->setMargin(0);
00351 CurveGraphicsView *curveView = new CurveGraphicsView;
00352 curveView->setFrameShape(QFrame::Panel);
00353 curveView->setFrameShadow(QFrame::Sunken);
00354 curveView->setLineWidth(1);
00355 curveView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00356 curveView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00357 _scene = new CurveScene;
00358 curveView->setScene(_scene);
00359 curveView->setTransform(QTransform().scale(1, -1));
00360 curveView->setRenderHints(QPainter::Antialiasing);
00361 curveFrameLayout->addWidget(curveView);
00362 curveFrame->setLayout(curveFrameLayout);
00363
00364 mainLayout->addWidget(edits);
00365 mainLayout->addWidget(curveFrame);
00366 if(expandable){
00367 QPushButton* expandButton=new QPushButton(">");
00368 expandButton->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Expanding);
00369 expandButton->setFixedWidth(15);
00370 mainLayout->addWidget(expandButton);
00371
00372 connect(expandButton, SIGNAL(clicked()), this, SLOT(openDetail()));
00373 }
00374 mainLayout->setStretchFactor(curveFrame,100);
00375 setLayout(mainLayout);
00376
00377
00378
00379
00380 connect(_scene, SIGNAL(cvSelected(double, double, T_INTERP)), this, SLOT(cvSelectedSlot(double, double, T_INTERP)));
00381
00382 connect(_interpComboBox, SIGNAL(activated(int)), _scene, SLOT(interpChanged(int)));
00383
00384 connect(_selPosEdit, SIGNAL(returnPressed()), this, SLOT(selPosChanged()));
00385 connect(this, SIGNAL(selPosChangedSignal(double)), _scene, SLOT(selPosChanged(double)));
00386
00387 connect(_selValEdit, SIGNAL(returnPressed()), this, SLOT(selValChanged()));
00388 connect(this, SIGNAL(selValChangedSignal(double)), _scene, SLOT(selValChanged(double)));
00389
00390 connect(curveView, SIGNAL(resizeSignal(int, int)), _scene, SLOT(resize(int, int)));
00391
00392 }
00393
00394
00395
00396 void SeExprEdCurve::cvSelectedSlot(double pos, double val, T_INTERP interp)
00397 {
00398 QString posStr;
00399 if (pos >= 0.0) posStr.setNum(pos, 'f', 3);
00400 _selPosEdit->setText(posStr);
00401 QString valStr;
00402 if (val >= 0.0) valStr.setNum(val, 'f', 3);
00403 _selValEdit->setText(valStr);
00404 _interpComboBox->setCurrentIndex(interp);
00405 }
00406
00407
00408
00409 void SeExprEdCurve::selPosChanged()
00410 {
00411 double pos = QString(_selPosEdit->text()).toDouble();
00412 _selPosEdit->setText(QString("%1").arg(pos, 0, 'f', 3));
00413 emit selPosChangedSignal(pos);
00414 }
00415
00416
00417
00418 void SeExprEdCurve::selValChanged()
00419 {
00420 double val = QString(_selValEdit->text()).toDouble();
00421 val=SeExpr::clamp(val,0,1);
00422 _selValEdit->setText(QString("%1").arg(val, 0, 'f', 3));
00423 emit selValChangedSignal(val);
00424 }
00425
00426 void SeExprEdCurve::openDetail()
00427 {
00428 QDialog* dialog=new QDialog();
00429 dialog->setMinimumWidth(1024);
00430 dialog->setMinimumHeight(400);
00431 SeExprEdCurve* curve=new SeExprEdCurve(0,"","","",false);
00432
00433
00434 const std::vector<T_CURVE::CV>& data=_scene->_cvs;
00435 typedef std::vector<T_CURVE::CV>::const_iterator ITERATOR;
00436 for(ITERATOR i=data.begin();i!=data.end();++i)
00437 curve->addPoint(i->_pos,i->_val,i->_interp);
00438
00439 QVBoxLayout* layout=new QVBoxLayout();
00440 dialog->setLayout(layout);
00441 layout->addWidget(curve);
00442 QDialogButtonBox* buttonbar=new QDialogButtonBox();
00443 buttonbar->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
00444 connect(buttonbar,SIGNAL(accepted()),dialog,SLOT(accept()));
00445 connect(buttonbar,SIGNAL(rejected()),dialog,SLOT(reject()));
00446 layout->addWidget(buttonbar);
00447
00448 if(dialog->exec()==QDialog::Accepted){
00449
00450 _scene->removeAll();
00451 const std::vector<T_CURVE::CV>& dataNew=curve->_scene->_cvs;
00452 typedef std::vector<T_CURVE::CV>::const_iterator ITERATOR;
00453 for(ITERATOR i=dataNew.begin();i!=dataNew.end();++i)
00454 addPoint(i->_pos,i->_val,i->_interp);
00455 _scene->emitCurveChanged();
00456 }
00457
00458
00459 if(dialog->exec()==QDialog::Accepted){
00460
00461 _scene->removeAll();
00462 const std::vector<T_CURVE::CV>& dataNew=curve->_scene->_cvs;
00463 typedef std::vector<T_CURVE::CV>::const_iterator ITERATOR;
00464 for(ITERATOR i=dataNew.begin();i!=dataNew.end();++i)
00465 addPoint(i->_pos,i->_val,i->_interp);
00466 _scene->emitCurveChanged();
00467 }
00468 }
00469
00470 void SeExprEdCurve::addPoint(const double x, const double y, T_INTERP interp, const bool select)
00471 {
00472 _scene->addPoint(x, y, interp, select);
00473 }
00474