|
|
|
@@ -65,9 +65,8 @@ namespace {
|
|
|
|
|
"SampleInterval",
|
|
|
|
|
"Sample Interval",
|
|
|
|
|
"The interval between samples of the trajectory. This value (together with "
|
|
|
|
|
"'TimeStampSubsampleFactor') determines how far apart (in time) the samples are "
|
|
|
|
|
"spaced along the trajectory. The time interval between 'StartTime' and "
|
|
|
|
|
"'EndTime' is split into 'SampleInterval' * 'TimeStampSubsampleFactor' segments.",
|
|
|
|
|
"'TimeStampSubsampleFactor') determines how far apart (in seconds) the samples "
|
|
|
|
|
"are spaced along the trajectory.",
|
|
|
|
|
openspace::properties::Property::Visibility::AdvancedUser
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@@ -75,9 +74,10 @@ namespace {
|
|
|
|
|
"TimeStampSubsampleFactor",
|
|
|
|
|
"Time Stamp Subsampling Factor",
|
|
|
|
|
"The factor that is used to create subsamples along the trajectory. This value "
|
|
|
|
|
"(together with 'SampleInterval') determines how far apart (in time) the samples "
|
|
|
|
|
"are spaced along the trajectory. The time interval between 'StartTime' and "
|
|
|
|
|
"'EndTime' is split into 'SampleInterval' * 'TimeStampSubsampleFactor' segments.",
|
|
|
|
|
"(together with 'SampleInterval') determines how far apart (in seconds) the "
|
|
|
|
|
"samples are spaced along the trajectory. Subsamples are rendered as smaller "
|
|
|
|
|
"points compared to normal samples (from 'SampleInterval') when rendering the "
|
|
|
|
|
"trail as points.",
|
|
|
|
|
openspace::properties::Property::Visibility::AdvancedUser
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@@ -89,23 +89,11 @@ namespace {
|
|
|
|
|
openspace::properties::Property::Visibility::NoviceUser
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo SweepChunkSizeInfo = {
|
|
|
|
|
"SweepChunkSize",
|
|
|
|
|
"Sweep Chunk Size",
|
|
|
|
|
"The number of vertices that will be calculated each frame whenever the trail "
|
|
|
|
|
"needs to be recalculated. A greater value will result in more calculations per "
|
|
|
|
|
"frame.",
|
|
|
|
|
openspace::properties::Property::Visibility::AdvancedUser
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo EnableSweepChunkingInfo = {
|
|
|
|
|
"EnableSweepChunking",
|
|
|
|
|
"Use Sweep Chunking",
|
|
|
|
|
"Enable or Disable the use of iterative calculations (chunking) during full "
|
|
|
|
|
"sweep vertex calculations. When enabled, small part of the trail will be "
|
|
|
|
|
"calculated each frame instead of calculating the entire trail in one go. "
|
|
|
|
|
"The size of each 'chunk' can be altered by changing the sweep chunk size "
|
|
|
|
|
"property.",
|
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo AccurateTrailInfo = {
|
|
|
|
|
"AccurateTrail",
|
|
|
|
|
"Use Accurate Trail",
|
|
|
|
|
"If true, the trail around the spacecraft will be recalculated to present a "
|
|
|
|
|
"smoother trail. If false, the original trail will be used.",
|
|
|
|
|
openspace::properties::Property::Visibility::AdvancedUser
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@@ -125,25 +113,21 @@ namespace {
|
|
|
|
|
// [[codegen::verbatim(EndTimeInfo.description)]]
|
|
|
|
|
std::string endTime [[codegen::annotation("A valid date in ISO 8601 format")]];
|
|
|
|
|
|
|
|
|
|
// The interval between samples of the trajectory. This value (together with
|
|
|
|
|
// 'TimeStampSubsampleFactor') determines how far apart (in time) the samples are
|
|
|
|
|
// spaced along the trajectory. The time interval between 'StartTime' and
|
|
|
|
|
// 'EndTime' is split into 'SampleInterval' * 'TimeStampSubsampleFactor' segments.
|
|
|
|
|
// If this value is not specified, it will be automatically calculated to produce
|
|
|
|
|
// one sample every two day between the 'StartTime' and 'EndTime'.
|
|
|
|
|
// [[codegen::verbatim(SampleIntervalInfo.description)]]
|
|
|
|
|
// The final interval is calculated as SampleInterval/TimeStampSubsampleFactor.
|
|
|
|
|
// If SampleInterval is not specified, it will be automatically calculated to produce
|
|
|
|
|
// two samples per day between the 'StartTime' and 'EndTime'.
|
|
|
|
|
std::optional<double> sampleInterval;
|
|
|
|
|
|
|
|
|
|
// [[codegen::verbatim(TimeSubSampleInfo.description)]]
|
|
|
|
|
// The final interval is calculated as SampleInterval/TimeStampSubsampleFactor.
|
|
|
|
|
std::optional<int> timeStampSubsampleFactor;
|
|
|
|
|
|
|
|
|
|
// [[codegen::verbatim(RenderFullPathInfo.description)]]
|
|
|
|
|
std::optional<bool> showFullTrail;
|
|
|
|
|
|
|
|
|
|
// [[codegen::verbatim(SweepChunkSizeInfo.description)]]
|
|
|
|
|
std::optional<int> sweepChunkSize;
|
|
|
|
|
|
|
|
|
|
// [[codegen::verbatim(SweepChunkSizeInfo.description)]]
|
|
|
|
|
std::optional<bool> enableSweepChunking;
|
|
|
|
|
// [[codegen::verbatim(AccurateTrailInfo.description)]]
|
|
|
|
|
std::optional<bool> useAccurateTrail;
|
|
|
|
|
|
|
|
|
|
// [[codegen::verbatim(AccurateTrailPositionsInfo.description)]]
|
|
|
|
|
std::optional<int> accurateTrailPositions;
|
|
|
|
@@ -162,14 +146,18 @@ documentation::Documentation RenderableTrailTrajectory::Documentation() {
|
|
|
|
|
|
|
|
|
|
RenderableTrailTrajectory::RenderableTrailTrajectory(const ghoul::Dictionary& dictionary)
|
|
|
|
|
: RenderableTrail(dictionary)
|
|
|
|
|
, _sweepChunkSize(SweepChunkSizeInfo, 200, 50, 5000)
|
|
|
|
|
, _enableSweepChunking(EnableSweepChunkingInfo, false)
|
|
|
|
|
, _startTime(StartTimeInfo)
|
|
|
|
|
, _endTime(EndTimeInfo)
|
|
|
|
|
, _sampleInterval(SampleIntervalInfo, 2.0, 2.0, 1e6)
|
|
|
|
|
, _timeStampSubsamplingFactor(TimeSubSampleInfo, 1, 1, 1000000000)
|
|
|
|
|
, _sampleInterval(
|
|
|
|
|
SampleIntervalInfo,
|
|
|
|
|
openspace::timeconstants::SecondsPerDay / 2.0,
|
|
|
|
|
1.0,
|
|
|
|
|
1e6
|
|
|
|
|
)
|
|
|
|
|
, _timeStampSubsamplingFactor(TimeSubSampleInfo, 1, 1, 100)
|
|
|
|
|
, _renderFullTrail(RenderFullPathInfo, false)
|
|
|
|
|
, _nReplacementPoints(AccurateTrailPositionsInfo, 100, 0, 1000)
|
|
|
|
|
, _useAccurateTrail(AccurateTrailInfo, true)
|
|
|
|
|
, _nReplacementPoints(AccurateTrailPositionsInfo, 100, 2, 1000)
|
|
|
|
|
, _maxVertex(glm::vec3(-std::numeric_limits<float>::max()))
|
|
|
|
|
, _minVertex(glm::vec3(std::numeric_limits<float>::max()))
|
|
|
|
|
{
|
|
|
|
@@ -180,6 +168,15 @@ RenderableTrailTrajectory::RenderableTrailTrajectory(const ghoul::Dictionary& di
|
|
|
|
|
_renderFullTrail = p.showFullTrail.value_or(_renderFullTrail);
|
|
|
|
|
addProperty(_renderFullTrail);
|
|
|
|
|
|
|
|
|
|
_useAccurateTrail = p.useAccurateTrail.value_or(_useAccurateTrail);
|
|
|
|
|
addProperty(_useAccurateTrail);
|
|
|
|
|
|
|
|
|
|
_nReplacementPoints = p.accurateTrailPositions.value_or(_nReplacementPoints);
|
|
|
|
|
_nReplacementPoints.onChange([this]() {
|
|
|
|
|
_nReplacementPoints = std::max<int>(2, _nReplacementPoints);
|
|
|
|
|
});
|
|
|
|
|
addProperty(_nReplacementPoints);
|
|
|
|
|
|
|
|
|
|
_startTime = p.startTime;
|
|
|
|
|
_startTime.onChange([this] { reset(); });
|
|
|
|
|
addProperty(_startTime);
|
|
|
|
@@ -188,30 +185,16 @@ RenderableTrailTrajectory::RenderableTrailTrajectory(const ghoul::Dictionary& di
|
|
|
|
|
_endTime.onChange([this] { reset(); });
|
|
|
|
|
addProperty(_endTime);
|
|
|
|
|
|
|
|
|
|
if (p.sampleInterval.has_value()) {
|
|
|
|
|
_sampleInterval = *p.sampleInterval;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const double delta = Time::convertTime(_endTime) - Time::convertTime(_startTime);
|
|
|
|
|
_sampleInterval = delta / (openspace::timeconstants::SecondsPerYear * 2);
|
|
|
|
|
}
|
|
|
|
|
_sampleInterval.onChange([this] { reset(); });
|
|
|
|
|
_sampleInterval = p.sampleInterval.value_or(_sampleInterval);
|
|
|
|
|
|
|
|
|
|
_sampleInterval.onChange([this]() { reset(); });
|
|
|
|
|
addProperty(_sampleInterval);
|
|
|
|
|
|
|
|
|
|
_timeStampSubsamplingFactor =
|
|
|
|
|
p.timeStampSubsampleFactor.value_or(_timeStampSubsamplingFactor);
|
|
|
|
|
_timeStampSubsamplingFactor.onChange([this] { _subsamplingIsDirty = true; });
|
|
|
|
|
_timeStampSubsamplingFactor.onChange([this]() { reset(); });
|
|
|
|
|
addProperty(_timeStampSubsamplingFactor);
|
|
|
|
|
|
|
|
|
|
_nReplacementPoints = p.accurateTrailPositions.value_or(_nReplacementPoints);
|
|
|
|
|
addProperty(_nReplacementPoints);
|
|
|
|
|
|
|
|
|
|
_enableSweepChunking = p.enableSweepChunking.value_or(_enableSweepChunking);
|
|
|
|
|
addProperty(_enableSweepChunking);
|
|
|
|
|
|
|
|
|
|
_sweepChunkSize = p.sweepChunkSize.value_or(_sweepChunkSize);
|
|
|
|
|
addProperty(_sweepChunkSize);
|
|
|
|
|
|
|
|
|
|
// We store the vertices with ascending temporal order
|
|
|
|
|
_primaryRenderInformation.sorting = RenderInformation::VertexSorting::OldestFirst;
|
|
|
|
|
_secondaryRenderInformation.sorting = RenderInformation::VertexSorting::OldestFirst;
|
|
|
|
@@ -249,109 +232,79 @@ void RenderableTrailTrajectory::deinitializeGL() {
|
|
|
|
|
|
|
|
|
|
void RenderableTrailTrajectory::reset() {
|
|
|
|
|
_needsFullSweep = true;
|
|
|
|
|
_sweepIteration = 0;
|
|
|
|
|
_maxVertex = glm::vec3(-std::numeric_limits<float>::max());
|
|
|
|
|
_minVertex = glm::vec3(std::numeric_limits<float>::max());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderableTrailTrajectory::updateBuffer() {
|
|
|
|
|
// Convert the start and end time from string representations to J2000 seconds
|
|
|
|
|
_start = SpiceManager::ref().ephemerisTimeFromDate(_startTime);
|
|
|
|
|
_end = SpiceManager::ref().ephemerisTimeFromDate(_endTime);
|
|
|
|
|
const double timespan = _end - _start;
|
|
|
|
|
|
|
|
|
|
_totalSampleInterval = _sampleInterval / _timeStampSubsamplingFactor;
|
|
|
|
|
_nVertices = static_cast<unsigned int>(std::ceil(timespan / _totalSampleInterval));
|
|
|
|
|
|
|
|
|
|
// Make space for the vertices
|
|
|
|
|
_vertexArray.clear();
|
|
|
|
|
_dVertexArray.clear();
|
|
|
|
|
_timeVector.clear();
|
|
|
|
|
_vertexArray.resize(_nVertices + 1);
|
|
|
|
|
_dVertexArray.resize(_nVertices + 1);
|
|
|
|
|
_timeVector.resize(_nVertices + 1);
|
|
|
|
|
|
|
|
|
|
// Calculate all vertex positions
|
|
|
|
|
for (unsigned int i = 0; i < _nVertices; i++) {
|
|
|
|
|
const glm::dvec3 dp = translationPosition(
|
|
|
|
|
Time(_start + i * _totalSampleInterval)
|
|
|
|
|
);
|
|
|
|
|
const glm::vec3 p = dp;
|
|
|
|
|
_vertexArray[i] = { p.x, p.y, p.z };
|
|
|
|
|
_timeVector[i] = Time(_start + i * _totalSampleInterval).j2000Seconds();
|
|
|
|
|
_dVertexArray[i] = { dp.x, dp.y, dp.z };
|
|
|
|
|
|
|
|
|
|
// Set max and min vertex for bounding sphere calculations
|
|
|
|
|
_maxVertex = glm::max(_maxVertex, dp);
|
|
|
|
|
_minVertex = glm::min(_minVertex, dp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Full sweep is complete here.
|
|
|
|
|
// Adds the last point in time to the _vertexArray so that we
|
|
|
|
|
// ensure that points for _start and _end always exists
|
|
|
|
|
const glm::dvec3 dp = translationPosition(Time(_end));
|
|
|
|
|
const glm::vec3 p = dp;
|
|
|
|
|
_vertexArray[_nVertices] = { p.x, p.y, p.z };
|
|
|
|
|
_timeVector[_nVertices] = Time(_end).j2000Seconds();
|
|
|
|
|
_dVertexArray[_nVertices] = { dp.x, dp.y, dp.z };
|
|
|
|
|
|
|
|
|
|
setBoundingSphere(glm::distance(_maxVertex, _minVertex) / 2.0);
|
|
|
|
|
|
|
|
|
|
// Upload vertices to the GPU
|
|
|
|
|
glBindVertexArray(_primaryRenderInformation._vaoID);
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, _primaryRenderInformation._vBufferID);
|
|
|
|
|
glBufferData(
|
|
|
|
|
GL_ARRAY_BUFFER,
|
|
|
|
|
_vertexArray.size() * sizeof(TrailVBOLayout<float>),
|
|
|
|
|
_vertexArray.data(),
|
|
|
|
|
GL_STATIC_DRAW
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
|
|
|
|
|
|
|
|
|
|
// We clear the indexArray just in case. The base class will take care not to use
|
|
|
|
|
// it if it is empty
|
|
|
|
|
_indexArray.clear();
|
|
|
|
|
|
|
|
|
|
_primaryRenderInformation.stride = _timeStampSubsamplingFactor;
|
|
|
|
|
_secondaryRenderInformation.stride = _timeStampSubsamplingFactor;
|
|
|
|
|
_floatingRenderInformation.stride = _timeStampSubsamplingFactor;
|
|
|
|
|
_needsFullSweep = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderableTrailTrajectory::update(const UpdateData& data) {
|
|
|
|
|
if (_needsFullSweep) {
|
|
|
|
|
if (_sweepIteration == 0) {
|
|
|
|
|
constexpr unsigned int MaxVertices = 1000000;
|
|
|
|
|
|
|
|
|
|
// Convert the start and end time from string representations to J2000 seconds
|
|
|
|
|
_start = SpiceManager::ref().ephemerisTimeFromDate(_startTime);
|
|
|
|
|
_end = SpiceManager::ref().ephemerisTimeFromDate(_endTime);
|
|
|
|
|
const double timespan = _end - _start;
|
|
|
|
|
|
|
|
|
|
_totalSampleInterval = _sampleInterval / _timeStampSubsamplingFactor;
|
|
|
|
|
|
|
|
|
|
// Cap _nVertices in order to prevent overflow and extreme performance
|
|
|
|
|
// degredation/RAM usage
|
|
|
|
|
_nVertices = std::min(
|
|
|
|
|
static_cast<unsigned int>(std::ceil(timespan / _totalSampleInterval)),
|
|
|
|
|
MaxVertices
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// We need to recalcuate the _totalSampleInterval if _nVertices equals
|
|
|
|
|
// MaxVertices. If we don't do this the position for each vertex
|
|
|
|
|
// will not be correct for the number of vertices we are doing along the trail
|
|
|
|
|
_totalSampleInterval = (_nVertices == MaxVertices) ?
|
|
|
|
|
(timespan / _nVertices) : _totalSampleInterval;
|
|
|
|
|
|
|
|
|
|
// Make space for the vertices
|
|
|
|
|
_vertexArray.clear();
|
|
|
|
|
_dVertexArray.clear();
|
|
|
|
|
_timeVector.clear();
|
|
|
|
|
_vertexArray.resize(_nVertices + 1);
|
|
|
|
|
_dVertexArray.resize(_nVertices + 1);
|
|
|
|
|
_timeVector.resize(_nVertices + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calculate sweeping range for this iteration
|
|
|
|
|
const unsigned int startIndex = _sweepIteration * _sweepChunkSize;
|
|
|
|
|
const unsigned int nextIndex = (_sweepIteration + 1) * _sweepChunkSize;
|
|
|
|
|
unsigned int stopIndex = std::min(nextIndex, _nVertices);
|
|
|
|
|
|
|
|
|
|
// If iterative calculations are disabled
|
|
|
|
|
if (!_enableSweepChunking) {
|
|
|
|
|
stopIndex = _nVertices;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calculate all vertex positions
|
|
|
|
|
for (unsigned int i = startIndex; i < stopIndex; i++) {
|
|
|
|
|
const glm::dvec3 dp = translationPosition(
|
|
|
|
|
Time(_start + i * _totalSampleInterval)
|
|
|
|
|
);
|
|
|
|
|
const glm::vec3 p(dp.x, dp.y, dp.z);
|
|
|
|
|
_vertexArray[i] = { p.x, p.y, p.z };
|
|
|
|
|
_timeVector[i] = Time(_start + i * _totalSampleInterval).j2000Seconds();
|
|
|
|
|
_dVertexArray[i] = {dp.x, dp.y, dp.z};
|
|
|
|
|
|
|
|
|
|
// Set max and min vertex for bounding sphere calculations
|
|
|
|
|
_maxVertex = glm::max(_maxVertex, dp);
|
|
|
|
|
_minVertex = glm::min(_minVertex, dp);
|
|
|
|
|
}
|
|
|
|
|
++_sweepIteration;
|
|
|
|
|
|
|
|
|
|
// Full sweep is complete here.
|
|
|
|
|
// Adds the last point in time to the _vertexArray so that we
|
|
|
|
|
// ensure that points for _start and _end always exists
|
|
|
|
|
if (stopIndex == _nVertices) {
|
|
|
|
|
const glm::dvec3 dp = translationPosition(Time(_end));
|
|
|
|
|
const glm::vec3 p(dp.x, dp.y, dp.z);
|
|
|
|
|
_vertexArray[stopIndex] = { p.x, p.y, p.z };
|
|
|
|
|
_timeVector[stopIndex] = Time(_end).j2000Seconds();
|
|
|
|
|
_dVertexArray[stopIndex] = { dp.x, dp.y, dp.z };
|
|
|
|
|
|
|
|
|
|
_sweepIteration = 0;
|
|
|
|
|
setBoundingSphere(glm::distance(_maxVertex, _minVertex) / 2.0);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Early return as we don't need to render if we are still
|
|
|
|
|
// doing full sweep calculations
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Upload vertices to the GPU
|
|
|
|
|
glBindVertexArray(_primaryRenderInformation._vaoID);
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, _primaryRenderInformation._vBufferID);
|
|
|
|
|
glBufferData(
|
|
|
|
|
GL_ARRAY_BUFFER,
|
|
|
|
|
_vertexArray.size() * sizeof(TrailVBOLayout<float>),
|
|
|
|
|
_vertexArray.data(),
|
|
|
|
|
GL_STATIC_DRAW
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
|
|
|
|
|
|
|
|
|
|
// We clear the indexArray just in case. The base class will take care not to use
|
|
|
|
|
// it if it is empty
|
|
|
|
|
_indexArray.clear();
|
|
|
|
|
|
|
|
|
|
_subsamplingIsDirty = true;
|
|
|
|
|
_needsFullSweep = false;
|
|
|
|
|
updateBuffer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This has to be done every update step;
|
|
|
|
@@ -372,7 +325,7 @@ void RenderableTrailTrajectory::update(const UpdateData& data) {
|
|
|
|
|
// Calculates number of vertices for the second segment (object to end point)
|
|
|
|
|
_secondaryRenderInformation.first = _primaryRenderInformation.count;
|
|
|
|
|
_secondaryRenderInformation.count = static_cast<GLsizei>(
|
|
|
|
|
_vertexArray.size() - (_primaryRenderInformation.count)
|
|
|
|
|
_vertexArray.size() - _primaryRenderInformation.count
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Calculate number of vertices in the trail
|
|
|
|
@@ -389,32 +342,28 @@ void RenderableTrailTrajectory::update(const UpdateData& data) {
|
|
|
|
|
_nUniqueVertices = _primaryRenderInformation.count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine the number of points to be recalculated
|
|
|
|
|
int prePaddingDelta = 0;
|
|
|
|
|
if (!_renderFullTrail && _nReplacementPoints == 0) {
|
|
|
|
|
// Enables trail from last point to current position
|
|
|
|
|
// if we don't do any replacement points
|
|
|
|
|
prePaddingDelta = 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
prePaddingDelta = std::min(
|
|
|
|
|
static_cast<int>(_primaryRenderInformation.count),
|
|
|
|
|
static_cast<int>(_nReplacementPoints)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
int postPaddingDelta = std::min(
|
|
|
|
|
static_cast<int>(_secondaryRenderInformation.count),
|
|
|
|
|
static_cast<int>(_nReplacementPoints)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Get current position of the object
|
|
|
|
|
const glm::dvec3 p = translationPosition(data.time);
|
|
|
|
|
|
|
|
|
|
// Calculates all replacement points before the object
|
|
|
|
|
// Determine the number of points before the object to be recalculated
|
|
|
|
|
int prePaddingDelta = 0;
|
|
|
|
|
if (_useAccurateTrail) {
|
|
|
|
|
prePaddingDelta = std::min<int>(
|
|
|
|
|
_primaryRenderInformation.count,
|
|
|
|
|
_nReplacementPoints
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else if (_renderFullTrail) {
|
|
|
|
|
_primaryRenderInformation.count += 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
prePaddingDelta = std::min(_primaryRenderInformation.count, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glm::dvec3 v = p;
|
|
|
|
|
for (int i = 0; i < prePaddingDelta; ++i) {
|
|
|
|
|
for (int i = 0; i < prePaddingDelta; i++) {
|
|
|
|
|
const int floatPointIndex =
|
|
|
|
|
_primaryRenderInformation.count - prePaddingDelta + i;
|
|
|
|
|
(_primaryRenderInformation.count - prePaddingDelta) + i;
|
|
|
|
|
|
|
|
|
|
glm::dvec3 fp = glm::dvec3(
|
|
|
|
|
_vertexArray[floatPointIndex].x,
|
|
|
|
@@ -431,17 +380,11 @@ void RenderableTrailTrajectory::update(const UpdateData& data) {
|
|
|
|
|
glm::dvec3 dv = fp - dp;
|
|
|
|
|
glm::dvec3 newPoint = dp - v;
|
|
|
|
|
|
|
|
|
|
// Scales position offset for smooth transition from '
|
|
|
|
|
// original points to accurate points
|
|
|
|
|
double mult = 0.0;
|
|
|
|
|
if (i == prePaddingDelta - 1) {
|
|
|
|
|
mult = (i == 0) ? 1.0 : 0.0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
mult = (prePaddingDelta - i) / static_cast<double>(prePaddingDelta);
|
|
|
|
|
}
|
|
|
|
|
// Scales offset for smooth transition from original to accurate points
|
|
|
|
|
const double mult = (i == prePaddingDelta - 1 && i > 0) ?
|
|
|
|
|
0.0 : (prePaddingDelta - i) / static_cast<double>(prePaddingDelta);
|
|
|
|
|
|
|
|
|
|
newPoint = newPoint + dv * mult;
|
|
|
|
|
newPoint += dv * pow(mult, 2.0);
|
|
|
|
|
_replacementPoints.push_back({
|
|
|
|
|
static_cast<float>(newPoint.x),
|
|
|
|
|
static_cast<float>(newPoint.y),
|
|
|
|
@@ -450,13 +393,21 @@ void RenderableTrailTrajectory::update(const UpdateData& data) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mid-point (model-space position for the object)
|
|
|
|
|
if (_nReplacementPoints > 0 || !_renderFullTrail) {
|
|
|
|
|
if (_useAccurateTrail || !_renderFullTrail) {
|
|
|
|
|
_replacementPoints.push_back({ 0.f, 0.f, 0.f });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calculates all replacement points after the object
|
|
|
|
|
v = glm::dvec3(p.x, p.y, p.z);
|
|
|
|
|
for (int i = 0; i < postPaddingDelta; ++i) {
|
|
|
|
|
int postPaddingDelta = _secondaryRenderInformation.count;
|
|
|
|
|
if (_useAccurateTrail) {
|
|
|
|
|
postPaddingDelta = std::min<int>(
|
|
|
|
|
_secondaryRenderInformation.count,
|
|
|
|
|
_nReplacementPoints
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v = p;
|
|
|
|
|
for (int i = 0; i < postPaddingDelta; i++) {
|
|
|
|
|
const int floatPointIndex = _secondaryRenderInformation.first + i;
|
|
|
|
|
|
|
|
|
|
glm::dvec3 fp = glm::dvec3(
|
|
|
|
@@ -474,13 +425,13 @@ void RenderableTrailTrajectory::update(const UpdateData& data) {
|
|
|
|
|
glm::dvec3 dv = fp - dp;
|
|
|
|
|
glm::dvec3 newPoint = dp - v;
|
|
|
|
|
|
|
|
|
|
// Scales position offset for smooth transition from '
|
|
|
|
|
// original points to accurate points
|
|
|
|
|
double mult = (i == postPaddingDelta - 1) ?
|
|
|
|
|
1.0 :
|
|
|
|
|
1.0 - (postPaddingDelta - i) / static_cast<double>(postPaddingDelta);
|
|
|
|
|
// Scales offset for smooth transition from original to accurate points
|
|
|
|
|
double mult = 1.0;
|
|
|
|
|
if (_useAccurateTrail && i != postPaddingDelta - 1) {
|
|
|
|
|
mult -= (postPaddingDelta - i) / static_cast<double>(postPaddingDelta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newPoint = newPoint + dv * mult;
|
|
|
|
|
newPoint += dv * pow(mult, 2.0);
|
|
|
|
|
_replacementPoints.push_back({
|
|
|
|
|
static_cast<float>(newPoint.x),
|
|
|
|
|
static_cast<float>(newPoint.y),
|
|
|
|
@@ -497,7 +448,7 @@ void RenderableTrailTrajectory::update(const UpdateData& data) {
|
|
|
|
|
|
|
|
|
|
// Adjusts number of unique vertices if we have inserted a new mid point
|
|
|
|
|
if (_floatingRenderInformation.count > 0 && _renderFullTrail) {
|
|
|
|
|
_nUniqueVertices++;
|
|
|
|
|
_nUniqueVertices += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Recalculate .count and .first based on the recalculated (floating) vertices
|
|
|
|
@@ -522,16 +473,6 @@ void RenderableTrailTrajectory::update(const UpdateData& data) {
|
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
|
|
|
|
|
}
|
|
|
|
|
else if (j2k >= _end || (j2k < _start && _renderFullTrail)) {
|
|
|
|
|
// Renders the whole trail if time has passed the end time
|
|
|
|
|
_primaryRenderInformation.first = 0;
|
|
|
|
|
_primaryRenderInformation.count = static_cast<GLsizei>(_vertexArray.size());
|
|
|
|
|
_nUniqueVertices = _primaryRenderInformation.count;
|
|
|
|
|
_secondaryRenderInformation.first = 0;
|
|
|
|
|
_secondaryRenderInformation.count = 0;
|
|
|
|
|
_floatingRenderInformation.first = 0;
|
|
|
|
|
_floatingRenderInformation.count = 0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
_primaryRenderInformation.first = 0;
|
|
|
|
|
_primaryRenderInformation.count = 0;
|
|
|
|
@@ -539,17 +480,11 @@ void RenderableTrailTrajectory::update(const UpdateData& data) {
|
|
|
|
|
_secondaryRenderInformation.count = 0;
|
|
|
|
|
_floatingRenderInformation.first = 0;
|
|
|
|
|
_floatingRenderInformation.count = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_subsamplingIsDirty) {
|
|
|
|
|
// If the subsampling information has changed (either by a property change or by
|
|
|
|
|
// a request of a full sweep) we update it here
|
|
|
|
|
|
|
|
|
|
_primaryRenderInformation.stride = _timeStampSubsamplingFactor;
|
|
|
|
|
_secondaryRenderInformation.stride = _timeStampSubsamplingFactor;
|
|
|
|
|
_floatingRenderInformation.stride = _timeStampSubsamplingFactor;
|
|
|
|
|
|
|
|
|
|
_subsamplingIsDirty = false;
|
|
|
|
|
if (_renderFullTrail || j2k >= _end) {
|
|
|
|
|
// Renders the whole trail if time has passed the end time
|
|
|
|
|
_primaryRenderInformation.count = static_cast<GLsizei>(_vertexArray.size());
|
|
|
|
|
_nUniqueVertices = _primaryRenderInformation.count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glBindVertexArray(0);
|
|
|
|
|