├── .gitattributes ├── .github └── workflows │ └── build_ubuntu_24.04.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── ReadMe.md ├── adm └── cmake │ └── FindOpenCASCADE.cmake ├── images ├── occt-ais-hello.png ├── occt-ais-object.gif ├── occt-ais-offscreen.png └── occt-xcaf-shape.png ├── models └── as1-oc-214.stp ├── occt-ais-hello ├── CMakeLists.txt ├── OcctAisHello.cpp ├── OcctAisHello.objc.mm ├── OcctAisHello.sln ├── OcctAisHello.vcxproj ├── OcctAisHello.vcxproj.filters └── ReadMe.md ├── occt-ais-object ├── CMakeLists.txt ├── OcctAisObject.cpp └── ReadMe.md ├── occt-ais-offscreen ├── CMakeLists.txt ├── OcctAisOffscreen.cpp ├── OcctAisOffscreen.objc.mm └── ReadMe.md ├── occt-draw-plugin ├── CMakeLists.txt ├── MYDrawTest ├── OcctDrawPlugin.cpp ├── ReadMe.md ├── cmake │ ├── occt-draw-debug.bat.in │ ├── occt-draw-release.bat.in │ └── occt-draw.sh.in └── tests │ ├── grid1 │ ├── begin │ ├── end │ ├── grids.list │ ├── parse.rules │ ├── subgrid1 │ │ ├── begin │ │ └── hello │ └── subgrid2 │ │ └── nodata │ └── parse.rules └── occt-xcaf-shape ├── CMakeLists.txt ├── OcctXCafShape.cpp └── ReadMe.md /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h text 2 | *.cpp text 3 | *.sh eol=lf 4 | *.workspace eol=lf 5 | *.cbp eol=lf 6 | *.vcxproj* eol=crlf 7 | *.filters eol=crlf 8 | *.sln eol=crlf 9 | *.bat eol=crlf 10 | *.rc eol=crlf 11 | *.def eol=crlf 12 | *.txt eol=crlf 13 | *.ico binary 14 | .gitignore eol=lf 15 | .gitattributes eol=lf 16 | -------------------------------------------------------------------------------- /.github/workflows/build_ubuntu_24.04.yml: -------------------------------------------------------------------------------- 1 | name: Build (Ubuntu 24.04) 2 | on: 3 | push: 4 | branches: [ master ] 5 | pull_request: 6 | branches: [ master ] 7 | workflow_dispatch: 8 | 9 | jobs: 10 | Ubuntu: 11 | runs-on: ubuntu-24.04 12 | steps: 13 | - name: Clone Tree 14 | uses: actions/checkout@v1 15 | with: 16 | fetch-depth: 1 17 | - name: Install Dependencies 18 | run: | 19 | sudo apt-get update 20 | sudo apt-get install -y \ 21 | g++ cmake ninja-build \ 22 | libocct-draw-dev libocct-visualization-dev libocct-ocaf-dev libocct-modeling-data-dev \ 23 | libocct-modeling-algorithms-dev libocct-foundation-dev libocct-data-exchange-dev \ 24 | libgl-dev libegl-dev \ 25 | tcllib tklib tcl-dev tk-dev \ 26 | libtbb-dev \ 27 | xvfb 28 | - name: Configure project 29 | run: | 30 | mkdir "build" 31 | cmake -G Ninja -S . -B "./build" 32 | - name: Build project 33 | run: | 34 | cmake --build "./build" --config Release 35 | - name: Run tests 36 | run: | 37 | pushd ./build 38 | xvfb-run ./occt-ais-offscreen/occt-ais-offscreen -noopen 39 | popd 40 | - name: Upload artifacts 41 | uses: actions/upload-artifact@v4 42 | with: 43 | name: occt-hello-ubuntu 44 | path: ./build/image.png 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.obj 3 | *.a 4 | *.vcxproj.user 5 | *.pdb 6 | *.suo 7 | *.sdf 8 | *.opensdf 9 | *.VC.db 10 | *.VC.opendb 11 | *.ipch 12 | *.depend 13 | *.layout 14 | *.bak 15 | *.backup 16 | *.cbTemp 17 | *.log 18 | *.bmarks 19 | *_build_log.html 20 | *.exe 21 | *.dll 22 | bin/ 23 | work/ 24 | x64-Release 25 | Win32-Release 26 | x64-Debug 27 | Win32-Debug 28 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.13) 2 | 3 | # common solution for multiple independent projects 4 | project (occt-hello) 5 | 6 | add_subdirectory (occt-ais-hello) 7 | add_subdirectory (occt-ais-object) 8 | add_subdirectory (occt-ais-offscreen) 9 | add_subdirectory (occt-draw-plugin) 10 | add_subdirectory (occt-xcaf-shape) 11 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Kirill Gavrilov 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | Hello OpenCASCADE Technology! 2 | ============================= 3 | 4 | [![Status](https://github.com/gkv311/occt-hello/actions/workflows/build_ubuntu_24.04.yml/badge.svg?branch=master)](https://github.com/gkv311/occt-hello/actions?query=branch%3Amaster) 5 | 6 | This repository contains Hello-World samples accompanying articles devoted to learning [Open CASCADE Technology](https://dev.opencascade.org) (also abbreviated as OCCT) 3D Viewer API. 7 | Samples require OCCT 7.6 or later for building. 8 | 9 | ## AIS Hello 10 | 11 | Project within [`occt-ais-hello`](occt-ais-hello/) subfolder shows basic steps of OCCT 3D viewer on Windows, Linux and macOS platforms 12 | based on [Tutorial](https://unlimited3d.wordpress.com/2021/03/27/occt-minimal-viewer-setup/). 13 | 14 | ![Hello World screenshot](/images/occt-ais-hello.png) 15 | 16 | ## AIS Object 17 | 18 | Project within [`occt-ais-object`](occt-ais-object/) subfolder demonstrates definition of `AIS_InteractiveObject` subclass 19 | based on [Tutorial](https://unlimited3d.wordpress.com/2021/11/16/ais-object-computing-presentation/). 20 | 21 | ![AIS Object screenshot](/images/occt-ais-object.gif) 22 | 23 | ## AIS Offscreen Dump 24 | 25 | Project within [`occt-ais-offscreen`](occt-ais-offscreen/) subfolder demonstrates OCCT 3D viewer setup for offscreen image dump 26 | based on [Tutorial](https://unlimited3d.wordpress.com/2022/01/30/offscreen-occt-viewer/). 27 | 28 | ![Offscreen screenshot](/images/occt-ais-offscreen.png) 29 | 30 | ## Draw Plugin 31 | 32 | Project within [`occt-draw-plugin`](occt-draw-plugin/) subfolder demonstrates Draw Harness plugin sample. 33 | 34 | ## XCAF Shape 35 | 36 | Project within [`occt-xcaf-shape`](occt-xcaf-shape/) subfolder demonstrates reading of STEP file into XCAF document and displaying it via `XCAFPrs_AISObject` in 3D Viewer. 37 | 38 | ![AIS Object screenshot](/images/occt-xcaf-shape.png) 39 | -------------------------------------------------------------------------------- /adm/cmake/FindOpenCASCADE.cmake: -------------------------------------------------------------------------------- 1 | # This script finds OpenCASCADE Technology libraries (OCCT). 2 | # https://dev.opencascade.org/ 3 | # 4 | # The script requires: 5 | # OpenCASCADE_DIR - root OCCT folder or folder with CMake configuration files 6 | # 7 | # Script will define the following variables on success: 8 | # OpenCASCADE_FOUND - package is successfully found 9 | # OpenCASCADE_INCLUDE_DIR - directory with headers 10 | # OpenCASCADE_LIBRARY_DIR - directory with libraries for linker 11 | # OpenCASCADE_BINARY_DIR - directory with DLLs 12 | # OpenCASCADE_RESOURCE_DIR - directory with resource files 13 | include(FindPackageHandleStandardArgs) 14 | 15 | # MY_PLATFORM variable 16 | math (EXPR MY_BITNESS "32 + 32*(${CMAKE_SIZEOF_VOID_P}/8)") 17 | if (WIN32) 18 | set (MY_PLATFORM "win${MY_BITNESS}") 19 | elseif(APPLE) 20 | set (MY_PLATFORM "mac") 21 | else() 22 | set (MY_PLATFORM "lin") 23 | endif() 24 | 25 | # MY_PLATFORM_AND_COMPILER variable 26 | if (MSVC) 27 | if (MSVC90) 28 | set (MY_COMPILER vc9) 29 | elseif (MSVC10) 30 | set (MY_COMPILER vc10) 31 | elseif (MSVC11) 32 | set (MY_COMPILER vc11) 33 | elseif (MSVC12) 34 | set (MY_COMPILER vc12) 35 | elseif (MSVC14) 36 | set (MY_COMPILER vc14) 37 | else() 38 | set (MY_COMPILER vc15) 39 | message (WARNING "Unknown msvc version. $$MY_COMPILER is used") 40 | endif() 41 | elseif (DEFINED CMAKE_COMPILER_IS_GNUCC) 42 | set (MY_COMPILER gcc) 43 | elseif (DEFINED CMAKE_COMPILER_IS_GNUCXX) 44 | set (MY_COMPILER gcc) 45 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 46 | set (MY_COMPILER clang) 47 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") 48 | set (MY_COMPILER icc) 49 | else() 50 | set (MY_COMPILER ${CMAKE_GENERATOR}) 51 | string (REGEX REPLACE " " "" COMPILER ${MY_COMPILER}) 52 | endif() 53 | set (MY_PLATFORM_AND_COMPILER "${MY_PLATFORM}/${MY_COMPILER}") 54 | 55 | set (OpenCASCADE_DIR "" CACHE PATH "Path to Open CASCADE libraries.") 56 | 57 | # default paths 58 | set (OpenCASCADE_INCLUDE_DIR "${OpenCASCADE_DIR}/inc") 59 | set (OpenCASCADE_LIBRARY_DIR "${OpenCASCADE_DIR}/${MY_PLATFORM_AND_COMPILER}/lib") 60 | set (OpenCASCADE_BINARY_DIR "${OpenCASCADE_DIR}/${MY_PLATFORM_AND_COMPILER}/bin") 61 | set (OpenCASCADE_RESOURCE_DIR "${OpenCASCADE_DIR}/src") 62 | 63 | # complete list of OCCT Toolkits (copy-paste from adm/UDLIST, since installed OCCT does not include UDLIST) 64 | set (OpenCASCADE_TKLIST "") 65 | set (OpenCASCADE_TKLIST ${OpenCASCADE_TKLIST} TKernel TKMath) # FoundationClasses 66 | set (OpenCASCADE_TKLIST ${OpenCASCADE_TKLIST} TKG2d TKG3d TKGeomBase TKBRep) # ModelingData 67 | set (OpenCASCADE_TKLIST ${OpenCASCADE_TKLIST} TKGeomAlgo TKTopAlgo TKPrim TKBO TKBool TKHLR TKFillet TKOffset TKFeat TKMesh TKXMesh TKShHealing) # ModelingAlgorithms 68 | set (OpenCASCADE_TKLIST ${OpenCASCADE_TKLIST} TKService TKV3d TKOpenGl TKMeshVS TKIVtk TKD3DHost) # Visualization 69 | set (OpenCASCADE_TKLIST ${OpenCASCADE_TKLIST} TKCDF TKLCAF TKCAF TKBinL TKXmlL TKBin TKXml TKStdL TKStd TKTObj TKBinTObj TKXmlTObj TKVCAF) # ApplicationFramework 70 | set (OpenCASCADE_TKLIST ${OpenCASCADE_TKLIST} TKXSBase TKSTEPBase TKSTEPAttr TKSTEP209 TKSTEP TKIGES TKXCAF TKXDEIGES TKXDESTEP TKSTL TKVRML TKXmlXCAF TKBinXCAF TKRWMesh) # DataExchange 71 | set (OpenCASCADE_TKLIST ${OpenCASCADE_TKLIST} TKDraw TKViewerTest) # Draw 72 | 73 | # validate location of OCCT libraries and headers 74 | set (OpenCASCADE_INCLUDE_DIR_FOUND) 75 | set (OpenCASCADE_LIBRARY_DIR_FOUND) 76 | set (OpenCASCADE_LIBRARY_DEBUG_DIR_FOUND) 77 | set (OpenCASCADE_IMPLIB_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX}) 78 | set (OpenCASCADE_SHAREDLIB_RELEASE_FOUND) 79 | set (OpenCASCADE_SHAREDLIB_DEBUG_FOUND) 80 | if (EXISTS "${OpenCASCADE_INCLUDE_DIR}/Standard.hxx") 81 | set (OpenCASCADE_INCLUDE_DIR_FOUND ON) 82 | endif() 83 | 84 | if (EXISTS "${OpenCASCADE_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}TKernel${CMAKE_STATIC_LIBRARY_SUFFIX}") 85 | set (OpenCASCADE_LIBRARY_DIR_FOUND ON) 86 | elseif (NOT WIN32 AND EXISTS "${OpenCASCADE_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}TKernel${CMAKE_SHARED_LIBRARY_SUFFIX}") 87 | set (OpenCASCADE_LIBRARY_DIR_FOUND ON) 88 | set (OpenCASCADE_IMPLIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) 89 | endif() 90 | 91 | if (EXISTS "${OpenCASCADE_LIBRARY_DIR}d/${CMAKE_SHARED_LIBRARY_PREFIX}TKernel${CMAKE_STATIC_LIBRARY_SUFFIX}") 92 | set (OpenCASCADE_LIBRARY_DEBUG_DIR_FOUND ON) 93 | elseif (NOT WIN32 AND EXISTS "${OpenCASCADE_LIBRARY_DIR}d/${CMAKE_SHARED_LIBRARY_PREFIX}TKernel${CMAKE_SHARED_LIBRARY_SUFFIX}") 94 | set (OpenCASCADE_LIBRARY_DEBUG_DIR_FOUND ON) 95 | set (OpenCASCADE_IMPLIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) 96 | elseif (OpenCASCADE_LIBRARY_DIR_FOUND) 97 | message (STATUS "Only release OpenCASCADE libraries have been found") 98 | endif() 99 | 100 | if (NOT OpenCASCADE_LIBRARY_DIR_FOUND AND OpenCASCADE_LIBRARY_DEBUG_DIR_FOUND) 101 | set (OpenCASCADE_LIBRARY_DIR_FOUND ON) 102 | message (WARNING "Only debug OpenCASCADE libraries have been found") 103 | endif() 104 | 105 | if (WIN32) 106 | if (EXISTS "${OpenCASCADE_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}TKernel${CMAKE_SHARED_LIBRARY_SUFFIX}") 107 | set (OpenCASCADE_SHAREDLIB_RELEASE_FOUND ON) 108 | endif() 109 | if (EXISTS "${OpenCASCADE_BINARY_DIR}d/${CMAKE_SHARED_LIBRARY_PREFIX}TKernel${CMAKE_SHARED_LIBRARY_SUFFIX}") 110 | set (OpenCASCADE_SHAREDLIB_DEBUG_FOUND ON) 111 | endif() 112 | else() 113 | if (EXISTS "${OpenCASCADE_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}TKernel${CMAKE_SHARED_LIBRARY_SUFFIX}") 114 | set (OpenCASCADE_SHAREDLIB_RELEASE_FOUND ON) 115 | endif() 116 | if (EXISTS "${OpenCASCADE_LIBRARY_DIR}d/${CMAKE_SHARED_LIBRARY_PREFIX}TKernel${CMAKE_SHARED_LIBRARY_SUFFIX}") 117 | set (OpenCASCADE_SHAREDLIB_DEBUG_FOUND ON) 118 | endif() 119 | endif() 120 | 121 | if (OpenCASCADE_INCLUDE_DIR_FOUND AND OpenCASCADE_LIBRARY_DIR_FOUND) 122 | set (OpenCASCADE_FOUND ON) 123 | set (OpenCASCADE_INSTALL_PREFIX ${OpenCASCADE_DIR}) 124 | 125 | # Define OCCT toolkits so that CMake can put absolute paths to linker; 126 | # the library existence is not checked here, since modules can be disabled. 127 | foreach (aLibIter ${OpenCASCADE_TKLIST}) 128 | add_library (${aLibIter} SHARED IMPORTED) 129 | 130 | set_property (TARGET ${aLibIter} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) 131 | set_target_properties (${aLibIter} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${OpenCASCADE_INCLUDE_DIR}) 132 | set_target_properties (${aLibIter} PROPERTIES IMPORTED_IMPLIB_RELEASE "${OpenCASCADE_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${OpenCASCADE_IMPLIB_SUFFIX}") 133 | if (OpenCASCADE_SHAREDLIB_RELEASE_FOUND) 134 | if (WIN32) 135 | set_target_properties (${aLibIter} PROPERTIES IMPORTED_LOCATION_RELEASE "${OpenCASCADE_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${CMAKE_SHARED_LIBRARY_SUFFIX}") 136 | else() 137 | set_target_properties (${aLibIter} PROPERTIES IMPORTED_LOCATION_RELEASE "${OpenCASCADE_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${CMAKE_SHARED_LIBRARY_SUFFIX}") 138 | endif() 139 | endif() 140 | 141 | if (OpenCASCADE_LIBRARY_DEBUG_DIR_FOUND) 142 | set_property (TARGET ${aLibIter} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) 143 | set_target_properties (${aLibIter} PROPERTIES IMPORTED_IMPLIB_DEBUG "${OpenCASCADE_LIBRARY_DIR}d/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${OpenCASCADE_IMPLIB_SUFFIX}") 144 | if (OpenCASCADE_SHAREDLIB_DEBUG_FOUND) 145 | if (WIN32) 146 | set_target_properties (${aLibIter} PROPERTIES IMPORTED_LOCATION_DEBUG "${OpenCASCADE_BINARY_DIR}d/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${CMAKE_SHARED_LIBRARY_SUFFIX}") 147 | else() 148 | set_target_properties (${aLibIter} PROPERTIES IMPORTED_LOCATION_DEBUG "${OpenCASCADE_LIBRARY_DIR}d/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${CMAKE_SHARED_LIBRARY_SUFFIX}") 149 | endif() 150 | endif() 151 | endif() 152 | endforeach() 153 | else() 154 | # fallback searching for CMake configs 155 | if (NOT "${OpenCASCADE_DIR}" STREQUAL "") 156 | set (anOcctDirBak "${OpenCASCADE_DIR}") 157 | find_package (OpenCASCADE CONFIG QUIET PATHS "${OpenCASCADE_DIR}" NO_DEFAULT_PATH) 158 | set (OpenCASCADE_DIR "${anOcctDirBak}" CACHE PATH "Path to Open CASCADE libraries." FORCE) 159 | else() 160 | find_package (OpenCASCADE CONFIG QUIET) 161 | endif() 162 | endif() 163 | -------------------------------------------------------------------------------- /images/occt-ais-hello.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gkv311/occt-hello/21fdd822c6c39f722917a07a641b75e6adad0cb4/images/occt-ais-hello.png -------------------------------------------------------------------------------- /images/occt-ais-object.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gkv311/occt-hello/21fdd822c6c39f722917a07a641b75e6adad0cb4/images/occt-ais-object.gif -------------------------------------------------------------------------------- /images/occt-ais-offscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gkv311/occt-hello/21fdd822c6c39f722917a07a641b75e6adad0cb4/images/occt-ais-offscreen.png -------------------------------------------------------------------------------- /images/occt-xcaf-shape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gkv311/occt-hello/21fdd822c6c39f722917a07a641b75e6adad0cb4/images/occt-xcaf-shape.png -------------------------------------------------------------------------------- /occt-ais-hello/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.13) 2 | 3 | project (occt-ais-hello) 4 | 5 | set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../adm/cmake" ${CMAKE_MODULE_PATH}) 6 | 7 | set (APP_VERSION_MAJOR 1) 8 | set (APP_VERSION_MINOR 0) 9 | set (APP_TARGET occt-ais-hello) 10 | set (CMAKE_CXX_STANDARD 11) 11 | 12 | find_package (OpenGL REQUIRED) 13 | find_package (OpenCASCADE REQUIRED) 14 | if (NOT OpenCASCADE_FOUND) 15 | message (FATAL_ERROR "could not find OpenCASCADE, please set OpenCASCADE_DIR variable" ) 16 | else() 17 | message (STATUS "Using OpenCASCADE from \"${OpenCASCADE_INSTALL_PREFIX}\"" ) 18 | message (STATUS "OpenCASCADE_INCLUDE_DIR=${OpenCASCADE_INCLUDE_DIR}") 19 | message (STATUS "OpenCASCADE_LIBRARY_DIR=${OpenCASCADE_LIBRARY_DIR}") 20 | endif() 21 | 22 | # compiler flags 23 | if (MSVC) 24 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:precise /EHa /MP") 25 | string (REGEX REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 26 | add_definitions (-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) 27 | else() 28 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -fPIC") 29 | add_definitions(-DOCC_CONVERT_SIGNALS) 30 | endif() 31 | 32 | if (APPLE) 33 | enable_language(OBJCXX) 34 | else() 35 | set_source_files_properties (OcctAisHello.objc.mm PROPERTIES HEADER_FILE_ONLY TRUE) 36 | endif() 37 | 38 | add_executable (${APP_TARGET} 39 | OcctAisHello.cpp OcctAisHello.objc.mm ReadMe.md) 40 | 41 | # extra search paths 42 | include_directories(${OpenCASCADE_INCLUDE_DIR}) 43 | link_directories (${OpenCASCADE_LIBRARY_DIR}) 44 | 45 | # define dependencies 46 | set (anOcctLibs TKOpenGl TKV3d TKService TKPrim TKTopAlgo TKGeomAlgo TKBRep TKGeomBase TKG3d TKG2d TKMath TKernel) 47 | target_link_libraries (${PROJECT_NAME} PRIVATE ${anOcctLibs}) 48 | 49 | target_link_libraries (${PROJECT_NAME} PRIVATE ${OPENGL_LIBRARIES}) 50 | if (APPLE) 51 | find_library (Appkit_LIB NAMES AppKit) 52 | target_link_libraries (${PROJECT_NAME} PRIVATE ${Appkit_LIB}) 53 | target_link_libraries (${PROJECT_NAME} PRIVATE objc) 54 | elseif (UNIX) 55 | target_link_libraries (${PROJECT_NAME} PRIVATE EGL) 56 | target_link_libraries (${PROJECT_NAME} PRIVATE X11) 57 | target_link_libraries (${PROJECT_NAME} PRIVATE dl) 58 | target_link_libraries (${PROJECT_NAME} PRIVATE pthread) 59 | endif() 60 | 61 | # auxiliary development environment 62 | if (MSVC) 63 | set (3RDPARTY_DLL_DIRS "" CACHE STRING "Paths to external DLLs separated by semicolon (FreeImage, FreeType, etc.)") 64 | 65 | get_target_property (aTKernelRel "TKernel" IMPORTED_LOCATION_RELEASE) 66 | get_target_property (aTKernelDbg "TKernel" IMPORTED_LOCATION_DEBUG) 67 | get_filename_component (OpenCASCADE_BINARY_DIR_RELEASE ${aTKernelRel} DIRECTORY) 68 | get_filename_component (OpenCASCADE_BINARY_DIR_DEBUG ${aTKernelDbg} DIRECTORY) 69 | if (NOT EXISTS "${OpenCASCADE_BINARY_DIR_DEBUG}" AND EXISTS "${OpenCASCADE_BINARY_DIR_RELEASE}") 70 | set (OpenCASCADE_BINARY_DIR_DEBUG "${OpenCASCADE_BINARY_DIR_RELEASE}") 71 | elseif (NOT EXISTS "${OpenCASCADE_BINARY_DIR_RELEASE}" AND EXISTS "${OpenCASCADE_BINARY_DIR_DEBUG}") 72 | set (OpenCASCADE_BINARY_DIR_RELEASE "${OpenCASCADE_BINARY_DIR_DEBUG}") 73 | endif() 74 | 75 | set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_ENVIRONMENT "PATH=%PATH%;$,${OpenCASCADE_BINARY_DIR_DEBUG},${OpenCASCADE_BINARY_DIR_RELEASE}>;${3RDPARTY_DLL_DIRS}") 76 | endif() 77 | -------------------------------------------------------------------------------- /occt-ais-hello/OcctAisHello.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #include 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef _WIN32 15 | #include 16 | #include 17 | #elif defined(__APPLE__) 18 | #include 19 | #include 20 | #else 21 | #include 22 | #include 23 | #endif 24 | 25 | #ifdef _MSC_VER 26 | #pragma comment(lib, "TKOpenGl.lib") 27 | #pragma comment(lib, "TKV3d.lib") 28 | #pragma comment(lib, "TKPrim.lib") 29 | #pragma comment(lib, "TKTopAlgo.lib") 30 | #pragma comment(lib, "TKBRep.lib") 31 | #pragma comment(lib, "TKService.lib") 32 | #pragma comment(lib, "TKMath.lib") 33 | #pragma comment(lib, "TKernel.lib") 34 | #endif 35 | 36 | #ifdef __APPLE__ 37 | void occtNSAppCreate(); // implemented in .mm file 38 | void occtNSAppRun(); 39 | void occtNSAppSetEventView(const Handle(Cocoa_Window)& theWindow, AIS_ViewController* theCtrl); 40 | #endif 41 | 42 | //! Sample single-window viewer class. 43 | class OcctAisHello : public AIS_ViewController 44 | { 45 | public: 46 | //! Main constructor. 47 | OcctAisHello() 48 | { 49 | // graphic driver setup 50 | Handle(Aspect_DisplayConnection) aDisplay = new Aspect_DisplayConnection(); 51 | Handle(Graphic3d_GraphicDriver) aDriver = new OpenGl_GraphicDriver (aDisplay); 52 | 53 | // viewer setup 54 | Handle(V3d_Viewer) aViewer = new V3d_Viewer (aDriver); 55 | aViewer->SetDefaultLights(); 56 | aViewer->SetLightOn(); 57 | 58 | // view setup 59 | myView = new V3d_View (aViewer); 60 | #ifdef _WIN32 61 | const TCollection_AsciiString aClassName ("MyWinClass"); 62 | Handle(WNT_WClass) aWinClass = new WNT_WClass (aClassName.ToCString(), &windowProcWrapper, 63 | CS_VREDRAW | CS_HREDRAW, 0, 0, 64 | ::LoadCursor (NULL, IDC_ARROW)); 65 | Handle(WNT_Window) aWindow = new WNT_Window ("OCCT Viewer", aWinClass, WS_OVERLAPPEDWINDOW, 66 | 100, 100, 512, 512, Quantity_NOC_BLACK); 67 | ::SetWindowLongPtrW ((HWND )aWindow->NativeHandle(), GWLP_USERDATA, (LONG_PTR )this); 68 | #elif defined(__APPLE__) 69 | Handle(Cocoa_Window) aWindow = new Cocoa_Window ( "OCCT Viewer", 100, 100, 512, 512); 70 | occtNSAppSetEventView(aWindow, this); 71 | #else 72 | Handle(Xw_Window) aWindow = new Xw_Window (aDisplay, "OCCT Viewer", 100, 100, 512, 512); 73 | Display* anXDisplay = (Display* )aDisplay->GetDisplayAspect(); 74 | XSelectInput (anXDisplay, (Window )aWindow->NativeHandle(), 75 | ExposureMask | KeyPressMask | KeyReleaseMask | FocusChangeMask | StructureNotifyMask 76 | | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | Button1MotionMask | Button2MotionMask | Button3MotionMask); 77 | Atom aDelWinAtom = aDisplay->GetAtom (Aspect_XA_DELETE_WINDOW); 78 | XSetWMProtocols (anXDisplay, (Window )aWindow->NativeHandle(), &aDelWinAtom, 1); 79 | #endif 80 | myView->SetWindow (aWindow); 81 | myView->SetBackgroundColor (Quantity_NOC_GRAY50); 82 | myView->TriedronDisplay (Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, 0.1); 83 | myView->ChangeRenderingParams().RenderResolutionScale = 2.0f; 84 | 85 | // interactive context and demo scene 86 | myContext = new AIS_InteractiveContext (aViewer); 87 | 88 | TopoDS_Shape aShape = BRepPrimAPI_MakeBox (100, 100, 100).Solid(); 89 | Handle(AIS_InteractiveObject) aShapePrs = new AIS_Shape (aShape); 90 | myContext->Display (aShapePrs, AIS_Shaded, 0, false); 91 | myView->FitAll (0.01, false); 92 | 93 | aWindow->Map(); 94 | myView->Redraw(); 95 | } 96 | 97 | //! Return context. 98 | const Handle(AIS_InteractiveContext)& Context() const { return myContext; } 99 | 100 | //! Return view. 101 | const Handle(V3d_View)& View() const { return myView; } 102 | 103 | private: 104 | //! Handle expose event. 105 | virtual void ProcessExpose() override 106 | { 107 | if (!myView.IsNull()) 108 | { 109 | FlushViewEvents (myContext, myView, true); 110 | } 111 | } 112 | 113 | //! Handle window resize event. 114 | virtual void ProcessConfigure (bool theIsResized) override 115 | { 116 | if (!myView.IsNull() && theIsResized && !myView->Window().IsNull()) 117 | { 118 | myView->Window()->DoResize(); 119 | myView->MustBeResized(); 120 | myView->Invalidate(); 121 | FlushViewEvents (myContext, myView, true); 122 | } 123 | } 124 | 125 | //! Handle input. 126 | virtual void ProcessInput() override 127 | { 128 | if (!myView.IsNull()) 129 | { 130 | ProcessExpose(); 131 | } 132 | } 133 | 134 | #ifdef _WIN32 135 | //! Window message handler. 136 | static LRESULT WINAPI windowProcWrapper (HWND theWnd, UINT theMsg, WPARAM theParamW, LPARAM theParamL) 137 | { 138 | if (theMsg == WM_CLOSE) 139 | { 140 | exit (0); 141 | return 0; 142 | } 143 | 144 | if (OcctAisHello* aThis = (OcctAisHello* )::GetWindowLongPtrW (theWnd, GWLP_USERDATA)) 145 | { 146 | WNT_Window* aWindow = dynamic_cast(aThis->myView->Window().get()); 147 | MSG aMsg = { theWnd, theMsg, theParamW, theParamL }; 148 | if (aWindow->ProcessMessage (*aThis, aMsg)) 149 | { 150 | return 0; 151 | } 152 | } 153 | return ::DefWindowProcW (theWnd, theMsg, theParamW, theParamL); 154 | } 155 | #endif 156 | private: 157 | 158 | Handle(AIS_InteractiveContext) myContext; 159 | Handle(V3d_View) myView; 160 | }; 161 | 162 | int main() 163 | { 164 | OSD::SetSignal (false); 165 | 166 | #ifdef __APPLE__ 167 | occtNSAppCreate(); 168 | #endif 169 | 170 | OcctAisHello aViewer; 171 | #ifdef _WIN32 172 | // WinAPI message loop 173 | for (;;) 174 | { 175 | MSG aMsg = {}; 176 | if (GetMessageW (&aMsg, NULL, 0, 0) <= 0) 177 | { 178 | return 0; 179 | } 180 | TranslateMessage(&aMsg); 181 | DispatchMessageW(&aMsg); 182 | } 183 | #elif defined(__APPLE__) 184 | // run Cocoa event loop 185 | occtNSAppRun(); 186 | #else 187 | // X11 event loop 188 | Handle(Xw_Window) aWindow = Handle(Xw_Window)::DownCast (aViewer.View()->Window()); 189 | Handle(Aspect_DisplayConnection) aDispConn = aViewer.View()->Viewer()->Driver()->GetDisplayConnection(); 190 | Display* anXDisplay = (Display* )aDispConn->GetDisplayAspect(); 191 | for (;;) 192 | { 193 | XEvent anXEvent; 194 | XNextEvent (anXDisplay, &anXEvent); 195 | aWindow->ProcessMessage (aViewer, anXEvent); 196 | if (anXEvent.type == ClientMessage && (Atom)anXEvent.xclient.data.l[0] == aDispConn->GetAtom(Aspect_XA_DELETE_WINDOW)) 197 | { 198 | return 0; // exit when window is closed 199 | } 200 | } 201 | #endif 202 | return 0; 203 | } 204 | -------------------------------------------------------------------------------- /occt-ais-hello/OcctAisHello.objc.mm: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | //! Main Cocoa application responder - minimal implementation for offscreen viewer. 9 | @interface OcctTestNSResponder : NSObject 10 | { 11 | } 12 | 13 | //! Default constructor. 14 | - (id ) init; 15 | 16 | //! Access singleton. 17 | + (OcctTestNSResponder* ) sharedInstance; 18 | 19 | //! Dummy method for thread-safety Cocoa initialization. 20 | + (void ) doDummyThread: (id )theParam; 21 | 22 | @end 23 | 24 | //! Custom Cocoa view to handle events 25 | @interface OcctAisCocoaEventManagerView : NSView 26 | @end 27 | 28 | //! Custom Cocoa window delegate to handle window events 29 | @interface OcctAisCocoaWindowController : NSObject 30 | @end 31 | 32 | @implementation OcctTestNSResponder 33 | 34 | - (id )init 35 | { 36 | self = [super init]; 37 | return self; 38 | } 39 | 40 | // Singletone implementation 41 | + (OcctTestNSResponder* ) sharedInstance 42 | { 43 | static OcctTestNSResponder* TheAppResponder = [[super allocWithZone: nullptr] init]; 44 | return TheAppResponder; 45 | } 46 | + (id ) allocWithZone: (NSZone* )theZone { return [[self sharedInstance] retain]; } 47 | - (id ) copyWithZone: (NSZone* )theZone { return self; } 48 | - (id ) retain { return self; } 49 | - (NSUInteger ) retainCount { return NSUIntegerMax; } 50 | - (oneway void ) release {} 51 | - (id ) autorelease { return self; } 52 | 53 | - (BOOL ) application: (NSApplication* )theApplication openFile: (NSString* )theFilename { return YES; } 54 | - (void ) applicationWillFinishLaunching: (NSNotification* )theNotif { [self createMenu]; } 55 | - (void ) applicationDidFinishLaunching: (NSNotification* )theNotif {} 56 | - (void ) applicationWillTerminate: (NSNotification* )theNotif {} 57 | 58 | + (void ) doDummyThread: (id )theParam {} 59 | 60 | - (void ) createMenu 61 | { 62 | NSMenu* aMenubar = [[NSMenu alloc] init]; 63 | NSMenuItem* aMenuBarItem = [[NSMenuItem alloc] init]; 64 | [aMenubar addItem: aMenuBarItem]; 65 | [NSApp setMainMenu: aMenubar]; 66 | NSMenu* aMenu = [[NSMenu alloc] init]; 67 | NSString* aQuitTitle = @"Quit"; 68 | NSMenuItem* aQuitMenuItem = [[NSMenuItem alloc] initWithTitle: aQuitTitle action: @selector(terminate:) keyEquivalent: @"q"]; 69 | [aMenu addItem: aQuitMenuItem]; 70 | [aMenuBarItem setSubmenu: aMenu]; 71 | } 72 | 73 | @end 74 | 75 | @implementation OcctAisCocoaWindowController 76 | 77 | - (void )windowWillClose: (NSNotification* )theNotif 78 | { 79 | (void )theNotif; 80 | [[NSApplication sharedApplication] terminate: nil]; 81 | } 82 | 83 | - (void )windowDidBecomeKey: (NSNotification* )theNotif 84 | { 85 | //NSWindow* aWindow = [theNotif object]; 86 | //ActivateView(aWindow); 87 | } 88 | 89 | @end 90 | 91 | //! Retrieve cursor position 92 | static Graphic3d_Vec2i getMouseCoords(NSView* theView, NSEvent* theEvent) 93 | { 94 | NSPoint aMouseLoc = [theView convertPoint: [theEvent locationInWindow] fromView: nil]; 95 | NSRect aBounds = [theView bounds]; 96 | return Graphic3d_Vec2i(int(aMouseLoc.x), int(aBounds.size.height - aMouseLoc.y)); 97 | } 98 | 99 | //! Convert key flags from mouse event. 100 | static Aspect_VKeyFlags getMouseKeyFlags (NSEvent* theEvent) 101 | { 102 | Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE; 103 | if (([theEvent modifierFlags] & NSEventModifierFlagShift) != 0) 104 | aFlags |= Aspect_VKeyFlags_SHIFT; 105 | 106 | if (([theEvent modifierFlags] & NSEventModifierFlagControl) != 0) 107 | aFlags |= Aspect_VKeyFlags_CTRL; 108 | 109 | if (([theEvent modifierFlags] & NSEventModifierFlagOption) != 0) 110 | aFlags |= Aspect_VKeyFlags_ALT; 111 | 112 | return aFlags; 113 | } 114 | 115 | @implementation OcctAisCocoaEventManagerView 116 | 117 | AIS_ViewController* myViewCtrl = nullptr; 118 | 119 | - (void )setViewController: (AIS_ViewController* )theCtrl 120 | { 121 | myViewCtrl = theCtrl; 122 | } 123 | 124 | - (void )updateTrackingAreas 125 | { 126 | // to track mouse movements for dynamic highlight 127 | NSTrackingAreaOptions aFlags = (NSTrackingActiveAlways | NSTrackingInVisibleRect | NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved); 128 | NSTrackingArea* anArea = [[NSTrackingArea alloc] initWithRect: [self bounds] options: aFlags owner: self userInfo: nil]; 129 | [self addTrackingArea: anArea]; 130 | } 131 | 132 | - (void )setFrameSize: (NSSize )theNewSize 133 | { 134 | [super setFrameSize: theNewSize]; 135 | myViewCtrl->ProcessConfigure(true); 136 | } 137 | 138 | - (void )drawRect: (NSRect )theDirtyRect 139 | { 140 | (void )theDirtyRect; 141 | if (myViewCtrl != nullptr) 142 | myViewCtrl->ProcessExpose(); 143 | } 144 | 145 | - (void )mouseMoved: (NSEvent* )theEvent 146 | { 147 | const Graphic3d_Vec2i aPos = getMouseCoords(self, theEvent); 148 | const Aspect_VKeyFlags aFlags = getMouseKeyFlags(theEvent); 149 | const Aspect_VKeyMouse aButtons = myViewCtrl->PressedMouseButtons(); 150 | myViewCtrl->UpdateMousePosition(aPos, aButtons, aFlags, false); 151 | myViewCtrl->ProcessInput(); 152 | } 153 | 154 | - (BOOL )acceptsFirstResponder 155 | { 156 | return YES; 157 | } 158 | 159 | - (void )mouseDown: (NSEvent* )theEvent 160 | { 161 | const Graphic3d_Vec2i aPos = getMouseCoords(self, theEvent); 162 | const Aspect_VKeyFlags aFlags = getMouseKeyFlags(theEvent); 163 | myViewCtrl->PressMouseButton(aPos, Aspect_VKeyMouse_LeftButton, aFlags, false); 164 | myViewCtrl->ProcessInput(); 165 | } 166 | 167 | - (void )mouseUp: (NSEvent* )theEvent 168 | { 169 | const Graphic3d_Vec2i aPos = getMouseCoords(self, theEvent); 170 | const Aspect_VKeyFlags aFlags = getMouseKeyFlags(theEvent); 171 | myViewCtrl->ReleaseMouseButton(aPos, Aspect_VKeyMouse_LeftButton, aFlags, false); 172 | myViewCtrl->ProcessInput(); 173 | } 174 | 175 | - (void )mouseDragged: (NSEvent* )theEvent 176 | { 177 | const Graphic3d_Vec2i aPos = getMouseCoords(self, theEvent); 178 | const Aspect_VKeyFlags aFlags = getMouseKeyFlags(theEvent); 179 | const Aspect_VKeyMouse aButtons = myViewCtrl->PressedMouseButtons(); 180 | myViewCtrl->UpdateMousePosition(aPos, aButtons, aFlags, false); 181 | myViewCtrl->ProcessInput(); 182 | } 183 | 184 | - (void )rightMouseDown: (NSEvent* )theEvent 185 | { 186 | const Graphic3d_Vec2i aPos = getMouseCoords(self, theEvent); 187 | const Aspect_VKeyFlags aFlags = getMouseKeyFlags(theEvent); 188 | myViewCtrl->PressMouseButton(aPos, Aspect_VKeyMouse_RightButton, aFlags, false); 189 | myViewCtrl->ProcessInput(); 190 | } 191 | 192 | - (void )rightMouseUp: (NSEvent* )theEvent 193 | { 194 | const Graphic3d_Vec2i aPos = getMouseCoords(self, theEvent); 195 | const Aspect_VKeyFlags aFlags = getMouseKeyFlags(theEvent); 196 | myViewCtrl->ReleaseMouseButton(aPos, Aspect_VKeyMouse_RightButton, aFlags, false); 197 | myViewCtrl->ProcessInput(); 198 | } 199 | 200 | - (void )rightMouseDragged: (NSEvent* )theEvent 201 | { 202 | const Graphic3d_Vec2i aPos = getMouseCoords(self, theEvent); 203 | const Aspect_VKeyFlags aFlags = getMouseKeyFlags(theEvent); 204 | const Aspect_VKeyMouse aButtons = myViewCtrl->PressedMouseButtons(); 205 | myViewCtrl->UpdateMousePosition (aPos, aButtons, aFlags, false); 206 | myViewCtrl->ProcessInput(); 207 | } 208 | 209 | - (void )scrollWheel: (NSEvent* )theEvent 210 | { 211 | const Graphic3d_Vec2i aPos = getMouseCoords(self, theEvent); 212 | const Aspect_VKeyFlags aFlags = getMouseKeyFlags(theEvent); 213 | 214 | const double aDelta = [theEvent deltaY]; 215 | if (Abs (aDelta) < 0.001) // a lot of values near zero can be generated by touchpad 216 | return; 217 | 218 | myViewCtrl->UpdateMouseScroll(Aspect_ScrollDelta(aPos, aDelta, aFlags)); 219 | myViewCtrl->ProcessInput(); 220 | } 221 | 222 | - (void )keyDown: (NSEvent* )theEvent 223 | { 224 | unsigned int aKeyCode = [theEvent keyCode]; 225 | const Aspect_VKey aVKey = Cocoa_Window::VirtualKeyFromNative(aKeyCode); 226 | if (aVKey != Aspect_VKey_UNKNOWN) 227 | { 228 | const double aTimeStamp = [theEvent timestamp]; 229 | myViewCtrl->KeyDown(aVKey, aTimeStamp); 230 | myViewCtrl->ProcessInput(); 231 | } 232 | } 233 | 234 | - (void )keyUp: (NSEvent* )theEvent 235 | { 236 | unsigned int aKeyCode = [theEvent keyCode]; 237 | const Aspect_VKey aVKey = Cocoa_Window::VirtualKeyFromNative(aKeyCode); 238 | if (aVKey != Aspect_VKey_UNKNOWN) 239 | { 240 | const double aTimeStamp = [theEvent timestamp]; 241 | myViewCtrl->KeyUp(aVKey, aTimeStamp); 242 | myViewCtrl->ProcessInput(); 243 | } 244 | } 245 | 246 | @end 247 | 248 | void occtNSAppCreate() 249 | { 250 | // create dummy NSThread to ensure Cocoa thread-safety 251 | [NSThread detachNewThreadSelector: @selector(doDummyThread: ) toTarget: [OcctTestNSResponder class] withObject: nullptr]; 252 | 253 | NSApplication* anAppNs = [NSApplication sharedApplication]; 254 | OcctTestNSResponder* anAppResp = [OcctTestNSResponder sharedInstance]; 255 | [anAppNs setDelegate: anAppResp]; 256 | //[NSBundle loadNibNamed: @"MainMenu" owner: anAppResp]; 257 | 258 | // allow our application to steal input focus (when needed) 259 | [anAppNs activateIgnoringOtherApps: YES]; 260 | } 261 | 262 | void occtNSAppRun() 263 | { 264 | NSApplication* anAppNs = [NSApplication sharedApplication]; 265 | //[[NSApp mainWindow] makeKeyAndOrderFront: anAppNs]; 266 | [anAppNs run]; // Cocoa event loop 267 | } 268 | 269 | void occtNSAppSetEventView(const Handle(Cocoa_Window)& theWindow, AIS_ViewController* theCtrl) 270 | { 271 | if (theWindow.IsNull()) 272 | return; 273 | 274 | NSWindow* aWin = [theWindow->HView() window]; 275 | NSRect aBounds = [[aWin contentView] bounds]; 276 | 277 | OcctAisCocoaEventManagerView* aView = [[OcctAisCocoaEventManagerView alloc] initWithFrame: aBounds]; 278 | [aView setViewController: theCtrl]; 279 | 280 | // replace content view in the window 281 | theWindow->SetHView(aView); 282 | 283 | // set delegate for window 284 | OcctAisCocoaWindowController* aWindowController = [[[OcctAisCocoaWindowController alloc] init] autorelease]; 285 | [aWin setDelegate: aWindowController]; 286 | 287 | // make view as first responder in winow to capture all useful events 288 | [aWin makeFirstResponder: aView]; 289 | [aWin setAcceptsMouseMovedEvents: YES]; 290 | 291 | // should be retained by parent NSWindow 292 | [aView release]; 293 | } 294 | -------------------------------------------------------------------------------- /occt-ais-hello/OcctAisHello.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OcctAisHello", "OcctAisHello.vcxproj", "{4DE72600-930D-408E-B593-E4E87FE7460B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {4DE72600-930D-408E-B593-E4E87FE7460B}.Debug|x64.ActiveCfg = Debug|x64 17 | {4DE72600-930D-408E-B593-E4E87FE7460B}.Debug|x64.Build.0 = Debug|x64 18 | {4DE72600-930D-408E-B593-E4E87FE7460B}.Debug|x86.ActiveCfg = Debug|Win32 19 | {4DE72600-930D-408E-B593-E4E87FE7460B}.Debug|x86.Build.0 = Debug|Win32 20 | {4DE72600-930D-408E-B593-E4E87FE7460B}.Release|x64.ActiveCfg = Release|x64 21 | {4DE72600-930D-408E-B593-E4E87FE7460B}.Release|x64.Build.0 = Release|x64 22 | {4DE72600-930D-408E-B593-E4E87FE7460B}.Release|x86.ActiveCfg = Release|Win32 23 | {4DE72600-930D-408E-B593-E4E87FE7460B}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /occt-ais-hello/OcctAisHello.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {4DE72600-930D-408E-B593-E4E87FE7460B} 23 | Win32Proj 24 | OcctAisHello 25 | 8.1 26 | 27 | 28 | 29 | Application 30 | true 31 | v140 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v140 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v140 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v140 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | 87 | 88 | Level3 89 | Disabled 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | c:\occt750_vc141_64\opencascade-7.5.0\inc\ 105 | 106 | 107 | Console 108 | true 109 | c:\occt750_vc141_64\opencascade-7.5.0\win64\vc14\lib\ 110 | 111 | 112 | 113 | 114 | Level3 115 | 116 | 117 | MaxSpeed 118 | true 119 | true 120 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | Level3 132 | 133 | 134 | MaxSpeed 135 | true 136 | true 137 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 138 | c:\occt750_vc141_64\opencascade-7.5.0\inc\ 139 | 140 | 141 | Console 142 | true 143 | true 144 | true 145 | c:\occt750_vc141_64\opencascade-7.5.0\win64\vc14\lib\ 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /occt-ais-hello/OcctAisHello.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /occt-ais-hello/ReadMe.md: -------------------------------------------------------------------------------- 1 | OCCT Viewer minimal setup (on Windows, Linux and macOS platforms).
2 | https://unlimited3d.wordpress.com/2021/03/27/occt-minimal-viewer-setup/ 3 | -------------------------------------------------------------------------------- /occt-ais-object/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.13) 2 | 3 | project (occt-ais-object) 4 | 5 | set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../adm/cmake" ${CMAKE_MODULE_PATH}) 6 | 7 | set (APP_VERSION_MAJOR 1) 8 | set (APP_VERSION_MINOR 0) 9 | set (APP_TARGET occt-ais-object) 10 | set (CMAKE_CXX_STANDARD 11) 11 | 12 | find_package (OpenGL REQUIRED) 13 | find_package (OpenCASCADE REQUIRED) 14 | if (NOT OpenCASCADE_FOUND) 15 | message (FATAL_ERROR "could not find OpenCASCADE, please set OpenCASCADE_DIR variable" ) 16 | else() 17 | message (STATUS "Using OpenCASCADE from \"${OpenCASCADE_INSTALL_PREFIX}\"" ) 18 | message (STATUS "OpenCASCADE_INCLUDE_DIR=${OpenCASCADE_INCLUDE_DIR}") 19 | message (STATUS "OpenCASCADE_LIBRARY_DIR=${OpenCASCADE_LIBRARY_DIR}") 20 | endif() 21 | 22 | # compiler flags 23 | if (MSVC) 24 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:precise /EHa /MP") 25 | string (REGEX REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 26 | add_definitions (-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) 27 | else() 28 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -fPIC") 29 | add_definitions(-DOCC_CONVERT_SIGNALS) 30 | endif() 31 | 32 | add_executable (${APP_TARGET} 33 | OcctAisObject.cpp ReadMe.md) 34 | 35 | # extra search paths 36 | include_directories(${OpenCASCADE_INCLUDE_DIR}) 37 | #link_directories (${OpenCASCADE_LIBRARY_DIR}) 38 | 39 | # define dependencies 40 | set (anOcctLibs TKOpenGl TKV3d TKService TKPrim TKTopAlgo TKGeomAlgo TKBRep TKGeomBase TKG3d TKG2d TKMath TKernel) 41 | target_link_libraries (${PROJECT_NAME} PRIVATE ${anOcctLibs}) 42 | 43 | target_link_libraries (${PROJECT_NAME} PRIVATE ${OPENGL_LIBRARIES}) 44 | if (APPLE) 45 | find_library (Appkit_LIB NAMES AppKit) 46 | target_link_libraries (${PROJECT_NAME} PRIVATE ${Appkit_LIB}) 47 | target_link_libraries (${PROJECT_NAME} PRIVATE objc) 48 | elseif (UNIX) 49 | target_link_libraries (${PROJECT_NAME} PRIVATE EGL) 50 | target_link_libraries (${PROJECT_NAME} PRIVATE X11) 51 | target_link_libraries (${PROJECT_NAME} PRIVATE dl) 52 | target_link_libraries (${PROJECT_NAME} PRIVATE pthread) 53 | endif() 54 | 55 | # auxiliary development environment 56 | if (MSVC) 57 | set (3RDPARTY_DLL_DIRS "" CACHE STRING "Paths to external DLLs separated by semicolon (FreeImage, FreeType, etc.)") 58 | 59 | get_target_property (aTKernelRel "TKernel" IMPORTED_LOCATION_RELEASE) 60 | get_target_property (aTKernelDbg "TKernel" IMPORTED_LOCATION_DEBUG) 61 | get_filename_component (OpenCASCADE_BINARY_DIR_RELEASE ${aTKernelRel} DIRECTORY) 62 | get_filename_component (OpenCASCADE_BINARY_DIR_DEBUG ${aTKernelDbg} DIRECTORY) 63 | if (NOT EXISTS "${OpenCASCADE_BINARY_DIR_DEBUG}" AND EXISTS "${OpenCASCADE_BINARY_DIR_RELEASE}") 64 | set (OpenCASCADE_BINARY_DIR_DEBUG "${OpenCASCADE_BINARY_DIR_RELEASE}") 65 | elseif (NOT EXISTS "${OpenCASCADE_BINARY_DIR_RELEASE}" AND EXISTS "${OpenCASCADE_BINARY_DIR_DEBUG}") 66 | set (OpenCASCADE_BINARY_DIR_RELEASE "${OpenCASCADE_BINARY_DIR_DEBUG}") 67 | endif() 68 | 69 | set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_ENVIRONMENT "PATH=%PATH%;$,${OpenCASCADE_BINARY_DIR_DEBUG},${OpenCASCADE_BINARY_DIR_RELEASE}>;${3RDPARTY_DLL_DIRS}") 70 | endif() 71 | -------------------------------------------------------------------------------- /occt-ais-object/OcctAisObject.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #include 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef _WIN32 15 | #include 16 | #include 17 | #elif defined(__APPLE__) 18 | #include 19 | #else 20 | #include 21 | #include 22 | #endif 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | //! Custom AIS object. 46 | class MyAisObject : public AIS_InteractiveObject 47 | { 48 | DEFINE_STANDARD_RTTI_INLINE(MyAisObject, AIS_InteractiveObject) 49 | public: 50 | enum MyDispMode { MyDispMode_Main = 0, MyDispMode_Highlight = 1 }; 51 | public: 52 | MyAisObject(); 53 | void SetAnimation (const Handle(AIS_Animation)& theAnim) { myAnim = theAnim; } 54 | public: 55 | virtual void Compute (const Handle(PrsMgr_PresentationManager)& thePrsMgr, 56 | const Handle(Prs3d_Presentation)& thePrs, 57 | const Standard_Integer theMode) override; 58 | 59 | virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, 60 | const Standard_Integer theMode) override; 61 | 62 | virtual bool AcceptDisplayMode (const Standard_Integer theMode) const override 63 | { 64 | return theMode == MyDispMode_Main || theMode == MyDispMode_Highlight; 65 | } 66 | protected: 67 | Handle(AIS_Animation) myAnim; 68 | gp_Pnt myDragPntFrom; 69 | }; 70 | 71 | MyAisObject::MyAisObject() 72 | { 73 | //SetHilightMode (MyDispMode_Highlight); 74 | myDrawer->SetupOwnShadingAspect(); 75 | myDrawer->ShadingAspect()->SetMaterial (Graphic3d_NameOfMaterial_Silver); 76 | myDrawer->SetWireAspect (new Prs3d_LineAspect (Quantity_NOC_GREEN, Aspect_TOL_SOLID, 2.0)); 77 | } 78 | 79 | void MyAisObject::Compute (const Handle(PrsMgr_PresentationManager)& thePrsMgr, 80 | const Handle(Prs3d_Presentation)& thePrs, 81 | const Standard_Integer theMode) 82 | { 83 | const double aRadius = 100.0, aHeight = 100.0; 84 | TopoDS_Shape aShape = BRepPrimAPI_MakeCone (aRadius, 0.0, aHeight); 85 | if (theMode == MyDispMode_Main) 86 | { 87 | //StdPrs_ShadedShape::Add (thePrs, aShape, myDrawer); 88 | //StdPrs_WFShape::Add (thePrs, aShape, myDrawer); // add wireframe 89 | Prs3d_ToolCylinder aCyl (aRadius, 0.0, aHeight, 25, 25); 90 | Prs3d_ToolDisk aDisk (0.0, aRadius, 25, 1); 91 | Handle(Graphic3d_ArrayOfTriangles) aTris = 92 | new Graphic3d_ArrayOfTriangles (aCyl.VerticesNb() + aDisk.VerticesNb(), 93 | (aCyl.TrianglesNb() + aDisk.TrianglesNb()) * 3, 94 | Graphic3d_ArrayFlags_VertexNormal); 95 | aCyl .FillArray (aTris, gp_Trsf()); 96 | aDisk.FillArray (aTris, gp_Trsf()); 97 | Handle(Graphic3d_Group) aGroupTris = thePrs->NewGroup(); 98 | aGroupTris->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect()); 99 | aGroupTris->AddPrimitiveArray (aTris); 100 | aGroupTris->SetClosed (true); // 101 | 102 | Handle(Graphic3d_ArrayOfSegments) aSegs = new Graphic3d_ArrayOfSegments (3, 3 * 2, Graphic3d_ArrayFlags_None); 103 | aSegs->AddVertex (gp_Pnt (0.0, 0.0, aHeight)); 104 | aSegs->AddVertex (gp_Pnt (0.0, -aRadius, 0.0)); 105 | aSegs->AddVertex (gp_Pnt (0.0, aRadius, 0.0)); 106 | aSegs->AddEdges (1, 2); 107 | aSegs->AddEdges (2, 3); 108 | aSegs->AddEdges (3, 1); 109 | Handle(Graphic3d_Group) aGroupSegs = thePrs->NewGroup(); 110 | aGroupSegs->SetGroupPrimitivesAspect (myDrawer->WireAspect()->Aspect()); 111 | aGroupSegs->AddPrimitiveArray (aSegs); 112 | } 113 | else if (theMode == MyDispMode_Highlight) 114 | { 115 | Bnd_Box aBox; 116 | BRepBndLib::Add (aShape, aBox); 117 | Prs3d_BndBox::Add (thePrs, aBox, myDrawer); 118 | } 119 | } 120 | 121 | //! Custom AIS owner. 122 | class MyAisOwner : public SelectMgr_EntityOwner 123 | { 124 | DEFINE_STANDARD_RTTI_INLINE(MyAisOwner, SelectMgr_EntityOwner) 125 | public: 126 | MyAisOwner (const Handle(MyAisObject)& theObj, int thePriority = 0) 127 | : SelectMgr_EntityOwner (theObj, thePriority) {} 128 | 129 | void SetAnimation (const Handle(AIS_Animation)& theAnim) { myAnim = theAnim; } 130 | 131 | virtual void HilightWithColor (const Handle(PrsMgr_PresentationManager)& thePM, 132 | const Handle(Prs3d_Drawer)& theStyle, 133 | const Standard_Integer theMode) override; 134 | virtual void Unhilight (const Handle(PrsMgr_PresentationManager)& thePM, 135 | const Standard_Integer theMode) override; 136 | 137 | virtual bool IsForcedHilight() const override { return true; } 138 | virtual bool HandleMouseClick (const Graphic3d_Vec2i& thePoint, 139 | Aspect_VKeyMouse theButton, 140 | Aspect_VKeyFlags theModifiers, 141 | bool theIsDoubleClick) override; 142 | virtual void SetLocation (const TopLoc_Location& theLocation) override 143 | { 144 | if (!myPrs.IsNull()) { myPrs->SetTransformation (new TopLoc_Datum3D (theLocation.Transformation())); } 145 | } 146 | protected: 147 | Handle(Prs3d_Presentation) myPrs; 148 | Handle(AIS_Animation) myAnim; 149 | }; 150 | 151 | void MyAisOwner::HilightWithColor (const Handle(PrsMgr_PresentationManager)& thePM, 152 | const Handle(Prs3d_Drawer)& theStyle, 153 | const Standard_Integer theMode) 154 | { 155 | auto anObj = dynamic_cast (mySelectable); 156 | if (myPrs.IsNull()) 157 | { 158 | myPrs = new Prs3d_Presentation (thePM->StructureManager()); 159 | anObj->Compute (thePM, myPrs, MyAisObject::MyDispMode_Highlight); 160 | } 161 | if (thePM->IsImmediateModeOn()) 162 | { 163 | Handle(StdSelect_ViewerSelector3d) aSelector = anObj->InteractiveContext()->MainSelector(); 164 | SelectMgr_SortCriterion aPickPnt; 165 | for (int aPickIter = 1; aPickIter <= aSelector->NbPicked(); ++aPickIter) 166 | { 167 | if (aSelector->Picked (aPickIter) == this) 168 | { 169 | aPickPnt = aSelector->PickedData (aPickIter); 170 | break; 171 | } 172 | } 173 | 174 | Handle(Prs3d_Presentation) aPrs = mySelectable->GetHilightPresentation (thePM); 175 | aPrs->Clear(); 176 | Handle(Graphic3d_Group) aGroupPnt = aPrs->NewGroup(); 177 | aGroupPnt->SetGroupPrimitivesAspect (theStyle->ArrowAspect()->Aspect()); 178 | 179 | gp_Trsf aTrsfInv (mySelectable->InversedTransformation().Trsf()); 180 | gp_Dir aNorm (aPickPnt.Normal.x(), aPickPnt.Normal.y(), aPickPnt.Normal.z()); 181 | Handle(Graphic3d_ArrayOfTriangles) aTris = 182 | Prs3d_Arrow::DrawShaded (gp_Ax1(aPickPnt.Point, aNorm).Transformed (aTrsfInv), 183 | 1.0, 15.0, 184 | 3.0, 4.0, 10); 185 | aGroupPnt->AddPrimitiveArray (aTris); 186 | 187 | aPrs->SetZLayer (Graphic3d_ZLayerId_Top); 188 | thePM->AddToImmediateList (aPrs); 189 | 190 | //Handle(Prs3d_PresentationShadow) aShadow = new Prs3d_PresentationShadow (thePM->StructureManager(), myPrs); 191 | //aShadow->SetZLayer (Graphic3d_ZLayerId_Top); 192 | //aShadow->Highlight (theStyle); 193 | //thePM->AddToImmediateList (aShadow); 194 | } 195 | else 196 | { 197 | myPrs->SetTransformation (mySelectable->TransformationGeom()); 198 | myPrs->Display(); 199 | } 200 | } 201 | 202 | void MyAisOwner::Unhilight (const Handle(PrsMgr_PresentationManager)& thePM, 203 | const Standard_Integer theMode) 204 | { 205 | if (!myPrs.IsNull()) 206 | { 207 | myPrs->Erase(); 208 | } 209 | } 210 | 211 | bool MyAisOwner::HandleMouseClick (const Graphic3d_Vec2i& thePoint, 212 | Aspect_VKeyMouse theButton, 213 | Aspect_VKeyFlags theModifiers, 214 | bool theIsDoubleClick) 215 | { 216 | { 217 | static math_BullardGenerator aRandGen; 218 | Quantity_Color aRandColor (float(aRandGen.NextInt() % 256) / 255.0f, 219 | float(aRandGen.NextInt() % 256) / 255.0f, 220 | float(aRandGen.NextInt() % 256) / 255.0f, 221 | Quantity_TOC_sRGB); 222 | mySelectable->Attributes()->ShadingAspect()->SetColor(aRandColor); 223 | mySelectable->SynchronizeAspects(); 224 | } 225 | 226 | if (!myAnim.IsNull()) 227 | { 228 | static bool isFirst = true; 229 | isFirst = !isFirst; 230 | auto anObj = dynamic_cast (mySelectable); 231 | 232 | gp_Trsf aTrsfTo; 233 | aTrsfTo.SetRotation (gp_Ax1 (gp::Origin(), gp::DX()), isFirst ? M_PI * 0.5 : -M_PI * 0.5); 234 | gp_Trsf aTrsfFrom = anObj->LocalTransformation(); 235 | Handle(AIS_AnimationObject) anAnim = new AIS_AnimationObject ("MyAnim", anObj->InteractiveContext(), anObj, aTrsfFrom, aTrsfTo); 236 | anAnim->SetOwnDuration (2.0); 237 | 238 | myAnim->Clear(); 239 | myAnim->Add (anAnim); 240 | myAnim->StartTimer (0.0, 1.0, true); 241 | } 242 | 243 | return true; 244 | } 245 | 246 | void MyAisObject::ComputeSelection (const Handle(SelectMgr_Selection)& theSel, 247 | const Standard_Integer theMode) 248 | { 249 | const double aRadius = 100.0, aHeight = 100.0; 250 | TopoDS_Shape aShape = BRepPrimAPI_MakeCone (aRadius, 0.0, aHeight); 251 | Bnd_Box aBox; 252 | BRepBndLib::Add (aShape, aBox); 253 | Handle(MyAisOwner) anOwner = new MyAisOwner (this); 254 | anOwner->SetAnimation (myAnim); 255 | 256 | Handle(Graphic3d_ArrayOfTriangles) aTris = Prs3d_ToolCylinder::Create (aRadius, 0.0, aHeight, 25, 25, gp_Trsf()); 257 | auto aSensTri = new Select3D_SensitivePrimitiveArray (anOwner); 258 | aSensTri->InitTriangulation (aTris->Attributes(), aTris->Indices(), TopLoc_Location()); 259 | theSel->Add (aSensTri); 260 | 261 | //Handle(SelectMgr_EntityOwner) anOwner = new SelectMgr_EntityOwner (this); 262 | //Handle(Select3D_SensitiveBox) aSensBox = new Select3D_SensitiveBox (anOwner, aBox); 263 | //theSel->Add (aSensBox); 264 | } 265 | 266 | //! Sample single-window viewer class. 267 | class MyViewer : public AIS_ViewController 268 | { 269 | public: 270 | //! Main constructor. 271 | MyViewer() 272 | { 273 | // graphic driver setup 274 | Handle(Aspect_DisplayConnection) aDisplay = new Aspect_DisplayConnection(); 275 | Handle(Graphic3d_GraphicDriver) aDriver = new OpenGl_GraphicDriver (aDisplay); 276 | 277 | // viewer setup 278 | Handle(V3d_Viewer) aViewer = new V3d_Viewer (aDriver); 279 | aViewer->SetDefaultLights(); 280 | aViewer->SetLightOn(); 281 | 282 | // view setup 283 | myView = new V3d_View (aViewer); 284 | #ifdef _WIN32 285 | const TCollection_AsciiString aClassName ("MyWinClass"); 286 | Handle(WNT_WClass) aWinClass = new WNT_WClass (aClassName.ToCString(), &windowProcWrapper, 287 | CS_VREDRAW | CS_HREDRAW, 0, 0, 288 | ::LoadCursor (NULL, IDC_ARROW)); 289 | Handle(WNT_Window) aWindow = new WNT_Window ("OCCT Viewer", aWinClass, WS_OVERLAPPEDWINDOW, 290 | 100, 100, 512, 512, Quantity_NOC_BLACK); 291 | ::SetWindowLongPtrW ((HWND )aWindow->NativeHandle(), GWLP_USERDATA, (LONG_PTR )this); 292 | #elif defined(__APPLE__) 293 | Handle(Cocoa_Window) aWindow = new Cocoa_Window ( "OCCT Viewer", 100, 100, 512, 512); 294 | #else 295 | Handle(Xw_Window) aWindow = new Xw_Window (aDisplay, "OCCT Viewer", 100, 100, 512, 512); 296 | Display* anXDisplay = (Display* )aDisplay->GetDisplayAspect(); 297 | XSelectInput (anXDisplay, (Window )aWindow->NativeHandle(), 298 | ExposureMask | KeyPressMask | KeyReleaseMask | FocusChangeMask | StructureNotifyMask 299 | | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | Button1MotionMask | Button2MotionMask | Button3MotionMask); 300 | Atom aDelWinAtom = aDisplay->GetAtom (Aspect_XA_DELETE_WINDOW); 301 | XSetWMProtocols (anXDisplay, (Window )aWindow->NativeHandle(), &aDelWinAtom, 1); 302 | #endif 303 | myView->SetWindow (aWindow); 304 | myView->SetBackgroundColor (Quantity_NOC_GRAY50); 305 | myView->TriedronDisplay (Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, 0.1); 306 | myView->ChangeRenderingParams().RenderResolutionScale = 2.0f; 307 | 308 | // interactive context and demo scene 309 | myContext = new AIS_InteractiveContext (aViewer); 310 | 311 | Handle(MyAisObject) aPrs = new MyAisObject(); 312 | aPrs->SetAnimation (AIS_ViewController::ObjectsAnimation()); 313 | myContext->Display (aPrs, MyAisObject::MyDispMode_Main, 0, false); 314 | myView->FitAll (0.01, false); 315 | 316 | aWindow->Map(); 317 | myView->Redraw(); 318 | } 319 | 320 | //! Return context. 321 | const Handle(AIS_InteractiveContext)& Context() const { return myContext; } 322 | 323 | //! Return view. 324 | const Handle(V3d_View)& View() const { return myView; } 325 | 326 | private: 327 | //! Handle expose event. 328 | virtual void ProcessExpose() override 329 | { 330 | if (!myView.IsNull()) 331 | { 332 | FlushViewEvents (myContext, myView, true); 333 | } 334 | } 335 | 336 | //! Handle window resize event. 337 | virtual void ProcessConfigure (bool theIsResized) override 338 | { 339 | if (!myView.IsNull() && theIsResized) 340 | { 341 | myView->Window()->DoResize(); 342 | myView->MustBeResized(); 343 | myView->Invalidate(); 344 | FlushViewEvents (myContext, myView, true); 345 | } 346 | } 347 | 348 | //! Handle input. 349 | virtual void ProcessInput() override 350 | { 351 | if (!myView.IsNull()) 352 | { 353 | ProcessExpose(); 354 | } 355 | } 356 | 357 | #ifdef _WIN32 358 | //! Window message handler. 359 | static LRESULT WINAPI windowProcWrapper (HWND theWnd, UINT theMsg, WPARAM theParamW, LPARAM theParamL) 360 | { 361 | if (theMsg == WM_CLOSE) 362 | { 363 | exit (0); 364 | return 0; 365 | } 366 | 367 | if (MyViewer* aThis = (MyViewer* )::GetWindowLongPtrW (theWnd, GWLP_USERDATA)) 368 | { 369 | WNT_Window* aWindow = dynamic_cast(aThis->myView->Window().get()); 370 | MSG aMsg = { theWnd, theMsg, theParamW, theParamL }; 371 | if (aWindow->ProcessMessage (*aThis, aMsg)) 372 | { 373 | return 0; 374 | } 375 | } 376 | return ::DefWindowProcW (theWnd, theMsg, theParamW, theParamL); 377 | } 378 | #endif 379 | private: 380 | 381 | Handle(AIS_InteractiveContext) myContext; 382 | Handle(V3d_View) myView; 383 | }; 384 | 385 | int main() 386 | { 387 | OSD::SetSignal (false); 388 | 389 | MyViewer aViewer; 390 | #ifdef _WIN32 391 | // WinAPI message loop 392 | for (;;) 393 | { 394 | MSG aMsg = {}; 395 | if (GetMessageW (&aMsg, NULL, 0, 0) <= 0) 396 | { 397 | return 0; 398 | } 399 | TranslateMessage(&aMsg); 400 | DispatchMessageW(&aMsg); 401 | } 402 | #elif defined(__APPLE__) 403 | /// TODO 404 | Message::SendFail() << "Critical error: Cocoa message loop is not implemented"; 405 | #else 406 | // X11 event loop 407 | Handle(Xw_Window) aWindow = Handle(Xw_Window)::DownCast (aViewer.View()->Window()); 408 | Handle(Aspect_DisplayConnection) aDispConn = aViewer.View()->Viewer()->Driver()->GetDisplayConnection(); 409 | Display* anXDisplay = (Display* )aDispConn->GetDisplayAspect(); 410 | for (;;) 411 | { 412 | XEvent anXEvent; 413 | XNextEvent (anXDisplay, &anXEvent); 414 | aWindow->ProcessMessage (aViewer, anXEvent); 415 | if (anXEvent.type == ClientMessage && (Atom)anXEvent.xclient.data.l[0] == aDispConn->GetAtom(Aspect_XA_DELETE_WINDOW)) 416 | { 417 | return 0; // exit when window is closed 418 | } 419 | } 420 | #endif 421 | return 0; 422 | } 423 | -------------------------------------------------------------------------------- /occt-ais-object/ReadMe.md: -------------------------------------------------------------------------------- 1 | Custom AIS object sample – computing presentation and computing selection.
2 | https://unlimited3d.wordpress.com/2021/11/16/ais-object-computing-presentation/ 3 | -------------------------------------------------------------------------------- /occt-ais-offscreen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.13) 2 | 3 | project (occt-ais-offscreen) 4 | 5 | set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../adm/cmake" ${CMAKE_MODULE_PATH}) 6 | 7 | set (APP_VERSION_MAJOR 1) 8 | set (APP_VERSION_MINOR 0) 9 | set (APP_TARGET occt-ais-offscreen) 10 | set (CMAKE_CXX_STANDARD 11) 11 | 12 | find_package (OpenGL REQUIRED) 13 | find_package (OpenCASCADE REQUIRED) 14 | if (NOT OpenCASCADE_FOUND) 15 | message (FATAL_ERROR "could not find OpenCASCADE, please set OpenCASCADE_DIR variable" ) 16 | else() 17 | message (STATUS "Using OpenCASCADE from \"${OpenCASCADE_INSTALL_PREFIX}\"" ) 18 | message (STATUS "OpenCASCADE_INCLUDE_DIR=${OpenCASCADE_INCLUDE_DIR}") 19 | message (STATUS "OpenCASCADE_LIBRARY_DIR=${OpenCASCADE_LIBRARY_DIR}") 20 | endif() 21 | 22 | # compiler flags 23 | if (MSVC) 24 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:precise /EHa /MP") 25 | string (REGEX REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 26 | add_definitions (-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) 27 | else() 28 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -fPIC") 29 | add_definitions(-DOCC_CONVERT_SIGNALS) 30 | endif() 31 | 32 | if (APPLE) 33 | enable_language(OBJCXX) 34 | else() 35 | set_source_files_properties (OcctAisOffscreen.objc.mm PROPERTIES HEADER_FILE_ONLY TRUE) 36 | endif() 37 | 38 | add_executable (${APP_TARGET} 39 | OcctAisOffscreen.cpp OcctAisOffscreen.objc.mm ReadMe.md) 40 | 41 | # extra search paths 42 | include_directories(${OpenCASCADE_INCLUDE_DIR}) 43 | #link_directories (${OpenCASCADE_LIBRARY_DIR}) 44 | 45 | # define dependencies 46 | set (anOcctLibs TKOpenGl TKV3d TKService TKPrim TKTopAlgo TKGeomAlgo TKBRep TKGeomBase TKG3d TKG2d TKMath TKernel) 47 | target_link_libraries (${PROJECT_NAME} PRIVATE ${anOcctLibs}) 48 | 49 | target_link_libraries (${PROJECT_NAME} PRIVATE ${OPENGL_LIBRARIES}) 50 | if (APPLE) 51 | find_library (Appkit_LIB NAMES AppKit) 52 | target_link_libraries (${PROJECT_NAME} PRIVATE ${Appkit_LIB}) 53 | target_link_libraries (${PROJECT_NAME} PRIVATE objc) 54 | elseif (UNIX) 55 | target_link_libraries (${PROJECT_NAME} PRIVATE EGL) 56 | target_link_libraries (${PROJECT_NAME} PRIVATE X11) 57 | target_link_libraries (${PROJECT_NAME} PRIVATE dl) 58 | target_link_libraries (${PROJECT_NAME} PRIVATE pthread) 59 | endif() 60 | 61 | # auxiliary development environment 62 | if (MSVC) 63 | set (3RDPARTY_DLL_DIRS "" CACHE STRING "Paths to external DLLs separated by semicolon (FreeImage, FreeType, etc.)") 64 | 65 | get_target_property (aTKernelRel "TKernel" IMPORTED_LOCATION_RELEASE) 66 | get_target_property (aTKernelDbg "TKernel" IMPORTED_LOCATION_DEBUG) 67 | get_filename_component (OpenCASCADE_BINARY_DIR_RELEASE ${aTKernelRel} DIRECTORY) 68 | get_filename_component (OpenCASCADE_BINARY_DIR_DEBUG ${aTKernelDbg} DIRECTORY) 69 | if (NOT EXISTS "${OpenCASCADE_BINARY_DIR_DEBUG}" AND EXISTS "${OpenCASCADE_BINARY_DIR_RELEASE}") 70 | set (OpenCASCADE_BINARY_DIR_DEBUG "${OpenCASCADE_BINARY_DIR_RELEASE}") 71 | elseif (NOT EXISTS "${OpenCASCADE_BINARY_DIR_RELEASE}" AND EXISTS "${OpenCASCADE_BINARY_DIR_DEBUG}") 72 | set (OpenCASCADE_BINARY_DIR_RELEASE "${OpenCASCADE_BINARY_DIR_DEBUG}") 73 | endif() 74 | 75 | set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_ENVIRONMENT "PATH=%PATH%;$,${OpenCASCADE_BINARY_DIR_DEBUG},${OpenCASCADE_BINARY_DIR_RELEASE}>;${3RDPARTY_DLL_DIRS}") 76 | endif() 77 | -------------------------------------------------------------------------------- /occt-ais-offscreen/OcctAisOffscreen.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #include 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #ifdef _WIN32 22 | #include 23 | #include 24 | #elif defined(__APPLE__) 25 | #include 26 | #include 27 | #else 28 | #include 29 | #include 30 | #endif 31 | 32 | //! Sample offscreen viewer class. 33 | class OcctOffscreenViewer 34 | { 35 | public: 36 | 37 | //! Return view instance. 38 | const Handle(V3d_View)& View() const { return myView; } 39 | 40 | //! Return AIS context. 41 | const Handle(AIS_InteractiveContext)& Context() const { return myContext; } 42 | 43 | //! Initialize offscreen viewer. 44 | //! @param[in] theWinSize view dimensions 45 | //! @return FALSE in case of initialization error 46 | bool InitOffscreenViewer (const Graphic3d_Vec2i& theWinSize) 47 | { 48 | try 49 | { 50 | OCC_CATCH_SIGNALS 51 | 52 | // create graphic driver 53 | Handle(Aspect_DisplayConnection) aDispConnection = new Aspect_DisplayConnection(); 54 | Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver (aDispConnection, true); 55 | aDriver->ChangeOptions().ffpEnable = false; 56 | aDriver->ChangeOptions().swapInterval = 0; 57 | 58 | // create viewer and AIS context 59 | myViewer = new V3d_Viewer (aDriver); 60 | myContext = new AIS_InteractiveContext (myViewer); 61 | 62 | // light sources setup 63 | myViewer->SetDefaultLights(); 64 | myViewer->SetLightOn(); 65 | 66 | // create offscreen window 67 | const TCollection_AsciiString aWinName ("OCCT offscreen window"); 68 | #ifdef __ANDROID__ 69 | Handle(Aspect_NeutralWindow) aWindow = new Aspect_NeutralWindow(); 70 | aWindow->SetSize (theWinSize.x(), theWinSize.y()); 71 | #elif defined(_WIN32) 72 | const TCollection_AsciiString aClassName ("OffscreenClass"); 73 | Handle(WNT_WClass) aWinClass = new WNT_WClass (aClassName.ToCString(), NULL, 0); // empty callback! 74 | Handle(WNT_Window) aWindow = new WNT_Window (aWinName.ToCString(), aWinClass, 0x80000000L, //WS_POPUP, 75 | 64, 64, 64, 64, Quantity_NOC_BLACK); 76 | aWindow->SetVirtual (true); 77 | aWindow->SetPos (0, 0, theWinSize.x(), theWinSize.y()); 78 | #elif defined(__APPLE__) 79 | Handle(Cocoa_Window) aWindow = new Cocoa_Window (aWinName.ToCString(), 64, 64, theWinSize.x(), theWinSize.y()); 80 | #else 81 | Handle(Xw_Window) aWindow = new Xw_Window (aDispConnection, aWinName.ToCString(), 82 | 64, 64, theWinSize.x(), theWinSize.y()); 83 | #endif 84 | aWindow->SetVirtual (true); 85 | 86 | // create 3D view from offscreen window 87 | myView = new V3d_View (myViewer); 88 | myView->SetWindow (aWindow); 89 | } 90 | catch (const Standard_Failure& theErr) 91 | { 92 | Message::SendFail() << "Offscreen Viewer creation FAILED:\n" << theErr; 93 | return false; 94 | } 95 | return true; 96 | } 97 | 98 | //! Print information about graphics context. 99 | void DumpGlInfo() 100 | { 101 | TColStd_IndexedDataMapOfStringString aGlCapsDict; 102 | myView->DiagnosticInformation (aGlCapsDict, Graphic3d_DiagnosticInfo_Basic); 103 | TCollection_AsciiString anInfo = "OpenGL info:\n"; 104 | for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aGlCapsDict); aValueIter.More(); aValueIter.Next()) 105 | { 106 | if (!aValueIter.Value().IsEmpty()) 107 | { 108 | anInfo += TCollection_AsciiString(" ") + aValueIter.Key() + ": " + aValueIter.Value() + "\n"; 109 | } 110 | } 111 | Message::SendInfo (anInfo); 112 | } 113 | 114 | private: 115 | 116 | Handle(V3d_Viewer) myViewer; 117 | Handle(V3d_View) myView; 118 | Handle(AIS_InteractiveContext) myContext; 119 | 120 | }; 121 | 122 | #ifdef __APPLE__ 123 | void occtNSAppCreate(); // implemented in .mm file 124 | #endif 125 | 126 | int main(int argc, const char** argv) 127 | { 128 | OSD::SetSignal (false); 129 | 130 | #ifdef __APPLE__ 131 | occtNSAppCreate(); 132 | #endif 133 | 134 | // image dimensions 135 | Graphic3d_Vec2i aWinSize (1920, 1080); 136 | double aScaleRatio = 2.0; 137 | 138 | // create offsreen viewer 139 | OcctOffscreenViewer aViewer; 140 | if (!aViewer.InitOffscreenViewer (aWinSize)) 141 | { 142 | return 1; 143 | } 144 | 145 | // setup rendering parameters 146 | const Handle(V3d_View)& aView = aViewer.View(); 147 | Graphic3d_RenderingParams& aRendParams = aView->ChangeRenderingParams(); 148 | aRendParams.Resolution = (unsigned int )(96.0 * aScaleRatio + 0.5); // text resolution 149 | //aRendParams.NbMsaaSamples = 4; // MSAA 150 | aRendParams.RenderResolutionScale = 2.0f; // SSAA as alternative to MSAA 151 | aViewer.DumpGlInfo(); 152 | 153 | // display something 154 | aView->SetBackgroundColor (Quantity_NOC_BLACK); 155 | aView->TriedronDisplay (Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, aScaleRatio * 0.1); 156 | { 157 | const Handle(AIS_InteractiveContext)& aCtx = aViewer.Context(); 158 | const Handle(Prs3d_Drawer)& aDrawer = aCtx->DefaultDrawer(); 159 | aDrawer->ShadingAspect()->SetMaterial (Graphic3d_NameOfMaterial_Glass); 160 | aDrawer->SetFaceBoundaryDraw (true); 161 | 162 | TopoDS_Shape aShape = BRepPrimAPI_MakeCone (100, 10, 100).Solid(); 163 | Handle(AIS_InteractiveObject) aShapePrs = new AIS_Shape (aShape); 164 | aCtx->Display (aShapePrs, AIS_Shaded, -1, false); 165 | 166 | TopTools_IndexedMapOfShape anEdges; 167 | TopExp::MapShapes (aShape, TopAbs_EDGE, anEdges); 168 | for (TopTools_IndexedMapOfShape::Iterator anEdgeIter (anEdges); anEdgeIter.More(); anEdgeIter.Next()) 169 | { 170 | const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgeIter.Value()); 171 | Standard_Real aParRange[2] = {}; 172 | Handle(Geom_Curve) aCurve = BRep_Tool::Curve (anEdge, aParRange[0], aParRange[1]); 173 | if (Handle(Geom_Circle) aCircle = Handle(Geom_Circle)::DownCast (aCurve)) 174 | { 175 | Handle(PrsDim_DiameterDimension) aDiamDim = new PrsDim_DiameterDimension (anEdge); 176 | aDiamDim->SetFlyout (aCircle->Radius() + 20.0); 177 | aCtx->Display (aDiamDim, 0, -1, false); 178 | } 179 | else if (Handle(Geom_Line) aLine = Handle(Geom_Line)::DownCast (aCurve)) 180 | { 181 | gp_Pln aPln (aLine->Value (aParRange[0]), gp::DY()); 182 | Handle(PrsDim_LengthDimension) aLenDim = new PrsDim_LengthDimension (anEdge, aPln); 183 | aLenDim->SetFlyout (20.0); 184 | aCtx->Display (aLenDim, 0, -1, false); 185 | } 186 | } 187 | } 188 | 189 | // setup camera orientation 190 | aView->SetProj (V3d_TypeOfOrientation_Zup_AxoRight); 191 | aView->FitAll (0.01, false); 192 | 193 | // make a screenshot 194 | Image_AlienPixMap anImage; 195 | if (!aView->ToPixMap (anImage, aWinSize.x(), aWinSize.y())) 196 | { 197 | Message::SendFail() << "View dump FAILED"; 198 | return 1; 199 | } 200 | 201 | // save image to file 202 | const char* anImageName = "image.png"; 203 | if (!anImage.Save (anImageName)) 204 | { 205 | Message::SendFail() << "Unable to save image " << anImage.Width() << "x" << anImage.Height() << "@" << Image_PixMap::ImageFormatToString(anImage.Format()) 206 | << " into file '" << anImageName << "'"; 207 | return 1; 208 | } 209 | Message::SendInfo() << "Screenshot " << anImage.Width() << "x" << anImage.Height() << "@" << Image_PixMap::ImageFormatToString(anImage.Format()) 210 | << " saved into file '" << anImageName << "'"; 211 | 212 | // use default application to open image 213 | for (int anArgIter = 1; anArgIter < argc; ++anArgIter) 214 | { 215 | if (TCollection_AsciiString::IsSameString (argv[anArgIter], "-noopen", false)) 216 | { 217 | return 0; 218 | } 219 | } 220 | #if defined(_WIN32) 221 | ShellExecuteW(NULL, L"open", TCollection_ExtendedString(anImageName).ToWideString(), NULL, NULL, SW_SHOWNORMAL); 222 | #elif defined(__APPLE__) 223 | TCollection_AsciiString aCmd = TCollection_AsciiString("open ") + anImageName; 224 | std::system(aCmd.ToCString()); 225 | #elif defined(__linux__) 226 | // https://www.freedesktop.org/wiki/Software/xdg-utils/ 227 | TCollection_AsciiString aCmd = TCollection_AsciiString("xdg-open ") + anImageName; 228 | std::system(aCmd.ToCString()); 229 | #endif 230 | return 0; 231 | } 232 | -------------------------------------------------------------------------------- /occt-ais-offscreen/OcctAisOffscreen.objc.mm: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #include 4 | #include 5 | 6 | //! Main Cocoa application responder - minimal implementation for offscreen viewer. 7 | @interface OcctTestNSResponder : NSObject 8 | { 9 | } 10 | 11 | //! Default constructor. 12 | - (id ) init; 13 | 14 | //! Access singleton. 15 | + (OcctTestNSResponder* ) sharedInstance; 16 | 17 | //! Dummy method for thread-safety Cocoa initialization. 18 | + (void ) doDummyThread: (id )theParam; 19 | 20 | @end 21 | 22 | @implementation OcctTestNSResponder 23 | 24 | - (id )init 25 | { 26 | self = [super init]; 27 | return self; 28 | } 29 | 30 | // Singletone implementation 31 | + (OcctTestNSResponder* ) sharedInstance 32 | { 33 | static OcctTestNSResponder* TheAppResponder = [[super allocWithZone: nullptr] init]; 34 | return TheAppResponder; 35 | } 36 | + (id ) allocWithZone: (NSZone* )theZone { return [[self sharedInstance] retain]; } 37 | - (id ) copyWithZone: (NSZone* )theZone { return self; } 38 | - (id ) retain { return self; } 39 | - (NSUInteger ) retainCount { return NSUIntegerMax; } 40 | - (oneway void ) release {} 41 | - (id ) autorelease { return self; } 42 | 43 | - (BOOL ) application: (NSApplication* )theApplication openFile: (NSString* )theFilename { return YES; } 44 | - (void ) applicationDidFinishLaunching: (NSNotification* )theNotification {} 45 | - (void ) applicationWillTerminate: (NSNotification* )theNotification {} 46 | 47 | + (void ) doDummyThread: (id )theParam {} 48 | 49 | @end 50 | 51 | void occtNSAppCreate() 52 | { 53 | // create dummy NSThread to ensure Cocoa thread-safety 54 | [NSThread detachNewThreadSelector: @selector(doDummyThread: ) toTarget: [OcctTestNSResponder class] withObject: nullptr]; 55 | 56 | NSApplication* anAppNs = [NSApplication sharedApplication]; 57 | OcctTestNSResponder* anAppResp = [OcctTestNSResponder sharedInstance]; 58 | [anAppNs setDelegate: anAppResp]; 59 | //[anAppNs run]; // Cocoa event loop 60 | } 61 | -------------------------------------------------------------------------------- /occt-ais-offscreen/ReadMe.md: -------------------------------------------------------------------------------- 1 | Sample creates an offscreen instance of OCCT 3D Viewer for image dump purposes on Windows, Linux and macOS platforms.
2 | https://unlimited3d.wordpress.com/2022/01/30/offscreen-occt-viewer/ 3 | -------------------------------------------------------------------------------- /occt-draw-plugin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.13) 2 | 3 | project (occt-draw-plugin) 4 | 5 | set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../adm/cmake" ${CMAKE_MODULE_PATH}) 6 | 7 | set (APP_VERSION_MAJOR 1) 8 | set (APP_VERSION_MINOR 0) 9 | set (CMAKE_CXX_STANDARD 11) 10 | 11 | find_package (OpenCASCADE REQUIRED) 12 | if (NOT OpenCASCADE_FOUND) 13 | message (FATAL_ERROR "coult not find OpenCASCADE, please set OpenCASCADE_DIR variable" ) 14 | else() 15 | message (STATUS "Using OpenCASCADE from \"${OpenCASCADE_INSTALL_PREFIX}\"" ) 16 | message (STATUS "OpenCASCADE_INCLUDE_DIR=${OpenCASCADE_INCLUDE_DIR}") 17 | message (STATUS "OpenCASCADE_LIBRARY_DIR=${OpenCASCADE_LIBRARY_DIR}") 18 | endif() 19 | 20 | # compiler flags 21 | if (MSVC) 22 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:precise /EHa /MP") 23 | string (REGEX REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 24 | add_definitions (-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) 25 | else() 26 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -fPIC") 27 | add_definitions(-DOCC_CONVERT_SIGNALS) 28 | endif() 29 | 30 | add_library (${PROJECT_NAME} SHARED 31 | OcctDrawPlugin.cpp ReadMe.md) 32 | 33 | # extra search paths 34 | include_directories(${OpenCASCADE_INCLUDE_DIR}) 35 | 36 | # define dependencies 37 | set (anOcctLibs TKDraw TKV3d TKService TKPrim TKTopAlgo TKGeomAlgo TKBRep TKGeomBase TKG3d TKG2d TKMath TKernel) 38 | target_link_libraries (${PROJECT_NAME} PRIVATE ${anOcctLibs}) 39 | 40 | if (APPLE) 41 | target_link_libraries (${PROJECT_NAME} PRIVATE objc) 42 | elseif (UNIX) 43 | target_link_libraries (${PROJECT_NAME} PRIVATE dl) 44 | target_link_libraries (${PROJECT_NAME} PRIVATE pthread) 45 | endif() 46 | 47 | # auxiliary development environment 48 | if (MSVC) 49 | set (3RDPARTY_DLL_DIRS "" CACHE STRING "Paths to external DLLs separated by semicolon (FreeImage, FreeType, Tcl, etc.)") 50 | 51 | get_target_property (aTKernelRel "TKernel" IMPORTED_LOCATION_RELEASE) 52 | get_target_property (aTKernelDbg "TKernel" IMPORTED_LOCATION_DEBUG) 53 | get_filename_component (OpenCASCADE_BINARY_DIR_RELEASE ${aTKernelRel} DIRECTORY) 54 | get_filename_component (OpenCASCADE_BINARY_DIR_DEBUG ${aTKernelDbg} DIRECTORY) 55 | if (NOT EXISTS "${OpenCASCADE_BINARY_DIR_DEBUG}" AND EXISTS "${OpenCASCADE_BINARY_DIR_RELEASE}") 56 | set (OpenCASCADE_BINARY_DIR_DEBUG "${OpenCASCADE_BINARY_DIR_RELEASE}") 57 | elseif (NOT EXISTS "${OpenCASCADE_BINARY_DIR_RELEASE}" AND EXISTS "${OpenCASCADE_BINARY_DIR_DEBUG}") 58 | set (OpenCASCADE_BINARY_DIR_RELEASE "${OpenCASCADE_BINARY_DIR_DEBUG}") 59 | endif() 60 | 61 | # Visual Studio debugger environment 62 | set_target_properties(${PROJECT_NAME} PROPERTIES 63 | VS_DEBUGGER_ENVIRONMENT "\ 64 | PATH=%PATH%;$,${OpenCASCADE_BINARY_DIR_DEBUG},${OpenCASCADE_BINARY_DIR_RELEASE}>;${3RDPARTY_DLL_DIRS}\n\ 65 | CSF_MYDrawTestDefaults=${CMAKE_CURRENT_SOURCE_DIR}\n\ 66 | CSF_TestScriptsPath=${CMAKE_CURRENT_SOURCE_DIR}/tests\n\ 67 | CSF_TestDataPath=${CMAKE_CURRENT_SOURCE_DIR}/../models" 68 | VS_DEBUGGER_COMMAND "$,${OpenCASCADE_BINARY_DIR_DEBUG},${OpenCASCADE_BINARY_DIR_RELEASE}>/DRAWEXE.exe" 69 | VS_DEBUGGER_COMMAND_ARGUMENTS "-i -c dputs {pload -MYDrawTest};pload -MYDrawTest" 70 | VS_DEBUGGER_WORKING_DIRECTORY "$" 71 | ) 72 | 73 | # batch script file running DRAWEXE from make folder 74 | configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/cmake/occt-draw-release.bat.in" "${CMAKE_CURRENT_BINARY_DIR}/draw-release.bat" @ONLY) 75 | configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/cmake/occt-draw-debug.bat.in" "${CMAKE_CURRENT_BINARY_DIR}/draw-debug.bat" @ONLY) 76 | else() 77 | # batch script file running DRAWEXE from make folder 78 | configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/cmake/occt-draw.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/draw.sh" @ONLY 79 | FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) 80 | endif() 81 | -------------------------------------------------------------------------------- /occt-draw-plugin/MYDrawTest: -------------------------------------------------------------------------------- 1 | ! Hierarchy of plug-ins 2 | ALL : MYDRAWTEST 3 | DEFAULT : MYDRAWTEST 4 | 5 | ! Mapping from naming to toolkits (libraries) 6 | MYDRAWTEST : occt-draw-plugin 7 | -------------------------------------------------------------------------------- /occt-draw-plugin/OcctDrawPlugin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | //! Class defining static method 'Factory()' for 'DPLUGIN' macros. 9 | class OcctDrawPlugin 10 | { 11 | public: 12 | DEFINE_STANDARD_ALLOC 13 | 14 | //! Add commands to Draw_Interpretor. 15 | static void Factory (Draw_Interpretor& theDI); 16 | }; 17 | 18 | //! Command just printing "hello" message. 19 | static int myhello (Draw_Interpretor& theDI, 20 | int theNbArgs, const char** theArgVec) 21 | { 22 | if (theNbArgs != 1) 23 | { 24 | theDI << "Syntax error - wrong number of arguments"; 25 | return 1; // throw Tcl exception 26 | } 27 | 28 | // std::cout/std::cerr will appear in terminal, 29 | // but will be inaccessible to Tcl 30 | std::cout << "standard output\n"; 31 | 32 | // first argument equals to command name, e.g. "myhello" 33 | std::cout << "command '" << theArgVec[0] << "'\n"; 34 | 35 | // output to theDI will be accessible to Tcl 36 | theDI << "HELLO"; 37 | return 0; // normal result 38 | } 39 | 40 | //! A dummy drawable object. 41 | class MyDummyDrawable : public Draw_Drawable3D 42 | { 43 | DEFINE_STANDARD_RTTI_INLINE(MyDummyDrawable, Draw_Drawable3D) 44 | public: 45 | MyDummyDrawable() {} 46 | 47 | //! Draw object in axonometric viewer - not implemented. 48 | virtual void DrawOn (Draw_Display& theDisp) const override { (void )theDisp; } 49 | 50 | //! Variable dump. 51 | virtual void Dump (Standard_OStream& theStream) const override { theStream << "MyDummyDrawable dump"; } 52 | 53 | //! For whatis command. 54 | virtual void Whatis (Draw_Interpretor& theDI) const override { theDI << "MyDummyDrawable"; } 55 | }; 56 | 57 | //! Command working with drawables. 58 | static int mydrawable (Draw_Interpretor& theDI, 59 | int theNbArgs, const char** theArgVec) 60 | { 61 | Handle(Draw_Drawable3D) aDrawable; 62 | TCollection_AsciiString aName; 63 | for (int anArgIter = 1; anArgIter < theNbArgs; ++anArgIter) 64 | { 65 | TCollection_AsciiString anArg (theArgVec[anArgIter]); 66 | anArg.LowerCase(); 67 | if (anArg == "-create" 68 | && aDrawable.IsNull()) 69 | { 70 | aDrawable = new MyDummyDrawable(); 71 | } 72 | else if (aName.IsEmpty()) 73 | { 74 | aName = theArgVec[anArgIter]; 75 | } 76 | else 77 | { 78 | theDI << "Syntax error at '" << theArgVec[anArgIter] << "'"; 79 | return 1; 80 | } 81 | } 82 | if (aName.IsEmpty()) 83 | { 84 | theDI << "Syntax error: wrong number of arguments"; 85 | return 1; 86 | } 87 | 88 | if (aDrawable.IsNull()) 89 | { 90 | // get existing drawable 91 | const char* aNameStr = aName.ToCString(); 92 | aDrawable = Draw::Get (aNameStr); 93 | if (aDrawable.IsNull()) 94 | { 95 | theDI << "Error: drawable '" << aName << "' not found"; 96 | return 1; 97 | } 98 | } 99 | 100 | // print some basic info 101 | theDI << "DynamicType: " << aDrawable->DynamicType()->Name(); 102 | Draw::Set (aName.ToCString(), aDrawable); 103 | 104 | // try handling subclasses 105 | if (Handle(MyDummyDrawable) aMyDraw = Handle(MyDummyDrawable)::DownCast (aDrawable)) 106 | { 107 | theDI << "\nIt is my drawable!"; 108 | } 109 | if (Handle(DBRep_DrawableShape) aDrawShape = Handle(DBRep_DrawableShape)::DownCast (aDrawable)) 110 | { 111 | const TopoDS_Shape& aShape = aDrawShape->Shape(); 112 | theDI << "\nShapeType: " << TopAbs::ShapeTypeToString (aShape.ShapeType()); 113 | } 114 | 115 | return 0; 116 | } 117 | 118 | // Add commands to Draw_Interpretor. 119 | void OcctDrawPlugin::Factory (Draw_Interpretor& theDI) 120 | { 121 | // just some welcome message 122 | Message::SendInfo() << "Loading 'occt-draw-plugin'...\n" 123 | "Tip1: print 'help my*' to list commands defined by this plugin.\n" 124 | "Tip2: print 'testgrid' to run tests."; 125 | 126 | // register commands with description that could be retrieved via 'help CommandName' 127 | const char* aGroup = "My draw commands"; 128 | theDI.Add ("myhello", "myhello - hello draw", 129 | __FILE__, myhello, aGroup); 130 | 131 | theDI.Add ("mydrawable", "mydrawable name [-create]", 132 | __FILE__, mydrawable, aGroup); 133 | } 134 | 135 | // Implement exported function that will be called by DRAWEXE on loading plugin 136 | DPLUGIN(OcctDrawPlugin); 137 | -------------------------------------------------------------------------------- /occt-draw-plugin/ReadMe.md: -------------------------------------------------------------------------------- 1 | Sample defines a Draw Harness plugin - a library dynamically loaded by DRAWEXE application and exposing command to Tcl shell.
2 | -------------------------------------------------------------------------------- /occt-draw-plugin/cmake/occt-draw-debug.bat.in: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | 3 | rem Script to setup environment for running DRAWEXE with custom plugin 4 | 5 | set "PATH=@OpenCASCADE_BINARY_DIR_DEBUG@;@3RDPARTY_DLL_DIRS@;%PATH%" 6 | set "CSF_MYDrawTestDefaults=@CMAKE_CURRENT_SOURCE_DIR@" 7 | set "CSF_TestScriptsPath=@CMAKE_CURRENT_SOURCE_DIR@/tests" 8 | set "CSF_TestDataPath=@CMAKE_CURRENT_SOURCE_DIR@/../models" 9 | 10 | pushd "%~dp0Debug" 11 | "@OpenCASCADE_BINARY_DIR_DEBUG@/DRAWEXE@CMAKE_EXECUTABLE_SUFFIX@" -i -c dputs {pload -MYDrawTest}; pload -MYDrawTest 12 | popd 13 | -------------------------------------------------------------------------------- /occt-draw-plugin/cmake/occt-draw-release.bat.in: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | 3 | rem Script to setup environment for running DRAWEXE with custom plugin 4 | 5 | set "PATH=@OpenCASCADE_BINARY_DIR_RELEASE@;@3RDPARTY_DLL_DIRS@;%PATH%" 6 | set "CSF_MYDrawTestDefaults=@CMAKE_CURRENT_SOURCE_DIR@" 7 | set "CSF_TestScriptsPath=@CMAKE_CURRENT_SOURCE_DIR@/tests" 8 | set "CSF_TestDataPath=@CMAKE_CURRENT_SOURCE_DIR@/../models" 9 | 10 | pushd "%~dp0Release" 11 | "@OpenCASCADE_BINARY_DIR_RELEASE@/DRAWEXE@CMAKE_EXECUTABLE_SUFFIX@" -i -c dputs {pload -MYDrawTest}; pload -MYDrawTest 12 | popd 13 | -------------------------------------------------------------------------------- /occt-draw-plugin/cmake/occt-draw.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to setup environment for running DRAWEXE with custom plugin 4 | if [[ "$OSTYPE" == "darwin"* ]]; then 5 | export DYLD_LIBRARY_PATH="@CMAKE_CURRENT_BINARY_DIR@:@OpenCASCADE_LIBRARY_DIR@:$DYLD_LIBRARY_PATH" 6 | else 7 | export LD_LIBRARY_PATH="@CMAKE_CURRENT_BINARY_DIR@:@OpenCASCADE_LIBRARY_DIR@:$LD_LIBRARY_PATH" 8 | fi 9 | export CSF_MYDrawTestDefaults="@CMAKE_CURRENT_SOURCE_DIR@" 10 | export CSF_TestScriptsPath="@CMAKE_CURRENT_SOURCE_DIR@/tests" 11 | export CSF_TestDataPath="@CMAKE_CURRENT_SOURCE_DIR@/../models" 12 | 13 | if [[ -x "@OpenCASCADE_BINARY_DIR@/DRAWEXE" ]]; then 14 | "@OpenCASCADE_BINARY_DIR@/DRAWEXE" -i -c "dputs {pload -MYDrawTest}; pload -MYDrawTest" 15 | elif [[ -x "@OpenCASCADE_BINARY_DIR@/occt-draw" ]]; then 16 | "@OpenCASCADE_BINARY_DIR@/occt-draw" -i -c "dputs {pload -MYDrawTest}; pload -MYDrawTest" 17 | else 18 | echo "Error: @OpenCASCADE_BINARY_DIR@/DRAWEXE not found" 19 | fi 20 | 21 | -------------------------------------------------------------------------------- /occt-draw-plugin/tests/grid1/begin: -------------------------------------------------------------------------------- 1 | # 'begin' defines Tcl code shared between tests in this grid and included at the beginning of each test case 2 | 3 | # kill process on exceeding time limit (due to infinity loop or similar bugs) 4 | cpulimit 1000 5 | -------------------------------------------------------------------------------- /occt-draw-plugin/tests/grid1/end: -------------------------------------------------------------------------------- 1 | # 'end' defines Tcl code shared between tests in this grid and included at the end of each test case; 2 | # a good place to perform clean up like deletion of temporary files 3 | 4 | # test will be considered FAILED if the following output will not be found in the log 5 | puts "TEST COMPLETED" 6 | -------------------------------------------------------------------------------- /occt-draw-plugin/tests/grid1/grids.list: -------------------------------------------------------------------------------- 1 | 001 subgrid1 2 | 001 subgrid2 3 | -------------------------------------------------------------------------------- /occt-draw-plugin/tests/grid1/parse.rules: -------------------------------------------------------------------------------- 1 | FAILED /\bFaulty\b/ error 2 | -------------------------------------------------------------------------------- /occt-draw-plugin/tests/grid1/subgrid1/begin: -------------------------------------------------------------------------------- 1 | # 'begin' defines Tcl code shared between tests in this subgrid and included at the beginning of each test case 2 | -------------------------------------------------------------------------------- /occt-draw-plugin/tests/grid1/subgrid1/hello: -------------------------------------------------------------------------------- 1 | # load our custom plugin 2 | pload -MYDrawTest 3 | 4 | # execute out test command and put result into variable 'aRes' 5 | set aRes [myhello] 6 | 7 | # verify returned string and print error on failure 8 | if { "$aRes" != "HELLO" } { puts "Error: myhello doesn't work" } 9 | -------------------------------------------------------------------------------- /occt-draw-plugin/tests/grid1/subgrid2/nodata: -------------------------------------------------------------------------------- 1 | pload MODELING VISUALIZATION 2 | 3 | # look for a file; will emit exception if file will be not found within CSF_TestDataPath folders 4 | set aTestFile [locate_data_file "NonExistingFile.brep"] 5 | 6 | restore $aTestFile b 7 | nbshapes b 8 | -------------------------------------------------------------------------------- /occt-draw-plugin/tests/parse.rules: -------------------------------------------------------------------------------- 1 | SKIPPED /Tcl Exception: .*[fF]ile .* could not be found/ data file is missing 2 | SKIPPED /Tcl Exception: Skipping testgrid/ workstation is not configured for testgrid 3 | IGNORE /Tcl Exception: [*][*] Exception [*][*]/ duplicate report on exception on Tcl level 4 | IGNORE /Relative error of mass computation :/ diagnostic message of *props* commands 5 | FAILED /\b[Ee]xception\b/ exception 6 | FAILED /\b[Ee][Rr][Rr][Oo][Rr]\b/ error 7 | FAILED /\b[Ff][Aa][Ii][Ll][0-9]\b/ error 8 | FAILED /\b[Ff][Aa][Ii][Ll][Ee][Dd]\b/ error 9 | FAILED /\b[Ff][Aa][Ii][Ll][Uu][Rr][Ee]\b/ error 10 | FAILED /Process killed by CPU limit/ Killed by CPU limit 11 | FAILED /Process killed by elapsed limit/ Killed by elapsed time limit 12 | -------------------------------------------------------------------------------- /occt-xcaf-shape/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.13) 2 | 3 | project (occt-xcaf-shape) 4 | 5 | set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../adm/cmake" ${CMAKE_MODULE_PATH}) 6 | 7 | set (APP_VERSION_MAJOR 1) 8 | set (APP_VERSION_MINOR 0) 9 | set (APP_TARGET occt-xcaf-shape) 10 | set (CMAKE_CXX_STANDARD 11) 11 | 12 | find_package (OpenGL REQUIRED) 13 | find_package (OpenCASCADE REQUIRED) 14 | if (NOT OpenCASCADE_FOUND) 15 | message (FATAL_ERROR "could not find OpenCASCADE, please set OpenCASCADE_DIR variable" ) 16 | else() 17 | message (STATUS "Using OpenCASCADE from \"${OpenCASCADE_INSTALL_PREFIX}\"" ) 18 | message (STATUS "OpenCASCADE_INCLUDE_DIR=${OpenCASCADE_INCLUDE_DIR}") 19 | message (STATUS "OpenCASCADE_LIBRARY_DIR=${OpenCASCADE_LIBRARY_DIR}") 20 | endif() 21 | 22 | # compiler flags 23 | if (MSVC) 24 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:precise /EHa /MP") 25 | string (REGEX REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 26 | add_definitions (-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) 27 | else() 28 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -fPIC") 29 | add_definitions(-DOCC_CONVERT_SIGNALS) 30 | endif() 31 | 32 | add_executable (${APP_TARGET} 33 | OcctXCafShape.cpp ReadMe.md) 34 | 35 | # extra search paths 36 | include_directories(${OpenCASCADE_INCLUDE_DIR}) 37 | #link_directories (${OpenCASCADE_LIBRARY_DIR}) 38 | 39 | # define dependencies 40 | set (anOcctLibs 41 | TKXDESTEP TKSTEP TKSTEPAttr TKSTEP209 TKSTEPBase TKXSBase 42 | TKRWMesh TKBinXCAF TKBin TKBinL TKXCAF TKVCAF TKCAF TKLCAF 43 | TKOpenGl TKV3d TKService TKPrim TKTopAlgo TKGeomAlgo TKBRep TKGeomBase TKG3d TKG2d TKMath TKernel) 44 | target_link_libraries (${PROJECT_NAME} PRIVATE ${anOcctLibs}) 45 | 46 | target_link_libraries (${PROJECT_NAME} PRIVATE ${OPENGL_LIBRARIES}) 47 | if (APPLE) 48 | find_library (Appkit_LIB NAMES AppKit) 49 | target_link_libraries (${PROJECT_NAME} PRIVATE ${Appkit_LIB}) 50 | target_link_libraries (${PROJECT_NAME} PRIVATE objc) 51 | elseif (UNIX) 52 | target_link_libraries (${PROJECT_NAME} PRIVATE EGL) 53 | target_link_libraries (${PROJECT_NAME} PRIVATE X11) 54 | target_link_libraries (${PROJECT_NAME} PRIVATE dl) 55 | target_link_libraries (${PROJECT_NAME} PRIVATE pthread) 56 | endif() 57 | 58 | # auxiliary development environment 59 | if (MSVC) 60 | set (3RDPARTY_DLL_DIRS "" CACHE STRING "Paths to external DLLs separated by semicolon (FreeImage, FreeType, etc.)") 61 | 62 | get_target_property (aTKernelRel "TKernel" IMPORTED_LOCATION_RELEASE) 63 | get_target_property (aTKernelDbg "TKernel" IMPORTED_LOCATION_DEBUG) 64 | get_filename_component (OpenCASCADE_BINARY_DIR_RELEASE ${aTKernelRel} DIRECTORY) 65 | get_filename_component (OpenCASCADE_BINARY_DIR_DEBUG ${aTKernelDbg} DIRECTORY) 66 | if (NOT EXISTS "${OpenCASCADE_BINARY_DIR_DEBUG}" AND EXISTS "${OpenCASCADE_BINARY_DIR_RELEASE}") 67 | set (OpenCASCADE_BINARY_DIR_DEBUG "${OpenCASCADE_BINARY_DIR_RELEASE}") 68 | elseif (NOT EXISTS "${OpenCASCADE_BINARY_DIR_RELEASE}" AND EXISTS "${OpenCASCADE_BINARY_DIR_DEBUG}") 69 | set (OpenCASCADE_BINARY_DIR_RELEASE "${OpenCASCADE_BINARY_DIR_DEBUG}") 70 | endif() 71 | 72 | set_target_properties(${PROJECT_NAME} PROPERTIES 73 | VS_DEBUGGER_ENVIRONMENT "\ 74 | PATH=%PATH%;$,${OpenCASCADE_BINARY_DIR_DEBUG},${OpenCASCADE_BINARY_DIR_RELEASE}>;${3RDPARTY_DLL_DIRS}\n\ 75 | SAMPLE_MODELS_DIR=${CMAKE_CURRENT_SOURCE_DIR}/../models" 76 | ) 77 | endif() 78 | -------------------------------------------------------------------------------- /occt-xcaf-shape/OcctXCafShape.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #include 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef _WIN32 15 | #include 16 | #include 17 | #elif defined(__APPLE__) 18 | #include 19 | #else 20 | #include 21 | #include 22 | #endif 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | //! Sample single-window viewer class. 37 | class MyViewer : public AIS_ViewController 38 | { 39 | public: 40 | //! Main constructor. 41 | MyViewer() 42 | { 43 | // graphic driver setup 44 | Handle(Aspect_DisplayConnection) aDisplay = new Aspect_DisplayConnection(); 45 | Handle(Graphic3d_GraphicDriver) aDriver = new OpenGl_GraphicDriver (aDisplay); 46 | 47 | // viewer setup 48 | Handle(V3d_Viewer) aViewer = new V3d_Viewer (aDriver); 49 | aViewer->SetDefaultLights(); 50 | aViewer->SetLightOn(); 51 | 52 | // view setup 53 | myView = new V3d_View (aViewer); 54 | #ifdef _WIN32 55 | const TCollection_AsciiString aClassName ("MyWinClass"); 56 | Handle(WNT_WClass) aWinClass = new WNT_WClass (aClassName.ToCString(), &windowProcWrapper, 57 | CS_VREDRAW | CS_HREDRAW, 0, 0, 58 | ::LoadCursor (NULL, IDC_ARROW)); 59 | Handle(WNT_Window) aWindow = new WNT_Window ("OCCT Viewer - XCAF shape", aWinClass, WS_OVERLAPPEDWINDOW, 60 | 100, 100, 512, 512, Quantity_NOC_BLACK); 61 | ::SetWindowLongPtrW ((HWND )aWindow->NativeHandle(), GWLP_USERDATA, (LONG_PTR )this); 62 | #elif defined(__APPLE__) 63 | Handle(Cocoa_Window) aWindow = new Cocoa_Window ( "OCCT Viewer", 100, 100, 512, 512); 64 | #else 65 | Handle(Xw_Window) aWindow = new Xw_Window (aDisplay, "OCCT Viewer - XCAF shape", 100, 100, 512, 512); 66 | Display* anXDisplay = (Display* )aDisplay->GetDisplayAspect(); 67 | XSelectInput (anXDisplay, (Window )aWindow->NativeHandle(), 68 | ExposureMask | KeyPressMask | KeyReleaseMask | FocusChangeMask | StructureNotifyMask 69 | | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | Button1MotionMask | Button2MotionMask | Button3MotionMask); 70 | Atom aDelWinAtom = aDisplay->GetAtom (Aspect_XA_DELETE_WINDOW); 71 | XSetWMProtocols (anXDisplay, (Window )aWindow->NativeHandle(), &aDelWinAtom, 1); 72 | #endif 73 | myView->SetWindow (aWindow); 74 | myView->SetBackgroundColor (Quantity_NOC_GRAY50); 75 | myView->TriedronDisplay (Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, 0.1); 76 | myView->ChangeRenderingParams().RenderResolutionScale = 2.0f; 77 | 78 | // interactive context and demo scene 79 | myContext = new AIS_InteractiveContext (aViewer); 80 | 81 | aWindow->Map(); 82 | myView->Redraw(); 83 | } 84 | 85 | //! Return context. 86 | const Handle(AIS_InteractiveContext)& Context() const { return myContext; } 87 | 88 | //! Return view. 89 | const Handle(V3d_View)& View() const { return myView; } 90 | 91 | public: 92 | 93 | //! Save XBF file. 94 | bool SaveXBF (const TCollection_AsciiString& theFilePath) 95 | { 96 | if (myXdeDoc.IsNull()) { return false; } 97 | const PCDM_StoreStatus aStatus = myXdeApp->SaveAs (myXdeDoc, TCollection_ExtendedString (theFilePath)); 98 | if (aStatus != PCDM_SS_OK) 99 | { 100 | Message::SendFail() << "Error occurred during XBF export: " << (int )aStatus << ".\n" << theFilePath; 101 | return false; 102 | } 103 | return true; 104 | } 105 | 106 | //! Open XBF file. 107 | bool OpenXBF (const TCollection_AsciiString& theFilePath) 108 | { 109 | // create an empty XCAF document 110 | createXCAFApp(); 111 | newDocument(); 112 | 113 | const PCDM_ReaderStatus aReaderStatus = myXdeApp->Open (theFilePath, myXdeDoc); 114 | if (aReaderStatus != PCDM_RS_OK) 115 | { 116 | Message::SendFail() << "Error occurred during XBF import: " << (int )aReaderStatus << ".\n" << theFilePath; 117 | return false; 118 | } 119 | return true; 120 | } 121 | 122 | //! Open STEP file. 123 | bool OpenSTEP (const TCollection_AsciiString& theFilePath) 124 | { 125 | // create an empty XCAF document 126 | createXCAFApp(); 127 | newDocument(); 128 | 129 | // initialize STEP reader parameters 130 | STEPCAFControl_Controller::Init(); 131 | STEPControl_Controller::Init(); 132 | 133 | // read and translate STEP file into XCAF document 134 | STEPCAFControl_Reader aReader; 135 | OSD_Timer aTimer; 136 | aTimer.Start(); 137 | try 138 | { 139 | if (aReader.ReadFile (theFilePath.ToCString()) != IFSelect_RetDone) // read model from file 140 | { 141 | Message::SendFail() << "Error occurred reading STEP file\n" << theFilePath; 142 | return false; 143 | } 144 | if (!aReader.Transfer (myXdeDoc)) // translate model into document 145 | { 146 | Message::SendFail() << "Error occurred transferring STEP file\n" << theFilePath; 147 | return false; 148 | } 149 | 150 | Message::SendInfo() << "File '" << theFilePath << "' opened in " << aTimer.ElapsedTime() << " s"; 151 | } 152 | catch (Standard_Failure const& theFailure) 153 | { 154 | Message::SendFail() << "Exception raised during STEP import\n[" << theFailure.GetMessageString() << "]\n" << theFilePath; 155 | return false; 156 | } 157 | return true; 158 | } 159 | 160 | //! Dump XCAF document tree. 161 | void DumpXCafDocumentTree() 162 | { 163 | if (myXdeDoc.IsNull()) { return; } 164 | for (XCAFPrs_DocumentExplorer aDocExp (myXdeDoc, XCAFPrs_DocumentExplorerFlags_None); aDocExp.More(); aDocExp.Next()) 165 | { 166 | //std::cout << aDocExp.Current().Id << "\n"; 167 | //std::cout << getXCafNodePathNames (aDocExp, false, 0) << "\n"; 168 | 169 | TCollection_AsciiString aName = getXCafNodePathNames (aDocExp, false, aDocExp.CurrentDepth()); 170 | aName = TCollection_AsciiString (aDocExp.CurrentDepth() * 2, ' ') + aName; 171 | std::cout << aName << "\n"; 172 | } 173 | std::cout << "\n"; 174 | } 175 | 176 | //! Display XCAF document within AIS context. 177 | void DisplayXCafDocument (bool theToExplode) 178 | { 179 | if (myXdeDoc.IsNull()) { return; } 180 | for (XCAFPrs_DocumentExplorer aDocExp (myXdeDoc, XCAFPrs_DocumentExplorerFlags_None); aDocExp.More(); aDocExp.Next()) 181 | { 182 | const XCAFPrs_DocumentNode& aNode = aDocExp.Current(); 183 | if (theToExplode) 184 | { 185 | if (aNode.IsAssembly) { continue; } // handle only leaves 186 | } 187 | else 188 | { 189 | if (aDocExp.CurrentDepth() != 0) { continue; } // handle only roots 190 | } 191 | 192 | Handle(XCAFPrs_AISObject) aPrs = new XCAFPrs_AISObject (aNode.RefLabel); 193 | if (!aNode.Location.IsIdentity()) { aPrs->SetLocalTransformation (aNode.Location); } 194 | 195 | // AIS object's owner is an application-owned property; it is set to string object in this sample 196 | aPrs->SetOwner (new TCollection_HAsciiString (aNode.Id)); 197 | 198 | myContext->Display (aPrs, AIS_Shaded, 0, false); 199 | } 200 | 201 | myView->FitAll (0.01, false); 202 | AIS_ViewController::ProcessExpose(); 203 | } 204 | 205 | private: 206 | 207 | //! Create XCAF application instance. 208 | bool createXCAFApp() 209 | { 210 | if (!myXdeApp.IsNull()) { return true; } 211 | try 212 | { 213 | OCC_CATCH_SIGNALS 214 | myXdeApp = new TDocStd_Application(); 215 | //XmlXCAFDrivers::DefineFormat (myXdeApp); // to load XML files 216 | BinXCAFDrivers::DefineFormat (myXdeApp); // to load XBF files 217 | return true; 218 | } 219 | catch (Standard_Failure const& theFailure) 220 | { 221 | Message::SendFail() << "Error in creating XCAF application " << theFailure.GetMessageString(); 222 | return false; 223 | } 224 | } 225 | 226 | //! Create new document. 227 | void newDocument() 228 | { 229 | // close old document 230 | if (!myXdeDoc.IsNull()) 231 | { 232 | if (myXdeDoc->HasOpenCommand()) { myXdeDoc->AbortCommand(); } 233 | myXdeDoc->Main().Root().ForgetAllAttributes (true); 234 | myXdeApp->Close (myXdeDoc); 235 | myXdeDoc.Nullify(); 236 | } 237 | 238 | // create new document 239 | if (!myXdeApp.IsNull()) { myXdeApp->NewDocument (TCollection_ExtendedString ("BinXCAF"), myXdeDoc); } 240 | if (!myXdeDoc.IsNull()) { myXdeDoc->SetUndoLimit(10); } // set the maximum number of available "undo" actions 241 | } 242 | 243 | //! Format XCAF node's name(s) starting from parent to leaf. 244 | static TCollection_AsciiString getXCafNodePathNames (const XCAFPrs_DocumentExplorer& theExp, 245 | const bool theIsInstanceName, 246 | const int theLowerDepth = 0) 247 | { 248 | TCollection_AsciiString aPath; 249 | for (int aDepth = theLowerDepth; aDepth <= theExp.CurrentDepth(); ++aDepth) 250 | { 251 | const XCAFPrs_DocumentNode& aNode = theExp.Current (aDepth); 252 | TCollection_AsciiString aName; 253 | Handle(TDataStd_Name) aNodeName; 254 | if (theIsInstanceName) 255 | { 256 | if (aNode.Label.FindAttribute (TDataStd_Name::GetID(), aNodeName)) 257 | { 258 | aName = aNodeName->Get(); 259 | } 260 | } 261 | else 262 | { 263 | if (aNode.RefLabel.FindAttribute (TDataStd_Name::GetID(), aNodeName)) 264 | { 265 | aName = aNodeName->Get(); 266 | } 267 | } 268 | 269 | if (aName.IsEmpty()) { TDF_Tool::Entry (aNode.Label, aName); } 270 | if (aNode.IsAssembly) { aName += "/"; } 271 | aPath += aName; 272 | } 273 | return aPath; 274 | } 275 | 276 | private: 277 | 278 | //! Print some information about selected object. 279 | virtual void OnSelectionChanged (const Handle(AIS_InteractiveContext)& theCtx, 280 | const Handle(V3d_View)& theView) override 281 | { 282 | for (const Handle(SelectMgr_EntityOwner)& aSelIter : theCtx->Selection()->Objects()) 283 | { 284 | Handle(XCAFPrs_AISObject) anXCafPrs = Handle(XCAFPrs_AISObject)::DownCast (aSelIter->Selectable()); 285 | if (anXCafPrs.IsNull()) { continue; } 286 | 287 | { 288 | // AIS object's owner is an application-owned property; it is set to string object in this sample 289 | Handle(TCollection_HAsciiString) anId = Handle(TCollection_HAsciiString)::DownCast (anXCafPrs->GetOwner()); 290 | std::cout << "Selected Id: '" << (!anId.IsNull() ? anId->String() : "") << "'\n"; 291 | } 292 | 293 | { 294 | Handle(TDataStd_Name) aNodeName; 295 | if (anXCafPrs->GetLabel().FindAttribute (TDataStd_Name::GetID(), aNodeName)) 296 | { 297 | std::cout << " Name: '" << aNodeName->Get() << "'\n"; 298 | } 299 | } 300 | 301 | { 302 | // print information on colored subshapes 303 | TopLoc_Location aLoc; 304 | XCAFPrs_IndexedDataMapOfShapeStyle aStyles; 305 | XCAFPrs::CollectStyleSettings (anXCafPrs->GetLabel(), aLoc, aStyles); 306 | NCollection_Map aColorFilter; 307 | std::cout << " Colors:"; 308 | for (XCAFPrs_IndexedDataMapOfShapeStyle::Iterator aStyleIter (aStyles); aStyleIter.More(); aStyleIter.Next()) 309 | { 310 | const XCAFPrs_Style& aStyle = aStyleIter.Value(); 311 | if (aStyle.IsSetColorSurf() 312 | && aColorFilter.Add (aStyle.GetColorSurfRGBA())) 313 | { 314 | std::cout << " " << Quantity_ColorRGBA::ColorToHex (aStyle.GetColorSurfRGBA()); 315 | } 316 | } 317 | std::cout << "\n"; 318 | } 319 | } 320 | } 321 | 322 | //! Handle expose event. 323 | virtual void ProcessExpose() override 324 | { 325 | if (!myView.IsNull()) 326 | { 327 | FlushViewEvents (myContext, myView, true); 328 | } 329 | } 330 | 331 | //! Handle window resize event. 332 | virtual void ProcessConfigure (bool theIsResized) override 333 | { 334 | if (!myView.IsNull() && theIsResized) 335 | { 336 | myView->Window()->DoResize(); 337 | myView->MustBeResized(); 338 | myView->Invalidate(); 339 | FlushViewEvents (myContext, myView, true); 340 | } 341 | } 342 | 343 | //! Handle input. 344 | virtual void ProcessInput() override 345 | { 346 | if (!myView.IsNull()) 347 | { 348 | ProcessExpose(); 349 | } 350 | } 351 | 352 | #ifdef _WIN32 353 | //! Window message handler. 354 | static LRESULT WINAPI windowProcWrapper (HWND theWnd, UINT theMsg, WPARAM theParamW, LPARAM theParamL) 355 | { 356 | if (theMsg == WM_CLOSE) 357 | { 358 | exit (0); 359 | return 0; 360 | } 361 | 362 | if (MyViewer* aThis = (MyViewer* )::GetWindowLongPtrW (theWnd, GWLP_USERDATA)) 363 | { 364 | WNT_Window* aWindow = dynamic_cast(aThis->myView->Window().get()); 365 | MSG aMsg = { theWnd, theMsg, theParamW, theParamL }; 366 | if (aWindow->ProcessMessage (*aThis, aMsg)) 367 | { 368 | return 0; 369 | } 370 | } 371 | return ::DefWindowProcW (theWnd, theMsg, theParamW, theParamL); 372 | } 373 | #endif 374 | private: 375 | 376 | Handle(AIS_InteractiveContext) myContext; //!< AIS viewer interactive context 377 | Handle(V3d_View) myView; //!< AIS view (window) 378 | 379 | Handle(TDocStd_Application) myXdeApp; //!< XDE application instance 380 | Handle(TDocStd_Document) myXdeDoc; //!< XDE document instance 381 | }; 382 | 383 | //! Fill in array of program arguments. 384 | static void fillAppArguments (std::vector& theArgsOut, 385 | int theNbArgs, char** theArgVec) 386 | { 387 | #if defined(_WIN32) 388 | // fetch arguments using UNICODE interface 389 | (void )theNbArgs; (void )theArgVec; 390 | int aNbArgs = 0; 391 | wchar_t** anArgVecW = ::CommandLineToArgvW (GetCommandLineW(), &aNbArgs); 392 | for (int anArgIter = 0; anArgIter < aNbArgs; ++anArgIter) 393 | { 394 | theArgsOut.push_back (anArgVecW[anArgIter]); 395 | } 396 | ::LocalFree (anArgVecW); 397 | #else 398 | for (int anArgIter = 0; anArgIter < theNbArgs; ++anArgIter) 399 | { 400 | theArgsOut.push_back (theArgVec[anArgIter]); 401 | } 402 | #endif 403 | } 404 | 405 | int main (int theNbArgs, char** theArgVec) 406 | { 407 | OSD::SetSignal (false); 408 | 409 | std::vector anArgs; 410 | fillAppArguments (anArgs, theNbArgs, theArgVec); 411 | 412 | TCollection_AsciiString aModelPath; 413 | if (anArgs.size() > 2) 414 | { 415 | Message::SendFail() << "Syntax error: wrong number of arguments"; 416 | return 1; 417 | } 418 | 419 | if (anArgs.size() == 2) 420 | { 421 | aModelPath = anArgs[1]; 422 | } 423 | else 424 | { 425 | OSD_Environment aVarModDir ("SAMPLE_MODELS_DIR"); 426 | if (!aVarModDir.Value().IsEmpty()) 427 | { 428 | aModelPath = aVarModDir.Value() + "/as1-oc-214.stp"; 429 | } 430 | else 431 | { 432 | Message::SendFail() << "Warning: variable SAMPLE_MODELS_DIR not set"; 433 | } 434 | } 435 | 436 | MyViewer aViewer; 437 | if (!aModelPath.IsEmpty()) 438 | { 439 | TCollection_AsciiString aNameLower = aModelPath; 440 | aNameLower.LowerCase(); 441 | if (aNameLower.EndsWith (".xbf")) 442 | { 443 | aViewer.OpenXBF (aModelPath); 444 | } 445 | else //if (aNameLower.EndsWith (".stp") || aNameLower.EndsWith (".step")) 446 | { 447 | aViewer.OpenSTEP (aModelPath); 448 | } 449 | 450 | aViewer.DumpXCafDocumentTree(); 451 | aViewer.DisplayXCafDocument (true); 452 | } 453 | 454 | #ifdef _WIN32 455 | // WinAPI message loop 456 | for (;;) 457 | { 458 | MSG aMsg = {}; 459 | if (GetMessageW (&aMsg, NULL, 0, 0) <= 0) 460 | { 461 | return 0; 462 | } 463 | TranslateMessage(&aMsg); 464 | DispatchMessageW(&aMsg); 465 | } 466 | #elif defined(__APPLE__) 467 | /// TODO 468 | Message::SendFail() << "Critical error: Cocoa message loop is not implemented"; 469 | #else 470 | // X11 event loop 471 | Handle(Xw_Window) aWindow = Handle(Xw_Window)::DownCast (aViewer.View()->Window()); 472 | Handle(Aspect_DisplayConnection) aDispConn = aViewer.View()->Viewer()->Driver()->GetDisplayConnection(); 473 | Display* anXDisplay = (Display* )aDispConn->GetDisplayAspect(); 474 | for (;;) 475 | { 476 | XEvent anXEvent; 477 | XNextEvent (anXDisplay, &anXEvent); 478 | aWindow->ProcessMessage (aViewer, anXEvent); 479 | if (anXEvent.type == ClientMessage && (Atom)anXEvent.xclient.data.l[0] == aDispConn->GetAtom(Aspect_XA_DELETE_WINDOW)) 480 | { 481 | return 0; // exit when window is closed 482 | } 483 | } 484 | #endif 485 | return 0; 486 | } 487 | -------------------------------------------------------------------------------- /occt-xcaf-shape/ReadMe.md: -------------------------------------------------------------------------------- 1 | XCAFPrs_AISObject usage sample – displaying XCAF document in AIS 3D viewer.
2 | --------------------------------------------------------------------------------