QT之qwtplot3d使用(一)

qwtplot3d 简介

qwtplot3d是qt解决三维图形绘制的库,核心通过调用openGL库完成,可以实现三维曲面绘制,三维状态下折线,散点等图形的绘制。但是其在十多年前推出后一直没有太大的更新,而且自带的类并不够丰富,所以在使用时还是有一些问题的。主要参考了引用1中的博客,qwtplot3d库的代码在该博主的博客中可以下载到,另外在github中搜索qwtplot3d,找到标星最多的一个,但是该库有改动,另外可以在引用2中下载到官方库文件。

使用qwtplot3d画线

参考QWT3D 之 三维动态曲线的实现

画线的实现原理是改变了在各个顶点之间画图形的方式,由之前的画三维曲面改成直接将前后点相连。我使用的是从博主那里下载到的源码,其中的Line3D类已经写好,在qwt3d_enrichment_std.cpp中,我们看一下该类:

class QWT3D_EXPORT Line3D: public VertexEnrichment
{

public:
	Line3D();
	Line3D(double thick,bool smooth);
	Qwt3D::Enrichment * clone() const{ return new Line3D(*this);}

	void configure(double thick, bool smooth);
	void drawBegin();
	void drawEnd();
	virtual void draw(Qwt3D::Triple const&);

	virtual void draw();

	virtual void add(Qwt3D::Triple const & t);
    virtual void setLineColor(RGBA color);
    /*virtual void clear()
	{
		lineData.clear();
        //myColorMap.clear();
    }*/

    //virtual void setLineColor(int startIndex,RGBA color);
   // virtual void setLineColor(RGBA color);
    //virtual RGBA getColor(int pointIndex);

private:
	bool smooth_;
	double lineThick;
	GLboolean oldstate_;
std::vector<Qwt3D::Triple> lineData;

        RGBA rgba;

     //std::map<int,RGBA>		myColorMap;

};

该类中主要几个成员变量,double lineThick代表线的粗细;bool smooth_ 代表是否光滑,在点数较多时可能会出现显示问题,如果因为点数太多导致显示的图形颜色发挥可以将改变量设为false,点的形状会变成方形,但是颜色更加清晰;RGBA rgba; 是线的颜色,有r,g,b,a四个成员变量,都是double型,rgb合成一个颜色,a为透明度,不透明为1,rgb取值为0-1。std::vectorQwt3D::Triple lineData是折线顶点的向量,元素Qwt3D::Triple有x,y,z三个成员变量,是个三维坐标,画线操作即是读取lineData中的三维坐标按顺序画线。函数方面,configure 可以改变线的粗细和是否光滑,add 函数可以向lineData向量中添加一个坐标点,setLineColor 设置颜色,剩下的就是和实际画图相关的函数,使用时调用draw() 即可,它会调用其它几个画图相关函数,把lineData画完。我们看一下draw() 函数

void Qwt3D::Line3D::drawBegin()
{
    setDeviceLineWidth(lineThick);

	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::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]);
	}
}

通过这几个函数,最终调用了openGL库中的函数实现了折线的绘制。

使用qwtplot画点

实现画线之后,又需要用到画点功能,即绘制散点图。根据画线的实现原理,画点只需要将调用的openGL库函数改变即可,正好在qwtplot3d_enrichment_std.cpp有了一个Dot类用来实现画点,我们看一下原来的Dot类:

/
//
//   Dot
//
/

Dot::Dot()
{
  configure(1, false);
}

Dot::Dot(double pointsize, bool smooth)
{
  configure(pointsize, smooth);
}

void Dot::configure(double pointsize, bool smooth)
{
  plot = 0;
  pointsize_ = pointsize;
  smooth_ = smooth;
}

void Dot::drawBegin()
{
  setDevicePointSize( pointsize_ );
  oldstate_ = glIsEnabled(GL_POINT_SMOOTH);
  if (smooth_)
    glEnable(GL_POINT_SMOOTH);
  else
    glDisable(GL_POINT_SMOOTH);

  //glPointSize(10);
	glBegin( GL_POINTS );
}

void Dot::drawEnd()
{
  glEnd();

  if (oldstate_)
    glEnable(GL_POINT_SMOOTH);
  else
    glDisable(GL_POINT_SMOOTH);
}

void Dot::draw(Qwt3D::Triple const& pos)
{
	RGBA rgba = (*plot->dataColor())(pos);
  glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
  glVertex3d( pos.x, pos.y, pos.z);   
}

对比Line3D的实现,可以看出主要区别在drawBegindrawEnd 两个函数的设置,为了实现调用方式的统一,我对Dot类进行了修改,使其在格式上与Line3D相同,代码如下:

.H
class QWT3D_EXPORT Dot : public VertexEnrichment
{
public: 
  Dot();
  Dot(double pointsize, bool smooth);

  Qwt3D::Enrichment* clone() const {return new Dot(*this);}

  void configure(double thick, bool smooth);
  void drawBegin();
  void drawEnd();
  void draw(Qwt3D::Triple const&);
  virtual void draw();

