VS+QT+VTK三维网格显示-点面选择-法线法向量显示-配准-分割窗体程序

news2024/11/15 19:56:21

程序示例精选

VS+QT+VTK三维网格显示-点面选择-法线法向量显示-配准-分割窗体程序

如需安装运行环境或远程调试,见文章底部个人QQ名片,由专业技术人员远程协助!

前言

这篇博客针对<<VS+QT+VTK三维网格显示-点面选择-法线法向量显示-配准-分割窗体程序>>编写代码,代码整洁,规则,易读。 学习与应用推荐首选。

功能:读取三维网格数据,包括*.obj、*.stl、*.off,通过单击网格表面高亮显示单个顶点和多个顶点以及单个面和面法线,显示带/不带线框的网格数据,显示点数、面数和边数,ICP算法与半自动分割算法的实现


文章目录

一、所需工具软件

二、使用步骤

        1. 引入库

        2. 代码实现

        3. 运行结果

三、在线协助

一、所需工具软件

1. VS, Qt

2. VTK

二、使用步骤

1.引入库

#include <QtCore/QStringList>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMessageBox>

#include <vtkAppendPolyData.h>
#include <vtkCellData.h>
#include <vtkExtractEdges.h>
#include <vtkIdTypeArray.h>
#include <vtkMath.h>
#include <vtkLineSource.h>
#include <vtkLookupTable.h>
#include <vtkMatrix4x4.h>
#include <vtkNew.h>
#include <vtkOBJReader.h>
#include <vtkPointData.h>
#include <vtkPoints.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkScalarBarActor.h>
#include <vtkSphereSource.h>
#include <vtkSTLReader.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>

#include <iomanip>
#include <sstream>

#include "icp_algorithm.h"
#include "mesh_operation.h"
#include "mesh_segmenter.h"
#include "vtkOFFReader.h"

2. 代码实现

代码如下:

void MeshProcessing::OnWireframeMode() {
	bool isChecked = this->wireframe_mode_action_->isChecked();
	for (auto actor : this->mesh_processing_data_model_->wireframe_actor_vec_)
		actor->SetVisibility(isChecked);
	this->vtk_widget_->update();
}

void MeshProcessing::OnObserveMode() {
	this->removeVertexActors();
	this->removeFaceActors();
	this->removeMultiVertexActors();
	this->removeFillRegionFaceActors();
	this->mesh_processing_data_model_->pick_mode_ = MeshProcessingDataModel::OBSERVE;
	this->vtk_widget_->updateTopText();
}

void MeshProcessing::OnVertexMode() {
	this->removeFaceActors();
	this->removeMultiVertexActors();
	this->removeFillRegionFaceActors();
	this->mesh_processing_data_model_->pick_mode_ = MeshProcessingDataModel::VERTEX;
	this->vtk_widget_->updateTopText();
}

void MeshProcessing::OnFaceMode() {
	this->removeVertexActors();
	this->removeMultiVertexActors();
	this->removeFillRegionFaceActors();
	this->mesh_processing_data_model_->pick_mode_ = MeshProcessingDataModel::FACE;
	this->vtk_widget_->updateTopText();
}

void MeshProcessing::OnMultiVertexMode() {
	this->removeVertexActors();
	this->removeFaceActors();
	this->removeFillRegionFaceActors();
	this->mesh_processing_data_model_->pick_mode_ = MeshProcessingDataModel::MULTI_VERTEX;
	this->vtk_widget_->updateTopText();
}

void MeshProcessing::OnDisplayNormal() {
	if (this->mesh_processing_data_model_->pick_mode_ != MeshProcessingDataModel::FACE ||
		this->mesh_processing_data_model_->selected_face_id_ == -1) {
		QMessageBox::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("请在面拾取模式中选取一个面片!"));
		return;
	}

	int cellId = this->mesh_processing_data_model_->selected_face_id_;
	vtkCell * cell = this->mesh_processing_data_model_->combined_mesh_->GetCell(cellId);

	double p0[3], p1[3], p2[3];
	this->mesh_processing_data_model_->combined_mesh_->GetPoint(cell->GetPointId(0), p0);
	this->mesh_processing_data_model_->combined_mesh_->GetPoint(cell->GetPointId(1), p1);
	this->mesh_processing_data_model_->combined_mesh_->GetPoint(cell->GetPointId(2), p2);

	double c[3];
	for (int i = 0; i < 3; ++i) c[i] = (p0[i] + p1[i] + p2[i]) / 3;

	double p0p1[3], p0p2[3];
	vtkMath::Subtract(p1, p0, p0p1);
	vtkMath::Subtract(p2, p0, p0p2);

	double normal[3];
	vtkMath::Cross(p0p1, p0p2, normal);
	vtkMath::Normalize(normal);

	double constant = (
		std::sqrt(vtkMath::Distance2BetweenPoints(p0, p1)) +
		std::sqrt(vtkMath::Distance2BetweenPoints(p1, p2)) +
		std::sqrt(vtkMath::Distance2BetweenPoints(p2, p0))
	);
	double e[3];
	for (int i = 0; i < 3; ++i) e[i] = c[i] + constant * normal[i];

	vtkSmartPointer<vtkLineSource> lineSource =
		vtkSmartPointer<vtkLineSource>::New();
	lineSource->SetPoint1(c);
	lineSource->SetPoint2(e);
	lineSource->Update();

	this->mesh_processing_data_model_->selected_face_normal_actor_ = this->vtk_widget_->addActor(lineSource->GetOutput());
	this->mesh_processing_data_model_->selected_face_normal_actor_->GetProperty()->SetColor(.8, .8, .2);
	this->mesh_processing_data_model_->selected_face_normal_actor_->GetProperty()->SetLineWidth(5);

	this->vtk_widget_->update();
}

