STEP export: Use TDocStd_XLinkTool to copy model with colors instead of our DIY routine.

Now supports older OCCT versions.
Also puts components at a higher level in the hierarchy.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17549
This commit is contained in:
Alex Shvartzkop 2024-05-16 01:33:03 +03:00
parent a4583fdbc1
commit 2179685dd2
4 changed files with 627 additions and 117 deletions

View File

@ -218,6 +218,7 @@ set( PCBNEW_EXPORTERS
exporters/export_svg.cpp
exporters/step/exporter_step.cpp
exporters/step/step_pcb_model.cpp
exporters/step/KI_XCAFDoc_AssemblyGraph.cxx
exporters/exporter_vrml.cpp
exporters/place_file_exporter.cpp
exporters/gen_drill_report_files.cpp

View File

@ -0,0 +1,270 @@
// Created on: 2022-05-11
// Copyright (c) 2022 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Standard_NullObject.hxx>
#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
#include <TDataStd_TreeNode.hxx>
#include <TDF_ChildIterator.hxx>
#include <TDF_Tool.hxx>
#include <TDocStd_Document.hxx>
#include <XCAFDoc.hxx>
#include "KI_XCAFDoc_AssemblyGraph.hxx"
#include <XCAFDoc_DocumentTool.hxx>
#include <XCAFDoc_ShapeTool.hxx>
// =======================================================================
// function : KI_XCAFDoc_AssemblyGraph constructor
// purpose : Builds an assembly graph from the OCAF document
// =======================================================================
KI_XCAFDoc_AssemblyGraph::KI_XCAFDoc_AssemblyGraph(const Handle(TDocStd_Document)& theDoc)
{
Standard_NullObject_Raise_if(theDoc.IsNull(), "Null document!");
myShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDoc->Main());
Standard_NoSuchObject_Raise_if(myShapeTool.IsNull(), "No XCAFDoc_ShapeTool attribute!");
TDF_Label aDummy;
buildGraph(aDummy);
}
// =======================================================================
// function : KI_XCAFDoc_AssemblyGraph constructor
// purpose : Builds an assembly graph from the OCAF label
// =======================================================================
KI_XCAFDoc_AssemblyGraph::KI_XCAFDoc_AssemblyGraph(const TDF_Label& theLabel)
{
Standard_NullObject_Raise_if(theLabel.IsNull(), "Null label!");
myShapeTool = XCAFDoc_DocumentTool::ShapeTool(theLabel);
Standard_NoSuchObject_Raise_if(myShapeTool.IsNull(), "No XCAFDoc_ShapeTool attribute!");
buildGraph(theLabel);
}
// =======================================================================
// function : IsDirectLink
// purpose : Checks if one node is the direct child of other one
// =======================================================================
Standard_Boolean KI_XCAFDoc_AssemblyGraph::IsDirectLink(const Standard_Integer theNode1,
const Standard_Integer theNode2) const
{
if (!HasChildren(theNode1))
return Standard_False;
return GetChildren(theNode1).Contains(theNode2);
}
// =======================================================================
// function : GetNodeType
// purpose : Returns node type
// =======================================================================
KI_XCAFDoc_AssemblyGraph::NodeType
KI_XCAFDoc_AssemblyGraph::GetNodeType(const Standard_Integer theNode) const
{
const NodeType* typePtr = myNodeTypes.Seek(theNode);
if (typePtr == NULL)
return NodeType_UNDEFINED;
return (*typePtr);
}
// =======================================================================
// function : NbLinks
// purpose : Calculates and returns the number of links
// =======================================================================
Standard_Integer KI_XCAFDoc_AssemblyGraph::NbLinks() const
{
Standard_Integer aNumLinks = 0;
for (AdjacencyMap::Iterator it(myAdjacencyMap); it.More(); it.Next())
{
aNumLinks += it.Value().Extent();
}
return aNumLinks;
}
// =======================================================================
// function : GetUsageOccurrenceQuantity
// purpose :
// =======================================================================
Standard_Integer KI_XCAFDoc_AssemblyGraph::NbOccurrences(const Standard_Integer theNode) const
{
const Standard_Integer* aUsageOQPtr = myUsages.Seek(theNode);
if (aUsageOQPtr == NULL)
return 0;
return (*aUsageOQPtr);
}
// =======================================================================
// function : buildGraph
// purpose : Builds an assembly graph from the OCAF document
// =======================================================================
void KI_XCAFDoc_AssemblyGraph::buildGraph(const TDF_Label& theLabel)
{
// We start from those shapes which are "free" in terms of XDE.
TDF_LabelSequence aRoots;
if (theLabel.IsNull() || (myShapeTool->Label() == theLabel))
myShapeTool->GetFreeShapes(aRoots);
else
aRoots.Append(theLabel);
for (TDF_LabelSequence::Iterator it(aRoots); it.More(); it.Next())
{
TDF_Label aLabel = it.Value();
TDF_Label anOriginal;
if (!myShapeTool->GetReferredShape(aLabel, anOriginal))
anOriginal = aLabel;
const Standard_Integer aRootId = addNode(anOriginal, 0);
if (aRootId == 0)
continue;
myRoots.Add(aRootId);
// Add components (the objects nested into the current one).
if (myShapeTool->IsAssembly(anOriginal))
addComponents(anOriginal, aRootId);
}
}
// =======================================================================
// function : addComponents
// purpose : Adds components for the given parent to the graph structure
// =======================================================================
void KI_XCAFDoc_AssemblyGraph::addComponents(const TDF_Label& theParent,
const Standard_Integer theParentId)
{
if (!myShapeTool->IsShape(theParent))
{
return; // We have to return here in order to prevent iterating by
// sub-labels. For parts, sub-labels are used to encode
// metadata which is out of interest in conceptual design
// intent represented by assembly graph.
}
// Loop over the children (persistent representation of "part-of" relation).
for (TDF_ChildIterator anIt(theParent); anIt.More(); anIt.Next())
{
TDF_Label aComponent = anIt.Value();
// Add component
const Standard_Integer aComponentId = addNode(aComponent, theParentId);
if (aComponentId == 0)
continue;
// Protection against deleted empty labels (after expand compounds, for example).
Handle(TDataStd_TreeNode) aJumpNode;
if (!aComponent.FindAttribute(XCAFDoc::ShapeRefGUID(), aJumpNode))
continue;
// Jump to the referred object (the original).
TDF_Label aChildOriginal;
if (!aJumpNode.IsNull() && aJumpNode->HasFather())
aChildOriginal = aJumpNode->Father()->Label(); // Declaration-level origin.
if (aChildOriginal.IsNull())
continue;
// Add child
const Standard_Integer aChildId = addNode(aChildOriginal, aComponentId);
if (aChildId == 0)
continue;
// Process children: add components recursively.
addComponents(aChildOriginal, aChildId);
}
}
// =======================================================================
// function : addNode
// purpose : Adds node into the graph
// =======================================================================
Standard_Integer KI_XCAFDoc_AssemblyGraph::addNode(const TDF_Label& theLabel,
const Standard_Integer theParentId)
{
NodeType aNodeType = NodeType_UNDEFINED;
if (myShapeTool->IsAssembly(theLabel))
{
if (myShapeTool->IsFree(theLabel))
aNodeType = NodeType_AssemblyRoot;
else
aNodeType = NodeType_Subassembly;
}
else if (myShapeTool->IsComponent(theLabel))
{
aNodeType = NodeType_Occurrence;
}
else if (myShapeTool->IsSubShape(theLabel))
{
aNodeType = NodeType_Subshape;
}
else if (myShapeTool->IsSimpleShape(theLabel))
{
aNodeType = NodeType_Part;
}
if (aNodeType == NodeType_UNDEFINED)
return 0;
// Get ID of the insertion-level node in the abstract assembly graph.
const Standard_Integer aChildId = myNodes.Add(theLabel);
myNodeTypes.Bind(aChildId, aNodeType);
if (aNodeType != NodeType_Occurrence)
{
// Bind usage occurrences.
Standard_Integer* aUsageOQPtr = myUsages.ChangeSeek(aChildId);
if (aUsageOQPtr == NULL)
aUsageOQPtr = myUsages.Bound(aChildId, 1);
else
++(*aUsageOQPtr);
}
if (theParentId > 0)
{
// Add link
TColStd_PackedMapOfInteger* aMapPtr = myAdjacencyMap.ChangeSeek(theParentId);
if (aMapPtr == NULL)
aMapPtr = myAdjacencyMap.Bound(theParentId, TColStd_PackedMapOfInteger());
(*aMapPtr).Add(aChildId);
}
return aChildId;
}
// =======================================================================
// function : Iterator constructor
// purpose : Iteration starts from the specifid node.
// =======================================================================
KI_XCAFDoc_AssemblyGraph::Iterator::Iterator(const Handle(KI_XCAFDoc_AssemblyGraph)& theGraph,
const Standard_Integer theNode)
{
Standard_NullObject_Raise_if(theGraph.IsNull(), "Null assembly graph!");
Standard_NullObject_Raise_if(theNode < 1, "Node ID must be positive one-based integer!");
myGraph = theGraph;
myCurrentIndex = theNode;
}

