├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── apps ├── CMakeLists.txt ├── add.json ├── argh.h ├── geoflow-app.cpp ├── geoflow-config.json ├── geoflow-gui.cpp ├── resources │ ├── AppIcon.afdesign │ ├── AppIcon.icns │ ├── Info.plist │ ├── appicon.rc │ └── geoflow.ico └── toml.hpp ├── cmake ├── ComputeSharedHeadersHash.cmake ├── geoflow-config.cmake.in ├── geoflow_create_plugin.cmake ├── gf_plugin.cpp.in └── version.h ├── examples ├── Arithmetic │ ├── CMakeLists.txt │ ├── demo_dynamic.cpp │ ├── demo_simple.cpp │ ├── nodes.hpp │ └── plugin.cpp ├── CMakeLists.txt └── gui.cpp ├── resources ├── nl_nsgi_nlgeo2018.tif └── nl_nsgi_rdtrans2018.tif ├── src ├── DLLoader │ ├── IDLLoader.h │ ├── Unix │ │ └── DLLoader.h │ └── Windows │ │ └── DLLoader.h ├── geoflow │ ├── AttributeCalcNode.cpp │ ├── ExpressionComputer.cpp │ ├── ExpressionComputer.hpp │ ├── api.cpp │ ├── api.hpp │ ├── common.cpp │ ├── common.hpp │ ├── core_nodes.hpp │ ├── geoflow.cpp │ ├── geoflow.hpp │ ├── gui │ │ ├── ImNodes.cpp │ │ ├── ImNodes.h │ │ ├── ImNodesEz.cpp │ │ ├── ImNodesEz.h │ │ ├── gfImNodes.hpp │ │ ├── imgui_color_gradient.cpp │ │ ├── imgui_color_gradient.h │ │ ├── osdialog.cpp │ │ ├── osdialog.hpp │ │ ├── parameter_widgets.cpp │ │ ├── parameter_widgets.hpp │ │ └── povi_nodes.hpp │ ├── parameters.cpp │ ├── parameters.hpp │ ├── plugin_manager.hpp │ ├── projHelper.cpp │ └── projHelper.hpp └── viewer │ ├── app.cpp │ ├── app.h │ ├── app_povi.cpp │ ├── app_povi.h │ ├── gloo.cpp │ ├── gloo.h │ ├── main.cpp │ └── shaders │ ├── basic.frag │ ├── basic.vert │ ├── crosshair.frag │ └── crosshair.vert └── thirdparty ├── CMakeLists.txt ├── cpp-taskflow ├── LICENSE └── taskflow │ ├── core │ ├── error.hpp │ ├── executor.hpp │ ├── flow_builder.hpp │ ├── graph.hpp │ ├── notifier.hpp │ ├── observer.hpp │ ├── task.hpp │ ├── taskflow.hpp │ ├── topology.hpp │ └── tsq.hpp │ ├── cuda │ ├── device.hpp │ ├── error.hpp │ ├── flow_builder.hpp │ ├── graph.hpp │ └── task.hpp │ ├── cudaflow.hpp │ ├── declarations.hpp │ ├── nstd │ ├── any.hpp │ └── variant.hpp │ ├── taskflow.hpp │ └── utility │ ├── object_pool.hpp │ ├── passive_vector.hpp │ ├── stringify.hpp │ └── traits.hpp ├── exprtk └── exprtk.hpp └── glad ├── include ├── KHR │ └── khrplatform.h └── glad │ └── glad.h └── src └── glad.c /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "thirdparty/imgui"] 2 | path = thirdparty/imgui 3 | url = https://github.com/ocornut/imgui.git 4 | [submodule "thirdparty/osdialog"] 5 | path = thirdparty/osdialog 6 | url = https://github.com/AndrewBelt/osdialog.git 7 | [submodule "thirdparty/filesystem"] 8 | path = thirdparty/filesystem 9 | url = https://github.com/gulrak/filesystem.git 10 | [submodule "thirdparty/glm"] 11 | path = thirdparty/glm 12 | url = https://github.com/g-truc/glm.git 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.21) 2 | 3 | project (Geoflow VERSION 0.3.8) 4 | 5 | include(GNUInstallDirs) 6 | 7 | set(GF_PLUGIN_FOLDER "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/geoflow-plugins" CACHE STRING "Geoflow plugin folder") 8 | set(GF_PLUGIN_FOLDER_INSTALL "${GF_PLUGIN_FOLDER}") 9 | if(PROJECT_IS_TOP_LEVEL) 10 | if (WIN32) 11 | string(REPLACE "\\" "\\\\" GF_PLUGIN_FOLDER ${GF_PLUGIN_FOLDER}) 12 | string(REPLACE "\\" "\\\\" GF_PLUGIN_FOLDER_INSTALL ${GF_PLUGIN_FOLDER}) 13 | endif() 14 | else() 15 | if (WIN32) 16 | set(GF_PLUGIN_FOLDER_INSTALL "lib\\geoflow-plugins" PARENT_SCOPE ) # this needs to be a relative to the installed geof.exe 17 | set(GF_PLUGIN_FOLDER_INSTALL "lib\\geoflow-plugins" ) # this needs to be a relative to the installed geof.exe 18 | set(GF_PLUGIN_FOLDER "..\\lib\\geoflow-plugins" ) 19 | string(REPLACE "\\" "\\\\" GF_PLUGIN_FOLDER ${GF_PLUGIN_FOLDER}) 20 | string(REPLACE "\\" "\\\\" GF_PLUGIN_FOLDER_INSTALL ${GF_PLUGIN_FOLDER}) 21 | else() 22 | set(GF_PLUGIN_FOLDER_INSTALL "${GF_PLUGIN_FOLDER}" PARENT_SCOPE) 23 | endif() 24 | endif() 25 | 26 | option(GF_BUILD_GUI "Build the GUI components of geoflow" TRUE) 27 | option(GF_BUILD_GUI_FILE_DIALOGS "Build GUI with OS native file dialogs" TRUE) 28 | 29 | # dependencies 30 | add_subdirectory(thirdparty) 31 | 32 | find_package(nlohmann_json 3.10.5 CONFIG REQUIRED) 33 | if (WIN32) # vcpkg doesn't work when there is a version number here 34 | find_package(PROJ REQUIRED CONFIG) 35 | else() 36 | find_package(PROJ 9.0.0 REQUIRED CONFIG) 37 | endif() 38 | 39 | set(PROJ_DATA_DIR CACHE PATH ${PROJ_DIR}) 40 | 41 | if(GF_BUILD_GUI) 42 | find_package(glfw3 3.3 REQUIRED) 43 | #message(STATUS "GLFW libs: ${GLFW_LIBRARIES}") 44 | endif() 45 | 46 | # set(THREADS_PREFER_PTHREAD_FLAG ON) 47 | # find_package(Threads) 48 | 49 | # DLLoader 50 | if (WIN32) 51 | include_directories( 52 | src/DLLoader/Windows/ 53 | ) 54 | endif(WIN32) 55 | 56 | if(UNIX) 57 | include_directories( 58 | src/DLLoader/Unix/ 59 | ) 60 | # set (CMAKE_CXX_FLAGS "-W -Wall -Wextra") 61 | endif(UNIX) 62 | 63 | # definitions 64 | set(GF_SHADER_PATH ${CMAKE_INSTALL_PREFIX}/share/geoflow) 65 | if(WIN32) 66 | set(GF_SHADER_PATH "bin\\share") 67 | add_definitions( 68 | -DGF_SHADER_PATH=\"share\" 69 | ) 70 | else() 71 | add_definitions( 72 | -DGF_SHADER_PATH=\"${GF_SHADER_PATH}\" 73 | ) 74 | endif() 75 | add_definitions( 76 | -DGLFW_INCLUDE_NONE 77 | -DIMGUI_IMPL_OPENGL_LOADER_GLAD 78 | -DGLM_FORCE_CTOR_INIT 79 | ) 80 | if(MSVC) 81 | add_definitions(-DNOMINMAX) 82 | endif() 83 | if(GF_BUILD_GUI) 84 | add_definitions(-DGF_BUILD_GUI) 85 | endif() 86 | if(GF_BUILD_GUI_FILE_DIALOGS) 87 | add_definitions(-DGF_BUILD_GUI_FILE_DIALOGS) 88 | endif() 89 | 90 | # version 91 | configure_file(cmake/version.h ${PROJECT_BINARY_DIR}/version.h) 92 | 93 | # includes 94 | include_directories( 95 | src 96 | thirdparty/filesystem/include 97 | thirdparty/exprtk 98 | ${PROJECT_BINARY_DIR} 99 | ) 100 | 101 | # targets 102 | add_library(geoflow-core SHARED 103 | src/geoflow/geoflow.cpp 104 | src/geoflow/common.cpp 105 | src/geoflow/parameters.cpp 106 | # src/geoflow/api.cpp 107 | src/geoflow/AttributeCalcNode.cpp 108 | src/geoflow/ExpressionComputer.cpp 109 | src/geoflow/projHelper.cpp 110 | ) 111 | target_link_libraries(geoflow-core PRIVATE nlohmann_json::nlohmann_json PROJ::proj) 112 | set_target_properties(geoflow-core PROPERTIES 113 | CXX_STANDARD 17 114 | WINDOWS_EXPORT_ALL_SYMBOLS TRUE 115 | ) 116 | if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) 117 | target_compile_options(geoflow-core PUBLIC "/Zc:__cplusplus" PRIVATE /bigobj) 118 | endif() 119 | 120 | if(${GF_BUILD_GUI}) 121 | include_directories( 122 | thirdparty/glad/include 123 | thirdparty/imgui 124 | thirdparty/imgui/examples 125 | ) 126 | set(GF_SHADER_FILES 127 | ${CMAKE_CURRENT_SOURCE_DIR}/src/viewer/shaders/crosshair.frag 128 | ${CMAKE_CURRENT_SOURCE_DIR}/src/viewer/shaders/crosshair.vert 129 | ${CMAKE_CURRENT_SOURCE_DIR}/src/viewer/shaders/basic.frag 130 | ${CMAKE_CURRENT_SOURCE_DIR}/src/viewer/shaders/basic.vert) 131 | SET(GF_GUI_SOURCES 132 | src/viewer/app.cpp 133 | src/viewer/app_povi.cpp 134 | thirdparty/glad/src/glad.c 135 | src/viewer/gloo.cpp 136 | thirdparty/imgui/imgui.cpp 137 | thirdparty/imgui/misc/cpp/imgui_stdlib.cpp 138 | thirdparty/imgui/imgui_draw.cpp 139 | thirdparty/imgui/imgui_widgets.cpp 140 | thirdparty/imgui/imgui_demo.cpp 141 | thirdparty/imgui/examples/imgui_impl_glfw.cpp 142 | thirdparty/imgui/examples/imgui_impl_opengl3.cpp 143 | src/geoflow/gui/ImNodes.cpp 144 | src/geoflow/gui/ImNodesEz.cpp 145 | src/geoflow/gui/imgui_color_gradient.cpp 146 | src/geoflow/gui/parameter_widgets.cpp 147 | ) 148 | 149 | SET(GF_FILEDIALOG_LIBS "") 150 | if(GF_BUILD_GUI_FILE_DIALOGS) 151 | SET(GF_GUI_SOURCES 152 | ${GF_GUI_SOURCES} 153 | thirdparty/osdialog/osdialog.c 154 | src/geoflow/gui/osdialog.cpp 155 | ) 156 | include_directories( 157 | thirdparty/osdialog 158 | ) 159 | if(APPLE) 160 | SET(GF_GUI_SOURCES ${GF_GUI_SOURCES} 161 | thirdparty/osdialog/osdialog_mac.m) 162 | SET(GF_FILEDIALOG_LIBS ${GF_FILEDIALOG_LIBS} 163 | "-framework AppKit") 164 | elseif(MSVC) 165 | SET(GF_GUI_SOURCES ${GF_GUI_SOURCES} 166 | thirdparty/osdialog/osdialog_win.c) 167 | SET(GF_FILEDIALOG_LIBS ${GF_FILEDIALOG_LIBS} 168 | comdlg32) 169 | else() 170 | find_package(PkgConfig REQUIRED) 171 | pkg_check_modules(GTK2 REQUIRED gtk+-2.0) 172 | 173 | SET(GF_GUI_SOURCES ${GF_GUI_SOURCES} 174 | thirdparty/osdialog/osdialog_gtk2.c) 175 | SET(GF_FILEDIALOG_LIBS ${GF_FILEDIALOG_LIBS} 176 | ${GTK2_LIBRARIES}) 177 | include_directories(${GTK2_INCLUDE_DIRS}) 178 | endif() 179 | endif(GF_BUILD_GUI_FILE_DIALOGS) 180 | 181 | add_library(geoflow-gui STATIC ${GF_GUI_SOURCES}) 182 | # target_include_directories(geoflow-gui nlohmann_json::nlohmann_json) 183 | target_link_libraries(geoflow-gui PRIVATE geoflow-core glfw ${GF_FILEDIALOG_LIBS}) 184 | target_include_directories(geoflow-gui PRIVATE ${GLM_INCLUDE_DIRECTORIES}) 185 | set_target_properties(geoflow-gui PROPERTIES CXX_STANDARD 17) 186 | if (WIN32) 187 | get_target_property(GLFW_DLL_LOCATION glfw IMPORTED_LOCATION_RELEASE) 188 | message("GLFW DLL: ${GLFW_DLL_LOCATION}") 189 | install(FILES ${GLFW_DLL_LOCATION} DESTINATION bin) 190 | endif (WIN32) 191 | endif() 192 | 193 | # installation 194 | 195 | # ensure rpath is set up properly (https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling) 196 | # use, i.e. don't skip the full RPATH for the build tree 197 | SET(CMAKE_SKIP_BUILD_RPATH FALSE) 198 | 199 | # when building, don't use the install RPATH already 200 | # (but later on when installing) 201 | SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) 202 | 203 | SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") 204 | 205 | # add the automatically determined parts of the RPATH 206 | # which point to directories outside the build tree to the install RPATH 207 | SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 208 | 209 | 210 | add_definitions(-DGF_PLUGIN_FOLDER=\"${GF_PLUGIN_FOLDER}\") 211 | message(STATUS "Geoflow plugin folder set to ${GF_PLUGIN_FOLDER}") 212 | message(STATUS "Geoflow plugin folder install set to ${GF_PLUGIN_FOLDER_INSTALL}") 213 | 214 | set(GF_PLUGIN_EXTENSION ".so") 215 | if (WIN32) 216 | set(GF_PLUGIN_EXTENSION ".dll") 217 | endif() 218 | message(STATUS "Setting Geoflow plugin extension to ${GF_PLUGIN_EXTENSION}") 219 | add_definitions(-DGF_PLUGIN_EXTENSION=\"${GF_PLUGIN_EXTENSION}\") 220 | 221 | # write the hash of the concatenated shared header files to a new header file, so that we can check compatibility between main geof executable and the plugins 222 | set(GF_SHH_FILE ${CMAKE_BINARY_DIR}/include/geoflow/gfSharedHeadersHash.h) 223 | if(PROJECT_IS_TOP_LEVEL) 224 | add_custom_command( 225 | TARGET geoflow-core 226 | COMMAND ${CMAKE_COMMAND} -DOUTPUT_FILE=${GF_SHH_FILE} -DPROJECT_SOURCE_DIR=${CMAKE_CURRENT_LIST_DIR} -P "${CMAKE_CURRENT_LIST_DIR}/cmake/ComputeSharedHeadersHash.cmake" 227 | ) 228 | else() 229 | file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/geoflow/common.hpp s1) 230 | file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/geoflow/parameters.hpp s2) 231 | file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/geoflow/geoflow.hpp s3) 232 | string(CONCAT GF_SHARED_HEADERS ${s1} ${s2} ${s3}) 233 | string(MD5 GF_SHARED_HEADERS_HASH ${GF_SHARED_HEADERS}) 234 | message(STATUS "Setting Geoflow shared header hash to ${GF_SHARED_HEADERS_HASH}") 235 | file(WRITE ${GF_SHH_FILE} "#define GF_SHARED_HEADERS_HASH \"${GF_SHARED_HEADERS_HASH}\"\n") 236 | endif() 237 | 238 | 239 | set_property(TARGET geoflow-core PROPERTY PUBLIC_HEADER 240 | src/geoflow/common.hpp 241 | src/geoflow/parameters.hpp 242 | src/geoflow/geoflow.hpp 243 | src/geoflow/api.hpp 244 | src/geoflow/projHelper.hpp 245 | ${GF_SHH_FILE} 246 | ) 247 | 248 | # target_include_directories(geoflow-core PUBLIC 249 | # ${CMAKE_BINARY_DIR}/include 250 | # ) 251 | 252 | # target_sources(geoflow-core PUBLIC 253 | # $ 254 | # $ 255 | # $ 256 | # $ 257 | # $ 258 | # $ 259 | # $ 260 | # $ 261 | # ) 262 | 263 | install(TARGETS geoflow-core EXPORT geoflow-targets 264 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 265 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 266 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 267 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/geoflow) 268 | install(EXPORT geoflow-targets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/geoflow) 269 | 270 | include ( CMakePackageConfigHelpers ) 271 | configure_package_config_file(cmake/geoflow-config.cmake.in 272 | ${CMAKE_CURRENT_BINARY_DIR}/geoflow-config.cmake 273 | INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/geoflow 274 | ) 275 | 276 | install(FILES 277 | ${CMAKE_CURRENT_BINARY_DIR}/geoflow-config.cmake 278 | cmake/gf_plugin.cpp.in 279 | cmake/geoflow_create_plugin.cmake 280 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/geoflow) 281 | 282 | install(FILES LICENSE DESTINATION share/geoflow) 283 | 284 | # install proj.db and rasters for Dutch rijksdriehoekstelsel 285 | if(WIN32) 286 | install(FILES ${PROJ_DATA_DIR}/proj.db DESTINATION share/proj) 287 | install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/resources/ DESTINATION share/proj FILES_MATCHING PATTERN "*.tif") 288 | endif(WIN32) 289 | 290 | add_subdirectory(apps) 291 | 292 | include(cmake/geoflow_create_plugin.cmake) 293 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Geoflow 2 | Flowchart tool for geo-spatial data processing. Highly experimental with many rough edges! 3 | 4 | # Installation 5 | 6 | ## As part of [geoflow-bundle](https://github.com/geoflow3d/geoflow-bundle/) 7 | This the recommended way since it will also include the commonly used plugins and flowcharts to get you started quickly. Also binary pacakges are available. 8 | 9 | ## Building from source 10 | 11 | Requires compiler with c++17 support (see https://en.cppreference.com/w/cpp/compiler_support). 12 | 13 | ``` 14 | mkdir build 15 | cd build 16 | cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local -DGF_BUILD_GUI=OFF 17 | cmake --build . --parallel 4 --config Release 18 | ``` 19 | 20 | ### dependencies 21 | + [nlohmann JSON](https://github.com/nlohmann/json/releases) at least version 3.10.5 22 | 23 | # Usage 24 | ## Command line interface (`geof`) 25 | ``` 26 | Usage: 27 | geof [-v | -p | -n | -h] 28 | geof [-V] [-g] [-w] [-c ] [--GLOBAL1=A --GLOBAL2=B ...] 29 | 30 | Options: 31 | -v, --version Print version information 32 | -p, --list-plugins List available plugins 33 | -n, --list-nodes List available nodes for plugins that are loaded 34 | -h, --help Print this help message 35 | 36 | JSON flowchart file 37 | -V, --verbose Print verbose messages during flowchart execution 38 | -g, --list-globals List available flowchart globals. Cancels flowchart execution 39 | -w, --workdir Set working directory to folder containing flowchart file 40 | -c , --config Read globals from TOML config file 41 | --GLOBAL1=A --GLOBAL2=B ... Specify globals for flowchart (list availale globals with -g) 42 | ``` 43 | ### examples 44 | Print version information: 45 | ```geof --version``` 46 | 47 | Print help: 48 | ```geof --help``` 49 | 50 | Running a flowchart with default globals: 51 | ```geof ``` 52 | 53 | List available globals: 54 | ```geof --list-globals``` 55 | 56 | Running a flowchart with user-specified global values: 57 | ```geof [--config ] [--GLOBAL1=value1 --GLOBAL2=value2 ...]``` 58 | 59 | Command line specified globals have the highest priority and will override default values and/or config file provided values. 60 | -------------------------------------------------------------------------------- /apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # gui application 2 | if(${GF_BUILD_GUI}) 3 | if(APPLE) 4 | set(RESOURCE_FILES 5 | ${CMAKE_CURRENT_SOURCE_DIR}/resources/AppIcon.icns 6 | ) 7 | add_executable(geoflow geoflow-gui.cpp ${RESOURCE_FILES}) 8 | set_target_properties(geoflow PROPERTIES 9 | MACOSX_BUNDLE TRUE 10 | MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/resources/Info.plist 11 | RESOURCE ${RESOURCE_FILES} 12 | ) 13 | elseif(WIN32) 14 | set(RESOURCE_FILES 15 | ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.rc 16 | ) 17 | add_executable(geoflow geoflow-gui.cpp ${RESOURCE_FILES}) # add WIN32 as second parameter to make it a GUI app and suppress console window on execution 18 | else() 19 | add_executable(geoflow geoflow-gui.cpp) 20 | endif() 21 | 22 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR LINUX) 23 | target_link_libraries(geoflow PRIVATE -ldl) 24 | endif() 25 | target_link_libraries(geoflow PRIVATE geoflow-gui nlohmann_json::nlohmann_json PROJ::proj glfw) 26 | message("${CMAKE_BINARY_DIR}/include") 27 | # last include dir is for the shared header hash| 28 | target_include_directories(geoflow PRIVATE ${GLM_INCLUDE_DIRECTORIES} ${CMAKE_BINARY_DIR}/include) 29 | target_link_directories(geoflow PRIVATE ${CMAKE_SOURCE_DIR}/src) 30 | set_target_properties( geoflow PROPERTIES CXX_STANDARD 17 ) 31 | if (LINUX) 32 | target_compile_options( geoflow PRIVATE -Wl,-E ) # https://gcc.gnu.org/faq.html#dso 33 | endif() 34 | install(FILES ${GF_SHADER_FILES} DESTINATION ${GF_SHADER_PATH}) 35 | install(TARGETS geoflow 36 | RUNTIME DESTINATION bin 37 | BUNDLE DESTINATION /Applications) 38 | endif() 39 | 40 | # cli application 41 | add_executable(geof geoflow-app.cpp) 42 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR LINUX) 43 | target_link_libraries(geof PRIVATE -ldl) 44 | endif() 45 | target_link_libraries(geof PRIVATE geoflow-core nlohmann_json::nlohmann_json PROJ::proj) 46 | target_link_directories(geof PRIVATE ${CMAKE_SOURCE_DIR}/src) 47 | # last include dir is for the shared header hash| 48 | target_include_directories(geof PRIVATE ${CMAKE_BINARY_DIR}/include) 49 | set_target_properties( geof PROPERTIES CXX_STANDARD 17 ) 50 | if (LINUX) 51 | target_compile_options( geof PRIVATE -Wl,-E ) # https://gcc.gnu.org/faq.html#dso 52 | endif() 53 | 54 | install(TARGETS geof 55 | RUNTIME DESTINATION bin) 56 | -------------------------------------------------------------------------------- /apps/add.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "Adder(2)": { 4 | "position": [ 5 | 370.0, 6 | 142.0 7 | ], 8 | "type": [ 9 | "Arithmetic", 10 | "Adder" 11 | ] 12 | }, 13 | "Number(1)": { 14 | "connections": { 15 | "result": [ 16 | [ 17 | "Adder(2)", 18 | "in1" 19 | ] 20 | ] 21 | }, 22 | "parameters": { 23 | "number_value": 40 24 | }, 25 | "position": [ 26 | 191.0, 27 | 79.0 28 | ], 29 | "type": [ 30 | "Arithmetic", 31 | "Number" 32 | ] 33 | }, 34 | "Number(3)": { 35 | "connections": { 36 | "result": [ 37 | [ 38 | "Adder(2)", 39 | "in2" 40 | ] 41 | ] 42 | }, 43 | "parameters": { 44 | "number_value": 42 45 | }, 46 | "position": [ 47 | 186.0, 48 | 178.0 49 | ], 50 | "type": [ 51 | "Arithmetic", 52 | "Number" 53 | ] 54 | }, 55 | "Painter(4)": { 56 | "position": [ 57 | 620.0, 58 | 90.0 59 | ], 60 | "type": [ 61 | "Visualisation", 62 | "Painter" 63 | ] 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /apps/geoflow-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "node-libs": [ 3 | "/Users/ravi/git/geoflow-plugin-template/build/libgf_plugin_example.dylib", 4 | "/Users/ravi/git/geoflow-nodes/build/modules/gdal/libgdal_plugin.dylib" 5 | ] 6 | } -------------------------------------------------------------------------------- /apps/geoflow-gui.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | #define GF_BUILD_WITH_GUI 17 | #include "geoflow-app.cpp" 18 | #undef GF_BUILD_WITH_GUI -------------------------------------------------------------------------------- /apps/resources/AppIcon.afdesign: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoflow3d/geoflow/1ae729cfe23c765416fb07ef69297bfb05de445a/apps/resources/AppIcon.afdesign -------------------------------------------------------------------------------- /apps/resources/AppIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoflow3d/geoflow/1ae729cfe23c765416fb07ef69297bfb05de445a/apps/resources/AppIcon.icns -------------------------------------------------------------------------------- /apps/resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleName 8 | geoflow 9 | CFBundleExecutable 10 | geoflow 11 | CFBundleIconFile 12 | AppIcon 13 | CFBundleIdentifier 14 | tudelft3d.geoflow 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundlePackageType 18 | APPL 19 | 20 | -------------------------------------------------------------------------------- /apps/resources/appicon.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "geoflow.ico" -------------------------------------------------------------------------------- /apps/resources/geoflow.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoflow3d/geoflow/1ae729cfe23c765416fb07ef69297bfb05de445a/apps/resources/geoflow.ico -------------------------------------------------------------------------------- /cmake/ComputeSharedHeadersHash.cmake: -------------------------------------------------------------------------------- 1 | file(READ ${PROJECT_SOURCE_DIR}/src/geoflow/common.hpp s1) 2 | file(READ ${PROJECT_SOURCE_DIR}/src/geoflow/parameters.hpp s2) 3 | file(READ ${PROJECT_SOURCE_DIR}/src/geoflow/geoflow.hpp s3) 4 | string(CONCAT GF_SHARED_HEADERS ${s1} ${s2} ${s3}) 5 | string(MD5 GF_SHARED_HEADERS_HASH ${GF_SHARED_HEADERS}) 6 | message(STATUS "Setting Geoflow shared header hash to ${GF_SHARED_HEADERS_HASH}") 7 | file(WRITE ${OUTPUT_FILE} "#define GF_SHARED_HEADERS_HASH \"${GF_SHARED_HEADERS_HASH}\"\n") -------------------------------------------------------------------------------- /cmake/geoflow-config.cmake.in: -------------------------------------------------------------------------------- 1 | get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 2 | include(${SELF_DIR}/geoflow-targets.cmake) 3 | get_filename_component(geoflow_INCLUDE_DIRS "${SELF_DIR}/../../../include" ABSOLUTE) 4 | set_property(TARGET geoflow-core PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${geoflow_INCLUDE_DIRS}) 5 | 6 | set(geoflow_FOUND true) 7 | set(GF_PLUGIN_FILE ${SELF_DIR}/gf_plugin.cpp.in) 8 | 9 | include(${SELF_DIR}/geoflow_create_plugin.cmake) 10 | 11 | @PACKAGE_INIT@ 12 | set(GF_PLUGIN_FOLDER_INSTALL @GF_PLUGIN_FOLDER_INSTALL@) -------------------------------------------------------------------------------- /cmake/geoflow_create_plugin.cmake: -------------------------------------------------------------------------------- 1 | function(geoflow_create_plugin) 2 | configure_file(${GF_PLUGIN_FILE} ${PROJECT_BINARY_DIR}/gf_plugin.cpp) 3 | 4 | add_library(${GF_PLUGIN_TARGET_NAME} MODULE 5 | ${PROJECT_BINARY_DIR}/gf_plugin.cpp 6 | ${ARGN} 7 | ) 8 | set_target_properties( 9 | ${GF_PLUGIN_TARGET_NAME} PROPERTIES 10 | CXX_STANDARD 17 11 | CXX_VISIBILITY_PRESET hidden 12 | PREFIX "" 13 | ) 14 | 15 | # this is an unfortunate requirement due to how parameters currently work. Should get rid of it. 16 | find_package(nlohmann_json 3.10.5 CONFIG REQUIRED) 17 | target_link_libraries( ${GF_PLUGIN_TARGET_NAME} PRIVATE nlohmann_json::nlohmann_json ) 18 | 19 | install( 20 | TARGETS ${GF_PLUGIN_TARGET_NAME} 21 | LIBRARY DESTINATION ${GF_PLUGIN_FOLDER_INSTALL} 22 | ) 23 | endfunction() -------------------------------------------------------------------------------- /cmake/gf_plugin.cpp.in: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "@GF_PLUGIN_REGISTER@" 4 | 5 | #define FVISIBILITY __attribute__ ((visibility("default"))) 6 | #ifdef WIN32 7 | #define FVISIBILITY __declspec (dllexport) 8 | #endif 9 | 10 | extern "C" 11 | { 12 | FVISIBILITY geoflow::NodeRegister *allocator_@GF_PLUGIN_TARGET_NAME@() 13 | { 14 | auto node_register = new geoflow::NodeRegister("@GF_PLUGIN_NAME@"); 15 | register_nodes(*node_register); 16 | 17 | auto& info = node_register->get_plugin_info(); 18 | info["version_major"] = "@PROJECT_VERSION_MAJOR@"; 19 | info["version_minor"] = "@PROJECT_VERSION_MINOR@"; 20 | info["version_patch"] = "@PROJECT_VERSION_PATCH@"; 21 | info["host_system"] = "@CMAKE_HOST_SYSTEM@"; 22 | info["compiler_id"] = "@CMAKE_CXX_COMPILER_ID@"; 23 | info["compiler_version"] = "@CMAKE_CXX_COMPILER_VERSION@"; 24 | info["build_type"] = "@CMAKE_BUILD_TYPE@"; 25 | 26 | return node_register; 27 | } 28 | 29 | FVISIBILITY void deleter_@GF_PLUGIN_TARGET_NAME@(geoflow::NodeRegister *ptr) 30 | { 31 | delete ptr; 32 | } 33 | 34 | FVISIBILITY void get_shared_headers_hash_@GF_PLUGIN_TARGET_NAME@(char *hash) 35 | { 36 | strcpy(hash, GF_SHARED_HEADERS_HASH); 37 | } 38 | } -------------------------------------------------------------------------------- /cmake/version.h: -------------------------------------------------------------------------------- 1 | #define PROJECT_VERSION_MAJOR "@PROJECT_VERSION_MAJOR@"; 2 | #define PROJECT_VERSION_MINOR "@PROJECT_VERSION_MINOR@"; 3 | #define PROJECT_VERSION_PATCH "@PROJECT_VERSION_PATCH@"; 4 | #define CMAKE_HOST_SYSTEM "@CMAKE_HOST_SYSTEM@"; 5 | #define CMAKE_CXX_COMPILER_ID "@CMAKE_CXX_COMPILER_ID@"; 6 | #define CMAKE_CXX_COMPILER_VERSION "@CMAKE_CXX_COMPILER_VERSION@"; 7 | #define CMAKE_BUILD_TYPE "@CMAKE_BUILD_TYPE@"; -------------------------------------------------------------------------------- /examples/Arithmetic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_definitions(-DGF_PLUGIN_NAME=\"Arithmetic\") 3 | 4 | add_library(gf_arithmetic SHARED 5 | plugin.cpp 6 | ) 7 | target_link_libraries(gf_arithmetic geoflow-core) 8 | 9 | # add_executable(demo_dynamic demo_dynamic.cpp) 10 | # target_link_libraries(demo_dynamic geoflow-core) 11 | 12 | # add_executable(demo_simple demo_simple.cpp) 13 | # target_link_libraries(demo_simple geoflow-core) 14 | 15 | set_target_properties( 16 | gf_arithmetic 17 | # demo_simple 18 | # demo_dynamic 19 | PROPERTIES CXX_STANDARD 17 20 | ) -------------------------------------------------------------------------------- /examples/Arithmetic/demo_dynamic.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2019 Ravi Peters, 3D geoinformation TU Delft 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #include 18 | #include "DLLoader.h" 19 | #include 20 | 21 | using namespace geoflow; 22 | 23 | static const std::string path = "/Users/ravi/git/geoflow/debug/examples/libbasic_plugin.dylib"; 24 | 25 | int main(void) { 26 | dlloader::DLLoader dlloader(path); 27 | 28 | std::cout << "Loading " << path << std::endl; 29 | dlloader.DLOpenLib(); 30 | 31 | std::shared_ptr R = dlloader.DLGetInstance(); 32 | 33 | NodeManager N; 34 | auto adder = N.create_node(*R, "Adder"); 35 | auto number = N.create_node(*R, "Number"); 36 | auto adder2 = N.create_node(*R, "Adder"); 37 | auto number2 = N.create_node(*R, "Number"); 38 | 39 | connect(number->output("result"), adder->input("in1")); 40 | connect(number, adder, "result", "in2"); 41 | connect(adder, adder2, "result", "in1"); 42 | connect(adder, adder2, "result", "in2"); 43 | 44 | number->set_param("number_value", (int) 5); 45 | 46 | N.dump_json("out.json"); 47 | 48 | bool success = N.run(number); 49 | if (success){ 50 | std::cout << "Result: " << adder2->output("result").get() << "\n"; 51 | } else { 52 | std::cout << "No result\n"; 53 | } 54 | 55 | std::cout << "Unloading " << path << std::endl; 56 | dlloader.DLCloseLib(); 57 | } -------------------------------------------------------------------------------- /examples/Arithmetic/demo_simple.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2019 Ravi Peters, 3D geoinformation TU Delft 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #include "nodes.hpp" 18 | #include 19 | 20 | using namespace geoflow; 21 | 22 | int main(void) { 23 | auto R = nodes::arithmetic::create_register(); 24 | NodeManager N; 25 | auto adder = N.create_node(*R, "Adder"); 26 | auto number = N.create_node(*R, "Number"); 27 | auto adder2 = N.create_node(*R, "Adder"); 28 | auto number2 = N.create_node(*R, "Number"); 29 | 30 | connect(number->output("result"), adder->input("in1")); 31 | connect(number, adder, "result", "in2"); 32 | connect(adder, adder2, "result", "in1"); 33 | connect(adder, adder2, "result", "in2"); 34 | 35 | number->set_param("number_value", (int) 5); 36 | 37 | N.dump_json("out.json"); 38 | 39 | bool success = N.run(number); 40 | if (success){ 41 | std::cout << "Result: " << adder2->output("result").get() << "\n"; 42 | } else { 43 | std::cout << "No result\n"; 44 | } 45 | } -------------------------------------------------------------------------------- /examples/Arithmetic/nodes.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2019 Ravi Peters, 3D geoinformation TU Delft 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace geoflow; 23 | 24 | class AdderNode:public Node { 25 | public: 26 | using Node::Node; 27 | 28 | void init() { 29 | add_input("in1", typeid(float)); 30 | add_input("in2", typeid(float)); 31 | add_output("result", typeid(float)); 32 | } 33 | 34 | std::string info() { 35 | std::string s; 36 | if (output("result").has_data()) 37 | s = std::to_string(output("result").get()); 38 | return s; 39 | } 40 | 41 | void process() { 42 | std::cout << "begin AddderNode::process()" << "\n"; 43 | auto in1 = input("in1").get(); 44 | auto in2 = input("in2").get(); 45 | std::this_thread::sleep_for(std::chrono::microseconds(200)); 46 | output("result").set(float(in1+in2)); 47 | std::cout << "end AddderNode::process()" << "\n"; 48 | } 49 | }; 50 | 51 | class NumberNode:public Node { 52 | int value=21; 53 | public: 54 | using Node::Node; 55 | 56 | void init() { 57 | add_output("result", typeid(float)); 58 | 59 | add_param("number_value", ParamInt(value)); 60 | } 61 | 62 | void process() { 63 | std::cout << "begin NumberNode::process()" << "\n"; 64 | output("result").set(float(value)); 65 | std::cout << "end NumberNode::process()" << "\n"; 66 | } 67 | }; 68 | 69 | class NumberNodeI:public Node { 70 | public: 71 | using Node::Node; 72 | void init() { 73 | add_output("result", typeid(int)); 74 | } 75 | 76 | void process() { 77 | std::cout << "begin NumberNode::process()" << "\n"; 78 | output("result").set(1); 79 | std::cout << "end NumberNode::process()" << "\n"; 80 | } 81 | }; 82 | 83 | void register_nodes(NodeRegister& node_register) { 84 | node_register.register_node("Adder"); 85 | node_register.register_node("Number"); 86 | node_register.register_node("NumberI"); 87 | } 88 | 89 | NodeRegisterHandle create_register() { 90 | auto R = NodeRegister::create(GF_PLUGIN_NAME); 91 | register_nodes(*R); 92 | return R; 93 | } -------------------------------------------------------------------------------- /examples/Arithmetic/plugin.cpp: -------------------------------------------------------------------------------- 1 | #include "nodes.hpp" 2 | 3 | #define WIN_DECLSPEC 4 | #ifdef WIN32 5 | #define WIN_DECLSPEC __declspec (dllexport) 6 | #endif 7 | 8 | 9 | extern "C" 10 | { 11 | WIN_DECLSPEC geoflow::NodeRegister *allocator() 12 | { 13 | auto node_register = new geoflow::NodeRegister(GF_PLUGIN_NAME); 14 | register_nodes(*node_register); 15 | return node_register; 16 | } 17 | 18 | WIN_DECLSPEC void deleter(geoflow::NodeRegister *ptr) 19 | { 20 | delete ptr; 21 | } 22 | } -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_subdirectory("Arithmetic") 3 | 4 | # add_executable( 5 | # gui 6 | # gui.cpp 7 | # ) 8 | # target_link_libraries(gui geoflow-gui) 9 | 10 | # set_target_properties( 11 | # gui 12 | # PROPERTIES CXX_STANDARD 17 13 | # ) -------------------------------------------------------------------------------- /examples/gui.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2019 Ravi Peters, 3D geoinformation TU Delft 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | #include "Arithmetic/nodes.hpp" 24 | 25 | // #include 26 | 27 | // using json = nlohmann::json; 28 | 29 | // #include 30 | 31 | class FileOpenNode:public Node { 32 | public: 33 | using Node::Node; 34 | void init() { 35 | add_output("result", typeid(int)); 36 | add_param("path", (std::string) ""); 37 | } 38 | 39 | void gui() { 40 | ImGui::FilePicker(OSDIALOG_OPEN, param("path")); 41 | } 42 | 43 | void process(){ 44 | output("result").set(1); 45 | } 46 | }; 47 | 48 | 49 | int main(int ac, const char * av[]) 50 | { 51 | auto R = NodeRegister::create("Arithmetic"); 52 | R->register_node("Adder"); 53 | R->register_node("Number"); 54 | auto R_gui = NodeRegister::create("BasicShapes"); 55 | R_gui->register_node("Cube"); 56 | R_gui->register_node("Triangle"); 57 | R_gui->register_node("FileOpen"); 58 | 59 | NodeRegisterMap RM; 60 | RM.emplace(R); 61 | RM.emplace(R_gui); 62 | NodeManager N; 63 | N.create_node(R_gui, "Cube", {0,-200}); 64 | auto adder = N.create_node(R, "Adder", {300,0}); 65 | auto number = N.create_node(R, "Number", {0, 000}); 66 | 67 | number->set_params({ 68 | {"number_value", (int) 5} 69 | }); 70 | 71 | connect(number->output("result"), adder->input("in1")); 72 | connect(number->output("result"), adder->input("in2")); 73 | 74 | launch_flowchart(N, {R,R_gui}); 75 | 76 | } -------------------------------------------------------------------------------- /resources/nl_nsgi_nlgeo2018.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoflow3d/geoflow/1ae729cfe23c765416fb07ef69297bfb05de445a/resources/nl_nsgi_nlgeo2018.tif -------------------------------------------------------------------------------- /resources/nl_nsgi_rdtrans2018.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoflow3d/geoflow/1ae729cfe23c765416fb07ef69297bfb05de445a/resources/nl_nsgi_rdtrans2018.tif -------------------------------------------------------------------------------- /src/DLLoader/IDLLoader.h: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | #pragma once 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | struct ImGuiContext; 23 | 24 | namespace dlloader 25 | { 26 | 27 | /* 28 | ** Interface for Dynamic Library Loading (DLLoader) 29 | ** API for Unix and Windows. Handling of open, close, validity-check. 30 | */ 31 | template 32 | class IDLLoader 33 | { 34 | 35 | public: 36 | 37 | virtual ~IDLLoader() = default; 38 | 39 | /* 40 | ** 41 | */ 42 | virtual bool DLOpenLib(bool verbose=false) = 0; 43 | 44 | /* 45 | ** Return a shared pointer on an instance of class loaded through 46 | ** a dynamic library. 47 | */ 48 | virtual std::shared_ptr DLGetInstance() = 0; 49 | 50 | /* 51 | ** Correctly delete the instance of the "dynamically loaded" class. 52 | */ 53 | virtual void DLCloseLib(bool verbose=false) = 0; 54 | 55 | }; 56 | } -------------------------------------------------------------------------------- /src/DLLoader/Unix/DLLoader.h: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | #pragma once 17 | 18 | #include 19 | #include 20 | #include 21 | #include "../IDLLoader.h" 22 | 23 | namespace dlloader 24 | { 25 | template 26 | class DLLoader : public IDLLoader 27 | { 28 | 29 | private: 30 | 31 | void *_handle; 32 | std::string _pathToLib; 33 | std::string _allocClassSymbol; 34 | std::string _deleteClassSymbol; 35 | std::string _getHeaderHashSymbol; 36 | 37 | public: 38 | 39 | DLLoader(std::string const &pathToLib, 40 | std::string const &pluginTargetName) 41 | : 42 | _handle(nullptr), _pathToLib(pathToLib), 43 | _allocClassSymbol("allocator_"+pluginTargetName), 44 | _deleteClassSymbol("deleter_"+pluginTargetName), 45 | _getHeaderHashSymbol("get_shared_headers_hash_"+pluginTargetName) 46 | { 47 | } 48 | 49 | ~DLLoader() = default; 50 | 51 | bool DLOpenLib(bool verbose) override 52 | { 53 | if (!(_handle = dlopen(_pathToLib.c_str(), RTLD_LAZY | RTLD_GLOBAL))) { 54 | if (verbose) std::cout << "Can't open and load " << _pathToLib << std::endl; 55 | if (verbose) std::cout << "->" << dlerror() << std::endl; 56 | return false; 57 | } 58 | 59 | // check header hash 60 | using getHeaderHash = void (*)(char *); 61 | auto headerHashFunc = reinterpret_cast( 62 | dlsym(_handle, _getHeaderHashSymbol.c_str())); 63 | if(!headerHashFunc) { 64 | if (verbose) std::cout << "Can't open and load " << _pathToLib << std::endl; 65 | if (verbose) std::cout << "->" << dlerror() << std::endl; 66 | DLCloseLib(verbose); 67 | return false; 68 | } else { 69 | char plugin_hash[33]; 70 | headerHashFunc(plugin_hash); 71 | if(strcmp(plugin_hash, GF_SHARED_HEADERS_HASH)!=0) { 72 | if (verbose) std::cout << "Can't open and load " << _pathToLib << std::endl; 73 | if (verbose) std::cout << "-> Plugin header hash incompatible!\n"; 74 | // std::cout << plugin_hash << ", geof: " << GF_SHARED_HEADERS_HASH << "\n"; 75 | DLCloseLib(verbose); 76 | return false; 77 | } 78 | } 79 | return true; 80 | } 81 | 82 | std::shared_ptr DLGetInstance() override 83 | { 84 | using allocClass = T *(*)(); 85 | using deleteClass = void (*)(T *); 86 | 87 | 88 | auto allocFunc = reinterpret_cast( 89 | dlsym(_handle, _allocClassSymbol.c_str())); 90 | if(!allocFunc) 91 | std::cout << dlerror() << std::endl; 92 | auto deleteFunc = reinterpret_cast( 93 | dlsym(_handle, _deleteClassSymbol.c_str())); 94 | if(!deleteFunc) 95 | std::cout << dlerror() << std::endl; 96 | 97 | if (!allocFunc || !deleteFunc) { 98 | DLCloseLib(true); 99 | } 100 | 101 | return std::shared_ptr( 102 | allocFunc(), 103 | [deleteFunc](T *p){ deleteFunc(p); }); 104 | } 105 | 106 | void DLCloseLib(bool verbose) override 107 | { 108 | if (dlclose(_handle) != 0) { 109 | if (verbose) std::cout << dlerror() << std::endl; 110 | } 111 | } 112 | 113 | }; 114 | } 115 | -------------------------------------------------------------------------------- /src/DLLoader/Windows/DLLoader.h: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | #pragma once 17 | 18 | #include 19 | #include "../IDLLoader.h" 20 | #include "Windows.h" 21 | 22 | namespace dlloader 23 | { 24 | template 25 | class DLLoader : public IDLLoader 26 | { 27 | 28 | private: 29 | HMODULE _handle; 30 | std::string _pathToLib; 31 | std::string _allocClassSymbol; 32 | std::string _deleteClassSymbol; 33 | std::string _getHeaderHashSymbol; 34 | 35 | public: 36 | DLLoader(std::string const &pathToLib, 37 | std::string const &pluginTargetName) 38 | : 39 | _handle(nullptr), _pathToLib(pathToLib), 40 | _allocClassSymbol("allocator_"+pluginTargetName), 41 | _deleteClassSymbol("deleter_"+pluginTargetName), 42 | _getHeaderHashSymbol("get_shared_headers_hash_"+pluginTargetName) 43 | {} 44 | 45 | ~DLLoader() = default; 46 | 47 | 48 | //Returns the last Win32 error, in string format. Returns an empty string if there is no error. 49 | std::string GetLastErrorAsString() 50 | { 51 | //Get the error message, if any. 52 | DWORD errorMessageID = ::GetLastError(); 53 | if(errorMessageID == 0) 54 | return std::string(); //No error message has been recorded 55 | 56 | LPSTR messageBuffer = nullptr; 57 | size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 58 | NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); 59 | 60 | std::string message(messageBuffer, size); 61 | 62 | //Free the buffer. 63 | LocalFree(messageBuffer); 64 | 65 | return message; 66 | } 67 | 68 | bool DLOpenLib(bool verbose) override 69 | { 70 | if (!(_handle = LoadLibrary(_pathToLib.c_str()))) { 71 | if (verbose) std::cout << "Can't open and load " << _pathToLib << std::endl; 72 | if (verbose) std::cout << "-> ERROR: " << GetLastErrorAsString() << std::endl; 73 | return false; 74 | } 75 | 76 | // check header hash 77 | using getHeaderHash = void (*)(char *); 78 | auto headerHashFunc = reinterpret_cast( 79 | GetProcAddress(_handle, _getHeaderHashSymbol.c_str())); 80 | if(!headerHashFunc) { 81 | if (verbose) std::cout << "Can't open and load " << _pathToLib << std::endl; 82 | if (verbose) std::cout << "-> Can't find _getHeaderHashSymbol" << std::endl; 83 | DLCloseLib(verbose); 84 | return false; 85 | } else { 86 | char plugin_hash[33]; 87 | headerHashFunc(plugin_hash); 88 | if(strcmp(plugin_hash, GF_SHARED_HEADERS_HASH)!=0) { 89 | if (verbose) std::cout << "Can't open and load " << _pathToLib << std::endl; 90 | if (verbose) std::cout << "-> Plugin header hash incompatible!\n"; 91 | // std::cout << plugin_hash << ", geof: " << GF_SHARED_HEADERS_HASH << "\n"; 92 | DLCloseLib(verbose); 93 | return false; 94 | } 95 | } 96 | return true; 97 | } 98 | 99 | std::shared_ptr DLGetInstance() override 100 | { 101 | using allocClass = T * (*)(); 102 | using deleteClass = void(*)(T *); 103 | 104 | auto allocFunc = reinterpret_cast( 105 | GetProcAddress(_handle, _allocClassSymbol.c_str())); 106 | auto deleteFunc = reinterpret_cast( 107 | GetProcAddress(_handle, _deleteClassSymbol.c_str())); 108 | 109 | if (!allocFunc || !deleteFunc) { 110 | DLCloseLib(true); 111 | std::cout << "Can't find allocator or deleter symbol in " << _pathToLib << std::endl; 112 | } 113 | 114 | return std::shared_ptr( 115 | allocFunc(), 116 | [deleteFunc](T *p) { deleteFunc(p); }); 117 | } 118 | 119 | void DLCloseLib(bool verbose) override 120 | { 121 | if (FreeLibrary(_handle) == 0) { 122 | if (verbose) std::cout << "Can't close " << _pathToLib << std::endl; 123 | } 124 | } 125 | 126 | }; 127 | 128 | } -------------------------------------------------------------------------------- /src/geoflow/AttributeCalcNode.cpp: -------------------------------------------------------------------------------- 1 | #include "core_nodes.hpp" 2 | #include "ExpressionComputer.hpp" 3 | 4 | namespace geoflow::nodes::core { 5 | 6 | void FloatExprNode::process(){ 7 | auto computer = createExpressionComputer(); 8 | 9 | computer->add_symbols(manager); 10 | computer->add_expression("result", expr_string_); 11 | 12 | output("value").set(computer->eval("result")); 13 | }; 14 | 15 | void AttributeCalcNode::process() { 16 | 17 | auto computer = createExpressionComputer(); 18 | 19 | computer->add_symbols(manager); 20 | 21 | // add input attributes 22 | for (auto& iterm : poly_input("attributes").sub_terminals()) { 23 | if(iterm->accepts_type(typeid(std::string))) { 24 | computer->add_symbol(iterm->get_full_name(), "a.", ""); 25 | } else { 26 | computer->add_symbol(iterm->get_full_name(), "a.", 0); 27 | } 28 | } 29 | 30 | if(as_string_) { 31 | computer->add_str_result_symbol(); 32 | } 33 | 34 | for(auto& [name, expr_str] : attribute_expressions) { 35 | computer->add_expression(name, expr_str); 36 | if(as_string_) { 37 | poly_output("attributes").add_vector(name, typeid(std::string)); 38 | } else { 39 | poly_output("attributes").add_vector(name, typeid(float)); 40 | } 41 | } 42 | 43 | size_t isize = poly_input("attributes").size(); 44 | // std::cout << "Expression results:" << std::endl; 45 | for(size_t i=0; iget_full_name(); 49 | if (iterm->accepts_type(typeid(float))) { 50 | computer->set_symbol(name, iterm->get(i)); 51 | } else if (iterm->accepts_type(typeid(int))) { 52 | computer->set_symbol(name, float(iterm->get(i))); 53 | } else if (iterm->accepts_type(typeid(bool))) { 54 | computer->set_symbol(name, float(iterm->get(i))); 55 | } else if (iterm->accepts_type(typeid(std::string))) { 56 | computer->set_symbol(name, iterm->get(i)); 57 | } 58 | } 59 | 60 | for(auto& [name, expr] : attribute_expressions) { 61 | // assign expression vars/consts 62 | // evaluate expression 63 | // push result to output 64 | // std::cout << result << std::endl; 65 | if(as_string_) { 66 | poly_output("attributes").sub_terminal(name).push_back(computer->eval_str(name)); 67 | } else { 68 | poly_output("attributes").sub_terminal(name).push_back(float(computer->eval(name))); 69 | } 70 | } 71 | } 72 | }; 73 | 74 | } -------------------------------------------------------------------------------- /src/geoflow/ExpressionComputer.cpp: -------------------------------------------------------------------------------- 1 | #include "exprtk.hpp" 2 | #include 3 | #include "ExpressionComputer.hpp" 4 | 5 | namespace geoflow { 6 | 7 | class ExpressionComputer : public ExpressionComputerInterface { 8 | typedef exprtk::symbol_table symbol_table_t; 9 | typedef exprtk::expression expression_t; 10 | typedef exprtk::parser parser_t; 11 | 12 | parser_t parser; 13 | symbol_table_t symbol_table; 14 | 15 | std::string str_result_; 16 | 17 | std::unordered_map symbols; 18 | std::unordered_map string_symbols; 19 | std::unordered_map expressions; 20 | 21 | void add_expression(const std::string& name, const std::string& expr_str) override { 22 | expression_t expression; 23 | expression.register_symbol_table(symbol_table); 24 | if (!parser.compile(expr_str, expression)) 25 | { 26 | throw gfException("Exprtk could not compile expression: " + expr_str); 27 | } 28 | expressions.insert({name, expression}); 29 | 30 | }; 31 | 32 | void add_symbol(const std::string& name, const std::string& prefix, float value) override { 33 | float& dval = (symbols.insert({prefix+name, value}).first)->second; // get iterator, then value 34 | symbol_table.add_variable(prefix+name, dval); // or use add_constants ? 35 | }; 36 | void add_symbol(const std::string& name, const std::string& prefix, std::string value) override { 37 | std::string& dval = (string_symbols.insert({prefix+name, value}).first)->second; // get iterator, then value 38 | symbol_table.add_stringvar(prefix+name, dval); // or use add_constants ? 39 | }; 40 | void add_str_result_symbol() { 41 | symbol_table.add_stringvar("str_result", str_result_); 42 | }; 43 | 44 | void add_symbols(NodeManager& manager) override { 45 | for (auto& [key,param_ptr] : manager.global_flowchart_params) { 46 | if(param_ptr->is_type(typeid(int))){ 47 | float val = static_cast*>(param_ptr.get())->get(); 48 | add_symbol(key, "g.", val); 49 | } else if(param_ptr->is_type(typeid(float))){ 50 | float val = static_cast*>(param_ptr.get())->get(); 51 | add_symbol(key, "g.", val); 52 | } else if(param_ptr->is_type(typeid(bool))){ 53 | float val = static_cast*>(param_ptr.get())->get(); 54 | add_symbol(key, "g.", val); 55 | } else if(param_ptr->is_type(typeid(std::string))){ 56 | auto* val = static_cast*>(param_ptr.get()); 57 | add_symbol(key, "g.", val->get()); // or use add_constants ? 58 | } 59 | } 60 | }; 61 | 62 | void set_symbol(const std::string& name, const float& value) override { 63 | symbols[name] = value; 64 | }; 65 | 66 | void set_symbol(const std::string& name, const std::string& value) override { 67 | string_symbols[name] = value; 68 | }; 69 | // T& get_symbol(name); 70 | 71 | float eval(const std::string& name) override { 72 | return expressions[name].value(); 73 | }; 74 | std::string eval_str(const std::string& name) override { 75 | expressions[name].value(); 76 | return str_result_; 77 | }; 78 | 79 | }; 80 | 81 | std::unique_ptr createExpressionComputer() { 82 | return std::make_unique(); 83 | }; 84 | 85 | } -------------------------------------------------------------------------------- /src/geoflow/ExpressionComputer.hpp: -------------------------------------------------------------------------------- 1 | #include "geoflow.hpp" 2 | 3 | namespace geoflow { 4 | 5 | class ExpressionComputerInterface { 6 | 7 | public: 8 | virtual void add_expression(const std::string& name, const std::string& expr_string) = 0; 9 | virtual void add_symbol(const std::string& name, const std::string& prefix, float value=0) = 0; 10 | virtual void add_symbol(const std::string& name, const std::string& prefix, std::string value="") = 0; 11 | virtual void add_str_result_symbol() = 0; 12 | virtual void add_symbols(NodeManager& manager) = 0; 13 | virtual void set_symbol(const std::string& name, const float& value) = 0; 14 | virtual void set_symbol(const std::string& name, const std::string& value) = 0; 15 | // T& get_symbol(name) = 0; 16 | virtual float eval(const std::string& name) = 0; 17 | virtual std::string eval_str(const std::string& name) = 0; 18 | 19 | }; 20 | 21 | std::unique_ptr createExpressionComputer(); 22 | } -------------------------------------------------------------------------------- /src/geoflow/api.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #include "api.hpp" 18 | #include 19 | #include 20 | 21 | namespace geoflow { 22 | 23 | GeoflowRunner::GeoflowRunner(std::string flowchart_json, bool verbose) 24 | : verbose(verbose), flowchart(node_registers), plugin_manager(createPluginManager()) 25 | { 26 | // load node registers from libraries 27 | auto R_core = NodeRegister::create("Core"); 28 | R_core->register_node("NestedFlowchart"); 29 | R_core->register_node("Int"); 30 | R_core->register_node("Float"); 31 | R_core->register_node("Bool"); 32 | R_core->register_node("Text"); 33 | R_core->register_node("TextWriter"); 34 | node_registers.emplace(R_core); 35 | 36 | 37 | std::string plugin_folder = GF_PLUGIN_FOLDER; 38 | if(const char* env_p = std::getenv("GF_PLUGIN_FOLDER")) { 39 | plugin_folder = env_p; 40 | } 41 | 42 | if(fs::exists(plugin_folder)) { 43 | plugin_manager->load(plugin_folder, node_registers, verbose); 44 | } else { 45 | throw gfException("Plugin folder does not exist: " + plugin_folder); 46 | }; 47 | 48 | 49 | // check for flowchart 50 | // flowchart = NodeManager(node_registers); 51 | if (!fs::exists(flowchart_json)) { 52 | throw gfException("no such flowchart_file: " + flowchart_json); 53 | } 54 | flowchart.load_json(flowchart_json); 55 | }; 56 | GeoflowRunner::~GeoflowRunner() { 57 | // NOTICE that we first must destruct any related node_registers before we can unload the plugin_manager! 58 | plugin_manager->unload(verbose); 59 | } 60 | 61 | /*========================================================================================== 62 | Run the flowchart 63 | ==========================================================================================*/ 64 | void GeoflowRunner::run() { 65 | 66 | // currently there is a lot of loggin and debug messages printed. We can turn this off using this: 67 | if( verbose ) { 68 | std::clog.setstate(std::ios_base::failbit); 69 | std::cout.setstate(std::ios_base::failbit); 70 | // std::cerr.setstate(std::ios_base::failbit); 71 | } 72 | 73 | flowchart.run_all(); 74 | 75 | if( verbose ) { 76 | std::clog.clear(); 77 | std::cout.clear(); 78 | // std::cerr.clear(); 79 | } 80 | }; 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/geoflow/api.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #include 18 | 19 | namespace geoflow { 20 | 21 | class GeoflowRunner { 22 | protected: 23 | bool verbose = false; 24 | std::unique_ptr plugin_manager; 25 | NodeRegisterMap node_registers; 26 | NodeManager flowchart; 27 | 28 | public: 29 | GeoflowRunner(std::string flowchart_json, bool verbose); 30 | ~GeoflowRunner(); 31 | void run(); 32 | 33 | }; 34 | 35 | } -------------------------------------------------------------------------------- /src/geoflow/common.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace geoflow 31 | { 32 | 33 | typedef std::array arr2f; 34 | typedef std::array arr2d; 35 | typedef std::array arr3f; 36 | typedef std::array arr3d; 37 | typedef std::vector vec3f; 38 | typedef std::vector> vec2f; 39 | typedef std::vector vec1i; 40 | typedef std::vector vec1b; 41 | typedef std::vector vec1f; 42 | typedef std::vector vec1ui; 43 | typedef std::vector vec1s; 44 | 45 | // Attribute types 46 | typedef std::variant attribute_value; 47 | typedef std::unordered_map> AttributeMap; 48 | 49 | typedef std::variant attribute_vec; 50 | typedef std::unordered_map attribute_vec_map; 51 | class AttributeVecMap 52 | { 53 | attribute_vec_map attribs_; 54 | template bool is_attribute_type(const std::string& name) const; 55 | template const T* get_attribute(const std::string& name) const; 56 | template T* get_attribute(const std::string& name); 57 | 58 | public: 59 | attribute_vec_map& get_attributes(); 60 | const attribute_vec_map& get_attributes() const; 61 | bool has_attributes() const; 62 | 63 | bool is_attribute_vec1b(const std::string& name) const; 64 | bool is_attribute_vec1i(const std::string& name) const; 65 | bool is_attribute_vec1s(const std::string& name) const; 66 | bool is_attribute_vec1f(const std::string& name) const; 67 | bool is_attribute_vec3f(const std::string& name) const; 68 | 69 | const vec1b* get_attribute_vec1b(const std::string& name) const; 70 | const vec1i* get_attribute_vec1i(const std::string& name) const; 71 | const vec1s* get_attribute_vec1s(const std::string& name) const; 72 | const vec1f* get_attribute_vec1f(const std::string& name) const; 73 | const vec3f* get_attribute_vec3f(const std::string& name) const; 74 | 75 | vec1b* get_attribute_vec1b(const std::string& name); 76 | vec1i* get_attribute_vec1i(const std::string& name); 77 | vec1s* get_attribute_vec1s(const std::string& name); 78 | vec1f* get_attribute_vec1f(const std::string& name); 79 | vec3f* get_attribute_vec3f(const std::string& name); 80 | 81 | vec1b& add_attribute_vec1b(const std::string& name); 82 | vec1i& add_attribute_vec1i(const std::string& name); 83 | vec1s& add_attribute_vec1s(const std::string& name); 84 | vec1f& add_attribute_vec1f(const std::string& name); 85 | vec3f& add_attribute_vec3f(const std::string& name); 86 | }; 87 | 88 | class Box 89 | { 90 | private: 91 | std::array pmin, pmax; 92 | bool just_cleared; 93 | 94 | public: 95 | Box(); 96 | 97 | std::array min() const; 98 | std::array max() const; 99 | float size_x() const; 100 | float size_y() const; 101 | void set(std::array nmin, std::array nmax); 102 | void add(float p[]); 103 | void add(double p[]); 104 | void add(arr3f a); 105 | void add(arr3d a); 106 | void add(const Box &otherBox); 107 | void add(Box &otherBox); 108 | void add(const vec3f &vec); 109 | void add(vec3f &vec); 110 | bool intersects(Box &otherBox) const; 111 | void clear(); 112 | bool isEmpty() const; 113 | arr3f center() const; 114 | }; 115 | 116 | class Geometry 117 | { 118 | protected: 119 | std::optional bbox; 120 | virtual void compute_box() = 0; 121 | 122 | public: 123 | virtual size_t vertex_count() const = 0; 124 | virtual const Box &box(); 125 | size_t dimension(); 126 | virtual float *get_data_ptr() = 0; 127 | }; 128 | 129 | // geometry types: 130 | // typedef arr3f Point; 131 | typedef std::array Triangle; 132 | // typedef std::array Segment; 133 | 134 | class LinearRing : public vec3f, public Geometry 135 | { 136 | std::vector interior_rings_; 137 | protected: 138 | void compute_box(); 139 | 140 | public: 141 | size_t vertex_count() const; 142 | float *get_data_ptr(); 143 | std::vector& interior_rings(); 144 | const std::vector& interior_rings() const; 145 | float signed_area() const; 146 | }; 147 | class Segment : public std::array, public Geometry 148 | { 149 | protected: 150 | void compute_box(); 151 | 152 | public: 153 | // using std::array::array; 154 | Segment(); 155 | Segment(arr3f source, arr3f target); 156 | size_t vertex_count() const; 157 | float *get_data_ptr(); 158 | }; 159 | 160 | // class Polygon : public LinearRing 161 | // { 162 | // public: 163 | // std::vector interior_rings_; 164 | // }; 165 | 166 | class LineString : public vec3f, public Geometry 167 | { 168 | protected: 169 | void compute_box(); 170 | 171 | public: 172 | size_t vertex_count() const; 173 | float *get_data_ptr(); 174 | }; 175 | template 176 | class GeometryCollection : public Geometry, public std::vector 177 | { 178 | }; 179 | 180 | class TriangleCollection : public GeometryCollection 181 | { 182 | public: 183 | size_t vertex_count() const; 184 | virtual void compute_box(); 185 | float *get_data_ptr(); 186 | }; 187 | 188 | // MultiTriangleCollection stores a collection of TriangleCollections along with 189 | // attributes for each TriangleCollection. The vector of TriangleCollections 190 | // `trianglecollections_` and the vector of AttributeMaps `attributes_` 191 | // supposed to have the same length when attributes are present, however this is 192 | // not enforced. The `attributes_` can be empty. 193 | class MultiTriangleCollection 194 | { 195 | std::vector trianglecollections_; 196 | std::vector attributes_; 197 | 198 | public: 199 | std::vector building_part_ids_; 200 | 201 | void push_back(TriangleCollection & trianglecollection); 202 | void push_back(AttributeMap & attributemap); 203 | std::vector& get_tricollections(); 204 | const std::vector& get_tricollections() const; 205 | std::vector& get_attributes(); 206 | const std::vector& get_attributes() const; 207 | TriangleCollection& tri_at(size_t i); 208 | const TriangleCollection& tri_at(size_t i) const; 209 | AttributeMap& attr_at(size_t i); 210 | const AttributeMap& attr_at(size_t i) const; 211 | size_t tri_size() const; 212 | size_t attr_size() const; 213 | bool has_attributes(); 214 | bool has_attributes() const; 215 | }; 216 | 217 | class SegmentCollection : public GeometryCollection>, public AttributeVecMap 218 | { 219 | public: 220 | size_t vertex_count() const; 221 | virtual void compute_box(); 222 | float *get_data_ptr(); 223 | }; 224 | 225 | class PointCollection : public GeometryCollection, public AttributeVecMap 226 | { 227 | public: 228 | size_t vertex_count() const; 229 | virtual void compute_box(); 230 | float *get_data_ptr(); 231 | }; 232 | 233 | class LineStringCollection : public GeometryCollection 234 | { 235 | public: 236 | size_t vertex_count() const; 237 | void compute_box(); 238 | float *get_data_ptr(); 239 | }; 240 | 241 | class LinearRingCollection : public GeometryCollection 242 | { 243 | public: 244 | size_t vertex_count() const; 245 | void compute_box(); 246 | float *get_data_ptr(); 247 | }; 248 | 249 | 250 | // struct AttributeVec { 251 | // AttributeVec(std::type_index ttype) : value_type(ttype) {}; 252 | // std::vector values; 253 | // std::type_index value_type; 254 | // }; 255 | 256 | // class Mesh : public Geometry { 257 | // use indexed vertices? 258 | class Mesh { 259 | std::vector polygons_; 260 | std::vector labels_; 261 | // std::unordered_map attributes_; 262 | 263 | public: 264 | // Mesh() {}; 265 | 266 | void push_polygon(LinearRing& polygon, int label); 267 | // template void create_attribute_field(std::string name) { 268 | // attributes_.emplace(name, typeid(T)); 269 | // } 270 | // void push_attribute(std::string name, std::any value); 271 | 272 | std::vector& get_polygons(); 273 | const std::vector& get_polygons() const; 274 | std::vector& get_labels(); 275 | const std::vector& get_labels() const; 276 | // std::unordered_map& get_attributes(); 277 | // const std::unordered_map& get_attributes() const; 278 | }; 279 | 280 | // modelled after https://gdal.org/api/ogrfeature_cpp.html#_CPPv4NK10OGRFeature18GetFieldAsDateTimeEiPiPiPiPiPiPiPi 281 | struct Date { 282 | int year; 283 | int month; 284 | int day; 285 | std::time_t to_time_t(); 286 | std::string format_to_ietf(); 287 | }; 288 | struct Time { 289 | int hour; 290 | int minute; 291 | float second; 292 | int timeZone; 293 | }; 294 | struct DateTime { 295 | Date date; 296 | Time time; 297 | std::time_t to_time_t(); 298 | std::string format_to_ietf(); 299 | }; 300 | 301 | struct Image { 302 | std::vector array; 303 | size_t dim_x; 304 | size_t dim_y; 305 | float min_x; 306 | float min_y; 307 | float cellsize; 308 | float nodataval; 309 | }; 310 | 311 | std::vector split_string(const std::string& s, std::string delimiter); 312 | 313 | } // namespace geoflow 314 | -------------------------------------------------------------------------------- /src/geoflow/gui/ImNodes.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Rokas Kupstys. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | 23 | #pragma once 24 | 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | // 31 | // Appearance can be styled by altering ImGui style before calls to ImNodes::*, 32 | // Style: 33 | // * FrameRounding - node border rounding. 34 | // * ItemInnerSpacing - spacing between node borders and node content. 35 | // 36 | 37 | namespace ImNodes 38 | { 39 | 40 | enum StyleColor 41 | { 42 | ColCanvasLines, 43 | ColNodeBg, 44 | ColNodeActiveBg, 45 | ColNodeBorder, 46 | ColConnection, 47 | ColConnectionActive, 48 | ColSelectBg, 49 | ColSelectBorder, 50 | ColNodeWaitingBorder, 51 | ColNodeReadyBorder, 52 | ColNodeDoneBorder, 53 | ColMax 54 | }; 55 | 56 | struct _CanvasStateImpl; 57 | 58 | struct IMGUI_API CanvasState 59 | { 60 | /// Current zoom of canvas. 61 | float zoom = 1.0; 62 | /// Current scroll offset of canvas. 63 | ImVec2 offset{}; 64 | /// bounding box of nodes 65 | ImRect nodes_bbox{}; 66 | bool nodes_bbox_empty; 67 | bool center_on_nodes = false; 68 | /// 69 | ImVec2 new_creation_mouse_pos; 70 | /// Colors used to style elements of this canvas. 71 | ImColor colors[StyleColor::ColMax]; 72 | /// Style parameters 73 | struct 74 | { 75 | /// Thickness of curves that connect slots together. 76 | float curve_thickness = 5.f; 77 | /// Indent connection into slot widget a little. Useful when slot content covers connection end with some kind 78 | /// of icon (like a circle) and then no seam between icon and connection end is visible. 79 | float connection_indent = 1.f; 80 | } style{}; 81 | /// Implementation detail. 82 | _CanvasStateImpl* _impl = nullptr; 83 | 84 | CanvasState() noexcept; 85 | ~CanvasState(); 86 | }; 87 | 88 | /// Create a node graph canvas in current window. 89 | IMGUI_API void BeginCanvas(CanvasState* canvas); 90 | /// Terminate a node graph canvas that was created by calling BeginCanvas(). 91 | IMGUI_API void EndCanvas(); 92 | /// Begin rendering of node in a graph. Render node content when returns `true`. 93 | IMGUI_API bool BeginNode(void* node_id, ImVec2* pos, bool* selected); 94 | /// Terminates current node. Should be called regardless of BeginNode() returns value. 95 | IMGUI_API void EndNode(); 96 | /// Specified node will be positioned at the mouse cursor on next frame. Call when new node is created. 97 | IMGUI_API void AutoPositionNode(void* node_id); 98 | /// Returns `true` when new connection is made. Connection information is returned into `connection` parameter. Must be 99 | /// called at id scope created by BeginNode(). 100 | IMGUI_API bool GetNewConnection(void** input_node, const char** input_slot_title, void** output_node, const char** output_slot_title); 101 | /// Get information of connection that is being made and has only one end connected. Returns true when pending connection exists, false otherwise. 102 | IMGUI_API bool GetPendingConnection(void** node_id, const char** slot_title, int* slot_kind); 103 | /// Render a connection. Returns `true` when connection is present, `false` if it is deleted. 104 | IMGUI_API bool Connection(void* input_node, const char* input_slot, void* output_node, const char* output_slot); 105 | /// Returns active canvas state when called between BeginCanvas() and EndCanvas(). Returns nullptr otherwise. This function is not thread-safe. 106 | IMGUI_API CanvasState* GetCurrentCanvas(); 107 | /// Convert kind id to input type. 108 | inline int InputSlotKind(int kind) { return kind > 0 ? -kind : kind; } 109 | /// Convert kind id to output type. 110 | inline int OutputSlotKind(int kind) { return kind < 0 ? -kind : kind; } 111 | /// Returns `true` if `kind` is from input slot. 112 | inline bool IsInputSlotKind(int kind) { return kind < 0; } 113 | /// Returns `true` if `kind` is from output slot. 114 | inline bool IsOutputSlotKind(int kind) { return kind > 0; } 115 | /// Begins slot region. Kind is unique value indicating slot type. Negative values mean input slots, positive - output slots. 116 | IMGUI_API bool BeginSlot(void* slot_id, const char* title, int kind); 117 | /// Rends rendering of slot. Call only if Begin*Slot() returned `true`. 118 | IMGUI_API void EndSlot(); 119 | /// Returns `true` if curve connected to current slot is hovered. Call between `Begin*Slot()` and `EndSlot()`. In-progress 120 | /// connection is considered hovered as well. 121 | IMGUI_API bool IsSlotCurveHovered(); 122 | /// Returns `true` when new slot is being created and current slot can be connected. Call between `Begin*Slot()` and `EndSlot()`. 123 | IMGUI_API bool IsConnectingCompatibleSlot(); 124 | 125 | } // namespace ImNodes 126 | -------------------------------------------------------------------------------- /src/geoflow/gui/ImNodesEz.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Rokas Kupstys. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | #ifndef IMGUI_DEFINE_MATH_OPERATORS 23 | # define IMGUI_DEFINE_MATH_OPERATORS 24 | #endif 25 | #include "ImNodesEz.h" 26 | #include 27 | 28 | namespace ImNodes 29 | { 30 | 31 | extern CanvasState* gCanvas; 32 | 33 | namespace Ez 34 | { 35 | 36 | bool BeginNode(void* node_id, ImVec2* pos, bool* selected) 37 | { 38 | bool result = ImNodes::BeginNode(node_id, pos, selected); 39 | auto gf_node = (geoflow::Node*)node_id; 40 | auto title = gf_node->get_name().c_str(); 41 | 42 | auto* storage = ImGui::GetStateStorage(); 43 | float node_width = storage->GetFloat(ImGui::GetID("node-width")); 44 | if (node_width > 0) 45 | { 46 | // Center node title 47 | ImVec2 title_size = ImGui::CalcTextSize(title); 48 | if (node_width > title_size.x) 49 | ImGui::SetCursorPosX(ImGui::GetCursorPosX() + node_width / 2.f - title_size.x / 2.f); 50 | } 51 | 52 | // Render node title 53 | ImGui::TextUnformatted(title); 54 | // ImGui::SameLine(); 55 | // ImGui::TextDisabled("(?)"); 56 | if (ImGui::IsItemHovered()) 57 | { 58 | ImGui::BeginTooltip(); 59 | ImGui::Text("%s [%s]", 60 | gf_node->get_type_name().c_str(), 61 | gf_node->get_register().get_name().c_str() 62 | ); 63 | ImGui::EndTooltip(); 64 | } 65 | 66 | ImGui::BeginGroup(); 67 | return result; 68 | } 69 | 70 | void EndNode() 71 | { 72 | // Store node width which is needed for centering title. 73 | auto* storage = ImGui::GetStateStorage(); 74 | ImGui::EndGroup(); 75 | storage->SetFloat(ImGui::GetID("node-width"), ImGui::GetItemRectSize().x); 76 | ImNodes::EndNode(); 77 | } 78 | 79 | bool Slot(geoflow::gfTerminal* term, int kind) 80 | { 81 | auto* storage = ImGui::GetStateStorage(); 82 | const auto& style = ImGui::GetStyle(); 83 | const float CIRCLE_RADIUS = 4.f * gCanvas->zoom; 84 | auto title = term->get_name().c_str(); 85 | ImVec2 title_size = ImGui::CalcTextSize(title); 86 | // Pull entire slot a little bit out of the edge so that curves connect into int without visible seams 87 | float item_offset_x = style.ItemSpacing.x * gCanvas->zoom; 88 | if (!ImNodes::IsOutputSlotKind(kind)) 89 | item_offset_x = -item_offset_x; 90 | ImGui::SetCursorScreenPos(ImGui::GetCursorScreenPos() + ImVec2{item_offset_x, 0}); 91 | 92 | if (ImNodes::BeginSlot(term, title, kind)) 93 | { 94 | auto* draw_lists = ImGui::GetWindowDrawList(); 95 | 96 | // Slot appearance can be altered depending on curve hovering state. 97 | bool is_active = ImNodes::IsSlotCurveHovered() || 98 | (ImNodes::IsConnectingCompatibleSlot() /*&& !IsAlreadyConnectedWithPendingConnection(title, kind)*/); 99 | 100 | ImColor color = gCanvas->colors[is_active ? ImNodes::ColConnectionActive : ImNodes::ColConnection]; 101 | 102 | ImGui::PushStyleColor(ImGuiCol_Text, color.Value); 103 | 104 | if (ImNodes::IsOutputSlotKind(kind)) 105 | { 106 | // Align output slots to the right edge of the node. 107 | ImGuiID max_width_id = ImGui::GetID("output-max-title-width"); 108 | float output_max_title_width = ImMax(storage->GetFloat(max_width_id, title_size.x), title_size.x); 109 | storage->SetFloat(max_width_id, output_max_title_width); 110 | float offset = (output_max_title_width + style.ItemSpacing.x) - title_size.x; 111 | ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offset); 112 | 113 | ImGui::TextUnformatted(title); 114 | ImGui::SameLine(); 115 | } 116 | 117 | ImRect circle_rect{ 118 | ImGui::GetCursorScreenPos(), 119 | ImGui::GetCursorScreenPos() + ImVec2{CIRCLE_RADIUS * 2, CIRCLE_RADIUS * 2} 120 | }; 121 | // Vertical-align circle in the middle of the line. 122 | float circle_offset_y = title_size.y / 2.f - CIRCLE_RADIUS; 123 | circle_rect.Min.y += circle_offset_y; 124 | circle_rect.Max.y += circle_offset_y; 125 | auto status_color = gCanvas->colors[term->has_data() ? ImNodes::ColNodeDoneBorder : ImNodes::ColNodeWaitingBorder]; 126 | draw_lists->AddCircleFilled(circle_rect.GetCenter(), CIRCLE_RADIUS, color); 127 | draw_lists->AddCircle(circle_rect.GetCenter(), CIRCLE_RADIUS, status_color, 12, term->is_marked()?4.0f:2.0f); 128 | 129 | ImGui::ItemSize(circle_rect.GetSize()); 130 | ImGui::ItemAdd(circle_rect, ImGui::GetID(title)); 131 | 132 | if (ImGui::IsItemHovered()) { 133 | if(ImGui::IsMouseDoubleClicked(0) && 134 | !ImGui::IsMouseDragging(1) 135 | ) { 136 | // ImGui::OpenPopup("TerminalActionsContextMenu"); 137 | term->set_marked(!term->is_marked()); 138 | } else { 139 | ImGui::BeginTooltip(); 140 | ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f,1.0f,1.0f,1.0f)); 141 | // ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); 142 | if (term->get_side()==geoflow::GF_IN) { 143 | auto* it = (geoflow::gfInputTerminal*) term; 144 | ImGui::Text("Input %s", it->is_optional() ? "(optional)" : ""); 145 | } else { 146 | auto* ot = (geoflow::gfOutputTerminal*) term; 147 | ImGui::Text("Output (%lu connections)", ot->get_connections().size()); 148 | } 149 | ImGui::Text("Is touched %s", term->is_touched() ? "yes" : "no"); 150 | ImGui::Text("Has connection %s", term->has_connection() ? "yes" : "no"); 151 | ImGui::Text("Has data: %s", term->has_data() ? "yes" : "no"); 152 | ImGui::Text("Marked: %s", term->is_marked() ? "yes" : "no"); 153 | if (term->get_family()==geoflow::GF_SINGLE_FEATURE ) { 154 | ImGui::TextUnformatted("Family: Single Feature"); 155 | if(term->has_data()) { 156 | if (term->get_side()==geoflow::GF_IN) { 157 | auto* it = (geoflow::gfSingleFeatureInputTerminal*) term; 158 | ImGui::SameLine(); ImGui::Text("(size: %lu)", it->size()); 159 | } else{ 160 | auto* ot = (geoflow::gfSingleFeatureOutputTerminal*) term; 161 | ImGui::SameLine(); ImGui::Text("(size: %lu)", ot->size()); 162 | } 163 | } 164 | } else if (term->get_family()==geoflow::GF_MULTI_FEATURE ) { 165 | if(term->get_side()==geoflow::GF_IN) { 166 | ImGui::TextUnformatted("Family: Multi Feature"); 167 | auto* it = (geoflow::gfMultiFeatureInputTerminal*) term; 168 | for (auto& subterm : it->sub_terminals()) { 169 | ImGui::Text(" %lu %s, ", subterm->size(), subterm->get_name().c_str()); 170 | // ImGui::Text(" %s)", subterm->get_type().name()); 171 | } 172 | } else { 173 | ImGui::TextUnformatted("Family: Multi Feature"); 174 | auto* it = (geoflow::gfMultiFeatureOutputTerminal*) term; 175 | for (auto& [name, subterm] : it->sub_terminals()) { 176 | ImGui::Text(" %lu %s, ", subterm->size(), subterm->get_name().c_str()); 177 | // ImGui::Text(" %s)", subterm->get_type().name()); 178 | } 179 | } 180 | } else 181 | ImGui::TextUnformatted("Family: Unknown"); 182 | 183 | ImGui::Text("Compatible types:"); 184 | for (auto& ti : term->get_types()) 185 | ImGui::Text(" %s", ti.name()); 186 | // ImGui::PopTextWrapPos(); 187 | ImGui::PopStyleColor(); 188 | ImGui::EndTooltip(); 189 | } 190 | } 191 | 192 | // if (ImGui::BeginPopup("TerminalActionsContextMenu")) 193 | // { 194 | // ImGui::Checkbox("marked", &term->is_marked()); 195 | // ImGui::EndPopup(); 196 | // } 197 | 198 | if (ImNodes::IsInputSlotKind(kind)) 199 | { 200 | ImGui::SameLine(); 201 | ImGui::TextUnformatted(title); 202 | } 203 | 204 | ImGui::PopStyleColor(); 205 | ImNodes::EndSlot(); 206 | 207 | // A dirty trick to place output slot circle on the border. 208 | ImGui::GetCurrentWindow()->DC.CursorMaxPos.x -= item_offset_x; 209 | return true; 210 | } 211 | return false; 212 | } 213 | 214 | void InputSlots(const geoflow::Node::InputTerminalMap& slots) 215 | { 216 | const auto& style = ImGui::GetStyle(); 217 | 218 | // Render input slots 219 | ImGui::BeginGroup(); 220 | { 221 | for (const auto& [name, term] : slots) { 222 | // const char* title = term->get_name().c_str(); 223 | ImNodes::Ez::Slot(&(*term), ImNodes::InputSlotKind(1)); 224 | } 225 | } 226 | ImGui::EndGroup(); 227 | 228 | // Move cursor to the next column 229 | ImGui::SetCursorScreenPos({ImGui::GetItemRectMax().x + style.ItemSpacing.x, ImGui::GetItemRectMin().y}); 230 | 231 | // Begin region for node content 232 | ImGui::BeginGroup(); 233 | } 234 | 235 | void OutputSlots(const geoflow::Node::OutputTerminalMap& slots) 236 | { 237 | const auto& style = ImGui::GetStyle(); 238 | 239 | // End region of node content 240 | ImGui::EndGroup(); 241 | 242 | // Render output slots in the next column 243 | ImGui::SetCursorScreenPos({ImGui::GetItemRectMax().x + style.ItemSpacing.x, ImGui::GetItemRectMin().y}); 244 | ImGui::BeginGroup(); 245 | { 246 | for (const auto& [name, term] : slots) { 247 | // const char* title = term->get_name().c_str(); 248 | ImNodes::Ez::Slot(&(*term), ImNodes::OutputSlotKind(1)); 249 | } 250 | } 251 | ImGui::EndGroup(); 252 | } 253 | 254 | } 255 | 256 | } 257 | -------------------------------------------------------------------------------- /src/geoflow/gui/ImNodesEz.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Rokas Kupstys. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | // 23 | #pragma once 24 | 25 | #include "ImNodes.h" 26 | #include 27 | 28 | namespace ImNodes 29 | { 30 | 31 | /// This namespace includes functions for easily creating nodes. They implement a somewhat nice node layout. If you need 32 | /// a quick solution - use easy nodes. If you want to customize node look - use lower level node functions from ImNodes.h 33 | namespace Ez 34 | { 35 | 36 | struct SlotInfo 37 | { 38 | /// Slot title, will be displayed on the node. 39 | const char* title; 40 | /// Slot kind, will be used for matching connections to slots of same kind. 41 | int kind; 42 | }; 43 | 44 | /// Begin rendering of node in a graph. Render node content when returns `true`. 45 | IMGUI_API bool BeginNode(void* node_id, ImVec2* pos, bool* selected); 46 | /// Terminates current node. Should be called regardless of BeginNode() returns value. 47 | IMGUI_API void EndNode(); 48 | /// Renders input slot region. Kind is unique value whose sign is ignored. 49 | /// This function must always be called after BeginNode() and before OutputSlots(). 50 | /// When no input slots are rendered call InputSlots(nullptr, 0); 51 | IMGUI_API void InputSlots(const geoflow::Node::InputTerminalMap& slots); 52 | 53 | /// Renders output slot region. Kind is unique value whose sign is ignored. This function must always be called after InputSlots() and function call is required (not optional). 54 | /// This function must always be called after InputSlots() and before EndNode(). 55 | /// When no input slots are rendered call OutputSlots(nullptr, 0); 56 | IMGUI_API void OutputSlots(const geoflow::Node::OutputTerminalMap& slots); 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/geoflow/gui/imgui_color_gradient.h: -------------------------------------------------------------------------------- 1 | // 2 | // imgui_color_gradient.h 3 | // imgui extension 4 | // 5 | // Created by David Gallardo on 11/06/16. 6 | 7 | /* 8 | 9 | Usage: 10 | 11 | ::GRADIENT DATA:: 12 | ImGradient gradient; 13 | 14 | ::BUTTON:: 15 | if(ImGui::GradientButton(&gradient)) 16 | { 17 | //set show editor flag to true/false 18 | } 19 | 20 | ::EDITOR:: 21 | static ImGradientMark* draggingMark = nullptr; 22 | static ImGradientMark* selectedMark = nullptr; 23 | 24 | bool updated = ImGui::GradientEditor(&gradient, draggingMark, selectedMark); 25 | 26 | ::GET A COLOR:: 27 | float color[3]; 28 | gradient.getColorAt(0.3f, color); //position from 0 to 1 29 | 30 | ::MODIFY GRADIENT WITH CODE:: 31 | gradient.getMarks().clear(); 32 | gradient.addMark(0.0f, ImColor(0.2f, 0.1f, 0.0f)); 33 | gradient.addMark(0.7f, ImColor(120, 200, 255)); 34 | 35 | ::WOOD BROWNS PRESET:: 36 | gradient.getMarks().clear(); 37 | gradient.addMark(0.0f, ImColor(0xA0, 0x79, 0x3D)); 38 | gradient.addMark(0.2f, ImColor(0xAA, 0x83, 0x47)); 39 | gradient.addMark(0.3f, ImColor(0xB4, 0x8D, 0x51)); 40 | gradient.addMark(0.4f, ImColor(0xBE, 0x97, 0x5B)); 41 | gradient.addMark(0.6f, ImColor(0xC8, 0xA1, 0x65)); 42 | gradient.addMark(0.7f, ImColor(0xD2, 0xAB, 0x6F)); 43 | gradient.addMark(0.8f, ImColor(0xDC, 0xB5, 0x79)); 44 | gradient.addMark(1.0f, ImColor(0xE6, 0xBF, 0x83)); 45 | 46 | */ 47 | 48 | #pragma once 49 | 50 | #include "imgui.h" 51 | 52 | #include 53 | 54 | struct ImGradientMark 55 | { 56 | float color[4]; 57 | float position; //0 to 1 58 | }; 59 | 60 | class ImGradient 61 | { 62 | public: 63 | ImGradient(); 64 | ~ImGradient(); 65 | 66 | void getTexture(unsigned char* tex); 67 | void getColorAt(float position, float* color) const; 68 | void addMark(float position, ImColor const color); 69 | void removeMark(ImGradientMark* mark); 70 | void refreshCache(); 71 | std::list & getMarks(){ return m_marks; } 72 | private: 73 | void computeColorAt(float position, float* color) const; 74 | std::list m_marks; 75 | float m_cachedValues[256 * 3]; 76 | }; 77 | 78 | namespace ImGui 79 | { 80 | bool GradientButton(ImGradient* gradient); 81 | 82 | bool GradientEditor(const char* label, ImGradient* gradient, 83 | ImGradientMark* & draggingMark, 84 | ImGradientMark* & selectedMark, ImVec2 bar_size=ImVec2(0,0)); 85 | 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/geoflow/gui/osdialog.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | #include "imgui.h" 17 | #include "misc/cpp/imgui_stdlib.h" 18 | #include 19 | #include 20 | #include 21 | #include "osdialog.hpp" 22 | 23 | std::optional osdialog_file(osdialog_file_action action, const char* filename, const char* filters) { 24 | osdialog_filters* filters_c=nullptr; 25 | if (filters) 26 | filters_c = osdialog_filters_parse(filters); 27 | 28 | std::optional result; 29 | char *filepath_c = osdialog_file(action, nullptr, filename, filters_c); 30 | if (filepath_c) { 31 | result = std::string(filepath_c); 32 | std::free(filepath_c); 33 | osdialog_filters_free(filters_c); 34 | } 35 | return result; 36 | }; 37 | 38 | namespace ImGui { 39 | 40 | bool FilePicker(osdialog_file_action action, std::string& picked_file, const char* filters) { 41 | bool changed = false; 42 | if (ImGui::Button("Open")) { 43 | auto result = osdialog_file(action, nullptr, filters); 44 | if (result.has_value()) { 45 | picked_file = result.value(); 46 | changed = true; 47 | } 48 | } 49 | ImGui::SameLine(); 50 | ImGui::InputText("", &picked_file); 51 | return changed; 52 | } 53 | } -------------------------------------------------------------------------------- /src/geoflow/gui/osdialog.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | #pragma once 17 | 18 | #include 19 | #include 20 | #include "osdialog.h" 21 | 22 | std::optional osdialog_file(osdialog_file_action action, const char* filename=NULL, const char* filters=NULL); 23 | 24 | namespace ImGui { 25 | bool FilePicker(osdialog_file_action action, std::string& picked_file, const char* filters=NULL); 26 | } -------------------------------------------------------------------------------- /src/geoflow/gui/parameter_widgets.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | #include "../geoflow.hpp" 17 | #include "parameter_widgets.hpp" 18 | #include "imgui.h" 19 | #include "misc/cpp/imgui_stdlib.h" 20 | #ifdef GF_BUILD_GUI_FILE_DIALOGS 21 | #include "osdialog.hpp" 22 | #endif 23 | 24 | namespace geoflow { 25 | void draw_global_parameter(Parameter* param) { 26 | if( auto* valptr = dynamic_cast*>(param)) { 27 | ImGui::InputText("?", &valptr->get_help()); 28 | ImGui::SameLine(); 29 | ImGui::DragInt(valptr->get_label().c_str(), &valptr->get()); 30 | } else if( auto* valptr = dynamic_cast*>(param)) { 31 | ImGui::InputText("?", &valptr->get_help()); 32 | ImGui::SameLine(); 33 | ImGui::DragFloat(valptr->get_label().c_str(), &valptr->get(), 0.1); 34 | } else if( auto* valptr = dynamic_cast*>(param)) { 35 | ImGui::InputText("?", &valptr->get_help()); 36 | ImGui::SameLine(); 37 | ImGui::InputText(valptr->get_label().c_str(), &valptr->get()); 38 | } else if( auto* valptr = dynamic_cast*>(param)) { 39 | ImGui::InputText("?", &valptr->get_help()); 40 | ImGui::SameLine(); 41 | ImGui::Checkbox(valptr->get_label().c_str(), &valptr->get()); 42 | } 43 | }; 44 | static void HelpMarker(const char* desc) 45 | { 46 | ImGui::TextDisabled("(?)"); 47 | if (ImGui::IsItemHovered()) 48 | { 49 | ImGui::BeginTooltip(); 50 | ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); 51 | ImGui::TextUnformatted(desc); 52 | ImGui::PopTextWrapPos(); 53 | ImGui::EndTooltip(); 54 | } 55 | } 56 | 57 | static std::string new_attr_name=""; 58 | static ImGuiComboFlags flags = 0; 59 | bool draw_parameter(Parameter* param) { 60 | bool changed=false; 61 | if( ParamTypeInt == param->get_ptype() ) { 62 | auto* valptr = static_cast(param); 63 | changed = ImGui::DragInt(valptr->get_label().c_str(), &valptr->get()); 64 | } else if( ParamTypeBool == param->get_ptype() ) { 65 | auto* valptr = static_cast(param); 66 | changed = ImGui::Checkbox(valptr->get_label().c_str(), &valptr->get()); 67 | } else if( ParamTypeBoundedFloat == param->get_ptype() ) { 68 | auto* valptr = static_cast(param); 69 | changed = ImGui::SliderFloat(valptr->get_label().c_str(), &valptr->get(), valptr->min(), valptr->max()); 70 | } else if( ParamTypeBoundedDouble == param->get_ptype() ) { 71 | auto* valptr = static_cast(param); 72 | const double dmin = valptr->min(), dmax = valptr->max(); 73 | changed = ImGui::SliderScalar(valptr->get_label().c_str(), ImGuiDataType_Double, &valptr->get(), &dmin, &dmax); 74 | } else if( ParamTypeFloatRange == param->get_ptype() ) { 75 | auto* valptr = static_cast(param); 76 | changed = ImGui::DragFloatRange2(valptr->get_label().c_str(), &valptr->get().first, &valptr->get().second); 77 | // } else if( ParamTypeFloatRange == param->get_ptype() ) { 78 | // auto* valptr = static_cast(param); 79 | // changed = ImGui::DragScalarN(valptr->get_label().c_str(), ImGuiDataType_Double, 2, &valptr->get().first, &valptr->get().second); 80 | } else if( ParamTypeIntRange == param->get_ptype() ) { 81 | auto* valptr = static_cast(param); 82 | changed = ImGui::DragIntRange2(valptr->get_label().c_str(), &valptr->get().first, &valptr->get().second); 83 | } else if( ParamTypeBoundedInt == param->get_ptype() ) { 84 | auto* valptr = static_cast(param); 85 | changed = ImGui::SliderInt(valptr->get_label().c_str(), &valptr->get(), valptr->min(), valptr->max()); 86 | } else if( ParamTypeFloat == param->get_ptype() ) { 87 | auto* valptr = static_cast(param); 88 | changed = ImGui::DragFloat(valptr->get_label().c_str(), &valptr->get(), 0.1); 89 | } else if( ParamTypeDouble == param->get_ptype() ) { 90 | auto* valptr = static_cast(param); 91 | changed = ImGui::DragScalar(valptr->get_label().c_str(), ImGuiDataType_Double, &valptr->get(), 0.1); 92 | } else if( ParamTypePath == param->get_ptype() ) { 93 | auto* valptr = static_cast(param); 94 | #ifdef GF_BUILD_GUI_FILE_DIALOGS 95 | changed = ImGui::FilePicker(OSDIALOG_OPEN, valptr->get()); 96 | ImGui::SameLine(); 97 | ImGui::Text("%s",valptr->get_label().c_str()); 98 | #else 99 | changed = ImGui::InputText(valptr->get_label().c_str(), &valptr->get()); 100 | #endif 101 | } else if( ParamTypeString == param->get_ptype() ) { 102 | auto* valptr = static_cast(param); 103 | changed = ImGui::InputText(valptr->get_label().c_str(), &valptr->get()); 104 | } else if( ParamTypeText == param->get_ptype() ) { 105 | auto* valptr = static_cast(param); 106 | changed = ImGui::InputTextMultiline(valptr->get_label().c_str(), &valptr->get(), ImVec2(ImGui::GetTextLineHeight() * 32, ImGui::GetTextLineHeight() * 16), ImGuiInputTextFlags_AllowTabInput); 107 | } else if( ParamTypeStrMapSelect == param->get_ptype() ) { 108 | auto* valptr = static_cast(param);; 109 | if (ImGui::TreeNode(valptr->get_label().c_str())) { 110 | auto& mapvalues = valptr->get(); 111 | for (auto it=mapvalues.begin(); it!=mapvalues.end(); ) { 112 | ImGui::InputTextWithHint(it->first.c_str(), "Value", &(it->second)); 113 | ImGui::SameLine(); 114 | ImGui::PushID(it->first.c_str()); 115 | if(ImGui::Button("Remove")) { 116 | mapvalues.erase(it++); 117 | } else { 118 | ++it; 119 | } 120 | ImGui::PopID(); 121 | } 122 | if (ImGui::BeginCombo("Create item", "select..", flags)) // The second parameter is the label previewed before opening the combo. 123 | { 124 | for (auto& key_option : valptr->key_options_) 125 | { 126 | if (ImGui::Selectable(key_option.c_str(), false)) { 127 | mapvalues.insert({key_option, ""}); 128 | } 129 | } 130 | ImGui::EndCombo(); 131 | } 132 | ImGui::TreePop(); 133 | } 134 | } else if( ParamTypeStrMapInput == param->get_ptype() ) { 135 | auto* valptr = static_cast(param);; 136 | if (ImGui::TreeNode(valptr->get_label().c_str())) { 137 | auto& mapvalues = valptr->get(); 138 | for (auto it=mapvalues.begin(); it!=mapvalues.end(); ) { 139 | // ImGui::InputTextWithHint(it->first.c_str(), "Value", &(it->second)); 140 | ImGui::InputTextMultiline(it->first.c_str(), &(it->second), ImVec2(ImGui::GetTextLineHeight() * 24, ImGui::GetTextLineHeight() * 10), ImGuiInputTextFlags_AllowTabInput); 141 | // ImGui::SameLine(); 142 | ImGui::PushID(it->first.c_str()); 143 | ImGui::Text("%s", it->first.c_str()); 144 | ImGui::SameLine(); 145 | if(ImGui::Button("^Remove")) { 146 | mapvalues.erase(it++); 147 | } else { 148 | ++it; 149 | } 150 | ImGui::PopID(); 151 | } 152 | 153 | ImGui::InputTextWithHint("##NewAttrName", "Attribute name", &new_attr_name); 154 | ImGui::SameLine(); 155 | if (!new_attr_name.empty()) { 156 | ImGui::PushID("##createAttr"); 157 | if(ImGui::Button("Create")) { 158 | mapvalues[new_attr_name] = ""; 159 | new_attr_name=""; 160 | } 161 | ImGui::PopID(); 162 | } 163 | ImGui::TreePop(); 164 | } 165 | } else { 166 | ImGui::Text("%s", param->get_label().c_str()); 167 | } 168 | ImGui::SameLine(); 169 | HelpMarker(param->get_help().c_str()); 170 | return changed; 171 | }; 172 | 173 | void draw_parameters(NodeHandle& node) { 174 | node->before_gui(); 175 | for(auto&& [name, param] : node->parameters) { 176 | ImGui::PushID(param.get()); 177 | if(ImGui::Button("G")) { 178 | ImGui::OpenPopup("GlobalSelector"); 179 | } 180 | ImGui::SameLine(); 181 | 182 | if (ImGui::BeginPopup("GlobalSelector")) 183 | { 184 | for (auto& [name, gparam] : node->get_manager().global_flowchart_params) 185 | { 186 | if(gparam->is_type_compatible(*param)) { 187 | if (ImGui::MenuItem(gparam->get_label().c_str())) { 188 | param->set_master(gparam); 189 | } 190 | } 191 | } 192 | if (ImGui::MenuItem("Clear")) { 193 | param->clear_master(); 194 | } 195 | ImGui::EndPopup(); 196 | } 197 | 198 | if(param->has_master()) 199 | ImGui::Text("%s = %s", param->get_label().c_str(), param->get_master().lock()->get_label().c_str()); 200 | else { 201 | bool changed = draw_parameter(param.get()); 202 | if(changed) { 203 | node->on_change_parameter(name, *param); 204 | } 205 | } 206 | ImGui::PopID(); 207 | } 208 | }; 209 | } -------------------------------------------------------------------------------- /src/geoflow/gui/parameter_widgets.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | #pragma once 17 | 18 | #include 19 | 20 | namespace geoflow { 21 | void draw_global_parameter(Parameter* param); 22 | 23 | bool draw_parameter(Parameter* param); 24 | 25 | void draw_parameters(NodeHandle& node); 26 | } -------------------------------------------------------------------------------- /src/geoflow/parameters.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "parameters.hpp" 26 | 27 | namespace geoflow { 28 | Parameter::Parameter(std::string label, std::string help, std::type_index ttype) : label_(label), help_(help), type_(ttype) {}; 29 | std::string Parameter::get_label() { 30 | return label_; 31 | } 32 | const std::string& Parameter::get_help() const { 33 | return help_; 34 | } 35 | std::string& Parameter::get_help() { 36 | return help_; 37 | } 38 | bool Parameter::is_type(std::type_index type) { 39 | return type_ == type; 40 | } 41 | bool Parameter::is_type_compatible(const Parameter& other_parameter) { 42 | return type_ == other_parameter.type_; 43 | } 44 | void Parameter::set_master(std::weak_ptr master_parameter) { 45 | if (!is_type_compatible(*master_parameter.lock())) 46 | std::cout << "Attempting to set incompatible master parameter\n"; 47 | else 48 | master_parameter_ = master_parameter; 49 | }; 50 | void Parameter::copy_value_from_master() { 51 | if(!master_parameter_.expired()) { 52 | from_json(master_parameter_.lock()->as_json()); 53 | } 54 | }; 55 | bool Parameter::has_master() const { 56 | return !master_parameter_.expired(); 57 | } 58 | void Parameter::clear_master() { 59 | master_parameter_.reset(); 60 | } 61 | std::weak_ptr Parameter::get_master() const { 62 | return master_parameter_; 63 | } 64 | 65 | template ParameterByReference::ParameterByReference(T& value, std::string label, std::string help) 66 | : value_(value), Parameter(label, help, typeid(T)) {}; 67 | template json ParameterByReference::as_json() const { 68 | return json(value_); 69 | }; 70 | template void ParameterByReference::from_json(const json& json_object) { 71 | value_ = json_object.get(); 72 | }; 73 | template T& ParameterByReference::get() { 74 | return value_; 75 | } 76 | template void ParameterByReference::set(T val) { 77 | value_ = val; 78 | } 79 | 80 | template ParameterByValue::ParameterByValue(T value, std::string label, std::string help) 81 | : value_(value), Parameter(label, help, typeid(T)) {}; 82 | template json ParameterByValue::as_json() const { 83 | return json(value_); 84 | }; 85 | template void ParameterByValue::from_json(const json& json_object) { 86 | value_ = json_object.get(); 87 | }; 88 | template T& ParameterByValue::get() { 89 | return value_; 90 | } 91 | template void ParameterByValue::set(T val) { 92 | value_ = val; 93 | } 94 | 95 | template ParameterBounded::ParameterBounded(T& val, T min, T max, std::string label, std::string help) : ParameterByReference(val, label, help), min_(min), max_(max) {}; 96 | template T ParameterBounded::min() { return min_;}; 97 | template T ParameterBounded::max() { return max_;}; 98 | template void ParameterBounded::set_bounds(T min, T max) { 99 | min_ = min; 100 | max_ = max; 101 | }; 102 | 103 | std::vector ParamSelector::get_options() { 104 | return options; 105 | } 106 | std::string ParamSelector::get_selected_option() { 107 | return options.at(value_); 108 | } 109 | 110 | ParamStrMapSelect::ParamStrMapSelect(StrMap& val, std::vector& key_options, std::string label, std::string help) : key_options_(key_options), ParameterByReference(val, label, help) {}; 111 | ParamStrMapInput::ParamStrMapInput(StrMap& val, std::string label, std::string help) : ParameterByReference(val, label, help) {}; 112 | 113 | ParamSelector::ParamSelector(std::vector options, size_t& index, std::string label, std::string help) : ParameterByReference(index, label, help) {}; 114 | 115 | template class ParameterByValue; 116 | template class ParameterByValue; 117 | template class ParameterByValue; 118 | template class ParameterByValue; 119 | template class ParameterByValue; 120 | template class ParameterByReference; 121 | template class ParameterByReference; 122 | template class ParameterByReference; 123 | template class ParameterByReference; 124 | template class ParameterByReference; 125 | template class ParameterByReference>; 126 | template class ParameterByReference>; 127 | template class ParameterByReference>; 128 | template class ParameterByReference>; 129 | template class ParameterBounded; 130 | template class ParameterBounded; 131 | template class ParameterBounded; 132 | }; -------------------------------------------------------------------------------- /src/geoflow/parameters.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | using json = nlohmann::json; 25 | 26 | namespace geoflow { 27 | enum ParamType { 28 | Undefined, 29 | ParamTypeFloat, 30 | ParamTypeDouble, 31 | ParamTypeFloatRange, 32 | ParamTypeIntRange, 33 | ParamTypeDoubleRange, 34 | ParamTypeBoundedFloat, 35 | ParamTypeBoundedDouble, 36 | ParamTypeInt, 37 | ParamTypeBoundedInt, 38 | ParamTypeBool, 39 | ParamTypePath, 40 | ParamTypeString, 41 | ParamTypeText, 42 | ParamTypeStrMapSelect, 43 | ParamTypeStrMapInput 44 | }; 45 | 46 | class Parameter { 47 | protected: 48 | std::string label_, help_; 49 | std::type_index type_; 50 | std::weak_ptr master_parameter_; 51 | public: 52 | Parameter(std::string label, std::string help, std::type_index ttype=typeid(void)); 53 | std::string get_label(); 54 | const std::string& get_help() const; 55 | std::string& get_help(); 56 | virtual json as_json() const = 0; 57 | virtual void from_json(const json& json_object) = 0; 58 | // virtual void to_string(std::string& str) const = 0; 59 | // virtual void from_string(const std::string& str) = 0; 60 | bool is_type(std::type_index type); 61 | bool is_type_compatible(const Parameter& other_parameter); 62 | void set_master(std::weak_ptr master_parameter); 63 | void copy_value_from_master(); 64 | bool has_master() const; 65 | void clear_master(); 66 | std::weak_ptr get_master() const; 67 | virtual ParamType get_ptype() { return Undefined; }; 68 | }; 69 | 70 | template class ParameterByReference : public Parameter { 71 | protected: 72 | T& value_; 73 | 74 | public: 75 | ParameterByReference(T& value, std::string label, std::string help); 76 | 77 | virtual json as_json() const override; 78 | virtual void from_json(const json& json_object) override; 79 | T& get(); 80 | void set(T val); 81 | }; 82 | template class ParameterByValue : public Parameter { 83 | protected: 84 | T value_; 85 | 86 | public: 87 | ParameterByValue(T value, std::string label, std::string help); 88 | 89 | virtual json as_json() const override; 90 | virtual void from_json(const json& json_object) override; 91 | T& get(); 92 | void set(T val); 93 | }; 94 | 95 | template class ParameterBounded : public ParameterByReference { 96 | T min_, max_; 97 | public: 98 | ParameterBounded(T& val, T min, T max, std::string label, std::string help=""); 99 | T min(); 100 | T max(); 101 | void set_bounds(T min, T max); 102 | }; 103 | 104 | class ParamFloat: public ParameterByReference { 105 | using ParameterByReference::ParameterByReference; 106 | public: 107 | ParamType get_ptype() { return ParamTypeFloat; }; 108 | }; 109 | class ParamDouble: public ParameterByReference { 110 | using ParameterByReference::ParameterByReference; 111 | public: 112 | ParamType get_ptype() { return ParamTypeDouble; }; 113 | }; 114 | class ParamFloatRange: public ParameterByReference> { 115 | using ParameterByReference::ParameterByReference; 116 | public: 117 | ParamType get_ptype() { return ParamTypeFloatRange; }; 118 | }; 119 | class ParamIntRange: public ParameterByReference> { 120 | using ParameterByReference::ParameterByReference; 121 | public: 122 | ParamType get_ptype() { return ParamTypeIntRange; }; 123 | }; 124 | class ParamDoubleRange: public ParameterByReference> { 125 | using ParameterByReference::ParameterByReference; 126 | public: 127 | ParamType get_ptype() { return ParamTypeDoubleRange; }; 128 | }; 129 | class ParamBoundedFloat: public ParameterBounded { 130 | using ParameterBounded::ParameterBounded; 131 | public: 132 | ParamType get_ptype() { return ParamTypeBoundedFloat; }; 133 | }; 134 | class ParamBoundedDouble: public ParameterBounded { 135 | using ParameterBounded::ParameterBounded; 136 | public: 137 | ParamType get_ptype() { return ParamTypeBoundedDouble; }; 138 | }; 139 | class ParamInt: public ParameterByReference { 140 | using ParameterByReference::ParameterByReference; 141 | public: 142 | ParamType get_ptype() { return ParamTypeInt; }; 143 | }; 144 | class ParamBoundedInt: public ParameterBounded { 145 | using ParameterBounded::ParameterBounded; 146 | public: 147 | ParamType get_ptype() { return ParamTypeBoundedInt; }; 148 | }; 149 | class ParamBool: public ParameterByReference { 150 | using ParameterByReference::ParameterByReference; 151 | public: 152 | ParamType get_ptype() { return ParamTypeBool; }; 153 | }; 154 | class ParamPath : public ParameterByReference { 155 | using ParameterByReference::ParameterByReference; 156 | public: 157 | ParamType get_ptype() { return ParamTypePath; }; 158 | }; 159 | class ParamString : public ParameterByReference { 160 | using ParameterByReference::ParameterByReference; 161 | public: 162 | ParamType get_ptype() { return ParamTypeString; }; 163 | }; 164 | class ParamText : public ParameterByReference { 165 | using ParameterByReference::ParameterByReference; 166 | public: 167 | ParamType get_ptype() { return ParamTypeText; }; 168 | }; 169 | 170 | typedef std::unordered_map StrMap; 171 | class ParamStrMapSelect : public ParameterByReference { 172 | public: 173 | std::vector& key_options_; 174 | ParamStrMapSelect(StrMap& val, std::vector& key_options, std::string label, std::string help=""); 175 | ParamType get_ptype() { return ParamTypeStrMapSelect; }; 176 | }; 177 | typedef ParamStrMapSelect ParamStrMap; // for compatibility 178 | class ParamStrMapInput : public ParameterByReference { 179 | public: 180 | ParamStrMapInput(StrMap& val, std::string label, std::string help=""); 181 | ParamType get_ptype() { return ParamTypeStrMapInput; }; 182 | }; 183 | 184 | class ParamSelector : public ParameterByReference { 185 | std::vector options; 186 | 187 | public: 188 | ParamSelector(std::vector options, size_t& index, std::string label, std::string help=""); 189 | 190 | std::vector get_options(); 191 | std::string get_selected_option(); 192 | }; 193 | 194 | extern template class ParameterByValue; 195 | extern template class ParameterByValue; 196 | extern template class ParameterByValue; 197 | extern template class ParameterByValue; 198 | extern template class ParameterByValue; 199 | extern template class ParameterByReference; 200 | extern template class ParameterByReference; 201 | extern template class ParameterByReference; 202 | extern template class ParameterByReference; 203 | extern template class ParameterByReference; 204 | extern template class ParameterByReference>; 205 | extern template class ParameterByReference>; 206 | extern template class ParameterByReference>; 207 | extern template class ParameterByReference>; 208 | extern template class ParameterBounded; 209 | extern template class ParameterBounded; 210 | extern template class ParameterBounded; 211 | 212 | typedef std::map> ParameterMap; 213 | } -------------------------------------------------------------------------------- /src/geoflow/plugin_manager.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | #include 17 | 18 | #include 19 | 20 | namespace geoflow { 21 | 22 | class PluginManager : public PluginManagerInterface { 23 | public: 24 | // PluginManager() {}; 25 | // ~PluginManager() { 26 | // // unload(); 27 | // }; 28 | void load(std::string& plugin_directory, NodeRegisterMap& node_registers, bool verbose=false) { 29 | for(auto& p: fs::directory_iterator(plugin_directory)) { 30 | if (p.path().extension() == GF_PLUGIN_EXTENSION) { 31 | const std::string path = p.path().string(); 32 | const std::string plugin_target_name = p.path().stem().string(); 33 | 34 | dloaders_.emplace(path, std::make_unique(path, plugin_target_name)); 35 | 36 | if (dloaders_[path]->DLOpenLib(verbose)) { 37 | if (verbose) std::cout << "Loaded " << path << std::endl; 38 | auto [reg, success] = node_registers.emplace( dloaders_[path]->DLGetInstance() ); 39 | } else { 40 | dloaders_.erase(path); 41 | } 42 | } 43 | } 44 | } 45 | 46 | void unload(bool verbose=false) { 47 | for (auto& [path, loader] : dloaders_) { 48 | if (verbose) std::cout << "Unloading " << path << "\n"; 49 | loader->DLCloseLib(verbose); 50 | } 51 | } 52 | 53 | private: 54 | typedef dlloader::DLLoader DLLoader; 55 | std::unordered_map> dloaders_; 56 | 57 | }; 58 | std::unique_ptr createPluginManager(){ 59 | return std::make_unique(); 60 | }; 61 | 62 | } -------------------------------------------------------------------------------- /src/geoflow/projHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "geoflow.hpp" 2 | #include "projHelper.hpp" 3 | #include 4 | #include 5 | 6 | namespace geoflow { 7 | static const char *proj_wkt_options[] = {"MULTILINE=NO", NULL}; 8 | 9 | struct projHelper : public projHelperInterface { 10 | 11 | projHelper(NodeManager& manager) : projHelperInterface(manager) { 12 | #ifdef _WIN32 13 | if(const char* env_p = std::getenv("GF_INSTALL_ROOT")) { 14 | std::string path = env_p; 15 | path += "\\share\\proj"; 16 | auto pathc = path.c_str(); 17 | proj_context_set_search_paths(nullptr, 1, &pathc); 18 | std::cout << "Setting PROJ DATA dir to " << path << "(default context)\n"; 19 | } 20 | #endif 21 | } 22 | 23 | PJ_CONTEXT *projContext = nullptr; 24 | PJ *processCRS = nullptr; 25 | PJ *sCRS = nullptr; 26 | PJ *tCRS = nullptr; 27 | PJ *projFwdTransform = nullptr; 28 | PJ *projRevTransform = nullptr; 29 | 30 | void proj_clear() override { 31 | data_offset.reset(); 32 | proj_context_destroy(projContext); 33 | projContext = proj_context_create(); 34 | proj_destroy(processCRS); 35 | processCRS = nullptr; 36 | clear_fwd_crs_transform(); 37 | clear_rev_crs_transform(); 38 | }; 39 | void proj_construct() override { 40 | projContext = proj_context_create(); 41 | 42 | #ifdef _WIN32 43 | if(const char* env_p = std::getenv("GF_INSTALL_ROOT")) { 44 | std::string path = env_p; 45 | path += "\\share\\proj"; 46 | auto pathc = path.c_str(); 47 | proj_context_set_search_paths(projContext, 1, &pathc); 48 | std::cout << "Setting PROJ DATA dir to " << path << "\n"; 49 | } 50 | #endif 51 | }; 52 | void proj_clone_from(const projHelperInterface& other_proj_helper) override { 53 | const projHelper* other_proj = static_cast(&other_proj_helper); 54 | data_offset = *other_proj->data_offset; 55 | projContext = proj_context_clone(other_proj->projContext); 56 | #ifdef _WIN32 57 | if(const char* env_p = std::getenv("GF_INSTALL_ROOT")) { 58 | std::string path = env_p; 59 | path += "\\share\\proj"; 60 | auto pathc = path.c_str(); 61 | proj_context_set_search_paths(projContext, 1, &pathc); 62 | std::cout << "Setting PROJ DATA dir to " << path << "\n"; 63 | } 64 | #endif 65 | if(other_proj->processCRS) processCRS = proj_clone(projContext, other_proj->processCRS); 66 | if(other_proj->projFwdTransform) projFwdTransform = proj_clone(projContext, other_proj->projFwdTransform); 67 | if(other_proj->projRevTransform) projRevTransform = proj_clone(projContext, other_proj->projRevTransform); 68 | }; 69 | 70 | arr3f coord_transform_fwd(const double& x, const double& y, const double& z) override { 71 | PJ_COORD coord = proj_coord(x, y, z, 0); 72 | 73 | if (projFwdTransform) 74 | if (proj_is_equivalent_to(sCRS, processCRS, PJ_COMP_EQUIVALENT)) 75 | coord = proj_trans(projFwdTransform, PJ_FWD, coord); 76 | 77 | if(!data_offset.has_value()) { 78 | data_offset = {coord.xyz.x, coord.xyz.y, coord.xyz.z}; 79 | if(manager.global_flowchart_params.count("GF_PROCESS_OFFSET_X")) { 80 | manager.global_flowchart_params["GF_PROCESS_OFFSET_X"]->from_json(coord.xyz.x); 81 | } else { 82 | manager.global_flowchart_params["GF_PROCESS_OFFSET_X"] = std::make_shared>(coord.xyz.x, "GF_PROCESS_OFFSET_X", "offset in X coordinate"); 83 | } 84 | if(manager.global_flowchart_params.count("GF_PROCESS_OFFSET_Y")) { 85 | manager.global_flowchart_params["GF_PROCESS_OFFSET_Y"]->from_json(coord.xyz.y); 86 | } else { 87 | manager.global_flowchart_params["GF_PROCESS_OFFSET_Y"] = std::make_shared>(coord.xyz.y, "GF_PROCESS_OFFSET_Y", "offset in Y coordinate"); 88 | } 89 | if(manager.global_flowchart_params.count("GF_PROCESS_OFFSET_Z")) { 90 | manager.global_flowchart_params["GF_PROCESS_OFFSET_Z"]->from_json(coord.xyz.z); 91 | } else { 92 | manager.global_flowchart_params["GF_PROCESS_OFFSET_Z"] = std::make_shared>(coord.xyz.z, "GF_PROCESS_OFFSET_Z", "offset in Z coordinate"); 93 | } 94 | } 95 | auto result = arr3f{ 96 | float(coord.xyz.x - (*data_offset)[0]), 97 | float(coord.xyz.y - (*data_offset)[1]), 98 | float(coord.xyz.z - (*data_offset)[2]) 99 | }; 100 | 101 | return result; 102 | }; 103 | arr3d coord_transform_rev(const float& x, const float& y, const float& z) override { 104 | PJ_COORD coord; 105 | if(!data_offset.has_value()) { 106 | coord = proj_coord(x, y, z, 0); 107 | } else { 108 | coord = proj_coord( 109 | x + (*data_offset)[0], 110 | y + (*data_offset)[1], 111 | z + (*data_offset)[2], 112 | 0 113 | ); 114 | }; 115 | 116 | if (projRevTransform) 117 | if (!proj_is_equivalent_to(processCRS, tCRS, PJ_COMP_EQUIVALENT)) 118 | coord = proj_trans(projRevTransform, PJ_FWD, coord); 119 | 120 | return arr3d{coord.xyz.x, coord.xyz.y, coord.xyz.z}; 121 | } 122 | arr3d coord_transform_rev(const arr3f& p) override { 123 | return coord_transform_rev(p[0], p[1], p[2]); 124 | }; 125 | 126 | void set_process_crs(const char* crs) override{ 127 | // https://proj.org/development/reference/functions.html#c.proj_create 128 | processCRS = proj_create(projContext, crs); 129 | processCRS = proj_normalize_for_visualization(projContext, processCRS); 130 | if (!processCRS) 131 | throw gfCRSError("Unable to create CRS from string: " + std::string(crs)); 132 | }; 133 | void set_fwd_crs_transform(const char* source_crs, bool normalize_for_visualization = false) override { 134 | if(processCRS) { 135 | sCRS = proj_create(projContext, source_crs); 136 | if (!sCRS) 137 | throw gfCRSError("Unable to create source CRS from string: " + std::string(source_crs)); 138 | 139 | if (normalize_for_visualization) sCRS = proj_normalize_for_visualization(projContext, sCRS); 140 | 141 | projFwdTransform = proj_create_crs_to_crs_from_pj(projContext, sCRS, processCRS, 0, 0); 142 | 143 | if (!projFwdTransform) 144 | throw gfCRSError("Unable to create forward transformation."); 145 | } else { 146 | std::cout << "Unable to create CRS transform, process CRS is undefined\n"; 147 | } 148 | }; 149 | void set_rev_crs_transform(const char* target_crs, bool normalize_for_visualization = false) override { 150 | if (processCRS) { 151 | tCRS = proj_create(projContext, target_crs); 152 | if (!tCRS) 153 | throw gfCRSError("Unable to create source CRS from string: " + std::string(target_crs)); 154 | 155 | if (normalize_for_visualization) tCRS = proj_normalize_for_visualization(projContext, tCRS); 156 | 157 | projRevTransform = proj_create_crs_to_crs_from_pj(projContext, processCRS, tCRS, 0, 0); 158 | 159 | if (!projRevTransform) 160 | throw gfCRSError("Unable to create reverse transformation."); 161 | } else { 162 | std::cout << "Unable to create CRS transform, process CRS is undefined\n"; 163 | } 164 | }; 165 | std::string get_rev_crs_id_auth_name() override { 166 | std::string auth_name; 167 | if (tCRS) 168 | auth_name = proj_get_id_auth_name(tCRS, 0); 169 | return auth_name; 170 | }; 171 | std::string get_rev_crs_id_code() override { 172 | std::string code; 173 | if (tCRS) 174 | code = proj_get_id_code(tCRS, 0); 175 | return code; 176 | }; 177 | 178 | std::string get_rev_crs_wkt() override { 179 | std::string wkt; 180 | if (tCRS) 181 | wkt = proj_as_wkt(projContext, tCRS, PJ_WKT1_GDAL, proj_wkt_options); 182 | return wkt; 183 | }; 184 | void clear_fwd_crs_transform() override { 185 | if (sCRS) { 186 | proj_destroy(sCRS); 187 | sCRS = nullptr; 188 | } 189 | if (projFwdTransform) { 190 | proj_destroy(projFwdTransform); 191 | projFwdTransform = nullptr; 192 | } 193 | }; 194 | void clear_rev_crs_transform() override { 195 | if (tCRS) { 196 | proj_destroy(tCRS); 197 | tCRS = nullptr; 198 | } 199 | if (projRevTransform) { 200 | proj_destroy(projRevTransform); 201 | projRevTransform = nullptr; 202 | } 203 | }; 204 | 205 | void set_data_offset(arr3d& offset) override { 206 | data_offset = offset; 207 | } 208 | }; 209 | 210 | 211 | std::unique_ptr createProjHelper(NodeManager& manager) { 212 | return std::make_unique(manager); 213 | }; 214 | }; 215 | // std::unique_ptr createProjHelper(projHelperInterface& ); -------------------------------------------------------------------------------- /src/geoflow/projHelper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.hpp" 3 | 4 | namespace geoflow { 5 | 6 | class NodeManager; 7 | 8 | struct projHelperInterface { 9 | 10 | NodeManager& manager; 11 | std::optional data_offset; 12 | 13 | projHelperInterface(NodeManager& manager) : manager(manager) {}; 14 | 15 | virtual void proj_construct() = 0; 16 | virtual void proj_clone_from(const projHelperInterface&) = 0; 17 | virtual void proj_clear() = 0; 18 | 19 | virtual arr3f coord_transform_fwd(const double& x, const double& y, const double& z) = 0; 20 | virtual arr3d coord_transform_rev(const float& x, const float& y, const float& z) = 0; 21 | virtual arr3d coord_transform_rev(const arr3f& p) = 0; 22 | 23 | virtual void set_process_crs(const char* crs) = 0; 24 | virtual void set_fwd_crs_transform(const char* source_crs, bool normalize_for_visualization = false) = 0; 25 | virtual void set_rev_crs_transform(const char* target_crs, bool normalize_for_visualization = false) = 0; 26 | virtual std::string get_rev_crs_id_auth_name() = 0; 27 | virtual std::string get_rev_crs_id_code() = 0; 28 | virtual std::string get_rev_crs_wkt() = 0; 29 | virtual void clear_fwd_crs_transform() = 0; 30 | virtual void clear_rev_crs_transform() = 0; 31 | 32 | virtual void set_data_offset(arr3d& offset) = 0; 33 | }; 34 | 35 | std::unique_ptr createProjHelper(NodeManager& manager); 36 | } 37 | -------------------------------------------------------------------------------- /src/viewer/app.h: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "gloo.h" 30 | 31 | static int redraw_counter = 0; 32 | class App 33 | { 34 | public: 35 | App (int width, int height, std::string title); 36 | // ~app (); 37 | 38 | virtual void on_initialise(){}; 39 | void run(); 40 | void draw(); 41 | virtual void draw_menu_bar(){}; 42 | virtual void on_draw(){}; 43 | 44 | virtual void on_resize(int new_width, int new_height){}; 45 | virtual void on_key_press(int key, int action, int mods){}; 46 | virtual void on_scroll(double xoffset, double yoffset){}; 47 | virtual void on_mouse_press(int button, int action, int mods){}; 48 | virtual void on_mouse_move(double xpos, double ypos){}; 49 | virtual void on_drop(int count, const char** paths){}; 50 | 51 | int width, height; 52 | int viewport_width, viewport_height; 53 | bool show_demo_window = false; 54 | 55 | protected: 56 | static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); 57 | static void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos); 58 | static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods); 59 | static void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); 60 | static void window_size_callback(GLFWwindow* window, int new_width, int new_height); 61 | static void error_callback(int error, const char* description); 62 | static void char_callback(GLFWwindow*, unsigned int c); 63 | static void drop_callback(GLFWwindow* window, int count, const char** paths); 64 | 65 | GLFWwindow* window; 66 | }; 67 | -------------------------------------------------------------------------------- /src/viewer/app_povi.h: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | // #include 34 | 35 | #include "app.h" 36 | 37 | enum mouse_drag{ 38 | NO_DRAG, 39 | TRANSLATE, 40 | ROTATE 41 | }; 42 | 43 | typedef struct {double x,y;} xy_pos; 44 | 45 | inline glm::quat arcball(xy_pos p){ 46 | double h,h2 = p.x*p.x+p.y*p.y; 47 | if (h2 > 1.){ 48 | h = glm::sqrt(h2); 49 | return glm::quat(0., p.x/h, p.y/h, 0.); 50 | } else 51 | return glm::quat(0., p.x, p.y, glm::sqrt(1.-h2)); 52 | } 53 | 54 | class RenderObject { 55 | public: 56 | virtual void render() = 0; 57 | virtual void menu(){}; 58 | }; 59 | 60 | class poviApp: public std::enable_shared_from_this, public App { 61 | public: 62 | poviApp(int width, int height, std::string title):App(width, height, title) { 63 | light_direction = std::make_shared("u_light_direction", glm::vec3(0.5,-1.0,-1.0)); 64 | light_color = std::make_shared("u_light_color"); 65 | cam_pos = std::make_shared("u_cam_pos", -15); 66 | }; 67 | void add_painter(std::shared_ptr painter, const std::string* name, bool visible=true); 68 | void remove_painter(std::shared_ptr painter); 69 | void draw_that(RenderObject* o) { render_objects.push_back(o); }; 70 | void center(float, float, float z=0); 71 | std::shared_ptr get_ptr() { 72 | return shared_from_this(); 73 | }; 74 | 75 | protected: 76 | void draw_menu_bar(); 77 | void on_initialise(); 78 | void on_resize(int new_width, int new_height); 79 | void on_draw(); 80 | void on_key_press(int key, int action, int mods); 81 | void on_scroll(double xoffset, double yoffset); 82 | void on_mouse_move(double xpos, double ypos); 83 | void on_mouse_press(int button, int action, int mods); 84 | 85 | // Shader shader; 86 | // Buffer buffer; 87 | private: 88 | GLuint FramebufferName, renderedTexture, depthrenderbuffer; 89 | ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); 90 | 91 | std::vector< std::tuple,const std::string*,bool> > painters; 92 | std::vector render_objects; 93 | 94 | glm::mat4 model; 95 | glm::mat4 view; 96 | glm::mat4 projection; 97 | 98 | mouse_drag drag = NO_DRAG; 99 | xy_pos drag_init_pos; 100 | xy_pos last_mouse_pos; 101 | 102 | geoflow::Box bbox; 103 | 104 | float fov = 30; 105 | float clip_near = 1; 106 | float clip_far = 10000; 107 | float zoom_speed = 200; 108 | std::shared_ptr cam_pos; 109 | std::shared_ptr light_direction; 110 | std::shared_ptr light_color; 111 | 112 | hudPainter ch_painter; 113 | 114 | glm::vec3 translation = glm::vec3(), center_point = glm::vec3(); 115 | glm::vec3 translation_ondrag = glm::vec3(); 116 | glm::quat rotation = glm::quat(); 117 | glm::quat rotation_ondrag = glm::quat(); 118 | 119 | void update_projection_matrix(); 120 | void update_view_matrix(); 121 | inline xy_pos screen2view(xy_pos p); 122 | 123 | void center(); 124 | 125 | }; 126 | -------------------------------------------------------------------------------- /src/viewer/main.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #include 18 | 19 | #include "app_povi.h" 20 | #include 21 | 22 | int main(void) 23 | { 24 | std::cout << "start." << std::endl; 25 | poviApp a(1280, 800, "test-app"); 26 | 27 | // Set up vertex data (and buffer(s)) and attribute pointers 28 | std::vector vertices = { 29 | // Positions 30 | 0.5f, -0.5f, 0.0f, // Bottom Right 31 | -0.5f, -0.5f, 0.0f, // Bottom Left 32 | 0.0f, 0.5f, 0.0f // Top 33 | }; 34 | // Colors 35 | // 1.0f, 0.0f, 0.0f, 36 | // 0.0f, 1.0f, 0.0f, 37 | // 0.0f, 0.0f, 1.0f 38 | 39 | auto data_painter = std::make_shared(); 40 | 41 | data_painter->set_attribute("position", vertices.data(), vertices.size(), {3}); 42 | data_painter->attach_shader("basic.vert"); 43 | data_painter->attach_shader("basic.frag"); 44 | data_painter->set_drawmode(GL_TRIANGLES); 45 | 46 | a.add_painter(std::move(data_painter), "triangle"); 47 | 48 | a.run(); 49 | } 50 | -------------------------------------------------------------------------------- /src/viewer/shaders/basic.frag: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #version 330 core 18 | in vec3 ourColor; 19 | in float texCoord; 20 | flat in int colorMode; 21 | in vec3 lightFactor; 22 | 23 | layout(location=0) out vec4 color; 24 | uniform sampler1D u_sampler; 25 | 26 | void main() 27 | { 28 | if(colorMode==2 || colorMode==3) 29 | color = vec4(lightFactor*texture(u_sampler, texCoord).xyz, 1.0); 30 | else 31 | color = vec4(lightFactor*ourColor,1.0); 32 | } -------------------------------------------------------------------------------- /src/viewer/shaders/basic.vert: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #version 330 core 18 | layout (location = 0) in vec3 position; 19 | layout (location = 1) in vec3 color; 20 | layout (location = 2) in float value; 21 | layout (location = 3) in float identifier; 22 | layout (location = 4) in vec3 normal; 23 | 24 | uniform mat4 u_model; 25 | uniform mat4 u_view; 26 | uniform mat4 u_projection; 27 | uniform mat4 u_mvp; 28 | uniform mat3 u_mv_normal; 29 | 30 | uniform float u_cam_pos; 31 | 32 | uniform float u_value_max; 33 | uniform float u_value_min; 34 | 35 | uniform float u_pointsize; 36 | uniform vec4 u_color; 37 | uniform int u_color_mode; // 3==texture-direct 2==texture-gradient, 1==uniform, 0==pervertex 38 | 39 | uniform float u_ambient; 40 | uniform float u_diffuse; 41 | uniform float u_specular; 42 | uniform vec3 u_light_direction; 43 | uniform vec4 u_light_color; 44 | 45 | out vec3 ourColor; 46 | out float texCoord; 47 | out vec3 lightFactor; 48 | flat out int colorMode; 49 | 50 | void main() 51 | { 52 | vec4 pos = u_mvp * vec4(position, 1.0); 53 | gl_Position = pos; 54 | 55 | vec3 n = normalize(u_mv_normal * normal); 56 | 57 | float diffuse = u_diffuse*max(dot(n, normalize(-u_light_direction)), 0.0); 58 | 59 | vec3 viewDir = normalize(vec3(0,0,u_cam_pos) - pos.xyz); 60 | vec3 reflectDir = reflect(-u_light_direction, n); 61 | float specular = u_specular*pow(max(dot(viewDir, reflectDir), 0.0), 4); 62 | 63 | lightFactor = (u_ambient + diffuse + specular) * u_light_color.xyz; 64 | 65 | colorMode = u_color_mode; 66 | if(u_color_mode==1) 67 | ourColor = u_color.xyz; 68 | if(u_color_mode==2) 69 | texCoord = (value-u_value_min)/(u_value_max-u_value_min); 70 | if(u_color_mode==3) 71 | texCoord = identifier; 72 | else if(u_color_mode==0) 73 | ourColor = color; 74 | gl_PointSize = u_pointsize; 75 | } -------------------------------------------------------------------------------- /src/viewer/shaders/crosshair.frag: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #version 330 core 18 | 19 | out vec4 color; 20 | 21 | void main() 22 | { 23 | color = vec4(0.5,0.5,0.5,1.0); 24 | } -------------------------------------------------------------------------------- /src/viewer/shaders/crosshair.vert: -------------------------------------------------------------------------------- 1 | // This file is part of Geoflow 2 | // Copyright (C) 2018-2022 Ravi Peters 3 | 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | #version 330 core 18 | 19 | layout (location = 0) in vec2 position; 20 | 21 | void main () { 22 | gl_Position = vec4(position, 0.0, 1.0); 23 | } -------------------------------------------------------------------------------- /thirdparty/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(GF_GIT_SUBMODULES filesystem) 2 | # if(NOT ${GF_USE_EXTERNAL_JSON}) 3 | # set(GF_GIT_SUBMODULES ${GF_GIT_SUBMODULES} json) 4 | # endif() 5 | if(${GF_BUILD_GUI}) 6 | set(GF_GIT_SUBMODULES ${GF_GIT_SUBMODULES} imgui glm) 7 | if(${GF_BUILD_GUI_FILE_DIALOGS}) 8 | set(GF_GIT_SUBMODULES ${GF_GIT_SUBMODULES} osdialog) 9 | endif() 10 | endif() 11 | 12 | if(EXISTS "${PROJECT_SOURCE_DIR}/.gitmodules") 13 | execute_process( 14 | COMMAND git submodule update --init ${GF_GIT_SUBMODULES} 15 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/thirdparty 16 | ) 17 | endif() 18 | 19 | # if(${GF_USE_EXTERNAL_JSON}) 20 | # find_package(nlohmann_json CONFIG REQUIRED) 21 | # else() 22 | # set(JSON_BuildTests OFF CACHE INTERNAL "") 23 | # set(JSON_Install OFF CACHE INTERNAL "") 24 | # add_subdirectory(json) 25 | # endif() 26 | 27 | if(${GF_BUILD_GUI}) 28 | set(GLM_INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR}/thirdparty/glm PARENT_SCOPE) 29 | endif() -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2020 T.-W. Huang, C.-X. Lin, G. Guo, and M. Wong 4 | 5 | University of Utah, Salt Lake City, UT, USA 6 | University of Illinois at Urbana-Champaign, IL, USA 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/core/error.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../utility/stringify.hpp" 8 | 9 | namespace tf { 10 | 11 | // Procedure: throw_se 12 | // Throws the system error under a given error code. 13 | template 14 | //void throw_se(const char* fname, const size_t line, Error::Code c, ArgsT&&... args) { 15 | void throw_re(const char* fname, const size_t line, ArgsT&&... args) { 16 | std::ostringstream oss; 17 | oss << "[" << fname << ":" << line << "] "; 18 | ostreamize(oss, std::forward(args)...); 19 | //(oss << ... << args); 20 | throw std::runtime_error(oss.str()); 21 | } 22 | 23 | } // ------------------------------------------------------------------------ 24 | 25 | #define TF_THROW(...) tf::throw_re(__FILE__, __LINE__, __VA_ARGS__); 26 | 27 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/core/notifier.hpp: -------------------------------------------------------------------------------- 1 | // 2019/02/09 - created by Tsung-Wei Huang 2 | // - modified the event count from Eigen 3 | 4 | #pragma once 5 | 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 | 20 | // This file is part of Eigen, a lightweight C++ template library 21 | // for linear algebra. 22 | // 23 | // Copyright (C) 2016 Dmitry Vyukov 24 | // 25 | // This Source Code Form is subject to the terms of the Mozilla 26 | // Public License v. 2.0. If a copy of the MPL was not distributed 27 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 28 | 29 | namespace tf { 30 | 31 | // Notifier allows to wait for arbitrary predicates in non-blocking 32 | // algorithms. Think of condition variable, but wait predicate does not need to 33 | // be protected by a mutex. Usage: 34 | // Waiting thread does: 35 | // 36 | // if (predicate) 37 | // return act(); 38 | // Notifier::Waiter& w = waiters[my_index]; 39 | // ec.prepare_wait(&w); 40 | // if (predicate) { 41 | // ec.cancel_wait(&w); 42 | // return act(); 43 | // } 44 | // ec.commit_wait(&w); 45 | // 46 | // Notifying thread does: 47 | // 48 | // predicate = true; 49 | // ec.notify(true); 50 | // 51 | // notify is cheap if there are no waiting threads. prepare_wait/commit_wait are not 52 | // cheap, but they are executed only if the preceeding predicate check has 53 | // failed. 54 | // 55 | // Algorihtm outline: 56 | // There are two main variables: predicate (managed by user) and _state. 57 | // Operation closely resembles Dekker mutual algorithm: 58 | // https://en.wikipedia.org/wiki/Dekker%27s_algorithm 59 | // Waiting thread sets _state then checks predicate, Notifying thread sets 60 | // predicate then checks _state. Due to seq_cst fences in between these 61 | // operations it is guaranteed than either waiter will see predicate change 62 | // and won't block, or notifying thread will see _state change and will unblock 63 | // the waiter, or both. But it can't happen that both threads don't see each 64 | // other changes, which would lead to deadlock. 65 | class Notifier { 66 | 67 | public: 68 | 69 | struct Waiter { 70 | std::atomic next; 71 | std::mutex mu; 72 | std::condition_variable cv; 73 | uint64_t epoch; 74 | unsigned state; 75 | enum { 76 | kNotSignaled, 77 | kWaiting, 78 | kSignaled, 79 | }; 80 | }; 81 | 82 | explicit Notifier(std::vector& waiters) : _waiters{waiters} { 83 | assert(waiters.size() < (1 << kWaiterBits) - 1); 84 | // Initialize epoch to something close to overflow to test overflow. 85 | _state = kStackMask | (kEpochMask - kEpochInc * waiters.size() * 2); 86 | } 87 | 88 | ~Notifier() { 89 | // Ensure there are no waiters. 90 | assert((_state.load() & (kStackMask | kWaiterMask)) == kStackMask); 91 | } 92 | 93 | // prepare_wait prepares for waiting. 94 | // After calling this function the thread must re-check the wait predicate 95 | // and call either cancel_wait or commit_wait passing the same Waiter object. 96 | void prepare_wait(Waiter* w) { 97 | w->epoch = _state.fetch_add(kWaiterInc, std::memory_order_relaxed); 98 | std::atomic_thread_fence(std::memory_order_seq_cst); 99 | } 100 | 101 | // commit_wait commits waiting. 102 | void commit_wait(Waiter* w) { 103 | w->state = Waiter::kNotSignaled; 104 | // Modification epoch of this waiter. 105 | uint64_t epoch = 106 | (w->epoch & kEpochMask) + 107 | (((w->epoch & kWaiterMask) >> kWaiterShift) << kEpochShift); 108 | uint64_t state = _state.load(std::memory_order_seq_cst); 109 | for (;;) { 110 | if (int64_t((state & kEpochMask) - epoch) < 0) { 111 | // The preceeding waiter has not decided on its fate. Wait until it 112 | // calls either cancel_wait or commit_wait, or is notified. 113 | std::this_thread::yield(); 114 | state = _state.load(std::memory_order_seq_cst); 115 | continue; 116 | } 117 | // We've already been notified. 118 | if (int64_t((state & kEpochMask) - epoch) > 0) return; 119 | // Remove this thread from prewait counter and add it to the waiter list. 120 | assert((state & kWaiterMask) != 0); 121 | uint64_t newstate = state - kWaiterInc + kEpochInc; 122 | newstate = (newstate & ~kStackMask) | (w - &_waiters[0]); 123 | if ((state & kStackMask) == kStackMask) 124 | w->next.store(nullptr, std::memory_order_relaxed); 125 | else 126 | w->next.store(&_waiters[state & kStackMask], std::memory_order_relaxed); 127 | if (_state.compare_exchange_weak(state, newstate, 128 | std::memory_order_release)) 129 | break; 130 | } 131 | _park(w); 132 | } 133 | 134 | // cancel_wait cancels effects of the previous prepare_wait call. 135 | void cancel_wait(Waiter* w) { 136 | uint64_t epoch = 137 | (w->epoch & kEpochMask) + 138 | (((w->epoch & kWaiterMask) >> kWaiterShift) << kEpochShift); 139 | uint64_t state = _state.load(std::memory_order_relaxed); 140 | for (;;) { 141 | if (int64_t((state & kEpochMask) - epoch) < 0) { 142 | // The preceeding waiter has not decided on its fate. Wait until it 143 | // calls either cancel_wait or commit_wait, or is notified. 144 | std::this_thread::yield(); 145 | state = _state.load(std::memory_order_relaxed); 146 | continue; 147 | } 148 | // We've already been notified. 149 | if (int64_t((state & kEpochMask) - epoch) > 0) return; 150 | // Remove this thread from prewait counter. 151 | assert((state & kWaiterMask) != 0); 152 | if (_state.compare_exchange_weak(state, state - kWaiterInc + kEpochInc, 153 | std::memory_order_relaxed)) 154 | return; 155 | } 156 | } 157 | 158 | // notify wakes one or all waiting threads. 159 | // Must be called after changing the associated wait predicate. 160 | void notify(bool all) { 161 | std::atomic_thread_fence(std::memory_order_seq_cst); 162 | uint64_t state = _state.load(std::memory_order_acquire); 163 | for (;;) { 164 | // Easy case: no waiters. 165 | if ((state & kStackMask) == kStackMask && (state & kWaiterMask) == 0) 166 | return; 167 | uint64_t waiters = (state & kWaiterMask) >> kWaiterShift; 168 | uint64_t newstate; 169 | if (all) { 170 | // Reset prewait counter and empty wait list. 171 | newstate = (state & kEpochMask) + (kEpochInc * waiters) + kStackMask; 172 | } else if (waiters) { 173 | // There is a thread in pre-wait state, unblock it. 174 | newstate = state + kEpochInc - kWaiterInc; 175 | } else { 176 | // Pop a waiter from list and unpark it. 177 | Waiter* w = &_waiters[state & kStackMask]; 178 | Waiter* wnext = w->next.load(std::memory_order_relaxed); 179 | uint64_t next = kStackMask; 180 | if (wnext != nullptr) next = wnext - &_waiters[0]; 181 | // Note: we don't add kEpochInc here. ABA problem on the lock-free stack 182 | // can't happen because a waiter is re-pushed onto the stack only after 183 | // it was in the pre-wait state which inevitably leads to epoch 184 | // increment. 185 | newstate = (state & kEpochMask) + next; 186 | } 187 | if (_state.compare_exchange_weak(state, newstate, 188 | std::memory_order_acquire)) { 189 | if (!all && waiters) return; // unblocked pre-wait thread 190 | if ((state & kStackMask) == kStackMask) return; 191 | Waiter* w = &_waiters[state & kStackMask]; 192 | if (!all) w->next.store(nullptr, std::memory_order_relaxed); 193 | _unpark(w); 194 | return; 195 | } 196 | } 197 | } 198 | 199 | private: 200 | 201 | // State_ layout: 202 | // - low kStackBits is a stack of waiters committed wait. 203 | // - next kWaiterBits is count of waiters in prewait state. 204 | // - next kEpochBits is modification counter. 205 | static const uint64_t kStackBits = 16; 206 | static const uint64_t kStackMask = (1ull << kStackBits) - 1; 207 | static const uint64_t kWaiterBits = 16; 208 | static const uint64_t kWaiterShift = 16; 209 | static const uint64_t kWaiterMask = ((1ull << kWaiterBits) - 1) 210 | << kWaiterShift; 211 | static const uint64_t kWaiterInc = 1ull << kWaiterBits; 212 | static const uint64_t kEpochBits = 32; 213 | static const uint64_t kEpochShift = 32; 214 | static const uint64_t kEpochMask = ((1ull << kEpochBits) - 1) << kEpochShift; 215 | static const uint64_t kEpochInc = 1ull << kEpochShift; 216 | std::atomic _state; 217 | std::vector& _waiters; 218 | 219 | void _park(Waiter* w) { 220 | std::unique_lock lock(w->mu); 221 | while (w->state != Waiter::kSignaled) { 222 | w->state = Waiter::kWaiting; 223 | w->cv.wait(lock); 224 | } 225 | } 226 | 227 | void _unpark(Waiter* waiters) { 228 | Waiter* next = nullptr; 229 | for (Waiter* w = waiters; w; w = next) { 230 | next = w->next.load(std::memory_order_relaxed); 231 | unsigned state; 232 | { 233 | std::unique_lock lock(w->mu); 234 | state = w->state; 235 | w->state = Waiter::kSignaled; 236 | } 237 | // Avoid notifying if it wasn't waiting. 238 | if (state == Waiter::kWaiting) w->cv.notify_one(); 239 | } 240 | } 241 | 242 | Notifier(const Notifier&) = delete; 243 | void operator=(const Notifier&) = delete; 244 | }; 245 | 246 | 247 | 248 | } // namespace tf ------------------------------------------------------------ 249 | 250 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/core/observer.hpp: -------------------------------------------------------------------------------- 1 | // 2019/07/31 - modified by Tsung-Wei Huang 2 | // - fixed the missing comma in outputing JSON 3 | // 4 | // 2019/06/13 - modified by Tsung-Wei Huang 5 | // - added TaskView interface 6 | // 7 | // 2019/04/17 - created by Tsung-Wei Huang 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "task.hpp" 26 | 27 | namespace tf { 28 | 29 | /** 30 | @class: ExecutorObserverInterface 31 | 32 | @brief The interface class for creating an executor observer. 33 | 34 | The tf::ExecutorObserver class let users define methods to monitor the behaviors 35 | of an executor. 36 | This is particularly useful when you want to inspect the performance of an executor. 37 | */ 38 | class ExecutorObserverInterface { 39 | 40 | public: 41 | 42 | /** 43 | @brief virtual destructor 44 | */ 45 | virtual ~ExecutorObserverInterface() = default; 46 | 47 | /** 48 | @brief constructor-like method to call when the executor observer is fully created 49 | @param num_workers the number of the worker threads in the executor 50 | */ 51 | virtual void set_up(unsigned num_workers) = 0; 52 | 53 | /** 54 | @brief method to call before a worker thread executes a closure 55 | @param worker_id the id of this worker thread 56 | @param task_view a constant wrapper object to the task 57 | */ 58 | virtual void on_entry(unsigned worker_id, TaskView task_view) = 0; 59 | 60 | /** 61 | @brief method to call after a worker thread executed a closure 62 | @param worker_id the id of this worker thread 63 | @param task_view a constant wrapper object to the task 64 | */ 65 | virtual void on_exit(unsigned worker_id, TaskView task_view) = 0; 66 | }; 67 | 68 | // ------------------------------------------------------------------ 69 | 70 | /** 71 | @class: ExecutorObserver 72 | 73 | @brief Default executor observer to dump the execution timelines 74 | 75 | */ 76 | class ExecutorObserver : public ExecutorObserverInterface { 77 | 78 | friend class Executor; 79 | 80 | // data structure to record each task execution 81 | struct Execution { 82 | 83 | TaskView task_view; 84 | 85 | std::chrono::time_point beg; 86 | std::chrono::time_point end; 87 | 88 | Execution( 89 | TaskView tv, 90 | std::chrono::time_point b 91 | ) : 92 | task_view {tv}, beg {b} { 93 | } 94 | 95 | Execution( 96 | TaskView tv, 97 | std::chrono::time_point b, 98 | std::chrono::time_point e 99 | ) : 100 | task_view {tv}, beg {b}, end {e} { 101 | } 102 | }; 103 | 104 | // data structure to store the entire execution timeline 105 | struct Timeline { 106 | std::chrono::time_point origin; 107 | std::vector> executions; 108 | }; 109 | 110 | public: 111 | 112 | /** 113 | @brief dump the timelines in JSON format to an ostream 114 | @param ostream the target std::ostream to dump 115 | */ 116 | inline void dump(std::ostream& ostream) const; 117 | 118 | /** 119 | @brief dump the timelines in JSON to a std::string 120 | @return a JSON string 121 | */ 122 | inline std::string dump() const; 123 | 124 | /** 125 | @brief clear the timeline data 126 | */ 127 | inline void clear(); 128 | 129 | /** 130 | @brief get the number of total tasks in the observer 131 | @return number of total tasks 132 | */ 133 | inline size_t num_tasks() const; 134 | 135 | private: 136 | 137 | inline void set_up(unsigned num_workers) override final; 138 | inline void on_entry(unsigned worker_id, TaskView task_view) override final; 139 | inline void on_exit(unsigned worker_id, TaskView task_view) override final; 140 | 141 | Timeline _timeline; 142 | }; 143 | 144 | // Procedure: set_up 145 | inline void ExecutorObserver::set_up(unsigned num_workers) { 146 | 147 | _timeline.executions.resize(num_workers); 148 | 149 | for(unsigned w=0; w(tv); // avoid warning from compiler 164 | assert(_timeline.executions[w].size() > 0); 165 | _timeline.executions[w].back().end = std::chrono::steady_clock::now(); 166 | } 167 | 168 | // Function: clear 169 | inline void ExecutorObserver::clear() { 170 | for(size_t w=0; w<_timeline.executions.size(); ++w) { 171 | _timeline.executions[w].clear(); 172 | } 173 | } 174 | 175 | // Procedure: dump 176 | inline void ExecutorObserver::dump(std::ostream& os) const { 177 | 178 | size_t first; 179 | 180 | for(first = 0; first<_timeline.executions.size(); ++first) { 181 | if(_timeline.executions[first].size() > 0) { 182 | break; 183 | } 184 | } 185 | 186 | os << '['; 187 | 188 | for(size_t w=first; w<_timeline.executions.size(); w++) { 189 | 190 | if(w != first && _timeline.executions[w].size() > 0) { 191 | os << ','; 192 | } 193 | 194 | for(size_t i=0; i<_timeline.executions[w].size(); i++) { 195 | 196 | os << '{' 197 | << "\"cat\":\"ExecutorObserver\"," 198 | << "\"name\":\"" << _timeline.executions[w][i].task_view.name() << "\"," 199 | << "\"ph\":\"X\"," 200 | << "\"pid\":1," 201 | << "\"tid\":" << w << ',' 202 | << "\"ts\":" << std::chrono::duration_cast( 203 | _timeline.executions[w][i].beg - _timeline.origin 204 | ).count() << ',' 205 | << "\"dur\":" << std::chrono::duration_cast( 206 | _timeline.executions[w][i].end - _timeline.executions[w][i].beg 207 | ).count(); 208 | 209 | if(i != _timeline.executions[w].size() - 1) { 210 | os << "},"; 211 | } 212 | else { 213 | os << '}'; 214 | } 215 | } 216 | } 217 | os << "]\n"; 218 | } 219 | 220 | // Function: dump 221 | inline std::string ExecutorObserver::dump() const { 222 | std::ostringstream oss; 223 | dump(oss); 224 | return oss.str(); 225 | } 226 | 227 | // Function: num_tasks 228 | inline size_t ExecutorObserver::num_tasks() const { 229 | return std::accumulate( 230 | _timeline.executions.begin(), _timeline.executions.end(), size_t{0}, 231 | [](size_t sum, const auto& exe){ 232 | return sum + exe.size(); 233 | } 234 | ); 235 | } 236 | 237 | 238 | } // end of namespace tf ------------------------------------------- 239 | 240 | 241 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/core/taskflow.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "flow_builder.hpp" 6 | #include "topology.hpp" 7 | 8 | namespace tf { 9 | 10 | // ---------------------------------------------------------------------------- 11 | 12 | /** 13 | @class Taskflow 14 | 15 | @brief the class to create a task dependency graph 16 | 17 | */ 18 | class Taskflow : public FlowBuilder { 19 | 20 | friend class Topology; 21 | friend class Executor; 22 | friend class FlowBuilder; 23 | 24 | public: 25 | 26 | /** 27 | @brief constructs a taskflow with a given name 28 | */ 29 | Taskflow(const std::string& name); 30 | 31 | /** 32 | @brief constructs a taskflow 33 | */ 34 | Taskflow(); 35 | 36 | /** 37 | @brief destroy the taskflow (virtual call) 38 | */ 39 | virtual ~Taskflow(); 40 | 41 | /** 42 | @brief dumps the taskflow to a std::ostream in DOT format 43 | 44 | @param ostream a std::ostream target 45 | */ 46 | void dump(std::ostream& ostream) const; 47 | 48 | /** 49 | @brief dumps the taskflow in DOT format to a std::string 50 | */ 51 | std::string dump() const; 52 | 53 | /** 54 | @brief queries the number of tasks in the taskflow 55 | */ 56 | size_t num_tasks() const; 57 | 58 | /** 59 | @brief queries the emptiness of the taskflow 60 | */ 61 | bool empty() const; 62 | 63 | /** 64 | @brief sets the name of the taskflow 65 | 66 | @return @c *this 67 | */ 68 | tf::Taskflow& name(const std::string&); 69 | 70 | /** 71 | @brief queries the name of the taskflow 72 | */ 73 | const std::string& name() const ; 74 | 75 | /** 76 | @brief clears the associated task dependency graph 77 | */ 78 | void clear(); 79 | 80 | /** 81 | @brief applies an visitor callable to each task in the taskflow 82 | */ 83 | template 84 | void for_each_task(V&& visitor) const; 85 | 86 | private: 87 | 88 | std::string _name; 89 | 90 | Graph _graph; 91 | 92 | std::mutex _mtx; 93 | 94 | std::list _topologies; 95 | 96 | void _dump(std::ostream&, const Taskflow*) const; 97 | 98 | void _dump( 99 | std::ostream&, 100 | const Node*, 101 | std::stack&, 102 | std::unordered_set& 103 | ) const; 104 | 105 | void _dump( 106 | std::ostream&, 107 | const Graph&, 108 | std::stack&, 109 | std::unordered_set& 110 | ) const; 111 | }; 112 | 113 | // Constructor 114 | inline Taskflow::Taskflow(const std::string& name) : 115 | FlowBuilder {_graph}, 116 | _name {name} { 117 | } 118 | 119 | // Constructor 120 | inline Taskflow::Taskflow() : FlowBuilder{_graph} { 121 | } 122 | 123 | // Destructor 124 | inline Taskflow::~Taskflow() { 125 | assert(_topologies.empty()); 126 | } 127 | 128 | // Procedure: 129 | inline void Taskflow::clear() { 130 | _graph.clear(); 131 | } 132 | 133 | // Function: num_noces 134 | inline size_t Taskflow::num_tasks() const { 135 | return _graph.size(); 136 | } 137 | 138 | // Function: empty 139 | inline bool Taskflow::empty() const { 140 | return _graph.empty(); 141 | } 142 | 143 | // Function: name 144 | inline Taskflow& Taskflow::name(const std::string &name) { 145 | _name = name; 146 | return *this; 147 | } 148 | 149 | // Function: name 150 | inline const std::string& Taskflow::name() const { 151 | return _name; 152 | } 153 | 154 | // Function: for_each_task 155 | template 156 | void Taskflow::for_each_task(V&& visitor) const { 157 | for(size_t i=0; i<_graph._nodes.size(); ++i) { 158 | visitor(Task(_graph._nodes[i])); 159 | } 160 | } 161 | 162 | // Procedure: dump 163 | inline std::string Taskflow::dump() const { 164 | std::ostringstream oss; 165 | dump(oss); 166 | return oss.str(); 167 | } 168 | 169 | // Function: dump 170 | inline void Taskflow::dump(std::ostream& os) const { 171 | os << "digraph Taskflow {\n"; 172 | _dump(os, this); 173 | os << "}\n"; 174 | } 175 | 176 | // Procedure: _dump 177 | inline void Taskflow::_dump(std::ostream& os, const Taskflow* top) const { 178 | 179 | std::stack stack; 180 | std::unordered_set visited; 181 | 182 | stack.push(top); 183 | visited.insert(top); 184 | 185 | while(!stack.empty()) { 186 | 187 | auto f = stack.top(); 188 | stack.pop(); 189 | 190 | os << "subgraph cluster_p" << f << " {\nlabel=\"Taskflow: "; 191 | if(f->_name.empty()) os << 'p' << f; 192 | else os << f->_name; 193 | os << "\";\n"; 194 | _dump(os, f->_graph, stack, visited); 195 | os << "}\n"; 196 | } 197 | } 198 | 199 | // Procedure: _dump 200 | inline void Taskflow::_dump( 201 | std::ostream& os, 202 | const Node* node, 203 | std::stack& stack, 204 | std::unordered_set& visited 205 | ) const { 206 | 207 | os << 'p' << node << "[label=\""; 208 | if(node->_name.empty()) os << 'p' << node; 209 | else os << node->_name; 210 | os << "\" "; 211 | 212 | // condition node is colored green 213 | if(node->_handle.index() == Node::CONDITION_WORK) { 214 | os << " shape=diamond color=black fillcolor=aquamarine style=filled"; 215 | } 216 | 217 | os << "];\n"; 218 | 219 | for(size_t s=0; s_successors.size(); ++s) { 220 | if(node->_handle.index() == Node::CONDITION_WORK) { 221 | // case edge is dashed 222 | os << 'p' << node << " -> p" << node->_successors[s] 223 | << " [style=dashed label=\"" << s << "\"];\n"; 224 | } 225 | else { 226 | os << 'p' << node << " -> p" << node->_successors[s] << ";\n"; 227 | } 228 | } 229 | 230 | // subflow join node 231 | if(node->_parent && node->_successors.size() == 0) { 232 | os << 'p' << node << " -> p" << node->_parent << ";\n"; 233 | } 234 | 235 | if(node->_handle.index() == Node::DYNAMIC_WORK) { 236 | 237 | auto& sbg = nstd::get(node->_handle).subgraph; 238 | 239 | //if(node->_subgraph && !node->_subgraph->empty()) { 240 | if(!sbg.empty()) { 241 | 242 | os << "subgraph cluster_p" << node << " {\nlabel=\"Subflow: "; 243 | if(node->_name.empty()) os << 'p' << node; 244 | else os << node->_name; 245 | 246 | os << "\";\n" << "color=blue\n"; 247 | _dump(os, sbg, stack, visited); 248 | os << "}\n"; 249 | } 250 | } 251 | } 252 | 253 | // Procedure: _dump 254 | inline void Taskflow::_dump( 255 | std::ostream& os, 256 | const Graph& graph, 257 | std::stack& stack, 258 | std::unordered_set& visited 259 | ) const { 260 | 261 | for(const auto& n : graph._nodes) { 262 | 263 | // regular task 264 | if(n->_handle.index() != Node::MODULE_WORK) { 265 | _dump(os, n, stack, visited); 266 | } 267 | // module task 268 | else { 269 | 270 | auto module = nstd::get(n->_handle).module; 271 | 272 | os << 'p' << n << "[shape=box, color=blue, label=\""; 273 | if(n->_name.empty()) os << n; 274 | else os << n->_name; 275 | os << " [Taskflow: "; 276 | if(module->_name.empty()) os << 'p' << module; 277 | else os << module->_name; 278 | os << "]\"];\n"; 279 | 280 | if(visited.find(module) == visited.end()) { 281 | visited.insert(module); 282 | stack.push(module); 283 | } 284 | 285 | for(const auto s : n->_successors) { 286 | os << 'p' << n << "->" << 'p' << s << ";\n"; 287 | } 288 | } 289 | } 290 | } 291 | 292 | // ---------------------------------------------------------------------------- 293 | // Backward compatibility 294 | // ---------------------------------------------------------------------------- 295 | 296 | using Framework = Taskflow; 297 | 298 | } // end of namespace tf. --------------------------------------------------- 299 | 300 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/core/topology.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#include "taskflow.hpp" 4 | 5 | namespace tf { 6 | 7 | // ---------------------------------------------------------------------------- 8 | 9 | // class: Topology 10 | class Topology { 11 | 12 | friend class Taskflow; 13 | friend class Executor; 14 | 15 | public: 16 | 17 | template 18 | Topology(Taskflow&, P&&, C&&); 19 | 20 | private: 21 | 22 | Taskflow& _taskflow; 23 | 24 | std::promise _promise; 25 | 26 | PassiveVector _sources; 27 | 28 | std::function _pred; 29 | std::function _call; 30 | 31 | std::atomic _join_counter {0}; 32 | }; 33 | 34 | // Constructor 35 | template 36 | inline Topology::Topology(Taskflow& tf, P&& p, C&& c): 37 | _taskflow(tf), 38 | _pred {std::forward

