VTK笔记——轴对齐包围盒(AABB)

什么是包围盒

包围盒是指能够包容物体的立方体或者二维长方形,是包围体的一种,常常用于模型的碰撞检测。包围体主要包括球体、轴对齐包围盒(AABB)有向包围盒(OBB)和凸包(Convex Hull)。
在较早的时候,包围盒按照坐标系的坐标轴进行排列,这被称为轴对齐的包围盒(AABB/Axis-aligned bounding box)。为了将AABB与通用的情况区分开来,将任意的包围盒称为有向包围盒(OBB/Oriented bounding box)。AABB检测模型的相交要比OBB更简单,但是他的缺点是当模型旋转的时候无法随之旋转,而必须重新计算。

轴对齐包围盒

在VTK中,轴对齐包围盒被定义为包含该模型,且边平行于坐标轴的最小六面体。AABB比较简单,存储空间小,仅需六个标量。
获取bounds的方法
1. vtkPolyData
vtkPolyData通过继承关系拥有GetBounds()方法,实际在vtkDataSet中定义,

double *GetBounds() VTK_SIZEHINT(6);
void GetBounds(double bounds[6]);

获取包围盒的参数,即三个轴向上的最大值和最小值。

	vtkSmartPointer<vtkPolyData> polydata =
		vtkSmartPointer<vtkPolyData>::New();
	double bounds[6];
	polydata->GetBounds(bounds);

需要注意的是,通过reader或者source来的模型,需要先Update();
而有时候仅仅是获取这些参数并不直观,还需要显示包围盒vtkOutlineFilter提供了这一方便的操作,输入模型的数据,就很容易的可视化显示。

	vtkSmartPointer<vtkOutlineFilter> outline =
		vtkSmartPointer<vtkOutlineFilter>::New();
	outline->SetInputData(polydata);
	outline->Update();

如果需要看实心表面,则需要打开,默认是关闭的。

	outline->GenerateFacesOn();

2. vtkBoundingBox
另一种方法是用vtkBoundingBox的GetBounds方法

  void GetBounds(double bounds[6]) const;
  void GetBounds(double &xMin, double &xMax,
                 double &yMin, double &yMax,
                 double &zMin, double &zMax) const;

vtkBoundingBox是专门用来处理3D bounds的,快速小巧,用了很多内联函数。它没有继承vtkObject,因此可以不用new,直接在栈上分配。
它的输入对的是点,所以对于点云来说很方便。

  double p0[3] = {3, 4, 5};
  vtkBoundingBox boundingBox;
  boundingBox.AddPoint(p0);
  double bounds[6];
  boundingBox.GetBounds(bounds);

效果

cow

示例代码

#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkSphereSource.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkActor.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkOutlineFilter.h>
#include <vtkProperty.h>

int main(int argc, char *argv[])
{
	vtkSmartPointer<vtkPolyData> polydata =
		vtkSmartPointer<vtkPolyData>::New();
	if (argc > 1)
	{
		vtkSmartPointer<vtkXMLPolyDataReader> reader =
			vtkSmartPointer<vtkXMLPolyDataReader>::New();
		reader->SetFileName(argv[1]);
		reader->Update();
		polydata = reader->GetOutput();
	}
	else
	{
		vtkSmartPointer<vtkSphereSource> modelSource =
			vtkSmartPointer<vtkSphereSource>::New();
		modelSource->Update();
		polydata = modelSource->GetOutput();
	}

	vtkSmartPointer<vtkOutlineFilter> outline =
		vtkSmartPointer<vtkOutlineFilter>::New();
	outline->SetInputData(polydata);
	outline->Update();

	double bounds[6];
	polydata->GetBounds(bounds);
	std::cout << "Polydata bounds: " << std::endl;
	std::cout << "xmin: " << bounds[0] << " "
			  << "xmax: " << bounds[1] << std::endl
			  << "ymin: " << bounds[2] << " "
			  << "ymax: " << bounds[3] << std::endl
			  << "zmin: " << bounds[4] << " "
			  << "zmax: " << bounds[5] << std::endl;

	outline->GetOutput()->GetBounds(bounds);
	std::cout << "Outline bounds: " << std::endl;
	std::cout << "xmin: " << bounds[0] << " "
			  << "xmax: " << bounds[1] << std::endl
			  << "ymin: " << bounds[2] << " "
			  << "ymax: " << bounds[3] << std::endl
			  << "zmin: " << bounds[4] << " "
			  << "zmax: " << bounds[5] << std::endl;

	vtkSmartPointer<vtkPolyDataMapper> modelMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	modelMapper->SetInputData(polydata);

	vtkSmartPointer<vtkActor> modelActor =
		vtkSmartPointer<vtkActor>::New();
	modelActor->SetMapper(modelMapper);

	vtkSmartPointer<vtkPolyDataMapper> outlineMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	outlineMapper->SetInputConnection(outline->GetOutputPort());

	vtkSmartPointer<vtkActor> outlineActor =
		vtkSmartPointer<vtkActor>::New();
	outlineActor->SetMapper(outlineMapper);
	outlineActor->GetProperty()->SetColor(1, 0, 0);
	outlineActor->GetProperty()->SetLineWidth(1.5);

	vtkSmartPointer<vtkRenderer> renderer =
		vtkSmartPointer<vtkRenderer>::New();
	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->SetSize(300, 300);
	renderWindow->AddRenderer(renderer);
	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	renderWindowInteractor->SetRenderWindow(renderWindow);

	renderer->AddActor(modelActor);
	renderer->AddActor(outlineActor);

	renderWindow->Render();
	renderWindowInteractor->Start();

	return EXIT_SUCCESS;
}

