如何在不更改线长的情况下重塑多边形

时间:2018-02-08 17:37:04

标签: javascript polygon

我可以使用代码片段来重塑鼠标的多边形。绘制多边形后,用户可以通过移动点来改变形状。但我想在不改变线长的情况下修改形状。这些点将尽可能地改变,但线的长度将保持不变。

我该怎么做?

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>

1 个答案:

答案 0 :(得分:1)

看看这个

&#13;
&#13;
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);
&#13;
<canvas id="cnPolygon" width="500" height="300" style="border:solid 1px silver"></canvas>
&#13;
&#13;
&#13;

这样做是计算两个给定点之间的角度,并根据该角度和距离增量施加力。施加的力量乘以stiffness

这必须前进(A点 - > B点)和后退(点A&lt; - B点)以便解释差异在链中的最后一点到第一点之间。

注意这不是100%准确。迭代计数可以提高准确度,但正如@bhspencer已经指出的那样,有些情况下这是不可能的,仅仅是因为几何。