Qt多文档实现参看Qt多文档程序的一种实现

概要

本文利用Occ搭建一个简易CAD程序框架,包括新建并显示一个box并、操作杆交互操纵box。其中视图中可以显示3d坐标系以及View Cube。本文主要讲实现,理论请参看OCC的官方文档即可。

简易CAD程序:使用OCC的自带的功能,搭建程序框架_3d

文档类CADDocument

  1. 在文档类中,关于occ的成员有3个,参看头文件声明
#pragma once

#include <QObject>
#include <list>

#include "V3d_Viewer.hxx"
#include "AIS_InteractiveContext.hxx"
#include "TDocStd_Document.hxx"

class CADChildWindow;

//相当与MFC的CDocument
class CADDocument : public QObject
{
	//其他略
	//...
public:
	Handle(V3d_Viewer) getOccViewer() const { return myViewer; }
	Handle(AIS_InteractiveContext) getAISContext() const { return myAISContext; }

private:
	//其他略
	//...
	Handle(V3d_Viewer) myViewer;
	Handle(AIS_InteractiveContext) myAISContext;
	Handle(TDocStd_Document) myDoc;
};
  1. 文档类构造函数中做了些工作,此处是为了演示,一般来说,构造函数不要做太多逻辑,职责单一需要遵守。构造函数中主要新建了V3d_Viewer,并将OpenGL的图形驱动传给它,然后开启了默认的光照,设置了背景色为黑色。接着创建了交互上下文AIS_InteractiveContext,并设置显示模式为着色。然后加入了View Cube,在occ 7.4.0版本开始,occ帮实现了一个View Cube,目前3d程序一般都有这个功能,在occ中,加入这个非常简单,只需要new一个AIS_ViewCube,然后设置下基本属性即可。最后使用BRepPrimAPI_MakeBox创建了一个box,然后加入显示,并且激活模型点、边、面的选择。
CADDocument::CADDocument(QObject *parent)
	: QObject(parent)
{
	//其他略
	//...
	
	Handle(Graphic3d_GraphicDriver) aGraphicDriver = ((CADApplication*)qApp)->GetGraphicDriver();
	myViewer = new V3d_Viewer(aGraphicDriver);
	myViewer->SetDefaultLights();
	myViewer->SetLightOn();
	myViewer->SetDefaultBackgroundColor(Quantity_Color(0.0, 0.0, 0.0, Quantity_TOC_RGB));
//	myViewer->SetDefaultVisualization(V3d_TypeOfVisualization::V3d_ZBUFFER);//暂不知干什么的,无法控制真实模式显示,默认还是线框

	myAISContext = new AIS_InteractiveContext(myViewer);
	myAISContext->SetDisplayMode(AIS_Shaded, Standard_True);//设置显示着色模式

	//View Cube
	Handle(AIS_ViewCube) hViewCube = new AIS_ViewCube();
	hViewCube->SetDrawAxes(Standard_False);
	hViewCube->SetTransformPersistence(new Graphic3d_TransformPers(
		Graphic3d_TMF_TriedronPers, Aspect_TOTP_RIGHT_UPPER, Graphic3d_Vec2i(70, 70)));
	myAISContext->Display(hViewCube, Standard_True);

	//此处直接加入一个box显示
	//BRepPrimAPI_MakeTorus mkTorus(30, 10);
	//create box for test
	BRepPrimAPI_MakeBox mkBox(gp_Pnt(0, 0, 0), 10, 20, 30);
	TopoDS_Shape aShpae = mkBox.Shape();
	Handle(AIS_Shape) hBoxShape = new AIS_Shape(aShpae);
	myAISContext->Display(hBoxShape, Standard_True);

	//开启点、边、面的选择
	myAISContext->Deactivate(hBoxShape);
	myAISContext->Activate(hBoxShape, AIS_Shape::SelectionMode(TopAbs_FACE));
	myAISContext->Activate(hBoxShape, AIS_Shape::SelectionMode(TopAbs_EDGE));
	myAISContext->Activate(hBoxShape, AIS_Shape::SelectionMode(TopAbs_VERTEX));

}

视图类 CADView

  1. 头文件声明
    CADView中定义了occ的视图类V3d_View
#pragma once

#include <QWidget>

#include "V3d_View.hxx"

class CADDocument;

//相当与MFC中的CView
class CADView : public QWidget
{
	Q_OBJECT

public:
	CADView(QWidget *parent = Q_NULLPTR);
	~CADView();

	CADDocument* getDocument() const;
	virtual QPaintEngine* paintEngine() const;
	virtual void paintEvent(QPaintEvent*);
	virtual void resizeEvent(QResizeEvent*);
	virtual void mousePressEvent(QMouseEvent*);
	virtual void mouseReleaseEvent(QMouseEvent*);
	virtual void mouseMoveEvent(QMouseEvent*);


private:
	Handle(V3d_View) myView;
	int m_nLastX = 0;
	int m_nLastY = 0;
};
  1. 初始化occ视图
