当前位置: 首页 > news >正文

Open CASCADE学习|小球沿样条曲线运动

1. 样条曲线的创建

在OpenCASCADE中,样条曲线(B样条曲线)是通过控制点来定义的。我们使用GeomAPI_PointsToBSpline类来根据给定的控制点生成B样条曲线。

TColgp_Array1OfPnt points(1, 4);
points.SetValue(1, gp_Pnt(-20, -20, 0));
points.SetValue(2, gp_Pnt(0, 30, 20));
points.SetValue(3, gp_Pnt(40, -20, 0));
points.SetValue(4, gp_Pnt(60, 30, 20));
GeomAPI_PointsToBSpline bsplineBuilder(points);
Handle(Geom_BSplineCurve) curve = bsplineBuilder.Curve();
  • TColgp_Array1OfPnt用于存储控制点。
  • GeomAPI_PointsToBSpline根据控制点生成B样条曲线。
  • curve是生成的B样条曲线对象。

2. 球体的创建

使用BRepPrimAPI_MakeSphere类创建一个球体。

BRepPrimAPI_MakeSphere makeSphere(3.0); // 半径为3
TopoDS_Shape sphere = makeSphere.Shape();
Handle(AIS_Shape) aisSphere = new AIS_Shape(sphere);
  • BRepPrimAPI_MakeSphere用于创建球体。
  • sphere是球体的形状对象。
  • aisSphere是用于显示球体的AIS_Shape对象。

3. 显示样条曲线和球体

将样条曲线和球体添加到视图中进行显示。

TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(curve);
Handle(AIS_Shape) aisCurve = new AIS_Shape(edge);
context->Display(aisCurve, Standard_True);

context->Display(aisSphere, Standard_True);
  • BRepBuilderAPI_MakeEdge将曲线转换为边。
  • aisCurve是用于显示曲线的AIS_Shape对象。
  • context->Display将对象添加到视图中显示。

4. 动画的实现

动画的核心是通过不断更新球体的位置来实现的。我们通过一个循环逐步改变球体在样条曲线上的位置。

void StartAnimation() {
    double uStart = curve->FirstParameter();
    double uEnd = curve->LastParameter();
    double t = 0.0;
    const double delta = 0.01;
    const int delayMs = 30;

    while (t <= 1.0) {
        MSG msg;
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_QUIT) {
                return;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        double u = uStart + t * (uEnd - uStart);
        gp_Pnt point;
        curve->D0(u, point);

        gp_Trsf trsf;
        trsf.SetTranslation(gp_Vec(point.X(), point.Y(), point.Z()));
        aisSphere->SetLocalTransformation(trsf);

        context->UpdateCurrentViewer();
        view->Redraw();

        std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
        t += delta;
    }
}
  • uStartuEnd是样条曲线的参数范围。
  • t是动画的参数,从0到1逐步增加。
  • u是当前的曲线参数,根据t计算得到。
  • curve->D0(u, point)计算曲线在参数u处的点point
  • gp_Trsf用于创建平移变换,将球体移动到point位置。
  • aisSphere->SetLocalTransformation(trsf)更新球体的位置。
  • context->UpdateCurrentViewer()view->Redraw()更新视图并重绘。
  • std::this_thread::sleep_for用于控制动画的速度。

5. 按钮点击事件

按钮点击事件触发动画函数StartAnimation

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_COMMAND:
        if (LOWORD(wParam) == 1) { // 按钮点击事件
            StartAnimation();
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProcW(hwnd, msg, wParam, lParam);
    }
    return 0;
}
  • WM_COMMAND消息处理按钮点击事件。
  • LOWORD(wParam) == 1判断点击的是哪个按钮。
  • 调用StartAnimation函数开始动画。

6. 完整代码

#include <Windows.h>
#include <AIS_Shape.hxx>
#include <AIS_InteractiveContext.hxx>
#include <V3d_Viewer.hxx>
#include <V3d_View.hxx>
#include <OpenGl_GraphicDriver.hxx>
#include <WNT_Window.hxx>
#include <GeomAPI_PointsToBSpline.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <gp_Pnt.hxx>
#include <gp_Trsf.hxx>
#include <TopoDS_Edge.hxx>
#include <Geom_BSplineCurve.hxx>
#include <chrono>
#include <thread>

// 全局变量,用于存储OpenCASCADE对象
Handle(AIS_Shape) aisSphere;
Handle(Geom_BSplineCurve) curve;
Handle(V3d_View) view;
Handle(AIS_InteractiveContext) context;

// 创建OpenCASCADE窗口
HWND CreateOCCWindow() {
    HINSTANCE hInstance = GetModuleHandle(NULL);
    WNDCLASSW wc = { 0 };
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = DefWindowProcW;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = L"OCCWindowClass";
    RegisterClassW(&wc);
    HWND hwnd = CreateWindowW(
        L"OCCWindowClass",
        L"OpenCASCADE Animation",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 1024, 768,
        NULL, NULL, hInstance, NULL
    );
    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);
    return hwnd;
}

