首页 前端知识 案例分析<空间规划——第一部分>:Three.js进行仓储、集装箱、仓库空间规划

案例分析<空间规划——第一部分>:Three.js进行仓储、集装箱、仓库空间规划

2025-03-11 15:03:30 前端知识 前端哥 877 746 我要收藏

一、需求描述

为了在一个17米长、2.5米宽、2.5米高的集装箱中最有效地利用空间,需要计算和展示多种规格的圆柱、正方体、梯形和三角形的摆放方式。Python用于计算装载数量和位置,Three.js用于3D可视化展示。

常见的箱体尺寸

类型小型中型大型特大型
纸箱30 cm x 20 cm x 15 cm40 cm x 30 cm x 20 cm60 cm x 40 cm x 40 cm80 cm x 60 cm x 60 cm
塑料箱30 cm x 20 cm x 15 cm40 cm x 30 cm x 25 cm60 cm x 40 cm x 30 cm80 cm x 60 cm x 40 cm

常见的柱状体尺寸

类型小型中型大型
桶状容器高 50 cm,直径 30 cm(约 50 升)高 80 cm,直径 50 cm(约 200 升)高 100 cm,直径 60 cm(约 300 升)
圆柱形包裹高 50 cm,直径 20 cm高 100 cm,直径 30 cm高 200 cm,直径 40 cm

集装箱尺寸

类型内部尺寸 (长 x 宽 x 高)容量
20 英尺集装箱5.9 m x 2.35 m x 2.39 m33.2 立方米
40 英尺集装箱12.03 m x 2.35 m x 2.39 m67.7 立方米
40 英尺高柜集装箱12.03 m x 2.35 m x 2.69 m76.3 立方米
20 英尺冷藏集装箱5.44 m x 2.29 m x 2.26 m28.4 立方米
40 英尺冷藏集装箱11.56 m x 2.29 m x 2.26 m59.1 立方米

托盘尺寸

类型尺寸
标准托盘(欧标)120 cm x 80 cm
标准托盘(中标)110 cm x 110 cm
半托盘80 cm x 60 cm

这些表格列出了物流运输中常用的箱体、柱状体、集装箱和托盘的标准尺寸,以便于装载、运输和堆叠。


二、空间利用方案需求

  • Python端计算

    • 计算各形状的装载数量和位置。
    • 提供API服务,供前端Three.js访问。
  • Three.js端展示

    • 获取Python端计算结果并生成3D形状和位置。
    • 提供交互功能,如旋转、缩放和平移。

客户要求

40 英尺高柜集装箱装载如下物品:

纸箱:小型、中型、大型各153,17,7个
桶状:小型、中型、大型各85,32,29个
圆柱形包裹:小型、中型、大型各189,68,21个

//------------------基础尺寸数据------------------
// 箱体尺寸
const boxSizes = {
    small: {
        cardboard: { length: 0.3, width: 0.2, height: 0.15 },
        plastic: { length: 0.3, width: 0.2, height: 0.15 }
    },
    medium: {
        cardboard: { length: 0.4, width: 0.3, height: 0.2 },
        plastic: { length: 0.4, width: 0.3, height: 0.25 }
    },
    large: {
        cardboard: { length: 0.6, width: 0.4, height: 0.4 },
        plastic: { length: 0.6, width: 0.4, height: 0.3 }
    },
    extraLarge: {
        cardboard: { length: 0.8, width: 0.6, height: 0.6 },
        plastic: { length: 0.8, width: 0.6, height: 0.4 }
    }
};

// 柱状体尺寸
const cylinderSizes = {
    small: { barrelContainer: { height: 0.5, diameter: 0.3 } },
    medium: { barrelContainer: { height: 0.8, diameter: 0.5 } },
    large: { barrelContainer: { height: 1.0, diameter: 0.6 } },
    cylindricalPackage: {
        small: { height: 0.5, diameter: 0.2 },
        medium: { height: 1.0, diameter: 0.3 },
        large: { height: 2.0, diameter: 0.4 }
    }
};

// 集装箱尺寸
const containerSizes = {
    "20ft": { internalDimensions: { length: 5.9, width: 2.35, height: 2.39 }, capacity: 33.2 },
    "40ft": { internalDimensions: { length: 12.03, width: 2.35, height: 2.39 }, capacity: 67.7 },
    "40ftHighCube": { internalDimensions: { length: 12.03, width: 2.35, height: 2.69 }, capacity: 76.3 },
    "20ftRefrigerated": { internalDimensions: { length: 5.44, width: 2.29, height: 2.26 }, capacity: 28.4 },
    "40ftRefrigerated": { internalDimensions: { length: 11.56, width: 2.29, height: 2.26 }, capacity: 59.1 }
};

