Skip to content

Commit

Permalink
Improve rotations for lines
Browse files Browse the repository at this point in the history
  • Loading branch information
jordisala1991 committed Jun 14, 2024
1 parent dceddc2 commit 03b9527
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 50 deletions.
12 changes: 8 additions & 4 deletions plugin-src/transformers/partials/transformRotationAndPosition.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { applyRotationToPoint } from '@plugin/utils';
import { applyInverseRotation, hasRotation } from '@plugin/utils';

import { ShapeBaseAttributes, ShapeGeomAttributes } from '@ui/lib/types/shapes/shape';

Expand All @@ -12,7 +12,7 @@ export const transformRotationAndPosition = (
const x = node.x + baseX;
const y = node.y + baseY;

if (rotation === 0 || !node.absoluteBoundingBox) {
if (!hasRotation(rotation) || !node.absoluteBoundingBox) {
return {
x,
y,
Expand All @@ -22,10 +22,14 @@ export const transformRotationAndPosition = (
};
}

const point = applyRotationToPoint({ x, y }, node.absoluteTransform, node.absoluteBoundingBox);
const referencePoint = applyInverseRotation(
{ x, y },
node.absoluteTransform,
node.absoluteBoundingBox
);

return {
...point,
...referencePoint,
rotation: -rotation < 0 ? -rotation + 360 : -rotation,
transform: {
a: node.absoluteTransform[0][0],
Expand Down
6 changes: 6 additions & 0 deletions plugin-src/transformers/transformLineNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import { translateLineNode } from '@plugin/translators/vectors';

import { PathShape } from '@ui/lib/types/shapes/pathShape';

/**
* In order to match the normal representation of a line in Penpot, we will assume that
* the line is never rotated, so we calculate its normal position.
*
* To represent the line rotated we do take into account the rotation of the line, but only in its content.
*/
export const transformLineNode = (node: LineNode, baseX: number, baseY: number): PathShape => {
return {
type: 'path',
Expand Down
56 changes: 38 additions & 18 deletions plugin-src/translators/vectors/translateLineNode.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,65 @@
import { Command } from 'svg-path-parser';

import { applyRotationToPoint } from '@plugin/utils';
import { applyInverseRotation, applyRotation, hasRotation } from '@plugin/utils';

import { Segment } from '@ui/lib/types/shapes/pathShape';

import { translateCommandsToSegments } from '.';

export const translateLineNode = (node: LineNode, baseX: number, baseY: number): Segment[] => {
if (!node.absoluteBoundingBox) return [];
if (!hasRotation(node.rotation) || !node.absoluteBoundingBox) {
return translateCommandsToSegments(
[
{
x: 0,
y: 0,
command: 'moveto',
code: 'M'
},
{
x: node.width,
y: 0,
command: 'lineto',
code: 'L'
}
],
baseX + node.x,
baseY + node.y
);
}

const inverseMatrix: Transform = [
[node.absoluteTransform[0][0], node.absoluteTransform[1][0], 0],
[node.absoluteTransform[0][1], node.absoluteTransform[1][1], 0]
];

const startPoint = applyRotationToPoint({ x: 0, y: 0 }, inverseMatrix, node.absoluteBoundingBox);
const endPoint = applyRotationToPoint(
{ x: node.width, y: 0 },
inverseMatrix,
const startPoint = applyRotation(
{ x: 0, y: 0 },
node.absoluteTransform,
node.absoluteBoundingBox
);
const referencePoint = applyRotationToPoint(
{ x: node.x, y: node.y },

const endPoint = applyRotation(
{ x: node.width, y: 0 },
node.absoluteTransform,
node.absoluteBoundingBox
);

const commands: Command[] = [
{
x: startPoint.x + referencePoint.x,
y: startPoint.y + referencePoint.y,
x: startPoint.x,
y: startPoint.y,
command: 'moveto',
code: 'M'
},
{
x: endPoint.x + referencePoint.x,
y: endPoint.y + referencePoint.y,
x: endPoint.x,
y: endPoint.y,
command: 'lineto',
code: 'L'
}
];

return translateCommandsToSegments(commands, baseX, baseY);
const referencePoint = applyInverseRotation(
{ x: node.x, y: node.y },
node.absoluteTransform,
node.absoluteBoundingBox
);

return translateCommandsToSegments(commands, baseX + referencePoint.x, baseY + referencePoint.y);
};
40 changes: 40 additions & 0 deletions plugin-src/utils/applyRotation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Point } from '@ui/lib/types/utils/point';

const ROTATION_TOLERANCE = 0.000001;

export const applyRotation = (point: Point, transform: Transform, boundingBox: Rect): Point => {
const centerPoint = calculateCenter(boundingBox);

const rotatedPoint = applyMatrix(transform, {
x: point.x - centerPoint.x,
y: point.y - centerPoint.y
});

return {
x: centerPoint.x + rotatedPoint.x,
y: centerPoint.y + rotatedPoint.y
};
};

export const applyInverseRotation = (
point: Point,
transform: Transform,
boundingBox: Rect
): Point => applyRotation(point, inverseMatrix(transform), boundingBox);

export const hasRotation = (rotation: number): boolean => Math.abs(rotation) > ROTATION_TOLERANCE;

const inverseMatrix = (matrix: Transform): Transform => [
[matrix[0][0], matrix[1][0], matrix[0][2]],
[matrix[0][1], matrix[1][1], matrix[1][2]]
];

const applyMatrix = (matrix: Transform, point: Point): Point => ({
x: point.x * matrix[0][0] + point.y * matrix[0][1],
y: point.x * matrix[1][0] + point.y * matrix[1][1]
});

const calculateCenter = (boundingBox: Rect): Point => ({
x: boundingBox.x + boundingBox.width / 2,
y: boundingBox.y + boundingBox.height / 2
});
27 changes: 0 additions & 27 deletions plugin-src/utils/applyRotationToPoint.ts

This file was deleted.

2 changes: 1 addition & 1 deletion plugin-src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from './applyMatrixToPoint';
export * from './applyRotationToPoint';
export * from './applyRotation';
export * from './calculateAdjustment';
export * from './calculateLinearGradient';
export * from './calculateRadialGradient';
Expand Down

0 comments on commit 03b9527

Please sign in to comment.