// 动画函数
void StartAnimation() {
    double uStart = curve->FirstParameter();
    double uEnd = curve->LastParameter();
    double t = 0.0;
    const double delta = 0.01;
    const int delayMs = 30;

    while (t <= 1.0) {
        MSG msg;
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_QUIT) {
                return;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        double u = uStart + t * (uEnd - uStart);
        gp_Pnt point;
        curve->D0(u, point);

        gp_Trsf trsf;
        trsf.SetTranslation(gp_Vec(point.X(), point.Y(), point.Z()));
        aisSphere->SetLocalTransformation(trsf);

        context->UpdateCurrentViewer();
        view->Redraw();

        std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
        t += delta;
    }
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_COMMAND:
        if (LOWORD(wParam) == 1) { // 按钮点击事件
            // 调用动画函数
            StartAnimation();
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProcW(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int main() {
    // 创建窗口
    HWND hwnd = CreateOCCWindow();

    // 创建按钮
    CreateWindowW(
        L"BUTTON",
        L"Start Animation",
        WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
        10, 10, 100, 30,
        hwnd,
        (HMENU)1,
        NULL,
        NULL
    );

    // 设置窗口过程
    SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)WndProc);

    Handle(WNT_Window) window = new WNT_Window(hwnd);

    // 初始化图形驱动
    Handle(OpenGl_GraphicDriver) graphicDriver = new OpenGl_GraphicDriver(new Aspect_DisplayConnection());

    // 创建Viewer
    Handle(V3d_Viewer) viewer = new V3d_Viewer(graphicDriver);
    viewer->SetDefaultLights();
    viewer->SetLightOn();

    // 创建View
    Handle(V3d_View) view_temp = viewer->CreateView();
    view_temp->SetWindow(window);
    view_temp->TriedronDisplay(Aspect_TOTP_LEFT_LOWER, Quantity_NOC_GOLD, 0.08, V3d_WIREFRAME);
    view_temp->SetBackgroundColor(Quantity_NOC_BLACK);
    view_temp->MustBeResized();
    view_temp->Redraw();

    // 创建InteractiveContext
    Handle(AIS_InteractiveContext) context_temp = new AIS_InteractiveContext(viewer);
    context_temp->SetDisplayMode(AIS_Shaded, Standard_True);

    // 创建样条曲线
    TColgp_Array1OfPnt points(1, 4);
    points.SetValue(1, gp_Pnt(-20, -20, 0));
    points.SetValue(2, gp_Pnt(0, 30, 20));
    points.SetValue(3, gp_Pnt(40, -20, 0));
    points.SetValue(4, gp_Pnt(60, 30, 20));
    GeomAPI_PointsToBSpline bsplineBuilder(points);
    Handle(Geom_BSplineCurve) curve_temp = bsplineBuilder.Curve();

    // 创建曲线Edge并显示
    TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(curve_temp);
    Handle(AIS_Shape) aisCurve = new AIS_Shape(edge);
    context_temp->Display(aisCurve, Standard_True);

    // 创建球体
    BRepPrimAPI_MakeSphere makeSphere(3.0);
    TopoDS_Shape sphere = makeSphere.Shape();
    Handle(AIS_Shape) aisSphere_temp = new AIS_Shape(sphere);
    context_temp->Display(aisSphere_temp, Standard_True);

    // 调整视图以适应内容
    view_temp->FitAll();

    // 将全局变量赋值
    aisSphere = aisSphere_temp;
    curve = curve_temp;
    view = view_temp;
    context = context_temp;

    // 保持窗口打开,直到用户关闭
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

相关文章:

  • MP4音视频格式
  • 中间件漏洞-Tomcat篇
  • 架构思维:如何设计一个支持海量数据存储的高扩展性架构_数据分片、存储、复制与一致性的原理性问题
  • 数据库第二周作业
  • (UI自动化测试web端)第三篇:元素的常用操作方法_元素操作
  • JavaScript 对事件的反应机制
  • js实现判断图片宽度高度不超过容器宽高度,刚好在容器中显示完
  • FreeRTOS学习(十):任务调度器挂起与恢复机制详解
  • mysql中的聚簇索引,什么是聚簇索引和非聚簇索引
  • Android14 Settings应用添加有线网开关条目实现
  • Android设计模式之Builder模式
  • uniapp用户登录及获取用户信息(头像昵称)
  • 阿里云国际站代理商:如何通过Serverless调用GPU资源?
  • Python基础语法元素(学习笔记)
  • 李泽湘和中国硬科技创新十年 | 媒体报道
  • 高并发电商商详网关系统设计:架构、优化与实战
  • SQL Server 锁类型介绍
  • c++ primer 阅读手记 第五章
  • C++中使用CopyFromRecordset将记录集拷贝到excel中时,如果记录集为0个,函数崩溃,是什么原因
  • 基于ngnix配置本地代理到对应服务器
  • 网警侦破特大“刷量引流”网络水军案:涉案金额达2亿余元
  • 第二艘国产大型邮轮爱达·花城号完成坞内起浮
  • 央行副行长:我们在研究丰富政策工具箱,将适时推出增量政策
  • 一季度全国城镇新增就业308万人
  • 国家发展改革委:我们对实现今年经济社会发展目标任务充满信心
  • 伊朗爆炸港口已恢复货物进出口工作