Open CASCADE学习|显示模型

发布时间:2024年01月17日

目录

1、编写代码

Viewer.h

Viewer.cpp

ViewerInteractor.h

ViewerInteractor.cpp

helloworld.cpp

2、配置

3、编译运行


1、编写代码

Viewer.h

#pragma once
?
#ifdef _WIN32
#include <Windows.h>
#endif
?
// Local includes
#include "ViewerInteractor.h"
?
// OpenCascade includes
#include <TopoDS_Shape.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;
    }
?
    void AddShape(const TopoDS_Shape& shape);
?
    void StartMessageLoop();
?
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.
?
    /* 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

// 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); // Shaded
        selDrawer->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 once
    static 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 positions
        Rect.right - Rect.left, Rect.bottom - Rect.top, // Adjusted width and height
        NULL, 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);
}
?
//-----------------------------------------------------------------------------
?
//! 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); // faces
        m_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 creation
    m_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 parameters
    Graphic3d_RenderingParams& RenderParams = m_view->ChangeRenderingParams();
    RenderParams.IsAntialiasingEnabled = true;
    RenderParams.NbMsaaSamples = 8; // Anti-aliasing by multi-sampling
    RenderParams.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 pair
            m_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 position
        CURSORINFO 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 state
                pos.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 windows
            break;
        }
?
        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);
}

ViewerInteractor.h

#pragma once
?
// OpenCascade includes
#include <AIS_ViewController.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TCollection_AsciiString.hxx>
?
class AIS_InteractiveContext;
class V3d_View;
?
//! Manages input events.
class ViewerInteractor : public Standard_Transient, public AIS_ViewController
{
public:
?
    // OCCT RTTI
    DEFINE_STANDARD_RTTI_INLINE(ViewerInteractor, Standard_Transient)
?
public:
?
    //! Ctor.
    //! \param[in] view the V3d view instance.
    //! \param[in] ctx  the interactive context.
    ViewerInteractor(const Handle(V3d_View)& view,
        const Handle(AIS_InteractiveContext)& ctx);
?
    //! Dtor.
    virtual ~ViewerInteractor();
?
public:
?
    //! Return interactive context.
    const Handle(AIS_InteractiveContext)&
        GetContext() const { return m_ctx; }
?
    //! Handle mouse button press/release event.
    virtual bool UpdateMouseButtons(const Graphic3d_Vec2i& thePoint,
        Aspect_VKeyMouse       theButtons,
        Aspect_VKeyFlags       theModifiers,
        bool                   theIsEmulated) Standard_OVERRIDE;
?
    //! Release key.
    virtual void KeyDown(Aspect_VKey theKey,
        double theTime,
        double thePressure = 1.0) Standard_OVERRIDE;
?
    //! Release key.
    virtual void KeyUp(Aspect_VKey theKey,
        double theTime) Standard_OVERRIDE;
?
    //! Redraw the View on an Expose Event
    virtual void ProcessExpose();
?
    //! Handle redraw.
    virtual void handleViewRedraw(const Handle(AIS_InteractiveContext)& theCtx,
        const Handle(V3d_View)& theView) Standard_OVERRIDE;
?
    //! Resize View.
    virtual void ProcessConfigure();
?
    //! Handle KeyPress event.
    void ProcessKeyPress(Aspect_VKey theKey);
?
private:
?
    Handle(V3d_View)               m_view; //!< 3D view.
    Handle(AIS_InteractiveContext) m_ctx;  //!< Interactive context.
?
};

ViewerInteractor.cpp

// Own include
#include "ViewerInteractor.h"
?
// OpenCascade includes
#include <Aspect_Grid.hxx>
#include <AIS_AnimationCamera.hxx>
#include <AIS_InteractiveContext.hxx>
#include <AIS_Shape.hxx>
#include <V3d_View.hxx>
?
//-----------------------------------------------------------------------------
?
ViewerInteractor::ViewerInteractor(const Handle(V3d_View)& view,
    const Handle(AIS_InteractiveContext)& ctx)
    : m_view(view),
    m_ctx(ctx)
{}
?
//-----------------------------------------------------------------------------
?
ViewerInteractor::~ViewerInteractor()
{}
?
//-----------------------------------------------------------------------------
?
bool ViewerInteractor::UpdateMouseButtons(const Graphic3d_Vec2i& point,
    Aspect_VKeyMouse       buttons,
    Aspect_VKeyFlags       modifiers,
    bool                   isEmulated)
{
    return AIS_ViewController::UpdateMouseButtons(point, buttons, modifiers, isEmulated);
}
?
//-----------------------------------------------------------------------------
?
void ViewerInteractor::ProcessExpose()
{
    if (!m_view.IsNull())
    {
        m_view->Invalidate();
        FlushViewEvents(m_ctx, m_view, true);
    }
}
?
//-----------------------------------------------------------------------------
?
void ViewerInteractor::handleViewRedraw(const Handle(AIS_InteractiveContext)& ctx,
    const Handle(V3d_View)& view)
{
    AIS_ViewController::handleViewRedraw(ctx, view);
}
?
//-----------------------------------------------------------------------------
?
void ViewerInteractor::ProcessConfigure()
{
    if (!m_view.IsNull())
    {
        m_view->MustBeResized();
        FlushViewEvents(m_ctx, m_view, true);
    }
}
?
//-----------------------------------------------------------------------------
?
void ViewerInteractor::KeyDown(Aspect_VKey key,
    double      time,
    double      pressure)
{
    AIS_ViewController::KeyDown(key, time, pressure);
}
?
//-----------------------------------------------------------------------------
?
void ViewerInteractor::KeyUp(Aspect_VKey key,
    double      time)
{
    const unsigned int modifOld = myKeys.Modifiers();
    //
    AIS_ViewController::KeyUp(key, time);
    //
    const unsigned int modifNew = myKeys.Modifiers();
?
    ProcessKeyPress(key | modifNew);
}
?
//-----------------------------------------------------------------------------
?
void ViewerInteractor::ProcessKeyPress(Aspect_VKey key)
{
    if (m_ctx.IsNull() || m_view.IsNull())
    {
        return;
    }
?
    switch (key)
    {
    case Aspect_VKey_F:
    {
        if (m_ctx->NbSelected() > 0)
        {
            m_ctx->FitSelected(m_view);
        }
        else
        {
            m_view->FitAll();
        }
        break;
    }
    case Aspect_VKey_S:
    case Aspect_VKey_W:
    {
        const int dm = (key == Aspect_VKey_S) ? AIS_Shaded : AIS_WireFrame;
?
        if (m_ctx->NbSelected() == 0)
        {
            m_ctx->SetDisplayMode(dm, false);
            m_ctx->UpdateCurrentViewer();
        }
        else
        {
            for (m_ctx->InitSelected(); m_ctx->MoreSelected(); m_ctx->NextSelected())
            {
                m_ctx->SetDisplayMode(m_ctx->SelectedInteractive(), dm, false);
            }
            m_ctx->UpdateCurrentViewer();
        }
        break;
    }
    case Aspect_VKey_Backspace: // Axonometry.
    {
        m_view->SetProj(V3d_XposYnegZpos);
        m_view->Redraw();
        break;
    }
    case Aspect_VKey_T:
    {
        m_view->SetProj(V3d_TypeOfOrientation_Zup_Top);
        m_view->Redraw();
        break;
    }
    case Aspect_VKey_B:
    {
        m_view->SetProj(V3d_TypeOfOrientation_Zup_Bottom);
        m_view->Redraw();
        break;
    }
    case Aspect_VKey_L:
    {
        m_view->SetProj(V3d_TypeOfOrientation_Zup_Left);
        m_view->Redraw();
        break;
    }
    case Aspect_VKey_R:
    {
        m_view->SetProj(V3d_TypeOfOrientation_Zup_Right);
        m_view->Redraw();
        break;
    }
    default: break;
    }
}
?

helloworld.cpp

#include "Viewer.h"
?
#include <BRepTools.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
?
int main(int argc, char** argv)
{
    Viewer vout(50, 50, 500, 500);
?
    vout << BRepPrimAPI_MakeBox(10, 10, 20)
        << BRepPrimAPI_MakeBox(20, 30, 10);
?
    if (argc > 1)
    {
        BRep_Builder bb;
        TopoDS_Shape fromFile;
        //
        if (!BRepTools::Read(fromFile, argv[1], bb))
        {
            std::cout << "Failed to read BREP shape from file " << argv[1] << std::endl;
            return 1;
        }
?
        vout << fromFile;
    }
?
    vout.StartMessageLoop();
?
    return 0;
}
?

2、配置

库文件和头文件同以前

附加依赖项添加以下:

TKernel.lib

TKMath.lib

TKTopAlgo.lib

TKBRep.lib

TKPrim.lib

TKOpenGl.lib

TKService.lib

TKV3d.lib

kernel32.lib

user32.lib

gdi32.lib

winspool.lib

把freetype.lib和freetype.dll拷贝到源码编译后的库文件目录

D:\vs pj\opencascade\3rdparty\freetype-2.5.5-vc14-64

D:\vs pj\opencascade\install\win64\vc14

3、编译运行

文章来源:https://blog.csdn.net/T20151470/article/details/135638451
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。