自学内容网 自学内容网

desmos和webgl绘制线条

目录

desmos绘制

webgl绘制

将线段坐标生成三角化坐标

处理斜接线段

 处理圆角

尖角 

 


先在desmos上面完成线条lineJoin绘制的,再将代码和公式转到js用webgl绘制.

desmos绘制

示例

desmos计角斜接角时,需要用到的一些函数。在desmos定义成公共函数,


这里填充线条的模式也是采用类似webgl中的三角形模式

webgl绘制

将线段坐标生成三角化坐标
 /**
         * @param {number} lineWidth
         * @param {"bevel" | "miter" | "round"} lineJoin
         * @param {"butt" | "round" | "square"} lineCap
        */
        function generateLineVertices(positions, lineWidth, lineJoin = 'miter', lineCap = 'butt', miterLimit = 10) {
            const vertices = [];
            const halfWidth = lineWidth / 2;
            for (let i = 0; i < positions.length - 1; i++) {
                const p1 = positions[i];
                const p2 = positions[i + 1];
            
                // 计算线段法线
                const dx = p2[0] - p1[0];
                const dy = p2[1] - p1[1];
                const len = Math.sqrt(dx * dx + dy * dy);
                const nx = -dy / len;
                const ny = dx / len;

                // 计算顶点偏移
                const offsetX = nx * halfWidth;
                const offsetY = ny * halfWidth;

                // 两条边
                const left1 = [p1[0] - offsetX, p1[1] - offsetY]; 
                const right1 = [p1[0] + offsetX, p1[1] + offsetY];
                const left2 = [p2[0] - offsetX, p2[1] - offsetY]; 
                const right2 = [p2[0] + offsetX, p2[1] + offsetY];

                // 将带状三角形的顶点加入数组
                vertices.push(...left1, ...right1, ...left2, ...right2);

                // 处理线端样式
                if (i === 0) {
                    generateCapVertices(p1,p2, halfWidth, vertices, true, lineCap); // 起点圆头
                } 
                 if (i === positions.length - 2) {
                    generateCapVertices(p2,p1, halfWidth, vertices, false, lineCap); // 终点圆头
                }

                // 处理线段连接样式
                if (i < positions.length - 2) {
                    const p3 = positions[i + 2];
                    handleLineJoin(p2, p1, p3, lineWidth, lineJoin, miterLimit, vertices);
                }
            }
            return new Float32Array(vertices);
        }
处理斜接线段
  // 处理线段连接
        function handleLineJoin(current, prev, next, lineWidth, lineJoin, miterLimit, vertices) {
            // 根据 lineJoin 类型处理拐角连接
            if (lineJoin === 'miter') {
                handleMiterJoin(current, prev, next, lineWidth, vertices)
            } else if (lineJoin === 'bevel') {
               // handleBevelJoin(current, prev, next, lineWidth, vertices);
            } else if (lineJoin === 'round') {
                handleRoundJoin(current, prev, next, lineWidth, vertices);
            }
        }
 处理圆角
         // 处理圆角连接
        function handleRoundJoin(current, prev, next, lineWidth, vertices) {
         
            const normal1 = computeDirection(prev, current);
            const normal2 = computeDirection(next, current);

            const cos=computeDot(normal1,normal2)
            if(cos==1){
                return
            }
            const normal1_perpendicular=[-normal1[1],normal1[0]]
            const normal2_perpendicular=[-normal2[1],normal2[0]]
            
            let angle_1=Math.atan2(normal1_perpendicular[1],normal1_perpendicular[0])
      
   
        
            const halfWidth = lineWidth / 2;
            const steps = 10; 
            const angleStep =Math.PI / steps; 

            let startAngle = angle_1//-(Math.PI*0.5);
            let prevX,prevY;
            // 圆弧生成点
            for (let i = 0; i <= steps; i++) {
                const angle = startAngle + i * angleStep;
                const x = current[0] + Math.cos(angle) * halfWidth;
                const y = current[1] + Math.sin(angle) * halfWidth;

                if (i > 0) {
                    vertices.push(current[0], current[1], prevX, prevY, x, y);
                }

                prevX = x;
                prevY = y;
            }
        }
尖角 
// 尖角 
function handleMiterJoin(current, prev, next, lineWidth, vertices) {
            const halfWidth = lineWidth / 2;
            const l1=subtract(prev,current)
            const l2=subtract(next,current)
            const d=computeCross(l1,l2)
            if(d===0){
                return
            }
            const l1_n=normalize(l1)
            const l2_n=normalize(l2)

            const lineAngle=computeDot(l1_n,l2_n)
            if(lineAngle==1){
                return
            }
            //const sign=
            const bisector=normalize(add(l1_n,l2_n))
            const ab_n=computeNormal(prev,current)
            const cos=computeDot(bisector,ab_n)
            if(cos===1){
                return
            }
            const miterLength=halfWidth/cos;
            const b1=add(current,multiplyScalar(bisector,miterLength))
            const b2=add(current,multiplyScalar(bisector,-miterLength))
     
            if(d<0){
                vertices.push(...b1)
            }else{
                vertices.push(...b2)
            }
        }


原文地址:https://blog.csdn.net/long5305350/article/details/142873678

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!