1. 程式人生 > 其它 >QwtPlot3D繪製三維曲線,一條多條都可

QwtPlot3D繪製三維曲線,一條多條都可

QwtPlot3D版本:0.2.7

QT版本:5.12.11

編譯器:Mingw64

參考:https://www.cnblogs.com/ybqjymy/p/13395533.html

先展示一下效果吧:我在空間內繪製了多條正弦曲線

正文開始:

step1:修改qwtplot3d的原始碼,新增Line3D這一空間基礎

首先在qwt3d_enrichment_std.h中新增如下程式碼段

 1 class QWT3D_EXPORT Line3D : public VertexEnrichment{
 2 public:
 3     Line3D();
 4     Line3D(double thick,bool
smooth=true); 5 Qwt3D::Enrichment* clone() const {return new Line3D(*this);} 6 7 void configure(double thick, bool smooth); 8 void drawBegin(); 9 void drawBegin(int type); 10 void drawEnd(); 11 virtual void draw(Qwt3D::Triple const&); 12 virtual void draw(); 13 14
virtual void clear(); 15 virtual void add(Qwt3D::Triple const & t); 16 virtual void setLineColor(RGBA color); 17 void setLineSize(int nLineSize);//資料的長度 18 private: 19 bool _smooth; 20 double _thick; 21 GLboolean oldstate_; 22 23 std::vector<Qwt3D::Triple> Linedata;
24 RGBA rgba; 25 };

  然後在其對應的cpp內實現該類:

Qwt3D::Line3D::Line3D(){
    rgba.a = 1;
    rgba.b = 0.3;
    rgba.r = 0.6;
    rgba.g = 1;
}
Qwt3D::Line3D::Line3D(double t,bool smo){
    rgba.a = 1;
    rgba.b = 0.3;
    rgba.r = 0.6;
    rgba.g = 1;
    _thick=t;
    _smooth=smo;
}
void Qwt3D::Line3D::clear(){
    Linedata.clear();
}

void Qwt3D::Line3D::configure(double thick, bool smooth)
{
    _thick = thick;
    _smooth  = smooth;

}
void Qwt3D::Line3D::drawBegin()
{
    setDeviceLineWidth(_thick);
    oldstate_ = glIsEnabled(GL_LINE_SMOOTH);
    if (_smooth)
        glEnable(GL_LINE_SMOOTH);
    else
        glDisable(GL_LINE_SMOOTH);
    //glPointSize(10);
    glBegin( GL_LINE_STRIP);
}
void Qwt3D::Line3D::drawBegin(int type)
{
    setDeviceLineWidth(_thick);
    oldstate_ = glIsEnabled(GL_LINE_SMOOTH);
    if (_smooth)
        glEnable(GL_LINE_SMOOTH);
    else
        glDisable(GL_LINE_SMOOTH);
    //glPointSize(10);
    glBegin( type);
}
void Qwt3D::Line3D::drawEnd()
{
    glEnd();
    if (oldstate_)
        glEnable(GL_LINE_SMOOTH);
    else
        glDisable(GL_LINE_SMOOTH);
}
void Qwt3D::Line3D::draw(Qwt3D::Triple const& pos)
{
    glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
    glVertex3d(pos.x,pos.y,pos.z);
}
void Qwt3D::Line3D::draw()
{
    for (int i = 0; i < Linedata.size(); i ++)
    {
        //RGBA rgba = getColor(i);
        //glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);

        draw(Linedata[i]);
    }
}

void Qwt3D::Line3D::add(const Qwt3D::Triple &t)
{
    Linedata.push_back(t);
}
void Qwt3D::Line3D::setLineColor(RGBA color)
{
   this->rgba = color;
}

  隨後修改qwt3d_plot.h,使之支援line3D,

    
//在public域內新增如下程式碼,過載函式,增加兩種資料型別,其實只要後者即可
void updateData(Line3D& p);
void updateData(std::vector<Line3D> &data);
//在protected域內新增如下程式碼
virtual void createData(Line3D& p ) = 0;
virtual void createData(std::vector<Line3D> &P ) = 0;

  在qwt3d_plot.cpp中新增如下程式碼段:

