ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvTorus.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "ecvTorus.h"
9 
10 // Local
11 #include "ecvNormalVectors.h"
12 #include "ecvPointCloud.h"
13 
15  PointCoordinateType outsideRadius,
16  double angle_rad /*=2.0*M_PI*/,
17  bool rectangularSection /*=false*/,
18  PointCoordinateType rectSectionHeight /*=0*/,
19  const ccGLMatrix* transMat /*=0*/,
20  QString name /*=QString("Torus")*/,
21  unsigned precision /*=DEFAULT_DRAWING_PRECISION*/)
22  : ccGenericPrimitive(name, transMat),
23  m_insideRadius(fabs(insideRadius)),
24  m_outsideRadius(fabs(outsideRadius)),
25  m_rectSection(rectangularSection),
26  m_rectSectionHeight(fabs(rectSectionHeight)),
27  m_angle_rad(fabs(angle_rad)) {
28  setDrawingPrecision(std::max<unsigned>(
29  precision, MIN_DRAWING_PRECISION)); // automatically calls
30  // updateRepresentation
31 }
32 
33 ccTorus::ccTorus(QString name /*=QString("Torus")*/)
35  m_insideRadius(0),
36  m_outsideRadius(0),
37  m_rectSection(false),
38  m_rectSectionHeight(0),
39  m_angle_rad(0) {}
40 
46 }
47 
49  if (m_drawPrecision < MIN_DRAWING_PRECISION) return false;
50 
51  // invalid parameters?
55  return false;
56  }
57  // topology
58  bool closed = (m_angle_rad >= 2.0 * M_PI);
59 
60  const unsigned steps = m_drawPrecision;
61 
62  unsigned sweepSteps =
63  4 * (closed ? steps
64  : static_cast<unsigned>(
65  ceil((m_angle_rad * steps) / (2.0 * M_PI))));
66  unsigned sectSteps = (m_rectSection ? 4 : steps);
67 
68  // vertices
69  unsigned vertCount = (sweepSteps + (closed ? 0 : 1)) *
70  sectSteps; // DGM: +1 row for non closed loops
71  // faces
72  unsigned facesCount = sweepSteps * sectSteps * 2;
73  // faces normals
74  unsigned faceNormCount = (sweepSteps + (closed ? 0 : 1)) *
75  sectSteps; // DGM: +1 row for non closed loops
76  if (!closed) facesCount += (m_rectSection ? 2 : sectSteps) * 2;
77 
78  if (!init(vertCount + (closed || m_rectSection ? 0 : 2), false, facesCount,
79  faceNormCount + (closed ? 0 : 2))) {
80  CVLog::Error("[ccTorus::buildUp] Not enough memory");
81  return false;
82  }
83 
84  // 2D section
85  std::vector<CCVector3> sectPoints;
86  try {
87  sectPoints.resize(sectSteps);
88  } catch (const std::bad_alloc&) {
89  init(0, false, 0, 0);
90  CVLog::Error("[ccTorus::buildUp] Not enough memory");
91  return false;
92  }
93 
94  double sweepStep_rad = m_angle_rad / sweepSteps;
95  double sectStep_rad = (2.0 * M_PI) / sectSteps;
96 
97  PointCoordinateType sectionRadius = (m_outsideRadius - m_insideRadius) / 2;
98  if (m_rectSection) {
99  // rectangular section
100  sectPoints[0].x = (m_outsideRadius - m_insideRadius) / 2;
101  sectPoints[0].z = m_rectSectionHeight / 2;
102  sectPoints[1].x = -sectPoints[0].x;
103  sectPoints[1].z = sectPoints[0].z;
104  sectPoints[2].x = sectPoints[1].x;
105  sectPoints[2].z = -sectPoints[1].z;
106  sectPoints[3].x = -sectPoints[2].x;
107  sectPoints[3].z = sectPoints[2].z;
108  } else {
109  // circular section
110  for (unsigned i = 0; i < sectSteps; ++i) {
111  double sect_angle_rad = i * sectStep_rad;
112  sectPoints[i].x = static_cast<PointCoordinateType>(
113  cos(sect_angle_rad) * sectionRadius);
114  sectPoints[i].z = static_cast<PointCoordinateType>(
115  sin(sect_angle_rad) * sectionRadius);
116  }
117  }
118 
119  ccPointCloud* verts = vertices();
120  assert(verts);
121  assert(m_triNormals);
122 
123  // main sweep
124  PointCoordinateType sweepRadius = (m_insideRadius + m_outsideRadius) / 2;
125  for (unsigned t = 0; t < (closed ? sweepSteps : sweepSteps + 1); ++t) {
126  // unit director vector
127  CCVector3 sweepU(
128  static_cast<PointCoordinateType>(cos(t * sweepStep_rad)),
129  static_cast<PointCoordinateType>(sin(t * sweepStep_rad)), 0);
130 
131  // section points
132  for (unsigned i = 0; i < sectSteps; ++i) {
133  CCVector3 P(sweepU.x * (sweepRadius + sectPoints[i].x),
134  sweepU.y * (sweepRadius + sectPoints[i].x),
135  sectPoints[i].z);
136  verts->addPoint(P);
137  }
138 
139  // normals
140  if (m_rectSection) {
142  ccNormalVectors::GetNormIndex(CCVector3(0.0, 0.0, 1.0).u));
144  ccNormalVectors::GetNormIndex((-sweepU).u));
146  ccNormalVectors::GetNormIndex(CCVector3(0.0, 0.0, -1.0).u));
148  } else // circular section
149  {
150  for (unsigned i = 0; i < sectSteps; ++i) {
151  double sectAngle_rad = i * sectStep_rad;
153  CCVector3(cos(sectAngle_rad), 0.0, sin(sectAngle_rad))
154  .u);
155  CCVector3 N(sweepU.x * sectU.x, sweepU.y * sectU.x, sectU.z);
157  }
158  }
159  }
160 
161  if (!closed && !m_rectSection) {
162  CCVector3 P(sweepRadius, 0, 0);
163  verts->addPoint(P);
164  CCVector3 P2(static_cast<PointCoordinateType>(cos(m_angle_rad)) *
165  sweepRadius,
166  static_cast<PointCoordinateType>(sin(m_angle_rad)) *
167  sweepRadius,
168  0);
169  verts->addPoint(P2);
170  }
171 
172  if (!closed) {
173  // first section (left side)
176  // last section (right side)
178  CCVector3(static_cast<PointCoordinateType>(-sin(m_angle_rad)),
179  static_cast<PointCoordinateType>(cos(m_angle_rad)), 0)
180  .u));
181  }
182 
183  sectPoints.clear();
184 
185  // mesh faces
186  {
187  assert(m_triVertIndexes);
188 
189  for (unsigned t = 0; t < sweepSteps; ++t) {
190  unsigned sweepStart = t * sectSteps;
191  for (unsigned i = 0; i < sectSteps; ++i) {
192  unsigned iNext = (i + 1) % sectSteps;
193  addTriangle(sweepStart + i,
194  (sweepStart + i + sectSteps) % vertCount,
195  (sweepStart + iNext + sectSteps) % vertCount);
196  if (m_rectSection)
198  sweepStart + i,
199  (sweepStart + i + sectSteps) % faceNormCount,
200  (sweepStart + i + sectSteps) % faceNormCount);
201  else
203  sweepStart + i,
204  (sweepStart + i + sectSteps) % faceNormCount,
205  (sweepStart + iNext + sectSteps) % faceNormCount);
206  addTriangle(sweepStart + i,
207  (sweepStart + iNext + sectSteps) % vertCount,
208  sweepStart + iNext);
209  if (m_rectSection)
211  sweepStart + i,
212  (sweepStart + i + sectSteps) % faceNormCount,
213  sweepStart + i);
214  else
216  sweepStart + i,
217  (sweepStart + iNext + sectSteps) % faceNormCount,
218  sweepStart + iNext);
219  }
220  }
221 
222  if (!closed) {
223  unsigned lastSectionShift = sweepSteps * sectSteps;
224  if (m_rectSection) {
225  // rectangular left section
226  addTriangle(0, 1, 2);
227  addTriangleNormalIndexes(faceNormCount, faceNormCount,
228  faceNormCount);
229  addTriangle(0, 2, 3);
230  addTriangleNormalIndexes(faceNormCount, faceNormCount,
231  faceNormCount);
232  // rectangular right section
233  addTriangle(lastSectionShift, lastSectionShift + 2,
234  lastSectionShift + 1);
235  addTriangleNormalIndexes(faceNormCount + 1, faceNormCount + 1,
236  faceNormCount + 1);
237  addTriangle(lastSectionShift, lastSectionShift + 3,
238  lastSectionShift + 2);
239  addTriangleNormalIndexes(faceNormCount + 1, faceNormCount + 1,
240  faceNormCount + 1);
241  } else {
242  unsigned lastSectionCenterShift = vertCount;
243  // circular 'left' section
244  for (unsigned i = 0; i < sectSteps; ++i) {
245  unsigned iNext = (i + 1) % sectSteps;
246  addTriangle(lastSectionCenterShift, i, iNext);
247  addTriangleNormalIndexes(faceNormCount, faceNormCount,
248  faceNormCount);
249  }
250  // circular 'right' section
251  for (unsigned i = 0; i < sectSteps; ++i) {
252  unsigned iNext = (i + 1) % sectSteps;
253  addTriangle(lastSectionCenterShift + 1,
254  lastSectionShift + iNext, lastSectionShift + i);
255  addTriangleNormalIndexes(faceNormCount + 1,
256  faceNormCount + 1,
257  faceNormCount + 1);
258  }
259  }
260  }
261  }
262 
264  showTriNorms(true);
265 
266  return true;
267 }
268 
269 bool ccTorus::toFile_MeOnly(QFile& out, short dataVersion) const {
270  assert(out.isOpen() && (out.openMode() & QIODevice::WriteOnly));
271  if (dataVersion < 21) {
272  assert(false);
273  return false;
274  }
275 
276  if (!ccGenericPrimitive::toFile_MeOnly(out, dataVersion)) return false;
277 
278  // parameters (dataVersion>=21)
279  QDataStream outStream(&out);
280  outStream << m_insideRadius;
281  outStream << m_outsideRadius;
282  outStream << m_rectSection;
283  outStream << m_rectSectionHeight;
284  outStream << m_angle_rad;
285 
286  return true;
287 }
288 
290  return std::max(static_cast<short>(21),
292 }
293 
295  short dataVersion,
296  int flags,
297  LoadedIDMap& oldToNewIDMap) {
298  if (!ccGenericPrimitive::fromFile_MeOnly(in, dataVersion, flags,
299  oldToNewIDMap))
300  return false;
301 
302  // parameters (dataVersion>=21)
303  QDataStream inStream(&in);
305  &m_insideRadius, 1);
307  &m_outsideRadius, 1);
308  inStream >> m_rectSection;
310  &m_rectSectionHeight, 1);
311  inStream >> m_angle_rad;
312 
313  return true;
314 }
constexpr double M_PI
Pi.
Definition: CVConst.h:19
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
Definition: CVGeom.h:798
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
std::string name
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
Type y
Definition: CVGeom.h:137
Type u[3]
Definition: CVGeom.h:139
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
Definition: CVGeom.h:268
void addElement(const Type &value)
Definition: ecvArray.h:105
Float version of ccGLMatrixTpl.
Definition: ecvGLMatrix.h:19
virtual void showTriNorms(bool state)
Sets whether to show or not per-triangle normals.
Generic primitive interface.
bool init(unsigned vertCount, bool vertNormals, unsigned faceCount, unsigned faceNormCount)
Inits internal structures.
virtual bool setDrawingPrecision(unsigned steps)
Sets drawing precision.
ccGenericPrimitive * finishCloneJob(ccGenericPrimitive *primitive) const
Finished 'clone' job (vertices color, etc.)
ccPointCloud * vertices()
Returns vertices.
unsigned m_drawPrecision
Drawing precision (for primitives that support this feature)
static const int MIN_DRAWING_PRECISION
Minimum drawing precision.
bool toFile_MeOnly(QFile &out, short dataVersion) const override
Save own object data.
bool fromFile_MeOnly(QFile &in, short dataVersion, int flags, LoadedIDMap &oldToNewIDMap) override
Loads own object data.
ccGLMatrix m_transformation
Associated transformation (applied to vertices)
short minimumFileVersion_MeOnly() const override
virtual void notifyGeometryUpdate()
Definition: ecvHObject.cpp:104
NormsIndexesTableType * m_triNormals
Per-triangle normals.
Definition: ecvMesh.h:1493
void addTriangle(unsigned i1, unsigned i2, unsigned i3)
Adds a triangle to the mesh.
Definition: ecvMesh.cpp:2428
void addTriangleNormalIndexes(int i1, int i2, int i3)
Adds a triplet of normal indexes for next triangle.
Definition: ecvMesh.cpp:3340
triangleIndexesContainer * m_triVertIndexes
Triangles' vertices indexes (3 per triangle)
Definition: ecvMesh.h:1502
static CompressedNormType GetNormIndex(const PointCoordinateType N[])
Returns the compressed index corresponding to a normal vector.
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
QMultiMap< unsigned, unsigned > LoadedIDMap
Map of loaded unique IDs (old ID --> new ID)
static void CoordsFromDataStream(QDataStream &stream, int flags, PointCoordinateType *out, unsigned count=1)
ccTorus(PointCoordinateType insideRadius, PointCoordinateType outsideRadius, double angle_rad=2.0 *M_PI, bool rectangularSection=false, PointCoordinateType rectSectionHeight=0, const ccGLMatrix *transMat=0, QString name=QString("Torus"), unsigned precision=DEFAULT_DRAWING_PRECISION)
Default constructor.
Definition: ecvTorus.cpp:14
virtual bool buildUp() override
Builds primitive.
Definition: ecvTorus.cpp:48
bool toFile_MeOnly(QFile &out, short dataVersion) const override
Save own object data.
Definition: ecvTorus.cpp:269
double m_angle_rad
Subtended angle (in radians)
Definition: ecvTorus.h:101
PointCoordinateType m_insideRadius
Inside radius.
Definition: ecvTorus.h:89
PointCoordinateType m_rectSectionHeight
Rectangular section height (along Y-axis) if applicable.
Definition: ecvTorus.h:98
bool fromFile_MeOnly(QFile &in, short dataVersion, int flags, LoadedIDMap &oldToNewIDMap) override
Loads own object data.
Definition: ecvTorus.cpp:294
bool m_rectSection
Whether torus has a rectangular (true) or circular (false) section.
Definition: ecvTorus.h:95
PointCoordinateType m_outsideRadius
Outside radius.
Definition: ecvTorus.h:92
virtual ccGenericPrimitive * clone() const override
Clones primitive.
Definition: ecvTorus.cpp:41
short minimumFileVersion_MeOnly() const override
Definition: ecvTorus.cpp:289
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Definition: MiniVec.h:89
bool LessThanEpsilon(float x)
Test a floating point number against our epsilon (a very small number).
Definition: CVMath.h:23