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;
}
}
uStart
和uEnd
是样条曲线的参数范围。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;
}