die TEFBOGEN sind korrigiert.

This commit is contained in:
2025-09-23 10:26:59 +02:00
parent ea678d7a23
commit 62e46562fc
89 changed files with 2930 additions and 2038 deletions
@@ -4,7 +4,7 @@ import os
import re
import xml.etree.ElementTree as ET
from xml.dom import minidom
import argparse
import shutil
def analyze_and_normalize_path(d, path_type, path_id=""):
"""Strictly normalize path direction and generate detailed report"""
@@ -365,6 +365,18 @@ def batch_process_svgs(input_dir, output_dir):
print("\nProcessing summary:")
print(f"Successfully processed: {success_count} files")
print(f"Failed to process: {failure_count} files")
def clear_output_dir(path: str):
os.makedirs(path, exist_ok=True)
for filename in os.listdir(path):
file_path = os.path.join(path, filename)
try:
if os.path.isdir(file_path):
shutil.rmtree(file_path) # 删除目录
elif os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path) # 删除文件或符号链接
except Exception as e:
print(f"Failed to delete {file_path}. Reason: {e}")
if __name__ == '__main__':
input_dir = os.environ.get('RD_CONF_OFBOGEN')
@@ -377,7 +389,12 @@ if __name__ == '__main__':
if not os.path.exists(input_dir):
print(f"Error: Input directory '{input_dir}' does not exist")
exit(1)
# 确保输出目录存在
os.makedirs(output_dir, exist_ok=True)
# 清空 output_dir
clear_output_dir(output_dir)
print(f"Starting SVG file processing, working directory: {input_dir}")
print("=" * 50)
@@ -1,247 +0,0 @@
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)
@@ -1,8 +1,67 @@
import os
import re
import xml.etree.ElementTree as ET
from typing import Tuple, List
from typing import Tuple, List,Optional
import math
def arc_to_points(x0, y0, rx, ry, phi, large_arc, sweep, x1, y1, steps=100):
"""
将SVG弧命令近似为一系列点
用公式计算中心和角度范围,然后采样,得到边界安全点
"""
phi = math.radians(phi)
dx2 = (x0 - x1) / 2.0
dy2 = (y0 - y1) / 2.0
cos_phi = math.cos(phi)
sin_phi = math.sin(phi)
# Step 1: Transform to ellipse coordinate system
x_ = cos_phi * dx2 + sin_phi * dy2
y_ = -sin_phi * dx2 + cos_phi * dy2
# Step 2: Correct radii
rx = abs(rx)
ry = abs(ry)
lam = (x_**2)/(rx**2) + (y_**2)/(ry**2)
if lam > 1:
rx *= math.sqrt(lam)
ry *= math.sqrt(lam)
# Step 3: Compute center
sign = 1 if large_arc != sweep else -1
coef = sign * math.sqrt(
max(0, ((rx**2 * ry**2) - (rx**2 * y_**2) - (ry**2 * x_**2)) /
((rx**2 * y_**2) + (ry**2 * x_**2)))
)
cx_ = coef * (rx * y_) / ry
cy_ = coef * (-ry * x_) / rx
cx = cos_phi * cx_ - sin_phi * cy_ + (x0 + x1)/2
cy = sin_phi * cx_ + cos_phi * cy_ + (y0 + y1)/2
# Step 4: Compute angles
def angle(u, v):
dot = u[0]*v[0] + u[1]*v[1]
det = u[0]*v[1] - u[1]*v[0]
return math.atan2(det, dot)
u = ((x_ - cx_) / rx, (y_ - cy_) / ry)
v = ((-x_ - cx_) / rx, (-y_ - cy_) / ry)
theta1 = angle((1,0), u)
delta_theta = angle(u, v)
if not sweep and delta_theta > 0:
delta_theta -= 2*math.pi
elif sweep and delta_theta < 0:
delta_theta += 2*math.pi
# Step 5: Sample points along the arc
points = []
for i in range(steps+1):
t = theta1 + delta_theta * i/steps
x = cx + rx*math.cos(phi)*math.cos(t) - ry*math.sin(phi)*math.sin(t)
y = cy + rx*math.sin(phi)*math.cos(t) + ry*math.cos(phi)*math.sin(t)
points.append((x,y))
return points
def parse_svg_path(d: str) -> List[Tuple[float, float]]:
"""Extract all coordinates from SVG path data (including curve control points)"""
points = []
@@ -31,13 +90,19 @@ def parse_svg_path(d: str) -> List[Tuple[float, float]]:
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)
elif cmd in ('A', 'a'):
for i in range(0, len(args), 7):
x, y = args[i+5], args[i+6]
rx, ry, phi, large_arc, sweep, x, y = args[i:i+7]
if cmd.islower():
x += current_pos[0]
y += current_pos[1]
points.append((x, y))
arc_points = arc_to_points(
current_pos[0], current_pos[1],
rx, ry, phi,
int(large_arc), int(sweep),
x, y
)
points.extend(arc_points)
current_pos = (x, y)
return points
@@ -155,4 +220,4 @@ def batch_process_svg(input_dir: str, output_dir: str):
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)
batch_process_svg(input_dir, output_dir)