C++ Qt/VTK装配体组成联动连接杆

16 篇文章 1 订阅
7 篇文章 2 订阅

效果

在这里插入图片描述

关键代码

#include "View3D.h"
#include "Axis.h"

#include <vtkActor.h>
#include <vtkAppendPolyData.h >
#include <vtkAreaPicker.h>
#include <vtkAxesActor.h>
#include <vtkBox.h>
#include <vtkCamera.h>
#include <vtkCaptionActor2D.h>
#include <vtkCellArray.h>
#include <vtkCleanPolyData.h >
#include <vtkContourFilter.h>
#include <vtkCubeSource.h>
#include <vtkCylinder.h>
#include <vtkCylinderSource.h>
#include <vtkDataSet.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkImplicitBoolean.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkLine.h>
#include <vtkMinimalStandardRandomSequence.h>
#include <vtkNamedColors.h>
#include <vtkObjectFactory.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkPlane.h>
#include <vtkPolyDataMapper.h>
#include <vtkPolyDataNormals.h>
#include <vtkPropPicker.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkRendererCollection.h>
#include <vtkReverseSense.h>
#include <vtkSTLReader.h>
#include <vtkSampleFunction.h>
#include <vtkSmartPointer.h>
#include <vtkSphere.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>

// 主体为长方体,端部两个半圆,半圆的圆心是空洞
decltype(auto) View3D::buildBoard(double r, double g, double b)
{
    // 创建长方体
    vtkNew<vtkCubeSource> cube;
    // 长度1,宽度0.2,厚度0.05
    cube->SetXLength(1);
    cube->SetYLength(0.05);
    cube->SetZLength(0.2);
    cube->Update();

    // 创建半圆
    vtkNew<vtkCylinderSource> cy;
    // 半径0.1,高度0.05,圆心0.5,0,0
    cy->SetRadius(0.1);
    cy->SetHeight(0.05);
    cy->SetCenter(0.5, 0, 0);
    cy->SetResolution(100);
    cy->Update();

    // 创建独立的对称半圆

    vtkNew<vtkCylinderSource> cy1;
    // 半径0.1,高度0.05,圆心-0.5,0,0
    cy1->SetRadius(0.1);
    cy1->SetHeight(0.05);
    cy1->SetResolution(100);
    cy1->SetCenter(-0.5, 0, 0);
    cy1->Update();

    // 小圆柱
    vtkNew<vtkCylinderSource> cy2;
    cy2->SetRadius(0.05);
    cy2->SetHeight(0.06);
    cy2->SetResolution(100);
    cy2->SetCenter(0.5, 0, 0);
    cy2->Update();

    // 小圆柱
    vtkNew<vtkCylinderSource> cy3;
    cy3->SetRadius(0.05);
    cy3->SetHeight(0.06);
    cy3->SetResolution(100);
    cy3->SetCenter(-0.5, 0, 0);
    cy3->Update();

    // 创建长方体和半圆的合体
    vtkNew<vtkAssembly> assembly;
    // cube actor
    vtkNew<vtkPolyDataMapper> cudeMapper;
    cudeMapper->SetInputConnection(cube->GetOutputPort());
    vtkNew<vtkActor> cudeActor;
    cudeActor->SetMapper(cudeMapper);
    cudeActor->GetProperty()->SetColor(r, g, b);
    assembly->AddPart(cudeActor);

    vtkNew<vtkPolyDataMapper> cyMapper;
    cyMapper->SetInputConnection(cy->GetOutputPort());
    vtkNew<vtkActor> cyActor;
    cyActor->SetMapper(cyMapper);
    cyActor->GetProperty()->SetColor(r, g, b);
    assembly->AddPart(cyActor);

    vtkNew<vtkPolyDataMapper> cy1Mapper;
    cy1Mapper->SetInputConnection(cy1->GetOutputPort());
    vtkNew<vtkActor> cy1Actor;
    cy1Actor->SetMapper(cy1Mapper);
    cy1Actor->GetProperty()->SetColor(r, g, b);
    assembly->AddPart(cy1Actor);

    vtkNew<vtkPolyDataMapper> cy2Mapper;
    cy2Mapper->SetInputConnection(cy2->GetOutputPort());
    vtkNew<vtkActor> cy2Actor;
    cy2Actor->SetMapper(cy2Mapper);
    cy2Actor->GetProperty()->SetColor(0.8, 0, 0);
    assembly->AddPart(cy2Actor);

    vtkNew<vtkPolyDataMapper> cy3Mapper;
    cy3Mapper->SetInputConnection(cy3->GetOutputPort());
    vtkNew<vtkActor> cy3Actor;
    cy3Actor->SetMapper(cy3Mapper);
    cy3Actor->GetProperty()->SetColor(0.8, 0, 0);
    assembly->AddPart(cy3Actor);
    return assembly;
}

