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
This commit is contained in:
Marek Roszko 2021-10-08 22:05:32 -04:00
parent ac3ade874e
commit e81b516a82
1 changed files with 82 additions and 106 deletions

View File

@ -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 ) )
if( data.m_color->IsVisible( label ) )
{
if( processLabel( label, data, data.scene, nullptr ) )
ret = true;
++id;
};
}
}
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,9 +732,16 @@ bool processSolid( const TopoDS_Shape& shape, DATA& data, SGNODE* parent,
{
const TopoDS_Shape& subShape = it.Value();
if( subShape.ShapeType() == TopAbs_SHELL )
{
if( processShell( subShape, data, pptr, &itemList, lcolor ) )
ret = true;
}
else
{
wxLogTrace( MASK_OCE, "Unsupported subshape in solid" );
}
}
if( !ret )
childNode.Destroy();
@ -765,20 +752,49 @@ 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<SGNODE*>* 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<int>( 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<int>( 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<int>( aLabel.Tag() ) );
gp_Trsf T = loc.Transformation();
gp_XYZ coord = T.TranslationPart();
childNode.SetTranslation( SGPOINT( coord.X(), coord.Y(), coord.Z() ) );
@ -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" );
aData.hasSolid = false;
switch( stype )
{
case TopAbs_COMPOUND:
case TopAbs_COMPSOLID:
if( processComp( shape, data, parent, items ) )
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;
}