一堆画圆的照片,做一些数学和睡在它之后,我想出了以下解决方案:
//draw the top and bottom edges of the lens
ctx.beginPath();
ctx.moveTo(lens.x - (lens.thickness/2), lens.y - lens.radius);
ctx.lineTo(lens.x + (lens.thickness/2), lens.y - lens.radius);
ctx.moveTo(lens.x - (lens.thickness/2), lens.y + lens.radius);
ctx.lineTo(lens.x + (lens.thickness/2), lens.y + lens.radius);
ctx.stroke();
ctx.beginPath();
//draw the left face of the lens
var lensToCircleRatio = lens.radius/lens.leftRadius;
var xOffset = lens.leftRadius * Math.cos(Math.asin(lensToCircleRatio)) - (lens.thickness/2); //change the - to a + for a right-side concave face
var arcStart = Math.PI - Math.asin(lensToCircleRatio);
var arcEnd = Math.PI + Math.asin(lensToCircleRatio);
ctx.arc(lens.x + xOffset, lens.y, lens.leftRadius, arcStart, arcEnd);
ctx.stroke();
ctx.beginPath();
//draw the right face of the lens
lensToCircleRatio = lens.radius/lens.rightRadius;
xOffset = lens.rightRadius * Math.cos(Math.asin(lensToCircleRatio)) - (lens.thickness/2); //change the - to a + for a left-side concave face
arcStart = -1 * Math.asin(lensToCircleRatio);
arcEnd = Math.asin(lensToCircleRatio);
ctx.arc(lens.x - xOffset, lens.y, lens.rightRadius, arcStart, arcEnd);
ctx.stroke();
这里有一个形象,真的类似于此代码完成: ![enter image description here](https://i.stack.imgur.com/5X7Z0.jpg)
它根据它们各自的曲率半径计算出每个面的弧长,然后计算出这些弧的中心位置。然后绘制弧线和边缘以连接它们(如果需要的话)。我的代码为这个模型增加了什么,如果透镜的两个面都是凸面的,则额外的透镜厚度。幸运的是,即使经过多种不同的尺寸和镜头配置,我认为这种方法可能会出现的精度问题还没有出现。
下面是一个早期的测试(略有更新的代码绘制):
![enter image description here](https://i.stack.imgur.com/Hl6jc.png)