// 托盘尺寸
const palletSizes = {
    standardEuro: { length: 1.2, width: 0.8 },
    standardUS: { length: 1.2, width: 1.0 },
    halfPallet: { length: 0.8, width: 0.6 }
};


//------------------需求尺寸数据------------------
// 纸箱数量和尺寸
const paper_box = {
    'small': { quantity: 153, size: boxSizes.small },
    'medium': { quantity: 17, size: boxSizes.medium },
    'large': { quantity: 7, size: boxSizes.large }
};


// 桶状容器数量和尺寸
const barrel = {
    'small': { quantity: 85, size: cylinderSizes.small.barrelContainer },
    'medium': { quantity: 32, size: cylinderSizes.medium.barrelContainer },
    'large': { quantity: 29, size: cylinderSizes.large.barrelContainer }
};

// 圆柱形包裹数量和尺寸
const cylinder = {
    'small': { quantity: 189, size: cylinderSizes.cylindricalPackage.small },
    'medium': { quantity: 68, size: cylinderSizes.cylindricalPackage.medium },
    'large': { quantity: 21, size: cylinderSizes.cylindricalPackage.large }
};

// 输出示例
console.log("纸箱数量和尺寸:");
console.log(paper_box);
console.log("\n桶状容器数量和尺寸:");
console.log(barrel);
console.log("\n圆柱形包裹数量和尺寸:");
console.log(cylinder);
console.log("\n箱体尺寸:");
console.log(boxSizes);
console.log("\n柱状体尺寸:");
console.log(cylinderSizes);
console.log("\n集装箱尺寸:");
console.log(containerSizes);
console.log("\n托盘尺寸:");
console.log(palletSizes);

//------------------用python计算上述体积,并选用合适的集装箱车辆------------------
import numpy as np

# 箱体尺寸定义(单位:米)
boxSizes = {
    'small': { 'cardboard': { 'length': 0.3, 'width': 0.2, 'height': 0.15 }, 'plastic': { 'length': 0.3, 'width': 0.2, 'height': 0.15 } },
    'medium': { 'cardboard': { 'length': 0.4, 'width': 0.3, 'height': 0.2 }, 'plastic': { 'length': 0.4, 'width': 0.3, 'height': 0.25 } },
    'large': { 'cardboard': { 'length': 0.6, 'width': 0.4, 'height': 0.4 }, 'plastic': { 'length': 0.6, 'width': 0.4, 'height': 0.3 } }
}

# 桶状容器尺寸定义(单位:米)
cylinderSizes = {
    'small': { 'barrelContainer': { 'height': 0.5, 'diameter': 0.3 } },
    'medium': { 'barrelContainer': { 'height': 0.8, 'diameter': 0.5 } },
    'large': { 'barrelContainer': { 'height': 1.0, 'diameter': 0.6 } },
    'cylindricalPackage': {
        'small': { 'height': 0.5, 'diameter': 0.2 },
        'medium': { 'height': 1.0, 'diameter': 0.3 },
        'large': { 'height': 2.0, 'diameter': 0.4 }
    }
}

# 集装箱尺寸定义(单位:米)
containerSizes = {
    '20ft': { 'internalDimensions': { 'length': 5.9, 'width': 2.35, 'height': 2.39 }, 'capacity': 33.2 },
    '40ft': { 'internalDimensions': { 'length': 12.03, 'width': 2.35, 'height': 2.39 }, 'capacity': 67.7 },
    '40ftHighCube': { 'internalDimensions': { 'length': 12.03, 'width': 2.35, 'height': 2.69 }, 'capacity': 76.3 },
    '20ftRefrigerated': { 'internalDimensions': { 'length': 5.44, 'width': 2.29, 'height': 2.26 }, 'capacity': 28.4 },
    '40ftRefrigerated': { 'internalDimensions': { 'length': 11.56, 'width': 2.29, 'height': 2.26 }, 'capacity': 59.1 }
}

# 物品数量和尺寸定义
paper_box = {
    'small': { 'quantity': 153, 'size': boxSizes['small'] },
    'medium': { 'quantity': 17, 'size': boxSizes['medium'] },
    'large': { 'quantity': 7, 'size': boxSizes['large'] }
}

barrel = {
    'small': { 'quantity': 85, 'size': cylinderSizes['small']['barrelContainer'] },
    'medium': { 'quantity': 32, 'size': cylinderSizes['medium']['barrelContainer'] },
    'large': { 'quantity': 29, 'size': cylinderSizes['large']['barrelContainer'] }
}

cylinder = {
    'small': { 'quantity': 189, 'size': cylinderSizes['cylindricalPackage']['small'] },
    'medium': { 'quantity': 68, 'size': cylinderSizes['cylindricalPackage']['medium'] },
    'large': { 'quantity': 21, 'size': cylinderSizes['cylindricalPackage']['large'] }
}

# 计算每种物品的尺寸列表(考虑翻转)
item_sizes = []
for item_type, items in {'paper_box': paper_box, 'barrel': barrel, 'cylinder': cylinder}.items():
    for size_key, item in items.items():
        quantity = item['quantity']
        size = item['size']
        for _ in range(quantity):
            # 加入所有可能的尺寸及其翻转
            for orientation in [(size['length'], size['width'], size['height']), 
                                (size['width'], size['length'], size['height']),
                                (size['height'], size['length'], size['width']),
                                (size['length'], size['height'], size['width']),
                                (size['width'], size['height'], size['length']),
                                (size['height'], size['width'], size['length'])]:
                item_sizes.append((item_type, orientation[0], orientation[1], orientation[2]))

# 装箱算法示例(考虑翻转)
def pack_items(item_sizes, container_length, container_width, container_height):
    container_volume = container_length * container_width * container_height
    packed_items = []

    for item_type, length, width, height in item_sizes:
        if length <= container_length and width <= container_width and height <= container_height:
            packed_items.append((item_type, length, width, height))
            container_volume -= length * width * height
            container_height -= height
        elif width <= container_length and length <= container_width and height <= container_height:
            packed_items.append((item_type, width, length, height))
            container_volume -= width * length * height
            container_height -= height
        elif height <= container_length and length <= container_width and width <= container_height:
            packed_items.append((item_type, height, length, width))
            container_volume -= height * length * width
            container_height -= width

    return packed_items

# 装箱
packed_items = pack_items(item_sizes, containerSizes['40ftHighCube']['internalDimensions']['length'],
                         containerSizes['40ftHighCube']['internalDimensions']['width'],
                         containerSizes['40ftHighCube']['internalDimensions']['height'])

# 输出装箱结果
for item_type, length, width, height in packed_items:
    print(f"Packed {item_type} (L: {length}, W: {width}, H: {height})")

# 计算剩余空间
remaining_volume = containerSizes['40ftHighCube']['internalDimensions']['length'] * \
                  containerSizes['40ftHighCube']['internalDimensions']['width'] * \
                  containerSizes['40ftHighCube']['internalDimensions']['height']
print(f"Remaining volume in container: {remaining_volume} cubic meters")


 

三、空间利用方案

假设:

  • 优先使用正方体和长方体,因其堆叠效率较高。
  • 考虑每种形状的摆放方式和尺寸,尽量减少空间浪费。

装载方案:

  1. 正方体

    • 优先使用较大尺寸的正方体(例如2.8米和3.0米),因为它们的装载效率高。
    • 利用较小尺寸的正方体填补空余空间。
  2. 圆柱

    • 圆柱适合填补不规则的空间,特别是在较大的箱子之间。
  3. 梯形和三角形

    • 使用它们填补空间,确保集装箱顶部和底部的利用率。

装载数量计算

为了简化,假设每个形状可以合理堆叠在一起,以下是每种形状的最大装载数量:

序号形状尺寸(米)数量(个)
1正方体3.0 x 3.0 x 3.02(2层)
2正方体2.8 x 2.8 x 2.83(2层)
3正方体2.2 x 2.2 x 2.25(2层)
4正方体1.4 x 1.4 x 1.412(2层)
5圆柱2.1 x 1.36
6圆柱1.7 x 2.55
7圆柱0.8 x 1.812
8梯形2.3 x 1.8 x 0.78
9梯形1.5 x 2.9 x 2.14
10三角形2.8 x 1.47
11三角形1.1 x 2.59

这是一种近似的装载数量计算,实际装载时需要具体考虑每个形状的排列方式和空间填充效果。

四、技术方案

  1. Python端:

    • 使用Python进行装载优化运算,计算各形状的摆放数量和位置。
    • 使用Pandas等数据处理库处理和存储形状和位置数据。
    • 使用Flask等框架提供后端服务,供前端Three.js访问。
  2. Three.js端:

    • 使用Three.js创建3D场景,并根据Python传递的数据生成各形状和位置。
    • 使用WebGL渲染3D场景,提供交互功能(如旋转、缩放、平移)。

步骤详解

1. Python端计算与数据处理

安装必要库:

