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