1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16
17 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
18
19
20 // NEVER COPY OR MOVE THE NEXT 2 LINES
21 #define ON_BOZO_VACCINE_17F24E7521BE4a7b9F3D7F85225247E3
22 #define ON_BOZO_VACCINE_B5628CA982C44CAE9883487B3E4AB28B
23 // NEVER COPY OR MOVE THE PREVIOUS 2 LINES
24
25
26
27
28 ///////////////////////////////////////////////////////
29 //
30 // Double precision vertices user data
31 //
32
33 class /* DO NOT copy, move, or export this class */ ON_MeshDoubleVertices : public ON_UserData
34 {
35 ON_OBJECT_DECLARE(ON_MeshDoubleVertices);
36
37 public:
38 ON_MeshDoubleVertices();
39 ~ON_MeshDoubleVertices();
40
41 // default copy constructor and operator= work fine.
42
43 /*
44 If the mesh has ON_MeshDoubleVertices user data, then return
45 a pointer to it.
46 */
47 static ON_MeshDoubleVertices* Get(const ON_Mesh* mesh);
48
49 /*
50 Attach new ON_MeshDoubleVertices user data to the mesh.
51 This will fail and return NULL if the mesh already has
52 ON_MeshDoubleVertices user data.
53 */
54 static ON_MeshDoubleVertices* Attach(const ON_Mesh* mesh);
55
56 // virtual ON_Object overrides
57 ON_BOOL32 IsValid( ON_TextLog* = NULL ) const;
58 void Dump( ON_TextLog& ) const;
59 unsigned int SizeOf() const;
60 ON__UINT32 DataCRC(ON__UINT32) const;
61 ON_BOOL32 Write(ON_BinaryArchive&) const;
62 ON_BOOL32 Read(ON_BinaryArchive&);
63
64 // virtual ON_UserData overrides
65 ON_BOOL32 GetDescription( ON_wString& );
66 ON_BOOL32 Archive() const;
67 ON_BOOL32 Transform( const ON_Xform& );
68
69 #if !defined(ON_BOZO_VACCINE_17F24E7521BE4a7b9F3D7F85225247E3)
70 #error DO NOT copy, move or export the definition of ON_MeshDoubleVertices
71 #endif
72 #undef ON_BOZO_VACCINE_17F24E7521BE4a7b9F3D7F85225247E3
73
74 ON__UINT32 DoubleCRC() const;
75 static ON__UINT32 FloatCRC( const ON_3fPointArray& );
76
77 // If m_dV.Count() != m_dcount or
78 // m_dCRC != ON_CRC32(0,m_dV.Count()*sizeof(ON_3dPoint),m_dV.Array()),
79 // then somebody has changed m_dV and not called
80 // SetDoublePrecisionVerticesAsValid() to mark the
81 // values as valid.
82 //
83 // If ON_Mesh.M_V.Count() != m_fcount or
84 // m_fCRC != ON_CRC32(0,m_V.Count()*sizeof(ON_3fPoint),m_V.Array()),
85 // then somebody has changed ON_Mesh.m_V and not called
86 // SetSinglePrecisionVerticesAsValid() to mark the
87 // values as valid.
88 //
89 // Whenever there is a question about which values are valid,
90 // it is assumed the m_V array is valid and the double precision
91 // informtion should be destroyed.
92 int m_fcount; // single precision vertex count
93 int m_dcount; // double precision vertex count
94 ON__UINT32 m_fCRC; // crc of float vertex array
95 ON__UINT32 m_dCRC; // crc of double vertex array
96
97 ON_3dPointArray m_dV; // double precision mesh vertices
98 };
99
Mesh_dV(const ON_Mesh & mesh)100 static const ON_3dPoint* Mesh_dV(const ON_Mesh& mesh)
101 {
102 if ( mesh.HasDoublePrecisionVertices() && mesh.DoublePrecisionVerticesAreValid() )
103 {
104 const ON_3dPointArray& a = mesh.DoublePrecisionVertices();
105 if ( a.Count() == mesh.m_V.Count() )
106 return a.Array();
107 }
108 return 0;
109 }
110
ON_MeshCurveParameters()111 ON_MeshCurveParameters::ON_MeshCurveParameters()
112 {
113 memset(this,0,sizeof(*this));
114 }
115
116 ON_OBJECT_IMPLEMENT(ON_Mesh,ON_Geometry,"4ED7D4E4-E947-11d3-BFE5-0010830122F0");
117
118 /*
119 ON_MeshEdge& ON_MeshEdge::operator=( const ON_MeshEdge& src )
120 {
121 int fc = src.m_fcount+(src.m_fcount%1);
122 if ( fc <= 2 ) {
123 if ( m_fi && m_fi != m_private_fi ) onfree((void*)m_fi);
124 m_fi = m_private_fi;
125 fc = 2;
126 }
127 else {
128 if ( (m_fcount+(m_fcount%1)) != fc ) {
129 if ( m_fi == m_private_fi )
130 m_fi = 0;
131 m_fi = (int*)onrealloc(m_fi,fc*sizeof(*m_fi));
132 }
133 }
134 memcpy(m_fi,src.m_fi,fc*sizeof(*m_fi));
135 m_fcount=src.m_fcount;
136 return *this;
137 }
138
139 void ON_MeshEdge::AppendFaceIndex(int face_index)
140 {
141 if ( m_fcount>0 && !(m_fcount%1) ) {
142 if ( m_fi == m_private_fi ) {
143 m_fi = (int*)onmalloc((m_fcount+2)*sizeof(*m_fi));
144 m_fi[0] = m_private_fi[0];
145 m_fi[1] = m_private_fi[1];
146 }
147 else {
148 m_fi = (int*)onrealloc(m_fi,(m_fcount+2)*sizeof(*m_fi));
149 }
150 }
151 m_fi[m_fcount++] = face_index;
152 }
153 */
154
155 bool
IsValid(int mesh_vertex_count) const156 ON_MeshFace::IsValid(int mesh_vertex_count) const
157 {
158 return ( vi[0] >= 0 && vi[0] < mesh_vertex_count
159 && vi[1] >= 0 && vi[1] < mesh_vertex_count
160 && vi[2] >= 0 && vi[2] < mesh_vertex_count
161 && vi[3] >= 0 && vi[3] < mesh_vertex_count
162 && vi[0] != vi[1] && vi[1] != vi[2] && vi[2] != vi[0]
163 && (vi[2]==vi[3]||(vi[0] != vi[3] && vi[1] != vi[3])) );
164 }
165
166
167 bool
IsValid(int mesh_vertex_count,const ON_3fPoint * V) const168 ON_MeshFace::IsValid(int mesh_vertex_count, const ON_3fPoint* V ) const
169 {
170 if ( !IsValid(mesh_vertex_count) )
171 return false;
172 if ( !(V[vi[0]] != V[vi[1]]) )
173 return false;
174 if ( !(V[vi[0]] != V[vi[2]]) )
175 return false;
176 if ( !(V[vi[1]] != V[vi[2]]) )
177 return false;
178 if ( vi[2] != vi[3] )
179 {
180 if ( !(V[vi[0]] != V[vi[3]]) )
181 return false;
182 if ( !(V[vi[1]] != V[vi[3]]) )
183 return false;
184 if ( !(V[vi[2]] != V[vi[3]]) )
185 return false;
186 }
187 return true;
188 }
189
190
191 bool
IsValid(int mesh_vertex_count,const ON_3dPoint * V) const192 ON_MeshFace::IsValid(int mesh_vertex_count, const ON_3dPoint* V ) const
193 {
194 if ( !IsValid(mesh_vertex_count) )
195 return false;
196 if ( !(V[vi[0]] != V[vi[1]]) )
197 return false;
198 if ( !(V[vi[0]] != V[vi[2]]) )
199 return false;
200 if ( !(V[vi[1]] != V[vi[2]]) )
201 return false;
202 if ( vi[2] != vi[3] )
203 {
204 if ( !(V[vi[0]] != V[vi[3]]) )
205 return false;
206 if ( !(V[vi[1]] != V[vi[3]]) )
207 return false;
208 if ( !(V[vi[2]] != V[vi[3]]) )
209 return false;
210 }
211 return true;
212 }
213
214
Repair(int mesh_vertex_count)215 bool ON_MeshFace::Repair(
216 int mesh_vertex_count
217 )
218 {
219 ON_MeshFace f;
220 int fvi_count = 0;
221 f.vi[0] = f.vi[1] = f.vi[2] = f.vi[3] = -1;
222
223 if ( vi[0] >= 0 && vi[0] < mesh_vertex_count )
224 f.vi[fvi_count++] = vi[0];
225
226 if ( vi[1] >= 0 && vi[1] < mesh_vertex_count && f.vi[0] != vi[1] )
227 f.vi[fvi_count++] = vi[1];
228
229 if ( vi[2] >= 0 && vi[2] < mesh_vertex_count && f.vi[0] != vi[2] && f.vi[1] != vi[2] )
230 f.vi[fvi_count++] = vi[2];
231
232 if ( vi[3] >= 0 && vi[3] < mesh_vertex_count && f.vi[0] != vi[3] && f.vi[1] != vi[3] && f.vi[2] != vi[3] )
233 f.vi[fvi_count++] = vi[3];
234
235 if ( fvi_count < 3 )
236 return false;
237
238 if ( 3 == fvi_count )
239 f.vi[3] = f.vi[2];
240
241 if ( !f.IsValid(mesh_vertex_count) )
242 return false;
243
244 vi[0] = f.vi[0];
245 vi[1] = f.vi[1];
246 vi[2] = f.vi[2];
247 vi[3] = f.vi[3];
248
249 return true;
250 }
251
Repair(int mesh_vertex_count,const ON_3fPoint * V)252 bool ON_MeshFace::Repair(
253 int mesh_vertex_count,
254 const ON_3fPoint* V
255 )
256 {
257 ON_MeshFace f;
258 int fvi_count = 0;
259 f.vi[0] = f.vi[1] = f.vi[2] = f.vi[3] = -1;
260
261 if ( vi[0] >= 0 && vi[0] < mesh_vertex_count )
262 f.vi[fvi_count++] = vi[0];
263
264 if ( vi[1] >= 0 && vi[1] < mesh_vertex_count && f.vi[0] != vi[1] )
265 {
266 if ( 0 == fvi_count || V[f.vi[0]] != V[vi[1]] )
267 f.vi[fvi_count++] = vi[1];
268 }
269
270 if ( fvi_count < 1 )
271 return false;
272
273 if ( vi[2] >= 0 && vi[2] < mesh_vertex_count && f.vi[0] != vi[2] && f.vi[1] != vi[2] && V[f.vi[0]] != V[vi[2]] )
274 {
275 if ( 1 == fvi_count || V[f.vi[1]] != V[vi[2]] )
276 f.vi[fvi_count++] = vi[2];
277 }
278
279 if ( fvi_count < 2 )
280 return false;
281
282 if ( vi[3] >= 0 && vi[3] < mesh_vertex_count && f.vi[0] != vi[3] && f.vi[1] != vi[3] && f.vi[2] != vi[3] && V[f.vi[0]] != V[vi[3]] && V[f.vi[1]] != V[vi[3]] )
283 {
284 if ( 2 == fvi_count || V[f.vi[2]] != V[vi[3]] )
285 f.vi[fvi_count++] = vi[3];
286 }
287
288 if ( fvi_count < 3 )
289 return false;
290
291 if ( 3 == fvi_count )
292 f.vi[3] = f.vi[2];
293
294 if ( !f.IsValid(mesh_vertex_count) )
295 return false;
296
297 vi[0] = f.vi[0];
298 vi[1] = f.vi[1];
299 vi[2] = f.vi[2];
300 vi[3] = f.vi[3];
301
302 return true;
303 }
304
305
Repair(int mesh_vertex_count,const ON_3dPoint * V)306 bool ON_MeshFace::Repair(
307 int mesh_vertex_count,
308 const ON_3dPoint* V
309 )
310 {
311 ON_MeshFace f;
312 int fvi_count = 0;
313 f.vi[0] = f.vi[1] = f.vi[2] = f.vi[3] = -1;
314
315 if ( vi[0] >= 0 && vi[0] < mesh_vertex_count )
316 f.vi[fvi_count++] = vi[0];
317
318 if ( vi[1] >= 0 && vi[1] < mesh_vertex_count && f.vi[0] != vi[1] )
319 {
320 if ( 0 == fvi_count || V[f.vi[0]] != V[vi[1]] )
321 f.vi[fvi_count++] = vi[1];
322 }
323
324 if ( fvi_count < 1 )
325 return false;
326
327 if ( vi[2] >= 0 && vi[2] < mesh_vertex_count && f.vi[0] != vi[2] && f.vi[1] != vi[2] && V[f.vi[0]] != V[vi[2]] )
328 {
329 if ( 1 == fvi_count || V[f.vi[1]] != V[vi[2]] )
330 f.vi[fvi_count++] = vi[2];
331 }
332
333 if ( fvi_count < 2 )
334 return false;
335
336 if ( vi[3] >= 0 && vi[3] < mesh_vertex_count && f.vi[0] != vi[3] && f.vi[1] != vi[3] && f.vi[2] != vi[3] && V[f.vi[0]] != V[vi[3]] && V[f.vi[1]] != V[vi[3]] )
337 {
338 if ( 2 == fvi_count || V[f.vi[2]] != V[vi[3]] )
339 f.vi[fvi_count++] = vi[3];
340 }
341
342 if ( fvi_count < 3 )
343 return false;
344
345 if ( 3 == fvi_count )
346 f.vi[3] = f.vi[2];
347
348 if ( !f.IsValid(mesh_vertex_count) )
349 return false;
350
351 vi[0] = f.vi[0];
352 vi[1] = f.vi[1];
353 vi[2] = f.vi[2];
354 vi[3] = f.vi[3];
355
356 return true;
357 }
358
ON_Mesh()359 ON_Mesh::ON_Mesh()
360 : m_packed_tex_rotate(0)
361 , m_parent(0)
362 , m_mesh_parameters(0)
363 , m_invalid_count(0)
364 , m_quad_count(0)
365 , m_triangle_count(0)
366 , m_mesh_is_closed(0)
367 , m_mesh_is_manifold(0)
368 , m_mesh_is_oriented(0)
369 , m_mesh_is_solid(0)
370 {
371 m_top.m_mesh = this;
372 m_srf_scale[0] = 0.0;
373 m_srf_scale[1] = 0.0;
374 m_kstat[0] = 0;
375 m_kstat[1] = 0;
376 m_kstat[2] = 0;
377 m_kstat[3] = 0;
378 InvalidateBoundingBoxes();
379 m_partition = 0;
380 m_hidden_count = 0;
381 }
382
383
ON_Mesh(int initial_facet_capacity,int initial_vertex_capacity,bool bHasVertexNormals,bool bHasTextureCoordinates)384 ON_Mesh::ON_Mesh(
385 int initial_facet_capacity, // initial facet array capacity
386 int initial_vertex_capacity, // initial vertex array capacity
387 bool bHasVertexNormals, // true if mesh has unit vertex normals
388 bool bHasTextureCoordinates // true if mesh has texture coordinates
389 )
390 : m_V(initial_vertex_capacity)
391 , m_F(initial_facet_capacity)
392 , m_N(bHasVertexNormals?initial_vertex_capacity:0)
393 , m_T(bHasTextureCoordinates?initial_vertex_capacity:0)
394 , m_packed_tex_rotate(0)
395 , m_parent(0)
396 , m_mesh_parameters(0)
397 , m_invalid_count(0)
398 , m_quad_count(0)
399 , m_triangle_count(0)
400 , m_mesh_is_closed(0)
401 , m_mesh_is_manifold(0)
402 , m_mesh_is_oriented(0)
403 , m_mesh_is_solid(0)
404 {
405 m_top.m_mesh = this;
406 m_srf_scale[0] = 0.0;
407 m_srf_scale[1] = 0.0;
408 m_kstat[0] = 0;
409 m_kstat[1] = 0;
410 m_kstat[2] = 0;
411 m_kstat[3] = 0;
412 InvalidateBoundingBoxes();
413 m_partition = 0;
414 m_hidden_count = 0;
415 }
416
ON_Mesh(const ON_Mesh & src)417 ON_Mesh::ON_Mesh( const ON_Mesh& src )
418 : ON_Geometry(src)
419 , m_packed_tex_rotate(0)
420 , m_parent(0)
421 , m_mesh_parameters(0)
422 , m_invalid_count(0)
423 , m_quad_count(0)
424 , m_triangle_count(0)
425 , m_mesh_is_closed(0)
426 , m_mesh_is_manifold(0)
427 , m_mesh_is_oriented(0)
428 , m_mesh_is_solid(0)
429 {
430 // Do not copy m_mesh_cache. Cached information will
431 // be recalculated if it is needed.
432 m_top.m_mesh = this;
433 m_srf_scale[0] = 0.0;
434 m_srf_scale[1] = 0.0;
435
436 m_kstat[0] = 0;
437 m_kstat[1] = 0;
438 m_kstat[2] = 0;
439 m_kstat[3] = 0;
440 InvalidateBoundingBoxes();
441 m_partition = 0;
442 m_hidden_count = 0;
443 ON_Mesh::operator=(src);
444 }
445
446
SizeOf() const447 unsigned int ON_Mesh::SizeOf() const
448 {
449 unsigned int sz = ON_Geometry::SizeOf();
450 sz += m_V.SizeOfArray();
451 sz += m_F.SizeOfArray();
452 sz += m_N.SizeOfArray();
453 sz += m_FN.SizeOfArray();
454 sz += m_T.SizeOfArray();
455 sz += m_S.SizeOfArray();
456 sz += m_K.SizeOfArray();
457 sz += m_C.SizeOfArray();
458 sz += m_top.m_topv_map.SizeOfArray();
459 sz += m_top.m_topv.SizeOfArray();
460 sz += m_top.m_tope.SizeOfArray();
461 sz += m_top.m_topf.SizeOfArray();
462 return sz;
463 }
464
DataCRC(ON__UINT32 current_remainder) const465 ON__UINT32 ON_Mesh::DataCRC(ON__UINT32 current_remainder) const
466 {
467 const ON_3fPoint* p = m_V.Array();
468 current_remainder = ON_CRC32(current_remainder,m_V.Count()*sizeof(p[0]),p);
469 current_remainder = ON_CRC32(current_remainder,m_F.Count()*sizeof(ON_MeshFace),m_F.Array());
470 const ON_3fVector* v = m_N.Array();
471 current_remainder = ON_CRC32(current_remainder,m_N.Count()*sizeof(v[0]),v);
472 return current_remainder;
473 }
474
operator =(const ON_Mesh & src)475 ON_Mesh& ON_Mesh::operator=( const ON_Mesh& src )
476 {
477 if ( this != &src )
478 {
479 Destroy();
480 ON_Geometry::operator=(src);
481
482 m_V = src.m_V;
483 m_F = src.m_F;
484 m_N = src.m_N;
485 m_FN = src.m_FN;
486 m_T = src.m_T;
487 m_TC = src.m_TC;
488 m_S = src.m_S;
489 m_H = src.m_H;
490 m_hidden_count = src.m_hidden_count;
491
492 m_Ctag = src.m_Ctag;
493 m_Ttag = src.m_Ttag;
494 m_packed_tex_domain[0] = src.m_packed_tex_domain[0];
495 m_packed_tex_domain[1] = src.m_packed_tex_domain[1];
496 m_srf_domain[0] = src.m_srf_domain[0];
497 m_srf_domain[1] = src.m_srf_domain[1];
498 m_srf_scale[0] = src.m_srf_scale[0];
499 m_srf_scale[1] = src.m_srf_scale[1];
500 m_packed_tex_rotate = src.m_packed_tex_rotate;
501
502 m_K = src.m_K;
503 m_C = src.m_C;
504
505 m_parent = src.m_parent;
506 //m_material_index = src.m_material_index;
507
508 if ( m_mesh_parameters ) {
509 delete m_mesh_parameters;
510 m_mesh_parameters = 0;
511 }
512 if ( src.m_mesh_parameters )
513 m_mesh_parameters = new ON_MeshParameters(*src.m_mesh_parameters);
514
515 m_invalid_count = src.m_invalid_count;
516 m_quad_count = src.m_quad_count;
517 m_triangle_count = src.m_triangle_count;
518
519 m_mesh_is_closed = src.m_mesh_is_closed;
520 m_mesh_is_manifold = src.m_mesh_is_manifold;
521 m_mesh_is_oriented = src.m_mesh_is_oriented;
522 m_mesh_is_solid = src.m_mesh_is_solid;
523
524 memcpy(m_vbox,src.m_vbox,sizeof(m_vbox));
525 memcpy(m_nbox,src.m_nbox,sizeof(m_nbox));
526 memcpy(m_tbox,src.m_tbox,sizeof(m_tbox));
527
528 int i;
529 for ( i = 0; i < 4; i++ ) {
530 if ( m_kstat[i] )
531 {
532 delete m_kstat[i];
533 m_kstat[i] = 0;
534 }
535 if ( src.m_kstat[i] )
536 {
537 m_kstat[i] = new ON_MeshCurvatureStats(*src.m_kstat[i]);
538 }
539 }
540
541 // do not copy m_top
542
543 // Do not copy m_mesh_cache. Cached information will
544 // be recalculated if it is needed.
545 }
546 return *this;
547 }
548
~ON_Mesh()549 ON_Mesh::~ON_Mesh()
550 {
551 Destroy();
552 m_top.m_mesh = 0;
553 }
554
MemoryRelocate()555 void ON_Mesh::MemoryRelocate()
556 {
557 // the back pointer on m_top needs to be updated.
558 m_top.m_mesh = this;
559 }
560
Destroy()561 void ON_Mesh::Destroy()
562 {
563 PurgeUserData();
564 DestroyRuntimeCache( true );
565 m_Ttag.Default();
566 m_Ctag.Default();
567 m_V.Destroy();
568 m_F.Destroy();
569 m_N.Destroy();
570 m_FN.Destroy();
571 m_T.Destroy();
572 m_TC.Destroy();
573 m_S.Destroy();
574 m_K.Destroy();
575 m_C.Destroy();
576 }
577
EmergencyDestroy()578 void ON_Mesh::EmergencyDestroy()
579 {
580 DestroyRuntimeCache( false );
581 m_V.EmergencyDestroy();
582 m_F.EmergencyDestroy();
583 m_N.EmergencyDestroy();
584 m_FN.EmergencyDestroy();
585 m_T.EmergencyDestroy();
586 m_TC.EmergencyDestroy();
587 m_S.EmergencyDestroy();
588 m_K.EmergencyDestroy();
589 m_C.EmergencyDestroy();
590 }
591
ON_MeshIsNotValid(bool bSilentError)592 static bool ON_MeshIsNotValid(bool bSilentError)
593 {
594 return bSilentError ? false : ON_IsNotValid(); // good place for a breakpoint;
595 }
596
IsValid(ON_TextLog * text_logx) const597 ON_BOOL32 ON_Mesh::IsValid( ON_TextLog* text_logx ) const
598 {
599 // If low bit of text_log pointer is 1, then ON_Error is not called when the
600 // knot vector is invalid.
601 const ON__INT_PTR lowbit = 1;
602 const ON__INT_PTR hightbits = ~lowbit;
603 bool bSilentError = ( 0 != (lowbit & ((ON__INT_PTR)text_logx)) );
604 ON_TextLog* text_log = (ON_TextLog*)(((ON__INT_PTR)text_logx) & hightbits);
605
606 const int facet_count = FaceCount();
607 const int vertex_count = VertexCount();
608 int fi, vi;
609
610 if (facet_count < 1)
611 {
612 if ( text_log )
613 {
614 text_log->Print("ON_Mesh.m_F.Count() < 1 (should be at least 1).\n");
615 }
616 return ON_MeshIsNotValid(bSilentError);
617 }
618
619 if ( vertex_count < 3 )
620 {
621 if ( text_log )
622 {
623 text_log->Print("ON_Mesh.m_V.Count() < 3 (should be at least 3).\n");
624 }
625 return ON_MeshIsNotValid(bSilentError);
626 }
627
628 if ( m_N.Count() > 0 && m_N.Count() != vertex_count )
629 {
630 if ( text_log )
631 {
632 text_log->Print("ON_Mesh.m_N.Count() = %d (should be 0 or %d=vertex_count).\n",
633 m_N.Count(),vertex_count);
634 }
635 return ON_MeshIsNotValid(bSilentError);
636 }
637
638 if ( m_T.Count() > 0 && m_T.Count() != vertex_count )
639 {
640 if ( text_log )
641 {
642 text_log->Print("ON_Mesh.m_T.Count() = %d (should be 0 or %d=vertex_count).\n",
643 m_T.Count(),vertex_count);
644 }
645 return ON_MeshIsNotValid(bSilentError);
646 }
647
648 if ( m_S.Count() > 0 && m_S.Count() != vertex_count )
649 {
650 if ( text_log )
651 {
652 text_log->Print("ON_Mesh.m_S.Count() = %d (should be 0 or %d=vertex_count).\n",
653 m_S.Count(),vertex_count);
654 }
655 return ON_MeshIsNotValid(bSilentError);
656 }
657
658 if ( HasVertexNormals() )
659 {
660 float x;
661 for ( vi = 0; vi < vertex_count; vi++ ) {
662 x = m_N[vi][0]*m_N[vi][0] + m_N[vi][1]*m_N[vi][1] + m_N[vi][2]*m_N[vi][2];
663 if ( x < 0.985 || x > 1.015 )
664 {
665 if ( text_log )
666 {
667 text_log->Print("ON_Mesh.m_N[%d] is not a unit vector (length = %g).\n",vi,sqrt(x));
668 }
669 return ON_MeshIsNotValid(bSilentError);
670 }
671 }
672 }
673
674 // Greg Arden 9 May 2003. Fixes TRR#10604. Attempt to detect meshes with non-finite vertices
675 // by testing the bounding box.
676 int i;
677 for ( i = 0; i < 3; i++ )
678 {
679 if ( !ON_IsValid( m_vbox[0][i] ) || !ON_IsValid( m_vbox[1][i] ) )
680 {
681 if ( text_log )
682 {
683 text_log->Print("ON_Mesh.m_vbox is not finite. Check for invalid vertices\n");
684 }
685 return ON_MeshIsNotValid(bSilentError);
686 }
687 }
688
689 const ON_3dPoint* dV = 0;
690 while ( HasDoublePrecisionVertices() )
691 {
692 bool bValidDoubles = DoublePrecisionVerticesAreValid();
693 if ( bValidDoubles )
694 dV = DoublePrecisionVertices().Array();
695 bool bValidFloats = SinglePrecisionVerticesAreValid();
696 bool bSynchronized = HasSynchronizedDoubleAndSinglePrecisionVertices();
697 if ( bSynchronized && bValidDoubles && bValidFloats )
698 break;
699
700 if ( !bSynchronized )
701 {
702 if ( text_log )
703 {
704 text_log->Print("Single and double precision vertices are not synchronized.\n");
705 }
706 return ON_MeshIsNotValid(bSilentError);
707 }
708
709 if ( !bValidDoubles )
710 {
711 if ( text_log )
712 {
713 text_log->Print("Double precision vertices appear to be ok but are not marked as valid\n");
714 }
715 return ON_MeshIsNotValid(bSilentError);
716 }
717
718 if ( !bValidFloats )
719 {
720 if ( text_log )
721 {
722 text_log->Print("Single precision vertices appear to be ok but are not marked as valid\n");
723 }
724 return ON_MeshIsNotValid(bSilentError);
725 }
726
727
728 break;
729 }
730
731 if ( 0 != dV )
732 {
733 for ( fi = 0; fi < facet_count; fi++ )
734 {
735 if ( !m_F[fi].IsValid( vertex_count, dV ) )
736 {
737 if ( text_log )
738 {
739 if ( !m_F[fi].IsValid( vertex_count) )
740 text_log->Print("ON_Mesh.m_F[%d].vi[] has invalid vertex indices.\n",fi);
741 else
742 text_log->Print("ON_Mesh.m_F[%d] has degenerate double precision vertex locations.\n",fi);
743 }
744 return ON_MeshIsNotValid(bSilentError);
745 }
746 }
747 }
748 else
749 {
750 //const ON_3fPoint* fV = m_V.Array();
751 for ( fi = 0; fi < facet_count; fi++ )
752 {
753 // This test was too harsh for float precision meshes
754 // with nearly degnerate faces after they are transformed
755 // by a transform with a reasonable sized translation
756 // component.
757 // See bug http://dev.mcneel.com/bugtrack/?q=87465
758
759 //if ( !m_F[fi].IsValid( vertex_count, fV ) )
760 //{
761 // if ( text_log )
762 // {
763 // if ( !m_F[fi].IsValid( vertex_count) )
764 // text_log->Print("ON_Mesh.m_F[%d].vi[] has invalid vertex indices.\n",fi);
765 // else
766 // text_log->Print("ON_Mesh.m_F[%d] has degenerate float precision vertex locations.\n",fi);
767 // }
768 // return ON_MeshIsNotValid(bSilentError);
769 //}
770
771 if ( !m_F[fi].IsValid( vertex_count ) )
772 {
773 if ( text_log )
774 text_log->Print("ON_Mesh.m_F[%d].vi[] has invalid vertex indices.\n",fi);
775 return ON_MeshIsNotValid(bSilentError);
776 }
777 }
778 }
779
780
781 return true;
782 }
783
Dump(ON_TextLog & dump) const784 void ON_Mesh::Dump( ON_TextLog& dump ) const
785 {
786 const int half_max = 8;
787
788 const int fcount = m_F.Count();
789 int i;
790 const int vcount = m_V.Count();
791 ON_3dPoint p, q;
792
793 bool bDoubles = vcount > 0
794 && HasDoublePrecisionVertices()
795 && HasSynchronizedDoubleAndSinglePrecisionVertices();
796
797 dump.Print("ON_Mesh: vertex count = %d facet count = %d\n", m_V.Count(), m_F.Count() );
798 dump.Print("double precision: %s\n",bDoubles?"true":"false");
799 dump.Print("vertex normals: %s\n",HasVertexNormals()?"true":"false");
800 dump.Print("face normals: %s\n",HasFaceNormals()?"true":"false");
801 dump.Print("srf parameters: %s\n",HasSurfaceParameters()?"true":"false");
802 dump.Print("tex coords: %s\n",HasTextureCoordinates()?"true":"false");
803 dump.Print("vertex kappa: %s\n",HasPrincipalCurvatures()?"true":"false");
804 dump.Print("vertex colors: %s\n",HasVertexColors()?"true":"false");
805 dump.Print("m_Ctag:\n"); dump.PushIndent(); m_Ctag.Dump(dump); dump.PopIndent();
806 dump.Print("m_packed_tex_rotate: %s\n",m_packed_tex_rotate?"true":"false");
807 dump.Print("m_packed_tex_domain: (%g,%g)x(%g,%g)\n",
808 m_packed_tex_domain[0][0],m_packed_tex_domain[0][1],
809 m_packed_tex_domain[1][0],m_packed_tex_domain[1][1]);
810 dump.Print("m_srf_domain: (%g,%g)x(%g,%g)\n",m_srf_domain[0][0],m_srf_domain[0][1],m_srf_domain[1][0],m_srf_domain[1][1]);
811 dump.Print("m_srf_scale: %g,%g\n",m_srf_scale[0],m_srf_scale[0]);
812 dump.Print("m_Ttag:\n"); dump.PushIndent(); m_Ttag.Dump(dump); dump.PopIndent();
813
814 dump.PushIndent();
815
816 dump.Print("%d mesh vertices:\n",m_V.Count());
817 {
818 dump.PushIndent();
819 const ON_3dPoint* D = 0;
820 if ( bDoubles )
821 {
822 D = DoublePrecisionVertices().Array();
823 }
824 for (i = 0; i < vcount; i++)
825 {
826 if ( i == half_max && 2*half_max < vcount )
827 {
828 dump.Print("...\n");
829 i = vcount-half_max;
830 }
831 else
832 {
833 p = m_V[i];
834 if ( 0 != D )
835 {
836 q = D[i];
837 dump.Print("m_V[%d] = (%.17g,%.17g,%.17g) D = (%.17g,%.17g,%.17g)\n",
838 i,
839 p.x,p.y,p.z,
840 q.x,q.y,q.z
841 );
842 }
843 else
844 {
845 dump.Print("m_V[%d] = (%g,%g,%g)\n",i,p.x,p.y,p.z);
846 }
847 }
848 }
849 dump.PopIndent();
850 }
851
852 if ( HasVertexNormals() )
853 {
854 dump.Print("%d mesh vertex normals:\n",m_N.Count());
855 {
856 dump.PushIndent();
857 for (i = 0; i < vcount; i++)
858 {
859 if ( i == half_max && 2*half_max < vcount )
860 {
861 dump.Print("...\n");
862 i = vcount-half_max;
863 }
864 else
865 {
866 p = m_N[i];
867 dump.Print("m_N[%d] = (%g,%g,%g)\n",i,p.x,p.y,p.z);
868 }
869 }
870 dump.PopIndent();
871 }
872 }
873
874 if ( HasTextureCoordinates() )
875 {
876 dump.Print("%d mesh vertex texture coordinates:\n",m_T.Count());
877 {
878 dump.PushIndent();
879 for (i = 0; i < vcount; i++)
880 {
881 if ( i == half_max && 2*half_max < vcount )
882 {
883 dump.Print("...\n");
884 i = vcount-half_max;
885 }
886 else
887 {
888 ON_2fPoint tp = m_T[i];
889 p.x = tp.x;
890 p.y = tp.y;
891 dump.Print("m_T[%d] = (%g,%g)\n",i,p.x,p.y);
892 }
893 }
894 dump.PopIndent();
895 }
896 }
897
898
899 if ( HasSurfaceParameters() )
900 {
901 dump.Print("%d mesh vertex surface parameters:\n",m_S.Count());
902 {
903 dump.PushIndent();
904 for (i = 0; i < vcount; i++)
905 {
906 if ( i == half_max && 2*half_max < vcount )
907 {
908 dump.Print("...\n");
909 i = vcount-half_max;
910 }
911 else
912 {
913 ON_2dPoint srfuv = m_S[i];
914 dump.Print("m_S[%d] = (%g,%g)\n",i,srfuv.x,srfuv.y);
915 }
916 }
917 dump.PopIndent();
918 }
919 }
920
921 dump.Print("%d mesh faces:\n",m_F.Count());
922 {
923 dump.PushIndent();
924 for (i = 0; i < fcount; i++)
925 {
926 if ( i == half_max && 2*half_max < fcount )
927 {
928 dump.Print("...\n");
929 i = fcount-half_max;
930 }
931 else if ( m_F[i].vi[2] == m_F[i].vi[3] )
932 dump.Print("m_F[%d].vi = (%d,%d,%d)\n",i,m_F[i].vi[0],m_F[i].vi[1],m_F[i].vi[2]);
933 else
934 dump.Print("m_F[%d].vi = (%d,%d,%d,%d)\n",i,m_F[i].vi[0],m_F[i].vi[1],m_F[i].vi[2],m_F[i].vi[3]);
935 }
936 dump.PopIndent();
937 }
938
939 if ( HasFaceNormals() )
940 {
941 dump.Print("%d mesh face normals:\n",m_FN.Count());
942 {
943 dump.PushIndent();
944 for (i = 0; i < fcount; i++)
945 {
946 if ( i == half_max && 2*half_max < fcount )
947 {
948 dump.Print("...\n");
949 i = fcount-half_max;
950 }
951 else
952 {
953 p = m_FN[i];
954 dump.Print("m_FN[%d] = (%g,%g,%g)\n",i,p.x,p.y,p.z);
955 }
956 }
957 dump.PopIndent();
958 }
959 }
960
961
962 dump.PopIndent();
963 }
964
965
WriteFaceArray(int vcount,int fcount,ON_BinaryArchive & file) const966 bool ON_Mesh::WriteFaceArray( int vcount, int fcount, ON_BinaryArchive& file ) const
967 {
968 unsigned char cvi[4];
969 unsigned short svi[4];
970 const int* vi;
971 int i_size = 0;
972 if ( vcount < 256 ) {
973 i_size = 1; // unsigned chars
974 }
975 else if (vcount < 65536 ) {
976 i_size = 2; // unsigned shorts
977 }
978 else {
979 i_size = 4; // 4 byte ints
980 }
981
982 bool rc = file.WriteInt( i_size );
983 int i;
984 switch(i_size) {
985 case 1:
986 for ( i = 0; i < fcount && rc ; i++ ) {
987 vi = m_F[i].vi;
988 cvi[0] = (unsigned char)vi[0];
989 cvi[1] = (unsigned char)vi[1];
990 cvi[2] = (unsigned char)vi[2];
991 cvi[3] = (unsigned char)vi[3];
992 rc = file.WriteChar( 4, cvi );
993 }
994 break;
995 case 2:
996 for ( i = 0; i < fcount && rc ; i++ ) {
997 vi = m_F[i].vi;
998 svi[0] = (unsigned short)vi[0];
999 svi[1] = (unsigned short)vi[1];
1000 svi[2] = (unsigned short)vi[2];
1001 svi[3] = (unsigned short)vi[3];
1002 rc = file.WriteShort( 4, svi );
1003 }
1004 break;
1005 case 4:
1006 for ( i = 0; i < fcount && rc ; i++ ) {
1007 rc = file.WriteInt( 4, m_F[i].vi );
1008 }
1009 break;
1010 }
1011
1012 return rc;
1013 }
1014
ReadFaceArray(int,int fcount,ON_BinaryArchive & file)1015 bool ON_Mesh::ReadFaceArray( int, int fcount, ON_BinaryArchive& file )
1016 {
1017 unsigned char cvi[4];
1018 unsigned short svi[4];
1019 unsigned int* vi;
1020 int i_size = 0;
1021
1022 if ( m_F.Capacity() < fcount )
1023 m_F.SetCapacity(fcount);
1024 bool rc = file.ReadInt( &i_size );
1025 int i = 0;
1026 switch(i_size) {
1027 case 1:
1028 for ( i = 0; i < fcount && rc ; i++ ) {
1029 rc = file.ReadChar( 4, cvi );
1030 vi = (unsigned int*)m_F[i].vi;
1031 vi[0] = cvi[0];
1032 vi[1] = cvi[1];
1033 vi[2] = cvi[2];
1034 vi[3] = cvi[3];
1035 }
1036 break;
1037 case 2:
1038 for ( i = 0; i < fcount && rc ; i++ ) {
1039 rc = file.ReadShort( 4, svi );
1040 vi = (unsigned int*)m_F[i].vi;
1041 vi[0] = svi[0];
1042 vi[1] = svi[1];
1043 vi[2] = svi[2];
1044 vi[3] = svi[3];
1045 }
1046 break;
1047 case 4:
1048 for ( i = 0; i < fcount && rc ; i++ ) {
1049 rc = file.ReadInt( 4, m_F[i].vi );
1050 }
1051 break;
1052 }
1053 m_F.SetCount(i);
1054
1055 return rc;
1056 }
1057
1058
Write_1(ON_BinaryArchive & file) const1059 bool ON_Mesh::Write_1( ON_BinaryArchive& file ) const
1060 {
1061 // ver 1.0 uncompressed format
1062
1063 bool rc = file.WriteArray( m_V );
1064 if (rc) rc = file.WriteArray( m_N );
1065 if (rc) rc = file.WriteArray( m_T );
1066 if (rc) rc = file.WriteArray( m_K );
1067 if (rc) rc = file.WriteArray( m_C );
1068
1069 return rc;
1070 }
1071
Read_1(ON_BinaryArchive & file)1072 bool ON_Mesh::Read_1( ON_BinaryArchive& file )
1073 {
1074 // common to all 1.x formats (uncompressed)
1075
1076 bool rc = file.ReadArray( m_V );
1077 if (rc) rc = file.ReadArray( m_N );
1078 if (rc) rc = file.ReadArray( m_T );
1079 if (rc) rc = file.ReadArray( m_K );
1080 if (rc) rc = file.ReadArray( m_C );
1081
1082 return rc;
1083 }
1084
Write_2(int Vcount,ON_BinaryArchive & file) const1085 bool ON_Mesh::Write_2( int Vcount, ON_BinaryArchive& file ) const
1086 {
1087 // ver 2.0 compressed format
1088 const ON::endian e = file.Endian();
1089
1090 bool rc = true;
1091
1092 if ( Vcount > m_V.Count() )
1093 return false;
1094
1095 if ( Vcount > 0 )
1096 {
1097 const int Ncount = (m_V.Count() == m_N.Count()) ? Vcount : 0;
1098 const int Tcount = (m_V.Count() == m_T.Count()) ? Vcount : 0;
1099 const int Kcount = (m_V.Count() == m_K.Count()) ? Vcount : 0;
1100 const int Ccount = (m_V.Count() == m_C.Count()) ? Vcount : 0;
1101
1102 if ( e == ON::big_endian )
1103 {
1104 // These calls temporarily put the m_V[], m_N[], m_T[], m_K[]
1105 // and m_C[] arrays in little endian byte order because 3dm archives
1106 // are always in little endian byte order.
1107 //
1108 // This code assumes sizeof(ON_Color)=4, sizeof(float)=4
1109 // and sizeof(double)=8.
1110 // If this is not the case, then changing the 4's and 8's below
1111 // will not work. You will have to copy the mesh definition
1112 // into temporary arrays of 4 byte floats/8 byte doubles
1113 // and them compress the temporary arrays. If you do this,
1114 // then remove the "restore" byte order calls below.
1115 file.ToggleByteOrder( Vcount*3, 4, m_V.Array(), (void*)m_V.Array() );
1116 file.ToggleByteOrder( Ncount*3, 4, m_N.Array(), (void*)m_N.Array() );
1117 file.ToggleByteOrder( Tcount*2, 4, m_T.Array(), (void*)m_T.Array() );
1118 file.ToggleByteOrder( Kcount*2, 8, m_K.Array(), (void*)m_K.Array() );
1119 file.ToggleByteOrder( Ccount, 4, m_C.Array(), (void*)m_C.Array() );
1120 }
1121 if (rc) rc = file.WriteCompressedBuffer( Vcount*sizeof(ON_3fPoint), m_V.Array() );
1122 if (rc) rc = file.WriteCompressedBuffer( Ncount*sizeof(ON_3fVector), m_N.Array() );
1123 if (rc) rc = file.WriteCompressedBuffer( Tcount*sizeof(ON_2fPoint), m_T.Array() );
1124 if (rc) rc = file.WriteCompressedBuffer( Kcount*sizeof(ON_SurfaceCurvature),m_K.Array() );
1125 if (rc) rc = file.WriteCompressedBuffer( Ccount*sizeof(ON_Color), m_C.Array() );
1126 if ( e == ON::big_endian )
1127 {
1128 // These calls restore the m_V[], m_N[], m_T[], m_K[] and m_C[] arrays
1129 // to the correct big endian runtime byte order. This must be done even
1130 // if rc is false.
1131 file.ToggleByteOrder( Vcount*3, 4, m_V.Array(), (void*)m_V.Array() );
1132 file.ToggleByteOrder( Ncount*3, 4, m_N.Array(), (void*)m_N.Array() );
1133 file.ToggleByteOrder( Tcount*2, 4, m_T.Array(), (void*)m_T.Array() );
1134 file.ToggleByteOrder( Kcount*2, 8, m_K.Array(), (void*)m_K.Array() );
1135 file.ToggleByteOrder( Ccount, 4, m_C.Array(), (void*)m_C.Array() );
1136 }
1137 }
1138
1139 return rc;
1140 }
1141
Read_2(int vcount,ON_BinaryArchive & file)1142 bool ON_Mesh::Read_2( int vcount, ON_BinaryArchive& file )
1143 {
1144 // common to all 2.x formats (compressed)
1145 const ON::endian e = file.Endian();
1146
1147 bool rc = true;
1148
1149
1150 if ( vcount > 0 )
1151 {
1152 std::size_t sz = 0;
1153 int bFailedCRC;
1154
1155 sz = 0;
1156 if (rc) rc = file.ReadCompressedBufferSize( &sz );
1157 if (rc && sz)
1158 {
1159 if ( sz == vcount*sizeof(m_V[0]) )
1160 {
1161 m_V.SetCapacity(vcount);
1162 if (rc) rc = file.ReadCompressedBuffer( sz,m_V.Array(),&bFailedCRC);
1163 if (rc) m_V.SetCount(vcount);
1164 }
1165 else
1166 {
1167 ON_ERROR("ON_Mesh::Read - compressed vertex point buffer size is wrong.");
1168 rc = false; // buffer is wrong size
1169 }
1170 }
1171
1172 sz = 0;
1173 if (rc) rc = file.ReadCompressedBufferSize( &sz );
1174 if (rc && sz)
1175 {
1176 if ( sz == vcount*sizeof(m_N[0]) )
1177 {
1178 m_N.SetCapacity(vcount);
1179 if (rc) rc = file.ReadCompressedBuffer( sz,m_N.Array(),&bFailedCRC );
1180 if (rc) m_N.SetCount(vcount);
1181 }
1182 else
1183 {
1184 ON_ERROR("ON_Mesh::Read - compressed vertex normal buffer size is wrong.");
1185 rc = false; // buffer is wrong size
1186 }
1187 }
1188
1189 sz = 0;
1190 if (rc) rc = file.ReadCompressedBufferSize( &sz );
1191 if (rc && sz)
1192 {
1193 if ( sz == vcount*sizeof(m_T[0]) )
1194 {
1195 m_T.SetCapacity(vcount);
1196 if (rc) rc = file.ReadCompressedBuffer( sz,m_T.Array(),&bFailedCRC );
1197 if (rc) m_T.SetCount(vcount);
1198 }
1199 else
1200 {
1201 ON_ERROR("ON_Mesh::Read - compressed texture coordinate buffer size is wrong.");
1202 rc = false; // buffer is wrong size
1203 }
1204 }
1205
1206 sz = 0;
1207 if (rc) rc = file.ReadCompressedBufferSize( &sz );
1208 if (rc && sz)
1209 {
1210 if ( sz == vcount*sizeof(m_K[0]) )
1211 {
1212 m_K.SetCapacity(vcount);
1213 if (rc) rc = file.ReadCompressedBuffer( sz,m_K.Array(),&bFailedCRC );
1214 if (rc) m_K.SetCount(vcount);
1215 }
1216 else
1217 {
1218 ON_ERROR("ON_Mesh::Read - compressed vertex curvature buffer size is wrong.");
1219 rc = false; // buffer is wrong size
1220 }
1221 }
1222
1223 sz = 0;
1224 if (rc) rc = file.ReadCompressedBufferSize( &sz );
1225 if (rc && sz)
1226 {
1227 if ( sz == vcount*sizeof(m_C[0]) )
1228 {
1229 m_C.SetCapacity(vcount);
1230 if (rc) rc = file.ReadCompressedBuffer( sz,m_C.Array(),&bFailedCRC );
1231 if (rc) m_C.SetCount(vcount);
1232 }
1233 else
1234 {
1235 ON_ERROR("ON_Mesh::Read - compressed vertex color buffer size is wrong.");
1236 rc = false; // buffer is wrong size
1237 }
1238 }
1239
1240 if ( e == ON::big_endian )
1241 {
1242 // This code assumes sizeof(ON_Color)=4, sizeof(float)=4
1243 // and sizeof(double)=8.
1244 // If this is not the case, then changing the 4's and 8's below
1245 // will not work. You will have to read the compressed
1246 // information into temporary arrays of 4 byte floats/8 byte doubles
1247 // and then convert those numbers to whatever is stored in the
1248 // m_V[], m_N[], m_T[], m_K[] and m_C[] arrays/
1249 file.ToggleByteOrder( m_V.Count()*3, 4, m_V.Array(), (void*)m_V.Array() );
1250 file.ToggleByteOrder( m_N.Count()*3, 4, m_N.Array(), (void*)m_N.Array() );
1251 file.ToggleByteOrder( m_T.Count()*2, 4, m_T.Array(), (void*)m_T.Array() );
1252 file.ToggleByteOrder( m_K.Count()*2, 8, m_K.Array(), (void*)m_K.Array() );
1253 file.ToggleByteOrder( m_C.Count()*3, 4, m_C.Array(), (void*)m_C.Array() );
1254 }
1255 }
1256
1257 return rc;
1258 }
1259
1260
Write(ON_BinaryArchive & file) const1261 ON_BOOL32 ON_Mesh::Write( ON_BinaryArchive& file ) const
1262 {
1263 int i;
1264 //const int major_version = 1; // uncompressed
1265 //const int major_version = 2; // beta format (never used)
1266 const int major_version = 3; // compressed
1267 bool rc = file.Write3dmChunkVersion(major_version,5);
1268
1269 const int vcount = VertexCount();
1270 const int fcount = FaceCount();
1271
1272 if (rc) rc = file.WriteInt( vcount );
1273 if (rc) rc = file.WriteInt( fcount );
1274 if (rc) rc = file.WriteInterval( m_packed_tex_domain[0] );
1275 if (rc) rc = file.WriteInterval( m_packed_tex_domain[1] );
1276 if (rc) rc = file.WriteInterval( m_srf_domain[0] );
1277 if (rc) rc = file.WriteInterval( m_srf_domain[1] );
1278 if (rc) rc = file.WriteDouble( 2, m_srf_scale );
1279 if (rc) rc = file.WriteFloat( 6, &m_vbox[0][0] );
1280 if (rc) rc = file.WriteFloat( 6, &m_nbox[0][0] );
1281 if (rc) rc = file.WriteFloat( 4, &m_tbox[0][0] );
1282
1283 // archive int value meaning: -1 = unknown 0 = mesh is not closed, 1 = mesh is closed
1284 i = -1;
1285 switch( m_mesh_is_closed )
1286 {
1287 case 0: // unset
1288 i = -1;
1289 break;
1290 case 1: // closed
1291 i = 1;
1292 break;
1293 case 2: // not closed
1294 i = 0;
1295 break;
1296 }
1297 if (rc) rc = file.WriteInt( i );
1298
1299 unsigned char b = m_mesh_parameters ? 1 : 0;
1300 if (rc) rc = file.WriteChar(b);
1301 if (rc && b) {
1302 if (rc) rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 0 );
1303 if (rc) {
1304 rc = m_mesh_parameters->Write(file);
1305 if ( !file.EndWrite3dmChunk() )
1306 rc = false;
1307 }
1308 }
1309
1310 for ( i = 0; rc && i < 4; i++ ) {
1311 b = m_kstat[i] ? 1 : 0;
1312 rc = file.WriteChar(b);
1313 if (b) {
1314 rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 0 );
1315 if (rc) {
1316 rc = m_kstat[i]->Write(file);
1317 if ( !file.EndWrite3dmChunk() )
1318 rc = false;
1319 }
1320 }
1321 }
1322
1323 if (rc) rc = WriteFaceArray( vcount, fcount, file );
1324
1325 if (rc) {
1326 // major version is a hard coded 3
1327
1328 //if ( major_version == 1 )
1329 // rc = Write_1(file);
1330 //else if ( major_version == 3 )
1331 rc = Write_2(vcount,file);
1332 //else
1333 // rc = false;
1334 }
1335
1336 // added for minor version 1.2 and 3.2
1337 i = m_packed_tex_rotate ? 1 : 0;
1338 if (rc) rc = file.WriteInt( i );
1339
1340 // added for minor version 3.3
1341 if (rc) rc = file.WriteUuid( m_Ttag.m_mapping_id );
1342
1343 // compressed m_S[]
1344 if ( rc && vcount > 0 )
1345 {
1346 // Before 201011049 there was a bug that let m_S[] arrays
1347 // with the wrong size get saved in files.
1348 const int Scount = (vcount == m_S.Count()) ? m_S.Count() : 0;
1349 const ON::endian e = file.Endian();
1350 if ( e == ON::big_endian )
1351 {
1352 file.ToggleByteOrder( Scount*2, 8, m_S.Array(), (void*)m_S.Array() );
1353 }
1354 if (rc) rc = file.WriteCompressedBuffer( Scount*sizeof(ON_2dPoint),m_S.Array() );
1355 if ( e == ON::big_endian )
1356 {
1357 file.ToggleByteOrder( Scount*2, 8, m_S.Array(), (void*)m_S.Array() );
1358 }
1359 }
1360
1361 // added for minor version 3.4
1362 if (rc) rc = m_Ttag.Write(file);
1363
1364 // added for minor version 3.5
1365 if (rc) rc = file.WriteChar( m_mesh_is_manifold );
1366 if (rc) rc = file.WriteChar( m_mesh_is_oriented );
1367 if (rc) rc = file.WriteChar( m_mesh_is_solid );
1368
1369
1370 return rc;
1371 }
1372
1373 //// This id was used in the ON_Mesh::m_mapping_id
1374 //// field to indicate the texture coordinates are the
1375 //// canonical ON_Mesh uv texture coordinates by the
1376 //// OpenNURBS parameteric surface meshers like
1377 //// ON_Surface::CreateMesh() and ON_Brep::CreateMesh().
1378 //
1379 //// {B988A6C2-61A6-45a7-AAEE-9AED7EF4E316}
1380 static const ON_UUID obsolete_default_srfp_mapping_id = { 0xb988a6c2, 0x61a6, 0x45a7, { 0xaa, 0xee, 0x9a, 0xed, 0x7e, 0xf4, 0xe3, 0x16 } };
1381
1382 // overrides virtual ON_Object::Write
Write(ON_BinaryArchive & file) const1383 ON_BOOL32 ON_TextureMapping::Write(
1384 ON_BinaryArchive& file
1385 ) const
1386 {
1387 bool rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,1);
1388 if (rc)
1389 {
1390
1391 for(;;)
1392 {
1393 rc = file.WriteUuid( m_mapping_id);
1394 if (!rc) break;
1395
1396 rc = file.WriteInt( m_type );
1397 if (!rc) break;
1398
1399 rc = file.WriteInt( m_projection );
1400 if (!rc) break;
1401
1402 rc = file.WriteXform( m_Pxyz );
1403 if (!rc) break;
1404
1405 // Do not write m_Nxyz - it is calculated from m_Pxyz.
1406 rc = file.WriteXform( m_uvw );
1407 if (!rc) break;
1408
1409 rc = file.WriteString(m_mapping_name);
1410 if (!rc) break;
1411
1412 rc = file.WriteObject(m_mapping_primitive);
1413 if (!rc) break;
1414
1415 // 13 October 2006 ver 1.1 fields
1416 rc = file.WriteInt(m_texture_space);
1417 if (!rc) break;
1418
1419 rc = file.WriteBool(m_bCapped);
1420 if (!rc) break;
1421
1422 break;
1423 }
1424
1425 if ( !file.EndWrite3dmChunk() )
1426 rc = false;
1427 }
1428
1429 return rc;
1430 }
1431
1432 // overrides virtual ON_Object::Read
Read(ON_BinaryArchive & file)1433 ON_BOOL32 ON_TextureMapping::Read(
1434 ON_BinaryArchive& file
1435 )
1436 {
1437 Default();
1438
1439 int major_version = 0;
1440 int minor_version = 0;
1441 int i;
1442
1443 bool rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
1444 if (rc)
1445 {
1446 if ( 1 == major_version )
1447 {
1448 // DO NOT SAVE m_mapping_index in archive.
1449 // 1.0 fields
1450 for(;;)
1451 {
1452 rc = file.ReadUuid( m_mapping_id );
1453 if (!rc) break;
1454 if ( 0 == ON_UuidCompare(&obsolete_default_srfp_mapping_id,&m_mapping_id) )
1455 m_mapping_id = ON_nil_uuid;
1456
1457 rc = file.ReadInt( &i );
1458 if (!rc) break;
1459 m_type = TypeFromInt(i);
1460
1461 rc = file.ReadInt( &i );
1462 if (!rc) break;
1463 m_projection = ProjectionFromInt(i);
1464
1465 rc = file.ReadXform( m_Pxyz );
1466 if (!rc) break;
1467
1468 m_Pxyz.GetSurfaceNormalXform(m_Nxyz);
1469
1470 rc = file.ReadXform( m_uvw );
1471 if (!rc) break;
1472
1473 rc = file.ReadString(m_mapping_name);
1474 if (!rc) break;
1475
1476 rc = (file.ReadObject(&m_mapping_primitive) >= 0);
1477 if (!rc) break;
1478
1479 if ( minor_version >= 1 )
1480 {
1481 rc = file.ReadInt(&i);
1482 if (!rc) break;
1483 m_texture_space = TextureSpaceFromInt(i);
1484
1485 rc = file.ReadBool(&m_bCapped);
1486 if (!rc) break;
1487 }
1488
1489 break;
1490 }
1491 }
1492
1493 if ( !file.EndRead3dmChunk() )
1494 rc = false;
1495 }
1496
1497 return rc;
1498 }
1499
1500 static
GetSurfaceParametersHelper(const ON_Mesh & mesh,double tex_x,double tex_y,double * srf_s,double * srf_t)1501 void GetSurfaceParametersHelper( const ON_Mesh& mesh,
1502 double tex_x, double tex_y,
1503 double* srf_s, double* srf_t )
1504 {
1505 // convert texture coordinates to surface parameters
1506 // Used to reconstruct m_S[] when old files are read.
1507 double tex_s, tex_t;
1508
1509 if ( mesh.m_packed_tex_rotate )
1510 {
1511 // undo rotation and normalize
1512 tex_s = mesh.m_packed_tex_domain[1].NormalizedParameterAt( tex_y );
1513 tex_t = 1.0 - mesh.m_packed_tex_domain[0].NormalizedParameterAt( tex_x );
1514 }
1515 else
1516 {
1517 // normalize
1518 tex_s = mesh.m_packed_tex_domain[0].NormalizedParameterAt( tex_x );
1519 tex_t = mesh.m_packed_tex_domain[1].NormalizedParameterAt( tex_y );
1520 }
1521 *srf_s = mesh.m_srf_domain[0].ParameterAt(tex_s);
1522 *srf_t = mesh.m_srf_domain[1].ParameterAt(tex_t);
1523 }
1524
1525
Read(ON_BinaryArchive & file)1526 ON_BOOL32 ON_Mesh::Read( ON_BinaryArchive& file )
1527 {
1528 Destroy();
1529
1530 int major_version = 0;
1531 int minor_version = 0;
1532 int i;
1533 bool rc = file.Read3dmChunkVersion(&major_version,&minor_version);
1534
1535 if (rc && (1 == major_version || 3 == major_version) )
1536 {
1537 int vcount = 0;
1538 int fcount = 0;
1539
1540 if (rc) rc = file.ReadInt( &vcount );
1541 if (rc) rc = file.ReadInt( &fcount );
1542 if (rc) rc = file.ReadInterval( m_packed_tex_domain[0] );
1543 if (rc) rc = file.ReadInterval( m_packed_tex_domain[1] );
1544 if (rc) rc = file.ReadInterval( m_srf_domain[0] );
1545 if (rc) rc = file.ReadInterval( m_srf_domain[1] );
1546 if (rc) rc = file.ReadDouble( 2, m_srf_scale );
1547 if (rc) rc = file.ReadFloat( 6, &m_vbox[0][0] );
1548 if (rc) rc = file.ReadFloat( 6, &m_nbox[0][0] );
1549 if (rc) rc = file.ReadFloat( 4, &m_tbox[0][0] );
1550
1551 // int value meaning: -1 = unknown 0 = mesh is not closed, 1 = mesh is closed
1552 i = -1;
1553 if (rc) rc = file.ReadInt( &i );
1554 if (rc)
1555 {
1556 switch(i)
1557 {
1558 case 0: // not closed;
1559 SetClosed(0);
1560 break;
1561 case 1: // closed;
1562 SetClosed(1);
1563 break;
1564 case 2: // 13 April 2010 Dale Lear - "2" value is obsolete but appears in old files
1565 SetClosed(1);
1566 break;
1567 }
1568 }
1569
1570 unsigned char b = 0;
1571 ON__UINT32 tcode=0;
1572 ON__INT64 big_value=0;
1573 if (rc) rc = file.ReadChar(&b);
1574 if (rc && b)
1575 {
1576 // mesh parameters are in an anonymous chunk
1577 rc = file.BeginRead3dmBigChunk(&tcode,&big_value);
1578 if (rc)
1579 {
1580 if ( TCODE_ANONYMOUS_CHUNK == tcode )
1581 {
1582 m_mesh_parameters = new ON_MeshParameters();
1583 rc = m_mesh_parameters->Read( file );
1584 }
1585 else
1586 rc = false;
1587 if (!file.EndRead3dmChunk())
1588 rc = false;
1589 }
1590 }
1591
1592 for ( i = 0; rc && i < 4; i++ )
1593 {
1594 rc = file.ReadChar(&b);
1595 if (rc && b)
1596 {
1597 // m_kstat[i] curvature stats are in an anonymous chunk
1598 tcode = 0;
1599 big_value = 0;
1600 rc = file.BeginRead3dmBigChunk( &tcode, &big_value );
1601 if (rc)
1602 {
1603 if ( TCODE_ANONYMOUS_CHUNK == tcode )
1604 {
1605 m_kstat[i] = new ON_MeshCurvatureStats();
1606 rc = m_kstat[i]->Read(file);
1607 }
1608 else
1609 rc = false;
1610 if ( !file.EndRead3dmChunk() )
1611 rc = false;
1612 }
1613 }
1614 }
1615
1616 if (rc) rc = ReadFaceArray( vcount, fcount, file );
1617
1618 if (rc) {
1619 if ( major_version==1) {
1620 rc = Read_1(file);
1621 }
1622 else if ( major_version == 3 ) {
1623 rc = Read_2(vcount,file);
1624 }
1625 else
1626 rc = false;
1627 }
1628
1629 if ( minor_version >= 2 )
1630 {
1631 int b = m_packed_tex_rotate;
1632 if (rc) rc = file.ReadInt( &b );
1633 m_packed_tex_rotate = b?true:false;
1634 }
1635
1636 if ( 3 == major_version )
1637 {
1638 if ( minor_version >= 3 )
1639 {
1640 // added for minor version 3.3
1641 if (rc) rc = file.ReadUuid( m_Ttag.m_mapping_id );
1642
1643 // compressed m_S[]
1644 if ( rc && vcount > 0 )
1645 {
1646 std::size_t sz = 0;
1647 ON_BOOL32 bFailedCRC=false;
1648 if (rc) rc = file.ReadCompressedBufferSize( &sz );
1649 if (rc && sz)
1650 {
1651 if ( sz == vcount*sizeof(ON_2dPoint) )
1652 {
1653 m_S.SetCapacity(vcount);
1654 if (rc) rc = file.ReadCompressedBuffer( sz, m_S.Array(), &bFailedCRC );
1655 if (rc) m_S.SetCount(vcount);
1656 if ( ON::big_endian == file.Endian() )
1657 {
1658 file.ToggleByteOrder( m_S.Count()*2, 8, m_S.Array(), (void*)m_S.Array() );
1659 }
1660 }
1661 else
1662 {
1663 ON_ERROR("ON_Mesh::Read - surface parameter buffer size is wrong.");
1664 if ( rc
1665 && file.ArchiveOpenNURBSVersion() <= 201011049
1666 && 0 == (sz % sizeof(ON_2dPoint))
1667 && sz >= sizeof(ON_2dPoint)
1668 )
1669 {
1670 // Before 201011049 there was a bug that let m_S[] arrays with
1671 // the wrong size get saved in files. There was also a bug in
1672 // the Rhino .OBJ file reader that created meshes with m_S[]
1673 // arrays that had the wrong size. The next 4 lines of code
1674 // let us read the junk, discard it and then successfully read
1675 // the rest of the file.
1676 int Scount = (int)(sz / sizeof(ON_2dPoint));
1677 m_S.SetCapacity(Scount);
1678 rc = file.ReadCompressedBuffer( sz, m_S.Array(), &bFailedCRC );
1679 m_S.Destroy();
1680 }
1681 else
1682 {
1683 rc = false; // buffer is wrong size
1684 }
1685 }
1686 }
1687 }
1688 if ( minor_version >= 4 && file.ArchiveOpenNURBSVersion() >= 200606010 )
1689 {
1690 if (rc) rc = m_Ttag.Read(file);
1691 if ( minor_version >= 5 )
1692 {
1693 if (rc) rc = file.ReadChar( &m_mesh_is_manifold );
1694 if (rc) rc = file.ReadChar( &m_mesh_is_oriented );
1695 if (rc) rc = file.ReadChar( &m_mesh_is_solid );
1696 }
1697 }
1698 }
1699 }
1700
1701 if ( 0 == m_S.Count()
1702 && m_V.Count() > 0
1703 && HasTextureCoordinates()
1704 && m_srf_domain[0].IsIncreasing()
1705 && m_srf_domain[1].IsIncreasing()
1706 && m_packed_tex_domain[0].IsInterval()
1707 && m_packed_tex_domain[1].IsInterval()
1708 && 0 == m_Ttag.m_mapping_crc
1709 && ON_UuidIsNil(m_Ttag.m_mapping_id)
1710 )
1711 {
1712 // This is a mesh from an old file - but there is enough
1713 // information to calculate the m_S[] values from the
1714 // m_T[] values.
1715 m_S.SetCapacity(vcount);
1716 m_S.SetCount(0);
1717 ON_2dPoint sp;
1718 ON_2fPoint tc;
1719 for ( i = 0; i < vcount; i++)
1720 {
1721 tc = m_T[i];
1722 sp.x = tc.x;
1723 sp.y = tc.y;
1724 GetSurfaceParametersHelper(*this,sp.x,sp.y,&sp.x,&sp.y);
1725 m_S.Append(sp);
1726 }
1727 m_Ttag.SetDefaultSurfaceParameterMappingTag();
1728 }
1729 }
1730
1731 return rc;
1732 }
1733
ObjectType() const1734 ON::object_type ON_Mesh::ObjectType() const
1735 {
1736 return ON::mesh_object;
1737 }
1738
Dimension() const1739 int ON_Mesh::Dimension() const
1740 {
1741 return 3;
1742 }
1743
1744 #if defined(ON_COMPILER_MSC)
1745 // Disable the MSC /W4 warning
1746 // C4189: 'breakpoint_here_for_bad_vbox' : local variable is initialized but not referenced
1747 // on the line
1748 // int breakpoint_here_for_bad_vbox = 0.
1749 // The warning disable is here because MS is ignoring it
1750 // if I put it inside of the function.
1751 #pragma warning( push )
1752 #pragma warning( disable : 4189 )
1753 #endif
1754
ON_FloatFloor(double x)1755 float ON_FloatFloor(double x)
1756 {
1757 // If x is a NaN, you get what you deserve.
1758 //
1759 // If x is a finite valid double in the range -3.402823466e+38
1760 // to +3.402823466e+38, then returned value of f is the largest
1761 // float value that is mathematically less than or equal to the
1762 // value of x.
1763 //
1764 // If x is not in the float range or x is a NaN, then you get
1765 // what you deserve.
1766 //
1767 // ON_FLOAT_EPSILON = 1.192092896e-07 is the smallest number such that
1768 // 1.0f + 1.192092896e-07f > 1.0f.
1769 //
1770 // If x < 0, then (1.0 + 0.5*1.192092896e-07)*x rounds x down so
1771 // that converting the double precision mantissa cannot create a
1772 // float value that is mathematically larger than the value of x.
1773 //
1774 // If x > 0, then (1.0 - 0.5*1.192092896e-07)*x rounds x down so
1775 // that converting the double precision mantissa cannot create a
1776 // float value that is mathematically larger than the value of x.
1777 //
1778 const double e = (x < 0.0) ? (1.0 + 0.5*ON_FLOAT_EPSILON) : (1.0 - 0.5*ON_FLOAT_EPSILON);
1779 float f;
1780 f = (float)(e*x);
1781 return f;
1782 }
1783
ON_FloatCeil(double x)1784 float ON_FloatCeil(double x)
1785 {
1786 float f = (x != 0.0) ? (-ON_FloatFloor(-x)) : ((float)x);
1787 return f;
1788 }
1789
GetBBox(double * boxmin,double * boxmax,ON_BOOL32 bGrowBox) const1790 ON_BOOL32 ON_Mesh::GetBBox( // returns true if successful
1791 double* boxmin, // minimum
1792 double* boxmax, // maximum
1793 ON_BOOL32 bGrowBox
1794 ) const
1795 {
1796 ON_BOOL32 rc = false;
1797 const int facet_count = FaceCount();
1798 const int vertex_count = VertexCount();
1799 if ( facet_count >= 1 && vertex_count >= 3 )
1800 {
1801 ON_BoundingBox vbox;
1802 if ( m_vbox[0][0] > m_vbox[1][0] )
1803 {
1804 // const lie - cache mesh bounding box
1805 float* fbbox[2] = {const_cast<float*>(&m_vbox[0][0]),const_cast<float*>(&m_vbox[1][0])};
1806 while ( HasDoublePrecisionVertices() && DoublePrecisionVerticesAreValid() )
1807 {
1808 double dbbox[2][3];
1809 const ON_3dPointArray& dV = DoublePrecisionVertices();
1810 rc = ON_GetPointListBoundingBox(
1811 3, 0, vertex_count, 3, &dV[0].x,
1812 &dbbox[0][0], &dbbox[1][0],
1813 false
1814 );
1815 if (!rc)
1816 break;
1817 // make sure we round min doubles down to the nearest float
1818 // and max doubles up to the nearest float.
1819 fbbox[0][0] = ON_FloatFloor(dbbox[0][0]);
1820 fbbox[0][1] = ON_FloatFloor(dbbox[0][1]);
1821 fbbox[0][2] = ON_FloatFloor(dbbox[0][2]);
1822 fbbox[1][0] = ON_FloatCeil(dbbox[1][0]);
1823 fbbox[1][1] = ON_FloatCeil(dbbox[1][1]);
1824 fbbox[1][2] = ON_FloatCeil(dbbox[1][2]);
1825
1826 // depending on how
1827 if ( SinglePrecisionVerticesAreValid() )
1828 {
1829 ON_GetPointListBoundingBox(
1830 3, 0, vertex_count, 3, &m_V[0].x,
1831 &fbbox[0][0], &fbbox[1][0],
1832 true
1833 );
1834 }
1835 break;
1836 }
1837
1838 if (!rc)
1839 {
1840 rc = ON_GetPointListBoundingBox( 3, 0,
1841 vertex_count, 3, &m_V[0].x,
1842 fbbox[0],fbbox[1],
1843 false
1844 );
1845 }
1846 }
1847 else
1848 {
1849 rc = true;
1850 }
1851
1852 if ( rc )
1853 {
1854 vbox.m_min.x = m_vbox[0][0];
1855 vbox.m_min.y = m_vbox[0][1];
1856 vbox.m_min.z = m_vbox[0][2];
1857 vbox.m_max.x = m_vbox[1][0];
1858 vbox.m_max.y = m_vbox[1][1];
1859 vbox.m_max.z = m_vbox[1][2];
1860 rc = vbox.IsValid();
1861 if (rc)
1862 {
1863 if ( bGrowBox )
1864 {
1865 vbox.Union( ON_BoundingBox(boxmin,boxmax) );
1866 }
1867
1868 boxmin[0] = vbox.m_min.x;
1869 boxmin[1] = vbox.m_min.y;
1870 boxmin[2] = vbox.m_min.z;
1871
1872 boxmax[0] = vbox.m_max.x;
1873 boxmax[1] = vbox.m_max.y;
1874 boxmax[2] = vbox.m_max.z;
1875 }
1876 #if defined(ON_DEBUG) && !defined(ON_COMPILER_GNU)
1877 // generates gcc unused variable warning
1878 else
1879 {
1880 int breakpoint_here_for_bad_vbox=0;
1881 }
1882 #endif
1883 }
1884 }
1885 return rc;
1886 }
1887
1888 #if defined(ON_COMPILER_MSC)
1889 #pragma warning( pop )
1890 #endif
1891
IsDeformable() const1892 bool ON_Mesh::IsDeformable() const
1893 {
1894 return true;
1895 }
1896
MakeDeformable()1897 bool ON_Mesh::MakeDeformable()
1898 {
1899 return true;
1900 }
1901
Transform(const ON_Xform & xform)1902 ON_BOOL32 ON_Mesh::Transform(
1903 const ON_Xform& xform
1904 )
1905 {
1906 const bool bIsValid_fV = SinglePrecisionVerticesAreValid();
1907 const bool bIsValid_dV = DoublePrecisionVerticesAreValid();
1908 const bool bSyncheddV = bIsValid_fV && bIsValid_dV && HasSynchronizedDoubleAndSinglePrecisionVertices();
1909 TransformUserData(xform);
1910 DestroyTree();
1911
1912 double d = xform.Determinant();
1913 const int vertex_count = VertexCount();
1914 bool rc = false;
1915 if ( bSyncheddV )
1916 {
1917 // transforming the double precision vertices is the
1918 // best way to set the floats.
1919 UpdateSinglePrecisionVertices();
1920 rc = true;
1921 }
1922 else
1923 {
1924 rc = ON_TransformPointList( 3, false, vertex_count, 3, &m_V[0][0], xform );
1925 }
1926
1927 if ( rc )
1928 {
1929 m_Ctag.Transform(xform);
1930 m_Ttag.Transform(xform);
1931 int tci, tccnt = m_TC.Count();
1932 for ( tci = 0; tci < tccnt; tci++ )
1933 {
1934 m_TC[tci].m_tag.Transform(xform);
1935 }
1936 }
1937
1938 if ( rc && 0.0 == d )
1939 {
1940 // mesh has been squashed to a plane (or worse)
1941 if ( HasVertexNormals() )
1942 {
1943 ComputeFaceNormals();
1944 ComputeVertexNormals();
1945 }
1946 else if ( HasFaceNormals() )
1947 {
1948 ComputeFaceNormals();
1949 }
1950 }
1951 else if ( rc )
1952 {
1953 if ( HasVertexNormals() )
1954 {
1955 // See http://www.gignews.com/realtime020100.htm or these
1956 // references.
1957 //
1958 // 1. Hanrahan, Pat,
1959 // "A Survey of Ray-Surface Intersection Algorithms",
1960 // chapter 3 in Andrew Glassner (editor),
1961 // An Introduction to Ray Tracing,
1962 // Academic Press Inc., London, 1989.
1963 //
1964 // 2. Turkowski, Ken,
1965 // "Properties of Surface-Normal Transformations",
1966 // in Andrew Glassner (editor),
1967 // Graphics Gems, Academic Press, Inc.,
1968 // pp. 539-547, 1990.
1969 ON_Xform N_xform;
1970 double d = xform.GetSurfaceNormalXform(N_xform);
1971 rc = ON_TransformVectorList( 3, vertex_count, 3, &m_N[0][0], N_xform )?true:false;
1972 if ( d < 0.0 )
1973 {
1974 FlipVertexNormals();
1975 }
1976 UnitizeVertexNormals();
1977 }
1978
1979 if ( rc && HasFaceNormals() )
1980 {
1981 ComputeFaceNormals();
1982 }
1983 }
1984
1985 if ( rc && HasPrincipalCurvatures() )
1986 {
1987 if ( fabs(fabs(d) - 1.0) > ON_SQRT_EPSILON )
1988 {
1989 // If it's a uniform scale, handle it, otherwise we can't do it.
1990 double scale = xform.m_xform[0][0];
1991 if ( 0.0 != scale && 0.0 != d
1992 && scale == xform.m_xform[1][1]
1993 && scale == xform.m_xform[2][2]
1994 && fabs(d - scale*scale*scale) <= d*ON_SQRT_EPSILON )
1995 {
1996 // uniform scale
1997 const double ks = 1.0/scale;
1998 ON_SurfaceCurvature* sc = m_K.Array();
1999 int ki = m_K.Count();
2000 while ( ki-- )
2001 {
2002 sc->k1 *= ks;
2003 sc->k2 *= ks;
2004 sc++;
2005 }
2006
2007 // update curvature stats.
2008 for ( int j = 0; j < 4; j++ )
2009 {
2010 if ( m_kstat[j] )
2011 m_kstat[j]->Set( m_kstat[j]->m_style,m_K.Count(),m_K.Array(),m_N.Array() );
2012 }
2013 }
2014 else
2015 {
2016 ON_ERROR("ON_Mesh::Transform() cannot apply this transform to curvatures.\n");
2017 rc = false;
2018 }
2019 }
2020 }
2021
2022 InvalidateVertexBoundingBox();
2023 InvalidateVertexNormalBoundingBox();
2024 if ( fabs(d) <= ON_ZERO_TOLERANCE )
2025 DestroyTopology(); // transform may not be one-to-one on vertices
2026
2027 if ( bIsValid_fV )
2028 SetSinglePrecisionVerticesAsValid();
2029 if ( bIsValid_dV )
2030 SetDoublePrecisionVerticesAsValid();
2031
2032 return rc;
2033 }
2034
DestroyRuntimeCache(bool bDelete)2035 void ON_Mesh::DestroyRuntimeCache( bool bDelete )
2036 {
2037 int i;
2038
2039 DestroyTree(bDelete);
2040
2041 if (bDelete )
2042 {
2043 DestroyPartition();
2044 m_top.Destroy();
2045 DeleteMeshParameters();
2046 InvalidateCurvatureStats();
2047 }
2048 else
2049 {
2050 // do not free any memory
2051 m_top.EmergencyDestroy();
2052 }
2053
2054 InvalidateBoundingBoxes();
2055 m_partition = 0;
2056 m_mesh_parameters = 0;
2057 m_top.m_mesh = this;
2058 m_parent = 0;
2059 //m_material_index = -1;
2060 m_mesh_is_closed = 0;
2061 m_mesh_is_manifold = 0;
2062 m_mesh_is_oriented = 0;
2063 m_mesh_is_solid = 0;
2064 for ( i = 0; i < 4; i++ )
2065 {
2066 m_kstat[i] = 0;
2067 }
2068 }
2069
SwapCoordinates(int i,int j)2070 ON_BOOL32 ON_Mesh::SwapCoordinates(
2071 int i, int j // indices of coords to swap
2072 )
2073 {
2074 if ( i == j )
2075 return true;
2076
2077 const bool bIsValid_fV = SinglePrecisionVerticesAreValid();
2078 const bool bIsValid_dV = DoublePrecisionVerticesAreValid();
2079
2080 const int vertex_count = VertexCount();
2081 ON_BOOL32 rc = ON_SwapPointListCoordinates( vertex_count, 3, &m_V[0][0], i, j );
2082 if ( rc && HasVertexNormals() ) {
2083 rc = ON_SwapPointListCoordinates( vertex_count, 3, &m_N[0][0], i, j );
2084 }
2085 if ( rc )
2086 {
2087 float x;
2088 if ( m_vbox[0][0] <= m_vbox[1][0] ) {
2089 x = m_vbox[0][i]; m_vbox[0][i] = m_vbox[0][j]; m_vbox[0][j] = x;
2090 x = m_vbox[1][i]; m_vbox[1][i] = m_vbox[1][j]; m_vbox[1][j] = x;
2091 }
2092 if ( m_nbox[0][0] <= m_nbox[1][0] ) {
2093 x = m_nbox[0][i]; m_nbox[0][i] = m_nbox[0][j]; m_nbox[0][j] = x;
2094 x = m_nbox[1][i]; m_nbox[1][i] = m_nbox[1][j]; m_nbox[1][j] = x;
2095 }
2096 }
2097
2098 if ( HasDoublePrecisionVertices() )
2099 {
2100 DoublePrecisionVertices().SwapCoordinates(i,j);
2101 if ( bIsValid_fV )
2102 SetSinglePrecisionVerticesAsValid();
2103 if ( bIsValid_dV )
2104 SetDoublePrecisionVerticesAsValid();
2105 }
2106
2107 return rc;
2108 }
2109
SetClosed(int b)2110 void ON_Mesh::SetClosed(int b)
2111 {
2112 // 6 Novermber 2003 Dale Lear - let expert user set m_mesh_is_closed
2113 char mesh_is_closed = 0;
2114 switch(b)
2115 {
2116 case 0: // not closed - at least one boundary edge
2117 mesh_is_closed = 2;
2118 SetSolidOrientation(0);
2119 break;
2120 case 1: // all edges are shared
2121 // DO NOT SET m_mesh_is_solid here.
2122 // Meshes can be closed but not solid
2123 mesh_is_closed = 1;
2124 break;
2125 case 2: // 31 April 2010 Dale Lear - 2 is obsolete - it's either 0 or 1 now.
2126 mesh_is_closed = 1;
2127 // DO NOT SET m_mesh_is_solid here.
2128 // Meshes can be closed but not solid
2129 break;
2130 default:
2131 mesh_is_closed = 0; // unset
2132 break;
2133 }
2134 if ( 0 == mesh_is_closed || m_mesh_is_closed != mesh_is_closed )
2135 {
2136 m_mesh_is_closed = mesh_is_closed;
2137 m_mesh_is_manifold = 0; // unset - will be reevaluated when needed
2138 m_mesh_is_oriented = 0; // unset - will be reevaluated when needed
2139 }
2140 }
2141
SetSolidOrientation(int solid_orientation)2142 void ON_Mesh::SetSolidOrientation(int solid_orientation)
2143 {
2144 switch(solid_orientation)
2145 {
2146 case -1: // closed oriented manifold solid with inward face normals
2147 SetClosed(1);
2148 m_mesh_is_manifold = 1;
2149 m_mesh_is_oriented = 1;
2150 m_mesh_is_solid = 2;
2151 break;
2152
2153 case 0: // not solid
2154 m_mesh_is_solid = 3;
2155 // DO NOT SET m_mesh_is_closed here.
2156 // Meshes can be closed but not solid
2157 break;
2158
2159 case 1: // closed oriented manifold solid with outward face normals
2160 SetClosed(1);
2161 m_mesh_is_manifold = 1;
2162 m_mesh_is_oriented = 1;
2163 m_mesh_is_solid = 1;
2164 break;
2165
2166 default:
2167 m_mesh_is_solid = 0;
2168 break;
2169 }
2170 }
2171
2172
2173 static
ON_MeshIsManifold_CompareV(const void * a,const void * b)2174 int ON_MeshIsManifold_CompareV( const void* a, const void* b )
2175 {
2176 return memcmp(a,b,sizeof(ON_3fPoint));
2177 /*
2178 float d;
2179 const float* fa = (const float*)a;
2180 const float* fb = (const float*)b;
2181 if ( 0.0f == (d = (*fa++ - *fb++)) )
2182 {
2183 if ( 0.0f == (d = (*fa++ - *fb++)) )
2184 {
2185 if ( 0.0f == (d = (*fa++ - *fb++)) )
2186 return 0;
2187 }
2188 }
2189 return ( d < 0.0f ) ? -1 : 1;
2190 */
2191 }
2192
2193 static
ON_MeshGetVertexEdges_Compare2dex(const void * a,const void * b)2194 int ON_MeshGetVertexEdges_Compare2dex( const void* a, const void* b )
2195 {
2196 return ON_Compare2dex((const ON_2dex*)a,(const ON_2dex*)b);
2197 }
2198
2199 static
ON_MeshIsManifold_Compare3dex(const void * a,const void * b)2200 int ON_MeshIsManifold_Compare3dex( const void* a, const void* b )
2201 {
2202 return ON_Compare3dex((const ON_3dex*)a,(const ON_3dex*)b);
2203 }
2204
2205 //static
2206 //int ON_MeshGetVertexEdges_CompareInt( const int* a, const int* b )
2207 //{
2208 // return (*a-*b);
2209 //}
2210
2211
GetVertexEdges(int vertex_index_count,const int * vertex_index,bool bNoDuplicates,ON_SimpleArray<ON_2dex> & edges) const2212 int ON_Mesh::GetVertexEdges(
2213 int vertex_index_count,
2214 const int* vertex_index,
2215 bool bNoDuplicates,
2216 ON_SimpleArray<ON_2dex>& edges
2217 ) const
2218 {
2219 // Get edges connected to vertices in vertex_index[] array.
2220 const int edges_count0 = edges.Count();
2221
2222 const int mesh_vcount = m_V.Count();
2223
2224 //03/12/2007 TimH. The line below appears to be a typo. Using the following line works better.
2225 //const int mesh_fcount = m_V.Count();
2226 const int mesh_fcount = m_F.Count();
2227
2228 if ( vertex_index_count <= 0 || 0 == vertex_index
2229 || mesh_fcount <= 0 || mesh_vcount < 3 )
2230 {
2231 return 0;
2232 }
2233
2234 int vei, efi, fvi, ei, fi, j, n, vi;
2235 const int* f_vi;
2236 ON_2dex edge_ends;
2237 const ON_MeshFace* f = m_F.Array();
2238
2239 if ( TopologyExists()
2240 && mesh_vcount == m_top.m_topv_map.Count()
2241 && m_top.m_tope.Count() > 0 )
2242 {
2243 // Topology looks good; use it to speed up the search.
2244 const int* topv_map = m_top.m_topv_map;
2245 const int top_vcount = m_top.m_topv.Count();
2246 const int top_ecount = m_top.m_tope.Count();
2247 int top_vi;
2248 for ( n = 0; n < vertex_index_count; n++ )
2249 {
2250 vi = vertex_index[n];
2251 if ( vi < 0 || vi >= mesh_vcount )
2252 continue;
2253 top_vi = topv_map[vi];
2254 if ( top_vi < 0 || top_vi > top_vcount )
2255 continue;
2256 edge_ends.i = vi;
2257 const ON_MeshTopologyVertex& v = m_top.m_topv[top_vi];
2258 for ( vei = 0; vei < v.m_tope_count; vei++ )
2259 {
2260 ei = v.m_topei[vei];
2261 if ( ei < 0 || ei >= top_ecount )
2262 continue;
2263 const ON_MeshTopologyEdge& e = m_top.m_tope[ei];
2264 for ( efi = 0; efi < e.m_topf_count; efi++ )
2265 {
2266 fi = e.m_topfi[efi];
2267 if ( fi < 0 || fi >= mesh_fcount )
2268 continue;
2269 f_vi = f[fi].vi;
2270 for ( fvi = 0; fvi < 4; fvi++ )
2271 {
2272 if ( f_vi[fvi] == vi )
2273 {
2274 j = f_vi[(fvi+3)%4];
2275 if ( j >= 0 && j < mesh_vcount && vi != j )
2276 {
2277 edge_ends.i = j;
2278 edge_ends.j = vi;
2279 edges.Append(edge_ends);
2280 }
2281 j = f_vi[ (2==fvi && f_vi[2]==f_vi[3]) ? 0 : ((fvi+1)%4) ];
2282 if ( j >= 0 && j < mesh_vcount && vi != j )
2283 {
2284 edge_ends.i = vi;
2285 edge_ends.j = j;
2286 edges.Append(edge_ends);
2287 }
2288 break; // done with this face
2289 }
2290 }
2291 }
2292 }
2293 }
2294 }
2295 else
2296 {
2297 // slow-n-stupid search through all the faces
2298
2299 // Sort vertex_index[] array so we can use a quick
2300 // binary search to see if a face is using one of
2301 // the vertices in the list.
2302 ON_Workspace ws;
2303 for ( vi = 1; vi < vertex_index_count; vi++ )
2304 {
2305 if ( vertex_index[vi] < vertex_index[vi-1] )
2306 {
2307 // need to sort vertex_index[] array
2308 int* tmp = ws.GetIntMemory(vertex_index_count);
2309 memcpy(tmp,vertex_index,vertex_index_count*sizeof(tmp[0]));
2310 ON_SortIntArray(ON::quick_sort,tmp,vertex_index_count);
2311 vertex_index = tmp;
2312 break;
2313 }
2314 }
2315
2316 // Find all the faces that use a vertex in the vertex_index[] array.
2317 for ( fi = 0; fi < mesh_fcount; fi++ )
2318 {
2319 f_vi = f[fi].vi;
2320 for ( fvi = 0; fvi < 4; fvi++ )
2321 {
2322 vi = f_vi[fvi];
2323 if ( ON_BinarySearchIntArray(vi,vertex_index,vertex_index_count) )
2324 {
2325 // vi is in the vertex_index[] array. Add the edges
2326 // of this face that begin and end at this vertex.
2327 j = f_vi[(fvi+3)%4];
2328 if ( j >= 0 && j < mesh_vcount && vi != j )
2329 {
2330 edge_ends.i = j;
2331 edge_ends.j = vi;
2332 edges.Append(edge_ends);
2333 }
2334 j = f_vi[ (2==fvi && f_vi[2]==f_vi[3]) ? 0 : ((fvi+1)%4) ];
2335 if ( j >= 0 && j < mesh_vcount && vi != j )
2336 {
2337 edge_ends.i = vi;
2338 edge_ends.j = j;
2339 edges.Append(edge_ends);
2340 }
2341 }
2342 }
2343 }
2344 }
2345
2346 if ( bNoDuplicates && edges.Count() > edges_count0 )
2347 {
2348 for ( ei = edges_count0; ei < edges.Count(); ei++ )
2349 {
2350 edge_ends = edges[ei];
2351 if ( edge_ends.i > edge_ends.j )
2352 {
2353 j = edge_ends.i; edge_ends.i = edge_ends.j; edge_ends.j = j;
2354 }
2355 }
2356 ON_qsort( edges.Array() + edges_count0,
2357 edges.Count() - edges_count0,
2358 sizeof(edge_ends),
2359 ON_MeshGetVertexEdges_Compare2dex);
2360 edge_ends = edges[edges_count0];
2361 for ( ei = j = edges_count0+1; ei < edges.Count(); ei++ )
2362 {
2363 if ( ON_Compare2dex(&edge_ends,&edges[ei]) )
2364 {
2365 edge_ends = edges[ei];
2366 if ( j != ei )
2367 edges[j] = edge_ends;
2368 j++;
2369 }
2370 }
2371 edges.SetCount(j);
2372 }
2373
2374 return (edges.Count() - edges_count0);
2375 }
2376
GetMeshEdges(ON_SimpleArray<ON_2dex> & edges) const2377 int ON_Mesh::GetMeshEdges(
2378 ON_SimpleArray<ON_2dex>& edges
2379 ) const
2380 {
2381 const int edges_count0 = edges.Count();
2382 int fi, ei, j, fvi;
2383 const int* f_vi;
2384 const ON_MeshFace* f = m_F.Array();
2385 const int mesh_vcount = m_V.Count();
2386 const int mesh_fcount = m_F.Count();
2387 edges.Reserve( edges_count0 + 4*mesh_fcount );
2388 ON_2dex e;
2389
2390 // Find all the faces that use a vertex in the vertex_index[] array.
2391 for ( fi = 0; fi < mesh_fcount; fi++ )
2392 {
2393 f_vi = f[fi].vi;
2394 ei = f_vi[3];
2395 for ( fvi = 0; fvi < 4; fvi++ )
2396 {
2397 e.i = ei;
2398 ei = *f_vi++;
2399 e.j = ei;
2400 if ( e.i > e.j )
2401 {
2402 j = e.i; e.i = e.j; e.j = j;
2403 }
2404 if ( e.i != e.j && e.i >= 0 && e.j < mesh_vcount )
2405 {
2406 edges.Append(e);
2407 }
2408 }
2409 }
2410
2411
2412 if ( edges.Count() > edges_count0 )
2413 {
2414 ON_qsort( edges.Array() + edges_count0,
2415 edges.Count() - edges_count0,
2416 sizeof(e),
2417 ON_MeshGetVertexEdges_Compare2dex);
2418 e = edges[edges_count0];
2419 for ( ei = j = edges_count0+1; ei < edges.Count(); ei++ )
2420 {
2421 if ( ON_Compare2dex(&e,&edges[ei]) )
2422 {
2423 e = edges[ei];
2424 if ( j != ei )
2425 edges[j] = e;
2426 j++;
2427 }
2428 }
2429 edges.SetCount(j);
2430 }
2431
2432 return edges.Count() - edges_count0;
2433 }
2434
2435
SolidOrientation() const2436 int ON_Mesh::SolidOrientation() const
2437 {
2438
2439 if ( m_mesh_is_solid <= 0 || m_mesh_is_solid > 3 )
2440 {
2441 // NOTE: calling IsSolid() will set m_mesh_is_solid
2442 // to 3 if mes is non-manifold
2443 IsSolid();
2444 }
2445
2446 switch(m_mesh_is_solid)
2447 {
2448 case 1:
2449 return 1;
2450 break;
2451
2452 case 2:
2453 return -1;
2454 break;
2455
2456 case 3:
2457 return 0;
2458 break;
2459 }
2460
2461 return 0; // answer "no" if we don't know.
2462 }
2463
2464
IsSolid() const2465 bool ON_Mesh::IsSolid() const
2466 {
2467 return ( IsClosed() && IsManifold() && IsOriented() );
2468 }
2469
2470
IsManifold(bool bTopologicalTest,bool * pbIsOriented,bool * pbHasBoundary) const2471 bool ON_Mesh::IsManifold(
2472 bool bTopologicalTest,
2473 bool* pbIsOriented,
2474 bool* pbHasBoundary
2475 ) const
2476 {
2477 bool bIsManifold = false;
2478 if ( pbIsOriented )
2479 *pbIsOriented = false;
2480 if ( pbHasBoundary )
2481 *pbHasBoundary = false;
2482 const int vcount = m_V.Count();
2483 const int fcount = m_F.Count();
2484 if ( vcount > 0 && fcount > 0 )
2485 {
2486 ON_Workspace ws;
2487 ON_3dex e;
2488 int i, j, ecount;
2489 const int* fvi;
2490 ON_3fPoint v0;
2491 const ON_3fPoint* v;
2492 const ON_MeshFace* f;
2493 int* vid = ws.GetIntMemory(vcount);
2494 ON_3dex* edge = (ON_3dex*)ws.GetMemory(4*fcount*sizeof(*edge));
2495
2496 if ( bTopologicalTest )
2497 {
2498 // coincident vertices are assigned the same vertex id
2499 ON_Sort(ON::quick_sort,vid,m_V.Array(),vcount,sizeof(m_V[0]),ON_MeshIsManifold_CompareV);
2500 ecount = 0;
2501 v = m_V.Array();
2502 ecount = 0;
2503 j = vcount;
2504 for ( i = 0; i < vcount; i = j)
2505 {
2506 v0 = v[vid[i]];
2507 vid[i] = ecount;
2508 for ( j = i+1; j < vcount; j++ )
2509 {
2510 if ( ON_MeshIsManifold_CompareV(&v,v+vid[j]) )
2511 {
2512 ecount++;
2513 break;
2514 }
2515 vid[j] = ecount;
2516 }
2517 }
2518 }
2519 else
2520 {
2521 // each vertex gets a unique id.
2522 for ( i = 0; i < vcount; i++ )
2523 vid[i] = i;
2524 }
2525
2526 // build a list of edges
2527 f = m_F.Array();
2528 ecount = 0;
2529 for ( i = 0; i < fcount; i++ )
2530 {
2531 fvi = (f++)->vi;
2532 if ( fvi[0] >= 0 && fvi[0] < vcount
2533 && fvi[1] >= 0 && fvi[1] < vcount
2534 && fvi[2] >= 0 && fvi[2] < vcount
2535 && fvi[3] >= 0 && fvi[3] < vcount )
2536 {
2537 // loop unrolled for speed
2538 j = ecount;
2539 e.i = vid[fvi[0]]; e.j = vid[fvi[1]];
2540 if ( 0 != (e.k = e.j - e.i) )
2541 {
2542 if ( e.k < 0 ) {e.k = e.i; e.i = e.j; e.j = e.k; e.k = 1;} else e.k = 0;
2543 edge[ecount++] = e;
2544 }
2545 e.i = vid[fvi[1]]; e.j = vid[fvi[2]];
2546 if ( 0 != (e.k = e.j - e.i) )
2547 {
2548 if ( e.k < 0 ) {e.k = e.i; e.i = e.j; e.j = e.k; e.k = 1;} else e.k = 0;
2549 edge[ecount++] = e;
2550 }
2551 e.i = vid[fvi[2]]; e.j = vid[fvi[3]];
2552 if ( 0 != (e.k = e.j - e.i) )
2553 {
2554 if ( e.k < 0 ) {e.k = e.i; e.i = e.j; e.j = e.k; e.k = 1;} else e.k = 0;
2555 edge[ecount++] = e;
2556 }
2557 e.i = vid[fvi[3]]; e.j = vid[fvi[0]];
2558 if ( 0 != (e.k = e.j - e.i) )
2559 {
2560 if ( e.k < 0 ) {e.k = e.i; e.i = e.j; e.j = e.k; e.k = 1;} else e.k = 0;
2561 edge[ecount++] = e;
2562 }
2563 if ( ecount < j+3 )
2564 ecount = j;
2565 }
2566 }
2567
2568 if ( ecount >= 4 )
2569 {
2570 bIsManifold = true;
2571 bool bIsOriented = (pbIsOriented) ? true : false;
2572 bool bHasBoundary = (pbHasBoundary) ? false : true;
2573 ON_qsort(edge,ecount,sizeof(edge[0]),ON_MeshIsManifold_Compare3dex);
2574
2575 i = 0;
2576 e = *edge;
2577 while ( --ecount )
2578 {
2579 edge++;
2580 if ( memcmp(&e,edge,2*sizeof(int)) )
2581 {
2582 if (!i)
2583 bHasBoundary = true;
2584 e = *edge;
2585 i = 0;
2586 }
2587 else
2588 {
2589 if ( i++ )
2590 {
2591 bIsManifold = false;
2592 break;
2593 }
2594 if ( e.k == edge->k )
2595 bIsOriented = false;
2596 }
2597 }
2598
2599 if ( bIsManifold )
2600 {
2601 if ( pbIsOriented )
2602 *pbIsOriented = bIsOriented;
2603 if ( pbHasBoundary )
2604 *pbHasBoundary = bHasBoundary;
2605 }
2606 }
2607 }
2608
2609 return bIsManifold;
2610 }
2611
ON_hsort_3dex(ON_3dex * e,std::size_t nel)2612 static void ON_hsort_3dex(ON_3dex *e, std::size_t nel)
2613 {
2614 // dictionary sort e[]
2615 std::size_t i_end,k,i,j;
2616 ON_3dex e_tmp;
2617
2618 if (nel < 2) return;
2619 k = nel >> 1;
2620 i_end = nel-1;
2621 for (;;)
2622 {
2623 if (k)
2624 {
2625 --k;
2626 e_tmp = e[k];
2627 }
2628 else
2629 {
2630 e_tmp = e[i_end];
2631 e[i_end] = e[0];
2632 if (!(--i_end))
2633 {
2634 e[0] = e_tmp;
2635 break;
2636 }
2637 }
2638 i = k;
2639 j = (k<<1) + 1;
2640 while (j <= i_end)
2641 {
2642 if ( j < i_end && ( e[j].i < e[j + 1].i || (e[j].i == e[j + 1].i && (e[j].j < e[j + 1].j || ( e[j].j == e[j + 1].j && e[j].k < e[j + 1].k)) ) ) )
2643 j++;
2644
2645 if ( e_tmp.i < e[j].i || (e_tmp.i == e[j].i && (e_tmp.j < e[j].j || ( e_tmp.j == e[j].j && e_tmp.k < e[j].k) ) ) )
2646 {
2647 e[i] = e[j];
2648 i = j;
2649 j = (j<<1) + 1;
2650 }
2651 else
2652 j = i_end + 1;
2653 }
2654 e[i] = e_tmp;
2655 }
2656 }
2657
ON_Mesh_SetClosedHelper(bool bClosedOnly,const ON_Mesh & mesh,const char & m_mesh_is_manifold,const char & m_mesh_is_oriented)2658 static void ON_Mesh_SetClosedHelper(
2659 bool bClosedOnly,
2660 const ON_Mesh& mesh,
2661 const char& m_mesh_is_manifold,
2662 const char& m_mesh_is_oriented
2663 )
2664 {
2665 // thread safe lazy evaluation for mesh's m_mesh_is_... flags
2666 // Sets: m_mesh_is_closed.
2667 // If bClosedOnly is false, also sets m_mesh_is_manifold and m_mesh_is_oriented
2668 int is_closed = 0;
2669 char is_manifold = 2;
2670 char is_oriented = 2;
2671 for (;;)
2672 {
2673 const int Vcount = mesh.m_V.Count();
2674 const int Fcount = mesh.m_F.Count();
2675 if ( Vcount < 3 || Fcount < 1 )
2676 {
2677 ON_ERROR("Mesh is not valid.");
2678 break;
2679 }
2680 if ( bClosedOnly && (Vcount < 4 || Fcount < 4) )
2681 {
2682 // not closed - don't waste any more time.
2683 break;
2684 }
2685
2686 int i, j;
2687 int Vidbuffer[256];
2688 int* Vid = mesh.GetVertexLocationIds(
2689 1,
2690 (Vcount*sizeof(*Vid) <= sizeof(Vidbuffer) ? &Vidbuffer[0] : 0),
2691 0
2692 );
2693 if ( 0 == Vid )
2694 {
2695 ON_ERROR("Mesh has corrupt vertex information.");
2696 bClosedOnly = false;
2697 break;
2698 }
2699
2700 // build an edge list where the "vertex" indices identify unique 3d locations
2701 ON_3dex* E_list = (ON_3dex*)onmalloc(4*Fcount*sizeof(E_list[0]));
2702 ON_3dex E;
2703 int Vid0;
2704 const int* fvi;
2705 int E_count = 0;
2706 const ON_MeshFace* F = mesh.m_F.Array();
2707 for ( j = 0; j < Fcount; j++ )
2708 {
2709 fvi = F[j].vi;
2710 E.i = Vid[fvi[0]];
2711 Vid0 = E.j = Vid[fvi[1]];
2712 if ( E.i == E.j )
2713 break;
2714 if ( E.i > E.j )
2715 {
2716 i = E.i; E.i = E.j; E.j = i;
2717 E.k = 1;
2718 }
2719 else
2720 {
2721 E.k = 0;
2722 }
2723 E_list[E_count++] = E;
2724
2725 E.i = Vid0;
2726 Vid0 = E.j = Vid[fvi[2]];
2727 if ( E.i == E.j )
2728 break;
2729 if ( E.i > E.j )
2730 {
2731 i = E.i; E.i = E.j; E.j = i;
2732 E.k = 1;
2733 }
2734 else
2735 {
2736 E.k = 0;
2737 }
2738 E_list[E_count++] = E;
2739
2740 if ( fvi[2] != fvi[3] )
2741 {
2742 // quad
2743 E.i = Vid0;
2744 Vid0 = E.j = Vid[fvi[3]];
2745 if ( E.i == E.j )
2746 break;
2747 if ( E.i > E.j )
2748 {
2749 i = E.i; E.i = E.j; E.j = i;
2750 E.k = 1;
2751 }
2752 else
2753 {
2754 E.k = 0;
2755 }
2756 E_list[E_count++] = E;
2757 }
2758
2759 E.i = Vid0;
2760 E.j = Vid[fvi[0]];
2761 if ( E.i == E.j )
2762 break;
2763 if ( E.i > E.j )
2764 {
2765 i = E.i; E.i = E.j; E.j = i;
2766 E.k = 1;
2767 }
2768 else
2769 {
2770 E.k = 0;
2771 }
2772 E_list[E_count++] = E;
2773 }
2774 if ( Vid != &Vidbuffer[0] )
2775 onfree(Vid);
2776
2777 if ( E_count < 3 || j != Fcount )
2778 {
2779 ON_ERROR("Mesh is corrupt or collapsed");
2780 bClosedOnly = false;
2781 break;
2782 }
2783
2784 // sort the the edges
2785 ON_hsort_3dex(E_list,E_count);
2786
2787 // Look for duplicate edges. If we find an edge with no duplicate,
2788 // then the mesh is open. It is possible that degenerate meshes,
2789 // like a flattened box, will be flagged as closed.
2790 is_closed = (Fcount >= 4 && E_count >= 6) ? 1 : 0;
2791 is_oriented = 1;
2792 is_manifold = 1;
2793 i = -1;
2794 if ( !bClosedOnly || 1 == is_closed ) for ( i = 0; i < E_count; /*empty iterator*/ )
2795 {
2796 E = E_list[i];
2797 if ( ++i >= E_count )
2798 {
2799 // boundary edge (and the last edge in our list)
2800 is_closed = 0;
2801 break;
2802 }
2803
2804 if ( E.i != E_list[i].i || E.j != E_list[i].j )
2805 {
2806 // boundary edge
2807 is_closed = 0;
2808 if ( 2 == is_oriented && 2 == is_manifold )
2809 {
2810 bClosedOnly = false;
2811 break;
2812 }
2813 if ( bClosedOnly )
2814 break; // don't spend time with further testing
2815 continue;
2816 }
2817
2818 if ( E.k == E_list[i].k )
2819 {
2820 // opposite face normals along this edge - mesh is not oriented
2821 is_oriented = 2;
2822 }
2823
2824 if ( ++i >= E_count || E.i != E_list[i].i || E.j != E_list[i].j )
2825 {
2826 // two faces share this edge
2827 continue;
2828 }
2829
2830 // three or more faces share this edge - mesh is not oriented manifold
2831 is_oriented = 2;
2832 is_manifold = 2;
2833 if ( 0 == is_closed )
2834 {
2835 bClosedOnly = false;
2836 break;
2837 }
2838
2839 // Check for more faces sharing this edge.
2840 for ( i++; i < E_count; i++ )
2841 {
2842 if ( E.i != E_list[i].i || E.j != E_list[i].j )
2843 {
2844 // the edges E and Eid_list[i] are in different locations
2845 break;
2846 }
2847 }
2848 }
2849 if ( i >= E_count )
2850 {
2851 // is_manifold and is_oriented are set correctly
2852 bClosedOnly = false;
2853 }
2854
2855 onfree(E_list);
2856
2857 break;
2858 }
2859
2860 const_cast<ON_Mesh&>(mesh).SetClosed(is_closed);
2861 if ( !bClosedOnly )
2862 {
2863 // is_manifold and is_oriented are set correctly
2864 if ( 2 == is_manifold )
2865 is_oriented = 2;
2866 const_cast<char&>(m_mesh_is_manifold) = is_manifold;
2867 const_cast<char&>(m_mesh_is_oriented) = is_oriented;
2868 }
2869 }
2870
IsClosed() const2871 bool ON_Mesh::IsClosed() const
2872 {
2873 if ( m_mesh_is_closed <= 0 || m_mesh_is_closed > 2)
2874 {
2875 // thread safe lazy evaluation
2876 ON_Mesh_SetClosedHelper( true, *this, m_mesh_is_manifold, m_mesh_is_oriented );
2877 }
2878
2879 return (1 == m_mesh_is_closed);
2880 }
2881
IsManifold() const2882 bool ON_Mesh::IsManifold() const
2883 {
2884 if ( m_mesh_is_manifold <= 0 || m_mesh_is_manifold > 2 )
2885 {
2886 // thread safe lazy evaluation
2887 ON_Mesh_SetClosedHelper( false, *this, m_mesh_is_manifold, m_mesh_is_oriented );
2888 }
2889 return (1 == m_mesh_is_manifold);
2890 }
2891
IsOriented() const2892 bool ON_Mesh::IsOriented() const
2893 {
2894 if ( m_mesh_is_oriented <= 0 || m_mesh_is_oriented > 2 )
2895 {
2896 // thread safe lazy evaluation
2897 ON_Mesh_SetClosedHelper( false, *this, m_mesh_is_manifold, m_mesh_is_oriented );
2898 }
2899 return (1 == m_mesh_is_oriented);
2900 }
2901
2902
SetVertex(int vertex_index,const ON_3dPoint & vertex_location)2903 bool ON_Mesh::SetVertex(
2904 int vertex_index,
2905 const ON_3dPoint& vertex_location
2906 )
2907 {
2908 bool rc = false;
2909 int vertex_count = m_V.Count();
2910 if ( vertex_index >= 0 && vertex_index <= vertex_count )
2911 {
2912 bool bIsValid_fV = false;
2913 if ( HasDoublePrecisionVertices() )
2914 {
2915 bIsValid_fV = SinglePrecisionVerticesAreValid();
2916 ON_3dPointArray& dV = DoublePrecisionVertices();
2917 if ( vertex_count == dV.Count() )
2918 {
2919 bool bIsValid_dV = DoublePrecisionVerticesAreValid();
2920 if ( vertex_index < vertex_count )
2921 dV[vertex_index] = vertex_location;
2922 else
2923 dV.Append(vertex_location);
2924 if ( bIsValid_dV )
2925 SetDoublePrecisionVerticesAsValid();
2926 }
2927 }
2928 if ( vertex_index < vertex_count )
2929 m_V[vertex_index] = vertex_location;
2930 else
2931 m_V.Append(vertex_location);
2932 if ( bIsValid_fV )
2933 SetSinglePrecisionVerticesAsValid();
2934 rc = true;
2935 }
2936 return rc;
2937 }
2938
SetVertex(int vertex_index,const ON_3fPoint & vertex_location)2939 bool ON_Mesh::SetVertex(
2940 int vertex_index,
2941 const ON_3fPoint& vertex_location
2942 )
2943 {
2944 bool rc = false;
2945 int vertex_count = m_V.Count();
2946 if ( vertex_index >= 0 && vertex_index <= vertex_count )
2947 {
2948 bool bIsValid_fV = false;
2949 if ( HasDoublePrecisionVertices() )
2950 {
2951 bIsValid_fV = SinglePrecisionVerticesAreValid();
2952 ON_3dPointArray& dV = DoublePrecisionVertices();
2953 if ( vertex_count == dV.Count() )
2954 {
2955 bool bIsValid_dV = DoublePrecisionVerticesAreValid();
2956 if ( vertex_index < vertex_count )
2957 dV[vertex_index] = vertex_location;
2958 else
2959 dV.Append(vertex_location);
2960 if ( bIsValid_dV )
2961 SetDoublePrecisionVerticesAsValid();
2962 }
2963 }
2964 if ( vertex_index < vertex_count )
2965 m_V[vertex_index] = vertex_location;
2966 else
2967 m_V.Append(vertex_location);
2968 if ( bIsValid_fV )
2969 SetSinglePrecisionVerticesAsValid();
2970 rc = true;
2971 }
2972 return rc;
2973 }
2974
SetVertexNormal(int vertex_index,const ON_3dVector & normal)2975 bool ON_Mesh::SetVertexNormal(
2976 int vertex_index,
2977 const ON_3dVector& normal
2978 )
2979 {
2980 bool rc = false;
2981 // use double precision for unitizing normal
2982 ON_3dVector unit_vector = normal;
2983 const bool bUnitVector = unit_vector.Unitize();
2984 ON_3fVector v((float)unit_vector.x, (float)unit_vector.y, (float)unit_vector.z);
2985 int normal_count = m_N.Count();
2986 if ( vertex_index >= 0 ) {
2987 if ( vertex_index < normal_count ) {
2988 m_N[vertex_index] = v;
2989 rc = bUnitVector;
2990 }
2991 else if ( vertex_index == normal_count ) {
2992 m_N.Append(v);
2993 rc = bUnitVector;
2994 }
2995 }
2996 return rc;
2997 }
2998
SetVertexNormal(int vertex_index,const ON_3fVector & normal)2999 bool ON_Mesh::SetVertexNormal(
3000 int vertex_index,
3001 const ON_3fVector& normal
3002 )
3003 {
3004 ON_3dVector v(normal.x,normal.y,normal.z);
3005 return SetVertexNormal(vertex_index,v);
3006 }
3007
SetTextureCoord(int vertex_index,double s,double t)3008 bool ON_Mesh::SetTextureCoord(
3009 int vertex_index,
3010 double s, double t // texture coordinates
3011 )
3012 {
3013 ON_2fPoint tc((float)s,(float)t);
3014 bool rc = false;
3015 int vertex_count = m_T.Count();
3016 if ( vertex_index >= 0 ) {
3017 if ( vertex_index < vertex_count ) {
3018 m_T[vertex_index] = tc;
3019 rc = true;
3020 }
3021 else if ( vertex_index == vertex_count ) {
3022 m_T.Append(tc);
3023 rc = true;
3024 }
3025 }
3026 return rc;
3027 }
3028
3029
SetTriangle(int face_index,int a,int b,int c)3030 bool ON_Mesh::SetTriangle(
3031 int face_index,
3032 int a,int b ,int c // vertex indices
3033 )
3034 {
3035 return SetQuad( face_index, a,b,c,c );
3036 }
3037
SetQuad(int face_index,int a,int b,int c,int d)3038 bool ON_Mesh::SetQuad(
3039 int face_index,
3040 int a, int b, int c, int d // vertex indices
3041 )
3042 {
3043 bool rc = false;
3044 int face_count = m_F.Count();
3045 if ( face_index >= 0 ) {
3046 ON_MeshFace f;
3047 f.vi[0] = a;
3048 f.vi[1] = b;
3049 f.vi[2] = c;
3050 f.vi[3] = d;
3051 if ( face_index < face_count ) {
3052 m_F[face_index] = f;
3053 rc = true;
3054 }
3055 else if ( face_index == face_count ) {
3056 m_F.Append(f);
3057 rc = true;
3058 }
3059 if ( rc )
3060 rc = f.IsValid(m_V.Count());
3061 }
3062 return rc;
3063 }
3064
3065
3066
FaceCount() const3067 int ON_Mesh::FaceCount() const
3068 {
3069 return m_F.Count();
3070 }
3071
QuadCount() const3072 int ON_Mesh::QuadCount() const
3073 {
3074 // number of faces that are quads
3075 if ( m_quad_count < 0
3076 || m_triangle_count < 0
3077 || m_invalid_count < 0
3078 || m_quad_count + m_triangle_count + m_invalid_count != FaceCount() )
3079 {
3080 const_cast<ON_Mesh*>(this)->CountQuads();
3081 }
3082 return m_quad_count;
3083 }
3084
TriangleCount() const3085 int ON_Mesh::TriangleCount() const
3086 {
3087 // number of faces that are triangles
3088 QuadCount(); // makes sure counts are valid
3089 return m_triangle_count;
3090 }
3091
InvalidFaceCount() const3092 int ON_Mesh::InvalidFaceCount() const
3093 {
3094 // number of faces that are invalid
3095 QuadCount(); // makes sure counts are valid
3096 return m_invalid_count;
3097 }
3098
3099
VertexCount() const3100 int ON_Mesh::VertexCount() const
3101 {
3102 return m_V.Count();
3103 }
3104
HasVertexNormals() const3105 bool ON_Mesh::HasVertexNormals() const
3106 {
3107 const int vertex_count = VertexCount();
3108 return ( vertex_count > 0 && m_N.Count() == vertex_count ) ? true : false;
3109 }
3110
HasFaceNormals() const3111 bool ON_Mesh::HasFaceNormals() const
3112 {
3113 const int face_count = FaceCount();
3114 return ( face_count > 0 && m_FN.Count() == face_count ) ? true : false;
3115 }
3116
HasTextureCoordinates() const3117 bool ON_Mesh::HasTextureCoordinates() const
3118 {
3119 const int vertex_count = VertexCount();
3120 return ( vertex_count > 0 && m_T.Count() == vertex_count ) ? true : false;
3121 }
3122
HasCachedTextureCoordinates() const3123 bool ON_Mesh::HasCachedTextureCoordinates() const
3124 {
3125 const int vertex_count = VertexCount();
3126 if (vertex_count > 0 )
3127 {
3128 int tci, tccount = m_TC.Count();
3129 for ( tci = 0; tci < tccount; tci++ )
3130 {
3131 if ( vertex_count == m_TC[tci].m_T.Count() )
3132 return true;
3133 }
3134 }
3135 return false;
3136 }
3137
3138 const ON_TextureCoordinates*
CachedTextureCoordinates(const ON_UUID & mapping_id) const3139 ON_Mesh::CachedTextureCoordinates( const ON_UUID& mapping_id ) const
3140 {
3141 const int vertex_count = VertexCount();
3142 if (vertex_count > 0 )
3143 {
3144 const ON_TextureCoordinates* TC = m_TC.Array();
3145 int tci, tccount = m_TC.Count();
3146 for ( tci = 0; tci < tccount; tci++ )
3147 {
3148 if ( vertex_count == TC->m_T.Count()
3149 && mapping_id == TC->m_tag.m_mapping_id )
3150 {
3151 return TC;
3152 }
3153 }
3154 }
3155 return 0;
3156 }
3157
HasSurfaceParameters() const3158 bool ON_Mesh::HasSurfaceParameters() const
3159 {
3160 const int vertex_count = VertexCount();
3161 return ( vertex_count > 0 && m_S.Count() == vertex_count ) ? true : false;
3162 }
3163
HasPrincipalCurvatures() const3164 bool ON_Mesh::HasPrincipalCurvatures() const
3165 {
3166 const int vertex_count = VertexCount();
3167 return ( vertex_count > 0 && m_K.Count() == vertex_count ) ? true : false;
3168 }
3169
HasVertexColors() const3170 bool ON_Mesh::HasVertexColors() const
3171 {
3172 const int vertex_count = VertexCount();
3173 return ( vertex_count > 0 && m_C.Count() == vertex_count ) ? true : false;
3174 }
3175
InvalidateBoundingBoxes()3176 void ON_Mesh::InvalidateBoundingBoxes()
3177 {
3178 InvalidateVertexBoundingBox();
3179 InvalidateVertexNormalBoundingBox();
3180 InvalidateTextureCoordinateBoundingBox();
3181 InvalidateCurvatureStats();
3182 }
3183
InvalidateVertexBoundingBox()3184 void ON_Mesh::InvalidateVertexBoundingBox()
3185 {
3186 m_vbox[0][0] = m_vbox[0][1] = m_vbox[0][2] = 1.0;
3187 m_vbox[1][0] = m_vbox[1][1] = m_vbox[1][2] = -1.0;
3188 }
3189
InvalidateVertexNormalBoundingBox()3190 void ON_Mesh::InvalidateVertexNormalBoundingBox()
3191 {
3192 m_nbox[0][0] = m_nbox[0][1] = m_nbox[0][2] = 1.0;
3193 m_nbox[1][0] = m_nbox[1][1] = m_nbox[1][2] = -1.0;
3194 }
3195
InvalidateTextureCoordinateBoundingBox()3196 void ON_Mesh::InvalidateTextureCoordinateBoundingBox()
3197 {
3198 m_tbox[0][0] = m_tbox[0][1] = 1.0;
3199 m_tbox[1][0] = m_tbox[1][1] = -1.0;
3200 }
3201
InvalidateCurvatureStats()3202 void ON_Mesh::InvalidateCurvatureStats()
3203 {
3204 int i;
3205 for ( i = 0; i < 4; i++ ) {
3206 if ( m_kstat[i] ) {
3207 delete m_kstat[i];
3208 m_kstat[i] = 0;
3209 }
3210 }
3211 }
3212
UnitizeVertexNormals()3213 bool ON_Mesh::UnitizeVertexNormals()
3214 {
3215 bool rc = HasVertexNormals();
3216 if ( rc ) {
3217 const int vertex_count = VertexCount();
3218 float* n = &m_N[0][0];
3219 int i;
3220 ON_3dVector N;
3221 for ( i = 0; i < vertex_count; i++ ) {
3222 N.x = n[0];
3223 N.y = n[1];
3224 N.z = n[2];
3225 if ( !N.Unitize() )
3226 rc = false;
3227 *n++ = (float)N.x;
3228 *n++ = (float)N.y;
3229 *n++ = (float)N.z;
3230 }
3231 }
3232 return rc;
3233 }
3234
UnitizeFaceNormals()3235 bool ON_Mesh::UnitizeFaceNormals()
3236 {
3237 bool rc = HasFaceNormals();
3238 if ( rc ) {
3239 const int face_count = FaceCount();
3240 float* n = &m_FN[0][0];
3241 int i;
3242 ON_3dVector N;
3243 for ( i = 0; i < face_count; i++ ) {
3244 N.x = n[0];
3245 N.y = n[1];
3246 N.z = n[2];
3247 if ( !N.Unitize() )
3248 rc = false;
3249 *n++ = (float)N.x;
3250 *n++ = (float)N.y;
3251 *n++ = (float)N.z;
3252 }
3253 }
3254 return rc;
3255 }
3256
3257
GetCurvatureStats(ON::curvature_style kappa_style,ON_MeshCurvatureStats & stats) const3258 bool ON_Mesh::GetCurvatureStats( // returns true if successful
3259 ON::curvature_style kappa_style,
3260 ON_MeshCurvatureStats& stats
3261 ) const
3262 {
3263 bool rc = false;
3264 stats.Destroy();
3265 int ksi;
3266 switch ( kappa_style ) {
3267 case ON::gaussian_curvature:
3268 ksi = 0;
3269 break;
3270 case ON::mean_curvature:
3271 ksi = 1;
3272 break;
3273 case ON::min_curvature: // minimum unsigned radius of curvature
3274 ksi = 2;
3275 break;
3276 case ON::max_curvature: // maximum unsigned radius of curvature
3277 ksi = 3;
3278 break;
3279 //case ON::section_curvature_x:
3280 // ksi = 4;
3281 // break;
3282 //case ON::section_curvature_y:
3283 // ksi = 5;
3284 // break;
3285 //case ON::section_curvature_z:
3286 // ksi = 6;
3287 // break;
3288 default:
3289 ksi = -1;
3290 break;
3291 }
3292 if ( ksi >= 0 && ksi <= 3 && HasPrincipalCurvatures() ) {
3293 ON_Mesh* p = (ON_Mesh*)this; // const lie
3294 if ( !m_kstat[ksi] ) {
3295 p->m_kstat[ksi] = new ON_MeshCurvatureStats();
3296 p->m_kstat[ksi]->Set( kappa_style, m_K.Count(), m_K.Array(), m_N.Array() );
3297 }
3298 if ( p->m_kstat[ksi] ) {
3299 stats = *p->m_kstat[ksi];
3300 rc = true;
3301 }
3302 }
3303 return rc;
3304 }
3305
WaitUntilReady(int) const3306 int ON_MeshTopology::WaitUntilReady(int) const
3307 {
3308 return m_b32IsValid;
3309 }
3310
3311
TopologyExists() const3312 bool ON_Mesh::TopologyExists() const
3313 {
3314 return (1 == m_top.WaitUntilReady(0));
3315 }
3316
Topology() const3317 const ON_MeshTopology& ON_Mesh::Topology() const
3318 {
3319 int top_b32IsValid = m_top.WaitUntilReady(-1);
3320
3321 if ( 0 == top_b32IsValid )
3322 {
3323 ON_MeshTopology& top = const_cast<ON_MeshTopology&>(m_top);
3324 top.m_mesh = this;
3325 top_b32IsValid = top.Create() ? 1 : 0;
3326 top.m_b32IsValid = top_b32IsValid;
3327 }
3328
3329 return m_top;
3330 }
3331
DestroyTopology()3332 void ON_Mesh::DestroyTopology()
3333 {
3334 m_top.Destroy();
3335 }
3336
3337 bool
IsTriangle() const3338 ON_MeshFace::IsTriangle() const
3339 {
3340 return vi[2]==vi[3];
3341 }
3342
3343 bool
IsQuad() const3344 ON_MeshFace::IsQuad() const
3345 {
3346 return vi[2]!=vi[3];
3347 }
3348
3349 void
Flip()3350 ON_MeshFace::Flip()
3351 {
3352 int i;
3353 if ( vi[2] == vi[3] ) {
3354 i = vi[1];
3355 vi[1] = vi[2];
3356 vi[2] = i;
3357 vi[3] = i;
3358 }
3359 else {
3360 i = vi[1];
3361 vi[1] = vi[3];
3362 vi[3] = i;
3363 }
3364 }
3365
3366 /*
3367 ON_MeshEdge::ON_MeshEdge() : m_fcount(0)
3368 {
3369 m_fi = m_private_fi;
3370 m_private_fi[0] = 0;
3371 m_private_fi[0] = 0;
3372 }
3373
3374 ON_MeshEdge::~ON_MeshEdge()
3375 {
3376 if ( m_fi && m_fi != m_private_fi ) onfree((void*)m_fi);
3377 }
3378
3379 ON_MeshEdge::ON_MeshEdge( const ON_MeshEdge& src ) : m_fcount(0), m_fi(0)
3380 {
3381 *this = src;
3382 }
3383
3384 int ON_MeshEdge::FaceIndexCount() const
3385 {
3386 return m_fcount;
3387 }
3388
3389 const int* ON_MeshEdge::FaceIndexArray() const
3390 {
3391 return m_fi;
3392 }
3393
3394 int& ON_MeshEdge::operator[](int i)
3395 {
3396 return (i>=0&&i<m_fcount) ? m_fi[i] : m_private_fi[0];
3397 }
3398
3399 int ON_MeshEdge::operator[](int i) const
3400 {
3401 return (i>=0&&i<m_fcount) ? m_fi[i] : m_private_fi[0];
3402 }
3403 */
3404
3405 void
Flip()3406 ON_Mesh::Flip()
3407 {
3408 FlipFaceOrientation();
3409 FlipFaceNormals();
3410 FlipVertexNormals();
3411
3412 // Do not modify m_S[] or m_T[]
3413 // values here.
3414 }
3415
3416 void
FlipVertexNormals()3417 ON_Mesh::FlipVertexNormals()
3418 {
3419 int i;
3420 const int vcount = VertexCount();
3421 if ( HasVertexNormals() ) {
3422 for ( i = 0; i < vcount; i++ ) {
3423 m_N[i].Reverse();
3424 }
3425 }
3426 }
3427
3428 void
FlipFaceNormals()3429 ON_Mesh::FlipFaceNormals()
3430 {
3431 int i;
3432 const int fcount = FaceCount();
3433 if ( HasFaceNormals() ) {
3434 for( i = 0; i < fcount; i++ ) {
3435 m_FN[i].Reverse();
3436 }
3437 }
3438 }
3439
3440 void
FlipFaceOrientation()3441 ON_Mesh::FlipFaceOrientation()
3442 {
3443 int i;
3444 const int fcount = FaceCount();
3445 for( i = 0; i < fcount; i++ ) {
3446 m_F[i].Flip();
3447 }
3448 if ( fcount > 0 )
3449 DestroyTopology(); // flipping changes order of face corners
3450 }
3451
ComputeFaceNormal(const ON_3dPoint * dV,ON_3dVector & FN) const3452 bool ON_MeshFace::ComputeFaceNormal( const ON_3dPoint* dV, ON_3dVector& FN ) const
3453 {
3454 if ( 0 != dV )
3455 {
3456 ON_3dVector a = dV[vi[2]] - dV[vi[0]];
3457 ON_3dVector b = dV[vi[3]] - dV[vi[1]];
3458 FN = ON_CrossProduct( a, b ); // works for triangles, quads, and nonplanar quads
3459 if ( FN.Unitize() )
3460 return true;
3461 }
3462
3463 FN.Zero();
3464 return false;
3465 }
3466
ComputeFaceNormal(const ON_3fPoint * fV,ON_3dVector & FN) const3467 bool ON_MeshFace::ComputeFaceNormal( const ON_3fPoint* fV, ON_3dVector& FN ) const
3468 {
3469 if ( 0 != fV )
3470 {
3471 ON_3dVector a = fV[vi[2]] - fV[vi[0]];
3472 ON_3dVector b = fV[vi[3]] - fV[vi[1]];
3473 FN = ON_CrossProduct( a, b ); // works for triangles, quads, and nonplanar quads
3474 if ( FN.Unitize() )
3475 return true;
3476 }
3477
3478 FN.Zero();
3479 return false;
3480 }
3481
3482 bool
ComputeFaceNormal(int fi)3483 ON_Mesh::ComputeFaceNormal( int fi )
3484 {
3485 if ( fi < 0 )
3486 return false;
3487 if ( fi >= m_F.Count() )
3488 return false;
3489 if ( m_FN.Count() != m_F.Count() )
3490 return false;
3491
3492 ON_3dVector FN;
3493 bool rc = ( HasDoublePrecisionVertices() )
3494 ? m_F[fi].ComputeFaceNormal(DoublePrecisionVertices().Array(),FN)
3495 : m_F[fi].ComputeFaceNormal(m_V.Array(),FN);
3496
3497 m_FN[fi] = FN;
3498
3499 return rc;
3500 }
3501
3502 bool
ComputeFaceNormals()3503 ON_Mesh::ComputeFaceNormals()
3504 {
3505 bool rc = false;
3506 const int fcount = FaceCount();
3507 if ( fcount > 0 )
3508 {
3509 ON_3dVector a, b, n;
3510 int fi;
3511 const int* vi;
3512 if ( m_FN.Capacity() < fcount )
3513 m_FN.SetCapacity(fcount);
3514 m_FN.SetCount(0);
3515 rc = true;
3516 if ( HasDoublePrecisionVertices() && DoublePrecisionVerticesAreValid() )
3517 {
3518 const ON_3dPointArray& dV = DoublePrecisionVertices();
3519 for ( fi = 0; fi < fcount; fi++ ) {
3520 vi = m_F[fi].vi;
3521 a = dV[vi[2]] - dV[vi[0]];
3522 b = dV[vi[3]] - dV[vi[1]];
3523 n = ON_CrossProduct( a, b ); // works for triangles, quads, and nonplanar quads
3524 n.Unitize();
3525 m_FN.Append(n);
3526 }
3527 }
3528 else
3529 {
3530 for ( fi = 0; fi < fcount; fi++ ) {
3531 vi = m_F[fi].vi;
3532 a = m_V[vi[2]] - m_V[vi[0]];
3533 b = m_V[vi[3]] - m_V[vi[1]];
3534 n = ON_CrossProduct( a, b ); // works for triangles, quads, and nonplanar quads
3535 n.Unitize();
3536 m_FN.Append(n);
3537 }
3538 }
3539 }
3540 else
3541 {
3542 m_FN.Destroy();
3543 }
3544 return rc;
3545 }
3546
3547
3548 //static int compareRadial3fPoint( const ON_3fPoint* a, const ON_3fPoint* b )
3549 //{
3550 // double ar = a->x+a->y+a->z;
3551 // double br = b->x+b->y+b->z;
3552 // if ( ar < br )
3553 // return -1;
3554 // if ( ar > br )
3555 // return 1;
3556 // return 0;
3557 //}
3558
CombineCoincidentVertices(const ON_3fVector,double)3559 bool ON_Mesh::CombineCoincidentVertices(
3560 const ON_3fVector /*tolerance*/,
3561 double //cos_normal_angle // = -1.0 // cosine(break angle) -1.0 will merge all coincident vertices
3562 )
3563 {
3564 // TODO - If you need this function, please ask Dale Lear to finish it.
3565 //bool rc = false;
3566 //const int vcount = VertexCount();
3567 //if ( vcount > 0 && rc ) {
3568 // ON_Workspace ws;
3569 // int* index = ws.GetIntMemory(vcount);
3570 // rc = m_V.Sort( ON::quick_sort, index, compareRadial3fPoint );
3571 // int i, j;
3572 // ON_3fPoint p0, p1, pmin, pmax;
3573 // for ( i = 0; i < vcount; i++ ) {
3574 // p0 = m_V[i];
3575 // pmin = p0 - tolerance;
3576 // pmax = p0 + tolerance;
3577 // for ( j = i+1; j < vcount; j++ ) {
3578 // p1 = m_V[j];
3579 // // TODO
3580 // }
3581 // }
3582 //}
3583 return false;
3584 }
3585
3586
3587 struct tagMESHPOINTS
3588 {
3589 // p0 = bogus pointer - never dereferenced - that is used
3590 // to calculate vertex index in CompareMeshPoint().
3591 const char* p0;
3592 ON_3fPoint* V;
3593 ON_2fPoint* T;
3594 ON_3fVector* N;
3595 ON_SurfaceCurvature* K;
3596 ON_Color* C;
3597 };
3598
CompareMeshPoint(const void * a,const void * b,void * ptr)3599 static int CompareMeshPoint(const void* a,const void* b,void* ptr)
3600 {
3601 float d;
3602 const struct tagMESHPOINTS * mp = (const struct tagMESHPOINTS *)ptr;
3603
3604 // use bogus pointer to convert a,b into vertex indices
3605 int i = (int)(((const char*)a) - mp->p0); // the (int) is for 64 bit std::size_t conversion
3606 int j = (int)(((const char*)b) - mp->p0);
3607
3608 d = mp->V[j].x - mp->V[i].x;
3609 if ( d == 0.0f )
3610 {
3611 d = mp->V[j].y - mp->V[i].y;
3612 if ( d == 0.0f )
3613 {
3614 d = mp->V[j].z - mp->V[i].z;
3615
3616 //if ( d == 0.0f )
3617 // return 0;
3618
3619 if ( d == 0.0f && 0 != mp->N)
3620 {
3621 d = mp->N[j].x - mp->N[i].x;
3622 if ( d == 0.0f )
3623 {
3624 d = mp->N[j].y - mp->N[i].y;
3625 if ( d == 0.0f )
3626 {
3627 d = mp->N[j].z - mp->N[i].z;
3628 }
3629 }
3630 }
3631
3632 if ( d == 0.0f && 0 != mp->T)
3633 {
3634 d = mp->T[j].x - mp->T[i].x;
3635 if ( d == 0.0f )
3636 {
3637 d = mp->T[j].y - mp->T[i].y;
3638 }
3639 }
3640
3641 if ( d == 0.0f && 0 != mp->C )
3642 {
3643 int u = ((int)mp->C[j])-((int)mp->C[i]);
3644 if ( u < 0 )
3645 d = -1.0f;
3646 else if ( u > 0 )
3647 d = 1.0f;
3648 }
3649
3650 if ( d == 0.0f && 0 != mp->K )
3651 {
3652 double dk = mp->K[j].k1 - mp->K[i].k1;
3653 if ( dk < 0.0 )
3654 d = -1.0;
3655 else if ( dk > 0.0 )
3656 d = 1.0;
3657 else
3658 {
3659 dk = mp->K[j].k2 - mp->K[i].k2;
3660 if ( dk < 0.0 )
3661 d = -1.0;
3662 else if ( dk > 0.0 )
3663 d = 1.0;
3664 }
3665 }
3666 }
3667 }
3668
3669 if ( d < 0.0f )
3670 return -1;
3671 if ( d > 0.0f )
3672 return 1;
3673 return 0;
3674 }
3675
CombineIdenticalVertices(bool bIgnoreVertexNormals,bool bIgnoreTextureCoordinates)3676 bool ON_Mesh::CombineIdenticalVertices(
3677 bool bIgnoreVertexNormals,
3678 bool bIgnoreTextureCoordinates
3679 )
3680 {
3681 // 11 June 2003 - added and tested.
3682 bool rc = false;
3683 ON_Mesh& mesh = *this;
3684
3685 int vertex_count = mesh.VertexCount();
3686 if ( vertex_count > 0 )
3687 {
3688 ON_SimpleArray<int> index_array(vertex_count);
3689 ON_SimpleArray<int> remap_array(vertex_count);
3690
3691 int remap_vertex_count = 0;
3692 int merge_count = 0;
3693 int i0, i1, k;
3694
3695 struct tagMESHPOINTS mp;
3696 memset(&mp,0,sizeof(mp));
3697 mp.p0 = (const char*)∓ // bogus pointer - never dereferenced
3698 mp.V = mesh.m_V.Array();
3699 mp.N = mesh.HasVertexNormals() ? mesh.m_N.Array() : 0;
3700 mp.T = mesh.HasTextureCoordinates() ? mesh.m_T.Array() : 0;
3701 mp.C = mesh.HasVertexColors() ? mesh.m_C.Array() : 0;
3702 mp.K = mesh.HasPrincipalCurvatures() ? mesh.m_K.Array() : 0;
3703
3704 if ( bIgnoreVertexNormals )
3705 {
3706 mp.N = 0;
3707 }
3708
3709 if ( bIgnoreTextureCoordinates )
3710 {
3711 mp.T = 0;
3712 mp.C = 0;
3713 mp.K = 0;
3714 }
3715
3716 index_array.SetCount(vertex_count);
3717 index_array.Zero();
3718 int* index = index_array.Array();
3719
3720 remap_array.SetCount(vertex_count);
3721 int* remap = remap_array.Array();
3722 for ( k = 0; k < vertex_count; k++ )
3723 remap[k] = -1;
3724
3725 ON_Sort(
3726 ON::quick_sort,
3727 index,
3728 mp.p0, // data buffer
3729 vertex_count,
3730 sizeof(*mp.p0),
3731 CompareMeshPoint,
3732 &mp
3733 );
3734
3735 for ( i0 = 0; i0 < vertex_count; i0 = i1 )
3736 {
3737 for ( i1 = i0+1; i1 < vertex_count; i1++ )
3738 {
3739 if ( CompareMeshPoint( mp.p0+index[i0], mp.p0+index[i1], &mp ) )
3740 break;
3741 else
3742 merge_count++;
3743 }
3744 for ( /*empty*/; i0 < i1; i0++ )
3745 {
3746 remap[index[i0]] = remap_vertex_count;
3747 }
3748 remap_vertex_count++;
3749 }
3750
3751 if ( bIgnoreVertexNormals )
3752 {
3753 mp.N = mesh.HasVertexNormals() ? mesh.m_N.Array() : 0;
3754 }
3755
3756 if ( bIgnoreTextureCoordinates )
3757 {
3758 mp.T = mesh.HasTextureCoordinates() ? mesh.m_T.Array() : 0;
3759 mp.C = mesh.HasVertexColors() ? mesh.m_C.Array() : 0;
3760 mp.K = mesh.HasPrincipalCurvatures() ? mesh.m_K.Array() : 0;
3761 }
3762
3763 if ( remap_vertex_count > 0 && remap_vertex_count < vertex_count )
3764 {
3765 ON_SimpleArray<ON_3fPoint> p_array(remap_vertex_count);
3766 p_array.SetCount(remap_vertex_count);
3767 ON_3fPoint* p = p_array.Array();
3768 ON_3fVector* v = (ON_3fVector*)p;
3769
3770 for ( k = 0; k < vertex_count; k++ )
3771 {
3772 p[remap[k]] = mp.V[k];
3773 }
3774 for ( k = 0; k < remap_vertex_count; k++ )
3775 mp.V[k] = p[k];
3776 mesh.m_V.SetCount(remap_vertex_count);
3777
3778 if ( 0 != mp.N )
3779 {
3780 if ( bIgnoreVertexNormals )
3781 {
3782 // average vertex normals of combined vertices
3783 p_array.Zero();
3784 for ( k = 0; k < vertex_count; k++ )
3785 {
3786 v[remap[k]] += mp.N[k];
3787 }
3788 for ( k = 0; k < remap_vertex_count; k++ )
3789 {
3790 v[k].Unitize();
3791 }
3792 }
3793 else
3794 {
3795 for ( k = 0; k < vertex_count; k++ )
3796 {
3797 v[remap[k]] = mp.N[k];
3798 }
3799 }
3800 for ( k = 0; k < remap_vertex_count; k++ )
3801 mp.N[k] = v[k];
3802 mesh.m_N.SetCount(remap_vertex_count);
3803 }
3804 else
3805 mesh.m_N.SetCount(0);
3806
3807 if ( 0 != mp.T && !bIgnoreTextureCoordinates )
3808 {
3809 for ( k = 0; k < vertex_count; k++ )
3810 {
3811 p[remap[k]] = mp.T[k];
3812 }
3813 for ( k = 0; k < remap_vertex_count; k++ )
3814 mp.T[k] = p[k];
3815 mesh.m_T.SetCount(remap_vertex_count);
3816 }
3817 else
3818 mesh.m_T.SetCount(0);
3819
3820 if ( 0 != mp.C && !bIgnoreTextureCoordinates )
3821 {
3822 ON_SimpleArray<ON_Color> c_array(remap_vertex_count);
3823 c_array.SetCount(remap_vertex_count);
3824 ON_Color* c = c_array.Array();
3825 for ( k = 0; k < vertex_count; k++ )
3826 {
3827 c[remap[k]] = mp.C[k];
3828 }
3829 for ( k = 0; k < remap_vertex_count; k++ )
3830 mp.C[k] = c[k];
3831 mesh.m_C.SetCount(remap_vertex_count);
3832 }
3833 else
3834 mesh.m_C.SetCount(0);
3835
3836 if ( 0 != mp.K && !bIgnoreTextureCoordinates )
3837 {
3838 ON_SimpleArray<ON_SurfaceCurvature> s_array(remap_vertex_count);
3839 s_array.SetCount(remap_vertex_count);
3840 ON_SurfaceCurvature* s = s_array.Array();
3841 for ( k = 0; k < vertex_count; k++ )
3842 {
3843 s[remap[k]] = mp.K[k];
3844 }
3845 for ( k = 0; k < remap_vertex_count; k++ )
3846 mp.K[k] = s[k];
3847 mesh.m_K.SetCount(remap_vertex_count);
3848 }
3849 else
3850 mesh.m_K.SetCount(0);
3851
3852 const int face_count = mesh.m_F.Count();
3853 ON_MeshFace* f = mesh.m_F.Array();
3854 int* fvi;
3855 for ( k = 0; k < face_count; k++ )
3856 {
3857 fvi = f[k].vi;
3858 fvi[0] = remap[fvi[0]];
3859 fvi[1] = remap[fvi[1]];
3860 fvi[2] = remap[fvi[2]];
3861 fvi[3] = remap[fvi[3]];
3862 }
3863
3864 if (0 != NgonList())
3865 {
3866 //This mesh has an ngon list.
3867 //Modify the vertex indexes in the ngons as
3868 //we did the faces above
3869 ON_MeshNgonList* ngonlist = ModifyNgonList();
3870 int kk, kkct = ngonlist->NgonCount();
3871 for (kk = 0; kk < kkct; kk++)
3872 {
3873 ON_MeshNgon* ngon = ngonlist->Ngon(kk);
3874 if (0 == ngon)
3875 continue;
3876 for ( k = 0; k < ngon->N; k++ )
3877 ngon->vi[k] = remap[ngon->vi[k]];
3878 }
3879 }
3880
3881 mesh.DestroyPartition();
3882 mesh.DestroyTopology();
3883
3884 if ( mesh.m_V.Capacity() > 4*mesh.m_V.Count() && mesh.m_V.Capacity() > 50 )
3885 {
3886 // There is lots of unused memory in the dynamic arrays.
3887 // Release what we can.
3888 mesh.Compact();
3889 }
3890 rc = true;
3891 }
3892 }
3893 return rc;
3894 }
3895
Append(int mesh_count,const ON_Mesh * const * meshes)3896 void ON_Mesh::Append( int mesh_count, const ON_Mesh* const* meshes )
3897 {
3898 if ( mesh_count <= 0 || 0 == meshes )
3899 return;
3900
3901 int mi;
3902 int vcount0 = VertexCount();
3903 if ( vcount0 <= 0 )
3904 m_F.SetCount(0);
3905 int fcount0 = FaceCount();
3906 int* vi;
3907 int j;
3908 const ON_Mesh* m;
3909
3910 // The calls to Has*() must happen before the m_V[] and m_F[] arrays get enlarged
3911 // Allow the appendage of VertexNormals, TextureCoordinates, PrincipalCurvatures to empty meshes
3912 // by checking for 0 == vcount0 && 0 == fcount0
3913 bool bHasVertexNormals = (0 == vcount0 || HasVertexNormals());
3914 bool bHasFaceNormals = (0 == vcount0 || 0 == fcount0 || HasFaceNormals());
3915 bool bHasTextureCoordinates = (0 == vcount0 || HasTextureCoordinates());
3916 bool bHasPrincipalCurvatures = (0 == vcount0 || HasPrincipalCurvatures());
3917 bool bHasVertexColors = (0 == vcount0 || HasVertexColors());
3918 bool bHasSurfaceParameters = (0 == vcount0 || HasSurfaceParameters());
3919 bool bHasDoubles = (0 == vcount0 || HasSynchronizedDoubleAndSinglePrecisionVertices());
3920
3921 int fcount = fcount0;
3922 int vcount = vcount0;
3923 for ( mi = 0; mi < mesh_count; mi++ )
3924 {
3925 m = meshes[mi];
3926 if ( 0 == m )
3927 continue;
3928 int vcount1 = m->m_V.Count();
3929 if ( vcount1 <= 0 )
3930 continue;
3931 int fcount1 = m->m_F.Count();
3932 if ( fcount1 > 0 )
3933 fcount += fcount1;
3934 vcount += vcount1;
3935 if ( bHasVertexNormals && !m->HasVertexNormals() )
3936 bHasVertexNormals = false;
3937 if ( bHasTextureCoordinates && !m->HasTextureCoordinates())
3938 bHasTextureCoordinates = false;
3939 if ( bHasPrincipalCurvatures && !m->HasPrincipalCurvatures())
3940 bHasPrincipalCurvatures = false;
3941 if ( bHasVertexColors && !m->HasVertexColors())
3942 bHasVertexColors = false;
3943 if ( bHasSurfaceParameters && !m->HasSurfaceParameters())
3944 bHasSurfaceParameters = false;
3945 if ( bHasDoubles && !m->HasSynchronizedDoubleAndSinglePrecisionVertices())
3946 bHasDoubles = false;
3947 if ( bHasFaceNormals && fcount1 > 0 && !m->HasFaceNormals() )
3948 bHasFaceNormals = false;
3949 }
3950
3951 if ( vcount <= vcount0 && fcount <= fcount0 )
3952 return;
3953
3954 m_top.Destroy();
3955
3956 // It is critical to call DoublePrecisionVertices() before
3957 // we modify m_V[] because DoublePrecisionVertices() will
3958 // attempt to update the double precision information
3959 // when it notices that m_V has new vertices added.
3960 ON_MeshDoubleVertices* dv = 0;
3961 if ( bHasDoubles )
3962 {
3963 dv = ON_MeshDoubleVertices::Get(this);
3964 if ( 0 == dv && 0 == m_V.Count() )
3965 {
3966 DoublePrecisionVertices(); // creates ON_MeshDoubleVertices info on "this"
3967 dv = ON_MeshDoubleVertices::Get(this);
3968 }
3969 if ( 0 == dv )
3970 bHasDoubles = false;
3971 }
3972
3973 m_V.Reserve(vcount);
3974 m_F.Reserve(fcount);
3975 for (mi = 0; mi < mesh_count; mi++ )
3976 {
3977 m = meshes[mi];
3978 if ( 0 == m )
3979 continue;
3980 int vcount1 = m->m_V.Count();
3981 if ( vcount1 <= 0 )
3982 continue;
3983 int fcount1 = m->m_F.Count();
3984 if ( fcount1 > 0 )
3985 {
3986 int vc0 = m_V.Count();
3987 j = m_F.Count();
3988 m_F.Append(fcount1,m->m_F.Array());
3989 fcount1 += j;
3990 while (j < fcount1)
3991 {
3992 vi = m_F[j].vi;
3993 vi[0] += vc0;
3994 vi[1] += vc0;
3995 vi[2] += vc0;
3996 vi[3] += vc0;
3997 j++;
3998 }
3999 }
4000 m_V.Append(vcount1,m->m_V.Array());
4001 }
4002
4003 if ( bHasDoubles)
4004 {
4005 // Now update the double precision vertex locations.
4006 dv->m_dV.Reserve(vcount);
4007 for (mi = 0; mi < mesh_count; mi++ )
4008 {
4009 m = meshes[mi];
4010 if ( 0 == m || m->m_V.Count() <= 0 )
4011 continue;
4012 ON_MeshDoubleVertices* dv1 = ON_MeshDoubleVertices::Get(m);
4013 if ( 0 == dv1 )
4014 break;
4015 dv->m_dV.Append(dv1->m_dV.Count(),dv1->m_dV.Array());
4016 }
4017 if ( dv->m_dV.Count() == vcount )
4018 {
4019 // The calculation of the CRCs in the following calls
4020 // is what slows down appending meshes one-by-one
4021 // when thousands of meshes are being appended.
4022 // That's why the code is structured to do the calculation
4023 // a single time here.
4024 SetSinglePrecisionVerticesAsValid();
4025 SetDoublePrecisionVerticesAsValid();
4026 }
4027 else
4028 {
4029 DestroyDoublePrecisionVertices();
4030 }
4031 }
4032 else
4033 {
4034 DestroyDoublePrecisionVertices();
4035 }
4036
4037
4038 if ( bHasVertexNormals )
4039 {
4040 m_N.Reserve(vcount);
4041 for (mi = 0; mi < mesh_count; mi++ )
4042 {
4043 m = meshes[mi];
4044 if ( 0 == m )
4045 continue;
4046 m_N.Append(m->m_N.Count(), m->m_N.Array());
4047 }
4048 }
4049 else
4050 {
4051 m_N.Destroy();
4052 }
4053
4054
4055 if ( bHasFaceNormals )
4056 {
4057 m_FN.Reserve(fcount);
4058 for (mi = 0; mi < mesh_count; mi++ )
4059 {
4060 m = meshes[mi];
4061 if ( 0 == m || m->m_V.Count() <= 0 )
4062 continue;
4063 m_FN.Append(m->m_FN.Count(), m->m_FN.Array());
4064 }
4065 }
4066 else
4067 {
4068 m_FN.Destroy();
4069 }
4070
4071 if ( bHasTextureCoordinates )
4072 {
4073 m_T.Reserve(vcount);
4074 for (mi = 0; mi < mesh_count; mi++ )
4075 {
4076 m = meshes[mi];
4077 if ( 0 == m )
4078 continue;
4079 m_T.Append(m->m_T.Count(), m->m_T.Array());
4080 }
4081 }
4082 else
4083 {
4084 m_T.Destroy();
4085 }
4086
4087
4088 if ( bHasSurfaceParameters )
4089 {
4090 m_S.Reserve(vcount);
4091 for (mi = 0; mi < mesh_count; mi++ )
4092 {
4093 m = meshes[mi];
4094 if ( 0 == m )
4095 continue;
4096 m_S.Append(m->m_S.Count(), m->m_S.Array());
4097 }
4098 }
4099 else
4100 {
4101 m_S.Destroy();
4102 }
4103
4104 if ( bHasPrincipalCurvatures )
4105 {
4106 m_K.Reserve(vcount);
4107 for (mi = 0; mi < mesh_count; mi++ )
4108 {
4109 m = meshes[mi];
4110 if ( 0 == m )
4111 continue;
4112 m_K.Append(m->m_K.Count(), m->m_K.Array());
4113 }
4114 }
4115 else
4116 {
4117 m_K.Destroy();
4118 }
4119
4120 if ( bHasVertexColors )
4121 {
4122 m_C.Reserve(vcount);
4123 for (mi = 0; mi < mesh_count; mi++ )
4124 {
4125 m = meshes[mi];
4126 if ( 0 == m )
4127 continue;
4128 m_C.Append(m->m_C.Count(), m->m_C.Array());
4129 }
4130 }
4131 else
4132 {
4133 m_C.Destroy();
4134 }
4135
4136 if ( 0 != m_mesh_parameters )
4137 {
4138 for (mi = 0; mi < mesh_count; mi++ )
4139 {
4140 m = meshes[mi];
4141 if ( 0 == m )
4142 continue;
4143 if ( 0 == m->m_mesh_parameters || *m_mesh_parameters != *m->m_mesh_parameters )
4144 {
4145 delete m_mesh_parameters;
4146 m_mesh_parameters = 0;
4147 break;
4148 }
4149 }
4150 }
4151
4152 for ( j = 0; j < 4; j++ )
4153 {
4154 if ( m_kstat[j] )
4155 {
4156 // will be recomputed if required
4157 delete m_kstat[j];
4158 m_kstat[j] = 0;
4159 }
4160 }
4161
4162 SetClosed(-99);
4163 SetSolidOrientation(-99);
4164 InvalidateBoundingBoxes();
4165 }
4166
Append(const ON_Mesh & m)4167 void ON_Mesh::Append( const ON_Mesh& m )
4168 {
4169 const ON_Mesh* meshes[1];
4170 meshes[0] = &m;
4171 Append(1,meshes);
4172 }
4173
ON_MeshParameters()4174 ON_MeshParameters::ON_MeshParameters()
4175 {
4176 Default();
4177 }
4178
~ON_MeshParameters()4179 ON_MeshParameters::~ON_MeshParameters()
4180 {
4181 }
4182
MinEdgeLength(double max_edge_length,double tolerance)4183 double ON_MeshParameters::MinEdgeLength( double max_edge_length, double tolerance )
4184 {
4185 // The 1.0e-4 is a guess. 1.0e-12 was too small to help with objects
4186 // like the one in 67885.
4187 double min_edge_length = 1.0e-4;
4188 if ( max_edge_length > 0.0 && min_edge_length > 1.0e-3*max_edge_length )
4189 min_edge_length = 1.0e-3*max_edge_length;
4190 if ( tolerance > 0.0 && min_edge_length > 1.0e-2*tolerance )
4191 min_edge_length = 1.0e-2*tolerance;
4192 return min_edge_length;
4193 }
4194
Tolerance(double density,double actual_size)4195 double ON_MeshParameters::Tolerance( double density, double actual_size )
4196 {
4197 // min_rel_tol creates the most facets
4198 //const double min_rel_tol = 5.0e-5;
4199
4200 //max rel tol creates the fewest facets
4201 //const double max_rel_tol = 0.1;
4202 //m_relative_tolerance = 0.0;
4203 //if ( density <= 0.0 )
4204 // m_relative_tolerance = max_rel_tol;
4205 //else if ( density >= 1.0 )
4206 // m_relative_tolerance = min_rel_tol;
4207 //else
4208 //{
4209 // ON_Interval e(log10(max_rel_tol),log10(min_rel_tol));
4210 // m_relative_tolerance = pow(10.0,e.ParameterAt(density));
4211 //}
4212
4213 double tol = 0.0;
4214 double x, e;
4215 if ( ON_IsValid(density) && ON_IsValid(actual_size)
4216 && density > 0.0 && actual_size > 0.0 )
4217 {
4218 if ( density > 1.0 )
4219 density = 1.0;
4220
4221 //e = (density*(12.0 + density*(2.0*density - 9.0)));
4222 //e = (1.0 + density*(8.0 - 4.0*density));
4223 //e = 1.0 + density*4.0;
4224 //x = 5.0*pow(10.0,-e);
4225
4226 e = (density < 0.5)
4227 ? 1.0 + density*(6.0 - 4.0*density) // 1.0 + 4.0*density
4228 : 2.0 + 2.0*density;
4229 x = pow(10.0,-e);
4230
4231 tol = actual_size*x;
4232 }
4233 return tol;
4234 }
4235
FastRenderMeshParameters()4236 static ON_MeshParameters FastRenderMeshParameters()
4237 {
4238 // If you change these, put your name, the date, and the reasons for
4239 // the change in this comment so we can keep track of what we are
4240 // trying to accomplish;
4241 ON_MeshParameters mp;
4242
4243 // Added 27 April 2006 for the Meshkateers
4244 // Attempting to make jagged and faster render meshes a little
4245 // more dense.
4246 //
4247 // Turn off everything ...
4248 mp.m_bComputeCurvature = false;
4249 mp.m_tolerance = 0.0;
4250 mp.m_bJaggedSeams = false;
4251 mp.m_max_edge_length = 0.0;
4252 mp.m_grid_aspect_ratio = 0.0;
4253 mp.m_grid_max_count = 0;
4254 mp.m_grid_angle = 0.0;
4255 mp.m_grid_amplification = 0.0;
4256 mp.m_refine_angle = 0.0;
4257
4258 // ... except ...
4259 // The m_relative_tolerance setting must be set so that
4260 // 0.0005 = ON_MeshParameters::Tolerance(m_relative_tolerance,1.0).
4261 mp.m_relative_tolerance = 0.65;
4262 //double x = Tolerance(m_relative_tolerance,1.0);
4263
4264 mp.m_grid_min_count = 16;
4265 mp.m_min_edge_length = 0.0001;
4266 mp.m_bRefine = true;
4267 mp.m_bSimplePlanes = true;
4268
4269 mp.m_texture_range = 2; // Don't change this without speaking to Dale Lear
4270
4271 //{
4272 // // 16 July, 2002 - copied V2 hard coded "jagged and faster" render mesh settings
4273 // //
4274 // // Settings used in V2, V3 and early V4 beta
4275 // mp.m_refine_angle = 20.0*ON_PI/180.0;
4276 // mp.m_grid_angle = 20.0*ON_PI/180.0;
4277 // mp.m_grid_aspect_ratio = 0.0;
4278 // mp.m_min_edge_length = 0.0001;
4279 // mp.m_max_edge_length = 0.0;
4280 // mp.m_tolerance = 0.0;
4281 // mp.m_grid_min_count = 16;
4282 // mp.m_bRefine = 1;
4283 // mp.m_bJaggedSeams = 0;
4284 // mp.m_bSimplePlanes = 0;
4285 //}
4286
4287 return mp;
4288 }
4289
QualityRenderMeshParameters()4290 static ON_MeshParameters QualityRenderMeshParameters()
4291 {
4292 // If you change these, put your name, the date, and the reasons for
4293 // the change in this comment so we can keep track of what we are
4294 // trying to accomplish;
4295 ON_MeshParameters mp;
4296
4297 // Added 27 April 2006 for the Meshkateers
4298 // Attempting to make smooth and slower render meshing a little
4299 // faster.
4300 //
4301 // Turn off everything ...
4302 mp.m_bComputeCurvature = false;
4303 mp.m_tolerance = 0.0;
4304 mp.m_bJaggedSeams = false;
4305 mp.m_max_edge_length = 0.0;
4306 mp.m_grid_aspect_ratio = 0.0;
4307 mp.m_grid_max_count = 0;
4308 mp.m_grid_angle = 0.0;
4309 mp.m_grid_amplification = 0.0;
4310
4311 // ... except ...
4312 // The m_relative_tolerance setting must be set so that
4313 // 0.00025 = ON_MeshParameters::Tolerance(m_relative_tolerance,1.0).
4314 mp.m_relative_tolerance = 0.8;
4315 //double x = Tolerance(m_relative_tolerance,1.0);
4316
4317 mp.m_grid_min_count = 16;
4318 mp.m_min_edge_length = 0.0001;
4319 mp.m_bRefine = true;
4320 mp.m_bSimplePlanes = true;
4321 mp.m_refine_angle = 20.0*ON_PI/180.0;
4322
4323 mp.m_texture_range = 2; // Don't change this without speaking to Dale Lear
4324
4325
4326 //// 16 July, 2002 - copied V2 hard coded "smooth and slower" render mesh settings
4327 ////
4328 //// Settings used in V2, V3 and early V4 beta
4329 //mp.m_refine_angle = 15.0*ON_PI/180.0;
4330 //mp.m_grid_angle = 15.0*ON_PI/180.0;
4331 //mp.m_grid_aspect_ratio = 6.0;
4332 //mp.m_min_edge_length = 0.0001;
4333 //mp.m_max_edge_length = 0.0;
4334 //mp.m_tolerance = 0.0;
4335 //mp.m_grid_min_count = 16;
4336 //mp.m_bRefine = 1;
4337 //mp.m_bJaggedSeams = 0;
4338 //mp.m_bSimplePlanes = 0;
4339
4340 return mp;
4341 }
4342
4343 const ON_MeshParameters ON_MeshParameters::FastRenderMesh(FastRenderMeshParameters());
4344
4345 const ON_MeshParameters ON_MeshParameters::QualityRenderMesh(QualityRenderMeshParameters());
4346
JaggedAndFasterMeshParameters()4347 void ON_MeshParameters::JaggedAndFasterMeshParameters()
4348 {
4349 *this = ON_MeshParameters::FastRenderMesh;
4350 }
4351
SmoothAndSlowerMeshParameters()4352 void ON_MeshParameters::SmoothAndSlowerMeshParameters()
4353 {
4354 *this = ON_MeshParameters::QualityRenderMesh;
4355 }
4356
DefaultAnalysisMeshParameters()4357 void ON_MeshParameters::DefaultAnalysisMeshParameters()
4358 {
4359 Default();
4360
4361 // 7 July 2006 Dale Lear
4362 // I added this line for RR 10330
4363 Set( 0.5, m_min_edge_length );
4364
4365 m_texture_range = 1; // THIS IS REQUIRED - DO NOT CHANGE IT
4366
4367 // Meshkateers
4368 // Add your stuff below this line.
4369 // Do not change m_texture_range.
4370 }
4371
operator ==(const ON_MeshParameters & m2) const4372 bool ON_MeshParameters::operator==(const ON_MeshParameters& m2) const
4373 {
4374 return (Compare(m2)==0) ? true : false;
4375 }
4376
operator !=(const ON_MeshParameters & m2) const4377 bool ON_MeshParameters::operator!=(const ON_MeshParameters& m2) const
4378 {
4379 return (Compare(m2)) ? true : false;
4380 }
4381
operator ==(const ON_Mesh & mesh) const4382 bool ON_MeshParameters::operator==(const ON_Mesh& mesh) const
4383 {
4384 const ON_MeshParameters* mp1 = mesh.MeshParameters();
4385 return mp1 ? (*this == *mp1) : false;
4386 }
4387
operator !=(const ON_Mesh & mesh) const4388 bool ON_MeshParameters::operator!=(const ON_Mesh& mesh) const
4389 {
4390 const ON_MeshParameters* mp1 = mesh.MeshParameters();
4391 return mp1 ? (*this != *mp1) : true;
4392 }
4393
Dump(ON_TextLog & text_log) const4394 void ON_MeshParameters::Dump( ON_TextLog& text_log ) const
4395 {
4396 text_log.Print("Gridding:\n");
4397 text_log.PushIndent();
4398 text_log.Print("Min grid count = %d\n",m_grid_min_count);
4399 text_log.Print("Max grid count = %d\n",m_grid_max_count);
4400 text_log.Print("Gridding angle = %g radians (%g degrees)\n",m_grid_angle,180.0*m_grid_angle/ON_PI);
4401 text_log.Print("Aspect ratio = %g\n",m_grid_aspect_ratio);
4402 text_log.Print("Amplification = %g\n",m_grid_amplification);
4403 text_log.PopIndent();
4404
4405 text_log.Print("Refining:\n");
4406 text_log.PushIndent();
4407 text_log.Print("Refine = %s\n",m_bRefine?"true":"false");
4408 text_log.Print("Refine angle = %g radians (%g degrees)\n",m_refine_angle,180.0*m_refine_angle/ON_PI);
4409 text_log.PopIndent();
4410
4411 text_log.Print("Metrics:\n");
4412 text_log.PushIndent();
4413 text_log.Print("Density = %g (relative tolerance = %g)\n",m_relative_tolerance,ON_MeshParameters::Tolerance(m_relative_tolerance,1.0));
4414 text_log.Print("Minimum tolerance = %g\n",m_min_tolerance);
4415 text_log.Print("Tolerance = %g\n",m_tolerance);
4416 text_log.Print("Min edge length = %g\n",m_min_edge_length);
4417 text_log.Print("Max edge length = %g\n",m_max_edge_length);
4418 text_log.PopIndent();
4419
4420 text_log.Print("Misceleanous:\n");
4421 text_log.PushIndent();
4422 text_log.Print("Face type = %d\n",m_face_type );
4423 text_log.Print("Compute curvature = %s\n",m_bComputeCurvature?"true":"false");
4424 text_log.Print("Texture range = %d\n",m_texture_range);
4425 text_log.Print("Simple planes = %s\n",m_bSimplePlanes?"true":"false");
4426 text_log.Print("Jagged Seams = %s\n",m_bJaggedSeams?"true":"false");
4427 text_log.Print("Double Precision = %s\n",m_bDoublePrecision?"true":"false");
4428 text_log.Print("Custom settings = %s\n",m_bCustomSettings?"true":"false");
4429 text_log.PopIndent();
4430 }
4431
Default()4432 void ON_MeshParameters::Default()
4433 {
4434 memset(this,0,sizeof(*this));
4435
4436 m_bCustomSettings = false;
4437 m_bComputeCurvature = false;
4438 m_bSimplePlanes = false;
4439 m_bRefine = true;
4440 m_bJaggedSeams = false;
4441 m_bDoublePrecision = false;
4442 m_bCustomSettingsEnabled = true;
4443 m_mesher = 0;
4444 m_texture_range = 2; // packed normalized textures
4445 m_reserved2 = 0;
4446 m_tolerance = 0.0;
4447 m_relative_tolerance = 0.0;
4448 m_min_tolerance = 0.0;
4449 m_min_edge_length = 0.0001;
4450 m_max_edge_length = 0.0;
4451 m_grid_aspect_ratio = 6.0;
4452 m_grid_min_count = 0;
4453 m_grid_max_count = 0;
4454 m_grid_angle = 20.0*ON_PI/180.0;
4455 m_grid_amplification = 1.0;
4456 m_refine_angle = 20.0*ON_PI/180.0;
4457 m_face_type = 0;
4458 m_reserved3 = 0;
4459 }
4460
Set(double density,double min_edge_length)4461 void ON_MeshParameters::Set( double density, double min_edge_length )
4462 {
4463 bool bRelTolTest = true;
4464
4465 Default();
4466
4467 // These 4 settings should not be changed
4468 m_bComputeCurvature = false;
4469 m_min_edge_length = min_edge_length;
4470 m_texture_range = 0;
4471 m_tolerance = 0.0;
4472
4473 if ( bRelTolTest )
4474 {
4475 // Added 27 April 2005
4476 m_relative_tolerance = density;
4477
4478 // The other meshing parameters are disabled.
4479 //
4480 // Dale Lear's remark:
4481 // I think it is a mistake to leave m_grid_aspect_ratio = 0
4482 // at all settings. This will result in long skinny triangles
4483 // in areas where the principal curvatures are dramatically
4484 // different.
4485 //
4486 m_bRefine = (density < 0.65);
4487 m_bSimplePlanes = (density <= 0.0);
4488 m_bJaggedSeams = false;
4489 m_max_edge_length = 0.0;
4490 m_grid_aspect_ratio = 0.0;
4491 m_grid_min_count = 0;
4492 m_grid_max_count = 0;
4493 m_grid_angle = 0.0;
4494 m_grid_amplification = 0.0;
4495 m_refine_angle = 0.0;
4496 }
4497 else
4498 {
4499 // Used in V3 and prior to 27 April 2005
4500 double t0, t1;
4501
4502 m_bRefine = true;
4503 m_bSimplePlanes = false;
4504 m_bJaggedSeams = false;
4505 m_max_edge_length = 0.0;
4506 m_grid_aspect_ratio = 0.0;
4507 m_grid_min_count = 16;
4508 m_grid_max_count = 0;
4509 m_grid_angle = 20.0*ON_PI/180.0;
4510 m_grid_amplification = 1.0;
4511 m_refine_angle = 20.0*ON_PI/180.0;
4512
4513 if ( density <= 0.0)
4514 {
4515 m_bSimplePlanes = true;
4516 m_bRefine = false;
4517
4518 m_grid_min_count = 0;
4519 m_grid_aspect_ratio = 0.0;
4520 m_grid_angle = 0.0;
4521 m_grid_amplification = 1.0;
4522
4523 m_refine_angle = m_grid_angle;
4524 }
4525 else if ( density < 0.5)
4526 {
4527 t1 = 2.0*density;
4528 t0 = 1.0-t1;
4529
4530 m_bRefine = density < 0.10 ? false : true;
4531
4532 m_grid_min_count = 0;
4533 m_grid_aspect_ratio = 6.0;
4534 m_grid_angle = 20.0*ON_PI/180.0;
4535 m_grid_amplification = (t1 > 0.0 ) ? t1 : 1.0;
4536
4537 m_refine_angle = (t0*65.0 + t1*20.0)*ON_PI/180.0;
4538 }
4539 else if ( density == 0.5 )
4540 {
4541 m_bRefine = true;
4542
4543 m_grid_min_count = 0;
4544 m_grid_aspect_ratio = 6.0;
4545 m_grid_angle = 20.0*ON_PI/180.0;
4546 m_grid_amplification = 1.0;
4547
4548 m_refine_angle = m_grid_angle;
4549 }
4550 else
4551 {
4552 t1 = 2.0*(density - 0.5);
4553 if ( t1 > 1.0 )
4554 t1 = 1.0;
4555 t0 = 1.0-t1;
4556
4557 m_bRefine = true;
4558
4559 m_grid_min_count = 0;
4560 m_grid_aspect_ratio = t0*6.0 + t1;
4561 m_grid_angle = (t0*20.0 + t1*5.0)*ON_PI/180.0;
4562 m_grid_amplification = 1.0 + t1;
4563
4564 m_refine_angle = m_grid_angle;
4565 }
4566 }
4567 }
4568
4569
Compare(const ON_MeshParameters & src) const4570 int ON_MeshParameters::Compare( const ON_MeshParameters& src ) const
4571 {
4572 // Discuss any changes with Dale Lear.
4573 if ( !m_bCustomSettings && src.m_bCustomSettings )
4574 return -1;
4575 if ( m_bCustomSettings && !src.m_bCustomSettings )
4576 return 1;
4577 if ( m_texture_range < src.m_texture_range )
4578 return -1;
4579 if ( m_texture_range > src.m_texture_range )
4580 return 1;
4581 return CompareGeometrySettings(src);
4582 }
4583
ON_MeshParameters_CompareDouble(double t0,double t1,double default_value)4584 static int ON_MeshParameters_CompareDouble(double t0, double t1, double default_value)
4585 {
4586 if ( !ON_IsValid(t0) || t0 <= 0.0 )
4587 t0 = default_value;
4588 if ( !ON_IsValid(t1) || t1 <= 0.0 )
4589 t1 = default_value;
4590 if ( t0 < t1 )
4591 return 1;
4592 if ( t1 < t0 )
4593 return -1;
4594 return 0;
4595 }
4596
ON_MeshParameters_CompareInt(int i0,int i1)4597 static int ON_MeshParameters_CompareInt(int i0, int i1)
4598 {
4599 if ( i0 <= 0 )
4600 i0 = 0;
4601 if ( i1 <= 0 )
4602 i1 = 0;
4603 return i1-i0;
4604 }
4605
ON_MeshParameters_CompareBool(bool b0,bool b1)4606 static int ON_MeshParameters_CompareBool(bool b0, bool b1)
4607 {
4608 const int i0 = b0 ? 1 : 0;
4609 const int i1 = b1 ? 1 : 0;
4610 return i1-i0;
4611 }
4612
CompareGeometrySettings(const ON_MeshParameters & src) const4613 int ON_MeshParameters::CompareGeometrySettings( const ON_MeshParameters& src ) const
4614 {
4615 int rc;
4616
4617 // Discuss any changes with Dale Lear.
4618 rc = ON_MeshParameters_CompareBool(m_bSimplePlanes,src.m_bSimplePlanes);
4619 if (rc)
4620 return rc;
4621 rc = ON_MeshParameters_CompareBool(m_bRefine,src.m_bRefine);
4622 if (rc)
4623 return rc;
4624 rc = ON_MeshParameters_CompareBool(m_bJaggedSeams,src.m_bJaggedSeams);
4625 if (rc)
4626 return rc;
4627 if ( m_mesher < src.m_mesher )
4628 return -1;
4629 if ( m_mesher > src.m_mesher )
4630 return 1;
4631
4632 rc = ON_MeshParameters_CompareDouble(m_tolerance,src.m_tolerance,0.0);
4633 if (rc)
4634 return rc;
4635
4636 rc = ON_MeshParameters_CompareDouble(m_relative_tolerance,src.m_relative_tolerance,0.0);
4637 if (rc)
4638 return rc;
4639
4640 // DO NOT COMPARE m_min_tolerance - it is a runtime lower bound clamp.
4641 // If it is included here, Rhino will remesh everytime
4642 // model tolerance changes.
4643
4644 rc = ON_MeshParameters_CompareDouble(m_min_edge_length,src.m_min_edge_length,0.0);
4645 if (rc)
4646 return rc;
4647
4648 rc = ON_MeshParameters_CompareDouble(m_max_edge_length,src.m_max_edge_length,0.0);
4649 if (rc)
4650 return rc;
4651
4652 rc = ON_MeshParameters_CompareDouble(m_grid_aspect_ratio,src.m_grid_aspect_ratio,0.0);
4653 if (rc)
4654 return rc;
4655
4656 rc = ON_MeshParameters_CompareInt(m_grid_min_count,src.m_grid_min_count);
4657 if (rc)
4658 return rc;
4659
4660 rc = ON_MeshParameters_CompareInt(m_grid_max_count,src.m_grid_max_count);
4661 if (rc)
4662 return rc;
4663
4664 rc = ON_MeshParameters_CompareDouble(m_grid_angle,src.m_grid_angle,ON_PI);
4665 if (rc)
4666 return rc;
4667
4668 rc = ON_MeshParameters_CompareDouble(m_refine_angle,src.m_refine_angle,0.0);
4669 if (rc)
4670 return rc;
4671
4672 rc = ON_MeshParameters_CompareDouble(m_grid_amplification,src.m_grid_amplification,1.0);
4673 if (rc)
4674 return rc;
4675
4676 if ( m_face_type < src.m_face_type )
4677 return -1;
4678 if ( m_face_type > src.m_face_type )
4679 return 1;
4680
4681 return 0;
4682 }
4683
DataCRC(ON__UINT32 current_remainder) const4684 ON__UINT32 ON_MeshParameters::DataCRC(ON__UINT32 current_remainder) const
4685 {
4686 ON__UINT32 crc = ON_CRC32(current_remainder,sizeof(m_bComputeCurvature),&m_bComputeCurvature);
4687 crc = ON_CRC32(crc,sizeof(m_bSimplePlanes),&m_bSimplePlanes);
4688 crc = ON_CRC32(crc,sizeof(m_bRefine),&m_bRefine);
4689 crc = ON_CRC32(crc,sizeof(m_bJaggedSeams),&m_bJaggedSeams);
4690 crc = ON_CRC32(crc,sizeof(m_tolerance),&m_tolerance);
4691 crc = ON_CRC32(crc,sizeof(m_min_edge_length),&m_min_edge_length);
4692 crc = ON_CRC32(crc,sizeof(m_max_edge_length),&m_max_edge_length);
4693 crc = ON_CRC32(crc,sizeof(m_grid_aspect_ratio),&m_grid_aspect_ratio);
4694 crc = ON_CRC32(crc,sizeof(m_grid_min_count),&m_grid_min_count);
4695 crc = ON_CRC32(crc,sizeof(m_grid_max_count),&m_grid_max_count);
4696 crc = ON_CRC32(crc,sizeof(m_grid_angle),&m_grid_angle);
4697 crc = ON_CRC32(crc,sizeof(m_grid_amplification),&m_grid_amplification);
4698 crc = ON_CRC32(crc,sizeof(m_refine_angle),&m_refine_angle);
4699 crc = ON_CRC32(crc,sizeof(m_face_type),&m_face_type);
4700 crc = ON_CRC32(crc,sizeof(m_texture_range),&m_texture_range);
4701 crc = ON_CRC32(crc,sizeof(m_bCustomSettings),&m_bCustomSettings);
4702 crc = ON_CRC32(crc,sizeof(m_relative_tolerance),&m_relative_tolerance);
4703 crc = ON_CRC32(crc,sizeof(m_mesher),&m_mesher);
4704 return crc;
4705 }
4706
Write(ON_BinaryArchive & file) const4707 bool ON_MeshParameters::Write( ON_BinaryArchive& file ) const
4708 {
4709 bool rc = file.Write3dmChunkVersion(1,4);
4710 if (rc) {
4711 if (rc) rc = file.WriteInt(m_bComputeCurvature);
4712 if (rc) rc = file.WriteInt(m_bSimplePlanes);
4713 if (rc) rc = file.WriteInt(m_bRefine);
4714 if (rc) rc = file.WriteInt(m_bJaggedSeams);
4715 if (rc) rc = file.WriteInt(0); // obsolete m_bWeld field
4716 if (rc) rc = file.WriteDouble(m_tolerance);
4717 if (rc) rc = file.WriteDouble(m_min_edge_length);
4718 if (rc) rc = file.WriteDouble(m_max_edge_length);
4719 if (rc) rc = file.WriteDouble(m_grid_aspect_ratio);
4720 if (rc) rc = file.WriteInt(m_grid_min_count);
4721 if (rc) rc = file.WriteInt(m_grid_max_count);
4722 if (rc) rc = file.WriteDouble(m_grid_angle);
4723 if (rc) rc = file.WriteDouble(m_grid_amplification);
4724 if (rc) rc = file.WriteDouble(m_refine_angle);
4725 if (rc) rc = file.WriteDouble(5.0*ON_PI/180.0); // obsolete m_combine_angle field
4726 int mft = m_face_type;
4727 if ( mft < 0 || mft > 2 )
4728 {
4729 ON_ERROR("ON_MeshParameters::Read() - m_face_type out of bounds.");
4730 mft = 0;
4731 }
4732 if (rc) rc = file.WriteInt(mft);
4733
4734 // added for chunk version 1.1
4735 if (rc) rc = file.WriteInt( m_texture_range );
4736
4737 // added for chunk version 1.2 - 14 October 2005
4738 if (rc) rc = file.WriteBool( m_bCustomSettings );
4739 if (rc) rc = file.WriteDouble( m_relative_tolerance );
4740 // DO NOT SAVE m_min_tolerance - yet ??
4741
4742 // added for chunk version 1.3 - 20 February 2006
4743 if (rc) rc = file.WriteChar(m_mesher);
4744
4745 // added for chunk version 1.4 - 3 March 2011
4746 if (rc) rc = file.WriteBool( m_bCustomSettingsEnabled );
4747 }
4748 return rc;
4749 }
4750
Read(ON_BinaryArchive & file)4751 bool ON_MeshParameters::Read( ON_BinaryArchive& file )
4752 {
4753 Default();
4754 int major_version = 0;
4755 int minor_version = 0;
4756 bool rc = file.Read3dmChunkVersion(&major_version,&minor_version);
4757 if ( rc && major_version == 1 )
4758 {
4759 int i;
4760
4761 i = m_bComputeCurvature;
4762 if (rc) rc = file.ReadInt(&i);
4763 m_bComputeCurvature = i?true:false;
4764
4765 i = m_bSimplePlanes;
4766 if (rc) rc = file.ReadInt(&i);
4767 m_bSimplePlanes = i?true:false;
4768
4769 i = m_bRefine;
4770 if (rc) rc = file.ReadInt(&i);
4771 m_bRefine = i?true:false;
4772
4773 i = m_bJaggedSeams;
4774 if (rc) rc = file.ReadInt(&i);
4775 m_bJaggedSeams = i?true:false;
4776
4777 int obsolete_m_bWeld;
4778 if (rc) rc = file.ReadInt(&obsolete_m_bWeld);
4779
4780 if (rc) rc = file.ReadDouble(&m_tolerance);
4781 if (rc) rc = file.ReadDouble(&m_min_edge_length);
4782 if (rc) rc = file.ReadDouble(&m_max_edge_length);
4783 if (rc) rc = file.ReadDouble(&m_grid_aspect_ratio);
4784 if (rc) rc = file.ReadInt(&m_grid_min_count);
4785 if (rc) rc = file.ReadInt(&m_grid_max_count);
4786 if (rc) rc = file.ReadDouble(&m_grid_angle);
4787 if (rc) rc = file.ReadDouble(&m_grid_amplification);
4788 if (rc) rc = file.ReadDouble(&m_refine_angle);
4789 double obsolete_m_combine_angle;
4790 if (rc) rc = file.ReadDouble(&obsolete_m_combine_angle);
4791 if (rc) rc = file.ReadInt(&m_face_type);
4792 if ( m_face_type < 0 || m_face_type > 2 )
4793 {
4794 ON_ERROR("ON_MeshParameters::Read() - m_face_type out of bounds.");
4795 m_face_type = 0;
4796 }
4797
4798 if ( rc && minor_version >= 1 )
4799 {
4800 rc = file.ReadInt( &m_texture_range );
4801 if ( rc && minor_version >= 2 )
4802 {
4803 rc = file.ReadBool(&m_bCustomSettings);
4804 if (rc) rc = file.ReadDouble(&m_relative_tolerance);
4805 if ( rc && minor_version >= 3 )
4806 {
4807 rc = file.ReadChar(&m_mesher);
4808 if ( rc && minor_version >= 4 )
4809 {
4810 rc = file.ReadBool(&m_bCustomSettingsEnabled);
4811 }
4812 }
4813 }
4814 }
4815 }
4816 return rc;
4817 }
4818
4819
4820
ON_MeshCurvatureStats()4821 ON_MeshCurvatureStats::ON_MeshCurvatureStats()
4822 {
4823 Destroy(); // initializes defaults
4824 }
4825
~ON_MeshCurvatureStats()4826 ON_MeshCurvatureStats::~ON_MeshCurvatureStats()
4827 {}
4828
Destroy()4829 void ON_MeshCurvatureStats::Destroy()
4830 {
4831 m_style = ON::unknown_curvature_style;
4832 m_infinity = 0.0;
4833 m_count_infinite = 0;
4834 m_count = 0;
4835 m_mode = 0.0;
4836 m_average = 0.0;
4837 m_adev = 0.0;
4838 m_range.Set(0.0,0.0);
4839 }
4840
EmergencyDestroy()4841 void ON_MeshCurvatureStats::EmergencyDestroy()
4842 {
4843 Destroy(); // - no memory is freed so Destroy() will work
4844 }
4845
ON_MeshCurvatureStats(const ON_MeshCurvatureStats & src)4846 ON_MeshCurvatureStats::ON_MeshCurvatureStats(const ON_MeshCurvatureStats& src)
4847 {
4848 *this = src;
4849 }
4850
operator =(const ON_MeshCurvatureStats & src)4851 ON_MeshCurvatureStats& ON_MeshCurvatureStats::operator=(const ON_MeshCurvatureStats& src)
4852 {
4853 if ( this != &src ) {
4854 m_style = src.m_style;
4855 m_infinity = src.m_infinity;
4856 m_count_infinite = src.m_count_infinite;
4857 m_count = src.m_count;
4858 m_mode = src.m_mode;
4859 m_average = src.m_average;
4860 m_adev = src.m_adev;
4861 m_range = src.m_range;
4862 }
4863 return *this;
4864 }
4865
Write(ON_BinaryArchive & file) const4866 bool ON_MeshCurvatureStats::Write( ON_BinaryArchive& file ) const
4867 {
4868 int i;
4869 bool rc = file.Write3dmChunkVersion(1,1);
4870 if (rc) {
4871 i = m_style;
4872 if (rc) rc = file.WriteInt(i);
4873 if (rc) rc = file.WriteDouble(m_infinity);
4874 if (rc) rc = file.WriteInt(m_count_infinite);
4875 if (rc) rc = file.WriteInt(m_count);
4876 if (rc) rc = file.WriteDouble(m_mode);
4877 if (rc) rc = file.WriteDouble(m_average);
4878 if (rc) rc = file.WriteDouble(m_adev);
4879 if (rc) rc = file.WriteInterval(m_range);
4880 }
4881 return rc;
4882 }
4883
4884
Read(ON_BinaryArchive & file)4885 bool ON_MeshCurvatureStats::Read( ON_BinaryArchive& file )
4886 {
4887 int major_version = 0;
4888 int minor_version = 0;
4889 Destroy();
4890 bool rc = file.Read3dmChunkVersion(&major_version,&minor_version);
4891 if (rc && major_version == 1) {
4892 int i=0;
4893 if (rc) rc = file.ReadInt(&i);
4894 if (rc) m_style = ON::CurvatureStyle(i);
4895 if (rc) rc = file.ReadDouble(&m_infinity);
4896 if (rc) rc = file.ReadInt(&m_count_infinite);
4897 if (rc) rc = file.ReadInt(&m_count);
4898 if (rc) rc = file.ReadDouble(&m_mode);
4899 if (rc) rc = file.ReadDouble(&m_average);
4900 if (rc) rc = file.ReadDouble(&m_adev);
4901 if (rc) rc = file.ReadInterval(m_range);
4902 }
4903 return rc;
4904 }
4905
Set(ON::curvature_style kappa_style,int Kcount,const ON_SurfaceCurvature * K,const ON_3fVector *,double infinity)4906 bool ON_MeshCurvatureStats::Set( ON::curvature_style kappa_style,
4907 int Kcount,
4908 const ON_SurfaceCurvature* K,
4909 const ON_3fVector* /*N*/, // needed for normal sectional curvatures
4910 double infinity
4911 )
4912 {
4913 bool rc = (Kcount > 0 && K != NULL);
4914
4915 Destroy();
4916
4917 if (rc) {
4918 ON_Workspace ws;
4919 //ON_3dVector tangent;
4920 double k;
4921 double* kappa = ws.GetDoubleMemory(Kcount);
4922 int i;
4923
4924 switch( kappa_style ) {
4925 case ON::gaussian_curvature:
4926 m_style = kappa_style;
4927 m_infinity = ( infinity > 0.0 ) ? infinity : 1.0e20;
4928 break;
4929 case ON::mean_curvature: // unsigned mean
4930 m_style = kappa_style;
4931 m_infinity = ( infinity > 0.0 ) ? infinity : 1.0e10;
4932 break;
4933 case ON::min_curvature: // minimum unsigned radius of curvature
4934 m_style = kappa_style;
4935 m_infinity = ( infinity > 0.0 ) ? infinity : 1.0e10;
4936 break;
4937 case ON::max_curvature: // maximum unsigned radius of curvature
4938 m_style = kappa_style;
4939 m_infinity = ( infinity > 0.0 ) ? infinity : 1.0e10;
4940 break;
4941 //case ON::section_curvature_x:
4942 // if ( !N )
4943 // kappa_style = ON::unknown_curvature_style;
4944 // m_style = kappa_style;
4945 // m_infinity = ( infinity > 0.0 ) ? infinity : 1.0e10;
4946 // break;
4947 //case ON::section_curvature_y:
4948 // if ( !N )
4949 // kappa_style = ON::unknown_curvature_style;
4950 // m_style = kappa_style;
4951 // m_infinity = ( infinity > 0.0 ) ? infinity : 1.0e10;
4952 // break;
4953 //case ON::section_curvature_z:
4954 // if ( !N )
4955 // kappa_style = ON::unknown_curvature_style;
4956 // m_style = kappa_style;
4957 // m_infinity = ( infinity > 0.0 ) ? infinity : 1.0e10;
4958 // break;
4959 default:
4960 rc = false;
4961 break;
4962 }
4963
4964 for ( i = 0; i < Kcount; i++ ) {
4965 switch( kappa_style ) {
4966 case ON::gaussian_curvature:
4967 k = K[i].GaussianCurvature();
4968 break;
4969 case ON::mean_curvature: // unsigned mean
4970 k = fabs(K[i].MeanCurvature());
4971 break;
4972 case ON::min_curvature: // minimum unsigned radius of curvature
4973 k = fabs(K[i].MinimumRadius());
4974 break;
4975 case ON::max_curvature: // maximum unsigned radius of curvature
4976 k = fabs(K[i].MaximumRadius());
4977 break;
4978 //case ON::section_curvature_x:
4979 // tangent.x = 0.0; tangent.y = -N[i].z; tangent.z = N[i].y;
4980 // if ( fabs(tangent.y) <= ON_SQRT_EPSILON && fabs(tangent.z) <= ON_SQRT_EPSILON )
4981 // tangent.Zero();
4982 // else
4983 // tangent.Unitize();
4984 // k = fabs(K[i].NormalCurvature(tangent));
4985 // break;
4986 //case ON::section_curvature_y:
4987 // tangent.x = N[i].z; tangent.y = 0.0; tangent.z = -N[i].x;
4988 // if ( fabs(tangent.x) <= ON_SQRT_EPSILON && fabs(tangent.z) <= ON_SQRT_EPSILON )
4989 // tangent.Zero();
4990 // else
4991 // tangent.Unitize();
4992 // k = fabs(K[i].NormalCurvature(tangent));
4993 // break;
4994 //case ON::section_curvature_z:
4995 // tangent.x = -N[i].y; tangent.y = N[i].x; tangent.z = 0.0;
4996 // if ( fabs(tangent.x) <= ON_SQRT_EPSILON && fabs(tangent.y) <= ON_SQRT_EPSILON )
4997 // tangent.Zero();
4998 // else
4999 // tangent.Unitize();
5000 // k = fabs(K[i].NormalCurvature(tangent));
5001 // break;
5002 default:
5003 k=0.0;
5004 break;
5005 }
5006 if ( fabs(k) >= m_infinity ) {
5007 m_count_infinite++;
5008 continue;
5009 }
5010 if ( m_count ) {
5011 if ( k < m_range.m_t[0] )
5012 m_range.m_t[0] = k;
5013 else if ( k > m_range.m_t[1] )
5014 m_range.m_t[1] = k;
5015 }
5016 else {
5017 m_range.m_t[0] = m_range.m_t[1] = k;
5018 }
5019 kappa[m_count++] = k;
5020 }
5021
5022
5023 if ( m_count == 0 )
5024 rc = false;
5025 else {
5026 // sum curvatures
5027 ON_SortDoubleArray( ON::quick_sort, kappa, m_count );
5028
5029 // mode
5030 m_mode = kappa[m_count/2];
5031 if ( 0 == (m_count % 2) ) {
5032 m_mode += kappa[(m_count/2)-1];
5033 m_mode *= 0.5;
5034 }
5035
5036 // average
5037 for ( i = 0; i < m_count; i++ ) {
5038 m_average += kappa[i];
5039 }
5040 m_average = m_average/m_count;
5041
5042 // average deviation
5043 for ( i = 0; i < m_count; i++ ) {
5044 m_adev += fabs(kappa[i] - m_average);
5045 }
5046 m_adev = m_adev/m_count;
5047 }
5048 }
5049
5050 return rc;
5051 }
5052
5053 struct EDGEINFO
5054 {
5055 int fi[2]; // m_F[] triangles on either side of the edge
5056 int vi[4]; // potential m_V[] quad indices
5057 int flag; // 0 = available,
5058 // 1 = side of quad,
5059 // 2 = bndry or nonmanifold edge,
5060 // 3 = edge crease angle > angle_tol_radians
5061 // 4 = edge is not longest side of triangle
5062 // 5 = edge length is zero
5063 // 6 = edge would be a boundary if mesh were exploded
5064 // 16 = edge will be removed to make a quad
5065 double length;
5066 };
5067
ConvertTrianglesToQuads(double angle_tol_radians,double min_diagonal_length_ratio)5068 bool ON_Mesh::ConvertTrianglesToQuads(
5069 double angle_tol_radians,
5070 double min_diagonal_length_ratio
5071 )
5072 {
5073 ON_Workspace ws;
5074
5075 double d;
5076
5077 int i, ii, jj;
5078 int diagonal_count;
5079 const int* f0vi;
5080 const int* f1vi;
5081 const int* fei;
5082
5083 diagonal_count = 0;
5084
5085 if ( angle_tol_radians < 0.0 || !ON_IsValid(angle_tol_radians) )
5086 {
5087 // 2.5 degrees
5088 angle_tol_radians = 0.043633231299858239423092269212215;
5089 }
5090 else if ( angle_tol_radians < ON_ZERO_TOLERANCE )
5091 {
5092 angle_tol_radians = ON_ZERO_TOLERANCE;
5093 }
5094
5095 angle_tol_radians = cos(angle_tol_radians);
5096 if ( angle_tol_radians < 0.5 )
5097 angle_tol_radians = 0.5;
5098 else if ( angle_tol_radians > 1.0-ON_SQRT_EPSILON )
5099 angle_tol_radians = 1.0-ON_SQRT_EPSILON;
5100
5101 const ON_MeshTopology& top = Topology();
5102
5103 if ( !HasFaceNormals() )
5104 ComputeFaceNormals();
5105
5106 if ( min_diagonal_length_ratio < ON_ZERO_TOLERANCE )
5107 min_diagonal_length_ratio = ON_ZERO_TOLERANCE;
5108
5109 double max_diagonal_length_ratio = 1.0/min_diagonal_length_ratio;
5110
5111 if( min_diagonal_length_ratio > max_diagonal_length_ratio )
5112 {
5113 d = min_diagonal_length_ratio;
5114 min_diagonal_length_ratio = max_diagonal_length_ratio;
5115 max_diagonal_length_ratio = d;
5116 }
5117
5118 //double rel_tol = ON_SQRT_EPSILON;
5119 double rel_tol = 8.0*ON_SQRT_EPSILON; // to fix RR 51543
5120 if ( min_diagonal_length_ratio > 1.0-rel_tol )
5121 min_diagonal_length_ratio = 1.0-rel_tol;
5122 if ( max_diagonal_length_ratio < 1.0+rel_tol )
5123 max_diagonal_length_ratio = 1.0+rel_tol;
5124
5125
5126 const int face_count = m_F.Count();
5127 int* face_flag = ws.GetIntMemory(face_count);
5128 for ( i = 0; i < face_count; i++ )
5129 {
5130 f0vi = m_F[i].vi;
5131 face_flag[i] = ( f0vi[2] == f0vi[3] ) ? 0 : 1;
5132 }
5133
5134 const int edge_count = top.m_tope.Count();
5135 struct EDGEINFO* EI = (struct EDGEINFO*)ws.GetMemory(edge_count*sizeof(*EI));
5136 for ( i = 0; i < edge_count; i++ )
5137 {
5138 struct EDGEINFO& ei = EI[i];
5139 const ON_MeshTopologyEdge& tope = top.m_tope[i];
5140 ei.flag = 0;
5141 ei.vi[0] = top.m_topv[tope.m_topvi[0]].m_vi[0];
5142 ei.vi[2] = top.m_topv[tope.m_topvi[1]].m_vi[0];
5143 ei.length = m_V[ei.vi[0]].DistanceTo(m_V[ei.vi[2]]);
5144 if ( ei.length <= 0.0 || !ON_IsValid(ei.length) )
5145 {
5146 ei.flag = 5;
5147 }
5148 else if ( tope.m_topf_count != 2 )
5149 {
5150 ei.flag = 2;
5151 }
5152 else
5153 {
5154 ei.fi[0] = tope.m_topfi[0];
5155 ei.fi[1] = tope.m_topfi[1];
5156 if (face_flag[ei.fi[0]] || face_flag[ei.fi[1]] )
5157 {
5158 ei.flag = 1;
5159 }
5160 else if ( m_FN[ei.fi[0]] * m_FN[ei.fi[1]] < angle_tol_radians )
5161 {
5162 ei.flag = 3;
5163 }
5164 else
5165 {
5166 f0vi = m_F[ei.fi[0]].vi;
5167 f1vi = m_F[ei.fi[1]].vi;
5168 ei.flag = 6;
5169 for ( ii = 0; ii < 3 && ei.flag; ii++ )
5170 {
5171 for (jj = 0; jj < 3; jj++)
5172 {
5173 if ( f0vi[ii] == f1vi[jj]
5174 && f0vi[(ii+1)%3] == f1vi[(jj+2)%3]
5175 && f0vi[(ii+2)%3] != f1vi[(jj+1)%3] )
5176 {
5177 if ( ei.fi[0] > ei.fi[1] )
5178 {
5179 jj = ei.fi[0]; ei.fi[0] = ei.fi[1]; ei.fi[1] = jj;
5180 }
5181 ei.vi[0] = f0vi[ii];
5182 ei.vi[1] = f1vi[(jj+1)%3];
5183 ei.vi[2] = f0vi[(ii+1)%3];
5184 ei.vi[3] = f0vi[(ii+2)%3];
5185 ei.flag = 0;
5186 break;
5187 }
5188 }
5189 }
5190 }
5191 }
5192 }
5193
5194 for ( i = 0; i < edge_count; i++ )
5195 {
5196 struct EDGEINFO& ei = EI[i];
5197 if ( ei.flag )
5198 continue;
5199
5200 ei.flag = 16;
5201
5202 // It is CRITICAL that the length compare use >=.
5203 // Otherwise tesselations of equailateral triangles
5204 // will not work right in this fuction.
5205 fei = top.m_topf[ei.fi[0]].m_topei;
5206 if ( ( i != fei[0] && EI[fei[0]].length >= ei.length )
5207 || ( i != fei[1] && EI[fei[1]].length >= ei.length )
5208 || ( i != fei[2] && EI[fei[2]].length >= ei.length )
5209 )
5210 {
5211 // diagonal is not strictly longest in this triangle
5212 continue;
5213 }
5214
5215 // It is CRITICAL that the length compare use >=.
5216 // Otherwise tesselations of equailateral triangles
5217 // will not work right in this fuction.
5218 fei = top.m_topf[ei.fi[1]].m_topei;
5219 if ( ( i != fei[0] && EI[fei[0]].length >= ei.length )
5220 || ( i != fei[1] && EI[fei[1]].length >= ei.length )
5221 || ( i != fei[2] && EI[fei[2]].length >= ei.length )
5222 )
5223 {
5224 // diagonal is not strictly longest in this triangle
5225 continue;
5226 }
5227
5228 d = m_V[ei.vi[1]].DistanceTo(m_V[ei.vi[3]]);
5229 d /= ei.length;
5230 if ( d < min_diagonal_length_ratio || d > max_diagonal_length_ratio )
5231 {
5232 // quad wouldn't be square enough
5233 continue;
5234 }
5235
5236 ei.flag = 0;
5237
5238 diagonal_count++;
5239 }
5240
5241 if ( diagonal_count > 0 )
5242 {
5243 DestroyTree();
5244 DestroyPartition();
5245 m_top.Destroy();
5246 for ( i = 0; i < edge_count; i++ )
5247 {
5248 struct EDGEINFO& ei = EI[i];
5249 if ( ei.flag )
5250 continue;
5251 memcpy( m_F[ei.fi[0]].vi, ei.vi, 4*sizeof(ei.vi[0]) );
5252 memset( m_F[ei.fi[1]].vi, 0xFF, 4*sizeof(ei.vi[0]) );
5253 m_triangle_count--;
5254 m_quad_count++;
5255 }
5256 CullDegenerateFaces();
5257 }
5258
5259 return (diagonal_count > 0 );
5260 }
5261
ConvertQuadsToTriangles()5262 bool ON_Mesh::ConvertQuadsToTriangles()
5263 {
5264 const bool bHasFaceNormals = HasFaceNormals();
5265 const int fcount = FaceCount();
5266 const int vcount = VertexCount();
5267 int fi, idmin;;
5268 double d0, d1, dmin, d;
5269 if ( fcount > 0 && QuadCount() > 0 )
5270 {
5271 // use SetCapacity() instead of Reserve() because it's unlikely
5272 // this mesh will have anything else added and we don't want to
5273 // waste memory.
5274 if ( m_F.Capacity() < fcount + m_quad_count )
5275 m_F.SetCapacity( fcount + m_quad_count );
5276 if ( bHasFaceNormals && m_FN.Capacity() < fcount + m_quad_count )
5277 m_FN.SetCapacity( fcount + m_quad_count );
5278
5279 const ON_3dPoint* dV = ( vcount > 0 && HasDoublePrecisionVertices()
5280 && ( HasSynchronizedDoubleAndSinglePrecisionVertices() || DoublePrecisionVerticesAreValid() )
5281 )
5282 ? DoublePrecisionVertices().Array()
5283 : 0;
5284
5285 const ON_3fPoint* fV = m_V.Array();
5286
5287 const double rel_tol = 8.0*( (0 != dV) ? ON_EPSILON : ON_FLOAT_EPSILON );
5288
5289 ON_3dVector FN;
5290
5291 for ( fi = 0; fi < fcount; fi++ )
5292 {
5293 ON_MeshFace& f0 = m_F[fi];
5294 if ( f0.IsValid(vcount) && f0.IsQuad() )
5295 {
5296 if ( 0 != dV )
5297 {
5298 d0 = dV[f0.vi[0]].DistanceTo(dV[f0.vi[2]]);
5299 d1 = dV[f0.vi[1]].DistanceTo(dV[f0.vi[3]]);
5300
5301 // if quad is degenerate, just turn it into a triangle
5302 idmin = -1;
5303 dmin = ((d0<=d1)?d0:d1)*rel_tol;
5304 if ( dmin > ON_ZERO_TOLERANCE )
5305 dmin = ON_ZERO_TOLERANCE;
5306 d = dV[f0.vi[0]].DistanceTo(dV[f0.vi[1]]);
5307 if ( d < dmin )
5308 {
5309 idmin = 0;
5310 dmin = d;
5311 }
5312 d = dV[f0.vi[1]].DistanceTo(dV[f0.vi[2]]);
5313 if ( d < dmin )
5314 {
5315 idmin = 1;
5316 dmin = d;
5317 }
5318 d = dV[f0.vi[2]].DistanceTo(dV[f0.vi[3]]);
5319 if ( d < dmin )
5320 {
5321 idmin = 2;
5322 dmin = d;
5323 }
5324 d = dV[f0.vi[3]].DistanceTo(dV[f0.vi[0]]);
5325 if ( d < dmin )
5326 {
5327 idmin = 3;
5328 dmin = d;
5329 }
5330 }
5331 else
5332 {
5333 d0 = m_V[f0.vi[0]].DistanceTo(m_V[f0.vi[2]]);
5334 d1 = m_V[f0.vi[1]].DistanceTo(m_V[f0.vi[3]]);
5335
5336 // if quad is degenerate, just turn it into a triangle
5337 idmin = -1;
5338 dmin = ((d0<=d1)?d0:d1)*rel_tol;
5339 if ( dmin > ON_ZERO_TOLERANCE )
5340 dmin = ON_ZERO_TOLERANCE;
5341 d = m_V[f0.vi[0]].DistanceTo(m_V[f0.vi[1]]);
5342 if ( d < dmin )
5343 {
5344 idmin = 0;
5345 dmin = d;
5346 }
5347 d = m_V[f0.vi[1]].DistanceTo(m_V[f0.vi[2]]);
5348 if ( d < dmin )
5349 {
5350 idmin = 1;
5351 dmin = d;
5352 }
5353 d = m_V[f0.vi[2]].DistanceTo(m_V[f0.vi[3]]);
5354 if ( d < dmin )
5355 {
5356 idmin = 2;
5357 dmin = d;
5358 }
5359 d = m_V[f0.vi[3]].DistanceTo(m_V[f0.vi[0]]);
5360 if ( d < dmin )
5361 {
5362 idmin = 3;
5363 dmin = d;
5364 }
5365 }
5366
5367 if ( !(d0 > 0.0) )
5368 {
5369 if ( !(d1 > 0.0) )
5370 continue;
5371 // d0 = 0 or is invalid and d1 > 0
5372 // force split along v[1],v[3]
5373 idmin = -1;
5374 d0 = 1.0;
5375 d1 = 0.0;
5376 }
5377 else if ( !(d1 > 0.0) )
5378 {
5379 // d1 = 0 or is invalid and d0 > 0
5380 // force split along v[0],v[1]
5381 idmin = -1;
5382 d1 = 1.0;
5383 d0 = 0.0;
5384 }
5385
5386 m_quad_count--;
5387 m_triangle_count++;
5388 if ( 0 == idmin ) // m_V[f0.vi[0]] == m_V[f0.vi[1]] (nearly)
5389 {
5390 // degenerate quad - remove duplicate vertex
5391 f0.vi[0] = f0.vi[1];
5392 f0.vi[1] = f0.vi[2];
5393 f0.vi[2] = f0.vi[3];
5394 }
5395 else if ( 1 == idmin ) // m_V[f0.vi[1]] == m_V[f0.vi[2]] (nearly)
5396 {
5397 // degenerate quad - remove duplicate vertex
5398 int vi0 = f0.vi[0];
5399 f0.vi[0] = f0.vi[2];
5400 f0.vi[1] = f0.vi[3];
5401 f0.vi[2] = vi0;
5402 f0.vi[3] = vi0;
5403 }
5404 else if ( 2 == idmin ) // m_V[f0.vi[2]] == m_V[f0.vi[3]] (nearly)
5405 {
5406 // degenerate quad - remove duplicate vertex
5407 f0.vi[2] = f0.vi[1];
5408 f0.vi[1] = f0.vi[0];
5409 f0.vi[0] = f0.vi[3];
5410 f0.vi[3] = f0.vi[2];
5411 }
5412 else if ( 3 == idmin ) // m_V[f0.vi[3]] == m_V[f0.vi[0]] (nearly)
5413 {
5414 // degenerate quad - remove duplicate vertex
5415 f0.vi[3] = f0.vi[2];
5416 }
5417 else
5418 {
5419 // split non-degenerate quad into two triangles
5420 ON_MeshFace& f1 = m_F.AppendNew();
5421 if ( d0 <= d1 )
5422 {
5423 f1.vi[0] = f0.vi[0];
5424 f1.vi[1] = f0.vi[2];
5425 f1.vi[2] = f0.vi[3];
5426 f1.vi[3] = f1.vi[2];
5427 f0.vi[3] = f0.vi[2];
5428 }
5429 else
5430 {
5431 f1.vi[0] = f0.vi[1];
5432 f1.vi[1] = f0.vi[2];
5433 f1.vi[2] = f0.vi[3];
5434 f1.vi[3] = f1.vi[2];
5435 f0.vi[2] = f0.vi[3];
5436 }
5437 if ( bHasFaceNormals )
5438 {
5439 if ( 0 != dV )
5440 {
5441 m_F[fi].ComputeFaceNormal(dV,FN);
5442 m_FN[fi] = FN;
5443 m_F[m_F.Count()-1].ComputeFaceNormal(dV,FN);
5444 }
5445 else
5446 {
5447 m_F[fi].ComputeFaceNormal(fV,FN);
5448 m_FN[fi] = FN;
5449 m_F[m_F.Count()-1].ComputeFaceNormal(fV,FN);
5450 }
5451 m_FN.AppendNew() = FN;
5452 }
5453 }
5454 }
5455 }
5456 if ( fcount != m_F.Count() )
5457 DestroyTopology(); // we added some triangles
5458 }
5459 return ( QuadCount() == 0 && TriangleCount() == FaceCount() ) ? true : false;
5460 }
5461
CountQuads()5462 bool ON_Mesh::CountQuads()
5463 {
5464 const int fcount = FaceCount();
5465 const int vcount = VertexCount();
5466 int fi;
5467 m_quad_count = 0;
5468 m_triangle_count = 0;
5469 m_invalid_count = 0;
5470 for ( fi = 0; fi < fcount; fi++ ) {
5471 const ON_MeshFace& f = m_F[fi];
5472 if ( f.IsValid(vcount) ) {
5473 if ( f.IsTriangle() )
5474 m_triangle_count++;
5475 else
5476 m_quad_count++;
5477 }
5478 else
5479 m_invalid_count++;
5480 }
5481 return true;
5482 }
5483
ComputeVertexNormals()5484 bool ON_Mesh::ComputeVertexNormals()
5485 {
5486 bool rc = false;
5487 const int fcount = FaceCount();
5488 const int vcount = VertexCount();
5489 int vi, fi, j;
5490 ON_3fVector n;
5491
5492 if ( fcount > 0 && vcount > 0 ) {
5493 rc = HasFaceNormals();
5494 if ( !rc )
5495 rc = ComputeFaceNormals();
5496 if ( rc ) {
5497 ON_Workspace ws;
5498 //double* face_area = ws.GetDoubleMemory(fcount);
5499 int* vfcount = ws.GetIntMemory( vcount );
5500 memset ( vfcount, 0, vcount*sizeof(*vfcount) );
5501
5502 // count number of faces that use each vertex
5503 for ( fi = 0; fi < fcount; fi++ ) {
5504 ON_MeshFace& f = m_F[fi];
5505 if ( f.IsValid(vcount) ) {
5506 vfcount[f.vi[0]]++;
5507 vfcount[f.vi[1]]++;
5508 vfcount[f.vi[2]]++;
5509 if ( f.IsQuad() )
5510 vfcount[f.vi[3]]++;
5511 }
5512 }
5513
5514 // set vfi[vi][] = array of face indices that use vertex vi
5515 int** vfi = (int**)ws.GetMemory( vcount*sizeof(vfi[0] ) );
5516 {
5517 int scratch_sz = 0;
5518 for ( vi = 0; vi < vcount; vi++ ) {
5519 scratch_sz += vfcount[vi];
5520 }
5521 int* scratch = ws.GetIntMemory(scratch_sz);
5522 for ( vi = 0; vi < vcount; vi++ ) {
5523 if ( vfcount[vi] ) {
5524 vfi[vi] = scratch;
5525 scratch += vfcount[vi];
5526 }
5527 vfcount[vi] = 0;
5528 }
5529 }
5530 for ( fi = 0; fi < fcount; fi++ ) {
5531 ON_MeshFace& f = m_F[fi];
5532 if ( f.IsValid(vcount) ) {
5533 vi = f.vi[0]; vfi[vi][vfcount[vi]++] = fi;
5534 vi = f.vi[1]; vfi[vi][vfcount[vi]++] = fi;
5535 vi = f.vi[2]; vfi[vi][vfcount[vi]++] = fi;
5536 if ( f.IsQuad() ) {
5537 vi = f.vi[3]; vfi[vi][vfcount[vi]++] = fi;
5538 }
5539 }
5540 }
5541
5542 // average face normals to get an estimate for a vertex normal
5543 m_N.SetCapacity(vcount);
5544 m_N.SetCount(0);
5545 for ( vi = 0; vi < vcount; vi++ ) {
5546 n.Zero();
5547 for ( j = vfcount[vi]-1; j >= 0; j-- ) {
5548 n += m_FN[vfi[vi][j]];
5549 }
5550 if ( !n.Unitize() )
5551 {
5552 // this vertex is not used by a face or the face normals cancel out.
5553 // set a unit z normal and press on.
5554 n.Set(0,0,1);
5555 }
5556 m_N.Append(n);
5557 }
5558 }
5559 }
5560 return rc;
5561 }
5562
NormalizeTextureCoordinates()5563 bool ON_Mesh::NormalizeTextureCoordinates()
5564 {
5565 ON_2fPoint t0;//, t1;
5566 int ti;
5567 const int vertex_count = m_V.Count();
5568 bool rc = HasSurfaceParameters();
5569 if ( rc )
5570 {
5571 const ON_2dPoint* S = m_S.Array();
5572 ON_Interval udom = m_srf_domain[0];
5573 ON_Interval vdom = m_srf_domain[1];
5574 rc = udom.IsIncreasing() && vdom.IsIncreasing();
5575 if ( !rc )
5576 {
5577 udom.Set(S[0].x,S[0].x);
5578 vdom.Set(S[0].y,S[0].y);
5579 for ( ti = 1; ti < vertex_count; ti++ )
5580 {
5581 if ( S[ti].x < udom.m_t[0] ) udom.m_t[0] = S[ti].x;
5582 else if ( S[ti].x > udom.m_t[1] ) udom.m_t[1] = S[ti].x;
5583 if ( S[ti].y < vdom.m_t[0] ) vdom.m_t[0] = S[ti].y;
5584 else if ( S[ti].y > vdom.m_t[1] ) vdom.m_t[1] = S[ti].y;
5585 }
5586 rc = udom.IsIncreasing() && vdom.IsIncreasing();
5587 }
5588
5589 if (rc)
5590 {
5591 m_T.Reserve(vertex_count);
5592 m_T.SetCount(0);
5593 for (ti = 0; ti < vertex_count; ti++ )
5594 {
5595 t0.x = (float)udom.NormalizedParameterAt(S[ti].x);
5596 t0.y = (float)vdom.NormalizedParameterAt(S[ti].y);
5597 m_T.Append(t0);
5598 }
5599 m_packed_tex_domain[0].Set(0.0,1.0);
5600 m_packed_tex_domain[1].Set(0.0,1.0);
5601 m_packed_tex_rotate = false;
5602 m_Ttag.SetDefaultSurfaceParameterMappingTag();
5603 if ( m_mesh_parameters )
5604 m_mesh_parameters->m_texture_range = 1;
5605 }
5606 }
5607
5608 return rc;
5609 }
5610
TransposeSurfaceParameters()5611 bool ON_Mesh::TransposeSurfaceParameters()
5612 {
5613 // swap m_srf_domain
5614 ON_Interval temp = m_srf_domain[0];
5615 m_srf_domain[0] = m_srf_domain[1];
5616 m_srf_domain[1] = temp;
5617
5618 double t = m_srf_scale[0];
5619 m_srf_scale[0] = m_srf_scale[1];
5620 m_srf_scale[1] = t;
5621
5622 int S_count = m_S.Count();
5623 ON_2dPoint* S_array = m_S.Array();
5624 for (int i = 0; i < S_count; i++ )
5625 {
5626 ON_2dPoint& S = S_array[i];
5627 t = S.x; S.x = S.y; S.y = t;
5628 }
5629 return true;
5630 }
5631
HasPackedTextureRegion() const5632 bool ON_Mesh::HasPackedTextureRegion() const
5633 {
5634 return ( ON_IsValid(m_srf_scale[0])
5635 && m_srf_scale[0] > 0.0
5636 && ON_IsValid(m_srf_scale[1])
5637 && m_srf_scale[1] > 0.0
5638 && m_packed_tex_domain[0].IsInterval()
5639 && m_packed_tex_domain[1].IsInterval()
5640 && 0.0 <= m_packed_tex_domain[0].Min()
5641 && m_packed_tex_domain[0].Max() <= 1.0
5642 && 0.0 <= m_packed_tex_domain[1].Min()
5643 && m_packed_tex_domain[1].Max() <= 1.0
5644 && ( fabs(m_packed_tex_domain[0].Length()) < 1.0
5645 || fabs(m_packed_tex_domain[1].Length()) < 1.0)
5646 );
5647 }
5648
5649
TransposeTextureCoordinates()5650 bool ON_Mesh::TransposeTextureCoordinates()
5651 {
5652 if ( !HasTextureCoordinates() )
5653 return false;
5654
5655 const int vcnt = m_T.Count();
5656 int i;
5657
5658 bool bPackedRegion = HasPackedTextureRegion();
5659
5660 bool bSrfParamTag = (!m_Ttag.IsSet() || m_Ttag.IsDefaultSurfaceParameterMapping());
5661
5662 if ( bPackedRegion && bSrfParamTag )
5663 {
5664 // The region of the bitmap the texture uses
5665 // cannot change. The texture coordinates
5666 // themselves get reflected in the subrectangle
5667 // about either the lowerleft to upperright
5668 // diagonal (llur = true) or the lowerright
5669 // to upperleft diagonal (llur = false).
5670 bool bRevU = m_packed_tex_domain[0].IsDecreasing();
5671 bool bRevV = m_packed_tex_domain[1].IsDecreasing();
5672 bool llur = (bRevU == bRevV) ? true : false;
5673 if ( m_packed_tex_rotate )
5674 llur = !llur;
5675
5676 ON_Interval TD[2];
5677 TD[0] = m_packed_tex_domain[0];
5678 TD[1] = m_packed_tex_domain[1];
5679 TD[0].MakeIncreasing();
5680 TD[1].MakeIncreasing();
5681 for( i=0; i<vcnt; i++)
5682 {
5683 ON_2fPoint tc = m_T[i];
5684 double x = TD[0].NormalizedParameterAt(tc[0]);
5685 double y = TD[1].NormalizedParameterAt(tc[1]);
5686 if(!llur)
5687 {
5688 x = 1.0-x;
5689 y = 1.0-y;
5690 }
5691 double s = TD[0].ParameterAt(y);
5692 double t = TD[1].ParameterAt(x);
5693 m_T[i].Set((float)s,(float)t);
5694 }
5695 }
5696 else
5697 {
5698 float f;
5699 for(i=0; i<vcnt; i++)
5700 {
5701 ON_2fPoint& tc = m_T[i];
5702 f = tc.x; tc.x = tc.y; tc.y = f;
5703 }
5704 }
5705 return true;
5706 }
5707
ReverseTextureCoordinates(int dir)5708 bool ON_Mesh::ReverseTextureCoordinates( int dir )
5709 {
5710 if ( dir < 0 || dir > 1 || !HasTextureCoordinates() )
5711 return false;
5712
5713 bool bPackedRegion = HasPackedTextureRegion();
5714
5715 bool bSrfParamTag = (!m_Ttag.IsSet() || m_Ttag.IsDefaultSurfaceParameterMapping());
5716
5717 const int vcount = m_T.Count();
5718 int i;
5719 if ( bPackedRegion && bSrfParamTag )
5720 {
5721 // The region of the bitmap the texture uses
5722 // cannot change. The texture coordinates
5723 // themselves get reflected in the subrectangle
5724 // about either the lowerleft to upperright
5725 // diagonal (llur = true) or the lowerright
5726 // to upperleft diagonal (llur = false).
5727 if ( m_packed_tex_rotate )
5728 dir = 1-dir;
5729 const ON_Interval tex_dom = m_packed_tex_domain[dir];
5730 double s;
5731 m_packed_tex_domain[dir].Swap(); // Swap() is correct - Reverse() is wrong.
5732 for (i = 0; i < vcount; i++ )
5733 {
5734 ON_2fPoint& tc = m_T[i];
5735 s = 1.0 - tex_dom.NormalizedParameterAt(tc[dir]);
5736 if ( dir )
5737 tc.y = (float)tex_dom.ParameterAt(s);
5738 else
5739 tc.x = (float)tex_dom.ParameterAt(s);
5740 }
5741 }
5742 else
5743 {
5744 for (i = 0; i < vcount; i++ )
5745 {
5746 ON_2fPoint& tc = m_T[i];
5747 if ( dir )
5748 tc.y = 1.0f-tc.y;
5749 else
5750 tc.x = 1.0f-tc.x;
5751 }
5752 }
5753 return true;
5754 }
5755
ReverseSurfaceParameters(int dir)5756 bool ON_Mesh::ReverseSurfaceParameters( int dir )
5757 {
5758 if ( dir < 0 || dir > 1 || !HasSurfaceParameters() )
5759 return false;
5760 if ( m_srf_domain[dir].IsIncreasing() )
5761 m_srf_domain[dir].Reverse();
5762 int i, vcount = m_S.Count();
5763 for (i = 0; i < vcount; i++)
5764 {
5765 ON_2dPoint& S = m_S[i];
5766 if ( dir )
5767 S.y = -S.y;
5768 else
5769 S.x = -S.x;
5770 }
5771 return true;
5772 }
5773
5774
EvaluateMeshGeometry(const ON_Surface & srf)5775 bool ON_Mesh::EvaluateMeshGeometry( const ON_Surface& srf )
5776 {
5777 bool rc = false;
5778 const int vcount = VertexCount();
5779 const bool bHasSurfaceParameters = HasSurfaceParameters();
5780 if ( bHasSurfaceParameters )
5781 {
5782 const bool bHasVertexNormals = HasVertexNormals();
5783 m_N.SetCapacity(vcount);
5784 int vi, side, hint[2];
5785 ON_3dPoint point;
5786 ON_3dVector normal, Ds, Dt, Dss, Dst, Dtt, K1, K2;
5787 const ON_2dPoint* srf_st;
5788 double s, t, kgauss, kmean;
5789 side = 0;
5790 hint[0] = 0;
5791 hint[1] = 0;
5792 const double smax = srf.Domain(0)[1];
5793 const double tmax = srf.Domain(1)[1];
5794 if ( HasPrincipalCurvatures() )
5795 {
5796 for ( vi = 0; vi < vcount; vi++ )
5797 {
5798 //ON_2fPoint& tex = m_T[vi];
5799 // convert texture coordinates to normalizied texture coordinates
5800 srf_st = &m_S[vi];
5801 s = srf_st->x;
5802 t = srf_st->y;
5803 // 19 April 2006 Dale Lear - added side setter so singular normals
5804 // are correctly evaluated RR 12482
5805 side = ( smax == s ) ? ((tmax == t) ? 3 : 2) : ((tmax == t) ? 4 : 1);
5806 srf.Ev2Der( s, t, point, Ds, Dt, Dss, Dst, Dtt, side, hint );
5807 ON_EvNormal( side, Ds, Dt, Dss, Dst, Dtt, normal );
5808 ON_EvPrincipalCurvatures( Ds, Dt, Dss, Dst, Dtt, normal,
5809 &kgauss, &kmean,
5810 &m_K[vi].k1, &m_K[vi].k2,
5811 K1, K2 ); //m_K[vi].e1, m_K[vi].e2 );
5812 m_V[vi] = &point.x; // use ON_3fPoint double* conversion (quiets gcc)
5813 if ( bHasVertexNormals )
5814 m_N[vi] = &normal.x; // use ON_3fVector double* conversion (quiets gcc)
5815 }
5816 InvalidateCurvatureStats();
5817 }
5818 else if ( bHasVertexNormals )
5819 {
5820 for ( vi = 0; vi < vcount; vi++ )
5821 {
5822 //ON_2fPoint& tex = m_T[vi];
5823 srf_st = &m_S[vi];
5824 s = srf_st->x;
5825 t = srf_st->y;
5826 // 19 April 2006 Dale Lear - added side setter so singular normals
5827 // are correctly evaluated RR 12482
5828 side = ( smax == s ) ? ((tmax == t) ? 3 : 2) : ((tmax == t) ? 4 : 1);
5829 srf.EvNormal( s, t, point, normal, side, hint );
5830 m_V[vi] = &point.x; // use ON_3fPoint double* conversion (quiets gcc)
5831 m_N[vi] = &normal.x; // use ON_3fVector double* conversion (quiets gcc)
5832 }
5833 }
5834 else
5835 {
5836 for ( vi = 0; vi < vcount; vi++ )
5837 {
5838 //ON_2fPoint& tex = m_T[vi];
5839 srf_st = &m_S[vi];
5840 s = srf_st->x;
5841 t = srf_st->y;
5842 srf.EvPoint( s, t, point, side, hint );
5843 m_V[vi] = &point.x;
5844 }
5845 }
5846 if ( HasFaceNormals() )
5847 {
5848 ComputeFaceNormals();
5849 }
5850 rc = true;
5851
5852 m_Ctag.Default();
5853 InvalidateVertexBoundingBox();
5854 InvalidateVertexNormalBoundingBox();
5855 DeleteMeshParameters();
5856 DestroyTree();
5857 }
5858 return rc;
5859 }
5860
SetMeshParameters(const ON_MeshParameters & mp)5861 void ON_Mesh::SetMeshParameters( const ON_MeshParameters& mp )
5862 {
5863 DeleteMeshParameters();
5864 m_mesh_parameters = new ON_MeshParameters(mp);
5865 }
5866
MeshParameters() const5867 const ON_MeshParameters* ON_Mesh::MeshParameters() const
5868 {
5869 return m_mesh_parameters;
5870 }
5871
DeleteMeshParameters()5872 void ON_Mesh::DeleteMeshParameters()
5873 {
5874 if ( m_mesh_parameters ) {
5875 delete m_mesh_parameters;
5876 m_mesh_parameters = 0;
5877 }
5878 }
5879
compare3fPoint(const ON_3fPoint * a,const ON_3fPoint * b)5880 static int compare3fPoint( const ON_3fPoint* a, const ON_3fPoint* b )
5881 {
5882 if ( a->x < b->x ) return -1;
5883 if ( a->x > b->x ) return 1;
5884 if ( a->y < b->y ) return -1;
5885 if ( a->y > b->y ) return 1;
5886 if ( a->z < b->z ) return -1;
5887 if ( a->z > b->z ) return 1;
5888 return 0;
5889 }
5890
compare3dPoint(const ON_3dPoint * a,const ON_3dPoint * b)5891 static int compare3dPoint( const ON_3dPoint* a, const ON_3dPoint* b )
5892 {
5893 if ( a->x < b->x ) return -1;
5894 if ( a->x > b->x ) return 1;
5895 if ( a->y < b->y ) return -1;
5896 if ( a->y > b->y ) return 1;
5897 if ( a->z < b->z ) return -1;
5898 if ( a->z > b->z ) return 1;
5899 return 0;
5900 }
5901
5902 using ON_COMPAR_LPVOID_LPVOID = int (*)(const void *, const void *);
5903
5904 static
GetPointMap(int pt_count,const ON_3fPoint * fV,const ON_3dPoint * dV,ON_SimpleArray<int> & pt_map)5905 int GetPointMap( int pt_count, const ON_3fPoint* fV, const ON_3dPoint* dV, ON_SimpleArray<int>& pt_map )
5906 {
5907 // Builds a mapping array, pt_map[], such that the length of pt_map[]
5908 // is pt_count and pt_map[i] == pt_map[j] if and only if pt[i] == pt[j]
5909 // as 3d points. The values in map[] run from 0 to max_pt_index.
5910 int vt0, vt1;
5911 ON_3fPoint fp0;
5912 ON_3dPoint dp0;
5913 int* map;
5914 int* index;
5915 int max_pt_index = 0;
5916 if ( pt_count > 0 && (dV || fV) )
5917 {
5918 index = (int*)onmalloc(pt_count*sizeof(*index));
5919
5920 if ( dV )
5921 ON_Sort( ON::quick_sort, index, dV, pt_count, sizeof(*dV), (ON_COMPAR_LPVOID_LPVOID)compare3dPoint );
5922 else
5923 ON_Sort( ON::quick_sort, index, fV, pt_count, sizeof(*fV), (ON_COMPAR_LPVOID_LPVOID)compare3fPoint );
5924
5925 pt_map.SetCapacity( pt_count );
5926 pt_map.SetCount( pt_count );
5927 map = pt_map.Array();
5928 for ( vt0 = 0; vt0 < pt_count; vt0++ )
5929 map[vt0] = -1;
5930
5931 if ( dV )
5932 {
5933 for (vt0 = 0; vt0 < pt_count; vt0 = vt1, max_pt_index++)
5934 {
5935 dp0 = dV[index[vt0]];
5936 for ( vt1=vt0+1; vt1<pt_count && 0==compare3dPoint(&dp0,dV+index[vt1]); vt1++ ) {
5937 // empty
5938 }
5939 while ( vt0 < vt1 ) {
5940 map[index[vt0++]] = max_pt_index;
5941 }
5942 }
5943 }
5944 else
5945 {
5946 for (vt0 = 0; vt0 < pt_count; vt0 = vt1, max_pt_index++)
5947 {
5948 fp0 = fV[index[vt0]];
5949 for ( vt1=vt0+1; vt1<pt_count && 0==compare3fPoint(&fp0,fV+index[vt1]); vt1++ ) {
5950 // empty
5951 }
5952 while ( vt0 < vt1 ) {
5953 map[index[vt0++]] = max_pt_index;
5954 }
5955 }
5956 }
5957 onfree(index);
5958 }
5959 if ( max_pt_index == 0 )
5960 pt_map.Destroy();
5961 return max_pt_index;
5962 }
5963
CullDegenerateFaces()5964 int ON_Mesh::CullDegenerateFaces()
5965 {
5966 // 30 December 2003 Dale Lear - fixed bug that was not culling
5967 // topologically degenerate faces.
5968
5969 int bad_count = 0;
5970 int degenerate_count = 0;
5971 const int fcount = m_F.Count();
5972 const int vcount = m_V.Count();
5973 ON_MeshFace f;
5974 int fi;
5975
5976 if ( fcount > 0 )
5977 {
5978 // use GetTopologyVertexMap() instead of calling Topology() because this mesh
5979 // may have lots of bogus faces that need to be culled.
5980 ON_SimpleArray<int> topv_map;
5981 const ON_3dPoint* dV = Mesh_dV(*this);
5982 const ON_3fPoint* fV = (0 == dV) ? m_V.Array() : 0;
5983 const int topv_count = GetPointMap( m_V.Count(), fV, dV, topv_map );
5984 if ( topv_count > 0 && topv_map.Count() == m_V.Count() )
5985 {
5986 ON_Workspace ws;
5987 const int* vtop = topv_map.Array();
5988 unsigned char* bBadFace = (unsigned char*)ws.GetMemory(fcount*sizeof(*bBadFace));
5989 memset( bBadFace, 0, fcount*sizeof(*bBadFace) );
5990 for ( fi = 0; fi < fcount; fi++ )
5991 {
5992 ON_MeshFace& f0 = m_F[fi];
5993 // set f.vi[] to values of topoligical indices
5994 {
5995 int f0vi = f0.vi[0];
5996 f.vi[0] = (f0vi < 0 || f0vi >= vcount) ? -1 : vtop[f0vi];
5997
5998 f0vi = f0.vi[1];
5999 f.vi[1] = (f0vi < 0 || f0vi >= vcount) ? -1 : vtop[f0vi];
6000
6001 f0vi = f0.vi[2];
6002 f.vi[2] = (f0vi < 0 || f0vi >= vcount) ? -1 : vtop[f0vi];
6003
6004 f0vi = f0.vi[3];
6005 f.vi[3] = (f0vi < 0 || f0vi >= vcount) ? -1 : vtop[f0vi];
6006 }
6007
6008 if ( !f.IsValid(topv_count) )
6009 {
6010 degenerate_count++;
6011 //f = m_F[fi];
6012 if ( f.vi[0] == f.vi[1] || f.vi[0] < 0 || f.vi[0] >= topv_count )
6013 {
6014 f0.vi[0] = f0.vi[1];
6015 f0.vi[1] = f0.vi[2];
6016 f0.vi[2] = f0.vi[3];
6017 f.vi[0] = f.vi[1];
6018 f.vi[1] = f.vi[2];
6019 f.vi[2] = f.vi[3];
6020 }
6021
6022 if ( f.vi[1] == f.vi[2] || f.vi[1] < 0 || f.vi[1] >= topv_count )
6023 {
6024 f0.vi[1] = f0.vi[2];
6025 f0.vi[2] = f0.vi[3];
6026 f.vi[1] = f.vi[2];
6027 f.vi[2] = f.vi[3];
6028 }
6029
6030 if ( f.vi[2] < 0 || f.vi[2] >= topv_count )
6031 {
6032 f0.vi[2] = f0.vi[3];
6033 f.vi[2] = f.vi[3];
6034 }
6035
6036 if ( f.vi[3] < 0 || f.vi[3] >= topv_count )
6037 {
6038 f0.vi[3] = f0.vi[2];
6039 f.vi[3] = f.vi[2];
6040 }
6041 else if ( f.vi[0] == f.vi[3] && f.vi[2] != f.vi[3] )
6042 {
6043 f0.vi[0] = f0.vi[1];
6044 f0.vi[1] = f0.vi[2];
6045 f0.vi[2] = f0.vi[3];
6046 f.vi[0] = f.vi[1];
6047 f.vi[1] = f.vi[2];
6048 f.vi[2] = f.vi[3];
6049 }
6050
6051 if ( !f0.IsValid(vcount) || !f.IsValid(topv_count) )
6052 {
6053 // face cannot be repaired by juggling vertex indices
6054 bBadFace[fi] = 1;
6055 bad_count++;
6056 }
6057 }
6058 }
6059
6060 if ( bad_count > 0 )
6061 {
6062 // remove bad faces.
6063 bool bHasFN = (m_FN.Count() == m_F.Count());
6064 if ( !bHasFN )
6065 m_FN.SetCount(0);
6066
6067 int fcnt = 0;
6068 for ( fi = fcnt = 0; fi < fcount; fi++ )
6069 {
6070 if ( !bBadFace[fi] )
6071 {
6072 if ( fcnt < fi )
6073 {
6074 m_F[fcnt] = m_F[fi];
6075 if ( bHasFN )
6076 m_FN[fcnt] = m_FN[fi];
6077 }
6078 fcnt++;
6079 }
6080 }
6081
6082 m_F.SetCount(fcnt);
6083 if ( bHasFN )
6084 m_FN.SetCount(fcnt);
6085 }
6086
6087 if ( degenerate_count > 0 )
6088 {
6089 // mesh was modified - destroy information that was
6090 // calculated using the old mesh
6091 DestroyTree();
6092 DestroyPartition();
6093 DestroyTopology();
6094 m_invalid_count = 0;
6095 m_quad_count = 0;
6096 m_triangle_count = 0;
6097 }
6098 }
6099 }
6100 return degenerate_count;
6101 }
6102
CullUnusedVertices()6103 int ON_Mesh::CullUnusedVertices()
6104 {
6105 //int cullcount = 0;
6106 int vi, fi;
6107 ON_Workspace ws;
6108 CullDegenerateFaces();
6109 int fcnt = m_F.Count();
6110 int vcnt = m_V.Count();
6111 int * vmap = ws.GetIntMemory( vcnt );
6112 memset ( vmap, 0, vcnt*sizeof(vmap[0]) );
6113 for ( fi = 0; fi < fcnt; fi++ )
6114 {
6115 const ON_MeshFace& f = m_F[fi];
6116 vmap[f.vi[0]] = 1;
6117 vmap[f.vi[1]] = 1;
6118 vmap[f.vi[2]] = 1;
6119 vmap[f.vi[3]] = 1;
6120 }
6121
6122 int newvcnt = 0;
6123 for ( vi = 0; vi < vcnt; vi++ )
6124 {
6125 if ( vmap[vi] )
6126 vmap[vi] = newvcnt++;
6127 else {
6128 vmap[vi] = -1;
6129 }
6130 }
6131
6132 if ( newvcnt == 0 )
6133 Destroy();
6134 else if ( newvcnt < vcnt )
6135 {
6136 DestroyTopology();
6137
6138 // buffer will hold up to vcnt 3d points
6139 void* buffer = ws.GetMemory(vcnt*9*sizeof(double));
6140
6141 if ( HasSurfaceParameters() ) {
6142 ON_2dPoint* s = (ON_2dPoint*)buffer;
6143 for ( vi = 0; vi < vcnt; vi++ )
6144 {
6145 if ( vmap[vi]>=0 )
6146 s[vmap[vi]] = m_S[vi];
6147 }
6148 memcpy( m_S.Array(), s, newvcnt*sizeof(s[0]) );
6149 m_S.SetCount(newvcnt);
6150 }
6151
6152 if ( HasDoublePrecisionVertices() )
6153 {
6154 ON_3dPointArray& D = DoublePrecisionVertices();
6155 if ( vcnt == D.Count() )
6156 {
6157 bool bValidDoubles = DoublePrecisionVerticesAreValid();
6158 ON_3dPoint* s = (ON_3dPoint*)buffer;
6159 for ( vi = 0; vi < vcnt; vi++ )
6160 {
6161 if ( vmap[vi]>=0 )
6162 s[vmap[vi]] = D[vi];
6163 }
6164 memcpy( D.Array(), s, newvcnt*sizeof(s[0]) );
6165 D.SetCount(newvcnt);
6166 if ( bValidDoubles )
6167 SetDoublePrecisionVerticesAsValid();
6168 }
6169 else
6170 {
6171 DestroyDoublePrecisionVertices();
6172 }
6173 }
6174
6175 if ( HasVertexNormals() ) {
6176 ON_3fVector* v = (ON_3fVector*)buffer;
6177 for ( vi = 0; vi < vcnt; vi++ )
6178 {
6179 if ( vmap[vi]>=0 )
6180 v[vmap[vi]] = m_N[vi];
6181 }
6182 memcpy( m_N.Array(), v, newvcnt*sizeof(v[0]) );
6183 m_N.SetCount(newvcnt);
6184 }
6185
6186 if ( HasTextureCoordinates() ) {
6187 ON_2fPoint* t = (ON_2fPoint*)buffer;
6188 for ( vi = 0; vi < vcnt; vi++ )
6189 {
6190 if ( vmap[vi]>=0 )
6191 t[vmap[vi]] = m_T[vi];
6192 }
6193 memcpy( m_T.Array(), t, newvcnt*sizeof(t[0]) );
6194 m_T.SetCount(newvcnt);
6195 }
6196
6197 if ( HasPrincipalCurvatures() ) {
6198 ON_SurfaceCurvature* k = (ON_SurfaceCurvature*)buffer;
6199 for ( vi = 0; vi < vcnt; vi++ )
6200 {
6201 if ( vmap[vi]>=0 )
6202 k[vmap[vi]] = m_K[vi];
6203 }
6204 memcpy( m_K.Array(), k, newvcnt*sizeof(k[0]) );
6205 m_K.SetCount(newvcnt);
6206 }
6207
6208 if ( HasVertexColors() ) {
6209 ON_Color* c = (ON_Color*)buffer;
6210 for ( vi = 0; vi < vcnt; vi++ )
6211 {
6212 if ( vmap[vi]>=0 )
6213 c[vmap[vi]] = m_C[vi];
6214 }
6215 memcpy( m_C.Array(), c, newvcnt*sizeof(c[0]) );
6216 m_C.SetCount(newvcnt);
6217 }
6218
6219 {
6220 bool bValidSingles = SinglePrecisionVerticesAreValid();
6221 ON_3fPoint* p = (ON_3fPoint*)buffer;
6222 for ( vi = 0; vi < vcnt; vi++ )
6223 {
6224 if ( vmap[vi]>=0 )
6225 p[vmap[vi]] = m_V[vi];
6226 }
6227 memcpy( m_V.Array(), p, newvcnt*sizeof(p[0]) );
6228 m_V.SetCount(newvcnt);
6229 if ( bValidSingles )
6230 SetSinglePrecisionVerticesAsValid();
6231 }
6232
6233 for ( fi = 0; fi < fcnt; fi++ )
6234 {
6235 ON_MeshFace& f = m_F[fi];
6236 f.vi[0] = vmap[f.vi[0]];
6237 f.vi[1] = vmap[f.vi[1]];
6238 f.vi[2] = vmap[f.vi[2]];
6239 f.vi[3] = vmap[f.vi[3]];
6240 }
6241
6242 }
6243 return vcnt - newvcnt;
6244 }
6245
Compact()6246 bool ON_Mesh::Compact()
6247 {
6248 // CullDegenerateFaces(); // CullUnusedVertices() does this
6249 CullUnusedVertices();
6250 m_V.Shrink();
6251 m_F.Shrink();
6252 m_N.Shrink();
6253 m_FN.Shrink();
6254 m_K.Shrink();
6255 m_C.Shrink();
6256 m_S.Shrink();
6257 m_T.Shrink();
6258 return true;
6259 }
6260
6261 ////////////////////////////////////////////////////////////////
6262 //
6263 // ON_SurfaceCurvature
6264 //
GaussianCurvature() const6265 double ON_SurfaceCurvature::GaussianCurvature() const
6266 {
6267 return k1*k2;
6268 }
6269
MeanCurvature() const6270 double ON_SurfaceCurvature::MeanCurvature() const
6271 {
6272 return 0.5*(k1+k2);
6273 }
6274
MinimumRadius() const6275 double ON_SurfaceCurvature::MinimumRadius() const
6276 {
6277 double k;
6278 k = (fabs(k1)>=fabs(k2)) ? fabs(k1) : fabs(k2); // k = maximum directional curvature
6279 k = ( k > 1.0e-300 ) ? 1.0/k : 1.0e300; // 1/k = minimum radius of curvature
6280 return k;
6281 }
6282
MaximumRadius() const6283 double ON_SurfaceCurvature::MaximumRadius() const
6284 {
6285 double k;
6286 if ( k1*k2 <= 0.0 ) {
6287 // if principal curvatures have opposite signs, there
6288 // is a direction with zero directional curvature
6289 k = 0.0;
6290 }
6291 else {
6292 k = (fabs(k1)<=fabs(k2)) ? fabs(k1) : fabs(k2);
6293 }
6294 // k = minimum directional curvature
6295 k = ( k > 1.0e-300 ) ? 1.0/k : 1.0e300; // 1/k = maximum radius of curvature
6296 return k;
6297 }
6298
6299 //double ON_SurfaceCurvature::NormalCurvature(const ON_3dVector& tangent) const
6300 //{
6301 // double c = tangent*e1;
6302 // double s = tangent*e2;
6303 // return k1*c*c + k2*s*s;
6304 //}
6305
6306 //double ON_SurfaceCurvature::NormalSectionCurvature( const ON_3dVector& section_normal, const ON_3dVector& surface_normal ) const
6307 //{
6308 // ON_3dVector tangent = ON_CrossProduct( section_normal, surface_normal );
6309 // if ( fabs(tangent.x) <= ON_SQRT_EPSILON && fabs(tangent.y) <= ON_SQRT_EPSILON && fabs(tangent.z) <= ON_SQRT_EPSILON )
6310 // tangent.Zero();
6311 // else
6312 // tangent.Unitize();
6313 // return NormalCurvature(tangent);
6314 //}
6315
ON_MeshTopology()6316 ON_MeshTopology::ON_MeshTopology()
6317 : m_mesh(0)
6318 , m_memchunk(0)
6319 , m_b32IsValid(0)
6320 {
6321 }
6322
~ON_MeshTopology()6323 ON_MeshTopology::~ON_MeshTopology()
6324 {
6325 Destroy();
6326 }
6327
Destroy()6328 void ON_MeshTopology::Destroy()
6329 {
6330 m_topv_map.Destroy();
6331 m_topv.Destroy();
6332 m_tope.Destroy();
6333 m_topf.Destroy();
6334 struct memchunk *p, *n;
6335 n = m_memchunk;
6336 while(n)
6337 {
6338 p = n;
6339 n = n->next;
6340 onfree(p);
6341 }
6342 m_memchunk = 0;
6343 if ( -1 != m_b32IsValid)
6344 m_b32IsValid = 0;
6345 }
6346
EmergencyDestroy()6347 void ON_MeshTopology::EmergencyDestroy()
6348 {
6349 m_mesh = 0;
6350 m_topv_map.EmergencyDestroy();
6351 m_topv.EmergencyDestroy();
6352 m_tope.EmergencyDestroy();
6353 m_topf.EmergencyDestroy();
6354 m_memchunk = 0;
6355 m_b32IsValid = 0;
6356 }
6357
TopVertexCount() const6358 int ON_MeshTopology::TopVertexCount() const
6359 {
6360 return m_topv.Count();
6361 }
6362
6363 //////////
6364 // number of topoligical edges
TopEdgeCount() const6365 int ON_MeshTopology::TopEdgeCount() const
6366 {
6367 return m_tope.Count();
6368 }
6369
6370 //////////
6371 // number of topoligical faces (same as m_mesh.FaceCount())
TopFaceCount() const6372 int ON_MeshTopology::TopFaceCount() const
6373 {
6374 return m_topf.Count();
6375 }
6376
TopVertexPoint(int vtopi) const6377 ON_3fPoint ON_MeshTopology::TopVertexPoint( int vtopi ) const
6378 {
6379 return m_mesh->m_V[m_topv[vtopi].m_vi[0]];
6380 }
6381
TopEdgeLine(int tope_index) const6382 ON_Line ON_MeshTopology::TopEdgeLine( int tope_index ) const
6383 {
6384 ON_Line L(ON_UNSET_POINT,ON_UNSET_POINT);
6385 if ( m_mesh && tope_index >= 0 && tope_index < m_tope.Count() )
6386 {
6387 const int* topvi = m_tope[tope_index].m_topvi;
6388 if ( topvi[0] >= 0 && topvi[0] < m_topv.Count()
6389 && topvi[1] >= 0 && topvi[1] < m_topv.Count() )
6390 {
6391 const ON_MeshTopologyVertex& v0 = m_topv[topvi[0]];
6392 const ON_MeshTopologyVertex& v1 = m_topv[topvi[1]];
6393 if ( v0.m_v_count > 0 && v0.m_vi && v1.m_v_count > 0 && v1.m_vi )
6394 {
6395 int vi0 = v0.m_vi[0];
6396 int vi1 = v1.m_vi[0];
6397 int vcount = m_mesh->m_V.Count();
6398 if ( vi0 >= 0 && vi0 < vcount && vi1 >= 0 && vi1 < vcount )
6399 {
6400 L.from = m_mesh->m_V[vi0];
6401 L.to = m_mesh->m_V[vi1];
6402 }
6403 }
6404 }
6405 }
6406 return L;
6407 }
6408
6409 ////////
6410 // returns index of edge that connects topological vertices
6411 // returns -1 if no edge is found.
TopEdge(int vtopi0,int vtopi1) const6412 int ON_MeshTopology::TopEdge( int vtopi0, int vtopi1 ) const
6413 {
6414 int i0, i1, ei, vi0;
6415 if ( vtopi0 > vtopi1 ) {vi0 = vtopi0; vtopi0 = vtopi1; vtopi1 = vi0;}
6416 if ( vtopi0 < vtopi1 ) {
6417 const int tope_count = TopEdgeCount();
6418 const ON_MeshTopologyEdge* tope = m_tope.Array(); // to speed array access
6419 i0 = 0;
6420 i1 = tope_count;
6421 while ( i0 < i1 )
6422 {
6423 ei = (i0+i1)/2;
6424 vi0 = tope[ei].m_topvi[0];
6425 if ( vi0 < vtopi0 ) {
6426 if ( i0 == ei )
6427 break;
6428 i0 = ei;
6429 }
6430 else if ( vi0 > vtopi0 ) {
6431 if ( i1 == ei )
6432 break;
6433 i1 = ei;
6434 }
6435 else {
6436 while (ei > 0 && tope[ei-1].m_topvi[0] == vtopi0 )
6437 ei--;
6438 while ( ei < tope_count && tope[ei].m_topvi[0] == vtopi0 ) {
6439 if ( tope[ei].m_topvi[1] == vtopi1 )
6440 return ei;
6441 ei++;
6442 }
6443 break;
6444 }
6445 }
6446 }
6447 return -1;
6448 }
6449
GetTopFaceVertices(int fi,int topvi[4]) const6450 bool ON_MeshTopology::GetTopFaceVertices( int fi, int topvi[4] ) const
6451 {
6452 if ( fi >= 0 && fi < m_mesh->m_F.Count() ) {
6453 const int* fvi = m_mesh->m_F[fi].vi;
6454 topvi[0] = m_topv_map[fvi[0]];
6455 topvi[1] = m_topv_map[fvi[1]];
6456 topvi[2] = m_topv_map[fvi[2]];
6457 topvi[3] = m_topv_map[fvi[3]];
6458 }
6459 return true;
6460 }
6461
SortVertexEdges() const6462 bool ON_MeshTopology::SortVertexEdges() const
6463 {
6464 bool rc = true;
6465 int topvi, topv_count = m_topv.Count();
6466 for ( topvi = 0; topvi < topv_count; topvi++ )
6467 {
6468 if ( !SortVertexEdges(topvi) )
6469 rc = false;
6470 }
6471 return rc;
6472 }
6473
6474 // TODO make public and add to header file new ON_SortIntArray
6475 static
ON_ReverseIntArray(int * e,std::size_t nel)6476 void ON_ReverseIntArray(
6477 int* e, // array of ints
6478 std::size_t nel // length of array
6479 )
6480 {
6481 int ei;
6482 std::size_t i;
6483 nel--;
6484 for ( i = 0; i<nel; i++, nel--)
6485 {
6486 ei = e[i];
6487 e[i] = e[nel];
6488 e[nel] = ei;
6489 }
6490 }
6491
SortVertexEdges(int topvi) const6492 bool ON_MeshTopology::SortVertexEdges(int topvi) const
6493 {
6494 if ( topvi < 0 || topvi >= m_topv.Count() )
6495 return false;
6496
6497 const ON_MeshTopologyVertex& topv = m_topv[topvi];
6498 if ( topv.m_tope_count < 2 )
6499 return true;
6500
6501 // Divide the edges that use this vertex into two sets:
6502 // e1f[] = indices of edges that bound 1 face, 3 or
6503 // more faces, or no faces (in that order).
6504 // e2f[] = indices of edges that bound exactly 2 faces.
6505 int i, j;
6506 int topei;
6507 int vei;
6508 int efcnt;
6509 int* new_tope = (int*)alloca(5*topv.m_tope_count*sizeof(new_tope[0]));
6510 int* e2f = new_tope + topv.m_tope_count;
6511 int* e1f = e2f + topv.m_tope_count;
6512 int e1fcnt = 0;
6513 int e2fcnt = 0;
6514 {
6515 int* e3f = e1f + topv.m_tope_count; // e3f[] = edges with 3 or more faces
6516 int* e0f = e3f + topv.m_tope_count; // e0f[] = edges with no faces
6517 int e3fcnt = 0;
6518 int e0fcnt = 0;
6519
6520 for ( vei = 0; vei < topv.m_tope_count; vei++ )
6521 {
6522 topei = topv.m_topei[vei];
6523 if ( topei >= 0 && topei < m_tope.Count() )
6524 {
6525 const ON_MeshTopologyEdge& tope = m_tope[topei];
6526 if ( tope.m_topvi[0] == topvi || tope.m_topvi[1] == topvi )
6527 {
6528 efcnt = m_tope[topei].m_topf_count;
6529 if ( efcnt < 0 )
6530 {
6531 ON_ERROR("ON_MeshTopology::SortVertexEdges(int topvi) - m_tope[topei].m_topf_count < 0");
6532 return false;
6533 }
6534 switch(efcnt)
6535 {
6536 case 0: // edge has no faces
6537 // (never happens if topology is from a valid ON_Mesh.)
6538 e0f[e0fcnt++] = topei;
6539 break;
6540
6541 case 1: // edge has exactly one face
6542 e1f[e1fcnt++] = topei;
6543 break;
6544
6545 case 2: // edge has exactly two faces
6546 e2f[e2fcnt++] = topei;
6547 break;
6548
6549 default: // edge has 3 or more faces
6550 // (happens when mesh is non-manifold)
6551 e3f[e3fcnt++] = topei;
6552 break;
6553 }
6554 }
6555 }
6556 }
6557
6558 // append list of non-manifold edges (3 or more faces) to e1f[]
6559 for ( i = 0; i < e3fcnt; i++ )
6560 {
6561 e1f[e1fcnt++] = e3f[i];
6562 }
6563
6564 // append list of wire edges (0 faces) to e1f[]
6565 for ( i = 0; i < e0fcnt; i++ )
6566 {
6567 e1f[e1fcnt++] = e0f[i];
6568 }
6569
6570 e0fcnt = 0;
6571 e3fcnt = 0;
6572 e0f = 0;
6573 e3f = 0;
6574 }
6575
6576 // Put the edge indices in new_tope[] in radial order.
6577 // NOTE: The code below works for non-oriented meshes and
6578 // non-manifold meshes. If you change the code, you
6579 // must make sure that it still works in these cases.
6580 if ( e1fcnt + e2fcnt != topv.m_tope_count )
6581 {
6582 ON_ERROR("ON_MeshTopology::SortVertexEdges() input vertex had bogus m_topei[]");
6583 return false;
6584 }
6585 int fi = -1;
6586 int next_topei = -1;
6587 int efi, fecnt, fei, next_fei;
6588 vei = 0;
6589 int vei0 = 0;
6590 int vei1 = 0;
6591 int elist_dir = 0;
6592 while(vei < topv.m_tope_count)
6593 {
6594 if ( next_topei >= 0 )
6595 {
6596 // continue with this group of edges
6597 topei = next_topei;
6598 next_topei = -1;
6599 }
6600 else if ( e1fcnt > 0 )
6601 {
6602 // start a new group of edges
6603 topei = *e1f++;
6604 e1fcnt--;
6605 vei1 = vei;
6606 }
6607 else if ( e2fcnt > 0 )
6608 {
6609 // start a new group of edges
6610 // (this only happens in non-manifold cases)
6611 topei = *e2f++;
6612 e2fcnt--;
6613 vei1 = vei;
6614 }
6615 else
6616 {
6617 ON_ERROR("ON_MeshTopology::SortVertexEdges() input vertex had bogus topology information.");
6618 return false;
6619 }
6620
6621 if ( vei0 < vei1 )
6622 {
6623 if ( 1 == elist_dir )
6624 {
6625 // 30 December 2003 Dale Lear added this feature
6626 // edges new_tope[vei0],...,new_tope[vei1-1] are radially sorted
6627 // but the order is not counterclockwise with respect to
6628 // the normal of the face attached to the first edge.
6629 // So, this group of edges in new_tope[] needs to
6630 // be reversed.
6631 ON_ReverseIntArray( new_tope+vei0, vei1-vei0 );
6632 }
6633 elist_dir = 0;
6634 vei0 = vei1;
6635 }
6636
6637 new_tope[vei++] = topei;
6638
6639 // search faces connected to tope for the next edge
6640 const ON_MeshTopologyEdge& tope = m_tope[topei];
6641 for ( efi = 0; next_topei < 0 && efi < tope.m_topf_count; efi++ )
6642 {
6643 fi = tope.m_topfi[efi];
6644 if ( fi < 0 || fi >= m_topf.Count() )
6645 {
6646 // bogus face index into m_topf[] array
6647 continue;
6648 }
6649
6650 // find fei so that topf.m_topei[fei] = topei
6651 const ON_MeshTopologyFace& topf = m_topf[fi];
6652 fecnt = topf.IsQuad() ? 4 : 3;
6653 for ( fei = 0; fei < fecnt; fei++ )
6654 {
6655 if ( topf.m_topei[fei] != topei )
6656 continue;
6657
6658 if ( tope.m_topvi[0] == topvi )
6659 {
6660 next_fei = ( topf.m_reve[fei] ) ? 1 : -1;
6661 }
6662 else
6663 {
6664 next_fei = ( topf.m_reve[fei] ) ? -1 : 1;
6665 }
6666
6667 if ( 0 == elist_dir )
6668 elist_dir = next_fei;
6669
6670 next_fei = (fei+next_fei+fecnt)%fecnt;
6671 next_topei = topf.m_topei[next_fei];
6672
6673 // next_topei = candidate for the next edge
6674 // Check to see that it is available by
6675 // finding it in the e1f[] or e2f[] arrays.
6676 j = 0;
6677 for ( i = 0; i < e1fcnt; i++ )
6678 {
6679 if ( next_topei == e1f[i] )
6680 {
6681 // found it in the e1f list.
6682 for ( j = i+1; j < e1fcnt; j++ )
6683 e1f[j-1] = e1f[j];
6684 e1fcnt--;
6685 break;
6686 }
6687 }
6688 if ( 0 == j )
6689 {
6690 // search the e2f[] list
6691 for ( i = 0; i < e2fcnt; i++ )
6692 {
6693 if ( next_topei == e2f[i] )
6694 {
6695 for ( j = i+1; j < e2fcnt; j++ )
6696 e2f[j-1] = e2f[j];
6697 e2fcnt--;
6698 break;
6699 }
6700 }
6701 }
6702 if ( 0 == j )
6703 {
6704 // the candidate was already used, check the next
6705 // face attached to this edge.
6706 next_topei = -1;
6707 }
6708 else
6709 {
6710 break;
6711 }
6712 }
6713 }
6714 }
6715
6716 if ( topv.m_tope_count != vei )
6717 {
6718 ON_ERROR("ON_MeshTopology::SortVertexEdges() edge sorting error.");
6719 return false;
6720 }
6721
6722 vei1 = vei;
6723 if ( vei0 < vei1 )
6724 {
6725 if ( 1 == elist_dir )
6726 {
6727 // 30 December 2003 Dale Lear added this feature
6728 // edges new_tope[vei0],...,new_tope[vei1-1] are radially sorted
6729 // but the order is not counterclockwise with respect to
6730 // the normal of the face attached to the first edge.
6731 // So, this group of edges in new_tope[] needs to
6732 // be reversed.
6733 ON_ReverseIntArray( new_tope+vei0, vei1-vei0 );
6734 }
6735 elist_dir = 0;
6736 vei0 = vei1;
6737 }
6738
6739 int* topv_m_topei = const_cast<int*>(topv.m_topei);
6740 for ( vei = 0; vei < topv.m_tope_count; vei++ )
6741 {
6742 topv_m_topei[vei] = new_tope[vei];
6743 }
6744
6745 return true;
6746 }
6747
GetIntArray(int length)6748 int* ON_MeshTopology::GetIntArray(int length)
6749 {
6750 int* a = 0;
6751 if ( length > 0 ) {
6752 struct memchunk* pm;
6753 pm = (struct memchunk*)onmalloc(length*sizeof(*a) + sizeof(*pm));
6754 if ( pm ) {
6755 pm->next = m_memchunk;
6756 m_memchunk = pm++;
6757 a = (int*)pm;
6758 }
6759 }
6760 return a;
6761 }
6762
IsTriangle() const6763 bool ON_MeshTopologyFace::IsTriangle() const
6764 {
6765 return ( m_topei[2] == m_topei[3] && m_topei[0] != m_topei[1] )
6766 ? true : false;
6767 }
6768
IsQuad() const6769 bool ON_MeshTopologyFace::IsQuad() const
6770 {
6771 return ( m_topei[2] != m_topei[3] ) ? true : false;
6772 }
6773
IsValid() const6774 bool ON_MeshTopologyFace::IsValid() const
6775 {
6776 return ( m_topei[0] != m_topei[1] ) ? true : false;
6777 }
6778
6779
IsValid() const6780 bool ON_MeshTopology::IsValid() const
6781 {
6782 ON_Workspace ws;
6783 int topvi, topei, topfi, vi, fi, j, jmax, k, tfvi[4];
6784 ON_3fPoint p;
6785
6786 WaitUntilReady(0);
6787
6788 // simple checks
6789 if ( 1 != m_b32IsValid )
6790 return false;
6791 if ( !m_mesh )
6792 return false;
6793 if ( this != &(m_mesh->Topology()) )
6794 return false;
6795 const int v_count = m_mesh->VertexCount();
6796 const int f_count = m_mesh->FaceCount();
6797 const int topv_count = TopVertexCount();
6798 const int tope_count = TopEdgeCount();
6799 const int topf_count = TopFaceCount();
6800 if ( topv_count > v_count || topv_count < 0 )
6801 return false;
6802 if ( topv_count == 0 && v_count > 0 )
6803 return false;
6804 if ( topf_count != f_count )
6805 return false;
6806 if ( f_count > 0 && tope_count < 3 )
6807 return false;
6808 if ( m_topv_map.Count() != v_count )
6809 return false;
6810
6811 // check vertex information
6812 for ( vi = 0; vi < v_count; vi++ ) {
6813 topvi = m_topv_map[vi];
6814 if ( topvi < 0 || topvi >= topv_count )
6815 return false;
6816 }
6817
6818 char* vCheck = (char*)ws.GetMemory( v_count*sizeof(*vCheck) );
6819 memset( vCheck, 0, v_count*sizeof(*vCheck) );
6820 for ( topvi = 0; topvi < topv_count; topvi++ )
6821 {
6822 const ON_MeshTopologyVertex& topv = m_topv[topvi];
6823 if ( topv.m_v_count <= 0 )
6824 return false;
6825 if ( !topv.m_vi )
6826 return false;
6827 p = TopVertexPoint(topvi);
6828 for ( j = 0; j < topv.m_v_count; j++ ) {
6829 vi = topv.m_vi[j];
6830 if ( vi < 0 )
6831 return false;
6832 if ( vi >= v_count )
6833 return false;
6834 if ( vCheck[vi] != 0 )
6835 return false; // mesh.m_V[vi] is referenced multiple times
6836 if ( compare3fPoint( &p, &m_mesh->m_V[vi] ) )
6837 return false; // mesh.m_V[vi] not at same location as topv
6838 if ( m_topv_map[vi] != topvi )
6839 return false;
6840 vCheck[vi] = 1;
6841 }
6842
6843 // check that edges in m_topei[] list have topvi has a start/end
6844 if ( topv.m_tope_count < 0 )
6845 return false;
6846 if ( topv.m_tope_count == 0 && topv.m_topei )
6847 return false; // array should be NULL
6848 if ( topv.m_tope_count > 0 && !topv.m_topei )
6849 return false; // array should not be NULL
6850 for ( j = 0; j < topv.m_tope_count; j++ ) {
6851 topei = topv.m_topei[j];
6852 if ( topei < 0 )
6853 return false;
6854 if ( topei >= tope_count )
6855 return false;
6856 const ON_MeshTopologyEdge& tope = m_tope[topei];
6857 if ( tope.m_topvi[0] != topvi && tope.m_topvi[1] != topvi )
6858 return false; // edge doesn't reference this top vtx
6859 for ( k = 0; k < j; k++ ) {
6860 if ( topv.m_topei[k] == topei )
6861 return false; // edge listed multiple times
6862 }
6863 }
6864 }
6865
6866 // make sure every mesh.m_V[] maps to a topoligical vertex
6867 for ( vi = 0; vi < v_count; vi++ ) {
6868 if ( vCheck[vi] != 1 )
6869 return false; // mesh.m_V[vi] is not referenced
6870 topvi = m_topv_map[vi];
6871 if ( topvi < 0 )
6872 return false;
6873 if ( topvi >= topv_count )
6874 return false;
6875 const ON_MeshTopologyVertex& topv = m_topv[topvi];
6876 for ( j = 0; j < topv.m_v_count; j++ ) {
6877 if ( topv.m_vi[j] == vi )
6878 break;
6879 }
6880 if ( j >= topv.m_v_count )
6881 return false; // bogus m_topv_map[] array
6882 }
6883
6884 // check edges
6885 for ( topei = 0; topei < tope_count; topei++ ) {
6886 const ON_MeshTopologyEdge& tope = m_tope[topei];
6887 if ( tope.m_topvi[0] < 0 || tope.m_topvi[0] >= topv_count )
6888 return false;
6889 if ( tope.m_topvi[1] < 0 || tope.m_topvi[1] >= topv_count )
6890 return false;
6891 if ( tope.m_topvi[0] == tope.m_topvi[1] )
6892 return false;
6893
6894 const ON_MeshTopologyVertex& topv0 = m_topv[tope.m_topvi[0]];
6895 for ( j = 0; j < topv0.m_tope_count; j++ ) {
6896 if ( topv0.m_topei[j] == topei )
6897 break;
6898 }
6899 if ( j >= topv0.m_tope_count )
6900 return false; // start vtx not linked to edge
6901
6902 const ON_MeshTopologyVertex& topv1 = m_topv[tope.m_topvi[1]];
6903 for ( j = 0; j < topv1.m_tope_count; j++ ) {
6904 if ( topv1.m_topei[j] == topei )
6905 break;
6906 }
6907 if ( j >= topv1.m_tope_count )
6908 return false; // end vtx not linked to edge
6909
6910 if ( tope.m_topf_count < 0 )
6911 return false;
6912 if ( tope.m_topf_count == 0 && tope.m_topfi )
6913 return false; // array should be NULL
6914 if ( tope.m_topf_count > 0 && !tope.m_topfi )
6915 return false; // array should not be NULL
6916 for ( j = 0; j < tope.m_topf_count; j++ ) {
6917 fi = tope.m_topfi[j];
6918 if ( fi < 0 || fi >= f_count )
6919 return false;
6920 const ON_MeshTopologyFace& topf = m_topf[fi];
6921 for ( k = 0; k < 4; k++ ) {
6922 if ( topf.m_topei[k] == topei )
6923 break;
6924 }
6925 if ( k >= 4 )
6926 return false; // edge not in face's list
6927 }
6928 }
6929
6930 // check faces
6931 for ( fi = 0; fi < f_count; fi++ ) {
6932 topfi = fi;
6933 const ON_MeshTopologyFace& topf = m_topf[topfi];
6934 const ON_MeshFace& f = m_mesh->m_F[fi];
6935 if ( topf.m_topei[0] < 0 || topf.m_topei[0] >= tope_count )
6936 return false;
6937 if ( topf.m_topei[1] < 0 || topf.m_topei[1] >= tope_count )
6938 return false;
6939 if ( topf.m_topei[2] < 0 || topf.m_topei[2] >= tope_count )
6940 return false;
6941 if ( topf.m_topei[3] < 0 || topf.m_topei[3] >= tope_count )
6942 return false;
6943 tfvi[0] = m_topv_map[f.vi[0]];
6944 tfvi[1] = m_topv_map[f.vi[1]];
6945 tfvi[2] = m_topv_map[f.vi[2]];
6946 tfvi[3] = m_topv_map[f.vi[3]];
6947 if ( topf.m_topei[0] != 0 || topf.m_topei[1] != 0
6948 || topf.m_topei[2] != 0 || topf.m_topei[3] != 0 ) {
6949 if ( !f.IsValid(v_count) )
6950 return false;
6951 if ( f.IsTriangle() ) {
6952 if (topf.m_topei[2] != topf.m_topei[3] )
6953 return false;
6954 jmax = 3;
6955 }
6956 else {
6957 if (topf.m_topei[2] == topf.m_topei[3] )
6958 return false;
6959 jmax = 4;
6960 }
6961 for ( j = 0; j < jmax; j++ ) {
6962 const ON_MeshTopologyEdge& tope = m_tope[topf.m_topei[j]];
6963 for ( k = 0; k < tope.m_topf_count; k++ ) {
6964 if ( tope.m_topfi[k] == topfi )
6965 break;
6966 }
6967 if ( k >= tope.m_topf_count )
6968 return false;
6969
6970 // topedge m_tope[topf.m_topei[j]] ENDS at topvtx m_topv[tfvi[j]]
6971 if ( topf.m_reve[j] ) {
6972 if ( tope.m_topvi[1] != tfvi[(j+3)%4] )
6973 return false;
6974 if ( tope.m_topvi[0] != tfvi[j] )
6975 return false;
6976 }
6977 else {
6978 if ( tope.m_topvi[0] != tfvi[(j+3)%4] )
6979 return false;
6980 if ( tope.m_topvi[1] != tfvi[j] )
6981 return false;
6982 }
6983 }
6984 }
6985 else {
6986 // all topf.m_topei[] must be zeros
6987 if ( topf.m_topei[0] != 0 || topf.m_topei[1] != 0
6988 || topf.m_topei[2] != 0 || topf.m_topei[3] != 0 )
6989 return false;
6990 }
6991 }
6992 return true;
6993 }
6994
Dump(ON_TextLog & dump) const6995 void ON_MeshTopology::Dump( ON_TextLog& dump ) const
6996 {
6997 ON_3fPoint p;
6998 int vi, ei, fi, j;
6999 const int topv_count = m_topv.Count();
7000 const int tope_count = m_tope.Count();
7001 const int topf_count = m_topf.Count();
7002
7003 // topological vertex information
7004 for ( vi = 0; vi < topv_count; vi++ ) {
7005 const ON_MeshTopologyVertex& v = m_topv[vi];
7006 dump.Print("topv %d: ",vi);
7007 if (m_mesh) {
7008 // dump geometric location of this vertex
7009 p = m_mesh->m_V[v.m_vi[0]];
7010 dump.Print("{%g,%g,%g} ", p.x, p.y, p.z);
7011 }
7012
7013 // list all mesh geometry viertices that are coincident with this
7014 // topological vertex
7015 dump.Print("(");
7016 for ( j = 0; j < v.m_v_count; j++ ) {
7017 if ( j )
7018 dump.Print(",");
7019 dump.Print("m_V[%d]",v.m_vi[j]);
7020 }
7021
7022 // list all toplogical edges that begin/end at this topological vertex
7023 dump.Print(") (");
7024 for ( j = 0; j < v.m_tope_count; j++ ) {
7025 if ( j )
7026 dump.Print(",");
7027 dump.Print("%d",v.m_topei[j]);
7028 }
7029 dump.Print(")\n");
7030 }
7031
7032 // topological edge information
7033 for ( ei = 0; ei < tope_count; ei++ ) {
7034 const ON_MeshTopologyEdge& e = m_tope[ei];
7035 dump.Print("tope %d: topv%d to topvv%d (", ei, e.m_topvi[0], e.m_topvi[1] );
7036 // list all mesh topolical faces attached to this topolical edge
7037 for ( j = 0; j < e.m_topf_count; j++ ) {
7038 if (j)
7039 dump.Print(",");
7040 dump.Print("f%d",e.m_topfi[j]);
7041 }
7042 dump.Print(")\n");
7043 }
7044
7045 // topological face information
7046 // mesh m_F[] index = mesh topology m_topf[] index
7047 for ( fi = 0; fi < topf_count; fi++ ) {
7048 const ON_MeshTopologyFace& f = m_topf[fi];
7049 dump.Print("topf %d: (",fi);
7050 for ( j = 0; j < 4; j++ ) {
7051 if ( j == 3 && f.m_topei[3] == f.m_topei[2] )
7052 break; // triangular face
7053 if (j)
7054 dump.Print(",");
7055 dump.Print("%ce%d",f.m_reve[j]?'-':'+',f.m_topei[j]);
7056 }
7057 dump.Print(")\n");
7058 }
7059 }
7060
7061
Create()7062 bool ON_MeshTopology::Create()
7063 {
7064 // When -1 == m_b32IsValid, this ON_MeshTopology
7065 // is the m_top field on an ON_Mesh and is being
7066 // created in an ON_Mesh::Topology() call and a
7067 // sleep lock is used to keep ON_Mesh::Topology()
7068 // thread safe.
7069 //
7070 // When 0 == m_b32IsValid, this ON_MeshTopology
7071 // is being created stand alone.
7072 //
7073 // When 1 == m_b32IsValid, this ON_MeshTopology
7074 // is already created and valid.
7075
7076 if ( 1 == m_b32IsValid )
7077 return true;
7078
7079 const int b32IsValid0 = m_b32IsValid;
7080
7081 if ( 0 == b32IsValid0 )
7082 {
7083 // no sleep lock is being used
7084 m_b32IsValid = -1;
7085 }
7086 int b32IsValid = b32IsValid0;
7087
7088 while ( 0 == b32IsValid || -1 == b32IsValid )
7089 {
7090 // while() is for flow control - this is a while() {... break;} statment.
7091 Destroy();
7092 b32IsValid = 0;
7093
7094 // build vertex topology information
7095 const int fcount = m_mesh->FaceCount();
7096 const int vcount = m_mesh->VertexCount();
7097 if ( 0 == vcount )
7098 break;
7099
7100 int* vindex = GetIntArray(vcount);
7101 m_topv_map.SetCapacity( vcount );
7102 m_topv_map.SetCount( vcount );
7103 if ( 0 == m_mesh->GetVertexLocationIds( 0, m_topv_map.Array(), vindex ) )
7104 {
7105 Destroy();
7106 break;
7107 }
7108
7109 {
7110 int topv_count = m_topv_map[vindex[vcount-1]]+1;
7111 m_topv_map.SetCapacity( vcount );
7112 m_topv_map.SetCount( vcount );
7113 m_topv.SetCapacity( topv_count );
7114 int vt0, vt1, topvi;
7115 ON_3fPoint p0;
7116 for (vt0 = 0; vt0 < vcount; vt0 = vt1)
7117 {
7118 topvi = m_topv.Count();
7119 #if defined(ON_DEBUG)
7120 if ( topvi != m_topv_map[vindex[vt0]] )
7121 {
7122 // 20 April 2010 Dale Lear:
7123 // If you get this error, save the mesh and tell Dale Lear.
7124 ON_ERROR("ON_MeshTopology::Create() - topvi != vertex id from GetVertexLocationIds()");
7125 }
7126 #endif
7127 ON_MeshTopologyVertex& topv = m_topv.AppendNew();
7128 topv.m_vi = vindex+vt0;
7129 for ( vt1=vt0+1; vt1<vcount && topvi == m_topv_map[vindex[vt1]]; vt1++ ) {
7130 // empty
7131 }
7132 topv.m_v_count = vt1-vt0;
7133 }
7134 }
7135
7136 // build edge topology information
7137 const int topv_count = m_topv.Count();
7138 if ( topv_count >= 2 )
7139 {
7140 int ei, ecnt, fi, vi0, vi1, efi, topfvi[4];
7141 ON_MeshFace f;
7142
7143 if ( fcount > 0 && vcount > 0 )
7144 {
7145 // When working on this code be sure to test bug# 9271 and 9254 and file fsv_r4.3dm
7146 ON_Workspace ws;
7147 struct ON_MeshFaceSide* e = (struct ON_MeshFaceSide*)ws.GetMemory( 4*fcount*sizeof(*e) );
7148 ecnt = m_mesh->GetMeshFaceSideList( m_topv_map.Array(), e );
7149
7150 if ( ecnt > 0 )
7151 {
7152 ON_SortMeshFaceSidesByVertexIndex( ecnt, e );
7153
7154 // count number of topological edges and allocate storage
7155 int etop_count = 0;
7156 ei = 0;
7157 while( ei < ecnt )
7158 {
7159 vi0 = e[ei].vi[0];
7160 vi1 = e[ei].vi[1];
7161 ei++;
7162 while (ei < ecnt && e[ei].vi[0] == vi0 && e[ei].vi[1] == vi1 )
7163 ei++;
7164 etop_count++;
7165 }
7166 m_tope.SetCapacity(etop_count);
7167
7168 // fill in the m_tope[] array information
7169 int* efindex = GetIntArray(ecnt);
7170 for ( ei = 0; ei < ecnt; /*empty*/ )
7171 {
7172 ON_MeshTopologyEdge& tope = m_tope.AppendNew();
7173 tope.m_topvi[0] = vi0 = e[ei].vi[0];
7174 tope.m_topvi[1] = vi1 = e[ei].vi[1];
7175 tope.m_topfi = efindex;
7176 tope.m_topf_count = 0;
7177 *efindex++ = e[ei].fi;
7178 tope.m_topf_count++;
7179 ei++;
7180 while( ei < ecnt && e[ei].vi[0] == vi0 && e[ei].vi[1] == vi1 )
7181 {
7182 *efindex++ = e[ei].fi;
7183 tope.m_topf_count++;
7184 ei++;
7185 }
7186 }
7187 efindex = 0; // memory deallocated by ~ON_MeshTopology()
7188
7189 // connect vertices to edges;
7190 ecnt = m_tope.Count();
7191 int* ve_count = (int*)onmalloc(topv_count*sizeof(*ve_count));
7192 // set ve_count[topvi] = number of edges that begin or end at m_topv[topvi]
7193 memset( ve_count, 0, topv_count*sizeof(*ve_count));
7194 for ( ei = 0; ei < ecnt; ei++ ) {
7195 const ON_MeshTopologyEdge& tope = m_tope[ei];
7196 ve_count[tope.m_topvi[0]]++;
7197 ve_count[tope.m_topvi[1]]++;
7198 }
7199 // allocate and distribute storage for the mopv.m_topei[] array
7200 int* vei = GetIntArray(2*ecnt);
7201 for ( vi0 = 0; vi0 < topv_count; vi0++ ) {
7202 ON_MeshTopologyVertex& topv = m_topv[vi0];
7203 if ( ve_count[vi0] > 0 ) {
7204 topv.m_topei = vei;
7205 vei += ve_count[vi0];
7206 }
7207 }
7208 onfree(ve_count); ve_count = 0;
7209 vei = 0; // memory deallocated by ~ON_MeshTopology()
7210
7211 // fill in the m_topv[].m_topei[] values
7212 for ( ei = 0; ei < ecnt; ei++ ) {
7213 ON_MeshTopologyEdge& tope = m_tope[ei];
7214 ON_MeshTopologyVertex& topv0 = m_topv[tope.m_topvi[0]];
7215 ON_MeshTopologyVertex& topv1 = m_topv[tope.m_topvi[1]];
7216 vei = const_cast<int*>(topv0.m_topei);
7217 vei[topv0.m_tope_count++] = ei;
7218 vei = const_cast<int*>(topv1.m_topei);
7219 vei[topv1.m_tope_count++] = ei;
7220 }
7221
7222 // build face topology information
7223 m_topf.SetCapacity(fcount);
7224 m_topf.SetCount(fcount);
7225 memset( m_topf.Array(), 0, fcount*sizeof(ON_MeshTopologyFace) );
7226 for ( fi = 0; fi < fcount; fi++ ) {
7227 ON_MeshTopologyFace& f = m_topf[fi];
7228 f.m_topei[0] = -1;
7229 f.m_topei[1] = -1;
7230 f.m_topei[2] = -1;
7231 f.m_topei[3] = -1;
7232 }
7233 for ( ei = 0; ei < ecnt; ei++ ) {
7234 ON_MeshTopologyEdge& tope = m_tope[ei];
7235 for (efi = 0; efi < tope.m_topf_count; efi++ ) {
7236 // Because ON_MeshFace.vi[2] == ON_MeshFace.vi[3] for triangles,
7237 // we have topf.m_topei[j] BEGIN at ON_MeshFace.vi[(j+3)%4] and END at ON_MeshFace.vi[j]
7238 fi = tope.m_topfi[efi];
7239 f = m_mesh->m_F[fi];
7240 topfvi[0] = m_topv_map[f.vi[0]];
7241 topfvi[1] = m_topv_map[f.vi[1]];
7242 topfvi[2] = m_topv_map[f.vi[2]];
7243 topfvi[3] = m_topv_map[f.vi[3]];
7244 ON_MeshTopologyFace& topf = m_topf[fi];
7245 vi0 = tope.m_topvi[0];
7246 vi1 = tope.m_topvi[1];
7247 // unroll loop for speed
7248 if ( vi0 == topfvi[3] && vi1 == topfvi[0] ) {
7249 topf.m_topei[0] = ei;
7250 topf.m_reve[0] = 0;
7251 }
7252 else if ( vi0 == topfvi[0] && vi1 == topfvi[1] ) {
7253 topf.m_topei[1] = ei;
7254 topf.m_reve[1] = 0;
7255 }
7256 else if ( vi0 == topfvi[1] && vi1 == topfvi[2] ) {
7257 topf.m_topei[2] = ei;
7258 topf.m_reve[2] = 0;
7259 }
7260 else if ( vi0 == topfvi[2] && vi1 == topfvi[3] ) {
7261 topf.m_topei[3] = ei;
7262 topf.m_reve[3] = 0;
7263 }
7264 else if ( vi1 == topfvi[3] && vi0 == topfvi[0] ) {
7265 topf.m_topei[0] = ei;
7266 topf.m_reve[0] = 1;
7267 }
7268 else if ( vi1 == topfvi[0] && vi0 == topfvi[1] ) {
7269 topf.m_topei[1] = ei;
7270 topf.m_reve[1] = 1;
7271 }
7272 else if ( vi1 == topfvi[1] && vi0 == topfvi[2] ) {
7273 topf.m_topei[2] = ei;
7274 topf.m_reve[2] = 1;
7275 }
7276 else if ( vi1 == topfvi[2] && vi0 == topfvi[3] ) {
7277 topf.m_topei[3] = ei;
7278 topf.m_reve[3] = 1;
7279 }
7280 }
7281 }
7282 for ( fi = 0; fi < fcount; fi++ ) {
7283 ON_MeshTopologyFace& f = m_topf[fi];
7284 bool bIsGood = false;
7285 if ( f.m_topei[0] >= 0 && f.m_topei[1] >= 0 && f.m_topei[2] >=0
7286 && f.m_topei[0] != f.m_topei[1]
7287 && f.m_topei[1] != f.m_topei[2]
7288 && f.m_topei[2] != f.m_topei[0]
7289 ) {
7290 if ( m_mesh->m_F[fi].IsTriangle() ) {
7291 bIsGood = true;
7292 f.m_topei[3] = f.m_topei[2];
7293 }
7294 else if ( f.m_topei[3] >= 0
7295 && f.m_topei[0] != f.m_topei[3]
7296 && f.m_topei[1] != f.m_topei[3]
7297 && f.m_topei[2] != f.m_topei[3] ) {
7298 bIsGood = true;
7299 }
7300 }
7301 if ( !bIsGood ) {
7302 f.m_topei[0] = 0;
7303 f.m_topei[1] = 0;
7304 f.m_topei[2] = 0;
7305 f.m_topei[3] = 0;
7306 f.m_reve[0] = 0;
7307 f.m_reve[1] = 0;
7308 f.m_reve[2] = 0;
7309 f.m_reve[3] = 0;
7310 }
7311 }
7312
7313 }
7314 }
7315 }
7316
7317 b32IsValid = 1;
7318 break;
7319 }
7320
7321 if ( -1 != b32IsValid0 )
7322 {
7323 // no sleep lock is in use
7324 m_b32IsValid = b32IsValid;
7325 }
7326
7327 if ( 1 != b32IsValid )
7328 {
7329 Destroy();
7330 }
7331
7332 return (1 == b32IsValid);
7333 }
7334
7335 struct tagFPT
7336 {
7337 int x, y, z;
7338 };
7339
7340 //static int compare_fpt( const struct tagFPT* a, const struct tagFPT* b )
7341 //{
7342 // if ( a->x < b->x )
7343 // return -1;
7344 // if ( a->x > b->x )
7345 // return 1;
7346 // if ( a->y < b->y )
7347 // return -1;
7348 // if ( a->y > b->y )
7349 // return 1;
7350 // if ( a->z < b->z )
7351 // return -1;
7352 // if ( a->z > b->z )
7353 // return 1;
7354 // return 0;
7355 //}
7356
compare_pmark(const int * a,const int * b)7357 static int compare_pmark( const int* a, const int* b )
7358 {
7359 if ( *a < *b )
7360 return -1;
7361 if ( *a > *b )
7362 return 1;
7363 if ( a < b )
7364 return -1;
7365 if ( a > b )
7366 return 1;
7367 return 0;
7368 }
7369
compare_vmap(const void * a,const void * b)7370 static int compare_vmap( const void* a, const void* b )
7371 {
7372 int i = *((int*)a);
7373 int j = *((int*)b);
7374 if ( i < j )
7375 return -1;
7376 if ( i > j )
7377 return 1;
7378 return 0;
7379 }
7380
DupVertex(ON_Mesh * mesh,int vi)7381 static int DupVertex( ON_Mesh* mesh, int vi )
7382 {
7383 int vertex_count = mesh->m_V.Count();
7384 ON_3fVector n;
7385 ON_3fPoint v;
7386 ON_Color c;
7387 ON_2fPoint t;
7388 ON_SurfaceCurvature k;
7389 v = mesh->m_V[vi];
7390 mesh->m_V.Append(v);
7391 if (mesh->m_N.Count() == vertex_count) {
7392 n = mesh->m_N[vi];
7393 mesh->m_N.Append(n);
7394 }
7395 if (mesh->m_T.Count() == vertex_count) {
7396 t = mesh->m_T[vi];
7397 mesh->m_T.Append(t);
7398 }
7399 if (mesh->m_K.Count() == vertex_count) {
7400 k = mesh->m_K[vi];
7401 mesh->m_K.Append(k);
7402 }
7403 if (mesh->m_C.Count() == vertex_count) {
7404 c = mesh->m_C[vi];
7405 mesh->m_C.Append(c);
7406 }
7407 return vertex_count;
7408 }
7409
7410
AddToPartition(ON_Mesh * mesh,ON_SimpleArray<int> & pmark,int vi,int partition_mark,int fi0)7411 static int AddToPartition( ON_Mesh* mesh, ON_SimpleArray<int>& pmark, int vi, int partition_mark, int fi0 )
7412 {
7413 bool b = true;
7414 int i, fi, new_vi, face_count, *fvi;
7415 i = pmark[vi];
7416 if ( !i ) {
7417 pmark[vi] = partition_mark;
7418 }
7419 else if ( i != partition_mark && i != partition_mark-1 ) {
7420 if ( i == partition_mark-2 )
7421 pmark[vi] = partition_mark-1; // vertex vi shared between two partitions
7422 else {
7423 new_vi = DupVertex(mesh,vi);
7424 face_count = mesh->m_F.Count();
7425 for ( fi = fi0; fi < face_count; fi++ ) {
7426 fvi = mesh->m_F[fi].vi;
7427 if ( fvi[0] == vi )
7428 fvi[0] = new_vi;
7429 if ( fvi[1] == vi )
7430 fvi[1] = new_vi;
7431 if ( fvi[2] == vi )
7432 fvi[2] = new_vi;
7433 if ( fvi[3] == vi )
7434 fvi[3] = new_vi;
7435 }
7436 pmark.Append(partition_mark);
7437 }
7438 }
7439 else
7440 b = false; // vertex already in this partition
7441 return b;
7442 }
7443
ON_MeshPartition_IsValid(const ON_MeshPartition & p,const ON_Mesh & mesh)7444 bool ON_MeshPartition_IsValid( const ON_MeshPartition& p, const ON_Mesh& mesh )
7445 {
7446 bool rc = false;
7447 const int* fvi;
7448 int j, tcnt, fi, parti, partcount;
7449 partcount = p.m_part.Count();
7450 rc = ( partcount > 0 );
7451 if ( p.m_partition_max_triangle_count < 1 )
7452 rc = false;
7453 if ( p.m_partition_max_vertex_count < 3 )
7454 rc = false;
7455 for ( parti = 0; parti < partcount && rc; parti++ ) {
7456 const ON_MeshPart& part = p.m_part[parti];
7457 if ( part.triangle_count < 1 )
7458 rc = false;
7459 if ( part.vertex_count < 1 )
7460 rc = false;
7461 if ( part.vertex_count != part.vi[1] - part.vi[0] )
7462 rc = false;
7463 tcnt = 0;
7464 for ( fi = part.fi[0]; fi < part.fi[1]; fi++ ) {
7465 fvi = mesh.m_F[fi].vi;
7466 tcnt++;
7467 if ( fvi[2] != fvi[3] )
7468 tcnt++;
7469 for ( j = 0; j < 4; j++ ) {
7470 if ( fvi[j] < part.vi[0] || fvi[j] >= part.vi[1] )
7471 rc = false;
7472 }
7473 }
7474 if ( tcnt != part.triangle_count )
7475 rc = false;
7476 if ( parti ) {
7477 if ( part.fi[0] != p.m_part[parti-1].fi[1] )
7478 rc = false;
7479 if ( part.vi[0] > p.m_part[parti-1].vi[1] )
7480 rc = false;
7481 }
7482 }
7483 if ( partcount ) {
7484 if ( p.m_part[0].fi[0] != 0 || p.m_part[partcount-1].fi[1] != mesh.m_F.Count() )
7485 rc = false;
7486 }
7487 return rc;
7488 }
7489
7490 static
ON_Mesh_CreatePartition_SortFaces(const ON_Mesh & mesh,int * fmap)7491 bool ON_Mesh_CreatePartition_SortFaces(const ON_Mesh& mesh, int* fmap )
7492 {
7493 ON_RTree rt;
7494 if ( !rt.CreateMeshFaceTree(&mesh) )
7495 return false;
7496
7497 const int mesh_F_count = mesh.m_F.Count();
7498 int fmap_count = 0;
7499
7500 const ON_RTreeBranch* branch;
7501 ON_RTreeIterator rit(rt);
7502 for ( rit.First(); 0 != (branch = rit.Value()); rit.Next() )
7503 {
7504 if ( fmap_count > mesh_F_count )
7505 break;
7506 fmap[fmap_count++] = (int)(branch->m_id);
7507 }
7508
7509 if ( fmap_count != mesh_F_count )
7510 {
7511 ON_ERROR("ON_Mesh::CreatePartition unable to get fmap[]");
7512 return false;
7513 }
7514
7515 return true;
7516 }
7517
CreatePartition(int partition_max_vertex_count,int partition_max_triangle_count)7518 const ON_MeshPartition* ON_Mesh::CreatePartition(
7519 int partition_max_vertex_count, // maximum number of vertices in a partition
7520 int partition_max_triangle_count // maximum number of triangles in a partition
7521 )
7522 {
7523 ON_Workspace ws;
7524 if ( m_partition )
7525 {
7526 if ( m_partition->m_partition_max_triangle_count > partition_max_triangle_count
7527 || m_partition->m_partition_max_vertex_count > partition_max_vertex_count )
7528 DestroyPartition();
7529 }
7530 if ( !m_partition )
7531 {
7532 // TODO: create one
7533 struct ON_MeshPart p;
7534 int vertex_count = VertexCount();
7535 const int face_count = FaceCount();
7536 const int triangle_count = TriangleCount() + 2*QuadCount();
7537 m_partition = new ON_MeshPartition();
7538 int k = triangle_count/partition_max_triangle_count;
7539 if ( k < vertex_count/partition_max_vertex_count )
7540 k = vertex_count/partition_max_vertex_count;
7541 k++;
7542 m_partition->m_part.Reserve(k);
7543 if ( vertex_count <= partition_max_vertex_count &&
7544 triangle_count <= partition_max_triangle_count )
7545 {
7546 m_partition->m_partition_max_vertex_count = vertex_count;
7547 m_partition->m_partition_max_triangle_count = triangle_count;
7548 memset(&p,0,sizeof(p));
7549 p.vi[0] = 0;
7550 p.vi[1] = vertex_count;
7551 p.fi[0] = 0;
7552 p.fi[1] = face_count;
7553 p.vertex_count = vertex_count;
7554 p.triangle_count = triangle_count;
7555 m_partition->m_part.Append(p);
7556 }
7557 else
7558 {
7559 int fi;
7560 int* fvi;
7561 DestroyTopology();
7562
7563 // sort faces
7564 int* fmap = (int*)ws.GetMemory( face_count*sizeof(fmap[0]) );
7565 if ( !ON_Mesh_CreatePartition_SortFaces(*this,fmap) )
7566 {
7567 for ( fi = 0; fi < face_count; fi++ )
7568 fmap[fi] = fi;
7569 }
7570
7571 //ON_SimpleArray<struct tagFPT> fpt(face_count);
7572 //fpt.SetCount(face_count);
7573 //if ( HasTextureCoordinates() )
7574 //{
7575 // ON_2fPoint fcenter;
7576 // ON_BoundingBox bbox = ON_PointListBoundingBox(2,0,m_T.Count(),2,&m_T[0].x);
7577 // const ON_Interval txdom(bbox.m_min.x,bbox.m_max.x);
7578 // const ON_Interval tydom(bbox.m_min.y,bbox.m_max.y);
7579 // for ( fi = 0; fi < face_count; fi++ ) {
7580 // fvi = m_F[fi].vi;
7581 // if ( fvi[2] == fvi[3] ) {
7582 // fcenter = 0.333333333333333333f*(m_T[fvi[0]] + m_T[fvi[1]] + m_T[fvi[2]]);
7583 // }
7584 // else {
7585 // fcenter = 0.25f*(m_T[fvi[0]] + m_T[fvi[1]] + m_T[fvi[2]] + m_T[fvi[3]]);
7586 // }
7587 // fpt[fi].x = (int)floor(txdom.NormalizedParameterAt(fcenter.x)*100);
7588 // fpt[fi].y = (int)floor(tydom.NormalizedParameterAt(fcenter.y)*100);
7589 // fpt[fi].z = 0;
7590 // }
7591 //}
7592 //else
7593 //{
7594 // ON_3dPoint fcenter;
7595 // ON_BoundingBox bbox = BoundingBox();
7596 // const ON_Interval vxdom(bbox.m_min.x,bbox.m_max.x);
7597 // const ON_Interval vydom(bbox.m_min.y,bbox.m_max.y);
7598 // const ON_Interval vzdom(bbox.m_min.z,bbox.m_max.z);
7599 // for ( fi = 0; fi < face_count; fi++ ) {
7600 // fvi = m_F[fi].vi;
7601 // if ( fvi[2] == fvi[3] ) {
7602 // fcenter = 0.333333333333333333f*(m_V[fvi[0]] + m_V[fvi[1]] + m_V[fvi[2]]);
7603 // }
7604 // else {
7605 // fcenter = 0.25f*(m_V[fvi[0]] + m_V[fvi[1]] + m_V[fvi[2]] + m_V[fvi[3]]);
7606 // }
7607 // fpt[fi].x = (int)floor(vxdom.NormalizedParameterAt(fcenter.x)*100);
7608 // fpt[fi].y = (int)floor(vydom.NormalizedParameterAt(fcenter.y)*100);
7609 // fpt[fi].z = (int)floor(vzdom.NormalizedParameterAt(fcenter.z)*100);
7610 // }
7611 //}
7612 //fpt.Sort( ON::quick_sort, fmap, compare_fpt );
7613 m_F.Permute( fmap );
7614 if ( m_FN.Count() == face_count )
7615 m_FN.Permute( fmap );
7616
7617 // sort vertices
7618 ON_SimpleArray<int>pmark(2*vertex_count);
7619 pmark.SetCount(vertex_count);
7620 pmark.Zero();
7621 int fi0, fi1, partition_mark, partition_vertex_count, partition_triangle_count;
7622 fi1 = 0;
7623 fi0 = 0;
7624 for ( partition_mark = 3, fi0 = 0; fi0 < face_count; fi0 = fi1, partition_mark += 2 )
7625 {
7626 partition_vertex_count = 0;
7627 partition_triangle_count = 0;
7628 for ( fi1 = fi0;
7629 fi1 < face_count
7630 && partition_triangle_count+2 <= partition_max_triangle_count
7631 && partition_vertex_count+4 <= partition_max_vertex_count;
7632 fi1++ )
7633 {
7634 fvi = m_F[fi1].vi;
7635 partition_triangle_count++;
7636 if ( AddToPartition( this, pmark, fvi[0], partition_mark, fi0 ) )
7637 partition_vertex_count++;
7638 if ( AddToPartition( this, pmark, fvi[1], partition_mark, fi0 ) )
7639 partition_vertex_count++;
7640 if ( AddToPartition( this, pmark, fvi[2], partition_mark, fi0 ) )
7641 partition_vertex_count++;
7642 if ( fvi[2] != fvi[3] ) {
7643 partition_triangle_count++; // quads = 2 triangles
7644 if ( AddToPartition( this, pmark, fvi[3], partition_mark, fi0 ) )
7645 partition_vertex_count++;
7646 }
7647 }
7648 if ( fi0 < fi1 ) {
7649 struct ON_MeshPart p;
7650 memset(&p,0,sizeof(p));
7651 p.fi[0] = fi0;
7652 p.fi[1] = fi1;
7653 p.vertex_count = partition_vertex_count;
7654 p.triangle_count = partition_triangle_count;
7655 m_partition->m_part.Append(p);
7656 }
7657 if ( partition_triangle_count > m_partition->m_partition_max_triangle_count )
7658 m_partition->m_partition_max_triangle_count = partition_triangle_count;
7659 if ( partition_vertex_count > m_partition->m_partition_max_vertex_count )
7660 m_partition->m_partition_max_vertex_count = partition_vertex_count;
7661 }
7662
7663 // the calls to AddToPartition() may have increased vertex count
7664 vertex_count = m_V.Count();
7665
7666 // sort vertices
7667 int* vmap = (int*)ws.GetMemory( vertex_count*sizeof(vmap[0]) );
7668 pmark.Sort( ON::quick_sort, vmap, compare_pmark );
7669 m_V.Permute( vmap );
7670 if ( m_N.Count() == vertex_count )
7671 m_N.Permute( vmap );
7672 if ( m_T.Count() == vertex_count )
7673 m_T.Permute( vmap );
7674 if ( m_K.Count() == vertex_count )
7675 m_K.Permute( vmap );
7676 if ( m_C.Count() == vertex_count )
7677 m_C.Permute( vmap );
7678 pmark.Permute( vmap );
7679 // pamv[] = inverse of mapv permutation
7680 int* pamv = (int*)ws.GetMemory( vertex_count*sizeof(pamv[0]) );
7681 ON_Sort( ON::quick_sort, pamv, vmap, vertex_count, sizeof(vmap[0]), compare_vmap );
7682 for ( fi = 0; fi < face_count; fi++ ) {
7683 fvi = m_F[fi].vi;
7684 fvi[0] = pamv[fvi[0]];
7685 fvi[1] = pamv[fvi[1]];
7686 fvi[2] = pamv[fvi[2]];
7687 fvi[3] = pamv[fvi[3]];
7688 }
7689
7690 // fill in m_part.vi[]
7691 int m, pi, partition_count = m_partition->m_part.Count();
7692 int vi0, vi2, vi3;
7693 for (vi2 = 0; vi2 < vertex_count && pmark[vi2]<2; vi2++)
7694 {/*empty for body*/}
7695 vi3=vi2;
7696 for ( pi = 0; pi < partition_count; pi++ ) {
7697 vi0 = vi2;
7698 m = 2*pi + 4;
7699 for ( vi2 = vi3; vi2 < vertex_count && pmark[vi2] < m; vi2++)
7700 {/*empty for body*/}
7701 for ( vi3 = vi2; vi3 < vertex_count && pmark[vi3] <= m; vi3++)
7702 {/*empty for body*/}
7703 m_partition->m_part[pi].vi[0] = vi0;
7704 m_partition->m_part[pi].vi[1] = vi3;
7705 }
7706 }
7707 // debugging - test partition
7708 if ( m_partition && !ON_MeshPartition_IsValid( *m_partition, *this ) ) {
7709 delete m_partition;
7710 m_partition = 0;
7711 }
7712 }
7713
7714 return m_partition;
7715 }
7716
Partition() const7717 const ON_MeshPartition* ON_Mesh::Partition() const
7718 {
7719 return m_partition;
7720 }
7721
DestroyPartition()7722 void ON_Mesh::DestroyPartition()
7723 {
7724 if ( m_partition ) {
7725 delete m_partition;
7726 m_partition = 0;
7727 }
7728 }
7729
ON_MeshPartition()7730 ON_MeshPartition::ON_MeshPartition()
7731 {
7732 m_partition_max_vertex_count = 0;
7733 m_partition_max_triangle_count = 0;
7734 m_part = 0;
7735 }
7736
~ON_MeshPartition()7737 ON_MeshPartition::~ON_MeshPartition()
7738 {
7739 m_part.Destroy();
7740 }
7741
7742
MeshPart(const ON_MeshPart & mesh_part,ON_Mesh * mesh) const7743 ON_Mesh* ON_Mesh::MeshPart(
7744 const ON_MeshPart& mesh_part,
7745 ON_Mesh* mesh
7746 ) const
7747 {
7748 if ( this == mesh )
7749 {
7750 ON_ERROR("ON_Mesh::MeshPart this == mesh");
7751 return 0;
7752 }
7753
7754 if ( mesh )
7755 mesh->Destroy();
7756
7757 if ( mesh_part.fi[0] < 0
7758 || mesh_part.fi[1] > m_F.Count()
7759 || mesh_part.fi[0] > mesh_part.fi[1]
7760 )
7761 {
7762 ON_ERROR("ON_Mesh::MeshPart mesh_part.fi[] is not valid");
7763 return 0;
7764 }
7765
7766 if ( mesh_part.vi[0] < 0
7767 || mesh_part.vi[1] > m_V.Count()
7768 || mesh_part.vi[0] >= mesh_part.vi[1]
7769 )
7770 {
7771 ON_ERROR("ON_Mesh::MeshPart mesh_part.vi[] is not valid");
7772 return 0;
7773 }
7774
7775 const int submesh_V_count = mesh_part.vi[1] - mesh_part.vi[0];
7776 const int submesh_F_count = mesh_part.fi[1] - mesh_part.fi[0];
7777
7778 const bool bHasVertexNormals = HasVertexNormals();
7779 const bool bHasTextureCoordinates = HasTextureCoordinates();
7780 const bool bHasVertexColors = HasVertexColors();
7781 const bool bHasFaceNormals = HasFaceNormals();
7782 const bool bHasSurfaceParameters = HasSurfaceParameters();
7783 const bool bHasPrincipalCurvatures = HasPrincipalCurvatures();
7784 const bool bHasHiddenVertices = HiddenVertexCount() > 0;
7785
7786 ON_Mesh* submesh = (0 != mesh)
7787 ? mesh
7788 : new ON_Mesh(mesh_part.triangle_count,
7789 mesh_part.vertex_count,
7790 bHasVertexNormals,
7791 bHasTextureCoordinates
7792 );
7793
7794 if ( bHasVertexColors )
7795 submesh->m_C.Reserve(submesh_V_count);
7796 if ( bHasSurfaceParameters )
7797 submesh->m_S.Reserve(submesh_V_count);
7798 if ( bHasPrincipalCurvatures )
7799 submesh->m_K.Reserve(submesh_V_count);
7800 if ( bHasHiddenVertices )
7801 submesh->m_H.Reserve(submesh_V_count);
7802 if ( bHasFaceNormals )
7803 submesh->m_FN.Reserve(submesh_F_count);
7804
7805 // put vertex information into submesh
7806 const int vi0 = mesh_part.vi[0];
7807 const int vi1 = mesh_part.vi[1];
7808 for ( int vi = vi0; vi < vi1; vi++ )
7809 {
7810 submesh->m_V.Append(m_V[vi]);
7811 if ( bHasVertexNormals )
7812 submesh->m_N.Append(m_N[vi]);
7813 if ( bHasTextureCoordinates )
7814 submesh->m_T.Append(m_T[vi]);
7815 if ( bHasVertexColors )
7816 submesh->m_C.Append(m_C[vi]);
7817 if ( bHasSurfaceParameters )
7818 submesh->m_S.Append(m_S[vi]);
7819 if ( bHasPrincipalCurvatures )
7820 submesh->m_K.Append(m_K[vi]);
7821 if ( bHasHiddenVertices )
7822 {
7823 bool bHidden = m_H[vi];
7824 submesh->m_H.Append(bHidden);
7825 if ( bHidden )
7826 submesh->m_hidden_count++;
7827 }
7828 }
7829 if ( submesh->m_hidden_count <= 0 )
7830 {
7831 submesh->m_H.Destroy();
7832 submesh->m_hidden_count = 0;
7833 }
7834
7835 // put face information into submesh
7836 int bad_face_count = 0;
7837 const int fi0 = mesh_part.fi[0];
7838 const int fi1 = mesh_part.fi[1];
7839 for ( int fi = fi0; fi < fi1; fi++ )
7840 {
7841 ON_MeshFace f = m_F[fi];
7842 f.vi[0] -= vi0;
7843 f.vi[1] -= vi0;
7844 f.vi[2] -= vi0;
7845 f.vi[3] -= vi0;
7846 if ( f.vi[0] >= submesh_V_count || f.vi[0] < 0
7847 || f.vi[1] >= submesh_V_count || f.vi[1] < 0
7848 || f.vi[2] >= submesh_V_count || f.vi[2] < 0
7849 || f.vi[3] >= submesh_V_count || f.vi[3] < 0
7850 )
7851 {
7852 bad_face_count++;
7853 ON_ERROR("ON_Mesh::MeshPart Invalid face in partition");
7854 continue;
7855 }
7856 submesh->m_F.Append(f);
7857 if ( bHasFaceNormals )
7858 submesh->m_FN.Append(m_FN[fi]);
7859 }
7860
7861 if ( submesh->m_F.Count() < 1 && bad_face_count > 0 )
7862 {
7863 if ( submesh != mesh )
7864 delete submesh;
7865 else
7866 mesh->Destroy();
7867
7868 submesh = 0;
7869 }
7870
7871 return submesh;
7872 }
7873
DuplicateFace(int face_index,ON_Mesh * mesh) const7874 ON_Mesh* ON_Mesh::DuplicateFace( int face_index, ON_Mesh* mesh ) const
7875 {
7876 if ( mesh == this )
7877 return 0;
7878 if ( 0 != mesh )
7879 mesh->Destroy();
7880 if ( face_index < 0 || face_index >= m_F.Count() )
7881 return 0;
7882 const int vcnt = m_V.Count();
7883 if ( vcnt < 3 )
7884 return 0;
7885
7886 const ON_3dPoint* dV = ( HasDoublePrecisionVertices() && DoublePrecisionVerticesAreValid() )
7887 ? DoublePrecisionVertices().Array()
7888 : 0;
7889 const ON_3fPoint* fV = (0 == dV) ? m_V.Array() : 0;
7890 bool bHasFaceNormals = HasFaceNormals();
7891 bool bHasVertexNormals = HasVertexNormals();
7892 bool bHasVertexColors = HasVertexColors();
7893 bool bHasTextureCoordinates = HasTextureCoordinates();
7894 bool bHasSurfaceParameters = HasSurfaceParameters();
7895 bool bHasPrincipalCurvatures = HasPrincipalCurvatures();
7896
7897 ON_MeshFace f = m_F[face_index];
7898 if ( dV )
7899 {
7900 if ( !f.IsValid(vcnt,dV) )
7901 {
7902 // invalid vertex indices - see if it can be fixed
7903 if ( !f.Repair(vcnt,dV) )
7904 return 0;
7905 }
7906 }
7907 else
7908 {
7909 if ( !f.IsValid(vcnt,fV) )
7910 {
7911 // invalid vertex indices - see if it can be fixed
7912 if ( !f.Repair(vcnt,fV) )
7913 return 0;
7914 }
7915 }
7916 const int newvcnt = f.IsTriangle() ? 3 : 4;
7917 if ( 0 == mesh )
7918 mesh = new ON_Mesh();
7919 ON_3dPointArray* newdV = 0;
7920 if ( dV )
7921 {
7922 newdV = &mesh->DoublePrecisionVertices();
7923 newdV->Reserve(newvcnt);
7924 }
7925 mesh->m_V.Reserve(newvcnt);
7926 mesh->m_F.Reserve(1);
7927 ON_MeshFace& newface = mesh->m_F.AppendNew();
7928 newface.vi[0] = 0;
7929 newface.vi[1] = 1;
7930 newface.vi[2] = 2;
7931 newface.vi[3] = (4 == newvcnt) ? 3 : newface.vi[2];
7932
7933 if ( bHasFaceNormals )
7934 {
7935 mesh->m_FN.Reserve(1);
7936 mesh->m_FN.Append(m_FN[face_index]);
7937 }
7938
7939 if ( bHasVertexNormals )
7940 mesh->m_N.Reserve(newvcnt);
7941 if ( bHasTextureCoordinates )
7942 mesh->m_T.Reserve(newvcnt);
7943 if ( bHasVertexColors )
7944 mesh->m_C.Reserve(newvcnt);
7945 if ( bHasSurfaceParameters )
7946 mesh->m_S.Reserve(newvcnt);
7947 if ( bHasPrincipalCurvatures )
7948 mesh->m_K.Reserve(newvcnt);
7949 for ( int vi = 0; vi < newvcnt; vi++ )
7950 {
7951 if ( dV )
7952 newdV->Append(dV[f.vi[vi]]);
7953 else
7954 mesh->m_V.Append(fV[f.vi[vi]]);
7955 if ( bHasVertexNormals )
7956 mesh->m_N.Append(m_N[f.vi[vi]]);
7957 if ( bHasTextureCoordinates )
7958 mesh->m_T.Append(m_T[f.vi[vi]]);
7959 if ( bHasVertexColors )
7960 mesh->m_C.Append(m_C[f.vi[vi]]);
7961 if ( bHasSurfaceParameters )
7962 mesh->m_S.Append(m_S[f.vi[vi]]);
7963 if ( bHasPrincipalCurvatures )
7964 mesh->m_K.Append(m_K[f.vi[vi]]);
7965 }
7966 if ( dV )
7967 {
7968 mesh->SetDoublePrecisionVerticesAsValid();
7969 mesh->UpdateSinglePrecisionVertices();
7970 }
7971
7972 return mesh;
7973 }
7974
7975
7976 ON_OBJECT_IMPLEMENT(ON_MeshVertexRef,ON_Geometry,"C547B4BD-BDCD-49b6-A983-0C4A7F02E31A");
7977
7978 ON_OBJECT_IMPLEMENT(ON_MeshEdgeRef,ON_Geometry,"ED727872-463A-4424-851F-9EC02CB0F155");
7979
7980 ON_OBJECT_IMPLEMENT(ON_MeshFaceRef,ON_Geometry,"4F529AA5-EF8D-4c25-BCBB-162D510AA280");
7981
ON_MeshVertexRef()7982 ON_MeshVertexRef::ON_MeshVertexRef()
7983 {
7984 m_mesh = 0;
7985 m_mesh_vi = -1;
7986 m_top_vi = -1;
7987 }
7988
~ON_MeshVertexRef()7989 ON_MeshVertexRef::~ON_MeshVertexRef()
7990 {
7991 m_mesh = 0;
7992 m_mesh_vi = -1;
7993 m_top_vi = -1;
7994 }
7995
operator =(const ON_MeshVertexRef & src)7996 ON_MeshVertexRef& ON_MeshVertexRef::operator=(const ON_MeshVertexRef& src)
7997 {
7998 if ( this != &src )
7999 {
8000 ON_Geometry::operator=(src);
8001 m_mesh = src.m_mesh;
8002 m_mesh_vi = src.m_mesh_vi;
8003 m_top_vi = src.m_top_vi;
8004 }
8005 return *this;
8006 }
8007
8008
IsValid(ON_TextLog * text_log) const8009 ON_BOOL32 ON_MeshVertexRef::IsValid( ON_TextLog* text_log ) const
8010 {
8011 if ( 0 == m_mesh )
8012 {
8013 if ( 0 != text_log )
8014 {
8015 text_log->Print("m_mesh = NULL\n");
8016 }
8017 return false;
8018 }
8019
8020 if ( -1 != m_mesh_vi )
8021 {
8022 if ( m_mesh_vi < 0 || m_mesh_vi >= m_mesh->m_V.Count() )
8023 {
8024 if ( 0 != text_log )
8025 {
8026 text_log->Print("m_mesh_vi = %d (should have 0 <= m_mesh_vi < %d)\n",m_mesh_vi,m_mesh->m_V.Count());
8027 }
8028 return false;
8029 }
8030 }
8031 else if ( -1 == m_top_vi )
8032 {
8033 if ( 0 != text_log )
8034 {
8035 text_log->Print("m_mesh_vi = -1 and m_top_vi = -1\n");
8036 }
8037 return false;
8038 }
8039
8040 if ( -1 != m_top_vi )
8041 {
8042 const ON_MeshTopology* top = MeshTopology();
8043 if ( 0 == top )
8044 {
8045 if ( 0 != text_log )
8046 {
8047 text_log->Print("m_top_vi = %d and MeshTopology()=NULL\n",m_top_vi);
8048 }
8049 return false;
8050 }
8051 if ( m_top_vi < 0 || m_top_vi >= top->m_tope.Count() )
8052 {
8053 if ( 0 != text_log )
8054 {
8055 text_log->Print("m_top_vi = %d (should have 0 <= m_top_vi < %d)\n",m_top_vi,top->m_topv.Count());
8056 }
8057 return false;
8058 }
8059
8060 if ( -1 != m_mesh_vi )
8061 {
8062 const ON_MeshTopologyVertex& topv = top->m_topv[m_top_vi];
8063 int i;
8064 for ( i = 0; i < topv.m_v_count; i++ )
8065 {
8066 if ( topv.m_vi[i] == m_mesh_vi )
8067 break;
8068 }
8069 if ( i >= topv.m_v_count )
8070 {
8071 if ( 0 != text_log )
8072 {
8073 text_log->Print("m_mesh_vi=%d is not in m_top->m_topv[m_top_vi=%d].m_vi[] array.\n",
8074 m_mesh_vi,m_top_vi);
8075
8076 }
8077 return false;
8078 }
8079 }
8080 }
8081
8082 return true;
8083 }
8084
Dump(ON_TextLog & text_log) const8085 void ON_MeshVertexRef::Dump( ON_TextLog& text_log ) const
8086 {
8087 text_log.Print("m_mesh=%08x m_mesh_vi=%d m_top_vi=%d\n",
8088 m_mesh,m_mesh_vi,m_top_vi);
8089 ON_3dPoint v = Point();
8090 if ( v.IsValid() )
8091 {
8092 text_log.PushIndent();
8093 text_log.Print("Location: ");
8094 text_log.Print(v);
8095 text_log.Print("\n");
8096 text_log.PopIndent();
8097 }
8098
8099 }
SizeOf() const8100 unsigned int ON_MeshVertexRef::SizeOf() const
8101 {
8102 unsigned int sz = sizeof(*this) - sizeof(ON_Geometry);
8103 sz += ON_Geometry::SizeOf();
8104 return sz;
8105 }
8106
ObjectType() const8107 ON::object_type ON_MeshVertexRef::ObjectType() const
8108 {
8109 return ON::meshvertex_object;
8110 }
8111
8112 // overrides of virtual ON_Geometry functions
Dimension() const8113 int ON_MeshVertexRef::Dimension() const
8114 {
8115 return 3;
8116 }
8117
GetBBox(double * boxmin,double * boxmax,ON_BOOL32 bGrowBox) const8118 ON_BOOL32 ON_MeshVertexRef::GetBBox(
8119 double* boxmin,
8120 double* boxmax,
8121 ON_BOOL32 bGrowBox
8122 ) const
8123 {
8124 bool rc = false;
8125 ON_3dPoint v = Point();
8126 if ( v.IsValid() )
8127 {
8128 rc = ON_GetPointListBoundingBox( 3, 0, 1, 3, &v.x, boxmin, boxmax, bGrowBox?true:false );
8129 }
8130 return rc;
8131 }
8132
Transform(const ON_Xform &)8133 ON_BOOL32 ON_MeshVertexRef::Transform(
8134 const ON_Xform&
8135 )
8136 {
8137 return false;
8138 }
8139
MeshTopology() const8140 const ON_MeshTopology* ON_MeshVertexRef::MeshTopology() const
8141 {
8142 return (0 != m_mesh) ? &m_mesh->m_top : 0;
8143 }
8144
Point() const8145 ON_3dPoint ON_MeshVertexRef::Point() const
8146 {
8147 ON_3dPoint v = ON_UNSET_POINT;
8148 if ( 0 != m_mesh )
8149 {
8150 int vi = m_mesh_vi;
8151 if ( -1 == vi && m_top_vi >= 0 && m_top_vi < m_mesh->m_top.m_topv.Count() )
8152 {
8153 const ON_MeshTopologyVertex& topv = m_mesh->m_top.m_topv[m_top_vi];
8154 if ( topv.m_v_count > 0 )
8155 vi = topv.m_vi[0];
8156 }
8157 if ( vi >= 0 && vi < m_mesh->m_V.Count() )
8158 v = m_mesh->m_V[vi];
8159 }
8160 return v;
8161 }
8162
MeshTopologyVertex() const8163 const ON_MeshTopologyVertex* ON_MeshVertexRef::MeshTopologyVertex() const
8164 {
8165 const ON_MeshTopologyVertex* topv = 0;
8166 if ( 0 != m_mesh && m_top_vi >= 0 && m_top_vi < m_mesh->m_top.m_topv.Count() )
8167 {
8168 topv = &m_mesh->m_top.m_topv[m_top_vi];
8169 }
8170 return topv;
8171 }
8172
ON_MeshEdgeRef()8173 ON_MeshEdgeRef::ON_MeshEdgeRef()
8174 {
8175 m_mesh = 0;
8176 m_top_ei = -1;
8177 }
8178
~ON_MeshEdgeRef()8179 ON_MeshEdgeRef::~ON_MeshEdgeRef()
8180 {
8181 m_mesh = 0;
8182 m_top_ei = -1;
8183 }
8184
operator =(const ON_MeshEdgeRef & src)8185 ON_MeshEdgeRef& ON_MeshEdgeRef::operator=(const ON_MeshEdgeRef& src)
8186 {
8187 if ( this != &src )
8188 {
8189 ON_Geometry::operator=(src);
8190 m_mesh = src.m_mesh;
8191 m_top_ei = src.m_top_ei;
8192 }
8193 return *this;
8194 }
8195
8196
IsValid(ON_TextLog * text_log) const8197 ON_BOOL32 ON_MeshEdgeRef::IsValid( ON_TextLog* text_log ) const
8198 {
8199 if ( 0 == m_mesh)
8200 {
8201 if ( 0 != text_log )
8202 {
8203 text_log->Print("m_mesh = NULL\n");
8204 }
8205 return false;
8206 }
8207
8208 if ( m_top_ei < 0 || m_top_ei >= m_mesh->m_top.m_tope.Count() )
8209 {
8210 if ( 0 != text_log )
8211 {
8212 text_log->Print("m_top_ei = %d (should have 0 <= m_top_ei < %d)\n",m_top_ei,m_mesh->m_top.m_tope.Count());
8213 }
8214 return false;
8215 }
8216
8217 return true;
8218 }
8219
Dump(ON_TextLog & text_log) const8220 void ON_MeshEdgeRef::Dump( ON_TextLog& text_log ) const
8221 {
8222 text_log.Print("m_mesh=%08x, m_top_ei=%d\n",m_mesh,m_top_ei);
8223 ON_Line line = Line();
8224 if ( line.from.IsValid() )
8225 {
8226 text_log.PushIndent();
8227 text_log.Print("Location: ");
8228 text_log.Print(line.from);
8229 text_log.Print(" to ");
8230 text_log.Print(line.to);
8231 text_log.Print("\n");
8232 text_log.PopIndent();
8233 }
8234
8235 }
SizeOf() const8236 unsigned int ON_MeshEdgeRef::SizeOf() const
8237 {
8238 unsigned int sz = sizeof(*this) - sizeof(ON_Geometry);
8239 sz += ON_Geometry::SizeOf();
8240 return sz;
8241 }
8242
ObjectType() const8243 ON::object_type ON_MeshEdgeRef::ObjectType() const
8244 {
8245 return ON::meshedge_object;
8246 }
8247
8248 // overrides of virtual ON_Geometry functions
Dimension() const8249 int ON_MeshEdgeRef::Dimension() const
8250 {
8251 return 3;
8252 }
8253
GetBBox(double * boxmin,double * boxmax,ON_BOOL32 bGrowBox) const8254 ON_BOOL32 ON_MeshEdgeRef::GetBBox(
8255 double* boxmin,
8256 double* boxmax,
8257 ON_BOOL32 bGrowBox
8258 ) const
8259 {
8260 bool rc = false;
8261 ON_Line line = Line();
8262 if ( line.from.IsValid() && line.to.IsValid() )
8263 {
8264 rc = ON_GetPointListBoundingBox( 3, 0, 2, 3, &line.from.x, boxmin, boxmax, bGrowBox?true:false );
8265 }
8266 return rc;
8267 }
8268
Transform(const ON_Xform &)8269 ON_BOOL32 ON_MeshEdgeRef::Transform(
8270 const ON_Xform&
8271 )
8272 {
8273 return false;
8274 }
8275
MeshTopology() const8276 const ON_MeshTopology* ON_MeshEdgeRef::MeshTopology() const
8277 {
8278 return (0 != m_mesh) ? &m_mesh->m_top : 0;
8279 }
8280
Line() const8281 ON_Line ON_MeshEdgeRef::Line() const
8282 {
8283 ON_Line line(ON_UNSET_POINT,ON_UNSET_POINT);
8284 const ON_MeshTopologyEdge* tope = MeshTopologyEdge();
8285 if ( 0 != tope )
8286 {
8287 ON_MeshVertexRef vr;
8288 vr.m_mesh = m_mesh;
8289 vr.m_top_vi = tope->m_topvi[0];
8290 line.from = vr.Point();
8291 if ( line.from.IsValid() )
8292 {
8293 vr.m_top_vi = tope->m_topvi[1];
8294 line.to = vr.Point();
8295 if ( !line.to.IsValid() )
8296 line.from = ON_UNSET_POINT;
8297 }
8298 }
8299 return line;
8300 }
8301
MeshTopologyEdge() const8302 const ON_MeshTopologyEdge* ON_MeshEdgeRef::MeshTopologyEdge() const
8303 {
8304 const ON_MeshTopologyEdge* tope = 0;
8305 if ( m_top_ei >= 0 )
8306 {
8307 const ON_MeshTopology* top = MeshTopology();
8308 if ( 0 != top && m_top_ei < top->m_tope.Count() )
8309 tope = &top->m_tope[m_top_ei];
8310 }
8311 return tope;
8312 }
8313
8314 /////////////////////////////////////////////////
8315
8316
ON_MeshFaceRef()8317 ON_MeshFaceRef::ON_MeshFaceRef()
8318 {
8319 m_mesh = 0;
8320 m_mesh_fi = -1;
8321 }
8322
~ON_MeshFaceRef()8323 ON_MeshFaceRef::~ON_MeshFaceRef()
8324 {
8325 m_mesh = 0;
8326 m_mesh_fi = -1;
8327 }
8328
operator =(const ON_MeshFaceRef & src)8329 ON_MeshFaceRef& ON_MeshFaceRef::operator=(const ON_MeshFaceRef& src)
8330 {
8331 if ( this != &src )
8332 {
8333 ON_Geometry::operator=(src);
8334 m_mesh = src.m_mesh;
8335 m_mesh_fi = src.m_mesh_fi;
8336 }
8337 return *this;
8338 }
8339
8340
IsValid(ON_TextLog * text_log) const8341 ON_BOOL32 ON_MeshFaceRef::IsValid( ON_TextLog* text_log ) const
8342 {
8343 if ( 0 == m_mesh)
8344 {
8345 if ( 0 != text_log )
8346 {
8347 text_log->Print("m_mesh = NULL\n");
8348 }
8349 return false;
8350 }
8351
8352 if ( m_mesh_fi < 0 || m_mesh_fi >= m_mesh->m_F.Count() )
8353 {
8354 if ( 0 != text_log )
8355 {
8356 text_log->Print("m_mesh_fi = %d (should have 0 <= m_mesh_fi < %d)\n",m_mesh_fi,m_mesh->m_F.Count());
8357 }
8358 return false;
8359 }
8360
8361 return true;
8362 }
8363
Dump(ON_TextLog & text_log) const8364 void ON_MeshFaceRef::Dump( ON_TextLog& text_log ) const
8365 {
8366 text_log.Print("m_mesh=%08x, m_mesh_fi=%d\n",m_mesh,m_mesh_fi);
8367 }
8368
SizeOf() const8369 unsigned int ON_MeshFaceRef::SizeOf() const
8370 {
8371 unsigned int sz = sizeof(*this) - sizeof(ON_Geometry);
8372 sz += ON_Geometry::SizeOf();
8373 return sz;
8374 }
8375
ObjectType() const8376 ON::object_type ON_MeshFaceRef::ObjectType() const
8377 {
8378 return ON::meshface_object;
8379 }
8380
8381 // overrides of virtual ON_Geometry functions
Dimension() const8382 int ON_MeshFaceRef::Dimension() const
8383 {
8384 return 3;
8385 }
8386
GetBBox(double * boxmin,double * boxmax,ON_BOOL32 bGrowBox) const8387 ON_BOOL32 ON_MeshFaceRef::GetBBox(
8388 double* boxmin,
8389 double* boxmax,
8390 ON_BOOL32 bGrowBox
8391 ) const
8392 {
8393 bool rc = false;
8394 if ( 0 != m_mesh && m_mesh_fi >= 0 && m_mesh_fi < m_mesh->m_F.Count() )
8395 {
8396 const int vcnt = m_mesh->m_V.Count();
8397 const int* Fvi = m_mesh->m_F[m_mesh_fi].vi;
8398 ON_3dPoint v[4];
8399 //int count = 0;
8400 int i;
8401 for ( i = 0; i < 4; i++ )
8402 {
8403 if ( Fvi[i] >= 0 && Fvi[i] < vcnt )
8404 {
8405 v[i] = m_mesh->m_V[Fvi[i]];
8406 }
8407 else
8408 return false;
8409 }
8410 rc = ON_GetPointListBoundingBox( 3, 0, 4, 3, &v[0].x, boxmin, boxmax, bGrowBox?true:false );
8411 }
8412 return rc;
8413 }
8414
Transform(const ON_Xform &)8415 ON_BOOL32 ON_MeshFaceRef::Transform(
8416 const ON_Xform&
8417 )
8418 {
8419 return false;
8420 }
8421
MeshTopology() const8422 const ON_MeshTopology* ON_MeshFaceRef::MeshTopology() const
8423 {
8424 return (0 != m_mesh) ? &m_mesh->m_top : 0;
8425 }
8426
8427
8428
MeshFace() const8429 const ON_MeshFace* ON_MeshFaceRef::MeshFace() const
8430 {
8431 const ON_MeshFace* f = 0;
8432 if ( 0 != m_mesh && m_mesh_fi >= 0 && m_mesh_fi < m_mesh->m_F.Count() )
8433 {
8434 f = &m_mesh->m_F[m_mesh_fi];
8435 }
8436 return f;
8437 }
8438
8439
MeshTopologyFace() const8440 const ON_MeshTopologyFace* ON_MeshFaceRef::MeshTopologyFace() const
8441 {
8442 const ON_MeshTopologyFace* topf = 0;
8443 if ( m_mesh_fi >= 0 )
8444 {
8445 const ON_MeshTopology* top = MeshTopology();
8446 if ( 0 != top && m_mesh_fi < top->m_topf.Count() )
8447 topf = &top->m_topf[m_mesh_fi];
8448 }
8449 return topf;
8450 }
8451
VertexRef(int mesh_V_index) const8452 ON_MeshVertexRef ON_Mesh::VertexRef(int mesh_V_index) const
8453 {
8454 ON_MeshVertexRef vr;
8455 if ( mesh_V_index >= 0 && mesh_V_index < m_V.Count() )
8456 {
8457 vr.m_mesh = this;
8458 vr.m_mesh_vi = mesh_V_index;
8459 if ( m_top.m_topv_map.Count() == m_V.Count() )
8460 {
8461 vr.m_top_vi = m_top.m_topv_map[mesh_V_index];
8462 }
8463 }
8464
8465 return vr;
8466 }
8467
VertexRef(ON_COMPONENT_INDEX ci) const8468 ON_MeshVertexRef ON_Mesh::VertexRef(ON_COMPONENT_INDEX ci) const
8469 {
8470 ON_MeshVertexRef vr;
8471
8472 //int vertex_index = -1;
8473 switch (ci.m_type)
8474 {
8475 case ON_COMPONENT_INDEX::meshtop_vertex:
8476 vr = m_top.VertexRef(ci);
8477 break;
8478 case ON_COMPONENT_INDEX::mesh_vertex:
8479 if ( ci.m_index >= 0 && ci.m_index < m_V.Count() )
8480 {
8481 vr.m_mesh = this;
8482 vr.m_mesh_vi = ci.m_index;
8483 if ( m_top.m_topv_map.Count() == m_V.Count() )
8484 {
8485 vr.m_top_vi = m_top.m_topv_map[vr.m_mesh_vi];
8486 }
8487 }
8488 break;
8489 default:
8490 // intentionally skipping other enum values (also quiets gcc warnings)
8491 break;
8492 }
8493
8494 return vr;
8495 }
8496
8497
EdgeRef(int tope_index) const8498 ON_MeshEdgeRef ON_Mesh::EdgeRef(int tope_index) const
8499 {
8500 return m_top.EdgeRef(tope_index);
8501 }
8502
EdgeRef(ON_COMPONENT_INDEX ci) const8503 ON_MeshEdgeRef ON_Mesh::EdgeRef(ON_COMPONENT_INDEX ci) const
8504 {
8505 return m_top.EdgeRef(ci);
8506 }
8507
FaceRef(int mesh_F_index) const8508 ON_MeshFaceRef ON_Mesh::FaceRef(int mesh_F_index) const
8509 {
8510 ON_MeshFaceRef fr;
8511
8512 if ( mesh_F_index >= 0 && mesh_F_index < m_F.Count() )
8513 {
8514 fr.m_mesh = this;
8515 fr.m_mesh_fi = mesh_F_index;
8516 }
8517
8518 return fr;
8519 }
8520
FaceRef(ON_COMPONENT_INDEX ci) const8521 ON_MeshFaceRef ON_Mesh::FaceRef(ON_COMPONENT_INDEX ci) const
8522 {
8523 ON_MeshFaceRef fr;
8524
8525 if ( ci.m_type == ON_COMPONENT_INDEX::mesh_face )
8526 {
8527 if ( ci.m_index >= 0 && ci.m_index < m_F.Count() )
8528 {
8529 fr.m_mesh = this;
8530 fr.m_mesh_fi = ci.m_index;
8531 }
8532 }
8533
8534 return fr;
8535 }
8536
VertexRef(ON_COMPONENT_INDEX ci) const8537 ON_MeshVertexRef ON_MeshTopology::VertexRef(ON_COMPONENT_INDEX ci) const
8538 {
8539 ON_MeshVertexRef vr;
8540 if ( ci.m_index >= 0 )
8541 {
8542 switch(ci.m_type)
8543 {
8544 case ON_COMPONENT_INDEX::mesh_vertex:
8545 if (m_mesh)
8546 {
8547 vr = m_mesh->VertexRef(ci);
8548 }
8549 break;
8550 case ON_COMPONENT_INDEX::meshtop_vertex:
8551 if ( ci.m_index < m_topv.Count() )
8552 {
8553 vr.m_mesh = m_mesh;
8554 vr.m_top_vi = ci.m_index;
8555 if ( m_topv[ci.m_index].m_vi && 1 == m_topv[ci.m_index].m_v_count )
8556 {
8557 vr.m_mesh_vi = m_topv[ci.m_index].m_vi[0];
8558 }
8559 }
8560 break;
8561 default:
8562 // intentionally skip other ON_COMPONENT_INDEX::TYPE
8563 // enum values.
8564 break;
8565 }
8566 }
8567 return vr;
8568 }
8569
VertexRef(int topv_index) const8570 ON_MeshVertexRef ON_MeshTopology::VertexRef(int topv_index) const
8571 {
8572 ON_MeshVertexRef vr;
8573
8574 if ( topv_index >= 0 && topv_index < m_topv.Count() )
8575 {
8576 vr.m_mesh = m_mesh;
8577 vr.m_top_vi = topv_index;
8578 if ( 1 == m_topv[topv_index].m_v_count )
8579 {
8580 vr.m_mesh_vi = m_topv[topv_index].m_vi[0];
8581 }
8582 }
8583
8584 return vr;
8585 }
8586
EdgeRef(ON_COMPONENT_INDEX ci) const8587 ON_MeshEdgeRef ON_MeshTopology::EdgeRef(ON_COMPONENT_INDEX ci) const
8588 {
8589 ON_MeshEdgeRef er;
8590 if ( ON_COMPONENT_INDEX::meshtop_edge == ci.m_type && ci.m_index >= 0 && ci.m_index < m_tope.Count() )
8591 {
8592 er.m_mesh = m_mesh;
8593 er.m_top_ei = ci.m_index;
8594 }
8595 return er;
8596 }
8597
EdgeRef(int tope_index) const8598 ON_MeshEdgeRef ON_MeshTopology::EdgeRef(int tope_index) const
8599 {
8600 ON_MeshEdgeRef er;
8601
8602 if ( tope_index >= 0 && tope_index < m_tope.Count() )
8603 {
8604 er.m_mesh = m_mesh;
8605 er.m_top_ei = tope_index;
8606 }
8607
8608 return er;
8609 }
8610
FaceRef(ON_COMPONENT_INDEX ci) const8611 ON_MeshFaceRef ON_MeshTopology::FaceRef(ON_COMPONENT_INDEX ci) const
8612 {
8613 ON_MeshFaceRef fr;
8614 if ( m_mesh )
8615 {
8616 fr = m_mesh->FaceRef(ci.m_index);
8617 }
8618 return fr;
8619 }
8620
FaceRef(int topf_index) const8621 ON_MeshFaceRef ON_MeshTopology::FaceRef(int topf_index) const
8622 {
8623 return ( 0 != m_mesh ) ? m_mesh->FaceRef(topf_index) : ON_MeshFaceRef();
8624 }
8625
8626
8627 /*
8628 ON_Mesh::COMPONENT_TYPE ON_Mesh::ComponentIndexType( int component_index )
8629 {
8630 switch( (mesh_component_mask & component_index) )
8631 {
8632 case mesh_vertex: return mesh_vertex;
8633 case meshtop_vertex: return meshtop_vertex;
8634 case meshtop_edge: return meshtop_edge;
8635 case mesh_face: return mesh_face;
8636 }
8637 return mesh_component_unset;
8638 }
8639 */
8640
ComponentIndex() const8641 ON_COMPONENT_INDEX ON_MeshVertexRef::ComponentIndex() const
8642 {
8643 ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::invalid_type,-1);
8644 if ( m_mesh_vi >= 0 )
8645 {
8646 if ( 0 == m_mesh || m_mesh_vi < m_mesh->m_V.Count() )
8647 {
8648 ci.Set(ON_COMPONENT_INDEX::mesh_vertex,m_mesh_vi);
8649 }
8650 }
8651 else if ( m_top_vi >= 0 )
8652 {
8653 if ( 0 == m_mesh )
8654 {
8655 // not enough information to perform validation check
8656 // assume this is a persistent index to be resolved
8657 // later and press on
8658 ci.Set(ON_COMPONENT_INDEX::meshtop_vertex,m_top_vi);
8659 }
8660 else if (m_top_vi < m_mesh->m_V.Count())
8661 {
8662 if ( 0 == m_mesh->m_top.m_topv.Count() )
8663 {
8664 // not enough information to perform validation check
8665 // assume this is a persistent index to be resolved
8666 // later and press on
8667 ci.Set(ON_COMPONENT_INDEX::meshtop_vertex,m_top_vi);
8668 }
8669 else if ( m_top_vi < m_mesh->m_top.m_topv.Count() )
8670 {
8671 // m_top is constructed and m_top_vi is valid
8672 ci.Set(ON_COMPONENT_INDEX::meshtop_vertex,m_top_vi);
8673 }
8674 }
8675 }
8676 return ci;
8677 }
8678
ComponentIndex() const8679 ON_COMPONENT_INDEX ON_MeshEdgeRef::ComponentIndex() const
8680 {
8681 ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::invalid_type,-1);
8682 if ( m_top_ei >= 0 )
8683 {
8684 if ( 0 == m_mesh || 0 == m_mesh->m_top.m_tope.Count() )
8685 {
8686 // not enough information to perform validation check
8687 // assume this is a persistent index to be resolved
8688 // later and press on
8689 ci.Set(ON_COMPONENT_INDEX::meshtop_edge,m_top_ei);
8690 }
8691 else if ( m_top_ei < m_mesh->m_top.m_tope.Count() )
8692 {
8693 // valid index
8694 ci.Set(ON_COMPONENT_INDEX::meshtop_edge,m_top_ei);
8695 }
8696 }
8697 return ci;
8698 }
8699
ComponentIndex() const8700 ON_COMPONENT_INDEX ON_MeshFaceRef::ComponentIndex() const
8701 {
8702 ON_COMPONENT_INDEX ci(ON_COMPONENT_INDEX::invalid_type,-1);
8703 if ( m_mesh_fi >= 0 )
8704 {
8705 if ( 0 == m_mesh || m_mesh_fi < m_mesh->m_F.Count() )
8706 {
8707 ci.Set(ON_COMPONENT_INDEX::mesh_face,m_mesh_fi);
8708 }
8709 }
8710 return ci;
8711 }
8712
MeshComponent(ON_COMPONENT_INDEX ci) const8713 ON_Geometry* ON_Mesh::MeshComponent(
8714 ON_COMPONENT_INDEX ci
8715 ) const
8716 {
8717 ON_Geometry* component = 0;
8718 if ( ci.m_index >= 0 )
8719 {
8720 switch( ci.m_type )
8721 {
8722 case ON_COMPONENT_INDEX::mesh_vertex:
8723 {
8724 ON_MeshVertexRef r = VertexRef(ci);
8725 component = new ON_MeshVertexRef(r);
8726 }
8727 break;
8728
8729 case ON_COMPONENT_INDEX::meshtop_vertex:
8730 {
8731 ON_MeshVertexRef r = Topology().VertexRef(ci);
8732 component = new ON_MeshVertexRef(r);
8733 }
8734 break;
8735
8736 case ON_COMPONENT_INDEX::meshtop_edge:
8737 {
8738 ON_MeshEdgeRef r = EdgeRef(ci);
8739 component = new ON_MeshEdgeRef(r);
8740 }
8741 break;
8742
8743 case ON_COMPONENT_INDEX::mesh_face:
8744 {
8745 ON_MeshFaceRef r = FaceRef(ci);
8746 component = new ON_MeshFaceRef(r);
8747 }
8748 break;
8749
8750 default:
8751 // intentionally skip other ON_COMPONENT_INDEX::TYPE
8752 // enum values.
8753 break;
8754 }
8755 }
8756 return component;
8757 }
8758
ON_TriangleNormal(const ON_3dPoint & A,const ON_3dPoint & B,const ON_3dPoint & C)8759 ON_3dVector ON_TriangleNormal(
8760 const ON_3dPoint& A,
8761 const ON_3dPoint& B,
8762 const ON_3dPoint& C
8763 )
8764 {
8765 // N = normal to triangle's plane
8766 ON_3dVector N;
8767 double a, b, c, d;
8768 N.x = A.y*(B.z-C.z) + B.y*(C.z-A.z) + C.y*(A.z-B.z);
8769 N.y = A.z*(B.x-C.x) + B.z*(C.x-A.x) + C.z*(A.x-B.x);
8770 N.z = A.x*(B.y-C.y) + B.x*(C.y-A.y) + C.x*(A.y-B.y);
8771
8772 a = fabs(N.x);
8773 b = fabs(N.y);
8774 c = fabs(N.z);
8775 if ( b > a )
8776 {
8777 if ( c > b )
8778 {
8779 // c is largest
8780 if ( c > ON_DBL_MIN )
8781 {
8782 a /= c; b /= c; d = c*sqrt(1.0 + a*a + b*b);
8783 }
8784 else
8785 {
8786 d = c;
8787 }
8788 }
8789 else
8790 {
8791 if ( b > ON_DBL_MIN )
8792 {
8793 // b is largest
8794 a /= b; c /= b; d = b*sqrt(1.0 + c*c + a*a);
8795 }
8796 else
8797 {
8798 d = b;
8799 }
8800 }
8801 }
8802 else if ( c > a )
8803 {
8804 // c is largest
8805 if ( c > ON_DBL_MIN )
8806 {
8807 a /= c; b /= c; d = c*sqrt(1.0 + a*a + b*b);
8808 }
8809 else
8810 {
8811 d = c;
8812 }
8813 }
8814 else if ( a > ON_DBL_MIN )
8815 {
8816 // a is largest
8817 b /= a; c /= a; d = a*sqrt(1.0 + b*b + c*c);
8818 }
8819 else
8820 {
8821 d = a;
8822 }
8823
8824 if ( d > 0.0 )
8825 {
8826 N.x /= d; N.y /= d; N.z /= d;
8827 }
8828
8829 return N;
8830 }
8831
ON_GetTrianglePlaneEquation(const ON_3dPoint & A,const ON_3dPoint & B,const ON_3dPoint & C,double * a,double * b,double * c,double * d,double * evaluation_tol)8832 bool ON_GetTrianglePlaneEquation(
8833 const ON_3dPoint& A,
8834 const ON_3dPoint& B,
8835 const ON_3dPoint& C,
8836 double* a,
8837 double* b,
8838 double* c,
8839 double* d,
8840 double* evaluation_tol
8841 )
8842 {
8843 const ON_3dVector N(ON_TriangleNormal(A,B,C));
8844 const double dd( -(N.x*A.x + N.y*A.y + N.z*A.z) );
8845
8846 *a = N.x;
8847 *b = N.y;
8848 *c = N.z;
8849 *d = dd;
8850
8851 if ( 0 != evaluation_tol )
8852 {
8853 *evaluation_tol = fabs(N.x*A.x + N.y*A.y + N.z*A.z + dd);
8854 double e = fabs(N.x*B.x + N.y*B.y + N.z*B.z + dd);
8855 if ( e > *evaluation_tol )
8856 *evaluation_tol = e;
8857 e = fabs(N.x*C.x + N.y*C.y + N.z*C.z + dd);
8858 if ( e > *evaluation_tol )
8859 *evaluation_tol = e;
8860 *evaluation_tol *= (1.0 + ON_EPSILON);
8861 }
8862
8863 return (0.0 != N.x || 0.0 != N.y || 0.0 != N.z);
8864 }
8865
HiddenVertexArray() const8866 const bool* ON_Mesh::HiddenVertexArray() const
8867 {
8868 return ( ( m_hidden_count > 0 && m_H.Count() == m_V.Count() ) ? m_H.Array() : 0);
8869 }
8870
DestroyHiddenVertexArray()8871 void ON_Mesh::DestroyHiddenVertexArray()
8872 {
8873 m_H.Destroy();
8874 m_hidden_count = 0;
8875 }
8876
HiddenVertexCount() const8877 int ON_Mesh::HiddenVertexCount() const
8878 {
8879 return ((m_H.Count() == m_V.Count()) ? m_hidden_count : 0);
8880 }
8881
SetVertexHiddenFlag(int meshvi,bool bHidden)8882 void ON_Mesh::SetVertexHiddenFlag( int meshvi, bool bHidden )
8883 {
8884 const int vcount = m_V.Count();
8885 if ( meshvi >= 0 && meshvi < vcount )
8886 {
8887 if ( bHidden )
8888 {
8889 if ( vcount != m_H.Count() )
8890 {
8891 m_H.SetCapacity(vcount);
8892 m_H.SetCount(vcount);
8893 m_H.Zero();
8894 m_H[meshvi] = true;
8895 m_hidden_count = 1;
8896 }
8897 else if ( false == m_H[meshvi] )
8898 {
8899 m_H[meshvi] = true;
8900 m_hidden_count++;
8901 }
8902 }
8903 else
8904 {
8905 // show this vertex
8906 if ( m_hidden_count > 0 && vcount == m_H.Count() )
8907 {
8908 if ( m_H[meshvi] )
8909 {
8910 m_H[meshvi] = false;
8911 m_hidden_count--;
8912 if ( 0 == m_hidden_count )
8913 {
8914 DestroyHiddenVertexArray();
8915 }
8916 }
8917 }
8918 else if ( m_hidden_count > 0 || m_H.Capacity() > 0 )
8919 {
8920 // if m_H exists, it is bogus.
8921 DestroyHiddenVertexArray();
8922 }
8923 }
8924 }
8925 }
8926
8927
VertexIsHidden(int meshvi) const8928 bool ON_Mesh::VertexIsHidden(int meshvi) const
8929 {
8930 const int vcount = m_V.Count();
8931 return ((m_hidden_count > 0 && meshvi >= 0 && meshvi < vcount && vcount == m_H.Count())
8932 ? m_H[meshvi]
8933 : false);
8934 }
8935
FaceIsHidden(int meshfi) const8936 bool ON_Mesh::FaceIsHidden(int meshfi) const
8937 {
8938 const bool* bHiddenVertex = HiddenVertexArray();
8939 if ( bHiddenVertex && meshfi >= 0 && meshfi < m_F.Count() )
8940 {
8941 ON_MeshFace f = m_F[meshfi];
8942 if ( bHiddenVertex[f.vi[0]] || bHiddenVertex[f.vi[1]] || bHiddenVertex[f.vi[2]] || bHiddenVertex[f.vi[3]] )
8943 return true;
8944 }
8945 return false;
8946 }
8947
TopVertexIsHidden(int topvi) const8948 bool ON_MeshTopology::TopVertexIsHidden( int topvi ) const
8949 {
8950 const bool* bHiddenVertex = m_mesh ? m_mesh->HiddenVertexArray() : 0;
8951 if ( bHiddenVertex && topvi >= 0 && topvi < m_topv.Count() )
8952 {
8953 const ON_MeshTopologyVertex& topv = m_topv[topvi];
8954 int i;
8955 for ( i = 0; i < topv.m_v_count; i++ )
8956 {
8957 if ( !bHiddenVertex[topv.m_vi[i]] )
8958 return false;
8959 }
8960 return true;
8961 }
8962 return false;
8963 }
8964
TopEdgeIsHidden(int topei) const8965 bool ON_MeshTopology::TopEdgeIsHidden( int topei ) const
8966 {
8967 // ugly - but faster than calling TopVertexIsHidden()
8968 const bool* bHiddenVertex = m_mesh ? m_mesh->HiddenVertexArray() : 0;
8969 if ( bHiddenVertex && topei >= 0 && topei < m_tope.Count() )
8970 {
8971 const ON_MeshTopologyEdge& tope = m_tope[topei];
8972 const ON_MeshTopologyVertex& topv0 = m_topv[tope.m_topvi[0]];
8973 const ON_MeshTopologyVertex& topv1 = m_topv[tope.m_topvi[1]];
8974 int i;
8975
8976 for ( i = 0; i < topv0.m_v_count; i++ )
8977 {
8978 if ( !bHiddenVertex[topv0.m_vi[i]] )
8979 break;
8980 }
8981 if ( i >= topv0.m_v_count )
8982 return true;
8983
8984 for ( i = 0; i < topv1.m_v_count; i++ )
8985 {
8986 if ( !bHiddenVertex[topv1.m_vi[i]] )
8987 return false;
8988 }
8989
8990 return true;
8991 }
8992 return false;
8993 }
8994
TopFaceIsHidden(int topfi) const8995 bool ON_MeshTopology::TopFaceIsHidden( int topfi ) const
8996 {
8997 // topology and mesh face indices are the same
8998 return m_mesh ? m_mesh->FaceIsHidden(topfi) : false;
8999 }
9000
9001
ON_MappingTag()9002 ON_MappingTag::ON_MappingTag()
9003 {
9004 Default();
9005 }
9006
Dump(ON_TextLog & text_log) const9007 void ON_MappingTag::Dump( ON_TextLog& text_log ) const
9008 {
9009 text_log.Print("Texture/color coordinates tag:\n");
9010 text_log.PushIndent();
9011 text_log.Print("mapping id: "); text_log.Print(m_mapping_id); text_log.Print("\n");
9012 text_log.Print("mapping crc: %08x\n",m_mapping_crc);
9013 text_log.Print("mesh xform:\n");
9014 text_log.PushIndent(); text_log.Print(m_mesh_xform); text_log.PopIndent();
9015 text_log.PushIndent();
9016 text_log.Print(m_mesh_xform);
9017 text_log.PopIndent();
9018 text_log.PopIndent();
9019 }
9020
Transform(const ON_Xform & xform)9021 void ON_MappingTag::Transform( const ON_Xform& xform )
9022 {
9023 if ( !ON_UuidIsNil(m_mapping_id) )
9024 {
9025 // Update mapping transformation.
9026 // Do NOT change the value of m_mapping_crc.
9027 m_mesh_xform = xform*m_mesh_xform;
9028 }
9029 }
9030
SetDefaultSurfaceParameterMappingTag()9031 void ON_MappingTag::SetDefaultSurfaceParameterMappingTag()
9032 {
9033 ON_TextureMapping srfp_mapping;
9034 srfp_mapping.m_type = ON_TextureMapping::srfp_mapping;
9035 srfp_mapping.m_mapping_id = ON_nil_uuid;
9036 Set(srfp_mapping);
9037 }
9038
Set(const ON_TextureMapping & mapping)9039 void ON_MappingTag::Set(const ON_TextureMapping& mapping)
9040 {
9041 Default();
9042 m_mapping_id = mapping.m_mapping_id;
9043 m_mapping_type = mapping.m_type;
9044 m_mapping_crc = mapping.MappingCRC();
9045 }
9046
IsSet() const9047 bool ON_MappingTag::IsSet() const
9048 {
9049 return (0 != m_mapping_crc || !ON_UuidIsNil(m_mapping_id));
9050 }
9051
IsDefaultSurfaceParameterMapping() const9052 bool ON_MappingTag::IsDefaultSurfaceParameterMapping() const
9053 {
9054 bool rc = (ON_TextureMapping::srfp_mapping == m_mapping_type);
9055 if ( rc )
9056 {
9057 // The crc needs to be checked to insure that m_uvw
9058 // was the identity.
9059 ON_TextureMapping tmp;
9060 tmp.m_type = ON_TextureMapping::srfp_mapping;
9061 rc = (m_mapping_crc == tmp.MappingCRC());
9062 }
9063 return rc;
9064 }
9065
9066
Default()9067 void ON_MappingTag::Default()
9068 {
9069 memset(this,0,sizeof(*this));
9070 m_mesh_xform.m_xform[0][0] = 1.0;
9071 m_mesh_xform.m_xform[1][1] = 1.0;
9072 m_mesh_xform.m_xform[2][2] = 1.0;
9073 m_mesh_xform.m_xform[3][3] = 1.0;
9074 }
9075
Compare(const ON_MappingTag & other,bool bCompareId,bool bCompareCRC,bool bCompareXform) const9076 int ON_MappingTag::Compare(
9077 const ON_MappingTag& other,
9078 bool bCompareId,
9079 bool bCompareCRC,
9080 bool bCompareXform
9081 ) const
9082 {
9083 int rc = 0;
9084 if ( !rc && bCompareId )
9085 {
9086 rc = ON_UuidCompare(m_mapping_id,other.m_mapping_id);
9087 }
9088 if ( !rc && bCompareCRC )
9089 {
9090 rc = ((int)m_mapping_crc) - ((int)other.m_mapping_crc);
9091 }
9092 if ( !rc && bCompareXform )
9093 {
9094 rc = m_mesh_xform.Compare(other.m_mesh_xform);
9095 }
9096 return rc;
9097 }
9098
9099
9100
Write(ON_BinaryArchive & archive) const9101 bool ON_MappingTag::Write(ON_BinaryArchive& archive) const
9102 {
9103 bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,1);
9104 if (!rc)
9105 return false;
9106
9107 for(;;)
9108 {
9109 rc = archive.WriteUuid(m_mapping_id);
9110 if(!rc) break;
9111 rc = archive.WriteInt(m_mapping_crc);
9112 if(!rc) break;
9113 rc = archive.WriteXform(m_mesh_xform);
9114 if(!rc) break;
9115
9116 // 1.1 fields
9117 rc = archive.WriteInt(m_mapping_type);
9118 if (!rc) break;
9119
9120 break;
9121 }
9122
9123 if ( !archive.EndWrite3dmChunk() )
9124 rc = false;
9125
9126 return rc;
9127 }
9128
Read(ON_BinaryArchive & archive)9129 bool ON_MappingTag::Read(ON_BinaryArchive& archive)
9130 {
9131 Default();
9132 int mjv = 0, mnv = 0;
9133 bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&mjv,&mnv);
9134 if (!rc)
9135 return false;
9136
9137 for(;;)
9138 {
9139 rc = (1 == mjv);
9140 if (!rc) break;
9141 rc = archive.ReadUuid(m_mapping_id);
9142 if(!rc) break;
9143 if ( 0 == ON_UuidCompare(&obsolete_default_srfp_mapping_id,&m_mapping_id) )
9144 m_mapping_id = ON_nil_uuid;
9145 rc = archive.ReadInt(&m_mapping_crc);
9146 if(!rc) break;
9147 rc = archive.ReadXform(m_mesh_xform);
9148 if(!rc) break;
9149
9150 if ( mnv >= 1 )
9151 {
9152 // 1.1 fields
9153 int i = m_mapping_type;
9154 rc = archive.ReadInt(&i);
9155 if ( rc )
9156 m_mapping_type = ON_TextureMapping::TypeFromInt(i);
9157 if (!rc) break;
9158 }
9159
9160
9161 break;
9162 }
9163
9164 if ( !archive.EndRead3dmChunk() )
9165 rc = false;
9166
9167 return rc;
9168 }
9169
ON_TextureCoordinates()9170 ON_TextureCoordinates::ON_TextureCoordinates()
9171 {
9172 m_dim = 0;
9173 }
9174
9175
9176 ///////////////////////////////////////////////////////
9177 //
9178 // Double precision vertices
9179 //
9180
9181 ON_OBJECT_IMPLEMENT(ON_MeshDoubleVertices,ON_UserData,"17F24E75-21BE-4a7b-9F3D-7F85225247E3");
9182
Get(const ON_Mesh * mesh)9183 ON_MeshDoubleVertices* ON_MeshDoubleVertices::Get(const ON_Mesh* mesh)
9184 {
9185 return ON_MeshDoubleVertices::Cast(mesh->GetUserData(ON_MeshDoubleVertices::m_ON_MeshDoubleVertices_class_id.Uuid()));
9186 }
9187
Attach(const ON_Mesh * mesh)9188 ON_MeshDoubleVertices* ON_MeshDoubleVertices::Attach(const ON_Mesh* mesh)
9189 {
9190 ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(mesh);
9191 if ( 0 != dv )
9192 return 0;
9193 dv = new ON_MeshDoubleVertices();
9194 const_cast<ON_Mesh*>(mesh)->AttachUserData(dv);
9195 return dv;
9196 }
9197
ON_MeshDoubleVertices()9198 ON_MeshDoubleVertices::ON_MeshDoubleVertices()
9199 : ON_UserData()
9200 , m_fcount(0)
9201 , m_dcount(0)
9202 , m_fCRC(0)
9203 , m_dCRC(0)
9204 {
9205 m_userdata_uuid = ON_MeshDoubleVertices::m_ON_MeshDoubleVertices_class_id.Uuid();
9206 m_application_uuid = ON_opennurbs5_id;
9207 m_userdata_copycount = 1;
9208 }
9209
~ON_MeshDoubleVertices()9210 ON_MeshDoubleVertices::~ON_MeshDoubleVertices()
9211 {}
9212
IsValid(ON_TextLog *) const9213 ON_BOOL32 ON_MeshDoubleVertices::IsValid( ON_TextLog* ) const
9214 {
9215 return true;
9216 }
9217
Dump(ON_TextLog & text_log) const9218 void ON_MeshDoubleVertices::Dump( ON_TextLog& text_log ) const
9219 {
9220 // TODO - print some double values
9221 ON_UserData::Dump(text_log);
9222 }
9223
SizeOf() const9224 unsigned int ON_MeshDoubleVertices::SizeOf() const
9225 {
9226 return m_dV.SizeOfArray() + ON_UserData::SizeOf();
9227 }
9228
DataCRC(ON__UINT32 current_remainder) const9229 ON__UINT32 ON_MeshDoubleVertices::DataCRC(ON__UINT32 current_remainder) const
9230 {
9231 current_remainder = ON_CRC32(current_remainder,sizeof(m_fcount),&m_fcount);
9232 current_remainder = ON_CRC32(current_remainder,sizeof(m_dcount),&m_dcount);
9233 current_remainder = ON_CRC32(current_remainder,sizeof(m_fCRC),&m_fCRC);
9234 current_remainder = ON_CRC32(current_remainder,sizeof(m_dCRC),&m_dCRC);
9235 current_remainder = m_dV.DataCRC(current_remainder);
9236 return current_remainder;
9237 }
9238
Write(ON_BinaryArchive & file) const9239 ON_BOOL32 ON_MeshDoubleVertices::Write(ON_BinaryArchive& file) const
9240 {
9241 bool rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
9242 if (!rc)
9243 return false;
9244 for(;;)
9245 {
9246 rc = file.WriteInt(m_fcount);
9247 if (!rc)
9248 break;
9249 rc = file.WriteInt(m_dcount);
9250 if (!rc)
9251 break;
9252 rc = file.WriteInt(m_fCRC);
9253 if (!rc)
9254 break;
9255 rc = file.WriteInt(m_dCRC);
9256 if (!rc)
9257 break;
9258 rc = file.WriteArray(m_dV);
9259 if (!rc)
9260 break;
9261 break;
9262 }
9263 if ( !file.EndWrite3dmChunk() )
9264 rc = false;
9265 return rc;
9266 }
9267
Read(ON_BinaryArchive & file)9268 ON_BOOL32 ON_MeshDoubleVertices::Read(ON_BinaryArchive& file)
9269 {
9270 m_fcount = 0;
9271 m_dcount = 0;
9272 m_fCRC = 0;
9273 m_dCRC = 0;
9274 m_dV.Destroy();
9275
9276 int major_version = 0;
9277 int minor_version = 0;
9278 bool rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
9279 if (!rc)
9280 return false;
9281 for(;;)
9282 {
9283 rc = file.ReadInt(&m_fcount);
9284 if (!rc)
9285 break;
9286 rc = file.ReadInt(&m_dcount);
9287 if (!rc)
9288 break;
9289 rc = file.ReadInt(&m_fCRC);
9290 if (!rc)
9291 break;
9292 rc = file.ReadInt(&m_dCRC);
9293 if (!rc)
9294 break;
9295 rc = file.ReadArray(m_dV);
9296 if (!rc)
9297 break;
9298 break;
9299 }
9300 if ( !file.EndRead3dmChunk() )
9301 rc = false;
9302 return rc;
9303 }
9304
9305 // virtual ON_UserData overrides
GetDescription(ON_wString & description)9306 ON_BOOL32 ON_MeshDoubleVertices::GetDescription( ON_wString& description )
9307 {
9308 description = L"ON_Mesh double precision vertices";
9309 return true;
9310 }
9311
Archive() const9312 ON_BOOL32 ON_MeshDoubleVertices::Archive() const
9313 {
9314 // refuse to save garbage in files.
9315
9316 if ( m_fcount != m_dcount )
9317 {
9318 ON_ERROR("m_fcount != m_dcount");
9319 return false;
9320 }
9321
9322 if ( m_dcount != m_dV.Count() )
9323 {
9324 ON_ERROR("m_dcount != m_dV.Count()");
9325 return false;
9326 }
9327
9328 if ( m_dCRC != DoubleCRC() )
9329 {
9330 ON_ERROR("m_dCRC != DoubleCRC()");
9331 return false;
9332 }
9333
9334 const ON_Mesh* mesh = ON_Mesh::Cast( Owner() );
9335 if ( 0 == mesh )
9336 {
9337 ON_ERROR("0 = ON_Mesh::Cast( Owner() )");
9338 return false;
9339 }
9340
9341 if ( m_fcount != mesh->m_V.Count() )
9342 {
9343 ON_ERROR("m_fcount != mesh->m_V.Count()");
9344 return false;
9345 }
9346
9347 if ( m_fCRC != ON_MeshDoubleVertices::FloatCRC(mesh->m_V) )
9348 {
9349 ON_ERROR("m_fCRC != ON_MeshDoubleVertices::FloatCRC(mesh->m_V)");
9350 return false;
9351 }
9352
9353 return true;
9354 }
9355
Transform(const ON_Xform & xform)9356 ON_BOOL32 ON_MeshDoubleVertices::Transform( const ON_Xform& xform )
9357 {
9358 if ( !xform.IsIdentity() )
9359 {
9360 const ON__UINT32 crc0 = DoubleCRC();
9361 m_dV.Transform(xform);
9362 const ON__UINT32 crc1 = DoubleCRC();
9363 if ( crc0 == m_dCRC && m_dV.Count() == m_dcount )
9364 m_dCRC = crc1; // update m_dCRC so it stays valid
9365 else
9366 m_dCRC = (0==crc1)?1:0; // make sure m_dCRC is not valid
9367 }
9368 return true;
9369 }
9370
HasSynchronizedDoubleAndSinglePrecisionVertices() const9371 bool ON_Mesh::HasSynchronizedDoubleAndSinglePrecisionVertices() const
9372 {
9373 ON_3fPoint P;
9374 const ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9375 if ( 0 == dv )
9376 return false;
9377 int count = m_V.Count();
9378 if ( count != dv->m_dV.Count() )
9379 return false;
9380 const ON_3fPoint* FV = m_V.Array();
9381 const ON_3dPoint* DV = dv->m_dV.Array();
9382 while (count--)
9383 {
9384 // Compare float values.
9385 P.x = (float)DV->x;
9386 P.y = (float)DV->y;
9387 P.z = (float)DV->z;
9388 if ( !(P.x == FV->x && P.y == FV->y && P.z == FV->z) )
9389 return false;
9390 }
9391 return true;
9392 }
9393
HasDoublePrecisionVertices() const9394 bool ON_Mesh::HasDoublePrecisionVertices() const
9395 {
9396 return ( 0 != ON_MeshDoubleVertices::Get(this));
9397 }
9398
DestroyDoublePrecisionVertices()9399 void ON_Mesh::DestroyDoublePrecisionVertices()
9400 {
9401 ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9402 if ( dv )
9403 delete dv;
9404 }
9405
EnableDoublePrecisionVertices(bool bEnableDoublePrecisionVertices)9406 void ON_Mesh::EnableDoublePrecisionVertices(bool bEnableDoublePrecisionVertices)
9407 {
9408 ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9409 if ( bEnableDoublePrecisionVertices )
9410 {
9411 if ( 0 == dv )
9412 {
9413 dv = ON_MeshDoubleVertices::Attach(this);
9414 UpdateDoublePrecisionVertices();
9415 }
9416 }
9417 else
9418 {
9419 // destroy double precision vertices
9420 if ( 0 != dv )
9421 delete dv;
9422 }
9423 }
9424
FloatCRC(const ON_3fPointArray & V)9425 ON__UINT32 ON_MeshDoubleVertices::FloatCRC( const ON_3fPointArray& V )
9426 {
9427 return V.DataCRC(0);
9428 }
9429
DoubleCRC() const9430 ON__UINT32 ON_MeshDoubleVertices::DoubleCRC() const
9431 {
9432 return m_dV.DataCRC(0);
9433 }
9434
UpdateSinglePrecisionVertices()9435 void ON_Mesh::UpdateSinglePrecisionVertices()
9436 {
9437 ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9438 if ( 0 == dv )
9439 return;
9440 int count = dv->m_dV.Count();
9441 m_V.Reserve(count);
9442 m_V.SetCount(count);
9443 ON_3fPoint* fV = m_V.Array();
9444 const ON_3dPoint* dV = dv->m_dV.Array();
9445 while(count--)
9446 {
9447 fV->x = (float)dV->x;
9448 fV->y = (float)dV->y;
9449 fV->z = (float)dV->z;
9450 fV++;
9451 dV++;
9452 }
9453 dv->m_fcount = dv->m_dV.Count();
9454 dv->m_dcount = dv->m_dV.Count();
9455 dv->m_fCRC = ON_MeshDoubleVertices::FloatCRC(m_V);
9456 dv->m_dCRC = dv->DoubleCRC();
9457 }
9458
UpdateDoublePrecisionVertices()9459 void ON_Mesh::UpdateDoublePrecisionVertices()
9460 {
9461 ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9462 if ( 0 == dv )
9463 return;
9464 int count = m_V.Count();
9465 bool bSelectiveUpdate = (count == dv->m_dV.Count());
9466 dv->m_dV.Reserve(count);
9467 dv->m_dV.SetCount(count);
9468 ON_3dPoint* dV = dv->m_dV.Array();
9469 const ON_3fPoint* fV = m_V.Array();
9470 if ( bSelectiveUpdate )
9471 {
9472 // double precision vertices already existed
9473 // and there is a reasonable chance that
9474 // a subset of the float precision vertices
9475 // have been modified. So, attempt to
9476 // keep the precision on double vertices
9477 // that alread agree with the float vertices
9478 // in float precision.
9479 ON_3fPoint P;
9480 while(count--)
9481 {
9482 P.x = (float)dV->x;
9483 P.y = (float)dV->y;
9484 P.z = (float)dV->z;
9485 if ( !(P.x == fV->x && P.y == fV->y && P.z == fV->z) )
9486 {
9487 // (float)dV != fV, so update dV
9488 dV->x = (double)fV->x;
9489 dV->y = (double)fV->y;
9490 dV->z = (double)fV->z;
9491 }
9492 dV++;
9493 fV++;
9494 }
9495 }
9496 else
9497 {
9498 while(count--)
9499 {
9500 dV->x = (double)fV->x;
9501 dV->y = (double)fV->y;
9502 dV->z = (double)fV->z;
9503 dV++;
9504 fV++;
9505 }
9506 }
9507 dv->m_fcount = m_V.Count();
9508 dv->m_dcount = m_V.Count();
9509 dv->m_fCRC = ON_MeshDoubleVertices::FloatCRC(m_V);
9510 dv->m_dCRC = dv->DoubleCRC();
9511 }
9512
SetSinglePrecisionVerticesAsValid()9513 void ON_Mesh::SetSinglePrecisionVerticesAsValid()
9514 {
9515 ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9516 if ( 0 == dv )
9517 return;
9518 dv->m_fcount = m_V.Count();
9519 dv->m_fCRC = ON_MeshDoubleVertices::FloatCRC(m_V);
9520 }
9521
SetDoublePrecisionVerticesAsValid()9522 void ON_Mesh::SetDoublePrecisionVerticesAsValid()
9523 {
9524 ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9525 if ( 0 == dv )
9526 return;
9527 dv->m_dcount = dv->m_dV.Count();
9528 dv->m_dCRC = dv->DoubleCRC();
9529 }
9530
SinglePrecisionVerticesAreValid() const9531 bool ON_Mesh::SinglePrecisionVerticesAreValid() const
9532 {
9533 const ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9534 if ( 0 == dv )
9535 return true;
9536 return ( dv->m_fcount == m_V.Count() && dv->m_fCRC == ON_MeshDoubleVertices::FloatCRC(m_V) );
9537 }
9538
DoublePrecisionVerticesAreValid() const9539 bool ON_Mesh::DoublePrecisionVerticesAreValid() const
9540 {
9541 const ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9542 if ( 0 == dv )
9543 return true;
9544 // DO NOT COMPARE dv->m_dV.Count() and m_V.Count() because m_V might be
9545 // the bogus set of values.
9546 return ( dv->m_dcount == dv->m_dV.Count() && dv->m_dCRC == dv->DoubleCRC() );
9547 }
9548
9549
9550
DoublePrecisionVertices()9551 ON_3dPointArray& ON_Mesh::DoublePrecisionVertices()
9552 {
9553 ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9554
9555 bool bUpdate = false;
9556 if ( 0 == dv )
9557 {
9558 dv = ON_MeshDoubleVertices::Attach(this);
9559 bUpdate = true;
9560 }
9561 else if ( dv->m_dcount != dv->m_dV.Count()|| dv->m_dCRC != dv->DoubleCRC() )
9562 {
9563 if ( dv->m_fcount == m_V.Count() && dv->m_fCRC == ON_MeshDoubleVertices::FloatCRC(m_V) )
9564 bUpdate = true;
9565 }
9566
9567 if ( bUpdate )
9568 UpdateDoublePrecisionVertices();
9569
9570 return dv->m_dV;
9571 }
9572
Vertex(int vertex_index) const9573 ON_3dPoint ON_Mesh::Vertex(int vertex_index) const
9574 {
9575 if ( vertex_index < 0 || vertex_index >= m_V.Count() )
9576 return ON_3dPoint::UnsetPoint;
9577
9578 const ON_3fPoint F = m_V[vertex_index];
9579 ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9580 if ( 0 != dv && dv->m_dV.Count() == m_V.Count() )
9581 {
9582 ON_3dPoint D = dv->m_dV[vertex_index];
9583 if ( F.x == (float)D.x && F.y == (float)D.y && F.z == (float)D.z )
9584 {
9585 // double precision vertex is valid
9586 return D;
9587 }
9588 }
9589
9590 return F;
9591 }
9592
DoublePrecisionVertices() const9593 const ON_3dPointArray& ON_Mesh::DoublePrecisionVertices() const
9594 {
9595 ON_Mesh& mesh = const_cast<ON_Mesh&>(*this);
9596 ON_3dPointArray& a = mesh.DoublePrecisionVertices();
9597 return a;
9598 }
9599
SinglePrecisionVertices()9600 ON_3fPointArray& ON_Mesh::SinglePrecisionVertices()
9601 {
9602 ON_MeshDoubleVertices* dv = ON_MeshDoubleVertices::Get(this);
9603
9604 if ( 0 != dv )
9605 {
9606 if ( dv->m_fcount != m_V.Count()|| dv->m_fCRC != ON_MeshDoubleVertices::FloatCRC(m_V) )
9607 {
9608 if ( dv->m_dcount == dv->m_dV.Count() && dv->m_dCRC == dv->DoubleCRC() )
9609 UpdateSinglePrecisionVertices();
9610 }
9611 }
9612
9613 return m_V;
9614 }
9615
SinglePrecisionVertices() const9616 const ON_3fPointArray& ON_Mesh::SinglePrecisionVertices() const
9617 {
9618 ON_Mesh& mesh = const_cast<ON_Mesh&>(*this);
9619 ON_3fPointArray& a = mesh.SinglePrecisionVertices();
9620 return a;
9621 }
9622
9623
9624 ////////////////////////////////////////////////////////////////
9625 //
9626 // BEGIN ON_PerObjectMeshParameters user data class
9627 //
9628
9629
9630 class /*NEVER EXPORT THIS CLASS DEFINITION*/ ON_PerObjectMeshParameters : public ON_UserData
9631 {
9632 #if !defined(ON_BOZO_VACCINE_B5628CA982C44CAE9883487B3E4AB28B)
9633 #error Never copy this class definition or put this definition in a header file!
9634 #endif
9635 ON_OBJECT_DECLARE(ON_PerObjectMeshParameters);
9636
9637 public:
9638 ON_PerObjectMeshParameters();
9639 ~ON_PerObjectMeshParameters();
9640 // default copy constructor and operator= work fine.
9641
9642 public:
9643 // virtual ON_Object override
9644 ON_BOOL32 IsValid( ON_TextLog* text_log = NULL ) const;
9645 // virtual ON_Object override
9646 unsigned int SizeOf() const;
9647 // virtual ON_Object override
9648 ON__UINT32 DataCRC(ON__UINT32 current_remainder) const;
9649 // virtual ON_Object override
9650 ON_BOOL32 Write(ON_BinaryArchive& binary_archive) const;
9651 // virtual ON_Object override
9652 ON_BOOL32 Read(ON_BinaryArchive& binary_archive);
9653 // virtual ON_UserData override
9654 ON_BOOL32 Archive() const;
9655 // virtual ON_UserData override
9656 ON_BOOL32 GetDescription( ON_wString& description );
9657
9658 public:
9659 static
9660 ON_PerObjectMeshParameters* FindOrCreate( const ON_Object*, bool bCreate );
9661
9662 ON_MeshParameters m_mp;
9663 };
9664
9665 #undef ON_BOZO_VACCINE_B5628CA982C44CAE9883487B3E4AB28B
9666
9667 ON_OBJECT_IMPLEMENT(ON_PerObjectMeshParameters,ON_UserData,"B5628CA9-82C4-4CAE-9883-487B3E4AB28B");
9668
FindOrCreate(const ON_Object * object,bool bCreate)9669 ON_PerObjectMeshParameters* ON_PerObjectMeshParameters::FindOrCreate(const ON_Object* object,bool bCreate)
9670 {
9671 if ( 0 == object )
9672 return 0;
9673 ON_PerObjectMeshParameters* ud = ON_PerObjectMeshParameters::Cast(object->GetUserData(ON_PerObjectMeshParameters::m_ON_PerObjectMeshParameters_class_id.Uuid()));
9674 if ( !ud && bCreate )
9675 {
9676 ud = new ON_PerObjectMeshParameters();
9677 const_cast< ON_Object* >(object)->AttachUserData(ud);
9678 }
9679 return ud;
9680 }
9681
ON_PerObjectMeshParameters()9682 ON_PerObjectMeshParameters::ON_PerObjectMeshParameters()
9683 : m_mp(ON_MeshParameters::FastRenderMesh)
9684 {
9685 m_userdata_uuid = ON_PerObjectMeshParameters::m_ON_PerObjectMeshParameters_class_id.Uuid();
9686 m_application_uuid = ON_opennurbs5_id;
9687 m_userdata_copycount = 1;
9688 m_mp.m_bCustomSettings = true;
9689 m_mp.m_bComputeCurvature = false;
9690 }
9691
~ON_PerObjectMeshParameters()9692 ON_PerObjectMeshParameters::~ON_PerObjectMeshParameters()
9693 {
9694 }
9695
9696 // virtual ON_Object override
IsValid(ON_TextLog *) const9697 ON_BOOL32 ON_PerObjectMeshParameters::IsValid( ON_TextLog* ) const
9698 {
9699 return true;
9700 }
9701
9702 // virtual ON_Object override
SizeOf() const9703 unsigned int ON_PerObjectMeshParameters::SizeOf() const
9704 {
9705 std::size_t sz = sizeof(*this) - sizeof(ON_UserData);
9706 return (unsigned int)sz;
9707 }
9708
9709 // virtual ON_Object override
DataCRC(ON__UINT32 current_remainder) const9710 ON__UINT32 ON_PerObjectMeshParameters::DataCRC(ON__UINT32 current_remainder) const
9711 {
9712 return m_mp.DataCRC(current_remainder);
9713 }
9714
9715 // virtual ON_Object override
Write(ON_BinaryArchive & binary_archive) const9716 ON_BOOL32 ON_PerObjectMeshParameters::Write(ON_BinaryArchive& binary_archive) const
9717 {
9718 if ( !binary_archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0) )
9719 return false;
9720
9721 bool rc = false;
9722 for(;;)
9723 {
9724 if ( !binary_archive.BeginWrite3dmBigChunk(TCODE_ANONYMOUS_CHUNK,0) )
9725 break;
9726 bool mprc = m_mp.Write(binary_archive);
9727 if ( !binary_archive.EndWrite3dmChunk() )
9728 break;
9729 if ( !mprc )
9730 break;
9731 rc = true;
9732 break;
9733 }
9734
9735 if ( !binary_archive.EndWrite3dmChunk() )
9736 rc = false;
9737
9738 return rc;
9739 }
9740
9741 // virtual ON_Object override
Read(ON_BinaryArchive & binary_archive)9742 ON_BOOL32 ON_PerObjectMeshParameters::Read(ON_BinaryArchive& binary_archive)
9743 {
9744 m_mp = ON_MeshParameters::FastRenderMesh;
9745 m_mp.m_bCustomSettings = true;
9746 m_mp.m_bComputeCurvature = false;
9747
9748 int major_version = 0;
9749 int minor_version = 0;
9750 if ( !binary_archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version) )
9751 return false;
9752
9753 bool rc = false;
9754 for(;;)
9755 {
9756 if ( 1 != major_version )
9757 break;
9758
9759 unsigned int tcode(0);
9760 ON__INT64 value(0);
9761 if (!binary_archive.BeginRead3dmBigChunk(&tcode,&value))
9762 break;
9763 bool mprc = false;
9764 for(;;)
9765 {
9766 if (TCODE_ANONYMOUS_CHUNK != tcode )
9767 break;
9768 if (value <= 0)
9769 break;
9770 if (!m_mp.Read(binary_archive))
9771 break;
9772 mprc = true;
9773 break;
9774 }
9775 if (!binary_archive.EndRead3dmChunk())
9776 break;
9777 if (!mprc)
9778 break;
9779
9780 rc = true;
9781 break;
9782 }
9783
9784 if ( !binary_archive.EndRead3dmChunk() )
9785 rc = false;
9786
9787 m_mp.m_bCustomSettings = true;
9788 m_mp.m_bComputeCurvature = false;
9789
9790 return rc;
9791 }
9792
9793 // virtual ON_UserData override
Archive() const9794 ON_BOOL32 ON_PerObjectMeshParameters::Archive() const
9795 {
9796 return true;
9797 }
9798
9799 // virtual ON_UserData override
GetDescription(ON_wString & description)9800 ON_BOOL32 ON_PerObjectMeshParameters::GetDescription( ON_wString& description )
9801 {
9802 description = L"Custom Render Mesh Parameters";
9803 return true;
9804 }
9805
9806 //
9807 // END ON_PerObjectMeshParameters user data class
9808 //
9809 ////////////////////////////////////////////////////////////////
9810
CustomRenderMeshParameters() const9811 const ON_MeshParameters* ON_3dmObjectAttributes::CustomRenderMeshParameters() const
9812 {
9813 const ON_PerObjectMeshParameters* ud = ON_PerObjectMeshParameters::FindOrCreate(this,false);
9814 return (0 != ud) ? &ud->m_mp : 0;
9815 }
9816
SetCustomRenderMeshParameters(const ON_MeshParameters & mp)9817 bool ON_3dmObjectAttributes::SetCustomRenderMeshParameters( const ON_MeshParameters& mp )
9818 {
9819 ON_PerObjectMeshParameters* ud = ON_PerObjectMeshParameters::FindOrCreate(this,true);
9820 if ( 0 == ud )
9821 return false;
9822 ud->m_mp = mp;
9823 ud->m_mp.m_bCustomSettings = true;
9824 ud->m_mp.m_bComputeCurvature = false;
9825 if ( 1 != ud->m_mp.m_texture_range && 2 != ud->m_mp.m_texture_range )
9826 ud->m_mp.m_texture_range = 2;
9827 return true;
9828 }
9829
DeleteCustomRenderMeshParameters()9830 void ON_3dmObjectAttributes::DeleteCustomRenderMeshParameters()
9831 {
9832 ON_PerObjectMeshParameters* ud = ON_PerObjectMeshParameters::FindOrCreate(this,false);
9833 if ( 0 != ud )
9834 delete ud;
9835 }
9836
EnableCustomRenderMeshParameters(bool bEnable)9837 bool ON_3dmObjectAttributes::EnableCustomRenderMeshParameters(bool bEnable)
9838 {
9839 ON_PerObjectMeshParameters* ud = ON_PerObjectMeshParameters::FindOrCreate(this,false);
9840 if ( 0 != ud )
9841 ud->m_mp.m_bCustomSettingsEnabled = bEnable ? true : false;
9842 return (!bEnable || 0 != ud);
9843 }
9844
DestroyTree(bool)9845 void ON_Mesh::DestroyTree( bool )
9846 {
9847 }
9848
9849
9850 int* ON_Mesh_GetVidHelper( const int Vcount, const ON_3fPoint* fV, const ON_3dPoint* dV, int first_vid, int* Vid, int* Vindex );
comparefV(const void * a,const void * b)9851 static int comparefV( const void* a, const void* b )
9852 {
9853 const float* af = (const float*)a;
9854 const float* bf = (const float*)b;
9855 if ( af[0] < bf[0] )
9856 return -1;
9857 if ( af[0] > bf[0] )
9858 return 1;
9859 if ( af[1] < bf[1] )
9860 return -1;
9861 if ( af[1] > bf[1] )
9862 return 1;
9863 if ( af[2] < bf[2] )
9864 return -1;
9865 if ( af[2] > bf[2] )
9866 return 1;
9867 return 0;
9868 }
9869
comparedV(const void * a,const void * b)9870 static int comparedV( const void* a, const void* b )
9871 {
9872 const double* af = (const double*)a;
9873 const double* bf = (const double*)b;
9874 if ( af[0] < bf[0] )
9875 return -1;
9876 if ( af[0] > bf[0] )
9877 return 1;
9878 if ( af[1] < bf[1] )
9879 return -1;
9880 if ( af[1] > bf[1] )
9881 return 1;
9882 if ( af[2] < bf[2] )
9883 return -1;
9884 if ( af[2] > bf[2] )
9885 return 1;
9886 return 0;
9887 }
9888
ON_Mesh_GetVidHelper(const int Vcount,const ON_3fPoint * fV,const ON_3dPoint * dV,int first_vid,int * Vid,int * Vindex)9889 int* ON_Mesh_GetVidHelper( const int Vcount, const ON_3fPoint* fV, const ON_3dPoint* dV, int first_vid, int* Vid, int* Vindex )
9890 {
9891 // Used here and in opennurbs_plus_xmeshfast.cpp
9892
9893 if ( Vcount <= 0 || (0 == dV && 0 == fV) )
9894 return 0;
9895
9896 int Vmapbuffer[1024];
9897 int* Vmap;
9898 int id, i;
9899 const ON_3fPoint* fP0;
9900 const ON_3fPoint* fP1;
9901 const ON_3dPoint* dP0;
9902 const ON_3dPoint* dP1;
9903 if ( Vindex )
9904 {
9905 Vmap = Vindex;
9906 }
9907 else
9908 {
9909 Vmap = ( Vcount*sizeof(*Vmap) <= sizeof(Vmapbuffer) )
9910 ? &Vmapbuffer[0]
9911 : (int*)onmalloc( Vcount*sizeof(*Vmap) );
9912 }
9913 if ( 0 == Vmap )
9914 return 0;
9915
9916 // The call to ON_Sort fills in Vmap[] with a permutation
9917 // of (0,1,...,Vcount-1) so that all coincident points
9918 // are adjacent in the Vmap[] list. The vertex locations
9919 // are often partially sorted. In the past, heap sort was
9920 // a better choice but the qsort in VC 2010
9921 // is now faster than heap sort.
9922 if ( 0 != dV )
9923 ON_Sort( ON::quick_sort, Vmap, dV, Vcount, sizeof(dV[0]), comparedV );
9924 else
9925 ON_Sort( ON::quick_sort, Vmap, fV, Vcount, sizeof(fV[0]), comparefV );
9926
9927 // Assign a sequential one based index to each unique point location.
9928 if ( 0 == Vid )
9929 Vid = (int*)onmalloc(Vcount*sizeof(*Vid));
9930
9931 if ( 0 != dV )
9932 {
9933 dP0 = dV + Vmap[0];
9934 id = first_vid;
9935 Vid[Vmap[0]] = id;
9936 for ( i = 1; i < Vcount; i++ )
9937 {
9938 dP1 = dV + Vmap[i];
9939 if ( dP0->x != dP1->x || dP0->y != dP1->y || dP0->z != dP1->z )
9940 {
9941 dP0 = dP1;
9942 id++;
9943 }
9944 Vid[Vmap[i]] = id;
9945 }
9946 }
9947 else
9948 {
9949 fP0 = fV + Vmap[0];
9950 id = first_vid;
9951 Vid[Vmap[0]] = id;
9952 for ( i = 1; i < Vcount; i++ )
9953 {
9954 fP1 = fV + Vmap[i];
9955 if ( fP0->x != fP1->x || fP0->y != fP1->y || fP0->z != fP1->z )
9956 {
9957 fP0 = fP1;
9958 id++;
9959 }
9960 Vid[Vmap[i]] = id;
9961 }
9962 }
9963
9964 if ( 0 != Vmap && Vmap != &Vmapbuffer[0] && Vmap != Vindex )
9965 onfree(Vmap);
9966
9967 return Vid;
9968 }
9969
GetVertexLocationIds(int first_vid,int * Vid,int * Vindex) const9970 int* ON_Mesh::GetVertexLocationIds( int first_vid, int* Vid, int* Vindex ) const
9971 {
9972 const ON_3dPoint* dV = Mesh_dV(*this);
9973 const ON_3fPoint* fV = (0 == dV) ? m_V.Array() : 0;
9974 return ON_Mesh_GetVidHelper( m_V.Count(), fV, dV, first_vid, Vid, Vindex );
9975 }
9976
9977 /*
9978 Description:
9979 Helper to get edge info array needed by ON_Mesh::GetEdgeList()
9980 and ON_Mesh::IsClosed().
9981 Parameters:
9982 Fcount - [in]
9983 F - [in]
9984 Vid - [in] array from ON_Mesh_GetVidHelper()
9985 Eid_list - [out]
9986 input array needs to be large enough to hold one element for
9987 each face side. 4*Fcount is always large enough.
9988 */
9989
ON_Mesh_GetEidHelper(const int Vcount,const int Fcount,const ON_MeshFace * F,const int * Vid,ON_MeshFaceSide * Eid_list)9990 int ON_Mesh_GetEidHelper(
9991 const int Vcount,
9992 const int Fcount,
9993 const ON_MeshFace* F,
9994 const int* Vid,
9995 ON_MeshFaceSide* Eid_list
9996 )
9997 {
9998 // Used here and in opennurbs_plus_xmeshfast.cpp
9999 const int* fvi;
10000 int i, Vid0;
10001 int Eid_count = 0;
10002 struct ON_MeshFaceSide Eid;
10003 memset(&Eid,0,sizeof(Eid));
10004
10005 if ( 0 == Vid )
10006 {
10007 // use mesh m_V[] index
10008 for ( Eid.fi = 0; Eid.fi < Fcount; Eid.fi++ )
10009 {
10010 fvi = F[Eid.fi].vi;
10011
10012 // These checks are necessary to prevent crashes
10013 if ( fvi[0] < 0 || fvi[0] >= Vcount )
10014 continue;
10015 if ( fvi[1] < 0 || fvi[1] >= Vcount )
10016 continue;
10017 if ( fvi[2] < 0 || fvi[2] >= Vcount )
10018 continue;
10019 if ( fvi[3] < 0 || fvi[3] >= Vcount )
10020 continue;
10021
10022 Eid.vi[0] = fvi[0];
10023 Vid0 = Eid.vi[1] = fvi[1];
10024 Eid.side = 0;
10025 if ( Eid.vi[0] < Eid.vi[1] )
10026 {
10027 Eid.dir = 0;
10028 Eid_list[Eid_count++] = Eid;
10029 }
10030 else if ( Eid.vi[0] > Eid.vi[1] )
10031 {
10032 i = Eid.vi[0]; Eid.vi[0] = Eid.vi[1]; Eid.vi[1] = i;
10033 Eid.dir = 1;
10034 Eid_list[Eid_count++] = Eid;
10035 }
10036
10037 Eid.vi[0] = Vid0;
10038 Vid0 = Eid.vi[1] = fvi[2];
10039 Eid.side = 1;
10040 if ( Eid.vi[0] < Eid.vi[1] )
10041 {
10042 Eid.dir = 0;
10043 Eid_list[Eid_count++] = Eid;
10044 }
10045 else if ( Eid.vi[0] > Eid.vi[1] )
10046 {
10047 i = Eid.vi[0]; Eid.vi[0] = Eid.vi[1]; Eid.vi[1] = i;
10048 Eid.dir = 1;
10049 Eid_list[Eid_count++] = Eid;
10050 }
10051
10052 if ( fvi[2] != fvi[3] )
10053 {
10054 // quad
10055 Eid.vi[0] = Vid0;
10056 Vid0 = Eid.vi[1] = fvi[3];
10057 Eid.side = 2;
10058 if ( Eid.vi[0] < Eid.vi[1] )
10059 {
10060 Eid.dir = 0;
10061 Eid_list[Eid_count++] = Eid;
10062 }
10063 else if ( Eid.vi[0] > Eid.vi[1] )
10064 {
10065 i = Eid.vi[0]; Eid.vi[0] = Eid.vi[1]; Eid.vi[1] = i;
10066 Eid.dir = 1;
10067 Eid_list[Eid_count++] = Eid;
10068 }
10069 }
10070
10071 Eid.vi[0] = Vid0;
10072 Eid.vi[1] = fvi[0];
10073 Eid.side = 3;
10074 if ( Eid.vi[0] < Eid.vi[1] )
10075 {
10076 Eid.dir = 0;
10077 Eid_list[Eid_count++] = Eid;
10078 }
10079 else if ( Eid.vi[0] > Eid.vi[1] )
10080 {
10081 i = Eid.vi[0]; Eid.vi[0] = Eid.vi[1]; Eid.vi[1] = i;
10082 Eid.dir = 1;
10083 Eid_list[Eid_count++] = Eid;
10084 }
10085 }
10086 }
10087 else
10088 {
10089 // use Vid[mesh m_V[] index]
10090
10091 for ( Eid.fi = 0; Eid.fi < Fcount; Eid.fi++ )
10092 {
10093 fvi = F[Eid.fi].vi;
10094
10095 // These checks are necessary to prevent crashes
10096 if ( fvi[0] < 0 || fvi[0] >= Vcount )
10097 continue;
10098 if ( fvi[1] < 0 || fvi[1] >= Vcount )
10099 continue;
10100 if ( fvi[2] < 0 || fvi[2] >= Vcount )
10101 continue;
10102 if ( fvi[3] < 0 || fvi[3] >= Vcount )
10103 continue;
10104
10105 Eid.vi[0] = Vid[fvi[0]];
10106 Vid0 = Eid.vi[1] = Vid[fvi[1]];
10107 Eid.side = 0;
10108 if ( Eid.vi[0] < Eid.vi[1] )
10109 {
10110 Eid.dir = 0;
10111 Eid_list[Eid_count++] = Eid;
10112 }
10113 else if ( Eid.vi[0] > Eid.vi[1] )
10114 {
10115 i = Eid.vi[0]; Eid.vi[0] = Eid.vi[1]; Eid.vi[1] = i;
10116 Eid.dir = 1;
10117 Eid_list[Eid_count++] = Eid;
10118 }
10119
10120 Eid.vi[0] = Vid0;
10121 Vid0 = Eid.vi[1] = Vid[fvi[2]];
10122 Eid.side = 1;
10123 if ( Eid.vi[0] < Eid.vi[1] )
10124 {
10125 Eid.dir = 0;
10126 Eid_list[Eid_count++] = Eid;
10127 }
10128 else if ( Eid.vi[0] > Eid.vi[1] )
10129 {
10130 i = Eid.vi[0]; Eid.vi[0] = Eid.vi[1]; Eid.vi[1] = i;
10131 Eid.dir = 1;
10132 Eid_list[Eid_count++] = Eid;
10133 }
10134
10135 if ( fvi[2] != fvi[3] )
10136 {
10137 // quad
10138 Eid.vi[0] = Vid0;
10139 Vid0 = Eid.vi[1] = Vid[fvi[3]];
10140 Eid.side = 2;
10141 if ( Eid.vi[0] < Eid.vi[1] )
10142 {
10143 Eid.dir = 0;
10144 Eid_list[Eid_count++] = Eid;
10145 }
10146 else if ( Eid.vi[0] > Eid.vi[1] )
10147 {
10148 i = Eid.vi[0]; Eid.vi[0] = Eid.vi[1]; Eid.vi[1] = i;
10149 Eid.dir = 1;
10150 Eid_list[Eid_count++] = Eid;
10151 }
10152 }
10153
10154 Eid.vi[0] = Vid0;
10155 Eid.vi[1] = Vid[fvi[0]];
10156 Eid.side = 3;
10157 if ( Eid.vi[0] < Eid.vi[1] )
10158 {
10159 Eid.dir = 0;
10160 Eid_list[Eid_count++] = Eid;
10161 }
10162 else if ( Eid.vi[0] > Eid.vi[1] )
10163 {
10164 i = Eid.vi[0]; Eid.vi[0] = Eid.vi[1]; Eid.vi[1] = i;
10165 Eid.dir = 1;
10166 Eid_list[Eid_count++] = Eid;
10167 }
10168 }
10169 }
10170
10171 return Eid_count;
10172 }
10173
GetMeshFaceSideList(const int * Vid,struct ON_MeshFaceSide * & sides) const10174 int ON_Mesh::GetMeshFaceSideList(
10175 const int* Vid,
10176 struct ON_MeshFaceSide*& sides
10177 ) const
10178 {
10179 const int Vcount = m_V.Count();
10180 const int Fcount = m_F.Count();
10181 const ON_MeshFace* F = m_F.Array();
10182
10183 if ( Fcount < 1 || 0 == F || Vcount < 2 )
10184 return 0;
10185
10186 struct ON_MeshFaceSide* Elist = sides;
10187 if ( 0 == Elist )
10188 {
10189 Elist = (struct ON_MeshFaceSide*)onmalloc(4*Fcount*sizeof(Elist[0]));
10190 if ( 0 == Elist )
10191 return 0;
10192 }
10193
10194 int sides_count = ON_Mesh_GetEidHelper( Vcount, Fcount, F, Vid, Elist );
10195 if ( sides_count <= 0 )
10196 {
10197 if ( 0 == sides )
10198 delete(Elist);
10199 }
10200 else if ( 0 == sides )
10201 {
10202 sides = Elist;
10203 }
10204
10205 return sides_count;
10206 }
10207
10208 #define ON_COMPILING_OPENNURBS_QSORT_FUNCTIONS
10209 #define ON_SORT_TEMPLATE_STATIC_FUNCTION
10210 #define ON_SORT_TEMPLATE_TYPE struct ON_MeshFaceSide
10211
10212 #define ON_SORT_TEMPLATE_COMPARE ON_qsort_MeshFaceSide_compare
ON_SORT_TEMPLATE_COMPARE(ON_SORT_TEMPLATE_TYPE const * side1,ON_SORT_TEMPLATE_TYPE const * side2)10213 static int ON_SORT_TEMPLATE_COMPARE(
10214 ON_SORT_TEMPLATE_TYPE const * side1,
10215 ON_SORT_TEMPLATE_TYPE const * side2
10216 )
10217 {
10218 if ( side1->vi[0] < side2->vi[0] )
10219 return -1;
10220 if ( side1->vi[0] > side2->vi[0] )
10221 return 1;
10222 if ( side1->vi[1] < side2->vi[1] )
10223 return -1;
10224 if ( side1->vi[1] > side2->vi[1] )
10225 return 1;
10226 if ( side1->fi < side2->fi )
10227 return -1;
10228 if ( side1->fi > side2->fi )
10229 return 1;
10230 if ( side1->side < side2->side )
10231 return -1;
10232 if ( side1->side > side2->side )
10233 return 1;
10234 return 0;
10235 }
10236
10237 #define ON_QSORT_FNAME ON_qsort_MeshFaceSide
10238 #include "pcl/surface/3rdparty/opennurbs/opennurbs_qsort_template.h"
10239
ON_SortMeshFaceSidesByVertexIndex(int sides_count,struct ON_MeshFaceSide * sides)10240 void ON_SortMeshFaceSidesByVertexIndex( int sides_count, struct ON_MeshFaceSide* sides )
10241 {
10242 if ( sides_count >= 2 && 0 != sides )
10243 ON_QSORT_FNAME( sides, sides_count );
10244 }
10245
10246 #undef ON_COMPILING_OPENNURBS_QSORT_FUNCTIONS
10247 #undef ON_SORT_TEMPLATE_STATIC_FUNCTION
10248 #undef ON_SORT_TEMPLATE_TYPE
10249 #undef ON_QSORT_FNAME
10250