Added renderablefieldlines class which renders fieldlines as geometry

This commit is contained in:
Hans-Christian Helltegen
2014-06-05 10:12:42 -04:00
parent 67778209d2
commit 3373ffd10d
8 changed files with 344 additions and 71 deletions

View File

@@ -0,0 +1,74 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014 *
* *
* 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. *
****************************************************************************************/
#ifndef RENDERABLEFIELDLINES_H_
#define RENDERABLEFIELDLINES_H_
// open space includes
#include <openspace/rendering/renderablevolume.h>
// ghoul includes
#include <ghoul/opengl/programobject.h>
#include <ghoul/filesystem/file.h>
#ifdef __APPLE__
#include <memory>
#else
#include <mutex>
#endif
namespace openspace {
class RenderableFieldlines : public RenderableVolume {
public:
RenderableFieldlines(const ghoul::Dictionary& dictionary);
~RenderableFieldlines();
bool initialize();
bool deinitialize();
virtual void render(const Camera *camera, const psc& thisPosition);
virtual void update();
private:
ghoul::Dictionary _hintsDictionary;
std::string _filename;
ghoul::opengl::ProgramObject* _fieldlinesProgram;
GLuint _VAO;
std::mutex* _shaderMutex;
ghoul::filesystem::File* _vertexSourceFile;
ghoul::filesystem::File* _fragmentSourceFile;
bool _programUpdateOnSave;
void safeShaderCompilation();
std::vector<GLint> _lineStart;
std::vector<GLsizei> _lineCount;
};
} // namespace openspace
#endif // RENDERABLEFIELDLINES_H_

View File

@@ -25,7 +25,7 @@
#ifndef KAMELEONWRAPPER_H_
#define KAMELEONWRAPPER_H_
#include <glm/glm.hpp>
//#include <glm/glm.hpp>
#include <glm/gtx/std_based_type.hpp>
namespace ccmc {
@@ -54,13 +54,18 @@ public:
float* getUniformSampledVectorValues(const std::string& xVar, const std::string& yVar,
const std::string& zVar, glm::size3_t outDimensions);
float* getFieldLines(const std::string& xVar, const std::string& yVar,
float* getVolumeFieldLines(const std::string& xVar, const std::string& yVar,
const std::string& zVar, glm::size3_t outDimensions, std::vector<glm::vec3> seedPoints);
std::vector<std::vector<glm::vec3> > getFieldLines(const std::string& xVar,
const std::string& yVar, const std::string& zVar,
std::vector<glm::vec3> seedPoints);
private:
void traceCartesianFieldlines(const std::string& xVar, const std::string& yVar,
const std::string& zVar, glm::size3_t outDimensions,
std::vector<glm::vec3> seedPoints, TraceDirection direction, float* data);
std::vector<glm::vec3> traceCartesianFieldline(const std::string& xVar,
const std::string& yVar, const std::string& zVar,
glm::vec3 seedPoint, TraceDirection direction);
void getGridVariables(std::string& x, std::string& y, std::string& z);
void progressBar(int current, int end);

View File

@@ -0,0 +1,170 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014 *
* *
* 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. *
****************************************************************************************/
#include <openspace/rendering/renderablefieldlines.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/util/powerscaledcoordinate.h>
#include <openspace/util/kameleonwrapper.h>
namespace {
std::string _loggerCat = "RenderableFieldlines";
}
namespace openspace {
RenderableFieldlines::RenderableFieldlines(const ghoul::Dictionary& dictionary) :
RenderableVolume(dictionary), _VAO(0), _programUpdateOnSave(false) {
_shaderMutex = new std::mutex;
_filename = "";
if(dictionary.hasKey("Volume")) {
if(dictionary.getValue("Volume", _filename)) {
_filename = findPath(_filename);
}
}
LDEBUG("filename: " << _filename);
if(dictionary.hasKey("Hints"))
dictionary.getValue("Hints", _hintsDictionary);
std::string vshaderpath = "";
std::string fshaderpath = "";
if (dictionary.hasKey("Shaders")) {
ghoul::Dictionary shaderDictionary;
if(dictionary.getValue("Shaders", shaderDictionary)) {
if (shaderDictionary.hasKey("VertexShader")) {
shaderDictionary.getValue("VertexShader", vshaderpath);
}
if (shaderDictionary.hasKey("FragmentShader")) {
shaderDictionary.getValue("FragmentShader", fshaderpath);
}
vshaderpath = findPath(vshaderpath);
fshaderpath = findPath(fshaderpath);
_vertexSourceFile = new ghoul::filesystem::File(vshaderpath, false);
_fragmentSourceFile = new ghoul::filesystem::File(fshaderpath, false);
_fieldlinesProgram = new ghoul::opengl::ProgramObject("FieldlinesProgram");
ghoul::opengl::ShaderObject* vertexShader = new ghoul::opengl::ShaderObject(ghoul::opengl::ShaderObject::ShaderTypeVertex,vshaderpath);
ghoul::opengl::ShaderObject* fragmentShader = new ghoul::opengl::ShaderObject(ghoul::opengl::ShaderObject::ShaderTypeFragment,fshaderpath);
_fieldlinesProgram->attachObject(vertexShader);
_fieldlinesProgram->attachObject(fragmentShader);
}
}
if(dictionary.hasKey("UpdateOnSave")) {
dictionary.getValue("UpdateOnSave", _programUpdateOnSave);
}
setBoundingSphere(PowerScaledScalar::CreatePSS(5));
}
RenderableFieldlines::~RenderableFieldlines() {
}
bool RenderableFieldlines::initialize() {
assert(_filename != "");
KameleonWrapper kameleon(_filename, KameleonWrapper::Model::BATSRUS);
std::vector<glm::vec3> seedPoints;
for (int x = -3; x <= 3; x+=3) {
for (int y = -3; y <= 3; y+=3) {
for (int z = -3; z <= 3; z+=3) {
seedPoints.push_back(glm::vec3((float)x, (float)y, (float)z));
}
}
}
std::vector<std::vector<glm::vec3> > fieldlines = kameleon.getFieldLines("bx", "by", "bz", seedPoints);
std::vector<glm::vec3> vertexData;
LDEBUG("Fieldlines.size() = " << fieldlines.size());
int prevEnd = 0;
for (int i = 0; i < fieldlines.size(); i++) {
_lineStart.push_back(prevEnd);
_lineCount.push_back(fieldlines[i].size());
prevEnd = prevEnd + fieldlines[i].size();
vertexData.insert( vertexData.end(), fieldlines[i].begin(), fieldlines[i].end());
}
GLuint vertexPositionBuffer;
glGenVertexArrays(1, &_VAO); // generate array
glBindVertexArray(_VAO); // bind array
glGenBuffers(1, &vertexPositionBuffer); // generate buffer
glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer
glBufferData(GL_ARRAY_BUFFER, vertexData.size()*sizeof(glm::vec3), &vertexData.front(), GL_STATIC_DRAW);
// Vertex positions
GLuint vertexLocation = 0;
glEnableVertexAttribArray(vertexLocation);
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), reinterpret_cast<void*>(0));
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind buffer
glBindVertexArray(0); //unbind array
_fieldlinesProgram->compileShaderObjects();
_fieldlinesProgram->linkProgramObject();
return true;
}
bool RenderableFieldlines::deinitialize() {
return true;
}
void RenderableFieldlines::render(const Camera* camera, const psc& thisPosition) {
glm::mat4 transform = camera->viewProjectionMatrix();
glm::mat4 camTransform = camera->viewRotationMatrix();
psc relative = thisPosition-camera->position();
transform = transform*camTransform;
transform = glm::translate(transform, relative.vec3());
transform = glm::scale(transform, glm::vec3(0.1));
_shaderMutex->lock();
_fieldlinesProgram->activate();
_fieldlinesProgram->setUniform("modelViewProjection", transform);
glBindVertexArray(_VAO);
glMultiDrawArrays(GL_LINE_STRIP, &_lineStart[0], &_lineCount[0], _lineStart.size());
glBindVertexArray(0);
_fieldlinesProgram->deactivate();
_shaderMutex->unlock();
}
void RenderableFieldlines::update() {
}
void RenderableFieldlines::safeShaderCompilation() {
}
} // namespace openspace

View File

