35#include <wx/filename.h>
37#include <wx/stdpaths.h>
40#include <wx/wfstream.h>
41#include <wx/zipstrm.h>
44#include <decompress.hpp>
46#include <TDocStd_Document.hxx>
48#include <TopoDS_Shape.hxx>
49#include <Quantity_Color.hxx>
50#include <XCAFApp_Application.hxx>
52#include <AIS_Shape.hxx>
54#include <IGESControl_Reader.hxx>
55#include <IGESCAFControl_Reader.hxx>
56#include <Interface_Static.hxx>
58#include <STEPControl_Reader.hxx>
59#include <STEPCAFControl_Reader.hxx>
61#include <XCAFDoc_DocumentTool.hxx>
62#include <XCAFDoc_ColorTool.hxx>
63#include <XCAFDoc_ShapeTool.hxx>
65#include <BRep_Tool.hxx>
66#include <BRepMesh_IncrementalMesh.hxx>
69#include <TopoDS_Shape.hxx>
70#include <TopoDS_Face.hxx>
71#include <TopoDS_Compound.hxx>
72#include <TopExp_Explorer.hxx>
74#include <Quantity_Color.hxx>
75#include <Poly_Triangulation.hxx>
76#include <Poly_PolygonOnTriangulation.hxx>
77#include <Precision.hxx>
79#include <NCollection_Sequence.hxx>
80#include <TDF_Label.hxx>
81#include <TDF_ChildIterator.hxx>
82#include <TDF_Tool.hxx>
83#include <TDataStd_Name.hxx>
84#include <Standard_Version.hxx>
90#define MASK_OCE wxT( "PLUGIN_OCE" )
91#define MASK_OCE_EXTRA wxT( "PLUGIN_OCE_EXTRA" )
93typedef std::map<std::size_t, SGNODE*>
COLORMAP;
94typedef std::map<std::string, SGNODE*>
FACEMAP;
95typedef std::map<std::string, std::vector<SGNODE*>>
NODEMAP;
96typedef std::pair<std::string, std::vector<SGNODE*>>
NODEITEM;
101 std::vector< SGNODE* >* aItems );
105 std::vector< SGNODE* >* items, Quantity_ColorRGBA* color );
107#if OCC_VERSION_HEX >= 0x070500
108#define OCC_COLOR_SPACE Quantity_TOC_sRGB
110#define OCC_COLOR_SPACE Quantity_TOC_RGB
131 refColor.SetValues( Quantity_NOC_BLACK );
141 COLORMAP::iterator sC =
colors.begin();
142 COLORMAP::iterator eC =
colors.end();
161 FACEMAP::iterator sF =
faces.begin();
162 FACEMAP::iterator eF =
faces.end();
178 NODEMAP::iterator sS =
shapes.begin();
179 NODEMAP::iterator eS =
shapes.end();
183 std::vector< SGNODE* >::iterator sV = sS->second.begin();
184 std::vector< SGNODE* >::iterator eV = sS->second.end();
206 bool GetShape(
const std::string&
id, std::vector< SGNODE* >*& listPtr )
209 NODEMAP::iterator item;
212 if( item ==
shapes.end() )
215 listPtr = &item->second;
222 FACEMAP::iterator item;
223 item =
faces.find(
id );
225 if( item ==
faces.end() )
234 if(
nullptr == colorObj )
249 Quantity_Color colorRgb = colorObj->GetRGB();
254 std::size_t hash = std::hash<double>{}( colorRgb.Distance(
refColor ) )
255 ^ ( std::hash<float>{}( colorObj->Alpha() ) << 1 );
257 std::map<std::size_t, SGNODE*>::iterator item;
258 item =
colors.find( hash );
260 if( item !=
colors.end() )
287 wxFileName fname( wxString::FromUTF8Unchecked( aFileName ) );
288 wxFFileInputStream ifile( fname.GetFullPath() );
293 if( fname.GetExt().MakeUpper().EndsWith( wxT(
"STPZ" ) )
294 || fname.GetExt().MakeUpper().EndsWith( wxT(
"GZ" ) ) )
304 const int max_line_count = 3;
306 for(
int ii = 0; ii < max_line_count; ii++ )
308 memset( iline, 0, 82 );
309 ifile.Read( iline, 82 );
314 if( !strncmp( iline,
"ISO-10303-21;", 13 ) )
320 std::string fstr = iline;
324 if( fstr.find(
"urn:oid:1.0.10303." ) != std::string::npos )
330 if( iline[72] ==
'S' && ( iline[80] == 0 || iline[80] == 13 || iline[80] == 10 ) )
334 if( strncmp( iline,
"/*", 2 ) != 0 )
348void getTag(
const TDF_Label& aLabel, std::string& aTag )
350 std::ostringstream ostr;
352 if( aLabel.IsNull() )
354 wxLogTrace(
MASK_OCE, wxT(
"Null label passed to getTag" ) );
358 NCollection_List<int> tagList;
359 TDF_Tool::TagList( aLabel, tagList );
361 for(
const int& tag : tagList )
376 if( !aLabel.IsNull() && aLabel.FindAttribute( TDataStd_Name::GetID(),
name ) )
378 TCollection_ExtendedString extstr =
name->Get();
379 char* str =
new char[extstr.LengthOfCString() + 1];
380 extstr.ToUTF8CString( str );
382 txt = wxString::FromUTF8( str );
399 case TopAbs_COMPOUND:
return "COMPOUND";
400 case TopAbs_COMPSOLID:
return "COMPSOLID";
401 case TopAbs_SOLID:
return "SOLID";
402 case TopAbs_SHELL:
return "SHELL";
403 case TopAbs_FACE:
return "FACE";
404 case TopAbs_WIRE:
return "WIRE";
405 case TopAbs_EDGE:
return "EDGE";
406 case TopAbs_VERTEX:
return "VERTEX";
407 case TopAbs_SHAPE:
return "SHAPE";
419static inline std::ostream&
operator<<( std::ostream& aOStream,
const Quantity_ColorRGBA& aColor )
421 Quantity_Color rgb = aColor.GetRGB();
440 Handle( XCAFDoc_ColorTool ) aColorTool,
const char* aPreMsg =
nullptr )
442 if( aLabel.IsNull() )
448 TCollection_AsciiString entry;
449 TDF_Tool::Entry( aLabel, entry );
450 std::ostringstream ss;
451 ss << aPreMsg << entry <<
", " <<
getLabelName( aLabel )
452 << ( aShapeTool->IsShape( aLabel ) ?
", shape" :
"" )
453 << ( aShapeTool->IsTopLevel( aLabel ) ?
", topLevel" :
"" )
454 << ( aShapeTool->IsFree( aLabel ) ?
", free" :
"" )
455 << ( aShapeTool->IsAssembly( aLabel ) ?
", assembly" :
"" )
456 << ( aShapeTool->IsSimpleShape( aLabel ) ?
", simple" :
"" )
457 << ( aShapeTool->IsCompound( aLabel ) ?
", compound" :
"" )
458 << ( aShapeTool->IsReference( aLabel ) ?
", reference" :
"" )
459 << ( aShapeTool->IsComponent( aLabel ) ?
", component" :
"" )
460 << ( aShapeTool->IsSubShape( aLabel ) ?
", subshape" :
"" );
462 if( aShapeTool->IsSubShape( aLabel ) )
464 auto shape = aShapeTool->GetShape( aLabel );
465 if( !shape.IsNull() )
469 if( aShapeTool->IsShape( aLabel ) )
471 Quantity_ColorRGBA c;
472 if( aColorTool->GetColor( aLabel, XCAFDoc_ColorGen, c ) )
474 if( aColorTool->GetColor( aLabel, XCAFDoc_ColorSurf, c ) )
476 if( aColorTool->GetColor( aLabel, XCAFDoc_ColorCurv, c ) )
480 wxLogTrace(
MASK_OCE, ss.str().c_str() );
493 Handle( XCAFDoc_ColorTool ) aColorTool,
int aDepth = 0 )
495 std::string indent( aDepth * 2,
' ' );
496 printLabel( aLabel, aShapeTool, aColorTool, indent.c_str() );
497 TDF_ChildIterator it;
498 for( it.Initialize( aLabel ); it.More(); it.Next() )
499 dumpLabels( it.Value(), aShapeTool, aColorTool, aDepth + 1 );
507 if( data.m_color->
GetColor( label, XCAFDoc_ColorSurf, color ) )
509 else if( data.m_color->
GetColor( label, XCAFDoc_ColorCurv, color ) )
511 else if( data.m_color->
GetColor( label, XCAFDoc_ColorGen, color ) )
514 label = label.Father();
529 std::vector< SGNODE* >::iterator sL = lp->begin();
530 std::vector< SGNODE* >::iterator eL = lp->end();
549 IGESCAFControl_Reader reader;
550 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
551 reader.PrintCheckLoad(
false, IFSelect_ItemsByEntity );
553 if( stat != IFSelect_RetDone )
557 if( !Interface_Static::SetIVal(
"read.precision.mode", 0 ) )
561 reader.SetColorMode(
true);
562 reader.SetNameMode(
false);
563 reader.SetLayerMode(
false);
565 if( !reader.Transfer( m_doc ) )
567 if( m_doc->CanClose() == CDM_CCS_OK )
574 if( reader.NbShapes() < 1 )
576 if( m_doc->CanClose() == CDM_CCS_OK )
588 wxLogTrace(
MASK_OCE, wxT(
"Reading step file %s" ), fname );
590 STEPCAFControl_Reader reader;
591 IFSelect_ReturnStatus stat = reader.ReadFile( fname );
593 if( stat != IFSelect_RetDone )
597 if( !Interface_Static::SetIVal(
"read.precision.mode", 1 ) )
601 if( !Interface_Static::SetRVal(
"read.precision.val",
ADVANCED_CFG::GetCfg().m_OcePluginLinearDeflection ) )
605 reader.SetColorMode(
true );
606 reader.SetNameMode(
false );
607 reader.SetLayerMode(
false );
609 if( !reader.Transfer( m_doc ) )
611 if( m_doc->CanClose() == CDM_CCS_OK )
618 if( reader.NbRootsForTransfer() < 1 )
620 if( m_doc->CanClose() == CDM_CCS_OK )
632 wxFileName fname( wxString::FromUTF8Unchecked( aFileName ) );
633 wxFFileInputStream ifile( fname.GetFullPath() );
635 wxFileName outFile( fname );
637 outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
638 outFile.SetExt( wxT(
"STEP" ) );
640 wxFileOffset size = ifile.GetLength();
641 wxBusyCursor busycursor;
643 if( size == wxInvalidOffset )
647 bool success =
false;
648 wxFFileOutputStream ofile( outFile.GetFullPath() );
653 char *buffer =
new char[size];
655 ifile.Read( buffer, size);
656 std::string expanded;
660 expanded = gzip::decompress( buffer, size );
666 if( expanded.empty() )
670 wxZipInputStream izipfile( ifile );
671 std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
673 if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
675 izipfile.Read( ofile );
681 ofile.Write( expanded.data(), expanded.size() );
691 bool retval =
readSTEP( m_doc, outFile.GetFullPath().mb_str() );
694 wxRemoveFile( outFile.GetFullPath() );
704 Handle(XCAFApp_Application) m_app = XCAFApp_Application::GetApplication();
705 m_app->NewDocument(
"MDTV-XCAF", data.m_doc );
713 if( !
readIGES( data.m_doc, filename ) )
719 if( !
readSTEP( data.m_doc, filename ) )
732 if( m_app->CanClose( data.m_doc ) == CDM_CCS_OK )
733 m_app->Close( data.m_doc );
739 data.m_assy = XCAFDoc_DocumentTool::ShapeTool( data.m_doc->Main() );
740 data.m_color = XCAFDoc_DocumentTool::ColorTool( data.m_doc->Main() );
743 if( wxLog::IsAllowedTraceMask(
MASK_OCE ) )
745 dumpLabels( data.m_doc->Main(), data.m_assy, data.m_color );
749 NCollection_Sequence<TDF_Label> frshapes;
750 data.m_assy->GetFreeShapes( frshapes );
758 for(
int i = 1; i <= frshapes.Length(); i++ )
760 const TDF_Label& label = frshapes.Value( i );
762 if( data.m_color->IsVisible( label ) )
771 if( m_app->CanClose( data.m_doc ) == CDM_CCS_OK )
772 m_app->Close( data.m_doc );
780#if ( defined( DEBUG_OCE ) && DEBUG_OCE > 3 )
783 wxFileName fn( wxString::FromUTF8Unchecked( filename ) );
791 output.append( fn.GetName() );
792 output.append( wxT(
".wrl" ) );
798 data.
scene =
nullptr;
800 if( m_app->CanClose( data.m_doc ) == CDM_CCS_OK )
801 m_app->Close( data.m_doc );
808 std::vector<SGNODE*>* items, Quantity_ColorRGBA* color )
813 wxLogTrace(
MASK_OCE, wxT(
"Processing shell" ) );
814 for( it.Initialize( shape,
false,
false ); it.More(); it.Next() )
816 const TopoDS_Face& face = TopoDS::Face( it.Value() );
818 if(
processFace( face, data, parent, items, color ) )
827 std::vector< SGNODE* >* items )
831 Quantity_ColorRGBA col;
832 Quantity_ColorRGBA* lcolor =
nullptr;
834 data.
hasSolid = shape.ShapeType() == TopAbs_SOLID;
836 wxLogTrace(
MASK_OCE, wxT(
"Processing solid" ) );
839 if( !data.m_assy->Search( shape, label ) )
842 std::ostringstream ostr;
843 ostr <<
"KMISC_" << i++;
848 bool found_color =
false;
859 if( data.m_assy->Search( shape, label,
false,
true,
true ) &&
870 if( data.m_assy->Search( shape, label,
false,
false,
883 if( data.m_assy->Search( shape, label,
false,
false,
901 std::vector< SGNODE* >* component =
nullptr;
903 if( !partID.empty() )
910 if(
nullptr != items )
911 items->push_back( pptr );
915 std::vector<SGNODE*> itemList;
917 TopAbs_ShapeEnum stype = shape.ShapeType();
918 if( stype == TopAbs_SHELL )
920 if(
processShell( shape, data, pptr, &itemList, lcolor ) )
926 for( it.Initialize( shape,
false,
false ); it.More(); it.Next() )
928 const TopoDS_Shape& subShape = it.Value();
930 if( subShape.ShapeType() == TopAbs_SHELL )
932 if(
processShell( subShape, data, pptr, &itemList, lcolor ) )
937 wxLogTrace(
MASK_OCE, wxT(
"Unsupported subshape in solid" ) );
944 else if(
nullptr != items )
945 items->push_back( pptr );
952 std::vector<SGNODE*>* aItems )
954 std::string labelTag;
956 if( wxLog::IsAllowedTraceMask(
MASK_OCE ) )
959 getTag( aLabel, labelTag );
962 wxLogTrace(
MASK_OCE, wxT(
"Processing label %s" ), labelTag );
964 TopoDS_Shape originalShape;
965 TDF_Label shapeLabel = aLabel;
967 if( !aData.m_assy->
GetShape( shapeLabel, originalShape ) )
972 TopoDS_Shape shape = originalShape;
974 if( aData.m_assy->IsReference( aLabel ) )
976 wxLogTrace(
MASK_OCE, wxT(
"Label %s is ref, trying to pull up referred label" ),
979 if( !aData.m_assy->GetReferredShape( aLabel, shapeLabel ) )
984 labelTag =
static_cast<int>( shapeLabel.Tag() );
987 if( !aData.m_assy->
GetShape( shapeLabel, shape ) )
997 const TopLoc_Location& loc = originalShape.Location();
999 if( !loc.IsIdentity() )
1001 wxLogTrace(
MASK_OCE, wxT(
"Label %d has location" ),
static_cast<int>( aLabel.Tag() ) );
1002 gp_Trsf
T = loc.Transformation();
1003 gp_XYZ coord =
T.TranslationPart();
1005 wxLogTrace(
MASK_OCE, wxT(
"Translation %f, %f, %f" ), coord.X(), coord.Y(), coord.Z() );
1009 if(
T.GetRotation( axis, angle ) )
1012 wxLogTrace(
MASK_OCE, wxT(
"Rotation %f, %f, %f, angle %f" ),
1013 axis.X(), axis.Y(), axis.Z(), angle );
1017 TopAbs_ShapeEnum stype = shape.ShapeType();
1023 case TopAbs_COMPOUND:
1027 if( !aData.m_assy->IsAssembly( shapeLabel ) )
1031 for( xp.Init( shape, TopAbs_SOLID ); xp.More(); xp.Next() )
1038 for( xp.Init( shape, TopAbs_SHELL, TopAbs_SOLID ); xp.More(); xp.Next() )
1045 for( xp.Init( shape, TopAbs_FACE, TopAbs_SHELL ); xp.More(); xp.Next() )
1047 const TopoDS_Face& face = TopoDS::Face( xp.Current() );
1048 processFace( face, aData, pptr, aItems,
nullptr );
1068 if(
processFace( TopoDS::Face( shape ), aData, pptr, aItems,
nullptr ) )
1077 if(
nullptr != aItems )
1078 aItems->push_back( pptr );
1080 if( !aData.m_assy->IsSimpleShape( shapeLabel ) && shapeLabel.HasChild() )
1082 wxLogTrace(
MASK_OCE, wxT(
"Label %s has children" ), labelTag );
1083 TDF_ChildIterator it;
1085 for( it.Initialize( shapeLabel ); it.More(); it.Next() )
1097 Quantity_ColorRGBA* color )
1099 if(
true == face.IsNull() )
1102 bool reverse = ( face.Orientation() == TopAbs_REVERSED );
1103 SGNODE* ashape =
nullptr;
1107 bool useBothSides =
false;
1112 useBothSides =
true;
1114 if( data.m_assy->FindShape( face, label,
false ) )
1117 if( !partID.empty() )
1118 ashape = data.
GetFace( partID );
1127 if(
nullptr != items )
1128 items->push_back( ashape );
1132 std::string id2 = partID;
1141 if(
nullptr != items )
1142 items->push_back( shapeB );
1148 TopLoc_Location loc;
1149 bool isTessellate (
false);
1150 Handle( Poly_Triangulation ) triangulation = BRep_Tool::Triangulation( face, loc );
1153 if( triangulation.IsNull() || triangulation->Deflection() > linDeflection + Precision::Confusion() )
1154 isTessellate =
true;
1158 BRepMesh_IncrementalMesh IM(face, linDeflection,
false,
1160 triangulation = BRep_Tool::Triangulation( face, loc );
1163 if( triangulation.IsNull() ==
true )
1166 Quantity_ColorRGBA lcolor;
1169 if( data.m_color->
GetColor( face, XCAFDoc_ColorSurf, lcolor )
1170 || data.m_color->
GetColor( face, XCAFDoc_ColorCurv, lcolor )
1171 || data.m_color->
GetColor( face, XCAFDoc_ColorGen, lcolor ) )
1190 std::vector< SGPOINT > vertices;
1191 std::vector< int > indices;
1192 std::vector< int > indices2;
1196 bool applyTransform = !loc.IsIdentity();
1197 gp_Trsf tx = applyTransform ? loc.Transformation() : gp_Trsf();
1199 for(
int i = 1; i <= triangulation->NbNodes(); i++ )
1201 gp_XYZ v = applyTransform ? triangulation->Node( i ).Transformed( tx ).Coord()
1202 : triangulation->Node( i ).Coord();
1203 vertices.emplace_back( v.X(), v.Y(), v.Z() );
1206 for(
int i = 1; i <= triangulation->NbTriangles(); i++ )
1209 triangulation->Triangle(i).Get(a, b, c);
1224 indices.push_back( a );
1225 indices.push_back( b );
1226 indices.push_back( c );
1230 indices2.push_back( b );
1231 indices2.push_back( a );
1232 indices2.push_back( c );
1237 coordIdx.
SetIndices( indices.size(), &indices[0] );
1241 if( !partID.empty() )
1248 std::string id2 = partID;
1257 coordIdx2.
SetIndices( indices2.size(), &indices2[0] );
1261 if( !partID.empty() )
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
bool SetDiffuse(float aRVal, float aGVal, float aBVal)
bool SetSpecular(float aRVal, float aGVal, float aBVal)
bool SetShininess(float aShininess) noexcept
bool SetAmbient(float aRVal, float aGVal, float aBVal)
bool SetTransparency(float aTransparency) noexcept
The wrapper for SGCOORDINDEX.
The wrapper for SGCOORDS.
bool SetCoordsList(size_t aListSize, const SGPOINT *aCoordsList)
The wrapper for the SGFACESET class.
bool CalcNormals(SGNODE **aPtr)
bool SetIndices(size_t nIndices, int *aIndexList)
Set the number of indices and creates a copy of the given index data.
bool SetParent(SGNODE *aParent)
Set the parent SGNODE of this object.
SGNODE * GetRawPtr(void) noexcept
Return the raw internal SGNODE pointer.
void Destroy(void)
Delete the object held by this wrapper.
The wrapper for the SGSHAPE class.
Define the basic data set required to represent a 3D model.
The base class of all Scene Graph nodes.
double m_OcePluginLinearDeflection
OCE (STEP/IGES) 3D Plugin Tesselation Linear Deflection.
collects header files for all SG* wrappers and the API
Handle(KICAD3D_INFO) KICAD3D_INFO
bool processShell(const TopoDS_Shape &shape, DATA &data, SGNODE *parent, std::vector< SGNODE * > *items, Quantity_ColorRGBA *color)
std::map< std::string, std::vector< SGNODE * > > NODEMAP
std::map< std::size_t, SGNODE * > COLORMAP
bool processFace(const TopoDS_Face &face, DATA &data, SGNODE *parent, std::vector< SGNODE * > *items, Quantity_ColorRGBA *color)
std::pair< std::string, std::vector< SGNODE * > > NODEITEM
bool getColor(DATA &data, TDF_Label label, Quantity_ColorRGBA &color)
static int colorFloatToDecimal(float aVal)
void getTag(const TDF_Label &aLabel, std::string &aTag)
Gets the absolute tag string for a given label in the form of ##:##:##:##.
void addItems(SGNODE *parent, std::vector< SGNODE * > *lp)
std::string getShapeName(TopAbs_ShapeEnum aShape)
Gets a string for a given TopAbs_ShapeEnum element.
static void printLabel(TDF_Label aLabel, Handle(XCAFDoc_ShapeTool) aShapeTool, Handle(XCAFDoc_ColorTool) aColorTool, const char *aPreMsg=nullptr)
Gets a string for a given TopAbs_ShapeEnum element.
SCENEGRAPH * LoadModel(char const *filename)
static void dumpLabels(TDF_Label aLabel, Handle(XCAFDoc_ShapeTool) aShapeTool, Handle(XCAFDoc_ColorTool) aColorTool, int aDepth=0)
Dumps a label and the entire tree underneath it.
FormatType fileType(const char *aFileName)
bool readSTEP(Handle(TDocStd_Document)&m_doc, const char *fname)
static std::ostream & operator<<(std::ostream &aOStream, const Quantity_ColorRGBA &aColor)
bool processSolidOrShell(const TopoDS_Shape &shape, DATA &data, SGNODE *parent, std::vector< SGNODE * > *items)
static wxString getLabelName(const TDF_Label &aLabel)
bool processLabel(const TDF_Label &aLabel, DATA &aData, SGNODE *aParent, std::vector< SGNODE * > *aItems)
std::map< std::string, SGNODE * > FACEMAP
bool readSTEPZ(Handle(TDocStd_Document)&m_doc, const char *aFileName)
bool readIGES(Handle(TDocStd_Document) &m_doc, const char *fname)
SGLIB_API bool WriteVRML(const char *filename, bool overwrite, SGNODE *aTopNode, bool reuse, bool renameNodes)
Write out the given node and its subnodes to a VRML2 file.
SGLIB_API SGNODE * GetSGNodeParent(SGNODE *aNode)
SGLIB_API void DestroyNode(SGNODE *aNode) noexcept
Delete the given SG* class node.
SGLIB_API bool AddSGNodeChild(SGNODE *aParent, SGNODE *aChild)
SGLIB_API bool AddSGNodeRef(SGNODE *aParent, SGNODE *aChild)
static SGNODE * getColor(IFSG_SHAPE &shape, int colorIdx)
Handle(XCAFDoc_ColorTool) m_color
SGNODE * GetFace(const std::string &id)
Handle(TDocStd_Document) m_doc
bool GetShape(const std::string &id, std::vector< SGNODE * > *&listPtr)
Handle(XCAFDoc_ShapeTool) m_assy
SGNODE * GetColor(Quantity_ColorRGBA *colorObj)