diff --git a/.github/workflows/build/osx/action.yml b/.github/workflows/build/osx/action.yml index 1f1d312a41..18fbce1dea 100644 --- a/.github/workflows/build/osx/action.yml +++ b/.github/workflows/build/osx/action.yml @@ -6,10 +6,6 @@ inputs: default: true osxTargetDeploymentVersion: default: 13.3 - freeTypeArchive: - default: https://download.savannah.gnu.org/releases/freetype/freetype-2.12.1.tar.gz - ftglRepo: - default: https://github.com/disorderedmaterials/ftgl-2.4.0 cacheOnly: type: boolean default: false @@ -37,7 +33,6 @@ runs: set -ex brew update-reset brew install gsl - brew uninstall --ignore-dependencies freetype - name: Get ANTLR working-directory: ${{ runner.temp }} @@ -57,74 +52,6 @@ runs: export PATH="$(python3 -m site --user-base)/bin:$PATH" aqt install-qt --outputdir ${{ runner.temp }}/qt mac desktop ${{ inputs.qtVersion }} -m all - # - # Build / Retrieve Freetype - # - - - name: Retrieve FreeType Cache - id: cache-freetype - uses: actions/cache@v4 - with: - key: osx-freetype - path: | - ${{ runner.temp }}/freetype-latest - ${{ runner.temp }}/freetype-install - - - name: Download FreeType - if: ${{ steps.cache-freetype.outputs.cache-hit != 'true' }} - working-directory: ${{ runner.temp }} - shell: bash - run: | - set -ex - wget ${{ inputs.freeTypeArchive }} -Ofreetype.tgz - tar -zxvf freetype.tgz - rm freetype.tgz - mv freetype-* freetype-latest - - - name: Build FreeType - if: ${{ steps.cache-freetype.outputs.cache-hit != 'true' }} - working-directory: ${{ runner.temp }} - shell: bash - run: | - set -ex - mkdir freetype-build && cd freetype-build - cmake ../freetype-latest -G Ninja -DCMAKE_BUILD_TYPE:STRING="Release" -DCMAKE_DISABLE_FIND_PACKAGE_HarfBuzz:bool=true -DCMAKE_DISABLE_FIND_PACKAGE_BZip2:bool=true -DCMAKE_DISABLE_FIND_PACKAGE_PNG:bool=true -DCMAKE_DISABLE_FIND_PACKAGE_ZLIB:bool=true -DCMAKE_DISABLE_FIND_PACKAGE_BrotliDec:bool=true -DCMAKE_INSTALL_PREFIX:path=../freetype-install -DBUILD_SHARED_LIBS:bool=OFF -DCMAKE_OSX_DEPLOYMENT_TARGET=${{ inputs.osxTargetDeploymentVersion }} - cmake --build . --target install --config Release - - # - # Build / Retrieve FTGL - # - - - name: Retrieve FTGL Cache - id: cache-ftgl - uses: actions/cache@v4 - with: - key: osx-ftgl - path: | - ${{ runner.temp }}/ftgl-latest - ${{ runner.temp }}/ftgl-install - - - name: Download FTGL - if: ${{ steps.cache-ftgl.outputs.cache-hit != 'true' }} - working-directory: ${{ runner.temp }} - shell: bash - run: | - set -ex - git clone ${{ inputs.ftglRepo }} ftgl-latest - - - name: Build FTGL - if: ${{ steps.cache-ftgl.outputs.cache-hit != 'true' }} - working-directory: ${{ runner.temp }} - shell: bash - run: | - set -ex - mkdir ftgl-build && cd ftgl-build - INCLUDE="${RUNNER_TEMP}/freetype-latest;$INCLUDE" - LIB="${RUNNER_TEMP}/freetype-install/lib;${RUNNER_TEMP}/freetype-install/bin;$LIB" - export FREETYPE_DIR="${RUNNER_TEMP}/freetype-install" - cmake ../ftgl-latest -G Ninja -DCMAKE_BUILD_TYPE:STRING="Release" -DCMAKE_INSTALL_PREFIX:path=../ftgl-install -DBUILD_SHARED_LIBS:bool=OFF -DCMAKE_OSX_DEPLOYMENT_TARGET=${{ inputs.osxTargetDeploymentVersion }} - cmake --build . --target install --config Release - # # Main Build # @@ -155,8 +82,6 @@ runs: export PATH="$(python3 -m site --user-base)/bin:$PATH" Qt6_DIR=${{ runner.temp }}/qt/${{ inputs.qtVersion }}/macos/lib/cmake/Qt6 QT_BASE_DIR=${{ runner.temp }}/qt/${{ inputs.qtVersion }}/macos - export FTGL_DIR="${RUNNER_TEMP}/ftgl-install" - export FREETYPE_DIR="${RUNNER_TEMP}/freetype-install" # Find ANTLR4 ANTLR_EXE="${{ runner.temp }}/antlr-${{ inputs.antlrVersion }}-complete.jar" diff --git a/.github/workflows/build/windows/action.yml b/.github/workflows/build/windows/action.yml index 6d05f4ef1e..de65b3f078 100644 --- a/.github/workflows/build/windows/action.yml +++ b/.github/workflows/build/windows/action.yml @@ -4,10 +4,6 @@ description: Build on Windows inputs: threading: default: true - freeTypeArchive: - default: https://download.savannah.gnu.org/releases/freetype/freetype-2.12.1.tar.gz - ftglRepo: - default: https://github.com/disorderedmaterials/ftgl-2.4.0 cacheOnly: type: boolean default: false @@ -58,82 +54,6 @@ runs: - name: Setup MSVC Compiler uses: ilammy/msvc-dev-cmd@v1 - # - # Build / Retrieve Freetype - # - - - name: Retrieve FreeType Cache - id: cache-freetype - uses: actions/cache@v4 - with: - key: windows-freetype - path: | - ${{ runner.temp }}\freetype-latest - ${{ runner.temp }}\freetype-install - - - name: Download FreeType - if: ${{ steps.cache-freetype.outputs.cache-hit != 'true' }} - working-directory: ${{ runner.temp }} - shell: bash - run: | - set -ex - wget ${{ inputs.freeTypeArchive }} -Ofreetype.tgz - tar -zxvf freetype.tgz - rm freetype.tgz - mv freetype-* freetype-latest - - - name: Build FreeType - if: ${{ steps.cache-freetype.outputs.cache-hit != 'true' }} - working-directory: ${{ runner.temp }} - shell: bash - run: | - set -ex - mkdir freetype-build && cd freetype-build - cmake ../freetype-latest -G Ninja -DCMAKE_BUILD_TYPE:STRING="Release" -DCMAKE_C_COMPILER=cl -DBUILD_SHARED_LIBS:STRING=ON -DCMAKE_DISABLE_FIND_PACKAGE_HarfBuzz:bool=true -DCMAKE_DISABLE_FIND_PACKAGE_BZip2:bool=true -DCMAKE_DISABLE_FIND_PACKAGE_PNG:bool=true -DCMAKE_DISABLE_FIND_PACKAGE_ZLIB:bool=true -DCMAKE_DISABLE_FIND_PACKAGE_BrotliDec:bool=true -DCMAKE_INSTALL_PREFIX:path=../freetype-install - cmake --build . --target install --config Release - - # - # Build / Retrieve FTGL - # - - - name: Retrieve FTGL Cache - id: cache-ftgl - uses: actions/cache@v4 - with: - key: windows-ftgl - path: | - ${{ runner.temp }}\ftgl-latest - ${{ runner.temp }}\ftgl-install - - - name: Download FTGL - if: ${{ steps.cache-ftgl.outputs.cache-hit != 'true' }} - working-directory: ${{ runner.temp }} - shell: bash - run: | - set -ex - git clone ${{ inputs.ftglRepo }} ftgl-latest - - - name: Build FTGL - if: ${{ steps.cache-ftgl.outputs.cache-hit != 'true' }} - working-directory: ${{ runner.temp }} - shell: bash - run: | - set -ex - mkdir ftgl-build && cd ftgl-build - INCLUDE="${RUNNER_TEMP}\freetype-latest;$INCLUDE" - LIB="${RUNNER_TEMP}\freetype-install\lib;${RUNNER_TEMP}\freetype-install\bin;$LIB" - cmake ../ftgl-latest -G Ninja -DCMAKE_BUILD_TYPE:STRING="Release" -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_INSTALL_PREFIX:path=../ftgl-install - cmake --build . --target install --config Release - - - name: Get ANTLR and Java - working-directory: ${{ runner.temp }} - shell: bash - run: | - set -ex - wget https://www.antlr.org/download/antlr-${{ inputs.antlrVersion }}-complete.jar -Oantlr-${{ inputs.antlrVersion }}-complete.jar - wget https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.zip -Ojava.zip - unzip java.zip - # # Main Build # diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fe91737d6..6648e91339 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,19 +108,13 @@ if(MULTI_THREADING) endif(MULTI_THREADING) if(GUI) - find_package(Freetype REQUIRED) - find_package(FTGL REQUIRED) - list(APPEND CMAKE_PREFIX_PATH "${QT_BASE_DIR}") - find_package(OpenGL REQUIRED) find_package( Qt6 COMPONENTS Core DBusTools Gui Widgets - OpenGL - OpenGLWidgets Qml QmlModels QmlTools @@ -153,11 +147,6 @@ if(WIN32) set(gui_target_name Dissolve-GUI) set(qmlgui_target_name Dissolve-GUI-QML) - # Adjust external include directories for GUI - if(GUI) - include_directories(${FTGL_INCLUDE_DIRS}) - endif(GUI) - # Format requires on MSVC std:c++latest, so we have to ask for C++23, despite the fact it's part of the C++20 standard. set(CMAKE_CXX_STANDARD 23) @@ -195,15 +184,6 @@ if(APPLE) set(qmlgui_target_name dissolve-gui-qml) add_definitions(-D_MAC) - - if(GUI) - # Find GLUT - find_package(GLUT REQUIRED) - - # Adjust external include directories for GUI - include_directories(${FTGL_INCLUDE_DIRS}) - include_directories(${FREETYPE_INCLUDE_DIRS}) - endif(GUI) endif(APPLE) set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) diff --git a/flake.nix b/flake.nix index 597417ff31..57ced7e246 100644 --- a/flake.nix +++ b/flake.nix @@ -45,7 +45,6 @@ gbenchmark cmake cli11 - freetype gsl inetutils # for rsh ninja @@ -56,8 +55,6 @@ ]; gui_libs = system: pkgs: qt: [ pkgs.glib - pkgs.freetype - pkgs.ftgl pkgs.libGL.dev pkgs.libglvnd pkgs.libglvnd.dev diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index eb3362a315..6a9f9fe198 100755 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -16,10 +16,7 @@ target_include_directories( gui PRIVATE ${PROJECT_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}/src - ${FREETYPE_INCLUDE_DIRS} ${Qt6Core_INCLUDE_DIRS} - ${Qt6OpenGL_INCLUDE_DIRS} - ${Qt6OpenGLWidgets_INCLUDE_DIRS} ${Qt6Widgets_INCLUDE_DIRS} ) @@ -29,8 +26,6 @@ target_link_libraries( widgets models base - Qt6::OpenGL - Qt6::OpenGLWidgets Qt6::Quick Qt6::QuickControls2 Qt6::Core @@ -42,7 +37,6 @@ target_link_libraries( # Subdirectories add_subdirectory(delegates) -add_subdirectory(render) add_subdirectory(widgets) add_subdirectory(models) add_subdirectory(icons) diff --git a/src/gui/render/CMakeLists.txt b/src/gui/render/CMakeLists.txt deleted file mode 100755 index d4100d4734..0000000000 --- a/src/gui/render/CMakeLists.txt +++ /dev/null @@ -1,107 +0,0 @@ -# TextPrimitive ANTLR Lexer/Parser -antlr_target(TextPrimitiveGrammarLexer TextPrimitiveLexer.g4 LEXER) -# PACKAGE TextPrimitiveGrammar) -antlr_target( - TextPrimitiveGrammarParser - TextPrimitiveParser.g4 - PARSER - # PACKAGE TextPrimitiveGrammar - DEPENDS_ANTLR - TextPrimitiveGrammarLexer - COMPILE_FLAGS - -no-listener - -visitor - -lib - ${ANTLR_TextPrimitiveGrammarLexer_OUTPUT_DIR} -) - -# Append path to ANTLR parser output, and set cache variable -list(APPEND ANTLR_OUTPUT_DIRS ${ANTLR_TextPrimitiveGrammarLexer_OUTPUT_DIR}) -list(APPEND ANTLR_OUTPUT_DIRS ${ANTLR_TextPrimitiveGrammarParser_OUTPUT_DIR}) -set(ANTLR_OUTPUT_DIRS - ${ANTLR_OUTPUT_DIRS} - CACHE INTERNAL "" -) - -# Target 'render' -add_library( - render - axes.h - colourDefinition.h - colourScaleDelta.h - colourScale.h - colourScalePoint.h - fontInstance.h - lineStipple.h - lineStyle.h - numberFormat.h - primitiveAssembly.h - primitive.h - primitiveInfo.h - primitiveInstance.h - primitiveList.h - renderable.h - renderableConfiguration.h - renderableData1D.h - renderableData2D.h - renderableData3D.h - renderableGroup.h - renderableGroupManager.h - renderableSpecies.h - renderableSpeciesSite.h - symbol.h - textFormat.h - textFragment.h - textPrimitive.h - textPrimitiveList.h - vertexChunk.h - view.h - TextPrimitiveErrorListeners.h - TextPrimitiveVisitor.h - axes.cpp - colourDefinition.cpp - colourScale.cpp - colourScaleDelta.cpp - colourScalePoint.cpp - fontInstance.cpp - lineStipple.cpp - lineStyle.cpp - numberFormat.cpp - primitiveAssembly.cpp - primitive.cpp - primitiveInfo.cpp - primitiveInstance.cpp - primitiveList.cpp - renderable.cpp - renderableConfiguration.cpp - renderableData1D.cpp - renderableData2D.cpp - renderableData3D.cpp - renderableGroup.cpp - renderableGroupManager.cpp - renderableSpecies.cpp - renderableSpeciesSite.cpp - symbol.cpp - textFormat.cpp - textFragment.cpp - textPrimitive.cpp - textPrimitiveList.cpp - vertexChunk.cpp - view.cpp - TextPrimitiveErrorListeners.cpp - TextPrimitiveVisitor.cpp - ${ANTLR_TextPrimitiveGrammarLexer_CXX_OUTPUTS} - ${ANTLR_TextPrimitiveGrammarParser_CXX_OUTPUTS} -) - -target_include_directories( - render PRIVATE ${PROJECT_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}/src ${Qt6Widgets_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS} - ${ANTLR_TextPrimitiveGrammarLexer_OUTPUT_DIR} ${ANTLR_TextPrimitiveGrammarParser_OUTPUT_DIR} -) - -# Because Qt has its own way of checking for C++17 -if(MSVC) - target_compile_options(render PUBLIC /Zc:__cplusplus) -endif(MSVC) - -target_link_libraries(render PRIVATE base) diff --git a/src/gui/render/TextPrimitiveErrorListeners.cpp b/src/gui/render/TextPrimitiveErrorListeners.cpp deleted file mode 100644 index 663210de15..0000000000 --- a/src/gui/render/TextPrimitiveErrorListeners.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/TextPrimitiveErrorListeners.h" -#include "base/messenger.h" -#include "base/sysFunc.h" - -/* - * TextPrimitive Lexer Error Listener - */ - -TextPrimitiveLexerErrorListener::TextPrimitiveLexerErrorListener(const std::string inputString) : inputString_{inputString} {} - -void TextPrimitiveLexerErrorListener::syntaxError(antlr4::Recognizer *recognizer, antlr4::Token *token, size_t line, - size_t charPositionInLine, const std::string &message, std::exception_ptr ep) -{ - Messenger::print("\nError in TextPrimitive definition '{}'\n", inputString_); - std::string marker(34 + charPositionInLine, ' '); - marker += '^'; - Messenger::print("{}\n", marker); - - // The actual error message can contain braces, so escape those to avoid breaking fmt - auto escaped = DissolveSys::replace(DissolveSys::replace(message, "{", "{{"), "}", "}}"); - - throw TextPrimitiveExceptions::TextPrimitiveSyntaxException(std::format("Syntax Error: {}", escaped)); -} - -/* - * TextPrimitive Parser Error Listener - */ - -TextPrimitiveParserErrorListener::TextPrimitiveParserErrorListener(const std::string inputString) : inputString_{inputString} {} - -void TextPrimitiveParserErrorListener::syntaxError(antlr4::Recognizer *recognizer, antlr4::Token *token, size_t line, - size_t charPositionInLine, const std::string &message, std::exception_ptr ep) -{ - Messenger::print("\nError in TextPrimitive definition '{}'\n", inputString_); - std::string marker(34 + charPositionInLine, ' '); - marker += '^'; - Messenger::print("{}\n", marker); - - // The actual error message can contain braces, so escape those to avoid breaking fmt - auto escaped = DissolveSys::replace(DissolveSys::replace(message, "{", "{{"), "}", "}}"); - - throw TextPrimitiveExceptions::TextPrimitiveSyntaxException(std::format("Syntax Error: {}", escaped)); -} diff --git a/src/gui/render/TextPrimitiveErrorListeners.h b/src/gui/render/TextPrimitiveErrorListeners.h deleted file mode 100644 index 2543fad397..0000000000 --- a/src/gui/render/TextPrimitiveErrorListeners.h +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include -#include - -namespace TextPrimitiveExceptions -{ -// TextPrimitive Syntax Exception -class TextPrimitiveSyntaxException : public std::exception -{ - public: - TextPrimitiveSyntaxException(std::string_view message = "Undefined TextPrimitive Syntax Exception") : message_{message} {} - - private: - // Error message - std::string message_; - - public: - virtual const char *what() const throw() { return message_.c_str(); } -}; - -// TextPrimitive Internal Error Exception -class TextPrimitiveInternalErrorException : public std::exception -{ - public: - TextPrimitiveInternalErrorException(std::string_view message = "TextPrimitive internal error.") : message_{message} {} - - private: - // Input string to TextPrimitive - std::string message_; - - public: - virtual const char *what() const throw() { return message_.c_str(); } -}; -} // namespace TextPrimitiveExceptions - -// TextPrimitive Lexer Error Listener -class TextPrimitiveLexerErrorListener : public antlr4::BaseErrorListener -{ - public: - TextPrimitiveLexerErrorListener(const std::string inputString); - - private: - // Input string to TextPrimitive - const std::string inputString_; - - /* - * BaseErrorListener Overrides - */ - public: - void syntaxError(antlr4::Recognizer *recognizer, antlr4::Token *, size_t line, size_t charPositionInLine, - const std::string &, std::exception_ptr ep); -}; - -// TextPrimitive Parser Error Listener -class TextPrimitiveParserErrorListener : public antlr4::BaseErrorListener -{ - public: - TextPrimitiveParserErrorListener(const std::string inputString); - - private: - // Input string to TextPrimitive - const std::string inputString_; - - /* - * BaseErrorListener Overrides - */ - public: - void syntaxError(antlr4::Recognizer *recognizer, antlr4::Token *, size_t line, size_t charPositionInLine, - const std::string &, std::exception_ptr ep); -}; diff --git a/src/gui/render/TextPrimitiveLexer.g4 b/src/gui/render/TextPrimitiveLexer.g4 deleted file mode 100644 index f5181b1859..0000000000 --- a/src/gui/render/TextPrimitiveLexer.g4 +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -lexer grammar TextPrimitiveLexer; - -// Lexer file header -@lexer::header {/* TextPrimitive ANTLR Lexer */} - -// Add custom includes after standard ANTLR includes in both *.h and *.cpp files -@lexer::postinclude { - #include "gui/render/symbol.h" - #include "gui/render/TextPrimitiveVisitor.h" -} - -// Directly precedes the lexer class declaration in the h file (e.g. for additional types etc.). -@lexer::context {/* lexer context section */} - -// Appears in the private part of the lexer in the h file. -@lexer::declarations { - bool isFormatter(std::string text) { return TextPrimitiveVisitor::escapedFormatters().isValid(text.substr(1)); } - bool isSymbol(std::string text) { return SymbolData::symbol(text) != SymbolData::nSymbols; } -} - -// Appears in line with the other class member definitions in the cpp file. -@lexer::definitions {/* lexer definitions section */} - -/* - * Lexer Rules - */ - -// Fragments -fragment LETTER: [a-zA-Z]; -fragment ESCAPE: '\\'; - -// Symbols -OpenBrace: '{'; -CloseBrace: '}'; - -// Escape Sequences -FormatterEscape: ESCAPE LETTER+ { isFormatter(getText()) }?; -SymbolEscape: ESCAPE 's' 'y' 'm'; - -// Enumerated Tokens -Symbol: LETTER+ { isSymbol(getText()) }?; - -// Text -Text: (~([\\{}]))+; diff --git a/src/gui/render/TextPrimitiveParser.g4 b/src/gui/render/TextPrimitiveParser.g4 deleted file mode 100644 index 44ff624aae..0000000000 --- a/src/gui/render/TextPrimitiveParser.g4 +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -parser grammar TextPrimitiveParser; - -options { - tokenVocab = TextPrimitiveLexer; -} - -// Parser file header -@parser::header {/* TextPrimitive ANTLR Parser */} - -// Add custom includes after standard ANTLR includes in both *.h and *.cpp files -@parser::postinclude { } - -// Appears in the private part of the parser in the h file. -@parser::members { /* public parser declarations/members section */ } - -// Appears in the public part of the parser in the h file. -@parser::declarations {/* private parser declarations section */} - -// Appears in line with the other class member definitions in the cpp file. -@parser::definitions {/* parser definitions section */} - -/* - * TextPrimitive Grammar - */ - -// Text Primitive -primitive: frag* EOF; - -// Text Fragment -frag: Text #plainText -| FormatterEscape OpenBrace frag* CloseBrace #formatter -| SymbolEscape OpenBrace Symbol CloseBrace #symbol -; - diff --git a/src/gui/render/TextPrimitiveVisitor.cpp b/src/gui/render/TextPrimitiveVisitor.cpp deleted file mode 100644 index 6efc48ada6..0000000000 --- a/src/gui/render/TextPrimitiveVisitor.cpp +++ /dev/null @@ -1,212 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/TextPrimitiveVisitor.h" -#include "gui/render/TextPrimitiveErrorListeners.h" -#include "gui/render/fontInstance.h" -#include "gui/render/symbol.h" - -// Return enum options for EscapedFormatter -EnumOptions TextPrimitiveVisitor::escapedFormatters() -{ - return EnumOptions("EscapedFormatter", - {{TextPrimitiveVisitor::BoldFormatter, "b"}, - {TextPrimitiveVisitor::ItalicFormatter, "it"}, - {TextPrimitiveVisitor::SubScriptFormatter, "sub"}, - {TextPrimitiveVisitor::SuperScriptFormatter, "sup"}}); -} - -/* - * Construction - */ - -// Return the topmost format in the stack -const TextFormat &TextPrimitiveVisitor::currentFormat() const -{ - assert(formatStack_.size() != 0); - - return formatStack_.back(); -} - -// Construct description within supplied object, from given tree -std::vector TextPrimitiveVisitor::create(TextPrimitiveParser::PrimitiveContext *tree, FontInstance *fontInstance) -{ - fontInstance_ = fontInstance; - horizontalPosition_ = 0.0; - fragments_.clear(); - formatStack_.clear(); - formatStack_.emplace_back(); - - // Traverse the AST - visitChildren(tree); - - return fragments_; -} - -/* - * Private Functions - */ - -// Add new text fragment -void TextPrimitiveVisitor::addText(std::string_view text, const TextFormat format) -{ - // Add new fragment using supplied format settings - fragments_.emplace_back(text, format.scale(), Vector3(horizontalPosition_, format.y(), 0.0), format.isItalic(), - format.isBold()); - - // Update horizontal position - horizontalPosition_ += fontInstance_->boundingBoxWidth(text) * format.scale(); -} - -/* - * Visitor Overrides - */ - -antlrcpp::Any TextPrimitiveVisitor::visitPlainText(TextPrimitiveParser::PlainTextContext *ctx) -{ - addText(ctx->getText(), currentFormat()); - - return visitChildren(ctx); -} - -antlrcpp::Any TextPrimitiveVisitor::visitFormatter(TextPrimitiveParser::FormatterContext *ctx) -{ - // Determine supplied formatter - auto formatter = escapedFormatters().enumeration(ctx->FormatterEscape()->getText().substr(1)); - - // Copy existing format - auto format = formatStack_.back(); - - switch (formatter) - { - case (TextPrimitiveVisitor::BoldFormatter): - format.setBold(true); - break; - case (TextPrimitiveVisitor::ItalicFormatter): - format.setItalic(true); - break; - case (TextPrimitiveVisitor::SubScriptFormatter): - format.adjustY(-fontInstance_->fontBaseHeight() * format.scale() * (1.0 / 3.0)); - format.setScale(0.583 * format.scale()); - break; - case (TextPrimitiveVisitor::SuperScriptFormatter): - format.adjustY(fontInstance_->fontBaseHeight() * format.scale() * (2.0 / 3.0)); - format.setScale(0.583 * format.scale()); - break; - default: - throw(std::runtime_error("Unhandled formatting escape sequence found in text.\n")); - break; - } - - // Push new format - formatStack_.emplace_back(format); - - auto result = visitChildren(ctx); - - formatStack_.pop_back(); - - return result; -} - -antlrcpp::Any TextPrimitiveVisitor::visitSymbol(TextPrimitiveParser::SymbolContext *ctx) -{ - // Get symbol data - auto symbol = SymbolData::symbol(ctx->Symbol()->getText()); - - addText(SymbolData::symbol(symbol), formatStack_.back()); - - return visitChildren(ctx); -} - -/* - // Set fragment info - Vector3 translation(horizontalPosition_, format->y(), 0.0); - QString textToAdd; - if (!format->symbol()) - textToAdd = text; - else - { - // Must convert the supplied text into a symbol - use '??' if we don't recognise it - SymbolData *symbol = SymbolData::symbol(text); - if (symbol) - textToAdd = symbol->character; - else - textToAdd = ""; - } - fragments_.emplace_back(ctx->getText(), format->scale(), Vector3(horizontalPosition_, format->y(), 0.0), - format->italic(), format->bold()); - - // We have just added some text, so update the horizontal position - horizontalPosition_ += fontInstance_->boundingBoxWidth(qPrintable(textToAdd)) * format->scale(); - - return visitChildren(ctx); - - */ - -/* -// Add text fragment -bool TextPrimitiveVisitor::addFragment(QString text) -{ - TextFragment *fragment = fragments_.add(); - if (formatStack_.nItems() == 0) - { - Messenger::print("Internal Error: No TextFormat on stack in TextPrimitiveVisitor::addFragment().\n"); - fragment->set(text); - return false; - } - - // Get topmost TextFormat - TextFormat *format = formatStack_.last(); - - // Set fragment info - Vector3 translation(horizontalPosition_, format->y(), 0.0); - QString textToAdd; - if (!format->symbol()) - textToAdd = text; - else - { - // Must convert the supplied text into a symbol - use '??' if we don't recognise it - SymbolData *symbol = SymbolData::symbol(text); - if (symbol) - textToAdd = symbol->character; - else - textToAdd = ""; - } - fragment->set(textToAdd, format->scale(), translation, format->italic(), format->bold()); - - // We have just added some text, so update the horizontal position - horizontalPosition_ += fontInstance_->boundingBoxWidth(qPrintable(textToAdd)) * format->scale(); - - return true; -} - -// Add escape code -bool TextPrimitiveVisitor::addEscape(TextPrimitiveVisitor::EscapeSequence escSeq) -{ - // Copy topmost formatting node first, since we retain any previously-set (i.e. nested) formats - TextFormat *topMostFormat = formatStack_.last(); - TextFormat *newFormat = formatStack_.add(); - if (topMostFormat) - (*newFormat) = (*topMostFormat); - else - Messenger::print("Internal Error: No topmost TextFormat to copy from in TextPrimitiveVisitor::addEscape().\n"); - - // Deal with the escape sequence - switch (escSeq) - { - // Add a symbol (flags that any text added to it should be converted to a named symbol) - case (TextPrimitiveVisitor::SymbolFormatter): - newFormat->setSymbol(true); - break; - default: - Messenger::print("Escape {} not handled in TextPrimitiveVisitor::addEscape().\n", escSeq); - return false; - break; - } - - return true; -} - -// Remove escape code -void TextPrimitiveVisitor::removeEscape() { formatStack_.removeLast(); } -*/ diff --git a/src/gui/render/TextPrimitiveVisitor.h b/src/gui/render/TextPrimitiveVisitor.h deleted file mode 100644 index 27840b806f..0000000000 --- a/src/gui/render/TextPrimitiveVisitor.h +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "TextPrimitiveParserBaseVisitor.h" -#include "base/enumOptions.h" -#include "gui/render/textFormat.h" -#include "gui/render/textFragment.h" -#include "templates/optionalRef.h" -#include - -// Forward Declarations -class FontInstance; - -// TextPrimitive Visitor for ANTLR -class TextPrimitiveVisitor : TextPrimitiveParserBaseVisitor -{ - public: - // Escaped Formatters Enum - enum EscapedFormatter - { - BoldFormatter, - ItalicFormatter, - SubScriptFormatter, - SuperScriptFormatter, - nEscapedFormatters - }; - // Return enum options for EscapedFormatter - static EnumOptions escapedFormatters(); - - /* - * Construction - */ - private: - // Generated fragments - std::vector fragments_; - // Current horizontal position - double horizontalPosition_; - // Current font instance - FontInstance *fontInstance_; - // Format stack - std::vector formatStack_; - - private: - // Return the topmost format in the stack - const TextFormat ¤tFormat() const; - // Add new text fragment - void addText(std::string_view text, const TextFormat format); - - public: - // Construct description within supplied object, from given tree - std::vector create(TextPrimitiveParser::PrimitiveContext *tree, FontInstance *fontInstance); - - /* - * Visitor Overrides - */ - private: - antlrcpp::Any visitPlainText(TextPrimitiveParser::PlainTextContext *ctx) override; - antlrcpp::Any visitFormatter(TextPrimitiveParser::FormatterContext *ctx) override; - antlrcpp::Any visitSymbol(TextPrimitiveParser::SymbolContext *ctx) override; -}; diff --git a/src/gui/render/axes.cpp b/src/gui/render/axes.cpp deleted file mode 100644 index 1acc9de4dc..0000000000 --- a/src/gui/render/axes.cpp +++ /dev/null @@ -1,1369 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/axes.h" -#include "base/sysFunc.h" -#include "gui/render/fontInstance.h" -#include "gui/render/view.h" -#include "math/doubleExp.h" - -Axes::Axes(View &parent, FontInstance &fontInstance) : parentView_(parent), fontInstance_(fontInstance) -{ - // Definition - limitMin_.zero(); - limitMax_.set(10.0, 10.0, 10.0); - min_.zero(); - max_.set(10.0, 10.0, 10.0); - inverted_ = {false, false, false}; - logarithmic_ = {false, false, false}; - visible_ = {true, true, true}; - positionIsFractional_ = {true, true, true}; - positionReal_[0].zero(); - positionReal_[1].zero(); - positionReal_[2].zero(); - positionFractional_[0].zero(); - positionFractional_[1].zero(); - positionFractional_[2].zero(); - coordMin_[0].zero(); - coordMin_[1].zero(); - coordMin_[2].zero(); - coordMax_[0].zero(); - coordMax_[1].zero(); - coordMax_[2].zero(); - coordCentre_.set(5.0, 5.0, 5.0); - stretch_.set(1.0, 1.0, 1.0); - autoScale_[0] = Axes::NoAutoScale; - autoScale_[1] = Axes::NoAutoScale; - autoScale_[2] = Axes::NoAutoScale; - - // Ticks - tickDirection_[0].set(0.0, -1.0, 0.0); - tickDirection_[1].set(-1.0, 0.0, 0.0); - tickDirection_[2].set(-1.0, 0.0, 0.0); - tickSize_.set(0.2, 0.2, 0.2); - tickFirst_.zero(); - tickDelta_.set(1.0, 1.0, 1.0); - autoTicks_ = {true, true, true}; - minorTicks_.set(1, 1, 1); - - // Labels - autoNumberFormat_ = {true, true, true}; - labelAnchor_[0] = TextPrimitive::TopMiddleAnchor; - labelAnchor_[1] = TextPrimitive::MiddleRightAnchor; - labelAnchor_[2] = TextPrimitive::MiddleRightAnchor; - labelOrientation_[0].set(0.0, 0.0, 0.2); - labelOrientation_[1].set(0.0, 0.0, 0.2); - labelOrientation_[2].set(90.0, 0.0, 0.2); - title_[0] = "X Axis"; - title_[1] = "Y Axis"; - title_[2] = "Z Axis"; - titleOrientation_[0].set(0.0, 0.0, 0.0); - titleOrientation_[1].set(0.0, 0.0, 270.0); - titleOrientation_[2].set(90.0, 270.0, 0.0); - titleDistances_.set(1.2, 1.2, 1.2); - titleHorizontalOffsets_.set(0.5, 0.5, 0.5); - titleAnchor_[0] = TextPrimitive::TopMiddleAnchor; - titleAnchor_[1] = TextPrimitive::BottomMiddleAnchor; - titleAnchor_[2] = TextPrimitive::BottomMiddleAnchor; - - // GridLines - gridLinesMajor_ = {true, true, true}; - gridLinesMinor_ = {true, true, true}; - - // Style override - useBestFlatView_ = false; - autoPositionTitles_ = true; - - // GL - for (auto n = 0; n < 3; ++n) - { - axisPrimitives_[n].initialise(GL_LINES, true); - axisPrimitives_[n].setNoInstances(); - gridLineMajorPrimitives_[n].initialise(GL_LINES, false); - gridLineMajorPrimitives_[n].setNoInstances(); - gridLineMinorPrimitives_[n].initialise(GL_LINES, false); - gridLineMinorPrimitives_[n].setNoInstances(); - } - clipMin_.set(0.0, 0.0, 0.0); - clipMax_.set(0.0, 0.0, 0.0); - gridLineMajorStyle_[0].set(1.0, LineStipple::NoStipple, 0.5, 0.5, 0.5, 1.0); - gridLineMinorStyle_[0].set(1.0, LineStipple::QuarterDashStipple, 0.75, 0.75, 0.75, 1.0); - gridLineMajorStyle_[1] = gridLineMajorStyle_[0]; - gridLineMinorStyle_[1] = gridLineMinorStyle_[0]; - gridLineMajorStyle_[2] = gridLineMajorStyle_[0]; - gridLineMinorStyle_[2] = gridLineMinorStyle_[0]; - primitiveVersion_ = -1; -} - -Axes::~Axes() {} - -/* - * Definition - */ - -// Return enum options for AutoScaleMethod -EnumOptions Axes::autoScaleMethods() -{ - return EnumOptions( - "AutoScaleMethod", - {{Axes::NoAutoScale, "None"}, {Axes::ExpandingAutoScale, "Expanding"}, {Axes::FullAutoScale, "Full"}}); -} - -// Recalculate minimum, maximum, and centre coordinates of axes -void Axes::updateCoordinates() -{ - // Loop over axes - for (auto axis = 0; axis < 3; ++axis) - { - // Determine central coordinate component - if (logarithmic_[axis]) - coordCentre_[axis] = - (inverted_[axis] ? log10(max_[axis] / min_[axis]) : log10(max_[axis] * min_[axis])) * 0.5 * stretch_[axis]; - else - coordCentre_[axis] = (max_[axis] + min_[axis]) * 0.5 * stretch_[axis]; - - // Set axis position along other directions - for (auto n = 0; n < 3; ++n) - { - // Get axis position - double position = (positionIsFractional_[axis] ? positionFractional_[axis][n] * (max_[n] - min_[n]) + min_[n] - : positionReal_[axis][n]); - if (logarithmic_[n]) - coordMin_[axis].set(n, (inverted_[n] ? log10(max_[n] / position) : log10(position)) * stretch_[n]); - else - coordMin_[axis].set(n, (inverted_[n] ? max_[n] - position + min_[n] : position) * stretch_[n]); - } - coordMax_[axis] = coordMin_[axis]; - - // Set axis min/max coordinates - if (logarithmic_[axis]) - { - coordMin_[axis].set(axis, (inverted_[axis] ? log10(max_[axis] / min_[axis]) : log10(min_[axis])) * stretch_[axis]); - coordMax_[axis].set(axis, (inverted_[axis] ? log10(max_[axis] / max_[axis]) : log10(max_[axis])) * stretch_[axis]); - } - else - { - coordMin_[axis].set(axis, (inverted_[axis] ? max_[axis] : min_[axis]) * stretch_[axis]); - coordMax_[axis].set(axis, (inverted_[axis] ? min_[axis] : max_[axis]) * stretch_[axis]); - } - } - - parentView_.updateViewMatrix(); -} - -// Clamp axis position and min/max to current limits if necessary -void Axes::clamp(int axis) -{ - if (logarithmic_[axis]) - { - if (min_[axis] <= 0.0) - setToLimit(axis, true); - } -} - -// Set minimum value for specified axis -void Axes::setMin(int axis, double value) -{ - min_[axis] = value; - - updateCoordinates(); - - ++version_; -} - -// Return minimum value for specified axis -double Axes::min(int axis) const { return min_.get(axis); } - -// Set maximum value for specified axis -void Axes::setMax(int axis, double value) -{ - max_[axis] = value; - - updateCoordinates(); - - ++version_; -} - -// Return maximum value for specified axis -double Axes::max(int axis) const { return max_.get(axis); } - -// Set range of specified axis -void Axes::setRange(int axis, double minValue, double maxValue) -{ - min_[axis] = minValue; - max_[axis] = maxValue; - - updateCoordinates(); - - ++version_; -} - -// Return real axis range (accounting for log axes) -double Axes::realRange(int axis) const -{ - if (logarithmic_[axis]) - return log10(max_.get(axis)) - log10(min_.get(axis)); - else - return max_.get(axis) - min_.get(axis); -} - -// Ensure a sensible (non-zero) range, modifying the supplied values -void Axes::ensureSensibleRange(double &minValue, double &maxValue, bool alwaysExpand, double expansionFactor) -{ - /* - * If exponents are different or the difference in the significands is large enough, we consider the range to be - * acceptable, and only expand the range if 'alwaysExpand' is true. The degree to which we expand the range is governed - * by the 'expansionFactor'. If positive this represents a fractional amount of the total range that we will increase - * by. If negative, this represents an absolute value by which we will increase the range. - */ - DoubleExp minimum(minValue), maximum(maxValue); - if (alwaysExpand || - ((minimum.exponent() == maximum.exponent()) && (fabs(minimum.mantissa() - maximum.mantissa()) < 1.0e-4))) - { - if (expansionFactor > 0.0) - { - double yDelta = (maxValue - minValue) * expansionFactor; - maxValue += yDelta; - minValue -= yDelta; - } - else - { - maxValue += fabs(expansionFactor); - minValue -= fabs(expansionFactor); - } - } -} - -// Return central value of axes -Vector3 Axes::centre() const { return min_ + (max_ - min_) * 0.5; } - -// Return real axis minimum (accounting for log axes) -double Axes::realMin(int axis) const { return (logarithmic_[axis] ? log10(min_.get(axis)) : min_.get(axis)); } - -// Return real axis maximum (accounting for log axes) -double Axes::realMax(int axis) const { return (logarithmic_[axis] ? log10(max_.get(axis)) : max_.get(axis)); } - -// Set axis to extreme limit -void Axes::setToLimit(int axis, bool minLim) -{ - if (minLim) - min_[axis] = limitMin_[axis]; - else - max_[axis] = limitMax_[axis]; - - updateCoordinates(); - - ++version_; -} - -// Set axis minimum limit for specified axis -void Axes::setLimitMin(int axis, double limit) -{ - limitMin_[axis] = limit; - - if ((autoScale_[axis] == Axes::ExpandingAutoScale) && (min_[axis] > limitMin_[axis])) - setToLimit(axis, true); - else if (autoScale_[axis] == Axes::FullAutoScale) - setToLimit(axis, true); - - clamp(axis); - - updateCoordinates(); - - ++version_; -} - -// Return axis minimum limit for specified axis -double Axes::limitMin(int axis) const { return limitMin_.get(axis); } - -// Set axis maximum limit for specified axis -void Axes::setLimitMax(int axis, double limit) -{ - limitMax_[axis] = limit; - - if ((autoScale_[axis] == Axes::ExpandingAutoScale) && (max_[axis] < limitMax_[axis])) - setToLimit(axis, false); - else if (autoScale_[axis] == Axes::FullAutoScale) - setToLimit(axis, false); - - clamp(axis); - - updateCoordinates(); - - ++version_; -} - -// Return axis maximum limit for specified axis -double Axes::limitMax(int axis) const { return limitMax_.get(axis); } - -// Set all axis limits at once -void Axes::expandLimits(bool noShrink) -{ - for (auto axis = 0; axis < 3; ++axis) - { - if ((min_[axis] > limitMin_[axis]) || (!noShrink)) - setToLimit(axis, true); - if ((max_[axis] < limitMax_[axis]) || (!noShrink)) - setToLimit(axis, false); - } -} - -// Return coordinate at centre of current axes -Vector3 Axes::coordCentre() const { return coordCentre_; } - -// Return coordinate at minimum of specified axis -Vector3 Axes::coordMin(int axis) const { return coordMin_[axis]; } - -// Return coordinate at maximum of specified axis -Vector3 Axes::coordMax(int axis) const { return coordMax_[axis]; } - -// Set whether axis is inverted -void Axes::setInverted(int axis, bool b) -{ - inverted_[axis] = b; - - updateCoordinates(); - - ++version_; -} - -// Return whether axis is inverted -bool Axes::inverted(int axis) const { return inverted_[axis]; } - -// Set whether axis is logarithmic -void Axes::setLogarithmic(int axis, bool b) -{ - logarithmic_[axis] = b; - - // Update minima / maxima - parentView_.updateAxisLimits(); - - // Update and clamp axis values according to data - clamp(axis); - - updateCoordinates(); - - ++version_; - - parentView_.recalculateView(); -} - -// Toggle whether axis is logarithmic -void Axes::toggleLogarithmic(int axis) { setLogarithmic(axis, !logarithmic_[axis]); } - -// Return whether axis is logarithmic -bool Axes::logarithmic(int axis) const { return logarithmic_[axis]; } - -// Set whether axis is visible -void Axes::setVisible(int axis, bool b) { visible_[axis] = b; } - -// Return whether specified axis is visible -bool Axes::visible(int axis) const { return visible_[axis]; } - -// Set stretch factor for axis -void Axes::setStretch(int axis, double value) -{ - stretch_[axis] = value; - - updateCoordinates(); - - ++version_; -} - -// Return stretch factor for axis -double Axes::stretch(int axis) const { return stretch_.get(axis); } - -// Set fractional position flag for axis -void Axes::setPositionIsFractional(int axis, bool b) -{ - positionIsFractional_[axis] = b; - - ++version_; -} - -// Return fractional position flag for axis -bool Axes::positionIsFractional(int axis) const { return positionIsFractional_[axis]; } - -// Set axis position (in real surface-space coordinates) -void Axes::setPositionReal(int axis, int dir, double value) -{ - positionReal_[axis].set(dir, value); - - updateCoordinates(); - - ++version_; -} - -// Set axis position to axis limit (in real surface-space coordinates) -void Axes::setPositionRealToLimit(int axis, int dir, bool minLim) -{ - if (minLim) - setPositionReal(axis, dir, limitMin_[dir]); - else - setPositionReal(axis, dir, limitMax_[dir]); -} - -// Return axis position (in real surface-space coordinates) -Vector3 Axes::positionReal(int axis) const { return positionReal_[axis]; } - -// Set axis position (in fractional axis coordinates) -void Axes::setPositionFractional(int axis, int dir, double value) -{ - // Clamp range to limits - if (value > 1.0) - value = 1.0; - else if (value < 0.0) - value = 0.0; - - positionFractional_[axis].set(dir, value); - - updateCoordinates(); - - ++version_; -} - -// Return axis position (in fractional axis coordinates) -Vector3 Axes::positionFractional(int axis) const { return positionFractional_[axis]; } - -// Set autoscaling method employed -void Axes::setAutoScale(int axis, Axes::AutoScaleMethod method) { autoScale_[axis] = method; } - -// Return autoscaling method employed -Axes::AutoScaleMethod Axes::autoScale(int axis) const { return autoScale_[axis]; } - -/* - * Data Transforms - */ - -// Return supplied data x value in local axes coordinates -double Axes::transformX(double x) const -{ - if (inverted_[0] && logarithmic_[0]) - return log10(max_.x / x) * stretch_.x; - else if (inverted_[0]) - return ((max_.x - x) + min_.x) * stretch_.x; - else if (logarithmic_[0]) - return log10(x) * stretch_.x; - else - return x * stretch_.x; -} - -// Transform entire array of values into local axes coordinates -void Axes::transformX(std::vector &xArray) const -{ - if (inverted_[0] && logarithmic_[0]) - for (auto n = 0; n < xArray.size(); ++n) - xArray[n] = log10(max_.x / xArray[n]) * stretch_.x; - else if (inverted_[0]) - for (auto n = 0; n < xArray.size(); ++n) - xArray[n] = ((max_.x - xArray[n]) + min_.x) * stretch_.x; - else if (logarithmic_[0]) - for (auto n = 0; n < xArray.size(); ++n) - xArray[n] = log10(xArray[n]) * stretch_.x; - else - std::transform(xArray.begin(), xArray.end(), xArray.begin(), [this](auto value) { return value * stretch_.x; }); -} - -// Return supplied data y value in local axes coordinates -double Axes::transformY(double y) const -{ - if (inverted_[1] && logarithmic_[1]) - return (max_.y / y <= 0.0 ? log10(max_.y / y) * stretch_.y : 0.0); - else if (inverted_[1]) - return ((max_.y - y) + min_.y) * stretch_.y; - else if (logarithmic_[1]) - return (y <= 0.0 ? log10(y) * stretch_.y : 0.0); - else - return y * stretch_.y; -} - -// Transform entire array of values into local axes coordinates -void Axes::transformY(std::vector &yArray) const -{ - if (inverted_[1] && logarithmic_[1]) - for (auto n = 0; n < yArray.size(); ++n) - { - yArray[n] = log10(max_.y / yArray[n]) * stretch_.y; - } - else if (inverted_[1]) - for (auto n = 0; n < yArray.size(); ++n) - yArray[n] = ((max_.y - yArray[n]) + min_.y) * stretch_.y; - else if (logarithmic_[1]) - for (auto n = 0; n < yArray.size(); ++n) - { - yArray[n] = log10(yArray[n]) * stretch_.y; - } - else - std::transform(yArray.begin(), yArray.end(), yArray.begin(), [this](auto value) { return value * stretch_.y; }); -} - -// Return supplied data z value in local axes coordinates -double Axes::transformZ(double z) const -{ - if (inverted_[2] && logarithmic_[2]) - return log10(max_.z / z) * stretch_.z; - else if (inverted_[2]) - return ((max_.z - z) + min_.z) * stretch_.z; - else if (logarithmic_[2]) - return log10(z) * stretch_.z; - else - return z * stretch_.z; -} - -// Transform entire array of values into local axes coordinates -void Axes::transformZ(std::vector &zArray) const -{ - if (inverted_[1] && logarithmic_[1]) - for (auto n = 0; n < zArray.size(); ++n) - { - zArray[n] = log10(max_.z / zArray[n]) * stretch_.z; - } - else if (inverted_[1]) - for (auto n = 0; n < zArray.size(); ++n) - zArray[n] = ((max_.z - zArray[n]) + min_.z) * stretch_.z; - else if (logarithmic_[1]) - for (auto n = 0; n < zArray.size(); ++n) - { - zArray[n] = log10(zArray[n]) * stretch_.z; - } - else - std::transform(zArray.begin(), zArray.end(), zArray.begin(), [this](auto value) { return value * stretch_.z; }); -} - -// Transform a 2D array of values into local axes coordinates -void Axes::transformX(Array2D &xArray) const -{ - std::transform(xArray.begin(), xArray.end(), xArray.begin(), [this](auto x) { return transformX(x); }); -} - -// Transform a 2D array of values into local axes coordinates -void Axes::transformY(Array2D &yArray) const -{ - std::transform(yArray.begin(), yArray.end(), yArray.begin(), [this](auto y) { return transformY(y); }); -} - -// Transform a 2D array of values into local axes coordinates -void Axes::transformZ(Array2D &zArray) const -{ - std::transform(zArray.begin(), zArray.end(), zArray.begin(), [this](auto z) { return transformZ(z); }); -} - -/* - * Ticks / Labels / Gridlines - */ - -// Recalculate tick deltas for specified axis -void Axes::calculateTickDeltas(int axis) -{ - const auto nBaseValues = 5, maxIterations = 10, maxTicks = 10; - auto power = 1, baseValueIndex = 0, minTicks = maxTicks / 2; - int nTicks, iteration; - auto baseValues = std::vector{1, 2, 3, 4, 5}; - - baseValueIndex = 0; - power = int(log10((max_[axis] - min_[axis]) / maxTicks) - 1); - iteration = 0; - - if ((max_[axis] - min_[axis]) > 1.0e-10) - { - do - { - // Calculate current tickDelta - tickDelta_[axis] = baseValues[baseValueIndex] * pow(10.0, power); - - // Get first tickmark value - tickFirst_[axis] = int(min_[axis] / tickDelta_[axis]) * tickDelta_[axis]; - - // How many ticks now fit between the firstTick and max value? - // Add 1 to get total ticks for this delta (i.e. including firstTick) - nTicks = int((max_[axis] - min_[axis]) / tickDelta_[axis]); - ++nTicks; - - // Check n... - if (nTicks > maxTicks) - { - ++baseValueIndex; - if (baseValueIndex == nBaseValues) - ++power; - baseValueIndex = baseValueIndex % nBaseValues; - } - else if (nTicks < minTicks) - { - --baseValueIndex; - if (baseValueIndex == -1) - { - --power; - baseValueIndex += nBaseValues; - } - } - - ++iteration; - if (iteration == maxIterations) - break; - - } while ((nTicks > maxTicks) || (nTicks < minTicks)); - } - else - { - tickFirst_[axis] = min_[axis]; - tickDelta_[axis] = 1.0; - } -} - -// Set axis tick direction -void Axes::setTickDirection(int axis, int dir, double value) -{ - tickDirection_[axis].set(dir, value); - - ++version_; -} - -// Return axis tick direction -Vector3 Axes::tickDirection(int axis) const -{ - if (useBestFlatView_ && parentView_.isFlatView()) - switch (parentView_.viewType()) - { - case (View::FlatXYView): - return (axis == 0 ? Vector3(0.0, inverted_[1] ? 1.0 : -1.0, 0.0) - : Vector3(inverted_[0] ? 1.0 : -1.0, 0.0, 0.0)); - case (View::FlatXZView): - return (axis == 0 ? Vector3(0.0, 0.0, inverted_[2] ? 1.0 : -1.0) - : Vector3(inverted_[0] ? 1.0 : -1.0, 0.0, 0.0)); - case (View::FlatZYView): - return (axis == 1 ? Vector3(0.0, 0.0, inverted_[2] ? 1.0 : -1.0) - : Vector3(0.0, inverted_[1] ? 1.0 : -1.0, 0.0)); - default: - break; - } - - // Safety catch - return tickDirection_[axis]; -} - -// Set axis tick size (relative to font size) -void Axes::setTickSize(int axis, double size) -{ - tickSize_[axis] = size; - - ++version_; -} - -// Return axis tick size (relative to font size) -double Axes::tickSize(int axis) const { return tickSize_.get(axis); } - -// Set position of first tick delta on axes -void Axes::setFirstTick(int axis, double value) -{ - tickFirst_[axis] = value; - - ++version_; -} - -// Return position of first tick delta on axes -double Axes::tickFirst(int axis) const { return tickFirst_.get(axis); } - -// Set tick delta for axes -void Axes::setTickDelta(int axis, double value) -{ - tickDelta_[axis] = value; - - ++version_; -} - -// Return tick delta for axes -double Axes::tickDelta(int axis) const { return tickDelta_.get(axis); } - -// Set whether to calculate ticks automatically -void Axes::setAutoTicks(int axis, bool b) -{ - autoTicks_[axis] = b; - - ++version_; -} - -// Return whether to calculate ticks automatically -bool Axes::autoTicks(int axis) const { return autoTicks_[axis]; } - -// Set number of minor ticks in major tick intervals -void Axes::setMinorTicks(int axis, int value) -{ - minorTicks_[axis] = value; - - ++version_; -} - -// Return number of minor ticks in major tick intervals -int Axes::minorTicks(int axis) const { return minorTicks_.get(axis); } - -/* - * Labels - */ - -// Determine suitable label format for the supplied axis -void Axes::determineLabelFormat(int axis) -{ - // Set axis value format based on tick delta - auto logTick = int(log10(tickDelta_[axis])); - if (abs(logTick) > 3) - { - numberFormat_[axis].setType(NumberFormat::FormatType::Scientific); - numberFormat_[axis].setUseENotation(true); - numberFormat_[axis].setNDecimals(3); - } - else if (logTick <= 0) - { - auto nDecimals = abs(logTick); - - numberFormat_[axis].setType(NumberFormat::FormatType::Decimal); - numberFormat_[axis].setUseENotation(false); - numberFormat_[axis].setNDecimals(nDecimals); - - // Check here that all tick values are now different - while (true) - { - // Loop over labels and check that they are all different - auto allDifferent = true; - QString tickLabel, oldLabel; - auto nTicks = (max_[axis] - min_[axis]) / tickDelta_[axis]; - double axisValue = tickFirst_[axis]; - for (auto n = 0; n < nTicks; ++n) - { - // Print the current label value - tickLabel = numberFormat_[axis].format(axisValue); - if (tickLabel == oldLabel) - { - allDifferent = false; - break; - } - - axisValue += tickDelta_[axis]; - oldLabel = tickLabel; - } - - // If all are different, we're done - if (allDifferent) - break; - - // Increase decimals by one - ++nDecimals; - - // If we're now at the threshold where we use exponential notation, set it and break now. - if (nDecimals > 3) - { - numberFormat_[axis].setType(NumberFormat::FormatType::Scientific); - numberFormat_[axis].setUseENotation(true); - numberFormat_[axis].setNDecimals(3); - break; - } - else - numberFormat_[axis].setNDecimals(nDecimals); - } - } - else - { - numberFormat_[axis].setType(NumberFormat::FormatType::Integer); - numberFormat_[axis].setUseENotation(false); - numberFormat_[axis].setNDecimals(0); - } -} - -// Return number format for specified axis -const NumberFormat &Axes::numberFormat(int axis) const { return numberFormat_[axis]; } - -// Set number format for specified axis -void Axes::setNumberFormat(int axis, const NumberFormat &numberFormat) { numberFormat_[axis] = numberFormat; } - -// Return whether to determine number format automatically for the specified axis -bool Axes::autoNumberFormat(int axis) const { return autoNumberFormat_[axis]; } - -// Set whether to determine number format automatically for the specified axis -void Axes::setAutoNumberFormat(int axis, bool b) { autoNumberFormat_[axis] = b; } - -// Set orientation of labels for specified axis -void Axes::setLabelOrientation(int axis, int component, double value) -{ - labelOrientation_[axis].set(component, value); - - ++version_; -} - -// Return orientation of labels for specified axis -Vector3 Axes::labelOrientation(int axis) const -{ - if (useBestFlatView_ && parentView_.isFlatView()) - switch (parentView_.viewType()) - { - case (View::FlatXYView): - return (axis == 0 ? Vector3(0.0, 0.0, 0.2) : Vector3(0.0, 0.0, 0.2)); - case (View::FlatXZView): - return (axis == 0 ? Vector3(270.0, 0.0, 0.2) : Vector3(270.0, 0.0, 0.2)); - case (View::FlatZYView): - return (axis == 1 ? Vector3(90.0, 0.0, 0.2) : Vector3(90.0, 0.0, 0.2)); - default: - break; - } - - // Safety catch - return labelOrientation_[axis]; -} - -// Set axis label text anchor position for specified axis -void Axes::setLabelAnchor(int axis, TextPrimitive::TextAnchor anchor) -{ - labelAnchor_[axis] = anchor; - - ++version_; -} - -// Return axis label text anchor position for specified axis -TextPrimitive::TextAnchor Axes::labelAnchor(int axis) const -{ - if (useBestFlatView_ && parentView_.isFlatView()) - switch (parentView_.viewType()) - { - case (View::FlatXYView): - return (axis == 0 ? (inverted_[1] ? TextPrimitive::BottomMiddleAnchor : TextPrimitive::TopMiddleAnchor) - : (inverted_[0] ? TextPrimitive::MiddleLeftAnchor : TextPrimitive::MiddleRightAnchor)); - case (View::FlatXZView): - return (axis == 0 ? (inverted_[2] ? TextPrimitive::BottomMiddleAnchor : TextPrimitive::TopMiddleAnchor) - : (inverted_[0] ? TextPrimitive::MiddleLeftAnchor : TextPrimitive::MiddleRightAnchor)); - case (View::FlatZYView): - return (axis == 1 ? (inverted_[2] ? TextPrimitive::MiddleLeftAnchor : TextPrimitive::MiddleRightAnchor) - : (inverted_[1] ? TextPrimitive::BottomMiddleAnchor : TextPrimitive::TopMiddleAnchor)); - default: - break; - } - - // Safety catch - return labelAnchor_[axis]; -} - -// Set title for specified axis -void Axes::setTitle(int axis, std::string_view title) -{ - title_[axis] = title; - - ++version_; -} - -// Return title for specified axis -std::string_view Axes::title(int axis) const { return title_[axis]; } - -// Set orientation of titles for specified axis -void Axes::setTitleOrientationNEW(int axis, int component, double value) -{ - titleOrientation_[axis].set(component, value); - - ++version_; -} - -// Return orientation of titles for specified axis -Vector3 Axes::titleOrientation(int axis) const -{ - if (useBestFlatView_ && parentView_.isFlatView()) - switch (parentView_.viewType()) - { - case (View::FlatXYView): - return (axis == 0 ? Vector3(0.0, 0.0, 0.0) : Vector3(0.0, 270.0, 0.0)); - case (View::FlatXZView): - return (axis == 0 ? Vector3(270.0, 0.0, 0.0) : Vector3(270.0, 0.0, 90.0)); - case (View::FlatZYView): - return (axis == 1 ? Vector3(0.0, 90.0, 90.0) : Vector3(0.0, 90.0, 0.0)); - default: - break; - } - - // Safety catch - return titleOrientation_[axis]; -} - -// Set title distance from axis -void Axes::setTitleDistance(int axis, double distance) { titleDistances_.set(axis, distance); } - -// Return title distance from axis -double Axes::titleDistance(int axis) const { return titleDistances_.get(axis); } - -// Set title horizontal offset -void Axes::setTitleHorizontalOffset(int axis, double offset) { titleHorizontalOffsets_.set(axis, offset); } - -// Return title horizontal offset -double Axes::titleHorizontalOffset(int axis) const { return titleHorizontalOffsets_.get(axis); } - -// Set axis title text anchor position for specified axis -void Axes::setTitleAnchor(int axis, TextPrimitive::TextAnchor anchor) -{ - titleAnchor_[axis] = anchor; - - ++version_; -} - -// Return axis title text anchor position for specified axis -TextPrimitive::TextAnchor Axes::titleAnchor(int axis) const -{ - if (useBestFlatView_ && parentView_.isFlatView()) - switch (parentView_.viewType()) - { - case (View::FlatXYView): - return (axis == 0 ? (inverted_[1] ? TextPrimitive::BottomMiddleAnchor : TextPrimitive::TopMiddleAnchor) - : (inverted_[0] ? TextPrimitive::TopMiddleAnchor : TextPrimitive::BottomMiddleAnchor)); - case (View::FlatXZView): - return (axis == 0 ? (inverted_[2] ? TextPrimitive::BottomMiddleAnchor : TextPrimitive::TopMiddleAnchor) - : (inverted_[0] ? TextPrimitive::TopMiddleAnchor : TextPrimitive::BottomMiddleAnchor)); - case (View::FlatZYView): - return (axis == 1 ? (inverted_[2] ? TextPrimitive::TopMiddleAnchor : TextPrimitive::BottomMiddleAnchor) - : (inverted_[1] ? TextPrimitive::BottomMiddleAnchor : TextPrimitive::TopMiddleAnchor)); - default: - break; - } - - // Safety catch - return titleAnchor_[axis]; -} - -/* - * Style Overrides - */ - -// Set whether to use best tick/label orientation for flat views -void Axes::setUseBestFlatView(bool b) -{ - useBestFlatView_ = b; - - ++version_; -} - -// Return whether to use best tick/label orientation for flat views -bool Axes::useBestFlatView() const { return useBestFlatView_; } - -// Set whether to automatically place titles at a sensible position after label text -void Axes::setAutoPositionTitles(bool b) -{ - autoPositionTitles_ = b; - - ++version_; -} - -// Return whether to automatically place titles at a sensible position after label text -bool Axes::autoPositionTitles() const { return autoPositionTitles_; } - -/* - * GridLines - */ - -// Set whether gridlines cover entire volume or just at axis lines -void Axes::setGridLinesFull(int axis, bool b) -{ - gridLinesFull_[axis] = b; - - ++version_; -} - -// Return whether gridlines cover entire volume or just at axis lines -bool Axes::gridLinesFull(int axis) const { return gridLinesFull_[axis]; } - -// Set whether gridLines at major tick intervals are active for specified axis -void Axes::setGridLinesMajor(int axis, bool on) -{ - gridLinesMajor_[axis] = on; - - ++version_; -} - -// Return whether gridLines at major tick intervals are active for specified axis -bool Axes::gridLinesMajor(int axis) const { return gridLinesMajor_[axis]; } - -// Set whether gridLines at minor tick intervals are active for specified axis -void Axes::setGridLinesMinor(int axis, bool on) -{ - gridLinesMinor_[axis] = on; - - ++version_; -} - -// Return whether gridLines at minor tick intervals are active for specified axis -bool Axes::gridLinesMinor(int axis) const { return gridLinesMinor_[axis]; } - -/* - * Version - */ - -// Return version of axws definitions -int Axes::version() const { return version_; } - -/* - * GL - */ - -// Update axes primitives -void Axes::updateAxisPrimitives() -{ - // Check whether we need to regenerate the axes primitives / data - if (version_ == primitiveVersion_) - return; - - QString s; - FTBBox boundingBox; - Vector3 centre; - double delta, value, clipPlaneDelta = 0.0001; - Vector3 u, v1, v2, tickDir, adjustment; - Matrix4 labelTransform, titleTransform; - std::vector tickPositions[3]; - std::vector tickIsMajor[3]; - - // Make sure coordinates are up-to-date - updateCoordinates(); - - // Get view rotation inverse - Matrix4 viewRotationInverse = parentView_.viewRotationInverse(); - - // Set clip coordinates - for (auto axis = 0; axis < 3; ++axis) - { - if (logarithmic_[axis]) - { - clipMin_[axis] = (inverted_[axis] ? 0.0 : log10(min_[axis])) * stretch_[axis] - clipPlaneDelta; - clipMax_[axis] = - (inverted_[axis] ? log10(max_[axis] / min_[axis]) : log10(max_[axis])) * stretch_[axis] + clipPlaneDelta; - } - else - { - clipMin_[axis] = (min_[axis] * stretch_[axis]) - clipPlaneDelta; - clipMax_[axis] = (max_[axis] * stretch_[axis]) + clipPlaneDelta; - } - } - - auto textColour = fontInstance_.colour(); - GLfloat colour[4] = {textColour.redF(), textColour.greenF(), textColour.blueF(), textColour.alphaF()}; - - // Construct axes - for (auto axis = 0; axis < 3; ++axis) - { - // Clear old axis primitives - axisPrimitives_[axis].forgetAll(); - labelPrimitives_[axis].clear(); - titlePrimitives_[axis].clear(); - - // Normalise tickDirection - tickDir = tickDirection(axis); - tickDir.normalise(); - - // Create tick label transformation matrix - labelTransform.setIdentity(); - // -- 1) Apply axial rotation along label left-to-right direction - if (parentView_.viewType() == View::FlatZYView) - labelTransform.applyPreRotationY(labelOrientation(axis).x); - else - labelTransform.applyPreRotationX(labelOrientation(axis).x); - // -- 2) Perform in-plane rotation - if (parentView_.viewType() == View::FlatZYView) - labelTransform.applyPreRotationX(labelOrientation(axis).y); - else if (parentView_.viewType() == View::FlatXZView) - labelTransform.applyPreRotationY(labelOrientation(axis).y); - else - labelTransform.applyPreRotationZ(labelOrientation(axis).y); - - // Create axis title transformation matrix - titleTransform.setIdentity(); - titleTransform.applyPreRotationX(titleOrientation(axis).x); - titleTransform.applyPreRotationY(titleOrientation(axis).y); - titleTransform.applyPreRotationZ(titleOrientation(axis).z); - - // Add axis labels - if (logarithmic_[axis]) - { - // For the log axis, the associated surface data coordinate will already be in log form - if (max_[axis] < 0.0) - { - Messenger::print("Axis range is inappropriate for a log scale ({} < x < {}). Axis will not be drawn.\n", - min_[axis], max_[axis]); - return; - } - - // Draw a line from min to max range, passing through the defined position - axisPrimitives_[axis].line(coordMin_[axis], coordMax_[axis], colour); - - // Grab logged min/max values for convenience, enforcing sensible minimum - double min = log10(min_[axis] <= 0.0 ? 1.0e-10 : min_[axis]); - - // Plot tickmarks - Start at floored (ceiling'd) integer of logAxisMin (logAxisMax), and go from there. - auto nMinorTicks = minorTicks_[axis] > 8 ? 8 : minorTicks_[axis]; - auto count = 0; - double power = floor(min); - double value = pow(10, power); - auto u = coordMin_[axis]; - while (value <= max_[axis]) - { - // If the current value is in range, plot a tick - u[axis] = (inverted_[axis] ? log10(max_[axis] / value) : log10(value)) * stretch_[axis]; - if (log10(value) >= min) - { - // Tick mark - axisPrimitives_[axis].line(u, u + tickDir * tickSize_[axis] * (count == 0 ? 1.0 : 0.5), colour); - tickPositions[axis].push_back(u[axis]); - tickIsMajor[axis].push_back(count == 0); - - // Tick label - if (count == 0) - { - // Get formatted value text - s = numberFormat_[axis].format(value); - - labelPrimitives_[axis].add(&fontInstance_, s, u + tickDir * tickSize_[axis], labelAnchor(axis), - tickDir * labelOrientation(axis).z, labelTransform, - parentView_.labelPointSize(), - parentView_.isFlatView() ? false : parentView_.flatLabelsIn3D()); - } - } - - // Increase tick counter, value, and power if necessary - ++count; - if (count > nMinorTicks) - { - count = 0; - power = power + 1.0; - value = pow(10, power); - } - else - value += pow(10, power); - } - } - else - { - // Calculate autoticks if requested - if (autoTicks_[axis]) - calculateTickDeltas(axis); - - // Autoformat the axia labels if requested - if (autoNumberFormat_[axis]) - determineLabelFormat(axis); - - // Draw a line from min to max limits, passing through the defined position - axisPrimitives_[axis].line(coordMin_[axis], coordMax_[axis], colour); - - // Check tickDelta - if (((max_[axis] - min_[axis]) / tickDelta_[axis]) > 1e6) - return; - - // Plot tickmarks - auto count = 0; - delta = tickDelta_[axis] / (minorTicks_[axis] + 1); - value = tickFirst_[axis]; - u = coordMin_[axis]; - u.set(axis, (inverted_[axis] ? (max_[axis] - tickFirst_[axis]) + min_[axis] : tickFirst_[axis]) * stretch_[axis]); - while (value <= max_[axis]) - { - // Draw tick here, only if value >= min_ - if (value >= min_[axis]) - { - tickPositions[axis].push_back(u[axis]); - - if (count % (minorTicks_[axis] + 1) == 0) - { - axisPrimitives_[axis].line(u, u + tickDir * tickSize_[axis], colour); - - // Get formatted label text - s = numberFormat_[axis].format(value); - - labelPrimitives_[axis].add(&fontInstance_, s, u + tickDir * tickSize_[axis], labelAnchor(axis), - tickDir * labelOrientation(axis).z, labelTransform, - parentView_.labelPointSize(), - parentView_.isFlatView() ? false : parentView_.flatLabelsIn3D()); - - tickIsMajor[axis].push_back(true); - - count = 0; - } - else - { - axisPrimitives_[axis].line(u, u + tickDir * tickSize_[axis] * 0.5, colour); - tickIsMajor[axis].push_back(false); - } - } - u.add(axis, delta * (inverted_[axis] ? -stretch_[axis] : stretch_[axis])); - value += delta; - ++count; - } - } - - // Add axis title - // -- Set basic position (corresponding to offset position of tick labels combined with title label axis - // position to start with...) - u = coordMin_[axis]; - if (logarithmic_[axis]) - { - value = log10(min_[axis]) + log10(max_[axis] / min_[axis]) * titleHorizontalOffsets_[axis]; - u.set(axis, (inverted_[axis] ? log10(max_[axis]) - value : value) * stretch_[axis]); - } - else - { - value = min_[axis] + (max_[axis] - min_[axis]) * titleHorizontalOffsets_[axis]; - u.set(axis, (inverted_[axis] ? (max_[axis] - value) + min_[axis] : value) * stretch_[axis]); - } - // -- Next step depends on whether we are automatically adjusting label positions - if ((useBestFlatView_ && parentView_.isFlatView()) || autoPositionTitles_) - { - Cuboid cuboid = labelPrimitives_[axis].boundingCuboid(fontInstance_, viewRotationInverse, parentView_.textZScale()); - // Project tick direction onto cuboid width/height - // TODO This does not account for the fact that the bounding cuboid may only partly extend over the end - // of ths axis tick mark (e.g. as with in-plane rotations/TopMiddle anchors)... - Vector3 extent = cuboid.maxima() - cuboid.minima(); - extent.multiply(tickDir.x, tickDir.y, tickDir.z); - // -- Add on extra distance from tick mark - u += tickDir * (tickSize_[axis]); - // -- Create adjustment vector. Start by adding space between tickmark, label text, and title text - adjustment = tickDir * (labelOrientation(axis).z + 0.2); - // -- Add on label extent in the tickmark direction - we must undo the scaling on the bounding box - // arising from display scales etc. - adjustment += (tickDir * extent.magnitude()) / - (fontInstance_.fontBaseHeight() * parentView_.labelPointSize() / parentView_.textZScale()); - // -- Scaling will be done by the title point size in TextPrimitive, but all our adjustments were done - // with label point size, so scale it... - adjustment *= parentView_.labelPointSize() / parentView_.titlePointSize(); - } - else - adjustment = tickDir * titleDistances_[axis]; - - // -- Add primitive - titlePrimitives_[axis].add(&fontInstance_, QString::fromStdString(title_[axis]), u, titleAnchor(axis), adjustment, - titleTransform, parentView_.titlePointSize(), - parentView_.isFlatView() ? false : parentView_.flatLabelsIn3D()); - } - - // GridLines - gridLineMinorPrimitives_[0].initialise(GL_LINES, false); - gridLineMajorPrimitives_[0].initialise(GL_LINES, false); - gridLineMinorPrimitives_[1].initialise(GL_LINES, false); - gridLineMajorPrimitives_[1].initialise(GL_LINES, false); - gridLineMinorPrimitives_[2].initialise(GL_LINES, false); - gridLineMajorPrimitives_[2].initialise(GL_LINES, false); - - // The 'axis' variable indicates the vector we are drawing lines along, and the relevant primitive store them in - for (auto axis = 0; axis < 3; ++axis) - { - // Check to see if there is anything to draw for this direction - if ((!gridLinesMajor_[axis]) && (!gridLinesMinor_[axis])) - continue; - - // Determine the indices of the remaining two axes to use - int ortho1 = (axis + 1) % 3; - int ortho2 = (axis + 2) % 3; - - // Double loop now, over the two sets of tickmarks that are orthogonal to 'axis' - for (auto i1 = 0; i1 < tickPositions[ortho1].size(); ++i1) - { - for (auto i2 = 0; i2 < tickPositions[ortho2].size(); ++i2) - { - // Set basic vector info - // The 'axis' will define its own component, with the other two coming from the tickmark - // positions of the other axes - v1[axis] = coordMin_[axis][axis]; - v1[ortho1] = tickPositions[ortho1][i1]; - v1[ortho2] = tickPositions[ortho2][i2]; - v2[axis] = coordMax_[axis][axis]; - v2[ortho1] = tickPositions[ortho1][i1]; - v2[ortho2] = tickPositions[ortho2][i2]; - - // If we are only drawing lines in the planes orthogonal to the axis, break if we have moved - // away from it... Otherwise, we change either the i1 or i2 components of v1 and v2 to position - // the gridline with the axis line itself - if (!gridLinesFull_[axis]) - { - // If both values are non-zero, we are done so we can break out of the loop - if ((i1 != 0) && (i2 != 0)) - break; - - // If the i1 counter is zero, change the values of the ortho1 axis to that of the 'axis' - // axis, and vice versa - if (i1 == 0) - { - v1[ortho1] = coordMin_[axis][ortho1]; - v2[ortho1] = coordMax_[axis][ortho1]; - } - else - { - v1[ortho2] = coordMin_[axis][ortho2]; - v2[ortho2] = coordMax_[axis][ortho2]; - } - } - - // Add line to the relevant primitive - if (tickIsMajor[ortho1][i1] && tickIsMajor[ortho2][i2]) - { - if (gridLinesMajor_[axis]) - gridLineMajorPrimitives_[axis].line(v1, v2, colour); - } - else if (gridLinesMinor_[axis]) - gridLineMinorPrimitives_[axis].line(v1, v2, colour); - } - } - } - - primitiveVersion_ = version_; -} - -// Return clip plane lower Y value -Vector3 Axes::clipMin() const { return clipMin_; } - -// Return clip plane upper Y value -Vector3 Axes::clipMax() const { return clipMax_; } - -// Flag primitives as invalid -void Axes::setPrimitivesInvalid() { primitiveVersion_ = -1; } - -// Return axis primitive for axis specified -Primitive &Axes::axisPrimitive(int axis) -{ - // Make sure primitives are up to date first... - updateAxisPrimitives(); - - return axisPrimitives_[axis]; -} - -// Return axis label primitive list for axis specified -TextPrimitiveList &Axes::labelPrimitive(int axis) -{ - // Make sure primitives are up to date first... - updateAxisPrimitives(); - - return labelPrimitives_[axis]; -} - -// Return axis title primitive list for axis specified -TextPrimitiveList &Axes::titlePrimitive(int axis) -{ - // Make sure primitives are up to date first... - updateAxisPrimitives(); - - return titlePrimitives_[axis]; -} - -// Return minor gridline primitive for axis specified -Primitive &Axes::gridLineMinorPrimitive(int axis) -{ - // Make sure primitives are up to date first... - updateAxisPrimitives(); - - return gridLineMinorPrimitives_[axis]; -} - -// Return major gridline primitive for axis specified -Primitive &Axes::gridLineMajorPrimitive(int axis) -{ - // Make sure primitives are up to date first... - updateAxisPrimitives(); - - return gridLineMajorPrimitives_[axis]; -} - -// Set major gridline style -void Axes::setGridLineMajorStyle(int axis, const LineStyle &style) { gridLineMajorStyle_[axis] = style; } - -// Return major GridLine style -const LineStyle &Axes::gridLineMajorStyle(int axis) const { return gridLineMajorStyle_[axis]; } - -// Set minor gridline style -void Axes::setGridLineMinorStyle(int axis, const LineStyle &style) { gridLineMinorStyle_[axis] = style; } - -// Return minor GridLine style -const LineStyle &Axes::gridLineMinorStyle(int axis) const { return gridLineMinorStyle_[axis]; } diff --git a/src/gui/render/axes.h b/src/gui/render/axes.h deleted file mode 100644 index 805af3826c..0000000000 --- a/src/gui/render/axes.h +++ /dev/null @@ -1,395 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "base/enumOptions.h" -#include "base/version.h" -#include "gui/render/lineStyle.h" -#include "gui/render/numberFormat.h" -#include "gui/render/primitive.h" -#include "gui/render/textPrimitiveList.h" -#include "math/vector3.h" -#include "math/vector3i.h" -#include "templates/array2D.h" -#include - -// Forward Declarations -class View; - -// Axes -class Axes -{ - private: - // Parent rendering View in which these axes are displayed - View &parentView_; - // Associated FontInstance from parent viewer - FontInstance &fontInstance_; - - public: - Axes(View &parent, FontInstance &fontInstance); - ~Axes(); - - /* - * Definition - */ - public: - // Autoscaling for axes - enum AutoScaleMethod - { - NoAutoScale, - ExpandingAutoScale, - FullAutoScale, - nAutoScaleMethods - }; - // Return enum options for AutoScaleMethod - static EnumOptions autoScaleMethods(); - - private: - // Data limits for surface generation - Vector3 min_, max_; - // Limiting values for axis limits (accounting for data, log scales etc.) - Vector3 limitMin_, limitMax_; - // Axis extreme coordinates - Vector3 coordMin_[3], coordMax_[3]; - // Central coordinate of current axes - Vector3 coordCentre_; - // Whether to invert axes - std::array inverted_; - // Whether axes should be plotted as logarithms - std::array logarithmic_; - // Axis visibility - std::array visible_; - // Stretch factors to apply to axes - Vector3 stretch_; - // Whether axis position is fractional or absolute - std::array positionIsFractional_; - // Axis position in real or surface-space coordinates - Vector3 positionReal_[3]; - // Axis position in fractional axis coordinates - Vector3 positionFractional_[3]; - // Autoscaling method employed for each axis - Axes::AutoScaleMethod autoScale_[3]; - - private: - // Recalculate minimum, maximum, and centre coordinates of axes - void updateCoordinates(); - // Clamp axis position and min/max to current limits - void clamp(int axis); - - public: - // Set minimum value for specified axis - void setMin(int axis, double value); - // Return minimum value for specified axis - double min(int axis) const; - // Set maximum value for specified axis - void setMax(int axis, double value); - // Return maximum value for specified axis - double max(int axis) const; - // Set range of specified axis - void setRange(int axis, double minValue, double maxValue); - // Return real axis range (accounting for log axes) - double realRange(int axis) const; - // Ensure a sensible (non-zero) range, modifying the supplied values - static void ensureSensibleRange(double &minValue, double &maxValue, bool alwaysExpand = false, - double expansionFactor = -1.0); - // Return central value of axes - Vector3 centre() const; - // Return real axis minimum (accounting for log axes) - double realMin(int axis) const; - // Return real axis maximum (accounting for log axes) - double realMax(int axis) const; - // Set axis to extreme limit - void setToLimit(int axis, bool minimumLimit); - // Set axis minimum limit for specified axis - void setLimitMin(int axis, double limit); - // Return axis minimum limit for specified axis - double limitMin(int axis) const; - // Set axis maximum limit for specified axis - void setLimitMax(int axis, double limit); - // Return axis maximum limit for specified axis - double limitMax(int axis) const; - // Set all axis limits at once - void expandLimits(bool noShrink); - // Return coordinate at centre of axes - Vector3 coordCentre() const; - // Return coordinate at minimum of specified axis - Vector3 coordMin(int axis) const; - // Return coordinate at maximum of specified axis - Vector3 coordMax(int axis) const; - // Set whether axis is inverted - void setInverted(int axis, bool b); - // Return whether axis is inverted - bool inverted(int axis) const; - // Set whether axis is logarithmic - void setLogarithmic(int axis, bool b); - // Toggle whether axis is logarithmic - void toggleLogarithmic(int axis); - // Return whether axis is logarithmic - bool logarithmic(int axis) const; - // Set whether axis is visible - void setVisible(int axis, bool b); - // Return whether specified axis is visible - bool visible(int axis) const; - // Set stretch factor for axis - void setStretch(int axis, double value); - // Return stretch factor for axis - double stretch(int axis) const; - // Set fractional position flag for axis - void setPositionIsFractional(int axis, bool b); - // Return fractional position flag for axis - bool positionIsFractional(int axis) const; - // Set axis position (in real surface-space coordinates) - void setPositionReal(int axis, int dir, double value); - // Set axis position to axis limit (in real surface-space coordinates) - void setPositionRealToLimit(int axis, int dir, bool minLim); - // Return axis position (in real surface-space coordinates) - Vector3 positionReal(int axis) const; - // Set axis position (in fractional axis coordinates) - void setPositionFractional(int axis, int dir, double value); - // Return axis position (in fractional axis coordinates) - Vector3 positionFractional(int axis) const; - // Set autoscaling method employed for specified axis - void setAutoScale(int axis, Axes::AutoScaleMethod method); - // Return autoscaling method employed for specified axis - Axes::AutoScaleMethod autoScale(int axis) const; - - /* - * Data Transforms - */ - public: - // Return supplied data x value in local axes coordinates - double transformX(double x) const; - // Transform entire array of values into local axes coordinates - void transformX(std::vector &xArray) const; - // Return supplied data y value in local axes coordinates - double transformY(double y) const; - // Transform entire array of values into local axes coordinates - void transformY(std::vector &yArray) const; - // Return supplied data z value in local axes coordinates - double transformZ(double z) const; - // Transform entire array of values into local axes coordinates - void transformZ(std::vector &zArray) const; - // Transform a 2D array of values into local axes coordinates - void transformX(Array2D &xArray) const; - // Transform a 2D array of values into local axes coordinates - void transformY(Array2D &yArray) const; - // Transform a 2D array of values into local axes coordinates - void transformZ(Array2D &zArray) const; - - /* - * Ticks - */ - private: - // Axis tick direction - Vector3 tickDirection_[3]; - // Axis tick size (relative to font size) - Vector3 tickSize_; - // Position of first tick delta on axes - Vector3 tickFirst_; - // Tick delta for axes - Vector3 tickDelta_; - // Whether to calculate ticks automatically - std::array autoTicks_; - // Number of minor ticks in major tick intervals - Vector3i minorTicks_; - - private: - // Recalculate tick deltas for specified axis - void calculateTickDeltas(int axis); - - public: - // Set axis tick direction - void setTickDirection(int axis, int dir, double value); - // Return axis tick direction for specified axis - Vector3 tickDirection(int axis) const; - // Set axis tick size (relative to font size) - void setTickSize(int axis, double size); - // Return axis tick size (relative to font size) - double tickSize(int axis) const; - // Set position of first tick delta on specified axis - void setFirstTick(int axis, double value); - // Return position of first tick delta on specified axis - double tickFirst(int axis) const; - // Set tick delta for specified axis - void setTickDelta(int axis, double value); - // Return tick delta for specified axis - double tickDelta(int axis) const; - // Set whether to calculate ticks automatically for specified axis - void setAutoTicks(int axis, bool b); - // Return whether to calculate ticks automatically for specified axis - bool autoTicks(int axis) const; - // Set number of minor ticks in major tick intervals for specified axis - void setMinorTicks(int axis, int value); - // Return number of minor ticks in major tick intervals for specified axis - int minorTicks(int axis) const; - - /* - * Labels - */ - private: - // Number formats for labels - NumberFormat numberFormat_[3]; - // Whether to determine number formats automatically - std::array autoNumberFormat_; - // Orientation of axis labels (axial rot, in-plane rot, distance) - Vector3 labelOrientation_[3]; - // Axis label text anchor positions - TextPrimitive::TextAnchor labelAnchor_[3]; - // Axis titles - std::string title_[3]; - // Orientation of axis titles (rotations around x, y, and z axes) - Vector3 titleOrientation_[3]; - // Title distances from axes - Vector3 titleDistances_; - // Title horizontal offsets - Vector3 titleHorizontalOffsets_; - // Axis title text anchor positions - TextPrimitive::TextAnchor titleAnchor_[3]; - - private: - // Determine suitable label format for the supplied axis - void determineLabelFormat(int axis); - - public: - // Return number format for specified axis - const NumberFormat &numberFormat(int axis) const; - // Set number format for specified axis - void setNumberFormat(int axis, const NumberFormat &numberFormat); - // Return whether to determine number format automatically for the specified axis - bool autoNumberFormat(int axis) const; - // Set whether to determine number format automatically for the specified axis - void setAutoNumberFormat(int axis, bool b); - // Set orientation of labels for specified axis - void setLabelOrientation(int axis, int component, double value); - // Return orientation of labels for specified axis - Vector3 labelOrientation(int axis) const; - // Set axis label text anchor position for specified axis - void setLabelAnchor(int axis, TextPrimitive::TextAnchor anchor); - // Return axis label text anchor position for specified axis - TextPrimitive::TextAnchor labelAnchor(int axis) const; - // Set title for specified axis - void setTitle(int axis, std::string_view title); - // Return title for specified axis - std::string_view title(int axis) const; - // Set orientation of titles for specified axis - void setTitleOrientationNEW(int axis, int component, double value); - // Return orientation of titles for specified axis - Vector3 titleOrientation(int axis) const; - // Set title distance from axis - void setTitleDistance(int axis, double distance); - // Return title distance from axis - double titleDistance(int axis) const; - // Set title horizontal offset - void setTitleHorizontalOffset(int axis, double offset); - // Return title horizontal offset - double titleHorizontalOffset(int axis) const; - // Set axis title text anchor position for specified axis - void setTitleAnchor(int axis, TextPrimitive::TextAnchor anchor); - // Return axis title text anchor position for specified axis - TextPrimitive::TextAnchor titleAnchor(int axis) const; - - /* - * Style Helpers - */ - private: - // Whether to use best tick/label orientation for flat views, or the user's definitions - bool useBestFlatView_; - // Whether to automatically place titles at a sensible position after label text - bool autoPositionTitles_; - - public: - // Set whether to use best tick/label orientation for view - void setUseBestFlatView(bool b); - // Return whether to use best tick/label orientation for view - bool useBestFlatView() const; - // Set whether to automatically place titles at a sensible position after label text - void setAutoPositionTitles(bool b); - // Return whether to automatically place titles at a sensible position after label text - bool autoPositionTitles() const; - - /* - * GridLines - */ - private: - // Whether gridlines cover entire volume or just at axis lines - std::array gridLinesFull_; - // Whether gridLines at major tick intervals are active - std::array gridLinesMajor_; - // Whether gridLines at minor tick intervals are active - std::array gridLinesMinor_; - - public: - // Set whether gridlines cover entire volume or just at axis lines - void setGridLinesFull(int axis, bool b); - // Return whether gridlines cover entire volume or just at axis lines - bool gridLinesFull(int axis) const; - // Set whether gridLines at major tick intervals are active for specified axis - void setGridLinesMajor(int axis, bool on); - // Return whether gridLines at major tick intervals are active for specified axis - bool gridLinesMajor(int axis) const; - // Set whether gridLines at minor tick intervals are active for specified axis - void setGridLinesMinor(int axis, bool on); - // Return whether gridLines at minor tick intervals are active for specified axis - bool gridLinesMinor(int axis) const; - - /* - * Versions - */ - private: - // Version of axes definitions - VersionCounter version_; - - public: - // Return version of axes definitions - int version() const; - - /* - * GL - */ - private: - // Clip plane coordinates - Vector3 clipMin_, clipMax_; - // Display primitives - Primitive axisPrimitives_[3]; - // Axis text primitives - TextPrimitiveList labelPrimitives_[3]; - // Axis title primitives - TextPrimitiveList titlePrimitives_[3]; - // GridLine primitives - Primitive gridLineMajorPrimitives_[3], gridLineMinorPrimitives_[3]; - // GridLine styles - LineStyle gridLineMajorStyle_[3], gridLineMinorStyle_[3]; - // Versions at which primitives were last generated - int primitiveVersion_; - - private: - // Update primitives for axis - void updateAxisPrimitives(); - - public: - // Return clip plane lower Y value - Vector3 clipMin() const; - // Return clip plane upper Y value - Vector3 clipMax() const; - // Flag primitives as invalid - void setPrimitivesInvalid(); - // Return axis primitive for axis specified - Primitive &axisPrimitive(int axis); - // Return axis label primitive list for axis specified - TextPrimitiveList &labelPrimitive(int axis); - // Return axis title primitive list for axis specified - TextPrimitiveList &titlePrimitive(int axis); - // Return minor gridline primitive for axis specified - Primitive &gridLineMajorPrimitive(int axis); - // Return major gridline primitive for axis specified - Primitive &gridLineMinorPrimitive(int axis); - // Set major gridline style - void setGridLineMajorStyle(int axis, const LineStyle &style); - // Return major gridline style - const LineStyle &gridLineMajorStyle(int axis) const; - // Set minor gridline style - void setGridLineMinorStyle(int axis, const LineStyle &style); - // Return minor gridline style - const LineStyle &gridLineMinorStyle(int axis) const; -}; diff --git a/src/gui/render/colourDefinition.cpp b/src/gui/render/colourDefinition.cpp deleted file mode 100644 index 8e4eca7614..0000000000 --- a/src/gui/render/colourDefinition.cpp +++ /dev/null @@ -1,324 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/colourDefinition.h" -#include "base/sysFunc.h" - -ColourDefinition::ColourDefinition() -{ - // Colour Definitions - singleColour_.setRgb(0, 0, 0, 255); - rgbGradient_.addPoint(0.0, QColor(255, 255, 255)); - rgbGradient_.addPoint(1.0, QColor(0, 0, 255)); - hsvGradient_.setUseHSV(true); - hsvGradient_.addPoint(0.0, QColor(255, 0, 0)); - hsvGradient_.addPoint(1.0, QColor(100, 40, 255)); - customGradient_.clear(); - - // Style - style_ = ColourDefinition::SingleColourStyle; - useGlobalAlpha_ = false; - globalAlpha_ = 0.5; -} - -ColourDefinition::~ColourDefinition() {} - -ColourDefinition::ColourDefinition(const ColourDefinition &source) { (*this) = source; } - -void ColourDefinition::operator=(const ColourDefinition &source) -{ - // Colour Definitions - style_ = source.style_; - singleColour_ = source.singleColour_; - rgbGradient_ = source.rgbGradient_; - hsvGradient_ = source.hsvGradient_; - customGradient_ = source.customGradient_; - useGlobalAlpha_ = source.useGlobalAlpha_; - globalAlpha_ = source.globalAlpha_; - version_ = source.version_; -} - -/* - * Enumerations - */ - -// Return enum options for ColourStyle -EnumOptions ColourDefinition::colourStyles() -{ - return EnumOptions("AutoScaleMethod", - {{ColourDefinition::SingleColourStyle, "SingleColour"}, - {ColourDefinition::RGBGradientStyle, "RGBGradient"}, - {ColourDefinition::HSVGradientStyle, "HSVGradient"}, - {ColourDefinition::CustomGradientStyle, "CustomGradient"}}); -} - -/* - * Style - */ - -// Set colour style to use -void ColourDefinition::setStyle(ColourStyle style) -{ - style_ = style; - - ++version_; -} - -// Return colour style in use -ColourDefinition::ColourStyle ColourDefinition::style() const { return style_; } - -// Set whether to use global alpha value -void ColourDefinition::setUseGlobalAlpha(bool useGlobalAlpha) -{ - useGlobalAlpha_ = useGlobalAlpha; - - ++version_; -} - -// Return whether to use global alpha value -bool ColourDefinition::useGlobalAlpha() const { return useGlobalAlpha_; } - -// Set global alpha value -void ColourDefinition::setGlobalAlpha(double alpha) -{ - globalAlpha_ = alpha; - - ++version_; -} - -// Return global alpha value -double ColourDefinition::globalAlpha() const { return globalAlpha_; } - -// Return version -int ColourDefinition::version() const { return version_; } - -/* - * Colour Definitions - */ - -// Set single colour -void ColourDefinition::setSingleColour(QColor colour) -{ - singleColour_ = colour; - - ++version_; -} - -// Return single colour -QColor ColourDefinition::singleColour() const { return singleColour_; } - -/* - * RGB Gradient Definition - */ - -// Set RGB gradient start value -void ColourDefinition::setRGBGradientStartValue(double value) -{ - rgbGradient_.setValue(0, value); - - ++version_; -} - -// Return RGB gradient start value -double ColourDefinition::rgbGradientStartValue() const { return rgbGradient_.point(0).value(); } - -// Set RGB gradient start colour -void ColourDefinition::setRGBGradientStartColour(QColor colour) -{ - rgbGradient_.setColour(0, colour); - - ++version_; -} - -// Return RGB gradient start colour -QColor ColourDefinition::rgbGradientStartColour() const { return rgbGradient_.point(0).colour(); } - -// Set RGB gradient start -void ColourDefinition::setRGBGradientStart(double value, QColor colour) -{ - rgbGradient_.setPoint(0, value, colour); - - ++version_; -} - -// Set RGB gradient end value -void ColourDefinition::setRGBGradientEndValue(double value) -{ - rgbGradient_.setValue(1, value); - - ++version_; -} - -// Return RGB gradient end value -double ColourDefinition::rgbGradientEndValue() const { return rgbGradient_.point(1).value(); } - -// Set RGB gradient end colour -void ColourDefinition::setRGBGradientEndColour(QColor colour) -{ - rgbGradient_.setColour(1, colour); - - ++version_; -} - -// Return RGB gradient end colour -QColor ColourDefinition::rgbGradientEndColour() const { return rgbGradient_.point(1).colour(); } - -// Set RGB gradient end -void ColourDefinition::setRGBGradientEnd(double value, QColor colour) -{ - rgbGradient_.setPoint(1, value, colour); - - ++version_; -} - -/* - * HSV Gradient Definition - */ - -// Set HSV gradient start value -void ColourDefinition::setHSVGradientStartValue(double value) -{ - hsvGradient_.setValue(0, value); - - ++version_; -} - -// Return HSV gradient start value -double ColourDefinition::hsvGradientStartValue() const { return hsvGradient_.point(0).value(); } - -// Set HSV gradient start colour -void ColourDefinition::setHSVGradientStartColour(QColor colour) -{ - hsvGradient_.setColour(0, colour); - - ++version_; -} - -// Return HSV gradient start colour -QColor ColourDefinition::hsvGradientStartColour() const { return hsvGradient_.point(0).colour(); } - -// Set HSV gradient start -void ColourDefinition::setHSVGradientStart(double value, QColor colour) -{ - hsvGradient_.setPoint(0, value, colour); - - ++version_; -} - -// Set HSV gradient end value -void ColourDefinition::setHSVGradientEndValue(double value) -{ - hsvGradient_.setValue(1, value); - - ++version_; -} - -// Return HSV gradient end value -double ColourDefinition::hsvGradientEndValue() const { return hsvGradient_.point(1).value(); } - -// Set HSV gradient end colour -void ColourDefinition::setHSVGradientEndColour(QColor colour) -{ - hsvGradient_.setColour(1, colour); - - ++version_; -} - -// Return HSV gradient end colour -QColor ColourDefinition::hsvGradientEndColour() const { return hsvGradient_.point(1).colour(); } - -// Set HSV gradient end -void ColourDefinition::setHSVGradientEnd(double value, QColor colour) -{ - hsvGradient_.setPoint(1, value, colour); - - ++version_; -} - -/* - * Custom Gradient Definition - */ - -// Set custom gradient point value and colour -void ColourDefinition::setCustomGradientPoint(int index, double value, QColor colour) -{ - customGradient_.setPoint(index, value, colour); - - ++version_; -} - -// Return custom gradient point specified -const ColourScalePoint &ColourDefinition::customGradientPoint(int index) const { return customGradient_.point(index); } - -// Return colour of custom gradient point specified -QColor ColourDefinition::customGradientColour(int index) const { return customGradient_.point(index).colour(); } - -// Return value of custom gradient point specified -double ColourDefinition::customGradientValue(ColourStyle source, int index) const -{ - return customGradient_.point(index).value(); -} - -// Append point to custom gradient -void ColourDefinition::appendCustomGradientPoint() -{ - customGradient_.addPoint(customGradient_.nPoints() > 0 ? customGradient_.lastPoint().value() + 1.0 : 0.0, Qt::white); - - ++version_; -} - -// Add point to custom gradient -void ColourDefinition::addCustomGradientPoint(double value, QColor colour) -{ - customGradient_.addPoint(value, colour); - - ++version_; -} - -// Return number of points in custom gradient -int ColourDefinition::nCustomGradientPoints() const { return customGradient_.nPoints(); } - -// Return custom gradient points -const std::vector &ColourDefinition::customGradientPoints() const { return customGradient_.points(); } - -// Remove specified colourscale point with index specified -void ColourDefinition::removeCustomGradientPoint(int id) -{ - customGradient_.removePoint(id); - - ++version_; -} - -/* - * Colour Access - */ - -// Return (set) colour for specified value -void ColourDefinition::colour(double value, GLfloat *rgba) const -{ - if (style_ == ColourDefinition::SingleColourStyle) - { - rgba[0] = singleColour_.redF(); - rgba[1] = singleColour_.greenF(); - rgba[2] = singleColour_.blueF(); - rgba[3] = useGlobalAlpha_ ? globalAlpha_ : singleColour_.alphaF(); - } - else if (style_ == ColourDefinition::RGBGradientStyle) - { - rgbGradient_.colour(value, rgba); - if (useGlobalAlpha_) - rgba[3] = globalAlpha_; - } - else if (style_ == ColourDefinition::HSVGradientStyle) - { - hsvGradient_.colour(value, rgba); - if (useGlobalAlpha_) - rgba[3] = globalAlpha_; - } - else - { - customGradient_.colour(value, rgba); - if (useGlobalAlpha_) - rgba[3] = globalAlpha_; - } -} diff --git a/src/gui/render/colourDefinition.h b/src/gui/render/colourDefinition.h deleted file mode 100644 index ac9213896a..0000000000 --- a/src/gui/render/colourDefinition.h +++ /dev/null @@ -1,168 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "base/enumOptions.h" -#include "base/version.h" -#include "gui/render/colourScale.h" - -// Colour Definition -class ColourDefinition -{ - public: - ColourDefinition(); - ~ColourDefinition(); - ColourDefinition(const ColourDefinition &source); - void operator=(const ColourDefinition &source); - - /* - * Enumerations - */ - public: - // Colour Styles - enum ColourStyle - { - SingleColourStyle, - RGBGradientStyle, - HSVGradientStyle, - CustomGradientStyle, - nColourStyles - }; - // Return enum options for ColourStyle - static EnumOptions colourStyles(); - - /* - * Style - */ - private: - // Current colour style in use - ColourStyle style_; - // Whether to use global alpha value - bool useGlobalAlpha_; - // Global alpha value - double globalAlpha_; - // Version - VersionCounter version_; - - public: - // Set colour style to use - void setStyle(ColourStyle source); - // Return colour style in use - ColourStyle style() const; - // Set whether to use global alpha value - void setUseGlobalAlpha(bool useGlobalAlpha); - // Return whether to use global alpha value - bool useGlobalAlpha() const; - // Set global alpha value - void setGlobalAlpha(double alpha); - // Return global alpha value - double globalAlpha() const; - // Return version - int version() const; - - /* - * Single Colour Definition - */ - private: - // Single colour - QColor singleColour_; - - public: - // Set single colour - void setSingleColour(QColor colour); - // Return single colour - QColor singleColour() const; - - /* - * RGB Gradient Definition - */ - private: - // RGB Gradient - ColourScale rgbGradient_; - - public: - // Set RGB gradient start value - void setRGBGradientStartValue(double value); - // Return RGB gradient start value - double rgbGradientStartValue() const; - // Set RGB gradient start colour - void setRGBGradientStartColour(QColor colour); - // Return RGB gradient start colour - QColor rgbGradientStartColour() const; - // Set RGB gradient start - void setRGBGradientStart(double value, QColor colour); - // Set RGB gradient end value - void setRGBGradientEndValue(double value); - // Return RGB gradient end value - double rgbGradientEndValue() const; - // Set RGB gradient end colour - void setRGBGradientEndColour(QColor colour); - // Return RGB gradient end colour - QColor rgbGradientEndColour() const; - // Set RGB gradient end - void setRGBGradientEnd(double value, QColor colour); - - /* - * HSV Gradient Definition - */ - private: - // HSV gradient - ColourScale hsvGradient_; - - public: - // Set HSV gradient start value - void setHSVGradientStartValue(double value); - // Return HSV gradient start value - double hsvGradientStartValue() const; - // Set HSV gradient start colour - void setHSVGradientStartColour(QColor colour); - // Return HSV gradient start colour - QColor hsvGradientStartColour() const; - // Set HSV gradient start - void setHSVGradientStart(double value, QColor colour); - // Set HSV gradient end value - void setHSVGradientEndValue(double value); - // Return HSV gradient end value - double hsvGradientEndValue() const; - // Set HSV gradient end colour - void setHSVGradientEndColour(QColor colour); - // Return HSV gradient end colour - QColor hsvGradientEndColour() const; - // Set HSV gradient end - void setHSVGradientEnd(double value, QColor colour); - - /* - * Custom Gradient Definition - */ - private: - // Custom gradient - ColourScale customGradient_; - - public: - // Set custom gradient point value and colour - void setCustomGradientPoint(int index, double value, QColor colour); - // Return custom gradient point specified - const ColourScalePoint &customGradientPoint(int index) const; - // Return colour of custom gradient point specified - QColor customGradientColour(int index) const; - // Return value of custom gradient point specified - double customGradientValue(ColourStyle source, int index) const; - // Append point to custom gradient - void appendCustomGradientPoint(); - // Add point to custom gradient - void addCustomGradientPoint(double value, QColor colour); - // Return number of points in custom gradient - int nCustomGradientPoints() const; - // Return custom gradient points - const std::vector &customGradientPoints() const; - // Remove specified colourscale point with index specified - void removeCustomGradientPoint(int id); - - /* - * Colour Access - */ - public: - // Return (set) colour for specified value - void colour(double value, GLfloat *rgba) const; -}; diff --git a/src/gui/render/colourScale.cpp b/src/gui/render/colourScale.cpp deleted file mode 100644 index 93c756b215..0000000000 --- a/src/gui/render/colourScale.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/colourScale.h" -#include "base/messenger.h" -#include - -ColourScale::ColourScale() -{ - // Private variables - interpolated_ = true; - useHSV_ = false; -} - -ColourScale::ColourScale(const ColourScale &source) { (*this) = source; } - -void ColourScale::operator=(const ColourScale &source) -{ - clear(); - - points_ = source.points_; - useHSV_ = source.useHSV_; - interpolated_ = source.interpolated_; - - calculateDeltas(); -} - -// Clear ColourScale -void ColourScale::clear() -{ - points_.clear(); - deltas_.clear(); -} - -/* - * Points - */ - -// Add point to scale -void ColourScale::addPoint(double value, QColor colour) -{ - /* - * If supplied value is less than that at the start of the list, add it at the beginning. - * If larger than the one at the end, then append it to the end of the list. - * If neither of these, find the first existing value which is larger, and add it before that one. - */ - if (points_.empty() || (value > points_.back().value())) - points_.emplace_back(value, colour); - else - { - // Find a suitable insertion point - auto it = std::find_if(points_.begin(), points_.end(), [value](const auto &point) { return point.value() > value; }); - points_.insert(it, {value, colour}); - } - - // Recalculate colour deltas - calculateDeltas(); -} - -// Return number of points in ColourScale -int ColourScale::nPoints() const { return points_.size(); } - -// Return points in ColourScale -const std::vector &ColourScale::points() const { return points_; } - -// Return first point in ColourScale -const ColourScalePoint &ColourScale::firstPoint() const { return points_.front(); } - -// Return last point in ColourScale -const ColourScalePoint &ColourScale::lastPoint() const { return points_.back(); } - -// Return specific point in ColourScale -const ColourScalePoint &ColourScale::point(int id) const { return points_[id]; } - -// Set colour and value data for point -void ColourScale::setPoint(int position, double value, QColor colour) -{ - assert(position >= 0 && position < points_.size()); - - points_[position].setColour(colour); - - // Set the new value - this will also update the position of the point if necessary - setValue(position, value); -} - -// Set value for point -void ColourScale::setValue(int position, double value) -{ - // Set the new value of the point - points_[position].setValue(value); - - // Position in list may have changed... - std::sort(points_.begin(), points_.end(), [](const auto &p1, const auto &p2) { return p1.value() < p2.value(); }); - - // Recalculate colour deltas - calculateDeltas(); -} - -// Set colour for point -void ColourScale::setColour(int position, QColor colour) -{ - points_[position].setColour(colour); - - // Recalculate colour deltas - calculateDeltas(); -} - -// Remove old point from ColourScale -void ColourScale::removePoint(int position) -{ - assert(position >= 0 && position < points_.size()); - - points_.erase(points_.begin() + position); - - // Recalculate colour deltas - calculateDeltas(); -} - -// Return colour associated with value provided -QColor ColourScale::colour(double value) const -{ - // Check for no points being defined - if (points_.empty()) - return QColor(0, 0, 0); - - // Is supplied value less than the value at the first point? - if (value <= points_.front().value()) - return points_.front().colour(); - else if (value >= points_.back().value()) - return points_.back().colour(); - - // Find the correct delta to use - auto it = std::find_if(deltas_.begin(), deltas_.end(), [value](const auto &delta) { return delta.containsValue(value); }); - if (it != deltas_.end()) - return interpolated_ ? it->colour(value) : it->startColour(); - - Messenger::exception("Failed to find a colour to return from the ColourScale.\n"); -} - -// Get colour associated with value supplied, setting as GLfloat[4] -void ColourScale::colour(double value, GLfloat *rgba) const -{ - auto qcol = colour(value); - - rgba[0] = qcol.redF(); - rgba[1] = qcol.greenF(); - rgba[2] = qcol.blueF(); - rgba[3] = qcol.alphaF(); -} - -/* - * Deltas - */ - -// Recalculate colour deltas between points -void ColourScale::calculateDeltas() -{ - deltas_.clear(); - if (points_.empty()) - return; - - for (auto n = points_.begin(); std::next(n) != points_.end(); ++n) - deltas_.emplace_back(*n, *std::next(n), useHSV_); -} - -/* - * Style - */ - -// Set whether the ColourScale is interpolated -void ColourScale::setInterpolated(bool b) { interpolated_ = b; } - -// Return whether the ColourScale is interpolated -bool ColourScale::interpolated() const { return interpolated_; } - -// Set whether or not to use HSV interpolation -void ColourScale::setUseHSV(bool b) -{ - useHSV_ = b; - - calculateDeltas(); -} - -// Return whether or not to use HSV interpolation -bool ColourScale::useHSV() const { return useHSV_; } diff --git a/src/gui/render/colourScale.h b/src/gui/render/colourScale.h deleted file mode 100644 index c6c1ca90b6..0000000000 --- a/src/gui/render/colourScale.h +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/colourScaleDelta.h" -#include "gui/render/colourScalePoint.h" -#include "math/vector4.h" -#include -#include -#include - -// Colour Scale -class ColourScale -{ - public: - ColourScale(); - ColourScale(const ColourScale &); - void operator=(const ColourScale &source); - // Clear ColourScale - void clear(); - - /* - * Points - */ - private: - // Vector of points in the ColourScale - std::vector points_; - - public: - // Add new point to ColourScale - void addPoint(double value, QColor colour); - // Return number of points in ColourScale - int nPoints() const; - // Return points in ColourScale - const std::vector &points() const; - // Return first point in ColourScale - const ColourScalePoint &firstPoint() const; - // Return last point in ColourScale - const ColourScalePoint &lastPoint() const; - // Return specific point in ColourScale - const ColourScalePoint &point(int id) const; - // Set colour and value data for point - void setPoint(int position, double value, QColor colour); - // Set value for specified point - void setValue(int position, double value); - // Set colour for specified point - void setColour(int position, QColor colour); - // Remove point from ColourScale - void removePoint(int position); - // Get colour associated with value supplied - QColor colour(double value) const; - // Get colour associated with value supplied, setting as GLfloat[4] - void colour(double value, GLfloat *rgba) const; - - /* - * Deltas - */ - private: - // Vector of colour deltas between points in the ColourScale - std::vector deltas_; - - private: - // Calculate colour deltas for current list of points - void calculateDeltas(); - - /* - * Style - */ - private: - // Whether colours are interpolated between points in the scale - bool interpolated_; - // Whether interpolation should be performed with HSV instead of RGB - bool useHSV_; - - public: - // Set whether the ColourScale is interpolated - void setInterpolated(bool b); - // Return whether the ColourScale is interpolated - bool interpolated() const; - // Set whether or not to use HSV interpolation - void setUseHSV(bool b); - // Return whether or not to use HSV interpolation - bool useHSV() const; -}; diff --git a/src/gui/render/colourScaleDelta.cpp b/src/gui/render/colourScaleDelta.cpp deleted file mode 100644 index 7c586f6b44..0000000000 --- a/src/gui/render/colourScaleDelta.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/colourScaleDelta.h" -#include "gui/render/colourScalePoint.h" - -ColourScaleDelta::ColourScaleDelta() -{ - // Private variables - start_ = 0.0; - delta_ = 0.0; - useHSV_ = false; -} - -ColourScaleDelta::ColourScaleDelta(const ColourScalePoint &start, const ColourScalePoint &end, bool useHSV) -{ - set(start, end, useHSV); -} - -// Check whether the delta 'contains' the supplied value -bool ColourScaleDelta::containsValue(double d) const -{ - if (d < start_) - return false; - if (d > (start_ + delta_)) - return false; - return true; -} - -// Create delta from ColourScalePoints -void ColourScaleDelta::set(const ColourScalePoint &start, const ColourScalePoint &end, bool useHSV) -{ - // Copy first colour point - start_ = start.value(); - startColour_ = start.colour(); - useHSV_ = useHSV; - - // Set the colour delta - if (useHSV) - { - deltaColourF_[0] = end.colour().hueF() - startColour_.hueF(); - deltaColourF_[1] = end.colour().saturationF() - startColour_.saturationF(); - deltaColourF_[2] = end.colour().valueF() - startColour_.valueF(); - } - else - { - deltaColourF_[0] = end.colour().redF() - startColour_.redF(); - deltaColourF_[1] = end.colour().greenF() - startColour_.greenF(); - deltaColourF_[2] = end.colour().blueF() - startColour_.blueF(); - } - deltaColourF_[3] = end.colour().alphaF() - startColour_.alphaF(); - - delta_ = end.value() - start_; -} - -// Return colour of the delta's starting point -QColor ColourScaleDelta::startColour() const { return startColour_; } - -// Return colour of the delta's starting point as GLfloat* -void ColourScaleDelta::startColour(GLfloat *rgba) const -{ - rgba[0] = startColour_.redF(); - rgba[1] = startColour_.greenF(); - rgba[2] = startColour_.blueF(); - rgba[3] = startColour_.alphaF(); -} - -// Get colour for value v -QColor ColourScaleDelta::colour(double value) const -{ - // Clamp 'v' to range 0.0 - 1.0 to span range of delta - double clampv = (value - start_) / delta_; - if (clampv < 0.0) - clampv = 0.0; - else if (clampv > 1.0) - clampv = 1.0; - QColor col; - if (useHSV_) - { - col.setHsvF(startColour_.hue() + deltaColourF_[0] * clampv, startColour_.saturationF() + deltaColourF_[1] * clampv, - startColour_.valueF() + deltaColourF_[2] * clampv); - } - else - { - col.setRedF(startColour_.redF() + deltaColourF_[0] * clampv); - col.setGreenF(startColour_.greenF() + deltaColourF_[1] * clampv); - col.setBlueF(startColour_.blueF() + deltaColourF_[2] * clampv); - } - - col.setAlphaF(startColour_.alphaF() + deltaColourF_[3] * clampv); - - return col; -} - -// Get colour for value as GLfloat* ranged from 0.0-1.0, assuming that v is within the range 0 -> value_ -void ColourScaleDelta::colour(double v, GLfloat *rgba) const -{ - // Clamp 'v' to range 0.0 - 1.0 to span range of delta - double clampv = (v - start_) / delta_; - if (clampv < 0.0) - clampv = 0.0; - else if (clampv > 1.0) - clampv = 1.0; - if (useHSV_) - { - QColor col; - col.setHsvF(startColour_.hueF() + deltaColourF_[0] * clampv, startColour_.saturationF() + deltaColourF_[1] * clampv, - startColour_.valueF() + deltaColourF_[2] * clampv); - rgba[0] = col.redF(); - rgba[1] = col.greenF(); - rgba[2] = col.blueF(); - } - else - { - rgba[0] = startColour_.redF() + deltaColourF_[0] * clampv; - rgba[1] = startColour_.greenF() + deltaColourF_[1] * clampv; - rgba[2] = startColour_.blueF() + deltaColourF_[2] * clampv; - } - rgba[3] = startColour_.alphaF() + deltaColourF_[3] * clampv; -} - -// Return the starting value of the range -double ColourScaleDelta::start() const { return start_; } - -// Return the range of the delta -double ColourScaleDelta::delta() const { return delta_; } diff --git a/src/gui/render/colourScaleDelta.h b/src/gui/render/colourScaleDelta.h deleted file mode 100644 index f0f54ff892..0000000000 --- a/src/gui/render/colourScaleDelta.h +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "math/vector4.h" -#include -#include - -// Forward declarations -class ColourScalePoint; - -// Colour Scale Delta -class ColourScaleDelta -{ - public: - ColourScaleDelta(); - ColourScaleDelta(const ColourScalePoint &start, const ColourScalePoint &end, bool useHSV); - - private: - // Value at which the delta starts - double start_; - // Range of the data from the start value - double delta_; - // Colour of the delta's starting point - QColor startColour_; - // Delta between the starting point and the final point - float deltaColourF_[4]; - // Whether to use HSV, rather than RGB, when generating colours - bool useHSV_; - - public: - // Check whether the delta 'contains' the supplied value - bool containsValue(double d) const; - // Create delta from ColourScalePoints - void set(const ColourScalePoint &start, const ColourScalePoint &end, bool useHSV); - // Return colour of the delta's starting point - QColor startColour() const; - // Return colour of the delta's starting point as GLfloat[4] - void startColour(GLfloat *rgba) const; - // Get colour for value, assuming that v is within the range 0 -> value_ - QColor colour(double v) const; - // Get colour for value as GLfloat[4], assuming that v is within the range 0 -> value_ - void colour(double v, GLfloat *rgba) const; - // Return the starting value of the range - double start() const; - // Return the range of the delta - double delta() const; -}; diff --git a/src/gui/render/colourScalePoint.cpp b/src/gui/render/colourScalePoint.cpp deleted file mode 100644 index 048bb5568e..0000000000 --- a/src/gui/render/colourScalePoint.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/colourScalePoint.h" - -ColourScalePoint::ColourScalePoint(double value, QColor colour) -{ - // Private variables - value_ = value; - setColour(colour); -} -ColourScalePoint::~ColourScalePoint() {} - -ColourScalePoint::ColourScalePoint(const ColourScalePoint &source) { (*this) = source; } - -void ColourScalePoint::operator=(const ColourScalePoint &source) -{ - value_ = source.value_; - colour_ = source.colour_; -} - -/* - * Value and Colour - */ - -// Set value and colour for point -void ColourScalePoint::set(double value, QColor colour) -{ - value_ = value; - colour_ = colour; -} - -// Set value of point -void ColourScalePoint::setValue(double d) { value_ = d; } - -// Return value of point -double ColourScalePoint::value() const { return value_; } - -// Set colour -void ColourScalePoint::setColour(QColor colour) { colour_ = colour; } - -// Return colour -QColor ColourScalePoint::colour() const { return colour_; } - -// Return colour as GLfloat* -void ColourScalePoint::colour(GLfloat *rgba) const -{ - rgba[0] = colour_.redF(); - rgba[1] = colour_.greenF(); - rgba[2] = colour_.blueF(); - rgba[3] = colour_.alphaF(); -} - -// Set alpha value -void ColourScalePoint::setAlpha(int alpha) { colour_.setAlpha(alpha); } diff --git a/src/gui/render/colourScalePoint.h b/src/gui/render/colourScalePoint.h deleted file mode 100644 index fcdcc368aa..0000000000 --- a/src/gui/render/colourScalePoint.h +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "math/vector4.h" -#include -#include - -// Colour Scale Point -class ColourScalePoint -{ - public: - ColourScalePoint(double value = 0.0, QColor colour = QColor()); - ~ColourScalePoint(); - ColourScalePoint(const ColourScalePoint &source); - void operator=(const ColourScalePoint &source); - - /* - * Value and Colour - */ - private: - // Value at which this point occurs - double value_; - // Colour of this point - QColor colour_; - - public: - // Set value and colour for point - void set(double value, QColor colour); - // Set value for point - void setValue(double value); - // Return value for point - double value() const; - // Set colour - void setColour(QColor colour); - // Return colour - QColor colour() const; - // Return colour as GLfloat[4] - void colour(GLfloat *rgba) const; - // Set alpha value - void setAlpha(int alpha); -}; diff --git a/src/gui/render/fontInstance.cpp b/src/gui/render/fontInstance.cpp deleted file mode 100644 index 825dbe4fa7..0000000000 --- a/src/gui/render/fontInstance.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/fontInstance.h" -#include "base/messenger.h" -#include - -FontInstance::FontInstance(QColor colour) : colour_(colour) -{ - fontData_ = nullptr; - font_ = nullptr; - fontBaseHeight_ = 0.0; - fontFullHeight_ = 0.0; - dotWidth_ = 0.0; - scaleFactor_ = 1.0; -} - -/* - * Font Data - */ - -// Set up font with font filename specified -bool FontInstance::setUp(QString fontFileName) -{ - // Delete any previous font - if (font_) - delete font_; - font_ = nullptr; - if (fontData_) - delete fontData_; - fontData_ = nullptr; - - // Check the fontFileName - if it's empty then we try to load the default font from our resource - fontFile_ = fontFileName; - if (fontFile_.isEmpty()) - fontData_ = new QResource(":/fonts/fonts/FreeSans.ttf"); - else - fontData_ = new QResource(fontFile_); - if (fontData_->size() <= 0) - { - Messenger::error("Font data is empty - correct resource path specified?\n"); - return false; - } - - // Construct font - auto *newFont = new FTPolygonFont(fontData_->data(), fontData_->size()); - if (newFont->Error()) - { - Messenger::error("Error generating font.\n"); - delete newFont; - fontBaseHeight_ = 1.0; - return false; - } - else - { - font_ = newFont; - - // Request unicode character mapping... - if (!font_->CharMap(ft_encoding_unicode)) - Messenger::print("Failed to set unicode character mapping for font - special characters may not render " - "correctly.\n"); - - font_->FaceSize(1); - FTBBox boundingBox = font_->BBox("0123456789"); - fontBaseHeight_ = boundingBox.Upper().Y() - boundingBox.Lower().Y(); - boundingBox = font_->BBox("ABCDEfghijKLMNOpqrstUVWXYz"); - fontFullHeight_ = boundingBox.Upper().Y() - boundingBox.Lower().Y(); - boundingBox = font_->BBox(".."); - dotWidth_ = boundingBox.Upper().X() - boundingBox.Lower().X(); - } - - return (font_ != nullptr); -} - -// Return whether font exists and is ready for use -bool FontInstance::fontOK() const { return (font_ != nullptr); } - -// Return base height of font -double FontInstance::fontBaseHeight() const { return fontBaseHeight_; } - -// Return full height of font -double FontInstance::fontFullHeight() const { return fontFullHeight_; } - -// Return bounding box for specified string -FTBBox FontInstance::boundingBox(std::string_view text) const -{ - if (!font_) - return FTBBox(); - - // Need to be a little careful here - we will put a '.' either side of the text so we get the full width of strings with - // trailing spaces.. - FTBBox box = font_->BBox(std::format(".{}.", text).c_str()); - return FTBBox(box.Lower(), FTPoint(box.Upper().X() - dotWidth_, box.Upper().Y())); -} - -// Set general scaling factor for primitives rendered with this font instance -void FontInstance::setScaleFactor(double scaleFactor) { scaleFactor_ = scaleFactor; } - -// Return general scaling factor for primitives rendered with this font instance -double FontInstance::scaleFactor() const { return scaleFactor_; } - -// Return text colour -QColor FontInstance::colour() const { return colour_; } - -/* - * Rendering - */ - -// Set face size -bool FontInstance::setFaceSize(double faceSize) -{ - if (!font_) - return false; - - font_->FaceSize(faceSize); - - return true; -} - -// Render supplied text -bool FontInstance::renderText(std::string text) const -{ - if (!font_) - return false; - - glColor4f(colour_.redF(), colour_.greenF(), colour_.blueF(), colour_.alphaF()); - font_->Render(text.c_str()); - - return true; -} - -/* - * Bounding Box Calculation - */ - -// Calculate bounding box for specified string -void FontInstance::boundingBox(std::string_view text, Vector3 &lowerLeft, Vector3 &upperRight) const -{ - FTBBox box = boundingBox(text); - lowerLeft.set(box.Lower().X(), box.Lower().Y(), box.Lower().Z()); - upperRight.set(box.Upper().X(), box.Upper().Y(), box.Upper().Z()); - lowerLeft *= scaleFactor_; - upperRight *= scaleFactor_; -} - -// Calculate bounding box width for specified string -double FontInstance::boundingBoxWidth(std::string_view text) const -{ - FTBBox box = boundingBox(text); - return scaleFactor_ * (box.Upper().X() - box.Lower().X()); -} - -// Calculate bounding box height for specified string -double FontInstance::boundingBoxHeight(std::string_view text) const -{ - FTBBox box = boundingBox(text); - return scaleFactor_ * (box.Upper().Y() - box.Lower().Y()); -} diff --git a/src/gui/render/fontInstance.h b/src/gui/render/fontInstance.h deleted file mode 100644 index f041fa12f0..0000000000 --- a/src/gui/render/fontInstance.h +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "math/vector3.h" -#include -#include -#include -#include - -// Font Instance -class FontInstance -{ - public: - FontInstance(QColor colour); - - /* - * Font Data - */ - private: - // Text colour - QColor colour_; - // Font file last passed to setupFont() - QString fontFile_; - // Font data - QResource *fontData_; - // FTGL font for text - FTFont *font_; - // Font full height (from bottom of descender to top of ascender) - double fontFullHeight_; - // Font base height (from baseline to top of ascender) - double fontBaseHeight_; - // Width of double dot (used for correction of width of strings with trailing spaces) - double dotWidth_; - // General scaling factor for primitives rendered with this font instance - double scaleFactor_; - - public: - // Set up font with font filename specified - bool setUp(QString fontFileName = ""); - // Return whether font exists and is ready for use - bool fontOK() const; - // Return full height of font - double fontFullHeight() const; - // Return base height of font - double fontBaseHeight() const; - // Set general scaling factor for primitives rendered with this font instance - void setScaleFactor(double scaleFactor); - // Return general scaling factor for primitives rendered with this font instance - double scaleFactor() const; - // Return the text colour - QColor colour() const; - - /* - * Rendering - */ - public: - // Set face size - bool setFaceSize(double faceSize); - // Render supplied text - bool renderText(std::string text) const; - - /* - * Bounding Box Calculation - */ - private: - // Return bounding box for specified string - FTBBox boundingBox(std::string_view text) const; - - public: - // Calculate bounding box for specified string - void boundingBox(std::string_view text, Vector3 &lowerLeft, Vector3 &upperRight) const; - // Calculate bounding box width for specified string - double boundingBoxWidth(std::string_view text) const; - // Calculate bounding box height for specified string - double boundingBoxHeight(std::string_view text) const; -}; diff --git a/src/gui/render/lineStipple.cpp b/src/gui/render/lineStipple.cpp deleted file mode 100644 index 43dc0f4963..0000000000 --- a/src/gui/render/lineStipple.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/lineStipple.h" -#include "base/sysFunc.h" -#include -#include -#include - -// Static list of LineStipples -LineStipple LineStipple::stipple[] = {{1, 0xffff, "Solid"}, {1, 0xaaaa, "Dots"}, {1, 0xcccc, "Fine Dash"}, - {3, 0xaaaa, "Eighth Dash"}, {1, 0xf0f0, "Quarter Dash"}, {1, 0xff00, "Half Dash"}, - {1, 0x6f6f, "Dot Dash 1"}}; - -// Convert text string to StippleType -LineStipple::StippleType LineStipple::stippleType(std::string_view s) -{ - for (auto n = 0; n < LineStipple::nStippleTypes; ++n) - if (DissolveSys::sameString(s, LineStipple::stipple[n].name)) - return (LineStipple::StippleType)n; - return LineStipple::nStippleTypes; -} - -// Convert StippleType to text string -std::string_view LineStipple::stippleType(LineStipple::StippleType st) { return LineStipple::stipple[st].name; } - -/* - * Stipple - */ - -// Add stipple pattern to specified QComboBox -void LineStipple::addStippleItem(QComboBox *combo, int lineHeight) -{ - auto lineWidth = combo->width() - 8; - QLine line(0, lineHeight / 2, lineWidth, lineHeight / 2); - QPalette palette = combo->palette(); - QPen pen; - pen.setWidth(lineHeight); - pen.setCapStyle(Qt::FlatCap); - combo->setIconSize(QSize(lineWidth, lineHeight)); - - // Create an icon with the stippled line on it - QPixmap lineImage(lineWidth, lineHeight); - QPainter painter(&lineImage); - painter.setRenderHint(QPainter::Antialiasing, false); - painter.setBackground(QBrush(Qt::white)); - painter.fillRect(0, 0, lineWidth, lineHeight, QBrush(palette.window())); - pen.setDashPattern(dashPattern()); - painter.setPen(pen); - painter.drawLine(line); - painter.end(); - combo->addItem(QIcon(lineImage), QString::fromStdString(name)); -} - -// Return stipple pattern as a Qt-compatible dash pattern -QVector &LineStipple::dashPattern() -{ - static QVector pattern; - pattern.clear(); - - // Look at each of the first 16 bits of the stipple in turn... - auto consecutive = 0, last = -1, nEntries = 0; - int bit; - for (auto n = 15; n >= 0; --n) - { - bit = (stipplePattern & (1 << n) ? 1 : 0); - - // If this bit is the same as the last, then increase the 'run' - if (bit == last) - ++consecutive; - else if (last == -1) - { - last = bit; - consecutive = 1; - } - else - { - // Special case if nEntries = 0, since if the first run is a space (0) we must skip the first dash... - if ((nEntries == 0) && (last == 0)) - pattern << 0; - - // Add next run integer - pattern << consecutive * stippleFactor; - - // Reset counter and flag - last = bit; - consecutive = 1; - ++nEntries; - } - } - // Add on the last bit that we have.... - pattern << consecutive * stippleFactor; - - // Ensure that we have an even number of entries in the vector... - if (pattern.size() % 2 == 1) - pattern << 0; - - return pattern; -} - -/* - * GL - */ - -// Apply stipple pattern -void LineStipple::apply() { glLineStipple(stippleFactor, stipplePattern); } diff --git a/src/gui/render/lineStipple.h b/src/gui/render/lineStipple.h deleted file mode 100644 index a063f1d871..0000000000 --- a/src/gui/render/lineStipple.h +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include -#include - -// Forward Declarations -class QComboBox; - -// Line Stipple -class LineStipple -{ - public: - // Line Stipple Types - enum StippleType - { - NoStipple, - DotStipple, - FineDashStipple, - EighthDashStipple, - QuarterDashStipple, - HalfDashStipple, - DotDash1Stipple, - nStippleTypes - }; - // Convert text string to StippleType - static LineStipple::StippleType stippleType(std::string_view s); - // Convert InputBlock to text string - static std::string_view stippleType(LineStipple::StippleType stipple); - - /* - * Stipple - */ - public: - // Line stipple factor - GLint stippleFactor; - // Line stipple pattern - GLushort stipplePattern; - // Name of stipple - std::string name; - - public: - // Add stipple pattern to specified QComboBox - void addStippleItem(QComboBox *combo, int lineHeight); - // Return stipple pattern as a Qt-compatible dash pattern - QVector &dashPattern(); - - /* - * GL - */ - public: - // Apply stipple pattern - void apply(); - - /* - * Singleton - */ - public: - // Static list of line stipples - static LineStipple stipple[]; -}; diff --git a/src/gui/render/lineStyle.cpp b/src/gui/render/lineStyle.cpp deleted file mode 100644 index db02a379c6..0000000000 --- a/src/gui/render/lineStyle.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/lineStyle.h" - -LineStyle::LineStyle(double width, LineStipple::StippleType stipple, double r, double g, double b, double a) -{ - width_ = width; - stipple_ = stipple; - setColour(r, g, b, a); -} - -LineStyle::~LineStyle() {} - -LineStyle::LineStyle(const LineStyle &source) { (*this) = source; } - -void LineStyle::operator=(const LineStyle &source) -{ - width_ = source.width_; - stipple_ = source.stipple_; - colour_[0] = source.colour_[0]; - colour_[1] = source.colour_[1]; - colour_[2] = source.colour_[2]; - colour_[3] = source.colour_[3]; -} - -/* - * Style - */ - -// Set line style -void LineStyle::set(double width, LineStipple::StippleType stipple) -{ - width_ = width; - stipple_ = stipple; -} - -// Set line style -void LineStyle::set(double width, LineStipple::StippleType stipple, QColor colour) -{ - width_ = width; - stipple_ = stipple; - setColour(colour); -} - -// Set line style -void LineStyle::set(double width, LineStipple::StippleType stipple, double r, double g, double b, double a) -{ - width_ = width; - stipple_ = stipple; - setColour(r, g, b, a); -} - -// Set line width -void LineStyle::setWidth(double width) { width_ = width; } - -// Return line width -double LineStyle::width() const { return width_; } - -// Set line stipple -void LineStyle::setStipple(LineStipple::StippleType stipple) { stipple_ = stipple; } - -// Return line stipple -LineStipple::StippleType LineStyle::stipple() const { return stipple_; } - -// Set line colour -void LineStyle::setColour(double r, double g, double b, double a) -{ - colour_[0] = r; - colour_[1] = g; - colour_[2] = b; - colour_[3] = a; -} - -// Set line colour -void LineStyle::setColour(QColor colour) -{ - colour_[0] = colour.redF(); - colour_[1] = colour.greenF(); - colour_[2] = colour.blueF(); - colour_[3] = colour.alphaF(); -} - -// Return line colour -const GLfloat *LineStyle::colour() const { return colour_; } - -/* - * GL - */ - -// Send line styling to GL -void LineStyle::sendToGL(const double pixelScaling) const -{ - // Set line width, including any supplied scaling factor - glLineWidth(width_ * pixelScaling); - - // Enable / disable stippling - if (stipple_ == LineStipple::NoStipple) - glDisable(GL_LINE_STIPPLE); - else - { - glEnable(GL_LINE_STIPPLE); - LineStipple::stipple[stipple_].apply(); - } - - // Apply colour - glColor4fv(colour_); -} diff --git a/src/gui/render/lineStyle.h b/src/gui/render/lineStyle.h deleted file mode 100644 index b1fcbc0f54..0000000000 --- a/src/gui/render/lineStyle.h +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/lineStipple.h" -#include - -// Line Style -class LineStyle -{ - public: - LineStyle(double width = 1.0, LineStipple::StippleType stipple = LineStipple::NoStipple, double r = 0.0, double g = 0.0, - double b = 0.0, double a = 1.0); - ~LineStyle(); - LineStyle(const LineStyle &source); - void operator=(const LineStyle &source); - - /* - * Style - */ - private: - // Line width - double width_; - // Line stipple - LineStipple::StippleType stipple_; - // Line colour - GLfloat colour_[4]; - - public: - // Set line style - void set(double width, LineStipple::StippleType stipple); - // Set line style and colour - void set(double width, LineStipple::StippleType stipple, double r, double g, double b, double a = 1.0); - // Set line style and colour - void set(double width, LineStipple::StippleType stipple, QColor colour); - // Set line width - void setWidth(double width); - // Return line width - double width() const; - // Set line stipple - void setStipple(LineStipple::StippleType stipple); - // Return line stipple - LineStipple::StippleType stipple() const; - // Set line colour - void setColour(double r, double g, double b, double a = 1.0); - // Set line colour - void setColour(QColor colour); - // Return line colour - const GLfloat *colour() const; - - /* - * GL - */ - public: - // Send line styling to GL - void sendToGL(const double pixelScaling = 1.0) const; -}; diff --git a/src/gui/render/numberFormat.cpp b/src/gui/render/numberFormat.cpp deleted file mode 100644 index 0e462c0ad2..0000000000 --- a/src/gui/render/numberFormat.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/numberFormat.h" -#include "math/doubleExp.h" -#include - -NumberFormat::NumberFormat(FormatType type, int nDecimals) - : type_(type), nDecimals_(nDecimals), forcePrecedingPlus_(false), useUpperCaseExponent_(true), useENotation_(true) -{ -} - -// Return enum options for FormatType -EnumOptions NumberFormat::formatTypes() -{ - return EnumOptions("FormatType", {{NumberFormat::FormatType::Decimal, "Decimal"}, - {NumberFormat::FormatType::Integer, "Integer"}, - {NumberFormat::FormatType::Scientific, "Scientific"}}); -} - -/* - * Definition - */ - -// Set format type -void NumberFormat::setType(NumberFormat::FormatType type) { type_ = type; } - -// Return format type -NumberFormat::FormatType NumberFormat::type() { return type_; } - -// Set number of decimals to use -void NumberFormat::setNDecimals(int n) { nDecimals_ = n; } - -// Return number of decimals to use -int NumberFormat::nDecimals() { return nDecimals_; } - -// Set whether to force display of preceding '+' as well as '-' -void NumberFormat::setForcePrecedingPlus(bool b) { forcePrecedingPlus_ = b; } - -// Return whether to force display of preceding '+' as well as '-' -bool NumberFormat::forcePrecedingPlus() { return forcePrecedingPlus_; } - -// Set whether or not use use uppercase exponent character (for ScientificFormat) -void NumberFormat::setUseUpperCaseExponent(bool b) { useUpperCaseExponent_ = b; } - -// Return whether or not use use uppercase exponent character (for ScientificFormat) -bool NumberFormat::useUpperCaseExponent() { return useUpperCaseExponent_; } - -// Set whether to use 'E' notation in preference to 'x10' notation -void NumberFormat::setUseENotation(bool b) { useENotation_ = b; } - -// Return whether to use 'E' notation in preference to 'x10' notation -bool NumberFormat::useENotation() { return useENotation_; } - -/* - * Number Conversion - */ - -// Return number formatted according to internal definition -QString NumberFormat::format(double number) -{ - QString result; - - DoubleExp x(number); - - // Add '+' onto string if requested and number is positive - if (forcePrecedingPlus_ && (number >= 0.0)) - result = "+"; - - // Construct rest of string - switch (type_) - { - case (NumberFormat::FormatType::Integer): - result += QString::number(int(number)); - break; - case (NumberFormat::FormatType::Decimal): - result += QString::number(number, 'f', nDecimals_); - break; - case (NumberFormat::FormatType::Scientific): - if (!useENotation_) - result += QString::number(x.mantissa(), 'f', nDecimals_) + QChar(0x00D7) + "10\\sup{" + - QString::number(x.exponent()) + "}"; - else if (useUpperCaseExponent_) - result += QString::number(x.mantissa(), 'f', nDecimals_) + "E" + QString::number(x.exponent()); - else - result += QString::number(x.mantissa(), 'f', nDecimals_) + "e" + QString::number(x.exponent()); - break; - default: - result += QString::number(number); - break; - } - - return result; -} diff --git a/src/gui/render/numberFormat.h b/src/gui/render/numberFormat.h deleted file mode 100644 index 3adf798114..0000000000 --- a/src/gui/render/numberFormat.h +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "base/enumOptions.h" -#include - -// Number Format -class NumberFormat -{ - public: - // Basic Number Type - enum class FormatType - { - Decimal, - Integer, - Scientific - }; - // Return enum options for FormatType - static EnumOptions formatTypes(); - NumberFormat(FormatType type = FormatType::Decimal, int nDecimals = 1); - ~NumberFormat() = default; - - /* - * Definition - */ - private: - // Format type - FormatType type_; - // Number of decimals to use - int nDecimals_; - // Whether to force display of preceding '+' as well as '-' - bool forcePrecedingPlus_; - // Whether or not use use uppercase exponent character (for ScientificFormat) - bool useUpperCaseExponent_; - // Whether to use 'E' notation in preference to 'x10' notation - bool useENotation_; - - public: - // Set format type - void setType(NumberFormat::FormatType type); - // Return format type - NumberFormat::FormatType type(); - // Set number of decimals to use - void setNDecimals(int n); - // Return number of decimals to use - int nDecimals(); - // Set whether to force display of preceding '+' as well as '-' - void setForcePrecedingPlus(bool b); - // Return whether to force display of preceding '+' as well as '-' - bool forcePrecedingPlus(); - // Set whether or not use use uppercase exponent character (for ScientificFormat) - void setUseUpperCaseExponent(bool b); - // Return whether or not use use uppercase exponent character (for ScientificFormat) - bool useUpperCaseExponent(); - // Set whether to use 'E' notation in preference to 'x10' notation - void setUseENotation(bool b); - // Return whether to use 'E' notation in preference to 'x10' notation - bool useENotation(); - - /* - * Number Conversion - */ - public: - // Return number formatted according to internal definition - QString format(double number); -}; diff --git a/src/gui/render/primitive.cpp b/src/gui/render/primitive.cpp deleted file mode 100644 index fa9670723b..0000000000 --- a/src/gui/render/primitive.cpp +++ /dev/null @@ -1,817 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/primitive.h" -#include "base/messenger.h" - -Primitive::Primitive() -{ - colouredVertexData_ = false; - type_ = GL_TRIANGLES; - dataPerVertex_ = 6; - nDefinedVertices_ = 0; - useInstances_ = true; -} - -Primitive::~Primitive() {} - -/* - * Data - */ - -// Initialise primitive -void Primitive::initialise(GLenum type, bool colourData, int arrayChunkSize) -{ - type_ = type; - colouredVertexData_ = colourData; - - // Set data per vertex based on the primitive type, and whether we have individual colour data or not - dataPerVertex_ = (colouredVertexData_ ? 10 : 6); - if (type_ == GL_TRIANGLES) - verticesPerType_ = 3; - else if ((type_ == GL_LINES) || (type_ == GL_LINE_LOOP) || (type_ == GL_LINE_STRIP)) - verticesPerType_ = 2; - else if (type_ == GL_POINTS) - verticesPerType_ = 1; - else - Messenger::error("Invalid GLenum type given to VertexChunk::initialise ({})\n", type_); - - forgetAll(); -} - -// Forget all vertex and index data -void Primitive::forgetAll() -{ - vertexData_.clear(); - indexData_.clear(); - nDefinedVertices_ = 0; -} - -// Return number of vertices currently defined in primitive -int Primitive::nDefinedVertices() const { return vertexData_.size(); } - -// Return number of indices currently defined in primitive -int Primitive::nDefinedIndices() const { return indexData_.size(); } - -// Return whether vertex data contains colour information -bool Primitive::colouredVertexData() const { return colouredVertexData_; } - -// Update mesh (VBO / display list) of dynamic primitive -void Primitive::updateMesh() -{ - // Check instances - if there is no current instance, create one - if (!instances_.empty()) - popInstance(QOpenGLContext::currentContext()); - pushInstance(QOpenGLContext::currentContext()); -} -/* - * Instances - */ - -// Flag that this primitive should not use instances (rendering will use vertex arrays) -void Primitive::setNoInstances() { useInstances_ = false; } - -// Push instance of primitive -void Primitive::pushInstance(const QOpenGLContext *context) -{ - // Does this primitive use instances? - if (!useInstances_) - return; - - // Clear the error flag - glGetError(); - - // Grab the QOpenGLFunctions object pointer - QOpenGLFunctions *glFunctions = context->functions(); - - // Create new instance - PrimitiveInstance *pi = instances_.emplace_back(std::make_unique()).get(); - - // Vertex buffer object or plain old display list? - if (PrimitiveInstance::globalInstanceType() == PrimitiveInstance::VBOInstance) - { - // Prepare local array of data to pass to VBO - GLuint vertexVBO = 0, indexVBO = 0; - if (nDefinedVertices_ <= 0) - { - // Store instance data - pi->setVBO(context, 0, 0); - return; - } - - // Determine total size of array (in bytes) for VBO - auto vboSize = nDefinedVertices_ * (colouredVertexData_ ? 10 : 6) * sizeof(GLfloat); - - // Generate vertex array object - glFunctions->glGenBuffers(1, &vertexVBO); - - // Bind VBO - glFunctions->glBindBuffer(GL_ARRAY_BUFFER, vertexVBO); - - // Initialise vertex array data - glFunctions->glBufferData(GL_ARRAY_BUFFER, vboSize, vertexData_.data(), GL_STATIC_DRAW); - if (glGetError() != GL_NO_ERROR) - { - glFunctions->glBindBuffer(GL_ARRAY_BUFFER, 0); - Messenger::error("Error occurred while generating vertex buffer object for Primitive.\n"); - glFunctions->glDeleteBuffers(1, &vertexVBO); - vertexVBO = 0; - return; - } - glFunctions->glBindBuffer(GL_ARRAY_BUFFER, 0); - - // Generate index array object (if using indices) - if (!indexData_.empty()) - { - // Generate index array object - glFunctions->glGenBuffers(1, &indexVBO); - - // Bind VBO - glFunctions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO); - - // Initialise index array data - glFunctions->glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexData_.size() * sizeof(GLuint), indexData_.data(), - GL_STATIC_DRAW); - if (glGetError() != GL_NO_ERROR) - { - glFunctions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - Messenger::error("Error occurred while generating index buffer object for Primitive.\n"); - glFunctions->glDeleteBuffers(1, &indexVBO); - indexVBO = 0; - return; - } - glFunctions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - // Store instance data - pi->setVBO(context, vertexVBO, indexData_.empty() ? 0 : indexVBO); - } - else - { - // Generate display list - auto listId = glGenLists(1); - if (listId == 0) - Messenger::error("Internal Error: Primitive::pushInstance - glGenLists(1) returned 0!\n!"); - else - { - glNewList(listId, GL_COMPILE); - - // Does the vertex data contain colour-per-vertex information? - glInterleavedArrays(colouredVertexData_ ? GL_C4F_N3F_V3F : GL_N3F_V3F, 0, vertexData_.data()); - - // Check if we are using indices - if (!indexData_.empty()) - glDrawElements(type_, indexData_.size(), GL_UNSIGNED_INT, indexData_.data()); - else - glDrawArrays(type_, 0, nDefinedVertices_); - - glEndList(); - } - - // Store data - pi->setDisplayList(context, listId); - } -} - -// Pop topmost instance on primitive's stack -void Primitive::popInstance(const QOpenGLContext *context) -{ - // Does this primitive use instances? - if (!useInstances_) - return; - - // Grab the QOpenGLFunctions object pointer - QOpenGLFunctions *glFunctions = context->functions(); - - auto &pi = instances_.back(); - if (pi != nullptr) - { - if (pi->context() == context) - { - // Vertex buffer object or plain old display list? - if (pi->type() == PrimitiveInstance::VBOInstance) - { - GLuint bufid = pi->vboVertexObject(); - if (bufid != 0) - glFunctions->glDeleteBuffers(1, &bufid); - if (!indexData_.empty()) - { - bufid = pi->vboIndexObject(); - if (bufid != 0) - glFunctions->glDeleteBuffers(1, &bufid); - } - } - else if (pi->listObject() != 0) - glDeleteLists(pi->listObject(), 1); - } - instances_.pop_back(); - } -} - -// Return number of instances available -int Primitive::nInstances() const { return instances_.size(); } - -// Send to OpenGL (i.e. render) -void Primitive::sendToGL() const -{ - // If no vertices are defined, nothing to do... - if (nDefinedVertices_ == 0) - return; - - // Check if using instances... - if (useInstances_) - { - // Grab topmost instance - auto &pi = instances_.back(); - if (pi->type() == PrimitiveInstance::VBOInstance) - { - // Get QOpenGLFunctions object from supplied context - QOpenGLFunctions *functions = pi->context()->functions(); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - if (!indexData_.empty()) - glEnableClientState(GL_INDEX_ARRAY); - else - glDisableClientState(GL_INDEX_ARRAY); - - // Bind VBO and index buffer (if using it) - functions->glBindBuffer(GL_ARRAY_BUFFER, pi->vboVertexObject()); - if (!indexData_.empty()) - functions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pi->vboIndexObject()); - - glInterleavedArrays(colouredVertexData_ ? GL_C4F_N3F_V3F : GL_N3F_V3F, 0, nullptr); - if (!indexData_.empty()) - glDrawElements(type_, indexData_.size(), GL_UNSIGNED_INT, 0); - else - glDrawArrays(type_, 0, nDefinedVertices_); - - // Revert to normal operation - pass 0 as VBO index - functions->glBindBuffer(GL_ARRAY_BUFFER, 0); - if (!indexData_.empty()) - functions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - if (!indexData_.empty()) - glDisableClientState(GL_INDEX_ARRAY); - } - else if (pi->listObject() != 0) - glCallList(pi->listObject()); - } - else - { - // Does the vertex data contain colour-per-vertex information? - glInterleavedArrays(colouredVertexData_ ? GL_C4F_N3F_V3F : GL_N3F_V3F, 0, vertexData_.data()); - - // Check if we are using indices - if (!indexData_.empty()) - glDrawElements(type_, indexData_.size(), GL_UNSIGNED_INT, indexData_.data()); - else - glDrawArrays(type_, 0, nDefinedVertices_); - } -} - -/* - * Vertex / Index Generation - */ - -// Define next vertex and normal -GLuint Primitive::defineVertex(GLfloat x, GLfloat y, GLfloat z, GLfloat nx, GLfloat ny, GLfloat nz, const GLfloat *rgba) -{ - if (colouredVertexData_) - { - if (rgba == nullptr) - { - Messenger::error("Internal Error: No colour given to defineVertex(), but the Primitive requires one.\n"); - return -1; - } - - // Store colour - vertexData_.push_back(rgba[0]); - vertexData_.push_back(rgba[1]); - vertexData_.push_back(rgba[2]); - vertexData_.push_back(rgba[3]); - } - else if (rgba != nullptr) - { - Messenger::error("Internal Error: Colour given to defineVertex(), but the Primitive does not require one.\n"); - return -1; - } - - // Store normal - vertexData_.push_back(nx); - vertexData_.push_back(ny); - vertexData_.push_back(nz); - - // Store vertex - vertexData_.push_back(x); - vertexData_.push_back(y); - vertexData_.push_back(z); - - // Increase vertex counter - ++nDefinedVertices_; - - // Return index of vertex - return (nDefinedVertices_ - 1); -} - -// Define next vertex and normal -GLuint Primitive::defineVertex(GLfloat x, GLfloat y, GLfloat z, Vector3 &normal, const GLfloat *rgba) -{ - return defineVertex(x, y, z, normal.x, normal.y, normal.z, rgba); -} - -// Define next vertex and normal -GLuint Primitive::defineVertex(Vector3 &vertex, Vector3 &normal, const GLfloat *rgba) -{ - return defineVertex(vertex.x, vertex.y, vertex.z, normal.x, normal.y, normal.z, rgba); -} - -// Define next index double -void Primitive::defineIndices(GLuint a, GLuint b) -{ - indexData_.push_back(a); - indexData_.push_back(b); -} - -// Define next index triple -void Primitive::defineIndices(GLuint a, GLuint b, GLuint c) -{ - indexData_.push_back(a); - indexData_.push_back(b); - indexData_.push_back(c); -} - -/* - * Geometric Primitive Generation - */ - -// Draw line -void Primitive::line(double x1, double y1, double z1, double x2, double y2, double z2, const GLfloat *rgba) -{ - defineVertex(x1, y1, z1, 1.0, 0.0, 0.0, rgba); - defineVertex(x2, y2, z2, 1.0, 0.0, 0.0, rgba); -} - -// Add line to axis primitive -void Primitive::line(Vector3 v1, Vector3 v2, const GLfloat *rgba) -{ - defineVertex(v1.x, v1.y, v1.z, 1.0, 0.0, 0.0, rgba); - defineVertex(v2.x, v2.y, v2.z, 1.0, 0.0, 0.0, rgba); -} - -// Create vertices of sphere with specified radius and quality -void Primitive::sphere(double radius, int nStacks, int nSlices) -{ - int i, j; - double stack0, stack1, z0, zr0, z1, zr1, slice0, slice1, x0, y0, x1, y1; - - for (i = 1; i <= nStacks; ++i) - { - stack0 = M_PI * (-0.5 + (double)(i - 1) / nStacks); - z0 = sin(stack0); - zr0 = cos(stack0); - - stack1 = M_PI * (-0.5 + (double)i / nStacks); - z1 = sin(stack1); - zr1 = cos(stack1); - - for (j = 1; j <= nSlices; ++j) - { - slice0 = 2 * M_PI * (double)(j - 1) / nSlices; - x0 = cos(slice0); - y0 = sin(slice0); - - slice1 = 2 * M_PI * (double)j / nSlices; - x1 = cos(slice1); - y1 = sin(slice1); - - // First triangle - {x0,y0,z0},{x0,y0,z1},{x1,y1,z0} - // N.B Don't plot if i == 1, to avoid overlapping with subsequent vertices in this pass - if (i > 1) - { - defineVertex(x0 * zr0 * radius, y0 * zr0 * radius, z0 * radius, x0 * zr0, y0 * zr0, z0); - defineVertex(x0 * zr1 * radius, y0 * zr1 * radius, z1 * radius, x0 * zr1, y0 * zr1, z1); - defineVertex(x1 * zr0 * radius, y1 * zr0 * radius, z0 * radius, x1 * zr0, y1 * zr0, z0); - } - - // Second triangle - {x0,y0,z0},{x0,y0,z1},{x1,y1,z0} - // N.B. Don't plot if i == nStacks, to avoid overlapping with previous vertices in this pass - if (i < nStacks) - { - defineVertex(x0 * zr1 * radius, y0 * zr1 * radius, z1 * radius, x0 * zr1, y0 * zr1, z1); - defineVertex(x1 * zr0 * radius, y1 * zr0 * radius, z0 * radius, x1 * zr0, y1 * zr0, z0); - defineVertex(x1 * zr1 * radius, y1 * zr1 * radius, z1 * radius, x1 * zr1, y1 * zr1, z1); - } - } - } -} - -// Plot cylinder vertices from origin {ox,oy,oz}, following vector {vx,vy,vz}, with radii and quality specified -void Primitive::cylinder(GLfloat ox, GLfloat oy, GLfloat oz, GLfloat vx, GLfloat vy, GLfloat vz, double startRadius, - double endRadius, int nStacks, int nSlices, bool capStart, bool capEnd) -{ - int i, j; - Vector3 u, v, w, vert[4], normal[2], deltarj, rj; - double d, dtheta, dradius; - - // Setup some variables - rj.set(vx, vy, vz); - dtheta = 2.0 * M_PI / nSlices; - dradius = (startRadius - endRadius) / nStacks; - deltarj = rj / nStacks; - - // Calculate orthogonal vectors - u = rj.orthogonal(); - v = rj * u; - v.normalise(); - w = rj; - w.normalise(); - - // TODO Normal calculation for cones will be incorrect - for (i = 1; i <= nStacks; ++i) - { - for (j = 1; j <= nSlices; ++j) - { - d = (j - 1) * dtheta; - normal[0] = u * cos(d) + v * sin(d); - vert[0] = normal[0] * (startRadius - (i - 1) * dradius) + deltarj * (i - 1); - vert[1] = normal[0] * (startRadius - i * dradius) + deltarj * i; - d = j * dtheta; - normal[1] = u * cos(d) + v * sin(d); - vert[2] = normal[1] * (startRadius - (i - 1) * dradius) + deltarj * (i - 1); - vert[3] = normal[1] * (startRadius - i * dradius) + deltarj * i; - - // Triangle 1 - if ((i > 1) || (startRadius > 1.0e-5)) - { - defineVertex(ox + vert[0].x, oy + vert[0].y, oz + vert[0].z, normal[0].x, normal[0].y, normal[0].z); - defineVertex(ox + vert[1].x, oy + vert[1].y, oz + vert[1].z, normal[0].x, normal[0].y, normal[0].z); - defineVertex(ox + vert[2].x, oy + vert[2].y, oz + vert[2].z, normal[1].x, normal[1].y, normal[1].z); - } - - // Triangle 2 - if ((i < nStacks) || (endRadius > 1.0e-5)) - { - defineVertex(ox + vert[1].x, oy + vert[1].y, oz + vert[1].z, normal[0].x, normal[0].y, normal[0].z); - defineVertex(ox + vert[2].x, oy + vert[2].y, oz + vert[2].z, normal[1].x, normal[1].y, normal[1].z); - defineVertex(ox + vert[3].x, oy + vert[3].y, oz + vert[3].z, normal[1].x, normal[1].y, normal[1].z); - } - - // Start cap - if ((i == 1) && (startRadius > 1.0e-5) && capStart) - { - defineVertex(ox, oy, oz, -w.x, -w.y, -w.z); - defineVertex(ox + vert[0].x, oy + vert[0].y, oz + vert[0].z, -w.x, -w.y, -w.z); - defineVertex(ox + vert[2].x, oy + vert[2].y, oz + vert[2].z, -w.x, -w.y, -w.z); - } - - // End cap - if ((i == nStacks) && (endRadius > 1.0e-5) && capEnd) - { - defineVertex(ox + rj.x, oy + rj.y, oz + rj.z, w.x, w.y, w.z); - defineVertex(ox + vert[1].x, oy + vert[1].y, oz + vert[1].z, w.x, w.y, w.z); - defineVertex(ox + vert[3].x, oy + vert[3].y, oz + vert[3].z, w.x, w.y, w.z); - } - } - } -} - -// Plot tube ring of specified radius and tube width -void Primitive::ring(double radius, double width, int nStacks, int nSlices, int nSegments, bool segmented) -{ - int n, m, o; - Vector3 x1, x2, y(0.0, 0.0, 1.0), normal[4], vert[4], r1, r2; - double d1, d2, dtheta, dphi, dpsi, cosphi1, sinphi1, cosphi2, sinphi2; - - // Setup some variables - dphi = 2.0 * M_PI / nStacks; - dpsi = dphi / nSegments; - dtheta = 2.0 * M_PI / nSlices; - - for (n = 0; n < nStacks; ++n) - { - // Calculate position around circle and orthogonal vectors (for cylinder plotting) - if (segmented && (n + 1) % 2) - continue; - - for (o = 0; o < nSegments; ++o) - { - cosphi1 = cos(n * dphi + o * dpsi); - sinphi1 = sin(n * dphi + o * dpsi); - cosphi2 = cos(n * dphi + (o + 1) * dpsi); - sinphi2 = sin(n * dphi + (o + 1) * dpsi); - r1.set(cosphi1 * radius, sinphi1 * radius, 0.0); - r2.set(cosphi2 * radius, sinphi2 * radius, 0.0); - x1.set(cosphi1, sinphi1, 0.0); - x2.set(cosphi2, sinphi2, 0.0); - - for (m = 0; m < nSlices; ++m) - { - // Plot along specified direction, and then map vertices from straight cylinder onto circle in - // XY plane - d1 = m * dtheta; - d2 = d1 + dtheta; - - normal[0] = x1 * cos(d1) + y * sin(d1); - normal[1] = x1 * cos(d2) + y * sin(d2); - normal[2] = x2 * cos(d1) + y * sin(d1); - normal[3] = x2 * cos(d2) + y * sin(d2); - - vert[0] = normal[0] * width + r1; - vert[1] = normal[1] * width + r1; - vert[2] = normal[2] * width + r2; - vert[3] = normal[3] * width + r2; - - // Triangle 1 - defineVertex(vert[0].x, vert[0].y, vert[0].z, normal[0].x, normal[0].y, normal[0].z); - defineVertex(vert[1].x, vert[1].y, vert[1].z, normal[1].x, normal[1].y, normal[1].z); - defineVertex(vert[2].x, vert[2].y, vert[2].z, normal[2].x, normal[2].y, normal[2].z); - - // Triangle 2 - defineVertex(vert[1].x, vert[1].y, vert[1].z, normal[1].x, normal[1].y, normal[1].z); - defineVertex(vert[2].x, vert[2].y, vert[2].z, normal[2].x, normal[2].y, normal[2].z); - defineVertex(vert[3].x, vert[3].y, vert[3].z, normal[3].x, normal[3].y, normal[3].z); - } - } - } -} - -// Plot circle of specified radius -void Primitive::circle(double radius, int nStacks, int nSegments, bool segmented) -{ - int n, o; - Vector3 r1, r2; - double dphi, dpsi, cosphi1, sinphi1, cosphi2, sinphi2; - - type_ = GL_LINES; - - // Setup some variables - dphi = 2.0 * M_PI / nStacks; - dpsi = dphi / nSegments; - - for (n = 0; n < nStacks; ++n) - { - // Calculate position around circle - if (segmented && (n + 1) % 2) - continue; - - for (o = 0; o < nSegments; ++o) - { - cosphi1 = cos(n * dphi + o * dpsi); - sinphi1 = sin(n * dphi + o * dpsi); - cosphi2 = cos(n * dphi + (o + 1) * dpsi); - sinphi2 = sin(n * dphi + (o + 1) * dpsi); - r1.set(cosphi1 * radius, sinphi1 * radius, 0.0); - r2.set(cosphi2 * radius, sinphi2 * radius, 0.0); - - defineVertex(r1.x, r1.y, r1.z, 0.0, 0.0, 1.0); - defineVertex(r2.x, r2.y, r2.z, 0.0, 0.0, 1.0); - } - } -} - -// Create vertices of cross with specified width -void Primitive::cross(double width) -{ - Vector3 v; - const auto halfWidth = 0.5 * width; - for (auto i = 0; i < 3; ++i) - { - v.zero(); - v.set(i, halfWidth); - defineVertex(v.x, v.y, v.z, 1.0, 1.0, 1.0); - defineVertex(-v.x, -v.y, -v.z, 1.0, 1.0, 1.0); - defineIndices(i * 2, i * 2 + 1); - } -} - -// Plot solid orthorhomboid of specified size at specified origin, and with sides subdivided into triangles ( ntriangles = -// 2*nSubs ) -void Primitive::orthorhomboid(double sizex, double sizey, double sizez, int nSubs, double ox, double oy, double oz) -{ - // Create each face individually - 'offset' calculated so centre of orthorhombus is at - GLfloat delta[3], veca[3], vecb[3], vertex[3], sizes[3], offset[3]; - int i, j, plane; - sizes[0] = (GLfloat)sizex; - sizes[1] = (GLfloat)sizey; - sizes[2] = (GLfloat)sizez; - delta[0] = (GLfloat)sizex / nSubs; - delta[1] = (GLfloat)sizey / nSubs; - delta[2] = (GLfloat)sizez / nSubs; - offset[0] = (-sizex / 2.0f) + ox; - offset[1] = (-sizey / 2.0f) + oy; - offset[2] = (-sizez / 2.0f) + oz; - - // Set general origin coordinate - // Loop over planes - for (plane = 0; plane < 3; ++plane) - { - // Define deltas for this plane - for (j = 0; j < 3; ++j) - { - veca[j] = 0.0; - vecb[j] = 0.0; - } - veca[(plane + 1) % 3] = delta[(plane + 1) % 3]; - vecb[(plane + 2) % 3] = delta[(plane + 2) % 3]; - // Loop over subdivisions in plane - for (i = 0; i < nSubs; ++i) - { - for (j = 0; j < nSubs; ++j) - { - vertex[0] = offset[0] + i * veca[0] + j * vecb[0]; - vertex[1] = offset[1] + i * veca[1] + j * vecb[1]; - vertex[2] = offset[2] + i * veca[2] + j * vecb[2]; - // Define triangle vertices for 'lower' plane - defineVertex(vertex[0], vertex[1], vertex[2], plane == 0, -1 * (plane == 1), -1 * (plane == 2)); - defineVertex(vertex[0] + veca[0], vertex[1] + veca[1], vertex[2] + veca[2], plane == 0, -1 * (plane == 1), - -1 * (plane == 2)); - defineVertex(vertex[0] + veca[0] + vecb[0], vertex[1] + veca[1] + vecb[1], vertex[2] + veca[2] + vecb[2], - plane == 0, -1 * (plane == 1), -1 * (plane == 2)); - defineVertex(vertex[0], vertex[1], vertex[2], plane == 0, -1 * (plane == 1), -1 * (plane == 2)); - defineVertex(vertex[0] + vecb[0], vertex[1] + vecb[1], vertex[2] + vecb[2], plane == 0, -1 * (plane == 1), - -1 * (plane == 2)); - defineVertex(vertex[0] + veca[0] + vecb[0], vertex[1] + veca[1] + vecb[1], vertex[2] + veca[2] + vecb[2], - plane == 0, -1 * (plane == 1), -1 * (plane == 2)); - - // Define trangle vertices for 'upper' plane - vertex[plane] += sizes[plane]; - defineVertex(vertex[0], vertex[1], vertex[2], plane == 0, plane == 1, plane == 2); - defineVertex(vertex[0] + veca[0], vertex[1] + veca[1], vertex[2] + veca[2], plane == 0, plane == 1, plane == 2); - defineVertex(vertex[0] + veca[0] + vecb[0], vertex[1] + veca[1] + vecb[1], vertex[2] + veca[2] + vecb[2], - plane == 0, plane == 1, plane == 2); - defineVertex(vertex[0], vertex[1], vertex[2], plane == 0, plane == 1, plane == 2); - defineVertex(vertex[0] + vecb[0], vertex[1] + vecb[1], vertex[2] + vecb[2], plane == 0, plane == 1, plane == 2); - defineVertex(vertex[0] + veca[0] + vecb[0], vertex[1] + veca[1] + vecb[1], vertex[2] + veca[2] + vecb[2], - plane == 0, plane == 1, plane == 2); - } - } - } -} - -// Plot wireframe orthorhomboid of specified size at specified origin, and with sides subdivided into triangles ( ntriangles = -// 2*nSubs ) -void Primitive::wireOrthorhomboid(double sizex, double sizey, double sizez, double ox, double oy, double oz) -{ - GLfloat offset[3]; - offset[0] = ox - sizex * 0.5; - offset[1] = oy - sizey * 0.5; - offset[2] = oz - sizez * 0.5; - - // Define the eight vertices of the orthorhomboid - defineVertex(offset[0], offset[1], offset[2], 1.0, 0.0, 0.0); // 0 - defineVertex(offset[0] + sizex, offset[1], offset[2], 1.0, 0.0, 0.0); // 1 - defineVertex(offset[0], offset[1] + sizey, offset[2], 1.0, 0.0, 0.0); // 2 - defineVertex(offset[0] + sizex, offset[1] + sizey, offset[2], 1.0, 0.0, 0.0); // 3 - defineVertex(offset[0], offset[1], offset[2] + sizez, 1.0, 0.0, 0.0); // 4 - defineVertex(offset[0] + sizex, offset[1], offset[2] + sizez, 1.0, 0.0, 0.0); // 5 - defineVertex(offset[0], offset[1] + sizey, offset[2] + sizez, 1.0, 0.0, 0.0); // 6 - defineVertex(offset[0] + sizex, offset[1] + sizey, offset[2] + sizez, 1.0, 0.0, 0.0); // 7 - - // Define edges - // -- Along X - defineIndices(0, 1); - defineIndices(2, 3); - defineIndices(4, 5); - defineIndices(6, 7); - // -- Along Y - defineIndices(0, 2); - defineIndices(1, 3); - defineIndices(4, 6); - defineIndices(5, 7); - // -- Along Z - defineIndices(0, 4); - defineIndices(1, 5); - defineIndices(2, 6); - defineIndices(3, 7); -} - -// Plot basic axes object -void Primitive::axes(double axisLength) -{ - const auto arrowSize = axisLength * 0.05; - - // X (first vertex = 0) - defineVertex(0.0, 0.0, 0.0, 0.0, 0.0, 1.0); - defineVertex(axisLength, 0.0, 0.0, 0.0, 0.0, 1.0); - defineVertex(axisLength - arrowSize, arrowSize, 0.0, 0.0, 0.0, 1.0); - defineVertex(axisLength - arrowSize, -arrowSize, 0.0, 0.0, 0.0, 1.0); - defineIndices(0, 1); - defineIndices(1, 2); - defineIndices(1, 3); - - // X label (first vertex = 4) - defineVertex(axisLength + arrowSize, arrowSize, 0.0, 0.0, 0.0, 1.0); - defineVertex(axisLength + arrowSize, -arrowSize, 0.0, 0.0, 0.0, 1.0); - defineVertex(axisLength + 2 * arrowSize, arrowSize, 0.0, 0.0, 0.0, 1.0); - defineVertex(axisLength + 2 * arrowSize, -arrowSize, 0.0, 0.0, 0.0, 1.0); - defineIndices(4, 7); - defineIndices(5, 6); - - // Y (first vertex = 8) - defineVertex(0.0, axisLength, 0.0, 0.0, 0.0, 1.0); - defineVertex(arrowSize, axisLength - arrowSize, 0.0, 0.0, 0.0, 1.0); - defineVertex(-arrowSize, axisLength - arrowSize, 0.0, 0.0, 0.0, 1.0); - defineIndices(0, 8); - defineIndices(8, 9); - defineIndices(8, 10); - - // Y label (first vertex = 11) - defineVertex(-arrowSize, axisLength + arrowSize, 0.0, 0.0, 0.0, 1.0); - defineVertex(-arrowSize, axisLength + 2 * arrowSize, 0.0, 0.0, 0.0, 1.0); - defineVertex(0.0, axisLength + 1.5 * arrowSize, 0.0, 0.0, 0.0, 1.0); - defineVertex(arrowSize, axisLength + 1.5 * arrowSize, 0.0, 0.0, 0.0, 1.0); - defineIndices(11, 13); - defineIndices(12, 13); - defineIndices(13, 14); - - // Z (first vertex = 15) - defineVertex(0.0, 0.0, axisLength, 0.0, 0.0, 1.0); - defineVertex(0.0, arrowSize, axisLength - arrowSize, 0.0, 0.0, 1.0); - defineVertex(0.0, -arrowSize, axisLength - arrowSize, 0.0, 0.0, 1.0); - defineIndices(0, 15); - defineIndices(15, 16); - defineIndices(15, 17); - - // Z label (first vertex = 18) - defineVertex(0.0, arrowSize, axisLength + arrowSize, 0.0, 0.0, 1.0); - defineVertex(0.0, arrowSize, axisLength + 2 * arrowSize, 0.0, 0.0, 1.0); - defineVertex(0.0, -arrowSize, axisLength + arrowSize, 0.0, 0.0, 1.0); - defineVertex(0.0, -arrowSize, axisLength + 2 * arrowSize, 0.0, 0.0, 1.0); - defineIndices(18, 19); - defineIndices(19, 20); - defineIndices(20, 21); -} - -// Plot basic coloured axes object -void Primitive::colouredAxes(double axisLength) -{ - const auto arrowSize = axisLength * 0.05; - GLfloat rgba[4], black[4]; - black[0] = 0.0; - black[1] = 0.0; - black[2] = 0.0; - black[3] = 1.0; - - // X (first vertex = 0) - rgba[0] = 1.0; - rgba[1] = 0.0; - rgba[2] = 0.0; - rgba[3] = 1.0; - defineVertex(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, rgba); - defineVertex(axisLength, 0.0, 0.0, 0.0, 0.0, 1.0, rgba); - defineVertex(axisLength - arrowSize, arrowSize, 0.0, 0.0, 0.0, 1.0, rgba); - defineVertex(axisLength - arrowSize, -arrowSize, 0.0, 0.0, 0.0, 1.0, rgba); - defineIndices(0, 1); - defineIndices(1, 2); - defineIndices(1, 3); - - // X label (first vertex = 4) - defineVertex(axisLength + arrowSize, arrowSize, 0.0, 0.0, 0.0, 1.0, black); - defineVertex(axisLength + arrowSize, -arrowSize, 0.0, 0.0, 0.0, 1.0, black); - defineVertex(axisLength + 2 * arrowSize, arrowSize, 0.0, 0.0, 0.0, 1.0, black); - defineVertex(axisLength + 2 * arrowSize, -arrowSize, 0.0, 0.0, 0.0, 1.0, black); - defineIndices(4, 7); - defineIndices(5, 6); - - // Y (first vertex = 8) - rgba[0] = 0.0; - rgba[1] = 1.0; - defineVertex(0.0, axisLength, 0.0, 0.0, 0.0, 1.0, rgba); - defineVertex(arrowSize, axisLength - arrowSize, 0.0, 0.0, 0.0, 1.0, rgba); - defineVertex(-arrowSize, axisLength - arrowSize, 0.0, 0.0, 0.0, 1.0, rgba); - defineIndices(0, 8); - defineIndices(8, 9); - defineIndices(8, 10); - - // Y label (first vertex = 11) - defineVertex(-arrowSize, axisLength + arrowSize, 0.0, 0.0, 0.0, 1.0, black); - defineVertex(-arrowSize, axisLength + 2 * arrowSize, 0.0, 0.0, 0.0, 1.0, black); - defineVertex(0.0, axisLength + 1.5 * arrowSize, 0.0, 0.0, 0.0, 1.0, black); - defineVertex(arrowSize, axisLength + 1.5 * arrowSize, 0.0, 0.0, 0.0, 1.0, black); - defineIndices(11, 13); - defineIndices(12, 13); - defineIndices(13, 14); - - // Z (first vertex = 15) - rgba[1] = 0.0; - rgba[2] = 1.0; - defineVertex(0.0, 0.0, axisLength, 0.0, 0.0, 1.0, rgba); - defineVertex(0.0, arrowSize, axisLength - arrowSize, 0.0, 0.0, 1.0, rgba); - defineVertex(0.0, -arrowSize, axisLength - arrowSize, 0.0, 0.0, 1.0, rgba); - defineIndices(0, 15); - defineIndices(15, 16); - defineIndices(15, 17); - - // Z label (first vertex = 18) - defineVertex(0.0, arrowSize, axisLength + arrowSize, 0.0, 0.0, 1.0, black); - defineVertex(0.0, arrowSize, axisLength + 2 * arrowSize, 0.0, 0.0, 1.0, black); - defineVertex(0.0, -arrowSize, axisLength + arrowSize, 0.0, 0.0, 1.0, black); - defineVertex(0.0, -arrowSize, axisLength + 2 * arrowSize, 0.0, 0.0, 1.0, black); - defineIndices(18, 19); - defineIndices(19, 20); - defineIndices(20, 21); -} diff --git a/src/gui/render/primitive.h b/src/gui/render/primitive.h deleted file mode 100644 index 546d40b0e7..0000000000 --- a/src/gui/render/primitive.h +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/primitiveInstance.h" -#include "math/matrix4.h" -#include - -// Rendering Primitive -class Primitive -{ - public: - Primitive(); - ~Primitive(); - - /* - * Data - */ - private: - // Vertex data array - std::vector vertexData_; - // Number of vertices defined in vertexData_ - int nDefinedVertices_; - // Index data array - std::vector indexData_; - // GL primitive type (GL_TRIANGLES, GL_LINES etc.) - GLenum type_; - // Number of vertices per primitive type - int verticesPerType_; - // Number of data points per vertex - int dataPerVertex_; - // Whether vertex data array also contains colour information - bool colouredVertexData_; - - public: - // Initialise primitive storage - void initialise(GLenum type, bool colourData, int arrayChunkSize = -1); - // Forget all data, leaving arrays intact - void forgetAll(); - // Return number of vertices currently defined in primitive - int nDefinedVertices() const; - // Return number of indices currently defined in primitive - int nDefinedIndices() const; - // Return whether vertex data contains colour information - bool colouredVertexData() const; - // Update mesh (recreate instance / VBO / display list) of primitive - void updateMesh(); - - /* - * Instances - */ - private: - // Stack of OpenGL VBO or display list IDs and the contexts in which they were created - std::vector> instances_; - // Flag stating whether or not instances should be used for this primitive - bool useInstances_; - - public: - // Flag that this primitive should not use instances (rendering will use vertex arrays) - void setNoInstances(); - // Push instance layer from current vertex chunk list - void pushInstance(const QOpenGLContext *context); - // Pop topmost instance layer - void popInstance(const QOpenGLContext *context); - // Return number of instances available - int nInstances() const; - // Send to OpenGL (i.e. render) - void sendToGL() const; - - /* - * Vertex / Index Generation - */ - public: - // Define next vertex and normal - GLuint defineVertex(GLfloat x, GLfloat y, GLfloat z, GLfloat nx, GLfloat ny, GLfloat nz, const GLfloat *rgba = nullptr); - // Define next vertex and normal - GLuint defineVertex(GLfloat x, GLfloat y, GLfloat z, Vector3 &normal, const GLfloat *rgba = nullptr); - // Define next vertex and normal - GLuint defineVertex(Vector3 &vertex, Vector3 &normal, const GLfloat *rgba = nullptr); - // Define next index double - void defineIndices(GLuint a, GLuint b); - // Define next index triple - void defineIndices(GLuint a, GLuint b, GLuint c); - - /* - * Geometric Primitive Generation - */ - public: - // Draw line - void line(double x1, double y1, double z1, double x2, double y2, double z2, const GLfloat *rgba = nullptr); - // Draw line - void line(Vector3 v1, Vector3 v2, const GLfloat *rgba = nullptr); - // Create vertices of sphere with specified radius and quality - void sphere(double radius, int nstacks, int nslices); - // Plot cylinder vertices from origin {ox,oy,oz}, following vector {vx,vy,vz}, with radii and quality specified - void cylinder(GLfloat ox, GLfloat oy, GLfloat oz, GLfloat vx, GLfloat vy, GLfloat vz, double startRadius, double endRadius, - int nStacks, int nSlices, bool capStart = false, bool capEnd = false); - // Plot tube ring of specified radius and tube width - void ring(double radius, double width, int nStacks, int nSlices, int nSegments, bool segmented); - // Plot circle of specified radius - void circle(double radius, int nStacks, int nSegments, bool segmented); - // Create vertices of cross with specified width - void cross(double halfWidth); - // Plot solid orthorhomboid of specified size at specified origin, and with sides subdivided into triangles ( ntriangles - // = 2*nSubs ) - void orthorhomboid(double sizex = 1.0, double sizey = 1.0, double sizez = 1.0, int nSubs = 4, double ox = 0.0, - double oy = 0.0, double oz = 0.0); - // Plot wireframe orthorhomboid of specified size at specified origin, and with sides subdivided into triangles ( - // ntriangles = 2*nSubs ) - void wireOrthorhomboid(double sizex = 1.0, double sizey = 1.0, double sizez = 1.0, double ox = 0.0, double oy = 0.0, - double oz = 0.0); - // Plot basic axes object - void axes(double axisLength); - // Plot basic coloured axes object - void colouredAxes(double axisLength); -}; diff --git a/src/gui/render/primitiveAssembly.cpp b/src/gui/render/primitiveAssembly.cpp deleted file mode 100644 index 8e944e0ef5..0000000000 --- a/src/gui/render/primitiveAssembly.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/primitiveAssembly.h" -#include - -PrimitiveAssembly::PrimitiveAssembly() {} - -PrimitiveAssembly::~PrimitiveAssembly() {} - -// Clear all existing primitives -void PrimitiveAssembly::clear() -{ - // Return all objects to their - assembly_.clear(); -} - -// Add Primitive to the assembly -void PrimitiveAssembly::add(Primitive *primitive, const Matrix4 &matrix) -{ - UncolouredPrimitiveInfo &pi = uncolouredPrimitiveFactory_.emplace_back(); - pi = UncolouredPrimitiveInfo(primitive, matrix); - assembly_.push_back(&pi); -} - -// Add Primitive with colour to the assembly -void PrimitiveAssembly::add(Primitive *primitive, const Matrix4 &matrix, const std::array &rgba) -{ - ColouredPrimitiveInfo &pi = colouredPrimitiveFactory_.emplace_back(); - pi = ColouredPrimitiveInfo(primitive, matrix, rgba[0], rgba[1], rgba[2], rgba[3]); - assembly_.push_back(&pi); -} - -// Add Primitive with colour to the assembly -void PrimitiveAssembly::add(Primitive *primitive, const Matrix4 &matrix, GLfloat r, GLfloat g, GLfloat b, GLfloat a) -{ - ColouredPrimitiveInfo &pi = colouredPrimitiveFactory_.emplace_back(); - pi = ColouredPrimitiveInfo(primitive, matrix, r, g, b, a); - assembly_.push_back(&pi); -} - -// Add styling information -void PrimitiveAssembly::add(bool lighting, GLenum polygonFillMode) -{ - StylePrimitiveInfo &pi = stylePrimitiveFactory_.emplace_back(); - pi = StylePrimitiveInfo(lighting, polygonFillMode); - assembly_.push_back(&pi); -} - -// Add line styling information -void PrimitiveAssembly::add(LineStyle lineStyle) -{ - LineStylePrimitiveInfo &pi = lineStylePrimitiveFactory_.emplace_back(); - pi = LineStylePrimitiveInfo(lineStyle); - assembly_.push_back(&pi); -} - -/* - * Object - */ - -// Create cylinder bond between supplied atoms in specified assembly -void PrimitiveAssembly::createCylinderBond(Primitive *bondPrimitive, Vector3 rI, Vector3 rJ, Vector3 vij, - const std::array &colI, const std::array &colJ, - bool drawFromAtoms, double radialScaling) -{ - Matrix4 A; - auto unit = vij; - const auto mag = unit.magAndNormalise(); - - // Create rotation matrix for Bond - A.setColumn(2, unit.x, unit.y, unit.z, 0.0); - A.setColumn(0, unit.orthogonal(), 0.0); - A.setColumn(1, unit * A.columnAsVec3(0), 0.0); - A.columnMultiply(2, 0.5 * mag); - A.applyScaling(radialScaling, radialScaling, 1.0); - - // If drawing from individual Atoms, locate on each Atom and draw the bond halves from there. If not, locate to the bond - // centre. - if (drawFromAtoms) - { - // Render half of Bond in colour of Atom j - A.setTranslation(rI); - add(bondPrimitive, A, colJ); - - // Render half of Bond in colour of Atom i - A.setTranslation(rJ); - A.columnMultiply(2, -1.0); - add(bondPrimitive, A, colI); - } - else - { - A.setTranslation(rI + vij * 0.5); - - // Render half of Bond in colour of Atom j - add(bondPrimitive, A, colJ); - - // Render half of Bond in colour of Atom i - A.columnMultiply(2, -1.0); - add(bondPrimitive, A, colI); - } -} - -/* - * GL - */ - -// Send to OpenGL (i.e. render) -void PrimitiveAssembly::sendToGL(double pixelScaling) -{ - for (auto *prim : assembly_) - prim->sendToGL(pixelScaling); -} diff --git a/src/gui/render/primitiveAssembly.h b/src/gui/render/primitiveAssembly.h deleted file mode 100644 index 464db2acfe..0000000000 --- a/src/gui/render/primitiveAssembly.h +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/primitiveInfo.h" -#include -#include - -// Rendering Primitive List -class PrimitiveAssembly -{ - public: - PrimitiveAssembly(); - ~PrimitiveAssembly(); - - /* - * Object Factories - */ - private: - // Factories for all PrimitiveInfo-derived classes - std::deque uncolouredPrimitiveFactory_; - std::deque colouredPrimitiveFactory_; - std::deque stylePrimitiveFactory_; - std::deque lineStylePrimitiveFactory_; - - /* - * Assembly - */ - private: - // Array of PrimitiveInfo pointers that constitute our assembly - std::vector assembly_; - - public: - // Clear existing data - void clear(); - // Add Primitive to the assembly - void add(Primitive *primitive, const Matrix4 &matrix); - // Add Primitive with colour to the assembly - void add(Primitive *primitive, const Matrix4 &matrix, const std::array &rgba); - // Add Primitive with colour to the assembly - void add(Primitive *primitive, const Matrix4 &matrix, GLfloat r, GLfloat g, GLfloat b, GLfloat a); - // Add styling information - void add(bool lighting, GLenum polygonFillMode); - // Add line styling information - void add(LineStyle lineStyle); - - /* - * Objects - */ - public: - // Create cylinder bond between supplied atoms in specified assembly - void createCylinderBond(Primitive *bondPrimitive, Vector3 rI, Vector3 rJ, Vector3 vij, const std::array &colI, - const std::array &colJ, bool drawFromAtoms, double radialScaling); - - /* - * GL - */ - public: - // Send to OpenGL (i.e. render) - void sendToGL(double pixelScaling); -}; diff --git a/src/gui/render/primitiveInfo.cpp b/src/gui/render/primitiveInfo.cpp deleted file mode 100644 index c8af71c542..0000000000 --- a/src/gui/render/primitiveInfo.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/primitiveInfo.h" -#include "gui/render/primitive.h" - -/* - * PrimitiveInfo - */ - -PrimitiveInfo::PrimitiveInfo() {} - -PrimitiveInfo::~PrimitiveInfo() {} - -/* - * UncolouredPrimitiveInfo - */ - -UncolouredPrimitiveInfo::UncolouredPrimitiveInfo(Primitive *prim, Matrix4 transform) : primitive_(prim), transform_(transform) -{ -} - -UncolouredPrimitiveInfo::~UncolouredPrimitiveInfo() {} - -// Expose contained info to GL -void UncolouredPrimitiveInfo::sendToGL(double pixelScaling) -{ - // Render Primitive if one is present - if (primitive_) - { - glPushMatrix(); - glMultMatrixd(transform_.matrix()); - primitive_->sendToGL(); - glPopMatrix(); - } -} - -/* - * ColouredPrimitiveInfo - */ - -ColouredPrimitiveInfo::ColouredPrimitiveInfo(Primitive *prim, Matrix4 transform, GLfloat r, GLfloat g, GLfloat b, GLfloat a) - : primitive_(prim), transform_(transform) -{ - colour_[0] = r; - colour_[1] = g; - colour_[2] = b; - colour_[3] = a; -} - -ColouredPrimitiveInfo::~ColouredPrimitiveInfo() {} - -// Expose contained info to GL -void ColouredPrimitiveInfo::sendToGL(double pixelScaling) -{ - // Apply colour - glColor4fv(colour_); - - // Render Primitive if one is present - if (primitive_) - { - glPushMatrix(); - glMultMatrixd(transform_.matrix()); - primitive_->sendToGL(); - glPopMatrix(); - } -} - -/* - * StylePrimitiveInfo - */ - -StylePrimitiveInfo::StylePrimitiveInfo(bool lighting, GLenum polygonFillMode) : lighting_(lighting), fillMode_(polygonFillMode) -{ -} - -StylePrimitiveInfo::~StylePrimitiveInfo() {} - -// Expose contained info to GL -void StylePrimitiveInfo::sendToGL(double pixelScaling) -{ - // Enable / disable lighting - if (lighting_) - glEnable(GL_LIGHTING); - else - glDisable(GL_LIGHTING); - - // Set polygon rendering mode and smoothing - glPolygonMode(GL_FRONT_AND_BACK, fillMode_); - if (fillMode_ == GL_POINT) - glEnable(GL_POINT_SMOOTH); - else - glDisable(GL_POINT_SMOOTH); - if (fillMode_ == GL_LINE) - glEnable(GL_LINE_SMOOTH); - else - glDisable(GL_LINE_SMOOTH); -} - -/* - * LineStylePrimitiveInfo - */ - -LineStylePrimitiveInfo::LineStylePrimitiveInfo(LineStyle style) : lineStyle_(style) {} - -LineStylePrimitiveInfo::~LineStylePrimitiveInfo() {} - -// Expose contained info to GL -void LineStylePrimitiveInfo::sendToGL(double pixelScaling) { lineStyle_.sendToGL(pixelScaling); } diff --git a/src/gui/render/primitiveInfo.h b/src/gui/render/primitiveInfo.h deleted file mode 100644 index b4447fe96d..0000000000 --- a/src/gui/render/primitiveInfo.h +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/lineStyle.h" -#include "math/matrix4.h" - -// Forward Declarations -class Primitive; - -// Primitive Info -class PrimitiveInfo -{ - public: - PrimitiveInfo(); - virtual ~PrimitiveInfo(); - - /* - * GL - */ - public: - // Expose contained info to GL - virtual void sendToGL(double pixelScaling) = 0; -}; - -/* - * Derived Classes - */ - -// Primitive Only -class UncolouredPrimitiveInfo : public PrimitiveInfo -{ - public: - UncolouredPrimitiveInfo(Primitive *prim = nullptr, Matrix4 transform = Matrix4()); - ~UncolouredPrimitiveInfo(); - - private: - // Target primitive - Primitive *primitive_; - // Transformation to apply before rendering Primitive - Matrix4 transform_; - - public: - // Expose contained info to GL - void sendToGL(double pixelScaling); -}; - -// Primitive and Colour -class ColouredPrimitiveInfo : public PrimitiveInfo -{ - public: - ColouredPrimitiveInfo(Primitive *prim = nullptr, Matrix4 transform = Matrix4(), GLfloat r = 0.0, GLfloat g = 0.0, - GLfloat b = 0.0, GLfloat a = 0.0); - ~ColouredPrimitiveInfo(); - - private: - // Target primitive - Primitive *primitive_; - // Transformation to apply before rendering Primitive - Matrix4 transform_; - // Colour of Primitive - GLfloat colour_[4]; - - public: - // Expose contained info to GL - void sendToGL(double pixelScaling); -}; - -// Style Information -class StylePrimitiveInfo : public PrimitiveInfo -{ - public: - StylePrimitiveInfo(bool lighting = true, GLenum polygonFillMode = GL_FILL); - ~StylePrimitiveInfo(); - - private: - // Whether lighting is enabled - bool lighting_; - // Polygon fill mode - GLenum fillMode_; - - public: - // Expose contained info to GL - void sendToGL(double pixelScaling); -}; - -// Line Style Information -class LineStylePrimitiveInfo : public PrimitiveInfo -{ - public: - LineStylePrimitiveInfo(LineStyle style = LineStyle()); - ~LineStylePrimitiveInfo(); - - private: - // Line styling to apply - LineStyle lineStyle_; - - public: - // Expose contained info to GL - void sendToGL(double pixelScaling); -}; diff --git a/src/gui/render/primitiveInstance.cpp b/src/gui/render/primitiveInstance.cpp deleted file mode 100644 index d13c681cf0..0000000000 --- a/src/gui/render/primitiveInstance.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/primitiveInstance.h" - -// Static members -PrimitiveInstance::InstanceType PrimitiveInstance::globalInstanceType_ = PrimitiveInstance::VBOInstance; - -PrimitiveInstance::PrimitiveInstance() -{ - // Private variables - context_ = nullptr; - type_ = PrimitiveInstance::ListInstance; - listObject_ = 0; - vboVertexObject_ = 0; - vboIndexObject_ = 0; -} - -// Return global instance type to use -PrimitiveInstance::InstanceType PrimitiveInstance::globalInstanceType() { return globalInstanceType_; } - -// Set global instance type to use -void PrimitiveInstance::setGlobalInstanceType(PrimitiveInstance::InstanceType instanceType) -{ - globalInstanceType_ = instanceType; -} - -// Return context to which primitive instance is associated -const QOpenGLContext *PrimitiveInstance::context() { return context_; } - -// Return type of instance -PrimitiveInstance::InstanceType PrimitiveInstance::type() const { return type_; } - -// Set display list data -void PrimitiveInstance::setDisplayList(const QOpenGLContext *context, GLuint listObject) -{ - context_ = context; - type_ = PrimitiveInstance::ListInstance; - listObject_ = listObject; -} - -// Set vbo object data -void PrimitiveInstance::setVBO(const QOpenGLContext *context, GLuint vertexObject, GLuint indexObject) -{ - context_ = context; - type_ = PrimitiveInstance::VBOInstance; - vboVertexObject_ = vertexObject; - vboIndexObject_ = indexObject; -} - -// Return display list object for instance -GLuint PrimitiveInstance::listObject() const { return listObject_; } - -// Return VBO ID of vertex array for instance -GLuint PrimitiveInstance::vboVertexObject() const { return vboVertexObject_; } - -// Return VBO ID of index array for instance -GLuint PrimitiveInstance::vboIndexObject() const { return vboIndexObject_; } diff --git a/src/gui/render/primitiveInstance.h b/src/gui/render/primitiveInstance.h deleted file mode 100644 index 91e99c4b4c..0000000000 --- a/src/gui/render/primitiveInstance.h +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include - -// Forward Declarations -class QOpenGLContext; -class GLExtensions; - -// Primitive Instance -class PrimitiveInstance -{ - public: - PrimitiveInstance(); - // Instance Type - enum InstanceType - { - NoInstances, - ListInstance, - VBOInstance - }; - - private: - // Global instance type to use - static PrimitiveInstance::InstanceType globalInstanceType_; - // Context to which primitive instance is associated - const QOpenGLContext *context_; - // GL extension function pointers for this context - GLExtensions *extensions_; - // Type of instance - InstanceType type_; - // List ID of instance (if using display lists) - GLuint listObject_; - // VBO ID of vertex array (if using VBOs) - GLuint vboVertexObject_; - // VBO ID of index array (if using indexed VBOs) - GLuint vboIndexObject_; - - public: - // Return global instance type to use - static PrimitiveInstance::InstanceType globalInstanceType(); - // Set global instance type to use - static void setGlobalInstanceType(PrimitiveInstance::InstanceType instanceType); - // Return context to which primitive instance is associated - const QOpenGLContext *context(); - // Return GL extensions - const GLExtensions *extensions() const; - // Set display list data - void setDisplayList(const QOpenGLContext *context, GLuint listObject); - // Set vbo object data - void setVBO(const QOpenGLContext *context, GLuint vertexObject, GLuint indexObject); - // Return type of instance - InstanceType type() const; - // Return display list object for instance - GLuint listObject() const; - // Return VBO ID of vertex array for instance - GLuint vboVertexObject() const; - // Return VBO ID of index array for instance - GLuint vboIndexObject() const; -}; diff --git a/src/gui/render/primitiveList.cpp b/src/gui/render/primitiveList.cpp deleted file mode 100644 index 472431ed62..0000000000 --- a/src/gui/render/primitiveList.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/primitiveList.h" - -PrimitiveList::PrimitiveList() {} - -PrimitiveList::~PrimitiveList() {} - -// Clear all existing Primitives -void PrimitiveList::clear() { primitives_.clear(); } - -// Forget all data, leaving arrays intact -void PrimitiveList::forgetAll() -{ - for (auto &prim : primitives_) - prim->forgetAll(); -} - -// Resize list so it is large enough to accommodate specified number of Primitives -void PrimitiveList::reinitialise(int newSize, GLenum type, bool colourData) -{ - // Add enough primitives to match the new size - primitives_.clear(); - primitives_.reserve(newSize); - std::generate_n(std::back_inserter(primitives_), newSize, [] { return std::make_unique(); }); - - // Loop over all current primitives and set information - for (auto &prim : primitives_) - prim->initialise(type, colourData); -} - -// Add a new Primitive to the end of the list -Primitive *PrimitiveList::add(GLenum type, bool colourData) -{ - auto *newPrim = primitives_.emplace_back(std::make_unique()).get(); - newPrim->initialise(type, colourData); - - return newPrim; -} - -// Register an existing Primitive with the list -void PrimitiveList::add(Primitive *primitive) { primitives_.emplace_back(primitive); } - -// Return number of primitives in the list -int PrimitiveList::nPrimitives() const { return primitives_.size(); } - -// Remove specified Primitive -void PrimitiveList::remove(Primitive *primitive) -{ - primitives_.erase( - std::remove_if(primitives_.begin(), primitives_.end(), [primitive](auto &prim) { return prim.get() == primitive; }), - primitives_.end()); -} - -// Return total number of defined vertices -int PrimitiveList::nDefinedVertices() -{ - auto totalVertices = 0; - for (auto &prim : primitives_) - totalVertices += prim->nDefinedVertices(); - return totalVertices; -} - -// Return total number of defined indices -int PrimitiveList::nDefinedIndices() -{ - auto totalIndices = 0; - for (auto &prim : primitives_) - totalIndices += prim->nDefinedIndices(); - return totalIndices; -} - -// Push instance layer -void PrimitiveList::pushInstance(const QOpenGLContext *context) -{ - for (auto &prim : primitives_) - prim->pushInstance(context); -} - -// Pop topmost instance layer -void PrimitiveList::popInstance(const QOpenGLContext *context) -{ - for (auto &prim : primitives_) - prim->popInstance(context); -} - -// Return number of instances of topmost primitive -int PrimitiveList::nInstances() -{ - if (primitives_.empty()) - return 0; - else - return primitives_.front()->nInstances(); -} - -// Send to OpenGL (i.e. render) -void PrimitiveList::sendToGL() -{ - for (auto &prim : primitives_) - prim->sendToGL(); -} - -/* - * Operators - */ - -Primitive *PrimitiveList::operator[](int index) { return primitives_[index].get(); } diff --git a/src/gui/render/primitiveList.h b/src/gui/render/primitiveList.h deleted file mode 100644 index 9a840a57cf..0000000000 --- a/src/gui/render/primitiveList.h +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/primitive.h" -#include - -// Forward Declarations -class QOpenGLContext; - -// Rendering Primitive List -class PrimitiveList -{ - public: - PrimitiveList(); - ~PrimitiveList(); - - /* - * Data - */ - private: - // List of Primitives owned and managed by this list - std::vector> primitives_; - - public: - // Clear all existing Primitives - void clear(); - // Forget all data, leaving arrays intact - void forgetAll(); - // Reinitialise list so it is large enough to accomodate specified number of Primitives - void reinitialise(int newSize, GLenum type, bool colourData); - // Add a new Primitive to the end of the list - Primitive *add(GLenum type = GL_LINES, bool colourData = false); - // Register an existing Primitive with the list - void add(Primitive *primitive); - // Return number of primitives in the list - int nPrimitives() const; - // Remove specified Primitive - void remove(Primitive *primitive); - // Return total number of defined vertices - int nDefinedVertices(); - // Return total number of defined indices - int nDefinedIndices(); - // Push instance layer - void pushInstance(const QOpenGLContext *context); - // Pop topmost instance layer - void popInstance(const QOpenGLContext *context); - // Return number of instances of topmost primitive - int nInstances(); - // Send to OpenGL (i.e. render) - void sendToGL(); - - /* - * Operators - */ - public: - Primitive *operator[](int index); -}; diff --git a/src/gui/render/renderable.cpp b/src/gui/render/renderable.cpp deleted file mode 100644 index 172639e8e0..0000000000 --- a/src/gui/render/renderable.cpp +++ /dev/null @@ -1,352 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/renderable.h" -#include "base/sysFunc.h" -#include "gui/render/renderableGroupManager.h" -#include "gui/render/view.h" - -// Static Singletons -bool Renderable::sourceDataAccessEnabled_ = true; -std::vector Renderable::instances_; - -// Return enum options for RenderableType -EnumOptions Renderable::renderableTypes() -{ - return EnumOptions("ErrorType", {{Renderable::ConfigurationRenderable, "Configuration"}, - {Renderable::Data1DRenderable, "Data1D"}, - {Renderable::Data2DRenderable, "Data2D"}, - {Renderable::Data3DRenderable, "Data3D"}, - {Renderable::SpeciesRenderable, "Species"}, - {Renderable::SpeciesSiteRenderable, "SpeciesSite"}}); -} - -Renderable::Renderable(Renderable::RenderableType type, std::string_view tag) -{ - // Instance - instances_.push_back(this); - - // Identity - type_ = type; - name_ = "New Renderable"; - - // Data tag - tag_ = tag; - - // Group - group_ = std::nullopt; - - // Transform - valuesTransformDataVersion_ = -1; - limitsMin_.zero(); - limitsMax_.set(10.0, 10.0, 10.0); - positiveLimitsMin_.set(0.1, 0.1, 0.1); - positiveLimitsMax_.set(10.0, 10.0, 10.0); - valuesMin_ = 0.0; - valuesMax_ = 10.0; - positiveValuesMin_ = 0.0; - positiveValuesMax_ = 10.0; - valuesTransform_.setEnabled(false); - valuesTransform_.setEquation("value"); - - // Rendering Versions - lastDataVersion_ = -1; - lastAxesVersion_ = -1; - lastStyleVersion_ = -1; - - // Display - visible_ = true; - styleVersion_ = 0; -} - -Renderable::~Renderable() -{ - auto it = std::find(instances_.begin(), instances_.end(), this); - instances_.erase(it); -} - -/* - * Identity - */ - -// Set name of Renderable -void Renderable::setName(std::string_view name) { name_ = name; } - -// Return name of Renderable -std::string_view Renderable::name() const { return name_; } - -// Return type of Renderable -Renderable::RenderableType Renderable::type() const { return type_; } - -/* - * Data - */ - -// Transform data values -void Renderable::transformValues() {} - -// Attempt to set the data source, searching the supplied list for the object -void Renderable::validateDataSource(const GenericList &sourceList) {} - -// Invalidate the current data source -void Renderable::invalidateDataSource() {} - -// Set whether access to source data is currently enabled -void Renderable::setSourceDataAccessEnabled(bool b) { sourceDataAccessEnabled_ = b; } - -// Return whether access to source data is currently enabled -bool Renderable::sourceDataAccessEnabled() { return sourceDataAccessEnabled_; } - -// Return identifying tag for source data object -std::string_view Renderable::tag() const { return tag_; } - -// Validate all renderables -void Renderable::validateAll(const GenericList &source) -{ - for (Renderable *rend : instances_) - rend->validateDataSource(source); -} - -// Invalidate renderable data for specified object tag -int Renderable::invalidate(std::string_view tag) -{ - auto count = 0; - for (Renderable *rend : instances_) - { - if (tag != rend->tag_) - continue; - - rend->invalidateDataSource(); - - ++count; - } - return count; -} - -// Invalidate all renderables -void Renderable::invalidateAll() -{ - for (Renderable *rend : instances_) - rend->invalidateDataSource(); -} - -// Return coordinate minima of all data (after value transform if enabled) -Vector3 Renderable::limitsMin() -{ - // Make sure transformed values are up to date - transformValues(); - - return limitsMin_; -} - -// Return coordinate maxima of all data (after value transform if enabled) -Vector3 Renderable::limitsMax() -{ - // Make sure transformed values are up to date - transformValues(); - - return limitsMax_; -} - -// Return positive coordinate minima of all data (after value transform if enabled) -Vector3 Renderable::positiveLimitsMin() -{ - // Make sure transformed values are up to date - transformValues(); - - return positiveLimitsMin_; -} - -// Return positive coordinate maxima of all data (after value transform if enabled) -Vector3 Renderable::positiveLimitsMax() -{ - // Make sure transformed values are up to date - transformValues(); - - return positiveLimitsMax_; -} - -// Return minimum of transformed values -double Renderable::valuesMin() -{ - // Make sure transformed values are up to date - transformValues(); - - return valuesMin_; -} - -// Return maximum of transformed values -double Renderable::valuesMax() -{ - // Make sure transformed values are up to date - transformValues(); - - return valuesMax_; -} - -// Return minimum positive of transformed values -double Renderable::positiveValuesMin() -{ - // Make sure transformed values are up to date - transformValues(); - - return positiveValuesMin_; -} - -// Return maximum positive of transformed values -double Renderable::positiveValuesMax() -{ - // Make sure transformed values are up to date - transformValues(); - - return positiveValuesMax_; -} - -// Set values transform equation specified -void Renderable::setValuesTransformEquation(std::string_view transformEquation) -{ - valuesTransform_.setEquation(transformEquation); - - if (valuesTransform_.enabled()) - valuesTransformDataVersion_ = -1; -} - -// Return values transform equation -std::string_view Renderable::valuesTransformEquation() const { return valuesTransform_.text(); } - -// Return whether values transform equation is valid -bool Renderable::valuesTransformEquationValid() const { return valuesTransform_.valid(); } - -// Set whether values transform is enabled -void Renderable::setValuesTransformEnabled(bool enabled) -{ - valuesTransform_.setEnabled(enabled); - - valuesTransformDataVersion_ = -1; -} - -// Return whether values transform is enabled -bool Renderable::valuesTransformEnabled() const { return valuesTransform_.enabled(); } - -// Return data version at which values were last transformed -int Renderable::valuesTransformDataVersion() const { return valuesTransformDataVersion_; } - -// Calculate min/max y value over specified x range (if possible in the underlying data) -bool Renderable::yRangeOverX(double xMin, double xMax, double &yMin, double &yMax) { return false; } - -/* - * Group - */ - -// Set group that this Renderable is associated to -void Renderable::setGroup(RenderableGroup &group) { group_ = group; } - -// Remove the renderagle's group association -void Renderable::unSetGroup() { group_ = std::nullopt; } - -// Return group that this Renderable is associated to -OptionalReferenceWrapper Renderable::group() const { return group_; } - -/* - * Style - */ - -// Set whether Renderable is visible -void Renderable::setVisible(bool visible) { visible_ = visible; } - -// Return whether Renderable is visible -bool Renderable::isVisible() const -{ - // Group visibility overrides our own (*if* we are currently visible)... - return visible_ && (group_ ? group_->get().isVisible() : visible_); -} - -// Set basic colour -void Renderable::setColour(int r, int g, int b, int a) { colour_.setSingleColour(QColor(r, g, b, a)); } - -// Set basic colour -void Renderable::setColour(StockColours::StockColour stockColour) -{ - colour_.setSingleColour(StockColours::stockColour(stockColour)); -} - -// Return local colour definition for display -ColourDefinition &Renderable::colour() { return colour_; } - -const ColourDefinition &Renderable::colour() const { return colour_; } - -// Return line style -LineStyle &Renderable::lineStyle() { return lineStyle_; } - -// Return style version -int Renderable::styleVersion() const { return styleVersion_; } - -/* - * Rendering Primitives - */ - -// Create single Primitive, whose instances will be managed by the Renderable -Primitive *Renderable::createPrimitive(GLenum type, bool colourData) { return primitives_.add(type, colourData); } - -// Reinitialise managed Primitive list to the size specified -void Renderable::reinitialisePrimitives(int newSize, GLenum type, bool colourData) -{ - primitives_.reinitialise(newSize, type, colourData); -} - -// Return number of primitives managed by the Renderable -int Renderable::nPrimitives() const { return primitives_.nPrimitives(); } - -// Return nth Primitive managed by the Renderable -Primitive *Renderable::primitive(int n) { return primitives_[n]; } - -// Remove specified Primitive -void Renderable::removePrimitive(Primitive *primitive) { primitives_.remove(primitive); } - -// Update primitives and send to display -void Renderable::updateAndSendPrimitives(const View &view, bool forceUpdate, bool pushAndPop, const QOpenGLContext *context, - double pixelScaling) -{ - // If this Renderable is not visible, return now - if (!visible_) - return; - - // Grab axes for the View - const Axes &axes = view.axes(); - - // Grab copy of the relevant colour definition for this Renderable - const ColourDefinition &colourDefinition = colour(); - - // If the primitive is out of date, recreate it - if (forceUpdate || lastAxesVersion_ != axes.version() || lastDataVersion_ != dataVersion() || - valuesTransformDataVersion_ != dataVersion() || lastStyleVersion_ != styleVersion() || - !DissolveSys::sameString(lastColourDefinitionFingerprint_, - std::format("{}@{}", group_ ? group_->get().name() : "NoGroup", colourDefinition.version()), - true)) - { - // Recreate Primitives for the underlying data - recreatePrimitives(view, colourDefinition); - - // Pop old Primitive instance (if they exist) - if (primitives_.nInstances() != 0) - primitives_.popInstance(context); - } - - // If there are no current instances, or we are forcing a push/pop of an instance, push an instance here - if ((primitives_.nInstances() == 0) || pushAndPop) - primitives_.pushInstance(context); - - // Send to GL - sendToGL(pixelScaling); - - // Pop current instances if required - if (pushAndPop) - primitives_.popInstance(context); - - // Store version points for the up-to-date primitive - lastAxesVersion_ = axes.version(); - lastColourDefinitionFingerprint_ = - std::format("{}@{}", group_ ? group_->get().name() : "NoGroup", colourDefinition.version()); - lastDataVersion_ = dataVersion(); - lastStyleVersion_ = styleVersion(); -} diff --git a/src/gui/render/renderable.h b/src/gui/render/renderable.h deleted file mode 100644 index e9eb75d147..0000000000 --- a/src/gui/render/renderable.h +++ /dev/null @@ -1,216 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/colourDefinition.h" -#include "gui/render/lineStyle.h" -#include "gui/render/primitiveAssembly.h" -#include "gui/render/primitiveList.h" -#include "gui/stockColours.h" -#include "math/transformer.h" - -// Forward Declarations -class GenericList; -class RenderableGroup; -class View; - -class Renderable -{ - public: - // Renderable type - enum RenderableType - { - ConfigurationRenderable, - Data1DRenderable, - Data2DRenderable, - Data3DRenderable, - SpeciesRenderable, - SpeciesSiteRenderable, - nRenderableTypes - }; - // Return enum options for RenderableType - static EnumOptions renderableTypes(); - Renderable(RenderableType type, std::string_view tag); - virtual ~Renderable(); - - /* - * Instances - */ - private: - // List of all current renderables - static std::vector instances_; - - /* - * Identity - */ - protected: - // Name of Renderable - std::string name_; - // Type of Renderable - RenderableType type_; - - public: - // Set name of Renderable - void setName(std::string_view name); - // Return name of Renderable - std::string_view name() const; - // Return type of Renderable - RenderableType type() const; - - /* - * Data - */ - protected: - // Whether access to source data is currently enabled - static bool sourceDataAccessEnabled_; - // Identifying tag for source data object - std::string tag_; - // Equation transformer for values - Transformer valuesTransform_; - // Coordinate limits of all data (after value transform if enabled) - Vector3 limitsMin_, limitsMax_; - // Positive coordinate extrema of all data (after value transform if enabled) - Vector3 positiveLimitsMin_, positiveLimitsMax_; - // Extrema of values (after transform if enabled) - double valuesMin_, valuesMax_; - // Extreme positive lixmits of transformed values - double positiveValuesMin_, positiveValuesMax_; - // Data version at which values were last transformed - int valuesTransformDataVersion_; - - protected: - // Transform data values - virtual void transformValues(); - - public: - // Attempt to set the data source, searching the supplied list for the object - virtual void validateDataSource(const GenericList &sourceList); - // Invalidate the current data source - virtual void invalidateDataSource(); - // Set whether access to source data is currently enabled - static void setSourceDataAccessEnabled(bool b); - // Return whether access to source data is currently enabled - static bool sourceDataAccessEnabled(); - // Return identifying tag for source data object - std::string_view tag() const; - // Validate all renderables - static void validateAll(const GenericList &source); - // Invalidate renderable data for specified object tag - static int invalidate(std::string_view tag); - // Invalidate all renderables - static void invalidateAll(); - // Return version of data - virtual int dataVersion() = 0; - // Return coordinate minima of all data (after value transform if enabled) - Vector3 limitsMin(); - // Return coordinate maxima of all data (after value transform if enabled) - Vector3 limitsMax(); - // Return positive coordinate minima of all data (after value transform if enabled) - Vector3 positiveLimitsMin(); - // Return positive coordinate maxima of all data (after value transform if enabled) - Vector3 positiveLimitsMax(); - // Return minimum of transformed values - double valuesMin(); - // Return maximum of transformed values - double valuesMax(); - // Return minimum positive of transformed values - double positiveValuesMin(); - // Return maximum positive of transformed values - double positiveValuesMax(); - // Set values transform equation - void setValuesTransformEquation(std::string_view transformEquation); - // Return values transform equation - std::string_view valuesTransformEquation() const; - // Return whether the values transform equation is valid - bool valuesTransformEquationValid() const; - // Set whether values transform is enabled - void setValuesTransformEnabled(bool enabled); - // Return whether values transform is enabled - bool valuesTransformEnabled() const; - // Return data version at which values were last transformed - int valuesTransformDataVersion() const; - // Calculate min/max y value over specified x range (if possible in the underlying data) - virtual bool yRangeOverX(double xMin, double xMax, double &yMin, double &yMax); - - /* - * Group - */ - protected: - // Group that this Renderable is associated to (if any) - OptionalReferenceWrapper group_; - - public: - // Set group that this Renderable is associated to - void setGroup(RenderableGroup &group); - // Remove the renderagle's group association - void unSetGroup(); - // Return group that this Renderable is associated to - OptionalReferenceWrapper group() const; - - /* - * Basic Style - */ - protected: - // Whether Renderable is visible - bool visible_; - // Colour definition - ColourDefinition colour_; - // Line style - LineStyle lineStyle_; - // Style version (relative to data version) - int styleVersion_; - - public: - // Set whether Renderable is visible - void setVisible(bool visible); - // Return whether Renderable is visible - bool isVisible() const; - // Set basic colour - void setColour(int r, int g, int b, int a = 255); - // Set basic colour - void setColour(StockColours::StockColour stockColour); - // Return local colour definition for display - ColourDefinition &colour(); - const ColourDefinition &colour() const; - // Return line style - LineStyle &lineStyle(); - // Return style version - int styleVersion() const; - - /* - * Rendering Primitives - */ - private: - // Primitives instance-managed by the Renderable - PrimitiveList primitives_; - // Data version at which bespoke primitives / assembled list were last created - int lastDataVersion_; - // ColourDefinition fingerprint at which primitives were last created - std::string lastColourDefinitionFingerprint_; - // Axes version at which primitives were last created - int lastAxesVersion_; - // Style version at which primitives were last created - int lastStyleVersion_; - - protected: - // Create single Primitive, whose instances will be managed by the Renderable - Primitive *createPrimitive(GLenum type = GL_LINES, bool colourData = false); - // Reinitialise managed Primitive list to the size specified - void reinitialisePrimitives(int newSize, GLenum type, bool colourData); - // Return number of primitives managed by the Renderable - int nPrimitives() const; - // Return nth Primitive managed by the Renderable - Primitive *primitive(int n); - // Remove specified Primitive - void removePrimitive(Primitive *primitive); - // Recreate necessary primitives / primitive assemblies for the data - virtual void recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) = 0; - // Send primitives for rendering - virtual const void sendToGL(double pixelScaling) = 0; - - public: - // Update primitives and send to display - void updateAndSendPrimitives(const View &view, bool forceUpdate, bool pushAndPop, const QOpenGLContext *context, - double pixelScaling); -}; diff --git a/src/gui/render/renderableConfiguration.cpp b/src/gui/render/renderableConfiguration.cpp deleted file mode 100644 index d31f7c56af..0000000000 --- a/src/gui/render/renderableConfiguration.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/renderableConfiguration.h" -#include "classes/box.h" -#include "classes/speciesAtom.h" -#include "classes/speciesBond.h" -#include "data/elementColours.h" -#include "gui/render/renderableGroupManager.h" -#include "gui/render/view.h" - -RenderableConfiguration::RenderableConfiguration(const Configuration *source) - : Renderable(Renderable::ConfigurationRenderable, "UNUSED"), source_(source) -{ - // Set defaults - displayStyle_ = LinesStyle; - linesAtomRadius_ = 0.05; - spheresAtomRadius_ = 0.3; - spheresBondRadius_ = 0.1; - - // Create basic primitives - atomPrimitive_ = createPrimitive(GL_TRIANGLES, false); - atomPrimitive_->sphere(1.0, 8, 10); - bondPrimitive_ = createPrimitive(GL_TRIANGLES, false); - bondPrimitive_ = createPrimitive(GL_TRIANGLES, false); - bondPrimitive_->cylinder(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1, 8); - unitCellPrimitive_ = createPrimitive(GL_LINES, false); - unitCellPrimitive_->wireOrthorhomboid(1.0, 1.0, 1.0, 0.5, 0.5, 0.5); - lineConfigurationPrimitive_ = createPrimitive(GL_LINES, true); - lineInteractionPrimitive_ = createPrimitive(GL_LINES, true); - lineInteractionPrimitive_->setNoInstances(); -} - -RenderableConfiguration::~RenderableConfiguration() {} - -/* - * Data - */ - -// Return version of data -int RenderableConfiguration::dataVersion() { return (source_ ? source_->version() : -99); } - -/* - * Transform / Limits - */ - -// Transform data according to current settings -void RenderableConfiguration::transformValues() -{ - if (!source_) - return; - - // If the transformed data are already up-to-date, no need to do anything - if (valuesTransformDataVersion_ == dataVersion()) - return; - - // Minimum corresponds to lower left corner of the box at {0,0,0} - limitsMin_.zero(); - - // Transform extreme upper right corner from unit to real space to get maxima - limitsMax_ = source_->box().getReal(Vector3(1.0, 1.0, 1.0)); - - positiveLimitsMin_ = limitsMin_; - positiveLimitsMax_ = limitsMax_; - - // Update the transformed data 'version' - valuesTransformDataVersion_ = dataVersion(); -} - -/* - * Rendering Primitives - */ - -// Recreate necessary primitives / primitive assemblies for the data -void RenderableConfiguration::recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) -{ - Matrix4 A; - const std::array colourBlack = {0.0, 0.0, 0.0, 1.0}; - Vector3 ri, rj; - - // Check data source - if (!source_) - return; - - // Clear existing data - lineConfigurationPrimitive_->forgetAll(); - configurationAssembly_.clear(); - unitCellAssembly_.clear(); - - // Grab the Configuration's Box and CellArray - const auto &box = source_->box(); - - // Render according to the current displayStyle - if (displayStyle_ == LinesStyle) - { - // Set basic styling and content for assemblies - configurationAssembly_.add(false, GL_LINE); - configurationAssembly_.add(lineConfigurationPrimitive_, A); - - // Draw Atoms - for (const auto &i : source_->atoms()) - { - // If the atom has no bonds draw it as a 'cross' - if (i.speciesAtom()->bonds().size() == 0) - { - const auto r = i.r(); - auto &colour = ElementColours::colour(i.speciesAtom()->Z()); - - lineConfigurationPrimitive_->line(r.x - linesAtomRadius_, r.y, r.z, r.x + linesAtomRadius_, r.y, r.z, - colour.data()); - lineConfigurationPrimitive_->line(r.x, r.y - linesAtomRadius_, r.z, r.x, r.y + linesAtomRadius_, r.z, - colour.data()); - lineConfigurationPrimitive_->line(r.x, r.y, r.z - linesAtomRadius_, r.x, r.y, r.z + linesAtomRadius_, - colour.data()); - } - else - { - // Draw all bonds from this atom - for (const auto *bond : i.speciesAtom()->bonds()) - { - // Blindly get partner Atom 'j' - don't check if it is the true partner, only if it is - // the same as 'i' (in which case we skip it, ensuring we draw every bond only once) - auto partner = i.molecule()->atom(bond->j()->index()); - if (&i == partner) - continue; - - ri = i.r(); - rj = partner->r(); - - // Determine half delta i-j for bond - const auto dij = - (source_->cells().minimumImageRequired(*i.cell(), *partner->cell()) ? box.minimumVector(ri, rj) - : rj - ri) * - 0.5; - - // Draw bond halves - lineConfigurationPrimitive_->line(ri.x, ri.y, ri.z, ri.x + dij.x, ri.y + dij.y, ri.z + dij.z, - ElementColours::colour(bond->i()->Z()).data()); - lineConfigurationPrimitive_->line(rj.x, rj.y, rj.z, rj.x - dij.x, rj.y - dij.y, rj.z - dij.z, - ElementColours::colour(bond->j()->Z()).data()); - } - } - } - } - else if (displayStyle_ == SpheresStyle) - { - // Set basic styling for assemblies - configurationAssembly_.add(true, GL_FILL); - - // Draw Atoms - for (const auto &i : source_->atoms()) - { - A.setIdentity(); - A.setTranslation(i.r()); - A.applyScaling(spheresAtomRadius_); - - // The atom itself - configurationAssembly_.add(atomPrimitive_, A, ElementColours::colour(i.speciesAtom()->Z())); - - // Bonds from this atom - for (const auto *bond : i.speciesAtom()->bonds()) - { - // Blindly get partner Atom 'j' - don't check if it is the true partner, only if it is the same - // as 'i' (in which case we skip it, ensuring we draw every bond only once) - auto partner = i.molecule()->atom(bond->j()->index()); - if (&i == partner) - continue; - - if (source_->cells().minimumImageRequired(*i.cell(), *partner->cell())) - configurationAssembly_.createCylinderBond( - bondPrimitive_, i.r(), partner->r(), box.minimumVector(i.r(), partner->r()), - ElementColours::colour(i.speciesAtom()->Z()), ElementColours::colour(partner->speciesAtom()->Z()), true, - spheresBondRadius_); - else - configurationAssembly_.createCylinderBond( - bondPrimitive_, i.r(), partner->r(), partner->r() - i.r(), ElementColours::colour(i.speciesAtom()->Z()), - ElementColours::colour(partner->speciesAtom()->Z()), false, spheresBondRadius_); - } - } - } - - // Add unit cell - A.setIdentity(); - A = source_->box().axes(); - unitCellAssembly_.add(unitCellPrimitive_, A, colourBlack); -} - -// Send primitives for rendering -const void RenderableConfiguration::sendToGL(const double pixelScaling) -{ - // Set appropriate lighting for the configuration and interaction assemblies - if (displayStyle_ == LinesStyle) - glDisable(GL_LIGHTING); - else - glEnable(GL_LIGHTING); - configurationAssembly_.sendToGL(pixelScaling); - interactionAssembly_.sendToGL(pixelScaling); - - // Draw unit cell - glDisable(GL_LIGHTING); - unitCellAssembly_.sendToGL(pixelScaling); -} - -/* - * Style - */ - -// Return EnumOptions for ConfigurationDisplayStyle -EnumOptions RenderableConfiguration::configurationDisplayStyles() -{ - return EnumOptions( - "ConfigurationDisplayStyle", - {{RenderableConfiguration::LinesStyle, "Lines"}, {RenderableConfiguration::SpheresStyle, "Spheres"}}); -} - -// Set display style for renderable -void RenderableConfiguration::setDisplayStyle(ConfigurationDisplayStyle displayStyle) -{ - displayStyle_ = displayStyle; - - ++styleVersion_; -} - -// Return display style for the renderable -RenderableConfiguration::ConfigurationDisplayStyle RenderableConfiguration::displayStyle() const { return displayStyle_; } diff --git a/src/gui/render/renderableConfiguration.h b/src/gui/render/renderableConfiguration.h deleted file mode 100644 index e7419778ad..0000000000 --- a/src/gui/render/renderableConfiguration.h +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "classes/configuration.h" -#include "gui/render/renderable.h" - -// Forward Declarations -class Axes; - -// Renderable for Configuration -class RenderableConfiguration : public Renderable -{ - public: - RenderableConfiguration(const Configuration *source); - ~RenderableConfiguration(); - - /* - * Data - */ - private: - // Source data - const Configuration *source_; - - public: - // Return version of data - int dataVersion() override; - - /* - * Transform / Limits - */ - protected: - // Transform data according to current settings - void transformValues() override; - - /* - * Rendering Primitives - */ - private: - // Basic primitives - Primitive *atomPrimitive_, *unitCellPrimitive_, *bondPrimitive_; - // Main primitives - Primitive *lineConfigurationPrimitive_, *lineInteractionPrimitive_; - // Main assemblies - PrimitiveAssembly configurationAssembly_, interactionAssembly_, unitCellAssembly_; - - protected: - // Recreate necessary primitives / primitive assemblies for the data - void recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) override; - // Send primitives for rendering - const void sendToGL(double pixelScaling) override; - - /* - * Style - */ - public: - // Display Styles enum - enum ConfigurationDisplayStyle - { - LinesStyle, - SpheresStyle, - nConfigurationDisplayStyles - }; - // Return EnumOptions for ConfigurationDisplayStyle - static EnumOptions configurationDisplayStyles(); - - private: - // Display style for the renderable - ConfigurationDisplayStyle displayStyle_; - // Radius of free (unbound) atoms when drawing with lines - double linesAtomRadius_; - // Radius of atoms when drawing with spheres - double spheresAtomRadius_; - // Radius of bonds when drawing with spheres - double spheresBondRadius_; - - public: - // Set display style for renderable - void setDisplayStyle(ConfigurationDisplayStyle displayStyle); - // Return display style for the renderable - ConfigurationDisplayStyle displayStyle() const; -}; diff --git a/src/gui/render/renderableData1D.cpp b/src/gui/render/renderableData1D.cpp deleted file mode 100644 index 38c27b1cad..0000000000 --- a/src/gui/render/renderableData1D.cpp +++ /dev/null @@ -1,293 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/renderableData1D.h" -#include "gui/render/renderableGroupManager.h" -#include "gui/render/view.h" -#include "math/sampledData1D.h" - -RenderableData1D::RenderableData1D(const Data1DBase &source) - : Renderable(Renderable::Data1DRenderable, ""), source_(source), displayStyle_(LinesStyle) -{ - dataPrimitive_ = createPrimitive(); -} - -RenderableData1D::RenderableData1D(std::string_view tag) - : Renderable(Renderable::Data1DRenderable, tag), displayStyle_(LinesStyle) -{ - dataPrimitive_ = createPrimitive(); -} - -/* - * Data - */ - -// Return source data -OptionalReferenceWrapper RenderableData1D::source() const { return source_; } - -// Attempt to set the data source, searching the supplied list for the object -void RenderableData1D::validateDataSource(const GenericList &sourceList) -{ - // Don't try to access source_ if we are not currently permitted to do so - if (!sourceDataAccessEnabled_) - return; - - if (source_) - return; - - // TODO DISSOLVE2 - // source_ = sourceList.searchBase(tag_); -} - -// Invalidate the current data source -void RenderableData1D::invalidateDataSource() { source_ = std::nullopt; } - -// Return version of data -int RenderableData1D::dataVersion() { return (source_ ? source_->get().version() : -99); } - -/* - * Transform / Limits - */ - -// Transform data according to current settings -void RenderableData1D::transformValues() -{ - // If the transformed data are already up-to-date, no need to do anything - if (valuesTransformDataVersion_ == dataVersion()) - return; - - // Copy original data and transform now. We do this even if the transformers are disabled, since they may have - // previously been active - if (!source_) - transformedData_.clear(); - else - transformedData_ = source_->get(); - valuesTransform_.transformValues(transformedData_); - - limitsMin_ = 0.0; - limitsMax_ = 0.0; - positiveLimitsMin_.set(-1.0, -1.0, 0.1); - positiveLimitsMax_.set(-1.0, -1.0, 1.0); - valuesMin_ = 0.0; - valuesMax_ = 0.0; - positiveValuesMin_ = -1.0; - positiveValuesMax_ = -1.0; - - // Set initial limits if we can - if (transformedData_.nValues() > 0) - { - valuesMin_ = transformedData_.minValue(); - valuesMax_ = transformedData_.maxValue(); - limitsMin_.set(transformedData_.xAxis().front(), valuesMin_, 0.0); - limitsMax_.set(transformedData_.xAxis().back(), valuesMax_, 0.0); - } - - // Now determine minimum positive limits - loop over points in data, searching for first positive, non-zero value - for (auto n = 0; n < transformedData_.nValues(); ++n) - { - // X - if (transformedData_.xAxis(n) > 0.0) - { - if (positiveLimitsMin_.x < 0.0) - positiveLimitsMin_.x = transformedData_.xAxis(n); - else if (transformedData_.xAxis(n) < positiveLimitsMin_.x) - positiveLimitsMin_.x = transformedData_.xAxis(n); - - if (transformedData_.xAxis(n) > positiveLimitsMax_.x) - positiveLimitsMax_.x = transformedData_.xAxis(n); - } - - // Value - if (transformedData_.value(n) > 0.0) - { - if (positiveValuesMin_ < 0.0) - positiveValuesMin_ = transformedData_.value(n); - else if (transformedData_.value(n) < positiveValuesMin_) - positiveValuesMin_ = transformedData_.value(n); - - if (transformedData_.value(n) > positiveValuesMax_) - positiveValuesMax_ = transformedData_.value(n); - } - } - - // Check positive value limits (since all datapoints might have been negative) - if (positiveLimitsMin_.x < 0.0) - { - positiveLimitsMin_.x = 0.1; - positiveLimitsMax_.x = 1.0; - } - if (positiveValuesMin_ < 0.0) - { - positiveValuesMin_ = 0.1; - positiveValuesMax_ = 1.0; - } - - // Copy positive value limits over to y axis - positiveLimitsMin_.y = positiveValuesMin_; - positiveLimitsMax_.y = positiveValuesMax_; - - // Update the transformed data 'version' - valuesTransformDataVersion_ = dataVersion(); -} - -// Return reference to transformed data -const Data1D &RenderableData1D::transformedData() -{ - // Check that we have a valid source - if (!source_) - return transformedData_; - - // If the value transform is not enabled, just return the original data - if (!valuesTransform_.enabled()) - transformedData_ = source_->get(); - else - // Make sure the transformed data is up-to-date - transformValues(); - - return transformedData_; -} - -// Calculate min/max y value over specified x range (if possible in the underlying data) -bool RenderableData1D::yRangeOverX(double xMin, double xMax, double &yMin, double &yMax) -{ - // Grab reference to transformed data - const auto &data = transformedData(); - - auto first = true; - for (auto n = 0; n < data.nValues(); ++n) - { - if (data.xAxis(n) < xMin) - continue; - else if (data.xAxis(n) > xMax) - break; - - if (first) - { - yMin = data.value(n); - yMax = yMin; - first = false; - } - else - { - if (data.value(n) < yMin) - yMin = data.value(n); - else if (data.value(n) > yMax) - yMax = data.value(n); - } - } - - return true; -} - -/* - * Rendering Primitives - */ - -// Recreate necessary primitives / primitive assemblies for the data -void RenderableData1D::recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) -{ - dataPrimitive_->initialise(GL_LINE_STRIP, true, 4096); - - constructLineXY(transformedData().xAxis(), transformedData().values(), dataPrimitive_, view.axes(), colourDefinition); -} - -// Send primitives for rendering -const void RenderableData1D::sendToGL(const double pixelScaling) -{ - // Apply the LineStyle of the Renderable - lineStyle_.sendToGL(pixelScaling); - - // Disable lighting - glDisable(GL_LIGHTING); - - dataPrimitive_->sendToGL(); - - // Reset LineStyle back to defaults - LineStyle().sendToGL(); -} - -// Create line strip primitive -void RenderableData1D::constructLineXY(const std::vector &displayAbscissa, const std::vector &displayValues, - Primitive *primitive, const Axes &axes, const ColourDefinition &colourDefinition, - double zCoordinate) -{ - // Copy and transform abscissa values (still in data space) into axes coordinates - std::vector x = displayAbscissa; - axes.transformX(x); - auto nX = x.size(); - if (nX < 2) - return; - - // Get some values from axes so we can calculate colours properly - auto yLogarithmic = axes.logarithmic(1); - double yStretch = axes.stretch(1); - - // Temporary variables - GLfloat colour[4]; - Vector3 nrm(0.0, 1.0, 0.0); - - // Create lines for slices - int vertexA, vertexB; - // Grab y and z values - std::vector y = displayValues; - axes.transformY(y); - double z = axes.transformZ(zCoordinate); - - // Set vertexA to -1 so we don't draw a line at n=0 - vertexA = -1; - - // Check for a single colour style in the colourDefinition - use optimised case in that eventuality - if (colourDefinition.style() == ColourDefinition::SingleColourStyle) - { - // Get the single colour - colourDefinition.colour(0.0, colour); - - // Loop over x values - for (auto n = 0; n < nX; ++n) - { - vertexB = primitive->defineVertex(x[n], y[n], z, nrm, colour); - - // If both vertices are valid, plot a line - if (vertexA != -1) - primitive->defineIndices(vertexA, vertexB); - - vertexA = vertexB; - } - } - else - { - // Loop over x values - for (auto n = 0; n < nX; ++n) - { - colourDefinition.colour(yLogarithmic ? pow(10.0, y[n] / yStretch) : y[n] / yStretch, colour); - vertexB = primitive->defineVertex(x[n], y[n], z, nrm, colour); - - // If both vertices are valid, plot a line - if (vertexA != -1) - primitive->defineIndices(vertexA, vertexB); - - vertexA = vertexB; - } - } -} - -/* - * Style - */ - -// Return EnumOptions for Data1DDisplayStyle -EnumOptions RenderableData1D::data1DDisplayStyles() -{ - return EnumOptions("Data1DDisplayStyle", {{RenderableData1D::LinesStyle, "Lines"}}); -} - -// Set display style for renderable -void RenderableData1D::setDisplayStyle(Data1DDisplayStyle displayStyle) -{ - displayStyle_ = displayStyle; - - ++styleVersion_; -} - -// Return display style for the renderable -RenderableData1D::Data1DDisplayStyle RenderableData1D::displayStyle() const { return displayStyle_; } diff --git a/src/gui/render/renderableData1D.h b/src/gui/render/renderableData1D.h deleted file mode 100644 index 723b99fc6c..0000000000 --- a/src/gui/render/renderableData1D.h +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/renderable.h" -#include "math/data1D.h" - -// Forward Declarations -class Axes; - -// Renderable for Data1D -class RenderableData1D : public Renderable -{ - public: - RenderableData1D(const Data1DBase &source); - RenderableData1D(std::string_view tag); - ~RenderableData1D() = default; - - /* - * Data - */ - private: - // Source data - OptionalReferenceWrapper source_; - - public: - // Return source data - OptionalReferenceWrapper source() const; - // Attempt to set the data source, searching the supplied list for the object - void validateDataSource(const GenericList &sourceList) override; - // Invalidate the current data source - void invalidateDataSource() override; - // Return version of data - int dataVersion() override; - - /* - * Transform / Limits - */ - private: - // Transformed data - Data1D transformedData_; - - protected: - // Transform data according to current settings - void transformValues() override; - // Return reference to transformed data - const Data1D &transformedData(); - - public: - // Calculate min/max y value over specified x range (if possible in the underlying data) - bool yRangeOverX(double xMin, double xMax, double &yMin, double &yMax) override; - - /* - * Rendering Primitives - */ - private: - // Primitive to represent data - Primitive *dataPrimitive_; - - private: - // Create line strip primitive - void constructLineXY(const std::vector &displayAbscissa, const std::vector &displayValues, - Primitive *primitive, const Axes &axes, const ColourDefinition &colourDefinition, - double zCoordinate = 0.0); - - protected: - // Recreate necessary primitives / primitive assemblies for the data - void recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) override; - // Send primitives for rendering - const void sendToGL(double pixelScaling) override; - - /* - * Style - */ - public: - // Display Styles enum - enum Data1DDisplayStyle - { - LinesStyle, - nDisplayStyles - }; - // Return EnumOptions for Data1DDisplayStyle - static EnumOptions data1DDisplayStyles(); - - private: - // Display style for the renderable - Data1DDisplayStyle displayStyle_; - - public: - // Set display style for renderable - void setDisplayStyle(Data1DDisplayStyle displayStyle); - // Return display style for the renderable - Data1DDisplayStyle displayStyle() const; -}; diff --git a/src/gui/render/renderableData2D.cpp b/src/gui/render/renderableData2D.cpp deleted file mode 100644 index fddbd8beec..0000000000 --- a/src/gui/render/renderableData2D.cpp +++ /dev/null @@ -1,299 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/renderableData2D.h" -#include "gui/render/renderableGroupManager.h" -#include "gui/render/view.h" -#include "math/data2D.h" -#include "templates/array2D.h" - -RenderableData2D::RenderableData2D(const Data2D &source) - : Renderable(Renderable::Data2DRenderable, ""), source_(source), displayStyle_(LinesStyle) -{ - colour().setStyle(ColourDefinition::HSVGradientStyle); -} - -RenderableData2D::RenderableData2D(std::string_view tag) - : Renderable(Renderable::Data2DRenderable, tag), displayStyle_(LinesStyle) -{ - colour().setStyle(ColourDefinition::HSVGradientStyle); -} - -/* - * Data - */ - -// Return source data -OptionalReferenceWrapper RenderableData2D::source() const { return source_; } - -// Attempt to set the data source, searching the supplied list for the object -void RenderableData2D::validateDataSource(const GenericList &sourceList) -{ - // Don't try to access source_ if we are not currently permitted to do so - if (!sourceDataAccessEnabled_) - return; - - if (source_) - return; - - // TODO DISSOLVE2 - // source_ = sourceList.search(tag_); -} - -// Invalidate the current data source -void RenderableData2D::invalidateDataSource() { source_ = std::nullopt; } - -// Return version of data -int RenderableData2D::dataVersion() { return (source_ ? source_->get().version() : -99); } - -/* - * Transform / Limits - */ - -// Transform data according to current settings -void RenderableData2D::transformValues() -{ - // If the transformed data are already up-to-date, no need to do anything - if (valuesTransformDataVersion_ == dataVersion()) - return; - - // Copy original data and transform now. We do this even if the transformers are disabled, since they may have - // previously been active - if (!source_) - transformedData_.clear(); - else - transformedData_ = *source_; - valuesTransform_.transformValues(transformedData_); - - limitsMin_ = 0.0; - limitsMax_ = 0.0; - positiveLimitsMin_ = -1.0; - positiveLimitsMax_ = -1.0; - valuesMin_ = 0.0; - valuesMax_ = 0.0; - positiveValuesMin_ = -1.0; - positiveValuesMax_ = -1.0; - - // Set initial limits if we can - if (transformedData_.nValues() > 0) - { - valuesMin_ = transformedData_.minValue(); - valuesMax_ = transformedData_.maxValue(); - limitsMin_.set(transformedData_.xAxis().front(), transformedData_.yAxis().front(), valuesMin_); - limitsMax_.set(transformedData_.xAxis().back(), transformedData_.yAxis().back(), valuesMax_); - } - - // Now determine minimum positive limits - loop over points in data, searching for first positive, non-zero value - // X - for (auto n = 0; n < transformedData_.xAxis().size(); ++n) - { - if (transformedData_.xAxis(n) > 0.0) - { - if (positiveLimitsMin_.x < 0.0) - positiveLimitsMin_.x = transformedData_.xAxis(n); - else if (transformedData_.xAxis(n) < positiveLimitsMin_.x) - positiveLimitsMin_.x = transformedData_.xAxis(n); - - if (transformedData_.xAxis(n) > positiveLimitsMax_.x) - positiveLimitsMax_.x = transformedData_.xAxis(n); - } - } - - // Y - for (auto n = 0; n < transformedData_.yAxis().size(); ++n) - { - if (transformedData_.yAxis(n) > 0.0) - { - if (positiveLimitsMin_.y < 0.0) - positiveLimitsMin_.y = transformedData_.yAxis(n); - else if (transformedData_.yAxis(n) < positiveLimitsMin_.y) - positiveLimitsMin_.y = transformedData_.yAxis(n); - - if (transformedData_.yAxis(n) > positiveLimitsMax_.y) - positiveLimitsMax_.y = transformedData_.yAxis(n); - } - } - - // Values - for (auto n = 0; n < transformedData_.nValues(); ++n) - { - if (transformedData_.value(n) > 0.0) - { - if (positiveValuesMin_ < 0.0) - positiveValuesMin_ = transformedData_.value(n); - else if (transformedData_.value(n) < positiveValuesMin_) - positiveValuesMin_ = transformedData_.value(n); - - if (transformedData_.value(n) > positiveValuesMax_) - positiveValuesMax_ = transformedData_.value(n); - } - } - - // Copy positive value limits over to z axis - positiveLimitsMin_.z = positiveValuesMin_; - positiveLimitsMax_.z = positiveValuesMax_; - - // Update the transformed data 'version' - valuesTransformDataVersion_ = dataVersion(); -} - -// Return reference to transformed data -const Data2D &RenderableData2D::transformedData() -{ - // Check that we have a valid source - if (!source_) - return transformedData_; - - // If the value transform is not enabled, just return the original data - if (!valuesTransform_.enabled()) - transformedData_ = *source_; - else - // Make sure the transformed data is up-to-date - transformValues(); - - return transformedData_; -} - -/* - * Rendering Primitives - */ - -// Recreate necessary primitives / primitive assemblies for the data -void RenderableData2D::recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) -{ - if (!source_) - { - reinitialisePrimitives(0, GL_LINE_STRIP, true); - return; - } - - reinitialisePrimitives(source_->get().yAxis().size(), GL_LINE_STRIP, true); - constructLine(transformedData().xAxis(), transformedData().yAxis(), transformedData().values(), view.axes(), - colourDefinition); -} - -// Send primitives for rendering -const void RenderableData2D::sendToGL(const double pixelScaling) -{ - // Apply the LineStyle of the Renderable - lineStyle_.sendToGL(pixelScaling); - - // Disable lighting - glDisable(GL_LIGHTING); - - for (auto n = 0; n < nPrimitives(); ++n) - primitive(n)->sendToGL(); - - // Reset LineStyle back to defaults - LineStyle().sendToGL(); -} - -// Create line strip primitive -void RenderableData2D::constructLine(const std::vector &displayXAbscissa, const std::vector &displayYAbscissa, - const Array2D &displayValues, const Axes &axes, - const ColourDefinition &colourDefinition) -{ - // Copy and transform abscissa values (still in data space) into axes coordinates - auto x = displayXAbscissa; - axes.transformX(x); - auto nX = x.size(); - if (nX < 2) - return; - - // Copy and transform abscissa values (still in data space) into axes coordinates - auto y = displayYAbscissa; - axes.transformY(y); - auto nY = y.size(); - if (nY == 0) - return; - - // Get some values from axes so we can calculate colours properly - auto vLogarithmic = axes.logarithmic(2); - - // Temporary variables - GLfloat colour[4]; - Vector3 nrm(0.0, 1.0, 0.0); - - // Create lines for slices - int vertexA, vertexB; - Array2D v = displayValues; - axes.transformZ(v); - - Primitive *p; - - // Check for a single colour style in the colourDefinition - use optimised case in that eventuality - if (colourDefinition.style() == ColourDefinition::SingleColourStyle) - { - // Get the single colour - colourDefinition.colour(0.0, colour); - - // Loop over y - for (auto n = 0; n < nY; ++n) - { - // Set vertexA to -1 so we don't draw a line at n=0 - vertexA = -1; - p = primitive(n); - // Loop over x - for (auto m = 0; m < nX; ++m) - { - vertexB = p->defineVertex(x[m], y[n], v[{m, n}], nrm, colour); - - // If both vertices are valid, plot a line - if (vertexA != -1) - p->defineIndices(vertexA, vertexB); - vertexA = vertexB; - } - } - } - else - { - ColourDefinition colourDef = colourDefinition; - - // Setting gradient start and end value based on minimum and maximum data points - colourDef.setHSVGradientStartValue(positiveValuesMin_); - colourDef.setHSVGradientEndValue(positiveValuesMax_); - - // Loop over y - for (auto n = 0; n < nY; ++n) - { - // Set vertexA to -1 so we don't draw a line at n=0 - vertexA = -1; - p = primitive(n); - - // Loop over x - for (auto m = 0; m < nX; ++m) - { - // Assigning colour based on value - double c = (vLogarithmic ? pow(displayValues[{m, n}], 10.0) : displayValues[{m, n}]); - colourDef.colour(c, colour); - vertexB = p->defineVertex(x[m], y[n], v[{m, n}], nrm, colour); - - // If both vertices are valid, plot a line - if (vertexA != -1) - p->defineIndices(vertexA, vertexB); - vertexA = vertexB; - } - } - } -} - -/* - * Style - */ - -// Return EnumOptions for Data2DDisplayStyle -EnumOptions RenderableData2D::data2DDisplayStyles() -{ - return EnumOptions("Data2DDisplayStyle", {{RenderableData2D::LinesStyle, "Lines"}}); -} - -// Set display style for renderable -void RenderableData2D::setDisplayStyle(Data2DDisplayStyle displayStyle) -{ - displayStyle_ = displayStyle; - - ++styleVersion_; -} - -// Return display style for the renderable -RenderableData2D::Data2DDisplayStyle RenderableData2D::displayStyle() const { return displayStyle_; } diff --git a/src/gui/render/renderableData2D.h b/src/gui/render/renderableData2D.h deleted file mode 100644 index 8787ba8c02..0000000000 --- a/src/gui/render/renderableData2D.h +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/renderable.h" -#include "math/data2D.h" - -// Forward Declarations -class Axes; - -// Renderable for Data2D -class RenderableData2D : public Renderable -{ - public: - RenderableData2D(const Data2D &source); - RenderableData2D(std::string_view tag); - ~RenderableData2D() = default; - - /* - * Data - */ - private: - // Source data - OptionalReferenceWrapper source_; - - public: - // Return source data - OptionalReferenceWrapper source() const; - // Attempt to set the data source, searching the supplied list for the object - void validateDataSource(const GenericList &sourceList) override; - // Invalidate the current data source - void invalidateDataSource() override; - // Return version of data - int dataVersion() override; - - /* - * Transform / Limits - */ - private: - // Transformed data - Data2D transformedData_; - - protected: - // Transform data according to current settings - void transformValues() override; - // Return reference to transformed data - const Data2D &transformedData(); - - /* - * Rendering Primitives - */ - - private: - // Create line strip primitive - void constructLine(const std::vector &displayXAbscissa, const std::vector &displayYAbscissa, - const Array2D &displayValues, const Axes &axes, const ColourDefinition &colourDefinition); - - protected: - // Recreate necessary primitives / primitive assemblies for the data - void recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) override; - // Send primitives for rendering - const void sendToGL(double pixelScaling) override; - - /* - * Style - */ - public: - // Display Styles enum - enum Data2DDisplayStyle - { - LinesStyle, - nData2DDisplayStyles - }; - // Return EnumOptions for Data2DDisplayStyle - static EnumOptions data2DDisplayStyles(); - - private: - // Display style for the renderable - Data2DDisplayStyle displayStyle_; - - public: - // Set display style for renderable - void setDisplayStyle(Data2DDisplayStyle displayStyle); - // Return display style for the renderable - Data2DDisplayStyle displayStyle() const; -}; diff --git a/src/gui/render/renderableData3D.cpp b/src/gui/render/renderableData3D.cpp deleted file mode 100644 index 3a9b5710cd..0000000000 --- a/src/gui/render/renderableData3D.cpp +++ /dev/null @@ -1,667 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/renderableData3D.h" -#include "gui/render/renderableGroupManager.h" -#include "gui/render/view.h" -#include "math/data3D.h" -#include "templates/array2D.h" -#include "templates/array3D.h" - -RenderableData3D::RenderableData3D(const Data3D &source) - : Renderable(Renderable::Data3DRenderable, ""), source_(source), displayStyle_(SolidStyle), lowerCutoff_(0.0), - upperCutoff_(1.0), surfaceShininess_(128.0) -{ - dataPrimitive_ = createPrimitive(); -} - -RenderableData3D::RenderableData3D(std::string_view tag) - : Renderable(Renderable::Data3DRenderable, tag), displayStyle_(SolidStyle), lowerCutoff_(0.0), upperCutoff_(1.0), - surfaceShininess_(128.0) -{ - dataPrimitive_ = createPrimitive(); -} - -/* - * Data - */ - -// Return source data -OptionalReferenceWrapper RenderableData3D::source() const { return source_; } - -// Attempt to set the data source, searching the supplied list for the object -void RenderableData3D::validateDataSource(const GenericList &sourceList) -{ - // Don't try to access source_ if we are not currently permitted to do so - if (!sourceDataAccessEnabled_) - return; - - if (source_) - return; - - // TODO DISSOLVE2 - // source_ = sourceList.search(tag_); -} - -// Invalidate the current data source -void RenderableData3D::invalidateDataSource() { source_ = std::nullopt; } - -// Return version of data -int RenderableData3D::dataVersion() { return (source_ ? source_->get().version() : -99); } - -/* - * Transform / Limits - */ - -// Transform data according to current settings -void RenderableData3D::transformValues() -{ - // If the transformed data are already up-to-date, no need to do anything - if (valuesTransformDataVersion_ == dataVersion()) - return; - - // Copy original data and transform now. We do this even if the transformers are disabled, since they may have - // previously been active - if (!source_) - transformedData_.clear(); - else - transformedData_ = *source_; - valuesTransform_.transformValues(transformedData_); - - limitsMin_ = 0.0; - limitsMax_ = 0.0; - positiveLimitsMin_ = -1.0; - positiveLimitsMax_ = -1.0; - valuesMin_ = 0.0; - valuesMax_ = 0.0; - positiveValuesMin_ = -1.0; - positiveValuesMax_ = -1.0; - - // Set initial limits if we can - if (transformedData_.nValues() > 0) - { - valuesMin_ = transformedData_.minValue(); - valuesMax_ = transformedData_.maxValue(); - limitsMin_.set(transformedData_.xAxis().front(), transformedData_.yAxis().front(), transformedData_.zAxis().front()); - limitsMax_.set(transformedData_.xAxis().back(), transformedData_.yAxis().back(), transformedData_.zAxis().back()); - } - - // Now determine minimum positive limits - loop over points in data, searching for first positive, non-zero value - // X - for (auto n = 0; n < transformedData_.xAxis().size(); ++n) - { - if (transformedData_.xAxis(n) > 0.0) - { - if (positiveLimitsMin_.x < 0.0) - positiveLimitsMin_.x = transformedData_.xAxis(n); - else if (transformedData_.xAxis(n) < positiveLimitsMin_.x) - positiveLimitsMin_.x = transformedData_.xAxis(n); - - if (transformedData_.xAxis(n) > positiveLimitsMax_.x) - positiveLimitsMax_.x = transformedData_.xAxis(n); - } - } - - // Y - for (auto n = 0; n < transformedData_.yAxis().size(); ++n) - { - if (transformedData_.yAxis(n) > 0.0) - { - if (positiveLimitsMin_.y < 0.0) - positiveLimitsMin_.y = transformedData_.yAxis(n); - else if (transformedData_.yAxis(n) < positiveLimitsMin_.y) - positiveLimitsMin_.y = transformedData_.yAxis(n); - - if (transformedData_.yAxis(n) > positiveLimitsMax_.y) - positiveLimitsMax_.y = transformedData_.yAxis(n); - } - } - - // Z - for (auto n = 0; n < transformedData_.zAxis().size(); ++n) - { - if (transformedData_.zAxis(n) > 0.0) - { - if (positiveLimitsMin_.z < 0.0) - positiveLimitsMin_.z = transformedData_.zAxis(n); - else if (transformedData_.zAxis(n) < positiveLimitsMin_.z) - positiveLimitsMin_.z = transformedData_.zAxis(n); - - if (transformedData_.zAxis(n) > positiveLimitsMax_.z) - positiveLimitsMax_.z = transformedData_.zAxis(n); - } - } - - // Values - for (auto n = 0; n < transformedData_.nValues(); ++n) - { - auto val = transformedData_.values().linearValue(n); - if (val > 0.0) - { - if (positiveValuesMin_ < 0.0) - positiveValuesMin_ = val; - else if (val < positiveValuesMin_) - positiveValuesMin_ = val; - - if (val > positiveValuesMax_) - positiveValuesMax_ = val; - } - } - - // Update the transformed data 'version' - valuesTransformDataVersion_ = dataVersion(); -} - -// Return reference to transformed data -const Data3D &RenderableData3D::transformedData() -{ - // Check that we have a valid source - if (!source_) - return transformedData_; - - // If the value transform is not enabled, just return the original data - if (!valuesTransform_.enabled()) - transformedData_ = *source_; - else - // Make sure the transformed data is up-to-date - transformValues(); - - return transformedData_; -} - -/* - * Rendering Primitives - */ - -// Recreate necessary primitives / primitive assemblies for the data -void RenderableData3D::recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) -{ - dataPrimitive_->initialise(GL_TRIANGLES, true, 65536); - - if (!source_) - return; - - marchingCubesOriginal(transformedData_.xAxis(), transformedData_.yAxis(), transformedData_.zAxis(), - transformedData_.values(), lowerCutoff_, upperCutoff_, colourDefinition, view.axes(), dataPrimitive_); -} - -// Send primitives for rendering -const void RenderableData3D::sendToGL(const double pixelScaling) -{ - // Apply the LineStyle of the Renderable - lineStyle_.sendToGL(pixelScaling); - - // Enable lighting and shininess - glEnable(GL_LIGHTING); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 127); - - dataPrimitive_->sendToGL(); - - // Reset LineStyle back to defaults - LineStyle().sendToGL(); -} - -// Marching Cube Edge Vertex Lookup Table -int edgevertices[12][2] = {{0, 1}, {1, 2}, {2, 3}, {0, 3}, {4, 5}, {5, 6}, {6, 7}, {4, 7}, {0, 4}, {1, 5}, {3, 7}, {2, 6}}; - -Vector3 vertexPos[8] = {Vector3(0, 0, 0), Vector3(1, 0, 0), Vector3(1, 1, 0), Vector3(0, 1, 0), - Vector3(0, 0, 1), Vector3(1, 0, 1), Vector3(1, 1, 1), Vector3(0, 1, 1)}; - -// Marching Cube Face Triplet Lookup Table -int facetriples[256][15] = { - {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 1, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 2, 11, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 8, 3, 2, 11, 8, 11, 9, 8, -1, -1, -1, -1, -1, -1}, - {3, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 10, 2, 8, 10, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 9, 0, 2, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 10, 2, 1, 9, 10, 9, 8, 10, -1, -1, -1, -1, -1, -1}, - {3, 11, 1, 10, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 11, 1, 0, 8, 11, 8, 10, 11, -1, -1, -1, -1, -1, -1}, - {3, 9, 0, 3, 10, 9, 10, 11, 9, -1, -1, -1, -1, -1, -1}, - {9, 8, 11, 11, 8, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1}, - {1, 2, 11, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 4, 7, 3, 0, 4, 1, 2, 11, -1, -1, -1, -1, -1, -1}, - {9, 2, 11, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1}, - {2, 11, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1}, - {8, 4, 7, 3, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {10, 4, 7, 10, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1}, - {9, 0, 1, 8, 4, 7, 2, 3, 10, -1, -1, -1, -1, -1, -1}, - {4, 7, 10, 9, 4, 10, 9, 10, 2, 9, 2, 1, -1, -1, -1}, - {3, 11, 1, 3, 10, 11, 7, 8, 4, -1, -1, -1, -1, -1, -1}, - {1, 10, 11, 1, 4, 10, 1, 0, 4, 7, 10, 4, -1, -1, -1}, - {4, 7, 8, 9, 0, 10, 9, 10, 11, 10, 0, 3, -1, -1, -1}, - {4, 7, 10, 4, 10, 9, 9, 10, 11, -1, -1, -1, -1, -1, -1}, - {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1}, - {1, 2, 11, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 8, 1, 2, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1}, - {5, 2, 11, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1}, - {2, 11, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1}, - {9, 5, 4, 2, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 10, 2, 0, 8, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1}, - {0, 5, 4, 0, 1, 5, 2, 3, 10, -1, -1, -1, -1, -1, -1}, - {2, 1, 5, 2, 5, 8, 2, 8, 10, 4, 8, 5, -1, -1, -1}, - {11, 3, 10, 11, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1}, - {4, 9, 5, 0, 8, 1, 8, 11, 1, 8, 10, 11, -1, -1, -1}, - {5, 4, 0, 5, 0, 10, 5, 10, 11, 10, 0, 3, -1, -1, -1}, - {5, 4, 8, 5, 8, 11, 11, 8, 10, -1, -1, -1, -1, -1, -1}, - {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1}, - {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1}, - {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 7, 8, 9, 5, 7, 11, 1, 2, -1, -1, -1, -1, -1, -1}, - {11, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1}, - {8, 0, 2, 8, 2, 5, 8, 5, 7, 11, 5, 2, -1, -1, -1}, - {2, 11, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1}, - {7, 9, 5, 7, 8, 9, 3, 10, 2, -1, -1, -1, -1, -1, -1}, - {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 10, -1, -1, -1}, - {2, 3, 10, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1}, - {10, 2, 1, 10, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1}, - {9, 5, 8, 8, 5, 7, 11, 1, 3, 11, 3, 10, -1, -1, -1}, - {5, 7, 10, 5, 10, 11, 1, 0, 9, -1, -1, -1, -1, -1, -1}, - {10, 11, 5, 10, 5, 7, 8, 0, 3, -1, -1, -1, -1, -1, -1}, - {10, 11, 5, 7, 10, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {11, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 5, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 0, 1, 5, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 8, 3, 1, 9, 8, 5, 11, 6, -1, -1, -1, -1, -1, -1}, - {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1}, - {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1}, - {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1}, - {2, 3, 10, 11, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {10, 0, 8, 10, 2, 0, 11, 6, 5, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, 2, 3, 10, 5, 11, 6, -1, -1, -1, -1, -1, -1}, - {5, 11, 6, 1, 9, 2, 9, 10, 2, 9, 8, 10, -1, -1, -1}, - {6, 3, 10, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1}, - {0, 8, 10, 0, 10, 5, 0, 5, 1, 5, 10, 6, -1, -1, -1}, - {3, 10, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1}, - {6, 5, 9, 6, 9, 10, 10, 9, 8, -1, -1, -1, -1, -1, -1}, - {5, 11, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 3, 0, 4, 7, 3, 6, 5, 11, -1, -1, -1, -1, -1, -1}, - {1, 9, 0, 5, 11, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1}, - {11, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1}, - {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1}, - {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1}, - {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1}, - {7, 3, 2, 7, 2, 6, 5, 9, 4, -1, -1, -1, -1, -1, -1}, - {3, 10, 2, 7, 8, 4, 11, 6, 5, -1, -1, -1, -1, -1, -1}, - {5, 11, 6, 4, 7, 2, 4, 2, 0, 2, 7, 10, -1, -1, -1}, - {0, 1, 9, 4, 7, 8, 2, 3, 10, 5, 11, 6, -1, -1, -1}, - {9, 4, 5, 11, 2, 1, 7, 10, 6, -1, -1, -1, -1, -1, -1}, - {8, 4, 7, 3, 10, 5, 3, 5, 1, 5, 10, 6, -1, -1, -1}, - {5, 1, 0, 5, 0, 4, 7, 10, 6, -1, -1, -1, -1, -1, -1}, - {0, 3, 8, 4, 5, 9, 10, 6, 7, -1, -1, -1, -1, -1, -1}, - {4, 5, 9, 7, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {11, 4, 9, 6, 4, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 11, 6, 4, 9, 11, 0, 8, 3, -1, -1, -1, -1, -1, -1}, - {11, 0, 1, 11, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1}, - {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 11, -1, -1, -1}, - {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1}, - {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1}, - {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1}, - {11, 4, 9, 11, 6, 4, 10, 2, 3, -1, -1, -1, -1, -1, -1}, - {0, 8, 2, 2, 8, 10, 4, 9, 11, 4, 11, 6, -1, -1, -1}, - {3, 10, 2, 0, 1, 6, 0, 6, 4, 6, 1, 11, -1, -1, -1}, - {6, 4, 8, 6, 8, 10, 2, 1, 11, -1, -1, -1, -1, -1, -1}, - {9, 6, 4, 9, 3, 6, 9, 1, 3, 10, 6, 3, -1, -1, -1}, - {8, 10, 6, 8, 6, 4, 9, 1, 0, -1, -1, -1, -1, -1, -1}, - {3, 10, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1}, - {6, 4, 8, 10, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 11, 6, 7, 8, 11, 8, 9, 11, -1, -1, -1, -1, -1, -1}, - {0, 7, 3, 0, 11, 7, 0, 9, 11, 6, 7, 11, -1, -1, -1}, - {11, 6, 7, 1, 11, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1}, - {11, 6, 7, 11, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1}, - {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1}, - {2, 6, 7, 2, 7, 3, 0, 9, 1, -1, -1, -1, -1, -1, -1}, - {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1}, - {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 3, 10, 11, 6, 8, 11, 8, 9, 8, 6, 7, -1, -1, -1}, - {2, 0, 9, 2, 9, 11, 6, 7, 10, -1, -1, -1, -1, -1, -1}, - {1, 11, 2, 3, 8, 0, 6, 7, 10, -1, -1, -1, -1, -1, -1}, - {11, 2, 1, 6, 7, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 9, 1, 8, 1, 3, 10, 6, 7, -1, -1, -1, -1, -1, -1}, - {0, 9, 1, 10, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 8, 0, 10, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 8, 10, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 1, 9, 10, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 1, 9, 8, 3, 1, 10, 7, 6, -1, -1, -1, -1, -1, -1}, - {11, 1, 2, 6, 10, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 11, 3, 0, 8, 6, 10, 7, -1, -1, -1, -1, -1, -1}, - {2, 9, 0, 2, 11, 9, 6, 10, 7, -1, -1, -1, -1, -1, -1}, - {2, 10, 3, 11, 8, 6, 11, 9, 8, 8, 7, 6, -1, -1, -1}, - {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1}, - {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1}, - {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1}, - {11, 7, 6, 11, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1}, - {11, 7, 6, 1, 7, 11, 1, 8, 7, 1, 0, 8, -1, -1, -1}, - {0, 3, 7, 0, 7, 11, 0, 11, 9, 6, 11, 7, -1, -1, -1}, - {7, 6, 11, 7, 11, 8, 8, 11, 9, -1, -1, -1, -1, -1, -1}, - {6, 8, 4, 10, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 6, 10, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1}, - {8, 6, 10, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1}, - {9, 4, 6, 9, 6, 3, 9, 3, 1, 10, 3, 6, -1, -1, -1}, - {6, 8, 4, 6, 10, 8, 2, 11, 1, -1, -1, -1, -1, -1, -1}, - {3, 2, 10, 0, 6, 1, 0, 4, 6, 6, 11, 1, -1, -1, -1}, - {0, 2, 8, 2, 10, 8, 4, 11, 9, 4, 6, 11, -1, -1, -1}, - {11, 9, 4, 11, 4, 6, 10, 3, 2, -1, -1, -1, -1, -1, -1}, - {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1}, - {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 8, 0, 1, 9, 2, 2, 9, 4, 2, 4, 6, -1, -1, -1}, - {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1}, - {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 11, 1, -1, -1, -1}, - {11, 1, 0, 11, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1}, - {4, 6, 11, 4, 11, 9, 0, 3, 8, -1, -1, -1, -1, -1, -1}, - {11, 9, 4, 6, 11, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 9, 5, 7, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 3, 4, 9, 5, 10, 7, 6, -1, -1, -1, -1, -1, -1}, - {5, 0, 1, 5, 4, 0, 7, 6, 10, -1, -1, -1, -1, -1, -1}, - {8, 7, 4, 3, 5, 10, 3, 1, 5, 5, 6, 10, -1, -1, -1}, - {9, 5, 4, 11, 1, 2, 7, 6, 10, -1, -1, -1, -1, -1, -1}, - {0, 9, 1, 4, 8, 7, 2, 10, 3, 5, 6, 11, -1, -1, -1}, - {5, 6, 11, 4, 2, 7, 4, 0, 2, 2, 10, 7, -1, -1, -1}, - {3, 2, 10, 7, 4, 8, 11, 5, 6, -1, -1, -1, -1, -1, -1}, - {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1}, - {8, 7, 4, 9, 5, 0, 0, 5, 6, 0, 6, 2, -1, -1, -1}, - {1, 5, 2, 5, 6, 2, 3, 4, 0, 3, 7, 4, -1, -1, -1}, - {6, 2, 1, 6, 1, 5, 4, 8, 7, -1, -1, -1, -1, -1, -1}, - {11, 5, 6, 1, 7, 9, 1, 3, 7, 7, 4, 9, -1, -1, -1}, - {1, 0, 9, 5, 6, 11, 8, 7, 4, -1, -1, -1, -1, -1, -1}, - {4, 0, 3, 4, 3, 7, 6, 11, 5, -1, -1, -1, -1, -1, -1}, - {5, 6, 11, 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {6, 9, 5, 6, 10, 9, 10, 8, 9, -1, -1, -1, -1, -1, -1}, - {3, 6, 10, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1}, - {0, 10, 8, 0, 5, 10, 0, 1, 5, 5, 6, 10, -1, -1, -1}, - {6, 10, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1}, - {5, 6, 11, 1, 2, 9, 9, 2, 10, 9, 10, 8, -1, -1, -1}, - {0, 9, 1, 2, 10, 3, 5, 6, 11, -1, -1, -1, -1, -1, -1}, - {10, 8, 0, 10, 0, 2, 11, 5, 6, -1, -1, -1, -1, -1, -1}, - {2, 10, 3, 11, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1}, - {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1}, - {1, 5, 6, 1, 6, 2, 3, 8, 0, -1, -1, -1, -1, -1, -1}, - {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 3, 8, 1, 8, 9, 5, 6, 11, -1, -1, -1, -1, -1, -1}, - {9, 1, 0, 5, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 3, 8, 5, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {11, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {10, 5, 11, 7, 5, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {10, 5, 11, 10, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1}, - {5, 10, 7, 5, 11, 10, 1, 9, 0, -1, -1, -1, -1, -1, -1}, - {9, 8, 5, 8, 7, 5, 11, 3, 1, 11, 10, 3, -1, -1, -1}, - {10, 1, 2, 10, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1}, - {2, 10, 3, 0, 8, 1, 1, 8, 7, 1, 7, 5, -1, -1, -1}, - {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 10, 7, -1, -1, -1}, - {7, 5, 9, 7, 9, 8, 3, 2, 10, -1, -1, -1, -1, -1, -1}, - {2, 5, 11, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1}, - {8, 2, 0, 8, 5, 2, 8, 7, 5, 11, 2, 5, -1, -1, -1}, - {11, 2, 1, 9, 0, 5, 5, 0, 3, 5, 3, 7, -1, -1, -1}, - {9, 8, 7, 9, 7, 5, 11, 2, 1, -1, -1, -1, -1, -1, -1}, - {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1}, - {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1}, - {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {5, 8, 4, 5, 11, 8, 11, 10, 8, -1, -1, -1, -1, -1, -1}, - {5, 0, 4, 5, 10, 0, 5, 11, 10, 10, 3, 0, -1, -1, -1}, - {4, 5, 9, 0, 1, 8, 8, 1, 11, 8, 11, 10, -1, -1, -1}, - {11, 10, 3, 11, 3, 1, 9, 4, 5, -1, -1, -1, -1, -1, -1}, - {2, 5, 1, 2, 8, 5, 2, 10, 8, 4, 5, 8, -1, -1, -1}, - {0, 4, 5, 0, 5, 1, 2, 10, 3, -1, -1, -1, -1, -1, -1}, - {0, 2, 10, 0, 10, 8, 4, 5, 9, -1, -1, -1, -1, -1, -1}, - {9, 4, 5, 2, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 5, 11, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1}, - {5, 11, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1}, - {3, 8, 0, 1, 11, 2, 4, 5, 9, -1, -1, -1, -1, -1, -1}, - {1, 11, 2, 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1}, - {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 4, 5, 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 10, 7, 4, 9, 10, 9, 11, 10, -1, -1, -1, -1, -1, -1}, - {4, 8, 7, 9, 10, 0, 9, 11, 10, 10, 3, 0, -1, -1, -1}, - {1, 11, 10, 1, 10, 4, 1, 4, 0, 7, 4, 10, -1, -1, -1}, - {3, 1, 11, 3, 11, 10, 7, 4, 8, -1, -1, -1, -1, -1, -1}, - {4, 10, 7, 9, 10, 4, 9, 2, 10, 9, 1, 2, -1, -1, -1}, - {9, 1, 0, 8, 7, 4, 2, 10, 3, -1, -1, -1, -1, -1, -1}, - {10, 7, 4, 10, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1}, - {8, 7, 4, 3, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 9, 11, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1}, - {9, 11, 2, 9, 2, 0, 8, 7, 4, -1, -1, -1, -1, -1, -1}, - {3, 7, 4, 3, 4, 0, 1, 11, 2, -1, -1, -1, -1, -1, -1}, - {1, 11, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1}, - {0, 9, 1, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {9, 11, 8, 11, 10, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 0, 9, 3, 9, 10, 10, 9, 11, -1, -1, -1, -1, -1, -1}, - {0, 1, 11, 0, 11, 8, 8, 11, 10, -1, -1, -1, -1, -1, -1}, - {3, 1, 11, 10, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 2, 10, 1, 10, 9, 9, 10, 8, -1, -1, -1, -1, -1, -1}, - {1, 0, 9, 2, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 2, 10, 8, 0, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {3, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {2, 3, 8, 2, 8, 11, 11, 8, 9, -1, -1, -1, -1, -1, -1}, - {9, 11, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 3, 8, 1, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, - {0, 3, 8, 11, 1, 2, 6, 10, 7, 4, 9, 5, -1, -1, -1} - // { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} -}; - -// marching cubes -// Render volumetric isosurface with Marching Cubes ORIGINAL -void RenderableData3D::marchingCubesOriginal(const std::vector &displayXAbscissa, - const std::vector &displayYAbscissa, - const std::vector &displayZAbscissa, const Array3D &displayValues, - double lowerCutoff, double upperCutoff, const ColourDefinition &colourDefinition, - const Axes &axes, Primitive *primitive) -{ - int i, j, k, n, cubeType, *faces; - Vector3 normal, gradient[8]; - Vector3 r, v1; - double vertex[8], ipol, a, b; - GLfloat colour[4]; - std::vector x = displayXAbscissa, y = displayYAbscissa, z = displayZAbscissa; - - // Get distances between grid points - double dx, dy, dz; - dx = x[1] - x[0]; - dy = y[1] - y[0]; - dz = z[1] - z[0]; - - // Transform abscissa values (still in data space) into axes coordinates - axes.transformX(x); - auto nX = x.size(); - if (nX < 2) - return; - - // Transform abscissa values (still in data space) into axes coordinates - axes.transformY(y); - auto nY = y.size(); - if (nY < 2) - return; - - // Transform abscissa values (still in data space) into axes coordinates - axes.transformZ(z); - auto nZ = z.size(); - if (nZ < 2) - return; - - // Get single colour for surface (if colourScale style == SingleColourStyle) - if (colourDefinition.style() == ColourDefinition::SingleColourStyle) - colourDefinition.colour(0.0, colour); - - // Generate isosurface - for (i = 1; i < x.size() - 2; ++i) - { - for (j = 1; j < y.size() - 2; ++j) - { - for (k = 1; k < z.size() - 2; ++k) - { - // Grab values that form vertices of cube. - vertex[0] = displayValues[std::tuple{i, j, k}]; - vertex[1] = displayValues[std::tuple{i + 1, j, k}]; - vertex[2] = displayValues[std::tuple{i + 1, j + 1, k}]; - vertex[3] = displayValues[std::tuple{i, j + 1, k}]; - vertex[4] = displayValues[std::tuple{i, j, k + 1}]; - vertex[5] = displayValues[std::tuple{i + 1, j, k + 1}]; - vertex[6] = displayValues[std::tuple{i + 1, j + 1, k + 1}]; - vertex[7] = displayValues[std::tuple{i, j + 1, k + 1}]; - - // Calculate gradients at the cube vertices - gradient[0].x = (vertex[1] - displayValues[std::tuple{i - 1, j, k}]) / dx; - gradient[0].y = (vertex[3] - displayValues[std::tuple{i, j - 1, k}]) / dy; - gradient[0].z = (vertex[4] - displayValues[std::tuple{i, j, k - 1}]) / dz; - gradient[1].x = (displayValues[std::tuple{i + 2, j, k}] - vertex[0]) / dx; - gradient[1].y = (vertex[2] - displayValues[std::tuple{i + 1, j - 1, k}]) / dy; - gradient[1].z = (vertex[5] - displayValues[std::tuple{i + 1, j, k - 1}]) / dz; - gradient[2].x = (displayValues[std::tuple{i + 2, j + 1, k}] - vertex[3]) / dx; - gradient[2].y = (displayValues[std::tuple{i + 1, j + 2, k}] - vertex[1]) / dy; - gradient[2].z = (vertex[6] - displayValues[std::tuple{i + 1, j + 1, k - 1}]) / dz; - gradient[3].x = (vertex[2] - displayValues[std::tuple{i - 1, j + 1, k}]) / dx; - gradient[3].y = (displayValues[std::tuple{i, j + 2, k}] - vertex[0]) / dy; - gradient[3].z = (vertex[7] - displayValues[std::tuple{i, j + 1, k - 1}]) / dz; - gradient[4].x = (vertex[5] - displayValues[std::tuple{i - 1, j, k + 1}]) / dx; - gradient[4].y = (vertex[7] - displayValues[std::tuple{i, j - 1, k + 1}]) / dy; - gradient[4].z = (displayValues[std::tuple{i, j, k + 2}] - vertex[0]) / dz; - gradient[5].x = (displayValues[std::tuple{i + 2, j, k + 1}] - vertex[4]) / dx; - gradient[5].y = (vertex[6] - displayValues[std::tuple{i + 1, j - 1, k + 1}]) / dy; - gradient[5].z = (displayValues[std::tuple{i + 1, j, k + 2}] - vertex[1]) / dz; - gradient[6].x = (displayValues[std::tuple{i + 2, j + 1, k + 1}] - vertex[7]) / dx; - gradient[6].y = (displayValues[std::tuple{i + 1, j + 2, k + 1}] - vertex[5]) / dy; - gradient[6].z = (displayValues[std::tuple{i + 1, j + 1, k + 2}] - vertex[2]) / dz; - gradient[7].x = (vertex[6] - displayValues[std::tuple{i - 1, j + 1, k + 1}]) / dx; - gradient[7].y = (displayValues[std::tuple{i, j + 2, k + 1}] - vertex[4]) / dy; - gradient[7].z = (displayValues[std::tuple{i, j + 1, k + 2}] - vertex[3]) / dz; - - // Determine cube type - cubeType = 0; - if ((vertex[0] >= lowerCutoff) && (vertex[0] <= upperCutoff)) - cubeType += 1; - if ((vertex[1] >= lowerCutoff) && (vertex[1] <= upperCutoff)) - cubeType += 2; - if ((vertex[2] >= lowerCutoff) && (vertex[2] <= upperCutoff)) - cubeType += 4; - if ((vertex[3] >= lowerCutoff) && (vertex[3] <= upperCutoff)) - cubeType += 8; - if ((vertex[4] >= lowerCutoff) && (vertex[4] <= upperCutoff)) - cubeType += 16; - if ((vertex[5] >= lowerCutoff) && (vertex[5] <= upperCutoff)) - cubeType += 32; - if ((vertex[6] >= lowerCutoff) && (vertex[6] <= upperCutoff)) - cubeType += 64; - if ((vertex[7] >= lowerCutoff) && (vertex[7] <= upperCutoff)) - cubeType += 128; - - if ((cubeType != 0) && (cubeType != 255)) - { - // Get edges from list and draw triangles or points - faces = facetriples[cubeType]; - for (n = 0; n < 15; n++) - { - if (faces[n] == -1) - break; - - // Interpolate between data values (a,b) along this edge - a = vertex[edgevertices[faces[n]][0]]; - b = vertex[edgevertices[faces[n]][1]]; - ipol = (lowerCutoff - a) / (b - a); - if (ipol > 1.0) - ipol = 1.0; - else if (ipol < 0.0) - ipol = 0.0; - - // Get vector for edge (in unit coordinates) and scale to data spacing (dx, dy, - // dz) - v1 = vertexPos[edgevertices[faces[n]][0]]; - r = (vertexPos[edgevertices[faces[n]][1]] - v1); - r.multiply(dx, dy, dz); - r *= ipol; - - normal = -(gradient[edgevertices[faces[n]][0]] + - (gradient[edgevertices[faces[n]][1]] - gradient[edgevertices[faces[n]][0]]) * ipol); - normal.normalise(); - - // Add data lower-left-corner coordinate to r, and data-scaled edge origin v1 - r.add(x[i] + dx * v1[0], y[j] + dy * v1[1], z[k] + dz * v1[2]); - - // Plot vertex - if (colourDefinition.style() == ColourDefinition::SingleColourStyle) - primitive->defineVertex(r.x, r.y, r.z, normal.x, normal.y, normal.z, colour); - else - { - // Get the colour from the colourscale - // TODO CHECK - Are we using the correct data value for the colour - // lookup here? - colourDefinition.colour((a + b) * 0.5, colour); - primitive->defineVertex(r.x, r.y, r.z, normal.x, normal.y, normal.z, colour); - } - } - } - } - } - } -} - -/* - * Style - */ - -// Return EnumOptions for Data3DDisplayStyle -EnumOptions RenderableData3D::data3DDisplayStyles() -{ - return EnumOptions("Data3DDisplayStyle", {{RenderableData3D::SolidStyle, "Solid"}}); -} - -// Set display style for renderable -void RenderableData3D::setDisplayStyle(Data3DDisplayStyle displayStyle) -{ - displayStyle_ = displayStyle; - - ++styleVersion_; -} - -// Return display style for the renderable -RenderableData3D::Data3DDisplayStyle RenderableData3D::displayStyle() const { return displayStyle_; } - -// Set lower cutoff for surface generation -void RenderableData3D::setLowerCutoff(double cutoff) -{ - lowerCutoff_ = cutoff; - - ++styleVersion_; -} - -// Return lower cutoff for surface generation -double RenderableData3D::lowerCutoff() const { return lowerCutoff_; } - -// Set upper cutoff for surface generation -void RenderableData3D::setUpperCutoff(double cutoff) -{ - upperCutoff_ = cutoff; - - ++styleVersion_; -} - -// Return upper cutoff for surface generation -double RenderableData3D::upperCutoff() const { return upperCutoff_; } diff --git a/src/gui/render/renderableData3D.h b/src/gui/render/renderableData3D.h deleted file mode 100644 index aaf8f32e03..0000000000 --- a/src/gui/render/renderableData3D.h +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/renderable.h" -#include "math/data3D.h" - -// Forward Declarations -class Axes; - -// Renderable for Data3D -class RenderableData3D : public Renderable -{ - public: - RenderableData3D(const Data3D &source); - RenderableData3D(std::string_view tag); - ~RenderableData3D() = default; - - /* - * Data - */ - private: - // Source data - OptionalReferenceWrapper source_; - - public: - // Return source data - OptionalReferenceWrapper source() const; - // Attempt to set the data source, searching the supplied list for the object - void validateDataSource(const GenericList &sourceList) override; - // Invalidate the current data source - void invalidateDataSource() override; - // Return version of data - int dataVersion() override; - - /* - * Transform / Limits - */ - private: - // Transformed data - Data3D transformedData_; - - protected: - // Transform data according to current settings - void transformValues() override; - // Return reference to transformed data - const Data3D &transformedData(); - - /* - * Rendering Primitives - */ - private: - // Primitive to represent data - Primitive *dataPrimitive_; - - private: - // Create line strip primitive - void constructLine(const std::vector &displayXAbscissa, const std::vector &displayYAbscissa, - const std::vector &displayAbscissa, const Array3D &displayValues, const Axes &axes, - const ColourDefinition &colourDefinition); - void marchingCubesOriginal(const std::vector &displayXAbscissa, const std::vector &displayYAbscissa, - const std::vector &displayZAbscissa, const Array3D &displayValues, - double lowerCutoff, double upperCutoff, const ColourDefinition &colourDefinition, - const Axes &axes, Primitive *primitive); - - protected: - // Recreate necessary primitives / primitive assemblies for the data - void recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) override; - // Send primitives for rendering - const void sendToGL(double pixelScaling) override; - - /* - * Style - */ - public: - // Display Styles enum - enum Data3DDisplayStyle - { - SolidStyle, - nData3DDisplayStyles - }; - // Return EnumOptions for Data3DDisplayStyle - static EnumOptions data3DDisplayStyles(); - - private: - // Display style for the renderable - Data3DDisplayStyle displayStyle_; - // Lower cutoff for surface generation - double lowerCutoff_; - // Upper cutoff for surface generation - double upperCutoff_; - // Surface shininess for SolidSurface style - double surfaceShininess_; - - public: - // Set display style for renderable - void setDisplayStyle(Data3DDisplayStyle displayStyle); - // Return display style for the renderable - Data3DDisplayStyle displayStyle() const; - // Set lower cutoff for surface generation - void setLowerCutoff(double cutoff); - // Return lower cutoff for surface generation - double lowerCutoff() const; - // Set upper cutoff for surface generation - void setUpperCutoff(double cutoff); - // Return upper cutoff for surface generation - double upperCutoff() const; -}; diff --git a/src/gui/render/renderableGroup.cpp b/src/gui/render/renderableGroup.cpp deleted file mode 100644 index 3bccaf79fb..0000000000 --- a/src/gui/render/renderableGroup.cpp +++ /dev/null @@ -1,277 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/renderableGroup.h" -#include "gui/render/renderable.h" - -RenderableGroup::RenderableGroup(std::string_view name, StockColours::StockColour colour) -{ - name_ = name; - - visible_ = true; - - colouringStyle_ = RenderableGroup::NoGroupColouring; - automaticStockColourUsageCount_.fill(0); - fixedStockColour_ = colour; - lineStipple_ = LineStipple::NoStipple; - - verticalShiftStyle_ = GroupVerticalShifting; - verticalShift_ = 0.0; - verticalShiftMultiplier_ = 1.0; -} - -RenderableGroup::RenderableGroup(RenderableGroup &&other) -{ - empty(); - - // Copy style settings - name_ = other.name_; - visible_ = other.visible_; - colouringStyle_ = other.colouringStyle_; - automaticStockColourUsageCount_ = other.automaticStockColourUsageCount_; - fixedStockColour_ = other.fixedStockColour_; - lineStipple_ = other.lineStipple_; - verticalShiftStyle_ = other.verticalShiftStyle_; - verticalShift_ = other.verticalShift_; - verticalShiftMultiplier_ = other.verticalShiftMultiplier_; - - // Copy the renderables by hand - for (auto &renderable : other.renderables_) - { - renderables_.emplace_back(renderable); - renderable->setGroup(*this); - } - other.renderables_.clear(); - other.automaticStockColourUsageCount_.fill(0); -} - -/* - * Name - */ - -// Return name of group -std::string_view RenderableGroup::name() const { return name_; } - -/* - * Renderable Targets - */ - -// Associate Renderable to group (if it isn't already) -void RenderableGroup::addRenderable(const std::shared_ptr &renderable) -{ - // Return immediately if tne renderable is already in the group - if (std::find(renderables_.begin(), renderables_.end(), renderable) != renderables_.end()) - return; - - renderables_.push_back(renderable); - - // Apply colouring information if necessary - setRenderableColour(renderable); - - // Apply vertical shift to the renderable if necessary - setRenderableVerticalShift(renderable.get(), renderables_.size() - 1); - - // Apply line style if necessary - setRenderableLineStyle(renderable.get()); -} - -// Remove Renderable from group (if it exists) -void RenderableGroup::removeRenderable(Renderable *renderable) -{ - auto it = std::find_if(renderables_.begin(), renderables_.end(), [&renderable](auto &r) { return r.get() == renderable; }); - if (it == renderables_.end()) - { - Messenger::warn("Renderable '{}' is not present in the group '{}', so can't remove it.\n", renderable->name(), name()); - return; - } - - renderables_.erase(it); - - // Remove shift from the renderable first, if one is being applied - renderable->setValuesTransformEnabled(false); - renderable->setValuesTransformEquation("value"); - - renderable->unSetGroup(); -} - -// Return whether the group is used by the specified renderable -bool RenderableGroup::usedByRenderable(const Renderable *renderable) const -{ - return std::find_if(renderables_.begin(), renderables_.end(), [&renderable](auto &r) { return r.get() == renderable; }) != - renderables_.end(); -} - -// Return list of Renderables using this group -std::vector> &RenderableGroup::renderables() { return renderables_; } -const std::vector> &RenderableGroup::renderables() const { return renderables_; } - -// Return whether the group is empty -bool RenderableGroup::isEmpty() const { return renderables_.empty(); } - -// Empty the group, removing all Renderable targets -void RenderableGroup::empty() -{ - for (auto &renderable : renderables_) - renderable->unSetGroup(); - - renderables_.clear(); - - // Reset colour counters - automaticStockColourUsageCount_.fill(0); -} - -/* - * Visibility - */ - -// Set whether group contents are visible -void RenderableGroup::setVisible(bool visible) { visible_ = visible; } - -// Return whether group contents are visible -bool RenderableGroup::isVisible() const { return visible_; } - -/* - * Colouring - */ - -// Return enum options for GroupColouring -EnumOptions RenderableGroup::groupColourings() -{ - return EnumOptions("GroupColouring", - {{RenderableGroup::NoGroupColouring, "None"}, - {RenderableGroup::FixedGroupColouring, "Fixed"}, - {RenderableGroup::AutomaticIndividualColouring, "Automatic"}}); -} - -// Set colour information for the supplied Renderable, according to our settings -void RenderableGroup::setRenderableColour(std::shared_ptr renderable) -{ - if (colouringStyle_ == FixedGroupColouring) - renderable->setColour(fixedStockColour_); - else if (colouringStyle_ == AutomaticIndividualColouring) - { - // Find the StockColour with the lowest usage count - auto lowestId = 0; - for (auto colourId = 0; colourId < StockColours::nStockColours; ++colourId) - { - if (automaticStockColourUsageCount_[colourId] < automaticStockColourUsageCount_[lowestId]) - lowestId = colourId; - } - - renderable->setColour((StockColours::StockColour)lowestId); - - ++automaticStockColourUsageCount_[lowestId]; - } -} - -// Set all renderable colours -void RenderableGroup::setRenderableColours() -{ - for (auto &renderable : renderables_) - setRenderableColour(renderable); -} - -// Set colouring style for the group -void RenderableGroup::setColouringStyle(RenderableGroup::GroupColouring colouringStyle) -{ - colouringStyle_ = colouringStyle; - - setRenderableColours(); -} - -// Return colouring style for the group -RenderableGroup::GroupColouring RenderableGroup::colouringStyle() const { return colouringStyle_; } - -// Set fixed stock colour for the group -void RenderableGroup::setFixedStockColour(StockColours::StockColour stockColour) -{ - fixedStockColour_ = stockColour; - - setRenderableColours(); -} - -// Return fixed stock colour associated to the group -StockColours::StockColour RenderableGroup::fixedStockColour() const { return fixedStockColour_; } - -/* - * Line Style - */ - -// Set line style for the supplied Renderable, according to our settings -void RenderableGroup::setRenderableLineStyle(Renderable *renderable) -{ - if (lineStipple_ != LineStipple::NoStipple) - renderable->lineStyle().setStipple(lineStipple_); -} - -// Set all Renderable line styles -void RenderableGroup::setRenderableLineStyles() -{ - for (auto &renderable : renderables_) - setRenderableLineStyle(renderable.get()); -} - -// Set line stipple for the group -void RenderableGroup::setLineStipple(LineStipple::StippleType stipple) -{ - lineStipple_ = stipple; - - setRenderableLineStyles(); -} - -// Return line stipple for the group -LineStipple::StippleType RenderableGroup::lineStipple() const { return lineStipple_; } - -/* - * Vertical Shifting - */ - -// Return enum options for VerticalShiftStyle -EnumOptions RenderableGroup::verticalShiftStyles() -{ - return EnumOptions("VerticalShiftStyle", - {{RenderableGroup::PreventVerticalShifting, "Prevent"}, - {RenderableGroup::GroupVerticalShifting, "Group"}, - {RenderableGroup::IndividualVerticalShifting, "Individual"}}); -} - -// Set vertical shift in specified Renderable -void RenderableGroup::setRenderableVerticalShift(Renderable *renderable, int rendIndex) -{ - renderable->setValuesTransformEnabled(verticalShiftStyle_ != PreventVerticalShifting); - - if (verticalShiftStyle_ == GroupVerticalShifting) - renderable->setValuesTransformEquation(std::format("value+{}", verticalShift_ * verticalShiftMultiplier_)); - else if (verticalShiftStyle_ == IndividualVerticalShifting) - renderable->setValuesTransformEquation(std::format("value+{}", verticalShift_ * rendIndex)); - else - renderable->setValuesTransformEquation("value"); -} - -// Set vertical shift in all Renderables in the group via their transform equations -void RenderableGroup::setRenderableVerticalShifts() -{ - auto index = 0; - for (auto &renderable : renderables_) - setRenderableVerticalShift(renderable.get(), index++); -} - -// Set whether vertical shifting is enabled in this group -void RenderableGroup::setVerticalShiftStyle(RenderableGroup::VerticalShiftStyle shiftStyle) -{ - verticalShiftStyle_ = shiftStyle; - - setRenderableVerticalShifts(); -} - -// Return vertical shifting in force for this group -RenderableGroup::VerticalShiftStyle RenderableGroup::verticalShiftStyle() const { return verticalShiftStyle_; } - -// Apply the specified vertical shift (if VerticalShiftStyle != PreventVerticalShifting) -void RenderableGroup::applyVerticalShift(double dy, int groupIndex) -{ - verticalShift_ = dy; - verticalShiftMultiplier_ = groupIndex; - - setRenderableVerticalShifts(); -} diff --git a/src/gui/render/renderableGroup.h b/src/gui/render/renderableGroup.h deleted file mode 100644 index 601a700354..0000000000 --- a/src/gui/render/renderableGroup.h +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/colourDefinition.h" -#include "gui/render/lineStipple.h" -#include "gui/stockColours.h" -#include - -// Forward declarations -class Renderable; - -// Renderable Group -class RenderableGroup -{ - public: - RenderableGroup(std::string_view name, StockColours::StockColour colour); - RenderableGroup(const RenderableGroup &other) = delete; - RenderableGroup(RenderableGroup &&other); - - /* - * Name - */ - private: - // Name of the group - std::string name_; - - public: - // Return name of group - std::string_view name() const; - - /* - * Renderable Targets - */ - private: - // Renderables using this group - std::vector> renderables_; - - public: - // Add Renderable to group (if it isn't already) - void addRenderable(const std::shared_ptr &renderable); - // Remove Renderable from group (if it exists) - void removeRenderable(Renderable *renderable); - // Return whether the group is used by the specified renderable - bool usedByRenderable(const Renderable *renderable) const; - // Return list of Renderables using this group - std::vector> &renderables(); - const std::vector> &renderables() const; - // Return whether the group is empty - bool isEmpty() const; - // Empty the group, removing all Renderable targets - void empty(); - - /* - * Visibility - */ - private: - // Whether data within the group is visible - bool visible_; - - public: - // Set whether group contents are visible - void setVisible(bool visible); - // Return whether group contents are visible - bool isVisible() const; - - /* - * Colouring - */ - public: - // Colouring to apply to targeted renderables - enum GroupColouring - { - NoGroupColouring, /* Renderables will use their own colour definition */ - FixedGroupColouring, /* Renderables will be coloured as per the group colour definition */ - AutomaticIndividualColouring /* Renderables will be coloured individually by the group */ - }; - // Return enum options for GroupColouring - static EnumOptions groupColourings(); - - private: - // Colouring style for the group - GroupColouring colouringStyle_; - // Stock colour associated to this group - StockColours::StockColour fixedStockColour_; - // Usage counters for stock colours when colouringStyle_ == AutomaticIndividualColouring - std::array automaticStockColourUsageCount_; - - private: - // Set colour information for the supplied Renderable, according to our settings - void setRenderableColour(std::shared_ptr renderable); - // Set all Renderable colours - void setRenderableColours(); - - public: - // Set colouring style for the group - void setColouringStyle(GroupColouring colouringStyle); - // Return colouring style for the group - GroupColouring colouringStyle() const; - // Set fixed stock colour for the group - void setFixedStockColour(StockColours::StockColour stockColour); - // Return fixed stock colour associated to the group - StockColours::StockColour fixedStockColour() const; - // Return fixed colour definition for the group - const ColourDefinition &fixedColour() const; - - /* - * Line Style - */ - private: - // Line stipple for the group - LineStipple::StippleType lineStipple_; - - private: - // Set line style for the supplied Renderable, according to our settings - void setRenderableLineStyle(Renderable *renderable); - // Set all Renderable line styles - void setRenderableLineStyles(); - - public: - // Set line stipple for the group - void setLineStipple(LineStipple::StippleType stipple); - // Return line stipple for the group - LineStipple::StippleType lineStipple() const; - - /* - * Vertical Shifting - */ - public: - // Vertical Shift Style - enum VerticalShiftStyle - { - PreventVerticalShifting, /* Data within the group will not be subject to vertical shifting */ - GroupVerticalShifting, /* Data within the group will be shifted by the same amount */ - IndividualVerticalShifting /* Data within the group will be shifted individually and incrementally by the - specified amount */ - }; - // Return enum options for VerticalShiftStyle - static EnumOptions verticalShiftStyles(); - - private: - // Vertical shifting style for this group - VerticalShiftStyle verticalShiftStyle_; - // Shift (in vertical axis) to apply to Renderables - double verticalShift_; - // Shift multiplier - int verticalShiftMultiplier_; - - private: - // Set vertical shift in specified Renderable - void setRenderableVerticalShift(Renderable *renderable, int rendIndex); - // Set vertical shift in all Renderables in the group via their transform equations - void setRenderableVerticalShifts(); - - public: - // Set whether vertical shifting is enabled in this group - void setVerticalShiftStyle(VerticalShiftStyle shiftStyle); - // Return vertical shifting in force for this group - VerticalShiftStyle verticalShiftStyle() const; - // Apply the specified vertical shift (if VerticalShiftStyle != PreventVerticalShifting) - void applyVerticalShift(double dy, int groupIndex); -}; diff --git a/src/gui/render/renderableGroupManager.cpp b/src/gui/render/renderableGroupManager.cpp deleted file mode 100644 index fea306b565..0000000000 --- a/src/gui/render/renderableGroupManager.cpp +++ /dev/null @@ -1,201 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/renderableGroupManager.h" -#include "base/sysFunc.h" -#include "gui/render/renderable.h" -#include - -RenderableGroupManager::RenderableGroupManager() -{ - stockColourUsageCount_.resize(StockColours::nStockColours, 0); - - clear(); -} - -// Clear all groups -void RenderableGroupManager::clear() -{ - std::fill(stockColourUsageCount_.begin(), stockColourUsageCount_.end(), 0); - verticalShiftAmount_ = NoVerticalShift; - - emptyGroups(); - - groups_.clear(); -} - -/* - * Group Management - */ - -// Create named group, or return existing group by the same name -RenderableGroup &RenderableGroupManager::createGroup(std::string_view name) -{ - // Does a group with this name already exist? - auto optGroup = group(name); - if (optGroup) - return *optGroup; - - // No existing group, so must add a new one - // First, find the StockColour with the lowest usage count - auto lowestId = 0; - for (auto colourId = 0; colourId < StockColours::nStockColours; ++colourId) - { - if (stockColourUsageCount_[colourId] < stockColourUsageCount_[lowestId]) - lowestId = colourId; - } - - auto &newGroup = groups_.emplace_back(name, static_cast(lowestId)); - ++stockColourUsageCount_[lowestId]; - - // Need to update vertical shifts - setRenderableGroupShifts(); - - return newGroup; -} - -// Add Renderable to its specified group, creating / associating as necessary -RenderableGroup &RenderableGroupManager::addToGroup(const std::shared_ptr &renderable, std::string_view groupName) -{ - // Check to see if the Renderable is already associated to a group... - if (renderable->group()) - { - auto &group = renderable->group()->get(); - if (group.name() == groupName) - { - std::cout << std::format("Renderable '{}' already associated to group '{}'...", renderable->name(), group.name()) - << std::endl; - return group; - } - - // Remove it from the current group - group.removeRenderable(renderable.get()); - } - - // Create / retrieve the group - auto &renderableGroup = createGroup(groupName); - - // Add unique Renderable reference to the group - renderableGroup.addRenderable(renderable); - renderable->setGroup(renderableGroup); - - return renderableGroup; -} - -// Return named group, if it exists -OptionalReferenceWrapper RenderableGroupManager::group(std::string_view name) -{ - auto it = std::find_if(groups_.begin(), groups_.end(), [name](auto &group) { return group.name() == name; }); - if (it != groups_.end()) - return *it; - - return {}; -} - -// Return group for specified Renderable, if one has been assigned -OptionalReferenceWrapper RenderableGroupManager::group(const std::shared_ptr &renderable) -{ - return renderable->group(); -} - -// Return current RenderableGroups in use -std::vector &RenderableGroupManager::groups() { return groups_; } -const std::vector &RenderableGroupManager::groups() const { return groups_; } - -// Empty all groups of Renderables -void RenderableGroupManager::emptyGroups() -{ - for (auto &group : groups_) - group.empty(); -} - -/* - * Colouring - */ - -// Set colouring style for named group -void RenderableGroupManager::setGroupColouring(std::string_view groupName, RenderableGroup::GroupColouring colouringStyle) -{ - auto g = group(groupName); - if (!g) - g = createGroup(groupName); - - g->get().setColouringStyle(colouringStyle); -} - -// Set fixed colour for named group -void RenderableGroupManager::setGroupFixedColour(std::string_view groupName, StockColours::StockColour stockColour) -{ - auto g = group(groupName); - if (!g) - g = createGroup(groupName); - - g->get().setFixedStockColour(stockColour); -} - -/* - * Line Styling - */ - -// Line stipple to use for group -void RenderableGroupManager::setGroupStipple(std::string_view groupName, LineStipple::StippleType stipple) -{ - auto g = group(groupName); - if (!g) - g = createGroup(groupName); - - g->get().setLineStipple(stipple); -} - -/* - * Vertical Shifting - */ - -// Vertical shifts -double VerticalShiftAmounts[] = {0.0, 0.5, 1.0, 2.0}; - -// Set vertical shifts for current RenderableGroups -void RenderableGroupManager::setRenderableGroupShifts() -{ - auto groupIndex = 0; - for (auto &group : groups_) - group.applyVerticalShift(VerticalShiftAmounts[verticalShiftAmount_], groupIndex++); -} - -// Set vertical shifting style for named group -void RenderableGroupManager::setGroupVerticalShifting(std::string_view groupName, - RenderableGroup::VerticalShiftStyle shiftStyle) -{ - auto g = group(groupName); - if (!g) - g = createGroup(groupName); - - g->get().setVerticalShiftStyle(shiftStyle); -} - -// Cycle vertical shift amount applied to RenderableGroups -void RenderableGroupManager::cycleVerticalShiftAmount() -{ - verticalShiftAmount_ = (RenderableGroupManager::VerticalShiftAmount)((verticalShiftAmount_ + 1) % nVerticalShifts); - - setRenderableGroupShifts(); -} - -// Set vertical shift applied to RenderableGroups -void RenderableGroupManager::setVerticalShiftAmount(VerticalShiftAmount shiftType) -{ - verticalShiftAmount_ = shiftType; - - setRenderableGroupShifts(); -} - -// Return current vertical shift amount -RenderableGroupManager::VerticalShiftAmount RenderableGroupManager::verticalShiftAmount() const { return verticalShiftAmount_; } - -// Remove all vertical shifts from RenderableGroups -void RenderableGroupManager::removeVerticalShifts() -{ - verticalShiftAmount_ = NoVerticalShift; - - setRenderableGroupShifts(); -} diff --git a/src/gui/render/renderableGroupManager.h b/src/gui/render/renderableGroupManager.h deleted file mode 100644 index 991d120d18..0000000000 --- a/src/gui/render/renderableGroupManager.h +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/renderableGroup.h" -#include "templates/optionalRef.h" - -// Renderable Group Manager -class RenderableGroupManager -{ - public: - RenderableGroupManager(); - // Clear all groups - void clear(); - - /* - * Group Management - */ - private: - // Vector of current RenderableGroups in use - std::vector groups_; - // Usage counters for stock colours - std::vector stockColourUsageCount_; - - public: - // Create named group, or return existing group by the same name - RenderableGroup &createGroup(std::string_view name); - // Add Renderable to its specified group, creating / associating as necessary - RenderableGroup &addToGroup(const std::shared_ptr &renderable, std::string_view groupName); - // Return named group, if it exists - OptionalReferenceWrapper group(std::string_view name); - // Return group for specified Renderable, if one has been assigned - OptionalReferenceWrapper group(const std::shared_ptr &renderable); - // Return current RenderableGroups in use - std::vector &groups(); - const std::vector &groups() const; - // Empty all groups - void emptyGroups(); - - /* - * Colouring - */ - public: - // Set colouring style for named group - void setGroupColouring(std::string_view groupName, RenderableGroup::GroupColouring colouringStyle); - // Set fixed colour for named group - void setGroupFixedColour(std::string_view groupName, StockColours::StockColour stockColour); - - /* - * Line Styling - */ - public: - // Line stipple to use for group - void setGroupStipple(std::string_view groupName, LineStipple::StippleType stipple); - - /* - * Vertical Shifting - */ - public: - // Vertical Shift Amounts - enum VerticalShiftAmount - { - NoVerticalShift, - HalfVerticalShift, - OneVerticalShift, - TwoVerticalShift, - nVerticalShifts - }; - - private: - // Current vertical shift delta index being applied to groups - VerticalShiftAmount verticalShiftAmount_; - - private: - // Set vertical shifts for current RenderableGroups - void setRenderableGroupShifts(); - - public: - // Set vertical shifting style for named group - void setGroupVerticalShifting(std::string_view groupName, RenderableGroup::VerticalShiftStyle shiftStyle); - // Cycle vertical shift amount applied to RenderableGroups - void cycleVerticalShiftAmount(); - // Set vertical shift amount applied to RenderableGroups - void setVerticalShiftAmount(VerticalShiftAmount shiftAmount); - // Return current vertical shift amount - VerticalShiftAmount verticalShiftAmount() const; - // Remove all vertical shifts from RenderableGroups - void removeVerticalShifts(); -}; diff --git a/src/gui/render/renderableSpecies.cpp b/src/gui/render/renderableSpecies.cpp deleted file mode 100644 index c333ab0d87..0000000000 --- a/src/gui/render/renderableSpecies.cpp +++ /dev/null @@ -1,525 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/renderableSpecies.h" -#include "classes/configurationAtom.h" -#include "data/elementColours.h" -#include "gui/render/renderableConfiguration.h" -#include "gui/render/renderableGroupManager.h" -#include "gui/render/view.h" - -RenderableSpecies::RenderableSpecies(const Species *source, std::string_view name) - : Renderable(Renderable::SpeciesRenderable, name), source_(source) -{ - // Set defaults - displayStyle_ = SpheresStyle; - linesAtomRadius_ = 0.05; - spheresAtomRadius_ = 0.3; - spheresBondRadius_ = 0.1; - - // Create basic primitives - atomPrimitive_ = createPrimitive(GL_TRIANGLES, false); - atomPrimitive_->sphere(1.0, 8, 10); - selectedAtomPrimitive_ = createPrimitive(GL_LINES, false); - selectedAtomPrimitive_->sphere(1.25, 8, 10); - bondPrimitive_ = createPrimitive(GL_TRIANGLES, false); - bondPrimitive_->cylinder(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1, 8); - crossBoxPrimitive_ = createPrimitive(GL_LINES, false); - crossBoxPrimitive_->wireOrthorhomboid(1.0, 1.0, 1.0, 0.0, 0.0); - lineSpeciesPrimitive_ = createPrimitive(GL_LINES, true); - lineSelectionPrimitive_ = createPrimitive(GL_LINES, true); - lineSelectionPrimitive_->setNoInstances(); - lineInteractionPrimitive_ = createPrimitive(GL_LINES, true); - lineInteractionPrimitive_->setNoInstances(); - unitCellPrimitive_ = createPrimitive(GL_LINES, false); - unitCellPrimitive_->wireOrthorhomboid(1.0, 1.0, 1.0, 0.5, 0.5, 0.5); - - // Set versions - selectionPrimitiveVersion_ = -1; -} - -RenderableSpecies::~RenderableSpecies() {} - -/* - * Data - */ - -// Return version of data -int RenderableSpecies::dataVersion() { return -99; } - -/* - * Transform / Limits - */ - -// Transform data according to current settings -void RenderableSpecies::transformValues() -{ - if (!source_) - return; - - // If the transformed data are already up-to-date, no need to do anything - if (valuesTransformDataVersion_ == dataVersion()) - return; - - // For periodic systems use the box - otherwise, loop over Atoms seeking extreme x, y, and z values - if (source_->box().type() != Box::BoxType::None) - { - // Minimum corresponds to lower left corner of the box at {0,0,0} - limitsMin_.zero(); - - // Transform extreme upper right corner from unit to real space to get maxima - limitsMax_ = source_->box().getReal(Vector3(1.0, 1.0, 1.0)); - } - else if (source_->nAtoms() > 0) - { - limitsMin_ = source_->atoms()[0].r(); - limitsMax_ = source_->atoms()[0].r(); - - for (const auto &i : source_->atoms()) - { - if (i.r().x < limitsMin_.x) - limitsMin_.x = i.r().x; - else if (i.r().x > limitsMax_.x) - limitsMax_.x = i.r().x; - if (i.r().y < limitsMin_.y) - limitsMin_.y = i.r().y; - else if (i.r().y > limitsMax_.y) - limitsMax_.y = i.r().y; - if (i.r().z < limitsMin_.z) - limitsMin_.z = i.r().z; - else if (i.r().z > limitsMax_.z) - limitsMax_.z = i.r().z; - } - - // Need to add on a little extra to the limits since the atoms have a radius - limitsMin_ -= 1.0; - limitsMax_ += 1.0; - } - else - { - limitsMin_ = -1.0; - limitsMax_ = 1.0; - } - - positiveLimitsMin_.x = limitsMin_.x < 0.0 ? 0.01 : limitsMin_.x; - positiveLimitsMin_.y = limitsMin_.y < 0.0 ? 0.01 : limitsMin_.y; - positiveLimitsMin_.z = limitsMin_.z < 0.0 ? 0.01 : limitsMin_.z; - positiveLimitsMax_.x = limitsMax_.x < 0.0 ? 1.0 : limitsMax_.x; - positiveLimitsMax_.y = limitsMax_.y < 0.0 ? 1.0 : limitsMax_.y; - positiveLimitsMax_.z = limitsMax_.z < 0.0 ? 1.0 : limitsMax_.z; - - // Update the transformed data 'version' - valuesTransformDataVersion_ = dataVersion(); -} - -/* - * Rendering Primitives - */ - -// Recreate necessary primitives / primitive assemblies for the data -void RenderableSpecies::recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) -{ - Matrix4 A; - const std::array colourBlack = {0.0, 0.0, 0.0, 1.0}; - - // Clear existing data - lineSpeciesPrimitive_->forgetAll(); - lineSelectionPrimitive_->forgetAll(); - speciesAssembly_.clear(); - selectionAssembly_.clear(); - unitCellAssembly_.clear(); - - // Check data source - if (!source_) - return; - - // Render according to the current displayStyle - if (displayStyle_ == LinesStyle) - { - // Set basic styling and content for assemblies - speciesAssembly_.add(LineStyle(1.0)); - speciesAssembly_.add(false, GL_LINE); - speciesAssembly_.add(lineSpeciesPrimitive_, A); - - // Draw Atoms - for (const auto &i : source_->atoms()) - { - // Only draw the atom if it has no bonds, in which case draw it as a 'cross' - if (i.bonds().size() != 0) - continue; - - const auto r = i.r(); - auto &colour = ElementColours::colour(i.Z()); - - lineSpeciesPrimitive_->line(r.x - linesAtomRadius_, r.y, r.z, r.x + linesAtomRadius_, r.y, r.z, colour.data()); - lineSpeciesPrimitive_->line(r.x, r.y - linesAtomRadius_, r.z, r.x, r.y + linesAtomRadius_, r.z, colour.data()); - lineSpeciesPrimitive_->line(r.x, r.y, r.z - linesAtomRadius_, r.x, r.y, r.z + linesAtomRadius_, colour.data()); - } - - // Draw bonds - auto periodic = source_->box().type() != Box::BoxType::None; - for (const auto &bond : source_->bonds()) - { - // Determine half delta i-j for bond - const auto ri = bond.i()->r(); - const auto rj = bond.j()->r(); - const auto dij = (periodic ? source_->box().minimumVector(ri, rj) : (rj - ri)) * 0.5; - - // Draw bond halves - lineSpeciesPrimitive_->line(ri.x, ri.y, ri.z, ri.x + dij.x, ri.y + dij.y, ri.z + dij.z, - ElementColours::colour(bond.i()->Z()).data()); - lineSpeciesPrimitive_->line(rj.x, rj.y, rj.z, rj.x - dij.x, rj.y - dij.y, rj.z - dij.z, - ElementColours::colour(bond.j()->Z()).data()); - } - } - else if (displayStyle_ == SpheresStyle) - { - // Set basic styling for assemblies - speciesAssembly_.add(true, GL_FILL); - selectionAssembly_.add(true, GL_LINE); - - // Draw Atoms - for (const auto &i : source_->atoms()) - { - A.setIdentity(); - A.setTranslation(i.r()); - A.applyScaling(spheresAtomRadius_); - - // The atom itself - speciesAssembly_.add(atomPrimitive_, A, ElementColours::colour(i.Z())); - - // Is the atom selected? - // if (i.isSelected()) - // selectionAssembly_.add(selectedAtomPrimitive_, A, colourBlack); - } - - // Draw bonds - auto periodic = source_->box().type() != Box::BoxType::None; - for (const auto &bond : source_->bonds()) - { - if (periodic) - speciesAssembly_.createCylinderBond( - bondPrimitive_, bond.i()->r(), bond.j()->r(), source_->box().minimumVector(bond.i()->r(), bond.j()->r()), - ElementColours::colour(bond.j()->Z()), ElementColours::colour(bond.i()->Z()), true, spheresBondRadius_); - else - speciesAssembly_.createCylinderBond(bondPrimitive_, bond.i()->r(), bond.j()->r(), bond.j()->r() - bond.i()->r(), - ElementColours::colour(bond.i()->Z()), - ElementColours::colour(bond.j()->Z()), false, spheresBondRadius_); - } - } - - // Add unit cell - if (source_->box().type() != Box::BoxType::None) - { - A.setIdentity(); - A = source_->box().axes(); - unitCellAssembly_.add(unitCellPrimitive_, A, colourBlack); - } -} - -// Send primitives for rendering -const void RenderableSpecies::sendToGL(const double pixelScaling) -{ - // Set appropriate lighting for the species and interaction assemblies - if (displayStyle_ == LinesStyle) - glDisable(GL_LIGHTING); - else - glEnable(GL_LIGHTING); - speciesAssembly_.sendToGL(pixelScaling); - interactionAssembly_.sendToGL(pixelScaling); - - // Selection assembly is always drawn with no lighting as it comprises only of lines - glDisable(GL_LIGHTING); - selectionAssembly_.sendToGL(pixelScaling); - - // Draw unit cell - unitCellAssembly_.sendToGL(pixelScaling); -} - -// Recreate selection Primitive -void RenderableSpecies::recreateSelectionPrimitive() -{ - // if (selectionPrimitiveVersion_ == source_->atomSelectionVersion()) - // return; - - // Clear existing data - selectionAssembly_.clear(); - lineSelectionPrimitive_->forgetAll(); - - Matrix4 A; - - if (displayStyle_ == LinesStyle) - { - // Set basic styling for assemblies - selectionAssembly_.add(false, GL_LINE); - selectionAssembly_.add(LineStyle(3.0)); - selectionAssembly_.add(lineSelectionPrimitive_, A); - - // Draw selection - for (const auto &i : source_->atoms()) - { - // If not selected, continue - // if (!i.isSelected()) - // continue; - - // Get element colour - auto &colour = ElementColours::colour(i.Z()); - - // If the atom has no bonds, draw it as a 'cross', otherwise render all bond halves - if (i.bonds().size() == 0) - { - const auto &r = i.r(); - - lineSelectionPrimitive_->line(r.x - linesAtomRadius_, r.y, r.z, r.x + linesAtomRadius_, r.y, r.z, - colour.data()); - lineSelectionPrimitive_->line(r.x, r.y - linesAtomRadius_, r.z, r.x, r.y + linesAtomRadius_, r.z, - colour.data()); - lineSelectionPrimitive_->line(r.x, r.y, r.z - linesAtomRadius_, r.x, r.y, r.z + linesAtomRadius_, - colour.data()); - } - else - { - // Draw all bonds from this atom - for (const auto *bond : i.bonds()) - { - const auto ri = i.r(); - const auto dij = (bond->partner(&i)->r() - ri) * 0.5; - - // Draw bond halves - lineSelectionPrimitive_->line(ri.x, ri.y, ri.z, ri.x + dij.x, ri.y + dij.y, ri.z + dij.z, colour.data()); - } - } - } - } - else if (displayStyle_ == SpheresStyle) - { - // Set basic styling - selectionAssembly_.add(true, GL_LINE); - - for (auto &i : source_->atoms()) - { - // if (!i.isSelected()) - // continue; - - A.setIdentity(); - A.setTranslation(i.r()); - A.applyScaling(spheresAtomRadius_); - - selectionAssembly_.add(selectedAtomPrimitive_, A, 0.5, 0.5, 0.5, 1.0); - } - } - - // selectionPrimitiveVersion_ = source_->atomSelectionVersion(); -} - -// Clear interaction Primitive -void RenderableSpecies::clearInteractionPrimitive() -{ - interactionAssembly_.clear(); - lineInteractionPrimitive_->forgetAll(); -} - -// Recreate interaction Primitive to display drawing interaction (from existing atom to existing atom) -void RenderableSpecies::recreateDrawInteractionPrimitive(SpeciesAtom *fromAtom, SpeciesAtom *toAtom) -{ - // Clear existing data - clearInteractionPrimitive(); - - Matrix4 A; - - // Render based on the current drawing style - if (displayStyle_ == LinesStyle) - { - // Set basic styling for assembly - interactionAssembly_.add(false, GL_LINE); - interactionAssembly_.add(lineInteractionPrimitive_, A); - - // Determine half delta i-j for bond - const auto ri = fromAtom->r(); - const auto rj = toAtom->r(); - const auto dij = (rj - ri) * 0.5; - - // Draw bond halves - lineInteractionPrimitive_->line(ri.x, ri.y, ri.z, ri.x + dij.x, ri.y + dij.y, ri.z + dij.z, - ElementColours::colour(fromAtom->Z()).data()); - lineInteractionPrimitive_->line(rj.x, rj.y, rj.z, rj.x - dij.x, rj.y - dij.y, rj.z - dij.z, - ElementColours::colour(toAtom->Z()).data()); - } - else if (displayStyle_ == SpheresStyle) - { - // Set basic styling for assembly - interactionAssembly_.add(true, GL_FILL); - - // Draw the temporary bond between the atoms - interactionAssembly_.createCylinderBond(bondPrimitive_, fromAtom->r(), toAtom->r(), toAtom->r() - fromAtom->r(), - ElementColours::colour(fromAtom->Z()), ElementColours::colour(toAtom->Z()), - true, spheresBondRadius_); - } -} - -// Recreate interaction Primitive to display drawing interaction (from existing atom to point) -void RenderableSpecies::recreateDrawInteractionPrimitive(SpeciesAtom *fromAtom, Vector3 toPoint, Elements::Element toElement) -{ - // Clear existing data - clearInteractionPrimitive(); - - Matrix4 A; - - // Temporary SpeciesAtom - static SpeciesAtom j(nullptr); - j.setZ(toElement); - j.setR(toPoint); - - // Render based on the current drawing style - if (displayStyle_ == LinesStyle) - { - // Set basic styling for assembly - interactionAssembly_.add(false, GL_LINE); - interactionAssembly_.add(lineInteractionPrimitive_, A); - - // Determine half delta i-j for bond - const auto ri = fromAtom->r(); - const auto rj = j.r(); - const auto dij = (rj - ri) * 0.5; - - // Draw bond halves - lineInteractionPrimitive_->line(ri.x, ri.y, ri.z, ri.x + dij.x, ri.y + dij.y, ri.z + dij.z, - ElementColours::colour(fromAtom->Z()).data()); - lineInteractionPrimitive_->line(rj.x, rj.y, rj.z, rj.x - dij.x, rj.y - dij.y, rj.z - dij.z, - ElementColours::colour(j.Z()).data()); - } - else if (displayStyle_ == SpheresStyle) - { - // Set basic styling for assembly - interactionAssembly_.add(true, GL_FILL); - - // Draw the temporary atom - A.setTranslation(j.r()); - A.applyScaling(spheresAtomRadius_); - interactionAssembly_.add(atomPrimitive_, A, ElementColours::colour(j.Z())); - - // Draw the temporary bond between the atoms - interactionAssembly_.createCylinderBond(bondPrimitive_, fromAtom->r(), j.r(), j.r() - fromAtom->r(), - ElementColours::colour(j.Z()), ElementColours::colour(fromAtom->Z()), true, - spheresBondRadius_); - } -} - -// Recreate interaction Primitive to display drawing interaction (from point to point) -void RenderableSpecies::recreateDrawInteractionPrimitive(Vector3 fromPoint, Elements::Element fromElement, Vector3 toPoint, - Elements::Element toElement) -{ - // Clear existing data - clearInteractionPrimitive(); - - Matrix4 A; - - // Temporary SpeciesAtoms - static SpeciesAtom i(nullptr), j(nullptr); - i.setZ(fromElement); - i.setR(fromPoint); - j.setZ(toElement); - j.setR(toPoint); - - // Render based on the current drawing style - if (displayStyle_ == LinesStyle) - { - // Set basic styling for assembly - interactionAssembly_.add(false, GL_LINE); - interactionAssembly_.add(lineInteractionPrimitive_, A); - - // Determine half delta i-j for bond - const auto ri = i.r(); - const auto rj = j.r(); - const auto dij = (rj - ri) * 0.5; - - // Draw bond halves - lineInteractionPrimitive_->line(ri.x, ri.y, ri.z, ri.x + dij.x, ri.y + dij.y, ri.z + dij.z, - ElementColours::colour(i.Z()).data()); - lineInteractionPrimitive_->line(rj.x, rj.y, rj.z, rj.x - dij.x, rj.y - dij.y, rj.z - dij.z, - ElementColours::colour(j.Z()).data()); - } - else if (displayStyle_ == SpheresStyle) - { - // Set basic styling for assembly - interactionAssembly_.add(true, GL_FILL); - - // Draw the temporary atoms - A.setTranslation(i.r()); - A.applyScaling(spheresAtomRadius_); - interactionAssembly_.add(atomPrimitive_, A, ElementColours::colour(i.Z())); - - A.setIdentity(); - A.setTranslation(j.r()); - A.applyScaling(spheresAtomRadius_); - interactionAssembly_.add(atomPrimitive_, A, ElementColours::colour(j.Z())); - - // Draw the temporary bond between the atoms - interactionAssembly_.createCylinderBond(bondPrimitive_, i.r(), j.r(), j.r() - i.r(), ElementColours::colour(i.Z()), - ElementColours::colour(j.Z()), true, spheresBondRadius_); - } -} - -// Recreate interaction Primitive to display delete interaction (from existing atom to existing atom) -void RenderableSpecies::recreateDeleteInteractionPrimitive(SpeciesAtom *fromAtom, SpeciesAtom *toAtom) -{ - // Clear existing data - clearInteractionPrimitive(); - - Matrix4 A; - - A.setTranslation(fromAtom->r()); - - // Render based on the current drawing style - if (displayStyle_ == LinesStyle) - { - A.applyScaling(0.1); - - // Set basic styling for assembly - interactionAssembly_.add(false, GL_LINE); - interactionAssembly_.add(crossBoxPrimitive_, A); - - if (toAtom) - { - A.setTranslation(toAtom->r()); - interactionAssembly_.add(crossBoxPrimitive_, A); - } - } - else if (displayStyle_ == SpheresStyle) - { - // Set basic styling for assembly - interactionAssembly_.add(true, GL_FILL); - - // Draw the indicators - A.applyScaling(spheresAtomRadius_ * 2.2); - interactionAssembly_.add(crossBoxPrimitive_, A, 0.0, 0.0, 0.0, 1.0); - - if (toAtom) - { - A.setTranslation(toAtom->r()); - interactionAssembly_.add(crossBoxPrimitive_, A, 0.0, 0.0, 0.0, 1.0); - } - } -} - -/* - * Style - */ - -// Return EnumOptions for SpeciesDisplayStyle -EnumOptions RenderableSpecies::speciesDisplayStyles() -{ - return EnumOptions( - "SpeciesDisplayStyle", {{RenderableSpecies::LinesStyle, "Lines"}, {RenderableSpecies::SpheresStyle, "Spheres"}}); -} - -// Set display style for renderable -void RenderableSpecies::setDisplayStyle(SpeciesDisplayStyle displayStyle) -{ - displayStyle_ = displayStyle; - - ++styleVersion_; -} - -// Return display style for the renderable -RenderableSpecies::SpeciesDisplayStyle RenderableSpecies::displayStyle() const { return displayStyle_; } diff --git a/src/gui/render/renderableSpecies.h b/src/gui/render/renderableSpecies.h deleted file mode 100644 index 4850e2925b..0000000000 --- a/src/gui/render/renderableSpecies.h +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "classes/species.h" -#include "gui/render/renderable.h" - -// Forward Declarations -class Axes; - -// Renderable for Species -class RenderableSpecies : public Renderable -{ - public: - RenderableSpecies(const Species *source, std::string_view name); - ~RenderableSpecies(); - - /* - * Data - */ - private: - // Source data - const Species *source_; - - public: - // Return version of data - int dataVersion() override; - - /* - * Transform / Limits - */ - protected: - // Transform data according to current settings - void transformValues() override; - - /* - * Rendering Primitives - */ - private: - // Basic primitives - Primitive *atomPrimitive_, *selectedAtomPrimitive_, *crossBoxPrimitive_, *bondPrimitive_, *unitCellPrimitive_; - // Main primitives - Primitive *lineSpeciesPrimitive_, *lineSelectionPrimitive_, *lineInteractionPrimitive_; - // Main assemblies - PrimitiveAssembly speciesAssembly_, selectionAssembly_, interactionAssembly_, unitCellAssembly_; - // Version at which selection primitive was created, relative to selection version - int selectionPrimitiveVersion_; - - protected: - // Recreate necessary primitives / primitive assemblies for the data - void recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) override; - // Send primitives for rendering - const void sendToGL(double pixelScaling) override; - - public: - // Recreate selection Primitive - void recreateSelectionPrimitive(); - // Clear interaction Primitive - void clearInteractionPrimitive(); - // Recreate interaction Primitive to display drawing interaction (from existing atom to existing atom) - void recreateDrawInteractionPrimitive(SpeciesAtom *fromAtom, SpeciesAtom *toAtom); - // Recreate interaction Primitive to display drawing interaction (from existing atom to point) - void recreateDrawInteractionPrimitive(SpeciesAtom *fromAtom, Vector3 toPoint, Elements::Element toElement); - // Recreate interaction Primitive to display drawing interaction (from point to point) - void recreateDrawInteractionPrimitive(Vector3 fromPoint, Elements::Element fromElement, Vector3 toPoint, - Elements::Element toElement); - // Recreate interaction Primitive to display delete interaction (from existing atom to existing atom) - void recreateDeleteInteractionPrimitive(SpeciesAtom *fromAtom, SpeciesAtom *toAtom = nullptr); - - /* - * Style - */ - public: - // Display Styles enum - enum SpeciesDisplayStyle - { - LinesStyle, - SpheresStyle, - nSpeciesDisplayStyles - }; - // Return EnumOptions for SpeciesDisplayStyle - static EnumOptions speciesDisplayStyles(); - - private: - // Display style for the renderable - SpeciesDisplayStyle displayStyle_; - // Radius of free (unbound) atoms when drawing with lines - double linesAtomRadius_; - // Radius of atoms when drawing with spheres - double spheresAtomRadius_; - // Radius of bonds when drawing with spheres - double spheresBondRadius_; - - public: - // Set display style for renderable - void setDisplayStyle(SpeciesDisplayStyle displayStyle); - // Return display style for the renderable - SpeciesDisplayStyle displayStyle() const; -}; diff --git a/src/gui/render/renderableSpeciesSite.cpp b/src/gui/render/renderableSpeciesSite.cpp deleted file mode 100644 index a499bac379..0000000000 --- a/src/gui/render/renderableSpeciesSite.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/renderableSpeciesSite.h" -#include "classes/configurationAtom.h" -#include "classes/molecule.h" -#include "classes/site.h" -#include "data/elementColours.h" -#include "gui/render/renderableGroupManager.h" -#include "gui/render/view.h" - -RenderableSpeciesSite::RenderableSpeciesSite(const Species *sp, const SpeciesSite *site) - : Renderable(Renderable::SpeciesSiteRenderable, "SiteRenderable") -{ - // Set defaults - displayStyle_ = LinesStyle; - - // Set sources - speciesSource_ = sp; - siteSource_ = site; - - // Create basic primitives - originPrimitive_ = createPrimitive(GL_LINES, false); - originPrimitive_->wireOrthorhomboid(0.7, 0.7, 0.7); - crossPrimitive_ = createPrimitive(GL_LINES, false); - crossPrimitive_->cross(0.9); - axesPrimitive_ = createPrimitive(GL_LINES, true); - axesPrimitive_->colouredAxes(1.2); -} - -RenderableSpeciesSite::~RenderableSpeciesSite() {} - -/* - * Data - */ - -// Return version of data -int RenderableSpeciesSite::dataVersion() { return (siteSource_ ? siteSource_->version() : -99); } - -/* - * Rendering Primitives - */ - -// Recreate necessary primitives / primitive assemblies for the data -void RenderableSpeciesSite::recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) -{ - Matrix4 A; - - // Clear existing data - siteAssembly_.clear(); - - // Check source pointers - if (!siteSource_) - return; - - // Generate temporary site(s) from the parent Species - auto sites = siteSource_->createFromParent(); - if (sites.empty()) - return; - - // Render according to the current displayStyle - if (displayStyle_ == LinesStyle) - { - for (auto &site : sites) - { - // Plot origin - A.setTranslation(site->origin()); - if (site->hasAxes()) - A.setRotation(site->axes()); - siteAssembly_.add(originPrimitive_, A, 0.0, 0.0, 0.0, 1.0); - siteAssembly_.add(crossPrimitive_, A, 0.0, 0.0, 0.0, 1.0); - - // Plot axes? - if (site->hasAxes()) - { - siteAssembly_.add(axesPrimitive_, A); - } - } - } - - // Set the value transform data version here, since we don't use it - valuesTransformDataVersion_ = dataVersion(); -} - -// Send primitives for rendering -const void RenderableSpeciesSite::sendToGL(const double pixelScaling) -{ - glDisable(GL_LIGHTING); - LineStyle(1.0).sendToGL(); - siteAssembly_.sendToGL(pixelScaling); -} - -/* - * Style - */ - -// Return EnumOptions for SpeciesSiteDisplayStyle -EnumOptions RenderableSpeciesSite::speciesSiteDisplayStyles() -{ - return EnumOptions("SpeciesSiteDisplayStyle", - {{RenderableSpeciesSite::LinesStyle, "Lines"}}); -} - -// Set display style for renderable -void RenderableSpeciesSite::setDisplayStyle(SpeciesSiteDisplayStyle displayStyle) -{ - displayStyle_ = displayStyle; - - ++styleVersion_; -} - -// Return display style for the renderable -RenderableSpeciesSite::SpeciesSiteDisplayStyle RenderableSpeciesSite::displayStyle() const { return displayStyle_; } diff --git a/src/gui/render/renderableSpeciesSite.h b/src/gui/render/renderableSpeciesSite.h deleted file mode 100644 index 96ddf66e8a..0000000000 --- a/src/gui/render/renderableSpeciesSite.h +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "classes/species.h" -#include "classes/speciesSite.h" -#include "gui/render/renderable.h" - -// Forward Declarations -class Axes; - -// Renderable for SpeciesSite -class RenderableSpeciesSite : public Renderable -{ - public: - RenderableSpeciesSite(const Species *sp, const SpeciesSite *site); - ~RenderableSpeciesSite(); - - /* - * Data - */ - private: - // Source Species - const Species *speciesSource_; - // Source site in Species - const SpeciesSite *siteSource_; - - public: - // Return version of data - int dataVersion() override; - - /* - * Rendering Primitives - */ - private: - // Basic primitives - Primitive *originPrimitive_, *crossPrimitive_, *axesPrimitive_; - // Main assemblies - PrimitiveAssembly siteAssembly_; - - protected: - // Recreate necessary primitives / primitive assemblies for the data - void recreatePrimitives(const View &view, const ColourDefinition &colourDefinition) override; - // Send primitives for rendering - const void sendToGL(double pixelScaling) override; - - /* - * Style - */ - public: - // Display Styles enum - enum SpeciesSiteDisplayStyle - { - LinesStyle, - nSpeciesSiteDisplayStyles - }; - // Return EnumOptions for SpeciesSiteDisplayStyle - static EnumOptions speciesSiteDisplayStyles(); - - private: - // Display style for the renderable - SpeciesSiteDisplayStyle displayStyle_; - - public: - // Set display style for renderable - void setDisplayStyle(SpeciesSiteDisplayStyle displayStyle); - // Return display style for the renderable - SpeciesSiteDisplayStyle displayStyle() const; -}; diff --git a/src/gui/render/symbol.cpp b/src/gui/render/symbol.cpp deleted file mode 100644 index b55a84c3dc..0000000000 --- a/src/gui/render/symbol.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/symbol.h" -#include "base/sysFunc.h" -#include - -namespace SymbolData -{ - -// Return symbol vector -const std::vector> &symbols() -{ - static std::vector> symbolData = { - {MultiplySymbol, "mult", "\u00D7", "Multiplication Sign"}, - {DivisionSymbol, "div", "\u00F7", "Division Sign"}, - {AngstromSymbol, "angstrom", "\u212B", "Angstrom"}, - {DegreeSymbol, "degree", "\u00B0", "Degree"}, - {AlphaSymbol, "alpha", "\u03B1", "Greek Small Letter Alpha"}, - {BetaSymbol, "beta", "\u03B2", "Greek Small Letter Beta"}, - {GammaSymbol, "gamma", "\u03B3", "Greek Small Letter Gamma"}, - {DeltaSymbol, "delta", "\u03B4", "Greek Small Letter Delta"}, - {EpsilonSymbol, "epsilon", "\u03B5", "Greek Small Letter Epsilon"}, - {ZetaSymbol, "zeta", "\u03B6", "Greek Small Letter Zeta"}, - {EtaSymbol, "eta", "\u03B7", "Greek Small Letter Eta"}, - {ThetaSymbol, "theta", "\u03B8", "Greek Small Letter Theta"}, - {IotaSymbol, "iota", "\u03B9", "Greek Small Letter Iota"}, - {KappaSymbol, "kappa", "\u03BA", "Greek Small Letter Kappa"}, - {LambdaSymbol, "lambda", "\u03BB", "Greek Small Letter Lambda"}, - {MuSymbol, "mu", "\u03BC", "Greek Small Letter Mu"}, - {NuSymbol, "nu", "\u03BD", "Greek Small Letter Nu"}, - {XiSymbol, "xi", "\u03BE", "Greek Small Letter Xi"}, - {OmicronSymbol, "omicron", "\u03BF", "Greek Small Letter Omicron"}, - {PiSymbol, "pi", "\u03C0", "Greek Small Letter Pi"}, - {RhoSymbol, "rho", "\u03C1", "Greek Small Letter Rho"}, - {SigmaSymbol, "sigma", "\u03C3", "Greek Small Letter Sigma"}, - {TauSymbol, "tau", "\u03C4", "Greek Small Letter Tau"}, - {UpsilonSymbol, "upsilon", "\u03C5", "Greek Small Letter Upsilon"}, - {PhiSymbol, "phi", "\u03C6", "Greek Small Letter Phi"}, - {ChiSymbol, "chi", "\u03C7", "Greek Small Letter Chi"}, - {PsiSymbol, "psi", "\u03C8", "Greek Small Letter Psi"}, - {OmegaSymbol, "omega", "\u03C9", "Greek Small Letter Omega"}, - {CapitalAlphaSymbol, "Alpha", "\u0391", "Greek Capital Letter Alpha"}, - {CapitalBetaSymbol, "Beta", "\u0392", "Greek Capital Letter Beta"}, - {CapitalGammaSymbol, "Gamma", "\u0393", "Greek Capital Letter Gamma"}, - {CapitalDeltaSymbol, "Delta", "\u0394", "Greek Capital Letter Delta"}, - {CapitalEpsilonSymbol, "Epsilon", "\u0395", "Greek Capital Letter Epsilon"}, - {CapitalZetaSymbol, "Zeta", "\u0396", "Greek Capital Letter Zeta"}, - {CapitalEtaSymbol, "Eta", "\u0397", "Greek Capital Letter Eta"}, - {CapitalThetaSymbol, "Theta", "\u0398", "Greek Capital Letter Theta"}, - {CapitalIotaSymbol, "Iota", "\u0399", "Greek Capital Letter Iota"}, - {CapitalKappaSymbol, "Kappa", "\u039A", "Greek Capital Letter Kappa"}, - {CapitalLambdaSymbol, "Lambda", "\u039B", "Greek Capital Letter Lambda"}, - {CapitalMuSymbol, "Mu", "\u039C", "Greek Capital Letter Mu"}, - {CapitalNuSymbol, "Nu", "\u039D", "Greek Capital Letter Nu"}, - {CapitalXiSymbol, "Xi", "\u039E", "Greek Capital Letter Xi"}, - {CapitalOmicronSymbol, "Omicron", "\u039F", "Greek Capital Letter Omicron"}, - {CapitalPiSymbol, "Pi", "\u03A0", "Greek Capital Letter Pi"}, - {CapitalRhoSymbol, "Rho", "\u03A1", "Greek Capital Letter Rho"}, - {CapitalSigmaSymbol, "Sigma", "\u03A3", "Greek Capital Letter Sigma"}, - {CapitalTauSymbol, "Tau", "\u03A4", "Greek Capital Letter Tau"}, - {CapitalUpsilonSymbol, "Upsilon", "\u03A5", "Greek Capital Letter Upsilon"}, - {CapitalPhiSymbol, "Phi", "\u03A6", "Greek Capital Letter Phi"}, - {CapitalChiSymbol, "Chi", "\u03A7", "Greek Capital Letter Chi"}, - {CapitalPsiSymbol, "Psi", "\u03A8", "Greek Capital Letter Psi"}, - {CapitalOmegaSymbol, "Omega", "\u03A9", "Greek Capital Letter Omega"}}; - - return symbolData; -} - -// Return enumeration for named symbol -Symbol symbol(std::string_view name) -{ - auto it = std::find_if(symbols().begin(), symbols().end(), - [&name](auto &sym) { return DissolveSys::sameString(std::get<1>(sym), name, true); }); - - if (it == symbols().end()) - return nSymbols; - - return std::get<0>(*it); -} - -// Return symbol string -std::string_view symbol(Symbol sym) { return std::get<2>(symbols()[sym]); } - -// Return symbol description -std::string_view description(Symbol sym) { return std::get<3>(symbols()[sym]); } - -// Return first symbol whose description contains the search text -Symbol firstDescriptionMatch(std::string_view text) -{ - auto it = std::find_if(symbols().begin(), symbols().end(), - [&text](auto &sym) { return std::get<3>(sym).find(text) != std::string::npos; }); - if (it == symbols().end()) - return nSymbols; - - return std::get<0>(*it); -} - -}; // namespace SymbolData diff --git a/src/gui/render/symbol.h b/src/gui/render/symbol.h deleted file mode 100644 index 29d2e91489..0000000000 --- a/src/gui/render/symbol.h +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include -#include -#include - -// Symbols -namespace SymbolData -{ -// Symbol -enum Symbol -{ - MultiplySymbol, - DivisionSymbol, - AngstromSymbol, - DegreeSymbol, - AlphaSymbol, - BetaSymbol, - GammaSymbol, - DeltaSymbol, - EpsilonSymbol, - ZetaSymbol, - EtaSymbol, - ThetaSymbol, - IotaSymbol, - KappaSymbol, - LambdaSymbol, - MuSymbol, - NuSymbol, - XiSymbol, - OmicronSymbol, - PiSymbol, - RhoSymbol, - SigmaSymbol, - TauSymbol, - UpsilonSymbol, - PhiSymbol, - ChiSymbol, - PsiSymbol, - OmegaSymbol, - CapitalAlphaSymbol, - CapitalBetaSymbol, - CapitalGammaSymbol, - CapitalDeltaSymbol, - CapitalEpsilonSymbol, - CapitalZetaSymbol, - CapitalEtaSymbol, - CapitalThetaSymbol, - CapitalIotaSymbol, - CapitalKappaSymbol, - CapitalLambdaSymbol, - CapitalMuSymbol, - CapitalNuSymbol, - CapitalXiSymbol, - CapitalOmicronSymbol, - CapitalPiSymbol, - CapitalRhoSymbol, - CapitalSigmaSymbol, - CapitalTauSymbol, - CapitalUpsilonSymbol, - CapitalPhiSymbol, - CapitalChiSymbol, - CapitalPsiSymbol, - CapitalOmegaSymbol, - nSymbols -}; - -// Return symbol vector -const std::vector> &symbols(); -// Return enumeration for named symbol -Symbol symbol(std::string_view name); -// Return symbol string -std::string_view symbol(Symbol sym); -// Return symbol description -std::string_view description(Symbol sym); -// Return first symbol whose description contains the search text -Symbol firstDescriptionMatch(std::string_view text); -}; // namespace SymbolData diff --git a/src/gui/render/textFormat.cpp b/src/gui/render/textFormat.cpp deleted file mode 100644 index 72bcdc8282..0000000000 --- a/src/gui/render/textFormat.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/textFormat.h" - -TextFormat::TextFormat() : y_(0.0), scale_(1.0), isItalic_(false), isBold_(false), isSymbol_(false) {} - -TextFormat::TextFormat(const TextFormat &source) { (*this) = source; } - -void TextFormat::operator=(const TextFormat &source) -{ - y_ = source.y_; - scale_ = source.scale_; - isItalic_ = source.isItalic_; - isBold_ = source.isBold_; - isSymbol_ = source.isSymbol_; -} - -// Set vertical (bottom-edge) position -void TextFormat::setY(double y) { y_ = y; } - -// Adjust vertical (bottom-edge) position -void TextFormat::adjustY(double delta) { y_ += delta; } - -// Return vertical (bottom-edge) position -double TextFormat::y() const { return y_; } - -// Set scale -void TextFormat::setScale(double scale) { scale_ = scale; } - -// Return scale -double TextFormat::scale() const { return scale_; } - -// Set whether text is italic -void TextFormat::setItalic(bool italic) { isItalic_ = italic; } - -// Return whether text is italic -bool TextFormat::isItalic() const { return isItalic_; } - -// Set whether text is bold -void TextFormat::setBold(bool bold) { isBold_ = bold; } - -// Return whether text is bold -bool TextFormat::isBold() const { return isBold_; } - -// Set whether text is actually a symbol -void TextFormat::setSymbol(bool symbol) { isSymbol_ = symbol; } - -// Return whether text is actually a symbol -bool TextFormat::isSymbol() const { return isSymbol_; } diff --git a/src/gui/render/textFormat.h b/src/gui/render/textFormat.h deleted file mode 100644 index 4d9129ee67..0000000000 --- a/src/gui/render/textFormat.h +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -// Text Formatting -class TextFormat -{ - public: - TextFormat(); - ~TextFormat() = default; - TextFormat(const TextFormat &source); - void operator=(const TextFormat &source); - - /* - * Definition - */ - private: - // Vertical (bottom-edge) position - double y_; - // Scale - double scale_; - // Whether text is italic - bool isItalic_; - // Whether text is bold - bool isBold_; - // Whether text is actually a symbol - bool isSymbol_; - - public: - // Set vertical (bottom-edge) position - void setY(double y); - // Adjust vertical (bottom-edge) position - void adjustY(double delta); - // Return vertical (bottom-edge) position - double y() const; - // Set scale - void setScale(double scale); - // Return scale - double scale() const; - // Set whether text is italic - void setItalic(bool italic); - // Return whether text is italic - bool isItalic() const; - // Set whether text is bold - void setBold(bool bold); - // Return whether text is bold - bool isBold() const; - // Set whether text is actually a symbol - void setSymbol(bool symbol); - // Return whether text is actually a symbol - bool isSymbol() const; -}; diff --git a/src/gui/render/textFragment.cpp b/src/gui/render/textFragment.cpp deleted file mode 100644 index 57df900cde..0000000000 --- a/src/gui/render/textFragment.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/textFragment.h" - -TextFragment::TextFragment(std::string_view text, double scale, Vector3 translation, bool isItalic, bool isBold) - : text_(text), scale_(scale), translation_(translation), isItalic_(isItalic), isBold_(isBold) -{ -} - -/* - * Data - */ - -// Return text of fragment -const std::string &TextFragment::text() const { return text_; } - -// Return local scale for fragment -double TextFragment::scale() const { return scale_; } - -// Return local translation for fragment -Vector3 TextFragment::translation() const { return translation_; } - -// Return whether fragment is to be drawn italic -bool TextFragment::isItalic() const { return isItalic_; } - -// Return whether fragment is to be drawn bold -bool TextFragment::isBold() const { return isBold_; } diff --git a/src/gui/render/textFragment.h b/src/gui/render/textFragment.h deleted file mode 100644 index 4211018a8b..0000000000 --- a/src/gui/render/textFragment.h +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "math/vector3.h" -#include - -// Text Fragment -class TextFragment -{ - public: - TextFragment(std::string_view text, double scale = 1.0, Vector3 translation = Vector3(), bool isItalic = false, - bool isBold = false); - ~TextFragment() = default; - - /* - * Data - */ - private: - // Fragment text - std::string text_; - // Local scale for fragment - double scale_; - // Local translation for fragment - Vector3 translation_; - // Whether fragment is to be drawn italic - bool isItalic_; - // Whether fragment is to be drawn bold - bool isBold_; - - public: - // Return fragment text - const std::string &text() const; - // Return local scale for fragment - double scale() const; - // Return local translation for fragment - Vector3 translation() const; - // Return whether fragment is to be drawn italic - bool isItalic() const; - // Return whether fragment is to be drawn bold - bool isBold() const; -}; diff --git a/src/gui/render/textPrimitive.cpp b/src/gui/render/textPrimitive.cpp deleted file mode 100644 index 3c3edaaf11..0000000000 --- a/src/gui/render/textPrimitive.cpp +++ /dev/null @@ -1,253 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -// This include must come before the others -#include "TextPrimitiveLexer.h" - -#include "base/sysFunc.h" -#include "gui/render/TextPrimitiveErrorListeners.h" -#include "gui/render/TextPrimitiveVisitor.h" -#include "gui/render/fontInstance.h" -#include "gui/render/textPrimitive.h" -#include - -// Return enum options for TextAnchor -EnumOptions TextPrimitive::textAnchors() -{ - return EnumOptions("TextAnchor", {{TextPrimitive::TopLeftAnchor, "TopLeft"}, - {TextPrimitive::TopMiddleAnchor, "TopMiddle"}, - {TextPrimitive::TopRightAnchor, "TopRight"}, - {TextPrimitive::MiddleLeftAnchor, "MiddleLeft"}, - {TextPrimitive::CentralAnchor, "Central"}, - {TextPrimitive::MiddleRightAnchor, "MiddleRight"}, - {TextPrimitive::BottomLeftAnchor, "BottomLeft"}, - {TextPrimitive::BottomMiddleAnchor, "BottomMiddle"}, - {TextPrimitive::BottomRightAnchor, "BottomRight"}}); -} - -// Set data -bool TextPrimitive::set(FontInstance *fontInstance, QString text, Vector3 anchorPoint, TextPrimitive::TextAnchor anchorPosition, - Vector3 adjustmentVector, Matrix4 localRotation, double textSize, bool flat) -{ - // Create string stream and set up ANTLR input strem - std::stringstream stream; - stream << qPrintable(text); - antlr4::ANTLRInputStream input(stream); - - // Create ANTLR lexer and set-up error listener - TextPrimitiveLexer lexer(&input); - TextPrimitiveLexerErrorListener lexerErrorListener(qPrintable(text)); - lexer.removeErrorListeners(); - lexer.addErrorListener(&lexerErrorListener); - - // Generate tokens from input stream - antlr4::CommonTokenStream tokens(&lexer); - - // Create ANTLR parser and set-up error listenres - TextPrimitiveParser parser(&tokens); - TextPrimitiveParserErrorListener parserErrorListener(qPrintable(text)); - parser.removeErrorListeners(); - parser.removeParseListeners(); - parser.addErrorListener(&lexerErrorListener); - parser.addErrorListener(&parserErrorListener); - - // Generate the AST - TextPrimitiveParser::PrimitiveContext *tree = nullptr; - try - { - tree = parser.primitive(); - } - catch (TextPrimitiveExceptions::TextPrimitiveSyntaxException &ex) - { - return Messenger::error("{}", ex.what()); - }; - - // Visit the nodes in the AST - TextPrimitiveVisitor visitor; - try - { - fragments_ = visitor.create(tree, fontInstance); - } - catch (TextPrimitiveExceptions::TextPrimitiveSyntaxException &ex) - { - return Messenger::error("{}", ex.what()); - } - - anchorPoint_ = anchorPoint; - anchorPosition_ = anchorPosition; - adjustmentVector_ = adjustmentVector; - localRotation_ = localRotation; - textSize_ = textSize; - flat_ = flat; - - return true; -} - -// Return transformation matrix to use when rendering the text -Matrix4 TextPrimitive::transformationMatrix(FontInstance &fontInstance, const Matrix4 &viewMatrixInverse, double baseFontSize, - OptionalReferenceWrapper optFragment) const -{ - Matrix4 textMatrix, A; - Vector3 lowerLeft, upperRight, anchorPos, anchorPosRotated, textCentre; - - // Calculate scaling factor for font - double scale = fontInstance.fontBaseHeight() * textSize_ / baseFontSize; - - // Calculate bounding box and anchor position on it - boundingBox(fontInstance, lowerLeft, upperRight); - switch (anchorPosition_) - { - case (TextPrimitive::TopLeftAnchor): - anchorPos.set(lowerLeft.x, upperRight.y, 0.0); - break; - case (TextPrimitive::TopMiddleAnchor): - anchorPos.set((lowerLeft.x + upperRight.x) * 0.5, upperRight.y, 0.0); - break; - case (TextPrimitive::TopRightAnchor): - anchorPos = upperRight; - break; - case (TextPrimitive::MiddleLeftAnchor): - anchorPos.set(lowerLeft.x, (lowerLeft.y + upperRight.y) * 0.5, 0.0); - break; - case (TextPrimitive::CentralAnchor): - anchorPos.set((lowerLeft.x + upperRight.x) * 0.5, (lowerLeft.y + upperRight.y) * 0.5, 0.0); - break; - case (TextPrimitive::MiddleRightAnchor): - anchorPos.set(upperRight.x, (lowerLeft.y + upperRight.y) * 0.5, 0.0); - break; - case (TextPrimitive::BottomLeftAnchor): - anchorPos = lowerLeft; - break; - case (TextPrimitive::BottomMiddleAnchor): - anchorPos.set((lowerLeft.x + upperRight.x) * 0.5, lowerLeft.y, 0.0); - break; - case (TextPrimitive::BottomRightAnchor): - anchorPos.set(upperRight.x, lowerLeft.y, 0.0); - break; - default: - break; - } - - // Rotate anchor position with local rotation matrix - textCentre = (lowerLeft + upperRight) * 0.5; - anchorPosRotated = localRotation_ * (anchorPos - textCentre) * scale; - - // Construct matrix - - // -- Translate to centre of text bounding box (not rotated) accounting for fragment translation if one was specified - if (optFragment) - textCentre -= optFragment->get().translation(); - textMatrix.createTranslation(-textCentre); - - // -- Apply scaled local rotation matrix (if not flat) - if (flat_) - A = viewMatrixInverse; - else - A = localRotation_; - A.applyScaling(scale, scale, scale); - textMatrix.preMultiply(A); - - // -- Apply translation to text anchor point - textMatrix.applyPreTranslation(-anchorPosRotated + anchorPoint_ + adjustmentVector_ * scale); - - // -- Apply fragment specific operations - if (optFragment) - { - // -- Apply local scaling to text (if fragment was provided) - textMatrix.applyScaling(optFragment->get().scale()); - // -- Apply local shear to text (if fragment is italic) - if (optFragment->get().isItalic()) - textMatrix.applyShearX(0.2); - } - - return textMatrix; -} - -// Calculate bounding box of primitive -void TextPrimitive::boundingBox(FontInstance &fontInstance, Vector3 &lowerLeft, Vector3 &upperRight) const -{ - // Check for zero fragments - if (fragments_.empty()) - { - lowerLeft.zero(); - upperRight.zero(); - return; - } - - // Loop over remaining fragments, keeping track of the total width of the primitive and the max/min y values - Vector3 ll, ur; - auto firstFragment = true; - for (const auto &fragment : fragments_) - { - // Get bounding box for this fragment - fontInstance.boundingBox(fragment.text(), ll, ur); - - // Scale the box by the current scaling factor... - ur.x = ll.x + (ur.x - ll.x) * fragment.scale(); - ur.y = ll.y + (ur.y - ll.y) * fragment.scale(); - - // Translate the box by the defined amount - ll += fragment.translation(); - ur += fragment.translation(); - - // Update lowerLeft and upperRight values - if (firstFragment) - { - lowerLeft = ll; - upperRight = ur; - firstFragment = false; - } - else - { - if (ll.y < lowerLeft.y) - lowerLeft.y = ll.y; - if (ur.y > upperRight.y) - upperRight.y = ur.y; - if (ur.x > upperRight.x) - upperRight.x = ur.x; - } - } -} - -// Render primitive -void TextPrimitive::render(FontInstance &fontInstance, const Matrix4 &viewMatrix, const Matrix4 &viewMatrixInverse, - double baseFontSize) const -{ - Matrix4 textMatrix; - - // Loop over fragments - for (const auto &fragment : fragments_) - { - textMatrix = viewMatrix * transformationMatrix(fontInstance, viewMatrixInverse, baseFontSize, fragment); - glLoadMatrixd(textMatrix.matrix()); - - // Draw bounding boxes around each fragment - if (false) - { - glDisable(GL_LINE_STIPPLE); - glLineWidth(1.0); - Vector3 ll, ur; - fontInstance.boundingBox(fragment.text(), ll, ur); - glBegin(GL_LINE_LOOP); - glVertex3d(ll.x, ll.y, 0.0); - glVertex3d(ur.x, ll.y, 0.0); - glVertex3d(ur.x, ur.y, 0.0); - glVertex3d(ll.x, ur.y, 0.0); - glEnd(); - } - - // Apply any scaling stored in the FontInstance - glScaled(fontInstance.scaleFactor(), fontInstance.scaleFactor(), fontInstance.scaleFactor()); - - if (fragment.isBold()) - { - // Render the text twice - once with lines, and once with polygon fill - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - fontInstance.renderText(fragment.text()); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - fontInstance.renderText(fragment.text()); - } - else - fontInstance.renderText(fragment.text()); - } -} diff --git a/src/gui/render/textPrimitive.h b/src/gui/render/textPrimitive.h deleted file mode 100644 index 2b6424fc5d..0000000000 --- a/src/gui/render/textPrimitive.h +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "base/enumOptions.h" -#include "gui/render/textFragment.h" -#include "math/matrix4.h" -#include "math/vector3.h" -#include "templates/optionalRef.h" -#include - -// Forward Declarations -class FontInstance; - -// Text Primitive -class TextPrimitive -{ - public: - TextPrimitive() = default; - ~TextPrimitive() = default; - // Text Anchors enum - enum TextAnchor - { - TopLeftAnchor, - TopMiddleAnchor, - TopRightAnchor, - MiddleLeftAnchor, - CentralAnchor, - MiddleRightAnchor, - BottomLeftAnchor, - BottomMiddleAnchor, - BottomRightAnchor, - nTextAnchors - }; - // Return enum options for TextAnchor - static EnumOptions textAnchors(); - - /* - * Definition - */ - private: - // Coordinates of anchorpoint of text - Vector3 anchorPoint_; - // Location of anchorpoint on text bounding box - TextAnchor anchorPosition_; - // Vector by which to adjust position of text - Vector3 adjustmentVector_; - // Local transform matrix for the text - Matrix4 localRotation_; - // Whether text should be rendered flat (w.r.t viewer's screen plane) - bool flat_; - // Text size - double textSize_; - // Text fragments to render - std::vector fragments_; - - public: - // Set data - bool set(FontInstance *fontInstance, QString text, Vector3 anchorPoint, TextAnchor anchorPosition, Vector3 adjustmentVector, - Matrix4 localRotation, double textSize, bool flat); - // Return transformation matrix to use when rendering (including fragment scale/translation if one is specified) - Matrix4 transformationMatrix(FontInstance &fontInstance, const Matrix4 &viewMatrixInverse, double baseFontSize, - OptionalReferenceWrapper optFragment = std::nullopt) const; - // Calculate bounding box of primitive - void boundingBox(FontInstance &fontInstance, Vector3 &lowerLeft, Vector3 &upperRight) const; - // Render primitive - void render(FontInstance &fontInstance, const Matrix4 &viewMatrix, const Matrix4 &viewMatrixInverse, - double baseFontSize) const; -}; diff --git a/src/gui/render/textPrimitiveList.cpp b/src/gui/render/textPrimitiveList.cpp deleted file mode 100644 index 56f8d75f4c..0000000000 --- a/src/gui/render/textPrimitiveList.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/textPrimitiveList.h" -#include "gui/render/fontInstance.h" -#include "gui/render/view.h" - -// Clear list -void TextPrimitiveList::clear() { textPrimitives_.clear(); } - -// Set data from literal coordinates and text -void TextPrimitiveList::add(FontInstance *fontInstance, QString text, Vector3 anchorPoint, - TextPrimitive::TextAnchor anchorPosition, Vector3 adjustmentVector, Matrix4 &localRotation, - double textSize, bool flat) -{ - auto &primitive = textPrimitives_.emplace_back(); - primitive.set(fontInstance, text, anchorPoint, anchorPosition, adjustmentVector, localRotation, textSize, flat); -} - -// Update global bounding cuboid for all text primitives in the list -Cuboid TextPrimitiveList::boundingCuboid(FontInstance &fontInstance, const Matrix4 &viewMatrixInverse, double baseFontSize, - Cuboid startingCuboid) -{ - Cuboid result = startingCuboid; - Matrix4 textMatrix; - Vector3 corners[4], local; - for (const auto &primitive : textPrimitives_) - { - // Get transformation matrix and bounding box for text - textMatrix = primitive.transformationMatrix(fontInstance, viewMatrixInverse, baseFontSize); - primitive.boundingBox(fontInstance, corners[0], corners[1]); - corners[2].set(corners[0].x, corners[1].y, 0.0); - corners[3].set(corners[1].x, corners[0].y, 0.0); - - // Transform the four corners of the bounding box with the text primitive's transformation matrix - // and determine the extreme x, y, and z coordinates of the primitives in the local frame - for (auto m = 0; m < 4; ++m) - { - local = textMatrix * corners[m]; - result.updateExtremes(local); - } - } - - return result; -} - -// Render all primitives in list -void TextPrimitiveList::renderAll(FontInstance &fontInstance, const Matrix4 &viewMatrix, const Matrix4 &viewMatrixInverse, - double baseFontSize) -{ - if (!fontInstance.fontOK()) - return; - - for (const auto &primitive : textPrimitives_) - primitive.render(fontInstance, viewMatrix, viewMatrixInverse, baseFontSize); -} diff --git a/src/gui/render/textPrimitiveList.h b/src/gui/render/textPrimitiveList.h deleted file mode 100644 index dc4e12d201..0000000000 --- a/src/gui/render/textPrimitiveList.h +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/textPrimitive.h" -#include "math/cuboid.h" -#include "math/matrix4.h" -#include "math/vector3.h" -#include - -// Forward Declarations -class FontInstance; - -// Text Primitive List -class TextPrimitiveList -{ - public: - TextPrimitiveList() = default; - ~TextPrimitiveList() = default; - - private: - // List of text primitives - std::vector textPrimitives_; - - public: - // Clear list - void clear(); - // Add primitive to list - void add(FontInstance *fontInstance, QString text, Vector3 anchorPoint, TextPrimitive::TextAnchor anchorPosition, - Vector3 adjustmentVector, Matrix4 &rotation, double textSize, bool flat); - // Update global bounding cuboid for all text primitives in the list - Cuboid boundingCuboid(FontInstance &fontInstance, const Matrix4 &viewMatrixInverse, double baseFontSize, - Cuboid startingCuboid = Cuboid()); - // Render all primitives in list - void renderAll(FontInstance &fontInstance, const Matrix4 &viewMatrix, const Matrix4 &viewMatrixInverse, - double baseFontSize); -}; diff --git a/src/gui/render/vertexChunk.cpp b/src/gui/render/vertexChunk.cpp deleted file mode 100644 index 5c4feca18b..0000000000 --- a/src/gui/render/vertexChunk.cpp +++ /dev/null @@ -1,202 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/vertexChunk.h" -#include "base/messenger.h" - -VertexChunk::VertexChunk() -{ - // Public variables - next = nullptr; - prev = nullptr; - - // Private variables - vertexData_ = nullptr; - centroids_ = nullptr; - verticesPerType_ = 0; - dataPerVertex_ = 0; - nDefinedVertices_ = 0; - maxVertices_ = -1; - nDefinedTypes_ = 0; - type_ = GL_TRIANGLES; -} - -VertexChunk::~VertexChunk() -{ - if (vertexData_ != nullptr) - delete[] vertexData_; - if (centroids_ != nullptr) - delete[] centroids_; -} - -// Update (or finalise) centroid for current primitive type -void VertexChunk::updateCentroid(GLfloat x, GLfloat y, GLfloat z, bool finalise) -{ - // Accumulate centroid - auto coff = nDefinedTypes_ * 3; - centroids_[coff] += x; - centroids_[coff + 1] += y; - centroids_[coff + 2] += z; - // Finalise centroid? - if (finalise) - { - centroids_[coff] /= verticesPerType_; - centroids_[coff + 1] /= verticesPerType_; - centroids_[coff + 2] /= verticesPerType_; - } -} - -// Initialise structure -void VertexChunk::initialise(GLenum type, bool colourData) -{ - type_ = type; - dataPerVertex_ = (colourData ? 10 : 6); - if (type_ == GL_TRIANGLES) - verticesPerType_ = 3; - else if (type_ == GL_LINES) - verticesPerType_ = 2; - else if (type_ == GL_POINTS) - verticesPerType_ = 1; - else - Messenger::error("Invalid GLenum type given to VertexChunk::initialise ({})\n", type_); - maxVertices_ = VERTEXCHUNKSIZE * verticesPerType_; - nDefinedVertices_ = 0; - nDefinedTypes_ = 0; - vertexData_ = new GLfloat[maxVertices_ * dataPerVertex_]; - centroids_ = new GLfloat[VERTEXCHUNKSIZE * 3]; - for (auto n = 0; n < VERTEXCHUNKSIZE * 3; ++n) - centroids_[n] = 0.0f; -} - -// Define next vertex and normal -void VertexChunk::defineVertex(GLfloat x, GLfloat y, GLfloat z, GLfloat nx, GLfloat ny, GLfloat nz, bool calcCentroid) -{ - if (nDefinedVertices_ == maxVertices_) - Messenger::error("Vertex limit for VertexChunk reached.\n"); - auto index = nDefinedVertices_ * dataPerVertex_; - if (dataPerVertex_ == 10) - { - Messenger::error("No colour specified in vertex creation, but the primitive requires one.\n"); - index += 4; - } - // Store normal - vertexData_[index++] = nx; - vertexData_[index++] = ny; - vertexData_[index++] = nz; - // Store vertex - vertexData_[index++] = x; - vertexData_[index++] = y; - vertexData_[index++] = z; - // Increase vertex counter - ++nDefinedVertices_; - // Update centroid - auto finalise = (nDefinedVertices_ % verticesPerType_) == 0; - if (calcCentroid) - updateCentroid(x, y, z, finalise); - if (finalise) - ++nDefinedTypes_; -} - -// Define next vertex and normal with specific colour (as array) -void VertexChunk::defineVertex(GLfloat x, GLfloat y, GLfloat z, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat *colour, - bool calcCentroid) -{ - if (nDefinedVertices_ == maxVertices_) - Messenger::error("Vertex limit for VertexChunk reached.\n"); - auto index = nDefinedVertices_ * dataPerVertex_; - // Store colour - if (dataPerVertex_ != 10) - Messenger::error("Colour specified in vertex creation, but it is not required for primitive.\n"); - else - { - vertexData_[index++] = colour[0]; - vertexData_[index++] = colour[1]; - vertexData_[index++] = colour[2]; - vertexData_[index++] = colour[3]; - } - // Store normal - vertexData_[index++] = nx; - vertexData_[index++] = ny; - vertexData_[index++] = nz; - // Store vertex - vertexData_[index++] = x; - vertexData_[index++] = y; - vertexData_[index++] = z; - // Increase vertex counter - ++nDefinedVertices_; - // Update centroid - auto finalise = (nDefinedVertices_ % verticesPerType_) == 0; - if (calcCentroid) - updateCentroid(x, y, z, finalise); - if (finalise) - ++nDefinedTypes_; -} - -// Define next vertex and normal with specific colour -void VertexChunk::defineVertex(GLfloat x, GLfloat y, GLfloat z, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat r, GLfloat g, - GLfloat b, GLfloat a, bool calcCentroid) -{ - if (nDefinedVertices_ == maxVertices_) - Messenger::error("Vertex limit for VertexChunk reached.\n"); - auto index = nDefinedVertices_ * dataPerVertex_; - // Store colour - if (dataPerVertex_ != 10) - Messenger::error("Colour specified in vertex creation, but it is not required for primitive.\n"); - else - { - vertexData_[index++] = r; - vertexData_[index++] = g; - vertexData_[index++] = b; - vertexData_[index++] = a; - } - // Store normal - vertexData_[index++] = nx; - vertexData_[index++] = ny; - vertexData_[index++] = nz; - // Store vertex - vertexData_[index++] = x; - vertexData_[index++] = y; - vertexData_[index++] = z; - // Increase vertex counter - ++nDefinedVertices_; - // Update centroid - auto finalise = (nDefinedVertices_ % verticesPerType_) == 0; - if (calcCentroid) - updateCentroid(x, y, z, finalise); - if (finalise) - ++nDefinedTypes_; -} - -// Return whether current array is full -bool VertexChunk::full() { return (nDefinedVertices_ == maxVertices_); } - -// Forget all vertex data currently stored in array (but retain array) -void VertexChunk::forgetAll() -{ - nDefinedTypes_ = 0; - nDefinedVertices_ = 0; - for (auto n = 0; n < VERTEXCHUNKSIZE * 3; ++n) - centroids_[n] = 0.0f; -} - -// Return number of defined primitive (GL) types -int VertexChunk::nDefinedTypes() { return nDefinedTypes_; } - -// Return vertex array -GLfloat *VertexChunk::vertexData() { return vertexData_; } - -// Return centroid array -GLfloat *VertexChunk::centroids() { return centroids_; } - -// Return number of defined vertices in chunk -int VertexChunk::nDefinedVertices() { return nDefinedVertices_; } - -// Send to OpenGL (i.e. render) -void VertexChunk::sendToGL() -{ - if (nDefinedVertices_ == 0) - return; - // Does the vertex data contain colour-per-vertex information? - glInterleavedArrays(dataPerVertex_ == 10 ? GL_C4F_N3F_V3F : GL_N3F_V3F, 0, vertexData_); - glDrawArrays(type_, 0, nDefinedVertices_); -} diff --git a/src/gui/render/vertexChunk.h b/src/gui/render/vertexChunk.h deleted file mode 100644 index 398898f0da..0000000000 --- a/src/gui/render/vertexChunk.h +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include - -#define VERTEXCHUNKSIZE 1020 - -// Chunk of triangles -class VertexChunk -{ - public: - VertexChunk(); - ~VertexChunk(); - // List pointers - VertexChunk *prev, *next; - - private: - // Vertex data array (containing normal and possibly colour data) - GLfloat *vertexData_; - // Centroid array - GLfloat *centroids_; - // Number of data points per vertex (NR=6, CNR=10) - int dataPerVertex_; - // Number of defined vertices in current chunk - int nDefinedVertices_; - // NUmber of primitive types (nDefinedVertices/verticesPerType) currently defined - int nDefinedTypes_; - // Maximum number of allowable vertices - int maxVertices_; - // Primitive type (GL) - GLenum type_; - // Number of vertices per primitive type - int verticesPerType_; - - private: - // Update (and finalise) centroid for current primitive type - void updateCentroid(GLfloat x, GLfloat y, GLfloat z, bool finalise); - - public: - // Initialise structure - void initialise(GLenum type, bool colourData); - // Forget all vertex data currently stored in array (but retain array) - void forgetAll(); - // Define next vertex and normal - void defineVertex(GLfloat x, GLfloat y, GLfloat z, GLfloat nx, GLfloat ny, GLfloat nz, bool calcCentroid = true); - // Define next vertex, normal, and colour (as array) - void defineVertex(GLfloat x, GLfloat y, GLfloat z, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat *colour, - bool calcCentroid = true); - // Define next vertex, normal, and colour - void defineVertex(GLfloat x, GLfloat y, GLfloat z, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat r, GLfloat g, GLfloat b, - GLfloat a, bool calcCentroid = true); - // Return whether current array is full - bool full(); - // Return number of defined primitive (GL) types - int nDefinedTypes(); - // Return vertex array - GLfloat *vertexData(); - // Return centroid array - GLfloat *centroids(); - // Return number of defined vertices in chunk - int nDefinedVertices(); - // Send to OpenGL (i.e. render) - void sendToGL(); -}; diff --git a/src/gui/render/view.cpp b/src/gui/render/view.cpp deleted file mode 100644 index b549a60cdf..0000000000 --- a/src/gui/render/view.cpp +++ /dev/null @@ -1,1276 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#include "gui/render/view.h" -#include "gui/render/fontInstance.h" -#include "gui/render/renderable.h" -#include "math/cuboid.h" -#include "math/mathFunc.h" -#include -#include - -// Static Members -const double View::defaultZTranslation_ = -10.0; - -View::View(const std::vector> &renderables, FontInstance &fontInstance) - : fontInstance_(fontInstance), renderables_(renderables), axes_(*this, fontInstance) -{ - clear(); -} - -View::~View() {} - -// Clear view, resetting to defaults -void View::clear() -{ - // Geometry / position - xOffset_ = 0; - yOffset_ = 0; - xScale_ = 1.0; - yScale_ = 1.0; - aspectRatio_ = 1.0; - - // Role - viewType_ = View::AutoStretchedView; - linkedView_ = nullptr; - autoFollowType_ = View::NoAutoFollow; - autoFollowXLength_ = 20.0; - - // Projection / view - hasPerspective_ = false; - perspectiveFieldOfView_ = 20.0; - viewportMatrix_[0] = 0; - viewportMatrix_[1] = 0; - viewportMatrix_[2] = 0; - viewportMatrix_[3] = 0; - viewportVersion_ = 0; - viewTranslation_.set(0.0, 0.0, defaultZTranslation_); - viewViewportUsedAt_ = -1; - viewAxesUsedAt_ = -1; - viewRotationPoint_ = 0; - viewRotation_.setIdentity(); - viewRotationInversePoint_ = -1; - updateViewMatrix(); - - // Style - labelPointSize_ = 16.0; - titlePointSize_ = 18.0; - textZScale_ = -1.0; - flatLabelsIn3D_ = false; -} - -/* - * Geometry - */ - -// Set pixel offsets and scales for view -void View::setOffsetAndScale(int xOffset, int yOffset, double xScale, double yScale) -{ - xOffset_ = xOffset; - yOffset_ = yOffset; - xScale_ = xScale; - yScale_ = yScale; -} - -// Recalculate viewport matrix based on pixel dimensions provided -void View::recalculateViewport(int width, int height) -{ - viewportMatrix_[0] = xOffset_; - viewportMatrix_[1] = yOffset_; - viewportMatrix_[2] = width * xScale_; - viewportMatrix_[3] = height * yScale_; - aspectRatio_ = double(viewportMatrix_[2]) / double(viewportMatrix_[3]); - ++viewportVersion_; - - // Recalculate projection matrix - if ((viewType_ == View::NormalView) || (viewType_ == View::AutoStretchedView)) - { - projectionMatrix_ = calculateProjectionMatrix(hasPerspective_, defaultZTranslation_); - } - else - projectionMatrix_ = calculateProjectionMatrix(false, defaultZTranslation_); - - calculateFontScaling(); - - // Recalculate view matrix - updateViewMatrix(); - - recalculateView(true); -} - -// Translate viewport by specified pixel amounts -void View::translateViewport(int deltaX, int deltaY) -{ - viewportMatrix_[0] += deltaX; - viewportMatrix_[1] += deltaY; -} - -// Return viewport matrix -const GLuint *View::viewportMatrix() const { return viewportMatrix_; } - -/* - * Projection / View - */ - -// Return enum options for FormatType -EnumOptions View::viewTypes() -{ - return EnumOptions("ViewType", {{View::NormalView, "Normal"}, - {View::AutoStretchedView, "AutoStretched"}, - {View::FlatXYView, "FlatXY"}, - {View::FlatXZView, "FlatXZ"}, - {View::FlatZYView, "FlatZY"}}); -} - -// Return enum options for FormatType -EnumOptions View::autoFollowTypes() -{ - return EnumOptions( - "AutoFollowType", {{View::NoAutoFollow, "None"}, {View::AllAutoFollow, "All"}, {View::XAutoFollow, "X"}}); -} - -// Return calculated projection matrix -Matrix4 View::calculateProjectionMatrix(bool hasPerspective, double orthoZoom) const -{ - Matrix4 result; - - GLdouble top, bottom, right, left; - GLdouble nearClip = 0.5, farClip = 2000.0; - - if (hasPerspective) - { - // Use reversed top and bottom values so we get y-axis (0,1,0) pointing up - top = tan(DissolveMath::toRadians(perspectiveFieldOfView_)) * 0.5; - bottom = -top; - left = -aspectRatio_ * top; - right = aspectRatio_ * top; - result.setColumn(0, (nearClip * 2.0) / (right - left), 0.0, 0.0, 0.0); - result.setColumn(1, 0.0, (nearClip * 2.0) / (top - bottom), 0.0, 0.0); - result.setColumn(2, (right + left) / (right - left), (top + bottom) / (top - bottom), - -(farClip + nearClip) / (farClip - nearClip), -1.0); - result.setColumn(3, 0.0, 0.0, -(2.0 * nearClip * farClip) / (farClip - nearClip), 0.0); - } - else - { - top = -tan(DissolveMath::toRadians(perspectiveFieldOfView_)) * orthoZoom; - bottom = -top; - left = -aspectRatio_ * top; - right = aspectRatio_ * top; - - result.setColumn(0, 2.0 / (right - left), 0.0, 0.0, (right + left) / (right - left)); - result.setColumn(1, 0.0, 2.0 / (top - bottom), 0.0, (top + bottom) / (top - bottom)); - result.setColumn(2, 0.0, 0.0, -1.0 / farClip, 0.0); - result.setColumn(3, 0.0, 0.0, 0.0, 1.0); - } - - return result; -} - -// Update view matrix -void View::updateViewMatrix() -{ - // Create translation to centre of Axes coordinates - viewMatrix_.createTranslation(-axes_.coordCentre()); - - // Apply rotation matrix about this local centre - viewMatrix_.preMultiply(viewRotation_); - - // Apply translation to apply view shift and zoom (the latter only if using perspective) - viewMatrix_.applyPreTranslation(viewTranslation_.x, viewTranslation_.y, hasPerspective_ ? viewTranslation_.z : 0.0); - - // Calculate inverse - viewMatrixInverse_ = viewMatrix_; - viewMatrixInverse_.invert(); -} - -// Set view type -void View::setViewType(View::ViewType vt) -{ - viewType_ = vt; - - // Forcibly turn off perspective if this is a flat view - if ((viewType_ >= View::FlatXYView) && (viewType_ <= View::FlatZYView)) - setHasPerspective(false); - - showAllData(); - - resetViewMatrix(); - - updateViewMatrix(); - - ++viewRotationPoint_; -} - -// Return view type -View::ViewType View::viewType() const { return viewType_; } - -// Set linked View, if any -void View::setLinkedView(View *linkedView) { linkedView_ = linkedView; } - -// Return linked View, if any -View *View::linkedView() const { return linkedView_; } - -// Return whether view type is flat -bool View::isFlatView() const { return ((viewType_ >= View::FlatXYView) && (viewType_ <= View::FlatZYView)); } - -// Return projection matrix -Matrix4 View::projectionMatrix() const { return projectionMatrix_; } - -// Set whether the view uses perspective -void View::setHasPerspective(bool perspective) -{ - hasPerspective_ = perspective; - - projectionMatrix_ = calculateProjectionMatrix(hasPerspective_, viewTranslation_.z); - - calculateFontScaling(); -} - -// Return whether the view uses perspective -bool View::hasPerspective() const { return hasPerspective_; } - -// Update transformation (view) matrix -void View::setViewRotation(Matrix4 &mat) -{ - // If this is a two-dimensional or linked view, ignore the request - if ((viewType_ != View::NormalView) && (viewType_ != View::AutoStretchedView)) - return; - - viewRotation_ = mat; - - updateViewMatrix(); - - ++viewRotationPoint_; -} - -// Update single column of view matrix -void View::setViewRotationColumn(int column, double x, double y, double z) -{ - // If this is a two-dimensional or linked view, ignore the request - if ((viewType_ != View::NormalView) && (viewType_ != View::AutoStretchedView)) - return; - - viewRotation_.setColumn(column, x, y, z, 0.0); - - updateViewMatrix(); - - ++viewRotationPoint_; -} - -// Rotate view matrix about x and y by amounts specified -void View::rotateView(double dx, double dy) -{ - // If this is a two-dimensional or linked view, ignore the request - if ((viewType_ != View::NormalView) && (viewType_ != View::AutoStretchedView)) - return; - - Matrix4 A; - A.createRotationXY(dx, dy); // TODO Create Matrix4::applyPreRotationXY() function. - viewRotation_.preMultiply(A); - - updateViewMatrix(); - - ++viewRotationPoint_; -} - -// Return rotation matrix -const Matrix4 &View::viewRotation() const { return viewRotation_; } - -// Return view rotation inverse -Matrix4 View::viewRotationInverse() -{ - if (viewRotationPoint_ != viewRotationInversePoint_) - { - viewRotationInverse_ = viewRotation_; - viewRotationInverse_.invert(); - - viewRotationInversePoint_ = viewRotationPoint_; - } - - return viewRotationInverse_; -} - -// Set view translation -void View::setViewTranslation(double x, double y, double z) -{ - viewTranslation_.set(x, y, z); - - if (!hasPerspective_) - projectionMatrix_ = calculateProjectionMatrix(false, viewTranslation_.z); - - updateViewMatrix(); - - calculateFontScaling(); -} - -// Translate view matrix by amounts specified -void View::translateView(double dx, double dy, double dz) -{ - // If this is a two-dimensional view, ignore the request - if ((viewType_ != View::NormalView) && (viewType_ != View::AutoStretchedView)) - return; - - viewTranslation_.add(dx, dy, dz); - if ((!hasPerspective_) && (fabs(dz) > 1.0e-4)) - projectionMatrix_ = calculateProjectionMatrix(false, viewTranslation_.z); - - updateViewMatrix(); - - calculateFontScaling(); -} - -// Return current view translation -Vector3 View::viewTranslation() const { return viewTranslation_; } - -// Return view matrix -const Matrix4 &View::viewMatrix() const { return viewMatrix_; } - -// Project given data coordinates into world coordinates -Vector3 View::dataToWorld(Vector3 r) const -{ - Matrix4 vmat; - Vector4 pos, temp; - - // Get the world coordinates of r - multiply by view matrix - pos.set(r, 1.0); - temp = viewMatrix_ * pos; - - return Vector3(temp.x, temp.y, temp.z); -} - -// Project given data coordinates into screen coordinates -Vector3 View::dataToScreen(Vector3 r) const -{ - Vector4 screenr, tempscreen; - Vector4 worldr; - Matrix4 vmat; - Vector4 pos; - - // Projection formula is : worldr = P x M x r - pos.set(r, 1.0); - - // Get the world coordinates of the point - Multiply by view matrix - worldr = viewMatrix_ * pos; - screenr = projectionMatrix_ * worldr; - screenr.x /= screenr.w; - screenr.y /= screenr.w; - screenr.x = viewportMatrix_[0] + viewportMatrix_[2] * (screenr.x + 1) * 0.5; - screenr.y = viewportMatrix_[1] + viewportMatrix_[3] * (screenr.y + 1) * 0.5; - screenr.z = screenr.z / screenr.w; - - return Vector3(screenr.x, screenr.y, screenr.z); -} - -// Project given data coordinates into screen coordinates, with corresponding distance 'delta' in data -Vector3 View::dataToScreen(Vector3 r, double &lengthScale) const -{ - Vector4 screenr; - Vector4 worldr; - Matrix4 vmat; - Vector4 pos; - - // Projection formula is : worldr = P x M x r - pos.set(r, 1.0); - - // Get the world coordinates of the point - Multiply by view matrix - worldr = viewMatrix_ * pos; - screenr = projectionMatrix_ * worldr; - screenr.x /= screenr.w; - screenr.y /= screenr.w; - screenr.x = viewportMatrix_[0] + viewportMatrix_[2] * (screenr.x + 1) * 0.5; - screenr.y = viewportMatrix_[1] + viewportMatrix_[3] * (screenr.y + 1) * 0.5; - screenr.z = screenr.z / screenr.w; - - // Calculate 2D lengthscale around the point - multiply world[x+lengthScale] coordinates by P - worldr.x += lengthScale; - Vector4 tempScreen = projectionMatrix_ * worldr; - tempScreen.x /= tempScreen.w; - lengthScale = fabs((viewportMatrix_[0] + viewportMatrix_[2] * (tempScreen.x + 1) * 0.5) - screenr.x); - - return Vector3(screenr.x, screenr.y, screenr.z); -} - -// Project given data coordinates into screen coordinates using supplied projection matrix, rotation matrix and translation -// vector -Vector3 View::dataToScreen(Vector3 r, Matrix4 projectionMatrix, Matrix4 rotationMatrix, Vector3 translation) const -{ - Vector4 screenr, tempscreen; - Vector4 worldr; - Matrix4 vmat; - Vector4 pos; - - // Projection formula is : worldr = P x M x r - pos.set(r, 1.0); - - // Get the screen coordinates of the point - vmat = rotationMatrix; - vmat.applyPreTranslation(translation); - worldr = vmat * pos; - screenr = projectionMatrix * worldr; - screenr.x /= screenr.w; - screenr.y /= screenr.w; - screenr.x = viewportMatrix_[0] + viewportMatrix_[2] * (screenr.x + 1) * 0.5; - screenr.y = viewportMatrix_[1] + viewportMatrix_[3] * (screenr.y + 1) * 0.5; - screenr.z = screenr.z / screenr.w; - - return Vector3(screenr.x, screenr.y, screenr.z); -} - -// Return z translation necessary to display coordinates supplied, assuming the identity view matrix -double View::calculateRequiredZoom(double xMax, double yMax, double fraction) const -{ - // The supplied x and y extents should indicate the number of units in those directions - // from the origin that are to be displaye on-screen. The 'fraction' indicates how much of the - // available range on-screen to use, allowing a margin to be added. A value of '1.0' would - // put the extent with the highest units on the very edge of the display. - - Matrix4 viewMatrix, projectionMatrix = calculateProjectionMatrix(hasPerspective_, viewTranslation_.z); - Vector4 rScreen, rWorld, rModel(xMax, yMax, 0.0, 1.0); - Vector3 translation(0.0, 0.0, -1.0); - - // Sanity check - if (viewportMatrix_[2] == 0) - return 1.0; - if (viewportMatrix_[3] == 0) - return 1.0; - - // Calculate target screen coordinate - auto targetX = viewportMatrix_[0] + (1.0 + fraction) * viewportMatrix_[2] * 0.5; - auto targetY = viewportMatrix_[1] + (1.0 + fraction) * viewportMatrix_[3] * 0.5; - - auto count = 0; - do - { - // If not using perspective, must recalculate the projection matrix - if (!hasPerspective_) - projectionMatrix = calculateProjectionMatrix(false, translation.z); - - // Project the point : worldr = P x M x modelr - viewMatrix.setIdentity(); - viewMatrix.applyPreTranslation(translation); - rWorld = viewMatrix * rModel; - rScreen = projectionMatrix * rWorld; - rScreen.x /= rScreen.w; - rScreen.y /= rScreen.w; - rScreen.x = viewportMatrix_[0] + viewportMatrix_[2] * (rScreen.x + 1) * 0.5; - rScreen.y = viewportMatrix_[1] + viewportMatrix_[3] * (rScreen.y + 1) * 0.5; - rScreen.z = rScreen.z / rScreen.w; - - // Increase zoom distance - translation.z -= std::max(std::max(rScreen.x / targetX, rScreen.y / targetY), 1.0); - - // Limit the number of iterations so we can never get into an infinite loop - if (++count == 1000) - break; - - } while ((rScreen.x > targetX) || (rScreen.y > targetY)); - - return translation.z; -} - -// Convert screen coordinates into data space coordinates -Vector3 View::screenToData(int x, int y, double z) const -{ - Vector4 temp, worldr; - int newx, newy; - double dx, dy; - - // Project points at guide z-position and two other points along literal x and y to get scaling factors for screen - // coordinates - worldr.set(0.0, 0.0, z, 1.0); - temp = projectionMatrix_ * worldr; - newx = viewportMatrix_[0] + viewportMatrix_[2] * (temp.x / temp.w + 1.0) * 0.5; - newy = viewportMatrix_[1] + viewportMatrix_[3] * (temp.y / temp.w + 1.0) * 0.5; - - for (auto n = 0; n < 10; ++n) - { - // Determine new (better) coordinate from a yardstick centred at current world coordinates - temp = projectionMatrix_ * Vector4(worldr.x + 1.0, worldr.y + 1.0, worldr.z, worldr.w); - dx = viewportMatrix_[0] + viewportMatrix_[2] * (temp.x / temp.w + 1.0) * 0.5 - newx; - dy = viewportMatrix_[1] + viewportMatrix_[3] * (temp.y / temp.w + 1.0) * 0.5 - newy; - - worldr.add((x - newx) / dx, (y - newy) / dy, 0.0, 0.0); - temp = projectionMatrix_ * worldr; - newx = viewportMatrix_[0] + viewportMatrix_[2] * (temp.x / temp.w + 1.0) * 0.5; - newy = viewportMatrix_[1] + viewportMatrix_[3] * (temp.y / temp.w + 1.0) * 0.5; - if ((x == newx) && (y == newy)) - break; - } - - // Finally, invert to model coordinates - return viewMatrixInverse_ * Vector3(worldr.x, worldr.y, worldr.z); -} - -// Calculate selection axis coordinate from supplied screen coordinates -double View::screenToAxis(int axis, int x, int y, bool clamp) const -{ - // Check for a valid axis - if (axis == -1) - return 0.0; - - // Project axis coordinates to get a screen-based yardstick - auto axmin = dataToScreen(axes_.coordMin(axis)); - auto axmax = dataToScreen(axes_.coordMax(axis)); - - // Calculate vectors between axis minimum and mouse position (AM) and axis maximum (AB) - Vector3 ab(axmax.x - axmin.x, axmax.y - axmin.y, 0.0); - Vector3 am(x - axmin.x, y - axmin.y, 0.0); - auto amNorm = am, abNorm = ab; - auto ratio = am.magnitude() / ab.magnitude(); - abNorm.normalise(); - amNorm.normalise(); - - // Calculate slice axis value - no need to account for inverted axes here, since this is accounted for in the vectors - // axmin and axmax - double axisValue; - if (axes_.logarithmic(axis)) - axisValue = - pow(10, abNorm.dp(amNorm) * ratio * (log10(axes_.max(axis)) - log10(axes_.min(axis))) + log10(axes_.min(axis))); - else - axisValue = abNorm.dp(amNorm) * ratio * (axes_.max(axis) - axes_.min(axis)) + axes_.min(axis); - - // Clamp value to data range - if (clamp) - { - if (axisValue < axes_.min(axis)) - axisValue = axes_.min(axis); - else if (axisValue > axes_.max(axis)) - axisValue = axes_.max(axis); - } - - return axisValue; -} - -// Recalculate current view parameters (e.g. for 2D, autoStretched 3D etc.) -void View::recalculateView(bool force) -{ - // Check viewport size to try and avoid nan errors - if ((viewportMatrix_[2] == 0) || (viewportMatrix_[3] == 0)) - return; - - // If the view is neither flat nor autoStretched, there is nothing to do here... - if (viewType_ == View::NormalView) - return; - - // If we are already up-to-date (w.r.t. the associated axes) then we can also return now - auto upToDate = true; - if (force) - upToDate = false; - else if (viewAxesUsedAt_ != axes().version()) - upToDate = false; - else if (viewViewportUsedAt_ != viewportVersion_) - upToDate = false; - - if (upToDate) - return; - - int axis; - - // Calculate ourselves a 'standard' projection matrix - if (viewType_ == View::AutoStretchedView) - projectionMatrix_ = calculateProjectionMatrix(hasPerspective_, viewTranslation_.z); - else - projectionMatrix_ = calculateProjectionMatrix(false, defaultZTranslation_); - - // Create a temporary, orthographic projection matrix - Matrix4 tempProjection = calculateProjectionMatrix(false, defaultZTranslation_); - - /* - * To begin, set the stretch factors to our best first estimate, dividing our width by the range of the axes - * Doing this first will allow us to get much better values for the pixel overlaps we need later on - */ - - // -- Project a point one unit each along X and Y and subtract off the viewport centre coordinate in order to get - // literal 'pixels per unit' for (screen) X and Y - auto unit = dataToScreen(Vector3(1.0, 1.0, 0.0), tempProjection, Matrix4()); - unit.x -= viewportMatrix_[0] + viewportMatrix_[2] / 2.0; - unit.y -= viewportMatrix_[1] + viewportMatrix_[3] / 2.0; - unit.z = unit.y; - - // Get axis min/max, accounting for logarithmic axes - Vector3 axisMin, axisMax; - for (axis = 0; axis < 3; ++axis) - { - axisMin[axis] = axes_.logarithmic(axis) ? log10(axes_.min(axis)) : axes_.min(axis); - axisMax[axis] = axes_.logarithmic(axis) ? log10(axes_.max(axis)) : axes_.max(axis); - } - - // Decide how we will set stretch factors for each axis (initially set to standard xyy) - auto axisX = 0, axisY = 1; - Vector3i axisDir(0, 1, 1); - if (viewType_ == View::FlatXZView) - axisY = 2; - else if (viewType_ == View::FlatZYView) - { - axisDir.set(1, 1, 0); - axisX = 2; - } - - // Set axis stretch factors to fill available pixel width/height - for (axis = 0; axis < 3; ++axis) - { - axes_.setStretch(axis, viewportMatrix_[axisDir[axis] + 2] / (unit[axisDir[axis]] * (axes_.realRange(axis)))); - if (!std::isnormal(axes_.stretch(axis))) - axes_.setStretch(axis, 1.0); - } - - const auto margin = 10.0 * fontInstance_.scaleFactor(); - Matrix4 viewMat, B, viewMatrixInverse; - double tempMin, tempMax; - Vector3 coordMin[3], coordMax[3], labelMin, labelMax, a, b, globalMin, globalMax; - - // Iterate for a few cycles - for (auto cycle = 0; cycle < 5; ++cycle) - { - // We will now calculate more accurate stretch factors to apply to the X and Y axes. - // Project the axis limits on to the screen using the relevant viewmatrix + coordinate centre translation - viewMat.createTranslation(-axes().coordCentre()); - if (viewType_ == View::FlatXZView) - viewMat.applyPreRotationX(90.0); - else if (viewType_ == View::FlatZYView) - viewMat.applyPreRotationY(-90.0); - - // Calculate view rotation matrix inverse - viewMatrixInverse = viewMat; - viewMatrixInverse.removeTranslationAndScaling(); - viewMatrixInverse.invert(); - - // Calculate coordinates and global extremes over axes and labels - globalMin.set(1e9, 1e9, 1e9); - globalMax = -globalMin; - labelMin = globalMin; - labelMax = -labelMin; - for (axis = 0; axis < 3; ++axis) - { - // Skip third (i.e. 'z') axis - if ((axis != axisX) && (axis != axisY)) - continue; - - // Project axis min/max coordinates onto screen - a = dataToScreen(axes_.coordMin(axis), tempProjection, viewMat); - b = dataToScreen(axes_.coordMax(axis), tempProjection, viewMat); - coordMin[axis].set(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)); - coordMax[axis].set(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)); - - // Update global min/max - for (auto n = 0; n < 3; ++n) - { - if (coordMin[axis][n] < globalMin[n]) - globalMin[n] = coordMin[axis][n]; - if (coordMax[axis][n] > globalMax[n]) - globalMax[n] = coordMax[axis][n]; - } - - // Get bounding cuboid for axis text - Cuboid cuboid; - cuboid = axes_.labelPrimitive(axis).boundingCuboid(fontInstance_, viewMatrixInverse, textZScale_); - cuboid = axes_.titlePrimitive(axis).boundingCuboid(fontInstance_, viewMatrixInverse, textZScale_, cuboid); - - // Project cuboid extremes and store projected coordinates - a = dataToScreen(cuboid.minima(), tempProjection, viewMat); - b = dataToScreen(cuboid.maxima(), tempProjection, viewMat); - - // Update global and label min/max - for (auto n = 0; n < 3; ++n) - { - tempMin = std::min(a[n], b[n]); - tempMax = std::max(a[n], b[n]); - if (tempMin < globalMin[n]) - globalMin[n] = tempMin; - if (tempMax > globalMax[n]) - globalMax[n] = tempMax; - if (tempMin < labelMin[n]) - labelMin[n] = tempMin; - if (tempMax > labelMax[n]) - labelMax[n] = tempMax; - } - } - - // Now have screen coordinates of all necessary objects (axes and labels) - // Calculate total width and height of objects as they are arranged - double globalWidth = globalMax.x - globalMin.x; - double globalHeight = globalMax.y - globalMin.y; - axisPixelLength_[axisX] = coordMax[axisX].x - coordMin[axisX].x; - axisPixelLength_[axisY] = coordMax[axisY].y - coordMin[axisY].y; - - // Now, we know the width and height of the axis on its own, and the extra 'added' by the labels, so work out - // how much we need to shrink the axis by - double deltaWidth = (viewportMatrix_[2] - 2 * margin) - globalWidth; - double deltaHeight = (viewportMatrix_[3] - 2 * margin) - globalHeight; - - // So, need to lose deltaWidth and deltaHeight pixels from the axis exents - we'll do this by scaling the - // stretchfactor - double factor = axisPixelLength_[axisX] / (axisPixelLength_[axisX] - deltaWidth); - axes_.setStretch(axisX, axes_.stretch(axisX) * factor); - factor = axisPixelLength_[axisY] / (axisPixelLength_[axisY] - deltaHeight); - axes_.setStretch(axisY, axes_.stretch(axisY) * factor); - } - - // Set new rotation matrix and translation vector (if not AutoStretchedView) - if (viewType_ > View::AutoStretchedView) - { - viewRotation_.setIdentity(); - if (viewType_ == View::FlatXZView) - viewRotation_.applyPreRotationX(90.0); - else if (viewType_ == View::FlatZYView) - viewRotation_.applyPreRotationY(-90.0); - - // Set a translation in order to set the margins as requested - // The viewTranslation_ is applied in 'normal' coordinate axes, so viewTranslation_.x is along screen x etc. - viewTranslation_.zero(); - viewTranslation_[0] = (margin - (globalMin.x - viewportMatrix_[0])) / unit.x; - viewTranslation_[1] = (margin - (globalMin.y - viewportMatrix_[1])) / unit.y; - } - - // Recalculate font scaling - calculateFontScaling(); - - // Recalculate view matrix (translation may have changed) - updateViewMatrix(); - - // Store new versions of view - viewAxesUsedAt_ = axes().version(); - viewViewportUsedAt_ = viewportVersion_; -} - -// Reset view -void View::resetViewMatrix() -{ - // Reset view matrix only if a normal or autostretched view - if (viewType_ <= View::AutoStretchedView) - { - viewRotation_.setIdentity(); - viewTranslation_.set(0.0, 0.0, 0.0); - - // Calculate zoom to show all data - viewTranslation_.z = calculateRequiredZoom(axes_.realRange(0) * 0.5 * axes_.stretch(0), - axes_.realRange(1) * 0.5 * axes_.stretch(1), 0.9); - - // Recalculate projection matrix - projectionMatrix_ = calculateProjectionMatrix(hasPerspective_, viewTranslation_.z); - } - else - { - // Recalculate projection matrix - projectionMatrix_ = calculateProjectionMatrix(false, viewTranslation_.z); - } - - updateViewMatrix(); - - calculateFontScaling(); - - ++viewRotationPoint_; -} - -// Set display limits to show all available data -void View::showAllData(double xFrac, double yFrac, double zFrac) -{ - updateAxisLimits(xFrac, yFrac, zFrac); - - // Set axes limits to the extreme data values, making sure we have a sensible (i.e. non-zero range) - for (auto axis = 0; axis < 3; ++axis) - { - // Grab axis limits and make sure the limits are sensible, expanding only if the range is zero - double limitMin = axes_.limitMin(axis); - double limitMax = axes_.limitMax(axis); - Axes::ensureSensibleRange(limitMin, limitMax); - - axes_.setRange(axis, limitMin, limitMax); - } -} - -// Zoom to specified region -void View::zoomTo(Vector3 limit1, Vector3 limit2) -{ - // The provided limits should be in local axis coordinates, and may not be in min/max order - Vector3 newMin(std::min(limit1.x, limit2.x), std::min(limit1.y, limit2.y), std::min(limit1.z, limit2.z)); - Vector3 newMax(std::max(limit1.x, limit2.x), std::max(limit1.y, limit2.y), std::max(limit1.z, limit2.z)); - - // Check the view type and set relevant coordinates - if (isFlatView()) - { - auto axisX = 0, axisY = 1; - if (viewType_ == View::FlatXZView) - axisY = 2; - else if (viewType_ == View::FlatZYView) - axisX = 2; - axes_.setRange(axisX, newMin.get(axisX), newMax.get(axisX)); - axes_.setRange(axisY, newMin.get(axisY), newMax.get(axisY)); - } - else - { - // 3D view, so set all three axes - for (auto axis = 0; axis < 3; ++axis) - { - axes_.setMin(axis, newMin.get(axis)); - axes_.setMax(axis, newMax.get(axis)); - } - } -} - -// Scale the currently displayed range -void View::scaleRange(double factor) -{ - // Set the axis to skip (if any) - auto skipAxis = -1; - if (viewType_ == View::FlatXYView) - skipAxis = 2; - else if (viewType_ == View::FlatXZView) - skipAxis = 1; - else if (viewType_ == View::FlatZYView) - skipAxis = 0; - - // Loop over axes - for (auto axis = 0; axis < 3; ++axis) - { - if (axis == skipAxis) - continue; - - // Get current range of axis (either the real or logged values stored) - double halfRange = 0.5 * (axes_.max(axis) - axes_.min(axis)); - double mid = axes_.min(axis) + halfRange; - halfRange *= factor; - axes_.setMin(axis, mid - halfRange); - axes_.setMax(axis, mid + halfRange); - } -} - -// Centre 2D view at specified coordinates, optionally moving only by a fraction of the distance required -void View::centre2DAt(Vector3 centre, double fraction) -{ - // Get delta distance - const auto delta = (centre - axes_.centre()) * fraction; - - // Add to current axis limits - axes_.setRange(0, axes_.min(0) + delta.x, axes_.max(0) + delta.x); - axes_.setRange(1, axes_.min(1) + delta.y, axes_.max(1) + delta.y); - axes_.setRange(2, axes_.min(2) + delta.z, axes_.max(2) + delta.z); -} - -// Set auto-follow type in effect -void View::setAutoFollowType(AutoFollowType aft) -{ - autoFollowType_ = aft; - - autoFollowTransformVersions_.clear(); -} - -// Cycle auto-follow type in effect -void View::cycleAutoFollowType() { autoFollowType_ = (View::AutoFollowType)((autoFollowType_ + 1) % nAutoFollowTypes); } - -// Auto-follow type in effect -View::AutoFollowType View::autoFollowType() const { return autoFollowType_; } - -// Set length of X region to follow, if autoFollowType_ == XFollow -void View::setAutoFollowXLength(double length) { autoFollowXLength_ = length; } - -// Return length of X region to follow, if autoFollowType_ == XFollow -double View::autoFollowXLength() const { return autoFollowXLength_; } - -// Set axis limits based on current auto-follow type -void View::autoFollowData() -{ - // Is autofollowing enabled? - if (autoFollowType_ == View::NoAutoFollow) - return; - - // If renderable data access is disabled, there's nothing to do - if (!Renderable::sourceDataAccessEnabled()) - return; - - // Only update the axes if one of the renderables transformed data has changed, to prevent needless primitive - // regeneration further down the line - auto updateRequired = false; - for (const auto &rend : renderables_) - { - // If the renderable isn't in the list, or our stored version is different, we need to update - auto it = std::find_if(autoFollowTransformVersions_.begin(), autoFollowTransformVersions_.end(), - [rend](auto data) { return data.first == rend; }); - if (it != autoFollowTransformVersions_.end() && (it->second == rend->dataVersion())) - continue; - - // Update stored transformedData versions - if (it == autoFollowTransformVersions_.end()) - autoFollowTransformVersions_.emplace_back(rend, rend->valuesTransformDataVersion()); - else - it->second = rend->valuesTransformDataVersion(); - - updateRequired = true; - } - - if (!updateRequired) - return; - - if (autoFollowType_ == View::AllAutoFollow) - showAllData(); - else if (autoFollowType_ == View::XAutoFollow) - { - // Establish min / max limits on x axis - double xMin = dataMinima().x; - double xMax = dataMaxima().x; - if ((xMax - xMin) > autoFollowXLength_) - xMin = xMax - autoFollowXLength_; - - // Get y range over the horizontal range we've established - auto first = true; - double yMin = 0.0, yMax = 0.0, yMinTest = 0.0, yMaxTest = 0.0; - for (const auto &rend : renderables_) - { - // Skip this Renderable if it is not currently visible - if (!rend->isVisible()) - continue; - - // Get y limits for the this data - if (!rend->yRangeOverX(xMin, xMax, yMinTest, yMaxTest)) - continue; - if (first) - { - yMin = yMinTest; - yMax = yMaxTest; - first = false; - } - else - { - if (yMinTest < yMin) - yMin = yMinTest; - if (yMaxTest > yMax) - yMax = yMaxTest; - } - } - - // If we didn't have any data to work with, return the current axis limits - if (first) - { - yMax = axes_.limitMax(1); - yMin = axes_.limitMin(1); - } - else - { - // Increase the range by 5% either way - double yDelta = (yMax - yMin) * 0.05; - yMax += yDelta; - yMin -= yDelta; - } - - // Ensure a sensible range for the axes - Axes::ensureSensibleRange(xMin, xMax); - Axes::ensureSensibleRange(yMin, yMax); - - // Set new limits - axes_.setRange(0, xMin, xMax); - axes_.setRange(1, yMin, yMax); - } -} - -/* - * Axes - */ - -// Return data minima over all displayed renderables -Vector3 View::dataMinima() -{ - // If there are no Renderables, just return the current limits - if (renderables_.empty()) - return Vector3(axes_.limitMin(0), axes_.limitMin(1), axes_.limitMin(2)); - - auto nCounted = 0; - Vector3 v, minima; - for (const auto &rend : renderables_) - { - // Skip this Renderable if it is not currently visible - if (!rend->isVisible()) - continue; - - if (nCounted == 0) - minima = rend->limitsMin(); - else - { - v = rend->limitsMin(); - if (v.x < minima.x) - minima.x = v.x; - if (v.y < minima.y) - minima.y = v.y; - if (v.z < minima.z) - minima.z = v.z; - } - ++nCounted; - } - - return minima; -} - -// Return data maxima over all displayed renderables -Vector3 View::dataMaxima() -{ - // If there are no Renderables, just return the current limits - if (renderables_.empty()) - return Vector3(axes_.limitMax(0), axes_.limitMax(1), axes_.limitMax(2)); - - auto nCounted = 0; - Vector3 v, maxima; - for (const auto &rend : renderables_) - { - // Skip this Renderable if it is not currently visible - if (!rend->isVisible()) - continue; - - if (nCounted == 0) - maxima = rend->limitsMax(); - else - { - v = rend->limitsMax(); - if (v.x > maxima.x) - maxima.x = v.x; - if (v.y > maxima.y) - maxima.y = v.y; - if (v.z > maxima.z) - maxima.z = v.z; - } - ++nCounted; - } - - return maxima; -} - -// Return positive data minima over all displayed renderables -Vector3 View::positiveDataMinima() -{ - auto nCounted = 0; - Vector3 v, minima; - for (const auto &rend : renderables_) - { - // Skip this Renderable if it is not currently visible - if (!rend->isVisible()) - continue; - - if (nCounted == 0) - minima = rend->positiveLimitsMin(); - else - { - v = rend->positiveLimitsMin(); - if (v.x < minima.x) - minima.x = v.x; - if (v.y < minima.y) - minima.y = v.y; - if (v.z < minima.z) - minima.z = v.z; - } - ++nCounted; - } - - // If we didn't have any data to work with, return the current axis limits - if (nCounted == 0) - return Vector3(axes_.limitMin(0), axes_.limitMin(1), axes_.limitMin(2)); - else - return minima; -} - -// Return positive data minima over all displayed renderables -Vector3 View::positiveDataMaxima() -{ - auto nCounted = 0; - Vector3 v, maxima; - for (const auto &rend : renderables_) - { - // Skip this Renderable if it is not currently visible - if (!rend->isVisible()) - continue; - - if (nCounted == 0) - maxima = rend->positiveLimitsMax(); - else - { - v = rend->positiveLimitsMax(); - if (v.x > maxima.x) - maxima.x = v.x; - if (v.y > maxima.y) - maxima.y = v.y; - if (v.z > maxima.z) - maxima.z = v.z; - } - ++nCounted; - } - - // If we didn't have any data to work with, return the current axis limits - if (nCounted == 0) - return Vector3(axes_.limitMax(0), axes_.limitMax(1), axes_.limitMax(2)); - else - return maxima; -} - -// Update axis limits to represent data extent of associated collections -void View::updateAxisLimits(double xFrac, double yFrac, double zFrac) -{ - // Get transformed data extents - auto dataMin = dataMinima(); - auto dataMax = dataMaxima(); - auto dataMinPositive = positiveDataMinima(); - auto dataMaxPositive = positiveDataMaxima(); - - // The fractional values we've been passed tell us how much of the 'data' to include in the limits - // A positive value, 0.0 < f < 1.0, tells us to shrink the maximum limit. - // A negative value, -1.0 < f < 0.0, tells us to increase the minimum limit - - // Store the fractional values in a temporary Vector to make things easier - Vector3 fractions(xFrac, yFrac, zFrac); - - // Loop over axes - for (auto axis = 0; axis < 3; ++axis) - { - // Adjust limits - if (fractions[axis] > 0.0) - { - dataMax[axis] = dataMin[axis] + (dataMax[axis] - dataMin[axis]) * fractions[axis]; - dataMaxPositive[axis] = dataMinPositive[axis] + (dataMaxPositive[axis] - dataMinPositive[axis]) * fractions[axis]; - } - else - { - dataMin[axis] = dataMax[axis] - (dataMin[axis] - dataMax[axis]) * fractions[axis]; - dataMinPositive[axis] = dataMaxPositive[axis] - (dataMinPositive[axis] - dataMaxPositive[axis]) * fractions[axis]; - } - - // Set allowable range to avoid negative numbers if axis is now logarithmic - if (axes_.logarithmic(axis)) - { - axes_.setLimitMin(axis, dataMinPositive[axis]); - axes_.setLimitMax(axis, dataMaxPositive[axis]); - } - else - { - axes_.setLimitMin(axis, dataMin[axis]); - axes_.setLimitMax(axis, dataMax[axis]); - } - } - - recalculateView(); -} - -// Shift flat view axis limits by specified amounts -void View::shiftFlatAxisLimits(double deltaH, double deltaV) -{ - // If this is not a flat view, return now - if (!isFlatView()) - return; - - // Set indices for target axes - int axes[2]; - axes[0] = 0; - axes[1] = 1; - if (viewType_ == View::FlatXZView) - axes[1] = 2; - else if (viewType_ == View::FlatZYView) - { - axes[0] = 1; - axes[1] = 2; - } - - // Loop over axis indices, and set new limits - double deltas[2]; - deltas[0] = deltaH; - deltas[1] = deltaV; - for (auto n = 0; n < 2; ++n) - { - double range = axes_.realRange(axes[n]); - auto logarithmic = axes_.logarithmic(axes[n]); - double ppUnit = axisPixelLength_[axes[n]] / range; - - // Flip sign of delta if the axis is inverted - if (axes_.inverted(axes[n])) - deltas[n] = -deltas[n]; - - // Get adjusted min/max values - double newMin, newMax; - if (logarithmic) - { - newMin = pow(10, axes_.realMin(axes[n]) - deltas[n] / ppUnit); - newMax = pow(10, axes_.realMax(axes[n]) - deltas[n] / ppUnit); - } - else - { - newMin = axes_.min(axes[n]) - deltas[n] / ppUnit; - newMax = axes_.max(axes[n]) - deltas[n] / ppUnit; - } - - axes_.setMin(axes[n], newMin); - axes_.setMax(axes[n], newMax); - } -} - -// Shift flat view axis limits by specified fractional amounts -void View::shiftFlatAxisLimitsFractional(double fracH, double fracV) -{ - // Set indices for target axes - int axes[2]; - axes[0] = 0; - axes[1] = 1; - if (viewType_ == View::FlatXZView) - axes[1] = 2; - else if (viewType_ == View::FlatZYView) - { - axes[0] = 1; - axes[1] = 2; - } - - // Determine deltas based on fractional amounts specified - double deltaH = (axes_.max(axes[0]) - axes_.min(axes[0])) * fracH; - double deltaV = (axes_.max(axes[1]) - axes_.min(axes[1])) * fracV; - - shiftFlatAxisLimits(deltaH, deltaV); -} - -// Return axes for the view -Axes &View::axes() { return axes_; } - -const Axes &View::axes() const { return axes_; } - -/* - * Style - */ - -// Calculate font scaling factor -void View::calculateFontScaling() -{ - // Calculate text scaling factor - Vector3 translate(0.0, 0.0, viewTranslation_.z); - if (hasPerspective_) - translate.z = 0.5; - auto unit = dataToScreen(Vector3(0.0, 1.0, viewTranslation_.z), projectionMatrix_, Matrix4(), translate); - unit.y -= viewportMatrix_[1] + viewportMatrix_[3] * 0.5; - textZScale_ = unit.y; -} - -// Set font point size for axis value labels -void View::setLabelPointSize(double value) -{ - labelPointSize_ = value; - - axes_.setPrimitivesInvalid(); -} - -// Return font point size for axis value labels -double View::labelPointSize() const { return labelPointSize_; } - -// Return font point size for titles -void View::setTitlePointSize(double value) -{ - titlePointSize_ = value; - - axes_.setPrimitivesInvalid(); -} - -// Return font point size for titles -double View::titlePointSize() const { return titlePointSize_; } - -// Return text z scaling factor -double View::textZScale() const { return textZScale_; } - -// Set whether axis text labels are drawn flat in 3D views -void View::setFlatLabelsIn3D(bool flat) -{ - flatLabelsIn3D_ = flat; - - axes_.setPrimitivesInvalid(); -} - -// Whether axis text labels are drawn flat in 3D views -bool View::flatLabelsIn3D() const { return flatLabelsIn3D_; } diff --git a/src/gui/render/view.h b/src/gui/render/view.h deleted file mode 100644 index 5142019e8e..0000000000 --- a/src/gui/render/view.h +++ /dev/null @@ -1,259 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright (c) 2026 Team Dissolve and contributors - -#pragma once - -#include "gui/render/axes.h" -#include "gui/render/renderable.h" -#include "gui/render/renderableGroup.h" -#include "math/matrix4.h" - -// Forward Declarations -class FontInstance; - -// Rendering View -class View -{ - private: - // Associated FontInstance from parent viewer - FontInstance &fontInstance_; - // List of Renderables that we are to display - const std::vector> &renderables_; - - public: - View(const std::vector> &renderables, FontInstance &fontInstance); - ~View(); - // Clear view, resetting to defaults - void clear(); - - /* - * Geometry - */ - private: - // Pixel offsets for view - int xOffset_, yOffset_; - // Scale factors for view - double xScale_, yScale_; - // Aspect ratio of view - double aspectRatio_; - // Viewport matrix for GL - GLuint viewportMatrix_[4]; - // Version of viewport matrix - int viewportVersion_; - - public: - // Set pixel offsets and scales to use - void setOffsetAndScale(int xOffset, int yOffset, double xScale, double yScale); - // Recalculate viewport matrix based on pixel dimensions provided - void recalculateViewport(int width, int height); - // Translate viewport by specified pixel amounts - void translateViewport(int deltaX, int deltaY); - // Return viewport matrix - const GLuint *viewportMatrix() const; - - /* - * Projection / View - */ - public: - // View type - enum ViewType - { - NormalView, - AutoStretchedView, - FlatXYView, - FlatXZView, - FlatZYView, - nViewTypes - }; - // Return enum options for ViewType - static EnumOptions viewTypes(); - // AutoFollow type - enum AutoFollowType - { - NoAutoFollow, - AllAutoFollow, - XAutoFollow, - nAutoFollowTypes - }; - // Return enum options for AutoFollowType - static EnumOptions autoFollowTypes(); - - private: - // Type of view to use - ViewType viewType_; - // Linked View, if any - View *linkedView_; - // Projection matrix for GL - Matrix4 projectionMatrix_; - // Whether projection has perspective - bool hasPerspective_; - // Field of view angle used in projectionMatrix_ when using perspective - double perspectiveFieldOfView_; - // View rotation matrix for GL - Matrix4 viewRotation_; - // Logpoint for view rotation matrix - int viewRotationPoint_; - // View rotation matrix inverse - Matrix4 viewRotationInverse_; - // Logpoint for view rotation inverse matrix calculation - int viewRotationInversePoint_; - // Current translation of view - Vector3 viewTranslation_; - // Full view matrix (rotation + translation) - Matrix4 viewMatrix_; - // Inverse of view matrix - Matrix4 viewMatrixInverse_; - // Default z offset for translation matrix - static const double defaultZTranslation_; - // Axes version at which view matrix was last calculated (mostly for keeping 2D view correct) - int viewAxesUsedAt_; - // Viewport version at which view matrix was last calculated - int viewViewportUsedAt_; - // Auto-follow type in effect - AutoFollowType autoFollowType_; - // Transformed data versions at last auto-follow - std::vector, int>> autoFollowTransformVersions_; - // Length of X region to follow, if autoFollowType_ == XFollow - double autoFollowXLength_; - - private: - // Return calculated projection matrix - Matrix4 calculateProjectionMatrix(bool hasPerspective, double orthoZoom = 0.0) const; - - public: - // Set view type - void setViewType(View::ViewType vt); - // Return view type - View::ViewType viewType() const; - // Set linked View, if any - void setLinkedView(View *linkedView); - // Return linked View, if any - View *linkedView() const; - // Return whether view type is flat - bool isFlatView() const; - // Return projection matrix - Matrix4 projectionMatrix() const; - // Set whether the view uses perspective - void setHasPerspective(bool perspective); - // Return whether the view uses perspective - bool hasPerspective() const; - // Update view matrix - void setViewRotation(Matrix4 &mat); - // Update single column of view matrix - void setViewRotationColumn(int column, double x, double y, double z); - // Rotate view matrix about x and y by amounts specified - void rotateView(double dx, double dy); - // Return rotation matrix - const Matrix4 &viewRotation() const; - // Return view rotation inverse - Matrix4 viewRotationInverse(); - // Set view translation - void setViewTranslation(double x, double y, double z); - // Translate view matrix by amounts specified - void translateView(double dx, double dy, double dz); - // Return current view translation - Vector3 viewTranslation() const; - // Update view matrix - void updateViewMatrix(); - // Return view matrix - const Matrix4 &viewMatrix() const; - // Project given data coordinates into world coordinates - Vector3 dataToWorld(Vector3 r) const; - // Project given data coordinates into screen coordinates - Vector3 dataToScreen(Vector3 r) const; - // Project given data coordinates into screen coordinates, with corresponding distance 'delta' in data - Vector3 dataToScreen(Vector3 r, double &delta) const; - // Project given data coordinates into screen coordinates using supplied rotation matrix and translation vector - Vector3 dataToScreen(Vector3 r, Matrix4 projectionMatrix, Matrix4 rotationMatrix, Vector3 translation = Vector3()) const; - // Return z translation necessary to display coordinates supplied, assuming the identity view matrix - double calculateRequiredZoom(double xMax, double yMax, double fraction) const; - // Convert screen coordinates into data space coordinates - Vector3 screenToData(int x, int y, double z) const; - // Calculate selection axis coordinate from supplied screen coordinates - double screenToAxis(int axis, int x, int y, bool clamp) const; - // Recalculate current view parameters (e.g. for 2D, autostretched 3D etc.) - void recalculateView(bool force = false); - // Reset view matrix to face XY plane - void resetViewMatrix(); - // Set display limits to show all available data - void showAllData(double xFrac = 1.0, double yFrac = 1.0, double zFrac = 1.0); - // Zoom to specified region - void zoomTo(Vector3 limit1, Vector3 limit2); - // Scale the currently displayed range - void scaleRange(double factor); - // Centre 2D view at specified coordinates, optionally moving only by a fraction of the distance required - void centre2DAt(Vector3 centre, double fraction); - // Set auto-follow type in effect - void setAutoFollowType(AutoFollowType aft); - // Cycle auto-follow type in effect - void cycleAutoFollowType(); - // Return auto-follow type in effect - AutoFollowType autoFollowType() const; - // Set length of X region to follow, if autoFollowType_ == XFollow - void setAutoFollowXLength(double length); - // Return length of X region to follow, if autoFollowType_ == XFollow - double autoFollowXLength() const; - // Set axis limits based on current auto-follow type - void autoFollowData(); - - /* - * Axes - */ - private: - // Axes for the view - Axes axes_; - // Pixel 'lengths' of axes in flat views - Vector3 axisPixelLength_; - - public: - // Return data minima over all displayed renderables - Vector3 dataMinima(); - // Return data maxima over all displayed renderables - Vector3 dataMaxima(); - // Return positive data minima over all displayed renderables - Vector3 positiveDataMinima(); - // Return positive data maxima over all displayed renderables - Vector3 positiveDataMaxima(); - // Update axis limits to represent data extent of renderables - void updateAxisLimits(double xFrac = 1.0, double yFrac = 1.0, double zFrac = 1.0); - // Shift flat view axis limits by specified amounts - void shiftFlatAxisLimits(double deltaH, double deltaV); - // Shift flat view axis limits by specified fractional amounts - void shiftFlatAxisLimitsFractional(double fracH, double fracV); - // Return axes for the view - Axes &axes(); - const Axes &axes() const; - - /* - * Style - */ - private: - // Font scaling for axis value labels - double labelPointSize_; - // Font scaling for titles - double titlePointSize_; - // Text z scaling factor - double textZScale_; - // Whether axis text labels are drawn flat in 3D views - bool flatLabelsIn3D_; - - private: - // Calculate font scaling factor - void calculateFontScaling(); - - public: - // Set font point size for axis value labels - void setLabelPointSize(double value); - // Return font point size for axis value labels - double labelPointSize() const; - // Return font point size for titles - void setTitlePointSize(double value); - // Return font point size for titles - double titlePointSize() const; - // Return text z scaling factor - double textZScale() const; - // Set whether axis text labels are drawn flat in 3D views - void setFlatLabelsIn3D(bool flat); - // Whether axis text labels are drawn flat in 3D views - bool flatLabelsIn3D() const; -};