반지름 25 인 (200,200)을 중심으로 한 원이 주어지면 270도에서 135도 사이의 원호와 270도에서 45도 사이의 원호를 어떻게 그릴 수 있습니까?
0 도는 x 축 (오른쪽)에서 오른쪽을 의미하고 (3시 방향을 의미) 270 도는 12시 위치를 의미하고 90은 6시 위치를 의미
더 일반적으로 원의 일부에 대한 호의 경로는 무엇입니까?
x, y, r, d1, d2, direction
의미
center (x,y), radius r, degree_start, degree_end, direction
답변
@wdebeaum의 훌륭한 답변을 확장하여 다음은 호형 경로를 생성하는 방법입니다.
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
function describeArc(x, y, radius, startAngle, endAngle){
var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);
var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");
return d;
}
쓰다
document.getElementById("arc1").setAttribute("d", describeArc(200, 400, 100, 0, 180));
그리고 당신의 HTML에서
<path id="arc1" fill="none" stroke="#446688" stroke-width="20" />
답변
elliptical A
rc 명령 을 사용하려고합니다 . 불행히도, 이것은 당신이 가지고있는 극좌표 (반지름, 각도) 대신 시작점과 끝점의 데카르트 좌표 (x, y)를 지정해야하므로 수학을 수행해야합니다. 다음은 작동하지 않아야하지만 테스트하지는 않았지만 상당히 자명 한 JavaScript 함수입니다.
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = angleInDegrees * Math.PI / 180.0;
var x = centerX + radius * Math.cos(angleInRadians);
var y = centerY + radius * Math.sin(angleInRadians);
return [x,y];
}
어느 각도가 어떤 클록 위치에 대응하는지는 좌표계에 의존한다; 필요에 따라 sin / cos 용어를 바꾸거나 무효화하면됩니다.
arc 명령에는 다음과 같은 매개 변수가 있습니다.
rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y
첫 번째 예 :
rx
타원이 아닌 원을 원하므로 = ry
= 25 및 x-axis-rotation
= 0입니다. M
위의 함수를 사용하여 시작 좌표 (이동해야 함)와 끝 좌표 (x, y)를 모두 계산 하여 각각 (200, 175) 및 약 (182.322, 217.678)을 산출 할 수 있습니다. 지금까지 이러한 제약 조건이 주어지면 실제로 그릴 수있는 4 개의 호가 있으므로 두 플래그가 그 중 하나를 선택합니다. large-arc-flag
각도가 감소하는 방향 ( = 0) 으로 작은 호 ( = 0) 를 그리려고 할 것입니다 sweep-flag
. 모두 함께 SVG 경로는 다음과 같습니다.
M 200 175 A 25 25 0 0 0 182.322 217.678
두 번째 예의 경우 (같은 방향으로 가고 큰 원호로 이동한다고 가정하면) SVG 경로는 다음과 같습니다.
M 200 175 A 25 25 0 1 0 217.678 217.678
다시, 나는 이것을 테스트하지 않았습니다.
@clocksmith와 같이 왜 그들이이 API를 선택했는지 궁금하다면 구현 노트를 살펴보십시오 . 여기에는 두 가지 가능한 아크 매개 변수화, “종료점 매개 변수화”(선택한 것) 및 “중심 매개 변수화”(질문이 사용하는 것과 유사 함)가 설명되어 있습니다. “엔드 포인트 매개 변수화”에 대한 설명에서 다음과 같이 말합니다.
엔드 포인트 매개 변수화의 장점 중 하나는 모든 경로 명령이 새로운 “현재 점”의 좌표로 끝나는 일관된 경로 구문을 허용한다는 것입니다.
따라서 기본적으로 아크는 별도의 객체가 아닌 더 큰 경로의 일부로 간주되는 아크의 부작용입니다. SVG 렌더러가 불완전하면 경로 구성 요소를 건너 뛸 수 있다고 가정합니다. 어떤 인수가 필요한지 알고있는 한 렌더링 방법을 모릅니다. 또는 많은 구성 요소가있는 경로의 다른 청크를 병렬 렌더링 할 수 있습니다. 또는 복잡한 경로의 길이에 따라 반올림 오류가 발생하지 않도록하기 위해 수행했을 수도 있습니다.
구현 노트는 두 개의 매개 변수화 사이에서 변환하기 위해 더 수학적 의사 코드가 있기 때문에 원래 질문에 유용합니다 (처음 에이 답변을 작성할 때 알지 못했습니다).
답변
opsb의 답변을 약간 수정 하고 서클 섹터에 대한 지원을 작성했습니다.
http://codepen.io/anon/pen/AkoGx
JS
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
function describeArc(x, y, radius, startAngle, endAngle){
var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);
var arcSweep = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, arcSweep, 0, end.x, end.y,
"L", x,y,
"L", start.x, start.y
].join(" ");
return d;
}
document.getElementById("arc1").setAttribute("d", describeArc(200, 400, 100, 0, 220));
HTML
<svg>
<path id="arc1" fill="orange" stroke="#446688" stroke-width="0" />
</svg>
답변
이것은 오래된 질문이지만 코드가 유용하다는 것을 알았고 3 분의 생각을 절약했습니다. 🙂 @opsb 의 답변에 작은 확장을 추가하고 있습니다.
이 호를 슬라이스로 변환하려면 (채우기 위해) 코드를 약간 수정할 수 있습니다.
function describeArc(x, y, radius, spread, startAngle, endAngle){
var innerStart = polarToCartesian(x, y, radius, endAngle);
var innerEnd = polarToCartesian(x, y, radius, startAngle);
var outerStart = polarToCartesian(x, y, radius + spread, endAngle);
var outerEnd = polarToCartesian(x, y, radius + spread, startAngle);
var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", outerStart.x, outerStart.y,
"A", radius + spread, radius + spread, 0, largeArcFlag, 0, outerEnd.x, outerEnd.y,
"L", innerEnd.x, innerEnd.y,
"A", radius, radius, 0, largeArcFlag, 1, innerStart.x, innerStart.y,
"L", outerStart.x, outerStart.y, "Z"
].join(" ");
return d;
}
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
var path = describeArc(150, 150, 50, 30, 0, 50)
document.getElementById("p").innerHTML = path
document.getElementById("path").setAttribute('d',path)
<p id="p">
</p>
<svg width="300" height="300" style="border:1px gray solid">
<path id="path" fill="blue" stroke="cyan"></path>
</svg>
그리고 당신은 간다!
답변
@opsb의 대답은 깔끔하지만 @Jithin이 지적했듯이 중심점이 정확하지 않습니다. 각도가 360이면 아무 것도 그려지지 않습니다.
@Jithin은 360 문제를 해결했지만 360도 미만을 선택하면 아크 루프를 닫는 선이 생겨 필요하지 않습니다.
나는 그것을 고치고 아래 코드에 애니메이션을 추가했다.
function myArc(cx, cy, radius, max){
var circle = document.getElementById("arc");
var e = circle.getAttribute("d");
var d = " M "+ (cx + radius) + " " + cy;
var angle=0;
window.timer = window.setInterval(
function() {
var radians= angle * (Math.PI / 180); // convert degree to radians
var x = cx + Math.cos(radians) * radius;
var y = cy + Math.sin(radians) * radius;
d += " L "+x + " " + y;
circle.setAttribute("d", d)
if(angle==max)window.clearInterval(window.timer);
angle++;
}
,5)
}
myArc(110, 110, 100, 360);
<svg xmlns="http://www.w3.org/2000/svg" style="width:220; height:220;">
<path d="" id="arc" fill="none" stroke="red" stroke-width="2" />
</svg>
답변
@Ahtenus의 답변, 특히 Ray Hulha의 의견에 대해 언급하고 싶었습니다.
이 코드 펜이 작동하지 않는 이유는 HTML에 획 너비가 0이므로 결함이 있기 때문입니다.
나는 그것을 고치고 여기에 두 번째 예를 추가했다 : http://codepen.io/AnotherLinuxUser/pen/QEJmkN .
html :
<svg>
<path id="theSvgArc"/>
<path id="theSvgArc2"/>
</svg>
관련 CSS :
svg {
width : 500px;
height : 500px;
}
path {
stroke-width : 5;
stroke : lime;
fill : #151515;
}
자바 스크립트 :
document.getElementById("theSvgArc").setAttribute("d", describeArc(150, 150, 100, 0, 180));
document.getElementById("theSvgArc2").setAttribute("d", describeArc(300, 150, 100, 45, 190));
답변
이미지와 파이썬
더 명확하게하고 다른 솔루션을 제공하십시오. Arc
[ A
] 명령은 현재 위치를 시작점으로 사용하므로 먼저 Moveto
[M] 명령 을 사용해야 합니다.
그런 다음의 매개 변수 Arc
는 다음과 같습니다.
rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, xf, yf
예를 들어 다음 svg 파일을 정의하면 :
<svg viewBox="0 0 500 500">
<path fill="red" d="
M 250 250
A 100 100 0 0 0 450 250
Z"/>
</svg>
M
매개 변수 xf
및 yf
의 시작점으로 시작점을 설정합니다 A
.
우리는 원을 찾고 있으므로 기본적으로 그렇게하는 rx
것과 동일하게 설정 하면 시작점과 끝점과 교차하는 ry
모든 반경의 원을 찾으려고 시도합니다 rx
.
import numpy as np
def write_svgarc(xcenter,ycenter,r,startangle,endangle,output='arc.svg'):
if startangle > endangle:
raise ValueError("startangle must be smaller than endangle")
if endangle - startangle < 360:
large_arc_flag = 0
radiansconversion = np.pi/180.
xstartpoint = xcenter + r*np.cos(startangle*radiansconversion)
ystartpoint = ycenter - r*np.sin(startangle*radiansconversion)
xendpoint = xcenter + r*np.cos(endangle*radiansconversion)
yendpoint = ycenter - r*np.sin(endangle*radiansconversion)
#If we want to plot angles larger than 180 degrees we need this
if endangle - startangle > 180: large_arc_flag = 1
with open(output,'a') as f:
f.write(r"""<path d=" """)
f.write("M %s %s" %(xstartpoint,ystartpoint))
f.write("A %s %s 0 %s 0 %s %s"
%(r,r,large_arc_flag,xendpoint,yendpoint))
f.write("L %s %s" %(xcenter,ycenter))
f.write(r"""Z"/>""" )
else:
with open(output,'a') as f:
f.write(r"""<circle cx="%s" cy="%s" r="%s"/>"""
%(xcenter,ycenter,r))
내가 쓴 이 게시물 에서 더 자세한 설명을 할 수 있습니다 .