VTK用户指南 第三章 系统概览 3.2

本篇介绍了使用Tcl、C++、Java和Python开发VTK应用程序的基础知识,包括回调(用户方法、观察者和命令)的实现。通过示例展示了如何在不同语言中创建应用程序,以及如何设置和使用回调。VTK支持的语言都提供了回调功能,允许用户与VTK对象交互,如在事件触发时执行自定义操作。
摘要由CSDN通过智能技术生成

3.2 创建应用程序

本节介绍使用四种编程语言Tcl,C++,Java和Python开发VTK应用程序所需的基本信息。阅读完此介绍之后,您应该跳到讨论您感兴趣的语言使用的小节。除了为您提供有关如何创建和运行简单应用程序的说明之外,每节还将向您展示如何利用该语言的回调。

用户方法、观察者和命令
回调(或用户方法)是使用主题/观察者和命令设计模式在VTK中实现的。这意味着VTK中几乎每个类(vtkObject的每个子类)都有一个AddObserver()方法,该方法可用于从VTK设置回调。观察者查看在对象上调用的每个事件,如果它与观察者正在观察的事件之一匹配,则将调用关联的命令(即回调)。例如,所有VTK筛选器都在开始执行之前立即调用StartEvent。如果您添加了一个监视StartEvent的观察器,则每次过滤器开始执行时都会调用该观察器。考虑以下Tcl脚本,该脚本创建vtkElevationFilter的实例,并为StartEvent添加观察者以调用过程PrintStatus。

proc PrintStatus {} { 
puts "Starting to execute the elevation filter" 
} 
vtkElevationFilter foo 
foo AddObserver StartEvent PrintStatus 

VTK支持的所有语言均提供这种类型的功能(即回调)。接下来的每一节将简要说明如何使用它。第421页的“与窗口系统集成”中提供了有关用户方法的进一步讨论。(本节还讨论了用户界面集成问题。)
要创建自己的应用程序,建议从VTK附带的示例之一开始。可以在源代码发布的VTK/Examples中找到它们。在源代码分发中,示例首先按主题进行组织,然后按语言进行组织。在“VTK/Examples”下,您将找到不同主题的目录,并且在目录下将存在不同语言(例如Tcl)的子目录。

Tcl
Tcl是开始创建VTK应用程序的最简单的语言之一。一旦安装了VTK,就应该能够运行发行版随附的Tcl示例。在UNIX下,您必须按照第14页“在Unix系统上安装VTK”中所述使用Tcl支持编译VTK。在Windows下,您可以按照第10页“在Windows XP,Vista或更高版本上安装VTK”中的说明安装自解压存档。

Windows。 在Windows下,只需双击文件(在此示例中为Cone.tcl)即可运行Tcl脚本。如果没有任何反应,则可能是脚本错误或将Tcl文件与vtk.exe可执行文件相关联的问题。要检测到这一点,您需要先运行vtk.exe。vtk.exe可以在VTK下的开始菜单中找到。执行开始后,将出现一个控制台窗口,其中带有提示。在此提示符下,键入cd命令以更改为Cone.tcl所在的目录。以下是两个示例:

% cd "c:/VTK/Examples/Tutorial/Step1/Tcl" 

然后,您需要使用以下命令来获取示例脚本:

% source Cone.tcl 

Tcl将尝试执行Cone.tcl,您将能够看到错误或警告消息,否则它们将不会出现。

Unix。 在UNIX下,可以通过运行在二进制目录(例如,VTK-bin/bin/vtk,VTKSolaris/bin/vtk等)中找到的VTK可执行文件(在编译源代码之后)来完成Tcl开发。然后提供Tcl脚本作为第一个参数,如下所示。

unix machine> cd VTK/Examples/Tutorial/Step1/Tcl 
unix machine> /home/VTK-Solaris/bin/vtk Cone.tcl

可以按照本节简介中所示设置用户方法。可以在Examples/Tutorial/Step2/Tcl/Cone2.tcl中找到一个示例。关键更改如下所示。

proc myCallback {} {  
	puts "Starting to render" 
} 
vtkRenderer ren1 
ren1 AddObserver StartEvent myCallback 

您可以改为直接将proc的主体直接提供给AddObserver()。

vtkRenderer ren1 
ren1 AddObserver StartEvent {puts "Starting to render"}

