alle Weiche in 2D mit M und mit P ohne TEF sind korrigiert und in 2D Wizard eingepflegt.
This commit is contained in:
@@ -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 = r'C:\Users\y.wang\Documents\SSG-Ruledesigner-Konfigurator\SVGs\Omniflo\Weichen'
|
||||
output_dir = r'C:\Users\y.wang\Documents\SSG-Ruledesigner-Konfigurator\SVGs\Omniflo\Weichen\outputdir'
|
||||
# Example usage:
|
||||
batch_process_svgs(input_dir, output_dir)
|
||||
Reference in New Issue
Block a user