目录
1、修改代码
Viewer.h:
Viewer.cpp:
2、显示文本
OpenCasCade 你好啊
霜吹花落
1、修改代码
在文章《Open CASCADE学习|显示模型》基础上,增加部分代码,实现对文本显示的支持,具体如下:
Viewer.h:
//-----------------------------------------------------------------------------
// Created on: 24 August 2017
//-----------------------------------------------------------------------------
// Copyright (c) 2017, Sergey Slyadnev (sergey.slyadnev@gmail.com)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the copyright holder(s) nor the
// names of all contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------
#pragma once
#ifdef _WIN32
#include <Windows.h>
#endif
// Local includes
#include "ViewerInteractor.h"
// OpenCascade includes
#include <TopoDS_Shape.hxx>
#include <AIS_TextLabel.hxx>
#include <WNT_Window.hxx>
// Standard includes
#include <vector>
class V3d_Viewer;
class V3d_View;
class AIS_InteractiveContext;
class AIS_ViewController;
//-----------------------------------------------------------------------------
//! Simple 3D viewer.
class Viewer
{
public:
Viewer(const int left,
const int top,
const int width,
const int height);
public:
Viewer& operator<<(const TopoDS_Shape& shape)
{
this->AddShape(shape);
return *this;
}
Viewer& operator<<(const Handle(AIS_TextLabel)& label)
{
this->AddLabel(label);
return *this;
}
void AddShape(const TopoDS_Shape& shape);
void AddLabel(const Handle(AIS_TextLabel)& label);
void StartMessageLoop();
void StartMessageLoop2();
private:
static LRESULT WINAPI
wndProcProxy(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam);
LRESULT CALLBACK
wndProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam);
void init(const HANDLE& windowHandle);
/* API-related things */
private:
std::vector<TopoDS_Shape> m_shapes; //!< Shapes to visualize.
std::vector<Handle(AIS_TextLabel)> m_labels; //!< Shapes to visualize.
/* OpenCascade's things */
private:
Handle(V3d_Viewer) m_viewer;
Handle(V3d_View) m_view;
Handle(AIS_InteractiveContext) m_context;
Handle(WNT_Window) m_wntWindow;
Handle(ViewerInteractor) m_evtMgr;
/* Lower-level things */
private:
HINSTANCE m_hInstance; //!< Handle to the instance of the module.
HWND m_hWnd; //!< Handle to the instance of the window.
bool m_bQuit; //!< Indicates whether user want to quit from window.
};
Viewer.cpp:
//-----------------------------------------------------------------------------
// Created on: 24 August 2017
//-----------------------------------------------------------------------------
// Copyright (c) 2017, Sergey Slyadnev (sergey.slyadnev@gmail.com)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the copyright holder(s) nor the
// names of all contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------// Own include
#include "Viewer.h"// OpenCascade includes
#include <AIS_InteractiveContext.hxx>
#include <AIS_Shape.hxx>
#include <Aspect_DisplayConnection.hxx>
#include <Aspect_Handle.hxx>
#include <OpenGl_GraphicDriver.hxx>
#include <V3d_AmbientLight.hxx>
#include <V3d_DirectionalLight.hxx>
#include <V3d_View.hxx>
#include <V3d_Viewer.hxx>namespace {//! Adjust the style of local selection.//! \param[in] context the AIS context.void AdjustSelectionStyle(const Handle(AIS_InteractiveContext)& context){// Initialize style for sub-shape selection.Handle(Prs3d_Drawer) selDrawer = new Prs3d_Drawer;//selDrawer->SetLink(context->DefaultDrawer());selDrawer->SetFaceBoundaryDraw(true);selDrawer->SetDisplayMode(1); // ShadedselDrawer->SetTransparency(0.5f);selDrawer->SetZLayer(Graphic3d_ZLayerId_Topmost);selDrawer->SetColor(Quantity_NOC_GOLD);selDrawer->SetBasicFillAreaAspect(new Graphic3d_AspectFillArea3d());// Adjust fill area aspect.const Handle(Graphic3d_AspectFillArea3d)&fillArea = selDrawer->BasicFillAreaAspect();//fillArea->SetInteriorColor(Quantity_NOC_GOLD);fillArea->SetBackInteriorColor(Quantity_NOC_GOLD);//fillArea->ChangeFrontMaterial().SetMaterialName(Graphic3d_NOM_NEON_GNC);fillArea->ChangeFrontMaterial().SetTransparency(0.4f);fillArea->ChangeBackMaterial().SetMaterialName(Graphic3d_NOM_NEON_GNC);fillArea->ChangeBackMaterial().SetTransparency(0.4f);selDrawer->UnFreeBoundaryAspect()->SetWidth(1.0);// Update AIS context.context->SetHighlightStyle(Prs3d_TypeOfHighlight_LocalSelected, selDrawer);}
}//-----------------------------------------------------------------------------Viewer::Viewer(const int left,const int top,const int width,const int height): m_hWnd(NULL),m_bQuit(false)
{// Register the window class oncestatic HINSTANCE APP_INSTANCE = NULL;if (APP_INSTANCE == NULL){APP_INSTANCE = GetModuleHandleW(NULL);m_hInstance = APP_INSTANCE;WNDCLASSW WC;WC.cbClsExtra = 0;WC.cbWndExtra = 0;WC.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);WC.hCursor = LoadCursor(NULL, IDC_ARROW);WC.hIcon = LoadIcon(NULL, IDI_APPLICATION);WC.hInstance = APP_INSTANCE;WC.lpfnWndProc = (WNDPROC)wndProcProxy;WC.lpszClassName = L"OpenGLClass";WC.lpszMenuName = 0;WC.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;if (!RegisterClassW(&WC)){return;}}// Set coordinates for window's area rectangle.RECT Rect;SetRect(&Rect,left, top,left + width, top + height);// Adjust window rectangle.AdjustWindowRect(&Rect, WS_OVERLAPPEDWINDOW, false);// Create window.m_hWnd = CreateWindow(L"OpenGLClass",L"Quaoar >>> 3D",WS_OVERLAPPEDWINDOW,Rect.left, Rect.top, // Adjusted x, y positionsRect.right - Rect.left, Rect.bottom - Rect.top, // Adjusted width and heightNULL, NULL,m_hInstance,this);// Check if window has been created successfully.if (m_hWnd == NULL){return;}// Show window finally.ShowWindow(m_hWnd, TRUE);HANDLE windowHandle = (HANDLE)m_hWnd;this->init(windowHandle);
}//-----------------------------------------------------------------------------void Viewer::AddShape(const TopoDS_Shape& shape)
{m_shapes.push_back(shape);
}void Viewer::AddLabel(const Handle(AIS_TextLabel)& label)
{m_labels.push_back(label);
}
//-----------------------------------------------------------------------------//! Starts message loop.
void Viewer::StartMessageLoop()
{for (auto sh : m_shapes){Handle(AIS_Shape) shape = new AIS_Shape(sh);m_context->Display(shape, true);m_context->SetDisplayMode(shape, AIS_Shaded, true);// Adjust selection style.::AdjustSelectionStyle(m_context);// Activate selection modes.m_context->Activate(4, true); // facesm_context->Activate(2, true); // edges}MSG Msg;while (!m_bQuit){switch (::MsgWaitForMultipleObjectsEx(0, NULL, 12, QS_ALLINPUT, 0)){case WAIT_OBJECT_0:{while (::PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)){if (Msg.message == WM_QUIT)m_bQuit = true;// return;::TranslateMessage(&Msg);::DispatchMessage(&Msg);}}}}
}//! Starts message loop.
void Viewer::StartMessageLoop2()
{for (auto sh : m_labels){//Handle(AIS_Shape) shape = new AIS_Shape(sh);m_context->Display(sh,0);//m_context->SetDisplayMode(shape, AIS_Shaded, true);// Adjust selection style.::AdjustSelectionStyle(m_context);// Activate selection modes.m_context->Activate(4, true); // facesm_context->Activate(2, true); // edges}MSG Msg;while (!m_bQuit){switch (::MsgWaitForMultipleObjectsEx(0, NULL, 12, QS_ALLINPUT, 0)){case WAIT_OBJECT_0:{while (::PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)){if (Msg.message == WM_QUIT)m_bQuit = true;// return;::TranslateMessage(&Msg);::DispatchMessage(&Msg);}}}}
}//-----------------------------------------------------------------------------void Viewer::init(const HANDLE& windowHandle)
{static Handle(Aspect_DisplayConnection) displayConnection;//if (displayConnection.IsNull())displayConnection = new Aspect_DisplayConnection();HWND winHandle = (HWND)windowHandle;//if (winHandle == NULL)return;// Create OCCT viewer.Handle(OpenGl_GraphicDriver)graphicDriver = new OpenGl_GraphicDriver(displayConnection, false);m_viewer = new V3d_Viewer(graphicDriver);// Lightning.Handle(V3d_DirectionalLight) LightDir = new V3d_DirectionalLight(V3d_Zneg, Quantity_Color(Quantity_NOC_GRAY97), 1);Handle(V3d_AmbientLight) LightAmb = new V3d_AmbientLight();//LightDir->SetDirection(1.0, -2.0, -10.0);//m_viewer->AddLight(LightDir);m_viewer->AddLight(LightAmb);m_viewer->SetLightOn(LightDir);m_viewer->SetLightOn(LightAmb);// AIS context.m_context = new AIS_InteractiveContext(m_viewer);// Configure some global props.const Handle(Prs3d_Drawer)& contextDrawer = m_context->DefaultDrawer();//if (!contextDrawer.IsNull()){const Handle(Prs3d_ShadingAspect)& SA = contextDrawer->ShadingAspect();const Handle(Graphic3d_AspectFillArea3d)& FA = SA->Aspect();contextDrawer->SetFaceBoundaryDraw(true); // Draw edges.FA->SetEdgeOff();// Fix for inifinite lines has been reduced to 1000 from its default value 500000.contextDrawer->SetMaximalParameterValue(1000);}// Main view creation.m_view = m_viewer->CreateView();m_view->SetImmediateUpdate(false);// Event manager is constructed when both contex and view become available.m_evtMgr = new ViewerInteractor(m_view, m_context);// Aspect window creationm_wntWindow = new WNT_Window(winHandle);m_view->SetWindow(m_wntWindow, nullptr);//if (!m_wntWindow->IsMapped()){m_wntWindow->Map();}m_view->MustBeResized();// View settings.m_view->SetShadingModel(V3d_PHONG);// Configure rendering parametersGraphic3d_RenderingParams& RenderParams = m_view->ChangeRenderingParams();RenderParams.IsAntialiasingEnabled = true;RenderParams.NbMsaaSamples = 8; // Anti-aliasing by multi-samplingRenderParams.IsShadowEnabled = false;RenderParams.CollectedStats = Graphic3d_RenderingParams::PerfCounters_NONE;
}//-----------------------------------------------------------------------------LRESULT WINAPI Viewer::wndProcProxy(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
{if (message == WM_CREATE){// Save pointer to our class instance (sent on window create) to window storage.CREATESTRUCTW* pCreateStruct = (CREATESTRUCTW*)lparam;SetWindowLongPtr(hwnd, int(GWLP_USERDATA), (LONG_PTR)pCreateStruct->lpCreateParams);}// Get pointer to our class instance.Viewer* pThis = (Viewer*)GetWindowLongPtr(hwnd, int(GWLP_USERDATA));return (pThis != NULL) ? pThis->wndProc(hwnd, message, wparam, lparam): DefWindowProcW(hwnd, message, wparam, lparam);
}//-----------------------------------------------------------------------------//! Window procedure.
LRESULT Viewer::wndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
{if (m_view.IsNull())return DefWindowProc(hwnd, message, wparam, lparam);switch (message){case WM_PAINT:{PAINTSTRUCT aPaint;BeginPaint(m_hWnd, &aPaint);EndPaint(m_hWnd, &aPaint);m_evtMgr->ProcessExpose();break;}case WM_SIZE:{m_evtMgr->ProcessConfigure();break;}case WM_MOVE:case WM_MOVING:case WM_SIZING:{switch (m_view->RenderingParams().StereoMode){case Graphic3d_StereoMode_RowInterlaced:case Graphic3d_StereoMode_ColumnInterlaced:case Graphic3d_StereoMode_ChessBoard:{// track window moves to reverse stereo pairm_view->MustBeResized();m_view->Update();break;}default:break;}break;}case WM_KEYUP:case WM_KEYDOWN:{const Aspect_VKey vkey = WNT_Window::VirtualKeyFromNative((int)wparam);//if (vkey != Aspect_VKey_UNKNOWN){const double timeStamp = m_evtMgr->EventTime();if (message == WM_KEYDOWN){m_evtMgr->KeyDown(vkey, timeStamp);}else{m_evtMgr->KeyUp(vkey, timeStamp);}}break;}case WM_LBUTTONUP:case WM_MBUTTONUP:case WM_RBUTTONUP:case WM_LBUTTONDOWN:case WM_MBUTTONDOWN:case WM_RBUTTONDOWN:{const Graphic3d_Vec2i pos(LOWORD(lparam), HIWORD(lparam));const Aspect_VKeyFlags flags = WNT_Window::MouseKeyFlagsFromEvent(wparam);Aspect_VKeyMouse button = Aspect_VKeyMouse_NONE;//switch (message){case WM_LBUTTONUP:case WM_LBUTTONDOWN:button = Aspect_VKeyMouse_LeftButton;break;case WM_MBUTTONUP:case WM_MBUTTONDOWN:button = Aspect_VKeyMouse_MiddleButton;break;case WM_RBUTTONUP:case WM_RBUTTONDOWN:button = Aspect_VKeyMouse_RightButton;break;}if (message == WM_LBUTTONDOWN|| message == WM_MBUTTONDOWN|| message == WM_RBUTTONDOWN){SetFocus(hwnd);SetCapture(hwnd);if (!m_evtMgr.IsNull())m_evtMgr->PressMouseButton(pos, button, flags, false);}else{ReleaseCapture();if (!m_evtMgr.IsNull())m_evtMgr->ReleaseMouseButton(pos, button, flags, false);}m_evtMgr->FlushViewEvents(m_context, m_view, true);break;}case WM_MOUSEWHEEL:{const int delta = GET_WHEEL_DELTA_WPARAM(wparam);const double deltaF = double(delta) / double(WHEEL_DELTA);//const Aspect_VKeyFlags flags = WNT_Window::MouseKeyFlagsFromEvent(wparam);//Graphic3d_Vec2i pos(int(short(LOWORD(lparam))), int(short(HIWORD(lparam))));POINT cursorPnt = { pos.x(), pos.y() };if (ScreenToClient(hwnd, &cursorPnt)){pos.SetValues(cursorPnt.x, cursorPnt.y);}if (!m_evtMgr.IsNull()){m_evtMgr->UpdateMouseScroll(Aspect_ScrollDelta(pos, deltaF, flags));m_evtMgr->FlushViewEvents(m_context, m_view, true);}break;}case WM_MOUSEMOVE:{Graphic3d_Vec2i pos(LOWORD(lparam), HIWORD(lparam));Aspect_VKeyMouse buttons = WNT_Window::MouseButtonsFromEvent(wparam);Aspect_VKeyFlags flags = WNT_Window::MouseKeyFlagsFromEvent(wparam);// don't make a slide-show from input events - fetch the actual mouse cursor positionCURSORINFO cursor;cursor.cbSize = sizeof(cursor);if (::GetCursorInfo(&cursor) != FALSE){POINT cursorPnt = { cursor.ptScreenPos.x, cursor.ptScreenPos.y };if (ScreenToClient(hwnd, &cursorPnt)){// as we override mouse position, we need overriding also mouse statepos.SetValues(cursorPnt.x, cursorPnt.y);buttons = WNT_Window::MouseButtonsAsync();flags = WNT_Window::MouseKeyFlagsAsync();}}if (m_wntWindow.IsNull() || (HWND)m_wntWindow->HWindow() != hwnd){// mouse move events come also for inactive windowsbreak;}if (!m_evtMgr.IsNull()){m_evtMgr->UpdateMousePosition(pos, buttons, flags, false);m_evtMgr->FlushViewEvents(m_context, m_view, true);}break;}default:{break;}case WM_DESTROY:m_bQuit = true;}return DefWindowProc(hwnd, message, wparam, lparam);
}
2、显示文本
OpenCasCade 你好啊
#include "TCollection_ExtendedString.hxx"
#include "Resource_Unicode.hxx"
#include "AIS_TextLabel.hxx"
#include "AIS_InteractiveContext.hxx"
#include"Viewer.h"
int main() {
TCollection_ExtendedString tostr;
Standard_CString str = "OpenCasCade 你好啊";
Resource_Unicode::ConvertGBToUnicode(str, tostr);
Handle(AIS_TextLabel) aLabel = new AIS_TextLabel();
aLabel->SetText(tostr);
aLabel->SetColor(Quantity_NOC_RED);
aLabel->SetFont("SimHei");
Viewer vout(50, 50, 500, 500);
vout << aLabel;
vout.StartMessageLoop2();
return 0;
}
霜吹花落
#include "TCollection_ExtendedString.hxx"
#include "Resource_Unicode.hxx"
#include "AIS_TextLabel.hxx"
#include "AIS_InteractiveContext.hxx"
#include"Viewer.h"
int main() {
TCollection_ExtendedString tostr;
Standard_CString str = "霜吹花落";
Resource_Unicode::ConvertGBToUnicode(str, tostr);
Handle(AIS_TextLabel) aLabel = new AIS_TextLabel();
aLabel->SetPosition(gp_Pnt(0, 0, 0));
aLabel->SetText(tostr);
aLabel->SetHJustification(Graphic3d_HTA_CENTER);
aLabel->SetVJustification(Graphic3d_VTA_CENTER);
aLabel->SetHeight(50);
aLabel->SetZoomable(false);//如果允许缩放,你会发现放大后字太难看了
aLabel->SetAngle(0);
aLabel->SetColor(Quantity_NOC_YELLOW);
aLabel->SetFont("SimHei");//一定要设置合适的字体,不然不能实现功能
//如果有一天你需要鼠标选中文本时,下面代码有用,高亮文本
Handle(Prs3d_Drawer) aStyle = new Prs3d_Drawer(); // 获取高亮风格
aLabel->SetHilightAttributes(aStyle);
aStyle->SetMethod(Aspect_TOHM_COLOR);
aStyle->SetColor(Quantity_NOC_RED); // 设置高亮颜色
aStyle->SetDisplayMode(1); // 整体高亮
aLabel->SetDynamicHilightAttributes(aStyle);
Viewer vout(50, 50, 500, 500);
vout << aLabel;
vout.StartMessageLoop2();
return 0;
}