train tracking: basic detection for manual controlled trains
Dieser Commit ist enthalten in:
Ursprung
29eb8402ee
Commit
bcf92585b5
@ -316,6 +316,37 @@ bool BlockPath::operator ==(const BlockPath& other) const noexcept
|
||||
(m_nxButtonTo == other.m_nxButtonTo);
|
||||
}
|
||||
|
||||
bool BlockPath::isReady() const
|
||||
{
|
||||
for(const auto& [turnoutWeak, position] : m_turnouts)
|
||||
{
|
||||
auto turnout = turnoutWeak.lock();
|
||||
if(!turnout) /*[[unlikely]]*/
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(turnout->position != position)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for(const auto& [directionControlWeak, state] : m_directionControls)
|
||||
{
|
||||
auto directionControl = directionControlWeak.lock();
|
||||
if(!directionControl) /*[[unlikely]]*/
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(directionControl->state != state && directionControl->state != DirectionControlState::Both)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<NXButtonRailTile> BlockPath::nxButtonFrom() const
|
||||
{
|
||||
return m_nxButtonFrom.lock();
|
||||
|
||||
@ -71,6 +71,9 @@ class BlockPath : public Path, public std::enable_shared_from_this<BlockPath>
|
||||
|
||||
bool operator ==(const BlockPath& other) const noexcept;
|
||||
|
||||
//! \return \c true if all turnouts are in position and direction controls are allowed to pass.
|
||||
bool isReady() const;
|
||||
|
||||
bool hasNXButtons() const
|
||||
{
|
||||
return !m_nxButtonFrom.expired() && !m_nxButtonTo.expired();
|
||||
|
||||
@ -214,6 +214,81 @@ BlockRailTile::BlockRailTile(World& world, std::string_view _id) :
|
||||
|
||||
void BlockRailTile::inputItemValueChanged(BlockInputMapItem& item)
|
||||
{
|
||||
if(item.value() == SensorState::Occupied)
|
||||
{
|
||||
switch(state.value())
|
||||
{
|
||||
case BlockState::Free:
|
||||
case BlockState::Unknown:
|
||||
{
|
||||
// Something entered the block, try to determine what it is.
|
||||
|
||||
if(inputMap->items.size() > 2 && (&item != inputMap->items.front().get()) && (&item != inputMap->items.back().get()))
|
||||
{
|
||||
// Non block edge sensor.
|
||||
|
||||
//! \todo log something (at least in debug)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
const bool anySide = inputMap->items.size() == 1; // block with one sensor
|
||||
const BlockSide enterSide = (&item == inputMap->items.front().get()) ? BlockSide::A : BlockSide::B;
|
||||
|
||||
std::shared_ptr<Train> train;
|
||||
BlockTrainDirection direction;
|
||||
|
||||
for(const auto& path : m_pathsIn)
|
||||
{
|
||||
if(path->toBlock().get() == this && (anySide || path->toSide() == enterSide) && !path->fromBlock().trains.empty() && path->isReady())
|
||||
{
|
||||
const auto status = path->fromSide() == BlockSide::A ? path->fromBlock().trains.front() : path->fromBlock().trains.back();
|
||||
|
||||
if(isDirectionTowardsSide(status->direction, path->fromSide()) &&
|
||||
status->train &&
|
||||
status->train->powered &&
|
||||
status->train->mode == TrainMode::ManualUnprotected &&
|
||||
!status->train->isStopped)
|
||||
{
|
||||
if(train) // another train?? then we don't know
|
||||
{
|
||||
train.reset();
|
||||
//! \todo log something (at least in debug)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
train = status->train.value();
|
||||
direction = path->toSide() == BlockSide::A ? BlockTrainDirection::TowardsB : BlockTrainDirection::TowardsA;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(train)
|
||||
{
|
||||
auto blockStatus = TrainBlockStatus::create(*this, *train, direction);
|
||||
|
||||
blockStatus->train->blocks.insertInternal(0, blockStatus); // head of train
|
||||
trains.appendInternal(blockStatus);
|
||||
updateTrainMethodEnabled();
|
||||
|
||||
fireEvent<const std::shared_ptr<Train>&, const std::shared_ptr<BlockRailTile>&>(
|
||||
onTrainEntered,
|
||||
blockStatus->train.value(),
|
||||
shared_ptr<BlockRailTile>(),
|
||||
blockStatus->direction.value());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BlockState::Reserved:
|
||||
break;
|
||||
|
||||
case BlockState::Occupied:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(inputMap->items.size() != sensorStates.size())
|
||||
{
|
||||
std::vector<SensorState> values;
|
||||
@ -226,6 +301,40 @@ void BlockRailTile::inputItemValueChanged(BlockInputMapItem& item)
|
||||
sensorStates.setValueInternal(inputMap->items.indexOf(item), item.value());
|
||||
|
||||
updateState();
|
||||
|
||||
if(item.value() == SensorState::Free && state.value() == BlockState::Reserved)
|
||||
{
|
||||
if(trains.size() == 1)
|
||||
{
|
||||
auto blockStatus = trains.front();
|
||||
|
||||
// Train must be in at least two blocks, else we loose it.
|
||||
// Release tailing block of train only. (When using current detection not all wagons might consume power.)
|
||||
if(blockStatus->train &&
|
||||
blockStatus->train->blocks.size() > 1 &&
|
||||
blockStatus->train->blocks.back() == blockStatus)
|
||||
{
|
||||
blockStatus->train->blocks.removeInternal(blockStatus);
|
||||
trains.removeInternal(blockStatus);
|
||||
updateTrainMethodEnabled();
|
||||
|
||||
updateState();
|
||||
|
||||
fireEvent<const std::shared_ptr<Train>&, const std::shared_ptr<BlockRailTile>&>(
|
||||
onTrainLeft,
|
||||
blockStatus->train.value(),
|
||||
shared_ptr<BlockRailTile>(),
|
||||
blockStatus->direction.value());
|
||||
|
||||
blockStatus->destroy();
|
||||
#ifndef NDEBUG
|
||||
std::weak_ptr<TrainBlockStatus> blockStatusWeak = blockStatus;
|
||||
blockStatus.reset();
|
||||
assert(blockStatusWeak.expired());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlockRailTile::identificationEvent(BlockInputMapItem& /*item*/, IdentificationEventType eventType, uint16_t identifier, Direction direction, uint8_t /*category*/)
|
||||
|
||||
@ -106,6 +106,12 @@ class ObjectVectorProperty : public AbstractObjectVectorProperty
|
||||
changed();
|
||||
}
|
||||
|
||||
void insertInternal(size_t index, std::shared_ptr<T> value)
|
||||
{
|
||||
m_values.emplace(m_values.begin() + std::min(index, m_values.size()), std::move(value));
|
||||
changed();
|
||||
}
|
||||
|
||||
void removeInternal(const std::shared_ptr<T>& value)
|
||||
{
|
||||
auto it = std::find(m_values.begin(), m_values.end(), value);
|
||||
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren