gpt4 book ai didi

javascript - 如何将 TCanvas->Arc 值转换为 SVG Arc

转载 作者:行者123 更新时间:2023-12-01 00:56:56 25 4
gpt4 key购买 nike

我为我的公司编写了一个从图元文件到 SVG 的转换器(TCanvas->arc)。我已经完成了矩形或其他一些元素的转换,但我不知道如何转换圆弧。我用 JavaScript 编写代码。 :)

我有一个文件,我在缓冲区中读取它并获取值,但这对你来说并不有趣。

所以我们目前拥有我可以获得的所有值:点1,点2,开始,结束

给出了这 4 点,我现在应该画一个圆弧

    dc->Arc (Point1.x + offset->x,
Point1.y + offset->y,
Point2.x + offset->x,
Point2.y + offset->y,
Start.x + offset->x,
Start.y + offset->y,
Ende.x + offset->x,
Ende.y + offset->y);

他们当前正在使用此命令绘制圆弧。这里可以不关注偏移量。

如何从给定点获取所有信息以在 SVG 中绘制 Arc。

例如实际值:

         Point1: -50, -6
Point2: -10, 34
Start: -10, 34
End: -10, -6

         Point1:  1, 18
Point2: 41, 58
Start: 1, 18
End: 1, 58

我如何获得:大弧标志、扫描标志和旋转,以及我必须使用或计算哪些值才能正确绘制。

我尝试绘制它并查看了很多文档并尝试以书面形式创建它。

最佳答案

我已经想出了一些似乎有效的东西。它基于the documentation here .

我还没有彻底测试过。

我假设在 TCanvas 中,(0,0) 位于顶部。如果不是,您需要反转扫描和大弧标志的逻辑。

var svg = document.querySelector("svg");
var debug = svg.getElementById("debug");


function arc(x1, y1, x2, y2, x3, y3, x4, y4)
{
let xRadius = Math.abs(x2 - x1) / 2;
let yRadius = Math.abs(y2 - y1) / 2;
let xCentre = Math.min(x1, x2) + xRadius;
let yCentre = Math.min(y1, y2) + yRadius;

// get intercepts relative to ellipse centre
let startpt = interceptEllipseAndLine(xRadius, yRadius, x3 - xCentre, y3 - yCentre);
let endpt = interceptEllipseAndLine(xRadius, yRadius, x4 - xCentre, y4 - yCentre);
let largeArcFlag = isLargeArc(startpt, endpt) ? 1 : 0;

return ['M', xCentre + startpt.x, yCentre + startpt.y,
'A', xRadius, yRadius, 0, largeArcFlag, 0, xCentre + endpt.x, yCentre + endpt.y].join(' ');
}

// Finds the intercept of an ellipse and a line from centre to x0,y0
function interceptEllipseAndLine(xRadius, yRadius, x0,y0)
{
let den = Math.sqrt(xRadius * xRadius * y0 * y0 + yRadius * yRadius * x0 * x0);
let mult = xRadius * yRadius / den;
return {x: mult * x0, y: mult * y0};
}

// Returns true if the angle between the two intercept lines is >= 180deg
function isLargeArc(start, end)
{
let angle = Math.atan2(start.x * end.y - start.y * end.x, start.x * end.x + start.y * end.y);
return angle > 0;
}


let path1 = svg.getElementById("path1");
path1.setAttribute("d", arc(1, 18, 41, 58, 1, 18, 1, 58) );

let path2 = svg.getElementById("path2");
path2.setAttribute("d", arc(-50, -6, -10, 34, -10, 34, -10, -6) );
svg {
width: 400px;
}

path {
fill: none;
stroke: red;
stroke-width: 1px;
}
<svg viewBox="-100 -100 200 200">
<path id="path1"/>
<path id="path2"/>
</svg>

这里的版本添加了一些额外的形状以用于调试目的......

var svg = document.querySelector("svg");
var debug = svg.getElementById("debug");


