Logo Search packages:      
Sourcecode: kalgebra version File versions  Download package

qgraph.cpp

#include "qgraph.h"

QGraph::QGraph(QWidget *parent, const char *name) : QWidget(parent, name, Qt::WStyle_NormalBorder) {
      m_squares=true;
      QColor cfons;
      cfons.setRgb(255,255,255);
      this->setPaletteBackgroundColor(cfons);
      resolucio=32;
      pushed=0;
      
      viewport = QRect::QRect(QPoint::QPoint(-12, 10), QPoint::QPoint(12, -10));
//    qDebug("%d", viewport.top());
      this->setFocusPolicy(QWidget::WheelFocus);
      micepos = new QLabel("", this);
      micepos->setFrameShape(QFrame::Box);
      micepos->setPaletteBackgroundColor(QColor(255,230,255));
      micepos->setAlignment(AlignAuto | AlignVCenter | AlignHCenter);
      micepos->hide();
      this->setCursor(QCursor(Qt::CrossCursor));
      setMouseTracking(true);
}

QGraph::~QGraph() {
      finestra.flush();
}

QSizePolicy QGraph::sizePolicy() const {
      return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}

void QGraph::dibuixa_eixos(QPainter *finestra){
      QPen ceixos;
      QPoint centre;
      double x;
      
      if(m_squares) {
            ceixos.setStyle(Qt::DotLine);
            ceixos.setColor(QColor(175,175,255));
            finestra->setPen(ceixos);
      } else {
            ceixos.setColor(QColor(100,100,255));
            ceixos.setStyle(Qt::SolidLine);
            finestra->setPen(ceixos);
      }
      
      for(x=viewport.left(); x<viewport.right()+1; x+=1.0f) {// ralletes X
            if(m_squares)
                  finestra->drawLine(QPoint( toWidget(x,viewport.top()).x(), this->height()), QPoint( toWidget(x,viewport.bottom()+1).x(), 0));
            else
                  finestra->drawLine(toWidget(x,0.0f), toWidget(x,0.0f)+QPoint(0,-3));
      }
            
      for(x=viewport.top(); x>viewport.bottom(); x-=1.0f) { // ralletes y
            if(m_squares)
                  finestra->drawLine(toWidget(viewport.left(),-x), QPoint(this->width(), toWidget(viewport.right()+1, -x).y()));
            else
                  finestra->drawLine(toWidget(0.0f,-x), toWidget(0.0f,-x)+QPoint(3,0));
      }
      
      ceixos.setColor(QColor(100,100,255));
      ceixos.setStyle(Qt::SolidLine);
      finestra->setPen(ceixos);
      //dibuixa eixos viewport
      finestra->drawLine(toWidget(viewport.left(),0), QPoint(this->width(), toWidget(viewport.right()+1, 0).y()));
      finestra->drawLine(QPoint( toWidget(0,viewport.top()).x(), this->height()), QPoint( toWidget(0,viewport.bottom()+1).x(), 0));
      //dibuixa eixos viewport
}


void QGraph::paintEvent( QPaintEvent * ){
      rang_x=(double) this->width()/((double)viewport.width()-1.0);
      rang_y=(double) this->height()/((double)viewport.height()-1);
      pintafunc(NULL);
}

void QGraph::mousePressEvent(QMouseEvent *e){
      pushed |= e->button(); //Left=1; Right=1<<1=2; Center=1<<2=4; Compatibilize with 3d's graph?
//    qDebug("%d", e->button());
      if(e->button() == Qt::LeftButton || e->button() == Qt::MidButton){
            press = e->pos();
            ant = toViewport(e->pos());
      }
}

void QGraph::wheelEvent(QWheelEvent *e){
      int d = e->delta()>0 ? 1 : -1;
//    qDebug("(%d, %d)(%d, %d)", viewport.left(), viewport.top()+d, viewport.right(), viewport.bottom()-d);
      if(viewport.left() < -1 && viewport.top()-d < -1 && viewport.right() > 1 && viewport.bottom()+d > 1){
//          qDebug("no surto");
            viewport.setLeft(viewport.left() - d);
            viewport.setTop(viewport.top() - d);
            viewport.setRight(viewport.right() + d);
            viewport.setBottom(viewport.bottom() + d);
            update_points();
      }
//    qDebug("(%d, %d)-(%d, %d)", viewport.left(), viewport.top(), viewport.right(),viewport.bottom());
}

void QGraph::mouseReleaseEvent(QMouseEvent *e){
      pushed &= ~e->button();
      if(e->button() == Qt::LeftButton){
            if((toViewport(press) - toViewport(e->pos())).isNull())
                  return;
            QPoint p=toViewport(e->pos())+viewport.topLeft(), p1=toViewport(press)+viewport.topLeft();
            if(p.x()<p1.x())
                  viewport = QRect(p, p1);
            else
                  viewport = QRect(p1, p);
            update_points();
      }
}

