/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2020 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ //including our own h file #include //includes from fieldlinessequence, might not need all of them #include #include #include #include #include #include #include #include #include #include #include #include //test debugging tools more then logmanager #include #include #include #include #include #include #include //this is a call to use the nlohmann json file using json = nlohmann::json; namespace { //log category constexpr const char* _loggerCat = "renderableStreamNodes"; //gl variables for shaders, probably needed some of them atleast constexpr const GLuint VaPosition = 0; // MUST CORRESPOND TO THE SHADER PROGRAM constexpr const GLuint VaColor = 1; // MUST CORRESPOND TO THE SHADER PROGRAM constexpr const GLuint VaFiltering = 2; // MUST CORRESPOND TO THE SHADER PROGRAM constexpr const GLuint VaIndex = 3; // MUST CORRESPOND TO THE SHADER PROGRAM // ----- KEYS POSSIBLE IN MODFILE. EXPECTED DATA TYPE OF VALUE IN [BRACKETS] ----- // // ---------------------------- MANDATORY MODFILE KEYS ---------------------------- // // [STRING] "cdf", "json" or "osfls" constexpr const char* KeyInputFileType = "InputFileType"; // [STRING] should be path to folder containing the input files constexpr const char* KeySourceFolder = "SourceFolder"; // ---------------------- MANDATORY INPUT TYPE SPECIFIC KEYS ---------------------- // // [STRING] Currently supports: "batsrus", "enlil" & "pfss" constexpr const char* KeyJsonSimulationModel = "SimulationModel"; // ----------------------- OPTIONAL INPUT TYPE SPECIFIC KEYS ---------------------- // // [STRING ARRAY] constexpr const char* KeyCdfExtraVariables = "ExtraVariables"; // [STRING] constexpr const char* KeyCdfTracingVariable = "TracingVariable"; // [STRING] constexpr const char* KeyJsonScalingFactor = "ScaleToMeters"; // [BOOLEAN] If value False => Load in initializing step and store in RAM constexpr const char* KeyOslfsLoadAtRuntime = "LoadAtRuntime"; //[INT] Threshold Radius should have a range constexpr const char* KeyThresholdRadius = "ThresholdRadius"; // ---------------------------- OPTIONAL MODFILE KEYS ---------------------------- // // [STRING ARRAY] Values should be paths to .txt files constexpr const char* KeyColorTablePaths = "ColorTablePaths"; // [VEC2 ARRAY] Values should be entered as {X, Y}, where X & Y are numbers constexpr const char* KeyColorTableRanges = "ColorTableRanges"; //[INT] Line Width should have a range constexpr const char* minValTableRange = "minTableValue"; //[INT] Line Width should have a range constexpr const char* KeyLineWidth = "LineWidth"; // ------------- POSSIBLE STRING VALUES FOR CORRESPONDING MODFILE KEY ------------- // constexpr const char* ValueInputFileTypeCdf = "cdf"; constexpr const char* ValueInputFileTypeJson = "json"; constexpr const char* ValueInputFileTypeOsfls = "osfls"; //properties::PropertyOwner _pStreamGroup; constexpr openspace::properties::Property::PropertyInfo ColorModeInfo = { "colorMode", "Color Mode", "Color lines uniformly or using color tables based on specific values on nodes," "for examples flux values." }; constexpr openspace::properties::Property::PropertyInfo ColorFluxInfo = { "colorFlux", "Flux value to Color By", "Flux values used to color lines if the 'By Flux value' color method is selected." }; constexpr openspace::properties::Property::PropertyInfo ColorFluxMinInfo = { "colorFluxMin", "ColorTable Min Value", "Value to map to the lowest end of the color table." }; constexpr openspace::properties::Property::PropertyInfo ColorFluxMaxInfo = { "colorFluxMax", "ColorTable Max Value", "Value to map to the highest end of the color table." }; constexpr openspace::properties::Property::PropertyInfo ColorTablePathInfo = { "colorTablePath", "Path to Color Table", "Color Table/Transfer Function to use for 'By Quantity' coloring." }; // Size of simulated flow particles constexpr openspace::properties::Property::PropertyInfo StreamColorInfo = { "color", "Color", "Color of particles." }; constexpr openspace::properties::Property::PropertyInfo StreamsenabledInfo = { "streamsEnabled", "Stream Direction", "Toggles the rendering of moving particles along the lines. Can, for example, " "illustrate magnetic flow." }; constexpr openspace::properties::Property::PropertyInfo NodeSizeInfo = { "nodeSize", "Size of nodes", "Change the size of the nodes" }; constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = { "lineWidth", "Line Width", "This value specifies the line width of the field lines if the " "selected rendering method includes lines." }; constexpr openspace::properties::Property::PropertyInfo ThresholdFluxInfo = { "thresholdFlux", "Threshold flux value", "This value specifies the threshold that will be changed with the flux value." }; constexpr openspace::properties::Property::PropertyInfo FilteringInfo = { "filteringlower", "FilteringLower in AU", "Use filtering to show nodes within a given range." }; constexpr openspace::properties::Property::PropertyInfo FilteringUpperInfo = { "filteringupper", "FilteringUpper in AU", "Use filtering to show nodes within a given range." }; constexpr openspace::properties::Property::PropertyInfo AmountofNodesInfo = { "AmountofNodes", "Every nth node to render in", "Show only every nth node" }; constexpr openspace::properties::Property::PropertyInfo DefaultNodeSkipInfo = { "NodeSkipInfo", "Every nth node to render default", "Show only every nth node outside of skippingmethod" }; constexpr openspace::properties::Property::PropertyInfo ScalingmethodInfo = { "Scaling flux", "Scale the flux value with colortable", "Use scaling to color nodes with a given method." }; constexpr openspace::properties::Property::PropertyInfo NodeskipMethodInfo = { "Skipping Nodes", "How to select nodes to skip", "Methods to select nodes to skip." }; constexpr openspace::properties::Property::PropertyInfo colorTableRangeInfo = { "colorTableRange", "Color Table Range", "Valid range for the color table. [Min, Max]" }; constexpr openspace::properties::Property::PropertyInfo DomainZInfo = { "limitsZLower", "Z-limits Lower", "Valid range along the Z-axis. [Min, Max]" }; constexpr openspace::properties::Property::PropertyInfo FluxColorAlphaInfo = { "fluxColorAlpha", "Flux Color Alpha", "The value of alpha for the flux color mode" }; constexpr openspace::properties::Property::PropertyInfo FluxNodeskipThresholdInfo = { "Skipping Nodes by Flux", "Select nodes to skip by flux", "Skip nodes by Flux" }; constexpr openspace::properties::Property::PropertyInfo RadiusNodeSkipThresholdInfo = { "Skipping Nodes by Radius", "Select nodes to skip by Radius", "Skip nodes by Radius" }; enum class SourceFileType : int { Json = 0, Cdf, Osfls, Invalid }; float stringToFloat(const std::string input, const float backupValue = 0.f) { float tmp; try { tmp = std::stof(input); } catch (const std::invalid_argument& ia) { LWARNING(fmt::format( "Invalid argument: {}. '{}' is NOT a valid number", ia.what(), input )); return backupValue; } return tmp; } double stringToDouble(const std::string input, const float backupValue = 0.f) { double tmp; try { tmp = std::stod(input); } catch (const std::invalid_argument& ia) { LWARNING(fmt::format( "Invalid argument: {}. '{}' is NOT a valid number", ia.what(), input )); return backupValue; } return tmp; } //changed everything from dvec3 to vec3 glm::vec3 sphericalToCartesianCoord(glm::vec3 position) { glm::vec3 cartesianPosition = glm::vec3(); //LDEBUG("spherical R:" + std::to_string(position.x)); //ρsinφcosθ cartesianPosition.x = position.x * sin(position.z) * cos(position.y); //ρsinφsinθ cartesianPosition.y = position.x * sin(position.z) * sin(position.y); //ρcosφ cartesianPosition.z = position.x * cos(position.z); //LDEBUG("cartesian position x: " + std::to_string(cartesianPosition.x)); //cartesian position x : 0.002175 return cartesianPosition; } } //namespace namespace openspace { using namespace properties; RenderableStreamNodes::RenderableStreamNodes(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _pColorGroup({ "Color" }) , _pColorMode(ColorModeInfo, OptionProperty::DisplayType::Radio) , _pScalingmethod(ScalingmethodInfo, OptionProperty::DisplayType::Radio) , _pNodeskipMethod(NodeskipMethodInfo, OptionProperty::DisplayType::Radio) , _pColorFlux(ColorFluxInfo, OptionProperty::DisplayType::Dropdown) //, _pColorFluxMin(ColorFluxMinInfo) //, _pColorFluxMax(ColorFluxMaxInfo) , _pColorTablePath(ColorTablePathInfo) , _pStreamColor(StreamColorInfo, glm::vec4(0.96f, 0.88f, 0.8f, 0.5f), glm::vec4(0.f), glm::vec4(1.f)) , _pStreamsEnabled(StreamsenabledInfo, true) , _pStreamGroup({ "Streams" }) , _pNodesamountGroup({ "NodeGroup" }) , _pNodeSize(NodeSizeInfo, 2.f, 1.f, 20.f) , _pLineWidth(LineWidthInfo, 1.f, 1.f, 20.f) , _pColorTableRange(colorTableRangeInfo) , _pDomainZ(DomainZInfo) , _pFluxColorAlpha(FluxColorAlphaInfo, 1.f, 0.f, 1.f) , _pThresholdFlux(ThresholdFluxInfo, -10.f, -10.f, 10.f) // , _pFiltering(FilteringInfo, 100000.f, 10000000.f, 1000000000000.f) // , _pFilteringUpper(FilteringUpperInfo, 600000000000.f, 1000000.f, 1000000000000.f) , _pFiltering(FilteringInfo, 0.f, 0.f, 5.f) , _pFilteringUpper(FilteringUpperInfo, 5.f, 0.f, 5.f) , _pAmountofNodes(AmountofNodesInfo, 1, 1, 100) , _pDefaultNodeSkip(DefaultNodeSkipInfo, 1, 1, 100) , _pFluxNodeskipThreshold(FluxNodeskipThresholdInfo, 0, -10, 10) , _pRadiusNodeSkipThreshold(RadiusNodeSkipThresholdInfo, 0.f, 0.f, 5.f) { _dictionary = std::make_unique(dictionary); } void RenderableStreamNodes::definePropertyCallbackFunctions() { /*_pColorTablePath = _colorTablePaths[0]; _transferFunction->setPath(_pColorTablePath); _colorTablePaths[0] = _pColorTablePath;*/ _pColorFlux.onChange([this] { _pColorTablePath = _colorTablePaths[_pColorFlux]; }); _pColorTablePath.onChange([this] { _transferFunction->setPath(_pColorTablePath); _colorTablePaths[_pColorFlux] = _pColorTablePath; }); } void RenderableStreamNodes::setModelDependentConstants() { float limit = 8.f; // Just used as a default value. _pColorTableRange.setMinValue(glm::vec2(-limit)); _pColorTableRange.setMaxValue(glm::vec2(limit)); _pColorTableRange = glm::vec2(-2, 4); //float limitZ = 1000000000000; // Just used as a default value. float limitZMin = -1000000000000; float limitZMax = 1000000000000; _pDomainZ.setMinValue(glm::vec2(limitZMin)); _pDomainZ.setMaxValue(glm::vec2(limitZMax)); _pDomainZ = glm::vec2(limitZMin, limitZMax); } void RenderableStreamNodes::initializeGL() { // EXTRACT MANDATORY INFORMATION FROM DICTIONARY //std::string filepath = "C:/Users/chrad171//openspace/OpenSpace/sync/http/bastille_day_streamnodes/1/datawithoutprettyprint_newmethod.json"; //LDEBUG("testar json"); //log(ghoul::logging::LogLevel::Debug, _loggerCat, "testar json"); SourceFileType sourceFileType = SourceFileType::Invalid; if (!extractMandatoryInfoFromDictionary(sourceFileType)) { return; } // Set a default color table, just in case the (optional) user defined paths are // corrupt or not provided! _colorTablePaths.push_back(FieldlinesSequenceModule::DefaultTransferFunctionFile); _transferFunction = std::make_unique(absPath(_colorTablePaths[0])); // EXTRACT OPTIONAL INFORMATION FROM DICTIONARY std::string outputFolderPath; //extractOptionalInfoFromDictionary(outputFolderPath); // EXTRACT SOURCE FILE TYPE SPECIFIC INFOMRATION FROM DICTIONARY & GET STATES FROM // SOURCE if (!loadJsonStatesIntoRAM(outputFolderPath)) { return; } ghoul::Dictionary colorTablesPathsDictionary; if (_dictionary->getValue(KeyColorTablePaths, colorTablesPathsDictionary)) { const size_t nProvidedPaths = colorTablesPathsDictionary.size(); LDEBUG("Number of provided Paths: " + std::to_string(nProvidedPaths)); if (nProvidedPaths > 0) { // Clear the default! It is already specified in the transferFunction _colorTablePaths.clear(); for (size_t i = 1; i <= nProvidedPaths; ++i) { _colorTablePaths.push_back( colorTablesPathsDictionary.value(std::to_string(i))); } } } // dictionary is no longer needed as everything is extracted _dictionary.reset(); // No need to store source paths in memory if they are already in RAM! //if (!_loadingStatesDynamically) { // _sourceFiles.clear(); //} //_nStates = 274; setModelDependentConstants(); setupProperties(); extractTriggerTimesFromFileNames(); computeSequenceEndTime(); LDEBUG("filepath i init: " + std::to_string(_sourceFiles.size())); if (!_loadingStatesDynamically) { LoadfilesintoRam(); } std::string filepath = _sourceFiles[0]; //std::string filepath = "C:/Users/emiho502/desktop/OpenSpace/sync/http/bastille_day_streamnodes/1/datawithoutprettyprint_newmethod.json"; //std::vector vec = LoadJsonfile(filepath); // Setup shader program computeSequenceEndTime(); _shaderProgram = global::renderEngine.buildRenderProgram( "Streamnodes", absPath("${MODULE_FIELDLINESSEQUENCE}/shaders/streamnodes_vs.glsl"), absPath("${MODULE_FIELDLINESSEQUENCE}/shaders/streamnodes_fs.glsl") ); _uniformCache.streamColor = _shaderProgram->uniformLocation("streamColor"); _uniformCache.usingParticles = _shaderProgram->uniformLocation("usingParticles"); _uniformCache.nodeSize = _shaderProgram->uniformLocation("nodeSize"); _uniformCache.thresholdFlux = _shaderProgram->uniformLocation("thresholdFlux"); glGenVertexArrays(1, &_vertexArrayObject); glGenBuffers(1, &_vertexPositionBuffer); glGenBuffers(1, &_vertexColorBuffer); glGenBuffers(1, &_vertexFilteringBuffer); glGenBuffers(1, &_vertexindexBuffer); // Probably not needed, seems to be needed for additive blending //setRenderBin(Renderable::RenderBin::Overlay); } bool RenderableStreamNodes::LoadfilesintoRam() { //size_t filesnumbers = 270; for (size_t j = 0; j < _nStates; ++j) { std::ifstream streamdata(_sourceFiles[j]); if (!streamdata.is_open()) { LDEBUG("did not read the data.json file"); return false; } json jsonobj = json::parse(streamdata); const char* sNode = "node0"; const char* sStream = "stream0"; const char* sData = "data"; const json& jTmp = *(jsonobj.begin()); // First node in the file const char* sTime = "time"; //double testtime = jTmp[sTime]; std::string testtime = jsonobj["time"]; size_t lineStartIdx = 0; //Loop through all the nodes const int numberofStreams = 383; constexpr const float AuToMeter = 149597870700.f; // Astronomical Units _vertexPositions.clear(); _lineCount.clear(); _lineStart.clear(); _vertexRadius.clear(); _vertexColor.clear(); _vertexIndex.clear(); int counter = 0; int NodeIndexCounter = 0; const size_t nPoints = 1; for (int i = 0; i < numberofStreams; ++i) { //i += 20; /* if (i > 37 && i < 154) { i = 154; } if (i > 154 && i < 210) { i = 210; } if (i > 210) { break; } */ NodeIndexCounter = 0; for (json::iterator lineIter = jsonobj["stream" + std::to_string(i)].begin(); lineIter != jsonobj["stream" + std::to_string(i)].end(); ++lineIter) { std::string r = (*lineIter)["R"].get(); std::string phi = (*lineIter)["Phi"].get(); std::string theta = (*lineIter)["Theta"].get(); std::string flux = (*lineIter)["Flux"].get(); //--------FLOAT float rValue = stringToFloat(r); float phiValue = stringToFloat(phi); float thetaValue = stringToFloat(theta); float fluxValue = stringToFloat(flux); float ninetyDeToRad = 1.57079633f * 2; const float pi = 3.14159265359f; //float rTimesFluxValue = rValue * rValue * fluxValue; float rTimesFluxValue = fluxValue; _vertexColor.push_back(rTimesFluxValue); _vertexRadius.push_back(rValue); _vertexIndex.push_back(NodeIndexCounter); NodeIndexCounter++; rValue = rValue * AuToMeter; //if(thetaValue > 1.4 && thetaValue < 1.6){ //if(rTimesFluxValue > 0) glm::vec3 sphericalcoordinates = glm::vec3(rValue, phiValue, thetaValue); glm::vec3 position = sphericalToCartesianCoord(sphericalcoordinates); //KOLLA OM DEN KONVERTATION FROM DEGREE //Look in to convertion //Roterar åt fel håll counter clockwise //position.x = position.x * AuToMeter; //position.y = position.y * AuToMeter; //position.z = position.z * AuToMeter; _vertexPositions.push_back( position); ++counter; _lineCount.push_back(static_cast(nPoints)); _lineStart.push_back(static_cast(lineStartIdx)); lineStartIdx += nPoints; // int skipcounter = 0; // int nodeskipn = 10; // while (skipcounter < nodeskipn && lineIter != jsonobj["stream" + std::to_string(i)].end() - 1) { // ++lineIter; // ++skipcounter; // } // } } } LDEBUG("vertPos size:" + std::to_string(_vertexPositions.size())); LDEBUG("counter for how many times we push back" + std::to_string(counter)); _statesPos.push_back(_vertexPositions); _statesColor.push_back(_vertexColor); _statesRadius.push_back(_vertexRadius); _statesIndex.push_back(_vertexIndex); LDEBUG("_states size: " + std::to_string(_statesPos.size())); } return true; } /** * Extracts the general information (from the lua modfile) that is mandatory for the class * to function; such as the file type and the location of the source files. * Returns false if it fails to extract mandatory information! */ bool RenderableStreamNodes::extractMandatoryInfoFromDictionary( SourceFileType& sourceFileType) { _dictionary->getValue(SceneGraphNode::KeyIdentifier, _identifier); // ------------------- EXTRACT MANDATORY VALUES FROM DICTIONARY ------------------- // std::string inputFileTypeString; if (!_dictionary->getValue(KeyInputFileType, inputFileTypeString)) { LERROR(fmt::format("{}: The field {} is missing", _identifier, KeyInputFileType)); } else { // Verify that the input type is corrects if (inputFileTypeString == ValueInputFileTypeJson) { sourceFileType = SourceFileType::Json; } else { LERROR(fmt::format( "{}: {} is not a recognized {}", _identifier, inputFileTypeString, KeyInputFileType )); sourceFileType = SourceFileType::Invalid; return false; } } _colorTableRanges.push_back(glm::vec2(0, 1)); std::string sourceFolderPath; if (!_dictionary->getValue(KeySourceFolder, sourceFolderPath)) { LERROR(fmt::format("{}: The field {} is missing", _identifier, KeySourceFolder)); return false; } // Ensure that the source folder exists and then extract // the files with the same extension as ghoul::filesystem::Directory sourceFolder(sourceFolderPath); if (FileSys.directoryExists(sourceFolder)) { // Extract all file paths from the provided folder _sourceFiles = sourceFolder.readFiles( ghoul::filesystem::Directory::Recursive::No, ghoul::filesystem::Directory::Sort::Yes ); // Ensure that there are available and valid source files left if (_sourceFiles.empty()) { LERROR(fmt::format( "{}: {} contains no {} files", _identifier, sourceFolderPath, inputFileTypeString )); return false; } } else { LERROR(fmt::format( "{}: FieldlinesSequence {} is not a valid directory", _identifier, sourceFolderPath )); return false; } return true; } void RenderableStreamNodes::extractOptionalInfoFromDictionary( std::string& outputFolderPath) { // ------------------- EXTRACT OPTIONAL VALUES FROM DICTIONARY ------------------- // // bool streamsEnabled; //if (_dictionary->getValue(KeyStreamsEnabled, streamsEnabledValue)) { //_pStreamsEnabled = streamsEnabledValue; //} } bool RenderableStreamNodes::extractJsonInfoFromDictionary(fls::Model& model) { std::string modelStr; if (_dictionary->getValue(KeyJsonSimulationModel, modelStr)) { std::transform( modelStr.begin(), modelStr.end(), modelStr.begin(), [](char c) { return static_cast(::tolower(c)); } ); model = fls::stringToModel(modelStr); } else { LERROR(fmt::format( "{}: Must specify '{}'", _identifier, KeyJsonSimulationModel )); return false; } float lineWidthValue; if (_dictionary->getValue(KeyLineWidth, lineWidthValue)) { _pLineWidth = lineWidthValue; } float thresholdRadiusValue; if (_dictionary->getValue(KeyThresholdRadius, thresholdRadiusValue)) { _pThresholdFlux = thresholdRadiusValue; } float scaleFactor; if (_dictionary->getValue(KeyJsonScalingFactor, scaleFactor)) { _scalingFactor = scaleFactor; } else { LWARNING(fmt::format( "{}: Does not provide scalingFactor. Assumes coordinates are in meters", _identifier )); } return true; } void RenderableStreamNodes::setupProperties() { // -------------- Add non-grouped properties (enablers and buttons) -------------- // addProperty(_pStreamsEnabled); addProperty(_pLineWidth); //addProperty(_pDomainZ); // ----------------------------- Add Property Groups ----------------------------- // addPropertySubOwner(_pStreamGroup); addPropertySubOwner(_pColorGroup); addPropertySubOwner(_pNodesamountGroup); // ------------------------- Add Properties to the groups ------------------------ // _pColorGroup.addProperty(_pColorMode); _pColorGroup.addProperty(_pScalingmethod); _pNodesamountGroup.addProperty(_pNodeskipMethod); _pNodesamountGroup.addProperty(_pAmountofNodes); _pNodesamountGroup.addProperty(_pDefaultNodeSkip); _pNodesamountGroup.addProperty(_pNodeSize); _pNodesamountGroup.addProperty(_pFluxNodeskipThreshold); _pNodesamountGroup.addProperty(_pRadiusNodeSkipThreshold); //_pColorGroup.addProperty(_pColorFlux); //_pColorGroup.addProperty(_pColorFluxMin); //_pColorGroup.addProperty(_pColorFluxMax); _pColorGroup.addProperty(_pColorTableRange); _pColorGroup.addProperty(_pColorTablePath); _pColorGroup.addProperty(_pStreamColor); _pColorGroup.addProperty(_pFluxColorAlpha); _pStreamGroup.addProperty(_pThresholdFlux); _pStreamGroup.addProperty(_pFiltering); _pStreamGroup.addProperty(_pFilteringUpper); _pStreamGroup.addProperty(_pDomainZ); // --------------------- Add Options to OptionProperties --------------------- // _pColorMode.addOption(static_cast(ColorMethod::Uniform), "Uniform"); _pColorMode.addOption(static_cast(ColorMethod::ByFluxValue), "By Flux Value"); _pScalingmethod.addOption(static_cast(ScalingMethod::Flux), "Flux"); _pScalingmethod.addOption(static_cast(ScalingMethod::RFlux), "Radius * Flux"); _pScalingmethod.addOption(static_cast(ScalingMethod::R2Flux), "Radius^2 * Flux"); _pScalingmethod.addOption(static_cast(ScalingMethod::log10RFlux), "log10(r) * Flux"); _pScalingmethod.addOption(static_cast(ScalingMethod::lnRFlux), "ln(r) * Flux"); _pNodeskipMethod.addOption(static_cast(NodeskipMethod::Uniform), "Uniform"); _pNodeskipMethod.addOption(static_cast(NodeskipMethod::Flux), "Flux"); _pNodeskipMethod.addOption(static_cast(NodeskipMethod::Radius), "Radius"); definePropertyCallbackFunctions(); // Set defaults //_pColorFlux = 0; _pColorTablePath = _colorTablePaths[0]; } void RenderableStreamNodes::deinitializeGL() { glDeleteVertexArrays(1, &_vertexArrayObject); _vertexArrayObject = 0; glDeleteBuffers(1, &_vertexPositionBuffer); _vertexPositionBuffer = 0; glDeleteBuffers(1, &_vertexColorBuffer); _vertexColorBuffer = 0; glDeleteBuffers(1, &_vertexFilteringBuffer); _vertexFilteringBuffer = 0; glDeleteBuffers(1, &_vertexindexBuffer); _vertexindexBuffer = 0; if (_shaderProgram) { global::renderEngine.removeRenderProgram(_shaderProgram.get()); _shaderProgram = nullptr; } // Stall main thread until thread that's loading states is done! bool printedWarning = false; while (_isLoadingStateFromDisk) { if (!printedWarning) { LWARNING("Trying to destroy class when an active thread is still using it"); printedWarning = true; } std::this_thread::sleep_for(std::chrono::milliseconds(5)); } } bool RenderableStreamNodes::isReady() const { return _shaderProgram != nullptr; } // Extract J2000 time from file names // Requires files to be named as such: 'YYYY-MM-DDTHH-MM-SS-XXX.osfls' void RenderableStreamNodes::extractTriggerTimesFromFileNames() { // number of characters in filename (excluding '.json') constexpr const int FilenameSize = 23; // size(".json") constexpr const int ExtSize = 5; for (const std::string& filePath : _sourceFiles) { LDEBUG("filepath " + filePath); const size_t strLength = filePath.size(); // Extract the filename from the path (without extension) std::string timeString = filePath.substr( strLength - FilenameSize - ExtSize, FilenameSize - 1 ); // Ensure the separators are correct timeString.replace(4, 1, "-"); timeString.replace(7, 1, "-"); timeString.replace(13, 1, ":"); timeString.replace(16, 1, ":"); timeString.replace(19, 1, "."); const double triggerTime = Time::convertTime(timeString); LDEBUG("timestring " + timeString); _startTimes.push_back(triggerTime); } } void RenderableStreamNodes::updateActiveTriggerTimeIndex(double currentTime) { auto iter = std::upper_bound(_startTimes.begin(), _startTimes.end(), currentTime); if (iter != _startTimes.end()) { if (iter != _startTimes.begin()) { _activeTriggerTimeIndex = static_cast( std::distance(_startTimes.begin(), iter) ) - 1; } else { _activeTriggerTimeIndex = 0; } } else { _activeTriggerTimeIndex = static_cast(_nStates) - 1; } } void RenderableStreamNodes::render(const RenderData& data, RendererTasks&) { if (_activeTriggerTimeIndex != -1) { _shaderProgram->activate(); // Calculate Model View MatrixProjection const glm::dmat4 rotMat = glm::dmat4(data.modelTransform.rotation); const glm::dmat4 modelMat = glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * rotMat * glm::dmat4(glm::scale(glm::dmat4(1), glm::dvec3(data.modelTransform.scale))); const glm::dmat4 modelViewMat = data.camera.combinedViewMatrix() * modelMat; _shaderProgram->setUniform("modelViewProjection", data.camera.sgctInternal.projectionMatrix() * glm::mat4(modelViewMat)); // Flow/Particles _shaderProgram->setUniform(_uniformCache.streamColor, _pStreamColor); _shaderProgram->setUniform(_uniformCache.usingParticles, _pStreamsEnabled); _shaderProgram->setUniform(_uniformCache.nodeSize, 1); _shaderProgram->setUniform(_uniformCache.thresholdFlux, _pThresholdFlux); _shaderProgram->setUniform("colorMode", _pColorMode); _shaderProgram->setUniform("filterRadius", _pFiltering); _shaderProgram->setUniform("filterUpper", _pFilteringUpper); _shaderProgram->setUniform("ScalingMode", _pScalingmethod); _shaderProgram->setUniform("colorTableRange", _pColorTableRange.value()); _shaderProgram->setUniform("domainLimZ", _pDomainZ.value()); _shaderProgram->setUniform("Nodeskip", _pAmountofNodes); _shaderProgram->setUniform("Nodeskipdefault", _pDefaultNodeSkip); _shaderProgram->setUniform("NodeskipMethod", _pNodeskipMethod); _shaderProgram->setUniform("NodeskipFluxThreshold", _pFluxNodeskipThreshold); _shaderProgram->setUniform("NodeskipRadiusThreshold", _pRadiusNodeSkipThreshold); _shaderProgram->setUniform("fluxColorAlpha", _pFluxColorAlpha); if (_pColorMode == static_cast(ColorMethod::ByFluxValue)) { ghoul::opengl::TextureUnit textureUnit; textureUnit.activate(); _transferFunction->bind(); // Calls update internally _shaderProgram->setUniform("colorTable", textureUnit); //_shaderProgram->setUniform("colorTableRange", //_colorTableRanges[0]); } const std::vector& vertPos = _vertexPositions; glBindVertexArray(_vertexArrayObject); glLineWidth(_pLineWidth); //glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); /*glMultiDrawArrays( GL_LINE_STRIP, //_drawingOutputType, _lineStart.data(), _lineCount.data(), static_cast(_lineStart.size()) );*/ glPointSize(_pNodeSize); GLint temp = 0; glDrawArrays( GL_POINTS, temp, static_cast(_lineCount.size()) ); glBindVertexArray(0); _shaderProgram->deactivate(); } } inline void unbindGL() { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } void RenderableStreamNodes::computeSequenceEndTime() { if (_nStates > 1) { const double lastTriggerTime = _startTimes[_nStates - 1]; const double sequenceDuration = lastTriggerTime - _startTimes[0]; const double averageStateDuration = sequenceDuration / (static_cast(_nStates) - 1.0); _sequenceEndTime = lastTriggerTime + averageStateDuration; //_sequenceEndTime = lastTriggerTime; } else { // If there's just one state it should never disappear! _sequenceEndTime = DBL_MAX; } } void RenderableStreamNodes::update(const UpdateData& data) { if (_shaderProgram->isDirty()) { _shaderProgram->rebuildFromFile(); } //Everything below is for updating depending on time. const double currentTime = data.time.j2000Seconds(); const bool isInInterval = (currentTime >= _startTimes[0]) && (currentTime < _sequenceEndTime); //const bool isInInterval = true; if (isInInterval) { const size_t nextIdx = _activeTriggerTimeIndex + 1; if ( // true => Previous frame was not within the sequence interval //_activeTriggerTimeIndex < 0 || // true => We stepped back to a time represented by another state currentTime < _startTimes[_activeTriggerTimeIndex] || // true => We stepped forward to a time represented by another state (nextIdx < _nStates && currentTime >= _startTimes[nextIdx])) { updateActiveTriggerTimeIndex(currentTime); //LDEBUG("Vi borde uppdatera1"); // _mustLoadNewStateFromDisk = true; _needsUpdate = true; _activeStateIndex = _activeTriggerTimeIndex; } // else {we're still in same state as previous frame (no changes needed)} } else { //not in interval => set everything to false //LDEBUG("not in interval"); _activeTriggerTimeIndex = -1; _needsUpdate = false; } if (_needsUpdate) { //LDEBUG("needsupdate"); if(_loadingStatesDynamically){ if (!_isLoadingStateFromDisk) { _isLoadingStateFromDisk = true; LDEBUG("triggertime: " + std::to_string(_activeTriggerTimeIndex)); std::string filePath = _sourceFiles[_activeTriggerTimeIndex]; // auto vec = LoadJsonfile(filePath); std::thread readBinaryThread([this, f = std::move(filePath)]{ auto vec = LoadJsonfile(f); }); readBinaryThread.detach(); } _needsUpdate = false; _newStateIsReady = false; if(_vertexPositions.size() > 5800){ updatePositionBuffer(); updateVertexColorBuffer(); updateVertexFilteringBuffer(); updateVertexIndexBuffer(); } } //needs fix, right now it stops cuz it cant find the states. else if(!_statesPos[_activeTriggerTimeIndex].empty()){ _vertexPositions = _statesPos[_activeTriggerTimeIndex]; _vertexColor = _statesColor[_activeTriggerTimeIndex]; _vertexRadius = _statesRadius[_activeTriggerTimeIndex]; _vertexIndex = _statesIndex[_activeTriggerTimeIndex]; _needsUpdate = false; _newStateIsReady = false; updatePositionBuffer(); updateVertexColorBuffer(); updateVertexFilteringBuffer(); updateVertexIndexBuffer(); } } } std::vector RenderableStreamNodes::LoadJsonfile(std::string filepath) { //'YYYY-MM-DDTHH-MM-SS-XXX.osfls' //C:\Users\Chrad171\openspace\ //std::ifstream streamdata("C:/Users/emiho502/desktop/OpenSpace/sync/http/bastille_day_streamnodes/1/datawithoutprettyprint_newmethod.json"); //std::ifstream streamdata("C:/Users/chrad171//openspace/OpenSpace/sync/http/bastille_day_streamnodes/1/datawithoutprettyprint_newmethod.json"); std::ifstream streamdata(filepath); //std::ifstream streamdata("C:/Users/chris/Documents/openspace/Openspace_ourbranch/OpenSpace/sync/http/bastille_day_streamnodes/2/datawithoutprettyprint_newmethod.json"); if (!streamdata.is_open()) { LDEBUG("did not read the data.json file"); } json jsonobj = json::parse(streamdata); //json jsonobj; //streamdata >> jsonobj; //printDebug(jsonobj["stream0"]); //LDEBUG(jsonobj["stream0"]); // std::ofstream o("C:/Users/chris/Documents/openspace/Openspace_ourbranch/OpenSpace/sync/http/bastille_day_streamnodes/1/newdata2.json"); //o << jsonobj << std::endl; LDEBUG("vi callade på loadJSONfile med " + filepath); const char* sNode = "node0"; const char* sStream = "stream0"; const char* sData = "data"; const json& jTmp = *(jsonobj.begin()); // First node in the file const char* sTime = "time"; //double testtime = jTmp[sTime]; std::string testtime = jsonobj["time"]; //double testtime = Time::now(); //const json::value_type& variableNameVec = jTmp[sStream][sNode][sData]; //const size_t nVariables = variableNameVec.size(); size_t lineStartIdx = 0; //Loop through all the nodes const int numberofStreams = 383; constexpr const float AuToMeter = 149597870700.f; // Astronomical Units //constexpr const float ReToMeter = 6371000.f; // Earth radius //constexpr const float RsToMeter = 695700000.f; // Sun radius //const int coordToMeters = 1; //we have to have coordToMeters * our coord. _vertexPositions.clear(); _lineCount.clear(); _lineStart.clear(); _vertexRadius.clear(); _vertexColor.clear(); _vertexIndex.clear(); int counter = 0; int NodeIndexCounter = 0; const size_t nPoints = 1; for (int i = 0; i < numberofStreams; ++i) { //i += 20; /* if (i > 37 && i < 154) { i = 154; } if (i > 154 && i < 210) { i = 210; } if (i > 210) { break; } */ NodeIndexCounter = 0; for (json::iterator lineIter = jsonobj["stream" + std::to_string(i)].begin(); lineIter != jsonobj["stream" + std::to_string(i)].end(); ++lineIter) { // for (size_t k = 0; k < 1999; ++k) { // json::iterator lineIter = jsonobj["stream" + std::to_string(i)][std::to_string(k)].begin(); //lineIter += 20; //const size_t Nodesamount = //LDEBUG("testar debuggen"); //log(ghoul::logging::LogLevel::Debug, _loggerCat, lineIter.key()); //LDEBUG("stream" + std::to_string(i)); //LDEBUG("Phi value: " + (*lineIter)["Phi"].get()); //LDEBUG("Theta value: " + (*lineIter)["Theta"].get()); //LDEBUG("R value: " + (*lineIter)["R"].get()); //LDEBUG("Flux value: " + (*lineIter)["Flux"].get()); //probably needs some work with types, not loading in strings. std::string r = (*lineIter)["R"].get(); std::string phi = (*lineIter)["Phi"].get(); std::string theta = (*lineIter)["Theta"].get(); std::string flux = (*lineIter)["Flux"].get(); //LDEBUG("testar koordinater: " + r + "phi" + phi + "theta: " + theta); //LDEBUG("flux: " + r); //------DOUBLE /* double rvalue = stringToDouble(r); double phivalue = stringToDouble(phi); double thetavalue = stringToDouble(theta); const double pi = 3.14159265359; phivalue = phivalue * (180 / pi); thetavalue = thetavalue * (180 / pi); rvalue = rvalue * AuToMeter; */ //lineIter += 20; //--------FLOAT float rValue = stringToFloat(r); float phiValue = stringToFloat(phi); float thetaValue = stringToFloat(theta); float fluxValue = stringToFloat(flux); float ninetyDeToRad = 1.57079633f * 2; const float pi = 3.14159265359f; //phiValue = phiValue * (180.f / pi); //thetaValue = thetaValue + ninetyDeToRad; //(180.f / pi); //phiValue = phiValue + ninetyDeToRad; //float rTimesFluxValue = rValue * rValue * fluxValue; float rTimesFluxValue = fluxValue; _vertexColor.push_back(rTimesFluxValue); _vertexRadius.push_back(rValue); _vertexIndex.push_back(NodeIndexCounter); NodeIndexCounter = NodeIndexCounter + 1; rValue = rValue * AuToMeter; //if(thetaValue < 1.6 && thetaValue > 1.4){ //if(rTimesFluxValue > 0) glm::vec3 sphericalcoordinates = glm::vec3(rValue, phiValue, thetaValue); //glm::dvec3 sphericalcoordinates = // glm::dvec3(stringToDouble((*lineIter)["R"].get()), // stringToDouble((*lineIter)["Phi"].get()), // stringToDouble((*lineIter)["Theta"].get())); //precision issue, right now rounding up at around 7th decimal. Probably //around conversion with string to Double. //LDEBUG("R value after string to Float: " + std::to_string(stringToDouble //((*lineIter)["R"].get()))); //sphericalcoordinates.x = sphericalcoordinates.x * AuToMeter; glm::vec3 position = sphericalToCartesianCoord(sphericalcoordinates); //KOLLA OM DEN KONVERTATION FROM DEGREE //Look in to convertion //Roterar åt fel håll counter clockwise //position.x = position.x * AuToMeter; //position.y = position.y * AuToMeter; //position.z = position.z * AuToMeter; _vertexPositions.push_back( position); ++counter; // coordToMeters * glm::vec3( // stringToFloat((*lineIter)["Phi"].get(), 0.0f), // , // ) //); _lineCount.push_back(static_cast(nPoints)); _lineStart.push_back(static_cast(lineStartIdx)); lineStartIdx += nPoints; //_vertexColor.push_back(rTimesFluxValue); //_vertexRadius.push_back(rValue); //skipping nodes // int skipcounter = 0; // int nodeskipn = 10; //while (skipcounter < nodeskipn && lineIter != jsonobj["stream" + std::to_string(i)].end() - 1) { // ++lineIter; // ++skipcounter; // } //} } } LDEBUG("vertPos size:" + std::to_string(_vertexPositions.size())); LDEBUG("counter for how many times we push back" + std::to_string(counter)); //log(ghoul::logging::LogLevel::Debug, _loggerCat, lineIter.value()); // } // for (auto& el : jsonobj.items()) // { // LDEBUG(el.key()); // } LDEBUG("Time:" + testtime); //openspace::printDebug("testar json"): //for //LWARNING(fmt::format("Testar json", data)); //LWARNING(fmt::format("Testar json")); _isLoadingStateFromDisk = false; //streamdata.close(); return std::vector(); } void RenderableStreamNodes::updatePositionBuffer() { glBindVertexArray(_vertexArrayObject); glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); const std::vector& vertPos = _vertexPositions; glBufferData( GL_ARRAY_BUFFER, vertPos.size() * sizeof(glm::vec3), vertPos.data(), GL_STATIC_DRAW ); glEnableVertexAttribArray(VaPosition); glVertexAttribPointer(VaPosition, 3, GL_FLOAT, GL_FALSE, 0, 0); unbindGL(); } void RenderableStreamNodes::updateVertexColorBuffer() { glBindVertexArray(_vertexArrayObject); glBindBuffer(GL_ARRAY_BUFFER, _vertexColorBuffer); const std::vector& vertColor = _vertexColor; glBufferData( GL_ARRAY_BUFFER, vertColor.size() * sizeof(float), vertColor.data(), GL_STATIC_DRAW ); glEnableVertexAttribArray(VaColor); glVertexAttribPointer(VaColor, 1, GL_FLOAT, GL_FALSE, 0, 0); unbindGL(); } void RenderableStreamNodes::updateVertexFilteringBuffer() { glBindVertexArray(_vertexArrayObject); glBindBuffer(GL_ARRAY_BUFFER, _vertexFilteringBuffer); const std::vector& vertexRadius = _vertexRadius; glBufferData( GL_ARRAY_BUFFER, vertexRadius.size() * sizeof(float), vertexRadius.data(), GL_STATIC_DRAW ); glEnableVertexAttribArray(VaFiltering); glVertexAttribPointer(VaFiltering, 1, GL_FLOAT, GL_FALSE, 0, 0); unbindGL(); } void RenderableStreamNodes::updateVertexIndexBuffer() { glBindVertexArray(_vertexArrayObject); glBindBuffer(GL_ARRAY_BUFFER, _vertexindexBuffer); const std::vector& vertexIndex = _vertexIndex; glBufferData( GL_ARRAY_BUFFER, vertexIndex.size() * sizeof(float), vertexIndex.data(), GL_STATIC_DRAW ); glEnableVertexAttribArray(VaIndex); glVertexAttribPointer(VaIndex, 1, GL_FLOAT, GL_FALSE, 0, 0); unbindGL(); } const std::vector& RenderableStreamNodes::lineCount() const { return _lineCount; } const std::vector& RenderableStreamNodes::lineStart() const { return _lineStart; } bool RenderableStreamNodes::loadJsonStatesIntoRAM(const std::string& outputFolder) { return true; } } // namespace openspace