@@ -163,12 +163,13 @@ ghoul::opengl::Texture* RenderableVolume::loadVolume(const std::string& filepath
// Seed 'em all
std::vector<glm::vec3> seedPoints;
// seedPoints.push_back(glm::vec3(5.0, 0.0, 0.0));
for (int z = -5; z <= 5; z+=5) {
for (int y = -5; y <= 5; y+=5)
seedPoints.push_back(glm::vec3(5.0, (float)y, (float)z));
}
float* fieldlinesData = kw.getFieldLines(xVariable, yVariable, zVariable, dimensions, seedPoints);
float* fieldlinesData = kw.getVolumeFieldLines(xVariable, yVariable, zVariable, dimensions, seedPoints);
// float* rhoData = kw.getUniformSampledValues("rho", dimensions);
//
// // Combine fieldlines with rhoData, clamp to [0,1]

View File

@@ -190,9 +190,6 @@ void RenderableVolumeGL::render(const Camera *camera, const psc &thisPosition) {
_colorBoxRenderer->render(transform);
// Draw screenquad
glClearColor(0.2f, 0.2f, 0.2f, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
_shaderMutex->lock();
_twopassProgram->activate();
_twopassProgram->setUniform("stepSize", _stepSize);

View File

@@ -27,6 +27,7 @@
#include <cassert>
// renderables
#include <openspace/rendering/renderablefieldlines.h>
#include <openspace/rendering/planets/renderableplanet.h>
#include <openspace/rendering/renderablevolumeexpert.h>
#include <openspace/rendering/renderablevolumecl.h>
@@ -62,6 +63,7 @@ void FactoryManager::initialize()
_manager->factory<Renderable>()->registerClass<RenderableVolumeExpert>(
"RenderableVolumeExpert");
_manager->factory<Renderable>()->registerClass<Flare>("RenderableFlare");
_manager->factory<Renderable>()->registerClass<RenderableFieldlines>("RenderableFieldlines");
// Add Ephimerides
_manager->addFactory(new ghoul::TemplateFactory<Ephemeris>);
@@ -102,4 +104,4 @@ void FactoryManager::addFactory(ghoul::TemplateFactoryBase* factory) {
}
} // namespace openspace
} // namespace openspace

View File

@@ -237,7 +237,7 @@ float* KameleonWrapper::getUniformSampledVectorValues(const std::string& xVar, c
return data;
}
float* KameleonWrapper::getFieldLines(const std::string& xVar,
float* KameleonWrapper::getVolumeFieldLines(const std::string& xVar,
const std::string& yVar, const std::string& zVar,
glm::size3_t outDimensions, std::vector<glm::vec3> seedPoints) {
assert(_model && _interpolator);
@@ -247,11 +247,28 @@ float* KameleonWrapper::getFieldLines(const std::string& xVar,
int size = outDimensions.x*outDimensions.y*outDimensions.z;
float* data = new float[size];
std::vector<glm::vec3> line;
if (_type == Model::BATSRUS) {
// Bi-directional tracing of fieldlines
traceCartesianFieldlines(xVar, yVar, zVar, outDimensions, seedPoints, TraceDirection::FORWARD, data);
traceCartesianFieldlines(xVar, yVar, zVar, outDimensions, seedPoints, TraceDirection::BACK, data);
for (glm::vec3 seedPoint : seedPoints) {
line = traceCartesianFieldline(xVar, yVar, zVar, seedPoint, TraceDirection::FORWARD);
for (glm::vec3 point : line) {
int vPosX = std::floor(outDimensions.x*(point.x-_xMin)/(_xMax-_xMin));
int vPosY = std::floor(outDimensions.y*(point.y-_yMin)/(_yMax-_yMin));
int vPosZ = std::floor(outDimensions.z*(point.z-_zMin)/(_zMax-_zMin));
int index = vPosX + vPosY*outDimensions.x + vPosZ*outDimensions.x*outDimensions.y;
data[index] = 1.0;
}
line = traceCartesianFieldline(xVar, yVar, zVar, seedPoint, TraceDirection::BACK);
for (glm::vec3 point : line) {
int vPosX = std::floor(outDimensions.x*(point.x-_xMin)/(_xMax-_xMin));
int vPosY = std::floor(outDimensions.y*(point.y-_yMin)/(_yMax-_yMin));
int vPosZ = std::floor(outDimensions.z*(point.z-_zMin)/(_zMax-_zMin));
int index = vPosX + vPosY*outDimensions.x + vPosZ*outDimensions.x*outDimensions.y;
data[index] = 1.0;
}
}
} else {
LERROR("Fieldlines are only supported for BATSRUS model");
}
@@ -259,71 +276,79 @@ float* KameleonWrapper::getFieldLines(const std::string& xVar,
return data;
}
void KameleonWrapper::traceCartesianFieldlines(const std::string& xVar,
const std::string& yVar, const std::string& zVar,
glm::size3_t outDimensions, std::vector<glm::vec3> seedPoints,
TraceDirection direction, float* data) {
std::vector<std::vector<glm::vec3> > KameleonWrapper::getFieldLines(
const std::string& xVar, const std::string& yVar,
const std::string& zVar, std::vector<glm::vec3> seedPoints) {
assert(_model && _interpolator);
assert(_type == Model::ENLIL || _type == Model::BATSRUS);
LINFO("Creating " << seedPoints.size() << " fieldlines from variables " << xVar << " " << yVar << " " << zVar);
std::vector<glm::vec3> fLine, bLine;
std::vector<std::vector<glm::vec3> > fieldLines;
if (_type == Model::BATSRUS) {
for (glm::vec3 seedPoint : seedPoints) {
fLine = traceCartesianFieldline(xVar, yVar, zVar, seedPoint, TraceDirection::FORWARD);
bLine = traceCartesianFieldline(xVar, yVar, zVar, seedPoint, TraceDirection::BACK);
bLine.insert(bLine.begin(), fLine.rbegin(), fLine.rend());
fieldLines.push_back(bLine);
}
} else {
LERROR("Fieldlines are only supported for BATSRUS model");
}
return fieldLines;
}
std::vector<glm::vec3> KameleonWrapper::traceCartesianFieldline(
const std::string& xVar, const std::string& yVar,
const std::string& zVar, glm::vec3 seedPoint, TraceDirection direction) {
int highNumber = 100000;
glm::vec3 pos, k1, k2, k3, k4;
std::vector<glm::vec3> line;
float stepSize = 2.0;
float stepX = stepSize*(_xMax-_xMin)/(static_cast<float>(outDimensions.x));
float stepY = stepSize*(_yMax-_yMin)/(static_cast<float>(outDimensions.y));
float stepZ = stepSize*(_zMax-_zMin)/(static_cast<float>(outDimensions.z));
float stepX = 0.5, stepY = 0.5, stepZ = 0.5;
for (int i = 0; i < seedPoints.size(); ++i) {
progressBar(i, seedPoints.size());
pos = seedPoints.at(i);
int avoidInfLoopPlz = 0;
while (pos.x < _xMax && pos.x > _xMin &&
pos.y < _yMax && pos.y > _yMin &&
pos.z < _zMax && pos.z > _zMin) {
int numSteps = 0;
int maxSteps = 1000;
pos = seedPoint;
// Save position
int vPosX = std::floor(outDimensions.x*(pos.x-_xMin)/(_xMax-_xMin));
int vPosY = std::floor(outDimensions.y*(pos.y-_yMin)/(_yMax-_yMin));
int vPosZ = std::floor(outDimensions.z*(pos.z-_zMin)/(_zMax-_zMin));
int index = vPosX + vPosY*outDimensions.x + vPosZ*outDimensions.x*outDimensions.y;
data[index] = 1.0;
// While we are inside the models boundries and not inside earth
while ((pos.x < _xMax && pos.x > _xMin && pos.y < _yMax && pos.y > _yMin &&
pos.z < _zMax && pos.z > _zMin) && !(pos.x < 1.0 && pos.x > -1.0 &&
pos.y < 1.0 && pos.y > -1.0 && pos.z < 1.0 && pos.z > -1.0)) {
// Calculate the next position
// Euler
// dir.x = _interpolator->interpolate(xVar, pos.x, pos.y, pos.z);
// dir.y = _interpolator->interpolate(yVar, pos.x, pos.y, pos.z);
// dir.z = _interpolator->interpolate(zVar, pos.x, pos.y, pos.z);
// dir = (float)direction*glm::normalize(dir);
// pos = glm::vec3(stepX*dir.x+pos.x, stepY*dir.y+pos.y, stepZ*dir.z+pos.z);
// Save position
line.push_back(pos);
// Runge-Kutta 4th order
k1.x = _interpolator->interpolate(xVar, pos.x, pos.y, pos.z);
k1.y = _interpolator->interpolate(yVar, pos.x, pos.y, pos.z);
k1.z = _interpolator->interpolate(zVar, pos.x, pos.y, pos.z);
k1 = (float)direction*glm::normalize(k1);
k2.x = _interpolator->interpolate(xVar, pos.x+(stepX/2.0)*k1.x, pos.y+(stepY/2.0)*k1.y, pos.z+(stepZ/2.0)*k1.z);
k2.y = _interpolator->interpolate(yVar, pos.x+(stepX/2.0)*k1.x, pos.y+(stepY/2.0)*k1.y, pos.z+(stepZ/2.0)*k1.z);
k2.z = _interpolator->interpolate(zVar, pos.x+(stepX/2.0)*k1.x, pos.y+(stepY/2.0)*k1.y, pos.z+(stepZ/2.0)*k1.z);
k2 = (float)direction*glm::normalize(k2);
k3.x = _interpolator->interpolate(xVar, pos.x+(stepX/2.0)*k2.x, pos.y+(stepY/2.0)*k2.y, pos.z+(stepZ/2.0)*k2.z);
k3.y = _interpolator->interpolate(yVar, pos.x+(stepX/2.0)*k2.x, pos.y+(stepY/2.0)*k2.y, pos.z+(stepZ/2.0)*k2.z);
k3.z = _interpolator->interpolate(zVar, pos.x+(stepX/2.0)*k2.x, pos.y+(stepY/2.0)*k2.y, pos.z+(stepZ/2.0)*k2.z);
k3 = (float)direction*glm::normalize(k3);
k4.x = _interpolator->interpolate(xVar, pos.x+stepX*k3.x, pos.y+stepY*k3.y, pos.z+stepZ*k3.z);
k4.y = _interpolator->interpolate(yVar, pos.x+stepX*k3.x, pos.y+stepY*k3.y, pos.z+stepZ*k3.z);
k4.z = _interpolator->interpolate(zVar, pos.x+stepX*k3.x, pos.y+stepY*k3.y, pos.z+stepZ*k3.z);
k4 = (float)direction*glm::normalize(k4);
pos.x = pos.x + (stepX/6.0)*(k1.x + 2.0*k2.x + 2.0*k3.x + k4.x);
pos.y = pos.y + (stepY/6.0)*(k1.y + 2.0*k2.y + 2.0*k3.y + k4.y);
pos.z = pos.z + (stepZ/6.0)*(k1.z + 2.0*k2.z + 2.0*k3.z + k4.z);
// Calculate new position with Runge-Kutta 4th order
k1.x = _interpolator->interpolate(xVar, pos.x, pos.y, pos.z);
k1.y = _interpolator->interpolate(yVar, pos.x, pos.y, pos.z);
k1.z = _interpolator->interpolate(zVar, pos.x, pos.y, pos.z);
k1 = (float)direction*glm::normalize(k1);
k2.x = _interpolator->interpolate(xVar, pos.x+(stepX/2.0)*k1.x, pos.y+(stepY/2.0)*k1.y, pos.z+(stepZ/2.0)*k1.z);
k2.y = _interpolator->interpolate(yVar, pos.x+(stepX/2.0)*k1.x, pos.y+(stepY/2.0)*k1.y, pos.z+(stepZ/2.0)*k1.z);
k2.z = _interpolator->interpolate(zVar, pos.x+(stepX/2.0)*k1.x, pos.y+(stepY/2.0)*k1.y, pos.z+(stepZ/2.0)*k1.z);
k2 = (float)direction*glm::normalize(k2);
k3.x = _interpolator->interpolate(xVar, pos.x+(stepX/2.0)*k2.x, pos.y+(stepY/2.0)*k2.y, pos.z+(stepZ/2.0)*k2.z);
k3.y = _interpolator->interpolate(yVar, pos.x+(stepX/2.0)*k2.x, pos.y+(stepY/2.0)*k2.y, pos.z+(stepZ/2.0)*k2.z);
k3.z = _interpolator->interpolate(zVar, pos.x+(stepX/2.0)*k2.x, pos.y+(stepY/2.0)*k2.y, pos.z+(stepZ/2.0)*k2.z);
k3 = (float)direction*glm::normalize(k3);
k4.x = _interpolator->interpolate(xVar, pos.x+stepX*k3.x, pos.y+stepY*k3.y, pos.z+stepZ*k3.z);
k4.y = _interpolator->interpolate(yVar, pos.x+stepX*k3.x, pos.y+stepY*k3.y, pos.z+stepZ*k3.z);
k4.z = _interpolator->interpolate(zVar, pos.x+stepX*k3.x, pos.y+stepY*k3.y, pos.z+stepZ*k3.z);
k4 = (float)direction*glm::normalize(k4);
pos.x = pos.x + (stepX/6.0)*(k1.x + 2.0*k2.x + 2.0*k3.x + k4.x);
pos.y = pos.y + (stepY/6.0)*(k1.y + 2.0*k2.y + 2.0*k3.y + k4.y);
pos.z = pos.z + (stepZ/6.0)*(k1.z + 2.0*k2.z + 2.0*k3.z + k4.z);
++avoidInfLoopPlz;
if (avoidInfLoopPlz > highNumber) {
LDEBUG("Inf loop averted");
break;
}
++numSteps;
if (numSteps > maxSteps) {
LDEBUG("Max number of steps taken");
break;
}
}
return line;
}
void KameleonWrapper::getGridVariables(std::string& x, std::string& y, std::string& z) {
@@ -367,4 +392,3 @@ void KameleonWrapper::progressBar(int current, int end) {
}
} // namespace openspace