void MeshProcessing::OnDefaultMode() {
	this->mesh_processing_data_model_->display_mode_ = MeshProcessingDataModel::DEFAULT;
	if (this->mesh_processing_data_model_->highlight_vec_[0] == 1)
		this->vtk_widget_->highlightMesh(this->mesh_processing_data_model_->actor_vec_[0]);
	else
		this->vtk_widget_->unhighlightMesh(this->mesh_processing_data_model_->actor_vec_[0]);
	this->vtk_widget_->update();
}

void MeshProcessing::OnDiscreteMode() {
	if (this->mesh_processing_data_model_->actor_vec_.size() != 1) {
		QMessageBox::critical(this, QString::fromLocal8Bit("错误"), QString::fromLocal8Bit("请检查目前读入的网格数是否为1!"));
		return;
	}

	this->mesh_processing_data_model_->display_mode_ = MeshProcessingDataModel::DISCRETE;
	this->mesh_processing_data_model_->mesh_vec_[0] = this->color_table_handler_->turnToDiscrete();

	this->mesh_processing_data_model_->hueLut = vtkSmartPointer<vtkLookupTable>::New();
	this->mesh_processing_data_model_->hueLut->SetNumberOfTableValues(this->color_table_handler_->maxScalar() - this->color_table_handler_->minScalar() + 1);
	this->mesh_processing_data_model_->hueLut->Build();

	for (int i = 0; i < this->color_table_handler_->maxScalar() - this->color_table_handler_->minScalar() + 1; ++i) {
		double hue = i * 1.0 / (this->color_table_handler_->maxScalar() - this->color_table_handler_->minScalar() + 1);
		double r, g, b;
		vtkMath::HSVToRGB(hue, 1.0, 1.0, &r, &g, &b);
		this->mesh_processing_data_model_->hueLut->SetTableValue(i, r, g, b, 1);
	}

	this->mesh_processing_data_model_->actor_vec_[0]->GetMapper()->SetScalarRange(0, this->color_table_handler_->maxScalar() - this->color_table_handler_->minScalar() + 1);
	this->mesh_processing_data_model_->actor_vec_[0]->GetMapper()->SetScalarModeToUseCellData();
	this->mesh_processing_data_model_->actor_vec_[0]->GetMapper()->SetColorModeToMapScalars();
	this->mesh_processing_data_model_->actor_vec_[0]->GetMapper()->SetLookupTable(this->mesh_processing_data_model_->hueLut);

	if (this->mesh_processing_data_model_->highlight_vec_[0] == 1)
		this->vtk_widget_->highlightMesh(this->mesh_processing_data_model_->actor_vec_[0]);
	else
		this->vtk_widget_->unhighlightMesh(this->mesh_processing_data_model_->actor_vec_[0]);
	this->vtk_widget_->update();
}

