1 #include "vehicleplacement.h"
8 VehiclePlacement::VehiclePlacement(const VehicleType &t):
11 const VehicleType::AxleArray &type_axles = type.get_axles();
12 const VehicleType::Axle *first_fixed = 0;
13 const VehicleType::Axle *last_fixed = 0;
14 for(VehicleType::AxleArray::const_iterator i=type_axles.begin(); i!=type_axles.end(); ++i)
23 float front_offset, back_offset;
26 axles.push_back(*first_fixed);
27 axles.push_back(*last_fixed);
28 front_offset = axles.front().type->position;
29 back_offset = axles.back().type->position;
33 const VehicleType::BogieArray &type_bogies = type.get_bogies();
34 if(type_bogies.size()>=2)
36 axles.push_back(*type_bogies.front().axles.front());
37 axles.push_back(*type_bogies.front().axles.back());
38 axles.push_back(*type_bogies.back().axles.front());
39 axles.push_back(*type_bogies.back().axles.back());
40 front_offset = type_bogies.front().position;
41 back_offset = type_bogies.back().position;
44 // TODO Handle weird configurations; one fixed axle and one bogie?
45 throw invalid_argument("unsupported axle configuration");
48 front_back_span = front_offset-back_offset;
49 front_back_ratio = front_offset/front_back_span;
52 void VehiclePlacement::place(const TrackOffsetIter &p, Anchor a)
57 float anchor = get_anchor_position(a);
59 for(vector<Axle>::iterator i=axles.begin(); i!=axles.end(); ++i)
60 i->position = p.advance(i->type->position-anchor);
62 fix_positions(anchor);
65 float VehiclePlacement::get_anchor_position(Anchor a) const
67 /* Use front and back axle from the type, as those are not necessarily the
68 same as the first and last axle used to determine position. */
70 return type.get_axles().front().position;
71 else if(a==FRONT_BUFFER)
72 return type.get_length()/2;
74 return type.get_axles().back().position;
75 else if(a==BACK_BUFFER)
76 return -type.get_length()/2;
81 void VehiclePlacement::place_after(const VehiclePlacement &other)
83 const Axle &other_axle = other.axles.back();
84 place(other_axle.position.advance(-other.type.get_length()/2-other_axle.type->position), FRONT_BUFFER);
87 void VehiclePlacement::place_before(const VehiclePlacement &other)
89 const Axle &other_axle = other.axles.front();
90 place(other_axle.position.advance(other.type.get_length()/2-other_axle.type->position), BACK_BUFFER);
93 void VehiclePlacement::unplace()
95 for(vector<Axle>::iterator i=axles.begin(); i!=axles.end(); ++i)
96 i->position = TrackOffsetIter();
99 bool VehiclePlacement::is_placed() const
101 return axles.front().position;
104 OrientedPoint VehiclePlacement::get_point() const
106 Vector front = get_front_point().position;
107 Vector back = get_back_point().position;
108 return create_point(front, back, front_back_ratio);
111 const TrackOffsetIter &VehiclePlacement::get_axle_position(unsigned i) const
113 for(vector<Axle>::const_iterator j=axles.begin(); j!=axles.end(); ++j)
114 if(j->type->index==i)
117 throw invalid_argument("VehiclePlacement::get_axle_position");
120 TrackOffsetIter VehiclePlacement::get_position(Anchor a) const
122 float position = get_anchor_position(a);
123 const Axle *closest_axle = 0;
124 float closest_diff = -1;
125 for(vector<Axle>::const_iterator j=axles.begin(); j!=axles.end(); ++j)
127 float diff = abs(j->type->position-position);
128 if(!closest_axle || diff<closest_diff)
135 return closest_axle->position.advance(position-closest_axle->type->position);
138 OrientedPoint VehiclePlacement::get_axle_point(unsigned i) const
140 return get_axle_position(i).point();
143 OrientedPoint VehiclePlacement::get_bogie_point(unsigned i) const
146 for(j=0; j<axles.size(); ++j)
147 if(axles[j].type->bogie && axles[j].type->bogie->index==i)
148 return get_bogie_point_from_axle(j);
150 // TODO Come up with positions of other bogies
151 throw invalid_argument("VehiclePlacement::get_bogie_point");
154 OrientedPoint VehiclePlacement::get_front_point() const
156 if(axles.front().type->bogie)
157 return get_bogie_point_from_axle(0);
159 return axles.front().position.point();
162 OrientedPoint VehiclePlacement::get_back_point() const
164 if(axles.back().type->bogie)
165 return get_bogie_point_from_axle(axles.size()-2);
167 return axles.back().position.point();
170 OrientedPoint VehiclePlacement::get_bogie_point_from_axle(unsigned i) const
172 Vector front = axles[i].position.point().position;
173 Vector back = axles[i+1].position.point().position;
174 float span = axles[i].type->local_position-axles[i+1].type->local_position;
175 float ratio = axles[i].type->local_position/span;
176 return create_point(front, back, ratio);
179 OrientedPoint VehiclePlacement::create_point(const Vector &front, const Vector &back, float ratio)
181 OrientedPoint result;
182 result.position = front*(1-ratio)+back*ratio;
183 result.rotation = Geometry::atan2<float>(front.y-back.y, front.x-back.x);
184 result.tilt = Geometry::atan2<float>(front.z-back.z, (front-back).slice<2>(0).norm());
188 void VehiclePlacement::advance(float d, Anchor a)
190 for(vector<Axle>::iterator i=axles.begin(); i!=axles.end(); ++i)
191 i->position = i->position.advance(d);
193 fix_positions(get_anchor_position(a));
196 void VehiclePlacement::fix_positions(float anchor)
198 float ratio = front_back_ratio-anchor/front_back_span;
199 float last_adjust = -1;
202 Vector front = get_front_point().position;
203 Vector back = get_back_point().position;
205 float adjust = compute_adjustment(front, back, front_back_span, last_adjust);
209 axles.front().position = axles.front().position.advance(adjust*ratio);
210 if(axles.front().type->bogie)
212 axles[1].position = axles[1].position.advance(adjust*ratio);
213 fix_bogie_position(0);
216 axles.back().position = axles.back().position.advance(adjust*(ratio-1));
217 if(axles.back().type->bogie)
219 axles[axles.size()-2].position = axles[axles.size()-2].position.advance(adjust*(ratio-1));
220 fix_bogie_position(axles.size()-2);
225 void VehiclePlacement::fix_bogie_position(unsigned i)
227 Axle &front_axle = axles[i];
228 Axle &back_axle = axles[i+1];
229 float target_span = front_axle.type->local_position-back_axle.type->local_position;
230 float ratio = front_axle.type->local_position/target_span;
232 float last_adjust = -1;
235 Vector front_point = front_axle.position.point().position;
236 Vector back_point = back_axle.position.point().position;
238 float adjust = compute_adjustment(front_point, back_point, target_span, last_adjust);
242 front_axle.position = front_axle.position.advance(adjust*ratio);
243 back_axle.position = back_axle.position.advance(adjust*(ratio-1));
247 float VehiclePlacement::compute_adjustment(const Vector &p1, const Vector &p2, float target, float &last)
249 float span = distance(p1, p2);
250 float adjust = target-span;
252 /* If the adjustment is not smaller than the last one, we've hit a gap or
253 other oddity in the track. Terminate to avoid an infinite loop. */
254 if(last>0 && abs(adjust)>=last)
257 if(abs(adjust)*10000<target)
265 VehiclePlacement::Axle::Axle(const VehicleType::Axle &t):