]> git.tdb.fi Git - r2c2.git/blob - source/designer/extendtool.cpp
Rework article numbers
[r2c2.git] / source / designer / extendtool.cpp
1 #include <msp/strings/format.h>
2 #include "libr2c2/articlenumber.h"
3 #include "designer.h"
4 #include "extendtool.h"
5
6 using namespace std;
7 using namespace Msp;
8 using namespace R2C2;
9
10 ExtendTool::ExtendTool(Designer &d, Input::Keyboard &k, Input::Mouse &m, const set<Object *> &objects):
11         Tool(d, k, m),
12         max_preference(0)
13 {
14         for(set<Object *>::const_iterator i=objects.begin(); i!=objects.end(); ++i)
15                 if(Track *t = dynamic_cast<Track *>(*i))
16                 {
17                         unsigned nls = t->get_n_link_slots();
18                         for(unsigned j=0; j<nls; ++j)
19                                 if(!t->get_link(j))
20                                         unlinked_endpoints.push_back(TrackIter(t, j));
21                 }
22
23         if(unlinked_endpoints.empty())
24         {
25                 set_status("No free endpoints");
26                 set_done(false);
27         }
28
29         list<TrackType *> track_types = designer.get_catalogue().get_list<TrackType>();
30         for(list<TrackType *>::iterator i=track_types.begin(); i!=track_types.end(); ++i)
31         {
32                 const vector<TrackPart> &parts = (*i)->get_parts();
33                 if(parts.size()!=1)
34                         continue;
35                 if(parts.front().is_curved() || parts.front().is_dead_end())
36                         continue;
37
38                 types_by_length[parts.front().get_length()] = *i;
39                 max_preference = max(max_preference, (*i)->get_autofit_preference());
40         }
41 }
42
43 ExtendTool::~ExtendTool()
44 {
45         if(!accepted)
46         {
47                 for(vector<R2C2::Track *>::iterator i=extend_tracks.begin(); i!=extend_tracks.end(); ++i)
48                         delete *i;
49         }
50 }
51
52 void ExtendTool::connect()
53 {
54         float limit;
55
56         Track *start_track = 0;
57         Track *end_track = 0;
58         Snap start_sn;
59         bool ok = false;
60         float gap = 0;
61         for(vector<TrackIter>::const_iterator i=unlinked_endpoints.begin(); i!=unlinked_endpoints.end(); ++i)
62         {
63                 start_sn = (*i)->get_snap_node(i->entry());
64                 limit = (*i)->get_type().get_gauge()/10;
65                 
66                 for(vector<TrackIter>::const_iterator j=i; ++j!=unlinked_endpoints.end(); )
67                 {
68                         Snap end_sn = (*j)->get_snap_node(j->entry());
69
70                         float dz = end_sn.position.z-start_sn.position.z;
71                         if(abs(dz)>0.02)
72                                 continue;
73
74                         Angle adiff = wrap_balanced(start_sn.rotation+Angle::half_turn()-end_sn.rotation);
75                         if(abs(adiff).radians()>0.01)
76                                 continue;
77
78                         Vector delta = rotated_vector(end_sn.position-start_sn.position, -start_sn.rotation);
79                         if(abs(delta.y)>limit)
80                                 continue;
81
82                         gap = delta.x;
83                         if(gap<0)
84                                 continue;
85
86                         start_track = i->track();
87                         end_track = j->track();
88                         ok = true;
89                 }
90
91                 if(ok)
92                         break;
93         }
94
95         if(!ok)
96         {
97                 set_status("No aligned endpoints found");
98                 set_done(false);
99                 return;
100         }
101
102         extend_tracks = create_straight(start_sn.position, start_sn.rotation, gap, limit);
103
104         if(extend_tracks.empty())
105         {
106                 set_status("No connection possible");
107                 set_done(false);
108                 return;
109         }
110
111         extend_tracks.front()->link_to(*start_track);
112         extend_tracks.back()->link_to(*end_track);
113
114         set_done(true);
115 }
116
117 void ExtendTool::pointer_motion()
118 {
119         Vector pos;
120         Angle dir;
121         float length = 0;
122
123         for(vector<TrackIter>::const_iterator i=unlinked_endpoints.begin(); i!=unlinked_endpoints.end(); ++i)
124         {
125                 Snap sn = (*i)->get_snap_node(i->entry());
126                 Vector delta = rotated_vector(ground_pointer-sn.position, -sn.rotation);
127
128                 if(delta.x<length)
129                         continue;
130
131                 pos = sn.position;
132                 dir = sn.rotation;
133                 length = delta.x;
134         }
135
136         if(length)
137         {
138                 vector<Track *> trks = create_straight(pos, dir, length, max(length/500, 0.001f));
139
140                 if(!trks.empty())
141                 {
142                         for(vector<Track *>::iterator i=extend_tracks.begin(); i!=extend_tracks.end(); ++i)
143                                 delete *i;
144                         extend_tracks = trks;
145
146                         map<const TrackType *, unsigned> counts;
147                         length = 0;
148                         for(vector<Track *>::iterator i=extend_tracks.begin(); i!=extend_tracks.end(); ++i)
149                         {
150                                 length += (*i)->get_type().get_total_length();
151                                 ++counts[&(*i)->get_type()];
152                         }
153
154                         string detail;
155                         for(map<const TrackType *, unsigned>::const_iterator i=counts.begin(); i!=counts.end(); ++i)
156                         {
157                                 if(!detail.empty())
158                                         detail += ", ";
159                                 detail += format("%dx %s", i->second, i->first->get_article_number());
160                         }
161
162                         signal_status.emit(format("Extend: %.0fmm (%s)", length*1000, detail));
163                 }
164         }
165 }
166
167 void ExtendTool::finish()
168 {
169         if(!extend_tracks.empty())
170         {
171                 for(vector<TrackIter>::const_iterator i=unlinked_endpoints.begin(); i!=unlinked_endpoints.end(); ++i)
172                         if(extend_tracks.front()->link_to(**i))
173                                 break;
174         }
175 }
176
177 vector<Track *> ExtendTool::create_straight(const Vector &start, const Angle &dir, float length, float limit)
178 {
179         vector<float> lengths;
180         unsigned preference = max_preference;
181         float removed = 0;
182         while(length>limit)
183         {
184                 bool found = false;
185                 for(map<float, const TrackType *>::iterator i=types_by_length.end(); i!=types_by_length.begin(); )
186                 {
187                         --i;
188                         if(i->second->get_autofit_preference()<preference)
189                                 continue;
190                         if((!removed || i->first<removed) && i->first<length+limit)
191                         {
192                                 unsigned n = static_cast<unsigned>((length+limit)/i->first);
193                                 lengths.insert(lengths.end(), n, i->first);
194                                 length -= n*i->first;
195                                 found = true;
196                                 break;
197                         }
198                 }
199
200                 if(found)
201                         continue;
202
203                 if(lengths.empty())
204                 {
205                         if(preference>0)
206                         {
207                                 --preference;
208                                 removed = 0;
209                                 continue;
210                         }
211                         break;
212                 }
213
214                 length += lengths.back();
215                 removed = lengths.back();
216                 lengths.pop_back();
217         }
218
219         vector<Track *> trks;
220
221         if(!lengths.empty())
222         {
223                 Vector pos = start;
224                 Transform trans = Transform::rotation(dir, Vector(0, 0, 1));
225                 for(vector<float>::iterator i=lengths.begin(); i!=lengths.end(); ++i)
226                 {
227                         Track *track = new Track(designer.get_layout(), *get_item(types_by_length, *i));
228                         track->set_position(pos);
229                         track->set_rotation(dir);
230
231                         if(!trks.empty())
232                                 track->link_to(*trks.back());
233                         trks.push_back(track);
234
235                         pos += trans.transform(Vector(*i, 0, 0));
236                 }
237         }
238
239         return trks;
240 }
241
242 void ExtendTool::update_selection(Selection &sel) const
243 {
244         if(accepted)
245                 sel.replace(extend_tracks.begin(), extend_tracks.end());
246 }