void Plot3D::updateData(Line3D& p)
{
    makeCurrent();
  GLStateBewarer dt(GL_DEPTH_TEST, true);
    GLStateBewarer ls(GL_LINE_SMOOTH, true);

    calculateHull();    

    SaveGlDeleteLists(displaylists_p[DataObject], 1); // nur Daten
    
    displaylists_p[DataObject] = glGenLists(1);
    glNewList(displaylists_p[DataObject], GL_COMPILE);
    
  //this->createEnrichments();
    this->createData(p);
        
    glEndList();
}
void Plot3D::updateData(std::vector<Line3D> &data)
{
    makeCurrent();
  GLStateBewarer dt(GL_DEPTH_TEST, true);
    GLStateBewarer ls(GL_LINE_SMOOTH, true);

    calculateHull();

    SaveGlDeleteLists(displaylists_p[DataObject], 1); // nur Daten

    displaylists_p[DataObject] = glGenLists(1);
    glNewList(displaylists_p[DataObject], GL_COMPILE);

  //this->createEnrichments();
    this->createData(data);

    glEndList();
}

接下來在qwt3d_surfaceplot.h中新增如下程式碼

注:createDataG的實現在qwt3d_gridplot.cpp中

protected:
    void createLines(Line3D &p);
    virtual void createData(Line3D& p);
    virtual void createData(std::vector<Line3D> & p);
private:
    virtual void createDataG(Line3D& p);
    virtual void createDataG(std::vector<Line3D> & p);

然後在qwt3d_surfaceplot.cpp中實現:

