]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/vehicletype.cpp
Also store gauge in VehicleType
[r2c2.git] / source / libr2c2 / vehicletype.cpp
1 #include <msp/core/maputils.h>
2 #include <msp/geometry/box.h>
3 #include <msp/geometry/transformedshape.h>
4 #include <msp/strings/regex.h>
5 #include <msp/strings/format.h>
6 #include "vehicletype.h"
7
8 using namespace std;
9 using namespace Msp;
10
11 namespace R2C2 {
12
13 VehicleType::VehicleType(const ArticleNumber &an):
14         ObjectType(an),
15         locomotive(false),
16         swap_direction(false),
17         gauge(1.524),
18         length(0),
19         width(0),
20         height(0),
21         rotate_object(false),
22         max_speed(0)
23 { }
24
25 unsigned VehicleType::get_max_function() const
26 {
27         if(functions.empty())
28                 return 0;
29         return (--functions.end())->first;
30 }
31
32 const VehicleType::Axle &VehicleType::get_axle(unsigned i) const
33 {
34         if(i>=axles.size())
35                 throw out_of_range("VehicleType::get_axle");
36         return axles[i];
37 }
38
39 const VehicleType::Axle &VehicleType::get_fixed_axle(unsigned i) const
40 {
41         if(i>=fixed_axles.size())
42                 throw out_of_range("VehicleType::get_fixed_axle");
43         return *fixed_axles[i];
44 }
45
46 const VehicleType::Bogie &VehicleType::get_bogie(unsigned i) const
47 {
48         if(i>=bogies.size())
49                 throw out_of_range("VehicleType::get_bogie");
50         return bogies[i];
51 }
52
53 const VehicleType::Axle &VehicleType::get_bogie_axle(unsigned i, unsigned j) const
54 {
55         if(i>=bogies.size())
56                 throw out_of_range("VehicleType::get_bogie_axle");
57         if(j>=bogies[i].axles.size())
58                 throw out_of_range("VehicleType::get_bogie_axle");
59         return *bogies[i].axles[j];
60 }
61
62 const VehicleType::Rod &VehicleType::get_rod(unsigned i) const
63 {
64         if(i>=rods.size())
65                 throw out_of_range("VehicleType::get_rod");
66         return rods[i];
67 }
68
69 float VehicleType::get_front_axle_offset() const
70 {
71         if(!axles.empty())
72                 return axles.front().position;
73         return length/2;
74 }
75
76 float VehicleType::get_back_axle_offset() const
77 {
78         if(!axles.empty())
79                 return axles.back().position;
80         return -length/2;
81 }
82
83
84 VehicleType::Axle::Axle():
85         index(0),
86         bogie(0),
87         local_position(0),
88         position(0),
89         wheel_dia(0),
90         powered(false)
91 { }
92
93
94 VehicleType::Bogie::Bogie():
95         position(0),
96         rotate_object(false)
97 { }
98
99
100 VehicleType::Rod::Rod():
101         mirror_object(false)
102 { }
103
104
105 VehicleType::Loader::Loader(VehicleType &vt):
106         DataFile::DerivedObjectLoader<VehicleType, ObjectType::Loader>(vt)
107 {
108         add("axle",       &Loader::axle);
109         add("bogie",      &Loader::bogie);
110         add("function",   &Loader::function);
111         add("gauge",      &Loader::gauge);
112         add("height",     &Loader::height);
113         add("length",     &Loader::length);
114         add("locomotive", &VehicleType::locomotive);
115         add("maximum_speed", &VehicleType::max_speed);
116         add("mirror_rods", &Loader::mirror_rods);
117         add("object",     &VehicleType::object);
118         add("rod",        &Loader::rod);
119         add("rotate_object", &VehicleType::rotate_object);
120         add("swap_direction", &VehicleType::swap_direction);
121         add("width",      &Loader::width);
122 }
123
124 void VehicleType::Loader::finish()
125 {
126         for(unsigned i=0; i<obj.bogies.size(); ++i)
127         {
128                 obj.bogies[i].index = i;
129                 for(unsigned j=0; j<obj.bogies[i].axles.size(); ++j)
130                 {
131                         obj.bogies[i].axles[j] = &obj.axles[obj.bogies[i].first_axle+j];
132                         obj.bogies[i].axles[j]->bogie = &obj.bogies[i];
133                         obj.bogies[i].axles[j]->position += obj.bogies[i].position;
134                 }
135         }
136
137         for(unsigned i=0; i<obj.axles.size(); ++i)
138         {
139                 obj.axles[i].index = i;
140                 if(!obj.axles[i].bogie)
141                         obj.fixed_axles.push_back(&obj.axles[i]);
142         }
143
144         for(TagMap::const_iterator i=rod_tags.begin(); i!=rod_tags.end(); ++i)
145                 if(i->second>=0x10000)
146                         throw runtime_error(format("unresolved reference to %s\n", i->first));
147
148         obj.shape = new Geometry::TransformedShape<float, 3>(
149                 Geometry::Box<float>(obj.length, obj.width, obj.height),
150                 Transform::translation(Vector(0, 0, obj.height/2)));
151 }
152
153 void VehicleType::Loader::axle()
154 {
155         Axle axl;
156         load_sub(axl);
157         obj.axles.push_back(axl);
158 }
159
160 void VehicleType::Loader::bogie()
161 {
162         Bogie bog;
163         Bogie::Loader ldr(obj, bog);
164         load_sub_with(ldr);
165         obj.bogies.push_back(bog);
166 }
167
168 void VehicleType::Loader::function(unsigned i, const string &f)
169 {
170         obj.functions[i] = f;
171 }
172
173 void VehicleType::Loader::gauge(float g)
174 {
175         obj.gauge = g/1000;
176 }
177
178 void VehicleType::Loader::height(float h)
179 {
180         obj.height = h/1000;
181 }
182
183 void VehicleType::Loader::length(float l)
184 {
185         obj.length = l/1000;
186 }
187
188 void VehicleType::Loader::mirror_rods()
189 {
190         MirrorParametersLoader params;
191         load_sub_with(params);
192         Regex r_filter(params.filter);
193
194         vector<unsigned> mirror_indices(obj.rods.size(), 0);
195         for(TagMap::const_iterator i=rod_tags.begin(); i!=rod_tags.end(); ++i)
196                 if(i->second<0x10000 && r_filter.match(i->first))
197                         mirror_indices[i->second] = 1;
198
199         for(unsigned i=0, j=obj.rods.size(); i<mirror_indices.size(); ++i)
200                 if(mirror_indices[i])
201                         mirror_indices[i] = j++;
202
203         Transform axle_trans = Transform::rotation(params.phase_offset, Vector(0, 1, 0));
204
205         for(unsigned i=0; i<mirror_indices.size(); ++i)
206         {
207                 if(!mirror_indices[i])
208                         continue;
209
210                 Rod mr = obj.rods[i];
211                 mr.initial_position.y = -mr.initial_position.y;
212                 mr.mirror_object = !mr.mirror_object;
213                 for(vector<RodConstraint>::iterator j=mr.constraints.begin(); j!=mr.constraints.end(); ++j)
214                 {
215                         j->target_position.y = -j->target_position.y;
216                         j->local_position.y = -j->local_position.y;
217                         j->axis.y = -j->axis.y;
218                         if(j->target==RodConstraint::ROD && mirror_indices[j->target_index])
219                                 j->target_index = mirror_indices[j->target_index];
220                         else if(j->target==RodConstraint::AXLE)
221                                 j->target_position = axle_trans.transform(j->target_position);
222                 }
223
224                 obj.rods.push_back(mr);
225         }
226 }
227
228 void VehicleType::Loader::rod(const string &t)
229 {
230         Rod rd;
231         Rod::Loader ldr(rd, rod_tags);
232         load_sub_with(ldr);
233
234         unsigned n = obj.rods.size();
235         if(rod_tags.count(t))
236         {
237                 unsigned p = rod_tags[t];
238                 for(vector<Rod>::iterator i=obj.rods.begin(); i!=obj.rods.end(); ++i)   
239                         for(vector<RodConstraint>::iterator j=i->constraints.begin(); j!=i->constraints.end(); ++j)
240                                 if(j->target_index==p)
241                                         j->target_index = n;
242         }
243         rod_tags[t] = n;
244         obj.rods.push_back(rd);
245 }
246
247 void VehicleType::Loader::width(float w)
248 {
249         obj.width = w/1000;
250 }
251
252
253 VehicleType::Axle::Loader::Loader(Axle &a):
254         DataFile::ObjectLoader<Axle>(a)
255 {
256         add("object",         &Axle::object);
257         add("position",       &Loader::position);
258         add("powered",        &Axle::powered);
259         add("wheel_diameter", &Loader::wheel_diameter);
260 }
261
262 void VehicleType::Axle::Loader::position(float p)
263 {
264         obj.local_position = p/1000;
265         obj.position = obj.local_position;
266 }
267
268 void VehicleType::Axle::Loader::wheel_diameter(float d)
269 {
270         obj.wheel_dia = d/1000;
271 }
272
273
274 VehicleType::Bogie::Loader::Loader(VehicleType &t, Bogie &b):
275         DataFile::ObjectLoader<Bogie>(b),
276         parent(t)
277 {
278         add("axle",          &Loader::axle);
279         add("object",        &Bogie::object);
280         add("position",      &Loader::position);
281         add("rotate_object", &Bogie::rotate_object);
282 }
283
284 void VehicleType::Bogie::Loader::axle()
285 {
286         Axle axl;
287         load_sub(axl);
288         if(obj.axles.empty())
289                 obj.first_axle = parent.axles.size();
290         parent.axles.push_back(axl);
291         // Actual pointers will be filled after everything is loaded
292         obj.axles.push_back(0);
293 }
294
295 void VehicleType::Bogie::Loader::position(float p)
296 {
297         obj.position = p/1000;
298 }
299
300
301 VehicleType::RodConstraint::RodConstraint():
302         type(MOVE),
303         target(BODY),
304         target_index(0)
305 { }
306
307
308 VehicleType::RodConstraint::Loader::Loader(RodConstraint &c, TagMap &t):
309         DataFile::ObjectLoader<RodConstraint>(c),
310         tags(t)
311 {
312         add("axis",            &Loader::axis);
313         add("local_position",  &Loader::local_position);
314         add("target_axle",     &Loader::target_axle);
315         add("target_position", &Loader::target_position);
316         add("target_rod",      &Loader::target_rod);
317 }
318
319 void VehicleType::RodConstraint::Loader::axis(float x, float y, float z)
320 {
321         obj.axis = Vector(x, y, z);
322         obj.axis.normalize();
323 }
324
325 void VehicleType::RodConstraint::Loader::local_position(float x, float y, float z)
326 {
327         obj.local_position = Vector(x/1000, y/1000, z/1000);
328 }
329
330 void VehicleType::RodConstraint::Loader::target_axle(unsigned i)
331 {
332         obj.target = AXLE;
333         obj.target_index = i;
334         // TODO check range
335 }
336
337 void VehicleType::RodConstraint::Loader::target_position(float x, float y, float z)
338 {
339         obj.target_position = Vector(x/1000, y/1000, z/1000);
340 }
341
342 void VehicleType::RodConstraint::Loader::target_rod(const string &n)
343 {
344         obj.target = ROD;
345         TagMap::iterator i = tags.find(n);
346         if(i!=tags.end())
347                 obj.target_index = i->second;
348         else
349         {
350                 obj.target_index = 0x10000+tags.size();
351                 tags[n] = obj.target_index;
352         }
353 }
354
355
356 VehicleType::Rod::Loader::Loader(Rod &r, TagMap &t):
357         DataFile::ObjectLoader<Rod>(r),
358         tags(t)
359 {
360         add("initial_position", &Loader::initial_position);
361         add("mirror_object", &Rod::mirror_object);
362         add("move", &Loader::constraint<RodConstraint::MOVE>);
363         add("object", &Rod::object);
364         add("rotate", &Loader::constraint<RodConstraint::ROTATE>);
365         add("slide", &Loader::constraint<RodConstraint::SLIDE>);
366 }
367
368 template<VehicleType::RodConstraint::Type t>
369 void VehicleType::Rod::Loader::constraint()
370 {
371         RodConstraint cns;
372         cns.type = t;
373         load_sub(cns, tags);
374         obj.constraints.push_back(cns);
375 }
376
377 void VehicleType::Rod::Loader::initial_position(float x, float y, float z)
378 {
379         obj.initial_position = Vector(x/1000, y/1000, z/1000);
380 }
381
382
383 VehicleType::MirrorParametersLoader::MirrorParametersLoader()
384 {
385         add("filter", &MirrorParametersLoader::filt);
386         add("phase_offset", &MirrorParametersLoader::phase_offs);
387 }
388
389 void VehicleType::MirrorParametersLoader::filt(const string &f)
390 {
391         filter = f;
392 }
393
394 void VehicleType::MirrorParametersLoader::phase_offs(float o)
395 {
396         phase_offset = Angle::from_degrees(o);
397 }
398
399 } // namespace R2C2