mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 02:49:19 +02:00
feat(roads): right of way and lane turns at junctions, road weights, kerbs, medians and forking roads, banks to the ground, roundabouts, pedestrian crossings, spawn sets by count; fix(editor): model skin export, placement on the ground under the orthophoto
This commit is contained in:
@@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "world/Track.h"
|
||||
#include "world/Event.h"
|
||||
#include "world/RoadOrder.h"
|
||||
#include "vehicle/DynObj.h"
|
||||
#include "vehicle/Driver.h"
|
||||
#include "vehicle/Train.h"
|
||||
@@ -37,6 +38,11 @@ constexpr double near_zone{30.0}; // a rail vehicle this close to the stop lines
|
||||
constexpr double clear_zone{20.0}; // a vehicle isn't put on the road with another one this close
|
||||
constexpr double retry_period{1.0}; // seconds to the next try, when a vehicle can't be put on the road
|
||||
constexpr double front_room{2.5}; // half the length a vehicle is presumed to have before it's made
|
||||
constexpr double queue_reach{250.0}; // how far back from a closed crossing the vehicles standing on the lanes are taken to wait for it
|
||||
constexpr double stuck_time{15.0}; // seconds a vehicle of a spawn point can stand still before it's taken off the road
|
||||
constexpr double stuck_speed{0.1}; // m/s, slower than this is standing still
|
||||
constexpr double reverse_speed{0.5}; // m/s, a vehicle going backwards faster than this is taken off the road
|
||||
constexpr double stripe_width{0.5}; // of a pedestrian crossing; the gaps are as wide
|
||||
|
||||
// a path as a curve: points along it, and distances along it
|
||||
class path_curve
|
||||
@@ -154,46 +160,34 @@ bool out_of_reach(segment_data const &Path, glm::dvec3 const &Point, double cons
|
||||
return glm::distance(glm::dvec2{start.x, start.z}, glm::dvec2{Point.x, Point.z}) > span + Reach;
|
||||
}
|
||||
|
||||
// an order for the drivers heading for a closed crossing; to them it's what a signal showing stop is to the driver of a train.
|
||||
// it doesn't go to the event manager and never runs: the drivers find it on the lane they scan, and ask it what speed it allows
|
||||
class stop_event : public basic_event
|
||||
// an order for the drivers heading for a closed crossing
|
||||
using stop_event = road_order;
|
||||
|
||||
// the road passing under specified point: the one whose axis is nearest. T: receives the value of the curve parameter of its axis there
|
||||
road_node const *road_under(glm::dvec3 const &Point, double &T)
|
||||
{
|
||||
|
||||
public:
|
||||
stop_event()
|
||||
road_node const *result{nullptr};
|
||||
auto best{std::numeric_limits<double>::max()};
|
||||
for (auto const *road : simulation::Roads.sequence())
|
||||
{
|
||||
m_passive = true;
|
||||
if (road == nullptr || road->m_editorremoved || out_of_reach(road->definition().axis, Point, 50.0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto const &layout{road->definition()};
|
||||
path_curve const axis{layout.axis};
|
||||
double distance{0.0};
|
||||
auto const t{axis.nearest(Point, distance)};
|
||||
if (distance > 0.5 * layout.span(t) + 1.0 || std::abs(axis.point(t).y - Point.y) > 3.0 || distance >= best)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
best = distance;
|
||||
result = road;
|
||||
T = t;
|
||||
}
|
||||
void init() override {}
|
||||
std::string input_text() const override
|
||||
{
|
||||
return "SetVelocity";
|
||||
}
|
||||
TCommandType input_command() const override
|
||||
{
|
||||
return TCommandType::cm_SetVelocity;
|
||||
}
|
||||
double input_value(int const Index) const override
|
||||
{
|
||||
return m_velocity;
|
||||
}
|
||||
glm::dvec3 input_location() const override
|
||||
{
|
||||
return m_location;
|
||||
}
|
||||
// members
|
||||
double m_velocity{-1.0}; // 0: stop, -1: no limit
|
||||
glm::dvec3 m_location{0.0};
|
||||
|
||||
private:
|
||||
std::string type() const override
|
||||
{
|
||||
return "roadstop";
|
||||
}
|
||||
void deserialize_(cParser &Input, scene::scratch_data &Scratchpad) override {}
|
||||
void run_() override {}
|
||||
void export_as_text_(std::ostream &Output) const override {}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
// lane of a road with the point nearest to specified one, within specified distance from it. Station: receives the distance of that point from the start of the lane
|
||||
TTrack *nearest_lane(glm::dvec3 const &Point, double const Reach, double &Station)
|
||||
@@ -242,24 +236,25 @@ void roadpoint_node::state::normalize()
|
||||
interval = std::clamp(interval, 1.f, 3600.f);
|
||||
variation = std::clamp(variation, 0.f, 1.f);
|
||||
velocity = std::clamp(velocity, 5.f, 200.f);
|
||||
copies = std::clamp(copies, 1, 16);
|
||||
count = std::clamp(count, 1, 64);
|
||||
radius = std::clamp(radius, 0.5f, 50.f);
|
||||
length = std::clamp(length, 1.f, 20.f);
|
||||
}
|
||||
|
||||
roadpoint_node::roadpoint_node(scene::node_data const &Nodedata) : basic_node(Nodedata)
|
||||
{
|
||||
m_state.kind = (Nodedata.type == "spawn" ? kind_type::spawn : Nodedata.type == "despawn" ? kind_type::despawn : kind_type::crossing);
|
||||
m_state.kind = (Nodedata.type == "spawn" ? kind_type::spawn : Nodedata.type == "despawn" ? kind_type::despawn : Nodedata.type == "crosswalk" ? kind_type::crosswalk : kind_type::crossing);
|
||||
}
|
||||
|
||||
// scenery keyword for specified kind of point
|
||||
std::string roadpoint_node::keyword(kind_type const Kind)
|
||||
{
|
||||
return Kind == kind_type::spawn ? "spawn" : Kind == kind_type::despawn ? "despawn" : "crossing";
|
||||
return Kind == kind_type::spawn ? "spawn" : Kind == kind_type::despawn ? "despawn" : Kind == kind_type::crosswalk ? "crosswalk" : "crossing";
|
||||
}
|
||||
|
||||
bool roadpoint_node::is_keyword(std::string const &Type)
|
||||
{
|
||||
return Type == "crossing" || Type == "spawn" || Type == "despawn";
|
||||
return Type == "crossing" || Type == "spawn" || Type == "despawn" || Type == "crosswalk";
|
||||
}
|
||||
|
||||
// reads vehicles out of a text
|
||||
@@ -341,6 +336,8 @@ void roadpoint_node::import(cParser &Input, glm::dvec3 const &Offset)
|
||||
Input.getTokens(3);
|
||||
Input >> m_state.position.x >> m_state.position.y >> m_state.position.z;
|
||||
m_state.position += Offset;
|
||||
int copies{0}; // of each vehicle, the way the first sceneries with spawn points gave the size of the set
|
||||
auto counted{false};
|
||||
|
||||
auto token{Input.getToken<std::string>()};
|
||||
while (false == token.empty() && token != "end" + type)
|
||||
@@ -374,10 +371,21 @@ void roadpoint_node::import(cParser &Input, glm::dvec3 const &Offset)
|
||||
Input.getTokens();
|
||||
Input >> m_state.velocity;
|
||||
}
|
||||
else if (token == "count")
|
||||
{
|
||||
Input.getTokens();
|
||||
Input >> m_state.count;
|
||||
counted = true;
|
||||
}
|
||||
else if (token == "copies")
|
||||
{
|
||||
Input.getTokens();
|
||||
Input >> m_state.copies;
|
||||
Input >> copies;
|
||||
}
|
||||
else if (token == "length")
|
||||
{
|
||||
Input.getTokens();
|
||||
Input >> m_state.length;
|
||||
}
|
||||
else if (token == "radius")
|
||||
{
|
||||
@@ -441,6 +449,10 @@ void roadpoint_node::import(cParser &Input, glm::dvec3 const &Offset)
|
||||
}
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
if (false == counted && copies > 0)
|
||||
{
|
||||
m_state.count = copies * static_cast<int>(std::max<std::size_t>(1, m_state.vehicles.size()));
|
||||
}
|
||||
m_state.normalize();
|
||||
location(m_state.position);
|
||||
}
|
||||
@@ -449,10 +461,10 @@ void roadpoint_node::import(cParser &Input, glm::dvec3 const &Offset)
|
||||
void roadpoint_node::define(state const &State)
|
||||
{
|
||||
auto const vehicles{m_state.vehicles};
|
||||
auto const copies{m_state.copies};
|
||||
auto const count{m_state.count};
|
||||
m_state = State;
|
||||
m_state.normalize();
|
||||
if (m_prepared && (m_state.vehicles != vehicles || m_state.copies != copies))
|
||||
if (m_prepared && (m_state.vehicles != vehicles || m_state.count != count))
|
||||
{
|
||||
// vehicles can't be unmade, there's too much holding on to them. the old ones are left alone:
|
||||
// those which wait stay where they are, those on the road drive on until something takes them away
|
||||
@@ -492,6 +504,24 @@ void roadpoint_node::bind()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kind_type::crosswalk:
|
||||
{
|
||||
// the stripes go across the road the point is on
|
||||
double t{0.0};
|
||||
auto const *road{road_under(m_state.position, t)};
|
||||
if (road != nullptr)
|
||||
{
|
||||
auto const &layout{road->definition()};
|
||||
path_curve const axis{layout.axis};
|
||||
m_onroad = true;
|
||||
m_along = axis.direction(t);
|
||||
m_halfwidth = 0.5 * layout.span(t);
|
||||
// the point itself may be off the axis, the stripes aren't
|
||||
auto const centre{axis.point(t)};
|
||||
m_state.position = centre;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kind_type::despawn:
|
||||
{
|
||||
// the vehicles are taken from every lane which passes close enough
|
||||
@@ -525,25 +555,8 @@ void roadpoint_node::bind()
|
||||
void roadpoint_node::bind_crossing()
|
||||
{
|
||||
// the road the crossing is on: the one whose axis passes nearest
|
||||
road_node const *crossed{nullptr};
|
||||
auto best{std::numeric_limits<double>::max()};
|
||||
for (auto const *road : simulation::Roads.sequence())
|
||||
{
|
||||
if (road == nullptr || road->m_editorremoved || out_of_reach(road->definition().axis, m_state.position, 50.0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto const &layout{road->definition()};
|
||||
path_curve const axis{layout.axis};
|
||||
double distance{0.0};
|
||||
auto const t{axis.nearest(m_state.position, distance)};
|
||||
if (distance > 0.5 * layout.width() * layout.scale(t) + 1.0 || std::abs(axis.point(t).y - m_state.position.y) > 3.0 || distance >= best)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
best = distance;
|
||||
crossed = road;
|
||||
}
|
||||
double where{0.0};
|
||||
auto const *crossed{road_under(m_state.position, where)};
|
||||
if (crossed != nullptr)
|
||||
{
|
||||
auto const &lanes{crossed->tracks()};
|
||||
@@ -659,6 +672,24 @@ void roadpoint_node::bind_crossing()
|
||||
{
|
||||
m_rails.emplace_back(entry.first);
|
||||
}
|
||||
// lanes the vehicles wait on while the crossing is closed: the ones with the stops, and what leads to them
|
||||
for (auto const &stop : m_stops)
|
||||
{
|
||||
auto *lane{stop.track};
|
||||
double reach{0.0};
|
||||
for (int guard = 0; lane != nullptr && guard < 64 && reach < queue_reach; ++guard)
|
||||
{
|
||||
if (std::find(m_queue.begin(), m_queue.end(), lane) == m_queue.end())
|
||||
{
|
||||
m_queue.emplace_back(lane);
|
||||
}
|
||||
if (false == lane->m_paths.empty())
|
||||
{
|
||||
reach += glm::distance(lane->m_paths.front().points[segment_data::point::start], lane->m_paths.front().points[segment_data::point::end]);
|
||||
}
|
||||
lane = lane->trPrev;
|
||||
}
|
||||
}
|
||||
close(m_closed);
|
||||
}
|
||||
|
||||
@@ -683,8 +714,10 @@ void roadpoint_node::unbind()
|
||||
}
|
||||
m_stops.clear();
|
||||
m_rails.clear();
|
||||
m_queue.clear();
|
||||
m_lanes.clear();
|
||||
m_seen.clear();
|
||||
m_onroad = false;
|
||||
}
|
||||
|
||||
// makes the vehicles of a spawn point
|
||||
@@ -709,47 +742,48 @@ void roadpoint_node::prepare()
|
||||
// vehicles are known by their names, so a point without one makes something up for them
|
||||
static int nameless{0};
|
||||
auto const basename{m_name.empty() ? "roadspawn" + std::to_string(++nameless) : m_name};
|
||||
for (auto const &definition : m_state.vehicles)
|
||||
// the listed vehicles are gone through as many times as it takes, from a random one on, so the set gets each kind in turn
|
||||
auto const kinds{m_state.vehicles.size()};
|
||||
auto const start{kinds > 0 ? std::min(kinds - 1, static_cast<std::size_t>(LocalRandom(0.0, static_cast<double>(kinds)))) : 0};
|
||||
for (int index = 0; index < m_state.count && kinds > 0; ++index)
|
||||
{
|
||||
for (int copy = 0; copy < m_state.copies; ++copy)
|
||||
auto const &definition{m_state.vehicles[(start + static_cast<std::size_t>(index)) % kinds]};
|
||||
// a vehicle like any other of the scenery, made where the point is and driven at the speed of the point...
|
||||
auto *vehicle{new TDynamicObject()};
|
||||
auto const length{vehicle->Init(basename + ":" + std::to_string(++m_made), definition.folder, definition.skin, definition.type, m_lanes.front(), m_offset + front_room, "headdriver",
|
||||
m_state.velocity, "", static_cast<float>(definition.load), definition.loadtype, false, "")};
|
||||
if (length == 0.0)
|
||||
{
|
||||
// a vehicle like any other of the scenery, made where the point is and driven at the speed of the point...
|
||||
auto *vehicle{new TDynamicObject()};
|
||||
auto const length{vehicle->Init(basename + ":" + std::to_string(++m_made), definition.folder, definition.skin, definition.type, m_lanes.front(), m_offset + front_room, "headdriver",
|
||||
m_state.velocity, "", static_cast<float>(definition.load), definition.loadtype, false, "")};
|
||||
if (length == 0.0)
|
||||
{
|
||||
ErrorLog("Bad road point: vehicle \"" + definition.folder + "/" + definition.type + "\" of spawn \"" + m_name + "\" couldn't be made");
|
||||
if (vehicle->MyTrack != nullptr)
|
||||
{
|
||||
vehicle->MyTrack->RemoveDynamicObject(vehicle);
|
||||
}
|
||||
delete vehicle;
|
||||
continue;
|
||||
}
|
||||
if (vehicle->mdModel != nullptr)
|
||||
{
|
||||
for (auto const &smokesource : vehicle->mdModel->smoke_sources())
|
||||
{
|
||||
simulation::Particles.insert(smokesource.first, vehicle, smokesource.second);
|
||||
}
|
||||
}
|
||||
if (false == simulation::Vehicles.insert(vehicle))
|
||||
{
|
||||
ErrorLog("Bad road point: vehicle name \"" + vehicle->name() + "\" made for spawn \"" + m_name + "\" is taken already");
|
||||
}
|
||||
pooled_vehicle entry;
|
||||
entry.vehicle = vehicle;
|
||||
entry.velocity = vehicle->MoverParameters->V;
|
||||
m_pool.emplace_back(entry);
|
||||
// ...which is taken off the road right away, the way the vehicles leaving the scenery are, to wait for its turn
|
||||
ErrorLog("Bad road point: vehicle \"" + definition.folder + "/" + definition.type + "\" of spawn \"" + m_name + "\" couldn't be made");
|
||||
if (vehicle->MyTrack != nullptr)
|
||||
{
|
||||
vehicle->MyTrack->RemoveDynamicObject(vehicle);
|
||||
vehicle->MyTrack = nullptr;
|
||||
}
|
||||
vehicle->bEnabled = false;
|
||||
delete vehicle;
|
||||
continue;
|
||||
}
|
||||
if (vehicle->mdModel != nullptr)
|
||||
{
|
||||
for (auto const &smokesource : vehicle->mdModel->smoke_sources())
|
||||
{
|
||||
simulation::Particles.insert(smokesource.first, vehicle, smokesource.second);
|
||||
}
|
||||
}
|
||||
if (false == simulation::Vehicles.insert(vehicle))
|
||||
{
|
||||
ErrorLog("Bad road point: vehicle name \"" + vehicle->name() + "\" made for spawn \"" + m_name + "\" is taken already");
|
||||
}
|
||||
pooled_vehicle entry;
|
||||
entry.vehicle = vehicle;
|
||||
entry.velocity = vehicle->MoverParameters->V;
|
||||
m_pool.emplace_back(entry);
|
||||
// ...which is taken off the road right away, the way the vehicles leaving the scenery are, to wait for its turn
|
||||
if (vehicle->MyTrack != nullptr)
|
||||
{
|
||||
vehicle->MyTrack->RemoveDynamicObject(vehicle);
|
||||
vehicle->MyTrack = nullptr;
|
||||
}
|
||||
vehicle->bEnabled = false;
|
||||
}
|
||||
if (m_pool.empty())
|
||||
{
|
||||
@@ -757,6 +791,12 @@ void roadpoint_node::prepare()
|
||||
}
|
||||
}
|
||||
|
||||
// true if specified vehicle stands in the line of vehicles held by the crossing
|
||||
bool roadpoint_node::holds(TDynamicObject const &Vehicle) const
|
||||
{
|
||||
return m_state.kind == kind_type::crossing && m_closed && false == m_editorremoved && std::find(m_queue.begin(), m_queue.end(), Vehicle.MyTrack) != m_queue.end();
|
||||
}
|
||||
|
||||
std::size_t roadpoint_node::waiting() const
|
||||
{
|
||||
return static_cast<std::size_t>(std::count_if(m_pool.begin(), m_pool.end(), [](pooled_vehicle const &Entry) { return false == Entry.vehicle->bEnabled && Entry.vehicle->MyTrack == nullptr; }));
|
||||
@@ -790,6 +830,11 @@ void roadpoint_node::update(double const Deltatime)
|
||||
update_despawn();
|
||||
break;
|
||||
}
|
||||
case kind_type::crosswalk:
|
||||
{
|
||||
// paint only
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,6 +891,36 @@ void roadpoint_node::update_spawn(double const Deltatime)
|
||||
// the point was made in the editor, or the scenery was loaded for editing
|
||||
prepare();
|
||||
}
|
||||
// vehicles of the point which got stuck are taken off the road, to wait for their next turn: the ones standing still
|
||||
// for too long, unless it's a closed level crossing they wait at, and the ones which started to go backwards
|
||||
for (auto &entry : m_pool)
|
||||
{
|
||||
auto *vehicle{entry.vehicle};
|
||||
if (false == vehicle->bEnabled || vehicle->MyTrack == nullptr || (simulation::Train != nullptr && simulation::Train->Dynamic() == vehicle))
|
||||
{
|
||||
// not on the road, or taken over by the user
|
||||
entry.standing = 0.0;
|
||||
continue;
|
||||
}
|
||||
auto const speed{vehicle->MoverParameters->V};
|
||||
// forward is the way it went when it was put on the road
|
||||
auto const backwards{speed * entry.velocity < 0.0 && std::abs(speed) > reverse_speed};
|
||||
if (std::abs(speed) > stuck_speed || simulation::Roadpoints.holds(*vehicle))
|
||||
{
|
||||
entry.standing = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.standing += Deltatime;
|
||||
}
|
||||
if (backwards || entry.standing > stuck_time)
|
||||
{
|
||||
WriteLog("Road traffic: vehicle \"" + vehicle->name() + "\" taken off the road, " + (backwards ? "it was going backwards" : "it stood still for too long"));
|
||||
entry.standing = 0.0;
|
||||
vehicle->bEnabled = false;
|
||||
TDynamicObject::bDynamicRemove = true;
|
||||
}
|
||||
}
|
||||
if (m_pool.empty() || m_lanes.empty())
|
||||
{
|
||||
return;
|
||||
@@ -933,15 +1008,41 @@ void roadpoint_node::update_despawn()
|
||||
std::vector<scene::shape_node> roadpoint_node::create_shapes() const
|
||||
{
|
||||
std::vector<scene::shape_node> shapes;
|
||||
if (m_state.kind != kind_type::crossing || false == m_state.stoplines || m_stops.empty())
|
||||
{
|
||||
return shapes;
|
||||
}
|
||||
std::vector<world_vertex> vertices;
|
||||
glm::dvec3 const lift{0.0, line_lift, 0.0};
|
||||
glm::vec3 const upwards{0.f, 1.f, 0.f};
|
||||
if (m_state.kind == kind_type::crosswalk && m_onroad)
|
||||
{
|
||||
// stripes laid along the road, side by side from one edge of it to the other
|
||||
glm::dvec3 across{m_along.z, 0.0, -m_along.x};
|
||||
if (glm::length2(across) > 1e-12)
|
||||
{
|
||||
across = glm::normalize(across);
|
||||
auto const reach{m_halfwidth - stopline_inset};
|
||||
auto const stripes{std::max(1, static_cast<int>(std::floor((2.0 * reach + stripe_width) / (2.0 * stripe_width))))};
|
||||
// the stripes are spread evenly over the width, with one at each edge
|
||||
auto const first{-0.5 * (stripes * 2 - 1) * stripe_width};
|
||||
auto const back{-m_along * static_cast<double>(m_state.length)};
|
||||
for (int stripe = 0; stripe < stripes; ++stripe)
|
||||
{
|
||||
auto const offset{first + stripe * 2.0 * stripe_width};
|
||||
auto const right{m_state.position + across * offset + m_along * (0.5 * m_state.length) + lift};
|
||||
auto const left{right + across * stripe_width};
|
||||
vertices.push_back({right + back, upwards, {0.f, 0.f}});
|
||||
vertices.push_back({right, upwards, {1.f, 0.f}});
|
||||
vertices.push_back({left + back, upwards, {0.f, 1.f}});
|
||||
vertices.push_back({right, upwards, {1.f, 0.f}});
|
||||
vertices.push_back({left, upwards, {1.f, 1.f}});
|
||||
vertices.push_back({left + back, upwards, {0.f, 1.f}});
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto const &stop : m_stops)
|
||||
{
|
||||
if (m_state.kind != kind_type::crossing || false == m_state.stoplines)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// a line across the lane, ending where the vehicles are to stop
|
||||
glm::dvec3 across{stop.direction.z, 0.0, -stop.direction.x};
|
||||
if (glm::length2(across) < 1e-12)
|
||||
@@ -993,7 +1094,7 @@ void roadpoint_node::hide()
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
float roadpoint_node::radius_()
|
||||
{
|
||||
return m_state.kind == kind_type::crossing ? m_state.clearance + 5.f : m_state.radius;
|
||||
return m_state.kind == kind_type::crossing ? m_state.clearance + 5.f : m_state.kind == kind_type::crosswalk ? static_cast<float>(m_halfwidth) + m_state.length : m_state.radius;
|
||||
}
|
||||
|
||||
// serialize() subclass details, sends content of the subclass to provided stream
|
||||
@@ -1025,7 +1126,7 @@ void roadpoint_node::export_as_text_(std::ostream &Output) const
|
||||
}
|
||||
case kind_type::spawn:
|
||||
{
|
||||
Output << "interval " << m_state.interval << ' ' << "variation " << m_state.variation << ' ' << "velocity " << m_state.velocity << ' ' << "copies " << m_state.copies << ' ';
|
||||
Output << "interval " << m_state.interval << ' ' << "variation " << m_state.variation << ' ' << "velocity " << m_state.velocity << ' ' << "count " << m_state.count << ' ';
|
||||
for (auto const &vehicle : m_state.vehicles)
|
||||
{
|
||||
// the way vehicles are put in a scenery. the path and the offset are there to keep that form, the point doesn't use them
|
||||
@@ -1043,6 +1144,11 @@ void roadpoint_node::export_as_text_(std::ostream &Output) const
|
||||
Output << "radius " << m_state.radius << ' ';
|
||||
break;
|
||||
}
|
||||
case kind_type::crosswalk:
|
||||
{
|
||||
Output << "length " << m_state.length << ' ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
Output << "end" << type << "\n";
|
||||
}
|
||||
@@ -1110,6 +1216,12 @@ void roadpoint_table::create_geometry()
|
||||
}
|
||||
}
|
||||
|
||||
// true if specified vehicle stands in the line of vehicles held by a closed level crossing
|
||||
bool roadpoint_table::holds(TDynamicObject const &Vehicle) const
|
||||
{
|
||||
return std::any_of(m_items.begin(), m_items.end(), [&Vehicle](roadpoint_node const *Point) { return Point != nullptr && Point->holds(Vehicle); });
|
||||
}
|
||||
|
||||
// to be called with each step of the simulation
|
||||
void roadpoint_table::update(double const Deltatime)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user