Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
// Given unit vectors u0 = (0, 1) and v0 = (1, 0).
//
// After matrix mapping, we get u1 and v1. Let Θ be the angle between u1 and v1.
// Then the final scale we want is:
//
// Math.min(|u1|sin(Θ),|v1|sin(Θ)) = |u1||v1|sin(Θ) / Math.max(|u1|,|v1|)
//
// If Math.max(|u1|,|v1|) = 0, that means either x or y has a scale of 0.
//
// For the non-skew case, which is most of the cases, matrix scale is
// computing exactly the scale on x and y axis, and take the minimal of these two.
//
// For the skew case, an unit square will mapped to a parallelogram,
// and this function will return the minimal height of the 2 bases.
const { matrix } = paper.project.activeLayer;
const m = new paper.Matrix(matrix.a, matrix.b, matrix.c, matrix.d, 0, 0);
const u0 = new paper.Point(0, 1);
const v0 = new paper.Point(1, 0);
const u1 = u0.transform(m);
const v1 = v0.transform(m);
const sx = Math.hypot(u1.x, u1.y);
const sy = Math.hypot(v1.x, v1.y);
const dotProduct = u1.y * v1.x - u1.x * v1.y;
const maxScale = Math.max(sx, sy);
return maxScale > 0 ? Math.abs(dotProduct) / maxScale : 0;
}
const { x, y } = this.paperLayer.globalToLocal(event.point);
const ellipseSize = new paper.Size(
x - downPoint.x,
// If shift is pressed, then create a circle.
event.modifiers.shift ? x - downPoint.x : y - downPoint.y,
);
const ellipsePath = paper.Shape
.Ellipse(new paper.Rectangle(downPoint, ellipseSize))
.toPath(false);
ellipsePath.applyMatrix = true;
if (event.modifiers.alt) {
// If alt is pressed, then the initial downpoint represents the ellipse's
// center point.
const halfWidth = ellipseSize.width / 2;
const halfHeight = ellipseSize.height / 2;
ellipsePath.transform(new paper.Matrix(1, 0, 0, 1, -halfWidth, -halfHeight));
}
this.ps.setPathOverlayInfo({ pathData: ellipsePath.pathData, strokeColor: 'black' });
}
setDimensions(
viewportWidth: number,
viewportHeight: number,
viewWidth: number,
viewHeight: number,
) {
// Note that viewWidth / viewportWidth === viewHeight / viewportHeight.
this.cssScaling = viewWidth / viewportWidth;
this.matrix = new paper.Matrix().scale(this.cssScaling);
this.updatePixelGridItem(viewportWidth, viewportHeight);
}
function newEditPathItem(path: paper.Path, info: EditPathInfo, cssScaling: number) {
const group = new paper.Group();
const scaleFactor = getRasterScaleFactor(cssScaling);
const matrix = path.globalMatrix.prepended(
new paper.Matrix(1 / cssScaling, 0, 0, 1 / cssScaling, 0, 0),
);
const addRasterFn = (raster: paper.Raster) => {
raster.scale(scaleFactor, scaleFactor);
group.addChild(raster);
return raster;
};
const addLineFn = (from: paper.Point, to: paper.Point) => {
const line = new paper.Path.Line(from, to);
line.guide = true;
line.strokeColor = '#aaaaaa';
line.strokeWidth = 1 / paper.view.zoom;
line.strokeScaling = false;
// line.transform(matrix);
group.addChild(line);
};
const {
else {
scaleFactor = gutterRatio * canvasContainer.offsetHeight / this.imageHeight;
}
this.offsetX = (this.viewWidth - scaleFactor * this.imageWidth) / 2;
this.offsetY = (this.viewHeight - scaleFactor * this.imageHeight) / 2;
this.sendMsg("zoomLevel", {value: Math.round(scaleFactor * 100) / 100});
// zoomPoint keeps the mouse position on every mouse moves to be able to zoom to the
// right position on mouse wheel events
this.zoomPoint = new Paper.Point(this.viewWidth / 2, this.viewHeight / 2);
// The scaling factor computed to display the whole image using the available room of the view
this.scaleFactor = scaleFactor;
const fullScreenMatrix = new Paper.Matrix().translate(this.offsetX, this.offsetY).scale(scaleFactor);
this.transformAllLayers(fullScreenMatrix);
this.disableSmoothing();
}
segments: path.segments!.map(seg => {
const newSeg = seg.clone()
newSeg.transform(
new Matrix(1, 0, 0, 1, -path.position!.x!, -path.position!.y!)
)
return newSeg
}),
position: path.position!
function fromGroupLayer(layer: GroupLayer) {
const { pivotX, pivotY, scaleX, scaleY, rotation, translateX, translateY } = layer;
const pivot = new paper.Matrix(1, 0, 0, 1, pivotX, pivotY);
const scale = new paper.Matrix(scaleX, 0, 0, scaleY, 0, 0);
const cosr = Math.cos(rotation * Math.PI / 180);
const sinr = Math.sin(rotation * Math.PI / 180);
const rotate = new paper.Matrix(cosr, sinr, -sinr, cosr, 0, 0);
const translate = new paper.Matrix(1, 0, 0, 1, translateX, translateY);
const matrix = new paper.Matrix()
.prepend(pivot.inverted())
.prepend(scale)
.prepend(rotate)
.prepend(translate)
.prepend(pivot);
return new paper.Group({ data: { id: layer.id }, matrix });
}
}
function fromGroupLayer(layer: GroupLayer) {
const { pivotX, pivotY, scaleX, scaleY, rotation, translateX, translateY } = layer;
const pivot = new paper.Matrix(1, 0, 0, 1, pivotX, pivotY);
const scale = new paper.Matrix(scaleX, 0, 0, scaleY, 0, 0);
const cosr = Math.cos(rotation * Math.PI / 180);
const sinr = Math.sin(rotation * Math.PI / 180);
const rotate = new paper.Matrix(cosr, sinr, -sinr, cosr, 0, 0);
const translate = new paper.Matrix(1, 0, 0, 1, translateX, translateY);
const matrix = new paper.Matrix()
.prepend(pivot.inverted())
.prepend(scale)
.prepend(rotate)
.prepend(translate)
.prepend(pivot);
return new paper.Group({ data: { id: layer.id }, matrix });
}
}
export function localToViewportCoordinates(item: paper.Item) {
const matrix = new paper.Matrix();
while (item !== paper.project.activeLayer) {
matrix.prepend(item.matrix);
item = item.parent;
}
return matrix;
}