如何通过算法生成十二面体的顶点?
我希望四面体的质心位于(0, 0, 0)
。
来自维基百科:
以下笛卡尔坐标定义了以原点为中心并适当缩放和定向的十二面体的顶点:
(±1、±1、±1)
(0, ±1/φ, ±φ)
(±1/φ, ±φ, 0)
(±φ, 0, ±1/φ)
其中 φ = (1 + √5) / 2 是黄金比例(也写为 τ)≈ 1.618。边长为 2/φ = √5 – 1。包含球体的半径为 √3。
我发现这个描述比一大段 C# 代码更简洁和信息丰富。(-:
由于这个问题现在是谷歌搜索的最高结果(数学上的欺骗是#2),我想我不妨添加一些代码。
下面是一个完整的控制台程序,应该可以编译和运行,并且通常是不言自明的。
该算法基于Wikipedia 文章(谢谢,来自 math.stackoverflow.com 的 mt_)
此代码应为您打印正确的顶点列表。您最关心的是方法Program.MakeDodecahedron
,但是不要只是复制和粘贴它,因为您需要修改它以使用您自己的顶点数据结构而不是我的模拟Vertex
对象。您可以轻松使用XNA 的 Vector3,它有一个与 my 签名完全相同的构造函数Vertex
。另外因为我的Vertex.ToString
方法很hacky,这个程序在使用时可能会打印一个丑陋的输出表,Vector3
所以请记住这一点。
另外,请注意,这是一个(不完美的)演示。例如,如果生成许多四面体,您将不必要地为每次调用重新计算常数(例如黄金分割率)。
使用 XNA,特别是如果您使用Microsoft.Xna.Framework
,您还可以轻松地将十二面体渲染为 3D。为此,您可以修改本教程中的代码。
using System;
using System.Collections.Generic;
namespace DodecahedronVertices
{
class Program
{
static void Main()
{
// Size parameter: This is distance of each vector from origin
var r = Math.Sqrt(3);
Console.WriteLine("Generating a dodecahedron with enclosing sphere radius: " + r);
// Make the vertices
var dodecahedron = MakeDodecahedron(r);
// Print them out
Console.WriteLine(" X Y Z");
Console.WriteLine(" ==========================");
for (var i = 0; i < dodecahedron.Count; i++)
{
var vertex = dodecahedron[i];
Console.WriteLine("{0,2}:" + vertex, i + 1);
}
Console.WriteLine("\nDone!");
Console.ReadLine();
}
/// <summary>
/// Generates a list of vertices (in arbitrary order) for a tetrahedron centered on the origin.
/// </summary>
/// <param name="r">The distance of each vertex from origin.</param>
/// <returns></returns>
private static IList<Vertex> MakeDodecahedron(double r)
{
// Calculate constants that will be used to generate vertices
var phi = (float)(Math.Sqrt(5) - 1) / 2; // The golden ratio
var a = 1 / Math.Sqrt(3);
var b = a / phi;
var c = a * phi;
// Generate each vertex
var vertices = new List<Vertex>();
foreach (var i in new[] { -1, 1 })
{
foreach (var j in new[] { -1, 1 })
{
vertices.Add(new Vertex(
0,
i * c * r,
j * b * r));
vertices.Add(new Vertex(
i * c * r,
j * b * r,
0));
vertices.Add(new Vertex(
i * b * r,
0,
j * c * r));
foreach (var k in new[] { -1, 1 })
vertices.Add(new Vertex(
i * a * r,
j * a * r,
k * a * r));
}
}
return vertices;
}
}
/// <summary>
/// A placeholder class to store data on a point in space. Don't actually use this, write a better class (or just use Vector3 from XNA).
/// </summary>
class Vertex
{
double x;
double y;
double z;
public Vertex(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
public override string ToString()
{
var s = String.Format("{0,8:F2},{1,8:F2},{2,8:F2}", x, y, z);
return s;
}
}
}
由于我的代码可能非常冗长且分散,我建议以支持折叠 for 循环和其他代码结构的方式阅读它。
以 P(0, 0, 0) 为中心的十二面体和以半径为 r 的球体为界的顶点的笛卡尔坐标由下式给出:
P(±r/√3,±r/√3,±r/√3)
P(0,±r/(√3*φ),±(r*φ)/√3)
P(± r/(√3*φ), ± (r*φ)/√3, 0)
P(± (r*φ)/√3, 0, ± r/(√3*φ))
其中 φ = (1 + √5) / 2 是黄金比例(也写为 τ)≈ 1.618。
这是一个以 0 顶点为中心的黎曼曲面立体投影。(抱歉,我找不到如何发布数学符号)
其中 T 是黄金比例,令 a = 1/T^2 并让复共轭对 b+-ic 定义为 b=sqrt(5)/4 和 c=sqrt(3)/4。将这三个点旋转 0、120 和 240 度,这样您现在就有了 9 个点,都在单位圆内。
使用映射 z -> -1/z 将每个点映射到单位圆外的图像。在零和无穷远处添加一个点,您现在拥有十二面体的所有顶点。
如果你想让你的十二面体在球体上,做通常的立体背图,使单位圆进入赤道。通过通常的刻划过程,这也会给您一个以顶点为中心的立方体或四面体,但分别旋转了大约 37.76 度或 22.24 度。