Fixed make_cylinder() / make_sphere() functions to produce meshes

without errors.
This commit is contained in:
bubnikv 2019-05-04 14:03:50 +02:00
parent 8e007c5b6a
commit e515ef4fbe

View file

@ -1847,116 +1847,101 @@ TriangleMesh make_cube(double x, double y, double z) {
// Generate the mesh for a cylinder and return it, using // Generate the mesh for a cylinder and return it, using
// the generated angle to calculate the top mesh triangles. // the generated angle to calculate the top mesh triangles.
// Default is 360 sides, angle fa is in radians. // Default is 360 sides, angle fa is in radians.
TriangleMesh make_cylinder(double r, double h, double fa) { TriangleMesh make_cylinder(double r, double h, double fa)
{
size_t n_steps = (size_t)ceil(2. * PI / fa);
double angle_step = 2. * PI / n_steps;
Pointf3s vertices; Pointf3s vertices;
std::vector<Vec3crd> facets; std::vector<Vec3crd> facets;
vertices.reserve(2 * n_steps + 2);
facets.reserve(4 * n_steps);
// 2 special vertices, top and bottom center, rest are relative to this // 2 special vertices, top and bottom center, rest are relative to this
vertices.emplace_back(Vec3d(0.0, 0.0, 0.0)); vertices.emplace_back(Vec3d(0.0, 0.0, 0.0));
vertices.emplace_back(Vec3d(0.0, 0.0, h)); vertices.emplace_back(Vec3d(0.0, 0.0, h));
// adjust via rounding to get an even multiple for any provided angle.
double angle = (2*PI / floor(2*PI / fa));
// for each line along the polygon approximating the top/bottom of the // for each line along the polygon approximating the top/bottom of the
// circle, generate four points and four facets (2 for the wall, 2 for the // circle, generate four points and four facets (2 for the wall, 2 for the
// top and bottom. // top and bottom.
// Special case: Last line shares 2 vertices with the first line. // Special case: Last line shares 2 vertices with the first line.
unsigned id = vertices.size() - 1; Vec2d p = Eigen::Rotation2Dd(0.) * Eigen::Vector2d(0, r);
vertices.emplace_back(Vec3d(sin(0) * r , cos(0) * r, 0));
vertices.emplace_back(Vec3d(sin(0) * r , cos(0) * r, h));
for (double i = 0; i < 2*PI; i+=angle) {
Vec2d p = Eigen::Rotation2Dd(i) * Eigen::Vector2d(0, r);
vertices.emplace_back(Vec3d(p(0), p(1), 0.)); vertices.emplace_back(Vec3d(p(0), p(1), 0.));
vertices.emplace_back(Vec3d(p(0), p(1), h)); vertices.emplace_back(Vec3d(p(0), p(1), h));
id = vertices.size() - 1; for (size_t i = 1; i < n_steps; ++i) {
p = Eigen::Rotation2Dd(angle_step * i) * Eigen::Vector2d(0, r);
vertices.emplace_back(Vec3d(p(0), p(1), 0.));
vertices.emplace_back(Vec3d(p(0), p(1), h));
int id = (int)vertices.size() - 1;
facets.emplace_back(Vec3crd( 0, id - 1, id - 3)); // top facets.emplace_back(Vec3crd( 0, id - 1, id - 3)); // top
facets.emplace_back(Vec3crd(id, 1, id - 2)); // bottom facets.emplace_back(Vec3crd(id, 1, id - 2)); // bottom
facets.emplace_back(Vec3crd(id, id - 2, id - 3)); // upper-right of side facets.emplace_back(Vec3crd(id, id - 2, id - 3)); // upper-right of side
facets.emplace_back(Vec3crd(id, id - 3, id - 1)); // bottom-left of side facets.emplace_back(Vec3crd(id, id - 3, id - 1)); // bottom-left of side
} }
// Connect the last set of vertices with the first. // Connect the last set of vertices with the first.
facets.emplace_back(Vec3crd( 2, 0, id - 1)); int id = (int)vertices.size() - 1;
facets.emplace_back(Vec3crd( 1, 3, id)); facets.emplace_back(Vec3crd( 0, 2, id - 1));
facets.emplace_back(Vec3crd(id, 3, 2)); facets.emplace_back(Vec3crd( 3, 1, id));
facets.emplace_back(Vec3crd(id, 2, id - 1)); facets.emplace_back(Vec3crd(id, 2, 3));
facets.emplace_back(Vec3crd(id, id - 1, 2));
TriangleMesh mesh(vertices, facets); return TriangleMesh(std::move(vertices), std::move(facets));
return mesh;
} }
// Generates mesh for a sphere centered about the origin, using the generated angle // Generates mesh for a sphere centered about the origin, using the generated angle
// to determine the granularity. // to determine the granularity.
// Default angle is 1 degree. // Default angle is 1 degree.
TriangleMesh make_sphere(double rho, double fa) { //FIXME better to discretize an Icosahedron recursively http://www.songho.ca/opengl/gl_sphere.html
TriangleMesh make_sphere(double radius, double fa)
{
int sectorCount = ceil(2. * M_PI / fa);
int stackCount = ceil(M_PI / fa);
float sectorStep = 2. * M_PI / sectorCount;
float stackStep = M_PI / stackCount;
Pointf3s vertices; Pointf3s vertices;
vertices.reserve((stackCount - 1) * sectorCount + 2);
for (int i = 0; i <= stackCount; ++ i) {
// from pi/2 to -pi/2
double stackAngle = 0.5 * M_PI - stackStep * i;
double xy = radius * cos(stackAngle);
double z = radius * sin(stackAngle);
if (i == 0 || i == stackCount)
vertices.emplace_back(Vec3d(xy, 0., z));
else
for (int j = 0; j < sectorCount; ++ j) {
// from 0 to 2pi
double sectorAngle = sectorStep * j;
vertices.emplace_back(Vec3d(xy * cos(sectorAngle), xy * sin(sectorAngle), z));
}
}
std::vector<Vec3crd> facets; std::vector<Vec3crd> facets;
facets.reserve(2 * (stackCount - 1) * sectorCount);
// Algorithm: for (int i = 0; i < stackCount; ++ i) {
// Add points one-by-one to the sphere grid and form facets using relative coordinates. // Beginning of current stack.
// Sphere is composed effectively of a mesh of stacked circles. int k1 = (i == 0) ? 0 : (1 + (i - 1) * sectorCount);
int k1_first = k1;
// adjust via rounding to get an even multiple for any provided angle. // Beginning of next stack.
double angle = (2*PI / floor(2*PI / fa)); int k2 = (i == 0) ? 1 : (k1 + sectorCount);
int k2_first = k2;
// Ring to be scaled to generate the steps of the sphere for (int j = 0; j < sectorCount; ++ j) {
std::vector<double> ring; // 2 triangles per sector excluding first and last stacks
for (double i = 0; i < 2*PI; i+=angle) { int k1_next = k1;
ring.emplace_back(i); int k2_next = k2;
if (i != 0) {
k1_next = (j + 1 == sectorCount) ? k1_first : (k1 + 1);
facets.emplace_back(Vec3crd(k1, k2, k1_next));
} }
const size_t steps = ring.size(); if (i + 1 != stackCount) {
const double increment = (double)(1.0 / (double)steps); k2_next = (j + 1 == sectorCount) ? k2_first : (k2 + 1);
facets.emplace_back(Vec3crd(k1_next, k2, k2_next));
// special case: first ring connects to 0,0,0
// insert and form facets.
vertices.emplace_back(Vec3d(0.0, 0.0, -rho));
size_t id = vertices.size();
for (size_t i = 0; i < ring.size(); i++) {
// Fixed scaling
const double z = -rho + increment*rho*2.0;
// radius of the circle for this step.
const double r = sqrt(abs(rho*rho - z*z));
Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r);
vertices.emplace_back(Vec3d(b(0), b(1), z));
facets.emplace_back((i == 0) ? Vec3crd(1, 0, ring.size()) : Vec3crd(id, 0, id - 1));
++ id;
} }
k1 = k1_next;
// General case: insert and form facets for each step, joining it to the ring below it. k2 = k2_next;
for (size_t s = 2; s < steps - 1; s++) {
const double z = -rho + increment*(double)s*2.0*rho;
const double r = sqrt(abs(rho*rho - z*z));
for (size_t i = 0; i < ring.size(); i++) {
Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r);
vertices.emplace_back(Vec3d(b(0), b(1), z));
if (i == 0) {
// wrap around
facets.emplace_back(Vec3crd(id + ring.size() - 1 , id, id - 1));
facets.emplace_back(Vec3crd(id, id - ring.size(), id - 1));
} else {
facets.emplace_back(Vec3crd(id , id - ring.size(), (id - 1) - ring.size()));
facets.emplace_back(Vec3crd(id, id - 1 - ring.size() , id - 1));
}
id++;
} }
} }
return TriangleMesh(std::move(vertices), std::move(facets));
// special case: last ring connects to 0,0,rho*2.0
// only form facets.
vertices.emplace_back(Vec3d(0.0, 0.0, rho));
for (size_t i = 0; i < ring.size(); i++) {
if (i == 0) {
// third vertex is on the other side of the ring.
facets.emplace_back(Vec3crd(id, id - ring.size(), id - 1));
} else {
facets.emplace_back(Vec3crd(id, id - ring.size() + i, id - ring.size() + (i - 1)));
}
}
id++;
TriangleMesh mesh(vertices, facets);
return mesh;
} }
} }