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