svg编辑器 —— 用贝塞尔曲线拟合矩形和圆形

383 阅读2分钟

用三次贝塞尔拟合矩形

拟合矩形比较简单,只需要四个锚点,因为是个闭合曲线,所以每个锚点都有两个控制点,而且控制点和锚点的坐标一样。

那么在鼠标Mousedown时记录当前pos作为矩形的第一个锚点(左上角),在mousemove的时候记录当前pos作为第三个锚点(右下角),在mouseup时计算出所有点的坐标,加入pathlist即可。 具体计算过程如下:

export function getRectNodes(node: Node){ 
  let {posX,posY,ctrPosY,ctrPosX} = node;

  let nodes = [];
  nodes[0] = { posX:posX, posY:posY, ctrPosX:posX, ctrPosY:posY, ctr2PosX:posX, ctr2PosY:posY }
  nodes[1] = { posX:ctrPosX, posY:posY, ctrPosX: ctrPosX, ctrPosY: posY, ctr2PosX:ctrPosX, ctr2PosY:posY }
  nodes[2] = { posX:ctrPosX, posY:ctrPosY, ctrPosX:ctrPosX, ctrPosY:ctrPosY, ctr2PosX:ctrPosX,  ctr2PosY:ctrPosY }
  nodes[3] = { posX:posX, posY:ctrPosY, ctrPosX: posX, ctrPosY: ctrPosY, ctr2PosX:posX, ctr2PosY:ctrPosY }
  return nodes;
}

用三次贝塞尔拟合圆形

用三次贝塞尔拟合圆形也需要四个锚点,每个锚点需要两个控制点。这里的关键点是锚点到控制点的距离,这个距离会影响曲线的弯曲程度。

通过查阅资料(具体证明)知道这个距离是半径*0.551915024494

那么在mousedown的时候记录pos作为圆心的位置,mousemove的pos和圆形的pos计算出半径,mousedown的时候计算四个锚点和相应控制点的坐标,然后加入pathlist。

具体计算过程:

export function getCircleNodes(node: Node){
  const C = 0.552284749831;  
  let {posX,posY,ctrPosY,ctrPosX} = node;
  let radius = Math.sqrt((posX-ctrPosX)*(posX-ctrPosX) + (posY-ctrPosY)* (posY-ctrPosY));
  let h = C * radius; 

  let nodes = [];
  nodes[0] = {
    posX:posX,
    posY:posY + radius,
    ctrPosX:posX + h,
    ctrPosY:posY + radius,
    ctr2PosX: posX - h,
    ctr2PosY: posY + radius,
  }
  nodes[1] = {
    posX:posX + radius,
    posY:posY,
    ctrPosX: posX + radius,
    ctrPosY: posY + h,
    ctr2PosX:posX + radius,
    ctr2PosY:posY - h
  }
  nodes[2] = {
    posX:posX,
    posY:posY - radius,
    ctrPosX: posX + h,
    ctrPosY: posY - radius,
    ctr2PosX:posX - h,
    ctr2PosY:posY - radius
  }
  nodes[3] = {
    posX:posX - radius,
    posY:posY,
    ctrPosX: posX - radius,
    ctrPosY: posY - h,
    ctr2PosX:posX - radius,
    ctr2PosY:posY + h
  }

  return nodes;
}