C++
与大多数其他语言相比,使用C++作为开发语言通常会导致更小,更快和更容易部署应用程序。C++开发还具有以下优点:您无需编译对Tcl,Java或Python的任何其他支持。本节将向您展示如何使用适当的编译器为带有Microsoft Visual C++的PC和UNIX创建简单的VTK C++应用程序。我们将从一个简单的示例Cone.cxx开始,该示例可以在Examples/Tutorial/Step1/Cxx中找到。对于Windows和UNIX,您都可以使用VTK的源代码安装或已安装的二进制文件。这些示例将同时适用于两者。

构建C++程序的第一步是使用CMake生成makefile或工作区文件,具体取决于您的编译器。Cone.cxx附带的CMakeList.txt文件(如下所示)使用FindVTK和UseVTK CMake模块。这些模块尝试找到VTK,然后设置用于构建C++程序的包含路径和链接线。如果他们没有成功找到VTK,则必须手动指定适当的CMake参数,并根据需要重新运行CMake。

PROJECT (Step1) 

FIND_PACKAGE(VTK REQUIRED) 
IF(NOT VTK_USE_RENDERING) 
MESSAGE(FATAL_ERROR 
	"Example ${PROJECT_NAME} requires VTK_USE_RENDERING.") 
ENDIF(NOT VTK_USE_RENDERING) 
INCLUDE(${VTK_USE_FILE}) 

ADD_EXECUTABLE(Cone Cone.cxx) 
TARGET_LINK_LIBRARIES(Cone vtkRendering) 

Microsoft Visual C++。为Cone示例运行CMake之后,就可以启动Microsoft Visual C++并加载生成的解决方案文件了。对于当前的.NET版本的编译器,其名称为Cone.sln。您现在可以选择一个生成类型(例如Release或Debug)并生成您的应用程序。如果要将VTK集成到不使用CMake的现有项目中,可以将此简单示例中的设置复制到现有工作区中。

现在考虑一个真正的Windows应用程序的示例。该过程与上面的过程非常相似,除了我们创建Windows应用程序而不是控制台应用程序,如下所示。许多代码是标准的Windows代码,任何Windows开发人员都会熟悉。可以在VTK/Examples/GUI/Win32/SimpleCxx/Win32Cone.cxx中找到此示例。请注意,对CMakeLists.txt文件的唯一重要更改是在ADD_EXECUTABLE命令中添加了WIN32参数。

#include "windows.h" 
#include "vtkConeSource.h" 
#include "vtkPolyDataMapper.h" 
#include "vtkRenderWindow.h" 
#include "vtkRenderWindowInteractor.h" 
#include "vtkRenderer.h" 
static HANDLE hinst; 
long FAR PASCAL WndProc(HWND, UINT, UINT, LONG); 
// define the vtk part as a simple c++ class 
class myVTKApp 
{
public: 
	myVTKApp(HWND parent); 
	~myVTKApp(); 

private: 
	vtkRenderWindow *renWin; 
	vtkRenderer *renderer; 
	vtkRenderWindowInteractor *iren; 
	vtkConeSource *cone; 
	vtkPolyDataMapper *coneMapper; 
	vtkActor *coneActor; 
}; 

我们首先包括所需的VTK包含文件。接下来,我们有两个标准的Windows原型,然后是一个名为myVTKApp的小类定义。使用C++开发时,应尝试使用面向对象的方法,而不是许多Tcl示例中的脚本编程风格。在这里,我们将应用程序的VTK组件封装为一个小类。

这是myVTKApp的构造函数。如您所见,它分配了所需的VTK对象,设置了它们的实例变量,然后将它们连接起来以形成可视化管道。除vtkRenderWindow之外,大多数代码都是简单的VTK代码。 此构造函数将HWND句柄带到应包含VTK渲染窗口的父窗口。然后,我们在vtkRenderWindow的SetParentId()方法中使用此方法,以便它将创建其窗口作为传递给构造函数的窗口的子级。