void SurfacePlot::createData(Line3D& p)
{

    createDataG(p);
}
void SurfacePlot::createData(std::vector<Line3D>&p)
{
    createDataG(p);
}
void SurfacePlot::createLines(Line3D& p)
{
    if (!actualData_p)
        return;
    if (p.type() != Enrichment::VERTEXENRICHMENT)
        return;

    p.assign(*this);
    p.drawBegin();

    VertexEnrichment* ve = (VertexEnrichment*)&p;
    if (plotStyle() == Qwt3D::LINE3D_STYLE)
    {
        p.draw();
    }
    p.drawEnd();

}
void SurfacePlot::createDataG(std::vector<Line3D>&p){
    createFloorData();

    if (plotStyle() == NOPLOT)
          return;

      int i, j;
      RGBA col;
      int step = resolution();

    if (plotStyle() == Qwt3D::POINTS)
    {
      createPoints();
      return;
    }
    else if (plotStyle() == Qwt3D::USER)
    {
      if (userplotstyle_p)
        createEnrichment(*userplotstyle_p);
      return;
    }
    else if(plotStyle() == Qwt3D::LINE3D_STYLE)
    {
        for(auto &line :p){
        createLines(line);
        }
        return;

    }

      setDeviceLineWidth(meshLineWidth());

    GLStateBewarer sb(GL_POLYGON_OFFSET_FILL,true);
      setDevicePolygonOffset(polygonOffset(),1.0);

      GLStateBewarer sb2(GL_LINE_SMOOTH, smoothDataMesh());
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


    int lastcol =  actualDataG_->columns();
    int lastrow =  actualDataG_->rows();

      if (plotStyle() != WIREFRAME)
      {
          glPolygonMode(GL_FRONT_AND_BACK, GL_QUADS);

          bool hl = (plotStyle() == HIDDENLINE);
          if (hl)
          {
              col = backgroundRGBAColor();
              glColor4d(col.r, col.g, col.b, col.a);
          }

          for (i = 0; i < lastcol - step; i += step)
          {
            glBegin(GL_TRIANGLE_STRIP);
                  setColorFromVertexG(i, 0, hl);
                  glNormal3dv(actualDataG_->normals[i][0]);
                  glVertex3dv(actualDataG_->vertices[i][0]);

                  setColorFromVertexG(i+step, 0, hl);
                  glNormal3dv(actualDataG_->normals[i+step][0]);
                  glVertex3dv(actualDataG_->vertices[i+step][0]);

                  for (j = 0; j < lastrow - step; j += step)
                  {
                      setColorFromVertexG(i,j+step, hl);
                      glNormal3dv(actualDataG_->normals[i][j+step]);
                      glVertex3dv(actualDataG_->vertices[i][j+step]);

                      setColorFromVertexG(i+step, j+step, hl);
                      glNormal3dv(actualDataG_->normals[i+step][j+step]);
                      glVertex3dv(actualDataG_->vertices[i+step][j+step]);
                  }
              glEnd();
          }
    }

      if (plotStyle() == FILLEDMESH || plotStyle() == WIREFRAME || plotStyle() == HIDDENLINE)
      {
          glColor4d(meshColor().r, meshColor().g, meshColor().b, meshColor().a);

          if (step < actualDataG_->columns() && step < actualDataG_->rows())
          {
              glBegin(GL_LINE_LOOP);
                  for (i = 0; i < actualDataG_->columns() - step; i += step)
                      glVertex3dv(actualDataG_->vertices[i][0]);
                  for (j = 0; j < actualDataG_->rows() - step; j += step)
                      glVertex3dv(actualDataG_->vertices[i][j]);
                  for (; i >= 0; i -= step)
                      glVertex3dv(actualDataG_->vertices[i][j]);
                  for (; j >= 0; j -= step)
                      glVertex3dv(actualDataG_->vertices[0][j]);
              glEnd();
          }

          // weaving
          for (i = step; i < actualDataG_->columns() - step; i += step)
          {
              glBegin(GL_LINE_STRIP);
                  for (j = 0; j < actualDataG_->rows(); j += step)
                      glVertex3dv(actualDataG_->vertices[i][j]);
              glEnd();
          }
          for (j = step; j < actualDataG_->rows() - step; j += step)
          {
              glBegin(GL_LINE_STRIP);
                  for (i = 0; i < actualDataG_->columns(); i += step)
                      glVertex3dv(actualDataG_->vertices[i][j]);
              glEnd();
          }
      }
}
void SurfacePlot::createDataG(Line3D& p)
{
  createFloorData();
  
  if (plotStyle() == NOPLOT)
        return;

    int i, j;
    RGBA col;
    int step = resolution();

  if (plotStyle() == Qwt3D::POINTS)
  {
    createPoints();
    return;
  }
  else if (plotStyle() == Qwt3D::USER)
  {
    if (userplotstyle_p)
      createEnrichment(*userplotstyle_p);
    return;
  }
  else if(plotStyle() == Qwt3D::LINE3D_STYLE)
  {
      createLines(p);
      return;

  }

    setDeviceLineWidth(meshLineWidth());
  
  GLStateBewarer sb(GL_POLYGON_OFFSET_FILL,true);
    setDevicePolygonOffset(polygonOffset(),1.0);

    GLStateBewarer sb2(GL_LINE_SMOOTH, smoothDataMesh());
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


  int lastcol =  actualDataG_->columns();
  int lastrow =  actualDataG_->rows(); 
 
    if (plotStyle() != WIREFRAME)
    {
        glPolygonMode(GL_FRONT_AND_BACK, GL_QUADS);
        
        bool hl = (plotStyle() == HIDDENLINE);
        if (hl)
        {
            col = backgroundRGBAColor();
            glColor4d(col.r, col.g, col.b, col.a);
        }

        for (i = 0; i < lastcol - step; i += step) 
        {
          glBegin(GL_TRIANGLE_STRIP);
                setColorFromVertexG(i, 0, hl);
                glNormal3dv(actualDataG_->normals[i][0]);
                glVertex3dv(actualDataG_->vertices[i][0]);
                    
                setColorFromVertexG(i+step, 0, hl);
                glNormal3dv(actualDataG_->normals[i+step][0]);
                glVertex3dv(actualDataG_->vertices[i+step][0]);

                for (j = 0; j < lastrow - step; j += step) 
                {                
                    setColorFromVertexG(i,j+step, hl);
                    glNormal3dv(actualDataG_->normals[i][j+step]);
                    glVertex3dv(actualDataG_->vertices[i][j+step]);

                    setColorFromVertexG(i+step, j+step, hl);
                    glNormal3dv(actualDataG_->normals[i+step][j+step]);
                    glVertex3dv(actualDataG_->vertices[i+step][j+step]);
                }
            glEnd();
        }
  }

    if (plotStyle() == FILLEDMESH || plotStyle() == WIREFRAME || plotStyle() == HIDDENLINE)
    {
        glColor4d(meshColor().r, meshColor().g, meshColor().b, meshColor().a);        

        if (step < actualDataG_->columns() && step < actualDataG_->rows())
        {
            glBegin(GL_LINE_LOOP);
                for (i = 0; i < actualDataG_->columns() - step; i += step) 
                    glVertex3dv(actualDataG_->vertices[i][0]);        
                for (j = 0; j < actualDataG_->rows() - step; j += step) 
                    glVertex3dv(actualDataG_->vertices[i][j]);                        
                for (; i >= 0; i -= step) 
                    glVertex3dv(actualDataG_->vertices[i][j]);            
                for (; j >= 0; j -= step) 
                    glVertex3dv(actualDataG_->vertices[0][j]);            
            glEnd();
        }

        // weaving
        for (i = step; i < actualDataG_->columns() - step; i += step) 
        {        
            glBegin(GL_LINE_STRIP);
                for (j = 0; j < actualDataG_->rows(); j += step) 
                    glVertex3dv(actualDataG_->vertices[i][j]);            
            glEnd();
        }
        for (j = step; j < actualDataG_->rows() - step; j += step) 
        {        
            glBegin(GL_LINE_STRIP);
                for (i = 0; i < actualDataG_->columns(); i += step) 
                    glVertex3dv(actualDataG_->vertices[i][j]);            
            glEnd();
        }
    }
}

  接下來我們還要在qwt3d_types.h中註冊我們新加的Line3D類

