10#if QT_CONFIG(concurrent)
11#include <QtConcurrentRun>
25 const float dY = length /
static_cast<
float>(rings - 1);
26 const float dTheta = (M_PI * 2) /
static_cast<
float>(slices);
29 bool isTruncatedCone = (topRadius > 0 && bottomRadius > 0);
30 bool isUpwardCone = (topRadius > 0 && bottomRadius == 0);
31 bool isDownwardCone = (topRadius == 0 && bottomRadius > 0);
33 for (
int ring = 0; ring < rings; ++ring) {
34 const float y = -length / 2.0f +
static_cast<
float>(ring) * dY;
36 const float t = (y + length / 2) / length;
37 const float radius = (bottomRadius * (1 - t)) + (t * topRadius);
39 for (
int slice = 0; slice <= slices; ++slice) {
40 const float theta =
static_cast<
float>(slice) * dTheta;
41 const float ta = std::tan((M_PI/2) - std::atan(length / (bottomRadius - topRadius)));
42 const float ct = std::cos(theta);
43 const float st = std::sin(theta);
46 *verticesPtr++ = radius * ct;
48 *verticesPtr++ = radius * st;
51 if (isTruncatedCone) {
54 float v = 0.5f + (y + length / 2.0f) / length / 2.0f;
55 *verticesPtr++ =
static_cast<
float>(slice) /
static_cast<
float>(slices);
58 }
else if (isDownwardCone) {
62 float rUV = 1.0f -
static_cast<
float>(ring) /
static_cast<
float>(rings - 1);
63 float u = 0.25f + rUV * ct * 0.25f;
64 float v = 0.25f + -rUV * st * 0.25f;
68 }
else if (isUpwardCone) {
72 float rUV =
static_cast<
float>(ring) /
static_cast<
float>(rings - 1);
73 float u = 0.75f + rUV * ct * 0.25f;
74 float v = 0.25f + rUV * st * 0.25f;
80 QVector3D n(ct, ta, st);
82 *verticesPtr++ = n.x();
83 *verticesPtr++ = n.y();
84 *verticesPtr++ = n.z();
91 for (
int ring = 0; ring < rings-1; ++ring) {
92 const int ringIndexStart = ring * (slices + 1);
93 const int nextRingIndexStart = (ring + 1) * (slices + 1);
95 for (
int slice = 0; slice <= slices; ++slice) {
99 const int nextSlice = slice + 1;
101 *indicesPtr++ = (ringIndexStart + slice);
102 *indicesPtr++ = (nextRingIndexStart + slice);
103 *indicesPtr++ = (ringIndexStart + nextSlice);
104 *indicesPtr++ = (ringIndexStart + nextSlice);
105 *indicesPtr++ = (nextRingIndexStart + slice);
106 *indicesPtr++ = (nextRingIndexStart + nextSlice);
118 const float dTheta = (M_PI * 2) /
static_cast<
float>(slices);
119 const double yNormal = (yPosition < 0.0f) ? -1.0f : 1.0f;
121 *verticesPtr++ = 0.0f;
122 *verticesPtr++ = yPosition;
123 *verticesPtr++ = 0.0f;
125 if (yPosition < 0.0f) {
127 *verticesPtr++ = 0.75f;
128 *verticesPtr++ = 0.25f;
131 *verticesPtr++ = 0.25f;
132 *verticesPtr++ = 0.25f;
136 *verticesPtr++ = 0.0f;
137 *verticesPtr++ = yNormal;
138 *verticesPtr++ = 0.0f;
141 for (
int slice = 0; slice <= slices; ++slice)
143 const float theta =
static_cast<
float>(slice) * dTheta;
144 const float ct = std::cos(theta);
145 const float st = std::sin(theta);
147 const float t = (yPosition + length / 2) / length;
148 const float radius = (bottomRadius * (1 - t)) + (t * topRadius);
151 *verticesPtr++ = radius * ct;
152 *verticesPtr++ = yPosition;
153 *verticesPtr++ = radius * st;
156 if (yPosition < 0.0f) {
158 *verticesPtr++ = 0.75f + 0.25f * ct;
159 *verticesPtr++ = 0.25f + 0.25f * st;
162 *verticesPtr++ = 0.25f + 0.25f * ct;
163 *verticesPtr++ = 0.25f + 0.25f * -st;
167 *verticesPtr++ = 0.0f;
168 *verticesPtr++ = yNormal;
169 *verticesPtr++ = 0.0f;
179 for (
int i = slices - 1 ; i >= 0 ; --i )
182 *indicesPtr++ = discCenterIndex;
183 *indicesPtr++ = discCenterIndex + i + 1;
184 *indicesPtr++ = discCenterIndex + i;
186 *indicesPtr++ = discCenterIndex;
187 *indicesPtr++ = discCenterIndex + i + 1;
188 *indicesPtr++ = discCenterIndex + slices;
192 for (
int i = 0 ; i < slices; ++i )
194 if ( i != slices - 1 ) {
195 *indicesPtr++ = discCenterIndex;
196 *indicesPtr++ = discCenterIndex + i + 1;
197 *indicesPtr++ = discCenterIndex + i + 2;
199 *indicesPtr++ = discCenterIndex;
200 *indicesPtr++ = discCenterIndex + i + 1;
201 *indicesPtr++ = discCenterIndex + 1;
210
211
212
213
214
215
216
217
218
219
222
223
224
225
226
229
230
231
232
233
236
237
238
239
242
243
244
245
248
249
250
251
254
255
256
257
260
261
262
263
264
265
266
267
268
269
271ConeGeometry::ConeGeometry(QQuick3DObject *parent)
272 : QQuick3DGeometry(parent)
274#if QT_CONFIG(concurrent)
275 connect(&m_geometryDataWatcher, &QFutureWatcher<GeometryData>::finished,
this, &ConeGeometry::requestFinished);
277 scheduleGeometryUpdate();
280ConeGeometry::~ConeGeometry()
285float ConeGeometry::topRadius()
const
290void ConeGeometry::setTopRadius(
float newTopRadius)
292 if (qFuzzyCompare(m_topRadius, newTopRadius))
294 m_topRadius = newTopRadius;
295 emit topRadiusChanged();
296 scheduleGeometryUpdate();
299float ConeGeometry::bottomRadius()
const
301 return m_bottomRadius;
304void ConeGeometry::setBottomRadius(
float newBottomRadius)
306 if (qFuzzyCompare(m_bottomRadius, newBottomRadius))
308 m_bottomRadius = newBottomRadius;
309 emit bottomRadiusChanged();
310 scheduleGeometryUpdate();
313float ConeGeometry::length()
const
318void ConeGeometry::setLength(
float newLength)
320 if (qFuzzyCompare(m_length, newLength))
322 m_length = newLength;
323 emit lengthChanged();
324 scheduleGeometryUpdate();
327int ConeGeometry::rings()
const
332void ConeGeometry::setRings(
int newRings)
334 if (m_rings == newRings)
338 scheduleGeometryUpdate();
341int ConeGeometry::segments()
const
346void ConeGeometry::setSegments(
int newSegments)
348 if (m_segments == newSegments)
350 m_segments = newSegments;
351 emit segmentsChanged();
352 scheduleGeometryUpdate();
355bool ConeGeometry::asynchronous()
const
357 return m_asynchronous;
360void ConeGeometry::setAsynchronous(
bool newAsynchronous)
362 if (m_asynchronous == newAsynchronous)
364 m_asynchronous = newAsynchronous;
365 emit asynchronousChanged();
368ConeGeometry::Status ConeGeometry::status()
const
373void ConeGeometry::doUpdateGeometry()
376 m_geometryUpdateRequested =
false;
378#if QT_CONFIG(concurrent)
379 if (m_geometryDataFuture.isRunning()) {
380 m_pendingAsyncUpdate =
true;
386 if (m_topRadius < 0 || m_bottomRadius < 0 || (m_topRadius <= 0 && m_bottomRadius <= 0) || m_length <= 0 || m_rings < 0 || m_segments < 3) {
392#if QT_CONFIG(concurrent)
394 if (m_asynchronous && QT_CONFIG(thread)) {
395 m_geometryDataFuture = QtConcurrent::run(generateConeGeometryAsync,
401 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
402 m_status = Status::Loading;
403 Q_EMIT statusChanged();
409 updateGeometry(generateConeGeometry(m_topRadius, m_bottomRadius, m_length, m_rings, m_segments));
413void ConeGeometry::requestFinished()
415#if QT_CONFIG(concurrent)
416 const auto output = m_geometryDataFuture.takeResult();
417 updateGeometry(output);
421void ConeGeometry::scheduleGeometryUpdate()
423 if (!m_geometryUpdateRequested) {
424 QMetaObject::invokeMethod(
this,
"doUpdateGeometry", Qt::QueuedConnection);
425 m_geometryUpdateRequested =
true;
429void ConeGeometry::updateGeometry(
const GeometryData &geometryData)
432 setStride(
sizeof(
float) * 8);
433 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
434 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
436 QQuick3DGeometry::Attribute::F32Type);
437 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
439 QQuick3DGeometry::Attribute::F32Type);
440 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
442 QQuick3DGeometry::Attribute::F32Type);
443 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
445 QQuick3DGeometry::Attribute::U16Type);
447 setBounds(geometryData.boundsMin, geometryData.boundsMax);
448 setVertexData(geometryData.vertexData);
449 setIndexData(geometryData.indexData);
453 if (m_pendingAsyncUpdate) {
454 m_pendingAsyncUpdate =
false;
455 scheduleGeometryUpdate();
457 m_status = Status::Ready;
458 Q_EMIT statusChanged();
461 emit geometryChanged();
464ConeGeometry::GeometryData ConeGeometry::generateConeGeometry(
float topRadius,
float bottomRadius,
float length,
int rings,
int slices)
466 GeometryData geomData;
471 int capCount = (topRadius > 0 ? 1 : 0) + (bottomRadius > 0 ? 1 : 0);
474 int totalFaces = (slices * 2) * (rings - 1) + slices * capCount;
475 int totalVertices = (slices + 1) * rings + capCount * (slices + 2);
476 int totalIndices = totalFaces * 3;
479 geomData.vertexData.resize(totalVertices * 8 *
sizeof(
float));
480 geomData.indexData.resize(totalIndices *
sizeof(quint16));
483 float* verticesPtr =
reinterpret_cast<
float*>(geomData.vertexData.data());
484 quint16* indicesPtr =
reinterpret_cast<quint16*>(geomData.indexData.data());
487 if (bottomRadius > 0 && topRadius > 0) {
488 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
489 createConeSidesIndices(indicesPtr, rings, slices);
490 int bottomCenterIndex = rings * (slices + 1);
491 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, -length / 2);
492 createDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
493 int topCenterIndex = bottomRadius > 0 ? rings * (slices + 1) + (slices + 2) : rings * (slices + 1);
494 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, length / 2);
495 createDiscIndices(indicesPtr, topCenterIndex, slices,
false);
500 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
501 createConeSidesIndices(indicesPtr, rings, slices);
504 int topCenterIndex = rings * (slices + 1);
505 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, length / 2);
506 createDiscIndices(indicesPtr, topCenterIndex, slices,
false);
510 if (bottomRadius > 0) {
512 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
513 createConeSidesIndices(indicesPtr, rings, slices);
516 int bottomCenterIndex = rings * (slices + 1);
517 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, -length / 2);
518 createDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
523 float* vertexData =
reinterpret_cast<
float*>(geomData.vertexData.data());
524 QVector3D boundsMin(std::numeric_limits<
float>::max(),
525 std::numeric_limits<
float>::max(),
526 std::numeric_limits<
float>::max());
527 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
528 std::numeric_limits<
float>::lowest(),
529 std::numeric_limits<
float>::lowest());
530 for (
int i = 0; i < totalVertices; ++i) {
531 QVector3D pos(vertexData[i * 8], vertexData[i * 8 + 1], vertexData[i * 8 + 2]);
532 boundsMin.setX(qMin(boundsMin.x(), pos.x()));
533 boundsMin.setY(qMin(boundsMin.y(), pos.y()));
534 boundsMin.setZ(qMin(boundsMin.z(), pos.z()));
536 boundsMax.setX(qMax(boundsMax.x(), pos.x()));
537 boundsMax.setY(qMax(boundsMax.y(), pos.y()));
538 boundsMax.setZ(qMax(boundsMax.z(), pos.z()));
540 geomData.boundsMin = boundsMin;
541 geomData.boundsMax = boundsMax;
546#if QT_CONFIG(concurrent)
547void ConeGeometry::generateConeGeometryAsync(QPromise<ConeGeometry::GeometryData> &promise,
554 auto output = generateConeGeometry(topRadius, bottomRadius, length, rings, segments);
555 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)