void MeshProcessing::OnContinuousMode() {
	if (this->mesh_processing_data_model_->actor_vec_.size() != 1) {
		QMessageBox::critical(this, QString::fromLocal8Bit("错误"), QString::fromLocal8Bit("请检查目前读入的网格数是否为1!"));
		return;
	}

	this->mesh_processing_data_model_->display_mode_ = MeshProcessingDataModel::CONTINUOUS;
	this->mesh_processing_data_model_->mesh_vec_[0] = this->color_table_handler_->turnToContinuous();

	this->mesh_processing_data_model_->hueLut = vtkSmartPointer<vtkLookupTable>::New();
	this->mesh_processing_data_model_->hueLut->SetTableRange(this->color_table_handler_->minScalar(), this->color_table_handler_->maxScalar() + 1);
	this->mesh_processing_data_model_->hueLut->SetHueRange(0, 1);
	this->mesh_processing_data_model_->hueLut->SetSaturationRange(1, 1);
	this->mesh_processing_data_model_->hueLut->SetValueRange(1, 1);
	this->mesh_processing_data_model_->hueLut->Build();

	this->mesh_processing_data_model_->actor_vec_[0]->GetMapper()->SetScalarRange(this->color_table_handler_->minScalar(), this->color_table_handler_->maxScalar() + 1);
	this->mesh_processing_data_model_->actor_vec_[0]->GetMapper()->SetScalarModeToUseCellData();
	this->mesh_processing_data_model_->actor_vec_[0]->GetMapper()->SetColorModeToMapScalars();
	this->mesh_processing_data_model_->actor_vec_[0]->GetMapper()->SetLookupTable(this->mesh_processing_data_model_->hueLut);

	if (this->mesh_processing_data_model_->highlight_vec_[0] == 1)
		this->vtk_widget_->highlightMesh(this->mesh_processing_data_model_->actor_vec_[0]);
	else
		this->vtk_widget_->unhighlightMesh(this->mesh_processing_data_model_->actor_vec_[0]);
	this->vtk_widget_->update();
}

void MeshProcessing::OnICPRegistration() {
	std::vector<int> active_ids;
	for (int i = 0; i < this->mesh_processing_data_model_->highlight_vec_.size(); ++i) {
		if (this->mesh_processing_data_model_->highlight_vec_[i])
			active_ids.push_back(i);
	}

	if (active_ids.size() != 2) {
		QMessageBox::warning(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("请检查目前选中的网格数是否为2!"));
		return;
	}

	this->wireframe_mode_action_->setChecked(false);
	OnWireframeMode();
	this->disableAllActions();
	this->OnObserveMode();
	this->register_scroll_area_->setVisible(true);

	this->mesh_processing_data_model_->source_id = active_ids.front();
	this->mesh_processing_data_model_->target_id = active_ids.back();

	this->mesh_processing_data_model_->actor_vec_[this->mesh_processing_data_model_->target_id]->GetProperty()->SetColor(.8, .2, .2);
	this->vtk_widget_->update();

	this->tab_widget_->setTabEnabled(0, false);
	this->tab_widget_->setTabEnabled(1, true);
	this->tab_widget_->setCurrentIndex(1);
}

void MeshProcessing::OnSegment() {
	if (this->mesh_processing_data_model_->mesh_vec_.size() != 1) {
		QMessageBox::critical(this, QString::fromLocal8Bit("错误"), QString::fromLocal8Bit("请检查目前读入的网格数是否为1!"));
		return;
	}

	this->wireframe_mode_action_->setChecked(false);
	OnWireframeMode();
	this->disableAllActions();
	this->OnObserveMode();

	if (this->color_table_handler_ != nullptr) {
		this->default_mode_action_->setEnabled(false);
		this->discrete_mode_action_->setEnabled(false);
		this->continuous_mode_action_->setEnabled(false);
		this->OnDefaultMode();
	}

	this->segment_scroll_area_->setVisible(true);
	this->cluster_num_slider_->setEnabled(false);

	this->mesh_processing_data_model_->segment_id = 0;

	this->tab_widget_->setTabEnabled(0, false);
	this->tab_widget_->setTabEnabled(1, true);
	this->tab_widget_->setCurrentIndex(1);
}

void MeshProcessing::OnFillRegionThreeVertices() {
	this->removeFillRegionFaceActors();

	for (int i = 0; i < this->mesh_processing_data_model_->combined_mesh_->GetNumberOfCells(); ++i) {
		vtkSmartPointer<vtkIdList> ptIds =
			vtkSmartPointer<vtkIdList>::New();
		this->mesh_processing_data_model_->combined_mesh_->GetCellPoints(i, ptIds);

		int validNum = 0;
		for (int k = 0; k < 3; ++k)
			validNum += this->mesh_processing_data_model_->selected_multi_vertex_set_.find(ptIds->GetId(k)) != this->mesh_processing_data_model_->selected_multi_vertex_set_.end() ? 1 : 0;

		if (validNum == 3) {
			this->mesh_processing_data_model_->fill_region_face_actor_vec_.push_back(this->vtk_widget_->highlightFace(this->mesh_processing_data_model_->combined_mesh_, i));
			this->mesh_processing_data_model_->fill_region_face_actor_vec_.back()->GetProperty()->SetColor(.8, .8, .2);
		}
	}

	this->vtk_widget_->update();
}