void QGraph::mouseMoveEvent(QMouseEvent *e){
      QDoublePoint p=fromWidget(e->pos());
      micepos->setText(QString("<qt>x=<b>%1</b> &nbsp; y=<b>%1<b></qt>").arg(p.x(),3,'f',2).arg(p.y(),3,'f',2));
      micepos->setGeometry(e->pos().x()+10, e->pos().y()+5, 160, 23);
      micepos->show();
      
      if(pushed & Qt::MidButton && ant != toViewport(e->pos())){
            QPoint rel = e->pos() - press;
            rel = toViewport(rel);
            qDebug("(%d, %d)", rel.x(), rel.y());
            viewport.setLeft(viewport.left() - rel.x()); viewport.setRight(viewport.right() - rel.x());
            viewport.setTop(viewport.top() + rel.y()); viewport.setBottom(viewport.bottom() + rel.y());
            update_points();
            press = e->pos();
            ant = toViewport(e->pos());
      }
}

void QGraph::keyPressEvent ( QKeyEvent * e ){
      switch(e->key()){
            case Qt::Key_Right:
                  viewport.setLeft(viewport.left() +1 ); viewport.setRight(viewport.right() +1 );
                  update_points();
                  break;
            case Qt::Key_Left:
                  viewport.setLeft(viewport.left() -1 ); viewport.setRight(viewport.right() -1 );
                  update_points();
                  break;
            case Qt::Key_Down:
                  viewport.setTop(viewport.top() +1 ); viewport.setBottom(viewport.bottom() +1);
                  update_points();
                  break;
            case Qt::Key_Up:
                  viewport.setTop(viewport.top() -1); viewport.setBottom(viewport.bottom() -1);
                  update_points();
                  break;
            case Qt::Key_Minus:
                  resolucio=(resolucio*viewport.width())/(viewport.width()+2);
                  viewport.setCoords(viewport.left() - 1, viewport.top() +1, viewport.right() + 1, viewport.bottom() -1);
                  update_points();
                  break;
            case Qt::Key_Plus:
                  if(viewport.height() < 3 && viewport.width() > 3){
                        resolucio=(resolucio*viewport.width())/(viewport.width()-2);
                        viewport.setCoords(viewport.left() + 1, viewport.top() -1, viewport.right() - 1, viewport.bottom() +1);
                  }
                  update_points();
                  break;
            
      }
}

void QGraph::update_points(){
//    QTime t;
//    t.restart();
      if(funclist.count()>0){
            for (QValueList<function>::iterator it = funclist.begin(); it != funclist.end(); ++it ){
                  (*it).update_points(viewport, resolucio);
            }
      }
//    qDebug( "_                                    Lasts: %d ms", t.elapsed() );
      this->repaint();
//    qDebug( "Repainted                            Lasts: %d ms", t.elapsed() );
}

void QGraph::pintafunc(QPaintDevice *qpd){
      QPoint ultim(0,0), act(0,0);
      QPen pfunc;
      pfunc.setColor(QColor(0,150,0));
      pfunc.setCapStyle(Qt::RoundCap);
      pfunc.setWidth(2);
      
      if(qpd)
            finestra.begin(qpd);
      else
            finestra.begin(this);
      
      dibuixa_eixos(&finestra);
      finestra.setPen(pfunc);
      
      bool nan=false;
      bool outside=false;
      
      if(funclist.count()>0){
            for (QValueList<function>::iterator it = funclist.begin(); it != funclist.end(); ++it ){
                  if((*it).isShown()){
                  pfunc.setColor((*it).color());
                  pfunc.setWidth((*it).selected()+1);
                  finestra.setPen(pfunc);
                  int i = (*it).npoints();      
                  for(register int j=0; j<i;j++){
                        if(!nan){
                              act=toWidget((*it).points[j].x(), (*it).points[j].y(), &nan);
//                            qDebug("%4d -- %4d", act.y(), act.x());//y->2
                              if(act.x() > 0 && (act.y() > 0 || (act.y()==0 && !outside)) && act.x() < this->width() && act.y() <= this->height()){
                                    finestra.drawLine(ultim, act);
                                    outside=false;
                              } else if(act.x() > 0 && act.x() < this->width() && ((act.y() < 0 && ultim.y()>0)  || (act.y() > this->height() && ultim.y() < this->height()))){
                                    bool out;
                                    QPoint act2 = act;
                                    trunca(&ultim, &act2, &out);
                                    if(!outside)
                                          finestra.drawLine(ultim, act2);
                                    outside = out;
                              }
                        }else
                              act=toWidget((*it).points[j].x(), (*it).points[j].y(), &nan);
                        ultim=act;
                  }
                  }}
      }
      finestra.end();
}

