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.
mightyscape-1.1-deprecated/extensions/fablabchemnitz/barrel_distorsion/barrel_distorsion.py

100 lines
4.2 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
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()