From: Mikko Rasa Date: Thu, 23 May 2013 20:12:00 +0000 (+0300) Subject: Make use of the geometry part of libmspmath X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=bde934f7d5ba07a9442a305192e10024820d13ed;p=r2c2.git Make use of the geometry part of libmspmath --- diff --git a/source/3d/layout.cpp b/source/3d/layout.cpp index d97dfe5..69af0d4 100644 --- a/source/3d/layout.cpp +++ b/source/3d/layout.cpp @@ -38,18 +38,13 @@ Layout3D::~Layout3D() void Layout3D::get_bounds(Vector &minp, Vector &maxp) const { - minp = maxp = Vector(); + Geometry::BoundingBox bbox; for(TrackMap::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) - { - Vector tmin; - Vector tmax; - i->second->get_bounds(Angle::zero(), tmin, tmax); - minp.x = min(minp.x, tmin.x); - minp.y = min(minp.y, tmin.y); - maxp.x = max(maxp.x, tmax.x); - maxp.y = max(maxp.y, tmax.y); - } + bbox = bbox|i->second->get_track().get_type().get_shape()->get_axis_aligned_bounding_box(); + + minp = bbox.get_minimum_point(); + maxp = bbox.get_maximum_point(); } void Layout3D::add_track(Track3D &t) diff --git a/source/3d/track.cpp b/source/3d/track.cpp index bd148a7..9797c4a 100644 --- a/source/3d/track.cpp +++ b/source/3d/track.cpp @@ -47,26 +47,11 @@ Track3D::~Track3D() delete *i; } -void Track3D::get_bounds(const Angle &angle, Vector &minp, Vector &maxp) const -{ - type.get_bounds(angle-track.get_rotation(), minp, maxp); - - Vector pos = rotated_vector(track.get_position(), -angle); - minp += pos; - maxp += pos; - - float slope = track.get_slope(); - if(slope>0) - maxp.z += slope; - else - minp.z += slope; -} - Vector Track3D::get_node() const { - Vector minp; - Vector maxp; - type.get_bounds(Angle::zero(), minp, maxp); + Geometry::BoundingBox bbox = track.get_type().get_shape()->get_axis_aligned_bounding_box(); + const Vector &minp = bbox.get_minimum_point(); + const Vector &maxp = bbox.get_maximum_point(); return track.get_position()+rotated_vector((minp+maxp)/2.0f, track.get_rotation())+Vector(0, 0, 0.02); } diff --git a/source/3d/track.h b/source/3d/track.h index 641f234..857b129 100644 --- a/source/3d/track.h +++ b/source/3d/track.h @@ -32,7 +32,6 @@ public: Layout3D &get_layout() const { return layout; } Track &get_track() const { return track; } const TrackType3D &get_type() const { return type; } - void get_bounds(const Angle &, Vector &, Vector &) const; Path3D &get_path() { return *path; } virtual Vector get_node() const; diff --git a/source/3d/tracktype.cpp b/source/3d/tracktype.cpp index a5e97cc..6dfd2a4 100644 --- a/source/3d/tracktype.cpp +++ b/source/3d/tracktype.cpp @@ -7,61 +7,6 @@ using namespace std; using namespace Msp; -namespace { - -bool compare_z(const R2C2::Vector &p1, const R2C2::Vector &p2) -{ - return p1.z -Iter graham_scan(Iter begin, Iter end) -{ - // http://en.wikipedia.org/wiki/Graham_scan - - // Find point with lowest X coordinate - R2C2::Vector lowest = *begin; - for(Iter i=begin; i!=end; ++i) - if(i->xx==lowest.x && i->y>lowest.y)) - lowest = *i; - - // Compute tangents and sort points - for(Iter i=begin; i!=end; ++i) - i->z = (i->x==lowest.x ? 1e5/(i->y-lowest.y-1) : (i->y-lowest.y)/(i->x-lowest.x)); - sort(begin, end, compare_z); - - for(Iter k=begin, i=k++, j=k++;; ) - { - // Compute winding by cross product - float turn = cross(*j-*i, *k-*j).z; - - if(turn<1e-5) - { - // Right turn - throw the middle point away - // Special case for collinear vertices in the beginning - if(i==begin) - j = k++; - else - j = i--; - } - else - { - // Left turn - store the middle point and advance - if(++i!=j) - *i = *j; - j = k++; - } - - // Cycle back to beginning and terminate after checking the last point - if(k==end) - k = begin; - else if(j==begin) - return ++i; - } -} - -} - namespace R2C2 { TrackType3D::TrackType3D(Catalogue3D &cat3d, const TrackType &tt): @@ -86,20 +31,7 @@ TrackType3D::TrackType3D(Catalogue3D &cat3d, const TrackType &tt): string obj_name = tt.get_object(); if(!obj_name.empty()) - { object = &catalogue.get(obj_name); - const GL::Mesh *m = object->get_mesh(); - const GL::VertexArray &vertices = m->get_vertices(); - int vertex_offs = vertices.get_format().offset(GL::VERTEX2); - if(vertex_offs>=0) - { - for(unsigned i=0; i::iterator i=border.begin(); i!=border.end(); ++i) - { - min_z = min(min_z, i->z); - max_z = max(max_z, i->z); - } - border.erase(graham_scan(border.begin(), border.end()), border.end()); } TrackType3D::~TrackType3D() @@ -154,25 +78,6 @@ TrackType3D::~TrackType3D() delete *i; } -void TrackType3D::get_bounds(const Angle &angle, Vector &minp, Vector &maxp) const -{ - Transform trans = Transform::rotation(-angle, Vector(0, 0, 1)); - - minp = maxp = Vector(); - minp.z = min_z; - maxp.z = max_z; - - for(vector::const_iterator i=border.begin(); i!=border.end(); ++i) - { - Vector v = trans.transform(*i); - - minp.x = min(minp.x, v.x); - minp.y = min(minp.y, v.y); - maxp.x = max(maxp.x, v.x); - maxp.y = max(maxp.y, v.y); - } -} - const GL::Mesh &TrackType3D::get_path_mesh(unsigned p) const { if(p>=path_meshes.size()) @@ -208,8 +113,6 @@ void TrackType3D::build_part(const TrackPart &part, const Profile &profile, cons bld.normal(n.x, n.y, n.z); bld.vertex(p.x, p.y, p.z); - - border.push_back(p); } } diff --git a/source/3d/tracktype.h b/source/3d/tracktype.h index 0f6b30f..ca999c3 100644 --- a/source/3d/tracktype.h +++ b/source/3d/tracktype.h @@ -18,15 +18,11 @@ private: Msp::GL::Mesh *mesh; Msp::GL::Object *object; std::vector path_meshes; - std::vector border; - float min_z; - float max_z; public: TrackType3D(Catalogue3D &, const TrackType &); ~TrackType3D(); - void get_bounds(const Angle &, Vector &, Vector &) const; const Msp::GL::Object &get_object() const { return *object; } const Msp::GL::Mesh &get_path_mesh(unsigned) const; diff --git a/source/3d/view.cpp b/source/3d/view.cpp index 8b63553..6b5115d 100644 --- a/source/3d/view.cpp +++ b/source/3d/view.cpp @@ -28,10 +28,13 @@ View3D::View3D(Layout3D &l, unsigned w, unsigned h): void View3D::view_all(bool tight) { - Vector minp; - Vector maxp; + const set &tracks = layout.get_layout().get_tracks(); + Geometry::BoundingBox bbox; + for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) + bbox = bbox|(*i)->get_bounding_box(); - layout.get_bounds(minp, maxp); + const Vector &minp = bbox.get_minimum_point(); + const Vector &maxp = bbox.get_maximum_point(); float t = tan(camera.get_field_of_view()/2)*2; float size = max((maxp.y-minp.y+0.1), (maxp.x-minp.x+0.1)/camera.get_aspect()); diff --git a/source/designer/designer.cpp b/source/designer/designer.cpp index 6d2fd41..6d4d49d 100644 --- a/source/designer/designer.cpp +++ b/source/designer/designer.cpp @@ -47,6 +47,7 @@ Designer::Designer(int argc, char **argv): cur_route(0), cur_zone(0), mode(SELECT), + sel_wrap(selection), manipulator(*this, mouse, selection), measure(*this) { @@ -133,8 +134,7 @@ Designer::Designer(int argc, char **argv): statusbar->add(*lbl_status); lbl_status->set_geometry(GLtk::Geometry(20, 2, 300, 16)); - track_wrap = new TrackWrap(*layout_3d, selection); - pipeline->add_renderable_for_pass(*track_wrap, "unlit"); + pipeline->add_renderable_for_pass(sel_wrap, "unlit"); overlay = new Overlay3D(ui_res.get_default_font()); pipeline->add_renderable_for_pass(*overlay, "overlay"); pipeline->add_renderable_for_pass(measure, "unlit"); @@ -154,7 +154,6 @@ Designer::~Designer() for(vector::iterator i=toolbars.begin(); i!=toolbars.end(); ++i) delete *i; delete camera_ctl; - delete track_wrap; delete overlay; delete main_view; delete base_object; @@ -532,7 +531,7 @@ Object *Designer::pick_object(const Vector &pointer) const GL::Vector3 &cpos = view.get_camera().get_position(); GL::Vector4 cray = view.get_camera().unproject(GL::Vector4(pointer.x, pointer.y, 0, 0)); - return view.get_layout().get_layout().pick_object(Vector(cpos.x, cpos.y, cpos.z), Vector(cray.x, cray.y, cray.z)); + return view.get_layout().get_layout().pick_object(Ray(cpos, Vector(cray))); } void Designer::update_track_icon(Track3D &track) diff --git a/source/designer/designer.h b/source/designer/designer.h index 5dbb067..8348f60 100644 --- a/source/designer/designer.h +++ b/source/designer/designer.h @@ -24,7 +24,7 @@ #include "manipulator.h" #include "measure.h" #include "selection.h" -#include "trackwrap.h" +#include "selectionwrap.h" class Toolbar; @@ -65,10 +65,10 @@ private: Mode mode; Selection selection; + SelectionWrap sel_wrap; Manipulator manipulator; Measure measure; CameraController *camera_ctl; - TrackWrap *track_wrap; Msp::Time::TimeStamp last_tick; diff --git a/source/designer/manipulator.cpp b/source/designer/manipulator.cpp index 8620fe7..2ee9676 100644 --- a/source/designer/manipulator.cpp +++ b/source/designer/manipulator.cpp @@ -504,38 +504,12 @@ void Manipulator::selection_changed() void Manipulator::update_objects() { - Vector minp, maxp; + Geometry::BoundingBox bbox; for(vector::iterator i=objects.begin(); i!=objects.end(); ++i) - { - // XXX Use generic bounding box when it is implemented - if(Track *track = dynamic_cast(i->object)) - { - unsigned n_endpoints = track->get_type().get_endpoints().size(); - for(unsigned j=0; jget_snap_node(j).position; - if(i==objects.begin() && j==0) - minp = maxp = p; - else - { - minp.x = min(minp.x, p.x); - maxp.x = max(maxp.x, p.x); - minp.y = min(minp.y, p.y); - maxp.y = max(maxp.y, p.y); - minp.z = min(minp.z, p.z); - } - } - } - else - { - const Vector &p = i->object->get_position(); - minp.x = min(minp.x, p.x); - maxp.x = max(maxp.x, p.x); - minp.y = min(minp.y, p.y); - maxp.y = max(maxp.y, p.y); - minp.z = min(minp.z, p.z); - } - } + bbox = bbox|i->object->get_bounding_box(); + + const Vector &minp = bbox.get_minimum_point(); + const Vector &maxp = bbox.get_maximum_point(); center = (minp+maxp)/2.0f; center.z = minp.z; diff --git a/source/designer/selectionwrap.cpp b/source/designer/selectionwrap.cpp new file mode 100644 index 0000000..fcc4df6 --- /dev/null +++ b/source/designer/selectionwrap.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include "selection.h" +#include "selectionwrap.h" + +using namespace std; +using namespace Msp; +using namespace R2C2; + +SelectionWrap::SelectionWrap(Selection &s): + selection(s) +{ + selection.signal_changed.connect(sigc::mem_fun(this, &SelectionWrap::selection_changed)); +} + +SelectionWrap::~SelectionWrap() +{ + for(map::iterator i=meshes.begin(); i!=meshes.end(); ++i) + delete i->second; +} + +void SelectionWrap::render(GL::Renderer &renderer, const GL::Tag &) const +{ + for(list::const_iterator i=wraps.begin(); i!=wraps.end(); ++i) + { + GL::MatrixStack::Push push(renderer.matrix_stack()); + const Vector &pos = i->object->get_position(); + renderer.matrix_stack() *= GL::Matrix::translation(pos); + renderer.matrix_stack() *= GL::Matrix::rotation(i->object->get_rotation(), 0, 0, 1); + i->mesh->draw(renderer); + } +} + +void SelectionWrap::selection_changed() +{ + wraps.clear(); + const set &objects = selection.get_objects(); + for(set::iterator i=objects.begin(); i!=objects.end(); ++i) + { + Wrap wrap; + wrap.object = *i; + wrap.mesh = &get_mesh((*i)->get_type()); + wraps.push_back(wrap); + } +} + +GL::Mesh &SelectionWrap::get_mesh(const ObjectType &type) +{ + map::iterator j = meshes.find(&type); + if(j!=meshes.end()) + return *j->second; + + GL::Mesh *mesh = new GL::Mesh((GL::COLOR4_UBYTE, GL::VERTEX2)); + GL::MeshBuilder bld(*mesh); + bld.color(0.0f, 1.0f, 0.0f, 1.0f); + + const Shape *shape = type.get_shape(); + if(!shape) + throw logic_error("No shape"); + + Geometry::BoundingBox bbox = shape->get_axis_aligned_bounding_box(); + const Vector &min_pt = bbox.get_minimum_point(); + const Vector &max_pt = bbox.get_maximum_point(); + + bld.begin(GL::LINE_LOOP); + bld.vertex(min_pt.x-0.005, min_pt.y-0.005); + bld.vertex(max_pt.x+0.005, min_pt.y-0.005); + bld.vertex(max_pt.x+0.005, max_pt.y+0.005); + bld.vertex(min_pt.x-0.005, max_pt.y+0.005); + bld.end(); + + meshes[&type] = mesh; + + return *mesh; +} diff --git a/source/designer/selectionwrap.h b/source/designer/selectionwrap.h new file mode 100644 index 0000000..7432809 --- /dev/null +++ b/source/designer/selectionwrap.h @@ -0,0 +1,36 @@ +#ifndef SELECTIONWRAP_H_ +#define SELECTIONWRAP_H_ + +#include +#include +#include "libr2c2/object.h" +#include "3d/layout.h" + +class Designer; +class Selection; + +class SelectionWrap: public Msp::GL::Renderable +{ +private: + struct Wrap + { + R2C2::Object *object; + Msp::GL::Mesh *mesh; + }; + + Selection &selection; + std::map meshes; + std::list wraps; + +public: + SelectionWrap(Selection &); + ~SelectionWrap(); + + virtual void render(Msp::GL::Renderer &, const Msp::GL::Tag &) const; + +private: + void selection_changed(); + Msp::GL::Mesh &get_mesh(const R2C2::ObjectType &); +}; + +#endif diff --git a/source/designer/trackwrap.cpp b/source/designer/trackwrap.cpp deleted file mode 100644 index 398285f..0000000 --- a/source/designer/trackwrap.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include -#include -#include "3d/tracktype.h" -#include "selection.h" -#include "trackwrap.h" - -using namespace std; -using namespace Msp; -using namespace R2C2; - -TrackWrap::TrackWrap(Layout3D &l, Selection &s): - layout(l), - selection(s) -{ - selection.signal_changed.connect(sigc::mem_fun(this, &TrackWrap::selection_changed)); -} - -TrackWrap::~TrackWrap() -{ - for(map::iterator i=meshes.begin(); i!=meshes.end(); ++i) - delete i->second; -} - -void TrackWrap::render(GL::Renderer &renderer, const GL::Tag &) const -{ - for(list::const_iterator i=wraps.begin(); i!=wraps.end(); ++i) - { - GL::MatrixStack::Push push(renderer.matrix_stack()); - const Vector &pos = i->track->get_position(); - renderer.matrix_stack() *= GL::Matrix::translation(pos); - renderer.matrix_stack() *= GL::Matrix::rotation(i->track->get_rotation(), 0, 0, 1); - i->mesh->draw(renderer); - } -} - -void TrackWrap::selection_changed() -{ - wraps.clear(); - const set &tracks = selection.get_objects(); - for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) - { - Wrap wrap; - wrap.track = *i; - wrap.mesh = &get_mesh((*i)->get_type()); - wraps.push_back(wrap); - } -} - -GL::Mesh &TrackWrap::get_mesh(const TrackType &type) -{ - map::iterator j = meshes.find(&type); - if(j!=meshes.end()) - return *j->second; - - const TrackType3D &type3d = layout.get_catalogue().get_track(type); - - float min_area = -1; - Angle angle; - Vector center; - float width = 0; - float height = 0; - for(Angle a; a -#include -#include "libr2c2/track.h" -#include "3d/layout.h" - -class Designer; -class Selection; - -class TrackWrap: public Msp::GL::Renderable -{ -private: - struct Wrap - { - R2C2::Track *track; - Msp::GL::Mesh *mesh; - }; - - R2C2::Layout3D &layout; - Selection &selection; - std::map meshes; - std::list wraps; - -public: - TrackWrap(R2C2::Layout3D &, Selection &); - ~TrackWrap(); - - virtual void render(Msp::GL::Renderer &, const Msp::GL::Tag &) const; - -private: - void selection_changed(); - Msp::GL::Mesh &get_mesh(const R2C2::TrackType &); -}; - -#endif diff --git a/source/engineer/engineer.cpp b/source/engineer/engineer.cpp index ad26e50..69dc47b 100644 --- a/source/engineer/engineer.cpp +++ b/source/engineer/engineer.cpp @@ -315,22 +315,16 @@ void Engineer::view_all() GL::Vector3 up; for(Angle angle; anglesecond->get_bounds(angle, minp, maxp); - min_x = min(min_x, minp.x); - max_x = max(max_x, maxp.x); - min_y = min(min_y, minp.y); - max_y = max(max_y, maxp.y); - } + bbox = bbox|trans.transform(i->second->get_track().get_bounding_box()); + + const Vector &minp = bbox.get_minimum_point(); + const Vector &maxp = bbox.get_maximum_point(); - float width = max_x-min_x; - float height = max_y-min_y; + float width = maxp.x-minp.x; + float height = maxp.y-minp.y; float aspect = width/height; float score = min(aspect/view_aspect, view_aspect/aspect); @@ -341,8 +335,8 @@ void Engineer::view_all() float size = max(width/view_aspect, height); float c = cos(angle); float s = sin(angle); - float x = (min_x+max_x)/2-size*105/window.get_height(); - float y = (min_y+max_y)/2; + float x = (minp.x+maxp.x)/2-size*105/window.get_height(); + float y = (minp.y+maxp.y)/2; float z = max(size*1.05/view_height, 0.15); pos = GL::Vector3(c*x-s*y, s*x+c*y, z); @@ -391,7 +385,7 @@ Track *Engineer::pick_track(const Vector &p) const GL::Vector3 &start = camera.get_position(); GL::Vector4 ray = camera.unproject(GL::Vector4(p.x, p.y, 0, 0)); - return layout.pick_track(Vector(start.x, start.y, start.z), Vector(ray.x, ray.y, ray.z)); + return layout.pick_track(Ray(start, Vector(ray))); } void Engineer::process_new_train(Train &train) diff --git a/source/libr2c2/geometry.h b/source/libr2c2/geometry.h index 09044e3..80d7553 100644 --- a/source/libr2c2/geometry.h +++ b/source/libr2c2/geometry.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include namespace R2C2 { @@ -24,6 +26,10 @@ inline Vector rotated_vector(const Vector &v, const Angle &a) inline Vector vector_at_angle(const Angle &a) { return rotated_vector(Vector(1, 0, 0), a); } +typedef Msp::Geometry::Shape Shape; +typedef Msp::Geometry::Ray Ray; +typedef Msp::Geometry::BoundingBox BoundingBox; + struct TrackPoint { Vector pos; diff --git a/source/libr2c2/layout.cpp b/source/libr2c2/layout.cpp index 45b18e3..c70ebb7 100644 --- a/source/libr2c2/layout.cpp +++ b/source/libr2c2/layout.cpp @@ -72,9 +72,9 @@ void Layout::add_track(Track &t) } } -Track *Layout::pick_track(const Vector &start, const Vector &ray) +Track *Layout::pick_track(const Ray &ray) { - return pick(tracks, start, ray); + return pick(tracks, ray); } void Layout::remove_track(Track &t) @@ -107,9 +107,9 @@ void Layout::add_signal(Signal &s) signal_signal_added.emit(s); } -Signal *Layout::pick_signal(const Vector &start, const Vector &ray) +Signal *Layout::pick_signal(const Ray &ray) { - return pick(signals, start, ray); + return pick(signals, ray); } void Layout::remove_signal(Signal &s) @@ -118,20 +118,20 @@ void Layout::remove_signal(Signal &s) signal_signal_removed.emit(s); } -Object *Layout::pick_object(const Vector &start, const Vector &ray) +Object *Layout::pick_object(const Ray &ray) { - if(Object *obj = pick_track(start, ray)) + if(Object *obj = pick_track(ray)) return obj; - else if((obj = pick_signal(start, ray))) + else if((obj = pick_signal(ray))) return obj; return 0; } template -T *Layout::pick(const set &objs, const Vector &start, const Vector &ray) +T *Layout::pick(const set &objs, const Ray &ray) { for(typename set::const_iterator i=objs.begin(); i!=objs.end(); ++i) - if((*i)->collide_ray(start, ray)) + if((*i)->collide_ray(ray)) return *i; return 0; diff --git a/source/libr2c2/layout.h b/source/libr2c2/layout.h index 48a2796..8e44fb5 100644 --- a/source/libr2c2/layout.h +++ b/source/libr2c2/layout.h @@ -86,20 +86,20 @@ public: void add_track(Track &); const std::set &get_tracks() const { return tracks; } - Track *pick_track(const Vector &, const Vector &); + Track *pick_track(const Ray &); void remove_track(Track &); unsigned allocate_turnout_id(); void add_signal(Signal &); const std::set &get_signals() const { return signals; } - Signal *pick_signal(const Vector &, const Vector &); + Signal *pick_signal(const Ray &); void remove_signal(Signal &); - Object *pick_object(const Vector &, const Vector &); + Object *pick_object(const Ray &); private: template - static T *pick(const std::set &, const Vector &, const Vector &); + static T *pick(const std::set &, const Ray &); public: void add_block(Block &); diff --git a/source/libr2c2/object.cpp b/source/libr2c2/object.cpp index cc56ede..e9e58ab 100644 --- a/source/libr2c2/object.cpp +++ b/source/libr2c2/object.cpp @@ -77,4 +77,26 @@ void Object::break_links() break_link(i); } +bool Object::collide_ray(const Ray &ray) const +{ + const Shape *shape = get_type().get_shape(); + if(!shape) + return false; + + Transform reverse_trans = Transform::rotation(rotation, Vector(0, 0, -1))* + Transform::translation(-position); + return shape->check_intersection(reverse_trans.transform(ray)); +} + +BoundingBox Object::get_bounding_box() const +{ + const Shape *shape = get_type().get_shape(); + if(!shape) + return BoundingBox(); + + Transform trans = Transform::translation(position)* + Transform::rotation(rotation, Vector(0, 0, 1)); + return trans.transform(shape->get_axis_aligned_bounding_box()); +} + } // namespace R2C2 diff --git a/source/libr2c2/object.h b/source/libr2c2/object.h index d36104f..31eb879 100644 --- a/source/libr2c2/object.h +++ b/source/libr2c2/object.h @@ -45,7 +45,8 @@ public: virtual bool break_link(unsigned) { return false; } virtual void break_links(); - virtual bool collide_ray(const Vector &, const Vector &) const = 0; + virtual bool collide_ray(const Ray &) const; + virtual BoundingBox get_bounding_box() const; }; } // namespace R2C2 diff --git a/source/libr2c2/objecttype.cpp b/source/libr2c2/objecttype.cpp index 10d9c88..09b2561 100644 --- a/source/libr2c2/objecttype.cpp +++ b/source/libr2c2/objecttype.cpp @@ -4,6 +4,17 @@ using namespace Msp; namespace R2C2 { +ObjectType::ObjectType(const ArticleNumber &an): + art_nr(an), + shape(0) +{ } + +ObjectType::~ObjectType() +{ + delete shape; +} + + ObjectType::Loader::Loader(ObjectType &ot): DataFile::ObjectLoader(ot) { diff --git a/source/libr2c2/objecttype.h b/source/libr2c2/objecttype.h index 0cca264..4102f94 100644 --- a/source/libr2c2/objecttype.h +++ b/source/libr2c2/objecttype.h @@ -4,6 +4,7 @@ #include #include #include "articlenumber.h" +#include "geometry.h" namespace R2C2 { @@ -20,14 +21,16 @@ protected: ArticleNumber art_nr; std::string name; std::string description; + Shape *shape; - ObjectType(const ArticleNumber &a): art_nr(a) { } + ObjectType(const ArticleNumber &); public: - virtual ~ObjectType() { } + virtual ~ObjectType(); const ArticleNumber &get_article_number() const { return art_nr; } const std::string &get_name() const { return name; } const std::string &get_description() const { return description; } + const Shape *get_shape() const { return shape; } }; } // namespace R2C2 diff --git a/source/libr2c2/signal.cpp b/source/libr2c2/signal.cpp index 3494467..a25f8ec 100644 --- a/source/libr2c2/signal.cpp +++ b/source/libr2c2/signal.cpp @@ -122,19 +122,6 @@ SnapType Signal::get_default_snap_type_to(const Object &other) const return NO_SNAP; } -bool Signal::collide_ray(const Vector &start, const Vector &ray) const -{ - // XXX Totally hardcoded stuff, should be replaced with a geometry system - Vector center = position+rotated_vector(Vector(0, -0.035, 0), rotation); - Vector span = center-start; - float x = (span.x*ray.x+span.y*ray.y)/(ray.x*ray.x+ray.y*ray.y); - Vector nearest = start+ray*x-center; - if(nearest.z<0 || nearest.z>0.12) - return false; - nearest.z = 0; - return dot(nearest, nearest)<0.0001; -} - void Signal::tick(const Time::TimeDelta &) { if(check_allocated_blocks) diff --git a/source/libr2c2/signal.h b/source/libr2c2/signal.h index 8adbd1b..886db69 100644 --- a/source/libr2c2/signal.h +++ b/source/libr2c2/signal.h @@ -60,8 +60,6 @@ private: virtual SnapType get_default_snap_type_to(const Object &) const; public: - virtual bool collide_ray(const Vector &, const Vector &) const; - void tick(const Msp::Time::TimeDelta &); private: diff --git a/source/libr2c2/signaltype.cpp b/source/libr2c2/signaltype.cpp index d3f48d9..545e4de 100644 --- a/source/libr2c2/signaltype.cpp +++ b/source/libr2c2/signaltype.cpp @@ -1,3 +1,6 @@ +#include +#include +#include #include "signaltype.h" using namespace std; @@ -8,6 +11,9 @@ namespace R2C2 { SignalType::SignalType(const ArticleNumber &an): ObjectType(an) { + shape = new Geometry::TransformedShape( + Geometry::ExtrudedShape(Geometry::Circle(0.01), 0.12), + Transform::translation(Vector(0, -0.035, 0.06))); } diff --git a/source/libr2c2/track.cpp b/source/libr2c2/track.cpp index c92ff37..c2b190f 100644 --- a/source/libr2c2/track.cpp +++ b/source/libr2c2/track.cpp @@ -316,17 +316,6 @@ bool Track::break_link(unsigned i) return true; } -bool Track::collide_ray(const Vector &start, const Vector &ray) const -{ - Transform trans = Transform::rotation(-rotation, Vector(0, 0, 1)); - Vector local_start = trans.transform(start-position); - Vector local_ray = trans.transform(ray); - - float width = layout.get_catalogue().get_ballast_profile().get_width(); - - return type.collide_ray(local_start, local_ray, width); -} - void Track::save(list &st) const { st.push_back((DataFile::Statement("position"), position.x, position.y, position.z)); diff --git a/source/libr2c2/track.h b/source/libr2c2/track.h index 7dfa752..168ac37 100644 --- a/source/libr2c2/track.h +++ b/source/libr2c2/track.h @@ -89,8 +89,6 @@ public: using Object::break_link; virtual bool break_link(unsigned); - virtual bool collide_ray(const Vector &, const Vector &) const; - void save(std::list &) const; private: void turnout_event(unsigned, unsigned); diff --git a/source/libr2c2/trackpart.cpp b/source/libr2c2/trackpart.cpp index d8dac07..b12ea72 100644 --- a/source/libr2c2/trackpart.cpp +++ b/source/libr2c2/trackpart.cpp @@ -1,4 +1,11 @@ #include +#include +#include +#include +#include +#include +#include +#include #include "trackpart.h" using namespace std; @@ -10,12 +17,18 @@ TrackPart::TrackPart(): length(0), radius(0), path(0), - dead_end(false) + dead_end(false), + shape(0) { links[0] = 0; links[1] = 0; } +TrackPart::~TrackPart() +{ + delete shape; +} + float TrackPart::get_length() const { if(radius) @@ -106,29 +119,43 @@ TrackPart *TrackPart::get_link(unsigned i) const return links[i]; } -bool TrackPart::collide_ray(const Vector &start, const Vector &ray, float width) const +void TrackPart::create_shape() { - Transform trans = Transform::rotation(dir, Vector(0, 0, -1)); - Vector local_start = trans.transform(start); - Vector local_ray = trans.transform_linear(ray); - - float d = -local_start.z/local_ray.z; - if(d<0) - return false; - - Vector base = local_start+d*local_ray; - + Transform trans = Transform::translation(pos)* + Transform::rotation(dir, LinAl::Vector(0, 0, 1)); if(radius) { - base.y -= radius; - if(radius<0) - base.y = -base.y; - float r = base.norm()-abs(radius); - float a = atan2(base.x, -base.y); - return (a>=0 && a<=length && r>=-width/2 && r<=width/2); + Geometry::ExtrudedShape ring( + Geometry::Intersection( + Geometry::Circle(abs(radius)+0.02), + Geometry::Negation(Geometry::Circle(abs(radius)-0.02))), + 0.01); + Geometry::HalfSpace start_wall(Vector(-1, 0, 0)); + Geometry::HalfSpace end_wall(rotated_vector(Vector(1, 0, 0), + Angle::from_radians(length*(radius<0 ? -1 : 1)))); + /* This box only exists so the bounding boxes of curves make sense. It + can be removed when libmspmath produces better bounding boxes. */ + float w = sin(length)*(abs(radius)+0.02); + float h = (1-cos(length))*abs(radius-0.02)+0.04; + Geometry::TransformedShape bounds( + Geometry::Box(w, h, 0.01), + Transform::translation(Vector(w/2, (h/2-0.02)*(radius<0 ? -1 : 1)-radius, 0.005))); + vector shapes; + shapes.push_back(&ring); + shapes.push_back(&start_wall); + shapes.push_back(&end_wall); + shapes.push_back(&bounds); + shape = new Geometry::TransformedShape( + Geometry::Intersection::from_iterator_range(shapes.begin(), shapes.end()), + trans*Transform::translation(Vector(0, radius, 0.005))); } else - return (base.x>=0 && base.x<=length && base.y>=-width/2 && base.y<=width/2); + { + // TODO Get the track profile dimensions from somewhere + shape = new Geometry::TransformedShape( + Geometry::Box(length, 0.04, 0.01), + trans*Transform::translation(Vector(length/2, 0, 0.005))); + } } diff --git a/source/libr2c2/trackpart.h b/source/libr2c2/trackpart.h index 9143ff8..9a17663 100644 --- a/source/libr2c2/trackpart.h +++ b/source/libr2c2/trackpart.h @@ -26,9 +26,11 @@ private: unsigned path; bool dead_end; TrackPart *links[2]; + Shape *shape; public: TrackPart(); + ~TrackPart(); float get_length() const; bool is_curved() const { return radius; } @@ -38,7 +40,8 @@ public: bool is_dead_end() const { return dead_end; } void check_link(TrackPart &); TrackPart *get_link(unsigned) const; - bool collide_ray(const Vector &, const Vector &, float) const; + void create_shape(); + const Shape &get_shape() const { return *shape; } }; } // namespace R2C2 diff --git a/source/libr2c2/tracktype.cpp b/source/libr2c2/tracktype.cpp index fbed4c1..fe3a54c 100644 --- a/source/libr2c2/tracktype.cpp +++ b/source/libr2c2/tracktype.cpp @@ -1,4 +1,5 @@ #include +#include #include "tracktype.h" using namespace std; @@ -131,15 +132,6 @@ TrackPoint TrackType::get_nearest_point(const Vector &p) const return result; } -bool TrackType::collide_ray(const Vector &start, const Vector &dir, float width) const -{ - for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) - if(i->collide_ray(start, dir, width)) - return true; - - return false; -} - void TrackType::collect_endpoints() { endpoints.clear(); @@ -198,6 +190,13 @@ TrackType::Loader::Loader(TrackType &t): void TrackType::Loader::finish() { obj.collect_endpoints(); + vector shapes; + for(vector::iterator i=obj.parts.begin(); i!=obj.parts.end(); ++i) + { + i->create_shape(); + shapes.push_back(&i->get_shape()); + } + obj.shape = Geometry::Union::from_iterator_range(shapes.begin(), shapes.end()).clone(); } void TrackType::Loader::part() diff --git a/source/libr2c2/tracktype.h b/source/libr2c2/tracktype.h index f446064..da0df71 100644 --- a/source/libr2c2/tracktype.h +++ b/source/libr2c2/tracktype.h @@ -62,7 +62,6 @@ public: const Endpoint &get_endpoint(unsigned) const; TrackPoint get_point(unsigned, unsigned, float) const; TrackPoint get_nearest_point(const Vector &) const; - bool collide_ray(const Vector &, const Vector &, float) const; private: void collect_endpoints();