41#include <Eigen/Geometry>
52Eigen::Matrix3f extractRotation(
const QMatrix4x4 &m)
55 for (
int r = 0; r < 3; ++r)
56 for (
int c = 0; c < 3; ++c)
67void MeshFactory::buildIcosphere(QVector<Eigen::Vector3f> &vertices,
68 QVector<Eigen::Vector3i> &faces,
72 const float phi = (1.0f + std::sqrt(5.0f)) / 2.0f;
75 vertices.reserve(12 + 30 * subdivisions);
76 vertices << Eigen::Vector3f(-1, phi, 0) << Eigen::Vector3f( 1, phi, 0)
77 << Eigen::Vector3f(-1, -phi, 0) << Eigen::Vector3f( 1, -phi, 0)
78 << Eigen::Vector3f( 0, -1, phi) << Eigen::Vector3f( 0, 1, phi)
79 << Eigen::Vector3f( 0, -1, -phi) << Eigen::Vector3f( 0, 1, -phi)
80 << Eigen::Vector3f( phi, 0, -1) << Eigen::Vector3f( phi, 0, 1)
81 << Eigen::Vector3f(-phi, 0, -1) << Eigen::Vector3f(-phi, 0, 1);
82 for (
auto &v : vertices)
87 faces << Eigen::Vector3i(0,11,5) << Eigen::Vector3i(0,5,1)
88 << Eigen::Vector3i(0,1,7) << Eigen::Vector3i(0,7,10)
89 << Eigen::Vector3i(0,10,11) << Eigen::Vector3i(1,5,9)
90 << Eigen::Vector3i(5,11,4) << Eigen::Vector3i(11,10,2)
91 << Eigen::Vector3i(10,7,6) << Eigen::Vector3i(7,1,8)
92 << Eigen::Vector3i(3,9,4) << Eigen::Vector3i(3,4,2)
93 << Eigen::Vector3i(3,2,6) << Eigen::Vector3i(3,6,8)
94 << Eigen::Vector3i(3,8,9) << Eigen::Vector3i(4,9,5)
95 << Eigen::Vector3i(2,4,11) << Eigen::Vector3i(6,2,10)
96 << Eigen::Vector3i(8,6,7) << Eigen::Vector3i(9,8,1);
99 for (
int s = 0; s < subdivisions; ++s) {
100 QMap<QPair<int,int>,
int> cache;
101 auto midpoint = [&](
int a,
int b) ->
int {
102 auto key = qMakePair(qMin(a, b), qMax(a, b));
103 if (cache.contains(key))
105 int idx = vertices.size();
106 vertices.append((vertices[a] + vertices[b]).normalized());
111 QVector<Eigen::Vector3i> newFaces;
112 newFaces.reserve(faces.size() * 4);
113 for (
const auto &f : faces) {
114 int ab = midpoint(f(0), f(1));
115 int bc = midpoint(f(1), f(2));
116 int ca = midpoint(f(2), f(0));
117 newFaces << Eigen::Vector3i(f(0), ab, ca)
118 << Eigen::Vector3i(f(1), bc, ab)
119 << Eigen::Vector3i(f(2), ca, bc)
120 << Eigen::Vector3i(ab, bc, ca);
122 faces = std::move(newFaces);
130 QVector<Eigen::Vector3f> verts;
131 QVector<Eigen::Vector3i> faces;
132 buildIcosphere(verts, faces, subdivisions);
143 QVector<Eigen::Vector3f> verts;
144 QVector<Eigen::Vector3i> faces;
145 buildIcosphere(verts, faces, subdivisions);
147 const int nV = verts.size();
148 const int nT = faces.size();
150 Eigen::MatrixX3f rr(nV, 3), nn(nV, 3);
151 for (
int i = 0; i < nV; ++i) {
152 nn(i, 0) = verts[i].x();
153 nn(i, 1) = verts[i].y();
154 nn(i, 2) = verts[i].z();
155 rr(i, 0) = verts[i].x() * radius + center.x();
156 rr(i, 1) = verts[i].y() * radius + center.y();
157 rr(i, 2) = verts[i].z() * radius + center.z();
160 Eigen::MatrixX3i tris(nT, 3);
161 for (
int i = 0; i < nT; ++i)
162 tris.row(i) = faces[i];
164 auto surf = std::make_shared<BrainSurface>();
165 surf->createFromData(rr, nn, tris, color);
172 const QMatrix4x4 &orientation,
176 const float hw = size / 2.0f;
177 const float hh = size / 2.0f;
178 const float hd = size * 0.05f;
180 const Eigen::Matrix3f rot = extractRotation(orientation);
182 Eigen::Vector3f corners[8] = {
183 {-hw, -hh, -hd}, { hw, -hh, -hd}, { hw, hh, -hd}, {-hw, hh, -hd},
184 {-hw, -hh, hd}, { hw, -hh, hd}, { hw, hh, hd}, {-hw, hh, hd}
186 for (
auto &c : corners)
189 const int faceIndices[6][4] = {
190 {4,5,6,7}, {1,0,3,2},
191 {3,7,6,2}, {0,1,5,4},
195 Eigen::MatrixX3f rr(24, 3), nn(24, 3);
196 Eigen::MatrixX3i tris(12, 3);
198 for (
int f = 0; f < 6; ++f) {
199 Eigen::Vector3f v0 = corners[faceIndices[f][0]];
200 Eigen::Vector3f v1 = corners[faceIndices[f][1]];
201 Eigen::Vector3f v2 = corners[faceIndices[f][2]];
202 Eigen::Vector3f e1 = v1 - v0;
203 Eigen::Vector3f e2 = v2 - v0;
204 Eigen::Vector3f fn = e1.cross(e2).normalized();
206 for (
int k = 0; k < 4; ++k) {
207 Eigen::Vector3f v = corners[faceIndices[f][k]];
208 rr.row(base + k) << v.x() + center.x(), v.y() + center.y(), v.z() + center.z();
209 nn.row(base + k) = fn;
211 tris.row(f * 2) << base, base + 1, base + 2;
212 tris.row(f * 2 + 1) << base, base + 2, base + 3;
215 auto surf = std::make_shared<BrainSurface>();
216 surf->createFromData(rr, nn, tris, color);
223 const QMatrix4x4 &orientation,
227 const Eigen::Matrix3f rot = extractRotation(orientation);
229 const float halfSpan = size * 0.6f;
230 const float sphereR = size * 0.2f;
231 const float rodR = size * 0.08f;
233 QVector<Eigen::Vector3f> allVerts;
234 QVector<Eigen::Vector3f> allNorms;
235 QVector<Eigen::Vector3i> allTris;
238 auto appendSphere = [&](
const QVector3D &pos,
float radius) {
239 QVector<Eigen::Vector3f> sv;
240 QVector<Eigen::Vector3i> sf;
241 buildIcosphere(sv, sf, 1);
243 const int base = allVerts.size();
244 allVerts.reserve(base + sv.size());
245 allNorms.reserve(base + sv.size());
246 allTris.reserve(allTris.size() + sf.size());
248 for (
const auto &v : sv) {
249 Eigen::Vector3f vn = rot * v;
250 Eigen::Vector3f vp = rot * (v * radius);
251 allVerts.append(Eigen::Vector3f(vp.x() + pos.x(), vp.y() + pos.y(), vp.z() + pos.z()));
252 allNorms.append(vn.normalized());
254 for (
const auto &f : sf) {
255 allTris.append(Eigen::Vector3i(base + f(0), base + f(1), base + f(2)));
260 auto appendRod = [&]() {
261 float hx = rodR, hy = halfSpan, hz = rodR;
262 Eigen::Vector3f corners[8] = {
263 {-hx, -hy, -hz}, { hx, -hy, -hz}, { hx, hy, -hz}, {-hx, hy, -hz},
264 {-hx, -hy, hz}, { hx, -hy, hz}, { hx, hy, hz}, {-hx, hy, hz}
266 for (
auto &c : corners) c = rot * c;
268 const int faceIdx[6][4] = {
269 {4,5,6,7}, {1,0,3,2}, {3,7,6,2}, {0,1,5,4}, {1,2,6,5}, {0,4,7,3}
272 const int base = allVerts.size();
273 for (
int f = 0; f < 6; ++f) {
274 Eigen::Vector3f v0 = corners[faceIdx[f][0]];
275 Eigen::Vector3f v1 = corners[faceIdx[f][1]];
276 Eigen::Vector3f v2 = corners[faceIdx[f][2]];
277 Eigen::Vector3f e1 = v1 - v0;
278 Eigen::Vector3f e2 = v2 - v0;
279 Eigen::Vector3f fn = e1.cross(e2).normalized();
280 int faceBase = base + f * 4;
281 for (
int k = 0; k < 4; ++k) {
282 Eigen::Vector3f v = corners[faceIdx[f][k]];
283 allVerts.append(Eigen::Vector3f(v.x() + center.x(), v.y() + center.y(), v.z() + center.z()));
286 allTris.append(Eigen::Vector3i(faceBase, faceBase + 1, faceBase + 2));
287 allTris.append(Eigen::Vector3i(faceBase, faceBase + 2, faceBase + 3));
292 QVector3D axis(rot(0,1), rot(1,1), rot(2,1));
293 appendSphere(center + axis * halfSpan, sphereR);
294 appendSphere(center - axis * halfSpan, sphereR);
298 Eigen::MatrixX3f rr(allVerts.size(), 3), nn(allNorms.size(), 3);
299 Eigen::MatrixX3i tt(allTris.size(), 3);
300 for (
int i = 0; i < allVerts.size(); ++i) {
301 rr.row(i) = allVerts[i].transpose();
302 nn.row(i) = allNorms[i].transpose();
304 for (
int i = 0; i < allTris.size(); ++i)
305 tt.row(i) = allTris[i];
307 auto surf = std::make_shared<BrainSurface>();
308 surf->createFromData(rr, nn, tt, color);
319 if (positions.isEmpty())
320 return std::make_shared<BrainSurface>();
323 QVector<Eigen::Vector3f> tmplVerts;
324 QVector<Eigen::Vector3i> tmplFaces;
325 buildIcosphere(tmplVerts, tmplFaces, subdivisions);
327 const int nVPerPt = tmplVerts.size();
328 const int nTPerPt = tmplFaces.size();
329 const int nPts = positions.size();
332 Eigen::MatrixX3f templateV(nVPerPt, 3), templateN(nVPerPt, 3);
333 for (
int i = 0; i < nVPerPt; ++i) {
334 templateN(i, 0) = tmplVerts[i].x();
335 templateN(i, 1) = tmplVerts[i].y();
336 templateN(i, 2) = tmplVerts[i].z();
337 templateV(i, 0) = tmplVerts[i].x() * radius;
338 templateV(i, 1) = tmplVerts[i].y() * radius;
339 templateV(i, 2) = tmplVerts[i].z() * radius;
341 Eigen::MatrixX3i templateT(nTPerPt, 3);
342 for (
int i = 0; i < nTPerPt; ++i)
343 templateT.row(i) = tmplFaces[i];
346 Eigen::MatrixX3f allVerts(nPts * nVPerPt, 3);
347 Eigen::MatrixX3f allNorms(nPts * nVPerPt, 3);
348 Eigen::MatrixX3i allTris(nPts * nTPerPt, 3);
350 for (
int p = 0; p < nPts; ++p) {
351 const QVector3D &pos = positions[p];
352 const int vOff = p * nVPerPt;
353 const int tOff = p * nTPerPt;
354 for (
int iv = 0; iv < nVPerPt; ++iv) {
355 allVerts(vOff + iv, 0) = templateV(iv, 0) + pos.x();
356 allVerts(vOff + iv, 1) = templateV(iv, 1) + pos.y();
357 allVerts(vOff + iv, 2) = templateV(iv, 2) + pos.z();
358 allNorms.row(vOff + iv) = templateN.row(iv);
360 for (
int it = 0; it < nTPerPt; ++it) {
361 allTris(tOff + it, 0) = templateT(it, 0) + vOff;
362 allTris(tOff + it, 1) = templateT(it, 1) + vOff;
363 allTris(tOff + it, 2) = templateT(it, 2) + vOff;
367 auto surf = std::make_shared<BrainSurface>();
368 surf->createFromData(allVerts, allNorms, allTris, color);
MeshFactory class declaration — static utilities for generating primitive meshes (spheres,...
BrainSurface class declaration.
static std::shared_ptr< BrainSurface > createPlate(const QVector3D ¢er, const QMatrix4x4 &orientation, const QColor &color, float size)
static std::shared_ptr< BrainSurface > createBatchedSpheres(const QVector< QVector3D > &positions, float radius, const QColor &color, int subdivisions=1)
static std::shared_ptr< BrainSurface > createBarbell(const QVector3D ¢er, const QMatrix4x4 &orientation, const QColor &color, float size)
static int sphereVertexCount(int subdivisions=1)
static std::shared_ptr< BrainSurface > createSphere(const QVector3D ¢er, float radius, const QColor &color, int subdivisions=1)