获取矩形角的点

Get the points for the corners of a rectangle

我得到了一个矩形的点数组,从左上角位置开始顺时针排序到每个角。我需要找到从角落到矩形每一边的每个特定角落长度的直线的起点和终点。我的代码将点旋转某个随机角度只是为了说明问题,但在我的实际场景中我只有角点并且需要起点和终点来映射每个角。我目前正在偏移每个点,就好像使用方向值数组的点一样,当矩形不旋转时,该点与数组中点的顺序相匹配,但它不起作用,因为点可以在该点旋转顺序也变了。我确定我没有掌握正弦和余弦的应用。我怎样才能得到每个角点的值向它的每一边偏移一个给定的长度,以便所有的东西一起均匀地旋转?

function rotate(cx, cy, x, y, angle) {
    var radians = (Math.PI / 180) * angle,
        cos = Math.cos(radians),
        sin = Math.sin(radians),
        nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
        ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
    return {x: nx, y: ny};
}

const colors =["red","blue", "green","black"];
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
let centroid = {};
let points = [{x:30,y:30},{x:110, y:30},{x:110,y:110},{x:30, y:110}];

function update() {
  const randAngle = Math.random() * 180 * (Math.random() > 0.5 ? -1:1);
  const length = points.length;
    centroid = points.reduce((last, current)=> {
    last.x += current.x / length;
    last.y += current.y / length;
    return last;
  }, {x: 0, y:0});  
  points = 
    points.map(point=> rotate(centroid.x, 
                              centroid.y, 
                              point.x, 
                              point.y, 
                              randAngle));
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);  
  // draw centroid
  ctx.beginPath();
  ctx.arc(centroid.x, centroid.y, 4, 0, Math.PI * 2); 
  ctx.stroke();
  // draw Square
  ctx.beginPath();
  ctx.moveTo(points[0].x, points[0].y);
  for(let i=1;i<points.length;i++) {    
    ctx.lineTo(points[i].x, points[i].y);
  }
  ctx.closePath();
  ctx.stroke();
  // draw corner points
  for(let i=0;i < points.length;i++) {
    ctx.beginPath();
    ctx.fillStyle = colors[i%colors.length];
    ctx.arc(points[i].x, points[i].y, 3, 0, Math.PI * 2);
    ctx.fill();
  }
  
  const cornerLength = 10;
  const startPointDirections = [{ x: 0, y: 1 },
{ x: -1, y: 0 },
{ x: 0, y: -1 },
{ x: 1, y: 0 }];

const endPointDirections = [{ x: 1, y: 0 },
{ x: 0, y: 1 },
{ x: -1, y: 0 },
{ x: 0, y: -1 }];
  // draw corner start points and endpoints
  for(let i=0;i < points.length;i++) {
    ctx.beginPath();
    ctx.fillStyle = colors[i%colors.length];    
    ctx.arc(startPointDirections[i].x * cornerLength + points[i].x, startPointDirections[i].y * cornerLength  + points[i].y, 3, 0, Math.PI * 2);
    ctx.arc(endPointDirections[i].x * cornerLength + points[i].x, endPointDirections[i].y * cornerLength  + points[i].y, 3, 0, Math.PI * 2);
    ctx.fill();
    }        
}

setInterval(()=> {
  update(); 
  draw();
}, 2000);
<canvas></canvas>

似乎您需要应用 rotate 函数来偏移相对于旋转角的点,但此时您没有角度值。所以你可以从旋转的边得到方向向量。

function rotate(cx, cy, x, y, angle) {
    var radians = (Math.PI / 180) * angle,
        cos = Math.cos(radians),
        sin = Math.sin(radians),
        nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
        ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
    return {x: nx, y: ny};
}

const colors =["red","blue", "green","black"];
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
let centroid = {};
let points = [{x:30,y:30},{x:110, y:30},{x:110,y:110},{x:30, y:110}];

function update() {
  const randAngle = Math.random() * 180 * (Math.random() > 0.5 ? -1:1);
  const length = points.length;
    centroid = points.reduce((last, current)=> {
    last.x += current.x / length;
    last.y += current.y / length;
    return last;
  }, {x: 0, y:0});  
  points = 
    points.map(point=> rotate(centroid.x, 
                              centroid.y, 
                              point.x, 
                              point.y, 
                              randAngle));
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);  
  // draw centroid
  ctx.beginPath();
  ctx.arc(centroid.x, centroid.y, 4, 0, Math.PI * 2); 
  ctx.stroke();
  // draw Square
  ctx.beginPath();
  ctx.moveTo(points[0].x, points[0].y);
  for(let i=1;i<points.length;i++) {    
    ctx.lineTo(points[i].x, points[i].y);
  }
  ctx.closePath();
  ctx.stroke();
  // draw corner points
  for(let i=0;i < points.length;i++) {
    ctx.beginPath();
    ctx.fillStyle = colors[i%colors.length];
    ctx.arc(points[i].x, points[i].y, 3, 0, Math.PI * 2);
    ctx.fill();
  }
  
  const cornerLength = 10;
  
  // draw corner start points and endpoints
  for(let i=0;i < points.length;i++) {
    ctx.beginPath();
    ctx.fillStyle = colors[i%colors.length];    
    let dx = points[i].x - points[(i+3)%4].x     //previous index in cyclic manner
    let dy = points[i].y - points[(i+3)%4].y 
    let len = Math.sqrt(dx*dx+dy*dy)   //really you know side length so use known value
    dx = cornerLength * dx/len      //normalized vector multiplied by magnitude
    dy = cornerLength * dy/len
 
    startx = points[i].x  + dx
    starty = points[i].y  + dy

    endx = points[i].x + dy   //here apply rotated by -Pi/2 offset vector 
    endy = points[i].y - dx   

    ctx.arc(startx, starty, 3, 0, Math.PI * 2);
    ctx.arc(endx, endy, 3, 0, Math.PI * 2);
    ctx.fill();
    }        
}

setInterval(()=> {
  update(); 
  draw();
}, 2000);
<canvas></canvas>

(实际上dx/lendy/len等于cos(angle)sin(angle),反之亦然,符号组合不同)