11#if QT_CONFIG(concurrent)
12#include <QtConcurrentRun>
27 const float dY = length /
static_cast<
float>(rings - 1);
28 const float dTheta = (M_PI * 2) /
static_cast<
float>(slices);
30 for (
int ring = 0; ring < rings; ++ring) {
31 const float y = -length / 2.0f +
static_cast<
float>(ring) * dY;
33 const float t = (y + length / 2) / length;
34 const float radius = (bottomRadius * (1 - t)) + (t * topRadius);
36 for (
int slice = 0; slice <= slices; ++slice) {
37 const float theta =
static_cast<
float>(slice) * dTheta;
38 const float ta = std::tan((M_PI/2) - std::atan(length / (bottomRadius - topRadius)));
39 const float ct = std::cos(theta);
40 const float st = std::sin(theta);
43 *verticesPtr++ = radius * ct;
45 *verticesPtr++ = radius * st;
48 float v = 0.5f + (y + length / 2.0f) / length / 2.0f;
49 *verticesPtr++ =
static_cast<
float>(slice) /
static_cast<
float>(slices);
53 QVector3D n(ct, ta, st);
55 *verticesPtr++ = n.x();
56 *verticesPtr++ = n.y();
57 *verticesPtr++ = n.z();
64 for (
int ring = 0; ring < rings-1; ++ring) {
65 const int ringIndexStart = ring * (slices + 1);
66 const int nextRingIndexStart = (ring + 1) * (slices + 1);
68 for (
int slice = 0; slice <= slices; ++slice) {
72 const int nextSlice = slice + 1;
74 *indicesPtr++ = (ringIndexStart + slice);
75 *indicesPtr++ = (nextRingIndexStart + slice);
76 *indicesPtr++ = (ringIndexStart + nextSlice);
77 *indicesPtr++ = (ringIndexStart + nextSlice);
78 *indicesPtr++ = (nextRingIndexStart + slice);
79 *indicesPtr++ = (nextRingIndexStart + nextSlice);
91 const float dTheta = (M_PI * 2) /
static_cast<
float>(slices);
92 const double yNormal = (yPosition < 0.0f) ? -1.0f : 1.0f;
94 *verticesPtr++ = 0.0f;
95 *verticesPtr++ = yPosition;
96 *verticesPtr++ = 0.0f;
98 if (yPosition < 0.0f) {
100 *verticesPtr++ = 0.75f;
101 *verticesPtr++ = 0.25f;
104 *verticesPtr++ = 0.25f;
105 *verticesPtr++ = 0.25f;
109 *verticesPtr++ = 0.0f;
110 *verticesPtr++ = yNormal;
111 *verticesPtr++ = 0.0f;
114 for (
int slice = 0; slice <= slices; ++slice)
116 const float theta =
static_cast<
float>(slice) * dTheta;
117 const float ct = std::cos(theta);
118 const float st = std::sin(theta);
120 const float t = (yPosition + length / 2) / length;
121 const float radius = (bottomRadius * (1 - t)) + (t * topRadius);
124 *verticesPtr++ = radius * ct;
125 *verticesPtr++ = yPosition;
126 *verticesPtr++ = radius * st;
129 if (yPosition < 0.0f) {
131 *verticesPtr++ = 0.75f + 0.25f * ct;
132 *verticesPtr++ = 0.25f + 0.25f * st;
135 *verticesPtr++ = 0.25f + 0.25f * ct;
136 *verticesPtr++ = 0.25f + 0.25f * -st;
140 *verticesPtr++ = 0.0f;
141 *verticesPtr++ = yNormal;
142 *verticesPtr++ = 0.0f;
152 for (
int i = slices - 1 ; i >= 0 ; --i )
155 *indicesPtr++ = discCenterIndex;
156 *indicesPtr++ = discCenterIndex + i + 1;
157 *indicesPtr++ = discCenterIndex + i;
159 *indicesPtr++ = discCenterIndex;
160 *indicesPtr++ = discCenterIndex + i + 1;
161 *indicesPtr++ = discCenterIndex + slices;
165 for (
int i = 0 ; i < slices; ++i )
167 if ( i != slices - 1 ) {
168 *indicesPtr++ = discCenterIndex;
169 *indicesPtr++ = discCenterIndex + i + 1;
170 *indicesPtr++ = discCenterIndex + i + 2;
172 *indicesPtr++ = discCenterIndex;
173 *indicesPtr++ = discCenterIndex + i + 1;
174 *indicesPtr++ = discCenterIndex + 1;
183
184
185
186
187
188
189
190
191
192
195
196
197
198
199
202
203
204
205
206
209
210
211
212
213
216
217
218
219
220
223
224
225
226
229
230
231
232
233
234
235
236
237
238
240CylinderGeometry::CylinderGeometry(QQuick3DObject *parent)
241 : QQuick3DGeometry(parent)
243#if QT_CONFIG(concurrent)
244 connect(&m_geometryDataWatcher, &QFutureWatcher<GeometryData>::finished,
this, &CylinderGeometry::requestFinished);
246 scheduleGeometryUpdate();
249CylinderGeometry::~CylinderGeometry()
254float CylinderGeometry::radius()
const
259void CylinderGeometry::setRadius(
float newRadius)
261 if (qFuzzyCompare(m_radius, newRadius))
263 m_radius = newRadius;
264 emit radiusChanged();
265 scheduleGeometryUpdate();
268float CylinderGeometry::length()
const
273void CylinderGeometry::setLength(
float newLength)
275 if (qFuzzyCompare(m_length, newLength))
277 m_length = newLength;
278 emit lengthChanged();
279 scheduleGeometryUpdate();
282int CylinderGeometry::rings()
const
287void CylinderGeometry::setRings(
int newRings)
289 if (m_rings == newRings)
293 scheduleGeometryUpdate();
296int CylinderGeometry::segments()
const
301void CylinderGeometry::setSegments(
int newSegments)
303 if (m_segments == newSegments)
305 m_segments = newSegments;
306 emit segmentsChanged();
307 scheduleGeometryUpdate();
310bool CylinderGeometry::asynchronous()
const
312 return m_asynchronous;
315void CylinderGeometry::setAsynchronous(
bool newAsynchronous)
317 if (m_asynchronous == newAsynchronous)
319 m_asynchronous = newAsynchronous;
320 emit asynchronousChanged();
323CylinderGeometry::Status CylinderGeometry::status()
const
328void CylinderGeometry::doUpdateGeometry()
331 m_geometryUpdateRequested =
false;
333#if QT_CONFIG(concurrent)
334 if (m_geometryDataFuture.isRunning()) {
335 m_pendingAsyncUpdate =
true;
341 if (m_radius <= 0 || m_length <= 0 || m_rings < 0 || m_segments < 3) {
347#if QT_CONFIG(concurrent)
348 if (m_asynchronous) {
349 m_geometryDataFuture = QtConcurrent::run(generateCylinderGeometryAsync,
354 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
355 m_status = Status::Loading;
356 Q_EMIT statusChanged();
362 updateGeometry(generateCylinderGeometry(m_radius, m_length, m_rings, m_segments));
366void CylinderGeometry::requestFinished()
368#if QT_CONFIG(concurrent)
369 const auto output = m_geometryDataFuture.takeResult();
370 updateGeometry(output);
374void CylinderGeometry::scheduleGeometryUpdate()
376 if (!m_geometryUpdateRequested) {
377 QMetaObject::invokeMethod(
this,
"doUpdateGeometry", Qt::QueuedConnection);
378 m_geometryUpdateRequested =
true;
382void CylinderGeometry::updateGeometry(
const GeometryData &geometryData)
384 setStride(
sizeof(
float) * 8);
385 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
386 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
388 QQuick3DGeometry::Attribute::F32Type);
389 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
391 QQuick3DGeometry::Attribute::F32Type);
392 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
394 QQuick3DGeometry::Attribute::F32Type);
395 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
397 QQuick3DGeometry::Attribute::U16Type);
399 setBounds(geometryData.boundsMin, geometryData.boundsMax);
400 setVertexData(geometryData.vertexData);
401 setIndexData(geometryData.indexData);
405 if (m_pendingAsyncUpdate) {
406 m_pendingAsyncUpdate =
false;
407 scheduleGeometryUpdate();
409 m_status = Status::Ready;
410 Q_EMIT statusChanged();
413 emit geometryChanged();
416CylinderGeometry::GeometryData CylinderGeometry::generateCylinderGeometry(
float radius,
float length,
int rings,
int slices)
418 GeometryData geomData;
426 int totalFaces = (slices * 2) * (rings - 1) + slices * capCount;
427 int totalVertices = (slices + 1) * rings + capCount * (slices + 2);
428 int totalIndices = totalFaces * 3;
431 geomData.vertexData.resize(totalVertices * 8 *
sizeof(
float));
432 geomData.indexData.resize(totalIndices *
sizeof(quint16));
435 float* verticesPtr =
reinterpret_cast<
float*>(geomData.vertexData.data());
436 quint16* indicesPtr =
reinterpret_cast<quint16*>(geomData.indexData.data());
440 createCylinderSidesVertices(verticesPtr, rings, slices, radius, radius, length);
441 createCylinderSidesIndices(indicesPtr, rings, slices);
442 int bottomCenterIndex = rings * (slices + 1);
443 createCylinderDiscVertices(verticesPtr, slices, radius, radius, length, -length / 2);
444 createCylinderDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
445 int topCenterIndex = radius > 0 ? rings * (slices + 1) + (slices + 2) : rings * (slices + 1);
446 createCylinderDiscVertices(verticesPtr, slices, radius, radius, length, length / 2);
447 createCylinderDiscIndices(indicesPtr, topCenterIndex, slices,
false);
451 float* vertexData =
reinterpret_cast<
float*>(geomData.vertexData.data());
452 QVector3D boundsMin(std::numeric_limits<
float>::max(),
453 std::numeric_limits<
float>::max(),
454 std::numeric_limits<
float>::max());
455 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
456 std::numeric_limits<
float>::lowest(),
457 std::numeric_limits<
float>::lowest());
458 for (
int i = 0; i < totalVertices; ++i) {
459 QVector3D pos(vertexData[i * 8], vertexData[i * 8 + 1], vertexData[i * 8 + 2]);
460 boundsMin.setX(qMin(boundsMin.x(), pos.x()));
461 boundsMin.setY(qMin(boundsMin.y(), pos.y()));
462 boundsMin.setZ(qMin(boundsMin.z(), pos.z()));
464 boundsMax.setX(qMax(boundsMax.x(), pos.x()));
465 boundsMax.setY(qMax(boundsMax.y(), pos.y()));
466 boundsMax.setZ(qMax(boundsMax.z(), pos.z()));
468 geomData.boundsMin = boundsMin;
469 geomData.boundsMax = boundsMax;
474#if QT_CONFIG(concurrent)
475void CylinderGeometry::generateCylinderGeometryAsync(QPromise<CylinderGeometry::GeometryData> &promise,
481 auto output = generateCylinderGeometry(radius, length, rings, segments);
482 promise.addResult(output);
void createCylinderSidesIndices(quint16 *&indicesPtr, int rings, int slices)
void createCylinderDiscVertices(float *&verticesPtr, int slices, double topRadius, double bottomRadius, double length, double yPosition)
void createCylinderSidesVertices(float *&verticesPtr, int rings, int slices, double topRadius, double bottomRadius, double length)
void createCylinderDiscIndices(quint16 *&indicesPtr, int discCenterIndex, int slices, bool isTopCap)