Выравнивание отраженного, вращающегося изображения в правом нижнем углу (или правом верхнем углу и т. Д.) Наброска формыJavascript

Форум по Javascript
Ответить Пред. темаСлед. тема
Anonymous
 Выравнивание отраженного, вращающегося изображения в правом нижнем углу (или правом верхнем углу и т. Д.) Наброска формы

Сообщение Anonymous »

Я беру арбитатные (любой угол) линии и создаю вокруг них формы, некоторые из которых отражаются в этих линиях. Формы могут быть треугольными или четырехугольными, включая непараллелограммы. Мой код для расчета работы отраженных точек работает, и я нарисую эти точки на холст, клип и удар. Затем мне нужно представить текстуру, перевернутую и повернутую, чтобы соответствовать этим точкам. Я создаю преобразование с Dommatrix, используя вращение и масштаб для создания отражения (FLIP) о линии и перевода, поэтому изображение выравнивается с контур, который не работает. Maxx, Макси плавает за пределами формы. Использование Minx/Y для верхнего левого также не сбои, что вы можете увидеть, рассматривая второй из моих тестовых случаев в примере. Это может означать, что оригинальная ограничивающая коробка тоже не верна. Но это все еще не удалось заметно на фигурах, где наклон нижнего края был положительным, поскольку правая нижняя точка будет иметь меньшую, чем нижний левый (так что изображение не будет нарисовано достаточно низко).
Я не думаю, что я могу просто выполнить математику на высоте/ширине изображения, потому что формы повторяются, что могут представлять только фракции. Мне нужны изображения, чтобы сидеть в точных границах, продиктованных путем вычисления отраженных точек (которые жестко кодируются в моем примере, извините). < /P>
Я сделал более минимальную версию моего кода, чтобы показать здесь. У него просто несколько предопределенных тестовых линий/форм, и, к сожалению, не охватывает все сценарии. Оригинальный код слишком большой, чтобы публиковать. Часть холста, которая читает «1», должна извлечь из начала координат. < /P>


canvas {
border: 1px solid grey;
margin: 2px;
}






"use strict";
const canvasWidth = 600;
const canvasHeight = 830;
const pieces = [
[{points:[new DOMPoint(140, 50),new DOMPoint(140.00000000000003, -90),new DOMPoint(90.00000000000001, -90),new DOMPoint(90, 0),], line:{ start: new DOMPoint(283.6663192636163, 193.66631926361632), end: new DOMPoint(-52.666319263616316, -142.66631926361632) }, original:[new DOMPoint(140, 50),new DOMPoint(0, 50),new DOMPoint(0, 0),new DOMPoint(90, 0),], intersects:[new DOMPoint(90, 0),new DOMPoint(140, 50),], origTopLeft:new DOMPoint(0, 0),width:50.00000000000003, height:50.00000000000003}, {points:[new DOMPoint(158.36517719568567, 44.67326250912334),new DOMPoint(163.97896049896048, -53.783451143451146),new DOMPoint(213.82095634095634, -49.58802494802492),new DOMPoint(211.1386748844376, -2.5451301597599514),], line:{ start: new DOMPoint(252.24682141160773, -39.3261033682806), end: new DOMPoint(101.75317858839227, 95.3261033682806) }, original:[new DOMPoint(158.36517719568567, 44.67326250912335),new DOMPoint(256.8378378378378, 50),new DOMPoint(258.18918918918916, -1.6317320576126618e-15),new DOMPoint(211.1386748844376, -2.5451301597599563),], intersects:[new DOMPoint(211.1386748844376, -2.5451301597599514),new DOMPoint(158.36517719568567, 44.67326250912334),], origTopLeft:new DOMPoint(158.36517719568567, -2.5451301597599563),width:55.45577914527067, height:55.45577914527067},{points:[new DOMPoint(198.38255973344914, 8.868236027966603),new DOMPoint(-153.64897521683866, 5.578032470538176),new DOMPoint(-154.11627140114496, 55.57584876561373),new DOMPoint(143.07549812764987, 58.3535016752606),], line:{ start: new DOMPoint(436.3443301443184, -204.04492697123226), end: new DOMPoint(-82.3443301443184, 260.04492697123226) }, original:[new DOMPoint(198.3825597334491, 8.868236027966553),new DOMPoint(162.65825355141538, 359.09787638799855),new DOMPoint(112.9163540869709, 354.0240772523315),new DOMPoint(143.0754981276499, 58.353501675260645),], intersects:[new DOMPoint(143.07549812764987, 58.3535016752606),new DOMPoint(198.38255973344914, 8.868236027966603),], origTopLeft:new DOMPoint(112.9163540869709, 8.868236027966553),width:352.49883113459407, height:352.49883113459407}, ],
[{points:[new DOMPoint(183, 0),new DOMPoint(-115.80000000000018, -398.4000000000001),new DOMPoint(-155.80000000000018, -368.4000000000001),new DOMPoint(158, 50),], line:{ start: new DOMPoint(466.81944546997806, -567.6388909399561), end: new DOMPoint(-126.81944546997806, 619.6388909399561) }, original:[new DOMPoint(183.00000000000003, 0),new DOMPoint(681, 0),new DOMPoint(681, 50),new DOMPoint(158, 50),], intersects:[new DOMPoint(158, 50),new DOMPoint(183, 0),], originalTopLeft:new DOMPoint(158, 0),width:338.8000000000002, height:338.8000000000002}, ],
[{points:[new DOMPoint(157.50666666666666, 24.98461538461538),new DOMPoint(232.01174895512395, 458.84515237596656),new DOMPoint(182.7330781575854, 467.307575458501),new DOMPoint(121.1733333333333, 108.830769230769),], line:{ start: new DOMPoint(358.8607804360353, -439.6787240831585), end: new DOMPoint(-43.86078043603533, 489.6787240831585) }, original:[new DOMPoint(157.50666666666666, 24.9846153846154),new DOMPoint(-210.00917431192647, 267.30275229357795),new DOMPoint(-182.48623853211006, 309.045871559633),new DOMPoint(121.17333333333352, 108.83076923076914),], intersects:[new DOMPoint(121.1733333333333, 108.830769230769),new DOMPoint(157.50666666666666, 24.98461538461538),], originalTopLeft:new DOMPoint(-210.00917431192647, 24.9846153846154),width:110.83841562179065, height:110.83841562179065}, {points:[new DOMPoint(118.49999999999997, 49.99999999999999),new DOMPoint(207.78082191780817, 127.91780821917807),new DOMPoint(240.6575342465753, 90.24657534246575),new DOMPoint(137.25, -4.9897642155143516e-15),], line:{ start: new DOMPoint(199.2848941516392, -165.42638440437122), end: new DOMPoint(55.71510584836079, 217.42638440437122) }, original:[new DOMPoint(118.5, 50),new DOMPoint(0, 50),new DOMPoint(0, 0),new DOMPoint(137.25, 0),], intersects:[new DOMPoint(137.25, -4.9897642155143516e-15),new DOMPoint(118.49999999999997, 49.99999999999999),], originalTopLeft:new DOMPoint(0, 0),width:122.15753424657532, height:122.15753424657532}]
];