//修改這個結構體即可
enum PLOTSTYLE
{
    NOPLOT     , //!< No visible data
    WIREFRAME  , //!< Wireframe style
    HIDDENLINE , //!< Hidden Line style
    FILLED     , //!< Color filled polygons w/o edges 
    FILLEDMESH , //!< Color filled polygons w/ separately colored 
    edges
    POINTS     , //!< User defined style (used by Enrichments)
    USER       ,  //!< User defined style (used by Enrichments)
    LINE3D_STYLE
};

到此,我們對原始碼的修改就完成,接下來對原始碼進行編譯,然後配置dll和lib的過程就不再贅述。

最後貼一下demo的程式碼,通過修改官方示例中的simpleplot得來:

//-----------------------------------------------------------------
//              simpleplot.cpp
//
//      A simple example which shows how to use SurfacePlot
//-----------------------------------------------------------------

#include <math.h>
#include <qapplication.h>
#include <qwt3d_surfaceplot.h>
#include <qwt3d_function.h>


using namespace Qwt3D;

class Rosenbrock : public Function
{
public:

  Rosenbrock(SurfacePlot& pw)
  :Function(pw)
  {
  }

  double operator()(double x, double y)
  {
    return 2*x*y;//在畫空間曲線的時候不重要,這個函式關係其實控制了空間曲面
  }
};


class Plot : public SurfacePlot
{
public:
    Plot();
};


Plot::Plot()
{
  setTitle("A Simple SurfacePlot Demonstration");
  setPlotStyle(Qwt3D::LINE3D_STYLE);
  Rosenbrock rosenbrock(*this);
  rosenbrock.setMesh(5,5);
  rosenbrock.setDomain(0,100,0,100);
  rosenbrock.setMinZ(0);
  rosenbrock.setMaxZ(100);
  rosenbrock.create();

  coordinates()->setGridLines(true,false,Qwt3D::LEFT|Qwt3D::BACK|Qwt3D::FLOOR);
  for (unsigned i=0; i!=coordinates()->axes.size(); ++i)
  {
    coordinates()->axes[i].setMajors(7);
    coordinates()->axes[i].setMinors(4);
  }


  coordinates()->axes[X1].setLabelString("x-axis");
  coordinates()->axes[Y1].setLabelString("y-axis");
  coordinates()->axes[Z1].setLabelString("z-axis"); // Omega - see http://www.unicode.org/charts/


  setCoordinateStyle(FRAME);



  Qwt3D::Line3D _l3d;
  Qwt3D::Line3D *myLine1 = dynamic_cast<Qwt3D::Line3D *>(addEnrichment(_l3d));
  myLine1->configure(1,true);
  myLine1->setLineColor(Qwt3D::RGBA(1,0,0,1));
  std::vector<Line3D> data;
  double x,y,z;
  for(int k=1;k<100;k+=10){
      x=k;
      for(float i = 0; i < 100; i+=0.1)
      {
        y=i;
        z=10*sin(i);
        myLine1->add(Qwt3D::Triple(x,y,z));
      }
      data.push_back(*myLine1);
      myLine1->clear();
  }
  updateData(data);
  updateGL();
}

int main(int argc, char **argv)
{
    QApplication a(argc, argv);
    Plot plot;
#if QT_VERSION < 0x040000
    a.setMainWidget(&plot);
#endif
    plot.resize(800,600);
    plot.show();
    return a.exec();
}