|
/************************************************************************************ |
|
Draw Shape Expression v1.02 |
|
Description: Draws a parametric rectangle path |
|
Author: Thomas Alberti <[email protected]> |
|
************************************************************************************/ |
|
|
|
function getMatrixComposite(tMatrix1, tMatrix2){ // Multiply matrices, 2x2 * 2x2 |
|
let cMatrix = []; |
|
for(let j = 0; j <= 1; j++) { |
|
cMatrix[j] = []; |
|
for(let k = 0; k <= 1; k++) { |
|
let mProduct = 0; |
|
for(let i = 0; i <= 1; i++) { |
|
mProduct += tMatrix1[i][k] * tMatrix2[j][i]; |
|
} |
|
cMatrix[j].push(mProduct); |
|
} |
|
} |
|
return cMatrix; |
|
} |
|
|
|
function getVecTransform(tMatrix,vec){ // Multiply matrices, 2x2 * 2x1 |
|
let tVec = []; |
|
for (let i = 0; i <= 1; i++) { |
|
let mProduct = 0; |
|
for (let j = 0; j <= 1; j++) { |
|
mProduct += tMatrix[j][i] * vec[j]; |
|
} |
|
tVec.push(mProduct); |
|
} |
|
return tVec; |
|
} |
|
|
|
function drawRectangle(xLeft, yTop, xWidth, yHeight) { // Define four points of a rectangle |
|
let rectPoints = [ |
|
[xLeft + xWidth, yTop + yHeight], |
|
[xLeft, yTop + yHeight], |
|
[xLeft, yTop], |
|
[xLeft + xWidth, yTop] |
|
]; |
|
return rectPoints; |
|
} |
|
|
|
function getChamferPoints(shapePoints, chamferAmount){ // For each corner, move a new point along each intersecting side, define tangents |
|
let chamferPoints = []; |
|
let chamferInTangents = []; |
|
let chamferOutTangents = []; |
|
let numPoints = shapePoints.length; |
|
for (let i = 0; i < numPoints; i++) { |
|
let pointA = shapePoints[i]; |
|
let pointB = shapePoints[(i + 1) % numPoints]; |
|
let uAb = normalize(pointA - pointB); |
|
let newPointAb = pointA - chamferAmount * uAb; // formula for moving a point along a vector |
|
let pointAbInTangent = uAb * chamferAmount * 0.551915024494; // in tangent is plotted c or kappa of some amount along that vector, see Bezier math |
|
let pointAbOutTangent = [0, 0]; |
|
let pointC = shapePoints[(i + numPoints - 1) % numPoints]; |
|
let uAc = normalize(pointA - pointC); |
|
let newPointAc = pointA - chamferAmount * uAc; |
|
let pointAcInTangent = [0, 0]; |
|
let pointAcOutTangent = uAc * chamferAmount * 0.551915024494; |
|
chamferPoints.push(newPointAc, newPointAb); |
|
chamferInTangents.push(pointAcInTangent, pointAbInTangent); |
|
chamferOutTangents.push(pointAcOutTangent, pointAbOutTangent); |
|
} |
|
let chamferPointsAndTangents = [chamferPoints, chamferInTangents, chamferOutTangents]; |
|
return chamferPointsAndTangents; |
|
} |
|
|
|
function getTransformPoints(shapePoints, tMatrixRot, tMatrixScl, posXY){ |
|
let tShape = [[],[],[]]; |
|
let cRotSclMatrix = getMatrixComposite(tMatrixRot, tMatrixScl); |
|
if (shapePoints.length == 3) { // check for tangent arrays and transform them if they're there |
|
for (let i = shapePoints[0].length-1; i >= 0; i--) { |
|
let tVertex = getVecTransform(cRotSclMatrix, shapePoints[0][i]) + posXY; |
|
let tIn = getVecTransform(cRotSclMatrix, shapePoints[1][i]); |
|
let tOut = getVecTransform(cRotSclMatrix, shapePoints[2][i]); |
|
tShape[0].push(tVertex); |
|
tShape[1].push(tOut); // swap tangent arrays because decrement loop reverses vertex order |
|
tShape[2].push(tIn); |
|
} |
|
} else { // if no tangents, only transform points |
|
for (let i = shapePoints.length-1; i >= 0; i--) { |
|
let tVertex = getVecTransform(cRotSclMatrix, shapePoints[i]) + posXY; |
|
tShape[0].push(tVertex); |
|
} |
|
} |
|
return tShape; |
|
} |
|
|
|
// Get controller values |
|
var controlWidth = (effect("Path Expression - Shape")("Path - Size X").value || .01); |
|
var controlHeight = (effect("Path Expression - Shape")("Path - Size Y").value || .01); |
|
|
|
var controlRoundness = effect("Path Expression - Shape")("Path - Roundness"); |
|
var minDimension = Math.min(Math.abs(controlWidth), Math.abs(controlHeight)); |
|
var roundnessMax = clamp(controlRoundness, 0, minDimension / 2); |
|
|
|
var controlAnchorX = -effect("Path Expression - Shape")("Path - Anchor X") / 100; |
|
var controlAnchorY = -effect("Path Expression - Shape")("Path - Anchor Y") / 100; |
|
|
|
var controlPositionX = effect("Path Expression - Shape")("Path - Position X"); |
|
var controlPositionY = effect("Path Expression - Shape")("Path - Position Y"); |
|
var movePos = [controlPositionX, controlPositionY]; |
|
|
|
var controlRotation = degreesToRadians(effect("Path Expression - Shape")("Path - Rotation")); |
|
var rotMatrix = [[Math.cos(controlRotation), Math.sin(controlRotation)],[-Math.sin(controlRotation), Math.cos(controlRotation)]]; |
|
|
|
var controlUniform = effect("Path Expression - Shape")("Path - Uniform Scale"); |
|
var controlScaleX = effect("Path Expression - Shape")("Path - Scale X") / 100; |
|
var controlScaleY = effect("Path Expression - Shape")("Path - Scale Y") / 100; |
|
if (controlUniform == 1){ |
|
var sclMatrix = [[controlScaleX,0],[0,controlScaleX]]; |
|
} else { |
|
var sclMatrix = [[controlScaleX,0],[0,controlScaleY]]; |
|
} |
|
|
|
// Define shape |
|
var rectLeft = controlAnchorX * controlWidth; |
|
var rectTop = controlAnchorY * controlHeight; |
|
var rectWidth = controlWidth; |
|
var rectHeight = controlHeight; |
|
var rect1 = drawRectangle(rectLeft, rectTop, rectWidth, rectHeight); |
|
|
|
if (roundnessMax > 0){ |
|
var roundRect1 = getChamferPoints(rect1, roundnessMax); |
|
var transformRect1 = getTransformPoints(roundRect1, rotMatrix, sclMatrix, movePos); |
|
} else { |
|
var transformRect1 = getTransformPoints(rect1, rotMatrix, sclMatrix, movePos); |
|
} |
|
|
|
createPath(transformRect1[0], transformRect1[1], transformRect1[2]) |