簡體   English   中英

圓形近似,是一個有 N 個角的正多邊形

[英]Circle approximation that is a regular polygon with N corners

我必須實現圓形近似的想法,即具有 N 個角的正多邊形,而 N 由用戶定義。

例如,如果 N=3 我會有一個三角形。 當 n=5 時,我會形成一個類似於圓形的形狀。 隨着 N 的增加,我會越來越接近圓形。

這個想法與以下問題/解決方案中的提問和回答非常相似: 繪制圓形內接的規則多邊形,但是,他們使用了 raphael.js 而不是 D3.js。

我試圖做的事情:

var vis = d3.select("body").append("svg")
         .attr("width", 1000)
         .attr("height", 667);


var svg = d3.select('svg');
var originX = 200;
var originY = 200;
var outerCircleRadius = 60;


var outerCircle = svg.append("circle").attr({
    cx: originX,
    cy: originY,
    r: outerCircleRadius,
    fill: "none",
    stroke: "black"
});

var chairWidth = 10;

var chairOriginX = originX + ((outerCircleRadius) * Math.sin(0));
var chairOriginY = originY - ((outerCircleRadius) * Math.cos(0));



var chair = svg.append("rect").attr({
    x: chairOriginX - (chairWidth / 2),
    y: chairOriginY - (chairWidth / 2),
    width: chairWidth,
    opacity: 1,
    height: 20,
    fill: "none",
    stroke: "blue"
});

var n_number = 5
var n_angles = 360/n_number
var angle_start=0;
var angle_next;

console.log(chair.node().getBBox().x);
console.log(chair.node().getBBox().y);
chair.attr("transform", "rotate(" + (angle_start+n_angles+n_angles) + ", 200, 200)");



        var circle = svg.append("circle")
                    .attr("cx", 195)
                    .attr("cy", 135)
                    .attr("r", 50)
                    .attr("fill", "red");




var chairOriginX2 = originX + ((outerCircleRadius) * Math.sin(0));
var chairOriginY2 = originY - ((outerCircleRadius) * Math.cos(0));


var chair2 = svg.append("rect").attr({
    x: chairOriginX2 - (chairWidth / 2),
    y: chairOriginY2 - (chairWidth / 2),
    width: chairWidth,
    opacity: 1,
    height: 20,
    fill: "none",
    stroke: "blue"
});

console.log(chair2.node().getBBox().x);
console.log(chair2.node().getBBox().y);

我的想法是行不通的,試圖創建一個圓(“outerCircle”),我將在圓的圓周(“chair.attr(“transform”...))內滑動,基於 N,獲得幾個不同的 (x,y) 坐標。然后,我將 (x,y) 坐標提供給多邊形。

我相信我解決這個問題的方法是錯誤的。 此外,我被卡住的部分是我無法繼續在圓周上滑動並存儲每個不同的 (x,y) 坐標。 我試過“console.log(chair2.node().getBBox().x);” 但它總是存儲與原點相同的坐標。

為了清楚起見,我簡化了您的代碼。 要獲得圓上一點的 x,您使用Math.cos(angle) ,對於 y 您使用Math.sin(angle) 這是你的錯誤。 現在您可以更改n_number的值

 var SVG_NS = 'http://www.w3.org/2000/svg'; var originX = 200; var originY = 200; var outerCircleRadius = 60; var polygon = document.createElementNS(SVG_NS, 'polygon'); svg.appendChild(polygon); let points=""; var n_number = 5; var n_angles = 2*Math.PI/n_number // building the value of the `points` attribute for the polygon for(let i = 0; i < n_number; i++){ let x = originX + outerCircleRadius * Math.cos(i*n_angles); let y = originY + outerCircleRadius * Math.sin(i*n_angles); points += ` ${x},${y} `; } // setting the value of the points attribute of the polygon polygon.setAttributeNS(null,"points",points)
 svg{border:1px solid;width:90vh;} polygon{fill: none; stroke: blue}
 <svg id="svg" viewBox = "100 100 200 200" > <circle cx="200" cy="200" r="60" fill="none" stroke="black" /> </svg>