void MeshProcessing::OnFillRegionTwoVertices() {
	this->removeFillRegionFaceActors();

	for (int i = 0; i < this->mesh_processing_data_model_->combined_mesh_->GetNumberOfCells(); ++i) {
		vtkSmartPointer<vtkIdList> ptIds =
			vtkSmartPointer<vtkIdList>::New();
		this->mesh_processing_data_model_->combined_mesh_->GetCellPoints(i, ptIds);

		int validNum = 0;
		for (int k = 0; k < 3; ++k)
			validNum += this->mesh_processing_data_model_->selected_multi_vertex_set_.find(ptIds->GetId(k)) != this->mesh_processing_data_model_->selected_multi_vertex_set_.end() ? 1 : 0;

		if (validNum >= 2) {
			this->mesh_processing_data_model_->fill_region_face_actor_vec_.push_back(this->vtk_widget_->highlightFace(this->mesh_processing_data_model_->combined_mesh_, i));
			this->mesh_processing_data_model_->fill_region_face_actor_vec_.back()->GetProperty()->SetColor(.8, .8, .2);
		}
	}

	this->vtk_widget_->update();
}

void MeshProcessing::OnListWidgetModelItemChanged(QListWidgetItem * item) {
	int row_id = this->list_widget_model_->row(item);

	if (item->checkState() == Qt::Unchecked) {
		this->vtk_widget_->unhighlightMesh(this->mesh_processing_data_model_->actor_vec_[row_id]);
		this->mesh_processing_data_model_->highlight_vec_[row_id] = 0;
	} else {
		this->vtk_widget_->highlightMesh(this->mesh_processing_data_model_->actor_vec_[row_id]);
		this->mesh_processing_data_model_->highlight_vec_[row_id] = 1;
	}

	this->resetParameters();

	this->vtk_widget_->update();
}

void MeshProcessing::OnRunICP() {
	ICPAlgorithm icp;
	icp.setSource(this->mesh_processing_data_model_->mesh_vec_[this->mesh_processing_data_model_->source_id]);
	icp.setTarget(this->mesh_processing_data_model_->mesh_vec_[this->mesh_processing_data_model_->target_id]);
	if (this->move_center_radio_button_->isChecked())
		icp.moveCenterOn();
	else
		icp.moveCenterOff();
	icp.setMaxIter(this->max_iter_spin_box_->value());
	icp.setMinError(this->min_error_double_spin_box_->value());
	icp.registration();

	vtkMatrix4x4 * transform_matrix = icp.getTransformMatrix();
	
	std::ostringstream oss;
	oss << setprecision(2);
	for (int i = 0; i < 4; ++i) {
		for (int j = 0; j < 4; ++j) oss << transform_matrix->GetElement(i, j) << "\t";
		oss << std::endl;
	}

	this->iter_num_label_->setText(QString::number(icp.getIterNum()));
	this->error_label_->setText(QString::number(icp.getError()));
	this->matrix_label_->setText(QString::fromStdString(oss.str()));

	vtkSmartPointer<vtkTransform> transform =
		vtkSmartPointer<vtkTransform>::New();
	transform->SetMatrix(transform_matrix);
	transform->Update();

	vtkNew<vtkTransformPolyDataFilter> transformFilter;
	transformFilter->SetInputData(this->mesh_processing_data_model_->mesh_vec_[0]);
	transformFilter->SetTransform(transform);
	transformFilter->Update();

	vtkPolyDataMapper * mapper = vtkPolyDataMapper::SafeDownCast(this->mesh_processing_data_model_->actor_vec_[0]->GetMapper());
	mapper->SetInputData(transformFilter->GetOutput());

	this->vtk_widget_->resetCamera();
	this->vtk_widget_->update();
}

void MeshProcessing::OnExitICP() {
	this->tab_widget_->setTabEnabled(0, true);
	this->tab_widget_->setTabEnabled(1, false);
	this->tab_widget_->setCurrentIndex(0);

	this->iter_num_label_->setText("");
	this->error_label_->setText("");
	this->matrix_label_->setText("");

	this->enableAllActions();

	this->mesh_processing_data_model_->mesh_vec_[0]->DeepCopy(this->mesh_processing_data_model_->actor_vec_[0]->GetMapper()->GetInput());
	this->mesh_processing_data_model_->actor_vec_[this->mesh_processing_data_model_->target_id]->GetProperty()->SetColor(.0, .5, 1.);
	this->vtk_widget_->update();

	this->register_scroll_area_->setVisible(false);
	this->resetParameters();
}

void MeshProcessing::OnCancelICP() {
	this->tab_widget_->setTabEnabled(0, true);
	this->tab_widget_->setTabEnabled(1, false);
	this->tab_widget_->setCurrentIndex(0);

	this->iter_num_label_->setText("");
	this->error_label_->setText("");
	this->matrix_label_->setText("");

	this->enableAllActions();

	vtkPolyDataMapper * mapper = vtkPolyDataMapper::SafeDownCast(this->mesh_processing_data_model_->actor_vec_[0]->GetMapper());
	mapper->SetInputData(this->mesh_processing_data_model_->mesh_vec_[0]);

	this->mesh_processing_data_model_->actor_vec_[this->mesh_processing_data_model_->target_id]->GetProperty()->SetColor(.0, .5, 1.);
	this->vtk_widget_->update();

	this->register_scroll_area_->setVisible(false);
	this->resetParameters();
}