// reflect, rotate by angle of the longest edge of the pre-reflected shape so that the image renders at the right angle on the page

function getReflectionMatrix(piece, ctx) {
const { line, original, points, intersects } = piece;
const anchor = intersects[0]; // point where the line and the other edges meet, used as an origin for reflection

const display = new DOMMatrix();
reflectMatrix(display, line, anchor);
rotateMatrix(display, original, anchor); // i do this so the image shows up at the right angle on the canvas
translateMatrix(display, original, points, ctx);
return display;
}

function reflectMatrix(matrix, line, anchor) {
const radians = getAngleFromOrigin(line);
const angle = getDegreesFromRadians(radians);

matrix.translateSelf(anchor.x, anchor.y);
matrix.rotateSelf(angle);
matrix.scaleSelf(1, -1);
matrix.rotateSelf(-angle);
}

function rotateMatrix(matrix, originalPoints, anchor) {
const longestEdgeAngle = getLongestEdgeAngle(originalPoints);
const degrees = getDegreesFromRadians(longestEdgeAngle);

matrix.rotateSelf(degrees);
matrix.translateSelf(-anchor.x, -anchor.y);
}

function translateMatrix(matrix, originalPoints, newPoints, ctx) {
const { width, height } = getDimensions(newPoints);
const { pointsUp, pointsLeft } = getMatrixDirection(matrix);

let { x, y } = getTopLeft(newPoints);
if (pointsUp) y += height;
if (pointsLeft) x += width;
//const target = findClosestPoint(newPoints, x, y); // if you look at the top left test, the bottom of the image is too high on the yellow shape
const target = new DOMPoint(x, y); // make a new dompoint for it just for ease of switching between variables in testing

const pt0T = new DOMPoint(0, 0).matrixTransform(matrix);
const dx = target.x - pt0T.x;
const dy = target.y - pt0T.y;
const translated = new DOMMatrix().translateSelf(dx, dy);
matrix.preMultiplySelf(translated);

drawDebugMarker(target.x, target.y, "blue", ctx);
}

// helpers for getting shape dimensions etc.

function getAngleFromOrigin(line) {
const { start, end } = line;
const dx = end.x - start.x;
const dy = end.y - start.y;
return Math.atan2(dy, dx);
}

function getLongestEdgeAngle(points) {
let maxLength = 0;
let bestAngle = 0;
for (let i = 0; i < points.length; i++) {
const a = points;
const b = points[(i + 1) % points.length];
const dx = b.x - a.x;
const dy = b.y - a.y;
const length = Math.hypot(dx, dy);
if (length > maxLength) {
maxLength = length;
bestAngle = Math.atan2(dy, dx);
}
}
return bestAngle;
}

