javascript - 如何在不改变线长的情况下 reshape 多边形

标签 javascript polygon

我可以使用片段中的代码用鼠标 reshape 多边形。绘制多边形后,用户可以通过移动点来改变形状。但我想修改形状而不改变线长度。点将尽可能改变,但线的长度将保持不变。

我该怎么做?

var canvas, ctx;
var canvasIsMouseDown = false;
var radius = 6;
var pointIndex = -1;

var points = [
    { x: 10, y: 10 },
    { x: 100, y: 50 },
    { x: 150, y: 100 },
    { x: 60, y: 110 },
    { x: 30, y: 160 }
];
function start() {
    canvas = document.getElementById("cnPolygon");
    ctx = canvas.getContext("2d");
    canvas.addEventListener("mousemove", canvasMouseMove);
    canvas.addEventListener("mousedown", canvasMouseDown);
    canvas.addEventListener("mouseup", canvasMouseUp);
    draw();
}
function canvasMouseMove(ev) {
if (!canvasIsMouseDown || pointIndex === -1) return;
    points[pointIndex].x = ev.pageX - this.offsetLeft;
    points[pointIndex].y = ev.pageY - this.offsetTop;
    draw();
}
function canvasMouseDown(ev) {
    canvasIsMouseDown = true;
    var x = ev.pageX - this.offsetLeft;
    var y = ev.pageY - this.offsetTop;
    pointIndex = -1;
    var dist;
    for (var i = 0; i < points.length; i++) {
        dist = Math.sqrt(Math.pow((x - points[i].x), 2) + Math.pow((y - points[i].y), 2));
        if (dist <= radius) {
            pointIndex = i;
            break;
        }
    }
}
function canvasMouseUp(ev) {
        canvasIsMouseDown = false;
}
function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.beginPath();
    ctx.moveTo(points[0].x, points[0].y);
    for (var i = 0; i < points.length; i++) {
        ctx.lineTo(points[i].x, points[i].y);
    }
    ctx.closePath();
    ctx.stroke();
    for (var i = 0; i < points.length; i++) {
        ctx.beginPath();
        ctx.arc(points[i].x, points[i].y, radius, 0, Math.PI * 2);
        ctx.stroke();
    }
}
document.addEventListener("DOMContentLoaded", start);
<canvas id="cnPolygon" width="200" height="200" style="border:solid 1px silver"></canvas>

最佳答案

看看这个

var canvas, ctx;
var canvasIsMouseDown = false;
var radius = 3;
var pointIndex = -1;
var points = [
    { x: 10, y: 10 },
    { x: 100, y: 50 },
    { x: 150, y: 100 },
    { x: 60, y: 110 },
    { x: 30, y: 160 }
];

// PHYSICS START ----------------
var stiffness = 0.25 // defines how elastic the contrainst should be
var oscillations = 10 // defines how many iterations should be made, more iterations mean higher precision

function getAngle(x1,y1,x2,y2){
	return Math.atan2(y2-y1,x2-x1) + Math.PI/2
}
function getConstraintPos(tx,ty,ox,oy,dist){
	var rot = getAngle(tx,ty,ox,oy)
	var x = tx+Math.sin(rot)*dist
	var y = ty-Math.cos(rot)*dist
	return [x,y]
}
function applyContraintForce(point,pos){
	point.x += (pos[0] - point.x)*stiffness
    point.y += (pos[1] - point.y)*stiffness
}
function defineDistances(){
	for (var i = 0; i < points.length; i++) {
		var next_point = points[(i+1)%points.length]
		points[i].distance = Math.sqrt(Math.pow((next_point.x - points[i].x), 2) + Math.pow((next_point.y - points[i].y), 2))
	}
}
function updateContraints(){
	// forward pass
	for (var i=0;i<points.length;i++) 
    {
       if(i==pointIndex) continue
       	var j = (+i+1)%points.length
       	var pos = getConstraintPos(points[j].x,points[j].y,points[i].x,points[i].y,points[i].distance)
       	applyContraintForce(points[i],pos)
    }
    //backward pass
    for (var i=points.length-1;i>=0;i--) 
    {
       if(i==pointIndex) continue
       	var j = (i-1)
       	j = j<0 ? points.length+j : j
       	var pos = getConstraintPos(points[j].x,points[j].y,points[i].x,points[i].y,points[j].distance)
       	applyContraintForce(points[i],pos)
    }
}
// PHYSICS END ----------------



function start() {
    canvas = document.getElementById("cnPolygon");
    ctx = canvas.getContext("2d");
    canvas.addEventListener("mousemove", canvasMouseMove);
    canvas.addEventListener("mousedown", canvasMouseDown);
    canvas.addEventListener("mouseup", canvasMouseUp);
    defineDistances()
    draw();
}
function canvasMouseMove(ev) {
    if (!canvasIsMouseDown || pointIndex === -1) return;
    points[pointIndex].x = ev.pageX - this.offsetLeft;
    points[pointIndex].y = ev.pageY - this.offsetTop;
    for(var i=0;i<oscillations;i++){
    	updateContraints()
    }
    draw();
}
function canvasMouseDown(ev) {
    canvasIsMouseDown = true;
    var x = ev.pageX - this.offsetLeft;
    var y = ev.pageY - this.offsetTop;
    pointIndex = -1;
    var dist;
    for (var i = 0; i < points.length; i++) {
        dist = Math.abs(Math.sqrt(Math.pow((x - points[i].x), 2) + Math.pow((y - points[i].y), 2)));
        if (dist <= radius) {
            pointIndex = i;
            break;
        }
    }
}
function canvasMouseUp(ev) {
    canvasIsMouseDown = false;
}
function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.beginPath();
    ctx.moveTo(points[0].x, points[0].y);
    for (var i = 0; i < points.length; i++) {
        ctx.lineTo(points[i].x, points[i].y);
    }
    ctx.closePath();
    ctx.stroke();
    for (var i = 0; i < points.length; i++) {
        ctx.beginPath();
        ctx.arc(points[i].x, points[i].y, radius * 2, 0, Math.PI * 2);
        ctx.stroke();
    }
}

document.addEventListener("DOMContentLoaded", start);
<canvas id="cnPolygon" width="500" height="300" style="border:solid 1px silver"></canvas>

它的作用是计算两个给定点之间的 Angular ,并根据该 Angular 和距离增量施加力。施加的力乘以刚度

这必须向前(点 A -> 点 B) 和向后(点 A <- 点 B) 进行,以便考虑到链中的最后一个点到第一个点。

注意这并非 100% 准确。精度可以通过迭代计数来提高,但正如 @bhspencer 已经指出的那样,在某些情况下这是不可能的,仅仅是因为几何形状。

关于javascript - 如何在不改变线长的情况下 reshape 多边形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48691566/

相关文章:

javascript - 如何使用 jQuery 设置/取消设置 cookie?

Java 2D 导航网格生成

python - 匀称的 LineString 交集是否错误?

javascript - 应该得到 3 张图像的网格

javascript - 合并两个数组并创建一个单独的数组

javascript - 复制网站,包括图像和样式

react-native-maps - 多边形 onPress 事件

python - Matplotlib 默认不会显示居中的多边形图?

algorithm - 从 2D 网格创建多边形的有效算法? (顶点+边)

javascript - 如何在 Chrome 调试器中找到错误的 catch 语句?