This repository has been archived on 2023-03-25. You can view files and clone it, but cannot push or open issues or pull requests.

103 lines
4.3 KiB
Python

import math
import re
import inkex
from inkex import bezier
from inkex.paths import Path, CubicSuperPath
class BarrelDistorsion(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument("--lambda_coef", type=float, default=-5.0, help="command line help")
def distort_coordinates(self, x, y):
"""Method applies barrel distorsion to given points with distorsion center in center of image, selected to
Args:
x (float): X coordinate of given point
y (float): Y coordinate of given point
Returns:
tuple(float, float): Tuple with X,Y distorted coordinates of given point
"""
x_u = (x - self.x_c) / (self.width + self.height)
y_u = (y - self.y_c) / (self.width + self.height)
x_d = x_u / 2 / (self.q * y_u**2 + x_u**2 * self.q) * (1 - math.sqrt(1 - 4 * self.q * y_u**2 - 4 * x_u**2 * self.q))
y_d = y_u / 2 / (self.q * y_u**2 + x_u**2 * self.q) * (1 - math.sqrt(1 - 4 * self.q * y_u**2 - 4 * x_u**2 * self.q))
x_d *= self.width + self.height
y_d *= self.width + self.height
x_d += self.x_c
y_d += self.y_c
return x_d, y_d
def split_into_nodes(self, nodes_number=1000):
for id, node in self.svg.selected.items():
if node.tag == inkex.addNS('path', 'svg'):
p = CubicSuperPath(node.get('d'))
new = []
for sub in p:
new.append([sub[0][:]])
i = 1
while i <= len(sub) - 1:
length = bezier.cspseglength(
new[-1][-1], sub[i])
splits = nodes_number
for s in range(int(splits), 1, -1):
new[-1][-1], next, sub[
i] = bezier.cspbezsplitatlength(
new[-1][-1], sub[i], 1.0 / s)
new[-1].append(next[:])
new[-1].append(sub[i])
i += 1
node.set('d', str(CubicSuperPath(new)))
def effect(self):
if re.match(r'g\d+',
list(self.svg.selected.items())[0][0]) is not None:
raise SystemExit(
"You are trying to distort group of objects.\n This extension works only with path objects due to Inkscape API restrictions.\n Ungroup your objects and try again."
)
self.split_into_nodes()
self.q = self.options.lambda_coef
if self.q == 0.0:
inkex.errormsg("Invalid lambda coefficient. May not be exactly zero.")
return
nodes = []
for id, node in self.svg.selected.items():
if node.tag == inkex.addNS('path', 'svg'):
path = Path(node.get('d')).to_arrays()
nodes += path
if len(nodes) == 0:
inkex.utils.debug("Selection is invalid. Please change selection to paths only.")
exit(1)
nodes_filtered = [x for x in nodes if x[0] != 'Z']
x_coordinates = [x[-1][-2] for x in nodes_filtered]
y_coordinates = [y[-1][-1] for y in nodes_filtered]
self.width = max(x_coordinates) - min(x_coordinates)
self.height = max(y_coordinates) - min(y_coordinates)
self.x_c = sum(x_coordinates) / len(x_coordinates)
self.y_c = sum(y_coordinates) / len(y_coordinates)
for id, node in self.svg.selected.items():
if node.tag == inkex.addNS('path', 'svg'):
path = Path(node.get('d')).to_arrays()
distorted = []
first = True
for cmd, params in path:
if cmd != 'Z':
if first == True:
x = params[-2]
y = params[-1]
distorted.append(
['M',
list(self.distort_coordinates(x, y))])
first = False
else:
x = params[-2]
y = params[-1]
distorted.append(
['L', self.distort_coordinates(x, y)])
node.set('d', str(Path(distorted)))
if __name__ == '__main__':
BarrelDistorsion().run()