void MeshProcessing::OnClusterNumChanged(int n) {
	using std::vector;

	this->color_table_handler_ = new ColorTableHandler;
	this->color_table_handler_->setMesh(this->mesh_processing_data_model_->mesh_vec_[this->mesh_processing_data_model_->segment_id]);

	vector<double> color_value_vec;
	vtkSmartPointer<vtkDoubleArray> scalars = this->mesh_processing_data_model_->mesh_segmenter_->getSegmentScalar(n);
	this->mesh_processing_data_model_->mesh_vec_[this->mesh_processing_data_model_->segment_id]->GetCellData()->SetScalars(scalars);
	for (int i = 0; i < scalars->GetNumberOfValues(); ++i)
		color_value_vec.push_back(scalars->GetValue(i));
	this->color_table_handler_->readColorValueVec(color_value_vec);

	this->OnDiscreteMode();
}

void MeshProcessing::OnRunSegment() {
	this->mesh_processing_data_model_->mesh_segmenter_ = new MeshSegmenter(this->seed_num_spin_box_->value(), this->phy_ratio_double_spin_box_->value());
	this->mesh_processing_data_model_->mesh_segmenter_->vtk_widget_ = this->vtk_widget_;
	this->mesh_processing_data_model_->mesh_segmenter_->setMesh(this->mesh_processing_data_model_->mesh_vec_[this->mesh_processing_data_model_->segment_id]);
	this->mesh_processing_data_model_->mesh_segmenter_->segment();

	this->cluster_num_slider_->setEnabled(true);
	this->cluster_num_slider_->setValue(2);
	this->OnClusterNumChanged(2);

	this->cluster_num_slider_->setMinimum(2);
	this->cluster_num_slider_->setMaximum(this->seed_num_spin_box_->value());
}

void MeshProcessing::OnExitSegment() {
	using std::vector;

	this->tab_widget_->setTabEnabled(0, true);
	this->tab_widget_->setTabEnabled(1, false);
	this->tab_widget_->setCurrentIndex(0);

	this->iter_num_label_->setText("");
	this->error_label_->setText("");
	this->matrix_label_->setText("");

	this->enableAllActions();

	this->default_mode_action_->setEnabled(true);
	this->discrete_mode_action_->setEnabled(true);
	this->continuous_mode_action_->setEnabled(true);

	this->segment_scroll_area_->setVisible(false);
	this->resetParameters();
}

void MeshProcessing::OnCancelSegment() {
	this->tab_widget_->setTabEnabled(0, true);
	this->tab_widget_->setTabEnabled(1, false);
	this->tab_widget_->setCurrentIndex(0);

	this->iter_num_label_->setText("");
	this->error_label_->setText("");
	this->matrix_label_->setText("");

	this->enableAllActions();

	this->default_mode_action_->setEnabled(false);
	this->discrete_mode_action_->setEnabled(false);
	this->continuous_mode_action_->setEnabled(false);

	this->mesh_processing_data_model_->combined_mesh_->GetCellData()->SetScalars(nullptr);
	this->mesh_processing_data_model_->actor_vec_[this->mesh_processing_data_model_->segment_id]->GetProperty()->SetColor(.0, .5, 1.);
	this->mesh_processing_data_model_->actor_vec_[this->mesh_processing_data_model_->segment_id]->GetMapper()->ScalarVisibilityOff();
	this->vtk_widget_->update();

	this->segment_scroll_area_->setVisible(false);
	this->resetParameters();
}

void MeshProcessing::OnSelectVertex(vtkIdType id) {
	if (id == -1) return;

	this->removeVertexActors();

	this->mesh_processing_data_model_->selected_vertex_actor_ = this->vtk_widget_->highlightVertex(this->mesh_processing_data_model_->combined_mesh_, id);
	this->mesh_processing_data_model_->selected_vertex_actor_->GetProperty()->SetInterpolationToGouraud();
	this->mesh_processing_data_model_->selected_vertex_actor_->GetProperty()->SetColor(.8, .2, .2);

	auto neighborVertexIds = MeshOperation::getConnectedVertices(this->mesh_processing_data_model_->combined_mesh_, id);
	for (const auto & neighbor : neighborVertexIds) {
		this->mesh_processing_data_model_->neighbor_vertex_actor_vec_.push_back(this->vtk_widget_->highlightVertex(this->mesh_processing_data_model_->combined_mesh_, neighbor));
		this->mesh_processing_data_model_->neighbor_vertex_actor_vec_.back()->GetProperty()->SetInterpolationToGouraud();
		this->mesh_processing_data_model_->neighbor_vertex_actor_vec_.back()->GetProperty()->SetColor(.8, .8, .2);
	}

	auto neighborFaceIds = MeshOperation::getVertexConnectedFaces(this->mesh_processing_data_model_->combined_mesh_, id);
	for (const auto & neighbor : neighborFaceIds) {
		this->mesh_processing_data_model_->neighbor_face_actor_vec_.push_back(this->vtk_widget_->highlightFace(this->mesh_processing_data_model_->combined_mesh_, neighbor));
		this->mesh_processing_data_model_->neighbor_face_actor_vec_.back()->GetProperty()->SetColor(.8, .5, .2);
	}

	this->vtk_widget_->update();
}

