KiCad PCB EDA Suite
loadmodel.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
5  * Copyright (C) 2020 KiCad Developers, see CHANGELOG.TXT for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <iostream>
26 #include <fstream>
27 #include <sstream>
28 #include <string>
29 #include <cstring>
30 #include <map>
31 #include <vector>
32 #include <wx/filename.h>
33 #include <wx/stdpaths.h>
34 #include <wx/string.h>
35 #include <wx/utils.h>
36 #include <wx/wfstream.h>
37 #include <wx/zipstrm.h>
38 
39 #include <decompress.hpp>
40 
41 #include <TDocStd_Document.hxx>
42 #include <TopoDS.hxx>
43 #include <TopoDS_Shape.hxx>
44 #include <Quantity_Color.hxx>
45 #include <XCAFApp_Application.hxx>
46 
47 #include <AIS_Shape.hxx>
48 
49 #include <IGESControl_Reader.hxx>
50 #include <IGESCAFControl_Reader.hxx>
51 #include <Interface_Static.hxx>
52 
53 #include <STEPControl_Reader.hxx>
54 #include <STEPCAFControl_Reader.hxx>
55 
56 #include <XCAFDoc_DocumentTool.hxx>
57 #include <XCAFDoc_ColorTool.hxx>
58 #include <XCAFDoc_ShapeTool.hxx>
59 
60 #include <BRep_Tool.hxx>
61 #include <BRepMesh_IncrementalMesh.hxx>
62 
63 #include <TopoDS.hxx>
64 #include <TopoDS_Shape.hxx>
65 #include <TopoDS_Face.hxx>
66 #include <TopoDS_Compound.hxx>
67 #include <TopExp_Explorer.hxx>
68 
69 #include <Quantity_Color.hxx>
70 #include <Poly_Triangulation.hxx>
71 #include <Poly_PolygonOnTriangulation.hxx>
72 #include <Precision.hxx>
73 
74 #include <TDF_LabelSequence.hxx>
75 #include <TDF_ChildIterator.hxx>
76 
77 #include "plugins/3dapi/ifsg_all.h"
78 
79 // log mask for wxLogTrace
80 #define MASK_OCE "PLUGIN_OCE"
81 
82 // precision for mesh creation; 0.07 should be good enough for ECAD viewing
83 #define USER_PREC (0.14)
84 
85 // angular deflection for meshing
86 // 10 deg (36 faces per circle) = 0.17453293
87 // 20 deg (18 faces per circle) = 0.34906585
88 // 30 deg (12 faces per circle) = 0.52359878
89 #define USER_ANGLE (0.52359878)
90 
91 typedef std::map< Standard_Real, SGNODE* > COLORMAP;
92 typedef std::map< std::string, SGNODE* > FACEMAP;
93 typedef std::map< std::string, std::vector< SGNODE* > > NODEMAP;
94 typedef std::pair< std::string, std::vector< SGNODE* > > NODEITEM;
95 
96 struct DATA;
97 
98 bool processNode( const TopoDS_Shape& shape, DATA& data, SGNODE* parent,
99  std::vector< SGNODE* >* items );
100 
101 bool processComp( const TopoDS_Shape& shape, DATA& data, SGNODE* parent,
102  std::vector< SGNODE* >* items );
103 
104 bool processFace( const TopoDS_Face& face, DATA& data, SGNODE* parent,
105  std::vector< SGNODE* >* items, Quantity_Color* color );
106 
107 struct DATA
108 {
109  Handle( TDocStd_Document ) m_doc;
110  Handle( XCAFDoc_ColorTool ) m_color;
111  Handle( XCAFDoc_ShapeTool ) m_assy;
114  Quantity_Color refColor;
115  NODEMAP shapes; // SGNODE lists representing a TopoDS_SOLID / COMPOUND
116  COLORMAP colors; // SGAPPEARANCE nodes
117  FACEMAP faces; // SGSHAPE items representing a TopoDS_FACE
118  bool renderBoth; // set TRUE if we're processing IGES
119  bool hasSolid; // set TRUE if there is no parent SOLID
120 
122  {
123  scene = NULL;
124  defaultColor = NULL;
125  refColor.SetValues( Quantity_NOC_BLACK );
126  renderBoth = false;
127  hasSolid = false;
128  }
129 
131  {
132  // destroy any colors with no parent
133  if( !colors.empty() )
134  {
135  COLORMAP::iterator sC = colors.begin();
136  COLORMAP::iterator eC = colors.end();
137 
138  while( sC != eC )
139  {
140  if( NULL == S3D::GetSGNodeParent( sC->second ) )
141  S3D::DestroyNode( sC->second );
142 
143  ++sC;
144  }
145 
146  colors.clear();
147  }
148 
151 
152  // destroy any faces with no parent
153  if( !faces.empty() )
154  {
155  FACEMAP::iterator sF = faces.begin();
156  FACEMAP::iterator eF = faces.end();
157 
158  while( sF != eF )
159  {
160  if( NULL == S3D::GetSGNodeParent( sF->second ) )
161  S3D::DestroyNode( sF->second );
162 
163  ++sF;
164  }
165 
166  faces.clear();
167  }
168 
169  // destroy any shapes with no parent
170  if( !shapes.empty() )
171  {
172  NODEMAP::iterator sS = shapes.begin();
173  NODEMAP::iterator eS = shapes.end();
174 
175  while( sS != eS )
176  {
177  std::vector< SGNODE* >::iterator sV = sS->second.begin();
178  std::vector< SGNODE* >::iterator eV = sS->second.end();
179 
180  while( sV != eV )
181  {
182  if( NULL == S3D::GetSGNodeParent( *sV ) )
183  S3D::DestroyNode( *sV );
184 
185  ++sV;
186  }
187 
188  sS->second.clear();
189  ++sS;
190  }
191 
192  shapes.clear();
193  }
194 
195  if( scene )
197 
198  return;
199  }
200 
201  // find collection of tagged nodes
202  bool GetShape( const std::string& id, std::vector< SGNODE* >*& listPtr )
203  {
204  listPtr = NULL;
205  NODEMAP::iterator item;
206  item = shapes.find( id );
207 
208  if( item == shapes.end() )
209  return false;
210 
211  listPtr = &item->second;
212  return true;
213  }
214 
215  // find collection of tagged nodes
216  SGNODE* GetFace( const std::string& id )
217  {
218  FACEMAP::iterator item;
219  item = faces.find( id );
220 
221  if( item == faces.end() )
222  return NULL;
223 
224  return item->second;
225  }
226 
227  // return color if found; if not found, create SGAPPEARANCE
228  SGNODE* GetColor( Quantity_Color* colorObj )
229  {
230  if( NULL == colorObj )
231  {
232  if( defaultColor )
233  return defaultColor;
234 
235  IFSG_APPEARANCE app( true );
236  app.SetShininess( 0.05f );
237  app.SetSpecular( 0.04f, 0.04f, 0.04f );
238  app.SetAmbient( 0.1f, 0.1f, 0.1f );
239  app.SetDiffuse( 0.6f, 0.6f, 0.6f );
240 
241  defaultColor = app.GetRawPtr();
242  return defaultColor;
243  }
244 
245  Standard_Real id = colorObj->Distance( refColor );
246  std::map< Standard_Real, SGNODE* >::iterator item;
247  item = colors.find( id );
248 
249  if( item != colors.end() )
250  return item->second;
251 
252  IFSG_APPEARANCE app( true );
253  app.SetShininess( 0.1f );
254  app.SetSpecular( 0.12f, 0.12f, 0.12f );
255  app.SetAmbient( 0.1f, 0.1f, 0.1f );
256  app.SetDiffuse( colorObj->Red(), colorObj->Green(), colorObj->Blue() );
257  colors.insert( std::pair< Standard_Real, SGNODE* >( id, app.GetRawPtr() ) );
258 
259  return app.GetRawPtr();
260  }
261 };
262 
263 
265 {
266  FMT_NONE = 0,
270 };
271 
272 
273 FormatType fileType( const char* aFileName )
274 {
275  wxFileName fname( wxString::FromUTF8Unchecked( aFileName ) );
276  wxFFileInputStream ifile( fname.GetFullPath() );
277 
278  if( !ifile.IsOk() )
279  return FMT_NONE;
280 
281  if( fname.GetExt().MakeUpper().EndsWith( "STPZ" ) ||
282  fname.GetExt().MakeUpper().EndsWith( "GZ" ) )
283  return FMT_STPZ;
284 
285  char iline[82];
286  memset( iline, 0, 82 );
287  ifile.Read( iline, 82 );
288  iline[81] = 0; // ensure NULL termination when string is too long
289 
290  // check for STEP in Part 21 format
291  // (this can give false positives since Part 21 is not exclusively STEP)
292  if( !strncmp( iline, "ISO-10303-21;", 13 ) )
293  return FMT_STEP;
294 
295  std::string fstr = iline;
296 
297  // check for STEP in XML format
298  // (this can give both false positive and false negatives)
299  if( fstr.find( "urn:oid:1.0.10303." ) != std::string::npos )
300  return FMT_STEP;
301 
302  // Note: this is a very simple test which can yield false positives; the only
303  // sure method for determining if a file *not* an IGES model is to attempt
304  // to load it.
305  if( iline[72] == 'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
306  return FMT_IGES;
307 
308  return FMT_NONE;
309 }
310 
311 
312 void getTag( TDF_Label& label, std::string& aTag )
313 {
314  if( label.IsNull() )
315  return;
316 
317  std::string rtag; // tag in reverse
318  aTag.clear();
319  int id = label.Tag();
320  std::ostringstream ostr;
321  ostr << id;
322  rtag = ostr.str();
323  ostr.str( "" );
324  ostr.clear();
325 
326  TDF_Label nlab = label.Father();
327 
328  while( !nlab.IsNull() )
329  {
330  rtag.append( 1, ':' );
331  id = nlab.Tag();
332  ostr << id;
333  rtag.append( ostr.str() );
334  ostr.str( "" );
335  ostr.clear();
336  nlab = nlab.Father();
337  };
338 
339  std::string::reverse_iterator bI = rtag.rbegin();
340  std::string::reverse_iterator eI = rtag.rend();
341 
342  while( bI != eI )
343  {
344  aTag.append( 1, *bI );
345  ++bI;
346  }
347 
348  return;
349 }
350 
351 
352 bool getColor( DATA& data, TDF_Label label, Quantity_Color& color )
353 {
354  while( true )
355  {
356  if( data.m_color->GetColor( label, XCAFDoc_ColorGen, color ) )
357  return true;
358  else if( data.m_color->GetColor( label, XCAFDoc_ColorSurf, color ) )
359  return true;
360  else if( data.m_color->GetColor( label, XCAFDoc_ColorCurv, color ) )
361  return true;
362 
363  label = label.Father();
364 
365  if( label.IsNull() )
366  break;
367  };
368 
369  return false;
370 }
371 
372 
373 void addItems( SGNODE* parent, std::vector< SGNODE* >* lp )
374 {
375  if( NULL == lp )
376  return;
377 
378  std::vector< SGNODE* >::iterator sL = lp->begin();
379  std::vector< SGNODE* >::iterator eL = lp->end();
380  SGNODE* item;
381 
382  while( sL != eL )
383  {
384  item = *sL;
385 
386  if( NULL == S3D::GetSGNodeParent( item ) )
387  S3D::AddSGNodeChild( parent, item );
388  else
389  S3D::AddSGNodeRef( parent, item );
390 
391  ++sL;
392  }
393 
394  return;
395 }
396 
397 
398 bool readIGES( Handle(TDocStd_Document)& m_doc, const char* fname )
399 {
400  IGESCAFControl_Reader reader;
401  IFSelect_ReturnStatus stat = reader.ReadFile( fname );
402  reader.PrintCheckLoad( Standard_False, IFSelect_ItemsByEntity );
403 
404  if( stat != IFSelect_RetDone )
405  return false;
406 
407  // Enable file-defined shape precision
408  if( !Interface_Static::SetIVal( "read.precision.mode", 0 ) )
409  return false;
410 
411  // set other translation options
412  reader.SetColorMode(true); // use model colors
413  reader.SetNameMode(false); // don't use IGES label names
414  reader.SetLayerMode(false); // ignore LAYER data
415 
416  if ( !reader.Transfer( m_doc ) )
417  return false;
418 
419  // are there any shapes to translate?
420  if( reader.NbShapes() < 1 )
421  return false;
422 
423  return true;
424 }
425 
426 
427 bool readSTEP( Handle(TDocStd_Document)& m_doc, const char* fname )
428 {
429  STEPCAFControl_Reader reader;
430  IFSelect_ReturnStatus stat = reader.ReadFile( fname );
431 
432  if( stat != IFSelect_RetDone )
433  return false;
434 
435  // Enable user-defined shape precision
436  if( !Interface_Static::SetIVal( "read.precision.mode", 1 ) )
437  return false;
438 
439  // Set the shape conversion precision to USER_PREC (default 0.0001 has too many triangles)
440  if( !Interface_Static::SetRVal( "read.precision.val", USER_PREC ) )
441  return false;
442 
443  // set other translation options
444  reader.SetColorMode(true); // use model colors
445  reader.SetNameMode(false); // don't use label names
446  reader.SetLayerMode(false); // ignore LAYER data
447 
448  if ( !reader.Transfer( m_doc ) )
449  {
450  m_doc->Close();
451  return false;
452  }
453 
454  // are there any shapes to translate?
455  if( reader.NbRootsForTransfer() < 1 )
456  return false;
457 
458  return true;
459 }
460 
461 
462 bool readSTEPZ( Handle(TDocStd_Document)& m_doc, const char* aFileName )
463 {
464  wxFileName fname( wxString::FromUTF8Unchecked( aFileName ) );
465  wxFFileInputStream ifile( fname.GetFullPath() );
466 
467  wxFileName outFile( fname );
468 
469  outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
470  outFile.SetExt( "STEP" );
471 
472  wxFileOffset size = ifile.GetLength();
473  wxBusyCursor busycursor;
474 
475  if( size == wxInvalidOffset )
476  return false;
477 
478  {
479  bool success = false;
480  wxFFileOutputStream ofile( outFile.GetFullPath() );
481 
482  if( !ofile.IsOk() )
483  return false;
484 
485  char *buffer = new char[size];
486 
487  ifile.Read( buffer, size);
488  std::string expanded;
489 
490  try
491  {
492  expanded = gzip::decompress( buffer, size );
493  success = true;
494  }
495  catch(...)
496  {}
497 
498  if( expanded.empty() )
499  {
500  ifile.Reset();
501  ifile.SeekI( 0 );
502  wxZipInputStream izipfile( ifile );
503  std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
504 
505  if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
506  {
507  izipfile.Read( ofile );
508  success = true;
509  }
510  }
511  else
512  {
513  ofile.Write( expanded.data(), expanded.size() );
514  }
515 
516  delete[] buffer;
517  ofile.Close();
518 
519  if( !success )
520  return false;
521  }
522 
523  bool retval = readSTEP( m_doc, outFile.GetFullPath().mb_str() );
524 
525  // Cleanup our temporary file
526  wxRemoveFile( outFile.GetFullPath() );
527 
528  return retval;
529 }
530 
531 
532 SCENEGRAPH* LoadModel( char const* filename )
533 {
534  DATA data;
535 
536  Handle(XCAFApp_Application) m_app = XCAFApp_Application::GetApplication();
537  m_app->NewDocument( "MDTV-XCAF", data.m_doc );
538  FormatType modelFmt = fileType( filename );
539 
540  switch( modelFmt )
541  {
542  case FMT_IGES:
543  data.renderBoth = true;
544 
545  if( !readIGES( data.m_doc, filename ) )
546  return NULL;
547  break;
548 
549  case FMT_STEP:
550  if( !readSTEP( data.m_doc, filename ) )
551  return NULL;
552  break;
553 
554  case FMT_STPZ:
555  if( !readSTEPZ( data.m_doc, filename ) )
556  return NULL;
557  break;
558 
559 
560  default:
561  return NULL;
562  break;
563  }
564 
565  data.m_assy = XCAFDoc_DocumentTool::ShapeTool( data.m_doc->Main() );
566  data.m_color = XCAFDoc_DocumentTool::ColorTool( data.m_doc->Main() );
567 
568  // retrieve all free shapes
569  TDF_LabelSequence frshapes;
570  data.m_assy->GetFreeShapes( frshapes );
571 
572  int nshapes = frshapes.Length();
573  int id = 1;
574  bool ret = false;
575 
576  // create the top level SG node
577  IFSG_TRANSFORM topNode( true );
578  data.scene = topNode.GetRawPtr();
579 
580  while( id <= nshapes )
581  {
582  TopoDS_Shape shape = data.m_assy->GetShape( frshapes.Value(id) );
583 
584  if ( !shape.IsNull() && processNode( shape, data, data.scene, NULL ) )
585  ret = true;
586 
587  ++id;
588  };
589 
590  if( !ret )
591  return NULL;
592 
593  SCENEGRAPH* scene = (SCENEGRAPH*)data.scene;
594 
595  // DEBUG: WRITE OUT VRML2 FILE TO CONFIRM STRUCTURE
596  #if ( defined( DEBUG_OCE ) && DEBUG_OCE > 3 )
597  if( data.scene )
598  {
599  wxFileName fn( wxString::FromUTF8Unchecked( filename ) );
600  wxString output;
601 
602  if( FMT_STEP == modelFmt )
603  output = wxT( "_step-" );
604  else
605  output = wxT( "_iges-" );
606 
607  output.append( fn.GetName() );
608  output.append( wxT(".wrl") );
609  S3D::WriteVRML( output.ToUTF8(), true, data.scene, true, true );
610  }
611  #endif
612 
613  // set to NULL to prevent automatic destruction of the scene data
614  data.scene = NULL;
615 
616  return scene;
617 }
618 
619 
620 bool processShell( const TopoDS_Shape& shape, DATA& data, SGNODE* parent,
621  std::vector< SGNODE* >* items, Quantity_Color* color )
622 {
623  TopoDS_Iterator it;
624  bool ret = false;
625 
626  for( it.Initialize( shape, false, false ); it.More(); it.Next() )
627  {
628  const TopoDS_Face& face = TopoDS::Face( it.Value() );
629 
630  if( processFace( face, data, parent, items, color ) )
631  ret = true;
632  }
633 
634  return ret;
635 }
636 
637 
638 bool processSolid( const TopoDS_Shape& shape, DATA& data, SGNODE* parent,
639  std::vector< SGNODE* >* items )
640 {
641  TDF_Label label;
642  data.hasSolid = true;
643  std::string partID;
644  Quantity_Color col;
645  Quantity_Color* lcolor = NULL;
646 
647  // Search the whole model first to make sure something exists (may or may not have color)
648  if( !data.m_assy->Search( shape, label ) )
649  {
650  static int i = 0;
651  std::ostringstream ostr;
652  ostr << "KMISC_" << i++;
653  partID = ostr.str();
654  }
655  else
656  {
657  bool found_color = false;
658 
659  if( getColor( data, label, col ) )
660  {
661  found_color = true;
662  lcolor = &col;
663  }
664 
665  // If the top-level label doesn't have the color information, search components
666  if( !found_color )
667  {
668  if( data.m_assy->Search( shape, label, Standard_False, Standard_True, Standard_True ) &&
669  getColor( data, label, col ) )
670  {
671  found_color = true;
672  lcolor = &col;
673  }
674  }
675 
676  // If the components do not have color information, search all components without location
677  if( !found_color )
678  {
679  if( data.m_assy->Search( shape, label, Standard_False, Standard_False, Standard_True ) &&
680  getColor( data, label, col ) )
681  {
682  found_color = true;
683  lcolor = &col;
684  }
685  }
686 
687  // Our last chance to find the color looks for color as a subshape of top-level simple shapes
688  if( !found_color )
689  {
690  if( data.m_assy->Search( shape, label, Standard_False, Standard_False, Standard_False ) &&
691  getColor( data, label, col ) )
692  {
693  found_color = true;
694  lcolor = &col;
695  }
696  }
697 
698  getTag( label, partID );
699  }
700 
701  TopoDS_Iterator it;
702  IFSG_TRANSFORM childNode( parent );
703  SGNODE* pptr = childNode.GetRawPtr();
704  const TopLoc_Location& loc = shape.Location();
705  bool ret = false;
706 
707  if( !loc.IsIdentity() )
708  {
709  gp_Trsf T = loc.Transformation();
710  gp_XYZ coord = T.TranslationPart();
711  childNode.SetTranslation( SGPOINT( coord.X(), coord.Y(), coord.Z() ) );
712  gp_XYZ axis;
713  Standard_Real angle;
714 
715  if( T.GetRotation( axis, angle ) )
716  childNode.SetRotation( SGVECTOR( axis.X(), axis.Y(), axis.Z() ), angle );
717  }
718 
719  std::vector< SGNODE* >* component = NULL;
720 
721  if( !partID.empty() )
722  data.GetShape( partID, component );
723 
724  if( component )
725  {
726  addItems( pptr, component );
727 
728  if( NULL != items )
729  items->push_back( pptr );
730  }
731 
732  // instantiate the solid
733  std::vector< SGNODE* > itemList;
734 
735  for( it.Initialize( shape, false, false ); it.More(); it.Next() )
736  {
737  const TopoDS_Shape& subShape = it.Value();
738 
739  if( processShell( subShape, data, pptr, &itemList, lcolor ) )
740  ret = true;
741  }
742 
743  if( !ret )
744  childNode.Destroy();
745  else if( NULL != items )
746  items->push_back( pptr );
747 
748  return ret;
749 }
750 
751 
752 bool processComp( const TopoDS_Shape& shape, DATA& data, SGNODE* parent,
753  std::vector< SGNODE* >* items )
754 {
755  TopoDS_Iterator it;
756  IFSG_TRANSFORM childNode( parent );
757  SGNODE* pptr = childNode.GetRawPtr();
758  const TopLoc_Location& loc = shape.Location();
759  bool ret = false;
760 
761  if( !loc.IsIdentity() )
762  {
763  gp_Trsf T = loc.Transformation();
764  gp_XYZ coord = T.TranslationPart();
765  childNode.SetTranslation( SGPOINT( coord.X(), coord.Y(), coord.Z() ) );
766  gp_XYZ axis;
767  Standard_Real angle;
768 
769  if( T.GetRotation( axis, angle ) )
770  childNode.SetRotation( SGVECTOR( axis.X(), axis.Y(), axis.Z() ), angle );
771  }
772 
773  for( it.Initialize( shape, false, false ); it.More(); it.Next() )
774  {
775  const TopoDS_Shape& subShape = it.Value();
776  TopAbs_ShapeEnum stype = subShape.ShapeType();
777  data.hasSolid = false;
778 
779  switch( stype )
780  {
781  case TopAbs_COMPOUND:
782  case TopAbs_COMPSOLID:
783  if( processComp( subShape, data, pptr, items ) )
784  ret = true;
785  break;
786 
787  case TopAbs_SOLID:
788  if( processSolid( subShape, data, pptr, items ) )
789  ret = true;
790  break;
791 
792  case TopAbs_SHELL:
793  if( processShell( subShape, data, pptr, items, NULL ) )
794  ret = true;
795  break;
796 
797  case TopAbs_FACE:
798  if( processFace( TopoDS::Face( subShape ), data, pptr, items, NULL ) )
799  ret = true;
800  break;
801 
802  default:
803  break;
804  }
805  }
806 
807  if( !ret )
808  childNode.Destroy();
809  else if( NULL != items )
810  items->push_back( pptr );
811 
812  return ret;
813 }
814 
815 
816 bool processNode( const TopoDS_Shape& shape, DATA& data, SGNODE* parent,
817  std::vector< SGNODE* >* items )
818 {
819  TopAbs_ShapeEnum stype = shape.ShapeType();
820  bool ret = false;
821  data.hasSolid = false;
822 
823  switch( stype )
824  {
825  case TopAbs_COMPOUND:
826  case TopAbs_COMPSOLID:
827  if( processComp( shape, data, parent, items ) )
828  ret = true;
829  break;
830 
831  case TopAbs_SOLID:
832  if( processSolid( shape, data, parent, items ) )
833  ret = true;
834  break;
835 
836  case TopAbs_SHELL:
837  if( processShell( shape, data, parent, items, NULL ) )
838  ret = true;
839  break;
840 
841  case TopAbs_FACE:
842  if( processFace( TopoDS::Face( shape ), data, parent, items, NULL ) )
843  ret = true;
844  break;
845 
846  default:
847  break;
848  }
849 
850  return ret;
851 }
852 
853 
854 bool processFace( const TopoDS_Face& face, DATA& data, SGNODE* parent,
855  std::vector< SGNODE* >* items, Quantity_Color* color )
856 {
857  if( Standard_True == face.IsNull() )
858  return false;
859 
860  bool reverse = ( face.Orientation() == TopAbs_REVERSED );
861  SGNODE* ashape = NULL;
862  std::string partID;
863  TDF_Label label;
864 
865  bool useBothSides = false;
866 
867  // for IGES renderBoth = TRUE; for STEP if a shell or face is not a descendant
868  // of a SOLID then hasSolid = false and we must render both sides
869  if( data.renderBoth || !data.hasSolid )
870  useBothSides = true;
871 
872  if( data.m_assy->FindShape( face, label, Standard_False ) )
873  getTag( label, partID );
874 
875  if( !partID.empty() )
876  ashape = data.GetFace( partID );
877 
878  if( ashape )
879  {
880  if( NULL == S3D::GetSGNodeParent( ashape ) )
881  S3D::AddSGNodeChild( parent, ashape );
882  else
883  S3D::AddSGNodeRef( parent, ashape );
884 
885  if( NULL != items )
886  items->push_back( ashape );
887 
888  if( useBothSides )
889  {
890  std::string id2 = partID;
891  id2.append( "b" );
892  SGNODE* shapeB = data.GetFace( id2 );
893 
894  if( NULL == S3D::GetSGNodeParent( shapeB ) )
895  S3D::AddSGNodeChild( parent, shapeB );
896  else
897  S3D::AddSGNodeRef( parent, shapeB );
898 
899  if( NULL != items )
900  items->push_back( shapeB );
901  }
902 
903  return true;
904  }
905 
906  TopLoc_Location loc;
907  Standard_Boolean isTessellate (Standard_False);
908  Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation( face, loc );
909 
910  if( triangulation.IsNull() || triangulation->Deflection() > USER_PREC + Precision::Confusion() )
911  isTessellate = Standard_True;
912 
913  if (isTessellate)
914  {
915  BRepMesh_IncrementalMesh IM(face, USER_PREC, Standard_False, USER_ANGLE );
916  triangulation = BRep_Tool::Triangulation( face, loc );
917  }
918 
919  if( triangulation.IsNull() == Standard_True )
920  return false;
921 
922  Quantity_Color lcolor;
923 
924  // check for a face color; this has precedence over SOLID colors
925  do
926  {
927  TDF_Label L;
928 
929  if( data.m_color->ShapeTool()->Search( face, L ) )
930  {
931  if( data.m_color->GetColor( L, XCAFDoc_ColorGen, lcolor )
932  || data.m_color->GetColor( L, XCAFDoc_ColorCurv, lcolor )
933  || data.m_color->GetColor( L, XCAFDoc_ColorSurf, lcolor ) )
934  color = &lcolor;
935  }
936  } while( 0 );
937 
938  SGNODE* ocolor = data.GetColor( color );
939 
940  // create a SHAPE and attach the color and data,
941  // then attach the shape to the parent and return TRUE
942  IFSG_SHAPE vshape( true );
943  IFSG_FACESET vface( vshape );
944  IFSG_COORDS vcoords( vface );
945  IFSG_COORDINDEX coordIdx( vface );
946 
947  if( NULL == S3D::GetSGNodeParent( ocolor ) )
948  S3D::AddSGNodeChild( vshape.GetRawPtr(), ocolor );
949  else
950  S3D::AddSGNodeRef( vshape.GetRawPtr(), ocolor );
951 
952  const TColgp_Array1OfPnt& arrPolyNodes = triangulation->Nodes();
953  const Poly_Array1OfTriangle& arrTriangles = triangulation->Triangles();
954 
955  std::vector< SGPOINT > vertices;
956  std::vector< int > indices;
957  std::vector< int > indices2;
958  gp_Trsf tx;
959 
960  for(int i = 1; i <= triangulation->NbNodes(); i++)
961  {
962  gp_XYZ v( arrPolyNodes(i).Coord() );
963  vertices.emplace_back( v.X(), v.Y(), v.Z() );
964  }
965 
966  for(int i = 1; i <= triangulation->NbTriangles(); i++)
967  {
968  int a, b, c;
969  arrTriangles( i ).Get( a, b, c );
970  a--;
971 
972  if( reverse )
973  {
974  int tmp = b - 1;
975  b = c - 1;
976  c = tmp;
977  } else {
978  b--;
979  c--;
980  }
981 
982  indices.push_back( a );
983  indices.push_back( b );
984  indices.push_back( c );
985 
986  if( useBothSides )
987  {
988  indices2.push_back( b );
989  indices2.push_back( a );
990  indices2.push_back( c );
991  }
992  }
993 
994  vcoords.SetCoordsList( vertices.size(), &vertices[0] );
995  coordIdx.SetIndices( indices.size(), &indices[0] );
996  vface.CalcNormals( NULL );
997  vshape.SetParent( parent );
998 
999  if( !partID.empty() )
1000  data.faces.insert( std::pair< std::string,
1001  SGNODE* >( partID, vshape.GetRawPtr() ) );
1002 
1003  // The outer surface of an IGES model is indeterminate so
1004  // we must render both sides of a surface.
1005  if( useBothSides )
1006  {
1007  std::string id2 = partID;
1008  id2.append( "b" );
1009  IFSG_SHAPE vshape2( true );
1010  IFSG_FACESET vface2( vshape2 );
1011  IFSG_COORDS vcoords2( vface2 );
1012  IFSG_COORDINDEX coordIdx2( vface2 );
1013  S3D::AddSGNodeRef( vshape2.GetRawPtr(), ocolor );
1014 
1015  vcoords2.SetCoordsList( vertices.size(), &vertices[0] );
1016  coordIdx2.SetIndices( indices2.size(), &indices2[0] );
1017  vface2.CalcNormals( NULL );
1018  vshape2.SetParent( parent );
1019 
1020  if( !partID.empty() )
1021  data.faces.insert( std::pair< std::string,
1022  SGNODE* >( id2, vshape2.GetRawPtr() ) );
1023  }
1024 
1025  return true;
1026 }
SGNODE * GetColor(Quantity_Color *colorObj)
Definition: loadmodel.cpp:228
bool readSTEPZ(Handle(TDocStd_Document)&m_doc, const char *aFileName)
Definition: loadmodel.cpp:462
DATA()
Definition: loadmodel.cpp:121
IFSG_COORDS is the wrapper for SGCOORDS.
Definition: ifsg_coords.h:40
IFSG_COORDINDEX is the wrapper for SGCOORDINDEX.
SGNODE * GetFace(const std::string &id)
Definition: loadmodel.cpp:216
FACEMAP faces
Definition: loadmodel.cpp:117
~DATA()
Definition: loadmodel.cpp:130
int color
Definition: DXF_plotter.cpp:60
bool SetDiffuse(float aRVal, float aGVal, float aBVal)
SGLIB_API SGNODE * GetSGNodeParent(SGNODE *aNode)
Definition: ifsg_api.cpp:492
bool processSolid(const TopoDS_Shape &shape, DATA &data, SGNODE *parent, std::vector< SGNODE * > *items)
Definition: loadmodel.cpp:638
bool SetParent(SGNODE *aParent)
Function SetParent sets the parent SGNODE of this object.
Definition: ifsg_node.cpp:87
The base class of all Scene Graph nodes.
Definition: sg_node.h:74
collects header files for all SG* wrappers and the API
COLORMAP colors
Definition: loadmodel.cpp:116
bool readSTEP(Handle(TDocStd_Document)&m_doc, const char *fname)
Definition: loadmodel.cpp:427
bool processNode(const TopoDS_Shape &shape, DATA &data, SGNODE *parent, std::vector< SGNODE * > *items)
Definition: loadmodel.cpp:816
std::pair< std::string, std::vector< SGNODE * > > NODEITEM
Definition: loadmodel.cpp:94
SGNODE * GetRawPtr(void) noexcept
Function GetRawPtr() returns the raw internal SGNODE pointer.
Definition: ifsg_node.cpp:65
SGLIB_API bool AddSGNodeRef(SGNODE *aParent, SGNODE *aChild)
Definition: ifsg_api.cpp:501
std::map< std::string, SGNODE * > FACEMAP
Definition: loadmodel.cpp:92
SGLIB_API bool WriteVRML(const char *filename, bool overwrite, SGNODE *aTopNode, bool reuse, bool renameNodes)
Function WriteVRML writes out the given node and its subnodes to a VRML2 file.
Definition: ifsg_api.cpp:76
std::map< std::string, std::vector< SGNODE * > > NODEMAP
Definition: loadmodel.cpp:93
SGLIB_API void DestroyNode(SGNODE *aNode) noexcept
Function DestroyNode deletes the given SG* class node.
Definition: ifsg_api.cpp:148
#define NULL
bool SetAmbient(float aRVal, float aGVal, float aBVal)
bool processFace(const TopoDS_Face &face, DATA &data, SGNODE *parent, std::vector< SGNODE * > *items, Quantity_Color *color)
Definition: loadmodel.cpp:854
bool readIGES(Handle(TDocStd_Document)&m_doc, const char *fname)
Definition: loadmodel.cpp:398
void getTag(TDF_Label &label, std::string &aTag)
Definition: loadmodel.cpp:312
Quantity_Color refColor
Definition: loadmodel.cpp:114
#define USER_ANGLE
Definition: loadmodel.cpp:89
SGLIB_API bool AddSGNodeChild(SGNODE *aParent, SGNODE *aChild)
Definition: ifsg_api.cpp:510
bool SetRotation(const SGVECTOR &aRotationAxis, double aAngle)
bool getColor(DATA &data, TDF_Label label, Quantity_Color &color)
Definition: loadmodel.cpp:352
FormatType fileType(const char *aFileName)
Definition: loadmodel.cpp:273
bool SetShininess(float aShininess) noexcept
bool CalcNormals(SGNODE **aPtr)
FormatType
Definition: loadmodel.cpp:264
#define USER_PREC
Definition: loadmodel.cpp:83
bool SetIndices(size_t nIndices, int *aIndexList)
Function SetIndices sets the number of indices and creates a copy of the given index data.
Definition: ifsg_index.cpp:47
SCENEGRAPH * LoadModel(char const *filename)
Definition: loadmodel.cpp:532
bool hasSolid
Definition: loadmodel.cpp:119
void addItems(SGNODE *parent, std::vector< SGNODE * > *lp)
Definition: loadmodel.cpp:373
bool SetSpecular(float aRVal, float aGVal, float aBVal)
bool SetCoordsList(size_t aListSize, const SGPOINT *aCoordsList)
SGNODE * scene
Definition: loadmodel.cpp:112
IFSG_FACESET is the wrapper for the SGFACESET class.
Definition: ifsg_faceset.h:40
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
IFSG_TRANSFORM is the wrapper for the VRML compatible TRANSFORM block class SCENEGRAPH.
bool SetTranslation(const SGPOINT &aTranslation) noexcept
SGNODE * defaultColor
Definition: loadmodel.cpp:113
Define the basic data set required to represent a 3D model.
Definition: scenegraph.h:44
Handle(TDocStd_Document) m_doc
void Destroy(void)
Function Destroy deletes the object held by this wrapper.
Definition: ifsg_node.cpp:55
std::map< Standard_Real, SGNODE * > COLORMAP
Definition: loadmodel.cpp:91
NODEMAP shapes
Definition: loadmodel.cpp:115
bool renderBoth
Definition: loadmodel.cpp:118
bool GetShape(const std::string &id, std::vector< SGNODE * > *&listPtr)
Definition: loadmodel.cpp:202
bool processComp(const TopoDS_Shape &shape, DATA &data, SGNODE *parent, std::vector< SGNODE * > *items)
Definition: loadmodel.cpp:752
IFSG_SHAPE is the wrapper for the SGSHAPE class.
Definition: ifsg_shape.h:40
bool processShell(const TopoDS_Shape &shape, DATA &data, SGNODE *parent, std::vector< SGNODE * > *items, Quantity_Color *color)
Definition: loadmodel.cpp:620