Ref

维基百科.包围体
DataBounds
BoundingBox
The End

<think>好的,用户问的是如何在VTK C++中获取STL模型AABB包围盒的最大点。首先,我需要回忆一下VTK的相关类和方法。VTK处理STL文件通常用vtkSTLReader来读取模型。然后,包围盒的话,可能涉及到vtkPolyData或者vtkDataSet的GetBounds方法,但那个返回的是数组,包含xmin, xmax, ymin, ymax, zmin, zmax。不过用户需要的是AABB包围盒的最大点,也就是这个包围盒的右上角顶点,也就是(xmax, ymax, zmax)。 那步骤应该是:首先读取STL文件,接着获取包围盒的边界数据,然后从中提取最大点。不过可能需要确认vtkPolyData是否有直接的方法获取包围盒,或者是否需要计算。另外,vtkPolyData的GetBounds()方法返回的是一个长度为6的数组,按顺序是xmin, xmax, ymin, ymax, zmin, zmax。所以最大点的坐标应该是xmax, ymax, zmax这三个值。 那具体代码步骤大概是:用vtkSTLReader读取STL文件,然后调用Update()方法确保数据更新。然后获取生成的vtkPolyData对象,调用GetBounds()得到数组。然后从数组中取出索引1、3、5的位置的数据,组合成最大点。比如bounds[1]是xmax,bounds[3]是ymax,bounds[5]是zmax。然后输出或者存储这三个值即可。 需要注意可能的错误处理,比如文件读取是否正确,数据是否有效。另外,是否需要考虑模型的变换,比如如果模型被平移或者缩放,可能需要先应用变换后再计算包围盒?不过用户的问题可能只是基础的AABB,即轴对齐的包围盒,不涉及任何变换,所以直接使用GetBounds()应该就足够了。 此外,是否还有其他方法?比如使用vtkBoundingBox这个类?vtkBoundingBox可能有计算包围盒的方法,但需要先初始化并添加点,或者从现有的vtkDataSet获取。可能更复杂,而直接使用GetBounds()更简单直接。 所以总结步骤:读取STL,获取其polydata,调用GetBounds,提取最大点坐标。</think>在VTK(Visualization Toolkit)中,通过C++获取STL模型AABB轴对齐包围盒)最大点的步骤如下: --- ### **1. 读取STL文件** 使用`vtkSTLReader`加载STL模型: ```cpp vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New(); reader->SetFileName("your_model.stl"); reader->Update(); // 确保数据加载完成 ``` --- ### **2. 获取包围盒信息** 通过`vtkPolyData`的`GetBounds()`方法获取AABB边界: ```cpp vtkPolyData* polydata = reader->GetOutput(); double bounds[6]; polydata->GetBounds(bounds); // 返回数组:[xmin, xmax, ymin, ymax, zmin, zmax] ``` --- ### **3. 提取最大点坐标** 从`bounds`数组中提取最大点(即包围盒右上角顶点): ```cpp double maxPoint[3]; maxPoint[0] = bounds[1]; // xmax maxPoint[1] = bounds[3]; // ymax maxPoint[2] = bounds[5]; // zmax ``` --- ### **4. 完整代码示例** ```cpp #include <vtkSmartPointer.h> #include <vtkSTLReader.h> #include <vtkPolyData.h> int main() { // 读取STL文件 vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New(); reader->SetFileName("input.stl"); reader->Update(); // 获取包围盒 vtkPolyData* polydata = reader->GetOutput(); double bounds[6]; polydata->GetBounds(bounds); // 计算最大点 double maxPoint[3]; maxPoint[0] = bounds[1]; // xmax maxPoint[1] = bounds[3]; // ymax maxPoint[2] = bounds[5]; // zmax // 输出结果 std::cout << "AABB最大点坐标: (" << maxPoint[0] << ", " << maxPoint[1] << ", " << maxPoint[2] << ")" << std::endl; return 0; } ``` --- ### **关键说明** - **AABB包围盒**:轴对齐包围盒模型坐标系中自然对齐的最小立方体,其边与坐标轴平行。 - **`GetBounds()`返回值**:数组`bounds`按顺序存储了`[xmin, xmax, ymin, ymax, zmin, zmax]`。 - **应用场景**:AABB常用于碰撞检测、空间划分等快速计算。 如果需要更复杂的包围盒(如OBB方向包围盒),需使用`vtkOBBTree`类进一步计算。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值