decltype(auto) View3D::buildConnectRod()
{
    // 淡绿色
    auto actor1 = buildBoard(0.5, 1, 0.5);
    // 淡黄色
    auto actor2 = buildBoard(1, 1, 0.5);
    // 淡蓝色
    auto actor3 = buildBoard(0.5, 1, 1);
    // 平移actor
    actor1->AddPosition(0.5, 0, 0);
    actor2->AddPosition(1.5, 0.05, 0);
    actor3->AddPosition(2.5, 0.1, 0);
    vtkNew<vtkAssembly> assembly1, assembly2, assembly3;
    assembly1->AddPart(actor1);
    assembly1->AddPart(assembly2);
    assembly2->AddPart(actor2);
    assembly2->AddPart(assembly3);
    assembly3->AddPart(actor3);
    assembly2->SetOrigin(1, 0.05, 0);
    assembly3->SetOrigin(2, 0, 0);
    return std::make_tuple(vtkSmartPointer<vtkAssembly>(assembly1),
        vtkSmartPointer<vtkAssembly>(assembly2),
        vtkSmartPointer<vtkAssembly>(assembly3));
}

View3D::View3D(QWidget* parent)
    : QVTKOpenGLNativeWidget(parent)
{
    vtkNew<vtkRenderer> renderer;
    this->renderWindow()->AddRenderer(renderer);
    renderer->AddActor(baseAxes = getBaseAxes());
    addGuideLine(3, 0.2);
    connectRods = buildConnectRod();
    auto&& [actor1, actor2, actor3] = connectRods;
    renderer->AddActor(actor1);

    // 水平旋转
    renderer->GetActiveCamera()->Azimuth(90);
    renderer->GetActiveCamera()->SetRoll(-90);
    renderer->GetActiveCamera()->Azimuth(45);
    renderer->GetActiveCamera()->Elevation(15);
    renderer->GetActiveCamera()->SetPosition(3, 3, 1);

    vtkSmartPointer<vtkOrientationMarkerWidget> widget = vtkSmartPointer<vtkOrientationMarkerWidget>::New();
    ;
    this->borderWidget = widget;
    vtkSmartPointer<vtkAxesActor> widgetAxesActor = vtkSmartPointer<vtkAxesActor>::New();
    widgetAxesActor->SetPosition(0, 0, 0);
    widgetAxesActor->SetShaftType(0);
    widgetAxesActor->SetCylinderRadius(0.02);
    // 设置大小
    widgetAxesActor->SetTotalLength(2, 2, 2);
    widget->SetOrientationMarker(widgetAxesActor);
    widget->SetInteractor(this->interactor());
    widget->SetEnabled(1);
    widget->InteractiveOn();

    // 连接信号槽
    connect(this, &View3D::rotateBased, this, &View3D::rotateBaseSlot);
    connect(this, &View3D::rotateBigArmed, this, &View3D::rotateBigArmSlot);
    connect(this, &View3D::rotateMiddleArmed, this, &View3D::rotateMiddleArmSlot);
    connect(this, &View3D::rotateSmallArmed, this, &View3D::rotateSmallArmSlot);
}

