1

可视化基础:已知2点坐标,如何求旋转角度? - ESnail

 1 year ago
source link: https://www.cnblogs.com/EnSnail/p/16461813.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

可视化基础:已知2点坐标,如何求旋转角度?

已知:fromto 两点的坐标,如何求两点连线的旋转角度?

806524-20220709201350356-833540194.png

可以通过余弦定理求解三个角的度数。具体说明如下:

在三角形中,已知边A、B、C, 且A、B、C所对的内角分别是a、b、c, 则:

  • cosa=[B²+C²-A²]/(2BC)
  • cosb=[A²+C²-B²]/(2AC)
  • cosc=[A²+B²-C²]/(2AB)

然后利用反三角函数求角度:

  • a = arccos(cosa)
  • b = arccos(cosb)
  • c = arccos(cosc)

代码实现如下:

// 求角a的度数
// 1.求出三角形的三条边
const a = to.y - from.y
const b = to.x - from.x
const c = Math.sqrt(a * a + b * b) // 勾股定理 c^2 = a^2 + b^2
// 2.求角a的cos值
const cosA = (b*b + c*c - a*a)/(2*b*c)
// 3.利用反cos求角a的度数
let rotate = Math.acos(cosA) * (180 / Math.PI) // 角度 = 弧度 * 180/π
// 4.处理正负号
to.y < from.y && (rotate = -rotate)

三角函数、反三角函数、角度与弧度互转说明:

const cosv = Math.cos(val)  // val 为弧度值
const val = Math.acos(cosv) // 结果 val 为弧度值,没有正负
// 角度转弧度:弧度 = 角度 * (π/180)
// 弧度转角度:角度 = 弧度 * (180/π)

svg 实现画一条带箭头的边,鼠标hover,边及箭头变色并显示文本。

806524-20220709202137226-418230829.png

react 实现如下:

import React, { useState } from 'react'

const link = {
  from: {
    x: 100,
    y: 100
  },
  to: {
    x: 300,
    y: 50
  },
}

const index = () => {

  const [linkHover, setLinkHover] = useState()

  const linkMouseEnter = () => {
    const { from, to } = link
    const a = to.y - from.y
    const b = to.x - from.x
    const c = Math.sqrt(a * a + b * b)
    const cosA = (b*b + c*c - a*a)/(2*b*c) // 求夹角a的角度
    let rotate = Math.acos(cosA) * (180 / Math.PI) // 角度 = 弧度 * 180/π
    to.y < from.y && (rotate = -rotate)
    
    setLinkHover({
      x: (from.x + to.x) / 2,
      y: (from.y + to.y) / 2,
      rotate,
    })
  }

  const linkMouseLeave = () => {
    setLinkHover(undefined)
  }

  return (
    <div>
      <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
          <g>
            <defs>
              <marker id="triangle" markerUnits="strokeWidth" markerWidth="5" markerHeight="4" refX="4" refY="2" orient="auto" fill="#67c23a">
                <path d="M 0 0 L 5 2 L 0 4 L 1 2 z" />
              </marker>
              <marker id="triangle-hover" markerUnits="strokeWidth" markerWidth="5" markerHeight="4" refX="4" refY="2" orient="auto" fill="red">
                <path d="M 0 0 L 5 2 L 0 4 L 1 2 z" />
              </marker>
            </defs>
            <line x1={link.from.x} y1={link.from.y} x2={link.to.x} y2={link.to.y}
              strokeLinecap="round" stroke={linkHover ? 'red' : '#67c23a'} stroke-width="2"
              style={{markerEnd: linkHover ? 'url(#triangle-hover)' : 'url(#triangle)'}}
            />
           {/* 增加 hover 边界,容易操作 */}
           <line x1={link.from.x} y1={link.from.y} x2={link.to.x} y2={link.to.y}
              stroke="red" stroke-opacity="0.2" stroke-width="12"
              onMouseEnter={linkMouseEnter}
              onMouseLeave={linkMouseLeave}
              style={{cursor: 'pointer'}}
           />
          </g>
          {linkHover ? (
            // 42 为文本宽度的一半,8 为文本高度的一半 svg transform="rotate(旋转角度 旋转中心x,旋转中心y)" 默认旋转中心为svg左上角
            <text x={linkHover.x - 42} y={linkHover.y - 8} fill="red" transform={`rotate(${linkHover.rotate} ${linkHover.x},${linkHover.y})`}>点击删除连线</text>
          ) : null}
        </svg>
    </div>
  )
}

export default index

未经允许不得转让。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK