Spaces:
Sleeping
Sleeping
File size: 9,461 Bytes
6a808d5 34e5fc6 72726e0 6a808d5 a23c7e1 72726e0 3f2e2d5 9e93492 3f2e2d5 72726e0 6a808d5 afaddb4 6a808d5 463d47b 72726e0 463d47b 72726e0 6a808d5 72726e0 6a808d5 463d47b 6a808d5 72726e0 6a808d5 72726e0 6a808d5 72726e0 6a808d5 463d47b 6a808d5 72726e0 6a808d5 3dd9d64 463d47b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
import pandas as pd
from itertools import permutations
from fastapi import FastAPI, File, UploadFile, Form, HTTPException, Request, Response
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allows all origins
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.options("/{rest_of_path:path}")
async def preflight_handler(request: Request, rest_of_path: str) -> Response:
return Response(headers={
"Access-Control-Allow-Origin": "*", # Allows all origins
"Access-Control-Allow-Methods": "POST, GET, OPTIONS, PUT, DELETE", # Specify methods allowed
"Access-Control-Allow-Headers": "*", # Allows all headers
})
class Box:
def __init__(self, length, width, height, quantity, box_type):
self.length = length
self.width = width
self.height = height
self.quantity = quantity if quantity > 0 else 1 # Ensure at least 1 box if quantity is not specified
self.type = box_type
def rotated_dimensions(self):
# Return rotations that maximize base area and minimize height
possible_rotations = [
(self.length, self.width, self.height),
(self.length, self.height, self.width),
(self.width, self.length, self.height),
(self.width, self.height, self.length),
(self.height, self.length, self.width),
(self.height, self.width, self.length)
]
# Sort by volume and base area to prioritize the best fit
return sorted(possible_rotations, key=lambda x: (x[0] * x[1], x[2]), reverse=True)
def volume(self):
return self.length * self.width * self.height
class Truck:
def __init__(self, length, width, height):
self.length = length
self.width = width
self.height = height
self.volume = length * width * height
self.placed_boxes = []
self.available_space = [(0, 0, 0, length, width, height)] # (x, y, z, l, w, h)
def add_box(self, box):
best_fit = None
best_fit_space_index = -1
for rotation in box.rotated_dimensions():
for i, space in enumerate(self.available_space):
x, y, z, l, w, h = space
# Check if the box can fit in the current space
if rotation[0] <= l and rotation[1] <= w and rotation[2] <= h:
if not best_fit or (rotation[0] * rotation[1] > best_fit[0] * best_fit[1]):
best_fit = rotation
best_fit_space_index = i
if best_fit:
x, y, z, l, w, h = self.available_space[best_fit_space_index]
box_position = (x, y, z)
# Place the box in the truck
self.placed_boxes.append((best_fit, box_position))
# Update available space after placing the box
self.available_space.pop(best_fit_space_index)
self.update_space(best_fit, box_position, l, w, h)
return box_position
else:
return None
def update_space(self, box, position, l, w, h):
x, y, z = position
bl, bw, bh = box
# Create new spaces based on the placement of the new box
new_spaces = [
(x + bl, y, z, l - bl, w, h), # Space to the right
(x, y + bw, z, bl, w - bw, h), # Space in front
(x, y, z + bh, bl, bw, h - bh), # Space above
]
# Filter out invalid spaces
new_spaces = [space for space in new_spaces if space[3] > 0 and space[4] > 0 and space[5] > 0]
# Add new valid spaces to the available_space list
self.available_space.extend(new_spaces)
# Sort available spaces to prioritize lower and more central spaces for stacking
self.available_space.sort(key=lambda space: (space[2], space[1], space[0]))
def pack_boxes(truck, boxes):
packed_positions = []
# Sort all boxes by volume (largest first)
boxes.sort(key=lambda b: b.volume(), reverse=True)
# Pack all boxes, ensuring practical stacking
for box in boxes:
for _ in range(box.quantity):
position = truck.add_box(box)
if position is None:
break
packed_positions.append((box, position))
return packed_positions
def suggest_truck(boxes):
trucks = {
"TATA ACE": {"length": 7, "width": 4.8, "height": 4.8},
"ASHOK LEYLAND DOST": {"length": 7, "width": 4.8, "height": 4.8},
"MAHINDRA BOLERO PICK UP": {"length": 8, "width": 5, "height": 4.8},
"ASHOK LEYLAND BADA DOST": {"length": 9.5, "width": 5.5, "height": 5},
"TATA 407": {"length": 9, "width": 5.5, "height": 5},
"EICHER 14 FEET": {"length": 14, "width": 6, "height": 6.5},
"EICHER 17 FEET": {"length": 17, "width": 6, "height": 7},
"EICHER 19 FEET": {"length": 19, "width": 7, "height": 7},
"TATA 22 FEET": {"length": 22, "width": 7.5, "height": 7},
"TATA TRUCK (6 TYRE)": {"length": 17.5, "width": 7, "height": 7},
"TAURUS 16 T (10 TYRE)": {"length": 21, "width": 7.2, "height": 7},
"TAURUS 21 T (12 TYRE)": {"length": 24, "width": 7.3, "height": 7},
"TAURUS 25 T (14 TYRE)": {"length": 28, "width": 7.8, "height": 7},
"CONTAINER 20 FT": {"length": 20, "width": 8, "height": 8},
"CONTAINER 32 FT SXL": {"length": 32, "width": 8, "height": 8},
"CONTAINER 32 FT MXL": {"length": 32, "width": 8, "height": 8},
"CONTAINER 32 FT SXL / MXL HQ": {"length": 32, "width": 8, "height": 10},
"20 FEET OPEN ALL SIDE (ODC)": {"length": 20, "width": 8, "height": 8},
"28-32 FEET OPEN-TRAILOR JCB ODC": {"length": 28, "width": 8, "height": 8},
"32 FEET OPEN-TRAILOR ODC": {"length": 32, "width": 8, "height": 8},
"40 FEET OPEN-TRAILOR ODC": {"length": 40, "width": 8, "height": 8},
"SCV": {"length": 5, "width": 12, "height": 6},
"LCV": {"length": 11, "width": 5, "height": 5},
"ICV": {"length": 16, "width": 6.5, "height": 6.5},
"MCV": {"length": 19, "width": 7, "height": 7}
}
# Sort trucks by volume (smallest first)
sorted_trucks = sorted(trucks.items(), key=lambda t: t[1]['length'] * t[1]['width'] * t[1]['height'])
# Try packing the boxes in each truck, return the first one that fits all boxes
for truck_name, dimensions in sorted_trucks:
truck = Truck(dimensions['length'] * 12, dimensions['width'] * 12, dimensions['height'] * 12) # Convert to inches
packed_positions = pack_boxes(truck, boxes)
# Check if all boxes were successfully packed
if len(packed_positions) == sum(box.quantity for box in boxes):
return {"name": truck_name, "dimensions": dimensions}
return None
@app.post("/upload/")
async def upload_file(
file: UploadFile = File(...),
length: float = Form(None), # Make these optional
width: float = Form(None),
height: float = Form(None),
name: str = Form(None),
autoSuggest: bool = Form(False)
):
if not file:
raise HTTPException(status_code=400, detail="No file uploaded")
print("truck name ", name)
ext = file.filename.split('.')[-1].lower()
if ext == 'csv':
data = pd.read_csv(file.file)
elif ext in ['xls', 'xlsx']:
data = pd.read_excel(file.file)
else:
raise HTTPException(status_code=400, detail="Unsupported file format")
# Convert dimensions from CM to inches
data['PieceLength'] = data['PieceLength'] / 2.54
data['PieceBreadth'] = data['PieceBreadth'] / 2.54
data['PieceHeight'] = data['PieceHeight'] / 2.54
# Create Box objects with quantity considered
boxes = [
Box(row['PieceLength'], row['PieceBreadth'], row['PieceHeight'], row.get('Quantity', 1), f"{row['PieceNo']}-{row['Priority']}")
for _, row in data.iterrows()
]
if autoSuggest:
# Suggest a truck that can fit all the boxes
suggested_truck = suggest_truck(boxes)
if suggested_truck:
length = suggested_truck['dimensions']['length']
width = suggested_truck['dimensions']['width']
height = suggested_truck['dimensions']['height']
else:
raise HTTPException(status_code=400, detail="No suitable truck found")
# Convert truck dimensions from feet to inches
truck_length = length * 12 # Convert to inches
truck_width = width * 12 # Convert to inches
truck_height = height * 12 # Convert to inches
truck = Truck(truck_length, truck_width, truck_height)
# Pack the boxes into the truck
packed_positions = pack_boxes(truck, boxes)
box_data = [
{
'length': box.length,
'width': box.width,
'height': box.height,
'type': box.type,
'quantity': box.quantity,
'position': {'x': pos[0], 'y': pos[1], 'z': pos[2]}
}
for box, pos in packed_positions
]
return {
"boxes": box_data,
"truck": {
"name": suggested_truck["name"] if autoSuggest else name,
"dimensions": {
"length": length,
"width": width,
"height": height
}
}
}
|