(p)}, 39 | _call {std::forward(c)} { 40 | } 41 | 42 | // Procedure: _bind 43 | // Re-builds the source links and the sink number for this topology. 44 | //inline void Topology::_bind(Graph& g) { 45 | // 46 | // _sources.clear(); 47 | // 48 | // //PassiveVector condition_nodes; 49 | // 50 | // // scan each node in the graph and build up the links 51 | // for(auto& node : g.nodes()) { 52 | // 53 | // node->_topology = this; 54 | // node->_clear_state(); 55 | // node->_set_up_join_counter(); 56 | // 57 | // if(node->num_dependents() == 0) { 58 | // _sources.push_back(node.get()); 59 | // } 60 | // 61 | // //int join_counter = 0; 62 | // //for(auto p : node->_dependents) { 63 | // // if(p->_work.index() == Node::CONDITION_WORK) { 64 | // // node->_set_state(Node::BRANCH); 65 | // // } 66 | // // else { 67 | // // join_counter++; 68 | // // } 69 | // //} 70 | // 71 | // //node->_join_counter.store(join_counter, std::memory_order_relaxed); 72 | // 73 | // //// TODO: Merge with the loop below? 74 | // //if(node->_work.index() == Node::CONDITION_WORK) { 75 | // // condition_nodes.push_back(node.get()); 76 | // //} 77 | // 78 | // //// Reset each node's num_dependents 79 | // //node->_join_counter.store(node->_dependents.size(), std::memory_order_relaxed); 80 | // } 81 | // 82 | // // We need to deduct the condition predecessors in impure case nodes 83 | // //for(auto& n: condition_nodes) { 84 | // // for(auto& s: n->_successors) { 85 | // // s->_join_counter.fetch_sub(1, std::memory_order_relaxed); 86 | // // s->set_branch(); 87 | // // } 88 | // //} 89 | //} 90 | 91 | 92 | 93 | } // end of namespace tf. ---------------------------------------------------- 94 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/core/tsq.hpp: -------------------------------------------------------------------------------- 1 | // 2020/02/24 - created by twhuang 2 | // - specialized work stealing queue for pointer 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace tf { 11 | 12 | /** 13 | @class: TaskQueue 14 | 15 | @tparam T data type (must be a pointer) 16 | 17 | @brief Lock-free unbounded single-producer multiple-consumer queue. 18 | 19 | This class implements the work stealing queue described in the paper, 20 | "Correct and Efficient Work-Stealing for Weak Memory Models," 21 | available at https://www.di.ens.fr/~zappa/readings/ppopp13.pdf. 22 | 23 | Only the queue owner can perform pop and push operations, 24 | while others can steal data from the queue. 25 | */ 26 | template 27 | class TaskQueue { 28 | 29 | static_assert(std::is_pointer::value, "T must be a pointer type"); 30 | 31 | struct Array { 32 | 33 | int64_t C; 34 | int64_t M; 35 | std::atomic* S; 36 | 37 | explicit Array(int64_t c) : 38 | C {c}, 39 | M {c-1}, 40 | S {new std::atomic[static_cast(C)]} { 41 | } 42 | 43 | ~Array() { 44 | delete [] S; 45 | } 46 | 47 | int64_t capacity() const noexcept { 48 | return C; 49 | } 50 | 51 | template 52 | void push(int64_t i, O&& o) noexcept { 53 | S[i & M].store(std::forward(o), std::memory_order_relaxed); 54 | } 55 | 56 | T pop(int64_t i) noexcept { 57 | return S[i & M].load(std::memory_order_relaxed); 58 | } 59 | 60 | Array* resize(int64_t b, int64_t t) { 61 | Array* ptr = new Array {2*C}; 62 | for(int64_t i=t; i!=b; ++i) { 63 | ptr->push(i, pop(i)); 64 | } 65 | return ptr; 66 | } 67 | 68 | }; 69 | 70 | std::atomic _top; 71 | std::atomic _bottom; 72 | std::atomic _array; 73 | std::vector _garbage; 74 | 75 | public: 76 | 77 | /** 78 | @brief constructs the queue with a given capacity 79 | 80 | @param capacity the capacity of the queue (must be power of 2) 81 | */ 82 | explicit TaskQueue(int64_t capacity = 1024); 83 | 84 | /** 85 | @brief destructs the queue 86 | */ 87 | ~TaskQueue(); 88 | 89 | /** 90 | @brief queries if the queue is empty at the time of this call 91 | */ 92 | bool empty() const noexcept; 93 | 94 | /** 95 | @brief queries the number of items at the time of this call 96 | */ 97 | size_t size() const noexcept; 98 | 99 | /** 100 | @brief queries the capacity of the queue 101 | */ 102 | int64_t capacity() const noexcept; 103 | 104 | /** 105 | @brief inserts an item to the queue 106 | 107 | Only the owner thread can insert an item to the queue. 108 | The operation can trigger the queue to resize its capacity 109 | if more space is required. 110 | 111 | @tparam O data type 112 | 113 | @param item the item to perfect-forward to the queue 114 | */ 115 | void push(T item); 116 | 117 | /** 118 | @brief pops out an item from the queue 119 | 120 | Only the owner thread can pop out an item from the queue. 121 | The return can be a @nullptr if this operation failed (empty queue). 122 | */ 123 | T pop(); 124 | 125 | /** 126 | @brief steals an item from the queue 127 | 128 | Any threads can try to steal an item from the queue. 129 | The return can be a @nullptr if this operation failed (not necessary empty). 130 | */ 131 | T steal(); 132 | }; 133 | 134 | // Constructor 135 | template 136 | TaskQueue::TaskQueue(int64_t c) { 137 | assert(c && (!(c & (c-1)))); 138 | _top.store(0, std::memory_order_relaxed); 139 | _bottom.store(0, std::memory_order_relaxed); 140 | _array.store(new Array{c}, std::memory_order_relaxed); 141 | _garbage.reserve(32); 142 | } 143 | 144 | // Destructor 145 | template 146 | TaskQueue::~TaskQueue() { 147 | for(auto a : _garbage) { 148 | delete a; 149 | } 150 | delete _array.load(); 151 | } 152 | 153 | // Function: empty 154 | template 155 | bool TaskQueue::empty() const noexcept { 156 | int64_t b = _bottom.load(std::memory_order_relaxed); 157 | int64_t t = _top.load(std::memory_order_relaxed); 158 | return b <= t; 159 | } 160 | 161 | // Function: size 162 | template 163 | size_t TaskQueue::size() const noexcept { 164 | int64_t b = _bottom.load(std::memory_order_relaxed); 165 | int64_t t = _top.load(std::memory_order_relaxed); 166 | return static_cast(b >= t ? b - t : 0); 167 | } 168 | 169 | // Function: push 170 | template 171 | void TaskQueue::push(T o) { 172 | int64_t b = _bottom.load(std::memory_order_relaxed); 173 | int64_t t = _top.load(std::memory_order_acquire); 174 | Array* a = _array.load(std::memory_order_relaxed); 175 | 176 | // queue is full 177 | if(a->capacity() - 1 < (b - t)) { 178 | Array* tmp = a->resize(b, t); 179 | _garbage.push_back(a); 180 | std::swap(a, tmp); 181 | _array.store(a, std::memory_order_relaxed); 182 | } 183 | 184 | a->push(b, o); 185 | std::atomic_thread_fence(std::memory_order_release); 186 | _bottom.store(b + 1, std::memory_order_relaxed); 187 | } 188 | 189 | // Function: pop 190 | template 191 | T TaskQueue::pop() { 192 | int64_t b = _bottom.load(std::memory_order_relaxed) - 1; 193 | Array* a = _array.load(std::memory_order_relaxed); 194 | _bottom.store(b, std::memory_order_relaxed); 195 | std::atomic_thread_fence(std::memory_order_seq_cst); 196 | int64_t t = _top.load(std::memory_order_relaxed); 197 | 198 | T item {nullptr}; 199 | 200 | if(t <= b) { 201 | item = a->pop(b); 202 | if(t == b) { 203 | // the last item just got stolen 204 | if(!_top.compare_exchange_strong(t, t+1, 205 | std::memory_order_seq_cst, 206 | std::memory_order_relaxed)) { 207 | item = nullptr; 208 | } 209 | _bottom.store(b + 1, std::memory_order_relaxed); 210 | } 211 | } 212 | else { 213 | _bottom.store(b + 1, std::memory_order_relaxed); 214 | } 215 | 216 | return item; 217 | } 218 | 219 | // Function: steal 220 | template 221 | T TaskQueue::steal() { 222 | int64_t t = _top.load(std::memory_order_acquire); 223 | std::atomic_thread_fence(std::memory_order_seq_cst); 224 | int64_t b = _bottom.load(std::memory_order_acquire); 225 | 226 | T item {nullptr}; 227 | 228 | if(t < b) { 229 | Array* a = _array.load(std::memory_order_consume); 230 | item = a->pop(t); 231 | if(!_top.compare_exchange_strong(t, t+1, 232 | std::memory_order_seq_cst, 233 | std::memory_order_relaxed)) { 234 | return nullptr; 235 | } 236 | } 237 | 238 | return item; 239 | } 240 | 241 | // Function: capacity 242 | template 243 | int64_t TaskQueue::capacity() const noexcept { 244 | return _array.load(std::memory_order_relaxed)->capacity(); 245 | } 246 | 247 | } // end of namespace tf ----------------------------------------------------- 248 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/cuda/device.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "error.hpp" 4 | 5 | namespace tf { 6 | 7 | /** 8 | @brief queries the number of available devices 9 | */ 10 | inline unsigned cuda_num_devices() { 11 | int N = 0; 12 | TF_CHECK_CUDA(cudaGetDeviceCount(&N), "failed to get device count"); 13 | return N; 14 | } 15 | 16 | /** 17 | @brief gets the current device associated with the caller thread 18 | */ 19 | inline int cuda_get_device() { 20 | int id; 21 | TF_CHECK_CUDA(cudaGetDevice(&id), "failed to get current device id"); 22 | return id; 23 | } 24 | 25 | /** 26 | @brief switches to a given device context 27 | */ 28 | inline void cuda_set_device(int id) { 29 | TF_CHECK_CUDA(cudaSetDevice(id), "failed to switch to device ", id); 30 | } 31 | 32 | /** @class cudaScopedDevice 33 | 34 | @brief RAII-style device context switch 35 | 36 | */ 37 | class cudaScopedDevice { 38 | 39 | public: 40 | 41 | cudaScopedDevice(int); 42 | ~cudaScopedDevice(); 43 | 44 | private: 45 | 46 | int _p; 47 | }; 48 | 49 | // Constructor 50 | inline cudaScopedDevice::cudaScopedDevice(int dev) { 51 | TF_CHECK_CUDA(cudaGetDevice(&_p), "failed to get current device scope"); 52 | if(_p == dev) { 53 | _p = -1; 54 | } 55 | else { 56 | TF_CHECK_CUDA(cudaSetDevice(dev), "failed to scope on device ", dev); 57 | } 58 | } 59 | 60 | // Destructor 61 | inline cudaScopedDevice::~cudaScopedDevice() { 62 | if(_p != -1) { 63 | cudaSetDevice(_p); 64 | //TF_CHECK_CUDA(cudaSetDevice(_p), "failed to scope back to device ", _p); 65 | } 66 | } 67 | 68 | } // end of namespace cuda --------------------------------------------------- 69 | 70 | 71 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/cuda/error.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../utility/stringify.hpp" 8 | 9 | #define TF_CUDA_REMOVE_FIRST_HELPER(N, ...) __VA_ARGS__ 10 | #define TF_CUDA_REMOVE_FIRST(...) TF_CUDA_REMOVE_FIRST_HELPER(__VA_ARGS__) 11 | #define TF_CUDA_GET_FIRST_HELPER(N, ...) N 12 | #define TF_CUDA_GET_FIRST(...) TF_CUDA_GET_FIRST_HELPER(__VA_ARGS__) 13 | 14 | #define TF_CHECK_CUDA(...) \ 15 | if(TF_CUDA_GET_FIRST(__VA_ARGS__) != cudaSuccess) { \ 16 | std::ostringstream oss; \ 17 | auto ev = TF_CUDA_GET_FIRST(__VA_ARGS__); \ 18 | auto unknown_str = "unknown error"; \ 19 | auto unknown_name = "cudaErrorUnknown"; \ 20 | auto error_str = ::cudaGetErrorString(ev); \ 21 | auto error_name = ::cudaGetErrorName(ev); \ 22 | oss << "[" << __FILE__ << ":" << __LINE__ << "] " \ 23 | << (error_str ? error_str : unknown_str) \ 24 | << " (" \ 25 | << (error_name ? error_name : unknown_name) \ 26 | << ") - "; \ 27 | tf::ostreamize(oss, TF_CUDA_REMOVE_FIRST(__VA_ARGS__)); \ 28 | throw std::runtime_error(oss.str()); \ 29 | } 30 | 31 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/cuda/flow_builder.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "task.hpp" 4 | 5 | namespace tf { 6 | 7 | class cudaFlow { 8 | 9 | public: 10 | 11 | cudaFlow(cudaGraph&); 12 | 13 | template 14 | cudaTask kernel(dim3 grid, dim3 block, size_t shm, F&& func, ArgsT&&... args); 15 | 16 | cudaTask copy(void* tgt, void* src, size_t num, size_t size); 17 | 18 | private: 19 | 20 | cudaGraph& _graph; 21 | }; 22 | 23 | // Constructor 24 | inline cudaFlow::cudaFlow(cudaGraph& g) : _graph {g} { 25 | } 26 | 27 | // Function: kernel 28 | template 29 | cudaTask cudaFlow::kernel(dim3 grid, dim3 block, size_t shm, F&& func, ArgsT&&... args) { 30 | 31 | void* arguments[sizeof...(ArgsT)] = { &args... }; 32 | 33 | auto node = _graph.emplace_back(); 34 | 35 | auto& param = node->_handle.emplace().param; 36 | 37 | param.func = (void*)func; 38 | param.gridDim = grid; 39 | param.blockDim = block; 40 | param.sharedMemBytes = shm; 41 | param.kernelParams = arguments; 42 | param.extra = nullptr; 43 | 44 | TF_CHECK_CUDA( 45 | ::cudaGraphAddKernelNode(&node->_node, _graph._handle, nullptr, 0, ¶m), 46 | "failed to create a cudaKernel node" 47 | ); 48 | 49 | return cudaTask(node); 50 | } 51 | 52 | // Function: copy 53 | inline cudaTask cudaFlow::copy(void* tgt, void* src, size_t num, size_t size) { 54 | 55 | auto node = _graph.emplace_back(); 56 | auto& param = node->_handle.emplace().param; 57 | 58 | param.srcArray = nullptr; 59 | param.srcPos = ::make_cudaPos(0, 0, 0); 60 | param.srcPtr = ::make_cudaPitchedPtr(src, num*size, num, 1); 61 | param.dstArray = nullptr; 62 | param.dstPos = ::make_cudaPos(0, 0, 0); 63 | param.dstPtr = ::make_cudaPitchedPtr(tgt, num*size, num, 1); 64 | param.extent = ::make_cudaExtent(num*size, 1, 1); 65 | param.kind = cudaMemcpyDefault; 66 | 67 | TF_CHECK_CUDA( 68 | cudaGraphAddMemcpyNode(&node->_node, _graph._handle, nullptr, 0, ¶m), 69 | "failed to create a cudaCopy node" 70 | ); 71 | 72 | return cudaTask(node); 73 | } 74 | 75 | } // end of namespace tf ----------------------------------------------------- 76 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/cuda/graph.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "device.hpp" 4 | 5 | #include "../declarations.hpp" 6 | #include "../utility/object_pool.hpp" 7 | #include "../utility/traits.hpp" 8 | #include "../utility/passive_vector.hpp" 9 | #include "../nstd/variant.hpp" 10 | 11 | namespace tf { 12 | 13 | // ---------------------------------------------------------------------------- 14 | // cudaNode class 15 | // ---------------------------------------------------------------------------- 16 | 17 | // class: cudaNode 18 | class cudaNode { 19 | 20 | friend class cudaFlow; 21 | friend class cudaGraph; 22 | friend class cudaTask; 23 | 24 | // Copy handle 25 | struct Copy { 26 | 27 | template 28 | Copy(ArgsT&&... args) { 29 | } 30 | 31 | cudaMemcpy3DParms param = {0}; 32 | }; 33 | 34 | // Kernel handle 35 | struct Kernel { 36 | 37 | template 38 | Kernel(ArgsT&&...) {} 39 | 40 | cudaKernelNodeParams param = {0}; 41 | }; 42 | 43 | public: 44 | 45 | cudaNode(cudaGraph&); 46 | 47 | private: 48 | 49 | cudaGraph& _graph; 50 | 51 | std::string _name; 52 | 53 | nstd::variant _handle; 54 | 55 | cudaGraphNode_t _node {nullptr}; 56 | 57 | PassiveVector _successors; 58 | 59 | void _precede(cudaNode*); 60 | }; 61 | 62 | // ---------------------------------------------------------------------------- 63 | // cudaGraph class 64 | // ---------------------------------------------------------------------------- 65 | 66 | // class: cudaGraph 67 | class cudaGraph { 68 | 69 | friend class cudaFlow; 70 | friend class cudaNode; 71 | 72 | public: 73 | 74 | cudaGraph(); 75 | ~cudaGraph(); 76 | 77 | template 78 | cudaNode* emplace_back(ArgsT&&...); 79 | 80 | private: 81 | 82 | cudaGraph_t _handle {nullptr}; 83 | 84 | std::vector> _nodes; 85 | }; 86 | 87 | // ---------------------------------------------------------------------------- 88 | // cudaNode definitions 89 | // ---------------------------------------------------------------------------- 90 | 91 | // Constructor 92 | inline cudaNode::cudaNode(cudaGraph& g) : _graph {g} { 93 | } 94 | 95 | // Procedure: _precede 96 | inline void cudaNode::_precede(cudaNode* v) { 97 | _successors.push_back(v); 98 | TF_CHECK_CUDA( 99 | ::cudaGraphAddDependencies(_graph._handle, &_node, &(v->_node), 1), 100 | "failed to add a preceding link" 101 | ); 102 | } 103 | 104 | // ---------------------------------------------------------------------------- 105 | // cudaGraph definitions 106 | // ---------------------------------------------------------------------------- 107 | 108 | // Constructor 109 | inline cudaGraph::cudaGraph() { 110 | TF_CHECK_CUDA(cudaGraphCreate(&_handle, 0), "failed to create a cudaGraph"); 111 | } 112 | 113 | // Destructor 114 | inline cudaGraph::~cudaGraph() { 115 | cudaGraphDestroy(_handle); 116 | } 117 | 118 | // Function: emplace_back 119 | template 120 | cudaNode* cudaGraph::emplace_back(ArgsT&&... args) { 121 | auto node = std::make_unique(*this, std::forward(args)...); 122 | _nodes.emplace_back(std::move(node)); 123 | return _nodes.back().get(); 124 | } 125 | 126 | 127 | //inline void cudaGraph::run() { 128 | // cudaGraphExec_t graphExec; 129 | // TF_CHECK_CUDA( 130 | // cudaGraphInstantiate(&graphExec, _handle, nullptr, nullptr, 0), 131 | // "failed to create an executable cudaGraph" 132 | // ); 133 | // TF_CHECK_CUDA(cudaGraphLaunch(graphExec, 0), "failed to launch cudaGraph") 134 | // TF_CHECK_CUDA(cudaStreamSynchronize(0), "failed to sync cudaStream"); 135 | // TF_CHECK_CUDA( 136 | // cudaGraphExecDestroy(graphExec), "failed to destroy an executable cudaGraph" 137 | // ); 138 | //} 139 | 140 | 141 | 142 | 143 | 144 | } // end of namespace tf ----------------------------------------------------- 145 | 146 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/cuda/task.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "graph.hpp" 4 | 5 | namespace tf { 6 | 7 | /** 8 | @class Task 9 | 10 | @brief task handle to a node in a cudaGraph 11 | */ 12 | class cudaTask { 13 | 14 | friend class cudaFlow; 15 | 16 | public: 17 | 18 | /** 19 | @brief constructs an empty cudaTask 20 | */ 21 | cudaTask() = default; 22 | 23 | /** 24 | @brief copy-constructs a cudaTask 25 | */ 26 | cudaTask(const cudaTask&) = default; 27 | 28 | /** 29 | @brief copy-assigns a cudaTask 30 | */ 31 | cudaTask& operator = (const cudaTask&) = default; 32 | 33 | /** 34 | @brief adds precedence links from this to other tasks 35 | 36 | @tparam Ts... parameter pack 37 | 38 | @param tasks one or multiple tasks 39 | 40 | @return @c *this 41 | */ 42 | template 43 | cudaTask& precede(Ts&&... tasks); 44 | 45 | /** 46 | @brief assigns a name to the task 47 | 48 | @param name a @std_string acceptable string 49 | 50 | @return @c *this 51 | */ 52 | cudaTask& name(const std::string& name); 53 | 54 | /** 55 | @brief queries the name of the task 56 | */ 57 | const std::string& name() const; 58 | 59 | private: 60 | 61 | cudaTask(cudaNode*); 62 | 63 | cudaNode* _node {nullptr}; 64 | 65 | template 66 | void _precede(T&&); 67 | 68 | template 69 | void _precede(T&&, Ts&&...); 70 | }; 71 | 72 | // Constructor 73 | inline cudaTask::cudaTask(cudaNode* node) : _node {node} { 74 | } 75 | 76 | // Function: precede 77 | template 78 | cudaTask& cudaTask::precede(Ts&&... tasks) { 79 | _precede(std::forward(tasks)...); 80 | return *this; 81 | } 82 | 83 | // Procedure: precede 84 | template 85 | void cudaTask::_precede(T&& other) { 86 | _node->_precede(other._node); 87 | } 88 | 89 | // Procedure: _precede 90 | template 91 | void cudaTask::_precede(T&& task, Ts&&... others) { 92 | _precede(std::forward(task)); 93 | _precede(std::forward(others)...); 94 | } 95 | 96 | // Function: name 97 | inline cudaTask& cudaTask::name(const std::string& name) { 98 | _node->_name = name; 99 | return *this; 100 | } 101 | 102 | // Function: name 103 | inline const std::string& cudaTask::name() const { 104 | return _node->_name; 105 | } 106 | 107 | } // end of namespace tf ----------------------------------------------------- 108 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/cudaflow.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define TF_CUDA 1 4 | 5 | #include 6 | #include "cuda/flow_builder.hpp" 7 | 8 | namespace tf { namespace cuda { 9 | 10 | }} // end of namespace tf::cuda ---------------------------------------------- 11 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/declarations.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace tf { 4 | 5 | // ---------------------------------------------------------------------------- 6 | // forward declarations inside tf 7 | // ---------------------------------------------------------------------------- 8 | class Node; 9 | class Graph; 10 | class FlowBuilder; 11 | class Subflow; 12 | class Task; 13 | class TaskView; 14 | class Taskflow; 15 | class Topology; 16 | class Executor; 17 | 18 | class cudaNode; 19 | class cudaGraph; 20 | class cudaTask; 21 | class cudaFlow; 22 | 23 | } // end of namespace tf ----------------------------------------------------- 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/taskflow.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core/executor.hpp" 4 | 5 | namespace tf { 6 | 7 | } // end of namespace tf. --------------------------------------------------- 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/utility/passive_vector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace tf { 10 | 11 | // Class: PassiveVector 12 | // A vector storing only passive data structure (PDS) or POD data type. 13 | template > 14 | class PassiveVector { 15 | 16 | static_assert(std::is_pod::value, "must be a passive data structure type"); 17 | 18 | public: 19 | 20 | typedef T value_type; 21 | typedef T & reference; 22 | typedef const T & const_reference; 23 | typedef T * pointer; 24 | typedef const T * const_pointer; 25 | typedef T * iterator; 26 | typedef const T * const_iterator; 27 | typedef std::reverse_iterator reverse_iterator; 28 | typedef std::reverse_iterator const_reverse_iterator; 29 | typedef ptrdiff_t difference_type; 30 | typedef size_t size_type; 31 | 32 | PassiveVector() noexcept : 33 | _data {reinterpret_cast(_stack)}, 34 | _num {0}, 35 | _cap {S} { 36 | } 37 | 38 | explicit PassiveVector(size_type n) : _num {n} { 39 | 40 | // need to place on heap 41 | if(n > S) { 42 | _cap = n << 2; 43 | _data = _allocator.allocate(_cap); 44 | } 45 | // stack 46 | else { 47 | _cap = S; 48 | _data = reinterpret_cast(_stack); 49 | } 50 | 51 | } 52 | 53 | PassiveVector(const PassiveVector& rhs) : _num {rhs._num} { 54 | 55 | // heap 56 | if(rhs._num > S) { 57 | _cap = rhs._cap; 58 | _data = _allocator.allocate(rhs._cap); 59 | } 60 | else { 61 | _cap = S; 62 | _data = reinterpret_cast(_stack); 63 | } 64 | 65 | std::memcpy(_data, rhs._data, _num * sizeof(T)); 66 | } 67 | 68 | PassiveVector(PassiveVector&& rhs) : _num {rhs._num} { 69 | 70 | // rhs is in the stack 71 | if(rhs.in_stack()) { 72 | _cap = S; 73 | _data = reinterpret_cast(_stack); 74 | std::memcpy(_stack, rhs._stack, rhs._num*sizeof(T)); 75 | } 76 | // rhs is in the heap 77 | else { 78 | _cap = rhs._cap; 79 | _data = rhs._data; 80 | rhs._data = reinterpret_cast(rhs._stack); 81 | rhs._cap = S; 82 | } 83 | 84 | rhs._num = 0; 85 | } 86 | 87 | ~PassiveVector() { 88 | if(!in_stack()) { 89 | _allocator.deallocate(_data, _cap); 90 | } 91 | } 92 | 93 | iterator begin() noexcept { return _data; } 94 | const_iterator begin() const noexcept { return _data; } 95 | const_iterator cbegin() const noexcept { return _data; } 96 | iterator end() noexcept { return _data + _num; } 97 | const_iterator end() const noexcept { return _data + _num; } 98 | const_iterator cend() const noexcept { return _data + _num; } 99 | 100 | reverse_iterator rbegin() noexcept { return _data + _num; } 101 | const_reverse_iterator crbegin() const noexcept { return _data + _num; } 102 | reverse_iterator rend() noexcept { return _data; } 103 | const_reverse_iterator crend() const noexcept { return _data; } 104 | 105 | reference operator [] (size_type idx) { return _data[idx]; } 106 | const_reference operator [] (size_type idx) const { return _data[idx]; } 107 | 108 | reference at(size_type pos) { 109 | if(pos >= _num) { 110 | throw std::out_of_range("accessed position is out of range"); 111 | } 112 | return this->operator[](pos); 113 | } 114 | 115 | const_reference at(size_type pos) const { 116 | if(pos >= _num) { 117 | throw std::out_of_range("accessed position is out of range"); 118 | } 119 | return this->operator[](pos); 120 | } 121 | 122 | 123 | reference front() { return _data[0]; } 124 | const_reference front() const { return _data[0]; } 125 | reference back() { return _data[_num-1]; } 126 | const_reference back() const { return _data[_num-1]; } 127 | 128 | pointer data() noexcept { return _data; } 129 | const_pointer data() const noexcept { return _data; } 130 | 131 | void push_back(const T& item) { 132 | if(_num == _cap) { 133 | _enlarge(_cap << 1); 134 | } 135 | _data[_num++] = item; 136 | } 137 | 138 | void push_back(T&& item) { 139 | if(_num == _cap) { 140 | _enlarge(_cap << 1); 141 | } 142 | _data[_num++] = item; 143 | } 144 | 145 | void pop_back() { 146 | if(_num > 0) { 147 | --_num; 148 | } 149 | } 150 | 151 | void clear() { 152 | _num = 0; 153 | } 154 | 155 | void resize(size_type N) { 156 | if(N > _cap) { 157 | _enlarge(N<<1); 158 | } 159 | _num = N; 160 | } 161 | 162 | void reserve(size_type C) { 163 | if(C > _cap) { 164 | _enlarge(C); 165 | } 166 | } 167 | 168 | bool empty() const { return _num == 0; } 169 | bool in_stack() const { return _data == reinterpret_cast(_stack); } 170 | 171 | size_type size() const { return _num; } 172 | size_type capacity() const { return _cap; } 173 | size_type max_size() const { return std::numeric_limits::max(); } 174 | 175 | bool operator == (const PassiveVector& rhs) const { 176 | if(_num != rhs._num) { 177 | return false; 178 | } 179 | return std::memcmp(_data, rhs._data, _num * sizeof(T)) == 0; 180 | } 181 | 182 | private: 183 | 184 | char _stack[S*sizeof(T)]; 185 | 186 | T* _data; 187 | 188 | size_type _num; 189 | size_type _cap; 190 | 191 | A _allocator; 192 | 193 | void _enlarge(size_type new_cap) { 194 | 195 | auto new_data = _allocator.allocate(new_cap); 196 | 197 | std::memcpy(new_data, _data, sizeof(T) * _num); 198 | 199 | if(!in_stack()) { 200 | _allocator.deallocate(_data, _cap); 201 | } 202 | 203 | _cap = new_cap; 204 | _data = new_data; 205 | } 206 | }; 207 | 208 | 209 | } // end of namespace tf. ---------------------------------------------------- 210 | 211 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/utility/stringify.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace tf { 7 | 8 | // Procedure: stringify 9 | template 10 | void ostreamize(std::ostringstream& oss, T&& token) { 11 | oss << std::forward(token); 12 | } 13 | 14 | // Procedure: stringify 15 | template 16 | void ostreamize(std::ostringstream& oss, T&& token, Rest&&... rest) { 17 | oss << std::forward(token); 18 | ostreamize(oss, std::forward(rest)...); 19 | } 20 | 21 | } // end of namespace tf ----------------------------------------------------- 22 | -------------------------------------------------------------------------------- /thirdparty/cpp-taskflow/taskflow/utility/traits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 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 | #include 21 | #include 22 | 23 | namespace tf { 24 | 25 | //----------------------------------------------------------------------------- 26 | // Traits 27 | //----------------------------------------------------------------------------- 28 | 29 | // Macro to check whether a class has a member function 30 | #define define_has_member(member_name) \ 31 | template \ 32 | class has_member_##member_name \ 33 | { \ 34 | typedef char yes_type; \ 35 | typedef long no_type; \ 36 | template static yes_type test(decltype(&U::member_name)); \ 37 | template static no_type test(...); \ 38 | public: \ 39 | static constexpr bool value = sizeof(test(0)) == sizeof(yes_type); \ 40 | } 41 | 42 | #define has_member(class_, member_name) has_member_##member_name::value 43 | 44 | // Struct: dependent_false 45 | template 46 | struct dependent_false { 47 | static constexpr bool value = false; 48 | }; 49 | 50 | template 51 | constexpr auto dependent_false_v = dependent_false::value; 52 | 53 | //----------------------------------------------------------------------------- 54 | // Move-On-Copy 55 | //----------------------------------------------------------------------------- 56 | 57 | // Struct: MoC 58 | template 59 | struct MoC { 60 | 61 | MoC(T&& rhs) : object(std::move(rhs)) {} 62 | MoC(const MoC& other) : object(std::move(other.object)) {} 63 | 64 | T& get() { return object; } 65 | 66 | mutable T object; 67 | }; 68 | 69 | template 70 | auto make_moc(T&& m) { 71 | return MoC(std::forward(m)); 72 | } 73 | 74 | //----------------------------------------------------------------------------- 75 | // Functors. 76 | //----------------------------------------------------------------------------- 77 | 78 | //// Overloadded. 79 | //template 80 | //struct Functors : Ts... { 81 | // using Ts::operator()... ; 82 | //}; 83 | // 84 | //template 85 | //Functors(Ts...) -> Functors; 86 | 87 | // ---------------------------------------------------------------------------- 88 | // callable traits 89 | // ---------------------------------------------------------------------------- 90 | 91 | template 92 | struct is_invocable : 93 | std::is_constructible< 94 | std::function, 95 | std::reference_wrapper::type> 96 | > { 97 | }; 98 | 99 | template 100 | constexpr bool is_invocable_v = is_invocable::value; 101 | 102 | template 103 | struct is_invocable_r : 104 | std::is_constructible< 105 | std::function, 106 | std::reference_wrapper::type> 107 | > { 108 | }; 109 | 110 | template 111 | constexpr bool is_invocable_r_v = is_invocable_r::value; 112 | 113 | 114 | // ---------------------------------------------------------------------------- 115 | // Function Traits 116 | // reference: https://github.com/ros2/rclcpp 117 | // ---------------------------------------------------------------------------- 118 | 119 | template 120 | struct tuple_tail; 121 | 122 | template 123 | struct tuple_tail> { 124 | using type = std::tuple; 125 | }; 126 | 127 | // std::function 128 | template 129 | struct function_traits 130 | { 131 | using arguments = typename tuple_tail< 132 | typename function_traits::argument_tuple_type 133 | >::type; 134 | 135 | static constexpr size_t arity = std::tuple_size::value; 136 | 137 | template 138 | struct argument { 139 | static_assert(N < arity, "error: invalid parameter index."); 140 | using type = std::tuple_element_t; 141 | }; 142 | 143 | template 144 | using argument_t = typename argument::type; 145 | 146 | using return_type = typename function_traits::return_type; 147 | }; 148 | 149 | // Free functions 150 | template 151 | struct function_traits { 152 | 153 | using return_type = R; 154 | using argument_tuple_type = std::tuple; 155 | 156 | static constexpr size_t arity = sizeof...(Args); 157 | 158 | template 159 | struct argument { 160 | static_assert(N < arity, "error: invalid parameter index."); 161 | using type = std::tuple_element_t>; 162 | }; 163 | 164 | template 165 | using argument_t = typename argument::type; 166 | }; 167 | 168 | // function pointer 169 | template 170 | struct function_traits : function_traits { 171 | }; 172 | 173 | // function reference 174 | template 175 | struct function_traits : function_traits { 176 | }; 177 | 178 | // immutable lambda 179 | template 180 | struct function_traits 181 | : function_traits 182 | {}; 183 | 184 | // mutable lambda 185 | template 186 | struct function_traits 187 | : function_traits 188 | {}; 189 | 190 | /*// std::bind for object methods 191 | template 192 | #if defined _LIBCPP_VERSION // libc++ (Clang) 193 | struct function_traits> 194 | #elif defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1) 195 | struct function_traits> 196 | #elif defined __GLIBCXX__ // glibc++ (GNU C++) 197 | struct function_traits(FArgs ...)>> 198 | #elif defined _MSC_VER // MS Visual Studio 199 | struct function_traits< 200 | std::_Binder> 201 | #else 202 | #error "Unsupported C++ compiler / standard library" 203 | #endif 204 | : function_traits 205 | {}; 206 | 207 | // std::bind for object const methods 208 | template 209 | #if defined _LIBCPP_VERSION // libc++ (Clang) 210 | struct function_traits> 211 | #elif defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1) 212 | struct function_traits> 213 | #elif defined __GLIBCXX__ // glibc++ (GNU C++) 214 | struct function_traits(FArgs ...)>> 215 | #elif defined _MSC_VER // MS Visual Studio 216 | struct function_traits< 217 | std::_Binder> 218 | #else 219 | #error "Unsupported C++ compiler / standard library" 220 | #endif 221 | : function_traits 222 | {}; 223 | 224 | // std::bind for free functions 225 | template 226 | #if defined _LIBCPP_VERSION // libc++ (Clang) 227 | struct function_traits> 228 | #elif defined __GLIBCXX__ // glibc++ (GNU C++) 229 | struct function_traits> 230 | #elif defined _MSC_VER // MS Visual Studio 231 | struct function_traits> 232 | #else 233 | #error "Unsupported C++ compiler / standard library" 234 | #endif 235 | : function_traits 236 | {}; */ 237 | 238 | // decay to the raw type 239 | template 240 | struct function_traits : function_traits {}; 241 | 242 | template 243 | struct function_traits : function_traits {}; 244 | 245 | 246 | } // end of namespace tf. --------------------------------------------------- 247 | -------------------------------------------------------------------------------- /thirdparty/glad/include/KHR/khrplatform.h: -------------------------------------------------------------------------------- 1 | #ifndef __khrplatform_h_ 2 | #define __khrplatform_h_ 3 | 4 | /* 5 | ** Copyright (c) 2008-2009 The Khronos Group Inc. 6 | ** 7 | ** Permission is hereby granted, free of charge, to any person obtaining a 8 | ** copy of this software and/or associated documentation files (the 9 | ** "Materials"), to deal in the Materials without restriction, including 10 | ** without limitation the rights to use, copy, modify, merge, publish, 11 | ** distribute, sublicense, and/or sell copies of the Materials, and to 12 | ** permit persons to whom the Materials are furnished to do so, subject to 13 | ** the following conditions: 14 | ** 15 | ** The above copyright notice and this permission notice shall be included 16 | ** in all copies or substantial portions of the Materials. 17 | ** 18 | ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. 25 | */ 26 | 27 | /* Khronos platform-specific types and definitions. 28 | * 29 | * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $ 30 | * 31 | * Adopters may modify this file to suit their platform. Adopters are 32 | * encouraged to submit platform specific modifications to the Khronos 33 | * group so that they can be included in future versions of this file. 34 | * Please submit changes by sending them to the public Khronos Bugzilla 35 | * (http://khronos.org/bugzilla) by filing a bug against product 36 | * "Khronos (general)" component "Registry". 37 | * 38 | * A predefined template which fills in some of the bug fields can be 39 | * reached using http://tinyurl.com/khrplatform-h-bugreport, but you 40 | * must create a Bugzilla login first. 41 | * 42 | * 43 | * See the Implementer's Guidelines for information about where this file 44 | * should be located on your system and for more details of its use: 45 | * http://www.khronos.org/registry/implementers_guide.pdf 46 | * 47 | * This file should be included as 48 | * #include 49 | * by Khronos client API header files that use its types and defines. 50 | * 51 | * The types in khrplatform.h should only be used to define API-specific types. 52 | * 53 | * Types defined in khrplatform.h: 54 | * khronos_int8_t signed 8 bit 55 | * khronos_uint8_t unsigned 8 bit 56 | * khronos_int16_t signed 16 bit 57 | * khronos_uint16_t unsigned 16 bit 58 | * khronos_int32_t signed 32 bit 59 | * khronos_uint32_t unsigned 32 bit 60 | * khronos_int64_t signed 64 bit 61 | * khronos_uint64_t unsigned 64 bit 62 | * khronos_intptr_t signed same number of bits as a pointer 63 | * khronos_uintptr_t unsigned same number of bits as a pointer 64 | * khronos_ssize_t signed size 65 | * khronos_usize_t unsigned size 66 | * khronos_float_t signed 32 bit floating point 67 | * khronos_time_ns_t unsigned 64 bit time in nanoseconds 68 | * khronos_utime_nanoseconds_t unsigned time interval or absolute time in 69 | * nanoseconds 70 | * khronos_stime_nanoseconds_t signed time interval in nanoseconds 71 | * khronos_boolean_enum_t enumerated boolean type. This should 72 | * only be used as a base type when a client API's boolean type is 73 | * an enum. Client APIs which use an integer or other type for 74 | * booleans cannot use this as the base type for their boolean. 75 | * 76 | * Tokens defined in khrplatform.h: 77 | * 78 | * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. 79 | * 80 | * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. 81 | * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. 82 | * 83 | * Calling convention macros defined in this file: 84 | * KHRONOS_APICALL 85 | * KHRONOS_APIENTRY 86 | * KHRONOS_APIATTRIBUTES 87 | * 88 | * These may be used in function prototypes as: 89 | * 90 | * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( 91 | * int arg1, 92 | * int arg2) KHRONOS_APIATTRIBUTES; 93 | */ 94 | 95 | /*------------------------------------------------------------------------- 96 | * Definition of KHRONOS_APICALL 97 | *------------------------------------------------------------------------- 98 | * This precedes the return type of the function in the function prototype. 99 | */ 100 | #if defined(_WIN32) && !defined(__SCITECH_SNAP__) 101 | # define KHRONOS_APICALL __declspec(dllimport) 102 | #elif defined (__SYMBIAN32__) 103 | # define KHRONOS_APICALL IMPORT_C 104 | #else 105 | # define KHRONOS_APICALL 106 | #endif 107 | 108 | /*------------------------------------------------------------------------- 109 | * Definition of KHRONOS_APIENTRY 110 | *------------------------------------------------------------------------- 111 | * This follows the return type of the function and precedes the function 112 | * name in the function prototype. 113 | */ 114 | #if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) 115 | /* Win32 but not WinCE */ 116 | # define KHRONOS_APIENTRY __stdcall 117 | #else 118 | # define KHRONOS_APIENTRY 119 | #endif 120 | 121 | /*------------------------------------------------------------------------- 122 | * Definition of KHRONOS_APIATTRIBUTES 123 | *------------------------------------------------------------------------- 124 | * This follows the closing parenthesis of the function prototype arguments. 125 | */ 126 | #if defined (__ARMCC_2__) 127 | #define KHRONOS_APIATTRIBUTES __softfp 128 | #else 129 | #define KHRONOS_APIATTRIBUTES 130 | #endif 131 | 132 | /*------------------------------------------------------------------------- 133 | * basic type definitions 134 | *-----------------------------------------------------------------------*/ 135 | #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) 136 | 137 | 138 | /* 139 | * Using 140 | */ 141 | #include 142 | typedef int32_t khronos_int32_t; 143 | typedef uint32_t khronos_uint32_t; 144 | typedef int64_t khronos_int64_t; 145 | typedef uint64_t khronos_uint64_t; 146 | #define KHRONOS_SUPPORT_INT64 1 147 | #define KHRONOS_SUPPORT_FLOAT 1 148 | 149 | #elif defined(__VMS ) || defined(__sgi) 150 | 151 | /* 152 | * Using 153 | */ 154 | #include 155 | typedef int32_t khronos_int32_t; 156 | typedef uint32_t khronos_uint32_t; 157 | typedef int64_t khronos_int64_t; 158 | typedef uint64_t khronos_uint64_t; 159 | #define KHRONOS_SUPPORT_INT64 1 160 | #define KHRONOS_SUPPORT_FLOAT 1 161 | 162 | #elif defined(_WIN32) && !defined(__SCITECH_SNAP__) 163 | 164 | /* 165 | * Win32 166 | */ 167 | typedef __int32 khronos_int32_t; 168 | typedef unsigned __int32 khronos_uint32_t; 169 | typedef __int64 khronos_int64_t; 170 | typedef unsigned __int64 khronos_uint64_t; 171 | #define KHRONOS_SUPPORT_INT64 1 172 | #define KHRONOS_SUPPORT_FLOAT 1 173 | 174 | #elif defined(__sun__) || defined(__digital__) 175 | 176 | /* 177 | * Sun or Digital 178 | */ 179 | typedef int khronos_int32_t; 180 | typedef unsigned int khronos_uint32_t; 181 | #if defined(__arch64__) || defined(_LP64) 182 | typedef long int khronos_int64_t; 183 | typedef unsigned long int khronos_uint64_t; 184 | #else 185 | typedef long long int khronos_int64_t; 186 | typedef unsigned long long int khronos_uint64_t; 187 | #endif /* __arch64__ */ 188 | #define KHRONOS_SUPPORT_INT64 1 189 | #define KHRONOS_SUPPORT_FLOAT 1 190 | 191 | #elif 0 192 | 193 | /* 194 | * Hypothetical platform with no float or int64 support 195 | */ 196 | typedef int khronos_int32_t; 197 | typedef unsigned int khronos_uint32_t; 198 | #define KHRONOS_SUPPORT_INT64 0 199 | #define KHRONOS_SUPPORT_FLOAT 0 200 | 201 | #else 202 | 203 | /* 204 | * Generic fallback 205 | */ 206 | #include 207 | typedef int32_t khronos_int32_t; 208 | typedef uint32_t khronos_uint32_t; 209 | typedef int64_t khronos_int64_t; 210 | typedef uint64_t khronos_uint64_t; 211 | #define KHRONOS_SUPPORT_INT64 1 212 | #define KHRONOS_SUPPORT_FLOAT 1 213 | 214 | #endif 215 | 216 | 217 | /* 218 | * Types that are (so far) the same on all platforms 219 | */ 220 | typedef signed char khronos_int8_t; 221 | typedef unsigned char khronos_uint8_t; 222 | typedef signed short int khronos_int16_t; 223 | typedef unsigned short int khronos_uint16_t; 224 | 225 | /* 226 | * Types that differ between LLP64 and LP64 architectures - in LLP64, 227 | * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears 228 | * to be the only LLP64 architecture in current use. 229 | */ 230 | #ifdef _WIN64 231 | typedef signed long long int khronos_intptr_t; 232 | typedef unsigned long long int khronos_uintptr_t; 233 | typedef signed long long int khronos_ssize_t; 234 | typedef unsigned long long int khronos_usize_t; 235 | #else 236 | typedef signed long int khronos_intptr_t; 237 | typedef unsigned long int khronos_uintptr_t; 238 | typedef signed long int khronos_ssize_t; 239 | typedef unsigned long int khronos_usize_t; 240 | #endif 241 | 242 | #if KHRONOS_SUPPORT_FLOAT 243 | /* 244 | * Float type 245 | */ 246 | typedef float khronos_float_t; 247 | #endif 248 | 249 | #if KHRONOS_SUPPORT_INT64 250 | /* Time types 251 | * 252 | * These types can be used to represent a time interval in nanoseconds or 253 | * an absolute Unadjusted System Time. Unadjusted System Time is the number 254 | * of nanoseconds since some arbitrary system event (e.g. since the last 255 | * time the system booted). The Unadjusted System Time is an unsigned 256 | * 64 bit value that wraps back to 0 every 584 years. Time intervals 257 | * may be either signed or unsigned. 258 | */ 259 | typedef khronos_uint64_t khronos_utime_nanoseconds_t; 260 | typedef khronos_int64_t khronos_stime_nanoseconds_t; 261 | #endif 262 | 263 | /* 264 | * Dummy value used to pad enum types to 32 bits. 265 | */ 266 | #ifndef KHRONOS_MAX_ENUM 267 | #define KHRONOS_MAX_ENUM 0x7FFFFFFF 268 | #endif 269 | 270 | /* 271 | * Enumerated boolean type 272 | * 273 | * Values other than zero should be considered to be true. Therefore 274 | * comparisons should not be made against KHRONOS_TRUE. 275 | */ 276 | typedef enum { 277 | KHRONOS_FALSE = 0, 278 | KHRONOS_TRUE = 1, 279 | KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM 280 | } khronos_boolean_enum_t; 281 | 282 | #endif /* __khrplatform_h_ */ 283 | --------------------------------------------------------------------------------