function getDegreesFromRadians(angle) {
const degrees = angle * 180 / Math.PI;
return ((degrees % 360) + 360) % 360;
}

function getTopLeft(points) {
const { minX, maxX, minY, maxY } = getBoundingBox(points);
return new DOMPoint(minX, minY);
}

function getBoundingBox(points) {
const coordsX = points.map(point => point.x);
const minX = Math.min(...coordsX);
const maxX = Math.max(...coordsX);
const coordsY = points.map(point => point.y);
const minY = Math.min(...coordsY);
const maxY = Math.max(...coordsY);
return { minX, maxX, minY, maxY };
}

function getDimensions(points) {
const { minX, maxX, minY, maxY } = getBoundingBox(points);
const width = maxX - minX;
const height = maxY - minY;
return { width, height };
}

function getMatrixDirection(matrix) {
const rightX = matrix.a;
const rightY = matrix.b;
const downX = matrix.c;
const downY = matrix.d;

const pointsLeft = Math.abs(rightX) >= Math.abs(rightY) ? rightX < 0 : rightY < 0;
const pointsUp = Math.abs(downY) >= Math.abs(downX) ? downY < 0 : downX < 0;
return { pointsLeft, pointsUp };
}

function findClosestPoint(points, x, y) {
let minDist = Infinity;
let closest = points[0];
for (const point of points) {
const dist = Math.hypot(point.x - x, point.y - y);
if (dist < minDist) {
minDist = dist;
closest = point;
}
}
return closest;
}

// drawing

function loopThroughPieces(test, ctx) {
for (let i = 0; i < test.length; i++) {
ctx.setTransform(canvasTransform);
const piece = test;
const colour = getColour(i);
const display = getReflectionMatrix(piece, ctx);
drawPiece(piece, colour, display, ctx);
}
}

function getColour(i) {
// red comes first
const hue = (i * 45) % 360;
const lightness = 100 - (40 + 10);
const alpha = 0.5;
return `hsla(${hue}, 90%, ${lightness}%, ${alpha})`;
}

function drawPiece(piece, colour, display, ctx) {
ctx.save();
tracePiecePath(piece.points, ctx);
ctx.globalAlpha = 0.65;
//ctx.clip(); // it's supposed to be clipped, but i unclipped for visualisation, since sometimes the image floats outside of the outline

ctx.setTransform(canvasTransform.multiply(display));
ctx.drawImage(image, 0, 0, image.width, image.height);

ctx.strokeStyle = colour;
ctx.lineWidth = 3;
ctx.globalAlpha = 1;
ctx.stroke();

ctx.restore();
ctx.save();
}

function tracePiecePath(points, ctx) {
ctx.beginPath();
const firstPoint = points[0];
ctx.moveTo(firstPoint.x, firstPoint.y);
points.slice(1).forEach(point => {
ctx.lineTo(point.x, point.y);
});
ctx.closePath();
}

function drawDebugMarker(x, y, colour, ctx) {
ctx.beginPath();
ctx.arc(x, y, 5, 0, 2 * Math.PI);
ctx.fillStyle = colour;
ctx.fill();
}

// everything below is just assembling test cases etc. and rendering them

function makeCanvasTransform() {
canvasTransform.scaleSelf(0.6, 0.6);
canvasTransform.translateSelf(canvasWidth/2, canvasHeight/2);
}

function drawDebugImage() {
const imgCtx = image.getContext("2d");
imgCtx.fillStyle = "white";
imgCtx.fillRect(0, 0, image.width, image.height);
imgCtx.font = "20px arial";
imgCtx.textAlign = "center";
imgCtx.fillStyle = "black";
const segmentWidth = image.width/12;
let offsetX = 0;
for (let i = 0; i < Math.ceil(image.width/segmentWidth); i++) {
imgCtx.strokeRect(offsetX, 0, segmentWidth, image.height);
imgCtx.fillText(i + 1, offsetX + segmentWidth/2, image.height/2);
offsetX += segmentWidth;
}
}

function gatherCtxs() {
const ctxs = [];
for (let i = 0; i < pieces.length; i++) {
const canvas = document.createElement("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
canvases.appendChild(canvas);
if (i % 2 == 1) {
const br = document.createElement("br");
canvases.appendChild(br);
}
ctxs.push(canvas.getContext("2d"));
}
return ctxs;
}

const image = document.getElementById("image");
const canvases = document.getElementById("canvases");
const canvasTransform = new DOMMatrix();

drawDebugImage();
makeCanvasTransform();
const ctxs = gatherCtxs();
for (let i = 0; i < pieces.length; i++) {
loopThroughPieces(pieces, ctxs);
}


< /code>
Спасибо за чтение! :)

Подробнее здесь: https://stackoverflow.com/questions/796 ... t-etc-of-a
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Javascript»