From e81b516a82605c3e3450b5ea488aea560d92cb5b Mon Sep 17 00:00:00 2001 From: Marek Roszko Date: Fri, 8 Oct 2021 22:05:32 -0400 Subject: [PATCH] Process step components by labels rather than shapes. Labels are the true structure. Extracting purely just shapes won't get you instances of shapes that are virtually placed by reference labels. Note, this may break the 3d placement of existing user models but they were most likely wrong loaded in the first place and losing any location data as simple as a boring offset from 0. There's no way to preserve the broken behavior and still allow complex step assemblies to locate correctly. Fixes https://gitlab.com/kicad/code/kicad/issues/4181 --- plugins/3d/oce/loadmodel.cpp | 188 +++++++++++++++-------------------- 1 file changed, 82 insertions(+), 106 deletions(-) diff --git a/plugins/3d/oce/loadmodel.cpp b/plugins/3d/oce/loadmodel.cpp index 42a2ec694d..49d6b739cb 100644 --- a/plugins/3d/oce/loadmodel.cpp +++ b/plugins/3d/oce/loadmodel.cpp @@ -97,12 +97,8 @@ typedef std::pair< std::string, std::vector< SGNODE* > > NODEITEM; struct DATA; -bool processNode( const TopoDS_Shape& shape, DATA& data, SGNODE* parent, - std::vector< SGNODE* >* items ); - - -bool processComp( const TopoDS_Shape& shape, DATA& data, SGNODE* parent, - std::vector< SGNODE* >* items ); +bool processLabel( const TDF_Label& aLabel, DATA& aData, SGNODE* aParent, + std::vector< SGNODE* >* aItems ); bool processFace( const TopoDS_Face& face, DATA& data, SGNODE* parent, @@ -315,7 +311,10 @@ FormatType fileType( const char* aFileName ) void getTag( TDF_Label& label, std::string& aTag ) { if( label.IsNull() ) + { + wxLogTrace( MASK_OCE, "Null label passed to getTag" ); return; + } std::string rtag; // tag in reverse aTag.clear(); @@ -573,23 +572,22 @@ SCENEGRAPH* LoadModel( char const* filename ) TDF_LabelSequence frshapes; data.m_assy->GetFreeShapes( frshapes ); - int nshapes = frshapes.Length(); - int id = 1; bool ret = false; // create the top level SG node IFSG_TRANSFORM topNode( true ); data.scene = topNode.GetRawPtr(); - while( id <= nshapes ) + for( Standard_Integer i = 1; i <= frshapes.Length(); i++ ) { - TopoDS_Shape shape = data.m_assy->GetShape( frshapes.Value( id ) ); + const TDF_Label& label = frshapes.Value( i ); - if ( !shape.IsNull() && processNode( shape, data, data.scene, nullptr ) ) - ret = true; - - ++id; - }; + if( data.m_color->IsVisible( label ) ) + { + if( processLabel( label, data, data.scene, nullptr ) ) + ret = true; + } + } if( !ret ) return nullptr; @@ -711,26 +709,8 @@ bool processSolid( const TopoDS_Shape& shape, DATA& data, SGNODE* parent, TopoDS_Iterator it; IFSG_TRANSFORM childNode( parent ); SGNODE* pptr = childNode.GetRawPtr(); - const TopLoc_Location& loc = shape.Location(); bool ret = false; - if( !loc.IsIdentity() ) - { - wxLogTrace( MASK_OCE, "Solid has location" ); - gp_Trsf T = loc.Transformation(); - gp_XYZ coord = T.TranslationPart(); - childNode.SetTranslation( SGPOINT( coord.X(), coord.Y(), coord.Z() ) ); - wxLogTrace( MASK_OCE, "Translation %f, %f, %f", coord.X(), coord.Y(), coord.Z() ); - gp_XYZ axis; - Standard_Real angle; - - if( T.GetRotation( axis, angle ) ) - { - childNode.SetRotation( SGVECTOR( axis.X(), axis.Y(), axis.Z() ), angle ); - wxLogTrace( MASK_OCE, "Rotation %f, %f, %f, angle %f", axis.X(), axis.Y(), axis.Z(), - angle ); - } - } std::vector< SGNODE* >* component = nullptr; @@ -752,8 +732,15 @@ bool processSolid( const TopoDS_Shape& shape, DATA& data, SGNODE* parent, { const TopoDS_Shape& subShape = it.Value(); - if( processShell( subShape, data, pptr, &itemList, lcolor ) ) - ret = true; + if( subShape.ShapeType() == TopAbs_SHELL ) + { + if( processShell( subShape, data, pptr, &itemList, lcolor ) ) + ret = true; + } + else + { + wxLogTrace( MASK_OCE, "Unsupported subshape in solid" ); + } } if( !ret ) @@ -765,25 +752,54 @@ bool processSolid( const TopoDS_Shape& shape, DATA& data, SGNODE* parent, } -bool processComp( const TopoDS_Shape& shape, DATA& data, SGNODE* parent, - std::vector< SGNODE* >* items ) +bool processLabel( const TDF_Label& aLabel, DATA& aData, SGNODE* aParent, + std::vector* aItems ) { - TopoDS_Iterator it; - IFSG_TRANSFORM childNode( parent ); - SGNODE* pptr = childNode.GetRawPtr(); - const TopLoc_Location& loc = shape.Location(); - bool ret = false; + int labelTag = static_cast( aLabel.Tag() ); + wxLogTrace( MASK_OCE, "Processing label %d", labelTag ); - wxLogTrace( MASK_OCE, "Processing component" ); + TopoDS_Shape originalShape; + TDF_Label shapeLabel = aLabel; + + if( !aData.m_assy->GetShape( shapeLabel, originalShape ) ) + { + return false; + } + + TopoDS_Shape shape = originalShape; + + if( aData.m_assy->IsReference( aLabel ) ) + { + wxLogTrace( MASK_OCE, "Label %d is ref, trying to pull up referred label", labelTag ); + + if( !aData.m_assy->GetReferredShape( aLabel, shapeLabel ) ) + { + return false; + } + + labelTag = static_cast( shapeLabel.Tag() ); + wxLogTrace( MASK_OCE, "Label %d referred", labelTag ); + + if( !aData.m_assy->GetShape( shapeLabel, shape ) ) + { + return false; + } + } + + // Now let's see if the original label has a location + // Labels can be used to place copies of other labels at a specific location + IFSG_TRANSFORM childNode( aParent ); + SGNODE* pptr = childNode.GetRawPtr(); + const TopLoc_Location& loc = originalShape.Location(); if( !loc.IsIdentity() ) { - wxLogTrace( MASK_OCE, "Component has location" ); + wxLogTrace( MASK_OCE, "Label %d has location", static_cast( aLabel.Tag() ) ); gp_Trsf T = loc.Transformation(); - gp_XYZ coord = T.TranslationPart(); + gp_XYZ coord = T.TranslationPart(); childNode.SetTranslation( SGPOINT( coord.X(), coord.Y(), coord.Z() ) ); wxLogTrace( MASK_OCE, "Translation %f, %f, %f", coord.X(), coord.Y(), coord.Z() ); - gp_XYZ axis; + gp_XYZ axis; Standard_Real angle; if( T.GetRotation( axis, angle ) ) @@ -794,85 +810,31 @@ bool processComp( const TopoDS_Shape& shape, DATA& data, SGNODE* parent, } } - for( it.Initialize( shape, false, false ); it.More(); it.Next() ) - { - const TopoDS_Shape& subShape = it.Value(); - TopAbs_ShapeEnum stype = subShape.ShapeType(); - data.hasSolid = false; - - switch( stype ) - { - case TopAbs_COMPOUND: - case TopAbs_COMPSOLID: - if( processComp( subShape, data, pptr, items ) ) - ret = true; - - break; - - case TopAbs_SOLID: - if( processSolid( subShape, data, pptr, items ) ) - ret = true; - - break; - - case TopAbs_SHELL: - if( processShell( subShape, data, pptr, items, nullptr ) ) - ret = true; - - break; - - case TopAbs_FACE: - if( processFace( TopoDS::Face( subShape ), data, pptr, items, nullptr ) ) - ret = true; - - break; - - default: - break; - } - } - - if( !ret ) - childNode.Destroy(); - else if( nullptr != items ) - items->push_back( pptr ); - - return ret; -} - - -bool processNode( const TopoDS_Shape& shape, DATA& data, SGNODE* parent, - std::vector< SGNODE* >* items ) -{ TopAbs_ShapeEnum stype = shape.ShapeType(); - bool ret = false; - data.hasSolid = false; - - wxLogTrace( MASK_OCE, "Processing node" ); + bool ret = false; + aData.hasSolid = false; switch( stype ) { case TopAbs_COMPOUND: case TopAbs_COMPSOLID: - if( processComp( shape, data, parent, items ) ) - ret = true; - + ret = true; break; case TopAbs_SOLID: - if( processSolid( shape, data, parent, items ) ) + if( processSolid( shape, aData, pptr, aItems ) ) ret = true; break; case TopAbs_SHELL: - if( processShell( shape, data, parent, items, nullptr ) ) + if( processShell( shape, aData, pptr, aItems, nullptr ) ) ret = true; break; case TopAbs_FACE: - if( processFace( TopoDS::Face( shape ), data, parent, items, nullptr ) ) + if( processFace( TopoDS::Face( shape ), aData, pptr, aItems, nullptr ) ) ret = true; break; @@ -881,6 +843,20 @@ bool processNode( const TopoDS_Shape& shape, DATA& data, SGNODE* parent, break; } + if( nullptr != aItems ) + aItems->push_back( pptr ); + + if( shapeLabel.HasChild() ) + { + TDF_ChildIterator it; + for( it.Initialize( shapeLabel ); it.More(); it.Next() ) + { + wxLogTrace( MASK_OCE, "Processing label %d child....", labelTag ); + if( processLabel( it.Value(), aData, pptr, aItems ) ) + ret = true; + } + } + return ret; }