Skip to content

Instantly share code, notes, and snippets.

@Jonty
Last active Sep 16, 2020
Embed
What would you like to do?
An extremely hacky bit of code to split an SVG of joined line paths into individual lines, and merge straight lines made of smaller lines into single lines
# An extremely hacky bit of code that takes SVG files output by Blender
# and splits all the multi-node line paths into single line paths to make
# editing easier. Example: A right-angle path is now two lines that meet.
#
# Blender has a habit of outputting really _weird_ paths that are annoying
# to edit on geometric shapes, and also outputs straight lines that are
# made up of many smaller straight line nodes. This code also merges those
# mini-line lines into single lines to stop you throwing your computer out
# of the window when you try and work with the SVG.
#
# The SVG parsing in this is hilarious and lazy because I only ever needed
# to use this once. It will likely not work with SVG output from any other
# program, or even different types of SVG from Blender - but just in case
# here's the code. I couldn't find anyone else doing this.
import sys
import re
import math
with open(sys.argv[1]) as f:
for line in f.readlines():
line = line.strip()
matches = re.search('(\s*<path d=" M )([^"]+)( ".*)$', line)
if matches:
tail = matches.group(3)
tail = tail.replace('stroke-width="3.0"', 'stroke-width="1.0"')
lines = []
# Split into individual lines
coords = re.findall('(\d+\.\d+, \d+.\d+)', matches.group(2))
last_coord = coords.pop(0)
for coord in coords:
lines.append((last_coord, coord))
last_coord = coord
# Merge lines that are part of a contiguous line
merged_lines = []
last_line = lines.pop(0)
last_point = last_line[0]
for line in lines:
# Last segment
x1, y1 = last_line[0].split(", ")
x2, y2 = last_line[1].split(", ")
last_slope = math.atan2(float(x2) - float(x1), float(y2) - float(y1))
# This segment
x1, y1 = line[0].split(", ")
x2, y2 = line[1].split(", ")
this_slope = math.atan2(float(x2) - float(x1), float(y2) - float(y1))
if abs(last_slope - this_slope) > 0.01:
merged_lines.append((last_point, last_line[1]))
last_point = line[0]
last_line = line
merged_lines.append((last_point, last_line[1]))
for line in merged_lines:
print("%s%s %s%s" % (matches.group(1), line[0], line[1], tail))
else:
print(line)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment