我读了一篇关于为我的一个项目创建球体的文章,可以找到here,并决定尝试将其移植到c语言,我正在使用的语言。我选择了二十面体方法,你从一个二十面体开始,然后从那里细分。问题是,我得到了seg故障,但它发生时,我试图细分它。但是如果我保持原样,不尝试细分,代码编译良好,没有错误。
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
#include <stdint.h>
struct Point
{
double x;
double y;
double z;
};
struct Triangle
{
int v1;
int v2;
int v3;
};
// normalizes a vertex and then adds it to an array
int add_vertex(struct Point verts[], struct Point point)
{
double length = (point.x * point.x) + (point.y * point.y) + (point.z * point.z);
int index = 0;
verts[index].x = point.x / length;
verts[index].y = point.y / length;
verts[index].z = point.z / length;
return index++;
}
// gets the middle of a triangle face but checks to make sure that no duplicate vertices are created
int get_middle_point(int p1, int p2, struct Triangle inds[], struct Point verts[], int cache[])
{
// check to see if the middle point is already calculated
uint64_t key = (p1 < p2) ? (p1, p2) : (p2, p1);
if (cache[key] != 0)
{
return cache[key];
}
// it isn't so calculate it
struct Point point1 = verts[p1];
struct Point point2 = verts[p2];
struct Point middle;
middle.x = (point1.x + point2.x) / 2.0;
middle.y = (point1.y + point2.y) / 2.0;
middle.z = (point1.z + point2.z) / 2.0;
// add middle vertex to unit sphere
int i = add_vertex(verts, middle);
return i;
}
// creates icosphere by subdividing icosahedron
void create_icosphere(int recursion_level, struct Point verts[], struct Triangle inds[])
{
// cache middle points
int middle_point_cache[1000];
// golden ratio
float t = 1 + sqrt(5) * 0.5;
// icosahedron cartisean coordinates from wikipedia
add_vertex(verts, (struct Point){-1, t, 0});
add_vertex(verts, (struct Point){1, t, 0});
add_vertex(verts, (struct Point){-1, -t, 0});
add_vertex(verts, (struct Point){1, -t, 0});
add_vertex(verts, (struct Point){0, -1, t});
add_vertex(verts, (struct Point){0, 1, t});
add_vertex(verts, (struct Point){0, -1, -t});
add_vertex(verts, (struct Point){0, 1, -t});
add_vertex(verts, (struct Point){t, 0, -1});
add_vertex(verts, (struct Point){t, 0, 1});
add_vertex(verts, (struct Point){-t, 0, -1});
add_vertex(verts, (struct Point){-t, 0, 1});
// icosahedron indices
// 5 faces around point 0
inds[0] = (struct Triangle){0, 11, 5};
inds[1] = (struct Triangle){0, 5, 1};
inds[2] = (struct Triangle){0, 1, 7};
inds[3] = (struct Triangle){0, 7, 10};
inds[4] = (struct Triangle){0, 10, 11};
// 5 adjacent faces
inds[5] = (struct Triangle){1, 5, 9};
inds[6] = (struct Triangle){5, 11, 4};
inds[7] = (struct Triangle){11, 10, 2};
inds[8] = (struct Triangle){10, 7, 6};
inds[9] = (struct Triangle){7, 1, 8};
// 5 faces around point 3
inds[10] = (struct Triangle){3, 9, 4};
inds[11] = (struct Triangle){3, 4, 2};
inds[12] = (struct Triangle){3, 2, 6};
inds[13] = (struct Triangle){3, 6, 8};
inds[14] = (struct Triangle){3, 8, 9};
// 5 adjacent faces
inds[15] = (struct Triangle){4, 9, 5};
inds[16] = (struct Triangle){2, 4, 11};
inds[17] = (struct Triangle){6, 2, 10};
inds[18] = (struct Triangle){8, 6, 7};
inds[19] = (struct Triangle){9, 8, 1};
// subdivide icosahedron
for (int i = 0; i < recursion_level; i++)
{
// create new array for newly created triangle faces
struct Triangle faces_2[1000];
int faces_2_index = 0;
for (int j = 0; j < 20; j++)
{
struct Triangle tri = inds[j];
// get the centroid of each triangle face
int a = get_middle_point(tri.v1, tri.v2, faces_2, verts, middle_point_cache);
int b = get_middle_point(tri.v2, tri.v3, faces_2, verts, middle_point_cache);
int c = get_middle_point(tri.v3, tri.v1, faces_2, verts, middle_point_cache);
// add new faces to new faces array
faces_2[faces_2_index++] = (struct Triangle){tri.v1, a, c};
faces_2[faces_2_index++] = (struct Triangle){tri.v2, b, a};
faces_2[faces_2_index++] = (struct Triangle){tri.v3, c, b};
faces_2[faces_2_index++] = (struct Triangle){tri.v1, tri.v2, tri.v3};
}
// copy over contents from new array to indices
for (int j = 0; j < faces_2_index; j++)
{
inds[j] = faces_2[j];
}
}
}
int main()
{
// example usage. works with a subdivision level of 0 but anything higher causes a seg fault
struct Point vertices[1000];
struct Triangle indices[1000];
create_icosphere(2, vertices, indices);
printf("No errors\n");
return 0;
}
我将问题缩小到细分循环或get_middle_point
函数(在细分循环中调用)。但我不知道为什么会有错误,甚至如何解决它们。这是我的编译器目前针对细分循环内的seg错误error in nested subdivide loop所指向的位置。
2条答案
按热度按时间mfuanj7w1#
在细分循环中,我创建了一个新数组
但随后写出出界,
所以为了解决我的问题,我只需要增加
而且很管用我保持它1000作为一个样本大小,但现在很快就会改变。
l7wslrjt2#
下面的代码不太可能实现您所认为的功能
这段代码接受一个数组(指向内存中某个位置的指针)和一个“point”。使用点信息计算长度(三维空间中的距离)。然后在0处创建一个“索引”,并将verts数组的第零个元素的字段设置为按长度标准化的值。到目前为止,一切顺利(假设这是你的意图)。
然后你增加'index',它不是无效的,但它是无用的。你在函数中声明了index,使它成为一个堆栈分配的变量。一旦函数返回,所有这些值就消失了。下一次调用该函数时,您将再次设置第零个元素。给定的函数将永远不会设置除元素[0]以外的任何内容。
你可以做几件事来纠正这一点,但它们都会影响调用代码的结构。一件事是将
index
作为函数参数传入。即在每次调用中指定索引值。如果你想增加索引,你需要将索引值作为指针(int *index
)传递,而不是在函数内部初始化它。简单地让函数返回一个Point结构可能会更干净。但是要做到这一点,你需要了解C中的内存是如何工作的。您可以参考此问题以获得帮助:Return a
struct
from a function in C简而言之,C变量(通常)存在于“堆”内存中(由malloc/alloc/free等函数控制)或堆栈中,它们只存在于包含函数的上下文中。Seg-faults发生在您超出不属于您的内存时。通常在步进数组的末尾时(相对于零)。
通常,一个好的调试器可以帮助你理解错误发生在哪里,但不能理解为什么。“为什么”往往很简单,但可能会变得非常复杂。仍然知道在哪里可以帮助你追溯到为什么。