2 #include <msp/geometry/union.h>
10 TrackType::TrackType(const ArticleNumber &an):
16 float TrackType::get_total_length() const
18 return get_path_length(-1);
21 float TrackType::get_path_length(int p) const
24 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
25 if(p<0 || i->get_path()==static_cast<unsigned>(p))
26 len += i->get_length();
30 unsigned TrackType::get_paths() const
33 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
34 mask |= 1<<i->get_path();
38 unsigned TrackType::get_n_paths() const
41 for(unsigned mask = get_paths(); mask; ++n)
46 bool TrackType::is_turnout() const
48 return endpoints.size()>2;
51 bool TrackType::is_dead_end() const
53 return endpoints.size()<2;
56 const TrackType::Endpoint &TrackType::get_endpoint(unsigned i) const
58 if(i>=endpoints.size())
59 throw out_of_range("TrackType::get_endpoint");
64 OrientedPoint TrackType::get_point(unsigned epi, unsigned path, float d) const
66 if(epi>=endpoints.size())
67 throw out_of_range("TrackType::get_point");
69 const TrackPart *part = 0;
71 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
73 if(endpoints[epi].has_path(path) && i->get_path()!=path)
76 unsigned n_part_eps = (i->is_dead_end() ? 1 : 2);
77 for(unsigned j=0; j<n_part_eps; ++j)
79 OrientedPoint p = i->get_point(j ? i->get_length() : 0);
80 Vector span = p.position-endpoints[epi].pos;
81 if(dot(span, span)<1e-6)
90 throw logic_error("internal error (endpoint does not match any part)");
94 float plen = part->get_length();
99 OrientedPoint p = part->get_point(d);
101 p.rotation += Angle::half_turn();
107 TrackPart *next = part->get_link(1-part_ep);
109 throw invalid_argument("TrackType::get_point");
110 part_ep = (next->get_link(0)==part ? 0 : 1);
116 OrientedPoint TrackType::get_nearest_point(const Vector &p) const
118 OrientedPoint result;
121 for(vector<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
123 OrientedPoint n = i->get_nearest_point(p);
124 float d = distance(n.position, p);
135 void TrackType::collect_endpoints()
139 for(vector<TrackPart>::iterator i=parts.begin(); i!=parts.end(); ++i)
141 for(vector<TrackPart>::iterator j=i; ++j!=parts.end();)
144 unsigned n_part_eps = (i->is_dead_end() ? 1 : 2);
145 for(unsigned j=0; j<n_part_eps; ++j)
148 OrientedPoint p = i->get_point(j ? i->get_length() : 0);
150 p.rotation += Angle::half_turn();
153 for(vector<Endpoint>::iterator k=endpoints.begin(); k!=endpoints.end(); ++k)
155 Vector d = k->pos-p.position;
157 Angle da = wrap_balanced(k->dir-p.rotation);
159 if(dot(d, d)<1e-6 && abs(da).radians()<0.01)
161 k->paths |= 1<<i->get_path();
168 endpoints.push_back(Endpoint(p.position.x, p.position.y, p.rotation, 1<<i->get_path()));
173 TrackType::Endpoint::Endpoint(float x, float y, const Angle &d, unsigned p):
180 TrackType::Loader::Loader(TrackType &t):
181 DataFile::DerivedObjectLoader<TrackType, ObjectType::Loader>(t),
182 state_bits_set(false)
184 add("autofit_preference", &TrackType::autofit_preference);
185 add("object", &TrackType::object);
186 add("state_bits", &Loader::state_bits);
187 add("part", &Loader::part);
190 void TrackType::Loader::finish()
192 obj.collect_endpoints();
193 vector<const Shape *> shapes;
194 for(vector<TrackPart>::iterator i=obj.parts.begin(); i!=obj.parts.end(); ++i)
197 shapes.push_back(&i->get_shape());
199 obj.shape = Geometry::Union<float, 3>::from_iterator_range(shapes.begin(), shapes.end()).clone();
202 void TrackType::Loader::part()
206 obj.parts.push_back(p);
207 if(!state_bits_set && p.get_path())
208 while(p.get_path()>=(1U<<obj.state_bits))
212 void TrackType::Loader::state_bits(unsigned b)
215 state_bits_set = true;