  virtual void add(Qwt3D::Triple const & t);
  virtual void setLineColor(RGBA color);
private:
  bool smooth_;
  double lineThick;
  GLboolean oldstate_;
  std::vector<Qwt3D::Triple> lineData;

          RGBA rgba;
};


.CPP
/
//
//   Dot
//
/
/*
Dot::Dot()
{
  configure(1, false);
}

Dot::Dot(double pointsize, bool smooth)
{
  configure(pointsize, smooth);
}

void Dot::configure(double pointsize, bool smooth)
{
  plot = 0;
  pointsize_ = pointsize;
  smooth_ = smooth;
}

void Dot::drawBegin()
{
  setDevicePointSize( pointsize_ );
  oldstate_ = glIsEnabled(GL_POINT_SMOOTH);
  if (smooth_)
    glEnable(GL_POINT_SMOOTH);
  else
    glDisable(GL_POINT_SMOOTH);

  //glPointSize(10);
	glBegin( GL_POINTS );
}

void Dot::drawEnd()
{
  glEnd();

  if (oldstate_)
    glEnable(GL_POINT_SMOOTH);
  else
    glDisable(GL_POINT_SMOOTH);
}

void Dot::draw(Qwt3D::Triple const& pos)
{
	RGBA rgba = (*plot->dataColor())(pos);
  glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
  glVertex3d( pos.x, pos.y, pos.z);   
}
*/
Qwt3D::Dot::Dot()
{

    rgba.a = 1;
    rgba.b = 0.3;
    rgba.r = 0.6;
    rgba.g = 1;
}
Qwt3D::Dot::Dot(double thick,bool smooth)
{
    lineThick = thick;
    smooth_  = smooth;
    rgba.a = 1;
    rgba.b = 0.3;
    rgba.r = 0.6;
    rgba.g = 1;
}


void Qwt3D::Dot::configure(double thick, bool smooth)
{
    lineThick = thick;
    smooth_  = smooth;

}

void Qwt3D::Dot::drawBegin()
{

    setDevicePointSize(lineThick);

    oldstate_ = glIsEnabled(GL_POINT_SMOOTH);
    if (smooth_)
        glEnable(GL_POINT_SMOOTH);
    else
        glDisable(GL_POINT_SMOOTH);

    //glPointSize(10);
    glBegin( GL_POINTS);

}

void Qwt3D::Dot::drawEnd()
{
    glEnd();

    if (oldstate_)
        glEnable(GL_POINT_SMOOTH);
    else
        glDisable(GL_POINT_SMOOTH);
}

void Qwt3D::Dot::draw(Qwt3D::Triple const& pos)
{

    glColor4d(rgba.r,rgba.g,rgba.b,rgba.a);
    glVertex3d(pos.x,pos.y,pos.z);


}

void Qwt3D::Dot::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::Dot::add(Qwt3D::Triple const & t)
{
    lineData.push_back(t);
}
 void Qwt3D::Dot::setLineColor(RGBA color)
 {
    this->rgba = color;
 }

draw()函数的调用

修改之后,对画线和画点的实现都可以通过调用相应类的draw() 函数实现。对该函数的调用在qwt3d_surfaceplot.cpp中,看下修改后的代码:

void SurfacePlot::createEnrichment(Enrichment& p)
{
   // printf("createEnrichment\n");
        if (!actualData_p)
    return;
  
  //todo future work
  if (p.type() != Enrichment::VERTEXENRICHMENT)
    return;
  
    p.assign(*this);
	p.drawBegin();

	

 /* VertexEnrichment* ve = (VertexEnrichment*)&p;
  if (actualData_p->datatype == Qwt3D::POLYGON)
  {	
    for (unsigned i = 0; i != actualDataC_->normals.size(); ++i) 
            ve->draw(actualDataC_->nodes[i]);
  }
  else if (actualData_p->datatype == Qwt3D::GRID &&plotStyle() != Qwt3D::LINE3D_STYLE )
 	{
    int step = resolution();
    for (int i = 0; i <= actualDataG_->columns() - step; i += step) 
      for (int j = 0; j <= actualDataG_->rows() - step; j += step) 
                        ve->draw(Triple(actualDataG_->vertices[i][j][0],
										              actualDataG_->vertices[i][j][1],
                                  actualDataG_->vertices[i][j][2]));
  }
  else if (plotStyle() == Qwt3D::LINE3D_STYLE)
  {*/
    //  printf("pdraw\n");
          p.draw();
 // }
  p.drawEnd(); 
}

原先的该函数时通过判断类的类型来调用不同绘制函数的,Qwt3D::LINE3D_STYLE等时枚举值,但是测试发现该判断没有生效,索性直接注释掉,保留了统一的p.draw()函数调用,这也是我把Dot类修改成与Line3D类格式相似的原因,不同的绘制方式在自己类中的draw()函数中实现。

小结

为了实现画线和画点功能,对于qwtplot3d库的修改就分享到这里,之后会写库函数调用和界面方面的问题。

qwtplot3d第二篇:
QT之qwtplot3d使用(二)

引用

QWT3D 之 三维动态曲线的实现
qwtplot3d官方库
github中的qwtplot库

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