View File

@ -0,0 +1,220 @@
// Created on: 2022-05-11
// Copyright (c) 2022 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _KI_XCAFDoc_AssemblyGraph_HeaderFile
#define _KI_XCAFDoc_AssemblyGraph_HeaderFile
#include <NCollection_DataMap.hxx>
#include <NCollection_IndexedMap.hxx>
#include <Standard.hxx>
#include <Standard_Type.hxx>
#include <TCollection_AsciiString.hxx>
#include <TColStd_PackedMapOfInteger.hxx>
#include <TDF_LabelIndexedMap.hxx>
class TDF_Label;
class TDocStd_Document;
class XCAFDoc_ShapeTool;
class KI_XCAFDoc_AssemblyGraph;
DEFINE_STANDARD_HANDLE(KI_XCAFDoc_AssemblyGraph, Standard_Transient)
// Assembly graph.
class KI_XCAFDoc_AssemblyGraph : public Standard_Transient
{
public:
//! \brief Type of the graph node.
enum NodeType
{
NodeType_UNDEFINED = 0, //!< Undefined node type.
NodeType_AssemblyRoot, //!< Root node.
NodeType_Subassembly, //!< Intermediate node.
NodeType_Occurrence, //!< Assembly/part occurrence node.
NodeType_Part, //!< Leaf node to represent parts.
NodeType_Subshape //!< Subshape node.
};
//! \brief Type definition for graph adjacency matrix.
//! This is how parent-component links are realized in the assembly graph.
typedef NCollection_DataMap<Standard_Integer, TColStd_PackedMapOfInteger> AdjacencyMap;
public:
//! \brief Graph iterator.
class Iterator
{
public:
//! \brief Accepting the assembly graph and starting node to iterate.
//! Iteration starts from the specified node.
//! \param [in] theGraph - assembly graph to iterate.
//! \param [in] theNode - graph node ID.
Standard_EXPORT Iterator(const Handle(KI_XCAFDoc_AssemblyGraph)& theGraph,
const Standard_Integer theNode = 1);
//! Checks if there are more graph nodes to iterate.
//! \return true/false.
Standard_Boolean More() const
{
return myCurrentIndex <= myGraph->NbNodes();
}
//! \return 1-based ID of the current node.
Standard_Integer Current() const
{
return myCurrentIndex;
}
//! Moves iterator to the next position.
void Next()
{
++myCurrentIndex;
}
private:
Handle(KI_XCAFDoc_AssemblyGraph) myGraph; //!< Assembly graph to iterate.
Standard_Integer myCurrentIndex; //!< Current 1-based node ID.
};
public:
//! \brief Constructs graph from XCAF document.
//! Construction of a formal graph will be done immediately.
//! \param [in] theDoc - document to iterate.
Standard_EXPORT KI_XCAFDoc_AssemblyGraph(const Handle(TDocStd_Document)& theDoc);
//! \brief Constructs graph from XCAF label.
//! Construction of a formal graph will be done immediately. The specified
//! label is used as a starting position.
//! \param [in] theDoc - document to iterate.
//! \param [in] theLabel - starting position.
Standard_EXPORT KI_XCAFDoc_AssemblyGraph(const TDF_Label& theLabel);
//! \return Document shape tool.
const Handle(XCAFDoc_ShapeTool)& GetShapeTool() const
{
return myShapeTool;
}
//! \brief Returns IDs of the root nodes.
//! \return IDs of the root nodes.
const TColStd_PackedMapOfInteger& GetRoots() const
{
return myRoots;
}
//! \brief Checks whether the assembly graph contains (n1, n2) directed link.
//! \param [in] theNode1 - one-based ID of the first node.
//! \param [in] theNode2 - one-based ID of the second node.
//! \return true/false.
Standard_EXPORT Standard_Boolean IsDirectLink(const Standard_Integer theNode1,
const Standard_Integer theNode2) const;
//! \brief Checks whether direct children exist for the given node.
//! \param [in] theNode - one-based node ID.
//! \return true/false.
Standard_Boolean HasChildren(const Standard_Integer theNode) const
{
return myAdjacencyMap.IsBound(theNode);
}
//! \brief Returns IDs of child nodes for the given node.
//! \param [in] theNode - one-based node ID.
//! \return set of child IDs.
const TColStd_PackedMapOfInteger& GetChildren(const Standard_Integer theNode) const
{
return myAdjacencyMap(theNode);
}
//! \brief Returns the node type from \ref NodeType enum.
//! \param [in] theNode - one-based node ID.
//! \return node type.
//! \sa NodeType
Standard_EXPORT NodeType GetNodeType(const Standard_Integer theNode) const;
//! \brief returns object ID by node ID.
//! \param [in] theNode - one-based node ID.
//! \return persistent ID.
const TDF_Label& GetNode(const Standard_Integer theNode) const
{
return myNodes(theNode);
}
//! \brief Returns the unordered set of graph nodes.
//! \return graph nodes.
const TDF_LabelIndexedMap& GetNodes() const
{
return myNodes;
}
//! \brief Returns the number of graph nodes.
//! \return number of graph nodes.
Standard_Integer NbNodes() const
{
return myNodes.Extent();
}
//! \brief Returns the collection of graph links in the form of adjacency matrix.
//! \return graph links.
const AdjacencyMap& GetLinks() const
{
return myAdjacencyMap;
}
//! \brief Returns the number of graph links.
//! \return number of graph links.
Standard_EXPORT Standard_Integer NbLinks() const;
//! Returns quantity of part usage occurrences.
//! \param [in] theNode - one-based part ID.
//! \return usage occurrence quantity.
Standard_EXPORT Standard_Integer NbOccurrences(const Standard_Integer theNode) const;
private:
//! Builds graph out of OCAF XDE structure.
//! \param [in] theLabel - optional starting position.
Standard_EXPORT void buildGraph(const TDF_Label& theLabel);
//! Adds components for the given parent to the graph structure.
//! \param [in] theParent - OCAF label of the parent object.
//! \param [in] theParentId - ID of the already registered node representing
//! the parent object in the assembly graph
//! being populated.
Standard_EXPORT void addComponents(const TDF_Label& theParent,
const Standard_Integer theParentId);
//! Adds node into the graph.
//! \param [in] theLabel - label at insertion level.
//! \param [in] theParentId - parent one-based node IDS.
//! \return one-based internal ID of the node.
Standard_EXPORT Standard_Integer addNode(const TDF_Label& theLabel,
const Standard_Integer theParentId);
private:
Handle(XCAFDoc_ShapeTool) myShapeTool; //!< Document shape tool.
TColStd_PackedMapOfInteger myRoots; //!< IDs of the root nodes.
TDF_LabelIndexedMap myNodes; //!< Maps assembly/part entries to graph node IDs.
AdjacencyMap myAdjacencyMap; //!< "Part-of" relations.
NCollection_DataMap<Standard_Integer, NodeType> myNodeTypes; //!< Node types.
NCollection_DataMap<Standard_Integer,
Standard_Integer> myUsages; //!< Occurrences usage.
};
#endif // _KI_XCAFDoc_AssemblyGraph_HeaderFile