這是另一個演示,我使用輸入類型范圍來更改n_number變量

 var SVG_NS = 'http://www.w3.org/2000/svg'; var originX = 200; var originY = 200; var outerCircleRadius = 60; var polygon = document.createElementNS(SVG_NS, 'polygon'); svg.appendChild(polygon); let points=""; var n_number = 5; setPoints(n_number); theRange.addEventListener("input", ()=>{ n_number = theRange.value; setPoints(n_number) }); function setPoints(n_number){ var n_angles = 2*Math.PI/n_number; points = "" // building the value of the `points` attribute for the polygon for(let i = 0; i < n_number; i++){ let x = originX + outerCircleRadius * Math.cos(i*n_angles); let y = originY + outerCircleRadius * Math.sin(i*n_angles); points += ` ${x},${y} `; } // setting the value of the points attribute of the polygon polygon.setAttributeNS(null,"points",points); }
 svg{border:1px solid; width:90vh;} polygon{fill: none; stroke: blue}
 <p><input type="range" min="3" max="50" value="5" id="theRange" /></p> <svg id="svg" viewBox = "100 100 200 200" > <circle cx="200" cy="200" r="60" fill="none" stroke="black" /> </svg>

enxaneta提供的答案非常好,當然是對此的經典方法。 然而,我經常喜歡讓瀏覽器做三角函數而不是我自己做。 典型的例子包括我的回答“復雜圓圖”一個“SVG標記-可以我設置的長度和角度?” . 我什至不確定它們是否優於更經典的,但我喜歡它們的簡單性。


我的解決方案側重於SVGGeometryElement及其方法.getTotalLength().getPointAtLength() 由於SVGCircleElement接口擴展了該接口,因此這些方法可用於具有以下含義的 SVG 圓:

  1. .getTotalLength() :圓的周長。

  2. .getPointAtLength() :給定長度的圓上 x/y 坐標中的點。 每個定義的測量從 3 點鍾位置開始並順時針進行。

鑒於這些解釋,很明顯您可以將圓的總長度(即它的周長)除以您的近似值的點數。 這為您提供了沿圓到下一個點的步距。 通過總結這些距離,您可以使用第二種方法來獲得每個點的 x/y 坐標。

可以按照以下方式進行編碼:

// Calculate step length as circumference / number of points.
const step = circleElement.getTotalLength() / count; 

// Build an array of points on the circle.
const data = Array.from({length: count}, (_, i) => {
  const point = circleElement.getPointAtLength(i * step);   // Get coordinates of next point.
  return `${point.x},${point.y}`; 
});
polygon.attr("points", data.join(" "));

光滑和容易! 不涉及三角函數。

最后,一個完整的工作演示:

 // Just setup, not related to problem. const svg = d3.select("body") .append("svg") .attr("width", 500) .attr("height", 500); const circle = svg.append("circle") .attr("cx", "150") .attr("cy", "150") .attr("r", "100") .attr("fill", "none") .attr("stroke", "black"); const polygon = svg.append("polygon") .attr("fill", "none") .attr("stroke", "blue"); const circleElement = circle.node(); const ranger = d3.select("#ranger").on("input", update); const label = d3.select("label"); // This function contains all the relevant logic. function update() { let count = ranger.node().value; label.text(count); // Calculate step length as circumference / number of points. const step = circleElement.getTotalLength() / count; // Build an array of all points on the circle. const data = Array.from({length: count}, (_, i) => { const point = circleElement.getPointAtLength(i * step); // Get coordinates of next point. return `${point.x},${point.y}`; }); polygon.attr("points", data.join(" ")); } update();
 <script src="https://d3js.org/d3.v5.js"></script> <p> <input id="ranger" type="range" min="3" max="15" value="5"> <label for="ranger"></label> </p>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM