Đây là một nhiệm vụ khó khăn để làm bằng tay bằng cách đặt trực quan hình tròn dọc theo con đường của một lá thư.
Thậm chí còn khó tự động hơn (tự động!) Mà không có sự can thiệp của con người.
Dưới đây là cách tự động sắp xếp vòng kết nối để tạo thành chữ cái.
Câu trả lời là trong 2 phần ...
Tìm kiếm "letterform",
Tạo vòng tròn để điền vào và phác thảo các letterform.
1. Phần cứng
Frederik De Bleser đã mã hóa một thư viện đẹp gọi opentype.js
mà phải mất một file font .ttf và phân tích ra phác thảo hình tượng bất kỳ ký tự được chỉ định sử dụng các đường cong bậc hai trên vải: https://github.com/nodebox/opentype.js
2. Các chỉ là một phần hơi ít khó
Đối với mỗi chữ cái:
Tìm "nhiều" điểm trên mỗi đường cong bậc hai. Đây là thuật toán để tính [x, y] trên đường cong tại một khoảng T. T sẽ nằm trong khoảng từ 0,00 ở đầu đường cong đến 1,00 ở cuối đường cong. T sẽ không tạo ra khoảng cách đều nhau [x, y] dọc theo đường cong, do đó bạn sẽ cần phải bỏ mẫu (Vì vậy, "nhiều" có thể có nghĩa là 1000 giá trị của T trong khoảng từ 0,00 đến 1,00).
function getQuadraticBezierXYatT(startPt,controlPt,endPt,T) {
var x = Math.pow(1-T,2) * startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x;
var y = Math.pow(1-T,2) * startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y;
return({x:x,y:y});
}
Tìm góc tiếp xúc với góc của đường cong tại các điểm đó. (Về cơ bản tính toán những gì sẽ là một góc bên phải để đường cong). Bạn có thể làm điều đó với đạo hàm tiếp theo của công thức bậc hai:
function quadraticBezierTangentAngle(t, p0, p2, p1) {
var tt = 1 - t;
var dx = (tt * p1.x + t * p2.x) - (tt * p0.x + t * p1.x);
var dy = (tt * p1.y + t * p2.y) - (tt * p0.y + t * p1.y);
return Math.tan(Math.atan2(dy,dx));
}
Bắt đầu từ lúc bắt đầu của đường cong, tính toán mỗi khoảng cách từ hiện tại [x, y] để tiếp theo [x, y].Bạn có thể làm điều này với lý Pythagore:
var dx=nextX-currentX;
var dy=nextY-currentY;
var distance=Math.sqrt(dx*dx+dy*dy);
De-lặp lại trong các mảng sao cho tất cả phần còn lại [x, y] yếu tố này là 1px xa từ [x, y] yếu tố trước đó. Bạn có thể làm điều này bằng cách điền vào mảng thứ hai với các giá trị từ đầu tiên trong đó parseInt(nextInOriginalArray - lastDistanceInNewArray)==1;
Quyết định bán kính cho vòng kết nối của bạn sẽ tạo thành từng chữ cái. Điều này thực sự khó hơn nó có vẻ. Đối với phông chữ "khối ô vuông", bạn có thể vẽ chữ "I" trên canvas. Sau đó tìm nạp tất cả các pixles bằng cách sử dụng getImageData
. Tính chiều rộng của đột quỵ dọc "I" bằng cách tìm kiếm số lượng điểm ảnh mờ đục chạy theo chiều ngang ở giữa dọc của chữ cái. Đối với phông chữ khối ô vuông, var radius = horizontalOpaquePixelCount/2;
. Đối với các phông chữ có độ rộng biến đổi đột biến, bạn sẽ phải sáng tạo. Có thể var radius = horizontalOpaquePixelCount/3;
hoặc var radius = horizontalOpaquePixelCount/4;
.
Lặp lại qua mảng điểm và xác định vòng kết nối mới mỗi radius*2
pixel. Bạn tính toán điểm trung tâm cho mỗi vòng tròn bằng cách sử dụng góc tiếp tuyến và lượng giác như thế này:
var centerX = curvePointX + radius*Math.cos(tangentAngle);
var centerY = curvePointY + radius*Math.sin(tangentAngle);
Trong khi tạo vòng tròn, tại một số điểm đường cong của bức thư sẽ quay lưng lại khi bản thân, vì vậy bạn phải kiểm tra mỗi vòng tròn mới mà bạn tạo để chắc chắn nó sẽ không chồng lên một vòng tròn hiện có. Bạn có thể tính toán xem một vòng tròn mới sẽ cắt nhau vòng kết nối hiện như thế này:
var dx = newCircleCenterX - existingCircleCenterX;
var dy = newCircleCenterY - existingCircleCenterY;
var distance=Math.sqrt(dx*dx+dy*dy);
var circlesAreIntersecting=(distance<=newCircleRadius+existingCircleRadius);
Tinh chỉnh: Gần một số điểm điểm cuối trên đường đi của bức thư, bạn sẽ thấy rằng một vòng tròn bán kính đầy đủ tới sẽ tràn ra khỏi dạng chữ. Nếu điều đó xảy ra, bạn có thể thu nhỏ bán kính của một số vòng tròn để phù hợp với dạng chữ. Nếu bạn hoàn toàn là bán kính cố định cho vòng kết nối, bạn có thể tính toán lại bán kính cố định của tất cả các vòng tròn dựa trên bán kính trung bình của tất cả các vòng tròn - bao gồm cả bán kính bạn muốn "thu nhỏ" để phù hợp với biểu mẫu.
Ví dụ: Đây là chữ "L hình thành bởi 15 vòng tròn.
Nhưng 2 vòng tròn màu đỏ rơi ra khỏi letterform của nó. Bạn có thể (1) thu nhỏ vòng tròn màu đỏ để phù hợp với bên trong letterform hoặc (2) tính toán lại một bán kính vòng tròn cố định mới dựa trên bán kính trung bình phù hợp với các letterform:
var total=0;
total += greenRadii * 13;
total += verticalRedRadiusResizedToFitInsideLetterform;
total += horizontalRedRadiusResizedToFitInsideLetterform;
var newRadius = total/15;
Bạn có thể tính toán độ dài của bán kính đỏ mà sẽ phù hợp với những letterform bằng cách tính toán giao điểm của 2 đường: (1) các đoạn thẳng được hình thành bằng cách kết nối trung tâm vòng tròn màu xanh lá cây cuối cùng và trung tâm vòng tròn màu đỏ, (2) dòng được hình thành vuông góc với nhau m điểm cuối cùng trên đường cong. Dưới đây là một thuật toán để tính toán giao điểm của 2 dòng:
// Get interseting point of 2 line segments (if any)
// Attribution: http://paulbourke.net/geometry/pointlineplane/
function line2lineIntersection(p0,p1,p2,p3) {
var unknownA = (p3.x-p2.x) * (p0.y-p2.y) - (p3.y-p2.y) * (p0.x-p2.x);
var unknownB = (p1.x-p0.x) * (p0.y-p2.y) - (p1.y-p0.y) * (p0.x-p2.x);
var denominator = (p3.y-p2.y) * (p1.x-p0.x) - (p3.x-p2.x) * (p1.y-p0.y);
// Test if Coincident
// If the denominator and numerator for the ua and ub are 0
// then the two lines are coincident.
if(unknownA==0 && unknownB==0 && denominator==0){return(null);}
// Test if Parallel
// If the denominator for the equations for ua and ub is 0
// then the two lines are parallel.
if (denominator == 0) return null;
// If the intersection of line segments is required
// then it is only necessary to test if ua and ub lie between 0 and 1.
// Whichever one lies within that range then the corresponding
// line segment contains the intersection point.
// If both lie within the range of 0 to 1 then
// the intersection point is within both line segments.
unknownA /= denominator;
unknownB /= denominator;
var isIntersecting=(unknownA>=0 && unknownA<=1 && unknownB>=0 && unknownB<=1)
if(!isIntersecting){return(null);}
return({
x: p0.x + unknownA * (p1.x-p0.x),
y: p0.y + unknownA * (p1.y-p0.y)
});
}
thể trùng lặp của [Html5 nút giao thông văn bản canvas] (http://stackoverflow.com/questions/19954058/html5-canvas-text- giao lộ) –