void QGraph::trunca(QPoint *ultim, QPoint *act, bool* outside){
      *outside=true;
      if(ultim->y()<0){
            double relation = ((double)ultim->x()-act->x())/((double)ultim->y()-act->y());
            ultim->setX(relation!=0.0? ultim->x() + round(relation*act->y()) : act->x());
            ultim->setY(0);
      } else if(act->y()<0){
            double relation = ((double)(act->x()-ultim->x()))/((double)(act->y()-ultim->y())*-1);
            act->setX( round(ultim->x() + ultim->y()*relation));
            act->setY(0);
      } else if(act->y() > this->height()) {
            act->setX( ultim->x()+1);
            act->setY(this->height());
      }/* else if(ultim->y() > this->height()) {
//          double relation = ((double) (act->x()-ultim->x()))/((double)(act->y()-ultim->y()));
            qDebug("4. %f", 0.);
      }*/
}

/*int QGraph::setFunc(const QValueList<function>& funcs){
      funclist.clear();
      funclist=funcs;
      update_points();
      return 0;
}*/

bool QGraph::addFunction(const function& func){
      bool exist=false;
      for (QValueList<function>::iterator it = funclist.begin(); it != funclist.end() && !exist; ++it ){
            if((*it).expression() == func.expression()){
                  exist=true;
                  (*it)=func;
            }
      }
      
      if(!exist)
            funclist << func;
      update_points();
      return exist;
}

bool QGraph::editFunction(const QString& tochange, const function& func){
      bool exist=false;
//    qDebug("<<%s>>", tochange.ascii());
      for (QValueList<function>::iterator it = funclist.begin(); it != funclist.end() && !exist; ++it ){
            if((*it).expression() == tochange){
                  exist=true;
                  (*it)=func;
            }
      }
      
      update_points();
      return false;
}

bool QGraph::editFunction(const unsigned int& num, const function& func){
      if(num<funclist.count())
            funclist[num]=func;
      update_points();
      return true;
}

bool QGraph::setSelected(const QString& exp){
      for (QValueList<function>::iterator it = funclist.begin(); it != funclist.end(); ++it ){
            if((*it).expression() == exp)
                  (*it).setSelected(true);
            else
                  (*it).setSelected(false);
      }
      
      update_points();
      return true;
}

bool QGraph::setShown(const QString& exp, const bool& shown){
      for (QValueList<function>::iterator it = funclist.begin(); it != funclist.end(); ++it ){
            if((*it).expression() == exp){
                  (*it).setShown(shown);
            }
      }
      
      update_points();
      return true;
}

QPoint QGraph::toWidget(double coord_x, double coord_y, bool* nan){
      double part_negativa_x = -viewport.left();
      double part_negativa_y = viewport.bottom();
      int y=0, aux=0;
      
      if(nan==0)
            y= round((part_negativa_y + coord_y ) * rang_y);
      else{
            if((aux = isinf(coord_y))!= 0) {
                  y = (aux<0)? y=this->height() : y=0;
                  *nan=true;
            } else if(isnan(coord_y) && nan!=0){
                  *nan=true;
            } else {
                  y=round((part_negativa_y + coord_y ) * rang_y);
                  *nan=false;
            }
      }
      
      QPoint orig (round((part_negativa_x + coord_x) * rang_x),  round(y));
      return orig;
}

QDoublePoint QGraph::fromWidget(QPoint p){
      double part_negativa_x = -viewport.left();
      double part_negativa_y = viewport.bottom();
      QDoublePoint p1;
      p1.setX(p.x()/rang_x-part_negativa_x);
      p1.setY(p.y()/rang_y-part_negativa_y);
      return p1;
}

QPoint QGraph::toViewport(const QPoint &mv){
      return QPoint((int) ceil(mv.x()/rang_x), (int) ceil(mv.y()/rang_y));
}

void QGraph::setResolution(int res) { resolucio = res; update_points(); }
void QGraph::setViewPort(QRect vp)  { viewport  = vp;  update_points(); }

//////////////////////////////////////////////////////////////
bool QGraph::toImage(QString path){
      if(path != "" && path.endsWith(".svg")) {
            QPicture pic;
            QPainter  p;
//          rang_x=(double) this->width()/((double)viewport.width()-1);
//          rang_y=(double) this->height()/((double)viewport.height()-1);
            pintafunc(&pic);
            pic.save(path, "svg");
      } else if(path != "" && path.endsWith(".png")) {
            QPixmap p(this->width(), this->height());
//          p.fill(Qt::white);
//          rang_x=(double) this->width()/((double)viewport.width()-1);
//          rang_y=(double) this->height()/((double)viewport.height()-1);
            pintafunc(&p);
            p.save(path, "PNG");
      } else
            return false;
      
            return true;
}
//////////////////////////////////////////////////////////////

#include "qgraph.moc"

Generated by  Doxygen 1.6.0   Back to index