]> git.tdb.fi Git - r2c2.git/commitdiff
Add a feature to autofit straight runs of track
authorMikko Rasa <tdb@tdb.fi>
Wed, 27 Oct 2010 12:10:03 +0000 (12:10 +0000)
committerMikko Rasa <tdb@tdb.fi>
Wed, 27 Oct 2010 12:10:03 +0000 (12:10 +0000)
source/designer/designer.cpp
source/designer/designer.h
source/designer/manipulator.cpp
source/designer/manipulator.h
source/libmarklin/tracktype.cpp
source/libmarklin/tracktype.h
tracks.dat

index cb327c560efeb51236169b369675d42b16c26798..92c2f25564b177918a80129fdd1a9b6a26778f88 100644 (file)
@@ -362,6 +362,8 @@ void Designer::key_press(unsigned key, unsigned mod, wchar_t)
                set_sensor_id();
        else if(key==Msp::Input::KEY_A)
                add_selection_to_route();
+       else if(key==Msp::Input::KEY_C)
+               manipulator.connect();
 }
 
 void Designer::button_press(int x, int y, unsigned btn, unsigned mod)
index d229324fb8ccc23a7d65a85d2b2a3937268984f1..d0f8e81e694cb7402e7d4ccba0e409224a5bbaad 100644 (file)
@@ -85,6 +85,7 @@ public:
        void save();
        void quit();
 
+       const Marklin::Catalogue &get_catalogue() const { return catalogue; }
        Marklin::Layout *get_layout() { return layout; }
        Marklin::Layout3D *get_layout_3d() { return layout_3d; }
        const Msp::GL::Camera &get_camera() const { return camera; }
index 35779a8ccc2896234f91e330b1872e7d75b7d58f..42c422923ab7540c4e686263f1bc4a82040370f2 100644 (file)
@@ -212,6 +212,156 @@ void Manipulator::cancel()
        signal_done.emit(false);
 }
 