function arc(x1, y1, x2, y2, x3, y3, x4, y4)
{
let xRadius = Math.abs(x2 - x1) / 2;
let yRadius = Math.abs(y2 - y1) / 2;
let xCentre = Math.min(x1, x2) + xRadius;
let yCentre = Math.min(y1, y2) + yRadius;

{
let rect = document.createElementNS(svg.namespaceURI, "rect");
rect.setAttribute("x", x1);
rect.setAttribute("y", y1);
rect.setAttribute("width", x2-x1);
rect.setAttribute("height", y2-y1);
debug.append(rect);

let ellipse = document.createElementNS(svg.namespaceURI, "ellipse");
ellipse.setAttribute("cx", xCentre);
ellipse.setAttribute("cy", yCentre);
ellipse.setAttribute("rx", xRadius);
ellipse.setAttribute("ry", yRadius);
debug.append(ellipse);

let start = document.createElementNS(svg.namespaceURI, "line");
start.setAttribute("x1", xCentre);
start.setAttribute("y1", yCentre);
start.setAttribute("x2", x3);
start.setAttribute("y2", y3);
debug.append(start);

let end = document.createElementNS(svg.namespaceURI, "line");
end.setAttribute("x1", xCentre);
end.setAttribute("y1", yCentre);
end.setAttribute("x2", x4);
end.setAttribute("y2", y4);
debug.append(end);
}

// get intercepts relative to ellipse centre
let startpt = interceptEllipseAndLine(xRadius, yRadius, x3 - xCentre, y3 - yCentre);
let endpt = interceptEllipseAndLine(xRadius, yRadius, x4 - xCentre, y4 - yCentre);
let largeArcFlag = isLargeArc(startpt, endpt) ? 1 : 0;

{
let circ = document.createElementNS(svg.namespaceURI, "circle");
circ.setAttribute("cx", xCentre + startpt.x);
circ.setAttribute("cy", yCentre + startpt.y);
circ.setAttribute("r", 1);
debug.append(circ);
}

return ['M', xCentre + startpt.x, yCentre + startpt.y,
'A', xRadius, yRadius, 0, largeArcFlag, 0, xCentre + endpt.x, yCentre + endpt.y].join(' ');
}

// Finds the intercept of an ellipse and a line from centre to x0,y0
function interceptEllipseAndLine(xRadius, yRadius, x0,y0)
{
let den = Math.sqrt(xRadius * xRadius * y0 * y0 + yRadius * yRadius * x0 * x0);
let mult = xRadius * yRadius / den;
return {x: mult * x0, y: mult * y0};
}

// Returns true if the angle between the two intercept lines is >= 180deg
function isLargeArc(start, end)
{
let angle = Math.atan2(start.x * end.y - start.y * end.x, start.x * end.x + start.y * end.y);
return angle > 0;
}


let path1 = svg.getElementById("path1");
path1.setAttribute("d", arc(1, 18, 41, 58, 1, 18, 1, 58) );

let path2 = svg.getElementById("path2");
path2.setAttribute("d", arc(-50, -6, -10, 34, -10, 34, -10, -6) );
svg {
width: 400px;
}

ellipse, rect, line {
fill: none;
stroke: lightgrey;
stroke-width: 0.5px;
}

path {
fill: none;
stroke: red;
stroke-width: 1px;
}
<svg viewBox="-100 -100 200 200">
<g id="debug"></g>

<path id="path1"/>
<path id="path2"/>
</svg>

更新:饼图

对于 Pie 函数,它应该与 arc() 几乎相同,但它会返回略有不同的路径。

function pie(x1, y1, x2, y2, x3, y3, x4, y4)
{
// ... rest of function is the same as arc() ...
return ['M', xCentre, yCentre,
'L', xCentre + startpt.x, yCentre + startpt.y,
'A', xRadius, yRadius, 0, largeArcFlag, 0, xCentre + endpt.x, yCentre + endpt.y,
'Z'].join(' ');
}

关于javascript - 如何将 TCanvas->Arc 值转换为 SVG Arc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56497636/

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