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)
349 if (m_asynchronous && QT_CONFIG(thread)) {
350 m_geometryDataFuture = QtConcurrent::run(generateCylinderGeometryAsync,
355 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
356 m_status = Status::Loading;
357 Q_EMIT statusChanged();
363 updateGeometry(generateCylinderGeometry(m_radius, m_length, m_rings, m_segments));
367void CylinderGeometry::requestFinished()
369#if QT_CONFIG(concurrent)
370 const auto output = m_geometryDataFuture.takeResult();
371 updateGeometry(output);
375void CylinderGeometry::scheduleGeometryUpdate()
377 if (!m_geometryUpdateRequested) {
378 QMetaObject::invokeMethod(
this,
"doUpdateGeometry", Qt::QueuedConnection);
379 m_geometryUpdateRequested =
true;
383void CylinderGeometry::updateGeometry(
const GeometryData &geometryData)
386 setStride(
sizeof(
float) * 8);
387 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
388 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
390 QQuick3DGeometry::Attribute::F32Type);
391 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
393 QQuick3DGeometry::Attribute::F32Type);
394 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
396 QQuick3DGeometry::Attribute::F32Type);
397 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
399 QQuick3DGeometry::Attribute::U16Type);
401 setBounds(geometryData.boundsMin, geometryData.boundsMax);
402 setVertexData(geometryData.vertexData);
403 setIndexData(geometryData.indexData);
407 if (m_pendingAsyncUpdate) {
408 m_pendingAsyncUpdate =
false;
409 scheduleGeometryUpdate();
411 m_status = Status::Ready;
412 Q_EMIT statusChanged();
415 emit geometryChanged();
418CylinderGeometry::GeometryData CylinderGeometry::generateCylinderGeometry(
float radius,
float length,
int rings,
int slices)
420 GeometryData geomData;
428 int totalFaces = (slices * 2) * (rings - 1) + slices * capCount;
429 int totalVertices = (slices + 1) * rings + capCount * (slices + 2);
430 int totalIndices = totalFaces * 3;
433 geomData.vertexData.resize(totalVertices * 8 *
sizeof(
float));
434 geomData.indexData.resize(totalIndices *
sizeof(quint16));
437 float* verticesPtr =
reinterpret_cast<
float*>(geomData.vertexData.data());
438 quint16* indicesPtr =
reinterpret_cast<quint16*>(geomData.indexData.data());
442 createCylinderSidesVertices(verticesPtr, rings, slices, radius, radius, length);
443 createCylinderSidesIndices(indicesPtr, rings, slices);
444 int bottomCenterIndex = rings * (slices + 1);
445 createCylinderDiscVertices(verticesPtr, slices, radius, radius, length, -length / 2);
446 createCylinderDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
447 int topCenterIndex = radius > 0 ? rings * (slices + 1) + (slices + 2) : rings * (slices + 1);
448 createCylinderDiscVertices(verticesPtr, slices, radius, radius, length, length / 2);
449 createCylinderDiscIndices(indicesPtr, topCenterIndex, slices,
false);
453 float* vertexData =
reinterpret_cast<
float*>(geomData.vertexData.data());
454 QVector3D boundsMin(std::numeric_limits<
float>::max(),
455 std::numeric_limits<
float>::max(),
456 std::numeric_limits<
float>::max());
457 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
458 std::numeric_limits<
float>::lowest(),
459 std::numeric_limits<
float>::lowest());
460 for (
int i = 0; i < totalVertices; ++i) {
461 QVector3D pos(vertexData[i * 8], vertexData[i * 8 + 1], vertexData[i * 8 + 2]);
462 boundsMin.setX(qMin(boundsMin.x(), pos.x()));
463 boundsMin.setY(qMin(boundsMin.y(), pos.y()));
464 boundsMin.setZ(qMin(boundsMin.z(), pos.z()));
466 boundsMax.setX(qMax(boundsMax.x(), pos.x()));
467 boundsMax.setY(qMax(boundsMax.y(), pos.y()));
468 boundsMax.setZ(qMax(boundsMax.z(), pos.z()));
470 geomData.boundsMin = boundsMin;
471 geomData.boundsMax = boundsMax;
476#if QT_CONFIG(concurrent)
477void CylinderGeometry::generateCylinderGeometryAsync(QPromise<CylinderGeometry::GeometryData> &promise,
483 auto output = generateCylinderGeometry(radius, length, rings, segments);
484 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)