8#if QT_CONFIG(concurrent)
9#include <QtConcurrentRun>
23 const float dY = length /
static_cast<
float>(rings - 1);
24 const float dTheta = (M_PI * 2) /
static_cast<
float>(slices);
27 bool isTruncatedCone = (topRadius > 0 && bottomRadius > 0);
28 bool isUpwardCone = (topRadius > 0 && bottomRadius == 0);
29 bool isDownwardCone = (topRadius == 0 && bottomRadius > 0);
31 for (
int ring = 0; ring < rings; ++ring) {
32 const float y = -length / 2.0f +
static_cast<
float>(ring) * dY;
34 const float t = (y + length / 2) / length;
35 const float radius = (bottomRadius * (1 - t)) + (t * topRadius);
37 for (
int slice = 0; slice <= slices; ++slice) {
38 const float theta =
static_cast<
float>(slice) * dTheta;
39 const float ta = std::tan((M_PI/2) - std::atan(length / (bottomRadius - topRadius)));
40 const float ct = std::cos(theta);
41 const float st = std::sin(theta);
44 *verticesPtr++ = radius * ct;
46 *verticesPtr++ = radius * st;
49 if (isTruncatedCone) {
52 float v = 0.5f + (y + length / 2.0f) / length / 2.0f;
53 *verticesPtr++ =
static_cast<
float>(slice) /
static_cast<
float>(slices);
56 }
else if (isDownwardCone) {
60 float rUV = 1.0f -
static_cast<
float>(ring) /
static_cast<
float>(rings - 1);
61 float u = 0.25f + rUV * ct * 0.25f;
62 float v = 0.25f + -rUV * st * 0.25f;
66 }
else if (isUpwardCone) {
70 float rUV =
static_cast<
float>(ring) /
static_cast<
float>(rings - 1);
71 float u = 0.75f + rUV * ct * 0.25f;
72 float v = 0.25f + rUV * st * 0.25f;
78 QVector3D n(ct, ta, st);
80 *verticesPtr++ = n.x();
81 *verticesPtr++ = n.y();
82 *verticesPtr++ = n.z();
89 for (
int ring = 0; ring < rings-1; ++ring) {
90 const int ringIndexStart = ring * (slices + 1);
91 const int nextRingIndexStart = (ring + 1) * (slices + 1);
93 for (
int slice = 0; slice <= slices; ++slice) {
97 const int nextSlice = slice + 1;
99 *indicesPtr++ = (ringIndexStart + slice);
100 *indicesPtr++ = (nextRingIndexStart + slice);
101 *indicesPtr++ = (ringIndexStart + nextSlice);
102 *indicesPtr++ = (ringIndexStart + nextSlice);
103 *indicesPtr++ = (nextRingIndexStart + slice);
104 *indicesPtr++ = (nextRingIndexStart + nextSlice);
116 const float dTheta = (M_PI * 2) /
static_cast<
float>(slices);
117 const double yNormal = (yPosition < 0.0f) ? -1.0f : 1.0f;
119 *verticesPtr++ = 0.0f;
120 *verticesPtr++ = yPosition;
121 *verticesPtr++ = 0.0f;
123 if (yPosition < 0.0f) {
125 *verticesPtr++ = 0.75f;
126 *verticesPtr++ = 0.25f;
129 *verticesPtr++ = 0.25f;
130 *verticesPtr++ = 0.25f;
134 *verticesPtr++ = 0.0f;
135 *verticesPtr++ = yNormal;
136 *verticesPtr++ = 0.0f;
139 for (
int slice = 0; slice <= slices; ++slice)
141 const float theta =
static_cast<
float>(slice) * dTheta;
142 const float ct = std::cos(theta);
143 const float st = std::sin(theta);
145 const float t = (yPosition + length / 2) / length;
146 const float radius = (bottomRadius * (1 - t)) + (t * topRadius);
149 *verticesPtr++ = radius * ct;
150 *verticesPtr++ = yPosition;
151 *verticesPtr++ = radius * st;
154 if (yPosition < 0.0f) {
156 *verticesPtr++ = 0.75f + 0.25f * ct;
157 *verticesPtr++ = 0.25f + 0.25f * st;
160 *verticesPtr++ = 0.25f + 0.25f * ct;
161 *verticesPtr++ = 0.25f + 0.25f * -st;
165 *verticesPtr++ = 0.0f;
166 *verticesPtr++ = yNormal;
167 *verticesPtr++ = 0.0f;
177 for (
int i = slices - 1 ; i >= 0 ; --i )
180 *indicesPtr++ = discCenterIndex;
181 *indicesPtr++ = discCenterIndex + i + 1;
182 *indicesPtr++ = discCenterIndex + i;
184 *indicesPtr++ = discCenterIndex;
185 *indicesPtr++ = discCenterIndex + i + 1;
186 *indicesPtr++ = discCenterIndex + slices;
190 for (
int i = 0 ; i < slices; ++i )
192 if ( i != slices - 1 ) {
193 *indicesPtr++ = discCenterIndex;
194 *indicesPtr++ = discCenterIndex + i + 1;
195 *indicesPtr++ = discCenterIndex + i + 2;
197 *indicesPtr++ = discCenterIndex;
198 *indicesPtr++ = discCenterIndex + i + 1;
199 *indicesPtr++ = discCenterIndex + 1;
208
209
210
211
212
213
214
215
216
217
220
221
222
223
224
227
228
229
230
231
234
235
236
237
240
241
242
243
246
247
248
249
252
253
254
255
258
259
260
261
262
263
264
265
266
267
269ConeGeometry::ConeGeometry(QQuick3DObject *parent)
270 : QQuick3DGeometry(parent)
272#if QT_CONFIG(concurrent)
273 connect(&m_geometryDataWatcher, &QFutureWatcher<GeometryData>::finished,
this, &ConeGeometry::requestFinished);
275 scheduleGeometryUpdate();
278ConeGeometry::~ConeGeometry()
283float ConeGeometry::topRadius()
const
288void ConeGeometry::setTopRadius(
float newTopRadius)
290 if (qFuzzyCompare(m_topRadius, newTopRadius))
292 m_topRadius = newTopRadius;
293 emit topRadiusChanged();
294 scheduleGeometryUpdate();
297float ConeGeometry::bottomRadius()
const
299 return m_bottomRadius;
302void ConeGeometry::setBottomRadius(
float newBottomRadius)
304 if (qFuzzyCompare(m_bottomRadius, newBottomRadius))
306 m_bottomRadius = newBottomRadius;
307 emit bottomRadiusChanged();
308 scheduleGeometryUpdate();
311float ConeGeometry::length()
const
316void ConeGeometry::setLength(
float newLength)
318 if (qFuzzyCompare(m_length, newLength))
320 m_length = newLength;
321 emit lengthChanged();
322 scheduleGeometryUpdate();
325int ConeGeometry::rings()
const
330void ConeGeometry::setRings(
int newRings)
332 if (m_rings == newRings)
336 scheduleGeometryUpdate();
339int ConeGeometry::segments()
const
344void ConeGeometry::setSegments(
int newSegments)
346 if (m_segments == newSegments)
348 m_segments = newSegments;
349 emit segmentsChanged();
350 scheduleGeometryUpdate();
353bool ConeGeometry::asynchronous()
const
355 return m_asynchronous;
358void ConeGeometry::setAsynchronous(
bool newAsynchronous)
360 if (m_asynchronous == newAsynchronous)
362 m_asynchronous = newAsynchronous;
363 emit asynchronousChanged();
366ConeGeometry::Status ConeGeometry::status()
const
371void ConeGeometry::doUpdateGeometry()
374 m_geometryUpdateRequested =
false;
376#if QT_CONFIG(concurrent)
377 if (m_geometryDataFuture.isRunning()) {
378 m_pendingAsyncUpdate =
true;
384 if (m_topRadius < 0 || m_bottomRadius < 0 || (m_topRadius <= 0 && m_bottomRadius <= 0) || m_length <= 0 || m_rings < 0 || m_segments < 3) {
390#if QT_CONFIG(concurrent)
391 if (m_asynchronous) {
392 m_geometryDataFuture = QtConcurrent::run(generateConeGeometryAsync,
398 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
399 m_status = Status::Loading;
400 Q_EMIT statusChanged();
406 updateGeometry(generateConeGeometry(m_topRadius, m_bottomRadius, m_length, m_rings, m_segments));
410void ConeGeometry::requestFinished()
412#if QT_CONFIG(concurrent)
413 const auto output = m_geometryDataFuture.takeResult();
414 updateGeometry(output);
418void ConeGeometry::scheduleGeometryUpdate()
420 if (!m_geometryUpdateRequested) {
421 QMetaObject::invokeMethod(
this,
"doUpdateGeometry", Qt::QueuedConnection);
422 m_geometryUpdateRequested =
true;
426void ConeGeometry::updateGeometry(
const GeometryData &geometryData)
428 setStride(
sizeof(
float) * 8);
429 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
430 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
432 QQuick3DGeometry::Attribute::F32Type);
433 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
435 QQuick3DGeometry::Attribute::F32Type);
436 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
438 QQuick3DGeometry::Attribute::F32Type);
439 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
441 QQuick3DGeometry::Attribute::U16Type);
443 setBounds(geometryData.boundsMin, geometryData.boundsMax);
444 setVertexData(geometryData.vertexData);
445 setIndexData(geometryData.indexData);
449 if (m_pendingAsyncUpdate) {
450 m_pendingAsyncUpdate =
false;
451 scheduleGeometryUpdate();
453 m_status = Status::Ready;
454 Q_EMIT statusChanged();
459ConeGeometry::GeometryData ConeGeometry::generateConeGeometry(
float topRadius,
float bottomRadius,
float length,
int rings,
int slices)
461 GeometryData geomData;
466 int capCount = (topRadius > 0 ? 1 : 0) + (bottomRadius > 0 ? 1 : 0);
469 int totalFaces = (slices * 2) * (rings - 1) + slices * capCount;
470 int totalVertices = (slices + 1) * rings + capCount * (slices + 2);
471 int totalIndices = totalFaces * 3;
474 geomData.vertexData.resize(totalVertices * 8 *
sizeof(
float));
475 geomData.indexData.resize(totalIndices *
sizeof(quint16));
478 float* verticesPtr =
reinterpret_cast<
float*>(geomData.vertexData.data());
479 quint16* indicesPtr =
reinterpret_cast<quint16*>(geomData.indexData.data());
482 if (bottomRadius > 0 && topRadius > 0) {
483 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
484 createConeSidesIndices(indicesPtr, rings, slices);
485 int bottomCenterIndex = rings * (slices + 1);
486 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, -length / 2);
487 createDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
488 int topCenterIndex = bottomRadius > 0 ? rings * (slices + 1) + (slices + 2) : rings * (slices + 1);
489 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, length / 2);
490 createDiscIndices(indicesPtr, topCenterIndex, slices,
false);
495 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
496 createConeSidesIndices(indicesPtr, rings, slices);
499 int topCenterIndex = rings * (slices + 1);
500 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, length / 2);
501 createDiscIndices(indicesPtr, topCenterIndex, slices,
false);
505 if (bottomRadius > 0) {
507 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
508 createConeSidesIndices(indicesPtr, rings, slices);
511 int bottomCenterIndex = rings * (slices + 1);
512 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, -length / 2);
513 createDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
518 float* vertexData =
reinterpret_cast<
float*>(geomData.vertexData.data());
519 QVector3D boundsMin(std::numeric_limits<
float>::max(),
520 std::numeric_limits<
float>::max(),
521 std::numeric_limits<
float>::max());
522 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
523 std::numeric_limits<
float>::lowest(),
524 std::numeric_limits<
float>::lowest());
525 for (
int i = 0; i < totalVertices; ++i) {
526 QVector3D pos(vertexData[i * 8], vertexData[i * 8 + 1], vertexData[i * 8 + 2]);
527 boundsMin.setX(qMin(boundsMin.x(), pos.x()));
528 boundsMin.setY(qMin(boundsMin.y(), pos.y()));
529 boundsMin.setZ(qMin(boundsMin.z(), pos.z()));
531 boundsMax.setX(qMax(boundsMax.x(), pos.x()));
532 boundsMax.setY(qMax(boundsMax.y(), pos.y()));
533 boundsMax.setZ(qMax(boundsMax.z(), pos.z()));
535 geomData.boundsMin = boundsMin;
536 geomData.boundsMax = boundsMax;
541#if QT_CONFIG(concurrent)
542void ConeGeometry::generateConeGeometryAsync(QPromise<ConeGeometry::GeometryData> &promise,
549 auto output = generateConeGeometry(topRadius, bottomRadius, length, rings, segments);
550 promise.addResult(output);
void createConeSidesVertices(float *&verticesPtr, int rings, int slices, double topRadius, double bottomRadius, double length)
void createConeSidesIndices(quint16 *&indicesPtr, int rings, int slices)
void createConeDiscVertices(float *&verticesPtr, int slices, double topRadius, double bottomRadius, double length, double yPosition)
void createDiscIndices(quint16 *&indicesPtr, int discCenterIndex, int slices, bool isTopCap)