3 This file is part of the MSP Märklin suite
4 Copyright © 2010 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
12 #include "tracktype.h"
14 #include "vehicletype.h"
21 Vehicle::Vehicle(Layout &l, const VehicleType &t):
27 bogie_dirs(type.get_bogies().size())
29 layout.add_vehicle(*this);
34 layout.remove_vehicle(*this);
37 void Vehicle::attach_back(Vehicle &veh)
40 throw InvalidState("Already attached");
46 void Vehicle::attach_front(Vehicle &veh)
49 throw InvalidState("Already attached");
55 void Vehicle::detach_back()
58 throw InvalidState("Not attached");
64 void Vehicle::detach_front()
67 throw InvalidState("Not attached");
73 void Vehicle::place(Track *t, unsigned e, float o, PlaceMode m)
75 track_pos = TrackPosition(t, e, o);
79 float front = type.get_length()/2;
80 if(!type.get_axles().empty())
81 front = type.get_axles().front().position;
82 if(!type.get_bogies().empty())
84 const VehicleType::Bogie &bogie = type.get_bogies().front();
85 front = max(front, bogie.position+bogie.axles.front().position);
87 track_pos.advance(-front);
89 else if(m==FRONT_BUFFER)
90 track_pos.advance(-type.get_length()/2);
93 float back = type.get_length()/2;
94 if(!type.get_axles().empty())
95 back = type.get_axles().back().position;
96 if(!type.get_bogies().empty())
98 const VehicleType::Bogie &bogie = type.get_bogies().back();
99 back = min(back, bogie.position+bogie.axles.back().position);
101 track_pos.advance(-back);
103 else if(m==BACK_BUFFER)
104 track_pos.advance(type.get_length()/2);
107 propagate_position();
110 void Vehicle::advance(float d)
112 track_pos.advance(d);
114 propagate_position();
117 float Vehicle::get_bogie_direction(unsigned i) const
119 if(i>=bogie_dirs.size())
120 throw InvalidParameterValue("Bogie index out of range");
121 return bogie_dirs[i];
124 void Vehicle::update_position()
128 const vector<VehicleType::Axle> &axles = type.get_axles();
131 float wheelbase = axles.front().position-axles.back().position;
132 tp = get_point(track_pos, wheelbase, -axles.back().position/wheelbase);
136 const vector<VehicleType::Bogie> &bogies = type.get_bogies();
139 TrackPosition front = track_pos;
140 front.advance(bogies.front().position);
141 TrackPosition back = track_pos;
142 back.advance(bogies.back().position);
143 float bogie_spacing = bogies.front().position-bogies.back().position;
144 adjust_for_distance(front, back, bogie_spacing);
146 const vector<VehicleType::Axle> &front_axles = bogies.front().axles;
147 float wheelbase = front_axles.front().position-front_axles.back().position;
148 TrackPoint front_point = get_point(front, wheelbase, -front_axles.back().position/wheelbase);
150 const vector<VehicleType::Axle> &back_axles = bogies.back().axles;
151 wheelbase = back_axles.front().position-back_axles.back().position;
152 TrackPoint back_point = get_point(back, wheelbase, -back_axles.back().position/wheelbase);
154 tp = get_point(front_point.pos, back_point.pos, -bogies.back().position/bogie_spacing);
156 bogie_dirs.front() = front_point.dir-tp.dir;
157 bogie_dirs.back() = back_point.dir-tp.dir;
160 tp = track_pos.get_point();
167 void Vehicle::update_position_from(const Vehicle &veh)
169 int sign = (&veh==prev ? -1 : 1);
171 float tdist = (type.get_length()+veh.type.get_length())/2;
172 float margin = layout.get_catalogue().get_scale();
174 float dist = distance(veh.position, position);
175 if(dist<tdist-margin || dist>tdist+margin)
177 track_pos = veh.track_pos;
178 track_pos.advance(sign*tdist);
181 dist = distance(veh.position, position);
184 track_pos.advance(sign*(tdist-dist));
188 void Vehicle::propagate_position()
193 propagate_backward();
196 void Vehicle::propagate_forward()
198 prev->update_position_from(*this);
201 prev->propagate_forward();
204 void Vehicle::propagate_backward()
206 next->update_position_from(*this);
209 next->propagate_backward();
212 void Vehicle::adjust_for_distance(TrackPosition &front, TrackPosition &back, float tdist, float ratio) const
214 float margin = 0.01*layout.get_catalogue().get_scale();
218 Point front_point = front.get_point().pos;
219 Point back_point = back.get_point().pos;
221 float dx = front_point.x-back_point.x;
222 float dy = front_point.y-back_point.y;
223 float dz = front_point.z-back_point.z;
224 float dist = sqrt(dx*dx+dy*dy+dz*dz);
226 float diff = tdist-dist;
227 if(diff<-margin && adjust_dir<=0)
232 else if(diff>margin && adjust_dir>=0)
240 front.advance(diff*(1-ratio));
241 back.advance(-diff*ratio);
245 TrackPoint Vehicle::get_point(const Point &front, const Point &back, float ratio) const
247 float dx = front.x-back.x;
248 float dy = front.y-back.y;
249 float dz = front.z-back.z;
252 tp.pos = Point(back.x+dx*ratio, back.y+dy*ratio, back.z+dz*ratio);
253 tp.dir = atan2(dy, dx);
258 TrackPoint Vehicle::get_point(const TrackPosition &pos, float tdist, float ratio) const
260 TrackPosition front = pos;
261 front.advance(tdist*(1-ratio));
263 TrackPosition back = pos;
264 back.advance(-tdist*ratio);
266 adjust_for_distance(front, back, tdist, ratio);
267 return get_point(front.get_point().pos, back.get_point().pos, ratio);
271 Vehicle::TrackPosition::TrackPosition():
277 Vehicle::TrackPosition::TrackPosition(Track *t, unsigned e, float o):
283 void Vehicle::TrackPosition::advance(float d)
288 unsigned path = track->get_active_path();
291 float path_len = track->get_type().get_path_length(path);
292 while(track && offs>=path_len)
294 unsigned out = track->traverse(ep, path);
295 Track *next = track->get_link(out);
299 ep = next->get_endpoint_by_link(*track);
303 path = track->get_active_path();
304 path_len = track->get_type().get_path_length(path);
310 while(track && offs<0)
312 Track *prev = track->get_link(ep);
315 unsigned in = prev->get_endpoint_by_link(*track);
318 path = track->get_active_path();
319 ep = track->traverse(in, path);
321 path_len = track->get_type().get_path_length(path);
335 TrackPoint Vehicle::TrackPosition::get_point() const
338 return track->get_point(ep, offs);
343 } // namespace Marklin