+void Manipulator::connect()
+{
+       if(tracks.size()!=2)
+       {
+               signal_status.emit("Exactly two tracks must be selected");
+               return;
+       }
+
+       float limit = 0.001;
+
+       Track *track1 = tracks.front().track;
+       Point pos1;
+       float dir1;
+       Track *track2 = tracks.back().track;
+       bool ok = false;
+       float gap;
+       for(unsigned i=0; i<track1->get_type().get_endpoints().size(); ++i)
+       {
+               if(track1->get_link(i))
+                       continue;
+
+               pos1 = track1->get_endpoint_position(i);
+               dir1 = track1->get_endpoint_direction(i);
+
+               for(unsigned j=0; j<track2->get_type().get_endpoints().size(); ++j)
+               {
+                       if(track2->get_link(j))
+                               continue;
+
+                       Point pos2 = track2->get_endpoint_position(j);
+                       float dir2 = track2->get_endpoint_direction(j);
+
+                       float dz = pos2.z-pos1.z;
+                       if(abs(dz)>0.02)
+                               continue;
+
+                       float adiff = dir1+M_PI-dir2;
+                       while(adiff<-M_PI)
+                               adiff += M_PI*2;
+                       while(adiff>M_PI)
+                               adiff -= M_PI*2;
+                       if(abs(adiff)>0.01)
+                               continue;
+
+                       float c = cos(dir1);
+                       float s = sin(dir1);
+                       float dx = pos2.x-pos1.x;
+                       float dy = pos2.y-pos1.y;
+                       if(abs(dx*s-dy*c)>limit)
+                               continue;
+
+                       gap = dx*c+dy*s;
+                       if(gap<0)
+                               continue;
+
+                       ok = true;
+               }
+
+               if(ok)
+                       break;
+       }
+
+       if(!ok)
+       {
+               signal_status.emit("No matching endpoints found");
+               return;
+       }
+
+       const map<unsigned, TrackType *> &track_types = designer.get_catalogue().get_tracks();
+       std::map<float, const TrackType *> types_by_length;
+       unsigned preference = 0;
+       for(map<unsigned, TrackType *>::const_iterator i=track_types.begin(); i!=track_types.end(); ++i)
+       {
+               const vector<TrackPart> &parts = i->second->get_parts();
+               if(parts.size()!=1)
+                       continue;
+               if(parts.front().is_curved() || parts.front().is_dead_end())
+                       continue;
+
+               types_by_length[parts.front().get_length()] = i->second;
+               preference = max(preference, i->second->get_autofit_preference());
+       }
+
+       vector<float> lengths;
+       float removed = 0;
+       while(gap>limit)
+       {
+               bool found = false;
+               for(map<float, const TrackType *>::iterator i=types_by_length.end(); i!=types_by_length.begin(); )
+               {
+                       --i;
+                       if(i->second->get_autofit_preference()<preference)
+                               continue;
+                       if((!removed || i->first<removed) && i->first<gap+limit)
+                       {
+                               unsigned n = static_cast<unsigned>((gap+limit)/i->first);
+                               lengths.insert(lengths.end(), n, i->first);
+                               gap -= n*i->first;
+                               found = true;
+                               break;
+                       }
+               }
+
+               if(found)
+                       continue;
+
+               if(lengths.empty())
+               {
+                       if(preference>0)
+                       {
+                               --preference;
+                               removed = 0;
+                               continue;
+                       }
+                       break;
+               }
+
+               gap += lengths.back();
+               removed = lengths.back();
+               lengths.pop_back();
+       }
+
+       if(lengths.empty())
+       {
+               signal_status.emit("No connection possible");
+               return;
+       }
+
+       float c = cos(dir1);
+       float s = sin(dir1);
+       for(vector<float>::iterator i=lengths.begin(); i!=lengths.end(); ++i)
+       {
+               map<float, const TrackType *>::iterator j = types_by_length.find(*i);
+               if(j==types_by_length.end())
+                       throw LogicError("Internal error");
+
+               Track *track = new Track(*designer.get_layout(), *j->second);
+               track->set_position(pos1);
+               track->set_rotation(dir1);
+
+               track->snap_to(*track1, true);
+               track1 = track;
+
+               pos1.x += c**i;
+               pos1.y += s**i;
+       }
+
+       track1->snap_to(*track2, true);
+}
+
 void Manipulator::button_press(int, int, float, float, unsigned btn)
 {
        if(btn==3)
index fa8598db186f7ebb55126777cd4a3cf375902720..8115ab4abd8dd7e8e3b1d6429a249737b2efbf09 100644 (file)
@@ -69,6 +69,7 @@ public:
        void duplicate();
        void flatten();
        void even_slope(bool =false);
+       void connect();
        void cancel();
        void button_press(int, int, float, float, unsigned);
        void pointer_motion(int, int, float, float);
index 8c1505b87033ca821526a7831f9a33d58d5b00cc..53c2bc47844c862e0a3b07db63f94aa71a37e041 100644 (file)
@@ -15,7 +15,8 @@ namespace Marklin {
 
 TrackType::TrackType(unsigned a):
        art_nr(a),
-       double_address(false)
+       double_address(false),
+       autofit_preference(1)
 { }
 
 float TrackType::get_total_length() const
@@ -164,6 +165,7 @@ TrackType::Endpoint::Endpoint(float x, float y, float d, unsigned p):
 TrackType::Loader::Loader(TrackType &t):
        Msp::DataFile::BasicLoader<TrackType>(t)
 {
+       add("autofit_preference", &TrackType::autofit_preference);
        add("description", &TrackType::description);
        add("double_address", &TrackType::double_address);
        add("part",        &Loader::part);
index 902a2f6ddd561df38ecb1c84dbdfbb0fb3d2c79b..b44374018239060f0dd62be2dbbae4cefc7701c3 100644 (file)
@@ -42,6 +42,7 @@ private:
        std::vector<TrackPart> parts;
        std::vector<Endpoint> endpoints;
        bool double_address;
+       unsigned autofit_preference;
 
 public:
        TrackType(unsigned);
@@ -55,6 +56,7 @@ public:
        bool is_turnout() const;
        bool is_dead_end() const;
        bool is_double_address() const { return double_address; }
+       unsigned get_autofit_preference() const { return autofit_preference; }
        const std::vector<TrackPart> &get_parts() const { return parts; }
        const std::vector<Endpoint> &get_endpoints() const { return endpoints; }
        TrackPoint get_point(unsigned, unsigned, float) const;
index fac3dfc8e676375e1188d1c74377686ac8aed576..96d0772e2b65caf59698361e4a8b60ff7704d6c9 100644 (file)
@@ -35,6 +35,7 @@ track 24071
        {
                length 70.8;
        };
+       autofit_preference 0;
 };
 
 track 24077
@@ -44,6 +45,7 @@ track 24077
        {
                length 77.5;
        };
+       autofit_preference 2;
 };
 
 track 24094
@@ -53,6 +55,7 @@ track 24094
        {
                length 94.2;
        };
+       autofit_preference 2;
 };
 
 track 24172
@@ -62,6 +65,7 @@ track 24172
        {
                length 171.7;
        };
+       autofit_preference 2;
 };
 
 track 24188
@@ -71,6 +75,7 @@ track 24188
        {
                length 188.3;
        };
+       autofit_preference 2;
 };
 
 track 24229