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.
2021-10-19 16:06:48 +02:00

#### 103 lines 4.3 KiB Python Raw Permalink Blame History

 ```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()`