Stap 12: XY-coördinaten van een SVG (Python Code)
Intro
We moeten een gemakkelijke manier van het maken van de foto's die we tekenen, willen dus heb ik gekozen voor het gebruik van Inkscape (dat is gratis) om te tekenen SVGs (schaalbare vectorafbeeldingen). Een SVG is eigenlijk een XML gebaseerde bestandstype, dus u het gemakkelijk genoeg met python parseren kunt. Het kan erg ingewikkeld, maar als we onze tekeningen padobjecten beperken, is eenvoudig.
De python code die ik hieronder heb geschreven kan worden uitgevoerd op uw computer, zodat u kunt zien de output, als u eenmaal begrijpt het is eenvoudig te implementeren hetzelfde op de Edison in onze controller.
Tekening
Eerste intall inkscape en tekenen iets eenvoudig met het hulpmiddel van de lijn (mijn tekening van het Intel-logo is bijgevoegd)
Zorg ervoor dat de coördinaten tot absolute zijn ingesteld door de volgende stappen:
- Shift + control + p
- input/output
- SVG-uitvoer
- pad gegevens
- tekenreeks padnotatie: absolute
Als u ingewikkelde paden tekenen of de tracering gebruiken, zorg ervoor dat u eerst "splitsen" de paden of het script zal niet verwerken.
Zodra u deze instelling hebt toegepast, selecteert u de hele afbeelding (ctrl + a) en verplaats het vernieuwen van de coördinaten en vervolgens opslaan als een svg
Met behulp van absolute coördinaten drastisch vermindert de verwerking die wij moeten doen om te blijken SVG paden in de lijnsegmenten die zijn gedefinieerd door paren van x, y-coördinaten.
Python Code
Hier is een klein beetje python code die in een SVG-bestand leest en, met behulp van de "minidom" module, parseert het bestand paden.
Elk pad bestaat uit een reeks opdrachten (zoals ben ' of 'L') gevolgd door een coördinaat. Hier zijn enkele voorbeelden (Lees dit voor de bijzonderheid: link):
- 'M ' betekent, "de pen te verplaatsen naar dit coördinaat"
- 'm ' betekent, "de pen te verplaatsen dit ver, relatieve op huidige positie"
- 'L' betekent, "de pen te verplaatsen naar dit coördinaat, terwijl u een lijn tekent"
- 'm ' betekent, "de pen te verplaatsen dit ver, relatieve op huidige positie, terwijl u een lijn tekent"
- 'Z' of 'z' betekent. "een lijn trekken terug naar waar we begonnen (sluit de shape)
Ik koos enkel te behandelen "M", "L" en "Z" in dit voorbeeld, vandaar de eis voor absolute coördinaten.
Ik heb ook een beetje code die gebruik maakt van Matplotlib (een python plotting gereedschap) te trekken van de SVG en sla het op als een PNG-bestand ook bekijken.
from xml.dom import minidom import re class svgHandler: def __init__(self): self.filename = "" self.lines = [] #list of segments of the form [x0 y0 x1 y1 RGB] where x and y are 0-1 floats def importFile(self,filename): doc = minidom.parse(filename) # parseString also exists paths = doc.getElementsByTagName('path') doc.unlink() pathsandcolours = [] self.lines = [] """ Go through the paths and store their coordinate strings and colours in a list of tuples """ for p in paths: styleValues = p.attributes['style'].value.split(";") for val in styleValues: if val.split(":")[0] == 'stroke': rgb = val.split(":")[1] pathsandcolours.append((p.getAttribute('d'),rgb)) """ For each path and its corresponding colour, convert to a set of line segments of the form [x0 y0 x1 y1 RGB] """ xMin = float("inf") xMax = -float("inf") yMin = float("inf") yMax = -float("inf") unScaledLines = [] for path,rgb in pathsandcolours: pathCoords = re.split(r'([CcLlMmZz])',path) startX = 0 startY = 0 lastX = 0 lastY = 0 newLine = True closeLine = False #we are assuming absolute coordinates in the SVG print pathCoords for coord in pathCoords: coord = coord.strip() if len(coord) == 0: pass elif coord == 'M': #'M' is move cursor to absolute position newLine = True elif coord == 'L': #'L' is draw line to absolute position newLine = False elif coord == 'Z' or coord.strip() == 'z': #close line to initial point closeLine = True else: try: x = float(re.split(r'[\s,]',coord)[0]) y = float(re.split(r'[\s,]',coord)[1]) xMin = min(xMin,x) yMin = min(yMin,y) xMax = max(xMax,x) yMax = max(yMax,y) if closeLine: lastX = x lastY = y startX = x startY = y unScaledLines.append([lastX,lastY,startX,startY,rgb]) elif newLine: lastX = x lastY = y startX = x startY = y else: unScaledLines.append([lastX,lastY,x,y,rgb]) #self.lines.append([lastX,lastY,x,y,rgb]) lastX = x lastY = y except: print "unhandled command: ",coord #print "xMin,yMin",xMin,yMin #print "xMax,yMax",xMax,yMax xTotal = xMax-xMin yTotal = yMax-yMin for x0,y0,x1,y1,rgb in unScaledLines: X0normalised = (x0-xMin)/xTotal X1normalised = (x1-xMin)/xTotal Y0normalised = (y0-yMin)/yTotal Y1normalised = (y1-yMin)/yTotal self.lines.append([X0normalised,Y0normalised,X1normalised,Y1normalised,rgb]) def plotPath(self): import matplotlib.pyplot as plt plt.gca().invert_yaxis() for x0,y0,x1,y1,rgb in self.lines: print int(rgb[1:3],16),int(rgb[3:5],16),int(rgb[5:7],16) plt.plot([x0,x1],[y0,y1],color=rgb) plt.savefig(self.filename.split('.')[0]+'.png') plt.show() svgh = svgHandler() svgh.importFile("example.svg") svgh.plotPath()