View File

@ -66,10 +66,11 @@
#include <Standard_Version.hxx>
#include <TCollection_ExtendedString.hxx>
#include <TDocStd_Document.hxx>
#include <TDocStd_XLinkTool.hxx>
#include <TDataStd_Name.hxx>
#include <TDataStd_TreeNode.hxx>
#include <TDF_LabelSequence.hxx>
#include <TDF_ChildIterator.hxx>
#include <TDF_Tool.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <XCAFApp_Application.hxx>
@ -77,6 +78,12 @@
#include <XCAFDoc_DocumentTool.hxx>
#include <XCAFDoc_ColorTool.hxx>
#include <XCAFDoc_ShapeTool.hxx>
#include <XCAFDoc_Area.hxx>
#include <XCAFDoc_Centroid.hxx>
#include <XCAFDoc_Location.hxx>
#include <XCAFDoc_Volume.hxx>
#include "KI_XCAFDoc_AssemblyGraph.hxx"
#include <BRep_Tool.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
@ -478,6 +485,113 @@ static TopoDS_Shape getOneShape( Handle( XCAFDoc_ShapeTool ) aShapeTool )
}
// Apply scaling to shapes within theLabel.
// Based on XCAFDoc_Editor::RescaleGeometry
static Standard_Boolean rescaleShapes( const TDF_Label& theLabel, const gp_XYZ& aScale )
{
if( theLabel.IsNull() )
{
Message::SendFail( "Null label." );
return Standard_False;
}
if( Abs( aScale.X() ) <= gp::Resolution() || Abs( aScale.Y() ) <= gp::Resolution()
|| Abs( aScale.Z() ) <= gp::Resolution() )
{
Message::SendFail( "Scale factor is too small." );
return Standard_False;
}
Handle( XCAFDoc_ShapeTool ) aShapeTool = XCAFDoc_DocumentTool::ShapeTool( theLabel );
if( aShapeTool.IsNull() )
{
Message::SendFail( "Couldn't find XCAFDoc_ShapeTool attribute." );
return Standard_False;
}
Handle( KI_XCAFDoc_AssemblyGraph ) aG = new KI_XCAFDoc_AssemblyGraph( theLabel );
if( aG.IsNull() )
{
Message::SendFail( "Couldn't create assembly graph." );
return Standard_False;
}
Standard_Boolean anIsDone = Standard_True;
// clang-format off
gp_GTrsf aGTrsf;
aGTrsf.SetVectorialPart( gp_Mat( aScale.X(), 0, 0,
0, aScale.Y(), 0,
0, 0, aScale.Z() ) );
// clang-format on
BRepBuilderAPI_GTransform aBRepTrsf( aGTrsf );
for( Standard_Integer idx = 1; idx <= aG->NbNodes(); idx++ )
{
const KI_XCAFDoc_AssemblyGraph::NodeType aNodeType = aG->GetNodeType( idx );
if( ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Part )
&& ( aNodeType != KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence ) )
{
continue;
}
const TDF_Label& aLabel = aG->GetNode( idx );
if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Part )
{
const TopoDS_Shape aShape = aShapeTool->GetShape( aLabel );
aBRepTrsf.Perform( aShape, Standard_True );
if( !aBRepTrsf.IsDone() )
{
Standard_SStream aSS;
TCollection_AsciiString anEntry;
TDF_Tool::Entry( aLabel, anEntry );
aSS << "Shape " << anEntry << " is not scaled!";
Message::SendFail( aSS.str().c_str() );
anIsDone = Standard_False;
return Standard_False;
}
TopoDS_Shape aScaledShape = aBRepTrsf.Shape();
aShapeTool->SetShape( aLabel, aScaledShape );
// Update sub-shapes
TDF_LabelSequence aSubshapes;
aShapeTool->GetSubShapes( aLabel, aSubshapes );
for( TDF_LabelSequence::Iterator anItSs( aSubshapes ); anItSs.More(); anItSs.Next() )
{
const TDF_Label& aLSs = anItSs.Value();
const TopoDS_Shape aSs = aShapeTool->GetShape( aLSs );
const TopoDS_Shape aSs1 = aBRepTrsf.ModifiedShape( aSs );
aShapeTool->SetShape( aLSs, aSs1 );
}
// These attributes will be recomputed eventually, but clear them just in case
aLabel.ForgetAttribute( XCAFDoc_Area::GetID() );
aLabel.ForgetAttribute( XCAFDoc_Centroid::GetID() );
aLabel.ForgetAttribute( XCAFDoc_Volume::GetID() );
}
else if( aNodeType == KI_XCAFDoc_AssemblyGraph::NodeType_Occurrence )
{
TopLoc_Location aLoc = aShapeTool->GetLocation( aLabel );
gp_Trsf aTrsf = aLoc.Transformation();
aTrsf.SetTranslationPart( aTrsf.TranslationPart().Multiplied( aScale ) );
XCAFDoc_Location::Set( aLabel, aTrsf );
}
}
if( !anIsDone )
{
return Standard_False;
}
aShapeTool->UpdateAssemblies();
return anIsDone;
}
STEP_PCB_MODEL::STEP_PCB_MODEL( const wxString& aPcbName )
{
m_app = XCAFApp_Application::GetApplication();
@ -2510,141 +2624,46 @@ bool STEP_PCB_MODEL::readSTEP( Handle( TDocStd_Document )& doc, const char* fnam
}
TDF_Label STEP_PCB_MODEL::transferModel( Handle( TDocStd_Document )& source,
Handle( TDocStd_Document )& dest, VECTOR3D aScale )
TDF_Label STEP_PCB_MODEL::transferModel( Handle( TDocStd_Document ) & source,
Handle( TDocStd_Document ) & dest, VECTOR3D aScale )
{
// transfer data from Source into a top level component of Dest
gp_GTrsf scale_transform;
scale_transform.SetVectorialPart( gp_Mat( aScale.x, 0, 0,
0, aScale.y, 0,
0, 0, aScale.z ) );
BRepBuilderAPI_GTransform brep( scale_transform );
// s_assy = shape tool for the source
Handle(XCAFDoc_ShapeTool) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
Handle( XCAFDoc_ShapeTool ) s_assy = XCAFDoc_DocumentTool::ShapeTool( source->Main() );
// retrieve all free shapes within the assembly
TDF_LabelSequence frshapes;
s_assy->GetFreeShapes( frshapes );
// d_assy = shape tool for the destination
Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool ( dest->Main() );
Handle( XCAFDoc_ShapeTool ) d_assy = XCAFDoc_DocumentTool::ShapeTool( dest->Main() );
// create a new shape within the destination and set the assembly tool to point to it
TDF_Label component = d_assy->NewShape();
TDF_Label d_targetLabel = d_assy->NewShape();
int nshapes = frshapes.Length();
int id = 1;
Handle( XCAFDoc_ColorTool ) scolor = XCAFDoc_DocumentTool::ColorTool( source->Main() );
Handle( XCAFDoc_ColorTool ) dcolor = XCAFDoc_DocumentTool::ColorTool( dest->Main() );
TopExp_Explorer dtop;
TopExp_Explorer stop;
while( id <= nshapes )
if( frshapes.Size() == 1 )
{
const TDF_Label& s_shapeLabel = frshapes.Value( id );
TopoDS_Shape shape = s_assy->GetShape( s_shapeLabel );
if( !shape.IsNull() )
TDocStd_XLinkTool link;
link.Copy( d_targetLabel, frshapes.First() );
}
else
{
// Rare case
for( TDF_Label& s_shapeLabel : frshapes )
{
Handle( TDataStd_Name ) s_nameAttr;
s_shapeLabel.FindAttribute( TDataStd_Name::GetID(), s_nameAttr );
TDF_Label d_component = d_assy->NewShape();
TCollection_ExtendedString s_labelName =
s_nameAttr ? s_nameAttr->Get() : TCollection_ExtendedString();
TDocStd_XLinkTool link;
link.Copy( d_component, s_shapeLabel );
TopoDS_Shape scaled_shape( shape );
if( aScale.x != 1.0 || aScale.y != 1.0 || aScale.z != 1.0 )
{
brep.Perform( shape, Standard_False );
if( brep.IsDone() )
{
scaled_shape = brep.Shape();
}
else
{
ReportMessage( wxT( " * transfertModel(): failed to scale model\n" ) );
scaled_shape = shape;
}
}
TDF_Label d_shapeLabel = d_assy->AddShape( scaled_shape, Standard_False );
if( s_labelName.Length() > 0 )
TDataStd_Name::Set( d_shapeLabel, s_labelName );
TDF_Label niulab = d_assy->AddComponent( component, d_shapeLabel, TopLoc_Location() );
// check for per-surface colors
stop.Init( shape, TopAbs_FACE );
dtop.Init( d_assy->GetShape( niulab ), TopAbs_FACE );
while( stop.More() && dtop.More() )
{
Quantity_Color face_color;
TDF_Label tl;
// give priority to the base shape's color
if( s_assy->FindShape( stop.Current(), tl ) )
{
if( scolor->GetColor( tl, XCAFDoc_ColorSurf, face_color )
|| scolor->GetColor( tl, XCAFDoc_ColorGen, face_color )
|| scolor->GetColor( tl, XCAFDoc_ColorCurv, face_color ) )
{
dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
}
}
else if( scolor->GetColor( stop.Current(), XCAFDoc_ColorSurf, face_color )
|| scolor->GetColor( stop.Current(), XCAFDoc_ColorGen, face_color )
|| scolor->GetColor( stop.Current(), XCAFDoc_ColorCurv, face_color ) )
{
dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
}
stop.Next();
dtop.Next();
}
// check for per-solid colors
stop.Init( shape, TopAbs_SOLID );
dtop.Init( d_assy->GetShape( niulab ), TopAbs_SOLID, TopAbs_FACE );
while( stop.More() && dtop.More() )
{
Quantity_Color face_color;
TDF_Label tl;
// give priority to the base shape's color
if( s_assy->FindShape( stop.Current(), tl ) )
{
if( scolor->GetColor( tl, XCAFDoc_ColorSurf, face_color )
|| scolor->GetColor( tl, XCAFDoc_ColorGen, face_color )
|| scolor->GetColor( tl, XCAFDoc_ColorCurv, face_color ) )
{
dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorGen );
}
}
else if( scolor->GetColor( stop.Current(), XCAFDoc_ColorSurf, face_color )
|| scolor->GetColor( stop.Current(), XCAFDoc_ColorGen, face_color )
|| scolor->GetColor( stop.Current(), XCAFDoc_ColorCurv, face_color ) )
{
dcolor->SetColor( dtop.Current(), face_color, XCAFDoc_ColorSurf );
}
stop.Next();
dtop.Next();
}
d_assy->AddComponent( d_targetLabel, d_component, TopLoc_Location() );
}
}
++id;
};
if( aScale.x != 1.0 || aScale.y != 1.0 || aScale.z != 1.0 )
rescaleShapes( d_targetLabel, gp_XYZ( aScale.x, aScale.y, aScale.z ) );
return component;
return d_targetLabel;
}