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 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
17
18
19 #if defined(ON_COMPILER_MSC)
20 // Disable the MSC /W4 warning C4127: conditional expression is constant
21 //
22 // This file has a lot of for( i = 0; true; i < 123 )...
23 // loops where the "true" generates a 4127 warning.
24 // This source code has to work on many different
25 // compilers I do not trust all of them to correctly
26 // compile for( i = 0; /* empty condition*/; i < 123) ...
27 #pragma warning( push )
28 #pragma warning( disable : 4127 )
29 #endif
30
31
32 #if defined(ON_DLL_EXPORTS)
33
34 ////////////////////////////////////////////////////////////////////////////////
35 //
36 // When openNURBS is used as a Microsoft Windows DLL, it is possible
37 // for new/delete to allocate memory in one executable and delete
38 // it in another. Because Microsoft Windows has incompatible memory
39 // managers in its plethora of C libraries and the choice of which
40 // C library actually gets used depends on the code generation
41 // options you choose, we get lots of support questions asking
42 // about hard to trace crashes.
43 //
44 // If you are using openNURBS as a Windows DLL, you are sure you know
45 // what you are doing, and you promise never to ask for support, then
46 // feel free to delete these overrides.
47 //
48 //
49 #pragma message( " --- OpenNURBS overriding ONX_Model new and delete" )
50
51 // ONX_Model_UserData new/delete
52
operator new(std::size_t sz)53 void* ONX_Model_UserData::operator new(std::size_t sz)
54 {
55 // ONX_Model_UserData new
56 return onmalloc(sz);
57 }
58
operator delete(void * p)59 void ONX_Model_UserData::operator delete(void* p)
60 {
61 // ONX_Model_UserData delete
62 onfree(p);
63 }
64
operator new[](std::size_t sz)65 void* ONX_Model_UserData::operator new[] (std::size_t sz)
66 {
67 // ONX_Model_UserData array new
68 return onmalloc(sz);
69 }
70
operator delete[](void * p)71 void ONX_Model_UserData::operator delete[] (void* p)
72 {
73 // ONX_Model_UserData array delete
74 onfree(p);
75 }
76
operator new(std::size_t,void * p)77 void* ONX_Model_UserData::operator new(std::size_t, void* p)
78 {
79 // ONX_Model_UserData placement new
80 return p;
81 }
82
operator delete(void *,void *)83 void ONX_Model_UserData::operator delete(void*, void*)
84 {
85 // ONX_Model_UserData placement delete
86 return;
87 }
88
89
90 // ONX_Model_Object new/delete
91
operator new(std::size_t sz)92 void* ONX_Model_Object::operator new(std::size_t sz)
93 {
94 // ONX_Model_Object new
95 return onmalloc(sz);
96 }
97
operator delete(void * p)98 void ONX_Model_Object::operator delete(void* p)
99 {
100 // ONX_Model_Object delete
101 onfree(p);
102 }
103
operator new[](std::size_t sz)104 void* ONX_Model_Object::operator new[] (std::size_t sz)
105 {
106 // ONX_Model_Object array new
107 return onmalloc(sz);
108 }
109
operator delete[](void * p)110 void ONX_Model_Object::operator delete[] (void* p)
111 {
112 // ONX_Model_Object array delete
113 onfree(p);
114 }
115
operator new(std::size_t,void * p)116 void* ONX_Model_Object::operator new(std::size_t, void* p)
117 {
118 // ONX_Model_Object placement new
119 return p;
120 }
121
operator delete(void *,void *)122 void ONX_Model_Object::operator delete(void*, void*)
123 {
124 // ONX_Model_Object placement delete
125 return;
126 }
127
128
129 // ONX_Model_RenderLight new/delete
130
operator new(std::size_t sz)131 void* ONX_Model_RenderLight::operator new(std::size_t sz)
132 {
133 // ONX_Model_RenderLight new
134 return onmalloc(sz);
135 }
136
operator delete(void * p)137 void ONX_Model_RenderLight::operator delete(void* p)
138 {
139 // ONX_Model_RenderLight delete
140 onfree(p);
141 }
142
operator new[](std::size_t sz)143 void* ONX_Model_RenderLight::operator new[] (std::size_t sz)
144 {
145 // ONX_Model_RenderLight array new
146 return onmalloc(sz);
147 }
148
operator delete[](void * p)149 void ONX_Model_RenderLight::operator delete[] (void* p)
150 {
151 // ONX_Model_RenderLight array delete
152 onfree(p);
153 }
154
operator new(std::size_t,void * p)155 void* ONX_Model_RenderLight::operator new(std::size_t, void* p)
156 {
157 // ONX_Model_RenderLight placement new
158 return p;
159 }
160
operator delete(void *,void *)161 void ONX_Model_RenderLight::operator delete(void*, void*)
162 {
163 // ONX_Model_RenderLight placement delete
164 return;
165 }
166
167
168 // ONX_Model new/delete
169
operator new(std::size_t sz)170 void* ONX_Model::operator new(std::size_t sz)
171 {
172 // ONX_Model new
173 return onmalloc(sz);
174 }
175
operator delete(void * p)176 void ONX_Model::operator delete(void* p)
177 {
178 // ONX_Model delete
179 onfree(p);
180 }
181
operator new[](std::size_t sz)182 void* ONX_Model::operator new[] (std::size_t sz)
183 {
184 // ONX_Model array new
185 return onmalloc(sz);
186 }
187
operator delete[](void * p)188 void ONX_Model::operator delete[] (void* p)
189 {
190 // ONX_Model array delete
191 onfree(p);
192 }
193
operator new(std::size_t,void * p)194 void* ONX_Model::operator new(std::size_t, void* p)
195 {
196 // ONX_Model placement new
197 return p;
198 }
199
operator delete(void *,void *)200 void ONX_Model::operator delete(void*, void*)
201 {
202 // ONX_Model placement delete
203 return;
204 }
205
206 #endif
207
208 //
209 //
210 ////////////////////////////////////////////////////////////////////////////////
211
212
213 static
ONX_IsValidNameFirstChar(wchar_t c)214 bool ONX_IsValidNameFirstChar( wchar_t c )
215 {
216 if ( c > 127 )
217 return true;
218 if ( c < '0' )
219 return false;
220 if ( c <= '9' )
221 return true;
222 if ( c < 'A' )
223 return false;
224 if ( c <= 'Z' )
225 return true;
226 if ( c == '_' )
227 return true;
228 if ( c < 'a' )
229 return false;
230 if ( c <= 'z' )
231 return true;
232 return false;
233 }
234
235 static
ONX_IsValidNameSecondChar(wchar_t c)236 bool ONX_IsValidNameSecondChar( wchar_t c )
237 {
238 // control characters, double quote, and DEL are
239 // not permited in names
240 return (c >= 32 && c != 34 && c != 127);
241 }
242
ONX_IsValidName(const wchar_t * name)243 bool ONX_IsValidName(
244 const wchar_t* name
245 )
246 {
247 bool is_valid = (0 != name && ONX_IsValidNameFirstChar(*name));
248 if ( is_valid )
249 {
250 bool is_integer = (*name >= '0' && *name <= '9');
251 name++;
252 while ( ONX_IsValidNameSecondChar(*name) )
253 {
254 if ( *name < '0' || *name >= '9' )
255 is_integer = false;
256 name++;
257 }
258 if ( *name || is_integer )
259 is_valid = false;
260 else if ( name[-1] <= 32 )
261 is_valid = false; // last character cannot be a space
262 }
263 return is_valid;
264 }
265
266 ////////////////////////////////////////////////////////////////////////
267 ////////////////////////////////////////////////////////////////////////
268
ONX_Model_RenderLight()269 ONX_Model_RenderLight::ONX_Model_RenderLight()
270 {
271 }
272
~ONX_Model_RenderLight()273 ONX_Model_RenderLight::~ONX_Model_RenderLight()
274 {
275 }
276
ONX_Model_RenderLight(const ONX_Model_RenderLight & src)277 ONX_Model_RenderLight::ONX_Model_RenderLight(const ONX_Model_RenderLight& src)
278 : m_light(src.m_light),
279 m_attributes(src.m_attributes)
280 {
281 }
282
operator =(const ONX_Model_RenderLight & src)283 ONX_Model_RenderLight& ONX_Model_RenderLight::operator=(const ONX_Model_RenderLight& src)
284 {
285 if ( this != &src )
286 {
287 m_light = src.m_light;
288 m_attributes = src.m_attributes;
289 }
290 return *this;
291 }
292
293 ////////////////////////////////////////////////////////////////////////
294 ////////////////////////////////////////////////////////////////////////
295
296
ONX_Model_Object()297 ONX_Model_Object::ONX_Model_Object()
298 : m_bDeleteObject(0),
299 m_object(0),
300 m_ref_count(0)
301 {
302 }
303
Destroy()304 void ONX_Model_Object::Destroy()
305 {
306 if ( m_ref_count )
307 {
308 if ( *m_ref_count > 0 )
309 (*m_ref_count)--;
310 if ( *m_ref_count <= 0 )
311 {
312 delete m_ref_count;
313 m_ref_count = 0;
314 }
315 }
316 if ( 0 == m_ref_count && 0 != m_object && m_bDeleteObject )
317 {
318 delete m_object;
319 }
320 m_object = 0;
321 m_bDeleteObject = false;
322 }
323
~ONX_Model_Object()324 ONX_Model_Object::~ONX_Model_Object()
325 {
326 Destroy();
327 }
328
ONX_Model_Object(const ONX_Model_Object & src)329 ONX_Model_Object::ONX_Model_Object(const ONX_Model_Object& src)
330 : m_bDeleteObject(0),
331 m_object(0),
332 m_ref_count(0)
333 {
334 *this = src;
335 }
336
operator =(const ONX_Model_Object & src)337 ONX_Model_Object& ONX_Model_Object::operator=(const ONX_Model_Object& src)
338 {
339 if ( this != &src )
340 {
341 Destroy();
342 m_bDeleteObject = src.m_bDeleteObject;
343 m_object = src.m_object;
344 m_attributes = src.m_attributes;
345 m_ref_count = src.m_ref_count;
346 if ( 0 != m_object && m_bDeleteObject )
347 {
348 if ( 0 != m_ref_count )
349 (*m_ref_count)++;
350 else
351 {
352 m_ref_count = new unsigned int;
353 *m_ref_count = 2; // 2 because this and src reference same m_object
354 const_cast<ONX_Model_Object*>(&src)->m_ref_count = m_ref_count; // need to defeat const
355 }
356 }
357 }
358 return *this;
359 }
360
361 ////////////////////////////////////////////////////////////////////////
362 ////////////////////////////////////////////////////////////////////////
363
364
ONX_Model_UserData()365 ONX_Model_UserData::ONX_Model_UserData()
366 : m_uuid(ON_nil_uuid)
367 , m_usertable_3dm_version(0)
368 , m_usertable_opennurbs_version(0)
369 {
370 }
371
~ONX_Model_UserData()372 ONX_Model_UserData::~ONX_Model_UserData()
373 {
374 }
375
ONX_Model_UserData(const ONX_Model_UserData & src)376 ONX_Model_UserData::ONX_Model_UserData(const ONX_Model_UserData& src)
377 : m_uuid(src.m_uuid)
378 , m_goo(src.m_goo)
379 , m_usertable_3dm_version(src.m_usertable_3dm_version)
380 , m_usertable_opennurbs_version(src.m_usertable_opennurbs_version)
381 {
382 }
383
operator =(const ONX_Model_UserData & src)384 ONX_Model_UserData& ONX_Model_UserData::operator=(const ONX_Model_UserData& src)
385 {
386 if ( this != &src )
387 {
388 m_uuid = src.m_uuid;
389 m_goo = src.m_goo;
390 m_usertable_3dm_version = src.m_usertable_3dm_version;
391 m_usertable_opennurbs_version = src.m_usertable_opennurbs_version;
392 }
393 return *this;
394 }
395
396 ////////////////////////////////////////////////////////////////////////
397 ////////////////////////////////////////////////////////////////////////
398
ONX_Model()399 ONX_Model::ONX_Model()
400 : m_3dm_file_version(0),
401 m_3dm_opennurbs_version(0),
402 m_file_length(0),
403 m_crc_error_count(0)
404 {
405 m_sStartSectionComments.Empty();
406 m_properties.Default();
407 m_settings.Default();
408 }
409
~ONX_Model()410 ONX_Model::~ONX_Model()
411 {
412 Destroy();
413 }
414
Destroy()415 void ONX_Model::Destroy()
416 {
417 int i;
418 m_3dm_file_version = 0;
419 m_3dm_opennurbs_version = 0;
420 m_sStartSectionComments.Empty();
421 m_properties.Default();
422 m_settings.Default();
423
424 for ( i = 0; i < m_history_record_table.Count(); i++ )
425 delete m_history_record_table[i];
426 m_history_record_table.Zero();
427
428 for ( i = 0; i < m_bitmap_table.Count(); i++ )
429 delete m_bitmap_table[i];
430 m_bitmap_table.Zero();
431
432 m_bitmap_table.SetCapacity(0);
433 m_mapping_table.SetCapacity(0);
434 m_material_table.SetCapacity(0);
435 m_linetype_table.SetCapacity(0);
436 m_layer_table.SetCapacity(0);
437 m_group_table.SetCapacity(0);
438 m_font_table.SetCapacity(0);
439 m_dimstyle_table.SetCapacity(0);
440 m_light_table.SetCapacity(0);
441 m_hatch_pattern_table.SetCapacity(0);
442 m_idef_table.SetCapacity(0);
443 m_object_table.SetCapacity(0);
444 m_history_record_table.SetCapacity(0);
445 m_userdata_table.SetCapacity(0);
446
447 m_file_length = 0;
448 m_crc_error_count = 0;
449
450 DestroyCache();
451 }
452
453
DestroyCache()454 void ONX_Model::DestroyCache()
455 {
456 m_mapping_id_index.Empty();
457 m_material_id_index.Empty();
458 m_idef_id_index.Empty();
459 m_object_id_index.Empty();
460
461 m__object_table_bbox.Destroy();
462 }
463
BoundingBox() const464 ON_BoundingBox ONX_Model::BoundingBox() const
465 {
466 if( !m__object_table_bbox.IsValid() && m_object_table.Count() > 0 )
467 {
468 ON_BoundingBox bbox;
469 int i, object_count = m_object_table.Count();
470 for ( i = 0; i < object_count; i++ )
471 {
472 const ON_Geometry* geo = ON_Geometry::Cast(m_object_table[i].m_object);
473 if ( geo )
474 bbox.Union(geo->BoundingBox());
475 const_cast<ONX_Model*>(this)->m__object_table_bbox = bbox;
476 }
477 }
478 return m__object_table_bbox;
479 }
480
GetRenderMaterial(const ON_3dmObjectAttributes & attributes,ON_Material & material) const481 void ONX_Model::GetRenderMaterial( const ON_3dmObjectAttributes& attributes, ON_Material& material ) const
482 {
483 int material_index = -1;
484
485 switch ( attributes.MaterialSource() )
486 {
487 case ON::material_from_layer:
488 if ( attributes.m_layer_index >= 0 && attributes.m_layer_index < m_layer_table.Count() )
489 material_index = m_layer_table[attributes.m_layer_index].RenderMaterialIndex();
490 break;
491 case ON::material_from_object:
492 material_index = attributes.m_material_index;
493 break;
494
495 case ON::material_from_parent:
496 material_index = attributes.m_material_index;
497 // TODO: If object is an idef, get material from iref attributes.
498 break;
499 }
500
501 if ( material_index < 0 || material_index >= m_material_table.Count() )
502 {
503 material_index = -1;
504 material.Default();
505 }
506 else
507 {
508 material = m_material_table[material_index];
509 }
510
511 material.SetMaterialIndex(material_index);
512 }
513
GetRenderMaterial(int object_index,ON_Material & material) const514 void ONX_Model::GetRenderMaterial(
515 int object_index,
516 ON_Material& material
517 ) const
518 {
519 if ( object_index < 0 || object_index >= m_object_table.Count() )
520 {
521 material.Default();
522 material.SetMaterialIndex(-1);
523 }
524 else
525 GetRenderMaterial( m_object_table[object_index].m_attributes, material );
526 }
527
GetLinetype(const ON_3dmObjectAttributes & attributes,ON_Linetype & linetype) const528 void ONX_Model::GetLinetype( const ON_3dmObjectAttributes& attributes, ON_Linetype& linetype ) const
529 {
530 int linetype_index = -1;
531
532 switch ( attributes.LinetypeSource() )
533 {
534 case ON::linetype_from_layer:
535 if ( attributes.m_layer_index >= 0 && attributes.m_layer_index < m_layer_table.Count() )
536 linetype_index = m_layer_table[attributes.m_layer_index].LinetypeIndex();
537 break;
538 case ON::linetype_from_object:
539 linetype_index = attributes.m_linetype_index;
540 break;
541 case ON::linetype_from_parent:
542 linetype_index = attributes.m_linetype_index;
543 // TODO: if object is an instance definition, get linetype
544 // from instance references.
545 break;
546 }
547
548 if ( linetype_index < 0 || linetype_index >= m_linetype_table.Count() )
549 {
550 linetype_index = -1;
551 linetype.Default();
552 }
553 else
554 {
555 linetype = m_linetype_table[linetype_index];
556 }
557
558 linetype.SetLinetypeIndex(linetype_index);
559 }
560
GetLinetype(int object_index,ON_Linetype & linetype) const561 void ONX_Model::GetLinetype(
562 int object_index,
563 ON_Linetype& linetype
564 ) const
565 {
566 if ( object_index < 0 || object_index >= m_object_table.Count() )
567 {
568 linetype.Default();
569 linetype.SetLinetypeIndex(-1);
570 }
571 else
572 {
573 GetLinetype( m_object_table[object_index].m_attributes, linetype );
574 }
575 }
576
577
578
WireframeColor(const ON_3dmObjectAttributes & attributes) const579 ON_Color ONX_Model::WireframeColor( const ON_3dmObjectAttributes& attributes ) const
580 {
581 ON_Color color = ON_UNSET_COLOR;
582
583 switch ( attributes.ColorSource() )
584 {
585 case ON::color_from_layer:
586 if ( attributes.m_layer_index >= 0 && attributes.m_layer_index < m_layer_table.Count() )
587 color = m_layer_table[attributes.m_layer_index].Color();
588 break;
589
590 case ON::color_from_object:
591 color = attributes.m_color;
592 break;
593
594 case ON::color_from_material:
595 {
596 ON_Material mat;
597 GetRenderMaterial( attributes, mat );
598 color = mat.Diffuse();
599 }
600 break;
601
602 case ON::color_from_parent:
603 color = attributes.m_color;
604 // TODO: if object is an instance definition, get color
605 // from instance references.
606 break;
607 }
608
609 if ( color == ON_UNSET_COLOR )
610 color.SetRGB(128,128,128);
611
612 return color;
613 }
614
WireframeColor(int object_index) const615 ON_Color ONX_Model::WireframeColor(int object_index) const
616 {
617 ON_Color c;
618 if ( object_index < 0 || object_index >= m_object_table.Count() )
619 {
620 ON_3dmObjectAttributes a;
621 c = a.m_color;
622 }
623 else
624 c = WireframeColor( m_object_table[object_index].m_attributes );
625 return c;
626 }
627
628
ONX_DumpView(ON_TextLog & dump,const ON_3dmView & view)629 void ONX_DumpView( ON_TextLog& dump, const ON_3dmView& view )
630 {
631 view.Dump(dump);
632 }
633
DumpSummary(ON_TextLog & dump) const634 void ONX_Model::DumpSummary( ON_TextLog& dump ) const
635 {
636 dump.Print("File version: %d\n",m_3dm_file_version);
637 dump.Print("File openNURBS version: %d\n",m_3dm_opennurbs_version);
638 if ( m_file_length > 0 )
639 dump.Print("File length: %d bytes\n",m_file_length);
640
641 if ( m_sStartSectionComments.Length() > 0 )
642 {
643 dump.Print("Start section comments:\n");
644 dump.PushIndent();
645 dump.PrintWrappedText(m_sStartSectionComments);
646 dump.PopIndent();
647 dump.Print("\n");
648 }
649
650 m_properties.Dump(dump);
651
652 dump.Print("\n");
653
654 m_settings.Dump(dump);
655
656 dump.Print("\n");
657
658 dump.Print("Contents:\n");
659 dump.PushIndent();
660 dump.Print("%d embedded bitmaps\n",m_bitmap_table.Count());
661 dump.Print("%d render material definitions\n",m_material_table.Count());
662 dump.Print("%d line type definitions\n",m_linetype_table.Count());
663 dump.Print("%d layers\n",m_layer_table.Count());
664 dump.Print("%d render lights\n",m_light_table.Count());
665 dump.Print("%d groups\n",m_group_table.Count());
666 dump.Print("%d objects\n",m_object_table.Count());
667 dump.Print("%d user data objects\n",m_userdata_table.Count());
668 dump.PopIndent();
669 }
670
DumpBitmapTable(ON_TextLog & dump) const671 void ONX_Model::DumpBitmapTable( ON_TextLog& dump) const
672 {
673 int i;
674 for ( i = 0; i < m_bitmap_table.Count(); i++ )
675 {
676 dump.Print("Bitmap %d:\n",i);
677 dump.PushIndent();
678 m_bitmap_table[i]->Dump(dump);
679 dump.PopIndent();
680 }
681 }
682
DumpTextureMappingTable(ON_TextLog & dump) const683 void ONX_Model::DumpTextureMappingTable( ON_TextLog& dump) const
684 {
685 int i;
686 for ( i = 0; i < m_mapping_table.Count(); i++ )
687 {
688 dump.Print("Texture Mapping %d:\n",i);
689 dump.PushIndent();
690 m_mapping_table[i].Dump(dump);
691 dump.PopIndent();
692 }
693 }
694
DumpMaterialTable(ON_TextLog & dump) const695 void ONX_Model::DumpMaterialTable( ON_TextLog& dump) const
696 {
697 int i;
698 for ( i = 0; i < m_material_table.Count(); i++ )
699 {
700 dump.Print("Material %d:\n",i);
701 dump.PushIndent();
702 m_material_table[i].Dump(dump);
703 dump.PopIndent();
704 }
705 }
706
DumpLinetypeTable(ON_TextLog & dump) const707 void ONX_Model::DumpLinetypeTable( ON_TextLog& dump ) const
708 {
709 int i;
710 for ( i = 0; i < m_linetype_table.Count(); i++ )
711 {
712 dump.Print("Linetype %d:\n",i);
713 dump.PushIndent();
714 m_linetype_table[i].Dump(dump);
715 dump.PopIndent();
716 }
717 }
718
DumpLayerTable(ON_TextLog & dump) const719 void ONX_Model::DumpLayerTable( ON_TextLog& dump) const
720 {
721 int i;
722 for ( i = 0; i < m_layer_table.Count(); i++ )
723 {
724 dump.Print("Layer %d:\n",i);
725 dump.PushIndent();
726 m_layer_table[i].Dump(dump);
727 dump.PopIndent();
728 }
729 }
730
DumpLightTable(ON_TextLog & dump) const731 void ONX_Model::DumpLightTable( ON_TextLog& dump) const
732 {
733 int i;
734 for ( i = 0; i < m_light_table.Count(); i++ )
735 {
736 dump.Print("Light %d:\n",i);
737 dump.PushIndent();
738 m_light_table[i].m_attributes.Dump(dump);
739 m_light_table[i].m_light.Dump(dump);
740 dump.PopIndent();
741 }
742 }
743
DumpGroupTable(ON_TextLog & dump) const744 void ONX_Model::DumpGroupTable( ON_TextLog& dump) const
745 {
746 int i;
747 for ( i = 0; i < m_group_table.Count(); i++ )
748 {
749 dump.Print("Group %d:\n",i);
750 dump.PushIndent();
751 m_group_table[i].Dump(dump);
752 dump.PopIndent();
753 }
754 }
755
DumpFontTable(ON_TextLog & dump) const756 void ONX_Model::DumpFontTable( ON_TextLog& dump) const
757 {
758 int i;
759 for ( i = 0; i < m_font_table.Count(); i++ )
760 {
761 dump.Print("Font %d:\n",i);
762 dump.PushIndent();
763 m_font_table[i].Dump(dump);
764 dump.PopIndent();
765 }
766 }
767
DumpDimStyleTable(ON_TextLog & dump) const768 void ONX_Model::DumpDimStyleTable( ON_TextLog& dump) const
769 {
770 int i;
771 for ( i = 0; i < m_dimstyle_table.Count(); i++ )
772 {
773 dump.Print("DimStyle %d:\n",i);
774 dump.PushIndent();
775 m_dimstyle_table[i].Dump(dump);
776 dump.PopIndent();
777 }
778 }
779
780
DumpHatchPatternTable(ON_TextLog & dump) const781 void ONX_Model::DumpHatchPatternTable( ON_TextLog& dump) const
782 {
783 int i;
784 for ( i = 0; i < m_hatch_pattern_table.Count(); i++ )
785 {
786 dump.Print("HatchPattern %d:\n",i);
787 dump.PushIndent();
788 m_hatch_pattern_table[i].Dump(dump);
789 dump.PopIndent();
790 }
791 }
792
DumpIDefTable(ON_TextLog & dump) const793 void ONX_Model::DumpIDefTable( ON_TextLog& dump) const
794 {
795 int i;
796 for ( i = 0; i < m_idef_table.Count(); i++ )
797 {
798 dump.Print("Instance Definition %d:\n",i);
799 dump.PushIndent();
800 m_idef_table[i].Dump(dump);
801 dump.PopIndent();
802 }
803 }
804
Dump(ON_TextLog & dump) const805 void ONX_Model_Object::Dump( ON_TextLog& dump ) const
806 {
807 if ( 0 != m_object )
808 {
809 m_object->Dump(dump);
810
811 // user data attached to this object
812 const ON_UserData* ud = m_object->FirstUserData();
813 while(0 != ud)
814 {
815 dump.Print("object user data:\n");
816 dump.PushIndent();
817 ud->Dump(dump);
818 dump.PopIndent();
819 ud = ud->Next();
820 }
821 }
822 else
823 {
824 dump.Print("NULL m_object pointer\n");
825 }
826
827 // Use Cast() if you need to get at the details.
828 /*
829 const ON_Geometry* pGeometry = ON_Geometry::Cast(m_object);
830 if ( pGeometry )
831 {
832 // m_object is some type of geometric object
833 if ( ON_Extrusion::Cast(m_object) )
834 {
835 // m_object is derived from ON_Extrusion
836 // Note:
837 // ON_Extrusion::BrepForm() will return a brep form
838 // if you don't want to explicitly handle extrusions.
839 const ON_Extrusion* extrusion = ON_Extrusion::Cast(m_object);
840 }
841 else if ( ON_Brep::Cast(m_object) )
842 {
843 // m_object is derived from ON_Brep
844 const ON_Brep* brep = ON_Brep::Cast(m_object);
845 }
846 else if ( pGeometry->HasBrepForm() )
847 {
848 // m_object is note derived from ON_Brep but its geometry can
849 // be represented by an ON_Brep.
850 ON_Brep* brep = pGeometry->BrepForm();
851 // you manage the ON_Brep returned by pGeometry->BrepForm();
852 delete brep;
853 }
854 else if ( ON_Curve::Cast(m_object) )
855 {
856 // curve objects
857 if ( ON_NurbsCurve::Cast(m_object) ) {
858 const ON_NurbsCurve* pCurve = ON_NurbsCurve::Cast(m_object);
859 }
860 else if ( ON_ArcCurve::Cast(m_object) ) {
861 const ON_ArcCurve* pCurve = ON_ArcCurve::Cast(m_object);
862 }
863 else if ( ON_CurveOnSurface::Cast(m_object) ) {
864 const ON_CurveOnSurface* pCurve = ON_CurveOnSurface::Cast(m_object);
865 }
866 else if ( ON_BrepEdge::Cast(m_object) ) {
867 const ON_BrepEdge* pCurve = ON_BrepEdge::Cast(m_object);
868 }
869 else if ( ON_LineCurve::Cast(m_object) ) {
870 const ON_LineCurve* pCurve = ON_LineCurve::Cast(m_object);
871 }
872 else if ( ON_PolyCurve::Cast(m_object) ) {
873 const ON_PolyCurve* pCurve = ON_PolyCurve::Cast(m_object);
874 }
875 else if ( ON_PolylineCurve::Cast(m_object) ) {
876 const ON_PolylineCurve* pCurve = ON_PolylineCurve::Cast(m_object);
877 }
878 else if ( ON_CurveProxy::Cast(m_object) ) {
879 const ON_CurveProxy* pCurve = ON_CurveProxy::Cast(m_object);
880 }
881 else {
882 const ON_Curve* pCurve = ON_Curve::Cast(m_object);
883 }
884 }
885 else if ( ON_Surface::Cast(m_object) )
886 {
887 // surface objects
888 if ( ON_NurbsSurface::Cast(m_object) ) {
889 const ON_NurbsSurface* pSurface = ON_NurbsSurface::Cast(m_object);
890 }
891 else if ( ON_PlaneSurface::Cast(m_object) ) {
892 const ON_PlaneSurface* pSurface = ON_PlaneSurface::Cast(m_object);
893 }
894 else if ( ON_RevSurface::Cast(m_object) ) {
895 const ON_RevSurface* pSurface = ON_RevSurface::Cast(m_object);
896 }
897 else if ( ON_BrepFace::Cast(m_object) ) {
898 const ON_BrepFace* pSurface = ON_BrepFace::Cast(m_object);
899 }
900 else if ( ON_SurfaceProxy::Cast(m_object) ) {
901 const ON_SurfaceProxy* pSurface = ON_SurfaceProxy::Cast(m_object);
902 }
903 else {
904 const ON_Surface* pSurface = ON_Surface::Cast(m_object);
905 }
906 }
907 else if ( ON_Mesh::Cast(m_object) )
908 {
909 const ON_Mesh* pMesh = ON_Mesh::Cast(m_object);
910 }
911 }
912 */
913 }
914
DumpObjectTable(ON_TextLog & dump) const915 void ONX_Model::DumpObjectTable( ON_TextLog& dump) const
916 {
917 int i;
918 for ( i = 0; i < m_object_table.Count(); i++ )
919 {
920 dump.Print("Object %d:\n",i);
921 dump.PushIndent();
922
923 // object's attibutes
924 m_object_table[i].m_attributes.Dump(dump);
925
926 // object definition
927 m_object_table[i].Dump(dump);
928
929 dump.PopIndent();
930 }
931 }
932
DumpHistoryRecordTable(ON_TextLog & dump) const933 void ONX_Model::DumpHistoryRecordTable( ON_TextLog& dump) const
934 {
935 int i;
936 for ( i = 0; i < m_history_record_table.Count(); i++ )
937 {
938 dump.Print("History record %d:\n",i);
939 dump.PushIndent();
940
941 const ON_HistoryRecord* history_record = m_history_record_table[i];
942 if ( history_record )
943 {
944 history_record->Dump(dump);
945 }
946 else
947 {
948 dump.Print("Missing.\n");
949 }
950
951 dump.PopIndent();
952 }
953 }
954
DumpUserDataTable(ON_TextLog & dump) const955 void ONX_Model::DumpUserDataTable( ON_TextLog& dump) const
956 {
957 int i;
958 for ( i = 0; i < m_userdata_table.Count(); i++ )
959 {
960 const ONX_Model_UserData& ud = m_userdata_table[i];
961 dump.Print("User Data Table %d:\n",i);
962 dump.PushIndent();
963 dump.Print("uuid = "); dump.Print(ud.m_uuid); dump.Print("\n");
964 ud.m_goo.Dump(dump);
965 dump.PopIndent();
966 }
967 }
968
Dump(ON_TextLog & dump) const969 void ONX_Model::Dump( ON_TextLog& dump ) const
970 {
971 dump.Print("Model summary:\n");
972 dump.PushIndent();
973 DumpSummary(dump);
974 dump.PopIndent();
975 dump.Print("\n");
976
977 dump.Print("Bitmap table:\n");
978 dump.PushIndent();
979 DumpBitmapTable(dump);
980 dump.PopIndent();
981 dump.Print("\n");
982
983 dump.Print("TextureMapping table:\n");
984 dump.PushIndent();
985 DumpTextureMappingTable(dump);
986 dump.PopIndent();
987 dump.Print("\n");
988
989 dump.Print("Material table:\n");
990 dump.PushIndent();
991 DumpMaterialTable(dump);
992 dump.PopIndent();
993 dump.Print("\n");
994
995 dump.Print("Line type table:\n");
996 dump.PushIndent();
997 DumpLinetypeTable(dump);
998 dump.PopIndent();
999 dump.Print("\n");
1000
1001 dump.Print("Layer table:\n");
1002 dump.PushIndent();
1003 DumpLayerTable(dump);
1004 dump.PopIndent();
1005 dump.Print("\n");
1006
1007 dump.Print("Group table:\n");
1008 dump.PushIndent();
1009 DumpGroupTable(dump);
1010 dump.PopIndent();
1011 dump.Print("\n");
1012
1013 dump.Print("Font table:\n");
1014 dump.PushIndent();
1015 DumpFontTable(dump);
1016 dump.PopIndent();
1017 dump.Print("\n");
1018
1019 dump.Print("DimStyle table:\n");
1020 dump.PushIndent();
1021 DumpDimStyleTable(dump);
1022 dump.PopIndent();
1023 dump.Print("\n");
1024
1025 dump.Print("Light table:\n");
1026 dump.PushIndent();
1027 DumpLightTable(dump);
1028 dump.PopIndent();
1029 dump.Print("\n");
1030
1031 dump.Print("HatchPattern table:\n");
1032 dump.PushIndent();
1033 DumpHatchPatternTable(dump);
1034 dump.PopIndent();
1035 dump.Print("\n");
1036
1037 dump.Print("Instance Definition table:\n");
1038 dump.PushIndent();
1039 DumpIDefTable(dump);
1040 dump.PopIndent();
1041 dump.Print("\n");
1042
1043 dump.Print("Object table:\n");
1044 dump.PushIndent();
1045 DumpObjectTable(dump);
1046 dump.PopIndent();
1047 dump.Print("\n");
1048
1049 dump.Print("History record table:\n");
1050 dump.PushIndent();
1051 DumpHistoryRecordTable(dump);
1052 dump.PopIndent();
1053 dump.Print("\n");
1054
1055 dump.Print("User data table:\n");
1056 dump.PushIndent();
1057 DumpUserDataTable(dump);
1058 dump.PopIndent();
1059 dump.Print("\n");
1060 }
1061
1062 static
CheckForCRCErrors(ON_BinaryArchive & archive,ONX_Model & model,ON_TextLog * error_log,const char * sSection)1063 bool CheckForCRCErrors(
1064 ON_BinaryArchive& archive,
1065 ONX_Model& model,
1066 ON_TextLog* error_log,
1067 const char* sSection
1068 )
1069 {
1070 // returns true if new CRC errors are found
1071 bool rc = false;
1072 int new_crc_count = archive.BadCRCCount();
1073
1074 if ( model.m_crc_error_count != new_crc_count )
1075 {
1076 if ( error_log )
1077 {
1078 error_log->Print("ERROR: Corrupt %s. (CRC errors).\n",sSection);
1079 error_log->Print("-- Attempting to continue.\n");
1080 }
1081 model.m_crc_error_count = new_crc_count;
1082 rc = true;
1083 }
1084
1085 return rc;
1086 }
1087
1088 class ON__CIndexPair
1089 {
1090 public:
1091 static int CompareOldIndex( const ON__CIndexPair* a, const ON__CIndexPair* b );
1092 static int CompareOldAndNewIndex( const ON__CIndexPair* a, const ON__CIndexPair* b );
1093 int m_old_index; // value in model.m_..._table[m_table_index].m_..._index; (Read from file)
1094 int m_new_index; // index in model.m_..._table[] array
1095 };
1096
CompareOldIndex(const ON__CIndexPair * a,const ON__CIndexPair * b)1097 int ON__CIndexPair::CompareOldIndex( const ON__CIndexPair* a, const ON__CIndexPair* b )
1098 {
1099 return (a->m_old_index - b->m_old_index);
1100 }
1101
CompareOldAndNewIndex(const ON__CIndexPair * a,const ON__CIndexPair * b)1102 int ON__CIndexPair::CompareOldAndNewIndex( const ON__CIndexPair* a, const ON__CIndexPair* b )
1103 {
1104 int i;
1105 if ( 0 == (i = a->m_old_index - b->m_old_index) )
1106 i = a->m_new_index - b->m_new_index;
1107 return i;
1108 }
1109
1110 class ON__CIndexMaps
1111 {
1112 public:
ON__CIndexMaps(ONX_Model & model)1113 ON__CIndexMaps( ONX_Model& model )
1114 : m_model(model),
1115 m_bRemapLayerIndex(0),
1116 m_bRemapMaterialIndex(0),
1117 m_bRemapLinetypeIndex(0),
1118 m_bRemapGroupIndex(0),
1119 m_bRemapFontIndex(0),
1120 m_bRemapDimstyleIndex(0),
1121 m_bRemapHatchPatternIndex(0),
1122 m_layer_count(0),
1123 m_group_count(0),
1124 m_material_count(0),
1125 m_linetype_count(0),
1126 m_font_count(0),
1127 m_dimstyle_count(0),
1128 m_hatch_pattern_count(0),
1129 m_default_layer_index(0),
1130 m_default_group_index(-1),
1131 m_default_material_index(-1),
1132 m_default_linetype_index(-1),
1133 m_default_font_index(0),
1134 m_default_dimstyle_index(0),
1135 m_default_hatch_pattern_index(-1)
1136 {
1137 CreateHelper();
1138 }
1139
1140 /*
1141 Description:
1142 Remap all tables in m_model.
1143 Returns:
1144 Number of indices that were changed.
1145 */
1146 int RemapModel();
1147
1148 ONX_Model& m_model;
1149
1150 bool m_bRemapLayerIndex;
1151 bool m_bRemapMaterialIndex;
1152 bool m_bRemapLinetypeIndex;
1153 bool m_bRemapGroupIndex;
1154 bool m_bRemapFontIndex;
1155 bool m_bRemapDimstyleIndex;
1156 bool m_bRemapHatchPatternIndex;
1157
1158 int m_layer_count;
1159 int m_group_count;
1160 int m_material_count;
1161 int m_linetype_count;
1162 int m_font_count;
1163 int m_dimstyle_count;
1164 int m_hatch_pattern_count;
1165
1166 int m_default_layer_index;
1167 int m_default_group_index;
1168 int m_default_material_index;
1169 int m_default_linetype_index;
1170 int m_default_font_index;
1171 int m_default_dimstyle_index;
1172 int m_default_hatch_pattern_index;
1173
1174 ON_SimpleArray<ON__CIndexPair> m_layer_map;
1175 ON_SimpleArray<ON__CIndexPair> m_group_map;
1176 ON_SimpleArray<ON__CIndexPair> m_material_map;
1177 ON_SimpleArray<ON__CIndexPair> m_linetype_map;
1178 ON_SimpleArray<ON__CIndexPair> m_font_map;
1179 ON_SimpleArray<ON__CIndexPair> m_dimstyle_map;
1180 ON_SimpleArray<ON__CIndexPair> m_hatch_pattern_map;
1181
1182
1183 /*
1184 Description:
1185 Low level tool to convert old_layer_index into a valid
1186 m_layer_table[] index.
1187 Parameters:
1188 old_layer_index - [in]
1189 Returns:
1190 new layer index to use.
1191 */
1192 int RemapLayerIndex( int old_layer_index ) const;
1193
1194 /*
1195 Description:
1196 Low level tool to convert old_material_index into a valid
1197 m_material_table[] index or -1 if the default material
1198 should be used.
1199 Parameters:
1200 old_material_index - [in]
1201 Returns:
1202 new material index to use.
1203 */
1204 int RemapMaterialIndex( int old_material_index ) const;
1205
1206 /*
1207 Description:
1208 Low level tool to convert old_linetype_index into a valid
1209 m_linetype_table[] index or -1 if the default linetype
1210 should be used.
1211 Parameters:
1212 old_linetype_index - [in]
1213 Returns:
1214 new linetype index to use.
1215 */
1216 int RemapLinetypeIndex( int old_linetype_index ) const;
1217
1218 /*
1219 Description:
1220 Low level tool to convert old_group_index into a valid
1221 m_group_table[] index or -1 if no conversion is possible.
1222 Parameters:
1223 old_group_index - [in]
1224 Returns:
1225 new group index to use or -1 if old_group_index makes no sense.
1226 */
1227 int RemapGroupIndex( int old_group_index ) const;
1228
1229 /*
1230 Description:
1231 Low level tool to convert old_font_index into a valid
1232 m_font_table[] index or -1 if no conversion is possible.
1233 Parameters:
1234 old_font_index - [in]
1235 Returns:
1236 new font index to use or -1 if old_font_index makes no sense.
1237 */
1238 int RemapFontIndex( int old_font_index ) const;
1239
1240 /*
1241 Description:
1242 Low level tool to convert old_dimstyle_index into a valid
1243 m_dimstyle_table[] index or -1 if no conversion is possible.
1244 Parameters:
1245 old_dimstyle_index - [in]
1246 Returns:
1247 new dimstyle index to use or -1 if old_dimstyle_index makes no sense.
1248 */
1249 int RemapDimstyleIndex( int old_dimstyle_index ) const;
1250
1251 /*
1252 Description:
1253 Low level tool to convert old_hatch_pattern_index into a valid
1254 m_hatch_pattern_table[] index or -1 if no conversion is possible.
1255 Parameters:
1256 old_hatch_pattern_index - [in]
1257 Returns:
1258 new hatch pattern index to use or -1 if old_hatch_pattern_index makes no sense.
1259 */
1260 int RemapHatchPatternIndex( int old_hatch_pattern_index ) const;
1261
1262 /*
1263 Description:
1264 Low level tool to remap table indices used by model objects in
1265 the object attributes class.
1266 */
1267 int RemapGeometryAndObjectAttributes( ONX_Model_Object& );
1268
1269 /*
1270 Description:
1271 Low level tool to remap table indices used by model objects in
1272 the object attributes class.
1273 Returns:
1274 Number of indices that were changed.
1275 */
1276 int RemapGeometryAttributes( ON_Object* );
1277
1278 /*
1279 Description:
1280 Low level tool to remap table indices saved in
1281 the object attributes class.
1282 Returns:
1283 Number of indices that were changed.
1284 */
1285 int RemapObjectAttributes( ON_3dmObjectAttributes& );
1286
1287 /*
1288 Description:
1289 Low level tool to remap table indices saved in
1290 the object attributes class.
1291 Returns:
1292 Number of indices that were changed.
1293 */
1294 int RemapLayerAttributes( ON_Layer& );
1295
1296 /*
1297 Description:
1298 Low level tool to remap material table indices saved in
1299 the rendering attributes class.
1300 Returns:
1301 Number of indices that were changed.
1302 */
1303 int RemapRenderingAttributes( ON_RenderingAttributes& ra );
1304
1305 private:
1306 int CreateHelper();
1307
1308 private:
1309 // no implementation - prohibit use
1310 ON__CIndexMaps(const ON__CIndexMaps&);
1311 ON__CIndexMaps& operator=(const ON__CIndexMaps&);
1312 };
1313
1314
CreateHelper()1315 int ON__CIndexMaps::CreateHelper()
1316 {
1317 int change_count = 0;
1318 int i;
1319
1320 // bitmaps are not referenced by index any place,
1321 // so just set bitmap index to match table index
1322 for ( i = 0; i < m_model.m_bitmap_table.Count(); i++ )
1323 {
1324 ON_Bitmap* bitmap = m_model.m_bitmap_table[i];
1325 if ( !bitmap )
1326 {
1327 change_count++;
1328 m_model.m_bitmap_table.Remove(i);
1329 i--;
1330 continue;
1331 }
1332
1333 if ( bitmap->m_bitmap_index != i )
1334 {
1335 bitmap->m_bitmap_index = i;
1336 change_count++;
1337 }
1338 if ( ON_nil_uuid == bitmap->m_bitmap_id )
1339 {
1340 ON_CreateUuid(bitmap->m_bitmap_id);
1341 change_count++;
1342 }
1343 }
1344
1345 // texture maps are not referenced by index
1346 // so just set texture map index to match table
1347 // index
1348 m_model.m_mapping_id_index.Empty();
1349 m_model.m_mapping_id_index.Reserve(m_model.m_mapping_table.Count());
1350 for ( i = 0; i < m_model.m_mapping_table.Count(); i++ )
1351 {
1352 ON_TextureMapping& mapping = m_model.m_mapping_table[i];
1353 if ( mapping.m_mapping_index != i )
1354 {
1355 mapping.m_mapping_index = i;
1356 change_count++;
1357 }
1358 if ( ON_nil_uuid == mapping.m_mapping_id )
1359 {
1360 ON_CreateUuid(mapping.m_mapping_id);
1361 change_count++;
1362 }
1363 m_model.m_mapping_id_index.AddUuidIndex(mapping.m_mapping_id,i,false);
1364 }
1365
1366 // make sure material indices are valid
1367 m_model.m_material_id_index.Empty();
1368 m_model.m_material_id_index.Reserve(m_model.m_material_table.Count());
1369 m_bRemapMaterialIndex = false;
1370 m_material_count = m_model.m_material_table.Count();
1371 m_material_map.SetCount(0);
1372 m_material_map.Reserve(m_material_count);
1373 for ( i = 0; i < m_material_count; i++ )
1374 {
1375 ON_Material& material = m_model.m_material_table[i];
1376 ON__CIndexPair& ip = m_material_map.AppendNew();
1377 ip.m_new_index = i;
1378 ip.m_old_index = material.m_material_index;
1379 if ( material.m_material_index != i )
1380 {
1381 material.m_material_index = i;
1382 m_bRemapMaterialIndex = true;
1383 change_count++;
1384 }
1385 if ( ON_nil_uuid == material.m_material_id )
1386 {
1387 ON_CreateUuid(material.m_material_id);
1388 change_count++;
1389 }
1390 m_model.m_material_id_index.AddUuidIndex(material.m_material_id,i,false);
1391 }
1392
1393 // make sure linetype indices are valid
1394 m_bRemapLinetypeIndex = false;
1395 m_linetype_count = m_model.m_linetype_table.Count();
1396 m_linetype_map.SetCount(0);
1397 m_linetype_map.Reserve(m_linetype_count);
1398 for ( i = 0; i < m_linetype_count; i++ )
1399 {
1400 ON_Linetype& linetype = m_model.m_linetype_table[i];
1401 ON__CIndexPair& ip = m_linetype_map.AppendNew();
1402 ip.m_new_index = i;
1403 ip.m_old_index = linetype.m_linetype_index;
1404 if ( linetype.m_linetype_index != i )
1405 {
1406 linetype.m_linetype_index = i;
1407 m_bRemapLinetypeIndex = true;
1408 change_count++;
1409 }
1410 if ( ON_nil_uuid == linetype.m_linetype_id )
1411 {
1412 ON_CreateUuid(linetype.m_linetype_id);
1413 change_count++;
1414 }
1415 }
1416
1417 // make sure there is at least one layer
1418 if ( m_model.m_layer_table.Count() < 1 )
1419 {
1420 ON_Layer layer;
1421 layer.Default();
1422 m_model.GetUnusedLayerName(layer.m_name);
1423 if ( !ONX_IsValidName(layer.m_name) )
1424 layer.m_name = L"Default";
1425 layer.m_layer_index = 0;
1426 ON_CreateUuid(layer.m_layer_id);
1427 m_model.m_layer_table.Append(layer);
1428 change_count++;
1429 }
1430
1431 // make sure layer indices are valid
1432 m_bRemapLayerIndex = false;
1433 m_layer_count = m_model.m_layer_table.Count();
1434 m_layer_map.SetCount(0);
1435 m_layer_map.Reserve(m_layer_count);
1436 for ( i = 0; i < m_layer_count; i++ )
1437 {
1438 ON_Layer& layer = m_model.m_layer_table[i];
1439 ON__CIndexPair& ip = m_layer_map.AppendNew();
1440 ip.m_new_index = i;
1441 ip.m_old_index = layer.m_layer_index;
1442 if ( layer.m_layer_index != i )
1443 {
1444 layer.m_layer_index = i;
1445 m_bRemapLayerIndex = true;
1446 change_count++;
1447 }
1448 if ( ON_nil_uuid == layer.m_layer_id )
1449 {
1450 ON_CreateUuid(layer.m_layer_id);
1451 change_count++;
1452 }
1453 }
1454
1455 // make sure group indices are valid
1456 m_bRemapGroupIndex = false;
1457 m_group_count = m_model.m_group_table.Count();
1458 m_group_map.SetCount(0);
1459 m_group_map.Reserve(m_group_count);
1460 for ( i = 0; i < m_group_count; i++ )
1461 {
1462 ON_Group& group = m_model.m_group_table[i];
1463 ON__CIndexPair& ip = m_group_map.AppendNew();
1464 ip.m_new_index = i;
1465 ip.m_old_index = group.m_group_index;
1466 if ( group.m_group_index != i )
1467 {
1468 group.m_group_index = i;
1469 m_bRemapGroupIndex = true;
1470 change_count++;
1471 }
1472 if ( ON_nil_uuid == group.m_group_id )
1473 {
1474 ON_CreateUuid(group.m_group_id);
1475 change_count++;
1476 }
1477 }
1478
1479 // make sure there is at least one font
1480 if ( m_model.m_font_table.Count() < 1 )
1481 {
1482 ON_Font font;
1483 font.Defaults();
1484 if ( !ONX_IsValidName(font.m_font_name) )
1485 font.m_font_name = L"Default";
1486 font.m_font_index = 0;
1487 ON_CreateUuid(font.m_font_id);
1488 m_model.m_font_table.Append(font);
1489 change_count++;
1490 }
1491
1492 // make sure font indices are valid
1493 m_bRemapFontIndex = false;
1494 m_font_count = m_model.m_font_table.Count();
1495 m_font_map.SetCount(0);
1496 m_font_map.Reserve(m_font_count);
1497 for ( i = 0; i < m_font_count; i++ )
1498 {
1499 ON_Font& font = m_model.m_font_table[i];
1500 ON__CIndexPair& ip = m_font_map.AppendNew();
1501 ip.m_new_index = i;
1502 ip.m_old_index = font.m_font_index;
1503 if ( font.m_font_index != i )
1504 {
1505 font.m_font_index = i;
1506 m_bRemapFontIndex = true;
1507 change_count++;
1508 }
1509 if ( ON_nil_uuid == font.m_font_id )
1510 {
1511 ON_CreateUuid(font.m_font_id);
1512 change_count++;
1513 }
1514 }
1515
1516 // make sure there is at least one dimstyle
1517 if ( m_model.m_dimstyle_table.Count() < 1 )
1518 {
1519 ON_DimStyle dimstyle;
1520 dimstyle.SetDefaults();
1521 if ( !ONX_IsValidName(dimstyle.m_dimstyle_name) )
1522 dimstyle.m_dimstyle_name = L"Default";
1523 dimstyle.m_dimstyle_index = 0;
1524 ON_CreateUuid(dimstyle.m_dimstyle_id);
1525 dimstyle.m_fontindex = 0;
1526 m_model.m_dimstyle_table.Append(dimstyle);
1527 change_count++;
1528 }
1529
1530 // make sure dimstyle indices are valid
1531 m_bRemapDimstyleIndex = false;
1532 m_dimstyle_count = m_model.m_dimstyle_table.Count();
1533 m_dimstyle_map.SetCount(0);
1534 m_dimstyle_map.Reserve(m_dimstyle_count);
1535 for ( i = 0; i < m_dimstyle_count; i++ )
1536 {
1537 ON_DimStyle& dimstyle = m_model.m_dimstyle_table[i];
1538 ON__CIndexPair& ip = m_dimstyle_map.AppendNew();
1539 ip.m_new_index = i;
1540 ip.m_old_index = dimstyle.m_dimstyle_index;
1541 if ( dimstyle.m_dimstyle_index != i )
1542 {
1543 dimstyle.m_dimstyle_index = i;
1544 m_bRemapDimstyleIndex = true;
1545 change_count++;
1546 }
1547 if ( ON_nil_uuid == dimstyle.m_dimstyle_id )
1548 {
1549 ON_CreateUuid(dimstyle.m_dimstyle_id);
1550 change_count++;
1551 }
1552 }
1553
1554 // lights are not referenced by index any place,
1555 // so just set light index to match table index
1556 for ( i = 0; i < m_model.m_light_table.Count(); i++ )
1557 {
1558 ONX_Model_RenderLight& light = m_model.m_light_table[i];
1559 if ( light.m_light.m_light_index != i )
1560 {
1561 light.m_light.m_light_index = i;
1562 change_count++;
1563 }
1564
1565 if ( light.m_light.m_light_id == light.m_attributes.m_uuid )
1566 {
1567 // ids match - this is good
1568 if ( ON_nil_uuid == light.m_light.m_light_id )
1569 {
1570 // ids not set
1571 ON_CreateUuid(light.m_light.m_light_id);
1572 light.m_attributes.m_uuid = light.m_light.m_light_id;
1573 change_count++;
1574 }
1575 }
1576 else if ( ON_nil_uuid == light.m_light.m_light_id )
1577 {
1578 // id not set on the light object
1579 light.m_light.m_light_id = light.m_attributes.m_uuid;
1580 change_count++;
1581 }
1582 else if ( ON_nil_uuid == light.m_attributes.m_uuid )
1583 {
1584 // id not set on the attributes
1585 light.m_attributes.m_uuid = light.m_light.m_light_id;
1586 change_count++;
1587 }
1588 else
1589 {
1590 // id's are different - the one on the light object wins
1591 light.m_attributes.m_uuid = light.m_light.m_light_id;
1592 change_count++;
1593 }
1594 }
1595
1596 // make sure hatch pattern indices are valid
1597 m_bRemapHatchPatternIndex = false;
1598 m_hatch_pattern_count = m_model.m_hatch_pattern_table.Count();
1599 m_hatch_pattern_map.SetCount(0);
1600 m_hatch_pattern_map.Reserve(m_hatch_pattern_count);
1601 for ( i = 0; i < m_hatch_pattern_count; i++ )
1602 {
1603 ON_HatchPattern& hatchpattern = m_model.m_hatch_pattern_table[i];
1604 ON__CIndexPair& ip = m_hatch_pattern_map.AppendNew();
1605 ip.m_new_index = i;
1606 ip.m_old_index = hatchpattern.m_hatchpattern_index;
1607 if ( ip.m_new_index != ip.m_old_index )
1608 {
1609 hatchpattern.m_hatchpattern_index = i;
1610 m_bRemapHatchPatternIndex = true;
1611 change_count++;
1612 }
1613 if ( ON_nil_uuid == hatchpattern.m_hatchpattern_id )
1614 {
1615 ON_CreateUuid(hatchpattern.m_hatchpattern_id);
1616 change_count++;
1617 }
1618 }
1619
1620 // make sure idefs have valid ids
1621 m_model.m_idef_id_index.Empty();
1622 m_model.m_idef_id_index.Reserve(m_model.m_idef_table.Count());
1623 for ( i = 0; i < m_model.m_idef_table.Count(); i++ )
1624 {
1625 ON_InstanceDefinition& idef = m_model.m_idef_table[i];
1626 if ( ON_nil_uuid == idef.m_uuid )
1627 {
1628 ON_CreateUuid(idef.m_uuid);
1629 change_count++;
1630 }
1631 m_model.m_idef_id_index.AddUuidIndex(idef.m_uuid,i,false);
1632 }
1633
1634 // make sure objects have valid ids
1635 m_model.m_object_id_index.Empty();
1636 m_model.m_object_id_index.Reserve(m_model.m_object_table.Count());
1637 for ( i = 0; i < m_model.m_object_table.Count(); i++ )
1638 {
1639 ONX_Model_Object& mo = m_model.m_object_table[i];
1640 if ( ON_nil_uuid == mo.m_attributes.m_uuid )
1641 {
1642 ON_CreateUuid(mo.m_attributes.m_uuid);
1643 change_count++;
1644 }
1645 m_model.m_object_id_index.AddUuidIndex(mo.m_attributes.m_uuid,i,false);
1646 }
1647
1648 // make sure history records have valid ids
1649 for ( i = 0; i < m_model.m_history_record_table.Count(); i++ )
1650 {
1651 ON_HistoryRecord* hr = m_model.m_history_record_table[i];
1652 if ( !hr )
1653 {
1654 change_count++;
1655 m_model.m_history_record_table.Remove(i);
1656 i--;
1657 continue;
1658 }
1659 if ( ON_nil_uuid == hr->m_record_id )
1660 {
1661 ON_CreateUuid(hr->m_record_id);
1662 change_count++;
1663 }
1664 }
1665
1666 // Sort the maps
1667 if ( m_bRemapLayerIndex )
1668 m_layer_map.QuickSort( ON__CIndexPair::CompareOldAndNewIndex );
1669 if ( m_bRemapGroupIndex )
1670 m_group_map.QuickSort( ON__CIndexPair::CompareOldAndNewIndex );
1671 if ( m_bRemapMaterialIndex )
1672 m_material_map.QuickSort( ON__CIndexPair::CompareOldAndNewIndex );
1673 if ( m_bRemapLinetypeIndex )
1674 m_linetype_map.QuickSort( ON__CIndexPair::CompareOldAndNewIndex );
1675 if ( m_bRemapFontIndex )
1676 m_font_map.QuickSort( ON__CIndexPair::CompareOldAndNewIndex );
1677 if ( m_bRemapDimstyleIndex )
1678 m_dimstyle_map.QuickSort( ON__CIndexPair::CompareOldAndNewIndex );
1679 if ( m_bRemapHatchPatternIndex )
1680 m_hatch_pattern_map.QuickSort( ON__CIndexPair::CompareOldAndNewIndex );
1681
1682 return change_count;
1683 }
1684
RemapGeometryAttributes(ON_Object * object)1685 int ON__CIndexMaps::RemapGeometryAttributes( ON_Object* object )
1686 {
1687 int change_count = 0;
1688
1689 switch(object ? object->ObjectType() : ON::unknown_object_type )
1690 {
1691 case ON::layer_object:
1692 {
1693 ON_Layer* layer = ON_Layer::Cast(object);
1694 if ( layer )
1695 change_count += RemapLayerAttributes(*layer);
1696 }
1697 break;
1698
1699 case ON::annotation_object:
1700 {
1701 ON_Annotation2* ann = ON_Annotation2::Cast(object);
1702 if ( ann )
1703 {
1704 if (ann->IsText() )
1705 {
1706 // ann->m_index is a font index
1707 int old_font_index = ann->m_index;
1708 int new_font_index = RemapFontIndex(old_font_index);
1709 if ( new_font_index != old_font_index )
1710 {
1711 ann->m_index = new_font_index;
1712 change_count++;
1713 }
1714 }
1715 else
1716 {
1717 // ann->m_index is a dimstyle index
1718 int old_dimstyle_index = ann->m_index;
1719 int new_dimstyle_index = RemapDimstyleIndex(old_dimstyle_index);
1720 {
1721 if ( old_dimstyle_index != new_dimstyle_index )
1722 {
1723 ann->m_index = new_dimstyle_index;
1724 change_count++;
1725 }
1726 }
1727 }
1728 }
1729 }
1730 break;
1731
1732 case ON::hatch_object:
1733 {
1734 ON_Hatch* hatch_object = ON_Hatch::Cast(object);
1735 if ( hatch_object )
1736 {
1737 int old_hatch_pattern_index = hatch_object->PatternIndex();
1738 int new_hatch_pattern_index = RemapHatchPatternIndex(old_hatch_pattern_index);
1739 if ( old_hatch_pattern_index != new_hatch_pattern_index )
1740 hatch_object->SetPatternIndex(new_hatch_pattern_index);
1741 }
1742 }
1743 break;
1744
1745 default:
1746 // other object types skipped on purpose
1747 break;
1748 }
1749
1750 return change_count;
1751 }
1752
RemapGeometryAndObjectAttributes(ONX_Model_Object & model_object)1753 int ON__CIndexMaps::RemapGeometryAndObjectAttributes( ONX_Model_Object& model_object )
1754 {
1755 int geometry_change_count = RemapGeometryAttributes(const_cast<ON_Object*>(model_object.m_object));
1756 int attribute_change_count = RemapObjectAttributes( model_object.m_attributes );
1757 return (geometry_change_count + attribute_change_count);
1758 }
1759
RemapModel()1760 int ON__CIndexMaps::RemapModel()
1761 {
1762 int change_count = 0;
1763
1764 int i, old_index, new_index;
1765
1766 // make sure current layer is valid and in "normal" mode
1767 old_index = m_model.m_settings.m_current_layer_index;
1768 new_index = RemapLayerIndex(old_index);
1769 if ( new_index < 0 || new_index >= m_layer_count )
1770 {
1771 new_index = 0;
1772 }
1773 m_model.m_settings.m_current_layer_index = new_index;
1774 if ( !m_model.m_layer_table[new_index].IsVisibleAndNotLocked() )
1775 {
1776 m_model.m_layer_table[new_index].SetVisible( true );
1777 m_model.m_layer_table[new_index].SetLocked( false );
1778 }
1779 m_default_layer_index = m_model.m_settings.m_current_layer_index;
1780
1781 for ( i = 0; i < m_model.m_layer_table.Count(); i++ )
1782 {
1783 change_count += RemapLayerAttributes(m_model.m_layer_table[i]);
1784 }
1785
1786 for ( i = 0; i < m_model.m_dimstyle_table.Count(); i++ )
1787 {
1788 old_index = m_model.m_dimstyle_table[i].m_fontindex;
1789 new_index = RemapFontIndex(old_index);
1790 if ( new_index != old_index )
1791 {
1792 m_model.m_dimstyle_table[i].m_fontindex = new_index;
1793 change_count++;
1794 }
1795 }
1796
1797 for ( i = 0; i < m_model.m_light_table.Count(); i++ )
1798 {
1799 change_count += RemapObjectAttributes( m_model.m_light_table[i].m_attributes );
1800 }
1801
1802 for ( i = 0; i < m_model.m_object_table.Count(); i++ )
1803 {
1804 change_count += RemapGeometryAndObjectAttributes( m_model.m_object_table[i] );
1805 }
1806
1807 return change_count;
1808 }
1809
1810
1811
RemapIndexHelper(int old_index,bool bRemapIndex,int count,int default_index,const ON_SimpleArray<ON__CIndexPair> & imap)1812 static int RemapIndexHelper(
1813 int old_index,
1814 bool bRemapIndex,
1815 int count,
1816 int default_index,
1817 const ON_SimpleArray<ON__CIndexPair>& imap
1818 )
1819 {
1820 int new_index = old_index;
1821 if ( bRemapIndex )
1822 {
1823 ON__CIndexPair ip;
1824 memset(&ip,0,sizeof(ip));
1825 ip.m_old_index = old_index;
1826 int j = imap.BinarySearch(&ip,ON__CIndexPair::CompareOldIndex);
1827 if ( j >= 0 )
1828 new_index = imap[j].m_new_index;
1829 }
1830 if ( new_index < 0 || new_index >= count )
1831 new_index = default_index;
1832 return new_index;
1833 }
1834
RemapLayerIndex(int old_layer_index) const1835 int ON__CIndexMaps::RemapLayerIndex( int old_layer_index ) const
1836 {
1837 return RemapIndexHelper(
1838 old_layer_index,
1839 m_bRemapLayerIndex,
1840 m_layer_count,
1841 m_default_layer_index,
1842 m_layer_map
1843 );
1844 }
1845
RemapMaterialIndex(int old_material_index) const1846 int ON__CIndexMaps::RemapMaterialIndex( int old_material_index ) const
1847 {
1848 return RemapIndexHelper(
1849 old_material_index,
1850 m_bRemapMaterialIndex,
1851 m_material_count,
1852 m_default_material_index,
1853 m_material_map
1854 );
1855 }
1856
RemapLinetypeIndex(int old_linetype_index) const1857 int ON__CIndexMaps::RemapLinetypeIndex( int old_linetype_index ) const
1858 {
1859 return RemapIndexHelper(
1860 old_linetype_index,
1861 m_bRemapLinetypeIndex,
1862 m_linetype_count,
1863 m_default_linetype_index,
1864 m_linetype_map
1865 );
1866 }
1867
RemapGroupIndex(int old_group_index) const1868 int ON__CIndexMaps::RemapGroupIndex( int old_group_index ) const
1869 {
1870 return RemapIndexHelper(
1871 old_group_index,
1872 m_bRemapGroupIndex,
1873 m_group_count,
1874 m_default_group_index,
1875 m_group_map
1876 );
1877 }
1878
RemapFontIndex(int old_font_index) const1879 int ON__CIndexMaps::RemapFontIndex( int old_font_index ) const
1880 {
1881 return RemapIndexHelper(
1882 old_font_index,
1883 m_bRemapFontIndex,
1884 m_font_count,
1885 m_default_font_index,
1886 m_font_map
1887 );
1888 }
1889
RemapDimstyleIndex(int old_dimstyle_index) const1890 int ON__CIndexMaps::RemapDimstyleIndex( int old_dimstyle_index ) const
1891 {
1892 return RemapIndexHelper(
1893 old_dimstyle_index,
1894 m_bRemapDimstyleIndex,
1895 m_dimstyle_count,
1896 m_default_dimstyle_index,
1897 m_dimstyle_map
1898 );
1899 }
1900
RemapHatchPatternIndex(int old_hatch_pattern_index) const1901 int ON__CIndexMaps::RemapHatchPatternIndex( int old_hatch_pattern_index ) const
1902 {
1903 return RemapIndexHelper(
1904 old_hatch_pattern_index,
1905 m_bRemapHatchPatternIndex,
1906 m_hatch_pattern_count,
1907 m_default_hatch_pattern_index,
1908 m_hatch_pattern_map
1909 );
1910 }
1911
RemapRenderingAttributes(ON_RenderingAttributes & ra)1912 int ON__CIndexMaps::RemapRenderingAttributes( ON_RenderingAttributes& ra )
1913 {
1914 int change_count = 0;
1915 int old_material_index, new_material_index, i;
1916 for ( i = ra.m_materials.Count()-1; i >= 0; i-- )
1917 {
1918 ON_MaterialRef& mr = ra.m_materials[i];
1919
1920 old_material_index = mr.m_material_index;
1921 if ( old_material_index >= 0 )
1922 {
1923 new_material_index = RemapMaterialIndex(old_material_index);
1924 if ( old_material_index != new_material_index )
1925 {
1926 mr.m_material_index = new_material_index;
1927 change_count++;
1928 }
1929 }
1930 else
1931 mr.m_material_index = -1;
1932
1933 old_material_index = mr.m_material_backface_index;
1934 if ( old_material_index >= 0 )
1935 {
1936 new_material_index = RemapMaterialIndex(old_material_index);
1937 if ( old_material_index != new_material_index )
1938 {
1939 mr.m_material_backface_index = new_material_index;
1940 change_count++;
1941 }
1942 }
1943 else
1944 mr.m_material_backface_index = -1;
1945
1946 if ( -1 == mr.m_material_index || mr.m_material_index >= m_material_count )
1947 {
1948 if ( ON_nil_uuid == mr.m_material_id )
1949 mr.m_material_index = -1;
1950 else if ( !m_model.m_material_id_index.FindUuid(mr.m_material_id,&mr.m_material_index) )
1951 mr.m_material_index = -1;
1952 }
1953 else if ( m_model.m_material_table[mr.m_material_index].m_material_id != mr.m_material_id )
1954 {
1955 new_material_index = -1;
1956 if ( !ON_UuidIsNil(mr.m_material_id)
1957 && m_model.m_material_id_index.FindUuid(mr.m_material_id,&new_material_index)
1958 && new_material_index >= 0
1959 && new_material_index < m_material_count
1960 )
1961 {
1962 mr.m_material_index = new_material_index;
1963 }
1964 else
1965 {
1966 mr.m_material_id = m_model.m_material_table[mr.m_material_index].m_material_id;
1967 }
1968 }
1969
1970 if ( -1 == mr.m_material_backface_index || mr.m_material_backface_index >= m_material_count )
1971 {
1972 if ( ON_nil_uuid == mr.m_material_backface_id )
1973 mr.m_material_backface_index = -1;
1974 else if ( !m_model.m_material_id_index.FindUuid(mr.m_material_backface_id,&mr.m_material_backface_index) )
1975 mr.m_material_backface_index = -1;
1976 }
1977 else if ( m_model.m_material_table[mr.m_material_backface_index].m_material_id != mr.m_material_backface_id )
1978 {
1979 new_material_index = -1;
1980 if ( !ON_UuidIsNil(mr.m_material_backface_id)
1981 && m_model.m_material_id_index.FindUuid(mr.m_material_backface_id,&new_material_index)
1982 && new_material_index >= 0
1983 && new_material_index < m_material_count
1984 )
1985 {
1986 mr.m_material_backface_index = new_material_index;
1987 }
1988 else
1989 {
1990 mr.m_material_backface_id = m_model.m_material_table[mr.m_material_backface_index].m_material_id;
1991 }
1992 }
1993
1994 if ( mr.m_material_index < 0 && mr.m_material_backface_index < 0 )
1995 {
1996 ra.m_materials.Remove(i);
1997 }
1998 }
1999 return change_count;
2000 }
2001
RemapLayerAttributes(ON_Layer & layer)2002 int ON__CIndexMaps::RemapLayerAttributes( ON_Layer& layer )
2003 {
2004 int change_count = 0;
2005
2006 if ( ON_UuidIsNil(layer.m_layer_id) )
2007 {
2008 ON_CreateUuid(layer.m_layer_id);
2009 change_count++;
2010 }
2011
2012 int old_linetype_index = layer.m_linetype_index;
2013 int new_linetype_index = RemapLinetypeIndex(old_linetype_index);
2014 if ( old_linetype_index != new_linetype_index )
2015 {
2016 layer.m_linetype_index = new_linetype_index;
2017 change_count++;
2018 }
2019
2020 int old_material_index = layer.m_material_index;
2021 int new_material_index = RemapMaterialIndex(old_material_index);
2022 if ( old_material_index != new_material_index )
2023 {
2024 layer.m_material_index = new_material_index;
2025 change_count++;
2026 }
2027
2028 change_count += RemapRenderingAttributes(layer.m_rendering_attributes);
2029
2030 return change_count;
2031 }
2032
RemapObjectAttributes(ON_3dmObjectAttributes & a)2033 int ON__CIndexMaps::RemapObjectAttributes( ON_3dmObjectAttributes& a )
2034 {
2035 int change_count = 0;
2036
2037 int i;
2038 if ( ON_UuidIsNil(a.m_uuid) )
2039 {
2040 ON_CreateUuid(a.m_uuid);
2041 change_count++;
2042 }
2043
2044 int old_layer_index = a.m_layer_index;
2045 int new_layer_index = RemapLayerIndex(old_layer_index);
2046 if ( old_layer_index != new_layer_index )
2047 {
2048 a.m_layer_index = new_layer_index;
2049 change_count++;
2050 }
2051
2052 int old_linetype_index = a.m_linetype_index;
2053 int new_linetype_index = RemapLinetypeIndex(old_linetype_index);
2054 if ( old_linetype_index != new_linetype_index )
2055 {
2056 a.m_linetype_index = new_linetype_index;
2057 change_count++;
2058 }
2059
2060 int old_material_index = a.m_material_index;
2061 int new_material_index = RemapMaterialIndex(old_material_index);
2062 if ( old_material_index != new_material_index )
2063 {
2064 a.m_material_index = new_material_index;
2065 change_count++;
2066 }
2067
2068 if ( a.TopGroup() != -1 )
2069 {
2070 bool bUpdateGroupList = true;
2071 ON_SimpleArray<int> group_list;
2072 a.GetGroupList(group_list);
2073 for ( i = group_list.Count()-1; i >= 0; i-- )
2074 {
2075 int old_group_index = group_list[i];
2076 int new_group_index = RemapGroupIndex(old_group_index);
2077 if ( new_group_index < 0 )
2078 {
2079 group_list.Remove(i);
2080 bUpdateGroupList = true;
2081 change_count++;
2082 }
2083 else if ( old_group_index != new_group_index )
2084 {
2085 group_list[i] = new_group_index;
2086 bUpdateGroupList = true;
2087 change_count++;
2088 }
2089 }
2090
2091 if ( bUpdateGroupList || group_list.Count() == 0 )
2092 {
2093 a.RemoveFromAllGroups();
2094 for( i = 0; i < group_list.Count(); i++ )
2095 a.AddToGroup(group_list[i]);
2096 }
2097 }
2098
2099 change_count += RemapRenderingAttributes(a.m_rendering_attributes);
2100
2101 return change_count;
2102 }
2103
Polish()2104 void ONX_Model::Polish()
2105 {
2106 DestroyCache();
2107
2108 // make sure there is a valid revision history
2109 if ( m_properties.m_RevisionHistory.m_revision_count == 0 )
2110 m_properties.m_RevisionHistory.NewRevision();
2111
2112
2113 // Get maps sorted so BinarySearch calls in PolishAttributes
2114 // will work.
2115 ON__CIndexMaps imaps(*this);
2116 imaps.RemapModel();
2117 }
2118
Read(const char * filename,ON_TextLog * error_log)2119 bool ONX_Model::Read(
2120 const char* filename,
2121 ON_TextLog* error_log
2122 )
2123 {
2124 Destroy(); // get rid of any residual stuff
2125 bool rc = false;
2126 if ( 0 != filename )
2127 {
2128 FILE* fp = ON::OpenFile(filename,"rb");
2129 if ( 0 != fp )
2130 {
2131 ON_BinaryFile file(ON::read3dm,fp);
2132 rc = Read(file,error_log);
2133 ON::CloseFile(fp);
2134 }
2135 }
2136 return rc;
2137 }
2138
Read(const wchar_t * filename,ON_TextLog * error_log)2139 bool ONX_Model::Read(
2140 const wchar_t* filename,
2141 ON_TextLog* error_log
2142 )
2143 {
2144 Destroy(); // get rid of any residual stuff
2145 bool rc = false;
2146 if ( 0 != filename )
2147 {
2148 FILE* fp = ON::OpenFile(filename,L"rb");
2149 if ( 0 != fp )
2150 {
2151 ON_BinaryFile file(ON::read3dm,fp);
2152 rc = Read(file,error_log);
2153 ON::CloseFile(fp);
2154 }
2155 }
2156 return rc;
2157 }
2158
Read(ON_BinaryArchive & archive,ON_TextLog * error_log)2159 bool ONX_Model::Read(
2160 ON_BinaryArchive& archive,
2161 ON_TextLog* error_log
2162 )
2163 {
2164 const int max_error_count = 2000;
2165 int error_count = 0;
2166 bool return_code = true;
2167 int count, rc;
2168
2169 Destroy(); // get rid of any residual stuff
2170
2171 // STEP 1: REQUIRED - Read start section
2172 if ( !archive.Read3dmStartSection( &m_3dm_file_version, m_sStartSectionComments ) )
2173 {
2174 if ( error_log) error_log->Print("ERROR: Unable to read start section. (ON_BinaryArchive::Read3dmStartSection() returned false.)\n");
2175 return false;
2176 }
2177 else if ( CheckForCRCErrors( archive, *this, error_log, "start section" ) )
2178 return_code = false;
2179
2180 // STEP 2: REQUIRED - Read properties section
2181 if ( !archive.Read3dmProperties( m_properties ) )
2182 {
2183 if ( error_log) error_log->Print("ERROR: Unable to read properties section. (ON_BinaryArchive::Read3dmProperties() returned false.)\n");
2184 return false;
2185 }
2186 else if ( CheckForCRCErrors( archive, *this, error_log, "properties section" ) )
2187 return_code = false;
2188
2189 // version of opennurbs used to write the file.
2190 m_3dm_opennurbs_version = archive.ArchiveOpenNURBSVersion();
2191
2192 // STEP 3: REQUIRED - Read properties section
2193 if ( !archive.Read3dmSettings( m_settings ) )
2194 {
2195 if ( error_log) error_log->Print("ERROR: Unable to read settings section. (ON_BinaryArchive::Read3dmSettings() returned false.)\n");
2196 return false;
2197 }
2198 else if ( CheckForCRCErrors( archive, *this, error_log, "settings section" ) )
2199 return_code = false;
2200
2201 // STEP 4: REQUIRED - Read embedded bitmap table
2202 if ( archive.BeginRead3dmBitmapTable() )
2203 {
2204 // At the moment no bitmaps are embedded so this table is empty
2205 ON_Bitmap* pBitmap = NULL;
2206 for( count = 0; true; count++ )
2207 {
2208 pBitmap = NULL;
2209 rc = archive.Read3dmBitmap(&pBitmap);
2210 if ( rc==0 )
2211 break; // end of bitmap table
2212 if ( rc < 0 )
2213 {
2214 if ( error_log)
2215 {
2216 error_log->Print("ERROR: Corrupt bitmap found. (ON_BinaryArchive::Read3dmBitmap() < 0.)\n");
2217 error_count++;
2218 if ( error_count > max_error_count )
2219 return false;
2220 error_log->Print("-- Attempting to continue.\n");
2221 }
2222 return_code = false;
2223 }
2224 m_bitmap_table.Append(pBitmap);
2225 }
2226
2227 // If BeginRead3dmBitmapTable() returns true,
2228 // then you MUST call EndRead3dmBitmapTable().
2229 if ( !archive.EndRead3dmBitmapTable() )
2230 {
2231 if ( error_log) error_log->Print("ERROR: Corrupt bitmap table. (ON_BinaryArchive::EndRead3dmBitmapTable() returned false.)\n");
2232 return false;
2233 }
2234 if ( CheckForCRCErrors( archive, *this, error_log, "bitmap table" ) )
2235 return_code = false;
2236 }
2237 else
2238 {
2239 if ( error_log)
2240 {
2241 error_log->Print("WARNING: Missing or corrupt bitmap table. (ON_BinaryArchive::BeginRead3dmBitmapTable() returned false.)\n");
2242 error_log->Print("-- Attempting to continue.\n");
2243 }
2244 return_code = false;
2245 }
2246
2247
2248
2249 // STEP 5: REQUIRED - Read texture mapping table
2250 if ( archive.BeginRead3dmTextureMappingTable() )
2251 {
2252 ON_TextureMapping* pTextureMapping = NULL;
2253 for( count = 0; true; count++ )
2254 {
2255 rc = archive.Read3dmTextureMapping(&pTextureMapping);
2256 if ( rc==0 )
2257 break; // end of texture_mapping table
2258 if ( rc < 0 )
2259 {
2260 if ( error_log)
2261 {
2262 error_log->Print("ERROR: Corrupt render texture_mapping found. (ON_BinaryArchive::Read3dmTextureMapping() < 0.)\n");
2263 error_count++;
2264 if ( error_count > max_error_count )
2265 return false;
2266 error_log->Print("-- Attempting to continue.\n");
2267 }
2268 continue;
2269 }
2270 ON_UserDataHolder ud;
2271 ud.MoveUserDataFrom(*pTextureMapping);
2272 m_mapping_table.Append(*pTextureMapping);
2273 pTextureMapping->m_mapping_index = count;
2274 ud.MoveUserDataTo(*m_mapping_table.Last(),false);
2275 delete pTextureMapping;
2276 pTextureMapping = NULL;
2277 }
2278
2279 // If BeginRead3dmTextureMappingTable() returns true,
2280 // then you MUST call EndRead3dmTextureMappingTable().
2281 if ( !archive.EndRead3dmTextureMappingTable() )
2282 {
2283 if ( error_log) error_log->Print("ERROR: Corrupt render texture_mapping table. (ON_BinaryArchive::EndRead3dmTextureMappingTable() returned false.)\n");
2284 return false;
2285 }
2286 if ( CheckForCRCErrors( archive, *this, error_log, "render texture_mapping table" ) )
2287 return_code = false;
2288 }
2289 else
2290 {
2291 if ( error_log)
2292 {
2293 error_log->Print("WARNING: Missing or corrupt render texture_mapping table. (ON_BinaryArchive::BeginRead3dmTextureMappingTable() returned false.)\n");
2294 error_log->Print("-- Attempting to continue.\n");
2295 }
2296 return_code = false;
2297 }
2298
2299
2300 // STEP 6: REQUIRED - Read render material table
2301 if ( archive.BeginRead3dmMaterialTable() )
2302 {
2303 ON_Material* pMaterial = NULL;
2304 for( count = 0; true; count++ )
2305 {
2306 rc = archive.Read3dmMaterial(&pMaterial);
2307 if ( rc==0 )
2308 break; // end of material table
2309 if ( rc < 0 )
2310 {
2311 if ( error_log)
2312 {
2313 error_log->Print("ERROR: Corrupt render material found. (ON_BinaryArchive::Read3dmMaterial() < 0.)\n");
2314 error_count++;
2315 if ( error_count > max_error_count )
2316 return false;
2317 error_log->Print("-- Attempting to continue.\n");
2318 }
2319 pMaterial = new ON_Material; // use default
2320 pMaterial->m_material_index = count;
2321 }
2322 ON_UserDataHolder ud;
2323 ud.MoveUserDataFrom(*pMaterial);
2324 m_material_table.Append(*pMaterial);
2325 ud.MoveUserDataTo(*m_material_table.Last(),false);
2326 delete pMaterial;
2327 pMaterial = NULL;
2328 }
2329
2330 // If BeginRead3dmMaterialTable() returns true,
2331 // then you MUST call EndRead3dmMaterialTable().
2332 if ( !archive.EndRead3dmMaterialTable() )
2333 {
2334 if ( error_log) error_log->Print("ERROR: Corrupt render material table. (ON_BinaryArchive::EndRead3dmMaterialTable() returned false.)\n");
2335 return false;
2336 }
2337 if ( CheckForCRCErrors( archive, *this, error_log, "render material table" ) )
2338 return_code = false;
2339 }
2340 else
2341 {
2342 if ( error_log)
2343 {
2344 error_log->Print("WARNING: Missing or corrupt render material table. (ON_BinaryArchive::BeginRead3dmMaterialTable() returned false.)\n");
2345 error_log->Print("-- Attempting to continue.\n");
2346 }
2347 return_code = false;
2348 }
2349
2350
2351 // STEP 7: REQUIRED - Read line type table
2352 if ( archive.BeginRead3dmLinetypeTable() )
2353 {
2354 ON_Linetype* pLinetype = NULL;
2355 for( count = 0; true; count++ )
2356 {
2357 rc = archive.Read3dmLinetype(&pLinetype);
2358 if ( rc==0 )
2359 break; // end of linetype table
2360 if ( rc < 0 )
2361 {
2362 if ( error_log)
2363 {
2364 error_log->Print("ERROR: Corrupt render linetype found. (ON_BinaryArchive::Read3dmLinetype() < 0.)\n");
2365 error_count++;
2366 if ( error_count > max_error_count )
2367 return false;
2368 error_log->Print("-- Attempting to continue.\n");
2369 }
2370 pLinetype = new ON_Linetype; // use default
2371 pLinetype->m_linetype_index = count;
2372 }
2373 ON_UserDataHolder ud;
2374 ud.MoveUserDataFrom(*pLinetype);
2375 m_linetype_table.Append(*pLinetype);
2376 ud.MoveUserDataTo(*m_linetype_table.Last(),false);
2377 delete pLinetype;
2378 pLinetype = NULL;
2379 }
2380
2381 // If BeginRead3dmLinetypeTable() returns true,
2382 // then you MUST call EndRead3dmLinetypeTable().
2383 if ( !archive.EndRead3dmLinetypeTable() )
2384 {
2385 if ( error_log) error_log->Print("ERROR: Corrupt render linetype table. (ON_BinaryArchive::EndRead3dmLinetypeTable() returned false.)\n");
2386 return false;
2387 }
2388 if ( CheckForCRCErrors( archive, *this, error_log, "render linetype table" ) )
2389 return_code = false;
2390 }
2391 else
2392 {
2393 if ( error_log)
2394 {
2395 error_log->Print("WARNING: Missing or corrupt render linetype table. (ON_BinaryArchive::BeginRead3dmLinetypeTable() returned false.)\n");
2396 error_log->Print("-- Attempting to continue.\n");
2397 }
2398 return_code = false;
2399 }
2400
2401 // STEP 8: REQUIRED - Read layer table
2402 if ( archive.BeginRead3dmLayerTable() )
2403 {
2404 ON_Layer* pLayer = NULL;
2405 for( count = 0; true; count++ )
2406 {
2407 pLayer = NULL;
2408 rc = archive.Read3dmLayer(&pLayer);
2409 if ( rc==0 )
2410 break; // end of layer table
2411 if ( rc < 0 )
2412 {
2413 if ( error_log)
2414 {
2415 error_log->Print("ERROR: Corrupt layer found. (ON_BinaryArchive::Read3dmLayer() < 0.)\n");
2416 error_count++;
2417 if ( error_count > max_error_count )
2418 return false;
2419 error_log->Print("-- Attempting to continue.\n");
2420 }
2421 pLayer = new ON_Layer; // use default
2422 pLayer->m_layer_index = count;
2423 }
2424 ON_UserDataHolder ud;
2425 ud.MoveUserDataFrom(*pLayer);
2426 m_layer_table.Append(*pLayer);
2427 ud.MoveUserDataTo(*m_layer_table.Last(),false);
2428 delete pLayer;
2429 pLayer = NULL;
2430 }
2431
2432 // If BeginRead3dmLayerTable() returns true,
2433 // then you MUST call EndRead3dmLayerTable().
2434 if ( !archive.EndRead3dmLayerTable() )
2435 {
2436 if ( error_log) error_log->Print("ERROR: Corrupt render layer table. (ON_BinaryArchive::EndRead3dmLayerTable() returned false.)\n");
2437 return false;
2438 }
2439 if ( CheckForCRCErrors( archive, *this, error_log, "layer table" ) )
2440 return_code = false;
2441 }
2442 else
2443 {
2444 if ( error_log)
2445 {
2446 error_log->Print("WARNING: Missing or corrupt layer table. (ON_BinaryArchive::BeginRead3dmLayerTable() returned false.)\n");
2447 error_log->Print("-- Attempting to continue.\n");
2448 }
2449 return_code = false;
2450 }
2451
2452 // STEP 9: REQUIRED - Read group table
2453 if ( archive.BeginRead3dmGroupTable() )
2454 {
2455 ON_Group* pGroup = NULL;
2456 for( count = 0; true; count++ )
2457 {
2458 rc = archive.Read3dmGroup(&pGroup);
2459 if ( rc==0 )
2460 break; // end of group table
2461 if ( rc < 0 )
2462 {
2463 if ( error_log)
2464 {
2465 error_log->Print("ERROR: Corrupt group found. (ON_BinaryArchive::Read3dmGroup() < 0.)\n");
2466 error_count++;
2467 if ( error_count > max_error_count )
2468 return false;
2469 error_log->Print("-- Attempting to continue.\n");
2470 }
2471 pGroup = new ON_Group; // use default
2472 pGroup->m_group_index = -1;
2473 }
2474 ON_UserDataHolder ud;
2475 ud.MoveUserDataFrom(*pGroup);
2476 m_group_table.Append(*pGroup);
2477 ud.MoveUserDataTo(*m_group_table.Last(),false);
2478 delete pGroup;
2479 pGroup = NULL;
2480 }
2481
2482 // If BeginRead3dmGroupTable() returns true,
2483 // then you MUST call EndRead3dmGroupTable().
2484 if ( !archive.EndRead3dmGroupTable() )
2485 {
2486 if ( error_log) error_log->Print("ERROR: Corrupt group table. (ON_BinaryArchive::EndRead3dmGroupTable() returned false.)\n");
2487 return false;
2488 }
2489 if ( CheckForCRCErrors( archive, *this, error_log, "group table" ) )
2490 return_code = false;
2491 }
2492 else
2493 {
2494 if ( error_log)
2495 {
2496 error_log->Print("WARNING: Missing or corrupt group table. (ON_BinaryArchive::BeginRead3dmGroupTable() returned false.)\n");
2497 error_log->Print("-- Attempting to continue.\n");
2498 }
2499 return_code = false;
2500 }
2501
2502 // STEP 10: REQUIRED - Read font table
2503 if ( archive.BeginRead3dmFontTable() )
2504 {
2505 ON_Font* pFont = NULL;
2506 for( count = 0; true; count++ )
2507 {
2508 rc = archive.Read3dmFont(&pFont);
2509 if ( rc==0 )
2510 break; // end of font table
2511 if ( rc < 0 )
2512 {
2513 if ( error_log)
2514 {
2515 error_log->Print("ERROR: Corrupt font found. (ON_BinaryArchive::Read3dmFont() < 0.)\n");
2516 error_count++;
2517 if ( error_count > max_error_count )
2518 return false;
2519 error_log->Print("-- Attempting to continue.\n");
2520 }
2521 pFont = new ON_Font; // use default
2522 pFont->m_font_index = -1;
2523 }
2524 ON_UserDataHolder ud;
2525 ud.MoveUserDataFrom(*pFont);
2526 m_font_table.Append(*pFont);
2527 ud.MoveUserDataTo(*m_font_table.Last(),false);
2528 delete pFont;
2529 pFont = NULL;
2530 }
2531
2532 // If BeginRead3dmFontTable() returns true,
2533 // then you MUST call EndRead3dmFontTable().
2534 if ( !archive.EndRead3dmFontTable() )
2535 {
2536 if ( error_log) error_log->Print("ERROR: Corrupt font table. (ON_BinaryArchive::EndRead3dmFontTable() returned false.)\n");
2537 return false;
2538 }
2539 if ( CheckForCRCErrors( archive, *this, error_log, "font table" ) )
2540 return_code = false;
2541 }
2542 else
2543 {
2544 if ( error_log)
2545 {
2546 error_log->Print("WARNING: Missing or corrupt font table. (ON_BinaryArchive::BeginRead3dmFontTable() returned false.)\n");
2547 error_log->Print("-- Attempting to continue.\n");
2548 }
2549 return_code = false;
2550 }
2551
2552 // STEP 11: REQUIRED - Read dimstyle table
2553 if ( archive.BeginRead3dmDimStyleTable() )
2554 {
2555 ON_DimStyle* pDimStyle = NULL;
2556 for( count = 0; true; count++ )
2557 {
2558 rc = archive.Read3dmDimStyle(&pDimStyle);
2559 if ( rc==0 )
2560 break; // end of dimstyle table
2561 if ( rc < 0 )
2562 {
2563 if ( error_log)
2564 {
2565 error_log->Print("ERROR: Corrupt dimstyle found. (ON_BinaryArchive::Read3dmDimStyle() < 0.)\n");
2566 error_count++;
2567 if ( error_count > max_error_count )
2568 return false;
2569 error_log->Print("-- Attempting to continue.\n");
2570 }
2571 pDimStyle = new ON_DimStyle; // use default
2572 pDimStyle->m_dimstyle_index = count;
2573 }
2574 ON_UserDataHolder ud;
2575 ud.MoveUserDataFrom(*pDimStyle);
2576 m_dimstyle_table.Append(*pDimStyle);
2577 ud.MoveUserDataTo(*m_dimstyle_table.Last(),false);
2578 delete pDimStyle;
2579 pDimStyle = NULL;
2580 }
2581
2582 // If BeginRead3dmDimStyleTable() returns true,
2583 // then you MUST call EndRead3dmDimStyleTable().
2584 if ( !archive.EndRead3dmDimStyleTable() )
2585 {
2586 if ( error_log) error_log->Print("ERROR: Corrupt dimstyle table. (ON_BinaryArchive::EndRead3dmDimStyleTable() returned false.)\n");
2587 return false;
2588 }
2589 if ( CheckForCRCErrors( archive, *this, error_log, "dimstyle table" ) )
2590 return_code = false;
2591 }
2592 else
2593 {
2594 if ( error_log)
2595 {
2596 error_log->Print("WARNING: Missing or corrupt dimstyle table. (ON_BinaryArchive::BeginRead3dmDimStyleTable() returned false.)\n");
2597 error_log->Print("-- Attempting to continue.\n");
2598 }
2599 return_code = false;
2600 }
2601
2602 // STEP 12: REQUIRED - Read render lights table
2603 if ( archive.BeginRead3dmLightTable() )
2604 {
2605 ON_Light* pLight = NULL;
2606 ON_3dmObjectAttributes object_attributes;
2607 for( count = 0; true; count++ )
2608 {
2609 object_attributes.Default();
2610 rc = archive.Read3dmLight(&pLight,&object_attributes);
2611 if ( rc==0 )
2612 break; // end of light table
2613 if ( rc < 0 )
2614 {
2615 if ( error_log)
2616 {
2617 error_log->Print("ERROR: Corrupt render light found. (ON_BinaryArchive::Read3dmLight() < 0.)\n");
2618 error_count++;
2619 if ( error_count > max_error_count )
2620 return false;
2621 error_log->Print("-- Attempting to continue.\n");
2622 }
2623 continue;
2624 }
2625 ONX_Model_RenderLight& light = m_light_table.AppendNew();
2626 ON_UserDataHolder ud;
2627 ud.MoveUserDataFrom(*pLight);
2628 light.m_light = *pLight;
2629 ud.MoveUserDataTo(light.m_light,false);
2630 light.m_attributes = object_attributes;
2631 delete pLight;
2632 pLight = NULL;
2633 }
2634
2635 // If BeginRead3dmLightTable() returns true,
2636 // then you MUST call EndRead3dmLightTable().
2637 if ( !archive.EndRead3dmLightTable() )
2638 {
2639 if ( error_log) error_log->Print("ERROR: Corrupt render light table. (ON_BinaryArchive::EndRead3dmLightTable() returned false.)\n");
2640 return false;
2641 }
2642 if ( CheckForCRCErrors( archive, *this, error_log, "render light table" ) )
2643 return_code = false;
2644 }
2645 else
2646 {
2647 if ( error_log)
2648 {
2649 error_log->Print("WARNING: Missing or corrupt render light table. (ON_BinaryArchive::BeginRead3dmLightTable() returned false.)\n");
2650 error_log->Print("-- Attempting to continue.\n");
2651 }
2652 return_code = false;
2653 }
2654
2655 // STEP 13 - read hatch pattern table
2656 if ( archive.BeginRead3dmHatchPatternTable() )
2657 {
2658 ON_HatchPattern* pHatchPattern = NULL;
2659 for( count = 0; true; count++ )
2660 {
2661 rc = archive.Read3dmHatchPattern(&pHatchPattern);
2662 if ( rc==0 )
2663 break; // end of hatchpattern table
2664 if ( rc < 0 )
2665 {
2666 if ( error_log)
2667 {
2668 error_log->Print("ERROR: Corrupt hatchpattern found. (ON_BinaryArchive::Read3dmHatchPattern() < 0.)\n");
2669 error_count++;
2670 if ( error_count > max_error_count )
2671 return false;
2672 error_log->Print("-- Attempting to continue.\n");
2673 }
2674 pHatchPattern = new ON_HatchPattern; // use default
2675 pHatchPattern->m_hatchpattern_index = count;
2676 }
2677 ON_UserDataHolder ud;
2678 ud.MoveUserDataFrom(*pHatchPattern);
2679 m_hatch_pattern_table.Append(*pHatchPattern);
2680 ud.MoveUserDataTo(*m_hatch_pattern_table.Last(),false);
2681 delete pHatchPattern;
2682 pHatchPattern = NULL;
2683 }
2684
2685 // If BeginRead3dmHatchPatternTable() returns true,
2686 // then you MUST call EndRead3dmHatchPatternTable().
2687 if ( !archive.EndRead3dmHatchPatternTable() )
2688 {
2689 if ( error_log) error_log->Print("ERROR: Corrupt hatchpattern table. (ON_BinaryArchive::EndRead3dmHatchPatternTable() returned false.)\n");
2690 return false;
2691 }
2692 if ( CheckForCRCErrors( archive, *this, error_log, "hatchpattern table" ) )
2693 return_code = false;
2694 }
2695 else
2696 {
2697 if ( error_log)
2698 {
2699 error_log->Print("WARNING: Missing or corrupt hatchpattern table. (ON_BinaryArchive::BeginRead3dmHatchPatternTable() returned false.)\n");
2700 error_log->Print("-- Attempting to continue.\n");
2701 }
2702 return_code = false;
2703 }
2704
2705 // STEP 14: REQUIRED - Read instance definition table
2706 if ( archive.BeginRead3dmInstanceDefinitionTable() )
2707 {
2708 ON_InstanceDefinition* pIDef = NULL;
2709 for( count = 0; true; count++ )
2710 {
2711 rc = archive.Read3dmInstanceDefinition(&pIDef);
2712 if ( rc==0 )
2713 break; // end of instance definition table
2714 if ( rc < 0 )
2715 {
2716 if ( error_log)
2717 {
2718 error_log->Print("ERROR: Corrupt instance definition found. (ON_BinaryArchive::Read3dmInstanceDefinition() < 0.)\n");
2719 error_count++;
2720 if ( error_count > max_error_count )
2721 return false;
2722 error_log->Print("-- Attempting to continue.\n");
2723 }
2724 continue;
2725 }
2726 ON_UserDataHolder ud;
2727 ud.MoveUserDataFrom(*pIDef);
2728 m_idef_table.Append(*pIDef);
2729 ud.MoveUserDataTo(*m_idef_table.Last(),false);
2730 delete pIDef;
2731 }
2732
2733 // If BeginRead3dmInstanceDefinitionTable() returns true,
2734 // then you MUST call EndRead3dmInstanceDefinitionTable().
2735 if ( !archive.EndRead3dmInstanceDefinitionTable() )
2736 {
2737 if ( error_log) error_log->Print("ERROR: Corrupt instance definition table. (ON_BinaryArchive::EndRead3dmInstanceDefinitionTable() returned false.)\n");
2738 return false;
2739 }
2740 if ( CheckForCRCErrors( archive, *this, error_log, "instance definition table" ) )
2741 return_code = false;
2742 }
2743 else
2744 {
2745 if ( error_log)
2746 {
2747 error_log->Print("WARNING: Missing or corrupt instance definition table. (ON_BinaryArchive::BeginRead3dmInstanceDefinitionTable() returned false.)\n");
2748 error_log->Print("-- Attempting to continue.\n");
2749 }
2750 return_code = false;
2751 }
2752
2753
2754
2755 // STEP 15: REQUIRED - Read object (geometry and annotation) table
2756 if ( archive.BeginRead3dmObjectTable() )
2757 {
2758 // optional filter made by setting ON::object_type bits
2759 // For example, if you just wanted to just read points and meshes, you would use
2760 // object_filter = ON::point_object | ON::mesh_object;
2761 int object_filter = 0;
2762
2763 for( count = 0; true; count++ )
2764 {
2765 ON_Object* pObject = NULL;
2766 ON_3dmObjectAttributes attributes;
2767 rc = archive.Read3dmObject(&pObject,&attributes,object_filter);
2768 if ( rc == 0 )
2769 break; // end of object table
2770 if ( rc < 0 )
2771 {
2772 if ( error_log)
2773 {
2774 error_log->Print("ERROR: Object table entry %d is corrupt. (ON_BinaryArchive::Read3dmObject() < 0.)\n",count);
2775 error_count++;
2776 if ( error_count > max_error_count )
2777 return false;
2778 error_log->Print("-- Attempting to continue.\n");
2779 }
2780 continue;
2781 }
2782 if ( m_crc_error_count != archive.BadCRCCount() )
2783 {
2784 if ( error_log)
2785 {
2786 error_log->Print("ERROR: Object table entry %d is corrupt. (CRC errors).\n",count);
2787 error_log->Print("-- Attempting to continue.\n");
2788 }
2789 m_crc_error_count = archive.BadCRCCount();
2790 }
2791 if ( pObject )
2792 {
2793 ONX_Model_Object& mo = m_object_table.AppendNew();
2794 mo.m_object = pObject;
2795 mo.m_bDeleteObject = true;
2796 mo.m_attributes = attributes;
2797 }
2798 else
2799 {
2800 if ( error_log)
2801 {
2802 if ( rc == 2 )
2803 error_log->Print("WARNING: Skipping object table entry %d because it's filtered.\n",count);
2804 else if ( rc == 3 )
2805 error_log->Print("WARNING: Skipping object table entry %d because it's newer than this code. Update your OpenNURBS toolkit.\n",count);
2806 else
2807 error_log->Print("WARNING: Skipping object table entry %d for unknown reason.\n",count);
2808 }
2809 }
2810 }
2811
2812 // If BeginRead3dmObjectTable() returns true,
2813 // then you MUST call EndRead3dmObjectTable().
2814 if ( !archive.EndRead3dmObjectTable() )
2815 {
2816 if ( error_log) error_log->Print("ERROR: Corrupt object light table. (ON_BinaryArchive::EndRead3dmObjectTable() returned false.)\n");
2817 return false;
2818 }
2819 if ( CheckForCRCErrors( archive, *this, error_log, "object table" ) )
2820 return_code = false;
2821 }
2822 else
2823 {
2824 if ( error_log)
2825 {
2826 error_log->Print("WARNING: Missing or corrupt object table. (ON_BinaryArchive::BeginRead3dmObjectTable() returned false.)\n");
2827 error_log->Print("-- Attempting to continue.\n");
2828 }
2829 return_code = false;
2830 }
2831
2832 // STEP 16: Read history table
2833 if ( archive.BeginRead3dmHistoryRecordTable() )
2834 {
2835 for( count = 0; true; count++ )
2836 {
2837 ON_HistoryRecord* pHistoryRecord = NULL;
2838 rc = archive.Read3dmHistoryRecord(pHistoryRecord);
2839 if ( rc == 0 )
2840 break; // end of history record table
2841 if ( rc < 0 )
2842 {
2843 if ( error_log)
2844 {
2845 error_log->Print("ERROR: History record table entry %d is corrupt. (ON_BinaryArchive::Read3dmHistoryRecord() < 0.)\n",count);
2846 error_count++;
2847 if ( error_count > max_error_count )
2848 return false;
2849 error_log->Print("-- Attempting to continue.\n");
2850 }
2851 continue;
2852 }
2853 if ( m_crc_error_count != archive.BadCRCCount() )
2854 {
2855 if ( error_log)
2856 {
2857 error_log->Print("ERROR: History record table entry %d is corrupt. (CRC errors).\n",count);
2858 error_log->Print("-- Attempting to continue.\n");
2859 }
2860 m_crc_error_count = archive.BadCRCCount();
2861 }
2862 if ( pHistoryRecord )
2863 {
2864 m_history_record_table.Append(pHistoryRecord);
2865 }
2866 else
2867 {
2868 if ( error_log)
2869 {
2870 error_log->Print("WARNING: Skipping history record table entry %d for unknown reason.\n",count);
2871 }
2872 }
2873 }
2874
2875 // If BeginRead3dmHistoryRecordTable() returns true,
2876 // then you MUST call EndRead3dmHistoryRecordTable().
2877 if ( !archive.EndRead3dmHistoryRecordTable() )
2878 {
2879 if ( error_log) error_log->Print("ERROR: Corrupt object light table. (ON_BinaryArchive::EndRead3dmObjectTable() returned false.)\n");
2880 return false;
2881 }
2882 if ( CheckForCRCErrors( archive, *this, error_log, "history record table" ) )
2883 return_code = false;
2884 }
2885 else
2886 {
2887 if ( error_log)
2888 {
2889 error_log->Print("WARNING: Missing or corrupt history record table. (ON_BinaryArchive::BeginRead3dmHistoryRecordTable() returned false.)\n");
2890 error_log->Print("-- Attempting to continue.\n");
2891 }
2892 return_code = false;
2893 }
2894
2895 // STEP 17: OPTIONAL - Read user tables as anonymous goo
2896 // If you develop a plug-ins or application that uses OpenNURBS files,
2897 // you can store anything you want in a user table.
2898 for(count=0;true;count++)
2899 {
2900 if ( archive.Archive3dmVersion() <= 1 )
2901 {
2902 // no user tables in version 1 archives.
2903 break;
2904 }
2905
2906 {
2907 ON__UINT32 tcode = 0;
2908 ON__INT64 big_value = 0;
2909 if ( !archive.PeekAt3dmBigChunkType(&tcode,&big_value) )
2910 break;
2911 if ( TCODE_USER_TABLE != tcode )
2912 break;
2913 }
2914 ON_UUID plugin_id = ON_nil_uuid;
2915 bool bGoo = false;
2916 int usertable_3dm_version = 0;
2917 int usertable_opennurbs_version = 0;
2918 if ( !archive.BeginRead3dmUserTable( plugin_id, &bGoo, &usertable_3dm_version, &usertable_opennurbs_version ) )
2919 {
2920 // attempt to skip bogus user table
2921 const ON__UINT64 pos0 = archive.CurrentPosition();
2922 ON__UINT32 tcode = 0;
2923 ON__INT64 big_value = 0;
2924 if ( !archive.BeginRead3dmBigChunk(&tcode,&big_value) )
2925 break;
2926 if ( !archive.EndRead3dmChunk() )
2927 break;
2928 const ON__UINT64 pos1 = archive.CurrentPosition();
2929 if (pos1 <= pos0)
2930 break;
2931 if ( TCODE_USER_TABLE != tcode )
2932 break;
2933
2934 continue; // skip this bogus user table
2935 }
2936
2937 ONX_Model_UserData& ud = m_userdata_table.AppendNew();
2938 ud.m_uuid = plugin_id;
2939 ud.m_usertable_3dm_version = usertable_3dm_version;
2940 ud.m_usertable_opennurbs_version = usertable_opennurbs_version;
2941
2942 if ( !archive.Read3dmAnonymousUserTable( usertable_3dm_version, usertable_opennurbs_version, ud.m_goo ) )
2943 {
2944 if ( error_log) error_log->Print("ERROR: User data table entry %d is corrupt. (ON_BinaryArchive::Read3dmAnonymousUserTable() is false.)\n",count);
2945 break;
2946 }
2947
2948 // If BeginRead3dmObjectTable() returns true,
2949 // then you MUST call EndRead3dmUserTable().
2950 if ( !archive.EndRead3dmUserTable() )
2951 {
2952 if ( error_log) error_log->Print("ERROR: Corrupt user data table. (ON_BinaryArchive::EndRead3dmUserTable() returned false.)\n");
2953 break;
2954 }
2955 }
2956
2957 // STEP 18: OPTIONAL - check for end mark
2958 if ( !archive.Read3dmEndMark(&m_file_length) )
2959 {
2960 if ( archive.Archive3dmVersion() != 1 )
2961 {
2962 // some v1 files are missing end-of-archive markers
2963 if ( error_log) error_log->Print("ERROR: ON_BinaryArchive::Read3dmEndMark(&m_file_length) returned false.\n");
2964 }
2965 }
2966
2967 // Remap layer, material, linetype, font, dimstyle, hatch pattern, etc.,
2968 // indices so the correspond to the model's table array index.
2969 //
2970 // Polish also sets revision history information if it is missing.
2971 // In this case, that is not appropriate so the value of
2972 // m_properties.m_RevisionHistory is saved before calling Polish()
2973 // and restored afterwards.
2974 const ON_3dmRevisionHistory saved_revision_history(m_properties.m_RevisionHistory);
2975 Polish();
2976 m_properties.m_RevisionHistory = saved_revision_history;
2977
2978 return return_code;
2979 }
2980
2981 static
ONX_Model_WriteHelper(ON_BinaryFile & file)2982 void ONX_Model_WriteHelper(ON_BinaryFile& file)
2983 {
2984 file.EnableSave3dmRenderMeshes(true);
2985 file.EnableSave3dmAnalysisMeshes(true);
2986 file.EnableSaveUserData(true);
2987 }
2988
Write(const char * filename,int version,const char * sStartSectionComment,ON_TextLog * error_log)2989 bool ONX_Model::Write(
2990 const char* filename,
2991 int version,
2992 const char* sStartSectionComment,
2993 ON_TextLog* error_log
2994 )
2995 {
2996 bool rc = false;
2997 if ( 0 != filename )
2998 {
2999 FILE* fp = ON::OpenFile( filename, "wb" );
3000 if ( 0 != fp )
3001 {
3002 ON_BinaryFile file( ON::write3dm, fp );
3003 ONX_Model_WriteHelper(file);
3004 rc = Write( file, version, sStartSectionComment, error_log );
3005 ON::CloseFile(fp);
3006 }
3007 }
3008 return rc;
3009 }
3010
Write(const wchar_t * filename,int version,const char * sStartSectionComment,ON_TextLog * error_log)3011 bool ONX_Model::Write(
3012 const wchar_t* filename,
3013 int version,
3014 const char* sStartSectionComment,
3015 ON_TextLog* error_log
3016 )
3017 {
3018 bool rc = false;
3019 if ( 0 != filename )
3020 {
3021 FILE* fp = ON::OpenFile( filename, L"wb" );
3022 if ( 0 != fp )
3023 {
3024 ON_BinaryFile file( ON::write3dm, fp );
3025 ONX_Model_WriteHelper(file);
3026 rc = Write( file, version, sStartSectionComment, error_log );
3027 ON::CloseFile(fp);
3028 }
3029 }
3030 return rc;
3031 }
3032
3033
Write(ON_BinaryArchive & archive,int version,const char *,ON_TextLog * error_log)3034 bool ONX_Model::Write(
3035 ON_BinaryArchive& archive,
3036 int version,
3037 const char*,
3038 ON_TextLog* error_log
3039 )
3040 {
3041 int i;
3042
3043 if ( !IsValid(error_log) )
3044 {
3045 // This model is not valid. See the error_log for details.
3046 if ( error_log) error_log->Print("ONX_Model::Write Your model is not valid and will not be saved.\n");
3047 return false;
3048 }
3049
3050 if ( 0 != version )
3051 {
3052 if ( version < 2
3053 || version > ON_BinaryArchive::CurrentArchiveVersion()
3054 || (version >= 50 && 0 != (version%10))
3055 || (version < 50 && version > ON_BinaryArchive::CurrentArchiveVersion()/10)
3056 )
3057 {
3058 // version must be 0, 2, 3, 4, 5 or 50
3059 version = 0;
3060 if ( error_log) error_log->Print("ONX_Model::Write version parameter = %d; it must be 0, or >= 2 and <= %d, or a multiple of 10 >= 50 and <= %d.\n",
3061 version,ON_BinaryArchive::CurrentArchiveVersion()/10,ON_BinaryArchive::CurrentArchiveVersion());
3062 }
3063 }
3064
3065 if ( !archive.WriteMode() )
3066 {
3067 // You passed in a bogus archive. You must pass ON::write3dm to the
3068 // archive constructor.
3069 if ( error_log) error_log->Print("ONX_Model::Write archive.Mode() is not ON::write3dm.\n"
3070 "See ONX_Model::Write example in the header file.\n");
3071 return false;
3072 }
3073
3074 bool ok;
3075
3076 // START SECTION
3077 ok = archive.Write3dmStartSection( version, m_sStartSectionComments );
3078 if ( !ok )
3079 {
3080 // make sure your archive was created with ON::write3dm mode.
3081 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmStartSection() failed.\n"
3082 "Your archive is not properly initialized\n"
3083 "(make sure you passed ON::write3dm to the constructor),\n"
3084 "a file is locked, a disk is locked, or something along those lines.\n");
3085 return false;
3086 }
3087
3088 // PROPERTIES SECTION
3089 ok = archive.Write3dmProperties( m_properties );
3090 if ( !ok )
3091 {
3092 // make sure m_properties is valid
3093 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmProperties() failed.\n"
3094 "Your m_properties information is not valid or basic file writing failed.\n"
3095 );
3096 return false;
3097 }
3098
3099 // SETTINGS SECTION
3100 ok = archive.Write3dmSettings( m_settings );
3101 if ( !ok )
3102 {
3103 // make sure m_settings is valid
3104 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmSettings() failed.\n"
3105 "Your m_settings information is not valid or basic file writing failed.\n");
3106 return false;
3107 }
3108
3109 // BITMAP TABLE
3110 ok = archive.BeginWrite3dmBitmapTable();
3111 if ( !ok )
3112 {
3113 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmBitmapTable() failed.\n");
3114 return false;
3115 }
3116 for( i = 0; ok && i < m_bitmap_table.Count(); i++ )
3117 {
3118 ok = archive.Write3dmBitmap(*m_bitmap_table[i]);
3119 if ( !ok )
3120 {
3121 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmBitmap(m_bitmap_table[%d]) failed.\n",i);
3122 }
3123 }
3124 if ( !archive.EndWrite3dmBitmapTable() )
3125 {
3126 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmBitmapTable() failed.\n");
3127 return false;
3128 }
3129 if (!ok)
3130 return false;
3131
3132 // RENDER TEXTURE MAPPING TABLE
3133 if ( archive.Archive3dmVersion() >= 4 )
3134 {
3135 ok = archive.BeginWrite3dmTextureMappingTable();
3136 if ( !ok )
3137 {
3138 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmTextureMappingTable() failed.\n");
3139 return false;
3140 }
3141 for( i = 0; ok && i < m_mapping_table.Count(); i++ )
3142 {
3143 ok = archive.Write3dmTextureMapping(m_mapping_table[i]);
3144 if ( !ok )
3145 {
3146 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmTextureMapping(m_mapping_table[%d]) failed.\n",i);
3147 }
3148 }
3149 if ( !archive.EndWrite3dmTextureMappingTable() )
3150 {
3151 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmTextureMappingTable() failed.\n");
3152 return false;
3153 }
3154 if (!ok)
3155 return false;
3156 }
3157
3158 // RENDER MATERIAL TABLE
3159 ok = archive.BeginWrite3dmMaterialTable();
3160 if ( !ok )
3161 {
3162 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmMaterialTable() failed.\n");
3163 return false;
3164 }
3165 for( i = 0; ok && i < m_material_table.Count(); i++ )
3166 {
3167 ok = archive.Write3dmMaterial(m_material_table[i]);
3168 if ( !ok )
3169 {
3170 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmMaterial(m_material_table[%d]) failed.\n",i);
3171 }
3172 }
3173 if ( !archive.EndWrite3dmMaterialTable() )
3174 {
3175 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmMaterialTable() failed.\n");
3176 return false;
3177 }
3178 if (!ok)
3179 return false;
3180
3181
3182 // LINETYPE TABLE
3183 if ( archive.Archive3dmVersion() >= 4 )
3184 {
3185 ok = archive.BeginWrite3dmLinetypeTable();
3186 if ( !ok )
3187 {
3188 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmLinetypeTable() failed.\n");
3189 return false;
3190 }
3191 for( i = 0; ok && i < m_linetype_table.Count(); i++ )
3192 {
3193 ok = archive.Write3dmLinetype(m_linetype_table[i]);
3194 if ( !ok )
3195 {
3196 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmLinetype(m_linetype_table[%d]) failed.\n",i);
3197 }
3198 }
3199 if ( !archive.EndWrite3dmLinetypeTable() )
3200 {
3201 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmLinetypeTable() failed.\n");
3202 return false;
3203 }
3204 if (!ok)
3205 return false;
3206 }
3207
3208 // LAYER TABLE
3209 ok = archive.BeginWrite3dmLayerTable();
3210 if ( !ok )
3211 {
3212 // make sure m_settings is valid
3213 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmLayerTable() failed.\n");
3214 return false;
3215 }
3216 for( i = 0; ok && i < m_layer_table.Count(); i++ )
3217 {
3218 ok = archive.Write3dmLayer(m_layer_table[i]);
3219 if ( !ok )
3220 {
3221 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmLayer(m_layer_table[%d]) failed.\n",i);
3222 }
3223 }
3224 if ( !archive.EndWrite3dmLayerTable() )
3225 {
3226 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmLayerTable() failed.\n");
3227 return false;
3228 }
3229 if (!ok)
3230 return false;
3231
3232 // GROUP TABLE
3233 ok = archive.BeginWrite3dmGroupTable();
3234 if ( !ok )
3235 {
3236 // make sure m_settings is valid
3237 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmGroupTable() failed.\n");
3238 return false;
3239 }
3240 for( i = 0; ok && i < m_group_table.Count(); i++ )
3241 {
3242 ok = archive.Write3dmGroup(m_group_table[i]);
3243 if ( !ok )
3244 {
3245 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmGroup(m_group_table[%d]) failed.\n",i);
3246 }
3247 }
3248 if ( !archive.EndWrite3dmGroupTable() )
3249 {
3250 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmGroupTable() failed.\n");
3251 return false;
3252 }
3253 if (!ok)
3254 return false;
3255
3256
3257 // FONT TABLE
3258 if ( archive.Archive3dmVersion() >= 3 )
3259 {
3260 ok = archive.BeginWrite3dmFontTable();
3261 if ( !ok )
3262 {
3263 // make sure m_settings is valid
3264 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmFontTable() failed.\n");
3265 return false;
3266 }
3267 for( i = 0; ok && i < m_font_table.Count(); i++ )
3268 {
3269 ok = archive.Write3dmFont(m_font_table[i]);
3270 if ( !ok )
3271 {
3272 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmFont(m_font_table[%d]) failed.\n",i);
3273 }
3274 }
3275 if ( !archive.EndWrite3dmFontTable() )
3276 {
3277 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmFontTable() failed.\n");
3278 return false;
3279 }
3280 if (!ok)
3281 return false;
3282 }
3283
3284
3285 // DIMSTYLE TABLE
3286 if ( archive.Archive3dmVersion() >= 3 )
3287 {
3288 ok = archive.BeginWrite3dmDimStyleTable();
3289 if ( !ok )
3290 {
3291 // make sure m_settings is valid
3292 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmDimStyleTable() failed.\n");
3293 return false;
3294 }
3295 for( i = 0; ok && i < m_dimstyle_table.Count(); i++ )
3296 {
3297 ok = archive.Write3dmDimStyle(m_dimstyle_table[i]);
3298 if ( !ok )
3299 {
3300 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmDimStyle(m_dimstyle_table[%d]) failed.\n",i);
3301 }
3302 }
3303 if ( !archive.EndWrite3dmDimStyleTable() )
3304 {
3305 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmDimStyleTable() failed.\n");
3306 return false;
3307 }
3308 if (!ok)
3309 return false;
3310 }
3311
3312
3313 // LIGHT TABLE
3314 ok = archive.BeginWrite3dmLightTable();
3315 if ( !ok )
3316 {
3317 // make sure m_settings is valid
3318 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmLightTable() failed.\n");
3319 return false;
3320 }
3321 for( i = 0; ok && i < m_light_table.Count(); i++ )
3322 {
3323 ok = archive.Write3dmLight(m_light_table[i].m_light,&m_light_table[i].m_attributes);
3324 if ( !ok )
3325 {
3326 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmLight(m_light_table[%d]) failed.\n",i);
3327 }
3328 }
3329 if ( !archive.EndWrite3dmLightTable() )
3330 {
3331 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmLightTable() failed.\n");
3332 return false;
3333 }
3334 if (!ok)
3335 return false;
3336
3337
3338 // HATCH PATTERN TABLE
3339 if ( archive.Archive3dmVersion() >= 4 )
3340 {
3341 ok = archive.BeginWrite3dmHatchPatternTable();
3342 if ( !ok )
3343 {
3344 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmHatchPatternTable() failed.\n");
3345 return false;
3346 }
3347 for( i = 0; ok && i < m_hatch_pattern_table.Count(); i++ )
3348 {
3349 ok = archive.Write3dmHatchPattern(m_hatch_pattern_table[i]);
3350 if ( !ok )
3351 {
3352 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmHatchPattern(m_hatch_pattern_table[%d]) failed.\n",i);
3353 }
3354 }
3355 if ( !archive.EndWrite3dmHatchPatternTable() )
3356 {
3357 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmHatchPatternTable() failed.\n");
3358 return false;
3359 }
3360 if (!ok)
3361 return false;
3362 }
3363
3364
3365 // INSTANCE DEFINITION TABLE
3366 if ( archive.Archive3dmVersion() >= 3 )
3367 {
3368 ok = archive.BeginWrite3dmInstanceDefinitionTable();
3369 if ( !ok )
3370 {
3371 // make sure m_settings is valid
3372 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmInstanceDefinitionTable() failed.\n");
3373 return false;
3374 }
3375 for( i = 0; ok && i < m_idef_table.Count(); i++ )
3376 {
3377 ok = archive.Write3dmInstanceDefinition(m_idef_table[i]);
3378 if ( !ok )
3379 {
3380 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmInstanceDefinition(m_IDef_table[%d]) failed.\n",i);
3381 }
3382 }
3383 if ( !archive.EndWrite3dmInstanceDefinitionTable() )
3384 {
3385 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmInstanceDefinitionTable() failed.\n");
3386 return false;
3387 }
3388 if (!ok)
3389 return false;
3390 }
3391
3392
3393 // OBJECT TABLE
3394 ok = archive.BeginWrite3dmObjectTable();
3395 if ( !ok )
3396 {
3397 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmObjectTable() failed.\n");
3398 return false;
3399 }
3400 for( i = 0; ok && i < m_object_table.Count(); i++ )
3401 {
3402 if ( 0 != m_object_table[i].m_object )
3403 {
3404 ok = archive.Write3dmObject(*m_object_table[i].m_object,&m_object_table[i].m_attributes);
3405 if ( !ok )
3406 {
3407 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmObject(m_IDef_table[%d]) failed.\n",i);
3408 }
3409 }
3410 }
3411 if ( !archive.EndWrite3dmObjectTable() )
3412 {
3413 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmObjectTable() failed.\n");
3414 return false;
3415 }
3416 if (!ok)
3417 return false;
3418
3419
3420 // HISTORY RECORD TABLE
3421 if ( archive.Archive3dmVersion() >= 4 )
3422 {
3423 ok = archive.BeginWrite3dmHistoryRecordTable();
3424 if ( !ok )
3425 {
3426 if ( error_log) error_log->Print("ONX_Model::Write archive.BeginWrite3dmHistoryRecordTable() failed.\n");
3427 return false;
3428 }
3429 for ( i = 0; ok && i < m_history_record_table.Count(); i++ )
3430 {
3431 const ON_HistoryRecord* history_record = m_history_record_table[i];
3432 if( history_record)
3433 ok = archive.Write3dmHistoryRecord( *history_record );
3434 }
3435 if( !archive.EndWrite3dmHistoryRecordTable() )
3436 {
3437 if ( error_log) error_log->Print("ONX_Model::Write archive.EndWrite3dmHistoryTable() failed.\n");
3438 return false;
3439 }
3440 if (!ok)
3441 return false;
3442 }
3443
3444 // USER DATA TABLE
3445 for( i = 0; ok && i < m_userdata_table.Count(); i++ )
3446 {
3447 const ONX_Model_UserData& ud = m_userdata_table[i];
3448 if ( ON_UuidIsNotNil(ud.m_uuid) )
3449 {
3450 if ( !archive.Write3dmAnonymousUserTableRecord(
3451 ud.m_uuid,
3452 ud.m_usertable_3dm_version,
3453 ud.m_usertable_opennurbs_version,ud.m_goo
3454 ) )
3455 {
3456 continue;
3457 }
3458 }
3459 }
3460
3461 if ( !archive.Write3dmEndMark() )
3462 {
3463 ok = false;
3464 if ( error_log) error_log->Print("ONX_Model::Write archive.Write3dmEndMark() failed.\n");
3465 }
3466
3467 return ok;
3468 }
3469
IsValid(ON_TextLog * text_log) const3470 bool ONX_Model::IsValid( ON_TextLog* text_log ) const
3471 {
3472 // Audit with no repairs will simply complain if it
3473 // finds something wrong;
3474 int i = const_cast<ONX_Model*>(this)->Audit(false,NULL,text_log,NULL);
3475 return (i>=0);
3476 }
3477
ObjectIndex(ON_UUID object_uuid) const3478 int ONX_Model::ObjectIndex( ON_UUID object_uuid ) const
3479 {
3480 // In a high quality app, you may want to override this
3481 // and do something a little smarter.
3482
3483 int object_index = -1;
3484 if ( ON_UuidIsNotNil(object_uuid) )
3485 {
3486 int i, object_count = m_object_table.Count();
3487 if ( object_count > 0 )
3488 {
3489 if ( object_count != m_object_id_index.Count() )
3490 {
3491 // rebuild m__object_uuid_index[]
3492 ON_UuidIndexList* p = const_cast< ON_UuidIndexList* >(&m_object_id_index);
3493 p->Empty();
3494 p->Reserve(object_count);
3495 for ( i = 0; i < object_count; i++ )
3496 {
3497 ON_UUID id = m_object_table[i].m_attributes.m_uuid;
3498 if ( ON_UuidIsNil(id) )
3499 {
3500 ON_ERROR("Nil object ids in model");
3501 ON_CreateUuid(id);
3502 *(const_cast<ON_UUID*>(&m_object_table[i].m_attributes.m_uuid)) = id;
3503 }
3504 if ( !p->AddUuidIndex(id,i,true) )
3505 {
3506 ON_ERROR("Duplicate object ids in model");
3507 ON_CreateUuid(id);
3508 *(const_cast<ON_UUID*>(&m_object_table[i].m_attributes.m_uuid)) = id;
3509 p->AddUuidIndex(id,i,false);
3510 }
3511 }
3512 }
3513
3514 if ( !m_object_id_index.FindUuid(object_uuid,&object_index) )
3515 object_index = -1;
3516 }
3517 }
3518
3519 return object_index;
3520 }
3521
IDefIndex(ON_UUID idef_uuid) const3522 int ONX_Model::IDefIndex( ON_UUID idef_uuid ) const
3523 {
3524 // In a high quality app, you may want to override this
3525 // and do something a little smarter.
3526
3527 int idef_index = -1;
3528 if ( ON_UuidIsNotNil(idef_uuid) )
3529 {
3530 int i, idef_count = m_idef_table.Count();
3531 if ( idef_count > 0 )
3532 {
3533 if ( idef_count != m_idef_id_index.Count() )
3534 {
3535 // rebuild m__idef_uuid_index[]
3536 ON_UuidIndexList* p = const_cast<ON_UuidIndexList*>(&m_idef_id_index);
3537 p->Empty();
3538 p->Reserve(idef_count);
3539 for ( i = 0; i < idef_count; i++ )
3540 {
3541 ON_UUID id = m_idef_table[i].m_uuid;
3542 if ( ON_UuidIsNil(id) )
3543 {
3544 ON_ERROR("Nil idef ids in model");
3545 ON_CreateUuid(id);
3546 (const_cast<ON_InstanceDefinition*>(&m_idef_table[i]))->m_uuid = id;
3547 }
3548 if ( !p->AddUuidIndex(id,i,true) )
3549 {
3550 ON_ERROR("Duplicate idef ids in model");
3551 ON_CreateUuid(id);
3552 (const_cast<ON_InstanceDefinition*>(&m_idef_table[i]))->m_uuid = id;
3553 p->AddUuidIndex(id,i,false);
3554 }
3555 }
3556 }
3557
3558 if ( !m_idef_id_index.FindUuid(idef_uuid,&idef_index) )
3559 idef_index = -1;
3560 }
3561 }
3562
3563 return idef_index;
3564 }
3565
IDefIndex(const wchar_t * idef_name) const3566 int ONX_Model::IDefIndex( const wchar_t* idef_name ) const
3567 {
3568 // slow and stupid search - what do you expect for free?
3569 // In a high quality app, you will want to override this
3570 // and do something a little smarter.
3571 //
3572 int idef_index = -1;
3573 if ( 0 != idef_name && 0 != idef_name[0] )
3574 {
3575 int i, idef_count = m_idef_table.Count();
3576 for ( i = 0; i < idef_count; i++ )
3577 {
3578 if ( 0 == on_wcsicmp(idef_name, m_idef_table[i].Name() ) )
3579 {
3580 idef_index = i;
3581 break;
3582 }
3583 }
3584 }
3585 return idef_index;
3586 }
3587
GetUnusedIDefName(ON_wString & idef_name) const3588 void ONX_Model::GetUnusedIDefName( ON_wString& idef_name ) const
3589 {
3590 int i = 1;
3591 for(i = 1; i < 100000; i++ )
3592 {
3593 idef_name.Format("IDef_%02d",i);
3594 if ( IDefIndex(idef_name) < 0 )
3595 return;
3596 }
3597 idef_name = "IDef";
3598 return;
3599 }
3600
UsesIDef(const ON_InstanceRef & iref,ON_UUID idef_uuid) const3601 int ONX_Model::UsesIDef(
3602 const ON_InstanceRef& iref,
3603 ON_UUID idef_uuid
3604 ) const
3605 {
3606 // get id of idef we are looking for
3607 if ( ON_UuidIsNil(idef_uuid) )
3608 return 0;
3609
3610 // id of idef that defines iref
3611 ON_UUID iref_idef_uuid = iref.m_instance_definition_uuid;
3612 if ( 0 == ON_UuidCompare( idef_uuid, iref_idef_uuid ) )
3613 return 1;
3614
3615 const int iref_idef_index = IDefIndex(iref_idef_uuid);
3616 if ( -1 == iref_idef_index )
3617 return -1;
3618 const ON_InstanceDefinition& iref_idef = m_idef_table[iref_idef_index];
3619
3620
3621 int i0 = 0;
3622 int i1 = 0;
3623 int i, j, k, depth, obj_index;
3624 const ON_InstanceRef* pNestedIRef;
3625
3626 // set iref_list[] = list of all nested instance references in iref_idef.
3627 ON_SimpleArray<const ON_InstanceRef*> iref_list(256);
3628 for ( j = 0; j < iref_idef.m_object_uuid.Count(); j++ )
3629 {
3630 obj_index = ObjectIndex(iref_idef.m_object_uuid[j]);
3631 if ( obj_index < 0 )
3632 continue;
3633 const ONX_Model_Object& obj = m_object_table[obj_index];
3634 if ( 0 == obj.m_object )
3635 continue;
3636 if ( obj.m_object->ObjectType() == ON::instance_reference )
3637 {
3638 pNestedIRef = ON_InstanceRef::Cast(obj.m_object);
3639 if ( 0 != pNestedIRef )
3640 {
3641 if ( 0 == ON_UuidCompare( idef_uuid, pNestedIRef->m_instance_definition_uuid ) )
3642 return 2;
3643 iref_list.Append(pNestedIRef);
3644 }
3645 }
3646 }
3647
3648 // test the nested instance references to see if they use idef_index.
3649 const int max_depth = 1000;
3650 for ( depth=3; depth < max_depth && i1 < iref_list.Count(); depth++ )
3651 {
3652 i0 = i1;
3653 i1 = iref_list.Count();
3654 for ( i = i0; i < i1; i++ )
3655 {
3656 pNestedIRef = iref_list[i];
3657 if ( 0 == pNestedIRef )
3658 continue;
3659 k = IDefIndex( pNestedIRef->m_instance_definition_uuid );
3660 if ( k < 0 )
3661 continue;
3662 const ON_InstanceDefinition& nested_idef = m_idef_table[k];
3663 for ( j = 0; j < nested_idef.m_object_uuid.Count(); j++ )
3664 {
3665 obj_index = ObjectIndex(nested_idef.m_object_uuid[j]);
3666 if ( obj_index < 0 )
3667 continue;
3668 const ONX_Model_Object& obj = m_object_table[obj_index];
3669 if ( 0 == obj.m_object )
3670 continue;
3671 if ( obj.m_object->ObjectType() == ON::instance_reference )
3672 {
3673 pNestedIRef = ON_InstanceRef::Cast(obj.m_object);
3674 if ( 0 != pNestedIRef )
3675 {
3676 if ( 0 == ON_UuidCompare( idef_uuid, pNestedIRef->m_instance_definition_uuid ) )
3677 return depth;
3678 iref_list.Append(pNestedIRef);
3679 }
3680 }
3681 }
3682 }
3683 }
3684
3685 return (depth < max_depth) ? 0 : -2;
3686 }
3687
LayerIndex(const wchar_t * layer_name) const3688 int ONX_Model::LayerIndex( const wchar_t* layer_name ) const
3689 {
3690 // slow and stupid search - what do you expect for free?
3691 // In a high quality app, you will want to override this
3692 // and do something a little smarter.
3693
3694 int layer_index = -1;
3695 if ( 0 != layer_name && 0 != layer_name[0] )
3696 {
3697 int i, layer_count = m_layer_table.Count();
3698 for ( i = 0; i < layer_count; i++ )
3699 {
3700 if ( 0 == on_wcsicmp(layer_name, m_layer_table[i].LayerName() ) )
3701 {
3702 layer_index = i;
3703 break;
3704 }
3705 }
3706 }
3707 return layer_index;
3708 }
3709
3710
GetUnusedLayerName(ON_wString & layer_name) const3711 void ONX_Model::GetUnusedLayerName( ON_wString& layer_name ) const
3712 {
3713 int i = 1;
3714 for(i = 1; i < 100000; i++ )
3715 {
3716 layer_name.Format("Layer_%02d",i);
3717 if ( LayerIndex(layer_name) < 0 )
3718 return;
3719 }
3720 layer_name = "Layer";
3721 return;
3722 }
3723
3724
3725
SetDocumentUserString(const wchar_t * key,const wchar_t * string_value)3726 bool ONX_Model::SetDocumentUserString( const wchar_t* key, const wchar_t* string_value )
3727 {
3728 // This is a slow and stupid way to set a single string,
3729 // but I cannot modify the ONX_Model class to transparently
3730 // store document user string information until I can break
3731 // the public SDK in V6.
3732 bool rc = false;
3733 if ( 0 != key && 0 != key[0] )
3734 {
3735 ON_UUID doc_userstring_id = ON_DocumentUserStringList::m_ON_DocumentUserStringList_class_id.Uuid();
3736 for (int i = 0; i < m_userdata_table.Count(); i++ )
3737 {
3738 ONX_Model_UserData& ud = m_userdata_table[i];
3739 if ( ud.m_uuid == doc_userstring_id )
3740 {
3741 if ( TCODE_USER_RECORD == ud.m_goo.m_typecode && ud.m_goo.m_value != 0 )
3742 {
3743 ON_Read3dmBufferArchive ba(
3744 (unsigned int)ud.m_goo.m_value,
3745 ud.m_goo.m_goo,
3746 false,
3747 m_3dm_file_version,
3748 m_3dm_opennurbs_version
3749 );
3750 ON_Object* p = 0;
3751 if ( ba.ReadObject(&p) )
3752 {
3753 ON_DocumentUserStringList* sl = ON_DocumentUserStringList::Cast(p);
3754 if ( 0 != sl )
3755 {
3756 // modify the user string information
3757 rc = sl->SetUserString(key,string_value);
3758 if ( rc )
3759 {
3760 // write the new informtion to a memory buffer
3761 ON_Write3dmBufferArchive newgoo(ud.m_goo.m_value+1024,0,m_3dm_file_version,ON::Version());
3762 if ( newgoo.BeginWrite3dmUserTable(doc_userstring_id,false,0,0)
3763 && newgoo.WriteObject(sl)
3764 && newgoo.EndWrite3dmUserTable()
3765 )
3766 {
3767 if ( newgoo.SizeOfArchive() > 0
3768 && newgoo.SizeOfArchive() <= 0xFFFFFFFF // max goo size if 4GB because we used an unsigned int back in the ice ages
3769 )
3770 {
3771 // update the "goo"
3772 unsigned char* goo = (unsigned char*)newgoo.HarvestBuffer();
3773 unsigned int value = (unsigned int)newgoo.SizeOfArchive();
3774 if ( 0 != goo && value > 0 )
3775 {
3776 onfree(ud.m_goo.m_goo); // delete old "goo"
3777 ud.m_goo.m_value = (int)value;
3778 ud.m_goo.m_goo = goo;
3779 }
3780 }
3781 }
3782 }
3783 }
3784 }
3785 if ( 0 != p )
3786 {
3787 delete p;
3788 p = 0;
3789 }
3790 }
3791 break;
3792 }
3793 }
3794 }
3795 return rc;
3796 }
3797
3798
GetDocumentUserString(const wchar_t * key,ON_wString & string_value) const3799 bool ONX_Model::GetDocumentUserString( const wchar_t* key, ON_wString& string_value ) const
3800 {
3801 const wchar_t* s = 0;
3802 if ( 0 != key && 0 != key[0] )
3803 {
3804 // This is a slow and stupid way to get a single string,
3805 // but I cannot modify the ONX_Model class to transparently
3806 // store document user string information until I can break
3807 // the public SDK in V6.
3808 ON_ClassArray<ON_UserString> user_strings;
3809 GetDocumentUserStrings( user_strings );
3810 for ( int i = 0; i < user_strings.Count(); i++ )
3811 {
3812 if ( !user_strings[i].m_key.CompareNoCase(key) )
3813 {
3814 s = user_strings[i].m_string_value;
3815 break;
3816 }
3817 }
3818 }
3819 string_value = s;
3820 return (0 != s);
3821 }
3822
3823
GetDocumentUserStrings(ON_ClassArray<ON_UserString> & user_strings) const3824 int ONX_Model::GetDocumentUserStrings( ON_ClassArray<ON_UserString>& user_strings ) const
3825 {
3826 int rc = 0;
3827 // user strings are stored as ON_Object user strings on
3828 // an ON_DocumentUserStringList object in a user table
3829 // with id = doc_userstring_id.
3830 ON_UUID doc_userstring_id = ON_DocumentUserStringList::m_ON_DocumentUserStringList_class_id.Uuid();
3831 for (int i = 0; i < m_userdata_table.Count(); i++ )
3832 {
3833 const ONX_Model_UserData& ud = m_userdata_table[i];
3834 if ( ud.m_uuid == doc_userstring_id )
3835 {
3836 if ( TCODE_USER_RECORD == ud.m_goo.m_typecode && ud.m_goo.m_value != 0 )
3837 {
3838 ON_Read3dmBufferArchive ba(
3839 (unsigned int)ud.m_goo.m_value,
3840 ud.m_goo.m_goo,
3841 false,
3842 m_3dm_file_version,
3843 m_3dm_opennurbs_version
3844 );
3845
3846 ON_Object* p = 0;
3847 if ( ba.ReadObject(&p) )
3848 {
3849 const ON_DocumentUserStringList* sl = ON_DocumentUserStringList::Cast(p);
3850 if ( 0 != sl )
3851 {
3852 rc = sl->GetUserStrings(user_strings);
3853 }
3854 }
3855 if ( 0 != p )
3856 {
3857 delete p;
3858 p = 0;
3859 }
3860 }
3861 break;
3862 }
3863 }
3864 return rc;
3865 }
3866
3867
AuditTextureMappingTableHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)3868 static int AuditTextureMappingTableHelper(
3869 ONX_Model& model,
3870 bool bAttemptRepair,
3871 int* repair_count,
3872 ON_TextLog* text_log
3873 )
3874 {
3875 if ( repair_count )
3876 *repair_count = 0;
3877 int i, count = model.m_mapping_table.Count();
3878 for ( i = 0; i < count; i++ )
3879 {
3880 ON_TextureMapping& mapping = model.m_mapping_table[i];
3881 if ( mapping.m_mapping_index != i )
3882 {
3883 if ( text_log )
3884 {
3885 text_log->Print("m_mapping_table[%d].m_mapping_index == %d (should be %d)\n",
3886 i,mapping.m_mapping_index,i);
3887 }
3888 if ( bAttemptRepair )
3889 {
3890 mapping.m_mapping_index = i;
3891 if ( text_log )
3892 {
3893 text_log->PushIndent();
3894 text_log->Print("Repaired.\n");
3895 text_log->PopIndent();
3896 }
3897 if ( repair_count )
3898 *repair_count += 1;
3899 }
3900 else
3901 {
3902 return -1;
3903 }
3904 }
3905 if ( !mapping.IsValid(text_log) )
3906 return 1;
3907 }
3908 return 0;
3909 }
3910
3911
AuditGroupTableHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)3912 static int AuditGroupTableHelper(
3913 ONX_Model& model,
3914 bool bAttemptRepair,
3915 int* repair_count,
3916 ON_TextLog* text_log
3917 )
3918 {
3919 if ( repair_count )
3920 *repair_count = 0;
3921 int i, count = model.m_group_table.Count();
3922 for ( i = 0; i < count; i++ )
3923 {
3924 ON_Group& group = model.m_group_table[i];
3925 if ( group.m_group_index != i )
3926 {
3927 if ( text_log )
3928 {
3929 text_log->Print("m_group_table[%d].m_group_index == %d (should be %d)\n",
3930 i,group.m_group_index,i);
3931 }
3932 if ( bAttemptRepair )
3933 {
3934 group.m_group_index = i;
3935 if ( text_log )
3936 {
3937 text_log->PushIndent();
3938 text_log->Print("Repaired.\n");
3939 text_log->PopIndent();
3940 }
3941 if ( repair_count )
3942 *repair_count += 1;
3943 }
3944 else
3945 {
3946 return -1;
3947 }
3948 }
3949 if ( !group.IsValid(text_log) )
3950 return 1;
3951 }
3952 return 0;
3953 }
3954
3955
AuditFontTableHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)3956 static int AuditFontTableHelper(
3957 ONX_Model& model,
3958 bool bAttemptRepair,
3959 int* repair_count,
3960 ON_TextLog* text_log
3961 )
3962 {
3963 if ( repair_count )
3964 *repair_count = 0;
3965 int i, count = model.m_font_table.Count();
3966 for ( i = 0; i < count; i++ )
3967 {
3968 ON_Font& font = model.m_font_table[i];
3969 if ( font.m_font_index != i )
3970 {
3971 if ( text_log )
3972 {
3973 text_log->Print("m_font_table[%d].m_font_index == %d (should be %d)\n",
3974 i,font.m_font_index,i);
3975 }
3976 if ( bAttemptRepair )
3977 {
3978 font.m_font_index = i;
3979 if ( text_log )
3980 {
3981 text_log->PushIndent();
3982 text_log->Print("Repaired.\n");
3983 text_log->PopIndent();
3984 }
3985 if ( repair_count )
3986 *repair_count += 1;
3987 }
3988 else
3989 {
3990 return -1;
3991 }
3992 }
3993 if ( !font.IsValid(text_log) )
3994 return 1;
3995 }
3996 return 0;
3997 }
3998
3999
AuditDimStyleTableHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4000 static int AuditDimStyleTableHelper(
4001 ONX_Model& model,
4002 bool bAttemptRepair,
4003 int* repair_count,
4004 ON_TextLog* text_log
4005 )
4006 {
4007 if ( repair_count )
4008 *repair_count = 0;
4009 int i, count = model.m_dimstyle_table.Count();
4010 for ( i = 0; i < count; i++ )
4011 {
4012 ON_DimStyle& dimstyle = model.m_dimstyle_table[i];
4013 if ( dimstyle.m_dimstyle_index != i )
4014 {
4015 if ( text_log )
4016 {
4017 text_log->Print("m_dimstyle_table[%d].m_dimstyle_index == %d (should be %d)\n",
4018 i,dimstyle.m_dimstyle_index,i);
4019 }
4020 if ( bAttemptRepair )
4021 {
4022 dimstyle.m_dimstyle_index = i;
4023 if ( text_log )
4024 {
4025 text_log->PushIndent();
4026 text_log->Print("Repaired.\n");
4027 text_log->PopIndent();
4028 }
4029 if ( repair_count )
4030 *repair_count += 1;
4031 }
4032 else
4033 {
4034 return -1;
4035 }
4036 }
4037 if ( !dimstyle.IsValid(text_log) )
4038 return 1;
4039 }
4040 return 0;
4041 }
4042
4043
AuditHatchPatternTableHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4044 static int AuditHatchPatternTableHelper(
4045 ONX_Model& model,
4046 bool bAttemptRepair,
4047 int* repair_count,
4048 ON_TextLog* text_log
4049 )
4050 {
4051 if ( repair_count )
4052 *repair_count = 0;
4053 int i, count = model.m_hatch_pattern_table.Count();
4054 for ( i = 0; i < count; i++ )
4055 {
4056 ON_HatchPattern& hatchpattern = model.m_hatch_pattern_table[i];
4057 if ( hatchpattern.m_hatchpattern_index != i )
4058 {
4059 if ( text_log )
4060 {
4061 text_log->Print("m_hatch_pattern_table[%d].m_hatchpattern_index == %d (should be %d)\n",
4062 i,hatchpattern.m_hatchpattern_index,i);
4063 }
4064 if ( bAttemptRepair )
4065 {
4066 hatchpattern.m_hatchpattern_index = i;
4067 if ( text_log )
4068 {
4069 text_log->PushIndent();
4070 text_log->Print("Repaired.\n");
4071 text_log->PopIndent();
4072 }
4073 if ( repair_count )
4074 *repair_count += 1;
4075 }
4076 else
4077 {
4078 return -1;
4079 }
4080 }
4081 if ( !hatchpattern.IsValid(text_log) )
4082 return 1;
4083 }
4084 return 0;
4085 }
4086
4087
AuditObjectAttributesHelper(ONX_Model & model,ON_3dmObjectAttributes & attributes,const char * parent_name,int parent_index,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4088 static int AuditObjectAttributesHelper(
4089 ONX_Model& model,
4090 ON_3dmObjectAttributes& attributes,
4091 const char* parent_name,
4092 int parent_index,
4093 bool bAttemptRepair,
4094 int* repair_count,
4095 ON_TextLog* text_log
4096 )
4097 {
4098 int repcount = 0;
4099 int errcount = 0;
4100
4101 // validate key attributes.
4102 int layer_index = attributes.m_layer_index;
4103 if ( layer_index < 0 || layer_index >= model.m_layer_table.Count() )
4104 {
4105 errcount++;
4106 if ( text_log )
4107 {
4108 text_log->Print(parent_name,parent_index);
4109 text_log->Print("m_layer_index = %d is not valid.",layer_index);
4110 }
4111
4112 if ( bAttemptRepair )
4113 {
4114 layer_index = model.m_settings.m_current_layer_index;
4115 if ( layer_index < 0 || layer_index >= model.m_layer_table.Count()
4116 )
4117 {
4118 layer_index = 0;
4119 }
4120 if ( layer_index >= 0 && layer_index < model.m_layer_table.Count() )
4121 {
4122 repcount++;
4123 attributes.m_layer_index = layer_index;
4124 if ( text_log )
4125 text_log->Print(" Repaired.");
4126 }
4127 }
4128 if ( text_log )
4129 {
4130 text_log->Print("\n");
4131 }
4132 }
4133
4134 int linetype_index = attributes.m_linetype_index;
4135 if ( linetype_index < -1 || linetype_index >= model.m_linetype_table.Count() )
4136 {
4137 errcount++;
4138 if ( text_log )
4139 {
4140 text_log->Print(parent_name,parent_index);
4141 text_log->Print("m_linetype_index = %d is not valid.",linetype_index);
4142 }
4143
4144 if ( bAttemptRepair )
4145 {
4146 linetype_index = -1;
4147 repcount++;
4148 attributes.m_linetype_index = linetype_index;
4149 if ( text_log )
4150 text_log->Print(" Repaired.");
4151 }
4152 if ( text_log )
4153 {
4154 text_log->Print("\n");
4155 }
4156 }
4157
4158 int material_index = attributes.m_material_index;
4159 if ( material_index < -1 || material_index >= model.m_material_table.Count() )
4160 {
4161 errcount++;
4162 if ( text_log )
4163 {
4164 text_log->Print(parent_name,parent_index);
4165 text_log->Print("m_material_index = %d is not valid.",material_index);
4166 }
4167
4168 if ( bAttemptRepair )
4169 {
4170 material_index = -1;
4171 repcount++;
4172 attributes.m_material_index = material_index;
4173 if ( text_log )
4174 text_log->Print(" Repaired.");
4175 }
4176 if ( text_log )
4177 {
4178 text_log->Print("\n");
4179 }
4180 }
4181
4182 if ( repcount > 0 && repair_count )
4183 *repair_count = *repair_count + repcount;
4184
4185 return (errcount>0) ? 9 : 0;
4186 }
4187
4188
4189
AuditLightTableHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4190 static int AuditLightTableHelper(
4191 ONX_Model& model,
4192 bool bAttemptRepair,
4193 int* repair_count,
4194 ON_TextLog* text_log
4195 )
4196 {
4197 int rc = 0;
4198 if ( repair_count )
4199 *repair_count = 0;
4200 int i, count = model.m_light_table.Count();
4201 for ( i = 0; i < count; i++ )
4202 {
4203 ONX_Model_RenderLight& xlight = model.m_light_table[i];
4204 ON_Light& light = xlight.m_light;
4205 if ( light.m_light_index != i )
4206 {
4207 if ( text_log )
4208 {
4209 text_log->Print("m_light_table[%d].m_light_index == %d (should be %d)\n",
4210 i,light.m_light_index,i);
4211 }
4212 if ( bAttemptRepair )
4213 {
4214 light.m_light_index = i;
4215 if ( text_log )
4216 {
4217 text_log->PushIndent();
4218 text_log->Print("Repaired.\n");
4219 text_log->PopIndent();
4220 }
4221 if ( repair_count )
4222 *repair_count += 1;
4223 }
4224 else
4225 {
4226 return -1;
4227 }
4228 }
4229
4230 int attrc = AuditObjectAttributesHelper(model,
4231 xlight.m_attributes,
4232 "m_light_table[%d].m_attributes",
4233 i,
4234 bAttemptRepair,
4235 repair_count,
4236 text_log
4237 );
4238
4239 if ( attrc && 0 == rc )
4240 rc = 9;
4241
4242 if ( !light.IsValid(text_log) )
4243 {
4244 if ( 0 == rc )
4245 rc = 1;
4246 }
4247
4248 }
4249 return rc;
4250 }
4251
AuditMaterialTableHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4252 static int AuditMaterialTableHelper(
4253 ONX_Model& model,
4254 bool bAttemptRepair,
4255 int* repair_count,
4256 ON_TextLog* text_log
4257 )
4258 {
4259 if ( repair_count )
4260 *repair_count = 0;
4261 int i, count = model.m_material_table.Count();
4262 for ( i = 0; i < count; i++ )
4263 {
4264 ON_Material& mat = model.m_material_table[i];
4265 if ( mat.MaterialIndex() != i )
4266 {
4267 if ( text_log )
4268 {
4269 text_log->Print("m_material_table[%d].MaterialIndex() == %d (should be %d)\n",
4270 i,mat.MaterialIndex(),i);
4271 }
4272 if ( bAttemptRepair )
4273 {
4274 mat.SetMaterialIndex(i);
4275 if ( text_log )
4276 {
4277 text_log->PushIndent();
4278 text_log->Print("Repaired.\n");
4279 text_log->PopIndent();
4280 }
4281 if ( repair_count )
4282 *repair_count += 1;
4283 }
4284 else
4285 {
4286 return -1;
4287 }
4288 }
4289 if ( !mat.IsValid(text_log) )
4290 return 1;
4291 }
4292 return 0;
4293 }
4294
AuditLinetypeTableHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4295 static int AuditLinetypeTableHelper(
4296 ONX_Model& model,
4297 bool bAttemptRepair,
4298 int* repair_count,
4299 ON_TextLog* text_log
4300 )
4301 {
4302 if ( repair_count )
4303 *repair_count = 0;
4304 int i, count = model.m_linetype_table.Count();
4305 for ( i = 0; i < count; i++ )
4306 {
4307 ON_Linetype& lt = model.m_linetype_table[i];
4308 if ( lt.LinetypeIndex() != i )
4309 {
4310 if ( text_log )
4311 {
4312 text_log->Print("m_linetype_table[%d].LinetypeIndex() == %d (should be %d)\n",
4313 i,lt.LinetypeIndex(),i);
4314 }
4315 if ( bAttemptRepair )
4316 {
4317 lt.SetLinetypeIndex(i);
4318 if ( text_log )
4319 {
4320 text_log->PushIndent();
4321 text_log->Print("Repaired.\n");
4322 text_log->PopIndent();
4323 }
4324 if ( repair_count )
4325 *repair_count += 1;
4326 }
4327 else
4328 {
4329 return -1;
4330 }
4331 }
4332 if ( !lt.IsValid(text_log) )
4333 return 10;
4334 }
4335 return 0;
4336 }
4337
AuditLayerTableHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4338 static int AuditLayerTableHelper(
4339 ONX_Model& model,
4340 bool bAttemptRepair,
4341 int* repair_count,
4342 ON_TextLog* text_log
4343 )
4344 {
4345 int rc = 0;
4346 if ( repair_count )
4347 *repair_count = 0;
4348 int i, count = model.m_layer_table.Count();
4349 if ( count == 0 && (model.m_object_table.Count()>0 || model.m_light_table.Count()>0))
4350 rc = 2;
4351 for ( i = 0; i < count; i++ )
4352 {
4353 ON_Layer& layer = model.m_layer_table[i];
4354 if ( layer.LayerIndex() != i )
4355 {
4356 if ( text_log )
4357 {
4358 text_log->Print("m_layer_table[%d].LayerIndex() == %d (should be %d)\n",
4359 i,layer.LayerIndex(),i);
4360 }
4361 if ( bAttemptRepair )
4362 {
4363 layer.SetLayerIndex(i);
4364 if ( text_log )
4365 {
4366 text_log->PushIndent();
4367 text_log->Print("Repaired.\n");
4368 text_log->PopIndent();
4369 }
4370 if ( repair_count )
4371 *repair_count += 1;
4372 }
4373 else
4374 {
4375 rc = -1;
4376 }
4377 }
4378
4379 const wchar_t* layer_name = layer.LayerName();
4380
4381 if ( 0 == layer_name || 0 == layer_name[0] )
4382 {
4383 if ( text_log )
4384 {
4385 text_log->Print("m_layer_table[%d].LayerName() is empty\n",i);
4386 }
4387 if ( bAttemptRepair )
4388 {
4389 ON_wString name;
4390 model.GetUnusedLayerName( name );
4391 layer.SetLayerName( name );
4392 if ( text_log )
4393 {
4394 text_log->PushIndent();
4395 text_log->Print("Repaired.\n");
4396 text_log->PopIndent();
4397 }
4398 if ( repair_count )
4399 *repair_count += 1;
4400 layer_name = layer.LayerName();
4401 }
4402 else if ( rc == 0 )
4403 {
4404 rc = 2;
4405 }
4406 }
4407
4408 if ( !ONX_IsValidName(layer_name) )
4409 {
4410 if ( text_log )
4411 {
4412 text_log->Print("m_layer_table[%d].LayerName() is not valid\n",i);
4413 }
4414 if ( bAttemptRepair )
4415 {
4416 ON_wString name;
4417 model.GetUnusedLayerName( name );
4418 layer.SetLayerName( name );
4419 if ( text_log )
4420 {
4421 text_log->PushIndent();
4422 text_log->Print("Repaired.\n");
4423 text_log->PopIndent();
4424 }
4425 if ( repair_count )
4426 *repair_count += 1;
4427 layer_name = layer.LayerName();
4428 }
4429 else if ( rc == 0 )
4430 {
4431 rc = 2;
4432 }
4433 }
4434
4435 int j = model.LayerIndex(layer_name);
4436 if ( i != j )
4437 {
4438 if ( text_log )
4439 {
4440 text_log->Print("m_layer_table[%d] and m_layer_table[%d] have same layer name.\n",i,j);
4441 }
4442 if ( bAttemptRepair )
4443 {
4444 ON_wString name;
4445 model.GetUnusedLayerName( name );
4446 layer.SetLayerName( name );
4447 if ( text_log )
4448 {
4449 text_log->PushIndent();
4450 text_log->Print("Repaired.\n");
4451 text_log->PopIndent();
4452 }
4453 if ( repair_count )
4454 *repair_count += 1;
4455 }
4456 else if ( rc == 0 )
4457 {
4458 rc = 2;
4459 }
4460 }
4461
4462 if ( rc == 0 && !layer.IsValid(text_log) )
4463 rc = 2;
4464 }
4465 return rc;
4466 }
4467
AuditIdsHelper(ON_SimpleArray<ON_UuidIndex> & id_list,ON_UuidIndexList * index_list,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log,const char * nil_id_msg,const char * dup_id_msg)4468 static int AuditIdsHelper(
4469 ON_SimpleArray<ON_UuidIndex>& id_list,
4470 ON_UuidIndexList* index_list,
4471 bool bAttemptRepair,
4472 int* repair_count,
4473 ON_TextLog* text_log,
4474 const char* nil_id_msg,
4475 const char* dup_id_msg
4476 )
4477 {
4478 int nil_count = 0;
4479 int dup_count = 0;
4480 int rep_count = 0;
4481
4482 if ( index_list )
4483 index_list->Empty();
4484 const int count = id_list.Count();
4485 if ( count > 0 )
4486 {
4487 int i;
4488 ON_UUID id;
4489
4490 // Make sure objects have non-nil ids
4491 for ( i = 0; i < count; i++ )
4492 {
4493 id_list[i].m_i = i;
4494 if ( ON_nil_uuid == id_list[i].m_id )
4495 {
4496 nil_count++;
4497 if ( text_log )
4498 text_log->Print(nil_id_msg,i);
4499
4500 if ( bAttemptRepair )
4501 {
4502 id = ON_nil_uuid;
4503 if ( ON_CreateUuid(id) && !ON_UuidIsNil(id) )
4504 {
4505 id_list[i].m_id = id;
4506 rep_count++;
4507 if ( text_log )
4508 text_log->Print(" Repaired.");
4509 }
4510 }
4511 if ( text_log )
4512 text_log->Print("\n");
4513 }
4514 }
4515
4516 if ( count > 1 )
4517 {
4518 // Make sure objects have unique ids
4519 id_list.QuickSort( ON_UuidIndex::CompareIdAndIndex );
4520 ON_UuidIndex id0 = id_list[0];
4521 for ( i = 1; i < count; i++ )
4522 {
4523 if ( ON_nil_uuid == id_list[i].m_id )
4524 {
4525 // nil ids were handled and counted above.
4526 // Either repair is false or we are not running
4527 // on Windows and the user supplied ON_CreateUuid
4528 // is returning nil ids.
4529 continue;
4530 }
4531
4532 if ( id_list[i].m_id == id0.m_id )
4533 {
4534 dup_count++;
4535 if ( text_log )
4536 text_log->Print(dup_id_msg,id0.m_i,id_list[i].m_i);
4537
4538 if ( bAttemptRepair )
4539 {
4540 // fix duplicate object id
4541 id = ON_nil_uuid;
4542 if ( ON_CreateUuid(id) && !ON_UuidIsNil(id) )
4543 {
4544 rep_count++;
4545 id_list[i].m_id = id;
4546 if ( text_log )
4547 text_log->Print(" Repaired.");
4548 }
4549 }
4550 if ( text_log )
4551 text_log->Print("\n");
4552 }
4553 else
4554 {
4555 id0 = id_list[i];
4556 }
4557 }
4558 }
4559
4560 if ( index_list )
4561 {
4562 // rebuild index_list
4563 index_list->Reserve(count);
4564 for ( i = 0; i < count; i++ )
4565 {
4566 index_list->AddUuidIndex(id_list[i].m_id,id_list[i].m_i,false);
4567 }
4568 }
4569 }
4570
4571 if ( repair_count )
4572 *repair_count = rep_count;
4573
4574 return dup_count + nil_count;
4575 }
4576
AuditObjectIdsHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4577 static int AuditObjectIdsHelper(
4578 ONX_Model& model,
4579 bool bAttemptRepair,
4580 int* repair_count,
4581 ON_TextLog* text_log
4582 )
4583 {
4584 int rc = 0;
4585 const int count = model.m_object_table.Count();
4586 model.m_object_id_index.Empty();
4587 if ( count > 0 )
4588 {
4589 int i;
4590 ON_SimpleArray<ON_UuidIndex> id_list(count);
4591 for ( i = 0; i < count; i++ )
4592 {
4593 id_list.AppendNew().m_id = model.m_object_table[i].m_attributes.m_uuid;
4594 }
4595 rc = AuditIdsHelper(
4596 id_list,
4597 &model.m_object_id_index,
4598 bAttemptRepair,
4599 repair_count,
4600 text_log,
4601 "m_object_table[%d].m_attributes.m_uuid is nil.",
4602 "m_object_table[%d] and [%d] have the same id."
4603 );
4604 if (rc && bAttemptRepair )
4605 {
4606 for ( i = 0; i < count; i++ )
4607 {
4608 model.m_object_table[id_list[i].m_i].m_attributes.m_uuid = id_list[i].m_id;
4609 }
4610 }
4611 }
4612 return rc;
4613 }
4614
4615
AuditLightIdsHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4616 static int AuditLightIdsHelper(
4617 ONX_Model& model,
4618 bool bAttemptRepair,
4619 int* repair_count,
4620 ON_TextLog* text_log
4621 )
4622 {
4623 int rc = 0;
4624 int mismatch_count = 0;
4625 const int count = model.m_light_table.Count();
4626 if ( count > 0 )
4627 {
4628 int i;
4629 ON_SimpleArray<ON_UuidIndex> id_list(count);
4630 for ( i = 0; i < count; i++ )
4631 {
4632 ONX_Model_RenderLight& light = model.m_light_table[i];
4633 if ( ON_UuidCompare(light.m_light.m_light_id,light.m_attributes.m_uuid) )
4634 {
4635 mismatch_count++;
4636 if ( text_log )
4637 {
4638 text_log->Print("m_light_table[%d] light id and attributes id differ.",i);
4639 }
4640 if ( bAttemptRepair )
4641 {
4642 if ( repair_count )
4643 *repair_count = *repair_count + 1;
4644 if ( ON_nil_uuid == light.m_light.m_light_id )
4645 light.m_light.m_light_id = light.m_attributes.m_uuid;
4646 else
4647 light.m_attributes.m_uuid = light.m_light.m_light_id;
4648 if ( text_log )
4649 text_log->Print(" Repaired.");
4650 }
4651 if ( text_log )
4652 text_log->Print("\n");
4653 }
4654
4655 if ( ON_nil_uuid == light.m_light.m_light_id )
4656 {
4657 id_list.AppendNew().m_id = light.m_attributes.m_uuid;
4658 }
4659 else
4660 {
4661 id_list.AppendNew().m_id = light.m_light.m_light_id;
4662 }
4663 }
4664
4665 rc = AuditIdsHelper(
4666 id_list,
4667 0, // no ONX_Model id index for lights
4668 bAttemptRepair,
4669 repair_count,
4670 text_log,
4671 "m_light_table[%d] light id is nil.",
4672 "m_light_table[%d] and[%d] have the same id."
4673 );
4674
4675 rc += mismatch_count;
4676
4677 if ( rc && bAttemptRepair )
4678 {
4679 for ( i = 0; i < count; i++ )
4680 {
4681 ONX_Model_RenderLight& light = model.m_light_table[id_list[i].m_i];
4682 light.m_light.m_light_id = id_list[i].m_id;
4683 light.m_attributes.m_uuid = light.m_light.m_light_id;
4684 }
4685 }
4686
4687 // make sure light ids are not duplicated in object id list
4688 for ( i = 0; i < count; i++ )
4689 {
4690 ONX_Model_RenderLight& light = model.m_light_table[i];
4691 int oi = -1;
4692 if ( model.m_object_id_index.FindUuid(light.m_light.m_light_id,&oi) )
4693 {
4694 rc++;
4695 if ( text_log )
4696 {
4697 text_log->Print("m_light_table[%d] and m_object_table[%d] have same id.",
4698 i,
4699 oi
4700 );
4701 }
4702 if ( bAttemptRepair )
4703 {
4704 ON_UuidIndex light_id;
4705 memset(&light_id,0,sizeof(light_id));
4706 light_id.m_id = ON_nil_uuid;
4707 light_id.m_i = -1;
4708 if ( ON_CreateUuid(light_id.m_id) && ON_nil_uuid != light_id.m_id )
4709 {
4710 if ( !model.m_object_id_index.FindUuid(light_id.m_id)
4711 && id_list.BinarySearch( &light_id, ON_UuidIndex::CompareId ) < 0
4712 )
4713 {
4714 if ( repair_count )
4715 *repair_count = *repair_count + 1;
4716 light.m_light.m_light_id = light_id.m_id;
4717 light.m_attributes.m_uuid = light.m_light.m_light_id;
4718 if ( text_log )
4719 text_log->Print(" Repaired.");
4720 }
4721 }
4722 }
4723 if ( text_log )
4724 text_log->Print("\n");
4725 }
4726 }
4727 }
4728
4729 return rc;
4730 }
4731
AuditIDefIdsHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4732 static int AuditIDefIdsHelper(
4733 ONX_Model& model,
4734 bool bAttemptRepair,
4735 int* repair_count,
4736 ON_TextLog* text_log
4737 )
4738 {
4739 int rc = 0;
4740 const int count = model.m_idef_table.Count();
4741 model.m_idef_id_index.Empty();
4742 if ( count > 0 )
4743 {
4744 int i;
4745 ON_SimpleArray<ON_UuidIndex> id_list(count);
4746 for ( i = 0; i < count; i++ )
4747 {
4748 id_list.AppendNew().m_id = model.m_idef_table[i].m_uuid;
4749 }
4750 rc = AuditIdsHelper(
4751 id_list,
4752 &model.m_idef_id_index,
4753 bAttemptRepair,
4754 repair_count,
4755 text_log,
4756 "m_idef_table[%d].m_attributes.m_uuid is nil.",
4757 "m_idef_table[%d] and[%d] are the same."
4758 );
4759 if (rc && bAttemptRepair )
4760 {
4761 for ( i = 0; i < count; i++ )
4762 {
4763 model.m_idef_table[id_list[i].m_i].m_uuid = id_list[i].m_id;
4764 }
4765 }
4766 }
4767 return rc;
4768 }
4769
AuditMappingIdsHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4770 static int AuditMappingIdsHelper(
4771 ONX_Model& model,
4772 bool bAttemptRepair,
4773 int* repair_count,
4774 ON_TextLog* text_log
4775 )
4776 {
4777 int rc = 0;
4778 const int count = model.m_mapping_table.Count();
4779 model.m_mapping_id_index.Empty();
4780 if ( count > 0 )
4781 {
4782 int i;
4783 ON_SimpleArray<ON_UuidIndex> id_list(count);
4784 for ( i = 0; i < count; i++ )
4785 {
4786 id_list.AppendNew().m_id = model.m_mapping_table[i].m_mapping_id;
4787 }
4788 rc = AuditIdsHelper(
4789 id_list,
4790 &model.m_mapping_id_index,
4791 bAttemptRepair,
4792 repair_count,
4793 text_log,
4794 "m_mapping_table[%d].m_mapping_id is nil.",
4795 "m_mapping_table[%d] and[%d] are the same."
4796 );
4797 if (rc && bAttemptRepair )
4798 {
4799 for ( i = 0; i < count; i++ )
4800 {
4801 model.m_mapping_table[id_list[i].m_i].m_mapping_id = id_list[i].m_id;
4802 }
4803 }
4804 }
4805 return rc;
4806 }
4807
4808
AuditMaterialIdsHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4809 static int AuditMaterialIdsHelper(
4810 ONX_Model& model,
4811 bool bAttemptRepair,
4812 int* repair_count,
4813 ON_TextLog* text_log
4814 )
4815 {
4816 int rc = 0;
4817 const int count = model.m_material_table.Count();
4818 model.m_material_id_index.Empty();
4819 if ( count > 0 )
4820 {
4821 int i;
4822 ON_SimpleArray<ON_UuidIndex> id_list(count);
4823 for ( i = 0; i < count; i++ )
4824 {
4825 id_list.AppendNew().m_id = model.m_material_table[i].m_material_id;
4826 }
4827 rc = AuditIdsHelper(
4828 id_list,
4829 &model.m_material_id_index,
4830 bAttemptRepair,
4831 repair_count,
4832 text_log,
4833 "m_material_table[%d].m_material_id is nil.",
4834 "m_material_table[%d] and[%d] are the same."
4835 );
4836 if (rc && bAttemptRepair )
4837 {
4838 for ( i = 0; i < count; i++ )
4839 {
4840 model.m_material_table[id_list[i].m_i].m_material_id = id_list[i].m_id;
4841 }
4842 }
4843 }
4844 return rc;
4845 }
4846
AuditModelIdsHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log,ON_SimpleArray<int> * warnings)4847 static int AuditModelIdsHelper(
4848 ONX_Model& model,
4849 bool bAttemptRepair,
4850 int* repair_count,
4851 ON_TextLog* text_log,
4852 ON_SimpleArray<int>* warnings
4853 )
4854 {
4855 int warning_count = 0;
4856 int i;
4857
4858 // object ids
4859 i = AuditObjectIdsHelper(model,bAttemptRepair,repair_count,text_log);
4860 if (i < 0 )
4861 return i;
4862 if (i > 0 )
4863 {
4864 warning_count += i;
4865 if (warnings)
4866 warnings->Append(3);
4867 }
4868
4869 // light ids
4870 i = AuditLightIdsHelper(model,bAttemptRepair,repair_count,text_log);
4871 if (i < 0 )
4872 return i;
4873 if (i > 0 )
4874 {
4875 warning_count += i;
4876 if (warnings)
4877 warnings->Append(15);
4878 }
4879
4880 // idef ids
4881 i = AuditIDefIdsHelper(model,bAttemptRepair,repair_count,text_log);
4882 if (i < 0 )
4883 return i;
4884 if (i > 0 )
4885 {
4886 warning_count += i;
4887 if (warnings)
4888 warnings->Append(12);
4889 }
4890
4891 // mapping ids
4892 i = AuditMappingIdsHelper(model,bAttemptRepair,repair_count,text_log);
4893 if (i < 0 )
4894 return i;
4895 if (i > 0 )
4896 {
4897 warning_count += i;
4898 if (warnings)
4899 warnings->Append(13);
4900 }
4901
4902 // material ids
4903 i = AuditMaterialIdsHelper(model,bAttemptRepair,repair_count,text_log);
4904 if (i < 0 )
4905 return i;
4906 if (i > 0 )
4907 {
4908 warning_count += i;
4909 if (warnings)
4910 warnings->Append(13);
4911 }
4912
4913 return warning_count;
4914 }
4915
AuditIDefTableHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)4916 static int AuditIDefTableHelper(
4917 ONX_Model& model,
4918 bool bAttemptRepair,
4919 int* repair_count,
4920 ON_TextLog* text_log
4921 )
4922 {
4923 int rc = 0;
4924 int i, j, count = model.m_idef_table.Count();
4925
4926 // AuditInstanceDefinitionIds() are already validated/repaired idef ids.
4927
4928 // make sure idef names are empty or valid and unique
4929 for ( i = 0; i < count; i++ )
4930 {
4931 bool idef_ok = true;
4932 ON_InstanceDefinition& idef = model.m_idef_table[i];
4933 const wchar_t* idef_name = idef.Name();
4934 if ( 0 == idef_name )
4935 continue;
4936
4937 if ( !ONX_IsValidName(idef_name) )
4938 {
4939 if ( text_log )
4940 text_log->Print("m_idef_table[%d].Name() = \"%ls\" is not valid.\n",i,idef_name);
4941 idef_ok = false;
4942 }
4943 else
4944 {
4945 j = model.IDefIndex( idef_name );
4946 if ( j != i )
4947 {
4948 if ( text_log )
4949 text_log->Print("m_idef_table[%d].Name() = m_idef_table[%d].Name().\n",i,j);
4950 idef_ok = false;
4951 }
4952 }
4953 if ( bAttemptRepair )
4954 {
4955 ON_wString new_name;
4956 model.GetUnusedIDefName(new_name);
4957 if ( ONX_IsValidName(new_name) && -1 == model.IDefIndex(new_name) )
4958 {
4959 idef.SetName(new_name);
4960 if ( repair_count )
4961 *repair_count = *repair_count + 1;
4962 if ( text_log )
4963 text_log->Print("Repaired.\n");
4964 idef_ok = true;
4965 }
4966 }
4967 if ( !idef_ok && rc == 0 )
4968 {
4969 rc = 5;
4970 }
4971 }
4972
4973 for ( i = 0; i < count; i++ )
4974 {
4975 bool idef_ok = true;
4976 ON_InstanceDefinition& idef = model.m_idef_table[i];
4977
4978 // make sure object uuid's are valid
4979 int k;
4980 j = 0;
4981 for ( j = k = 0; j < idef.m_object_uuid.Count(); k++ )
4982 {
4983 ON_UUID obj_uuid = idef.m_object_uuid[j];
4984 int obj_index = model.ObjectIndex(obj_uuid);
4985 if ( obj_index < 0 )
4986 {
4987 if ( text_log )
4988 text_log->Print("m_idef_table[%d].m_object_uuid[%d] is not an object's uuid.\n",i,k);
4989 if ( bAttemptRepair )
4990 {
4991 idef.m_object_uuid.Remove(j);
4992 if ( repair_count )
4993 *repair_count = *repair_count + 1;
4994 if ( text_log )
4995 text_log->Print("Repaired.\n");
4996 }
4997 else
4998 {
4999 j++;
5000 idef_ok = false;
5001 }
5002 }
5003 else
5004 {
5005 ONX_Model_Object& obj = model.m_object_table[obj_index];
5006 if ( ON::idef_object != obj.m_attributes.Mode() )
5007 {
5008 if ( text_log )
5009 text_log->Print("Object with uuid m_idef_table[%d].m_object_uuid[%d] does not have m_attributes.Mode()=ON::idef_object.\n",i,k);
5010 if ( bAttemptRepair )
5011 {
5012 idef.m_object_uuid.Remove(j);
5013 if ( repair_count )
5014 *repair_count = *repair_count + 1;
5015 if ( text_log )
5016 text_log->Print("Repaired.\n");
5017 }
5018 else
5019 {
5020 j++;
5021 idef_ok = false;
5022 }
5023 }
5024 else if ( 0 == obj.m_object )
5025 {
5026 if ( text_log )
5027 text_log->Print("Object with uuid m_idef_table[%d].m_object_uuid[%d] has NULL m_object.\n",i,k);
5028 if ( bAttemptRepair )
5029 {
5030 idef.m_object_uuid.Remove(j);
5031 if ( repair_count )
5032 *repair_count = *repair_count + 1;
5033 if ( text_log )
5034 text_log->Print("Repaired.\n");
5035 }
5036 else
5037 {
5038 j++;
5039 idef_ok = false;
5040 }
5041 }
5042 else if ( obj.m_object->ObjectType() == ON::instance_reference )
5043 {
5044 const ON_InstanceRef* pNestedRef = ON_InstanceRef::Cast(obj.m_object);
5045 if ( pNestedRef )
5046 {
5047 if ( model.UsesIDef( *pNestedRef, idef.Uuid() ) )
5048 {
5049 if ( text_log )
5050 text_log->Print("m_idef_table[%d].m_object_uuid[%d] is a circular reference.\n",i,k);
5051 if ( bAttemptRepair )
5052 {
5053 idef.m_object_uuid.Remove(j);
5054 if ( repair_count )
5055 *repair_count = *repair_count + 1;
5056 if ( text_log )
5057 text_log->Print("Repaired.\n");
5058 }
5059 else
5060 {
5061 j++;
5062 idef_ok = false;
5063 rc = -1; // circular reference
5064 }
5065 }
5066 else
5067 j++;
5068 }
5069 else
5070 j++;
5071 }
5072 else
5073 j++;
5074 }
5075 }
5076 if ( idef.m_object_uuid.Count() <= 0 )
5077 {
5078 if ( text_log )
5079 text_log->Print("m_idef_table[%d].m_object_uuid.Count() = 0.\n",i);
5080 idef_ok = false;
5081 }
5082 if ( !idef_ok && rc == 0 )
5083 rc = 6;
5084
5085 }
5086
5087 return rc;
5088 }
5089
5090
AuditObjectTableHelper(ONX_Model & model,bool bAttemptRepair,int * repair_count,ON_TextLog * text_log)5091 static int AuditObjectTableHelper(
5092 ONX_Model& model,
5093 bool bAttemptRepair,
5094 int* repair_count,
5095 ON_TextLog* text_log
5096 )
5097 {
5098 // AuditObjectIds() are already validated/repaired object ids.
5099
5100 int rc = 0;
5101 int i, count = model.m_object_table.Count();
5102
5103 for ( i = 0; i < count; i++ )
5104 {
5105 ONX_Model_Object& obj = model.m_object_table[i];
5106 if ( 0 == obj.m_object )
5107 {
5108 rc = 7;
5109 if ( text_log )
5110 text_log->Print("m_object_table[%d].m_object is NULL.\n",i);
5111 }
5112 else if ( false == obj.m_object->IsValid(NULL) )
5113 {
5114 rc = 8;
5115 if ( text_log )
5116 {
5117 text_log->Print("m_object_table[%d].m_object->IsValid() = false.\n",i);
5118 text_log->PushIndent();
5119 text_log->PushIndent();
5120 obj.m_object->IsValid(text_log);
5121 text_log->PopIndent();
5122 text_log->PopIndent();
5123 }
5124 }
5125
5126 int attrc = AuditObjectAttributesHelper(model,
5127 obj.m_attributes,
5128 "m_object_table[%d].m_attributes",
5129 i,
5130 bAttemptRepair,
5131 repair_count,
5132 text_log
5133 );
5134 if ( 0 == rc && attrc )
5135 rc = attrc;
5136 }
5137
5138 return rc;
5139 }
5140
AuditHistoryRecordTableHelper(ONX_Model &,bool,int *,ON_TextLog *)5141 static int AuditHistoryRecordTableHelper(
5142 ONX_Model&,
5143 bool,
5144 int*,
5145 ON_TextLog*
5146 )
5147 {
5148 // TODO - make sure object id's exist
5149 return 0;
5150 }
5151
Audit(bool bAttemptRepair,int * repair_count,ON_TextLog * text_log,ON_SimpleArray<int> * warnings)5152 int ONX_Model::Audit(
5153 bool bAttemptRepair,
5154 int* repair_count,
5155 ON_TextLog* text_log,
5156 ON_SimpleArray<int>* warnings
5157 )
5158 {
5159 int warning_count = 0;
5160 int rc = 0, i;
5161 int repcnt;
5162 if ( repair_count )
5163 *repair_count = 0;
5164
5165 repcnt = 0;
5166 i = AuditModelIdsHelper( *this, bAttemptRepair, &repcnt, text_log, warnings );
5167 if ( repair_count )
5168 *repair_count += repcnt;
5169 if ( i < 0 )
5170 return i;
5171 warning_count += i;
5172
5173 repcnt = 0;
5174 i = AuditTextureMappingTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5175 if ( repair_count )
5176 *repair_count += repcnt;
5177 if ( i < 0 )
5178 return i;
5179 if ( 0 == rc && 0 != i )
5180 rc = i;
5181
5182 repcnt = 0;
5183 i = AuditMaterialTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5184 if ( repair_count )
5185 *repair_count += repcnt;
5186 if ( i < 0 )
5187 return i;
5188 if ( 0 == rc && 0 != i )
5189 rc = i;
5190
5191 repcnt = 0;
5192 i = AuditLinetypeTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5193 if ( repair_count )
5194 *repair_count += repcnt;
5195 if ( i < 0 )
5196 return i;
5197 if ( 0 == rc && 0 != i )
5198 rc = i;
5199
5200 repcnt = 0;
5201 i = AuditLayerTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5202 if ( repair_count )
5203 *repair_count += repcnt;
5204 if ( i < 0 )
5205 return i;
5206 if ( 0 == rc && 0 != i )
5207 rc = i;
5208
5209 repcnt = 0;
5210 i = AuditGroupTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5211 if ( repair_count )
5212 *repair_count += repcnt;
5213 if ( i < 0 )
5214 return i;
5215 if ( 0 == rc && 0 != i )
5216 rc = i;
5217
5218 repcnt = 0;
5219 i = AuditFontTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5220 if ( repair_count )
5221 *repair_count += repcnt;
5222 if ( i < 0 )
5223 return i;
5224 if ( 0 == rc && 0 != i )
5225 rc = i;
5226
5227 repcnt = 0;
5228 i = AuditDimStyleTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5229 if ( repair_count )
5230 *repair_count += repcnt;
5231 if ( i < 0 )
5232 return i;
5233 if ( 0 == rc && 0 != i )
5234 rc = i;
5235
5236 repcnt = 0;
5237 i = AuditLightTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5238 if ( repair_count )
5239 *repair_count += repcnt;
5240 if ( i < 0 )
5241 return i;
5242 if ( 0 == rc && 0 != i )
5243 rc = i;
5244
5245 repcnt = 0;
5246 i = AuditHatchPatternTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5247 if ( repair_count )
5248 *repair_count += repcnt;
5249 if ( i < 0 )
5250 return i;
5251 if ( 0 == rc && 0 != i )
5252 rc = i;
5253
5254 repcnt = 0;
5255 i = AuditIDefTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5256 if ( repair_count )
5257 *repair_count += repcnt;
5258 if ( i < 0 )
5259 return i;
5260 if ( 0 == rc && 0 != i )
5261 rc = i;
5262
5263 repcnt = 0;
5264 i = AuditObjectTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5265 if ( repair_count )
5266 *repair_count += repcnt;
5267 if ( i < 0 )
5268 return i;
5269 if ( 0 == rc && 0 != i )
5270 rc = i;
5271
5272 repcnt = 0;
5273 i = AuditHistoryRecordTableHelper( *this, bAttemptRepair, &repcnt, text_log );
5274 if ( repair_count )
5275 *repair_count += repcnt;
5276 if ( i < 0 )
5277 return i;
5278 if ( 0 == rc && 0 != i )
5279 rc = i;
5280
5281 return warning_count;
5282 }
5283
RDKObjectUserDataHelper(const ON_UserData * objectud)5284 static const ON_UnknownUserData* RDKObjectUserDataHelper(const ON_UserData* objectud)
5285 {
5286 // CRhRdkUserData object id: AFA82772-1525-43dd-A63C-C84AC5806911
5287 // CRhRdkUserData::m_userdata_uuid = B63ED079-CF67-416c-800D-22023AE1BE21
5288
5289 // CRhRdkUserData object id
5290 // {AFA82772-1525-43dd-A63C-C84AC5806911}
5291 static const ON_UUID CRhRdkUserData_object_id =
5292 { 0xAFA82772, 0x1525, 0x43dd, { 0xA6, 0x3C, 0xC8, 0x4A, 0xC5, 0x80, 0x69, 0x11 } };
5293
5294 // CRhRdkUserData::m_userdata_uuid
5295 // {B63ED079-CF67-416c-800D-22023AE1BE21}
5296 static const ON_UUID CRhRdkUserData_userdata_uuid =
5297 { 0xB63ED079, 0xCF67, 0x416c, { 0x80, 0x0D, 0x22, 0x02, 0x3A, 0xE1, 0xBE, 0x21 } };
5298
5299 const ON_UnknownUserData* unknown_ud = ON_UnknownUserData::Cast(objectud);
5300
5301 bool rc = ( 0 != unknown_ud
5302 && unknown_ud->m_sizeof_buffer > 0
5303 && 0 != unknown_ud->m_buffer
5304 && 0 == ON_UuidCompare(CRhRdkUserData_object_id,unknown_ud->m_unknownclass_uuid)
5305 && 0 == ON_UuidCompare(CRhRdkUserData_userdata_uuid,unknown_ud->m_userdata_uuid)
5306 );
5307 return rc ? unknown_ud : 0;
5308 }
5309
IsRDKObjectInformation(const ON_UserData & objectud)5310 bool ONX_Model::IsRDKObjectInformation(const ON_UserData& objectud)
5311 {
5312 return 0 != RDKObjectUserDataHelper(&objectud);
5313 }
5314
GetRDKObjectInformation(const ON_Object & object,ON_wString & rdk_xml_object_data)5315 bool ONX_Model::GetRDKObjectInformation(const ON_Object& object,ON_wString& rdk_xml_object_data)
5316 {
5317 rdk_xml_object_data.SetLength(0);
5318 const ON_UnknownUserData* unknown_ud = 0;
5319 const ON_UserData* ud = ON_UserData::Cast(&object);
5320 if ( 0 != ud )
5321 {
5322 unknown_ud = RDKObjectUserDataHelper(ud);
5323 }
5324 else
5325 {
5326 for ( ud = object.FirstUserData(); 0 != ud && 0 == unknown_ud; ud = ud->Next() )
5327 {
5328 unknown_ud = RDKObjectUserDataHelper(ud);
5329 }
5330 }
5331
5332 if ( 0 == unknown_ud )
5333 return false;
5334
5335 ON_Read3dmBufferArchive a(unknown_ud->m_sizeof_buffer,unknown_ud->m_buffer,false,unknown_ud->m_3dm_version,unknown_ud->m_3dm_opennurbs_version);
5336 int version = 0;
5337 if (!a.ReadInt(&version) )
5338 return false;
5339
5340 if ( 1 == version )
5341 {
5342 if ( !a.ReadString(rdk_xml_object_data) )
5343 return false;
5344 }
5345 else if ( 2 == version )
5346 {
5347 // UTF8 string
5348 ON_SimpleArray< char > s;
5349 int slen = 0;
5350 if ( !a.ReadInt(&slen) )
5351 return false;
5352 if ( slen <= 0 )
5353 return false;
5354 if ( slen + 4 > unknown_ud->m_sizeof_buffer )
5355 return false;
5356 s.Reserve(slen+1);
5357 s.SetCount(slen+1);
5358 s[slen] = 0;
5359 if ( !a.ReadChar(slen,s.Array() ) )
5360 return false;
5361 const char* sArray = s.Array();
5362 if ( 0 != sArray && 0 != sArray[0] )
5363 {
5364 unsigned int error_status = 0;
5365 int wLen = ON_ConvertUTF8ToWideChar(sArray,-1,0,0,&error_status,0,0,0);
5366 if ( wLen > 0 && 0 == error_status )
5367 {
5368 rdk_xml_object_data.SetLength(wLen+2);
5369 wLen = ON_ConvertUTF8ToWideChar(sArray,-1,rdk_xml_object_data.Array(),wLen+1,&error_status,0,0,0);
5370 if ( wLen > 0 && 0 == error_status )
5371 rdk_xml_object_data.SetLength(wLen);
5372 else
5373 rdk_xml_object_data.SetLength(0);
5374 }
5375 if ( 0 != error_status )
5376 {
5377 ON_ERROR("RDK xml object information is not a valid UTF-8 string.");
5378 }
5379 }
5380 }
5381
5382 return rdk_xml_object_data.Length() > 0;
5383 }
5384
IsRDKDocumentInformation(const ONX_Model_UserData & docud)5385 bool ONX_Model::IsRDKDocumentInformation(const ONX_Model_UserData& docud)
5386 {
5387 // {16592D58-4A2F-401D-BF5E-3B87741C1B1B}
5388 static const ON_UUID rdk_plugin_id =
5389 { 0x16592D58, 0x4A2F, 0x401D, { 0xBF, 0x5E, 0x3B, 0x87, 0x74, 0x1C, 0x1B, 0x1B } };
5390
5391 return ( 0 == ON_UuidCompare(rdk_plugin_id,docud.m_uuid) && docud.m_goo.m_value >= 4 && 0 != docud.m_goo.m_goo );
5392 }
5393
5394
GetRDKDocumentInformation(const ONX_Model_UserData & docud,ON_wString & rdk_xml_document_data)5395 bool ONX_Model::GetRDKDocumentInformation(const ONX_Model_UserData& docud,ON_wString& rdk_xml_document_data)
5396 {
5397 if ( !ONX_Model::IsRDKDocumentInformation(docud) )
5398 return false;
5399
5400 ON_Read3dmBufferArchive a(docud.m_goo.m_value,docud.m_goo.m_goo,false,docud.m_usertable_3dm_version,docud.m_usertable_opennurbs_version);
5401
5402 int version = 0;
5403 if (!a.ReadInt(&version) )
5404 return false;
5405
5406 if ( 1 == version )
5407 {
5408 // UTF-16 string
5409 if ( !a.ReadString(rdk_xml_document_data) )
5410 return false;
5411 }
5412 else if ( 3 == version )
5413 {
5414 // UTF-8 string
5415 int slen = 0;
5416 if ( !a.ReadInt(&slen) )
5417 return 0;
5418 if ( slen <= 0 )
5419 return 0;
5420 if ( slen + 4 > docud.m_goo.m_value )
5421 return 0;
5422 ON_String s;
5423 s.SetLength(slen);
5424 if ( !a.ReadChar(slen,s.Array()) )
5425 return 0;
5426 const char* sArray = s.Array();
5427 if ( 0 != sArray && 0 != sArray[0] )
5428 {
5429 unsigned int error_status = 0;
5430 int wLen = ON_ConvertUTF8ToWideChar(sArray,-1,0,0,&error_status,0,0,0);
5431 if ( wLen > 0 && 0 == error_status )
5432 {
5433 rdk_xml_document_data.SetLength(wLen+2);
5434 wLen = ON_ConvertUTF8ToWideChar(sArray,-1,rdk_xml_document_data.Array(),wLen+1,&error_status,0,0,0);
5435 if ( wLen > 0 && 0 == error_status )
5436 rdk_xml_document_data.SetLength(wLen);
5437 else
5438 {
5439 rdk_xml_document_data.SetLength(0);
5440 }
5441 }
5442 if ( 0 != error_status )
5443 {
5444 ON_ERROR("RDK xml document settings is not a valid UTF-8 string.");
5445 }
5446 }
5447 }
5448
5449 return rdk_xml_document_data.Length() > 0;
5450 }
5451
5452 #if defined(ON_COMPILER_MSC)
5453 #pragma warning( pop )
5454 #endif
5455