void MeshProcessing::OnSelectFace(vtkIdType id) {
	if (id == -1) return;

	this->removeFaceActors();

	this->mesh_processing_data_model_->selected_face_actor_ = this->vtk_widget_->highlightFace(this->mesh_processing_data_model_->combined_mesh_, id);
	this->mesh_processing_data_model_->selected_face_actor_->GetProperty()->SetColor(.8, .2, .2);

	auto neighborFaceIds = MeshOperation::getFaceConnectedFaces(this->mesh_processing_data_model_->combined_mesh_, id);
	for (const auto & neighbor : neighborFaceIds) {
		this->mesh_processing_data_model_->neighbor_face2_actor_vec_.push_back(this->vtk_widget_->highlightFace(this->mesh_processing_data_model_->combined_mesh_, neighbor));
		this->mesh_processing_data_model_->neighbor_face2_actor_vec_.back()->GetProperty()->SetColor(.8, .8, .2);
	}

	this->mesh_processing_data_model_->selected_face_id_ = id;

	this->vtk_widget_->update();
}

void MeshProcessing::OnSelectMultiVertex(const std::vector<vtkIdType>& ids) {
	this->removeMultiVertexActors();

	this->mesh_processing_data_model_->selected_multi_vertex_set_.clear();
	for (const auto & id : ids) {
		this->mesh_processing_data_model_->selected_multi_vertex_actor_vec_.push_back(this->vtk_widget_->highlightVertex(this->mesh_processing_data_model_->combined_mesh_, id));
		this->mesh_processing_data_model_->selected_multi_vertex_actor_vec_.back()->GetProperty()->SetInterpolationToGouraud();
		this->mesh_processing_data_model_->selected_multi_vertex_actor_vec_.back()->GetProperty()->SetColor(.8, .2, .2);

		this->mesh_processing_data_model_->selected_multi_vertex_set_.insert(id);
	}

	this->vtk_widget_->update();
}

void MeshProcessing::resetParameters() {
	vtkSmartPointer<vtkAppendPolyData> appendFilter =
		vtkSmartPointer<vtkAppendPolyData>::New();
	int cnt = 0;
	int num_edges = 0;
	for (int i = 0; i < this->mesh_processing_data_model_->highlight_vec_.size(); ++i) {
		if (this->mesh_processing_data_model_->highlight_vec_[i]) {
			appendFilter->AddInputData(this->mesh_processing_data_model_->mesh_vec_[i]);
			num_edges += this->mesh_processing_data_model_->mesh_edge_vec_[i]->GetNumberOfLines();
			++cnt;
		}
	}
	if (cnt > 0) {
		appendFilter->Update();
		this->mesh_processing_data_model_->combined_mesh_ =
			vtkSmartPointer<vtkPolyData>::New();
		this->mesh_processing_data_model_->combined_mesh_->DeepCopy(appendFilter->GetOutput());

		vtkSmartPointer<vtkIdTypeArray> numberScalarArray =
			vtkSmartPointer<vtkIdTypeArray>::New();
		numberScalarArray->SetNumberOfComponents(1);
		numberScalarArray->SetName("number");
		numberScalarArray->SetNumberOfValues(this->mesh_processing_data_model_->combined_mesh_->GetNumberOfPoints());
		for (int i = 0; i < this->mesh_processing_data_model_->combined_mesh_->GetNumberOfPoints(); ++i)
			numberScalarArray->SetValue(i, i);

		this->mesh_processing_data_model_->combined_mesh_->GetPointData()->AddArray(numberScalarArray);

		int edge_count = 0;
		this->mesh_processing_data_model_->mean_edge_length = 0.0;
		for (int i = 0; i < this->mesh_processing_data_model_->highlight_vec_.size(); ++i) {
			if (this->mesh_processing_data_model_->highlight_vec_[i]) {
				this->mesh_processing_data_model_->mean_edge_length +=
					this->mesh_processing_data_model_->mesh_edge_vec_[i]->GetNumberOfLines() * this->mesh_processing_data_model_->mean_edge_length_vec_[i];
				edge_count += this->mesh_processing_data_model_->mesh_edge_vec_[i]->GetNumberOfLines();
			}
		}
		this->mesh_processing_data_model_->mean_edge_length /= edge_count;

		this->vtk_widget_->updateBottomText(
			this->mesh_processing_data_model_->combined_mesh_->GetNumberOfPoints(),
			this->mesh_processing_data_model_->combined_mesh_->GetNumberOfCells(),
			num_edges
		);
	} else {
		this->mesh_processing_data_model_->combined_mesh_ = nullptr;
		this->mesh_processing_data_model_->mean_edge_length = 0.0;
		this->vtk_widget_->updateBottomText(
			0, 0, 0
		);
	}
}

