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)
393 if (m_asynchronous) {
394 m_geometryDataFuture = QtConcurrent::run(generateConeGeometryAsync,
400 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
401 m_status = Status::Loading;
402 Q_EMIT statusChanged();
408 updateGeometry(generateConeGeometry(m_topRadius, m_bottomRadius, m_length, m_rings, m_segments));
412void ConeGeometry::requestFinished()
414#if QT_CONFIG(concurrent)
415 const auto output = m_geometryDataFuture.takeResult();
416 updateGeometry(output);
420void ConeGeometry::scheduleGeometryUpdate()
422 if (!m_geometryUpdateRequested) {
423 QMetaObject::invokeMethod(
this,
"doUpdateGeometry", Qt::QueuedConnection);
424 m_geometryUpdateRequested =
true;
428void ConeGeometry::updateGeometry(
const GeometryData &geometryData)
431 setStride(
sizeof(
float) * 8);
432 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
433 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
435 QQuick3DGeometry::Attribute::F32Type);
436 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
438 QQuick3DGeometry::Attribute::F32Type);
439 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
441 QQuick3DGeometry::Attribute::F32Type);
442 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
444 QQuick3DGeometry::Attribute::U16Type);
446 setBounds(geometryData.boundsMin, geometryData.boundsMax);
447 setVertexData(geometryData.vertexData);
448 setIndexData(geometryData.indexData);
452 if (m_pendingAsyncUpdate) {
453 m_pendingAsyncUpdate =
false;
454 scheduleGeometryUpdate();
456 m_status = Status::Ready;
457 Q_EMIT statusChanged();
460 emit geometryChanged();
463ConeGeometry::GeometryData ConeGeometry::generateConeGeometry(
float topRadius,
float bottomRadius,
float length,
int rings,
int slices)
465 GeometryData geomData;
470 int capCount = (topRadius > 0 ? 1 : 0) + (bottomRadius > 0 ? 1 : 0);
473 int totalFaces = (slices * 2) * (rings - 1) + slices * capCount;
474 int totalVertices = (slices + 1) * rings + capCount * (slices + 2);
475 int totalIndices = totalFaces * 3;
478 geomData.vertexData.resize(totalVertices * 8 *
sizeof(
float));
479 geomData.indexData.resize(totalIndices *
sizeof(quint16));
482 float* verticesPtr =
reinterpret_cast<
float*>(geomData.vertexData.data());
483 quint16* indicesPtr =
reinterpret_cast<quint16*>(geomData.indexData.data());
486 if (bottomRadius > 0 && topRadius > 0) {
487 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
488 createConeSidesIndices(indicesPtr, rings, slices);
489 int bottomCenterIndex = rings * (slices + 1);
490 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, -length / 2);
491 createDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
492 int topCenterIndex = bottomRadius > 0 ? rings * (slices + 1) + (slices + 2) : rings * (slices + 1);
493 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, length / 2);
494 createDiscIndices(indicesPtr, topCenterIndex, slices,
false);
499 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
500 createConeSidesIndices(indicesPtr, rings, slices);
503 int topCenterIndex = rings * (slices + 1);
504 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, length / 2);
505 createDiscIndices(indicesPtr, topCenterIndex, slices,
false);
509 if (bottomRadius > 0) {
511 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
512 createConeSidesIndices(indicesPtr, rings, slices);
515 int bottomCenterIndex = rings * (slices + 1);
516 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, -length / 2);
517 createDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
522 float* vertexData =
reinterpret_cast<
float*>(geomData.vertexData.data());
523 QVector3D boundsMin(std::numeric_limits<
float>::max(),
524 std::numeric_limits<
float>::max(),
525 std::numeric_limits<
float>::max());
526 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
527 std::numeric_limits<
float>::lowest(),
528 std::numeric_limits<
float>::lowest());
529 for (
int i = 0; i < totalVertices; ++i) {
530 QVector3D pos(vertexData[i * 8], vertexData[i * 8 + 1], vertexData[i * 8 + 2]);
531 boundsMin.setX(qMin(boundsMin.x(), pos.x()));
532 boundsMin.setY(qMin(boundsMin.y(), pos.y()));
533 boundsMin.setZ(qMin(boundsMin.z(), pos.z()));
535 boundsMax.setX(qMax(boundsMax.x(), pos.x()));
536 boundsMax.setY(qMax(boundsMax.y(), pos.y()));
537 boundsMax.setZ(qMax(boundsMax.z(), pos.z()));
539 geomData.boundsMin = boundsMin;
540 geomData.boundsMax = boundsMax;
545#if QT_CONFIG(concurrent)
546void ConeGeometry::generateConeGeometryAsync(QPromise<ConeGeometry::GeometryData> &promise,
553 auto output = generateConeGeometry(topRadius, bottomRadius, length, rings, segments);
554 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)