Library to optimise picking in the warehouse This library includes algorithms that should lead to improvements in picking path optimization in the warehouse. Any specifications that

Loading...
Searching...
No Matches
waddress_functions.hpp
Go to the documentation of this file.
1
12#ifndef _WADDRESS_FUNCTIONS_H_
13#define _WADDRESS_FUNCTIONS_H_
14
15#include <string>
16#include <iostream>
17#include <math.h>
18
19#include "WarehousePickingOpt.h"
20#include "helper.h"
21
22 typedef struct : public SECTOR_ADDR_T
23{
24 int current_weight = 0;
25} GRAPH_POINT_T;
26
28 namespace secV
29{
30 // V sector set up
31 // TODO not sure about all these values
32 const float x_offset = 25.0; // 2.5 meters from fictional left axis to the fictional corridor (at left)
33 const float y_offset = 0.0; // V addresses are at the top of the area - so zero offset set up
34 const float horizontal_corridor_width = 24.0,
35 middle_vertical_cor_width = 37.0, // middle and side-middle vertical corridors are of the same width as in G sector (also in the same place)
36 side_middle_vertical_cor_width = 31.0,
37 side_side_vertical_cor_width = 5.0;
38
39 const float small_cell_depth = 4.0f,
40 big_cell_depth = 6.0f,
41 pallet_cell_depth = 12.0f,
42 big_cell_width = 13.0f,
43 small_cell_width = 1.3f,
44 pallet_cell_width = 10.0f;
45
46 // the row (Y coordinate, but in addresse's format), which is first in the opposite of another row -> so there is a horizontal corridor between them
47 // for the better computation of distance while both addresses are in the same horizontal corridor but not with the same Y coord
48 const int first_row_opposite = 0;
49
50 const vector<int> vertical_corridors = {
51 (int)(x_offset + side_side_vertical_cor_width * 0.5), // the most left
52 (int)(x_offset + side_side_vertical_cor_width + 10.0 * big_cell_width + side_middle_vertical_cor_width * 0.5), // left from middle
53 (int)(x_offset + side_side_vertical_cor_width + (10 + 10) * big_cell_width + side_middle_vertical_cor_width + middle_vertical_cor_width * 0.5), // middle
54 (int)(x_offset + side_side_vertical_cor_width + (10 + 10 + 8) * big_cell_width + side_middle_vertical_cor_width + middle_vertical_cor_width + side_middle_vertical_cor_width * 0.5), // right from middle
55 (int)(x_offset + side_side_vertical_cor_width + (10 + 10 + 8 + 10) * big_cell_width + side_middle_vertical_cor_width + middle_vertical_cor_width + side_middle_vertical_cor_width + side_side_vertical_cor_width * 0.5)};
56
57 // FIXME 380 is not probably accurate...
58 const vector<string> rows_380_celled = {"BB", "DD"};
59
60 const map<int, int> V_East_exits = {
61 {vertical_corridors[4], y_offset + pallet_cell_depth + horizontal_corridor_width * 0.5},
62 {vertical_corridors[4], y_offset + pallet_cell_depth + horizontal_corridor_width + small_cell_depth + big_cell_depth + horizontal_corridor_width * 0.5},
63 {vertical_corridors[4], y_offset + pallet_cell_depth + 2 * horizontal_corridor_width + 2 * small_cell_depth + 2 * big_cell_depth + horizontal_corridor_width * 0.5},
64 };
65
66 const int y_for_south_exits = y_offset + pallet_cell_depth + 2 * horizontal_corridor_width + 2 * small_cell_depth + 2 * big_cell_depth + horizontal_corridor_width * 0.5;
67 const map<int, int> V_South_exits = {
68 {vertical_corridors[1], y_for_south_exits},
69 {vertical_corridors[2], y_for_south_exits},
70 {vertical_corridors[3], y_for_south_exits}};
71}
72
74 namespace secG
75{
76 // G sector set up
77 const float x_offset = 40.0; // 4 meters from fictional left axis to the first vertical corridor
78 const float y_offset = 130.0 + secV::y_offset; /*to the 00 row*/
79 const float horizontal_corridor_width = 16.0,
80 middle_vertical_cor_width = 37.0,
81 side_middle_vertical_cor_width = 31.0,
82 side_side_vertical_cor_width = 20.0;
83
84 const float cell_depth = 4.0f,
85 big_cell_width = 13.0f,
86 small_cell_width = 1.6f;
87
88 const vector<int> vertical_corridors = {
89 (int)(x_offset + side_side_vertical_cor_width * 0.5), // the most left
90 (int)(x_offset + side_side_vertical_cor_width + 7.0 * big_cell_width + side_middle_vertical_cor_width * 0.5), // left from middle
91 (int)(x_offset + side_side_vertical_cor_width + (7 + 10) * big_cell_width + side_middle_vertical_cor_width + middle_vertical_cor_width * 0.5), // middle
92 (int)(x_offset + side_side_vertical_cor_width + (7 + 10 + 7) * big_cell_width + side_middle_vertical_cor_width + middle_vertical_cor_width + side_middle_vertical_cor_width * 0.5), // right from middle
93 (int)(x_offset + side_side_vertical_cor_width + (7 + 10 + 7) * big_cell_width + side_middle_vertical_cor_width + middle_vertical_cor_width + side_middle_vertical_cor_width + 7.0 * big_cell_width + side_side_vertical_cor_width * 0.5)};
94 const vector<int> rows_246_celled = {0, 1, 2, 3, 36, 37, 38, 39, 40};
95
96 // the row (Y coordinate, but in addresse's format), which is first in the opposite of another row -> so there is a horizontal corridor between them
97 // for the better computation of distance while both addresses are in the same horizontal corridor but not with the same Y coord
98 const int first_row_opposite = 1;
99
100 // exits of sector G
101 // these coordinates should fit the exits of G sector towards the V sector
102 const GRAPH_POINT_T G_north_exit = {"G00", (int)y_offset, 0, 545 + (int)x_offset};
103 const GRAPH_POINT_T G_lower_exit = {"G00", (int)(y_offset + 448 + 24 + 24), 0, vertical_corridors[4] + (int)(side_side_vertical_cor_width * 0.5)};
104}
105
107 namespace secP
108{
109 // P sector set up
110 // notice, that P sector is turned by 90 degrees (so rows -> columns) against G sector
111 const float x_offset = 714.0 + secG::x_offset; // to the first cell from left site
112 const float y_offset = 115.0 + secV::y_offset;
113 const float horizontal_corridor_width = 20.0, // width of the only one horizontal corridor
114 vertical_cor_width = 34.0;
115
116 const float cell_depth = 10.0f,
117 cell_width = 9.5f; // note: measured vertically; it is with of one cell of four, which are in the once visible block
118
119 // definition of only three corridors
120 // defining X coordinates of them
121 // the rest is neglected, because of the small difference when computing the distance of the far cells of the P sector
122 const vector<int> vertical_corridors = {
123 (int)(x_offset), // corridor that is along the 00 column
124 (int)(x_offset + 2 * cell_depth + vertical_cor_width * 0.5),
125 (int)(x_offset + 4 * cell_depth + vertical_cor_width * 1.5),
126 (int)(x_offset + 6 * cell_depth + vertical_cor_width * 2.5)};
127
128 // defining Y coordinates
129 const vector<int> horizontal_cooridors = {
130 (int)(y_offset),
131 (int)(y_offset + 48 * cell_width + 0.5 * horizontal_corridor_width),
132 (int)(y_offset + 48 * cell_width + horizontal_corridor_width + 10 * cell_width + 0.5 * horizontal_corridor_width)};
133
134 // the row (X coordinate, but in addresse's format), which is first in the opposite of another column -> so there is a vertical corridor between them
135 // for the better computation of distance while both addresses are in the same vertical corridor but not with the same X coord
136 const int first_column_opposite = 1;
137
138 // exits of sector P
139 // these coordinates should fit the exits of P sector towards the G (GP) sector
140 const GRAPH_POINT_T P_middle_exit = {"P00", (int)horizontal_cooridors[0], 0, (int)x_offset};
141
142 const GRAPH_POINT_T P_north_exit = {"P00", (int)y_offset, 0, (int)x_offset};
143
144 const GRAPH_POINT_T P_south_exit = {"P00", (int)y_offset + 683, 0, (int)x_offset};
145}
146
148 namespace secGP
149{
150 // GP sector set up // TODO find the real layout
151 // notice, that GP sector is turned by 90 degrees (so rows -> columns) against G sector
152 const float x_offset = 545.0 + secG::x_offset;
153 const float y_offset = 134.0 + secG::y_offset;
154 const float horizontal_corridor_width = 32.0,
155 vertical_cor_width = 18.0;
156
157 const float cell_gap = 2.9f, // the gap between some cells (according to the real layout)
158 cell_depth = 6.0f,
159 cell_width = 11.7f; // the average of two types below, computed according to the layout of the column
160 // first_type_cell_width = 10.0f,// the real widths, not used, just approximated
161 // second_type_cell_width = 13.0f;
162
163 const vector<int> vertical_corridors = {
164 (int)(x_offset + cell_depth + vertical_cor_width * 0.5), // corridor that is along the 00 column
165 (int)(x_offset + 2 * cell_depth + vertical_cor_width * 1.5),
166 (int)(x_offset + 4 * cell_depth + vertical_cor_width * 2.5)};
167
168 const vector<int> horizontal_corridors = {
169 (int)(y_offset - 0.5 * horizontal_corridor_width),
170 (int)(y_offset + 6 * cell_width + 2 * cell_gap + 0.5 * horizontal_corridor_width),
171 (int)(y_offset + 26 * cell_width + 13 * cell_gap + 1.5 * horizontal_corridor_width)};
172
173 const int first_column_opposite = 1;
174
175 const vector<SECTOR_ADDR_T> GP_exits = {
176 {"GP0", horizontal_corridors[0], 0, (int)(vertical_corridors[2] + vertical_cor_width * 0.5 + 30)},
177 {"GP0", horizontal_corridors[1], 0, (int)(vertical_corridors[2] + vertical_cor_width * 0.5 + 30)},
178 {"GP0", horizontal_corridors[2], 0, (int)(vertical_corridors[2] + vertical_cor_width * 0.5 + 30)},
179 };
180}
181
183// original information unchanged (no recomputing or some mathematical changing)
184 inline namespace ver1
185{
186 inline namespace mapping
187 {
188 inline SECTOR_ADDR_T G_SectorMapping(string raw_addr)
189 {
190 // create the structure for address
191 SECTOR_ADDR_T parsed_addr;
192 // load each part of address using substring function
193 parsed_addr.section = raw_addr.substr(0, 3);
194 parsed_addr.y_coord = stoi(raw_addr.substr(3, 2));
195 parsed_addr.z_coord = stoi(raw_addr.substr(5, 2));
196 parsed_addr.x_coord = stoi(raw_addr.substr(7, 3));
197
198 return parsed_addr;
199 }
200 inline SECTOR_ADDR_T GP_SectorMapping(string raw_addr)
201 {
202 // same process as by G_Sector
203 return G_SectorMapping(raw_addr);
204 }
205 inline SECTOR_ADDR_T P_SectorMapping(string raw_addr)
206 {
207 // same process as by G_Sector
208 return G_SectorMapping(raw_addr);
209 }
210 inline SECTOR_ADDR_T V_SectorMapping(string raw_addr)
211 {
212 (void)raw_addr;
213 // TODO
214 return SECTOR_ADDR_T();
215 }
216 }
217 inline namespace measuring
218 {
219 inline int getDistanceInSectorG(WAddress first_addr, WAddress second_addr)
220 {
221 // the numbers of cells, between which there is a corridor
222 // as corridors are not numbered, then the number is between the number of neighbouring cells
223 const vector<float> vertical_corridors{7.5, 17.5, 24.5};
224 const vector<int> horizontal_corridors{};
225 // rows, which has 1-246 cells (the rest has 1-31)
226 const vector<int> rows_of_246_cells{0, 1, 40};
227
228 // if first_addr or second_addr is addresses in 0th or 1st or 40th row, then recalculate its cell-value (x axis)
229 // cause the rest of rows are each of 1-31 cells but in the rows mentioned above are each of 1-246 cells
230 // this knowledge is stored in these booleans
231 bool first_addr_has_246_cells = false, second_addr_has_246_cells = false;
232 if (find(rows_of_246_cells.begin(), rows_of_246_cells.end(), first_addr.getWarehouseWAddress().y_coord) != rows_of_246_cells.end())
233 {
234 // the row has 246 cells
235 // 1 cell in 31-celled-row is 8 cells in 246-celled-row
237 first_addr_has_246_cells = true;
238 }
239
240 if (find(rows_of_246_cells.begin(), rows_of_246_cells.end(), second_addr.getWarehouseWAddress().y_coord) != rows_of_246_cells.end())
241 {
242 second_addr_has_246_cells = true;
243 }
244
245 // do the pattern (it is for the euclidean space)
246 // THERE IS STORED THE FINAL DISTANCE
247 float distance = 0;
248
249 // THERE IS STORED THE USED CORRIDOR (the nearest to the first address)
250 float used_corridor = -1; // -1 ... unset
251
252 // DISTANCE TO THE NEAREST CORRIDOT from first address
253 for (auto corridor : vertical_corridors)
254 {
255 float tmp;
256 if ((float)first_addr.getWarehouseWAddress().x_coord < corridor && !first_addr_has_246_cells)
257 {
258 // cell in row of 31 cells
259 used_corridor = corridor;
260 distance += abs((used_corridor - (float)first_addr.getWarehouseWAddress().x_coord));
261 break;
262 }
263 else if ((float)first_addr.getWarehouseWAddress().x_coord > vertical_corridors.back() && !first_addr_has_246_cells)
264 {
265 // the cell number is greater then last (with highest number) corridor
266 // cell in row of 31 cells
267 used_corridor = vertical_corridors.back();
268 distance += abs((used_corridor - (float)first_addr.getWarehouseWAddress().x_coord));
269 break;
270 }
271 else if ((tmp = (float)first_addr.getWarehouseWAddress().x_coord / 8.0) < corridor && first_addr_has_246_cells)
272 {
273 // cell in row of 246 cells - has to be normalized
274 used_corridor = corridor;
275 distance += abs((used_corridor - tmp));
276 break;
277 }
278 else if ((tmp = (float)first_addr.getWarehouseWAddress().x_coord / 8.0) < corridor && first_addr_has_246_cells)
279 {
280 // the cell number is greater then last (with highest number) corridor
281 // cell in row of 246 cells - has to be normalized
282 used_corridor = vertical_corridors.back();
283 distance += abs((used_corridor - tmp));
284 break;
285 }
286 }
287
288 // VERTICAL DISTANCE BETWEEN THE two addresses (first_addr and second_addr)
289 distance += abs((second_addr.getWarehouseWAddress().y_coord - first_addr.getWarehouseWAddress().y_coord));
290
291 // DISTANCE FROM THE CORRIDOR (stored above) TO THE SECOND ADDRESS
292 if (!second_addr_has_246_cells)
293 {
294 // cell in row of 31 cells
295 distance += abs((used_corridor - (float)second_addr.getWarehouseWAddress().x_coord));
296 }
297 else if (second_addr_has_246_cells)
298 {
299 // cell in row of 246 cells - has to be normalized
300 distance += abs((used_corridor - (float)second_addr.getWarehouseWAddress().x_coord / 8.0));
301 }
302
303 // return the final distance between
304 return distance;
305 }
306 }
307}
308
310 inline namespace ver2
311{
312 inline namespace mapping
313 {
314 inline SECTOR_ADDR_T GP_SectorMapping(string raw_addr)
315 {
316 // TODO this mapping IS NOT PERFECT, there are place for enhance
317 using namespace secGP;
318
319 SECTOR_ADDR_T parsed_addr;
320 /****** GP sector mapping *******/
321 // NOTE: SEE DWG FILE FOR BETTER UNDERSTANDING
322
323 // X coord -> column
324 float x_tmp = stof(raw_addr.substr(3, 2));
325 parsed_addr.x_coord_original = x_tmp; // ORIDINAL PART
326 // note: columns start from 01
327 parsed_addr.x_coord = x_offset + x_tmp * cell_depth + (x_tmp - 1) * vertical_cor_width;
328 parsed_addr.x_coord -= (x_tmp == 3 || x_tmp == 5) ? cell_depth : 0; // correction according to the real layout and real possible of approach to the cells for picking
329 parsed_addr.x_coord -= (x_tmp == 4 || x_tmp == 5) ? vertical_cor_width : 0; // correction according to the real layout and real possible of approach to the cells for picking
330
331 // Z coord -> stays as it is
332 parsed_addr.z_coord = stoi(raw_addr.substr(5, 2));
333 parsed_addr.z_coord_original = parsed_addr.z_coord; // ORIDINAL PART
334
335 // Y coord -> row
336 // if the row is of 246 cells then
337 float y_tmp = stof(raw_addr.substr(7, 3));
338 parsed_addr.y_coord_original = y_tmp; // ORIDINAL PART
339 parsed_addr.y_coord = y_offset + y_tmp * cell_width + (y_tmp / 2) * cell_gap;
340 if (x_tmp > 6)
341 parsed_addr.y_coord += horizontal_corridor_width;
342
343 // return of the parsed (mapped) address
344 return parsed_addr;
345 }
346
347 inline SECTOR_ADDR_T G_SectorMapping(string raw_addr)
348 {
349 using namespace secG;
350
351 SECTOR_ADDR_T parsed_addr;
352 /****** G sector mapping *******/
353
354 // Y coord -> row
355 float y_tmp = stof(raw_addr.substr(3, 2));
356 parsed_addr.y_coord_original = y_tmp; // ORIDINAL PART
357 // parsed_addr.y_coord = ((int)(row_tmp / 2) * horizontal_corridor_width) + (row_tmp * cell_depth) + y_offset + ((int)row_tmp == 0 ? 0.0 : cell_depth) /*for the 00 row*/;
358 parsed_addr.y_coord = y_offset;
359 parsed_addr.y_coord += round((y_tmp - 0.3) / 2) * horizontal_corridor_width;
360 parsed_addr.y_coord += ((int)y_tmp % 2 == 0) ? (y_tmp * cell_depth) : (y_tmp * cell_depth + cell_depth);
361 // Z coord -> stays as it is
362 parsed_addr.z_coord = stoi(raw_addr.substr(5, 2));
363 parsed_addr.z_coord_original = parsed_addr.z_coord; // ORIDINAL PART
364 // X coord -> column
365 float x_tmp = stof(raw_addr.substr(7, 3));
366 parsed_addr.x_coord_original = x_tmp; // ORIDINAL PART
367 if (find(rows_246_celled.begin(), rows_246_celled.end(), y_tmp) != rows_246_celled.end())
368 {
369 // if the row is of 246 cells then
370
371 parsed_addr.x_coord = x_offset + side_side_vertical_cor_width + x_tmp * small_cell_width;
372 if (x_tmp > 192)
373 parsed_addr.x_coord += side_middle_vertical_cor_width * 2 + middle_vertical_cor_width;
374 else if (x_tmp > 136)
375 parsed_addr.x_coord += side_middle_vertical_cor_width + middle_vertical_cor_width;
376 else if (x_tmp > 56)
377 parsed_addr.x_coord += side_middle_vertical_cor_width;
378 }
379 else
380 {
381 // if the row is of 31 cells
382 parsed_addr.x_coord = x_offset + side_side_vertical_cor_width + x_tmp * big_cell_width;
383 if (x_tmp > 24)
384 parsed_addr.x_coord += side_middle_vertical_cor_width * 2 + middle_vertical_cor_width;
385 else if (x_tmp > 17)
386 parsed_addr.x_coord += side_middle_vertical_cor_width + middle_vertical_cor_width;
387 else if (x_tmp > 7)
388 parsed_addr.x_coord += side_middle_vertical_cor_width;
389 }
390
391 // return of the parsed (mapped) address
392 return parsed_addr;
393 }
394
395 inline SECTOR_ADDR_T P_SectorMapping(string raw_addr)
396 {
397 using namespace secP;
398
399 SECTOR_ADDR_T parsed_addr;
400 /****** P sector mapping *******/
401
402 // X coord -> column
403 float x_tmp = stof(raw_addr.substr(3, 2));
404 parsed_addr.x_coord_original = x_tmp; // ORIDINAL PART
405 parsed_addr.x_coord = x_offset + round((x_tmp - 0.3) / 2) * vertical_cor_width;
406 parsed_addr.x_coord += ((int)x_tmp % 2 == 0) ? (x_tmp * cell_depth) : (x_tmp * cell_depth + cell_depth);
407
408 // Z coord -> stays as it is
409 parsed_addr.z_coord = stoi(raw_addr.substr(5, 2));
410 parsed_addr.z_coord_original = parsed_addr.z_coord; // ORIDINAL PART
411
412 // Y coord -> row
413 // if the row is of 246 cells then
414 float y_tmp = stof(raw_addr.substr(7, 3));
415 parsed_addr.y_coord_original = y_tmp; // ORIDINAL PART
416 parsed_addr.y_coord = y_offset + (y_tmp - 0.3 / 4) * cell_width + cell_width;
417 if (x_tmp > 48) // TODO after that cell is marked horizontal corridor - BUT ONLY IN THIS CONFIGURATION, not sure if this is for real
418 parsed_addr.y_coord += horizontal_corridor_width;
419
420 // return of the parsed (mapped) address
421 return parsed_addr;
422 }
423
424 inline SECTOR_ADDR_T V_SectorMapping(string raw_addr)
425 {
426 using namespace secV; // the specification for sector V is used
427
428 SECTOR_ADDR_T parsed_addr;
429 /****** V sector mapping *******/
430
431 // Y coord -> row
432 int y_coord = toupper(raw_addr.substr(1, 1)[0]) - (int)'A'; // from 'VAA' -> 'A' -> 65, etc...
433 parsed_addr.y_coord_original = y_coord;
434 parsed_addr.y_coord = y_offset;
435 parsed_addr.y_coord += round((y_coord + 0.3) / 2) * horizontal_corridor_width;
436 parsed_addr.y_coord += pallet_cell_depth + (y_coord > 0) ? ((round((y_coord + 0.3) / 2) * small_cell_depth) + (y_coord / 2 * big_cell_depth)) : (0);
437 // Z coord -> stays as it is
438 parsed_addr.z_coord = stoi(raw_addr.substr(5, 2));
439 parsed_addr.z_coord_original = parsed_addr.z_coord;
440 // X coord -> column
441 float x_coord = stof(raw_addr.substr(7, 3));
442 parsed_addr.x_coord_original = x_coord;
443 if (y_coord == 0)
444 {
445 // pallet row AAA
446 // all constants used there serve for better coordinates expression according to the pallet row design
447 parsed_addr.x_coord = (x_offset + side_side_vertical_cor_width + big_cell_width * 0.5) + (x_coord - 1) * pallet_cell_width + pallet_cell_width * 0.5;
448 if (x_coord > 36)
449 parsed_addr.x_coord += side_middle_vertical_cor_width * 2.7 + middle_vertical_cor_width * 1.4;
450 else if (x_coord > 26)
451 parsed_addr.x_coord += side_middle_vertical_cor_width * 1.2 + middle_vertical_cor_width * 1.4;
452 else if (x_coord > 12)
453 parsed_addr.x_coord += side_middle_vertical_cor_width * 1.2;
454 }
455 else if (y_coord == 1 || y_coord == 3)
456 {
457 // rows BB and DD of 380 cells
458 parsed_addr.x_coord = (x_offset + side_side_vertical_cor_width) + (x_coord - 1) * small_cell_width + small_cell_width * 0.5;
459 if (x_coord > 280)
460 parsed_addr.x_coord += side_middle_vertical_cor_width * 1.66 /*some edit according to the real map*/ + middle_vertical_cor_width;
461 else if (x_coord > 200)
462 parsed_addr.x_coord += side_middle_vertical_cor_width + middle_vertical_cor_width;
463 else if (x_coord > 100)
464 parsed_addr.x_coord += side_middle_vertical_cor_width;
465 }
466 else
467 {
468 // rows CCC and EEE (of normal cells)
469 parsed_addr.x_coord = (x_offset + side_side_vertical_cor_width) + (x_coord - 1) * big_cell_width + big_cell_width * 0.5;
470 if (x_coord > 28)
471 parsed_addr.x_coord += side_middle_vertical_cor_width * 1.66 /*some edit according to the real map*/ + middle_vertical_cor_width;
472 else if (x_coord > 20)
473 parsed_addr.x_coord += side_middle_vertical_cor_width + middle_vertical_cor_width;
474 else if (x_coord > 10)
475 parsed_addr.x_coord += side_middle_vertical_cor_width;
476 }
477 // return of the parsed (mapped) address
478 return parsed_addr;
479 }
480 }
481
482 inline namespace measuring
483 {
484
490 inline int horizontalCorridorSpecialCase_G_V(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr, int first_row_opposite)
491 {
492 // SPECIAL CASE - CHECK FOR THE SAME ROW - return just the difference
493 // this computation is handled later on, but here it is set for faster result
494 if (first_addr.y_coord_original - second_addr.y_coord_original == 0)
495 {
496 return abs(first_addr.x_coord - second_addr.x_coord);
497 }
498 else
499 {
500 // for the next part of computation order the two addresses from down to up by Y coord (remember, in warehouse layout the beggining of axises are in the top left corner )
501 if (first_addr.y_coord_original > second_addr.y_coord_original)
502 swap(first_addr, second_addr);
503
504 // check for the same horizontal corridor, but not the same Y_coord
505 // the same corridor if and only if odd number follows the even one
506
507 // behave according to the number of the first row in first horizotnal corridor
508 if (first_row_opposite % 2 == 0)
509 {
510 if (first_addr.y_coord_original % 2 == 0 && first_addr.y_coord_original + 1 == second_addr.y_coord_original)
511 return euclidean_distance(first_addr, second_addr);
512 }
513 else
514 {
515 if (first_addr.y_coord_original % 2 == 1 && first_addr.y_coord_original + 1 == second_addr.y_coord_original)
516 return euclidean_distance(first_addr, second_addr);
517 }
518
519 // NOTE: simple explanation - to match this case handled right above, first row has to be for one unit before the second one
520 }
521
522 return -1; // when special case hasn't been recognized
523 }
524
525 inline int horizontalCorridorSpecialCase_P_GP(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr, int first_row_opposite)
526 {
527 // SPECIAL CASE - CHECK FOR THE SAME ROW - return just the difference
528 // this computation is handled later on, but here it is set for faster result
529 if (first_addr.x_coord_original - second_addr.x_coord_original == 0)
530 return abs(first_addr.y_coord - second_addr.y_coord);
531 else
532 {
533 // for the next part of computation order the two addresses from left to right by X coord (remember, in warehouse layout the beggining of axises are in the top left corner )
534 if (first_addr.x_coord_original > second_addr.x_coord_original)
535 swap(first_addr, second_addr);
536
537 // check for the same verticall corridor, but not the same X_coord
538 // the same corridor if and only if odd number follows the even one
539
540 // behave according to the number of the first row in first horizotnal corridor
541 if (first_row_opposite % 2 == 0)
542 {
543 if (first_addr.x_coord_original % 2 == 0 && first_addr.x_coord_original + 1 == second_addr.x_coord_original)
544 return euclidean_distance(first_addr, second_addr);
545 }
546 else
547 {
548 if (first_addr.x_coord_original % 2 == 1 && first_addr.x_coord_original + 1 == second_addr.x_coord_original)
549 return euclidean_distance(first_addr, second_addr);
550 }
551
552 // NOTE: simple explanation - to match this case handled right above, first row has to be for one unit before the second one
553 }
554
555 return -1; // when special case hasn't been recognized
556 }
557
558 inline int getDistanceInSectorG(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
559 {
560 using namespace secG;
561 //**************************** do the pattern (possible because of the EUCLIDEAN space) ***********************************************
562 // THERE IS STORED THE FINAL DISTANCE
563 float distance = 0;
564
565 // handling special case
566 int distance_tmp = horizontalCorridorSpecialCase_G_V(first_addr, second_addr, first_row_opposite);
567 if (distance_tmp >= 0)
568 {
569 return distance_tmp;
570 }
571
572 // for the next part of computation order the two addresses from left to right
573 if (first_addr.x_coord > second_addr.x_coord)
574 swap(first_addr, second_addr);
575
576 // stored x coord of both addresses for better readability
577 auto first_addr_x = first_addr.x_coord;
578 auto second_addr_x = second_addr.x_coord;
579 for (size_t i = 0; i < vertical_corridors.size() - 1; i++)
580 {
581 // check the first address of being between current two corridors
582 if (first_addr_x >= vertical_corridors[i] && first_addr_x <= vertical_corridors[i + 1])
583 {
584 // found the column of the first address
585 if (second_addr_x >= vertical_corridors[i] && second_addr_x <= vertical_corridors[i + 1])
586 {
587 // the second address fits too
588 if (first_addr_x - vertical_corridors[i] + second_addr_x - vertical_corridors[i] <
589 vertical_corridors[i + 1] - first_addr_x + vertical_corridors[i + 1] - second_addr_x)
590 {
591 // better is left corridor
592 distance += first_addr_x - vertical_corridors[i];
593 distance += abs(first_addr.y_coord - second_addr.y_coord);
594 distance += second_addr_x - vertical_corridors[i];
595 }
596 else
597 {
598 // better is right corridor
599 distance += vertical_corridors[i + 1] - first_addr_x;
600 distance += abs(first_addr.y_coord - second_addr.y_coord);
601 distance += vertical_corridors[i + 1] - second_addr_x;
602 }
603 }
604 else
605 {
606 // the second address doesnt fit the column as the first address is set to - so count at rest as normall
607 // as we make first address be the left one, count distance to the right corridor
608 distance += vertical_corridors[i + 1] - first_addr_x;
609 distance += abs(first_addr.y_coord - second_addr.y_coord);
610 distance += second_addr_x - vertical_corridors[i + 1]; // we know that the second address has to have greater x value, cause its
611 }
612 // nothing more to compute - return the result of distance measurement
613 return distance;
614 } // if
615 } // for
616 return distance;
617 }
618
619 inline int getDistanceInSectorV(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
620 {
621 using namespace secV;
622
623 //**************************** do the pattern (possible because of the EUCLIDEAN space) ***********************************************
624 // THERE IS STORED THE FINAL DISTANCE
625 float distance = 0;
626
627 // handling special case
628 int distance_tmp = horizontalCorridorSpecialCase_G_V(first_addr, second_addr, first_row_opposite);
629 if (distance_tmp >= 0)
630 return distance_tmp;
631
632 // for the next part of computation order the two addresses from left to right
633 if (first_addr.x_coord > second_addr.x_coord)
634 swap(first_addr, second_addr);
635
636 // stored x coord of both addresses for better readability
637 auto first_addr_x = first_addr.x_coord;
638 auto second_addr_x = second_addr.x_coord;
639 // first check for special case - both addresses in the same HORIZONTAL corridor (so the same Y coord) -> meaning there is shorter distacne to go
640
641 // find the best way, if the addresses are in the same column (bordered from both sites by vertical corridors)
642 // also there is handled the other way with simple subtraction of both coordinates
643 for (size_t i = 0; i < vertical_corridors.size() - 1; i++)
644 {
645 // check the first address whether it is between current two corridors
646 if (first_addr_x >= vertical_corridors[i] && first_addr_x <= vertical_corridors[i + 1])
647 {
648 // decide the column of the second address
649 if (second_addr_x >= vertical_corridors[i] && second_addr_x <= vertical_corridors[i + 1])
650 {
651 // the second address fits the same corridor too
652 if (first_addr_x - vertical_corridors[i] + second_addr_x - vertical_corridors[i] <
653 vertical_corridors[i + 1] - first_addr_x + vertical_corridors[i + 1] - second_addr_x)
654 {
655 // better is left corridor
656 distance += first_addr_x - vertical_corridors[i];
657 distance += abs(first_addr.y_coord - second_addr.y_coord);
658 distance += second_addr_x - vertical_corridors[i];
659 }
660 else
661 {
662 // better is right corridor
663 distance += vertical_corridors[i + 1] - first_addr_x;
664 distance += abs(first_addr.y_coord - second_addr.y_coord);
665 distance += vertical_corridors[i + 1] - second_addr_x;
666 }
667 }
668 else
669 {
670 // the second address doesnt fit the column as the first address is set to - so count the rest as normall
671 // as we make first address be the left one, count distance to the right corridor
672 distance += abs(first_addr_x - second_addr_x);
673 distance += abs(first_addr.y_coord - second_addr.y_coord);
674 }
675 // nothing more to compute - return the result of distance measurement
676 return distance;
677 } // if
678 } // for
679
680 // return just orthogonal distance
681 return orthogonal_distance(first_addr, second_addr);
682
683 return distance;
684 }
685
686 inline int getDistanceInSectorP(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
687 {
688 using namespace secP;
689 //**************************** do the pattern (possible because of the EUCLIDEAN space) ***********************************************
690 // THERE IS STORED THE FINAL DISTANCE
691 float distance = 0;
692
693 // handling special case
694 int distance_tmp = horizontalCorridorSpecialCase_G_V(first_addr, second_addr, first_column_opposite);
695 if (distance_tmp >= 0)
696 return distance_tmp;
697
698 // for the next part of computation order the two addresses from up to down
699 if (first_addr.y_coord > second_addr.y_coord)
700 swap(first_addr, second_addr);
701
702 // decide in which row (divided by the corridor) the first address is
703 for (int corr = 0; corr < (int)horizontal_cooridors.size() - 1; corr++)
704 {
705 // if the y coord of first addr fits the space between two corridors
706 if (horizontal_cooridors[corr] <= first_addr.y_coord && first_addr.y_coord <= horizontal_cooridors[corr + 1])
707 {
708 // if also the second address is in the same corridor
709 if (horizontal_cooridors[corr] <= second_addr.y_coord && second_addr.y_coord <= horizontal_cooridors[corr + 1])
710 {
711 // find the better one of the neighbouring corridors
712 if (abs(2 * horizontal_cooridors[corr] - first_addr.y_coord - second_addr.y_coord) <
713 abs(2 * horizontal_cooridors[corr + 1] - first_addr.y_coord - second_addr.y_coord))
714 {
715 // better is the upper corridor
716 distance += abs(2 * horizontal_cooridors[corr] - first_addr.y_coord - second_addr.y_coord);
717 distance += abs(first_addr.x_coord - second_addr.x_coord);
718 }
719 else
720 {
721 // better is the lower corridor
722 distance += abs(2 * horizontal_cooridors[corr + 1] - first_addr.y_coord - second_addr.y_coord);
723 distance += abs(first_addr.x_coord - second_addr.x_coord);
724 }
725 }
726 else
727 {
728 // the second address is in other row
729 distance += abs(first_addr.y_coord - second_addr.y_coord);
730 distance += abs(first_addr.x_coord - second_addr.x_coord);
731 }
732 }
733 }
734
735 return distance;
736 }
737
738 inline int getDistanceInSectorGP(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
739 {
740 using namespace secGP;
741 //**************************** do the pattern (possible because of the EUCLIDEAN space) ***********************************************
742 // THERE IS STORED THE FINAL DISTANCE
743 float distance = 0;
744
745 // handling special case
746 int distance_tmp = horizontalCorridorSpecialCase_G_V(first_addr, second_addr, first_column_opposite);
747 if (distance_tmp >= 0)
748 return distance_tmp;
749
750 // for the next part of computation order the two addresses from up to down
751 if (first_addr.y_coord > second_addr.y_coord)
752 swap(first_addr, second_addr);
753
754 // decide in which row (divided by the corridor) the first address is
755 for (int corr = 0; corr < (int)horizontal_corridors.size() - 1; corr++)
756 {
757 // if the y coord of first addr fits the space between two corridors
758 if (horizontal_corridors[corr] <= first_addr.y_coord && first_addr.y_coord <= horizontal_corridors[corr + 1])
759 {
760 // if also the second address is in the same corridor
761 if (horizontal_corridors[corr] <= second_addr.y_coord && second_addr.y_coord <= horizontal_corridors[corr + 1])
762 {
763 // find the better one of the neighbouring corridors
764 if (abs(2 * horizontal_corridors[corr] - first_addr.y_coord - second_addr.y_coord) <
765 abs(2 * horizontal_corridors[corr + 1] - first_addr.y_coord - second_addr.y_coord))
766 {
767 // better is the upper corridor
768 distance += abs(2 * horizontal_corridors[corr] - first_addr.y_coord - second_addr.y_coord);
769 distance += abs(first_addr.x_coord - second_addr.x_coord);
770 }
771 else
772 {
773 // better is the lower corridor
774 distance += abs(2 * horizontal_corridors[corr + 1] - first_addr.y_coord - second_addr.y_coord);
775 distance += abs(first_addr.x_coord - second_addr.x_coord);
776 }
777 }
778 else
779 {
780 // the second address is in other row
781 distance += abs(first_addr.y_coord - second_addr.y_coord);
782 distance += abs(first_addr.x_coord - second_addr.x_coord);
783 }
784 }
785 }
786
787 return distance;
788 }
789
790 inline int getDistanceBetweenSectors_G_V(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
791 {
792 //**************************** do the pattern (possible because of the EUCLIDEAN space) ***********************************************
793 // THERE IS STORED THE FINAL DISTANCE
794 float distance = 0;
795 // sort the addresses - first G, second V
796 if (first_addr.section[0] != 'G')
797 swap(first_addr, second_addr);
798
799 // special case - both addresses share the same corridor (one between G and V)
800 if (first_addr.y_coord_original == 0 && second_addr.y_coord_original == 4 /*stands for VEE*/)
801 return euclidean_distance(first_addr, second_addr);
802
803 // for the next part of computation order the two addresses from left to right
804 if (first_addr.x_coord > second_addr.x_coord)
805 swap(first_addr, second_addr);
806
807 // mostly used numbers and variables for secV
808 using namespace secG;
809
810 // stored x coord of both addresses for better readability of the code below
811 auto first_addr_x = first_addr.x_coord;
812 auto second_addr_x = second_addr.x_coord;
813
814 // loop through the corridors from 1, because these are same for both sectors (G&V)
815 for (size_t i = 0; i < vertical_corridors.size() - 1; i++)
816 {
817 // check the first address of being between current two corridors
818 if ((first_addr_x >= vertical_corridors[i] && first_addr_x <= vertical_corridors[i + 1]) ||
819 (first_addr_x < vertical_corridors[i] && i == 0) || /*the corridor is somewhere before the first corridor */
820 (first_addr_x > vertical_corridors[i + 1] && i + 1 == vertical_corridors.size() - 1) /*the corridor is somewhere after the last corridor*/)
821 {
822 // now try to decide whether the second address is in the same column or not
823 if ((second_addr_x >= vertical_corridors[i] && second_addr_x <= vertical_corridors[i + 1]) ||
824 (second_addr_x < vertical_corridors[i] && i == 0) ||
825 (second_addr_x > vertical_corridors[i + 1] && i + 1 == vertical_corridors.size() - 1) /*the corridor is somewhere after the last corridor*/)
826 {
827 // the second address fits the same column too
828 if (((first_addr_x - vertical_corridors[i] + second_addr_x - vertical_corridors[i] <
829 vertical_corridors[i + 1] - first_addr_x + vertical_corridors[i + 1] - second_addr_x) &&
830 i != 0) ||
831 i + 1 == vertical_corridors.size() - 1)
832 {
833 // better is left corridor
834 // or the i+1 vertical corridor is the one most right, so there is no option to use it while passing
835 // from G to V
836 distance += first_addr_x - vertical_corridors[i];
837 distance += abs(first_addr.y_coord - second_addr.y_coord);
838 distance += second_addr_x - vertical_corridors[i];
839 }
840 else
841 {
842 // better is right corridor
843 // or the used vertical corridor is 0 (viz the condition), so there is no option to use
844 // left corridor - so use the right one
845 distance += vertical_corridors[i + 1] - first_addr_x;
846 distance += abs(first_addr.y_coord - second_addr.y_coord);
847 distance += vertical_corridors[i + 1] - second_addr_x;
848 }
849 }
850 else
851 {
852 // the second address doesnt fit the column as the first address is set to - so count at rest as normall
853 // as we make first address be the left one, count distance to the right corridor
854 distance += abs(second_addr_x - first_addr_x);
855 distance += abs(first_addr.y_coord - second_addr.y_coord);
856 }
857 // nothing more to compute - return the result of distance measurement
858 return distance;
859 } // if
860 } // for
861 return distance;
862 }
863
864 inline int getDistanceBetweenSectors_G_P(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
865 {
866 // swap the addresses to fit order G - P
867 if (first_addr.section[0] == 'P')
868 swap(first_addr, second_addr);
869
870 //**************************** do the pattern (possible because of the EUCLIDEAN space) ***********************************************
871 // THERE IS STORED THE FINAL DISTANCE
872 float north_exit_distance = 0, lower_exit_distance = 0;
873 using namespace secG;
874 // distance to the north exit
875 if (first_addr.x_coord > vertical_corridors[4])
876 {
877 north_exit_distance += abs(first_addr.x_coord - vertical_corridors[4]) + abs(vertical_corridors[4] - G_north_exit.x_coord);
878 north_exit_distance += abs(first_addr.y_coord - G_north_exit.y_coord);
879 }
880 else
881 {
882 north_exit_distance += abs(first_addr.x_coord - G_north_exit.x_coord);
883 north_exit_distance += abs(first_addr.y_coord - G_north_exit.y_coord);
884 }
885 // lower exit distance
886 lower_exit_distance += orthogonal_distance(first_addr, secG::G_lower_exit);
887 vector<GRAPH_POINT_T> queue = {secP::P_north_exit, secP::P_middle_exit, secP::P_south_exit};
888 int best_distance_lower = INT32_MAX;
889 for (auto exit : queue)
890 {
891 int tmp = orthogonal_distance(secG::G_lower_exit, exit) + lower_exit_distance;
892 tmp += orthogonal_distance(exit, second_addr);
893 if (tmp < best_distance_lower)
894 best_distance_lower = tmp;
895 }
896
897 int best_distance_north = INT32_MAX;
898 for (auto exit : queue)
899 {
900 int tmp = orthogonal_distance(secG::G_north_exit, exit) + north_exit_distance;
901 tmp += orthogonal_distance(exit, second_addr);
902 if (tmp < best_distance_north)
903 best_distance_north = tmp;
904 }
905
906 return (best_distance_lower < best_distance_north) ? best_distance_lower : best_distance_north;
907 }
908
909 inline int getDistanceBetweenSectors_G_GP(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
910 {
911 int distance = 0;
912
913 // swap the addresses to be in order G -> GP
914 if (first_addr.section.substr(0, 2) == "GP")
915 swap(first_addr, second_addr);
916
917 // compute the distance between G address and the edge between G and GP sector
918 distance += orthogonal_distance(first_addr, secG::G_lower_exit);
919
920 // compute the distance between the edge and the GP address
921 distance += getDistanceInSectorGP(secG::G_lower_exit, second_addr);
922
923 return distance;
924 }
925
926 inline int getDistanceBetweenSectors_V_P(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
927 {
928 return orthogonal_distance(first_addr, second_addr);
929 }
930
931 inline int getDistanceBetweenSectors_V_GP(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
932 {
933 return orthogonal_distance(first_addr, second_addr);
934 }
935
936 inline int getDistanceBetweenSectors_GP_P(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
937 {
938 using namespace secGP;
939 if (first_addr.section[0] == 'P')
940 swap(first_addr, second_addr);
941
942 // loop through all the exists of GP, count all distances and to them and for each of them count distance to
943 // the final address in P sector
944 vector<GRAPH_POINT_T> queue = {secP::P_north_exit, secP::P_middle_exit, secP::P_south_exit};
945 int current_best = INT32_MAX;
946 for (auto exit : GP_exits)
947 {
948 int start_to_exit = getDistanceInSectorGP(first_addr, exit);
949 int tmp_best = INT32_MAX;
950 for (auto entrance : queue)
951 {
952 int entrance_to_final = euclidean_distance(exit, entrance) + orthogonal_distance(entrance, second_addr);
953 if (entrance_to_final < tmp_best)
954 tmp_best = entrance_to_final;
955 }
956 if (start_to_exit + tmp_best < current_best)
957 current_best = start_to_exit + tmp_best;
958 }
959
960 return current_best;
961 }
962 }
963}
964
965#endif
WarehousePickingOpt.h
translated with gcc version 12.2.1
WAddress
class representing the WAddress of product in warehouse
Definition: WarehousePickingOpt.h:181
WAddress::getWarehouseWAddress
SECTOR_ADDR_T getWarehouseWAddress()
Get the real Warehouse WAddress.
Definition: waddress.cpp:42
orthogonal_distance
float orthogonal_distance(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
computation of the distance between two points in euclidean space, meaning right-angle space
Definition: helper.cpp:53
euclidean_distance
float euclidean_distance(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr)
computation of the shortest (air) path between two points in warehouse
Definition: helper.cpp:48
helper.h
translated with gcc version 12.2.1
secGP
definition of sector GP (part of G sector)
Definition: waddress_functions.hpp:149
secG
definition of sector G
Definition: waddress_functions.hpp:75
secP
definition of sector P
Definition: waddress_functions.hpp:108
secV
definition of sector V
Definition: waddress_functions.hpp:29
ver1
namespace with functions usable when addresses are not mapped - addresses stay as they are,...
Definition: waddress_functions.hpp:185
ver1::measuring::getDistanceInSectorG
int getDistanceInSectorG(WAddress first_addr, WAddress second_addr)
Definition: waddress_functions.hpp:219
ver2
namespace with functions for mapping addresses to some global coordinates and counting distances in t...
Definition: waddress_functions.hpp:311
ver2::measuring::horizontalCorridorSpecialCase_G_V
int horizontalCorridorSpecialCase_G_V(SECTOR_ADDR_T first_addr, SECTOR_ADDR_T second_addr, int first_row_opposite)
handling the special case of the addresses in the same horizontal corridor (the same row)
Definition: waddress_functions.hpp:490
GRAPH_POINT_T
Definition: waddress_functions.hpp:23
SECTOR_ADDR_T
this structure stores parsed address in usable form in computation
Definition: WarehousePickingOpt.h:164