3. 运行结果

面选择 

法线显示 

 多点选择

配准 

三、在线协助:

如需安装运行环境或远程调试,见文章底部个人 QQ 名片,由专业技术人员远程协助!
1)远程安装运行环境,代码调试
2)Qt, C++, Python入门指导
3)界面美化
4)软件制作

当前文章连接:Python+Qt桌面端与网页端人工客服沟通工具_alicema1111的博客-CSDN博客

博主推荐文章:python人脸识别统计人数qt窗体-CSDN博客

博主推荐文章:Python Yolov5火焰烟雾识别源码分享-CSDN博客

                         Python OpenCV识别行人入口进出人数统计_python识别人数-CSDN博客

个人博客主页:alicema1111的博客_CSDN博客-Python,C++,网页领域博主

博主所有文章点这里alicema1111的博客_CSDN博客-Python,C++,网页领域博主

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/677322.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Quartz使用H2数据库(嵌入模式)进行持久化

使用H2(嵌入模式)持久化Quartz任务 &#x1f51d;前言&#xff1a; Quartz在包内提供了多种数据库的sql文件&#xff0c;大家可以选择方便的使用。路径如下。 1.初始化h2(不使用Server模式) public class InitH2 {private static String USER_NAME "lee";private…

Unity简单操作:InputSystem获取WASD键盘输入 移动人物

目录 安装InputSystem 在编辑的脚本中使用 InputSystem生成的脚本 Unity版本&#xff1a;2019.2.3f1 安装InputSystem 菜单栏/Window/Package Manager/Input System 工程面板内 右键-->创建Input Actions 选中New Controls改名为PlayerControls 然后属性 面板按下Edit as…

软件项目管理 第七章 软件项目的质量管理与配置管理 课后习题参考答案——主编:李冰、张桥珍、刘玉娥

第七章 软件项目的质量管理与配置管理 课后习题参考答案 1.选择题 (1)项目质量管理的最终责任由谁来承担?&#xff08;D&#xff09; A.项目开发人员 B.采购经理 C.质量经理 D.项目经理 (2)“质量成本”是一个项目管理概念,它说明了下列哪项成本?…

HDFS 写流程源码分析

HDFS 写流程源码分析 一、客户端&#xff08;一&#xff09;文件创建及Pipeline构建阶段&#xff08;二&#xff09;数据写入&#xff08;三&#xff09;输出流关闭 二、NameNode端&#xff08;一&#xff09;create 环境为hadoop 3.1.3 一、客户端 以下代码创建并写入文件。 …

如何优雅地安装 Android Studio

&#x1f4ad; 写在前面&#xff1a;我们假设读者已经搞定 JDK 了&#xff0c;如果没搞定请先搜索 JDK 的安装教程。访问 Oracle JDK 下载页面&#xff1a;访问 Java Downloads | Oracle &#xff0c;点击 "JDK Download" 按钮。选择适合您操作系统的 JDK 版本&#…

设计模式之模板方法模式笔记

设计模式之模板方法模式笔记 说明Template Method(模板方法)目录模板方法模式示例类图抽象类包菜类菜心类测试类 说明 记录下学习设计模式-模板方法模式的写法。JDK使用版本为1.8版本。 Template Method(模板方法) 意图:定义一个操作中的算法骨架&#xff0c;而将一些步骤延…

yolo格式visdrone转换

目录 yolo格式转换1. Visdrone2019格式转换 yolo格式转换 1. Visdrone2019格式转换 数据集下载地址https://aistudio.baidu.com/aistudio/datasetdetail/115729 如果是visdrone数据集&#xff0c;直接使用txt2xml.py去转换&#xff0c;修改annotation和img的路径&#xff0c…

<Linux开发>驱动开发 -之- Linux LCD 驱动

&#xff1c;Linux开发&#xff1e;驱动开发 -之- Linux LCD 驱动 交叉编译环境搭建&#xff1a; &#xff1c;Linux开发&#xff1e; linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下&#xff1a; &#xff1c;Linux开发&#xff1e; -之-系统移植 uboot移植过程详细…