pip install numpy pandas flask

 代码示例:

import numpy as np
import pandas as pd
from flask import Flask, jsonify

# 定义集装箱的尺寸
container_length = 17
container_width = 2.5
container_height = 2.5

# 定义箱子的尺寸
boxes = [
    {'shape': 'cube', 'size': (3.0, 3.0, 3.0)},
    {'shape': 'cube', 'size': (2.8, 2.8, 2.8)},
    {'shape': 'cube', 'size': (2.2, 2.2, 2.2)},
    {'shape': 'cube', 'size': (1.4, 1.4, 1.4)},
    {'shape': 'cylinder', 'size': (2.1, 1.3)},
    {'shape': 'cylinder', 'size': (1.7, 2.5)},
    {'shape': 'cylinder', 'size': (0.8, 1.8)},
    {'shape': 'trapezoid', 'size': (2.3, 1.8, 0.7)},
    {'shape': 'trapezoid', 'size': (1.5, 2.9, 2.1)},
    {'shape': 'triangle', 'size': (2.8, 1.4)},
    {'shape': 'triangle', 'size': (1.1, 2.5)}
]

# 计算每个形状的装载数量(简化版)
def calculate_loads(container_dims, boxes):
    container_volume = container_dims[0] * container_dims[1] * container_dims[2]
    loads = []
    for box in boxes:
        box_volume = np.prod(box['size'])
        max_boxes = container_volume // box_volume
        loads.append({'shape': box['shape'], 'size': box['size'], 'count': int(max_boxes)})
    return loads

loads = calculate_loads((container_length, container_width, container_height), boxes)
loads_df = pd.DataFrame(loads)

app = Flask(__name__)

@app.route('/api/loads')
def get_loads():
    return jsonify(loads_df.to_dict(orient='records'))

if __name__ == '__main__':
    app.run(debug=True)
2. Three.js端展示

安装Three.js: 在HTML文件中引用Three.js库,可以从CDN加载:

<!DOCTYPE html>
<html>
<head>
    <title>3D Container Visualization</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script>
</head>
<body>
    <script>
        // 创建场景、相机和渲染器
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        camera.position.z = 30;

        // 获取数据并创建形状
        axios.get('/api/loads')
            .then(response => {
                const loads = response.data;
                loads.forEach(load => {
                    const count = load.count;
                    const size = load.size;

                    for (let i = 0; i < count; i++) {
                        let geometry;
                        let material = new THREE.MeshBasicMaterial({color: Math.random() * 0xffffff});
                        let mesh;

                        if (load.shape === 'cube') {
                            geometry = new THREE.BoxGeometry(size[0], size[1], size[2]);
                        } else if (load.shape === 'cylinder') {
                            geometry = new THREE.CylinderGeometry(size[1], size[1], size[0], 32);
                        } else if (load.shape === 'trapezoid') {
                            // 自定义几何体(梯形)
                            geometry = new THREE.BoxGeometry(size[0], size[1], size[2]); // 简化为立方体展示
                        } else if (load.shape === 'triangle') {
                            geometry = new THREE.Geometry();
                            geometry.vertices.push(
                                new THREE.Vector3(0, size[1], 0),
                                new THREE.Vector3(-size[0] / 2, 0, 0),
                                new THREE.Vector3(size[0] / 2, 0, 0)
                            );
                            geometry.faces.push(new THREE.Face3(0, 1, 2));
                        }

                        if (geometry) {
                            mesh = new THREE.Mesh(geometry, material);
                            mesh.position.set(
                                Math.random() * 17 - 8.5,
                                Math.random() * 2.5 - 1.25,
                                Math.random() * 2.5 - 1.25
                            );
                            scene.add(mesh);
                        }
                    }
                });

                // 渲染函数
                function animate() {
                    requestAnimationFrame(animate);
                    renderer.render(scene, camera);
                }
                animate();
            })
            .catch(error => {
                console.error('Error fetching loads:', error);
            });
    </script>
</body>
</html>

运行与测试

  1. 运行Flask后端

    python your_flask_script.py
    

  2. 打开HTML文件

    • 将上述HTML代码保存为index.html
    • 在浏览器中打开该文件。

这将启动Flask服务器,计算装载数据并提供API服务,Three.js前端将从API获取装载数据,并在3D场景中进行可视化展示。

转载请注明出处或者链接地址:https://www.qianduange.cn//article/23249.html
标签
评论
发布的文章

面试题之强缓存协商缓存

2025-03-11 15:03:21

【C语言】数组篇

2025-03-11 15:03:19

正则表达式(复习)

2025-03-11 15:03:17

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!