2 #include <msp/datafile/collection.h>
3 #include <msp/geometry/union.h>
4 #include "trackappearance.h"
12 TrackType::TrackType(const ArticleNumber &an):
19 const TrackAppearance &TrackType::get_appearance() const
22 throw logic_error("no appearance");
26 float TrackType::get_gauge() const
28 return get_appearance().get_gauge();
31 float TrackType::get_total_length() const
33 return get_path_length(-1);
36 float TrackType::get_path_length(int p) const
39 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
40 if(p<0 || i->get_path()==static_cast<unsigned>(p))
41 len += i->get_length();
45 unsigned TrackType::get_paths() const
48 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
49 mask |= 1<<i->get_path();
53 unsigned TrackType::get_n_paths() const
56 for(unsigned mask = get_paths(); mask; ++n)
61 unsigned TrackType::coerce_path(unsigned entry, unsigned path) const
63 const Endpoint &ep = get_endpoint(entry);
67 unsigned paths = get_paths();
68 if(paths>>(1<<state_bits))
70 /* There are more paths than can be expressed with state_bits, so
71 multiple paths are set at once. See if one of the alternatives fits. */
72 unsigned step = 1<<state_bits;
73 for(unsigned p=path+step; paths>>p; p+=step)
78 // Find an endpoint that's connected to the entry and has the requested path
79 for(vector<Endpoint>::const_iterator i=endpoints.begin(); i!=endpoints.end(); ++i)
80 if(i->has_path(path) && i->has_common_paths(ep))
83 for(unsigned m=i->paths&ep.paths; m>>p; ++p) ;
87 // TODO crossings fall here
88 throw logic_error("TrackType::coerce_path");
91 bool TrackType::is_turnout() const
93 return endpoints.size()>2;
96 bool TrackType::is_dead_end() const
98 return endpoints.size()<2;
101 const TrackType::Endpoint &TrackType::get_endpoint(unsigned i) const
103 if(i>=endpoints.size())
104 throw out_of_range("TrackType::get_endpoint");
109 OrientedPoint TrackType::get_point(unsigned epi, unsigned path, float d) const
111 if(epi>=endpoints.size())
112 throw out_of_range("TrackType::get_point");
114 const TrackPart *part = 0;
115 unsigned part_ep = 0;
116 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
118 if(endpoints[epi].has_path(path) && i->get_path()!=path)
121 unsigned n_part_eps = (i->is_dead_end() ? 1 : 2);
122 for(unsigned j=0; j<n_part_eps; ++j)
124 OrientedPoint p = i->get_point(j ? i->get_length() : 0);
125 Vector span = p.position-endpoints[epi].pos;
126 if(dot(span, span)<1e-6)
135 throw logic_error("internal error (endpoint does not match any part)");
139 float plen = part->get_length();
144 OrientedPoint p = part->get_point(d);
146 p.rotation += Angle::half_turn();
152 TrackPart *next = part->get_link(1-part_ep);
154 throw invalid_argument("TrackType::get_point");
155 part_ep = (next->get_link(0)==part ? 0 : 1);
161 OrientedPoint TrackType::get_nearest_point(const Vector &p) const
163 OrientedPoint result;
166 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
168 OrientedPoint n = i->get_nearest_point(p);
169 float d = distance(n.position, p);
180 void TrackType::collect_endpoints()
184 for(vector<TrackPart>::iterator i=parts.begin(); i!=parts.end(); ++i)
186 for(vector<TrackPart>::iterator j=i; ++j!=parts.end();)
189 unsigned n_part_eps = (i->is_dead_end() ? 1 : 2);
190 for(unsigned j=0; j<n_part_eps; ++j)
193 OrientedPoint p = i->get_point(j ? i->get_length() : 0);
195 p.rotation += Angle::half_turn();
198 for(vector<Endpoint>::iterator k=endpoints.begin(); k!=endpoints.end(); ++k)
200 Vector d = k->pos-p.position;
202 Angle da = wrap_balanced(k->dir-p.rotation);
204 if(dot(d, d)<1e-6 && abs(da).radians()<0.01)
206 k->paths |= 1<<i->get_path();
213 endpoints.push_back(Endpoint(p.position.x, p.position.y, p.rotation, 1<<i->get_path()));
218 TrackType::Endpoint::Endpoint(float x, float y, const Angle &d, unsigned p):
225 TrackType::Loader::Loader(TrackType &t, Collection &c):
226 DataFile::DerivedObjectLoader<TrackType, ObjectType::Loader>(t),
228 state_bits_set(false)
230 add("appearance", &TrackType::appearance);
231 add("autofit_preference", &TrackType::autofit_preference);
232 add("object", &TrackType::object);
233 add("state_bits", &Loader::state_bits);
234 add("part", &Loader::part);
237 void TrackType::Loader::finish()
239 obj.collect_endpoints();
240 vector<const Shape *> shapes;
241 for(vector<TrackPart>::iterator i=obj.parts.begin(); i!=obj.parts.end(); ++i)
244 shapes.push_back(&i->get_shape());
246 obj.shape = Geometry::Union<float, 3>::from_iterator_range(shapes.begin(), shapes.end()).clone();
249 void TrackType::Loader::part()
253 obj.parts.push_back(p);
254 if(!state_bits_set && p.get_path())
255 while(p.get_path()>=(1U<<obj.state_bits))
259 void TrackType::Loader::state_bits(unsigned b)
262 state_bits_set = true;