54 lines
2.1 KiB
Python
54 lines
2.1 KiB
Python
# ComfyUI_DXF/svg_utils.py
|
|
import pyclipper
|
|
from lxml import etree
|
|
from svgpathtools import parse_path, Line, Arc, CubicBezier, QuadraticBezier
|
|
|
|
SCALE_FACTOR = 10000.0
|
|
|
|
def svg_string_to_clipper_paths(svg_text, curve_samples=60):
|
|
if not svg_text or not svg_text.strip(): return []
|
|
parser = etree.XMLParser(recover=True)
|
|
root = etree.fromstring(svg_text.encode('utf-8'), parser)
|
|
ns = {'svg': 'http://www.w3.org/2000/svg'}
|
|
clipper_paths = []
|
|
|
|
for path_element in root.xpath('//svg:path', namespaces=ns):
|
|
d_string = path_element.get('d');
|
|
if not d_string: continue
|
|
path_obj = parse_path(d_string)
|
|
if not path_obj: continue
|
|
|
|
polygon = []
|
|
# --- LOGIQUE D'ÉCHANTILLONNAGE DE HAUTE QUALITÉ ---
|
|
for segment in path_obj:
|
|
# On calcule le nombre de points en fonction de la longueur du segment
|
|
# pour une qualité adaptative.
|
|
length = segment.length()
|
|
if length < 1.0: # Pour les très petits segments
|
|
num_samples = 2
|
|
else:
|
|
num_samples = max(2, int(length / (100.0 / curve_samples)))
|
|
|
|
# Si c'est une ligne, 2 points suffisent
|
|
if isinstance(segment, Line): num_samples = 2
|
|
|
|
for i in range(num_samples):
|
|
point = segment.point(i / (num_samples - 1))
|
|
polygon.append((int(point.real * SCALE_FACTOR), int(point.imag * SCALE_FACTOR)))
|
|
|
|
if len(polygon) > 2:
|
|
unique_polygon = [p for i, p in enumerate(polygon) if i == 0 or p != polygon[i-1]]
|
|
if len(unique_polygon) > 2:
|
|
clipper_paths.append(unique_polygon)
|
|
|
|
return clipper_paths
|
|
|
|
def clipper_solution_to_svg_path_d(solution):
|
|
d_string = ""
|
|
if not solution: return d_string
|
|
for path in solution:
|
|
if not path or len(path) < 3: continue
|
|
d_string += f"M {path[0][0] / SCALE_FACTOR} {path[0][1] / SCALE_FACTOR} "
|
|
for point in path[1:]: d_string += f"L {point[0] / SCALE_FACTOR} {point[1] / SCALE_FACTOR} "
|
|
d_string += "Z "
|
|
return d_string.strip() |