327 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import os
class SceneBasicConverter:
def save_bin_locations_list(self):
"""
如果smap文件中有binLocationsList则单独保存为converted/binLocationsList.json。
"""
if hasattr(self, 'map_data') and 'binLocationsList' in self.map_data:
self.ensure_converted_dir()
filename = f"{self.converted_dir}/binLocationsList.json"
with open(filename, 'w', encoding='utf-8') as f:
json.dump({'binLocationsList': self.map_data['binLocationsList']}, f, indent=2, ensure_ascii=False)
print(f"已单独保存 binLocationsList 到: {filename}")
def __init__(self, scene_id, setting, ratio):
self.scene_data = {}
self.converted_dir = "converted"
self.scene_data['id'] = scene_id
self.scene_data['setting'] = setting
self.scene_data['ratio'] = ratio
def ensure_converted_dir(self):
if not os.path.exists(self.converted_dir):
os.makedirs(self.converted_dir)
print(f"创建转换结果目录: {self.converted_dir}")
def save_single_key_json(self, key_name, key_data):
self.ensure_converted_dir()
filename = f"{self.converted_dir}/{key_name}.json"
single_key_data = {key_name: key_data}
with open(filename, 'w', encoding='utf-8') as f:
json.dump(single_key_data, f, indent=2, ensure_ascii=False)
print(f"已保存 {key_name} 的独立JSON文件到: {filename}")
def load_source_files(self, smap_file, scene_file):
self.smap_file = smap_file
self.scene_file = scene_file
if os.path.exists(smap_file):
with open(smap_file, 'r', encoding='utf-8') as f:
self.map_data = json.load(f)
else:
print(f"警告: 地图文件 {smap_file} 不存在")
self.map_data = {}
if os.path.exists(scene_file):
with open(scene_file, 'r', encoding='utf-8') as f:
self.scene_source = json.load(f)
else:
print(f"警告: 场景文件 {scene_file} 不存在")
self.scene_source = {}
def extract_basic_info(self):
if 'header' in self.map_data:
header = self.map_data['header']
self.scene_data['name'] = header.get('mapName', '')
min_pos = header.get('minPos', {'x': 0, 'y': 0})
max_pos = header.get('maxPos', {'x': 0, 'y': 0})
width = max_pos['x'] - min_pos['x']
height = max_pos['y'] - min_pos['y']
self.scene_data['width'] = abs(width)
self.scene_data['height'] = abs(height)
else:
raise ValueError("无法计算地图尺寸map_data中缺少header信息")
basic_info_data = {
'id': self.scene_data['id'],
'name': self.scene_data['name'],
'width': self.scene_data['width'],
'height': self.scene_data['height'],
'setting': self.scene_data['setting'],
'ratio': self.scene_data['ratio']
}
self.save_single_key_json('basic_info', basic_info_data)
def extract_coordinate_system(self):
if self.scene_source:
self.scene_data['scale'] = self.scene_source.get('scale', 0.6599999999999997)
self.scene_data['origin'] = self.scene_source.get('origin', {
'x': -3679.5080777864587,
'y': -3925.231448210223
})
else:
self.scene_data['scale'] = 0.6599999999999997
self.scene_data['origin'] = {
'x': -3679.5080777864587,
'y': -3925.231448210223
}
coordinate_data = {
'scale': self.scene_data['scale'],
'origin': self.scene_data['origin']
}
self.save_single_key_json('coordinate_system', coordinate_data)
def extract_robots(self):
# 无论源数据如何robots 字段都输出空列表
self.scene_data['robots'] = []
self.save_single_key_json('robots', self.scene_data['robots'])
def extract_points(self):
if 'advancedPointList' in self.map_data:
self.scene_data['points'] = self.extract_advanced_points()
elif self.scene_source and 'points' in self.scene_source:
self.scene_data['points'] = self.scene_source['points']
else:
self.scene_data['points'] = []
self.save_single_key_json('points', self.scene_data['points'])
def extract_advanced_points(self):
points = []
if 'advancedPointList' in self.map_data:
advanced_points = self.map_data['advancedPointList']
for i, point in enumerate(advanced_points):
point_id = str(10000001 + i)
name = point.get('instanceName', f'Point{i+1}')
pos = point.get('pos', {})
x = pos.get('x', 0)
y = pos.get('y', 0)
className = point.get('className', 'ActionPoint')
point_type = self.get_point_type_by_class(className)
properties = []
if 'property' in point:
for prop in point['property']:
property_obj = {
"key": prop.get('key', ''),
"type": prop.get('type', ''),
"value": prop.get('value', ''),
"boolValue": prop.get('boolValue', False)
}
prop_type = prop.get('type', '')
if prop_type == 'bool':
property_obj["boolValue"] = prop.get('boolValue', False)
elif prop_type == 'string':
property_obj["stringValue"] = prop.get('stringValue', '')
elif prop_type == 'int32':
property_obj["int32Value"] = prop.get('int32Value', 0)
elif prop_type == 'float':
property_obj["floatValue"] = prop.get('floatValue', 0.0)
properties.append(property_obj)
point_obj = {
"id": point_id,
"name": name,
"x": x,
"y": y,
"type": point_type,
"config": {},
"properties": properties,
"associatedStorageLocations": [],
"robots": [],
"enabled": 1
}
points.append(point_obj)
return points
def get_point_type_by_class(self, className):
type_mapping = {
'LocationMark': 1,
'ParkPoint': 14,
'SwitchMap': 5,
'HomeRegion': 2,
'ActionPoint': 15,
'TransferLocation': 14,
'WorkingLocation': 16,
'ChargePoint': 13
}
if className not in type_mapping:
if className.startswith('LM'):
return 1
elif className.startswith('PP'):
return 14
elif className.startswith('SW'):
return 5
elif className.startswith('HR'):
return 2
elif className.startswith('AP'):
return 15
elif className.startswith('TL'):
return 14
elif className.startswith('WL'):
return 16
elif className.startswith('CP'):
return 13
else:
return 1
return type_mapping.get(className, 15)
def extract_routes(self):
self.scene_data['routes'] = self.extract_advanced_curves()
self.save_single_key_json('routes', self.scene_data['routes'])
def extract_advanced_curves(self):
routes = []
name_to_id_map = {}
points_file = f"{self.converted_dir}/points.json"
if os.path.exists(points_file):
try:
with open(points_file, 'r', encoding='utf-8') as f:
points_data = json.load(f)
if 'points' in points_data:
for point in points_data['points']:
name_to_id_map[point['name']] = point['id']
except Exception as e:
print(f"警告: 无法读取 {points_file} 文件: {e}")
else:
print(f"警告: 站点文件 {points_file} 不存在,无法建立映射关系")
curve_data = self.map_data
if 'advancedCurveList' in curve_data:
advanced_curves = curve_data['advancedCurveList']
print(f"找到 {len(advanced_curves)} 条路径数据")
# 路径类型映射表优先用className判断
path_type_map = {
"StraightPath": "line",
"BezierPath": "BezierPath",
"ArcPath": "bezier2",
"DegenerateBezier": "bezier3",
"NURBS6": "NURBS6"
}
for i, curve in enumerate(advanced_curves):
route_id = str(100000 + i)
desc = curve.get('instanceName', f'Route{i+1}')
start_pos = curve.get('startPos', {})
end_pos = curve.get('endPos', {})
from_instance_name = start_pos.get('instanceName', '')
to_instance_name = end_pos.get('instanceName', '')
from_point = name_to_id_map.get(from_instance_name, from_instance_name)
to_point = name_to_id_map.get(to_instance_name, to_instance_name)
if from_instance_name not in name_to_id_map:
print(f"警告: 找不到起点 '{from_instance_name}' 的映射")
if to_instance_name not in name_to_id_map:
print(f"警告: 找不到终点 '{to_instance_name}' 的映射")
control_pos1 = curve.get('controlPos1', {})
control_pos2 = curve.get('controlPos2', {})
control_pos3 = curve.get('controlPos3', {})
control_pos4 = curve.get('controlPos4', {})
properties = []
if 'property' in curve:
for prop in curve['property']:
properties.append({
"key": prop.get('key', ''),
"type": prop.get('type', ''),
"value": prop.get('value', ''),
"int32Value": prop.get('int32Value', 0),
"boolValue": prop.get('boolValue', False)
})
# 优先用className判断路径类型
class_name = curve.get('className', '')
curve_type = curve.get('type', '')
mapped_type = path_type_map.get(class_name, path_type_map.get(curve_type, "bezier3"))
route_obj = {
"id": route_id,
"desc": desc,
"from": from_point,
"to": to_point,
"type": mapped_type,
"pass": 0,
"config": {},
"properties": properties
}
# 按类型添加controlPos字段直线不添加c1/c2
if mapped_type == "BezierPath" or mapped_type == "bezier3":
route_obj["c1"] = {"x": control_pos1.get('x', 0), "y": control_pos1.get('y', 0)}
route_obj["c2"] = {"x": control_pos2.get('x', 0), "y": control_pos2.get('y', 0)}
elif mapped_type == "bezier2":
route_obj["c1"] = {"x": control_pos1.get('x', 0), "y": control_pos1.get('y', 0)}
elif mapped_type == "NURBS6":
route_obj["c1"] = {"x": control_pos1.get('x', 0), "y": control_pos1.get('y', 0), "z": control_pos1.get('z', 0)}
route_obj["c2"] = {"x": control_pos2.get('x', 0), "y": control_pos2.get('y', 0), "z": control_pos2.get('z', 0)}
route_obj["c3"] = {"x": control_pos3.get('x', 0), "y": control_pos3.get('y', 0), "z": control_pos3.get('z', 0)}
route_obj["c4"] = {"x": control_pos4.get('x', 0), "y": control_pos4.get('y', 0), "z": control_pos4.get('z', 0)}
# 直线line不添加c1/c2等字段
routes.append(route_obj)
print(f"成功生成 {len(routes)} 条路径")
else:
print("警告: 未找到advancedCurveList数据")
return routes
def extract_bin_locations(self):
"""
优先从converted/binLocationsList.json读取binLocationsList否则从map_data中读取并保存。
"""
import os
filename = f"{self.converted_dir}/binLocationsList.json"
bin_locations = None
if os.path.exists(filename):
with open(filename, 'r', encoding='utf-8') as f:
data = json.load(f)
bin_locations = data.get('binLocationsList', [])
else:
bin_locations = self.map_data.get('binLocationsList', [])
self.scene_data['binLocationsList'] = bin_locations
self.save_single_key_json('binLocationsList', self.scene_data['binLocationsList'])
def convert_basic(self, smap_file, scene_file, output_file="converted_scene.scene"):
print(f"开始基本信息转换...")
print(f"源地图文件: {smap_file}")
print(f"源场景文件: {scene_file}")
print(f"输出文件: {output_file}")
print("-" * 50)
self.load_source_files(smap_file, scene_file)
self.save_bin_locations_list()
self.extract_basic_info()
self.extract_coordinate_system()
self.extract_robots()
self.extract_points()
self.extract_routes()
self.extract_bin_locations()
# 获取所有一级key
all_keys = [
'id', 'setting', 'ratio', 'name', 'width', 'height', 'scale', 'origin',
'robotGroups', 'robots', 'points', 'routes', 'areas', 'blocks', 'binLocationsList'
]
# 补全缺失的一级key值为空空列表、空字典或空字符串
for key in all_keys:
if key not in self.scene_data:
if key in ['robotGroups', 'robots', 'points', 'routes', 'areas', 'binLocationsList']:
self.scene_data[key] = []
elif key in ['origin', 'scale']:
self.scene_data[key] = {} if key == 'origin' else 0
elif key in ['blocks']:
self.scene_data[key] = ""
else:
self.scene_data[key] = ""
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(self.scene_data, f, indent=2, ensure_ascii=False)
print(f"基本信息转换完成!结果已保存到 {output_file}")
return self.scene_data