我需要绘制一个具有初始点,半径和最终点的弧。
我在JavaScript中使用HTML5 canvas arc函数(x,y,radius,startAngle,endAngle,anticlockwise)。
context.arc(x,y,radius,startAngle,endAngle,逆时针)
有:
var initialPoint = { x: 20, y: 40 };
var radius = 40;
var finalPoint = { x: 180, y: 40 };
预期结果:
请帮忙
你必须做一些数学运算才能找到符合你3个约束的圆心: •与初始点相交 •与最终Point相交 •提供了半径
请注意,可能没有结果:如果点的距离是半径的两倍,则圆圈不能匹配。 如果积分<2 *半径之外,我们实际上有两个结果,我不知道您希望用户如何选择。
数学使用了一些属性: •圆心位于垂直于p1,p2的直线上。 •pm,(p1,p2)的中间点也是(c1,c2)的中间点。 •三角形(p1,pm,c1)和(p1,pm,c2)的下午角度为90°(法语称为“三角形矩形”,英语称为“donno”)。
这是一个截图,其中包含两个可能的绿色/红色弧:
http://jsbin.com/jutidigepeta/1/edit?js,output
var initialPoint = { x: 100, y: 160 };
var radius = 90;
var finalPoint = { x: 240, y: 190 };
var centers = findCenters(radius,initialPoint, finalPoint );
核心功能:
//
function findCenters(r, p1, p2) {
// pm is middle point of (p1, p2)
var pm = { x : 0.5 * (p1.x + p2.x) , y: 0.5*(p1.y+p2.y) } ;
drawPoint(pm, 'PM (middle)');
// compute leading vector of the perpendicular to p1 p2 == C1C2 line
var perpABdx= - ( p2.y - p1.y );
var perpABdy = p2.x - p1.x;
// normalize vector
var norm = Math.sqrt(sq(perpABdx) + sq(perpABdy));
perpABdx/=norm;
perpABdy/=norm;
// compute distance from pm to p1
var dpmp1 = Math.sqrt(sq(pm.x-p1.x) + sq(pm.y-p1.y));
// sin of the angle between { circle center, middle , p1 }
var sin = dpmp1 / r ;
// is such a circle possible ?
if (sin<-1 || sin >1) return null; // no, return null
// yes, compute the two centers
var cos = Math.sqrt(1-sq(sin)); // build cos out of sin
var d = r*cos;
var res1 = { x : pm.x + perpABdx*d, y: pm.y + perpABdy*d };
var res2 = { x : pm.x - perpABdx*d, y: pm.y - perpABdy*d };
return { c1 : res1, c2 : res2} ;
}
工具:
function sq(x) { return x*x ; }
function drawPoint(p, name) {
ctx.fillRect(p.x - 1,p.y - 1,2, 2);
ctx.textAlign = 'center';
ctx.fillText(name, p.x, p.y+10);
}
function drawCircle(c, r) {
ctx.beginPath();
ctx.arc(c.x, c.y, r, 0, 6.28);
ctx.strokeStyle='#000';
ctx.stroke();
}
function drawCircleArc(c, r, p1, p2, col) {
var ang1 = Math.atan2(p1.y-c.y, p1.x-c.x);
var ang2 = Math.atan2(p2.y-c.y, p2.x-c.x);
ctx.beginPath();
var clockwise = ( ang1 > ang2);
ctx.arc(c.x, c.y, r, ang1, ang2, clockwise);
ctx.strokeStyle=col;
ctx.stroke();
}
编辑:
这里是一个使用'side'的小提琴,一个布尔表示我们应该选择弧的哪一侧。
如果有人在SVG中寻找等价物(使用D3.js),使用answer from opsb:
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
function describeArc(x, y, radius, startAngle, endAngle){
var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);
var arcSweep = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, arcSweep, 0, end.x, end.y
].join(" ");
return d;
}
function sq(x) { return x*x ; }
function drawCircleArcSVG(c, r, p1, p2, col) {
var ang1 = Math.atan2(p1.y-c.y, p1.x-c.x)*180/Math.PI+90;
var ang2 = Math.atan2(p2.y-c.y, p2.x-c.x)*180/Math.PI+90;
var clockwise = side;
var path = describeArc(c.x, c.y, r, ang1, ang2)
console.log(path)
svg.append("path").attr("d", path).attr("fill", "none").attr("stroke-width", 3).attr("stroke", col)
}
function drawPointSVG(p, name) {
svg.append("circle").attr("cx", p.x).attr("cy", p.y).attr("r", 2)
svg.append("text").attr("x", p.x).attr("y", p.y+10).style("font-size", 10).text(name).style("font-family", "Arial")
}
function drawCircleSVG(c, r) {
svg.append("circle").attr("cx", c.x).attr("cy", c.y).attr("r", r).style("fill", "none").attr("stroke", "#000")
}