]> git.tdb.fi Git - r2c2.git/commitdiff
Make use of the geometry part of libmspmath
authorMikko Rasa <tdb@tdb.fi>
Thu, 23 May 2013 20:12:00 +0000 (23:12 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 23 May 2013 20:12:00 +0000 (23:12 +0300)
30 files changed:
source/3d/layout.cpp
source/3d/track.cpp
source/3d/track.h
source/3d/tracktype.cpp
source/3d/tracktype.h
source/3d/view.cpp
source/designer/designer.cpp
source/designer/designer.h
source/designer/manipulator.cpp
source/designer/selectionwrap.cpp [new file with mode: 0644]
source/designer/selectionwrap.h [new file with mode: 0644]
source/designer/trackwrap.cpp [deleted file]
source/designer/trackwrap.h [deleted file]
source/engineer/engineer.cpp
source/libr2c2/geometry.h
source/libr2c2/layout.cpp
source/libr2c2/layout.h
source/libr2c2/object.cpp
source/libr2c2/object.h
source/libr2c2/objecttype.cpp
source/libr2c2/objecttype.h
source/libr2c2/signal.cpp
source/libr2c2/signal.h
source/libr2c2/signaltype.cpp
source/libr2c2/track.cpp
source/libr2c2/track.h
source/libr2c2/trackpart.cpp
source/libr2c2/trackpart.h
source/libr2c2/tracktype.cpp
source/libr2c2/tracktype.h

index d97dfe507472824aa5fdb91f7fa947a0d4b76063..69af0d4dbed6f525ecd122d9b9916ed331ef2999 100644 (file)
@@ -38,18 +38,13 @@ Layout3D::~Layout3D()
 
 void Layout3D::get_bounds(Vector &minp, Vector &maxp) const
 {
-       minp = maxp = Vector();
+       Geometry::BoundingBox<float, 3> 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)
index bd148a7c3f307cb65ede9c21d341bec7b979137a..9797c4a67369c90a7e6d05b07495171fd7afdcfe 100644 (file)
@@ -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<float, 3> 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);
 }
index 641f234e232f4b926fa07936d85bd996ab092cd1..857b129c11fedbb85adc7796b16b50768bdeb3d7 100644 (file)
@@ -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;
index a5e97cc55a09ad10e89c0a7babbfa119fad1467b..6dfd2a4f86c166cbb9b336b8cdbcaa42e45ba592 100644 (file)
@@ -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<p2.z;
-}
-
-template<typename Iter>
-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->x<lowest.x || (i->x==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<GL::Object>(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<vertices.size(); ++i)
-                       {
-                               const float *v = vertices[i]+vertex_offs;
-                               border.push_back(Vector(v[0], v[1], 0));
-                       }
-               }
-       }
        else
        {
                mesh = new GL::Mesh((GL::NORMAL3, GL::TEXCOORD2, GL::VERTEX3));
@@ -138,14 +70,6 @@ TrackType3D::TrackType3D(Catalogue3D &cat3d, const TrackType &tt):
                }
                path_meshes.push_back(m);
        }
-
-       min_z = max_z = border.front().z;
-       for(vector<Vector>::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<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);
                }
        }
 
index 0f6b30fa29a1241047d45f8892b07404355a25c3..ca999c3ee2a1200e11e47e98a01419a020945f0b 100644 (file)
@@ -18,15 +18,11 @@ private:
        Msp::GL::Mesh *mesh;
        Msp::GL::Object *object;
        std::vector<Msp::GL::Mesh *> path_meshes;
-       std::vector<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;
 
index 8b63553d6fc348f294cd9a5e245c399301de6e16..6b5115d1ed79a2fd143b40cce34ac3e3d8bfd39a 100644 (file)
@@ -28,10 +28,13 @@ View3D::View3D(Layout3D &l, unsigned w, unsigned h):
 
 void View3D::view_all(bool tight)
 {
-       Vector minp;
-       Vector maxp;
+       const set<Track *> &tracks = layout.get_layout().get_tracks();
+       Geometry::BoundingBox<float, 3> bbox;
+       for(set<Track *>::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());
index 6d2fd41eca30c17451b1babc510b13796f064e96..6d4d49d10b1c349138f027988cc1fa0af302afcd 100644 (file)
@@ -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<Toolbar *>::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)
index 5dbb067af15e33528d7880508312c518c3bd8353..8348f60d3920d6ac276be5102571a000817cda16 100644 (file)
@@ -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;
 
index 8620fe7af8a6a53e8c0a43fd960d509805fa736f..2ee967679428ebdf1595b74669128a194b31291a 100644 (file)
@@ -504,38 +504,12 @@ void Manipulator::selection_changed()
 
 void Manipulator::update_objects()
 {
-       Vector minp, maxp;
+       Geometry::BoundingBox<float, 3> bbox;
        for(vector<MObject>::iterator i=objects.begin(); i!=objects.end(); ++i)
-       {
-               // XXX Use generic bounding box when it is implemented
-               if(Track *track = dynamic_cast<Track *>(i->object))
-               {
-                       unsigned n_endpoints = track->get_type().get_endpoints().size();
-                       for(unsigned j=0; j<n_endpoints; ++j)
-                       {
-                               Vector p = track->get_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 (file)
index 0000000..fcc4df6
--- /dev/null
@@ -0,0 +1,76 @@
+#include <msp/gl/matrix.h>
+#include <msp/gl/meshbuilder.h>
+#include <msp/gl/renderer.h>
+#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<const ObjectType *, GL::Mesh *>::iterator i=meshes.begin(); i!=meshes.end(); ++i)
+               delete i->second;
+}
+
+void SelectionWrap::render(GL::Renderer &renderer, const GL::Tag &) const
+{
+       for(list<Wrap>::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<Object *> &objects = selection.get_objects();
+       for(set<Object *>::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<const ObjectType *, GL::Mesh *>::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<float, 3> 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 (file)
index 0000000..7432809
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef SELECTIONWRAP_H_
+#define SELECTIONWRAP_H_
+
+#include <msp/gl/mesh.h>
+#include <msp/gl/renderable.h>
+#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<const R2C2::ObjectType *, Msp::GL::Mesh *> meshes;
+       std::list<Wrap> 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 (file)
index 398285f..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-#include <msp/gl/matrix.h>
-#include <msp/gl/meshbuilder.h>
-#include <msp/gl/renderer.h>
-#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<const TrackType *, GL::Mesh *>::iterator i=meshes.begin(); i!=meshes.end(); ++i)
-               delete i->second;
-}
-
-void TrackWrap::render(GL::Renderer &renderer, const GL::Tag &) const
-{
-       for(list<Wrap>::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<Track *> &tracks = selection.get_objects<Track>();
-       for(set<Track *>::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<const TrackType *, GL::Mesh *>::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<Angle::half_turn(); a+=Angle::from_radians(0.01))
-       {
-               Vector minp, maxp;
-               type3d.get_bounds(a, minp, maxp);
-               float area = (maxp.x-minp.x)*(maxp.y-minp.y);
-               if(area<min_area || min_area<0)
-               {
-                       center = rotated_vector((minp+maxp)/2.0f, a);
-                       center.z = minp.z;
-                       angle = a;
-                       width = maxp.x-minp.x+0.01;
-                       height = maxp.y-minp.y+0.01;
-
-                       min_area = area;
-               }
-       }
-
-       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);
-
-       float c = cos(angle);
-       float s = sin(angle);
-
-       bld.begin(GL::LINE_LOOP);
-       bld.vertex(center.x-c*width/2+s*height/2, center.y-s*width/2-c*height/2);
-       bld.vertex(center.x+c*width/2+s*height/2, center.y+s*width/2-c*height/2);
-       bld.vertex(center.x+c*width/2-s*height/2, center.y+s*width/2+c*height/2);
-       bld.vertex(center.x-c*width/2-s*height/2, center.y-s*width/2+c*height/2);
-       bld.end();
-
-       meshes[&type] = mesh;
-
-       return *mesh;
-}
diff --git a/source/designer/trackwrap.h b/source/designer/trackwrap.h
deleted file mode 100644 (file)
index 070794e..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef TRACKWRAP_H_
-#define TRACKWRAP_H_
-
-#include <msp/gl/mesh.h>
-#include <msp/gl/renderable.h>
-#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<const R2C2::TrackType *, Msp::GL::Mesh *> meshes;
-       std::list<Wrap> 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
index ad26e50c46ea087d99175f73a525089ee2b5fd0c..69dc47bc98832a080180c99c510fc649971a9f55 100644 (file)
@@ -315,22 +315,16 @@ void Engineer::view_all()
        GL::Vector3 up;
        for(Angle angle; angle<Angle::half_turn(); angle+=Angle::from_radians(0.01))
        {
-               float min_x = 0;
-               float max_x = 0;
-               float min_y = 0;
-               float max_y = 0;
+               Transform trans = Transform::rotation(-angle, Vector(0, 0, 1));
+               BoundingBox bbox;
                for(Layout3D::TrackMap::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
-               {
-                       Vector minp, maxp;
-                       i->second->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)
index 09044e35886d6ccf1df13d5d0c5b5d77a0acca0d..80d7553aa7e3140ad2a9ba2d2fbb697df5aef945 100644 (file)
@@ -5,6 +5,8 @@
 #include <vector>
 #include <msp/geometry/affinetransformation.h>
 #include <msp/geometry/angle.h>
+#include <msp/geometry/ray.h>
+#include <msp/geometry/shape.h>
 #include <msp/linal/vector.h>
 
 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<float, 3> Shape;
+typedef Msp::Geometry::Ray<float, 3> Ray;
+typedef Msp::Geometry::BoundingBox<float, 3> BoundingBox;
+
 struct TrackPoint
 {
        Vector pos;
index 45b18e322fa6e8db5a065fb616e002b869b206a8..c70ebb7b3879f0d528c5864bb594712093869d72 100644 (file)
@@ -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<typename T>
-T *Layout::pick(const set<T *> &objs, const Vector &start, const Vector &ray)
+T *Layout::pick(const set<T *> &objs, const Ray &ray)
 {
        for(typename set<T *>::const_iterator i=objs.begin(); i!=objs.end(); ++i)
-               if((*i)->collide_ray(start, ray))
+               if((*i)->collide_ray(ray))
                        return *i;
 
        return 0;
index 48a2796dcb7003affb134f99471e03ebcefb3324..8e44fb52d26dc362a9258f50017d2e9fef1271de 100644 (file)
@@ -86,20 +86,20 @@ public:
 
        void add_track(Track &);
        const std::set<Track *> &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<Signal *> &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<typename T>
-       static T *pick(const std::set<T *> &, const Vector &, const Vector &);
+       static T *pick(const std::set<T *> &, const Ray &);
 
 public:
        void add_block(Block &);
index cc56edeb6af28883f6619dd7953c8e21925d9e15..e9e58abf97041c44351a7becd185895e95f79304 100644 (file)
@@ -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
index d36104fa3deed081c5ae26cb29cf89b4e3cf9606..31eb879228d0076fa0bc47dad32b6ce01567ebca 100644 (file)
@@ -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
index 10d9c883a0991011fbee804a809a0faad2e10192..09b25610ef929e57d085a6f00ebe7f1edd5d7611 100644 (file)
@@ -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<ObjectType>(ot)
 {
index 0cca264b77c12bfb880270d67d8d04d4b11d97eb..4102f944041ee95f231b9c9924889115e87565fa 100644 (file)
@@ -4,6 +4,7 @@
 #include <string>
 #include <msp/datafile/objectloader.h>
 #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
index 3494467d84daf3c166ccbf851742712987b72d8d..a25f8eca4697fde499b993348a32a4de7f20e752 100644 (file)
@@ -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)
index 8adbd1b3b83fbda1e5d1919da2d9823bff26c2a8..886db6983710e6b4892599544d95956afc6f98e4 100644 (file)
@@ -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:
index d3f48d9066dc68914dcb8b6771ca9c60dc48a87e..545e4de8f253f5a28247838d7627041b0d94f3ad 100644 (file)
@@ -1,3 +1,6 @@
+#include <msp/geometry/circle.h>
+#include <msp/geometry/extrudedshape.h>
+#include <msp/geometry/transformedshape.h>
 #include "signaltype.h"
 
 using namespace std;
@@ -8,6 +11,9 @@ namespace R2C2 {
 SignalType::SignalType(const ArticleNumber &an):
        ObjectType(an)
 {
+       shape = new Geometry::TransformedShape<float, 3>(
+               Geometry::ExtrudedShape<float, 3>(Geometry::Circle<float>(0.01), 0.12),
+               Transform::translation(Vector(0, -0.035, 0.06)));
 }
 
 
index c92ff3779021783e82ef85f9683f1fa52984d4e2..c2b190f0551410b149a408e450ee16041151295c 100644 (file)
@@ -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<DataFile::Statement> &st) const
 {
        st.push_back((DataFile::Statement("position"), position.x, position.y, position.z));
index 7dfa7528081593a8982dd3975a25ab4d5fcef801..168ac37eb669bffe2f15a8457152feb068c1fe77 100644 (file)
@@ -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<Msp::DataFile::Statement> &) const;
 private:
        void turnout_event(unsigned, unsigned);
index d8dac075e68701dfc45d8dc3204d315335dd1d5b..b12ea7278da28ce984e1ad156fb0cb3064f8e1b7 100644 (file)
@@ -1,4 +1,11 @@
 #include <cmath>
+#include <msp/geometry/box.h>
+#include <msp/geometry/circle.h>
+#include <msp/geometry/extrudedshape.h>
+#include <msp/geometry/halfspace.h>
+#include <msp/geometry/intersection.h>
+#include <msp/geometry/negation.h>
+#include <msp/geometry/transformedshape.h>
 #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<float, 3>(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<float, 3> ring(
+                       Geometry::Intersection<float, 2>(
+                               Geometry::Circle<float>(abs(radius)+0.02),
+                               Geometry::Negation<float, 2>(Geometry::Circle<float>(abs(radius)-0.02))),
+                       0.01);
+               Geometry::HalfSpace<float, 3> start_wall(Vector(-1, 0, 0));
+               Geometry::HalfSpace<float, 3> 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<float, 3> bounds(
+                       Geometry::Box<float>(w, h, 0.01),
+                       Transform::translation(Vector(w/2, (h/2-0.02)*(radius<0 ? -1 : 1)-radius, 0.005)));
+               vector<const Shape *> shapes;
+               shapes.push_back(&ring);
+               shapes.push_back(&start_wall);
+               shapes.push_back(&end_wall);
+               shapes.push_back(&bounds);
+               shape = new Geometry::TransformedShape<float, 3>(
+                       Geometry::Intersection<float, 3>::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<float, 3>(
+                       Geometry::Box<float>(length, 0.04, 0.01),
+                       trans*Transform::translation(Vector(length/2, 0, 0.005)));
+       }
 }
 
 
index 9143ff84f32761ef1ee1d0e2989de7078369e5a3..9a17663aae1446884d4ebb97b79b6cbc348fc34d 100644 (file)
@@ -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
index fbed4c1d8d6020b9b19ed4c234b1c002d43f8b64..fe3a54cd824d7471cb78c95b47b8ba9ceb33e8df 100644 (file)
@@ -1,4 +1,5 @@
 #include <cmath>
+#include <msp/geometry/union.h>
 #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<TrackPart>::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<const Shape *> shapes;
+       for(vector<TrackPart>::iterator i=obj.parts.begin(); i!=obj.parts.end(); ++i)
+       {
+               i->create_shape();
+               shapes.push_back(&i->get_shape());
+       }
+       obj.shape = Geometry::Union<float, 3>::from_iterator_range(shapes.begin(), shapes.end()).clone();
 }
 
 void TrackType::Loader::part()
index f446064558442be5d7c8b318174637d8d08086bf..da0df71428f3514129f953f404133da3b6526dc8 100644 (file)
@@ -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();