假設我已經有一條由許多直線(bezier代碼中的陣列)近似的貝塞爾曲線,我想用一系列矩形來繪制它。我在下面有以下代碼可以做到這一點:
// don't change this array
const bezier = [{x:167.00,y:40.00},{x:154.37,y:42.09},{x:143.09,y:44.48},{x:133.08,y:47.15},{x:124.26,y:50.09},{x:116.55,y:53.27},{x:109.87,y:56.68},{x:104.15,y:60.31},{x:99.32,y:64.14},{x:95.28,y:68.15},{x:91.97,y:72.34},{x:89.31,y:76.67},{x:87.22,y:81.14},{x:85.63,y:85.74},{x:84.44,y:90.43},{x:83.60,y:95.22},{x:83.02,y:100.08},{x:82.63,y:105.00},{x:82.33,y:109.96},{x:82.07,y:114.94},{x:81.76,y:119.94},{x:81.33,y:124.93},{x:80.69,y:129.89},{x:79.77,y:134.82},{x:78.49,y:139.70},{x:76.78,y:144.50},{x:74.55,y:149.22},{x:71.74,y:153.84},{x:68.25,y:158.34},{x:64.03,y:162.71},{x:58.97,y:166.93},{x:53.02,y:170.98},{x:46.10,y:174.86},{x:38.11,y:178.54},{x:29.00,y:182.00}];
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const thickness = 35;
function rotateCanvas(x, y, a) {
ctx.translate(x, y);
ctx.rotate(a);
ctx.translate(-x, -y);
}
function drawRectangle(rX, rY, rW, rH, rA, color) {
ctx.beginPath();
rotateCanvas(rX rW / 2, rY rH / 2, rA);
ctx.rect(rX, rY, rW, rH);
rotateCanvas(rX rW / 2, rY rH / 2, -rA);
ctx.fill();
}
function calcRectFromLine(x1, y1, x2, y2) {
const dx = x2 - x1;
const dy = y2 - y1;
const mag = Math.sqrt(dx * dx dy * dy);
const angle = Math.atan2(dy, dx);
return {
x: (x1 x2) / 2 - mag / 2,
y: (y1 y2) / 2 - thickness / 2,
w: mag,
h: thickness,
a: angle
};
}
function calculateRectangles() {
const result = [];
for (let i = 1; i < bezier.length; i ) {
const prev = bezier[i - 1];
const curr = bezier[i];
result.push(calcRectFromLine(prev.x, prev.y, curr.x, curr.y));
}
return result;
}
const rectangles = calculateRectangles();
for (let r of rectangles) {
drawRectangle(r.x, r.y, r.w, r.h, r.a);
}
<canvas width="400" height="400"></canvas>
如果您運行代碼片段,您會發現曲線不是很粗,而且它是一系列矩形這一事實非常明顯。
如果將厚度引數從更改35為較小的數字并重新運行它,它看起來很好。只有當它非常厚時才會發生這種情況。
該代碼當前采用貝塞爾陣列,并創建一系列旋轉的矩形,然后渲染它們。
有沒有辦法修改calculateRectangles函式以回傳更好的曲線近似值?理想情況下,它仍然會回傳圍繞中心旋轉的矩形串列,但是在渲染時它看起來更像曲線,而不像矩形串列。
我能想到的唯一想法是以某種方式從 中回傳兩倍多的矩形calculateRectangles,每個矩形都與前一個倒置,這樣線條的兩邊都被填充了,雖然我認為這可能有效,但不幸的是它有回傳兩倍的矩形的副作用,這是不可取的,如果可能的話我會避免它。
uj5u.com熱心網友回復:
您應該繪制的形狀不是矩形,而是四邊形,通過將連續法線的端點連接到曲線而獲得。據推測,您可以通過 Path 物件來實作。
在高曲率區域中,您可能還必須減小步長,因為外部曲線可能不平滑。
事實上,您可以通過選擇步長來“拉平”貝塞爾曲線,以使連續線段之間的偏差保持在固定容差以下。
在粗曲線的情況下,您可以保留這個想法,但要確保有界偏差適用于曲線的兩側。
uj5u.com熱心網友回復:
您不能通過繪制矩形來真正制作“粗貝塞爾曲線”,您最終會在一個尺寸上在它們之間產生很多間隙,而在另一側看起來很奇怪的重疊。如果你想堅持多邊形近似,你需要在每個點使用法線,然后畫線來連接這些點。這會導致梯形截面,所以如果我們想要看起來不錯的結果,我們就不能使用普通的矩形。

然而,偏移量越大,在曲率半徑很小的區域中出現的問題就越多:通過查看左上角波峰下方相互交叉的法線,您已經可以看到一個這樣的問題,我們在這里實際上并不想連接所有法線偏移頂點,因為其中一個位于我們要跟蹤的形狀內。

或者,您可以使用“更多貝塞爾曲線”來偏移貝塞爾曲線本身,例如
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/460475.html
標籤:javascript 数学 html5-画布 三角学 贝塞尔曲线
