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)
385 setStride(
sizeof(
float) * 8);
386 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
387 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
389 QQuick3DGeometry::Attribute::F32Type);
390 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
392 QQuick3DGeometry::Attribute::F32Type);
393 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
395 QQuick3DGeometry::Attribute::F32Type);
396 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
398 QQuick3DGeometry::Attribute::U16Type);
400 setBounds(geometryData.boundsMin, geometryData.boundsMax);
401 setVertexData(geometryData.vertexData);
402 setIndexData(geometryData.indexData);
406 if (m_pendingAsyncUpdate) {
407 m_pendingAsyncUpdate =
false;
408 scheduleGeometryUpdate();
410 m_status = Status::Ready;
411 Q_EMIT statusChanged();
414 emit geometryChanged();
417CylinderGeometry::GeometryData CylinderGeometry::generateCylinderGeometry(
float radius,
float length,
int rings,
int slices)
419 GeometryData geomData;
427 int totalFaces = (slices * 2) * (rings - 1) + slices * capCount;
428 int totalVertices = (slices + 1) * rings + capCount * (slices + 2);
429 int totalIndices = totalFaces * 3;
432 geomData.vertexData.resize(totalVertices * 8 *
sizeof(
float));
433 geomData.indexData.resize(totalIndices *
sizeof(quint16));
436 float* verticesPtr =
reinterpret_cast<
float*>(geomData.vertexData.data());
437 quint16* indicesPtr =
reinterpret_cast<quint16*>(geomData.indexData.data());
441 createCylinderSidesVertices(verticesPtr, rings, slices, radius, radius, length);
442 createCylinderSidesIndices(indicesPtr, rings, slices);
443 int bottomCenterIndex = rings * (slices + 1);
444 createCylinderDiscVertices(verticesPtr, slices, radius, radius, length, -length / 2);
445 createCylinderDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
446 int topCenterIndex = radius > 0 ? rings * (slices + 1) + (slices + 2) : rings * (slices + 1);
447 createCylinderDiscVertices(verticesPtr, slices, radius, radius, length, length / 2);
448 createCylinderDiscIndices(indicesPtr, topCenterIndex, slices,
false);
452 float* vertexData =
reinterpret_cast<
float*>(geomData.vertexData.data());
453 QVector3D boundsMin(std::numeric_limits<
float>::max(),
454 std::numeric_limits<
float>::max(),
455 std::numeric_limits<
float>::max());
456 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
457 std::numeric_limits<
float>::lowest(),
458 std::numeric_limits<
float>::lowest());
459 for (
int i = 0; i < totalVertices; ++i) {
460 QVector3D pos(vertexData[i * 8], vertexData[i * 8 + 1], vertexData[i * 8 + 2]);
461 boundsMin.setX(qMin(boundsMin.x(), pos.x()));
462 boundsMin.setY(qMin(boundsMin.y(), pos.y()));
463 boundsMin.setZ(qMin(boundsMin.z(), pos.z()));
465 boundsMax.setX(qMax(boundsMax.x(), pos.x()));
466 boundsMax.setY(qMax(boundsMax.y(), pos.y()));
467 boundsMax.setZ(qMax(boundsMax.z(), pos.z()));
469 geomData.boundsMin = boundsMin;
470 geomData.boundsMax = boundsMax;
475#if QT_CONFIG(concurrent)
476void CylinderGeometry::generateCylinderGeometryAsync(QPromise<CylinderGeometry::GeometryData> &promise,
482 auto output = generateCylinderGeometry(radius, length, rings, segments);
483 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)