9#if QT_CONFIG(concurrent)
10#include <QtConcurrentRun>
25 const float dY = length /
static_cast<
float>(rings - 1);
26 const float dTheta = (M_PI * 2) /
static_cast<
float>(slices);
28 for (
int ring = 0; ring < rings; ++ring) {
29 const float y = -length / 2.0f +
static_cast<
float>(ring) * dY;
31 const float t = (y + length / 2) / length;
32 const float radius = (bottomRadius * (1 - t)) + (t * topRadius);
34 for (
int slice = 0; slice <= slices; ++slice) {
35 const float theta =
static_cast<
float>(slice) * dTheta;
36 const float ta = std::tan((M_PI/2) - std::atan(length / (bottomRadius - topRadius)));
37 const float ct = std::cos(theta);
38 const float st = std::sin(theta);
41 *verticesPtr++ = radius * ct;
43 *verticesPtr++ = radius * st;
46 float v = 0.5f + (y + length / 2.0f) / length / 2.0f;
47 *verticesPtr++ =
static_cast<
float>(slice) /
static_cast<
float>(slices);
51 QVector3D n(ct, ta, st);
53 *verticesPtr++ = n.x();
54 *verticesPtr++ = n.y();
55 *verticesPtr++ = n.z();
62 for (
int ring = 0; ring < rings-1; ++ring) {
63 const int ringIndexStart = ring * (slices + 1);
64 const int nextRingIndexStart = (ring + 1) * (slices + 1);
66 for (
int slice = 0; slice <= slices; ++slice) {
70 const int nextSlice = slice + 1;
72 *indicesPtr++ = (ringIndexStart + slice);
73 *indicesPtr++ = (nextRingIndexStart + slice);
74 *indicesPtr++ = (ringIndexStart + nextSlice);
75 *indicesPtr++ = (ringIndexStart + nextSlice);
76 *indicesPtr++ = (nextRingIndexStart + slice);
77 *indicesPtr++ = (nextRingIndexStart + nextSlice);
89 const float dTheta = (M_PI * 2) /
static_cast<
float>(slices);
90 const double yNormal = (yPosition < 0.0f) ? -1.0f : 1.0f;
92 *verticesPtr++ = 0.0f;
93 *verticesPtr++ = yPosition;
94 *verticesPtr++ = 0.0f;
96 if (yPosition < 0.0f) {
98 *verticesPtr++ = 0.75f;
99 *verticesPtr++ = 0.25f;
102 *verticesPtr++ = 0.25f;
103 *verticesPtr++ = 0.25f;
107 *verticesPtr++ = 0.0f;
108 *verticesPtr++ = yNormal;
109 *verticesPtr++ = 0.0f;
112 for (
int slice = 0; slice <= slices; ++slice)
114 const float theta =
static_cast<
float>(slice) * dTheta;
115 const float ct = std::cos(theta);
116 const float st = std::sin(theta);
118 const float t = (yPosition + length / 2) / length;
119 const float radius = (bottomRadius * (1 - t)) + (t * topRadius);
122 *verticesPtr++ = radius * ct;
123 *verticesPtr++ = yPosition;
124 *verticesPtr++ = radius * st;
127 if (yPosition < 0.0f) {
129 *verticesPtr++ = 0.75f + 0.25f * ct;
130 *verticesPtr++ = 0.25f + 0.25f * st;
133 *verticesPtr++ = 0.25f + 0.25f * ct;
134 *verticesPtr++ = 0.25f + 0.25f * -st;
138 *verticesPtr++ = 0.0f;
139 *verticesPtr++ = yNormal;
140 *verticesPtr++ = 0.0f;
150 for (
int i = slices - 1 ; i >= 0 ; --i )
153 *indicesPtr++ = discCenterIndex;
154 *indicesPtr++ = discCenterIndex + i + 1;
155 *indicesPtr++ = discCenterIndex + i;
157 *indicesPtr++ = discCenterIndex;
158 *indicesPtr++ = discCenterIndex + i + 1;
159 *indicesPtr++ = discCenterIndex + slices;
163 for (
int i = 0 ; i < slices; ++i )
165 if ( i != slices - 1 ) {
166 *indicesPtr++ = discCenterIndex;
167 *indicesPtr++ = discCenterIndex + i + 1;
168 *indicesPtr++ = discCenterIndex + i + 2;
170 *indicesPtr++ = discCenterIndex;
171 *indicesPtr++ = discCenterIndex + i + 1;
172 *indicesPtr++ = discCenterIndex + 1;
181
182
183
184
185
186
187
188
189
190
193
194
195
196
197
200
201
202
203
204
207
208
209
210
211
214
215
216
217
218
221
222
223
224
227
228
229
230
231
232
233
234
235
236
238CylinderGeometry::CylinderGeometry(QQuick3DObject *parent)
239 : QQuick3DGeometry(parent)
241#if QT_CONFIG(concurrent)
242 connect(&m_geometryDataWatcher, &QFutureWatcher<GeometryData>::finished,
this, &CylinderGeometry::requestFinished);
244 scheduleGeometryUpdate();
247CylinderGeometry::~CylinderGeometry()
252float CylinderGeometry::radius()
const
257void CylinderGeometry::setRadius(
float newRadius)
259 if (qFuzzyCompare(m_radius, newRadius))
261 m_radius = newRadius;
262 emit radiusChanged();
263 scheduleGeometryUpdate();
266float CylinderGeometry::length()
const
271void CylinderGeometry::setLength(
float newLength)
273 if (qFuzzyCompare(m_length, newLength))
275 m_length = newLength;
276 emit lengthChanged();
277 scheduleGeometryUpdate();
280int CylinderGeometry::rings()
const
285void CylinderGeometry::setRings(
int newRings)
287 if (m_rings == newRings)
291 scheduleGeometryUpdate();
294int CylinderGeometry::segments()
const
299void CylinderGeometry::setSegments(
int newSegments)
301 if (m_segments == newSegments)
303 m_segments = newSegments;
304 emit segmentsChanged();
305 scheduleGeometryUpdate();
308bool CylinderGeometry::asynchronous()
const
310 return m_asynchronous;
313void CylinderGeometry::setAsynchronous(
bool newAsynchronous)
315 if (m_asynchronous == newAsynchronous)
317 m_asynchronous = newAsynchronous;
318 emit asynchronousChanged();
321CylinderGeometry::Status CylinderGeometry::status()
const
326void CylinderGeometry::doUpdateGeometry()
329 m_geometryUpdateRequested =
false;
331#if QT_CONFIG(concurrent)
332 if (m_geometryDataFuture.isRunning()) {
333 m_pendingAsyncUpdate =
true;
339 if (m_radius <= 0 || m_length <= 0 || m_rings < 0 || m_segments < 3) {
345#if QT_CONFIG(concurrent)
346 if (m_asynchronous) {
347 m_geometryDataFuture = QtConcurrent::run(generateCylinderGeometryAsync,
352 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
353 m_status = Status::Loading;
354 Q_EMIT statusChanged();
360 updateGeometry(generateCylinderGeometry(m_radius, m_length, m_rings, m_segments));
364void CylinderGeometry::requestFinished()
366#if QT_CONFIG(concurrent)
367 const auto output = m_geometryDataFuture.takeResult();
368 updateGeometry(output);
372void CylinderGeometry::scheduleGeometryUpdate()
374 if (!m_geometryUpdateRequested) {
375 QMetaObject::invokeMethod(
this,
"doUpdateGeometry", Qt::QueuedConnection);
376 m_geometryUpdateRequested =
true;
380void CylinderGeometry::updateGeometry(
const GeometryData &geometryData)
382 setStride(
sizeof(
float) * 8);
383 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
384 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
386 QQuick3DGeometry::Attribute::F32Type);
387 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
389 QQuick3DGeometry::Attribute::F32Type);
390 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
392 QQuick3DGeometry::Attribute::F32Type);
393 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
395 QQuick3DGeometry::Attribute::U16Type);
397 setBounds(geometryData.boundsMin, geometryData.boundsMax);
398 setVertexData(geometryData.vertexData);
399 setIndexData(geometryData.indexData);
403 if (m_pendingAsyncUpdate) {
404 m_pendingAsyncUpdate =
false;
405 scheduleGeometryUpdate();
407 m_status = Status::Ready;
408 Q_EMIT statusChanged();
413CylinderGeometry::GeometryData CylinderGeometry::generateCylinderGeometry(
float radius,
float length,
int rings,
int slices)
415 GeometryData geomData;
423 int totalFaces = (slices * 2) * (rings - 1) + slices * capCount;
424 int totalVertices = (slices + 1) * rings + capCount * (slices + 2);
425 int totalIndices = totalFaces * 3;
428 geomData.vertexData.resize(totalVertices * 8 *
sizeof(
float));
429 geomData.indexData.resize(totalIndices *
sizeof(quint16));
432 float* verticesPtr =
reinterpret_cast<
float*>(geomData.vertexData.data());
433 quint16* indicesPtr =
reinterpret_cast<quint16*>(geomData.indexData.data());
437 createCylinderSidesVertices(verticesPtr, rings, slices, radius, radius, length);
438 createCylinderSidesIndices(indicesPtr, rings, slices);
439 int bottomCenterIndex = rings * (slices + 1);
440 createCylinderDiscVertices(verticesPtr, slices, radius, radius, length, -length / 2);
441 createCylinderDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
442 int topCenterIndex = radius > 0 ? rings * (slices + 1) + (slices + 2) : rings * (slices + 1);
443 createCylinderDiscVertices(verticesPtr, slices, radius, radius, length, length / 2);
444 createCylinderDiscIndices(indicesPtr, topCenterIndex, slices,
false);
448 float* vertexData =
reinterpret_cast<
float*>(geomData.vertexData.data());
449 QVector3D boundsMin(std::numeric_limits<
float>::max(),
450 std::numeric_limits<
float>::max(),
451 std::numeric_limits<
float>::max());
452 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
453 std::numeric_limits<
float>::lowest(),
454 std::numeric_limits<
float>::lowest());
455 for (
int i = 0; i < totalVertices; ++i) {
456 QVector3D pos(vertexData[i * 8], vertexData[i * 8 + 1], vertexData[i * 8 + 2]);
457 boundsMin.setX(qMin(boundsMin.x(), pos.x()));
458 boundsMin.setY(qMin(boundsMin.y(), pos.y()));
459 boundsMin.setZ(qMin(boundsMin.z(), pos.z()));
461 boundsMax.setX(qMax(boundsMax.x(), pos.x()));
462 boundsMax.setY(qMax(boundsMax.y(), pos.y()));
463 boundsMax.setZ(qMax(boundsMax.z(), pos.z()));
465 geomData.boundsMin = boundsMin;
466 geomData.boundsMax = boundsMax;
471#if QT_CONFIG(concurrent)
472void CylinderGeometry::generateCylinderGeometryAsync(QPromise<CylinderGeometry::GeometryData> &promise,
478 auto output = generateCylinderGeometry(radius, length, rings, segments);
479 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)