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