212 lines
4.5 KiB
C++
Executable File
212 lines
4.5 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* TrajectorySplitter
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Norbert Thoden, ESVG, 2026-04-10
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
//#include <LtsCoordinate/ltscoordinate_export.h>
|
|
|
|
#include <Core/core.hpp>
|
|
#include <QVector>
|
|
|
|
|
|
namespace AreaEffectSimulation
|
|
{
|
|
|
|
// E01562-294: Falsche Darstellung Flugkurve SMArt
|
|
// At SMArt ADLER (or SAA?) generates a polyline which is "dividing":
|
|
// x x
|
|
// x x
|
|
// x x x
|
|
// x x x
|
|
// | Start | T1 | T2 (Target 1 & Target 2)
|
|
// Same diagram, but with order
|
|
// x4 x5
|
|
// x3 x6 (duplicate)
|
|
// x2 x7 x10
|
|
// x1 x8 x11
|
|
// x12
|
|
// The relativeTime step backward between x8 and x10.
|
|
|
|
//using TRAJECTORY_POINT_TYPE = Core::RelativePositionRelativeTime;
|
|
//using TRAJECTORY_TYPE = std::vector<Core::RelativePositionRelativeTime>;
|
|
|
|
//!
|
|
//! \brief The TrajectorySplitter class splits a combined/special vector into single trajectories.
|
|
//! See UnitTestTrajectorySplitter
|
|
//!
|
|
template<typename TRAJECTORY_TYPE>
|
|
class TrajectorySplitter
|
|
{
|
|
public:
|
|
|
|
// friend class UnitTestTrajectorySplitter;
|
|
|
|
explicit TrajectorySplitter(const TRAJECTORY_TYPE &trajectory)
|
|
: m_trajectory(trajectory)
|
|
{}
|
|
|
|
TRAJECTORY_TYPE getTrunk() const
|
|
{
|
|
if (!init())
|
|
{
|
|
return {};
|
|
}
|
|
|
|
TRAJECTORY_TYPE trunk(m_trajectory.begin(), m_trajectory.begin()+m_branchIndex);
|
|
return trunk;
|
|
}
|
|
|
|
TRAJECTORY_TYPE getBranch1() const
|
|
{
|
|
if (!init())
|
|
{
|
|
return {};
|
|
}
|
|
|
|
const int idx = findIndexOfEndOfFirstBranchInternal(m_trajectory);
|
|
|
|
const TRAJECTORY_TYPE branch1(m_trajectory.begin()+m_branchIndex, m_trajectory.begin()+idx+1);
|
|
return branch1;
|
|
}
|
|
|
|
TRAJECTORY_TYPE getBranch2() const
|
|
{
|
|
if (!init())
|
|
{
|
|
return {};
|
|
}
|
|
|
|
const int idx = findIndexOfEndOfFirstBranchInternal(m_trajectory);
|
|
|
|
const TRAJECTORY_TYPE branch2(m_trajectory.begin()+idx+1, m_trajectory.end());
|
|
return branch2;
|
|
}
|
|
|
|
TRAJECTORY_TYPE getTrajectory1() const
|
|
{
|
|
if (!init())
|
|
{
|
|
return {};
|
|
}
|
|
|
|
auto complete = getTrunk();
|
|
const auto &branch = getBranch1();
|
|
complete.insert(complete.end(), branch.begin(), branch.end());
|
|
return complete;
|
|
}
|
|
|
|
TRAJECTORY_TYPE getTrajectory2() const
|
|
{
|
|
if (!init())
|
|
{
|
|
return {};
|
|
}
|
|
|
|
auto complete = getTrunk();
|
|
const auto &branch = getBranch2();
|
|
complete.insert(complete.end(), branch.begin(), branch.end());
|
|
return complete;
|
|
}
|
|
|
|
size_t rawTrajectorySize() const { return m_trajectory.size(); }
|
|
|
|
protected:
|
|
static qint64 findDuplicateTimeInternal(const TRAJECTORY_TYPE &trajectory)
|
|
{
|
|
// extract relativeTimes, sort, find adjacent duplicates
|
|
QVector<qint64> relativeTimes;
|
|
relativeTimes.reserve(static_cast<int>(trajectory.size()));
|
|
|
|
for (const auto &posTimeAware : trajectory)
|
|
{
|
|
relativeTimes.append(posTimeAware.relativeTime());
|
|
}
|
|
|
|
std::sort(relativeTimes.begin(), relativeTimes.end());
|
|
|
|
auto it = std::adjacent_find(relativeTimes.begin(), relativeTimes.end());
|
|
|
|
if (it == relativeTimes.end())
|
|
{
|
|
return -1; // not found
|
|
}
|
|
|
|
const qint64 duplicateRelativeTime = *it;
|
|
return duplicateRelativeTime;
|
|
}
|
|
static int findDuplicateBranchIndexInternal(const TRAJECTORY_TYPE &trajectory)
|
|
{
|
|
const qint64 duplicateRelativeTime = findDuplicateTimeInternal(trajectory);
|
|
|
|
if (duplicateRelativeTime < 0)
|
|
{
|
|
return -1; // not found
|
|
}
|
|
|
|
// find first occurance:
|
|
int idx = 0;
|
|
{
|
|
for (const auto &posTimeAware : trajectory)
|
|
{
|
|
const qint64 currentTime = posTimeAware.relativeTime();
|
|
|
|
if (duplicateRelativeTime == currentTime)
|
|
{
|
|
break;
|
|
}
|
|
++idx;
|
|
} // for
|
|
}
|
|
return idx;
|
|
}
|
|
static int findIndexOfEndOfFirstBranchInternal(const TRAJECTORY_TYPE &trajectory)
|
|
{
|
|
int idx = -1;
|
|
{
|
|
qint64 currentTime = std::numeric_limits<qint64>::min();
|
|
for (const auto &posTimeAware : trajectory)
|
|
{
|
|
if (posTimeAware.relativeTime() < currentTime)
|
|
{
|
|
break;
|
|
}
|
|
currentTime = posTimeAware.relativeTime();
|
|
++idx;
|
|
} // for
|
|
}
|
|
return idx;
|
|
}
|
|
|
|
bool init() const
|
|
{
|
|
// already calculated?
|
|
if (m_branchIndex > 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// sanity check:
|
|
if (m_trajectory.size() < 3)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_branchIndex = findDuplicateBranchIndexInternal(m_trajectory);
|
|
|
|
return (m_branchIndex >= 0);
|
|
}
|
|
|
|
private:
|
|
TRAJECTORY_TYPE m_trajectory;
|
|
mutable int m_branchIndex{0};
|
|
};
|
|
|
|
} // namespace AreaEffectSimulation
|
|
|