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)
430 setStride(
sizeof(
float) * 8);
431 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
432 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
434 QQuick3DGeometry::Attribute::F32Type);
435 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
437 QQuick3DGeometry::Attribute::F32Type);
438 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
440 QQuick3DGeometry::Attribute::F32Type);
441 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
443 QQuick3DGeometry::Attribute::U16Type);
445 setBounds(geometryData.boundsMin, geometryData.boundsMax);
446 setVertexData(geometryData.vertexData);
447 setIndexData(geometryData.indexData);
451 if (m_pendingAsyncUpdate) {
452 m_pendingAsyncUpdate =
false;
453 scheduleGeometryUpdate();
455 m_status = Status::Ready;
456 Q_EMIT statusChanged();
459 emit geometryChanged();
462ConeGeometry::GeometryData ConeGeometry::generateConeGeometry(
float topRadius,
float bottomRadius,
float length,
int rings,
int slices)
464 GeometryData geomData;
469 int capCount = (topRadius > 0 ? 1 : 0) + (bottomRadius > 0 ? 1 : 0);
472 int totalFaces = (slices * 2) * (rings - 1) + slices * capCount;
473 int totalVertices = (slices + 1) * rings + capCount * (slices + 2);
474 int totalIndices = totalFaces * 3;
477 geomData.vertexData.resize(totalVertices * 8 *
sizeof(
float));
478 geomData.indexData.resize(totalIndices *
sizeof(quint16));
481 float* verticesPtr =
reinterpret_cast<
float*>(geomData.vertexData.data());
482 quint16* indicesPtr =
reinterpret_cast<quint16*>(geomData.indexData.data());
485 if (bottomRadius > 0 && topRadius > 0) {
486 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
487 createConeSidesIndices(indicesPtr, rings, slices);
488 int bottomCenterIndex = rings * (slices + 1);
489 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, -length / 2);
490 createDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
491 int topCenterIndex = bottomRadius > 0 ? rings * (slices + 1) + (slices + 2) : rings * (slices + 1);
492 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, length / 2);
493 createDiscIndices(indicesPtr, topCenterIndex, slices,
false);
498 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
499 createConeSidesIndices(indicesPtr, rings, slices);
502 int topCenterIndex = rings * (slices + 1);
503 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, length / 2);
504 createDiscIndices(indicesPtr, topCenterIndex, slices,
false);
508 if (bottomRadius > 0) {
510 createConeSidesVertices(verticesPtr, rings, slices, topRadius, bottomRadius, length);
511 createConeSidesIndices(indicesPtr, rings, slices);
514 int bottomCenterIndex = rings * (slices + 1);
515 createConeDiscVertices(verticesPtr, slices, topRadius, bottomRadius, length, -length / 2);
516 createDiscIndices(indicesPtr, bottomCenterIndex, slices,
true);
521 float* vertexData =
reinterpret_cast<
float*>(geomData.vertexData.data());
522 QVector3D boundsMin(std::numeric_limits<
float>::max(),
523 std::numeric_limits<
float>::max(),
524 std::numeric_limits<
float>::max());
525 QVector3D boundsMax(std::numeric_limits<
float>::lowest(),
526 std::numeric_limits<
float>::lowest(),
527 std::numeric_limits<
float>::lowest());
528 for (
int i = 0; i < totalVertices; ++i) {
529 QVector3D pos(vertexData[i * 8], vertexData[i * 8 + 1], vertexData[i * 8 + 2]);
530 boundsMin.setX(qMin(boundsMin.x(), pos.x()));
531 boundsMin.setY(qMin(boundsMin.y(), pos.y()));
532 boundsMin.setZ(qMin(boundsMin.z(), pos.z()));
534 boundsMax.setX(qMax(boundsMax.x(), pos.x()));
535 boundsMax.setY(qMax(boundsMax.y(), pos.y()));
536 boundsMax.setZ(qMax(boundsMax.z(), pos.z()));
538 geomData.boundsMin = boundsMin;
539 geomData.boundsMax = boundsMax;
544#if QT_CONFIG(concurrent)
545void ConeGeometry::generateConeGeometryAsync(QPromise<ConeGeometry::GeometryData> &promise,
552 auto output = generateConeGeometry(topRadius, bottomRadius, length, rings, segments);
553 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)