void View3D::addAxis(const Axis& axis)
{
    vtkNew<vtkTransform> transform;
    transform->Translate(axis.xyz.x(), axis.xyz.y(), axis.xyz.z());

    vtkAxesActor* axes = vtkAxesActor::New();
    transform->RotateX(axis.xyzR.x());
    transform->RotateY(axis.xyzR.y());
    transform->RotateZ(axis.xyzR.z());
    axes->SetUserTransform(transform);
    // 设置大小
    axes->SetTotalLength(axis.xyzL.x(), axis.xyzL.y(), axis.xyzL.z());

    // 设置箭头大小
    axes->SetConeRadius(axis.xyzL[0] * 0.1);
    axes->SetCylinderRadius(axis.xyzL[0] * 0.1);
    axes->SetConeResolution(100);
    axes->SetCylinderResolution(100);

    axes->SetXAxisLabelText(axis.labels[0].toStdString().c_str());
    axes->SetYAxisLabelText(axis.labels[1].toStdString().c_str());
    axes->SetZAxisLabelText(axis.labels[2].toStdString().c_str());

    auto xLabelProperty = axes->GetXAxisCaptionActor2D();
    // 缩小
    xLabelProperty->SetWidth(axis.xyzL.x() * 0.1);

    auto yLabelProperty = axes->GetYAxisCaptionActor2D();
    yLabelProperty->SetWidth(axis.xyzL.y() * 0.1);

    auto zLabelProperty = axes->GetZAxisCaptionActor2D();
    zLabelProperty->SetWidth(axis.xyzL.z() * 0.1);

    // 添加到第一个render
    this->renderWindow()->GetRenderers()->GetFirstRenderer()->AddActor(axes);
    this->renderWindow()->Render();
}

void View3D::rotateBaseSlot(double angle)
{
    auto&& [a, b, c] = connectRods;
    // a世界坐标系旋转角归零
    a->SetOrientation(0, 0, 0);
    // a 绕世界坐标系旋转到angle
    a->RotateWXYZ(angle, 0, 0, 1);
    refresh();
}

void View3D::rotateBigArmSlot(double angle)
{
    auto&& [a, b, c] = connectRods;
    a->RotateY(angle - a->GetOrientation()[1]);
    refresh();
}

void View3D::rotateMiddleArmSlot(double angle)
{
    auto&& [a, b, c] = connectRods;
    b->RotateY(angle - b->GetOrientation()[1]);
    refresh();
}

void View3D::rotateSmallArmSlot(double angle)
{
    auto&& [a, b, c] = connectRods;
    c->RotateY(angle - c->GetOrientation()[1]);
    refresh();
}

void View3D::addGuideLine(float r, float space)
{
    // 创建网格线,间距space,范围-r~r
    vtkNew<vtkCellArray> lines;
    vtkNew<vtkPoints> points;
    for (size_t i = 0; i <= static_cast<unsigned long long>(r / space) * 2; i++) {
        points->InsertNextPoint(-r, r - space * i, 0);
        points->InsertNextPoint(r, r - space * i, 0);
        points->InsertNextPoint(-r + space * i, r, 0);
        points->InsertNextPoint(-r + space * i, -r, 0);
    }
    for (size_t i = 0; i <= static_cast<unsigned long long>(r / space) * 4 + 1; i++) {
        vtkNew<vtkLine> line;
        line->GetPointIds()->SetId(0, i * 2);
        line->GetPointIds()->SetId(1, i * 2 + 1);
        lines->InsertNextCell(line);
    }
    vtkNew<vtkPolyData> linesPolyData;
    linesPolyData->SetPoints(points);
    linesPolyData->SetLines(lines);
    vtkNew<vtkPolyDataMapper> mapper;
    mapper->SetInputData(linesPolyData);

    vtkNew<vtkActor> actor;
    actor->SetMapper(mapper);
    // 设置透明度
    actor->GetProperty()->SetOpacity(0.5);
    this->renderWindow()->GetRenderers()->GetFirstRenderer()->AddActor(actor);
    this->renderWindow()->Render();
}

vtkNew<vtkAxesActor> View3D::getBaseAxes()
{
    vtkNew<vtkAxesActor> axes;
    axes->SetTotalLength(1.0, 1.0, 1.0);
    axes->SetPosition(0, 0, 0);
    axes->SetShaftType(0);
    axes->SetConeResolution(100);
    axes->SetCylinderResolution(100);
    axes->SetConeRadius(0.1);
    axes->SetCylinderRadius(0.01);
    return axes;
}

void View3D::refresh()
{
    this->renderWindow()->Render();
}

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值