die TEFBOGEN sind korrigiert.
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user