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