2 #include <msp/geometry/box.h>
3 #include <msp/geometry/circle.h>
4 #include <msp/geometry/extrudedshape.h>
5 #include <msp/geometry/halfspace.h>
6 #include <msp/geometry/intersection.h>
7 #include <msp/geometry/negation.h>
8 #include <msp/geometry/transformedshape.h>
16 TrackPart::TrackPart():
27 TrackPart::~TrackPart()
32 float TrackPart::get_length() const
35 return abs(radius)*length;
40 OrientedPoint TrackPart::get_point(float d) const
44 Transform dir_trans = Transform::rotation(dir, Vector(0, 0, 1));
47 Angle a = Angle::from_radians(d/radius);
48 Vector r = dir_trans.transform(Vector(0, -radius, 0));
49 result.position = pos-r+Transform::rotation(a, Vector(0, 0, 1)).transform(r);
50 result.rotation = dir+a;
54 result.position = pos+dir_trans.transform(Vector(d, 0, 0));
55 result.rotation = dir;
61 OrientedPoint TrackPart::get_nearest_point(const Vector &p) const
64 Transform dir_trans = Transform::rotation(dir, Vector(0, 0, 1));
67 Vector r = dir_trans.transform(Vector(0, -radius, 0));
69 Angle a = Geometry::atan2(v.y, v.x)+Angle::quarter_turn()-dir;
71 a = Angle::half_turn()-a;
72 a.wrap_with_base(Angle::from_radians(length/2)-Angle::half_turn());
73 a = min(max(a, Angle::zero()), Angle::from_radians(length));
76 result.position = pos-r+Transform::rotation(a, Vector(0, 0, 1)).transform(r);
77 result.rotation = dir+a;
82 Vector dir_vec = dir_trans.transform(Vector(1, 0, 0));
83 float d = min(max(dot(dir_vec, v), 0.0f), length);
84 result.position = pos+dir_vec*d;
85 result.rotation = dir;
90 void TrackPart::check_link(TrackPart &other)
92 unsigned n_eps = (dead_end ? 1 : 2);
93 unsigned n_other_eps = (other.is_dead_end() ? 1 : 2);
94 for(unsigned i=0; i<n_eps; ++i)
96 OrientedPoint p1 = get_point(i ? get_length() : 0);
97 for(unsigned j=0; j<n_other_eps; ++j)
99 OrientedPoint p2 = other.get_point(j ? other.get_length() : 0);
101 Vector span = p2.position-p1.position;
103 Angle da = wrap_balanced(p2.rotation-p1.rotation+Angle::half_turn()*float((i+j+1)%2));
105 if(dot(span, span)<1e-6 && abs(da).radians()<=0.01)
108 other.links[j] = this;
115 TrackPart *TrackPart::get_link(unsigned i) const
118 throw out_of_range("TrackPart::get_link");
122 void TrackPart::create_shape()
124 Transform trans = Transform::translation(pos)*
125 Transform::rotation(dir, LinAl::Vector<float, 3>(0, 0, 1));
128 Geometry::ExtrudedShape<float, 3> ring(
129 Geometry::Intersection<float, 2>(
130 Geometry::Circle<float>(abs(radius)+0.02),
131 Geometry::Negation<float, 2>(Geometry::Circle<float>(abs(radius)-0.02))),
133 Geometry::HalfSpace<float, 3> start_wall(Vector(-1, 0, 0));
134 Geometry::HalfSpace<float, 3> end_wall(rotated_vector(Vector(1, 0, 0),
135 Angle::from_radians(length*(radius<0 ? -1 : 1))));
136 /* This box only exists so the bounding boxes of curves make sense. It
137 can be removed when libmspmath produces better bounding boxes. */
138 float w = sin(length)*(abs(radius)+0.02);
139 float h = (1-cos(length))*abs(radius-0.02)+0.04;
140 Geometry::TransformedShape<float, 3> bounds(
141 Geometry::Box<float>(w, h, 0.01),
142 Transform::translation(Vector(w/2, (h/2-0.02)*(radius<0 ? -1 : 1)-radius, 0.005)));
143 vector<const Shape *> shapes;
144 shapes.push_back(&ring);
145 shapes.push_back(&start_wall);
146 shapes.push_back(&end_wall);
147 shapes.push_back(&bounds);
148 shape = new Geometry::TransformedShape<float, 3>(
149 Geometry::Intersection<float, 3>::from_iterator_range(shapes.begin(), shapes.end()),
150 trans*Transform::translation(Vector(0, radius, 0.005)));
154 // TODO Get the track profile dimensions from somewhere
155 shape = new Geometry::TransformedShape<float, 3>(
156 Geometry::Box<float>(length, 0.04, 0.01),
157 trans*Transform::translation(Vector(length/2, 0, 0.005)));
162 TrackPart::Loader::Loader(TrackPart &p):
163 Msp::DataFile::ObjectLoader<TrackPart>(p)
165 add("start", &Loader::start);
166 add("length", &TrackPart::length);
167 add("radius", &TrackPart::radius);
168 add("path", &TrackPart::path);
169 add("dead_end", &TrackPart::dead_end);
172 void TrackPart::Loader::finish()
176 obj.length *= M_PI/180;
185 void TrackPart::Loader::start(float x, float y, float d)
187 obj.pos = Vector(x, y, 0);
188 obj.dir = Angle::from_degrees(d);