如何根据度数和坐标绘制椭圆

How to draw an ellipse from degree and coordinates

我正在使用 D3 图表绘制椭圆。我没有 Rx、Cx、Ry、Cy,但在每个 8 度的间隔都有坐标(x0 和 y0)。

θ (°)   x(θ)    y(θ)
0.00    0.00    3.09
8.00    0.48    3.37
16.00   0.94    3.59
24.00   1.39    3.74
32.00   1.81    3.81
40.00   2.20    3.81
48.00   2.54    3.74
56.00   2.83    3.59
64.00   3.07    3.37
72.00   3.25    3.09
80.00   3.36    2.75
88.00   3.41    2.35
96.00   3.40    1.91
104.00  3.31    1.43
112.00  3.17    0.92
120.00  2.96    0.40
128.00  2.69    -0.13
136.00  2.37    -0.66
144.00  2.01    -1.18
152.00  1.60    -1.67
160.00  1.17    -2.14
168.00  0.71    -2.56
176.00  0.24    -2.93
184.00  -0.24   -3.24
192.00  -0.71   -3.49
200.00  -1.17   -3.67
208.00  -1.60   -3.78
216.00  -2.01   -3.82
224.00  -2.37   -3.78
232.00  -2.69   -3.67
240.00  -2.96   -3.49
248.00  -3.17   -3.24
256.00  -3.31   -2.93
264.00  -3.40   -2.56
272.00  -3.41   -2.14
280.00  -3.36   -1.67
288.00  -3.25   -1.18
296.00  -3.07   -0.66
304.00  -2.83   -0.13
312.00  -2.54   0.40
320.00  -2.20   0.92
328.00  -1.81   1.43
336.00  -1.39   1.91
344.00  -0.94   2.35
352.00  -0.48   2.75
360.00  0.00    3.09

我们如何绘制连接所有点的椭圆?举个例子会很有帮助。

因为您拥有所有笛卡尔坐标,所以这里的最佳选择是使用 <path> 元素而不是 <ellipse>。此外,由于同样的原因,您实际上既不需要 D3 也不需要学位(您的第一列)。然而,如果你想坚持使用 D3,你只需要一个线生成器,就像这样:

const lineGenerator = d3.line()
    .x(d => xScale(d.xPos))
    .y(d => yScale(d.yPos));

我将您的 x(θ)y(θ) 重命名为 xPosyPos。另外,我用的是刻度(但要注意范围间隔,它们必须相同)。

这是结果:

const csv = `deg,xPos,yPos
0.00,0.00,3.09
8.00,0.48,3.37
16.00,0.94,3.59
24.00,1.39,3.74
32.00,1.81,3.81
40.00,2.20,3.81
48.00,2.54,3.74
56.00,2.83,3.59
64.00,3.07,3.37
72.00,3.25,3.09
80.00,3.36,2.75
88.00,3.41,2.35
96.00,3.40,1.91
104.00,3.31,1.43
112.00,3.17,0.92
120.00,2.96,0.40
128.00,2.69,-0.13
136.00,2.37,-0.66
144.00,2.01,-1.18
152.00,1.60,-1.67
160.00,1.17,-2.14
168.00,0.71,-2.56
176.00,0.24,-2.93
184.00,-0.24,-3.24
192.00,-0.71,-3.49
200.00,-1.17,-3.67
208.00,-1.60,-3.78
216.00,-2.01,-3.82
224.00,-2.37,-3.78
232.00,-2.69,-3.67
240.00,-2.96,-3.49
248.00,-3.17,-3.24
256.00,-3.31,-2.93
264.00,-3.40,-2.56
272.00,-3.41,-2.14
280.00,-3.36,-1.67
288.00,-3.25,-1.18
296.00,-3.07,-0.66
304.00,-2.83,-0.13
312.00,-2.54,0.40
320.00,-2.20,0.92
328.00,-1.81,1.43
336.00,-1.39,1.91
344.00,-0.94,2.35
352.00,-0.48,2.75
360.00,0.00,3.09`;

const data = d3.csvParse(csv, d3.autoType);
const svg = d3.select("svg");
const xScale = d3.scaleLinear()
  .domain(d3.extent(data, d => d.xPos))
  .range([85, 215]);
const yScale = d3.scaleLinear()
  .domain(d3.extent(data, d => d.yPos))
  .range([10, 140]);
const lineGenerator = d3.line()
  .x(d => xScale(d.xPos))
  .y(d => yScale(d.yPos));
const ellipse = svg.append("path")
  .datum(data)
  .attr("d", lineGenerator);
path {
  fill: none;
  stroke-width: 3px;
  stroke: steelblue;
}
<script src="https://d3js.org/d3.v6.min.js"></script>
<svg></svg>

因为你有这么多点,所以椭圆看起来不错,特别是在像这样的小 SVG 中。但是你也可以通过在点之间插值来改善它的外观,例如:

const lineGenerator = d3.line()
    .x(d => xScale(d.xPos))
    .y(d => yScale(d.yPos))
    .curve(d3.curveCatmullRom);

这是一个大 SVG 并排的结果(插值路径是红色的):

const csv = `deg,xPos,yPos
0.00,0.00,3.09
8.00,0.48,3.37
16.00,0.94,3.59
24.00,1.39,3.74
32.00,1.81,3.81
40.00,2.20,3.81
48.00,2.54,3.74
56.00,2.83,3.59
64.00,3.07,3.37
72.00,3.25,3.09
80.00,3.36,2.75
88.00,3.41,2.35
96.00,3.40,1.91
104.00,3.31,1.43
112.00,3.17,0.92
120.00,2.96,0.40
128.00,2.69,-0.13
136.00,2.37,-0.66
144.00,2.01,-1.18
152.00,1.60,-1.67
160.00,1.17,-2.14
168.00,0.71,-2.56
176.00,0.24,-2.93
184.00,-0.24,-3.24
192.00,-0.71,-3.49
200.00,-1.17,-3.67
208.00,-1.60,-3.78
216.00,-2.01,-3.82
224.00,-2.37,-3.78
232.00,-2.69,-3.67
240.00,-2.96,-3.49
248.00,-3.17,-3.24
256.00,-3.31,-2.93
264.00,-3.40,-2.56
272.00,-3.41,-2.14
280.00,-3.36,-1.67
288.00,-3.25,-1.18
296.00,-3.07,-0.66
304.00,-2.83,-0.13
312.00,-2.54,0.40
320.00,-2.20,0.92
328.00,-1.81,1.43
336.00,-1.39,1.91
344.00,-0.94,2.35
352.00,-0.48,2.75
360.00,0.00,3.09`;

const data = d3.csvParse(csv, d3.autoType);
const svg = d3.select("svg");
const xScale = d3.scaleLinear()
  .domain(d3.extent(data, d => d.xPos))
  .range([10, 490]);
const yScale = d3.scaleLinear()
  .domain(d3.extent(data, d => d.yPos))
  .range([10, 490]);
const lineGenerator = d3.line()
  .x(d => xScale(d.xPos))
  .y(d => yScale(d.yPos));
const ellipse = svg.append("path")
  .datum(data)
  .attr("d", lineGenerator);

const ellipse2 = svg.append("path")
  .attr("class", "path2")
  .attr("transform", "translate(500,0)")
  .datum(data)
  .attr("d", d => lineGenerator.curve(d3.curveCatmullRom)(d));
path {
  fill: none;
  stroke-width: 3px;
  stroke: steelblue;
}

.path2 {
  stroke: orangered;
}
<script src="https://d3js.org/d3.v6.min.js"></script>
<svg width="1000" height="500"></svg>