myVTKApp::myVTKApp(HWND hwnd) 
{ 
	// Similar to Examples/Tutorial/Step1/Cxx/Cone.cxx 
	// We create the basic parts of a pipeline and connect them 
	this->renderer = vtkRenderer::New(); 
	this->renWin = vtkRenderWindow::New(); 
	this->renWin->AddRenderer(this->renderer);
	 
	 // setup the parent window 
	 this->renWin->SetParentId(hwnd); 
	 this->iren = vtkRenderWindowInteractor::New(); 
	 this->iren->SetRenderWindow(this->renWin); 
	 this->cone = vtkConeSource::New(); 
	 this->cone->SetHeight( 3.0 ); 
	 this->cone->SetRadius( 1.0 ); 
	 this->cone->SetResolution( 10 ); 
	 this->coneMapper = vtkPolyDataMapper::New(); 
	 this->coneMapper->SetInputConnection(this->cone->GetOutputPort()); 
	 this->coneActor = vtkActor::New(); 
	 this->coneActor->SetMapper(this->coneMapper);
	  
	 this->renderer->AddActor(this->coneActor); 
	 this->renderer->SetBackground(0.2,0.4,0.3); 
	 this->renWin->SetSize(400,400); 
	 // Finally we start the interactor so that event will be handled 
	 this->renWin->Render(); 
} 

析构函数只是释放在构造函数中分配的所有VTK对象。

myVTKApp::~myVTKApp() 
{ 
	renWin->Delete(); 
	renderer->Delete(); 
	iren->Delete(); 
	cone->Delete(); 
	coneMapper->Delete(); 
	coneActor->Delete(); 
}

这里的WinMain代码是所有标准的Windows代码,并且其中没有VTK引用。如您所见,应用程序可以控制事件循环。事件由本节稍后介绍的WndProc处理。

int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) 
{ 
	static char szAppName[] = "Win32Cone"; 
	HWND hwnd ; 
	MSG msg ; 
	WNDCLASS wndclass ; 
	if (!hPrevInstance) 
	{ 
		wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 
		wndclass.lpfnWndProc = WndProc ; 
		wndclass.cbClsExtra = 0 ; 
		wndclass.cbWndExtra = 0 ; 
		wndclass.hInstance = hInstance; 
		wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION); 
		wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); 
		wndclass.lpszMenuName = NULL; 
		wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); 
		wndclass.lpszClassName = szAppName; 
		RegisterClass (&wndclass); 
	} 		
	hinst = hInstance; 
	hwnd = CreateWindow ( szAppName, "Draw Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 480, NULL, NULL, hInstance, NULL); 
	ShowWindow (hwnd, nCmdShow); 
	UpdateWindow (hwnd); 
	while (GetMessage (&msg, NULL, 0, 0)) 
	{ 
		TranslateMessage (&msg); 
		DispatchMessage (&msg); 
	} 
	return msg.wParam;
}

该WndProc是一个非常简单的事件处理程序。对于完整的应用程序,它要复杂得多,但是关键的集成问题是相同的。在此函数的顶部,我们声明对myVTKApp实例的静态引用。在处理WM_CREATE方法时,我们创建一个Exit按钮,然后构造一个myVTKApp实例,将其句柄传递给当前窗口。vtkRenderWindowInteractor将处理vtkRenderWindow的所有事件,因此您无需在此处处理它们。 可能需要添加代码以处理事件大小调整事件,以便相对于整个用户界面适当调整渲染窗口的大小。如果您未设置vtkRenderWindow的ParentId,它将显示为顶层独立窗口。其他所有内容的行为都应与以前相同。

long FAR PASCAL WndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam) 
{ 
	static HWND ewin; 
	static myVTKApp *theVTKApp; 
	switch (message) 
	{ 
		case WM_CREATE: 
		{	 
			ewin = CreateWindow("button","Exit", WS_CHILD | WS_VISIBLE | SS_CENTER, 0,400,400,60, hwnd,(HMENU)2, (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), NULL); 
			theVTKApp = new myVTKApp(hwnd); 
			return 0; 
		} 
		case WM_COMMAND: 
			switch (wParam) 
			{ 
				case 2: 
				PostQuitMessage (0); 
				if (theVTKApp) 
				{ 
					delete theVTKApp; 
					theVTKApp = NULL;
				} 
				break;
			} 
			return 0; 
		case WM_DESTROY: 
			PostQuitMessage (0); 
			if (theVTKApp) 
			{ 
				delete theVTKApp; 
				theVTKApp = NULL; 
			} 
			return 0; 
	} 
	return DefWindowProc (hwnd, message, wParam, lParam);
} 

UNIX。 通过运行CMake然后执行make,可以在UNIX上创建C ++应用程序。CMake创建一个makefile,该makefile指定包含路径,链接行和依赖项。然后,make程序使用此makefile编译应用程序。 这将导致您可以运行一个Cone可执行文件。如果Cone.cxx无法编译,请检查make错误并进行更正。确保CMakeCache.txt顶部的值有效。如果它可以编译,但是在尝试运行它时收到错误,则可能需要按照第二章“C++中的用户方法”中所述设置LD_LIBRARY_PATH。通过创建覆盖Execute()方法的vtkCommand的子类,可以在C++中添加用户方法(使用观察者/命令设计模式)。请考虑以下示例,该示例取自VTK/Examples/Tutorial/Step2/Cxx/Cone2.cxx。

class vtkMyCallback : public vtkCommand { 
  static myCallback *New() {return new vtkMyCallback;} 
  virtual void Execute(vtkObject *caller, unsigned long, void *) 
  {
     vtkRenderer *renderer = reinterpret_cast<vtkRenderer*>(caller);
     cout << renderer->GetActiveCamera()->GetPosition()[0] << " "
          << renderer->GetActiveCamera()->GetPosition()[1] << " "
          << renderer->GetActiveCamera()->GetPosition()[2] << "\n";
   } 
 };

尽管始终将Execute()方法传递给调用对象(调用者),但您无需使用它。如果您确实使用了调用方,则通常需要对实际类型执行SafeDownCast()。例如:

virtual void Execute(vtkObject *caller, unsigned long, void *callData) 
{ 
	vtkRenderer *ren = vtkRenderer::SafeDownCast(caller); 
	if (ren) { ren->SetBackground(0.2,0.3,0.4); } 
} 

一旦创建了vtkCommand的子类,就可以添加一个观察者,该观察者将在某些事件上调用您的命令。这可以如下进行。

// Here is where we setup the observer, 
//we do a new and ren1 will eventually free the observer 
vtkMyCallback *mo1 = vtkMyCallback::New(); 
ren1->AddObserver(vtkCommand::StartEvent,mo1); 
mo1->Delete(); 

上面的代码创建了myCallback的实例,然后在ren1上为StartEvent添加了一个观察者。每当ren1开始渲染时,将调用vtkMyCallback的Execute()方法。删除ren1后,回调也将被删除。

Java
要创建Java应用程序,您必须首先具有一个正常的Java开发环境。 本节提供了有关在Windows或UNIX上使用Sun的JDK 1.3或更高版本的说明。一旦安装了JDK并安装了VTK,就需要设置CLASSPATH环境变量以包含VTK类。在Microsoft Windows下,可以通过右键单击“我的电脑”图标,选择属性选项,然后选择“高级”选项卡,然后单击“环境变量”按钮来进行设置。 然后添加CLASSPATH环境变量,并将其设置为包括您的vtk.jar文件的路径,Wrapping/ ava目录和当前目录。对于Windows构建,它将类似于“ C:\vtk-bin\bin\vtk.jar; C:\vtkbin\Wrapping\ ava;”。在UNIX下,应该将CLASSPATH环境变量设置为类似于“ /yourdisk/vtk-bin/bin/vtk.jar;/yourdisk/vtk-bin/Wrapping/Java ;.”的名称。
下一步是对Java程序进行字节编译。对于初学者,请尝试使用VTK/Examples/Tutorial/Step1/Java在VTK附带的Cone.java示例中进行字节编译(使用javac)。然后,您应该能够使用java命令运行生成的应用程序。它应该显示一个旋转360度的圆锥,然后退出。 下一步是使用提供的示例作为起点来创建自己的应用程序。

public void myCallback() 
{ 
	System.out.println("Starting a render"); 
}	 

您可以通过传递三个参数来设置回调。第一个是您感兴趣的事件的名称,第二个是类的实例,第三个是您要调用的方法的名称。在此示例中,我们将StartEvent设置为在我身上调用myCallback方法(这是Cone2的实例)。myCallback方法当然必须是Cone2的有效方法,以避免发生错误。(此代码段来自VTK/Examples/Tutorial/Step2/Java/cone2.java。)

Cone2 me = new Cone2(); 
ren1.AddObserver("StartEvent",me,"myCallback");

Python
如果您已经建立了具有Python支持的VTK,将创建一个vtkpython可执行文件。使用此可执行文件,您应该能够按照以下方式运行Examples/Tutorial/Step1/Python/Cone.py。

vtkpython Cone.py 

使用我们的一些示例脚本作为起点,创建您自己的Python脚本很简单。可以通过定义一个函数,然后将其作为参数传递给AddObserver来设置用户方法,如下所示。

def myCallback(obj,event): 
	print "Starting to render" 
ren1.AddObserver("StartEvent",myCallback) 

上面显示的示例的完整源代码在VTK/Examples/Tutorial/Step2/Python/Cone2.py中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值