gpt4 book ai didi

svg arc,如何在给定开始结束和通过点的情况下确定扫描和大弧标志

转载 作者:行者123 更新时间:2023-12-04 14:45:21 24 4
gpt4 key购买 nike

在 svg 中,我想构建一个函数,该函数返回 path-d 属性中“弧元素”的所有参数。给定起点、终点和过境点。 (非直线上的 3 个点是圆上的每个定义)。我只对圆弧(rx == ry)感兴趣。

我可以很容易地计算出中心和半径。但是我在 2 个标志上苦苦挣扎,是否有明确的定义如何通过比较 3 个点的拓扑来设置这些标志?像角度或彼此的距离?)

我知道标志的含义,最小与最大弧,顺时针与逆时针对于扫旗。

最佳答案

是的,您可以通过查看由该弧的起点 (S)、通过 (V) 和终点 (E) 点形成的角度来确定 svg 路径弧段的大弧和扫掠标志。

大弧旗:

  • 如果|∠SVE| > π/2 然后标志 = 0
  • 如果|∠SVE| < π/2 然后标志 = 1
  • 您正在确定以 V 为中心的角度是锐角还是钝角。
  • 如果该角度是“尖角”(即锐角),那么您将绕圈走很长一段路。

  • 对于扫旗:
  • 如果 ∠ESV > 0 则标志 = 0
  • 如果 ∠ESV < 0 则标志 = 1
  • 您正在确定 V 点位于 S 到 E 线的哪一侧。
  • 当您从 S 向 E 看时,如果 V 向右,那么您将绕圆逆时针移动。

  • 请注意以下事项:
  • 形成角度的点的顺序很重要:S-V-E 与 E-S-V 分别用于大弧旗和横扫旗。
  • 所有角度都必须介于 -π 和 π 之间,即介于 -180° 和 180° 之间。
  • 绝对值用于确定大弧标志而不是扫描标志。

  • 此答案底部的演示代码演示了这些计算。直接回答 OP 问题的唯一重要代码是前两行:
    const lgArcFl = (S,V,E) => Math.abs(angle(S,V,E)) > pi/2 ? 0 : 1;
    const sweepFl = (S,V,E) => angle(E,S,V) > 0 ? 0 : 1;

    要使用该演示,请单击“运行代码片段”按钮,然后在矩形上单击 3x 以按该顺序定位起点 (S)、通过 (V) 和结束 (E) 点。该演示将计算半径,然后使用两个标志的各种组合绘制所有可能的 4 条弧线,即 0,0 , 0,1 , 1,01,1 .大弧和小弧分别为蓝色和红色,而顺时针和逆时针弧分别为实线和虚线。一条正确的弧线将以黄色突出显示。绘制圆弧后,您可以重新单击 3x 以重复等。请注意,在同一位置单击两次或在直线上单击 3x 不会产生任何圆弧,这在几何上是可以预期的。

    请注意,截至我最初发布此答案(2016 年 11 月 5 日)时,该演示适用于 Chrome、Opera 和 Safari,但不适用于 Firefox。 (我没有检查资源管理器或边缘,也没有检查任何移动浏览器。)我怀疑这可能是因为我使用了 ES6/ES2015 代码。但是,由于我不明白的原因,在代码编辑器中单击“使用 BabelJS/ES2015”按钮会以某种方式使代码无法使用。因此,如果您在运行演示时遇到问题,也许可以尝试不同的浏览器。

    const lgArcFl = (S,V,E) => Math.abs(angle(S,V,E)) > pi/2 ? 0 : 1;
    const sweepFl = (S,V,E) => angle(E,S,V) > 0 ? 0 : 1;

    const angle = ([a,b],[c,d],[e,f]) => (Math.atan2(f-d,e-c)-Math.atan2(b-d,a-c)+3*pi)%(2*pi)-pi;
    const qs = sel => document.querySelector(sel), pi = Math.PI, pts = [];
    const radius = ([a,b],[c,d],[e,f]) => {
    const g=c-a,h=2*(c-e)/g,i=d-b,j=c*c+d*d,k=j-a*a-b*b,l=(j-e*e-f*f-h*k/2)/(2*(d-f)-h*i);
    return Math.hypot(a+(i*l-k/2)/g,b-l);
    };
    const mkArc = (arc, [sx, sy], [ex, ey], r, lg, sw) => arc.setAttribute('d',
    `M ${sx} ${sy} A ${r} ${r} 0 ${lg} ${sw} ${ex} ${ey}`);
    const calcArcs = (S,V,E) => {
    const args = [S, E, radius(S,V,E)];
    [[0,0],[0,1],[1,0],[1,1]].forEach(([lg,sw]) => mkArc(qs(`#arc${lg}${sw}`), ...args, lg, sw));
    mkArc(qs(`#arc`), ...args, lgArcFl(S,V,E), sweepFl(S,V,E));
    };
    let ptNum = 0;
    qs('svg').addEventListener('click', evt => {
    const x = evt.x - 10, y = evt.y - 10;
    pts[ptNum] = [x, y];
    qs('#pt' + ptNum).setAttribute('transform', `translate(${x},${y})`);
    if (ptNum++ === 2) {
    calcArcs(...pts);
    ptNum = 0;
    }
    });
    text {
    font-family: courier;
    font-size: 18px;
    fill: black;
    stroke: none;
    transform: translate(-5px,5px);
    }
    #arc00, #arc01 {
    stroke: red;
    }
    #arc10, #arc11 {
    stroke: blue;
    }
    #arc00, #arc10 {
    stroke-width: 4;
    stroke-dasharray: 5,5;
    }
    #arc01, #arc11 {
    stroke-width: 2;
    }
    rect {
    fill: none;
    stroke: black;
    height: 200px;
    width: 600px;
    }
    <svg height="200" width="600">
    <defs>
    <path id="arc" />
    <circle id="circ" cx="0" cy="0" r="10" />
    </defs>
    <g fill="none">
    <use xlink:href="#arc" stroke="black" stroke-width="12" />
    <use xlink:href="#arc" stroke="#ff8" stroke-width="10" />
    <path id="arc00" />
    <path id="arc01" />
    <path id="arc10" />
    <path id="arc11" />
    </g>
    <g fill="#ff8" stroke="black">
    <g id="pt0" transform="translate(-99,0)"><use xlink:href="#circ" /><text>S</text></g>
    <g id="pt1" transform="translate(-99,0)"><use xlink:href="#circ" /><text>V</text></g>
    <g id="pt2" transform="translate(-99,0)"><use xlink:href="#circ" /><text>E</text></g>
    </g>
    <rect />
    </svg>

    关于svg arc,如何在给定开始结束和通过点的情况下确定扫描和大弧标志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21816286/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com