网络基础一

网络发展 独立模式&#xff1a;计算机之间相互独立。 网络互联&#xff1a;多台计算机连接在一起&#xff0c;完成数据共享。 局域网LAN&#xff1a;计算机数量更多了&#xff0c;通过交换机和路由器连接在一起&#xff1b; 广域网WAN&#xff1a;将远隔千里的计算机都连在…

[BPU部署教程] 万字长文!通透解读模型部署端到端大流程——以终为始,以行为知

去年6月份拿到开发板到现在&#xff0c;转眼已经过去大半年了&#xff0c;这个博客11月初就在写&#xff0c;断断续续写到现在。C部署需要考虑的问题很多&#xff0c;如果只给个简单部署教程的话&#xff0c;就算整理出来&#xff0c;感觉帮助也不大&#xff0c;各位开发时候我…

YOLOv5改进系列(11)——添加损失函数之EIoU、AlphaIoU、SIoU、WIoU

【YOLOv5改进系列】前期回顾: YOLOv5改进系列(0)——重要性能指标与训练结果评价及分析 YOLOv5改进系列(1)——添加SE注意力机制

模版方法模式在 JDK 及 spring 源码中的应用

模版方法模式 模板方法模式是一种行为设计模式&#xff0c; 它在超类中定义了一个算法的框架&#xff0c; 允许子类在不修改结构的情况下重写算法的特定步骤。 更多有关于模版方法模式的介绍详见&#xff1a;https://refactoringguru.cn/design-patterns/template-method 模版…

津津乐道设计模式 - 委派模式详解(以家庭弟位让你彻底明白)

&#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Micro麦可乐的博客 &#x1f425;《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程&#xff0c;入门到实战 &#x1f33a;《RabbitMQ》…

STM32 Proteus仿真DHT11温度湿度光敏光强DS1302闹钟-0044

STM32 Proteus仿真DHT11温度湿度光敏光强DS1302闹钟-0044 Proteus仿真小实验&#xff1a; STM32 Proteus仿真DHT11温度湿度光敏光强DS1302闹钟-0044 功能&#xff1a; 硬件组成&#xff1a; STM32F103C6T6单片机 DHT11温度湿度光敏电阻采集光强 多个按键模拟红外遥控1个LED…

node.js--vue仓库进销存管理信息系统whkb8

随着社会的发展&#xff0c;系统的管理形势越来越严峻。越来越多的用户利用互联网获得信息&#xff0c;但各种信息鱼龙混杂&#xff0c;信息真假难以辨别。为了方便用户更好的获得仓库管理信息&#xff0c;因此&#xff0c;设计一种安全高效的仓库管理信息系统极为重要。 为设计…

【从零开始学习JAVA | 第十五篇】 多态

前言&#xff1a; 本篇我们来解释一下什么是多态关系&#xff0c;多态关系属于面向对象三大特征的最后一个&#xff0c;可以说面向对象的重点就在多态&#xff0c;因此我们要学好面向对象编程思想&#xff0c;就要学好多态。 多态&#xff1a; Java中的多态是指同一类对象在不同…

nssctf之SSRF刷题记录

[NISACTF 2022]easyssrf 题目讲的主要是ssrf以及php伪协议的能力&#xff0c;题目详情如下 一般来说&#xff0c;当一个网站出现curl类的功能时就可能会出现ssrf之类的漏洞&#xff0c;常见的ssrf协议如下 file:/// dict:// sftp:// ldap:// tftp:// gopher://file:// 这种…

基于python的matplotlib、numpy库实现的图形绘制(数据可视化)

一、sin&#xff0c;cos函数 1.题目要求 编写程序&#xff0c;绘制正弦曲线和余弦曲线。 提示&#xff1a;利用numpy的linspace()、sin()或cos()函数生成样本数据、正弦或余弦值。 2.函数讲解及代码 import matplotlib.pyplot as plt import numpy as np#linspace函数是用…

【MySQL数据库 | 第二十篇】explain执行计划

目录 前言&#xff1a; explain&#xff1a; 语法&#xff1a; 总结&#xff1a; 前言&#xff1a; 上一篇我们介绍了从时间角度分析MySQL语句执行效率的三大工具&#xff1a;SQL执行频率&#xff0c;慢日志查询&#xff0c;profile。但是这三个方法也只是在时间角度粗略的…

kubernetes入门案例

kubernetes入门案例 本文我们通过一个 Java Web 应用例子来介绍 kubernetes 的使用&#xff0c;可以让新手快速上手和实践。 此 Java Web 应用的结构比较简单&#xff0c;是一个运行在 Tomcat 里的 Web App&#xff0c;JSP 页面通过 JDBC 直接访问 MySQL 数据库并展示数据。…