Do0rMaMu commited on
Commit
6a808d5
1 Parent(s): 6062885

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +157 -0
app.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ from itertools import permutations
3
+ from flask import Flask, jsonify, request
4
+ from flask_cors import CORS
5
+
6
+ app = Flask(__name__)
7
+ CORS(app)
8
+
9
+ class Box:
10
+ def __init__(self, length, width, height, quantity, box_type):
11
+ self.length = length
12
+ self.width = width
13
+ self.height = height
14
+ self.quantity = quantity if quantity > 0 else 1 # Ensure at least 1 box if quantity is not specified
15
+ self.type = box_type
16
+
17
+ def rotated_dimensions(self):
18
+ # Return rotations that maximize base area and minimize height
19
+ possible_rotations = [
20
+ (self.length, self.width, self.height),
21
+ (self.length, self.height, self.width),
22
+ (self.width, self.length, self.height),
23
+ (self.width, self.height, self.length),
24
+ (self.height, self.length, self.width),
25
+ (self.height, self.width, self.length)
26
+ ]
27
+ # Sort by volume and base area to prioritize the best fit
28
+ return sorted(possible_rotations, key=lambda x: (x[0] * x[1], x[2]), reverse=True)
29
+
30
+ def volume(self):
31
+ return self.length * self.width * self.height
32
+
33
+ class Truck:
34
+ def __init__(self, length, width, height):
35
+ self.length = length
36
+ self.width = width
37
+ self.height = height
38
+ self.volume = length * width * height
39
+ self.placed_boxes = []
40
+ self.available_space = [(0, 0, 0, length, width, height)] # (x, y, z, l, w, h)
41
+
42
+ def add_box(self, box):
43
+ best_fit = None
44
+ best_fit_space_index = -1
45
+
46
+ for rotation in box.rotated_dimensions():
47
+ for i, space in enumerate(self.available_space):
48
+ x, y, z, l, w, h = space
49
+
50
+ # Check if the box can fit in the current space
51
+ if rotation[0] <= l and rotation[1] <= w and rotation[2] <= h:
52
+ if not best_fit or (rotation[0] * rotation[1] > best_fit[0] * best_fit[1]):
53
+ best_fit = rotation
54
+ best_fit_space_index = i
55
+
56
+ if best_fit:
57
+ x, y, z, l, w, h = self.available_space[best_fit_space_index]
58
+ box_position = (x, y, z)
59
+
60
+ # Place the box in the truck
61
+ self.placed_boxes.append((best_fit, box_position))
62
+
63
+ # Update available space after placing the box
64
+ self.available_space.pop(best_fit_space_index)
65
+ self.update_space(best_fit, box_position, l, w, h)
66
+ return box_position
67
+ else:
68
+ return None
69
+
70
+ def update_space(self, box, position, l, w, h):
71
+ x, y, z = position
72
+ bl, bw, bh = box
73
+
74
+ # Create new spaces based on the placement of the new box
75
+ new_spaces = [
76
+ (x + bl, y, z, l - bl, w, h), # Space to the right
77
+ (x, y + bw, z, bl, w - bw, h), # Space in front
78
+ (x, y, z + bh, bl, bw, h - bh), # Space above
79
+ ]
80
+
81
+ # Filter out invalid spaces
82
+ new_spaces = [space for space in new_spaces if space[3] > 0 and space[4] > 0 and space[5] > 0]
83
+
84
+ # Add new valid spaces to the available_space list
85
+ self.available_space.extend(new_spaces)
86
+
87
+ # Sort available spaces to prioritize lower and more central spaces for stacking
88
+ self.available_space.sort(key=lambda space: (space[2], space[1], space[0]))
89
+
90
+ def pack_boxes(truck, boxes):
91
+ packed_positions = []
92
+
93
+ # Sort all boxes by volume (largest first)
94
+ boxes.sort(key=lambda b: b.volume(), reverse=True)
95
+
96
+ # Pack all boxes, ensuring practical stacking
97
+ for box in boxes:
98
+ for _ in range(box.quantity):
99
+ position = truck.add_box(box)
100
+ if position is None:
101
+ break
102
+ packed_positions.append((box, position))
103
+
104
+ return packed_positions
105
+
106
+ @app.route('/upload', methods=['POST'])
107
+ def upload_file():
108
+ file = request.files['file']
109
+ if not file:
110
+ return jsonify({"error": "No file uploaded"}), 400
111
+
112
+ ext = file.filename.split('.')[-1].lower()
113
+ if ext == 'csv':
114
+ data = pd.read_csv(file)
115
+ elif ext in ['xls', 'xlsx']:
116
+ data = pd.read_excel(file)
117
+ else:
118
+ return jsonify({"error": "Unsupported file format"}), 400
119
+
120
+ # Convert dimensions from CM to inches
121
+ data['PieceLength'] = data['PieceLength'] / 2.54
122
+ data['PieceBreadth'] = data['PieceBreadth'] / 2.54
123
+ data['PieceHeight'] = data['PieceHeight'] / 2.54
124
+
125
+ # Create Box objects with quantity considered
126
+ boxes = [
127
+ Box(row['PieceLength'], row['PieceBreadth'], row['PieceHeight'], row.get('Quantity', 1), f"{row['PieceNo']}-{row['Priority']}")
128
+ for _, row in data.iterrows()
129
+ ]
130
+
131
+ # Convert truck dimensions from feet to inches
132
+ truck_length = float(request.form['length']) * 12 # Convert to inches
133
+ truck_width = float(request.form['width']) * 12 # Convert to inches
134
+ truck_height = float(request.form['height']) * 12 # Convert to inches
135
+
136
+ truck = Truck(truck_length, truck_width, truck_height)
137
+
138
+ # Pack the boxes into the truck
139
+ packed_positions = pack_boxes(truck, boxes)
140
+
141
+ box_data = [
142
+ {
143
+ 'length': box.length,
144
+ 'width': box.width,
145
+ 'height': box.height,
146
+ 'type': box.type,
147
+ 'quantity': box.quantity,
148
+ 'position': {'x': pos[0], 'y': pos[1], 'z': pos[2]}
149
+ }
150
+ for box, pos in packed_positions
151
+ ]
152
+ print(f"quantity {[box_data[i]['quantity'] for i in range(len(box_data))]}")
153
+
154
+ return jsonify(box_data)
155
+
156
+ if __name__ == '__main__':
157
+ app.run(debug=True)