CADView::CADView( QWidget *parent)
	: QWidget(parent)
{
	this->setMinimumSize(300, 200);
	this->setAttribute(Qt::WA_PaintOnScreen);
	this->setAttribute(Qt::WA_NoSystemBackground);
	this->setMouseTracking(true);

	//创建V3dView并设置投影信息
	myView = getDocument()->getOccViewer()->CreateView();
	myView->SetProj(V3d_TypeOfOrientation::V3d_XnegYnegZpos);
//	myView->SetVisualization(V3d_TypeOfVisualization::V3d_ZBUFFER);//这句无作用
	//myView->SetComputedMode(Standard_True);
	myView->Camera()->SetProjectionType(Graphic3d_Camera::Projection::Projection_Orthographic);

	//关联Qt窗口到V3dView
	Handle(OcctWindow) aOcctWindow = new OcctWindow(this);
	myView->SetWindow(aOcctWindow);
	if (!aOcctWindow->IsMapped())
	{
		aOcctWindow->Map();
	}

	//显示坐标系
	myView->TriedronDisplay(Aspect_TOTP_LEFT_LOWER, Quantity_NOC_BLUE1, 0.15, V3d_ZBUFFER);
	myView->ZBufferTriedronSetup();

	myView->FitAll();

}
  1. 通用的一些设置,参看occ自带的例子程序
    CADView::paintEngine()、CADView::paintEvent(QPaintEvent *)、CADView::resizeEvent(QResizeEvent *)一般就这么写,重载的几个鼠标相关的函数,主要是为了图形选择、图形操作杆、ViewCube的功能。
QPaintEngine* CADView::paintEngine() const
{
	return 0;
}

void CADView::paintEvent(QPaintEvent *)
{
	myView->Redraw();
}

void CADView::resizeEvent(QResizeEvent *)
{
	if (!myView.IsNull())
	{
		myView->MustBeResized();
	}
}

void CADView::mousePressEvent(QMouseEvent* e)
{
	if (e->button() == Qt::RightButton)
	{
		if (e->modifiers() & Qt::ControlModifier)//开始旋转:ctrl+鼠标右键
		{
			myView->StartRotation(e->x(), e->y());
			m_nLastX = e->x();
			m_nLastY = e->y();
		}
	}
}

void CADView::mouseReleaseEvent(QMouseEvent* e)
{
	if (e->button() == Qt::LeftButton)
	{
		auto hAisContext = getDocument()->getAISContext();
		if (hAisContext)
		{
			//鼠标移动,激活选择功能
			hAisContext->MoveTo(e->x(), e->y(), myView, Standard_False);
			hAisContext->Select(Standard_True);

			//code for test
// 			SelectMgr_ListOfFilter aFilters = hAisContext->Filters();
// 			for (auto it = aFilters.begin(); it != aFilters.end(); ++it)
// 			{
// 				auto aFilter = *it;
// 				int b = 10;
// 			}
		}
	}

}

void CADView::mouseMoveEvent(QMouseEvent* e)
{
//	onMouseMove(e->buttons(), e->pos());
	Qt::MouseButtons mouseButtons = e->buttons();
	Qt::KeyboardModifiers keyFlags = e->modifiers();
	if (mouseButtons & Qt::MouseButton::MiddleButton)
	{
		if (keyFlags & Qt::ControlModifier)//平移:ctrl+鼠标中键
		{
			myView->Pan(e->x() - m_nLastX, m_nLastY - e->y());
		}
	}
	else if (mouseButtons & Qt::MouseButton::LeftButton)
	{
		if (keyFlags & Qt::ControlModifier)//缩放:ctrl+鼠标左键
		{
			myView->Zoom(m_nLastX, m_nLastY, e->x(), e->y());
		}
	}
	else if (mouseButtons & Qt::MouseButton::RightButton)
	{
		if (keyFlags & Qt::ControlModifier) //旋转:ctrl+鼠标中键
		{
			myView->Rotation(e->x(), e->y());
		}
	}

	m_nLastX = e->x();
	m_nLastY = e->y();

	//转达鼠标移动,激活选择功能、ViewCube的响应
	auto hAisContext = getDocument()->getAISContext();
	if (hAisContext)
	{
		hAisContext->MoveTo(e->x(), e->y(), myView, Standard_True);
	}
}
  1. OcctWindow
    直接从occ关于qt例子程序复制过来即可,这个类很重要,是occ在qt窗口中显示图形的关键。

源码

https://gitee.com/shanql/OccLearn/tree/v1.0.0/src

运行演示

简易CAD程序:使用OCC的自带的功能,搭建程序框架_3d_02