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