Die Code zur automatischen Erzeungung der SVG für OFWeiche wurde funitoniert.

This commit is contained in:
2025-07-16 15:52:47 +02:00
parent 489eaac2c5
commit 352f6b89be
98 changed files with 1895 additions and 1152 deletions
@@ -0,0 +1,513 @@
import json
import math
import os
def modify_json_values(json_file):
# Constant definitions
WeichenKoerperWidth = 32.5437
BogenProfileWidth = 42.080
WeichenkProfileWidth = 42.000
WeichenGerade = 360.000
# Read JSON file
with open(json_file, 'r', encoding='utf-8') as f:
data = json.load(f)
process_einzelweiche_items(data, WeichenKoerperWidth, WeichenkProfileWidth, BogenProfileWidth, WeichenGerade)
process_doppelweiche_items(data, BogenProfileWidth, WeichenGerade)
process_deltaweiche_items(data, WeichenkProfileWidth)
process_sternweiche_items(data)
# Save changes without confirmation
with open(json_file, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print("All changes saved automatically!")
def process_einzelweiche_items(data, WeichenKoerperWidth, WeichenkProfileWidth, BogenProfileWidth, WeichenGerade):
# Filter matching items with additional Sivasnr check
filtered_items = [
item for item in data
if (item.get("SivasnrTEF") is None and
item.get("KurvenRichtung") == 1 and
item.get("Schaltungstyp") == "M" and
str(item.get("Sivasnr", "")).isdigit())
]
print(f"Found {len(filtered_items)} matching records with numeric Sivasnr")
# Process each item
for item in filtered_items:
# Calculate related values
if (item["OFWeiche_center_line_width_mm"] is not None and
item["OFWeiche_center_line_height_mm"] is not None):
angle_rad = math.radians(item["KurvenWinkel"])
# Calculate basic values
item["Objekt_width_mm"] = round(WeichenKoerperWidth +
(BogenProfileWidth/2 * math.cos(angle_rad)) +
item["OFWeiche_center_line_width_mm"] +
WeichenkProfileWidth/2, 3)
if item["KurvenWinkel"] == 22.5:
item["Objekt_height_mm"] = round(
item["OFWeiche_center_line_height_mm"], 3)
else:
item["Objekt_height_mm"] = round(
(BogenProfileWidth/2 * math.sin(angle_rad)) +
item["OFWeiche_center_line_height_mm"], 3)
# Calculate CP point coordinates
item["OFWeiche_CP1_x_mm"] = round(
(BogenProfileWidth/2 * math.cos(angle_rad)) +
item["OFWeiche_center_line_width_mm"], 3)
item["OFWeiche_CP1_y_mm"] = round(
item["Objekt_height_mm"] - WeichenGerade, 3)
item["OFWeiche_CP2_x_mm"] = round(item["OFWeiche_CP1_x_mm"], 3)
item["OFWeiche_CP2_y_mm"] = round(item["Objekt_height_mm"], 3)
item["OFWeiche_CP3_x_mm"] = round(
BogenProfileWidth/2 * math.cos(angle_rad), 3)
item["OFWeiche_CP3_y_mm"] = round(
BogenProfileWidth/2 * math.sin(angle_rad), 3)
# Update items with identical ProfilTyp
current_profil = item["ProfilTyp"]
exact_matches = [x for x in data
if x["ProfilTyp"] == current_profil and
x is not item and
x.get("SivasnrTEF") is None]
if exact_matches:
for match in exact_matches:
fields_to_copy = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm",
"OFWeiche_CP1_x_mm",
"OFWeiche_CP1_y_mm",
"OFWeiche_CP2_x_mm",
"OFWeiche_CP2_y_mm",
"OFWeiche_CP3_x_mm",
"OFWeiche_CP3_y_mm"
]
for field in fields_to_copy:
match[field] = item[field]
# Find similar items with Schaltungstyp=P
if "S" in current_profil:
prefix = current_profil.rsplit(" ", 1)[0]
similar_items_p = [x for x in data
if x["ProfilTyp"].startswith(prefix) and
x["ProfilTyp"] != current_profil and
"WEICHE" in x["ProfilTyp"] and
x.get("SivasnrTEF") is None and
x.get("Schaltungstyp") == "P"]
for similar in similar_items_p:
fields_to_copy = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm",
"OFWeiche_CP1_x_mm",
"OFWeiche_CP1_y_mm",
"OFWeiche_CP2_x_mm",
"OFWeiche_CP2_y_mm",
"OFWeiche_CP3_x_mm",
"OFWeiche_CP3_y_mm"
]
for field in fields_to_copy:
similar[field] = item[field]
# Find L→R similar items with KurvenRichtung=2
if "S" in current_profil and "-L-" in current_profil:
r_profil = current_profil.replace("-L-", "-R-")
similar_items_r = [x for x in data
if x["ProfilTyp"] == r_profil and
x.get("SivasnrTEF") is None and
x.get("KurvenRichtung") == 2 and
x.get("Schaltungstyp") == "M"]
for similar in similar_items_r:
# Copy basic values
base_fields = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm"
]
for field in base_fields:
similar[field] = item[field]
# Calculate R-type specific CP points
similar["OFWeiche_CP1_x_mm"] = round(WeichenKoerperWidth+WeichenkProfileWidth/2, 3)
similar["OFWeiche_CP1_y_mm"] = round(item["Objekt_height_mm"] - WeichenGerade, 3)
similar["OFWeiche_CP2_x_mm"] = similar["OFWeiche_CP1_x_mm"]
similar["OFWeiche_CP2_y_mm"] = round(item["Objekt_height_mm"], 3)
similar["OFWeiche_CP3_x_mm"] = round(
similar["OFWeiche_CP1_x_mm"] + item["OFWeiche_center_line_width_mm"], 3)
similar["OFWeiche_CP3_y_mm"] = round(
BogenProfileWidth/2 * math.sin(angle_rad), 3)
# Find P-type counterparts for this R-type item
r_p_profil = r_profil.replace("MIT M", "MIT P")
similar_items_r_p = [x for x in data
if x["ProfilTyp"] == r_p_profil and
x.get("SivasnrTEF") is None and
x.get("Schaltungstyp") == "P"]
for similar_r_p in similar_items_r_p:
fields_to_copy_r_p = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm",
"OFWeiche_CP1_x_mm",
"OFWeiche_CP1_y_mm",
"OFWeiche_CP2_x_mm",
"OFWeiche_CP2_y_mm",
"OFWeiche_CP3_x_mm",
"OFWeiche_CP3_y_mm"
]
for field in fields_to_copy_r_p:
similar_r_p[field] = similar[field]
def process_doppelweiche_items(data, BogenProfileWidth, WeichenGerade):
# Filter Doppelweiche type items with numeric Sivasnr check
filtered_items = [
item for item in data
if (item.get("WeichenTyp") == "Doppelweiche" and
item.get("Schaltungstyp") == "M" and
item.get("SivasnrTEF") is None and
str(item.get("Sivasnr", "")).isdigit())
]
print(f"\nFound {len(filtered_items)} Doppelweiche type records with numeric Sivasnr")
# Process each Doppelweiche item
for item in filtered_items:
# Calculate related values
if (item["OFWeiche_center_line_width_mm"] is not None and
item["OFWeiche_center_line_height_mm"] is not None):
angle_rad = math.radians(item["KurvenWinkel"])
# Calculate basic values (Doppelweiche specific formula)
item["Objekt_width_mm"] = round(
(BogenProfileWidth/2 * math.cos(angle_rad)) +
item["OFWeiche_center_line_width_mm"] +
BogenProfileWidth/2 * math.cos(angle_rad), 3)
item["Objekt_height_mm"] = round(
(BogenProfileWidth/2 * math.sin(angle_rad)) +
item["OFWeiche_center_line_height_mm"], 3)
# Calculate CP point coordinates (Doppelweiche specific formula)
item["OFWeiche_CP1_x_mm"] = round(item["Objekt_width_mm"]/2, 3)
item["OFWeiche_CP1_y_mm"] = round(item["Objekt_height_mm"], 3)
item["OFWeiche_CP2_x_mm"] = round(BogenProfileWidth/2 * math.cos(angle_rad), 3)
item["OFWeiche_CP2_y_mm"] = round(BogenProfileWidth/2 * math.sin(angle_rad), 3)
item["OFWeiche_CP3_x_mm"] = round(BogenProfileWidth/2 * math.cos(angle_rad) + item["OFWeiche_center_line_width_mm"], 3)
item["OFWeiche_CP3_y_mm"] = item["OFWeiche_CP2_y_mm"]
# Update items with identical ProfilTyp
current_profil = item["ProfilTyp"]
exact_matches = [x for x in data
if x["ProfilTyp"] == current_profil and
x is not item and
x.get("SivasnrTEF") is None]
if exact_matches:
for match in exact_matches:
fields_to_copy = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm",
"OFWeiche_CP1_x_mm",
"OFWeiche_CP1_y_mm",
"OFWeiche_CP2_x_mm",
"OFWeiche_CP2_y_mm",
"OFWeiche_CP3_x_mm",
"OFWeiche_CP3_y_mm"
]
for field in fields_to_copy:
match[field] = item[field]
# Find similar items (D-type P-type)
if "S D" in current_profil:
d_p_profil = current_profil.replace("MIT M", "MIT P")
similar_items_d_p = [x for x in data
if x["ProfilTyp"] == d_p_profil and
x.get("SivasnrTEF") is None]
for similar in similar_items_d_p:
fields_to_copy = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm",
"OFWeiche_CP1_x_mm",
"OFWeiche_CP1_y_mm",
"OFWeiche_CP2_x_mm",
"OFWeiche_CP2_y_mm",
"OFWeiche_CP3_x_mm",
"OFWeiche_CP3_y_mm"
]
for field in fields_to_copy:
similar[field] = item[field]
# Find similar items (T-type M-type)
if "S D" in current_profil:
t_m_profil = current_profil.replace("S D", "S T")
similar_items_t_m = [x for x in data
if x["ProfilTyp"] == t_m_profil and
x.get("SivasnrTEF") is None and
x.get("Schaltungstyp") == "M"]
for similar in similar_items_t_m:
if similar["KurvenWinkel"] == 22.5:
# Special handling for KurvenWinkel=22.5
similar["OFWeiche_center_line_width_mm"] = item["OFWeiche_center_line_width_mm"]
similar["OFWeiche_center_line_height_mm"] = WeichenGerade
similar["Objekt_width_mm"] = item["Objekt_width_mm"]
similar["Objekt_height_mm"] = WeichenGerade
similar["OFWeiche_CP1_x_mm"] = item["OFWeiche_CP1_x_mm"]
similar["OFWeiche_CP1_y_mm"] = similar["Objekt_height_mm"]
similar["OFWeiche_CP2_x_mm"] = item["OFWeiche_CP2_x_mm"]
similar["OFWeiche_CP2_y_mm"] = 20
similar["OFWeiche_CP3_x_mm"] = item["OFWeiche_CP3_x_mm"]
similar["OFWeiche_CP3_y_mm"] = 20
else:
# Update basic fields
base_fields = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm",
"OFWeiche_CP1_x_mm",
"OFWeiche_CP1_y_mm",
"OFWeiche_CP2_x_mm",
"OFWeiche_CP2_y_mm",
"OFWeiche_CP3_x_mm",
"OFWeiche_CP3_y_mm"
]
for field in base_fields:
similar[field] = item[field]
# Add CP4 point (T-type specific)
similar["OFWeiche_CP4_x_mm"] = round(similar["Objekt_width_mm"]/2, 3)
similar["OFWeiche_CP4_y_mm"] = round(similar["Objekt_height_mm"] - WeichenGerade, 3)
# Find T-type P-type counterparts
t_p_profil = t_m_profil.replace("MIT M", "MIT P")
similar_items_t_p = [x for x in data
if x["ProfilTyp"] == t_p_profil and
x.get("SivasnrTEF") is None and
x.get("Schaltungstyp") == "P"]
for similar_t_p in similar_items_t_p:
fields_to_copy_t_p = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm",
"OFWeiche_CP1_x_mm",
"OFWeiche_CP1_y_mm",
"OFWeiche_CP2_x_mm",
"OFWeiche_CP2_y_mm",
"OFWeiche_CP3_x_mm",
"OFWeiche_CP3_y_mm",
"OFWeiche_CP4_x_mm",
"OFWeiche_CP4_y_mm"
]
for field in fields_to_copy_t_p:
similar_t_p[field] = similar[field]
def process_deltaweiche_items(data, WeichenkProfileWidth):
# Filter deltaweiche type items
filtered_items = [
item for item in data
if (item.get("WeichenTyp") == "Dreifachweiche" and
item.get("Schaltungstyp") == "M" and
item.get("SivasnrTEF") is None and
str(item.get("Sivasnr", "")).isdigit())
]
print(f"\nFound {len(filtered_items)} deltaweiche type records")
for item in filtered_items:
# Calculate related values
if (item["OFWeiche_center_line_width_mm"] is not None and
item["OFWeiche_center_line_height_mm"] is not None):
# Calculate basic dimensions
item["Objekt_width_mm"] = round(item["OFWeiche_center_line_width_mm"], 3)
item["Objekt_height_mm"] = round(WeichenkProfileWidth/2 + item["OFWeiche_center_line_height_mm"]+32.5437, 3)
# Calculate control points
item["OFWeiche_CP1_x_mm"] = round(item["Objekt_width_mm"]/2, 3)
item["OFWeiche_CP1_y_mm"] = round(item["Objekt_height_mm"], 3)
item["OFWeiche_CP2_x_mm"] = 0
item["OFWeiche_CP2_y_mm"] = round(WeichenkProfileWidth/2+32.5437 , 3)
item["OFWeiche_CP3_x_mm"] = round(item["Objekt_width_mm"], 3)
item["OFWeiche_CP3_y_mm"] = item["OFWeiche_CP2_y_mm"]
# Update items with identical ProfilTyp
current_profil = item["ProfilTyp"]
exact_matches = [x for x in data
if x["ProfilTyp"] == current_profil and
x is not item and
x.get("SivasnrTEF") is None]
if exact_matches:
for match in exact_matches:
fields_to_copy = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm",
"OFWeiche_CP1_x_mm",
"OFWeiche_CP1_y_mm",
"OFWeiche_CP2_x_mm",
"OFWeiche_CP2_y_mm",
"OFWeiche_CP3_x_mm",
"OFWeiche_CP3_y_mm"
]
for field in fields_to_copy:
match[field] = item[field]
# Find similar items (P-type)
if "WEICHE S C DELTA" in item["ProfilTyp"]:
similar_profil = item["ProfilTyp"].replace("KPL. MIT M", "KPL. MIT P")
similar_items = [x for x in data
if x["ProfilTyp"] == similar_profil and
x.get("SivasnrTEF") is None]
for similar in similar_items:
fields_to_copy = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm",
"OFWeiche_CP1_x_mm",
"OFWeiche_CP1_y_mm",
"OFWeiche_CP2_x_mm",
"OFWeiche_CP2_y_mm",
"OFWeiche_CP3_x_mm",
"OFWeiche_CP3_y_mm"
]
for field in fields_to_copy:
similar[field] = item[field]
def process_sternweiche_items(data):
# Filter sternweiche type items
filtered_items = [
item for item in data
if (item.get("WeichenTyp") == "Sternweiche" and
item.get("Schaltungstyp") == "M" and
item.get("SivasnrTEF") is None and
str(item.get("Sivasnr", "")).isdigit())
]
print(f"\nFound {len(filtered_items)} sternweiche type records")
for item in filtered_items:
# Calculate related values
if (item["OFWeiche_center_line_width_mm"] is not None and
item["OFWeiche_center_line_height_mm"] is not None):
# Calculate basic dimensions
item["Objekt_width_mm"] = round(item["OFWeiche_center_line_width_mm"], 3)
item["Objekt_height_mm"] = round(item["OFWeiche_center_line_height_mm"], 3)
# Calculate control points
item["OFWeiche_CP1_x_mm"] = round(item["Objekt_width_mm"]/2, 3)
item["OFWeiche_CP1_y_mm"] = round(item["Objekt_height_mm"], 3)
item["OFWeiche_CP2_x_mm"] = 0
item["OFWeiche_CP2_y_mm"] = round(item["OFWeiche_center_line_height_mm"]/2, 3)
item["OFWeiche_CP3_x_mm"] = round(item["OFWeiche_center_line_width_mm"], 3)
item["OFWeiche_CP3_y_mm"] = item["OFWeiche_CP2_y_mm"]
item["OFWeiche_CP4_x_mm"] = item["OFWeiche_CP1_x_mm"]
item["OFWeiche_CP4_y_mm"] = 0
# Update items with identical ProfilTyp
current_profil = item["ProfilTyp"]
exact_matches = [x for x in data
if x["ProfilTyp"] == current_profil and
x is not item and
x.get("SivasnrTEF") is None]
if exact_matches:
for match in exact_matches:
fields_to_copy = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm",
"OFWeiche_CP1_x_mm",
"OFWeiche_CP1_y_mm",
"OFWeiche_CP2_x_mm",
"OFWeiche_CP2_y_mm",
"OFWeiche_CP3_x_mm",
"OFWeiche_CP3_y_mm",
"OFWeiche_CP4_x_mm",
"OFWeiche_CP4_y_mm"
]
for field in fields_to_copy:
match[field] = item[field]
# Find similar items (P-type)
if "WEICHE S C STERN" in item["ProfilTyp"]:
similar_profil = item["ProfilTyp"].replace("KPL. MIT M", "KPL. MIT P")
similar_items = [x for x in data
if x["ProfilTyp"] == similar_profil and
x.get("SivasnrTEF") is None]
for similar in similar_items:
fields_to_copy = [
"OFWeiche_center_line_width_mm",
"OFWeiche_center_line_height_mm",
"Objekt_width_mm",
"Objekt_height_mm",
"OFWeiche_CP1_x_mm",
"OFWeiche_CP1_y_mm",
"OFWeiche_CP2_x_mm",
"OFWeiche_CP2_y_mm",
"OFWeiche_CP3_x_mm",
"OFWeiche_CP3_y_mm",
"OFWeiche_CP4_x_mm",
"OFWeiche_CP4_y_mm"
]
for field in fields_to_copy:
similar[field] = item[field]
if __name__ == "__main__":
json_path = os.environ.get("JSON_PATH", "JSON")
input_filename = os.path.join(json_path, "omniflo_weichen.json")
modify_json_values(input_filename)
@@ -0,0 +1,153 @@
import json
import os
def process_json_file(input_file, output_file):
# 确保输出目录存在
os.makedirs(os.path.dirname(output_file), exist_ok=True)
# 检查输入文件是否存在
if not os.path.exists(input_file):
raise FileNotFoundError(f"输入文件不存在: {input_file}")
# 加载JSON数据
with open(input_file, 'r', encoding='utf-8') as f:
data = json.load(f)
# Process each item in the JSON data
for item in data:
if item.get("SivasnrTEF") is None:
# Step 1: Calculate pixel dimensions
width_mm = item["Objekt_width_mm"]
height_mm = item["Objekt_height_mm"]
# Calculate initial pixel values
item["Objekt_width_px"] = round(width_mm * 3.7795, 3)
item["Objekt_height_px"] = round(height_mm * 3.7795, 3)
# Determine which dimension is larger and calculate scaling factor
if width_mm >= height_mm:
scale = 1000 / width_mm
item["calculated_SVG_width_px"] = 1000.0
item["calculated_SVG_height_px"] = round(height_mm * scale, 3)
scale_RD_H = round(1000 / item["calculated_SVG_height_px"],6)
scale_RD_W = 1
else:
scale = 1000 / height_mm
item["calculated_SVG_width_px"] = round(width_mm * scale, 3)
item["calculated_SVG_height_px"] = 1000.0
scale_RD_W = round(1000 / item["calculated_SVG_width_px"], 6)
scale_RD_H = 1
item["scale_factor"] = round(scale, 6)
item["scale_factor_RD_Width"] = round(scale_RD_W, 6)
item["scale_factor_RD_Height"] = round(scale_RD_H, 6)
# Process connection points
connection_points = []
# CP1
cp1_x = round(item["OFWeiche_CP1_x_mm"] * scale*scale_RD_W, 3)
cp1_y = round(item["OFWeiche_CP1_y_mm"] * scale*scale_RD_H, 3)
# CP2
cp2_x = round(item["OFWeiche_CP2_x_mm"] * scale*scale_RD_W, 3)
cp2_y = round(item["OFWeiche_CP2_y_mm"] * scale*scale_RD_H, 3)
# CP3
cp3_x = round(item["OFWeiche_CP3_x_mm"] * scale*scale_RD_W, 3)
cp3_y = round(item["OFWeiche_CP3_y_mm"] * scale*scale_RD_H, 3)
# Determine directions based on WeichenTyp
weichen_typ = item["WeichenTyp"]
kurven_winkel = item["KurvenWinkel"]
profil_typ = item["ProfilTyp"]
if weichen_typ == "Einzelweiche":
cp1_dir = 0.0
cp2_dir = 180.0
if "-L-" in profil_typ:
cp3_dir = round(360 - kurven_winkel, 1)
elif "-R-" in profil_typ:
cp3_dir = round(kurven_winkel, 1)
else:
cp3_dir = 0.0 # Default if pattern not found
elif weichen_typ == "Doppelweiche":
cp1_dir = 180.0
cp2_dir = round(360 - kurven_winkel, 1)
cp3_dir = round(kurven_winkel, 1)
elif weichen_typ == "Dreifachweiche":
cp1_dir = 180.0
cp2_dir = round(360 - kurven_winkel, 1)
cp3_dir = round(kurven_winkel, 1)
elif weichen_typ == "Dreiwegeweiche":
cp1_dir = 180.0
cp2_dir = round(360 - kurven_winkel, 1)
cp3_dir = round(kurven_winkel, 1)
# CP4 exists for Dreiwegeweiche
cp4_x = round(item["OFWeiche_CP4_x_mm"] * scale*scale_RD_W, 3)
cp4_y = round(item["OFWeiche_CP4_y_mm"] * scale*scale_RD_H, 3)
cp4_dir = 90.0
connection_points.append({
"id": "cp4",
"x": cp4_x,
"y": cp4_y,
"direction": cp4_dir
})
# Add common connection points
elif weichen_typ == "Sternweiche":
cp1_dir = 180
cp2_dir = round(360 - kurven_winkel, 1)
cp3_dir = round(kurven_winkel, 1)
# CP4 exists for Dreiwegeweiche
cp4_x = round(item["OFWeiche_CP4_x_mm"] * scale*scale_RD_W, 3)
cp4_y = round(item["OFWeiche_CP4_y_mm"] * scale*scale_RD_H, 3)
cp4_dir = 0
connection_points.append({
"id": "cp4",
"x": cp4_x,
"y": cp4_y,
"direction": cp4_dir
})
connection_points.extend([
{
"id": "cp1",
"x": cp1_x,
"y": cp1_y,
"direction": cp1_dir
},
{
"id": "cp2",
"x": cp2_x,
"y": cp2_y,
"direction": cp2_dir
},
{
"id": "cp3",
"x": cp3_x,
"y": cp3_y,
"direction": cp3_dir
}
])
item["connectionPoints"] = connection_points
# Save the processed data
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
if __name__ == "__main__":
json_path = os.environ.get("JSON_PATH", "JSON")
input_filename = os.path.join(json_path, "omniflo_weichen.json")
output_filename = os.path.join(json_path, "omniflo_weichen_output.json")
try:
process_json_file(input_filename, output_filename)
print(f"Process is finished , the File is saved as: {output_filename}")
except Exception as e:
print(f"Errno: {str(e)}")
@@ -0,0 +1,191 @@
''' Script Analysis
This Python script processes JSON and TXT files to update dimensions and connection points in SVG-related data, but only for entries where SivasnrTEF is null. Here's the main logic:
Input Handling:
Reads a JSON file containing reference data
Processes all TXT files in a specified directory
Data Processing:
Creates a mapping between Sivasnr (from filenames) and JSON data (only for entries with SivasnrTEF = null)
For each matching TXT file:
Updates width and height based on JSON data (converting mm to px)
Updates connection points (x, y, direction) from JSON data
Preserves the original file structure while updating specific values
Reporting:
Prints detailed change reports to console
Skips files without matching JSON data or where SivasnrTEF is not null '''
import json
import os
import glob
from datetime import datetime
def process_files(json_file_path, txt_files_dir):
# Create a log file with timestamp
if not os.path.exists(json_file_path):
print(f"Error: JSON file does not exist at {json_file_path}")
exit(1)
if not os.path.exists(txt_files_dir):
print(f"Error: Directory does not exist at {txt_files_dir}")
exit(1)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
log_file_path = os.path.join(txt_files_dir, f"modification_report_OFWeiche_{timestamp}.txt")
# Read JSON file
with open(json_file_path, 'r', encoding='utf-8') as f:
json_data = json.load(f)
# Create Sivasnr to JSON data mapping ONLY for items with SivasnrTEF = null
sivasnr_mapping = {str(item["Sivasnr"]): item for item in json_data if item["SivasnrTEF"] is None}
# Initialize counters
total_files = 0
processed_files = 0
skipped_files = 0
skipped_due_to_tef = 0
# Prepare report content
report_content = []
report_content.append(f"Modification Report - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
report_content.append(f"JSON Reference File: {json_file_path}")
report_content.append(f"TXT Files Directory: {txt_files_dir}")
report_content.append("Processing only files where SivasnrTEF is null")
report_content.append(f"Total JSON entries with SivasnrTEF=null: {len(sivasnr_mapping)}")
report_content.append("="*50 + "\n")
# Process all TXT files
for txt_file_path in glob.glob(os.path.join(txt_files_dir, '*.txt')):
total_files += 1
filename = os.path.basename(txt_file_path)
sivasnr = os.path.splitext(filename)[0]
# Check if corresponding JSON data exists and SivasnrTEF is null
if sivasnr in sivasnr_mapping:
json_item = sivasnr_mapping[sivasnr]
try:
# Read TXT file content
with open(txt_file_path, 'r', encoding='utf-8-sig') as f:
txt_content = json.load(f)
# Record old values
old_width = txt_content["width"]
old_height = txt_content["height"]
old_cps = {cp["id"]: {"x": cp["x"], "y": cp["y"], "direction": cp["direction"]}
for cp in txt_content["connectionPoints"]}
# Update width and height (using direct pixel values now)
new_width = round(json_item["Objekt_width_px"], 3)
new_height = round(json_item["Objekt_height_px"], 3)
txt_content["width"] = new_width
txt_content["height"] = new_height
# Update connectionPoints
cp_changes = []
for cp in txt_content["connectionPoints"]:
cp_id = cp["id"]
# Find corresponding connection point in JSON data
json_cp = next((item for item in json_item["connectionPoints"] if item["id"] == cp_id), None)
if json_cp:
# Record old values
old_x = cp["x"]
old_y = cp["y"]
old_dir = cp["direction"]
# Update values
cp["x"] = json_cp["x"]
cp["y"] = json_cp["y"]
cp["direction"] = json_cp["direction"]
# Record changes
cp_changes.append({
"id": cp_id,
"x": (old_x, cp["x"]),
"y": (old_y, cp["y"]),
"direction": (old_dir, cp["direction"])
})
# Write back to TXT file
with open(txt_file_path, 'w', encoding='utf-8') as f:
json.dump(txt_content, f, indent=2, ensure_ascii=False)
# Print success message to console
print(f"\nSuccessfully processed file: {filename}")
print("[Dimension Changes]")
print(f"width: {old_width}{new_width}")
print(f"height: {old_height}{new_height}")
if cp_changes:
print("\n[Connection Point Changes]")
for change in cp_changes:
print(f"Connection point {change['id']}:")
print(f" x: {change['x'][0]}{change['x'][1]}")
print(f" y: {change['y'][0]}{change['y'][1]}")
print(f" direction: {change['direction'][0]}{change['direction'][1]}")
print("="*50)
# Add to report
file_entry = []
file_entry.append(f"\nProcessing file: {filename}")
file_entry.append("="*50)
file_entry.append("[Dimension Changes]")
file_entry.append(f"width: {old_width}{new_width}")
file_entry.append(f"height: {old_height}{new_height}")
if cp_changes:
file_entry.append("\n[Connection Point Changes]")
for change in cp_changes:
file_entry.append(f"Connection point {change['id']}:")
file_entry.append(f" x: {change['x'][0]}{change['x'][1]}")
file_entry.append(f" y: {change['y'][0]}{change['y'][1]}")
file_entry.append(f" direction: {change['direction'][0]}{change['direction'][1]}")
processed_files += 1
file_entry.append(f"\nFile processed successfully")
file_entry.append("="*50)
report_content.extend(file_entry)
except Exception as e:
report_content.append(f"\nError processing file {filename}: {str(e)}")
else:
skipped_files += 1
# Check if the file was skipped because SivasnrTEF is not null
matching_json_items = [item for item in json_data if str(item["Sivasnr"]) == sivasnr]
if matching_json_items and matching_json_items[0]["SivasnrTEF"] is not None:
skipped_due_to_tef += 1
# Add processing statistics to report
report_content.append("\n" + "="*50)
report_content.append("Processing Statistics:")
report_content.append(f"Total TXT files found: {total_files}")
report_content.append(f"Total JSON records available: {len(json_data)}")
report_content.append(f"JSON records with SivasnrTEF = null: {len(sivasnr_mapping)}")
report_content.append(f"Successfully processed: {processed_files}")
report_content.append(f"Skipped files (no match): {skipped_files - skipped_due_to_tef}")
report_content.append(f"Skipped files (SivasnrTEF not null): {skipped_due_to_tef}")
if len(sivasnr_mapping) > 0:
success_rate = (processed_files / len(sivasnr_mapping)) * 100
report_content.append(f"Success rate: {success_rate:.2f}%")
report_content.append("="*50)
# Print final statistics to console
print("\n" + "="*50)
print("Processing Complete - Summary Statistics:")
print(f"Successfully processed files: {processed_files}")
print(f"Total files found in directory: {total_files}")
if len(sivasnr_mapping) > 0:
print(f"Success rate: {success_rate:.2f}%")
print("="*50)
print(f"Detailed report saved to: {log_file_path}")
# Write the report file
with open(log_file_path, 'w', encoding='utf-8') as f:
f.write("\n".join(report_content))
if __name__ == "__main__":
json_path = os.environ.get("JSON_PATH", "JSON")
json_file_path = os.path.join(json_path, "omniflo_weichen_output.json")
# txt_files_dir = r"C:\Program Files\RuleDesigner\RDConfigurator Fusion\WebApi\Editor2D\SSG\shapes\props"
txt_files_dir= os.environ.get("PROPS_PATH", "props")
process_files(json_file_path, txt_files_dir)
@@ -0,0 +1,425 @@
import os
import re
import xml.etree.ElementTree as ET
from xml.dom import minidom
import argparse
def analyze_and_normalize_path(d, path_type, path_id=""):
"""Strictly normalize path direction and generate detailed report"""
original_d = d
report = []
normalized = []
changed = False
# First check if path contains any arc commands
if 'A' in d or 'a' in d:
report.append(" Path contains arc commands - leaving unchanged")
return original_d, report, False
# Ensure path starts with M command
if not d.strip().startswith('M'):
d = 'M' + d[1:] if d.startswith('L') else 'M ' + d
report.append(" Fix: Added M command at path start")
changed = True
# Parse path commands
commands = []
current_cmd = None
for token in re.split('([A-Za-z])', d):
if not token:
continue
if token in 'MLAZHVCSQTa-z':
current_cmd = token
else:
if current_cmd:
commands.append((current_cmd, token.strip()))
prev_x, prev_y = None, None
for cmd, params in commands:
params = [float(p) for p in re.split('[, ]+', params.strip()) if p]
if cmd == 'M':
if len(params) >= 2:
x, y = params[0], params[1]
normalized.append(f"M {x} {y}")
prev_x, prev_y = x, y
continue
if path_type == 'Line segment' and cmd == 'L':
if len(params) >= 2 and prev_x is not None:
x, y = params[0], params[1]
need_swap = x < prev_x or (x == prev_x and y < prev_y)
if need_swap:
new_segment = [f"M {x} {y}", f"L {prev_x} {prev_y}"]
report.append(f" Need to swap start/end → New path: {' '.join(new_segment)}")
normalized = new_segment
changed = True
else:
normalized.append(f"L {x} {y}")
report.append(" Path direction already correct, no changes made")
prev_x, prev_y = x, y
continue
if path_type == 'Arc' and cmd == 'A':
if len(params) >= 7 and prev_x is not None:
rx, ry, xrot, large, sweep, x, y = params[0], params[1], params[2], int(params[3]), int(params[4]), params[5], params[6]
# Force left-to-right clockwise
need_swap = x < prev_x
new_sweep = 1
if need_swap:
new_segment = [f"M {x} {y}", f"A {rx} {ry} {xrot} {large} {new_sweep} {prev_x} {prev_y}"]
report.append(f" Need to swap start/end → New path: {' '.join(new_segment)}")
normalized = new_segment
changed = True
else:
if sweep != new_sweep:
new_segment = [f"A {rx} {ry} {xrot} {large} {new_sweep} {x} {y}"]
report.append(f" Need to adjust sweep to 1 → New path: {' '.join(new_segment)}")
normalized.extend(new_segment)
changed = True
else:
normalized.append(f"A {rx} {ry} {xrot} {large} {sweep} {x} {y}")
report.append(" Arc direction already correct, no changes made")
prev_x, prev_y = x, y
continue
normalized.append(f"{cmd} {' '.join(map(str, params))}")
new_d = ' '.join(normalized)
report_header = f"[{path_id}-Analysis] Type: {path_type}"
full_report = [report_header, f"Original path: {original_d}"] + report
if changed:
full_report.append(f"Modified path: {new_d}")
else:
full_report.append("Path not modified")
return new_d, '\n'.join(full_report)
def analyze_and_normalize_path(d, path_type, path_id=""):
"""Strictly normalize path direction and generate detailed report"""
original_d = d
report = []
normalized = []
changed = False
# First check if path contains any arc commands
if 'A' in d or 'a' in d:
report_header = f"[{path_id}-Analysis] Type: {path_type} (contains arcs)"
full_report = [report_header,
f"Original path: {original_d}",
" Path contains arc commands - leaving unchanged",
"Path not modified"]
return original_d, '\n'.join(full_report)
# Ensure path starts with M command
if not d.strip().startswith('M'):
d = 'M' + d[1:] if d.startswith('L') else 'M ' + d
report.append(" Fix: Added M command at path start")
changed = True
# Parse path commands
commands = []
current_cmd = None
for token in re.split('([A-Za-z])', d):
if not token:
continue
if token in 'MLAZHVCSQTa-z':
current_cmd = token
else:
if current_cmd:
commands.append((current_cmd, token.strip()))
prev_x, prev_y = None, None
for cmd, params in commands:
params = [float(p) for p in re.split('[, ]+', params.strip()) if p]
if cmd == 'M':
if len(params) >= 2:
x, y = params[0], params[1]
normalized.append(f"M {x} {y}")
prev_x, prev_y = x, y
continue
if path_type == 'Line segment' and cmd == 'L':
if len(params) >= 2 and prev_x is not None:
x, y = params[0], params[1]
need_swap = x < prev_x or (x == prev_x and y < prev_y)
if need_swap:
new_segment = [f"M {x} {y}", f"L {prev_x} {prev_y}"]
report.append(f" Need to swap start/end → New path: {' '.join(new_segment)}")
normalized = new_segment
changed = True
else:
normalized.append(f"L {x} {y}")
report.append(" Path direction already correct, no changes made")
prev_x, prev_y = x, y
continue
normalized.append(f"{cmd} {' '.join(map(str, params))}")
new_d = ' '.join(normalized)
report_header = f"[{path_id}-Analysis] Type: {path_type}"
full_report = [report_header, f"Original path: {original_d}"] + report
if changed:
full_report.append(f"Modified path: {new_d}")
else:
full_report.append("Path not modified")
return new_d, '\n'.join(full_report)
def optimize_svg(input_path, output_path):
"""Process single SVG file with all optimizations"""
try:
# Register namespace
ET.register_namespace('', 'http://www.w3.org/2000/svg')
# Parse SVG file
tree = ET.parse(input_path)
root = tree.getroot()
print(f"\nProcessing file: {os.path.basename(input_path)}")
print("="*60)
# Create parent map
parent_map = {c: p for p in tree.iter() for c in p}
# 1. Remove xlink namespace
for attr in list(root.attrib):
if 'xlink' in attr:
del root.attrib[attr]
# 2. Set standard dimensions
root.set('width', '1e3')
root.set('height', '1e3')
root.set('viewBox', '0 0 1e3 1e3')
# 3. Remove all clipPath definitions and references
defs = root.find('{http://www.w3.org/2000/svg}defs')
if defs is not None:
clip_paths = defs.findall('{http://www.w3.org/2000/svg}clipPath')
for cp in clip_paths:
defs.remove(cp)
if len(defs) == 0:
root.remove(defs)
# 4. Remove clip-path attributes
for elem in tree.iter():
if 'clip-path' in elem.attrib:
del elem.attrib['clip-path']
# 5. Force square line caps
for g in root.findall('.//{http://www.w3.org/2000/svg}g'):
g.set('stroke-linecap', 'square')
# 6. Remove dashed line styles
for elem in tree.iter():
if 'stroke-dasharray' in elem.attrib:
del elem.attrib['stroke-dasharray']
# 7. Completely remove empty groups
removed_groups = True
while removed_groups:
removed_groups = False
for g in root.findall('.//{http://www.w3.org/2000/svg}g'):
is_empty = (
len(g) == 0 and
not (g.text or '').strip() and
not (g.tail or '').strip() and
all(not k.startswith('{') for k in g.attrib))
if is_empty:
parent = parent_map.get(g)
if parent is not None:
parent.remove(g)
removed_groups = True
parent_map = {c: p for p in tree.iter() for c in p}
# 8. Convert polylines to paths
for polyline in root.findall('.//{http://www.w3.org/2000/svg}polyline'):
points = polyline.get('points', '').strip()
if points:
coords = [p for p in re.split(r'[\s,]', points) if p]
path_data = []
for i in range(0, len(coords), 2):
if i == 0:
path_data.append(f"M {coords[i]} {coords[i+1]}")
else:
path_data.append(f"L {coords[i]} {coords[i+1]}")
path = ET.Element('{http://www.w3.org/2000/svg}path')
new_d, analysis_report = analyze_and_normalize_path(
' '.join(path_data),
'Line segment',
"Polyline conversion"
)
path.set('d', new_d)
print(f"\n[Polyline conversion analysis]\n{analysis_report}")
for attr, value in polyline.attrib.items():
if attr not in ('points', 'stroke-dasharray'):
path.set(attr, value)
parent = parent_map.get(polyline)
if parent is not None:
parent.remove(polyline)
parent.append(path)
# 9. Normalize path directions (final step)
group_num = 0
for g in root.findall('.//{http://www.w3.org/2000/svg}g'):
group_num += 1
path_num = 0
group_report = []
for path in g.findall('.//{http://www.w3.org/2000/svg}path'):
path_num += 1
if 'd' not in path.attrib:
continue
# Auto-detect path type
path_type = 'Arc' if 'A' in path.get('d') else 'Line segment'
path_id = f"Group{group_num}-Path{path_num}"
new_d, analysis_report = analyze_and_normalize_path(
path.get('d'),
path_type,
path_id
)
if new_d != path.get('d'):
path.set('d', new_d)
group_report.append(analysis_report)
# Print all path reports for current group
if group_report:
print(f"\n=== Group {group_num} Path Analysis ===")
print('\n\n'.join(group_report))
# 10. Update colors and line width
for elem in root.findall('.//*[@stroke]'):
stroke = elem.get('stroke', '').lower()
if stroke == '#0ff' or stroke == 'rgb(0,255,255)':
elem.set('stroke', '#ffe31b')
elif stroke == '#000' or stroke == 'rgb(255,0,0)'or stroke == 'rgb(0,0,0)':
elem.set('stroke', '#ffe31b')
elem.set('stroke-width', f'{1}px')
# Generate final XML
rough_string = ET.tostring(root, encoding='utf-8', xml_declaration=True)
rough_string = rough_string.replace(b'standalone="no"', b'')
# Format output (remove empty lines)
reparsed = minidom.parseString(rough_string)
pretty_svg = reparsed.toprettyxml(indent=' ', encoding='utf-8')
pretty_svg = b'\n'.join(
line for line in pretty_svg.splitlines()
if line.strip()
).replace(b'<?xml version="1.0" ?>', b'<?xml version="1.0" encoding="utf-8"?>')
with open(output_path, 'wb') as f:
f.write(pretty_svg)
print("\n" + "="*60)
return True
except Exception as e:
print(f"\nProcessing error: {str(e)}")
print("="*60)
return False
def batch_process_svgs(input_dir, output_dir):
if not os.path.exists(output_dir):
os.makedirs(output_dir)
success_count = 0
failure_count = 0
for filename in os.listdir(input_dir):
if os.path.isdir(os.path.join(input_dir, filename)):
continue
if filename.lower().endswith('.svg') or '_new.svg' in filename.lower():
input_path = os.path.join(input_dir, filename)
output_filename = filename.replace('_new.svg', '_optimized.svg')
output_path = os.path.join(output_dir, output_filename)
if optimize_svg(input_path, output_path):
success_count += 1
print(f"✓ Processed successfully: {filename}{output_filename}")
else:
failure_count += 1
print(f"✗ Processing failed: {filename}")
print("\n" + "="*60 + "\n")
print("\nProcessing summary:")
print(f"Successfully processed: {success_count} files")
print(f"Failed to process: {failure_count} files")
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='copies svg files from directory and optimizes them', prog='svg_optimizer')
parser.add_argument('-f', '--file', action='store', help='just optimize this file')
parser.add_argument('-i', '--inputdir', action='store', help='input directory for all svg files which should be rewritten. Mandatory argument')
parser.add_argument('-o', '--outputdir', action='store', help='output directory for all svg files which are writte new')
parser.add_argument('-c', '--console', action='store_true', help='put the result to console')
parser.add_argument( '--bogen', action='store_true', help='just optimize all "bogen"')
parser.add_argument( '--tefbogen', action='store_true', help='just optimize all "tefbogen"')
parser.add_argument( '--weichen', action='store_true', help='just optimize all "weichen"')
parser.add_argument( '--tefweichen', action='store_true', help='just optimize all "tefweichen"')
args = parser.parse_args()
in_dir = None
if args.inputdir:
in_dir = args.inputdir
else:
if args.bogen:
in_dir = os.environ.get('RD_CONF_BOGEN')
elif args.tefbogen:
in_dir = os.environ.get('RD_CONF_TEFBOGEN')
elif args.weichen:
in_dir = os.environ.get('RD_CONF_WEICHEN')
elif args.tefweichen:
in_dir = os.environ.get('RD_CONF_TEFWEICHEN')
out_dir = os.environ.get('RD_CONF_WORK')
if not out_dir:
print("Error: RD_CONF_WORK environment variable must be set as output directory")
exit(1)
# Check if input directory exists
if not os.path.exists(in_dir):
print(f"Error: Input directory does not exist - {in_dir}")
exit(1)
# Ensure output directory exists (create if doesn't exist, ignore if already exists)
os.makedirs(out_dir, exist_ok=True)
# Processing logic
if args.file:
filename = args.file
input_path = os.path.join(in_dir, filename)
if os.path.exists(input_path):
optimize_svg(input_path, out_dir)
else:
print(f"file {filename} does not exist")
if in_dir:
"""Batch process SVG files"""
batch_process_svgs(in_dir, out_dir)
else:
print("Error: No input directory specified")
parser.print_help()
exit(1)
@@ -0,0 +1,247 @@
import os
from lxml import etree
import re
from math import sqrt, isclose
from collections import defaultdict
# Constants
WEICHEN_PROFILE_WIDTH = 42.000
L_R_TARGET_LENGTH = 55.7237
DELTA_TARGET_LENGTH = 53.5437
MATCH_TOLERANCE = 0.1 # Matching tolerance 0.1mm
def process_svg_files(directory):
print(f"🔍 Scanning directory: {directory}")
print("-" * 60)
result_stats = {
'total_files': 0,
'L_R_files': {'with_pairs': [], 'no_pairs': [], 'excess_pairs': []},
'Delta_files': {'with_triples': [], 'no_triples': [], 'excess_triples': []}
}
for filename in os.listdir(directory):
if not filename.endswith('.svg'):
continue
filepath = os.path.join(directory, filename)
result_stats['total_files'] += 1
if '_L_' in filename or '_R_' in filename:
print(f"\n📄 Processing L/R file: {filename}")
process_lr_file(filepath, filename, result_stats)
elif 'DeltaWeiche' in filename:
print(f"\n📄 Processing DeltaWeiche file: {filename}")
process_delta_file(filepath, filename, result_stats)
# Print final statistics
print("\n" + "="*60)
print("📊 Final processing statistics:")
print(f"Total files processed: {result_stats['total_files']}")
print("\nL/R type files results:")
print(f"✅ Files with matching path pairs: {len(result_stats['L_R_files']['with_pairs'])}")
print(f" {result_stats['L_R_files']['with_pairs']}")
print(f"⚠️ Files with no matching paths: {len(result_stats['L_R_files']['no_pairs'])}")
print(f" {result_stats['L_R_files']['no_pairs']}")
print(f"❌ Files with >2 matching paths: {len(result_stats['L_R_files']['excess_pairs'])}")
print(f" {result_stats['L_R_files']['excess_pairs']}")
print("\nDeltaWeiche type files results:")
print(f"✅ Files with matching path triples: {len(result_stats['Delta_files']['with_triples'])}")
print(f" {result_stats['Delta_files']['with_triples']}")
print(f"⚠️ Files with no matching paths: {len(result_stats['Delta_files']['no_triples'])}")
print(f" {result_stats['Delta_files']['no_triples']}")
print(f"❌ Files with ≠3 matching paths: {len(result_stats['Delta_files']['excess_triples'])}")
print(f" {result_stats['Delta_files']['excess_triples']}")
print("\n✨ Processing complete!")
def process_lr_file(filepath, filename, stats):
try:
tree = etree.parse(filepath)
root = tree.getroot()
# Find all straight line paths
straight_lines = find_straight_lines(root)
print(f" 📊 Found {len(straight_lines)} straight paths")
# Print all straight paths
print("\n 🔍 All straight path details:")
for line in straight_lines:
print(f" Path{line['index']}: ({line['p1'][0]:.2f},{line['p1'][1]:.2f})→"
f"({line['p2'][0]:.2f},{line['p2'][1]:.2f}) length={line['length']:.4f}mm")
# Group by length
length_groups = group_lines_by_length(straight_lines)
# Only print groups with exactly 2 paths
print("\n 🔍 Same-length path groups (2 paths):")
perfect_pairs = [group for group in length_groups.values() if len(group) == 2]
for group in perfect_pairs:
print(f" ┌ Length group ({group[0]['length']:.4f}mm, 2 paths)")
for line in group:
print(f" │ Path{line['index']}: ({line['p1'][0]:.2f},{line['p1'][1]:.2f})→"
f"({line['p2'][0]:.2f},{line['p2'][1]:.2f})")
print("" + "" * 40)
if len(perfect_pairs) == 1:
pair = perfect_pairs[0]
original_length = pair[0]['length']
scale_factor = WEICHEN_PROFILE_WIDTH / original_length
print(f"\n 🔄 Scaling calculation (based on length {original_length:.4f}mm):")
print(f" Scale factor: {scale_factor:.4f}")
# Print scaled lengths
print("\n 🔍 Scaled path lengths:")
for line in straight_lines:
scaled_len = line['length'] * scale_factor
print(f" Path{line['index']}: {line['length']:.4f}mm → {scaled_len:.4f}mm")
# Find path matching target length (within tolerance)
target_path = find_target_path(straight_lines, scale_factor, L_R_TARGET_LENGTH)
if target_path:
target_path['element'].set('style', 'stroke:none;fill:none;')
tree.write(filepath, encoding='utf-8', xml_declaration=True)
print(f"\n ✅ Hid path{target_path['index']} matching target length {L_R_TARGET_LENGTH:.4f}mm (±{MATCH_TOLERANCE}mm)")
stats['L_R_files']['with_pairs'].append(filename)
else:
print(f"\n ❌ No path found matching {L_R_TARGET_LENGTH:.4f}mm (±{MATCH_TOLERANCE}mm)")
stats['L_R_files']['no_pairs'].append(filename)
elif len(perfect_pairs) > 1:
print(f"\n ❗ Found multiple same-length path groups: {[len(g) for g in length_groups.values()]}")
stats['L_R_files']['excess_pairs'].append(filename)
else:
print("\n ❌ No same-length path pairs found")
stats['L_R_files']['no_pairs'].append(filename)
except Exception as e:
print(f" ❌ Processing failed: {str(e)}")
def process_delta_file(filepath, filename, stats):
try:
tree = etree.parse(filepath)
root = tree.getroot()
# Find all straight line paths
straight_lines = find_straight_lines(root)
print(f" 📊 Found {len(straight_lines)} straight paths")
# Print all straight paths
print("\n 🔍 All straight path details:")
for line in straight_lines:
print(f" Path{line['index']}: ({line['p1'][0]:.2f},{line['p1'][1]:.2f})→"
f"({line['p2'][0]:.2f},{line['p2'][1]:.2f}) length={line['length']:.4f}mm")
# Group by length
length_groups = group_lines_by_length(straight_lines)
# Only print groups with exactly 3 paths
print("\n 🔍 Same-length path groups (3 paths):")
perfect_triples = [group for group in length_groups.values() if len(group) == 3]
for group in perfect_triples:
print(f" ┌ Length group ({group[0]['length']:.4f}mm, 3 paths)")
for line in group:
print(f" │ Path{line['index']}: ({line['p1'][0]:.2f},{line['p1'][1]:.2f})→"
f"({line['p2'][0]:.2f},{line['p2'][1]:.2f})")
print("" + "" * 40)
if len(perfect_triples) == 1:
triple = perfect_triples[0]
original_length = triple[0]['length']
scale_factor = WEICHEN_PROFILE_WIDTH / original_length
print(f"\n 🔄 Scaling calculation (based on length {original_length:.4f}mm):")
print(f" Scale factor: {scale_factor:.4f}")
# Print scaled lengths
print("\n 🔍 Scaled path lengths:")
for line in straight_lines:
scaled_len = line['length'] * scale_factor
print(f" Path{line['index']}: {line['length']:.4f}mm → {scaled_len:.4f}mm")
# Find all paths matching target length (there might be multiple)
target_paths = [line for line in straight_lines
if abs(line['length'] * scale_factor - DELTA_TARGET_LENGTH) < MATCH_TOLERANCE]
if target_paths:
for target in target_paths:
target['element'].set('style', 'stroke:none;fill:none;')
tree.write(filepath, encoding='utf-8', xml_declaration=True)
print(f"\n ✅ Hid {len(target_paths)} paths matching target length {DELTA_TARGET_LENGTH:.4f}mm (±{MATCH_TOLERANCE}mm):")
for target in target_paths:
print(f" - Path{target['index']}")
stats['Delta_files']['with_triples'].append(filename)
else:
print(f"\n ❌ No path found matching {DELTA_TARGET_LENGTH:.4f}mm (±{MATCH_TOLERANCE}mm)")
stats['Delta_files']['no_triples'].append(filename)
elif len(perfect_triples) > 1:
print(f"\n ❗ Found multiple same-length path groups: {[len(g) for g in length_groups.values()]}")
stats['Delta_files']['excess_triples'].append(filename)
else:
print("\n ❌ No same-length path groups (3 paths) found")
stats['Delta_files']['no_triples'].append(filename)
except Exception as e:
print(f" ❌ Processing failed: {str(e)}")
def find_straight_lines(root):
"""Find all straight line paths"""
lines = []
paths = root.xpath('.//svg:path|.//svg:g//svg:path',
namespaces={'svg': 'http://www.w3.org/2000/svg'})
for i, path in enumerate(paths, 1):
d = path.get('d', '').strip()
if not d:
continue
if is_straight_line(d):
length, (p1, p2) = calculate_line_length(d)
if length > 0:
lines.append({
'index': i,
'element': path,
'length': round(length, 4), # Keep 4 decimal places
'p1': (round(p1[0], 2), round(p1[1], 2)), # Coordinates rounded to 2 decimals
'p2': (round(p2[0], 2), round(p2[1], 2))
})
return lines
def group_lines_by_length(lines):
"""Group straight paths by length"""
groups = defaultdict(list)
for line in lines:
groups[line['length']].append(line)
return groups
def find_target_path(lines, scale_factor, target_length):
"""Find path that matches target length after scaling (within tolerance)"""
for line in lines:
scaled_length = line['length'] * scale_factor
if abs(scaled_length - target_length) < MATCH_TOLERANCE:
return line
return None
def is_straight_line(d):
"""Check if path is strictly a straight line"""
commands = [cmd[0].upper() for cmd in re.findall('([A-Za-z])', d)]
return len(commands) == 2 and commands[0] == 'M' and commands[1] == 'L'
def calculate_line_length(d):
"""Calculate line length and return endpoints"""
points = []
for cmd, params in re.findall('([A-Za-z])([^A-Za-z]*)', d):
if cmd.upper() in ('M', 'L'):
coords = [float(p) for p in re.findall('[-+]?\d*\.\d+|[-+]?\d+', params)]
points.append((coords[0], coords[1]))
if len(points) != 2:
return 0, ((0,0), (0,0))
length = sqrt((points[1][0]-points[0][0])**2 + (points[1][1]-points[0][1])**2)
return round(length, 4), (points[0], points[1]) # Length rounded to 4 decimals
if __name__ == '__main__':
# Set SVG files directory path
# svg_directory = r'C:\Users\y.wang\Documents\SSG-Ruledesigner-Konfigurator\SVGs\Omniflo\work'
svg_directory =os.environ.get('RD_CONF_WORK')
process_svg_files(svg_directory)
@@ -0,0 +1,158 @@
import os
import re
import xml.etree.ElementTree as ET
from typing import Tuple, List
def parse_svg_path(d: str) -> List[Tuple[float, float]]:
"""Extract all coordinates from SVG path data (including curve control points)"""
points = []
commands = re.findall(
r'([MmLlCcQqAaHhVvZz])([^MmLlCcQqAaHhVvZz]*)',
d.strip().replace(',', ' ')
)
current_pos = (0.0, 0.0)
for cmd, args in commands:
args = list(map(float, re.findall(r'[-+]?\d*\.?\d+', args)))
if cmd in ('M', 'm', 'L', 'l'): # Move/line commands
for i in range(0, len(args), 2):
x, y = args[i], args[i+1]
if cmd.islower(): # Relative coordinates
x += current_pos[0]
y += current_pos[1]
points.append((x, y))
current_pos = (x, y)
elif cmd in ('C', 'c'): # Cubic Bezier curves
for i in range(0, len(args), 6):
x1, y1, x2, y2, x, y = args[i:i+6]
if cmd.islower():
x1 += current_pos[0]; y1 += current_pos[1]
x2 += current_pos[0]; y2 += current_pos[1]
x += current_pos[0]; y += current_pos[1]
points.extend([(x1, y1), (x2, y2), (x, y)])
current_pos = (x, y)
elif cmd in ('A', 'a'): # Arc commands (start/end points only)
for i in range(0, len(args), 7):
x, y = args[i+5], args[i+6]
if cmd.islower():
x += current_pos[0]
y += current_pos[1]
points.append((x, y))
current_pos = (x, y)
return points
def calculate_bounding_box(svg_file: str) -> Tuple[float, float, float, float]:
"""Calculate true bounding box of all paths in SVG"""
tree = ET.parse(svg_file)
root = tree.getroot()
all_points = []
for path in root.findall('.//{http://www.w3.org/2000/svg}path'):
d = path.get('d', '')
all_points.extend(parse_svg_path(d))
if not all_points:
return (0, 0, 0, 0)
x_min = min(p[0] for p in all_points)
x_max = max(p[0] for p in all_points)
y_min = min(p[1] for p in all_points)
y_max = max(p[1] for p in all_points)
return (x_min, y_min, x_max, y_max)
def normalize_stroke_widths2(root, scale):
"""Normalize stroke widths to ensure consistent appearance after scaling"""
for elem in root.iter():
if 'stroke-width' in elem.attrib:
# Remove existing stroke-width
del elem.attrib['stroke-width']
# Apply scaled stroke width (e.g., 1px → 1/scale)
elem.set('stroke-width', f'{1/scale:.6f}px')
def apply_non_scaling_stroke(root):
for elem in root.iter():
if 'stroke' in elem.attrib and elem.attrib['stroke'] != 'none':
# set stroke-width=1no unit
elem.set('stroke-width', '1')
# set vector-effect
elem.set('vector-effect', 'non-scaling-stroke')
def scale_svg_file(input_path: str, output_path: str):
"""Scale SVG file with consistent stroke widths"""
print(f"\nProcessing: {os.path.basename(input_path)}")
tree = ET.parse(input_path)
root = tree.getroot()
# Calculate original bounding box
x_min, y_min, x_max, y_max = calculate_bounding_box(input_path)
width = x_max - x_min
height = y_max - y_min
print(f"Original bounding box: ({x_min:.3f}, {y_min:.3f}) to ({x_max:.3f}, {y_max:.3f})")
print(f"Original dimensions: {width:.3f} (w) × {height:.3f} (h)")
# Determine scaling base (larger dimension → 1000px)
if width > height:
scale = 1000.0 / width
new_width = 1000.0
new_height = round(height * scale,3)
print(f"Scaling base: Width (larger dimension)")
else:
scale = 1000.0 / height
new_height = 1000.0
new_width = round(width * scale,3)
print(f"Scaling base: Height (larger dimension)")
print(f"Scale factor: {scale:.6f}")
print(f"New dimensions: {new_width:.3f}px × {new_height:.3f}px")
print(f"ViewBox: 0 0 {new_width:.3f} {new_height:.3f}")
normalize_stroke_widths2(root, scale)
#apply_non_scaling_stroke(root)
#
# Update SVG attributes
root.set('viewBox', f'0 0 {new_width:.3f} {new_height:.3f}')
root.set('width', f'{new_width:.3f}')
root.set('height', f'{new_height:.3f}')
# Apply translation and scaling
for g in root.findall('{http://www.w3.org/2000/svg}g'):
transform = g.get('transform', '')
new_transform = f'translate({-x_min*scale},{-y_min*scale}) scale({scale})'
if transform:
new_transform = f'{transform} {new_transform}'
g.set('transform', new_transform)
# Save modified SVG
tree.write(output_path, encoding='utf-8', xml_declaration=True)
print(f"Finished processing: {os.path.basename(input_path)}")
def batch_process_svg(input_dir: str, output_dir: str):
"""Batch process SVG files in directory (non-recursive)"""
if not os.path.exists(output_dir):
os.makedirs(output_dir)
svg_files = [
f for f in os.listdir(input_dir)
if f.lower().endswith('.svg') and os.path.isfile(os.path.join(input_dir, f))
]
if not svg_files:
print("No SVG files found in the input directory!")
return
print(f"\nFound {len(svg_files)} SVG files to process")
for filename in svg_files:
input_path = os.path.join(input_dir, filename)
output_path = os.path.join(output_dir, filename)
scale_svg_file(input_path, output_path)
print("\nAll files processed successfully!")
if __name__ == '__main__':
input_dir = os.environ.get('RD_CONF_WORK')
output_dir = os.environ.get('RD_CONF_WORK')
batch_process_svg(input_dir, output_dir)
@@ -0,0 +1,160 @@
import re
import os
import xml.etree.ElementTree as ET
from typing import List, Dict, Tuple
def process_svg_file(input_path: str, output_path: str) -> bool:
"""Process SVG file while preserving original dimensions and viewBox"""
try:
# Parse SVG file
tree = ET.parse(input_path)
root = tree.getroot()
# Store original dimensions and viewBox
original_attrs = {
'width': root.attrib.get('width', '100%'),
'height': root.attrib.get('height', '100%'),
'viewBox': root.attrib.get('viewBox', '')
}
# Remove namespace prefixes
for elem in root.iter():
if '}' in elem.tag:
elem.tag = elem.tag.split('}', 1)[1]
for attr in list(elem.attrib):
if '}' in attr:
new_attr = attr.split('}', 1)[1]
elem.attrib[new_attr] = elem.attrib[attr]
del elem.attrib[attr]
# Process all groups with transforms
for g in root.findall('g'):
if 'transform' in g.attrib:
# Parse transform and convert to matrix
transform = g.attrib['transform']
matrix_str = convert_transform_to_matrix(transform)
# Update group attributes
g.attrib['transform'] = matrix_str
g.attrib['stroke'] = '#ffe31b' # Force stroke color
g.attrib['fill'] = 'none'
g.attrib['stroke-linecap'] = 'square'
g.attrib['vector-effect'] = 'non-scaling-stroke'
# Format paths within group
for path in g.findall('path'):
path.attrib['d'] = simplify_path_data(path.attrib.get('d', ''))
path.tail = '\n ' # Maintain consistent indentation
# Set root attributes while preserving original dimensions
root.attrib.update({
'version': '1.1',
'xmlns': 'http://www.w3.org/2000/svg',
'width': original_attrs['width'],
'height': original_attrs['height'],
'viewBox': original_attrs['viewBox'],
'fill-rule': 'evenodd',
'stroke-linecap': 'round',
'stroke-linejoin': 'round',
'space': 'preserve'
})
# Format XML with proper indentation
indent(root)
# Generate XML string
xml_str = ET.tostring(root, encoding='unicode')
xml_str = '<?xml version="1.0" encoding="UTF-8"?>\n' + xml_str
# Clean up formatting
xml_str = re.sub(r'\n\s*\n', '\n', xml_str)
xml_str = re.sub(r'>\s+<', '>\n<', xml_str)
# Write to file
with open(output_path, 'w', encoding='utf-8') as f:
f.write(xml_str)
print(f"Processed: {os.path.basename(input_path)}")
return True
except Exception as e:
print(f"Failed {os.path.basename(input_path)}: {str(e)}")
return False
def convert_transform_to_matrix(transform: str) -> str:
"""Convert transform string to matrix notation with 4 decimal places"""
tx = ty = 0.0
translate_match = re.search(r'translate\(([^,]+),\s*([^)]+)\)', transform)
if translate_match:
tx = float(translate_match.group(1))
ty = float(translate_match.group(2))
scale = 1.0
scale_match = re.search(r'scale\(([^)]+)\)', transform)
if scale_match:
scale = float(scale_match.group(1))
return f"matrix({scale:.4f} 0 0 {scale:.4f} {tx:.2f} {ty:.2f})"
def simplify_path_data(d: str) -> str:
"""Simplify path data while maintaining relative commands"""
d = re.sub(r'\s+', ' ', d.strip())
def format_number(num_str: str) -> str:
try:
num = float(num_str)
if abs(num) < 0.001 and num != 0:
return f"{num:.0e}".replace('e-0', 'e-')
if abs(num - 1000) < 0.1:
return '1e3'
if abs(num - round(num, 3)) < 0.0001:
return f"{round(num, 3):g}"
return num_str
except ValueError:
return num_str
parts = []
for part in re.split(r'([ ,])', d):
if re.match(r'^[-+]?\d*\.?\d+$', part):
parts.append(format_number(part))
else:
parts.append(part)
return ''.join(parts).replace(' ,', ',')
def indent(elem: ET.Element, level: int = 0):
"""Properly indent XML elements"""
indent_str = "\n" + level * " "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = indent_str + " "
if not elem.tail or not elem.tail.strip():
elem.tail = indent_str
for child in elem:
indent(child, level + 1)
if not elem.tail or not elem.tail.strip():
elem.tail = indent_str
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = indent_str
def batch_process_svgs(input_dir: str, output_dir: str):
"""Process all SVG files in a directory"""
if not os.path.exists(output_dir):
os.makedirs(output_dir)
success_count = 0
for filename in sorted(os.listdir(input_dir)):
if filename.lower().endswith('.svg'):
input_path = os.path.join(input_dir, filename)
output_path = os.path.join(output_dir, filename)
if process_svg_file(input_path, output_path):
success_count += 1
print(f"\nCompleted: {success_count} files processed")
if __name__ == '__main__':
input_dir = os.environ.get('RD_CONF_WORK')
output_dir = os.environ.get('RD_CONF_OUTPUT_OFWEICHEN')
# Example usage:
batch_process_svgs(input_dir, output_dir)
@@ -0,0 +1,114 @@
import os
import json
import re
from shutil import copyfile
def process_svg_files(svg_folder, json_file_path):
"""Process SVG files with '_M_' pattern to create '_P_' versions"""
# Load JSON data file
try:
with open(json_file_path, 'r', encoding='utf-8') as f:
json_data = json.load(f)
print("JSON data loaded successfully")
except Exception as e:
print(f"Error loading JSON file: {e}")
return
# Process each SVG file in the directory
for filename in os.listdir(svg_folder):
if not filename.lower().endswith('.svg'):
continue
# Skip files that already contain '_P_' pattern
if '_P_' in filename:
print(f"Skipping already processed file: {filename}")
continue
# Only process files containing '_M_' pattern
if '_M_' not in filename:
print(f"Skipping non-target file (no '_M_' pattern): {filename}")
continue
print(f"\nProcessing target file: {filename}")
# Extract SIVASNR from filename
match = re.search(r'_M_(\d+)\.svg$', filename)
if not match:
print(f"Warning: Could not extract SIVASNR from filename: {filename}")
continue
sivasnr = match.group(1)
print(f"Extracted SIVASNR: {sivasnr}")
# Find matching item in JSON data
matched_item = next((item for item in json_data
if "Sivasnr" in item and str(item["Sivasnr"]) == sivasnr), None)
if not matched_item:
print(f"No matching SIVASNR found in JSON - skipping: {sivasnr}")
continue
profil_typ = matched_item.get("ProfilTyp", "")
if not profil_typ:
print(f"No ProfilTyp field found - skipping: {sivasnr}")
continue
print(f"Found ProfilTyp: {profil_typ}")
# Find similar item (replace M with P)
similar_profil_typ = profil_typ.replace(" MIT M", " MIT P")
print(f"Searching for similar ProfilTyp: {similar_profil_typ}")
similar_item = next((item for item in json_data
if item.get("ProfilTyp", "") == similar_profil_typ), None)
if not similar_item:
print(f"No similar item found - skipping: {similar_profil_typ}")
continue
similar_sivasnr = similar_item.get("Sivasnr")
print(f"Found similar item SIVASNR: {similar_sivasnr}")
# Create new filename
new_filename = filename.replace(f"_M_{sivasnr}", f"_P_{similar_sivasnr}")
new_filepath = os.path.join(svg_folder, new_filename)
print(f"Creating new file: {new_filename}")
try:
# Copy and modify file
copyfile(os.path.join(svg_folder, filename), new_filepath)
# Read and modify SVG content
with open(new_filepath, 'r', encoding='utf-8') as f:
svg_content = f.read()
modified_content = svg_content.replace('stroke="#ffe31b"', 'stroke="#1bff38"')
# Write modified content
with open(new_filepath, 'w', encoding='utf-8') as f:
f.write(modified_content)
# Verify replacement
if '#ffe31b' in modified_content:
print("Warning: Original color still exists in output file")
else:
print("Color replacement successful")
print(f"Successfully created modified version: {new_filename}")
except Exception as e:
print(f"Error processing file: {e}")
# Clean up if file creation failed
if os.path.exists(new_filepath):
os.remove(new_filepath)
if __name__ == "__main__":
# Configure paths (update these with your actual paths)
svg_folder = os.environ.get('RD_CONF_OUTPUT_OFWEICHEN')
json_path = os.environ.get("JSON_PATH", "JSON")
input_filename = os.path.join(json_path, "omniflo_weichen_output.json")
process_svg_files(svg_folder, input_filename)
print("Processing complete")
@@ -0,0 +1,194 @@
import os
import re
import json
from xml.etree import ElementTree as ET
from xml.dom import minidom
def extract_sivasnr(filename):
"""Extract numeric ID from filename"""
match = re.search(r'(\d+)\.svg$', filename)
return match.group(1) if match else None
def should_skip_stroke_width(element_attrib):
"""Check if element should skip stroke-width setting"""
# Check style attribute
if 'style' in element_attrib:
style = element_attrib['style'].lower()
if 'stroke:none' in style and 'fill:none' in style:
return True
# Check separate stroke and fill attributes
stroke = element_attrib.get('stroke', '').lower()
fill = element_attrib.get('fill', '').lower()
return stroke == 'none' and fill == 'none'
def create_xml_structure(svg_root):
"""Create target XML structure preserving all elements"""
# Create base structure
new_root = ET.Element("svg", xmlns="http://www.w3.org/2000/svg")
g_layer = ET.SubElement(new_root, "g", transform="rotate(0)")
# Add inner SVG container
inner_svg = ET.SubElement(g_layer, "svg", {
"viewBox": svg_root.attrib.get("viewBox", "0 0 1000 1000"),
"preserveAspectRatio": "none",
"position": "absolute",
"overflow": "visible"
})
# Transfer all content
for elem in svg_root:
if elem.tag.endswith("}g"):
# Process group with namespace
new_g = ET.SubElement(inner_svg, "g", attrib={
k: v for k, v in elem.attrib.items()
if not k.startswith("xmlns")
})
# Process all elements within group
for child in elem:
child_tag = child.tag.split("}")[-1] # Remove namespace
child_attrib = {}
# Preserve all original attributes (except namespace)
for k, v in child.attrib.items():
if not k.startswith("xmlns"):
child_attrib[k] = v
# Only add stroke-width if not stroke:none;fill:none
if not should_skip_stroke_width(child.attrib):
child_attrib["stroke-width"] = "1px"
# Create element with preserved attributes
ET.SubElement(new_g, child_tag, attrib=child_attrib)
else:
# Process standalone elements (path, circle, etc.)
elem_tag = elem.tag.split("}")[-1] # Remove namespace
elem_attrib = {}
# Preserve all original attributes (except namespace)
for k, v in elem.attrib.items():
if not k.startswith("xmlns"):
elem_attrib[k] = v
# Only add stroke-width if not stroke:none;fill:none
if not should_skip_stroke_width(elem.attrib):
elem_attrib["stroke-width"] = "1px"
ET.SubElement(inner_svg, elem_tag, attrib=elem_attrib)
return new_root
def format_xml(element):
"""Generate formatted XML string"""
# Generate XML with declaration
xml_str = ET.tostring(element, encoding="UTF-8", xml_declaration=True)
# Pretty format with 2-space indent
dom = minidom.parseString(xml_str)
pretty_xml = dom.toprettyxml(indent=" ", encoding="UTF-8").decode("UTF-8")
# Remove extra empty lines (preserve structure)
lines = []
for line in pretty_xml.split("\n"):
if line.strip() or line.lstrip().startswith("</"):
lines.append(line)
return "\n".join(lines)
def convert_svg_to_xml(svg_path, output_dir):
"""Convert SVG to target XML format"""
sivasnr = extract_sivasnr(os.path.basename(svg_path))
if not sivasnr:
raise ValueError(f"Invalid filename format: {os.path.basename(svg_path)}")
# Parse original SVG
try:
tree = ET.parse(svg_path)
svg_root = tree.getroot()
except Exception as e:
raise ValueError(f"SVG parsing error: {str(e)}")
# Build new structure
new_xml = create_xml_structure(svg_root)
formatted_xml = format_xml(new_xml)
# Ensure output directory exists
os.makedirs(output_dir, exist_ok=True)
output_path = os.path.join(output_dir, f"{sivasnr}.xml")
# Write file (UTF-8 encoding)
with open(output_path, "w", encoding="UTF-8") as f:
f.write(formatted_xml)
return f"SSG/shapes/svg/{sivasnr}.xml"
def update_txt_file(txt_path, xml_rel_path):
"""Update path in TXT file"""
try:
with open(txt_path, "r", encoding="UTF-8") as f:
data = json.load(f)
if "srcSVG" not in data:
raise ValueError("Missing srcSVG field")
data["srcSVG"] = xml_rel_path
with open(txt_path, "w", encoding="UTF-8") as f:
json.dump(data, f, indent=4, ensure_ascii=False)
return True
except Exception as e:
print(f"Update failed {os.path.basename(txt_path)}: {str(e)}")
return False
def process_files(svg_dir, txt_dir, output_dir):
"""Batch process files"""
if not all(map(os.path.exists, [svg_dir, txt_dir])):
raise FileNotFoundError("Input directory not found")
results = {"success": 0, "failed": 0}
for svg_file in os.listdir(svg_dir):
if not svg_file.endswith(".svg"):
continue
svg_path = os.path.join(svg_dir, svg_file)
sivasnr = extract_sivasnr(svg_file)
if not sivasnr:
print(f"Skipping invalid file: {svg_file}")
results["failed"] += 1
continue
try:
# Convert file
xml_rel_path = convert_svg_to_xml(svg_path, output_dir)
# Update TXT
txt_path = os.path.join(txt_dir, f"{sivasnr}.txt")
if not os.path.exists(txt_path):
raise FileNotFoundError(f"Corresponding TXT file not found: {sivasnr}.txt")
if update_txt_file(txt_path, xml_rel_path):
print(f"Success: {svg_file}{sivasnr}.xml")
results["success"] += 1
else:
results["failed"] += 1
except Exception as e:
print(f"Processing failed {svg_file}: {str(e)}")
results["failed"] += 1
# Output report
print(f"\nProcessing complete: {results['success']} succeeded, {results['failed']} failed")
if __name__ == "__main__":
# Configuration - modify these paths as needed
SVG_INPUT_FOLDER = os.environ.get('RD_CONF_OUTPUT_OFWEICHEN') # Folder containing SVG files
SVG_OUTPUT_FOLDER = os.environ.get("SVG_PATH","svg")
PRORPS_FOLDER = os.environ.get("PROPS_PATH", "props") # Folder containing txt files
# Start processing
process_files(SVG_INPUT_FOLDER, PRORPS_FOLDER, SVG_OUTPUT_FOLDER)
print("\nProcessing complete.")
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff