1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-14 13:30:48 +03:00

0029032: Provide XDE interface for exploration of assembly structure

Add assembly graph exploration tool with unit tests.
This commit is contained in:
ssv
2017-08-22 16:27:26 +03:00
parent cba287d62a
commit 51bb1b8d6d
12 changed files with 1145 additions and 0 deletions

View File

@@ -4,6 +4,8 @@ XCAFDoc.cxx
XCAFDoc.hxx
XCAFDoc_Area.cxx
XCAFDoc_Area.hxx
XCAFDoc_AssemblyGraph.cxx
XCAFDoc_AssemblyGraph.hxx
XCAFDoc_Centroid.cxx
XCAFDoc_Centroid.hxx
XCAFDoc_ClippingPlaneTool.cxx
@@ -40,6 +42,7 @@ XCAFDoc_Material.cxx
XCAFDoc_Material.hxx
XCAFDoc_MaterialTool.cxx
XCAFDoc_MaterialTool.hxx
XCAFDoc_ObjectId.hxx
XCAFDoc_ShapeMapTool.cxx
XCAFDoc_ShapeMapTool.hxx
XCAFDoc_ShapeTool.cxx

View File

@@ -0,0 +1,259 @@
// Created on: 2017-08-22
// Created by: Sergey SLYADNEV
// Copyright (c) 2017 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.
// Own include
#include <XCAFDoc_AssemblyGraph.hxx>
// OCCT includes
#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
#include <TDataStd_Name.hxx>
#include <TDataStd_TreeNode.hxx>
#include <TDF_ChildIterator.hxx>
#include <TDF_LabelSequence.hxx>
#include <TDF_Tool.hxx>
#include <XCAFDoc.hxx>
#include <XCAFDoc_DocumentTool.hxx>
#include <XCAFDoc_ShapeTool.hxx>
//-----------------------------------------------------------------------------
#define NodeLetter "N"
#define Whitespace " "
//-----------------------------------------------------------------------------
XCAFDoc_AssemblyGraph::XCAFDoc_AssemblyGraph(const Handle(TDocStd_Document)& M,
const bool withParts)
: Standard_Transient (),
m_model (M),
m_bWithParts (withParts)
{
this->buildGraph();
}
//-----------------------------------------------------------------------------
void XCAFDoc_AssemblyGraph::Dump(Standard_OStream& out) const
{
// Directed graph header
out << "digraph core_AssemblyGraph {\n";
out << "\n";
// Dump nodes with attributes
const NCollection_IndexedMap<XCAFDoc_ObjectId>& nodes = this->GetNodes();
//
for ( int n = 1; n <= nodes.Extent(); ++n )
{
// Get name of persistent object
TCollection_ExtendedString name;
this->getObjectName(nodes(n), name);
// Generate label
TCollection_AsciiString label(name);
label += "\\n"; label += nodes(n);
// Dump node with label
out << Whitespace << NodeLetter << n << " [label=\"" << label.ToCString() << "\"];\n";
}
out << "\n";
// Dump arcs
for ( t_adjacency::Iterator it(m_arcs); it.More(); it.Next() )
{
const int parentId = it.Key();
const TColStd_PackedMapOfInteger& children = it.Value();
// Loop over the children
for ( TColStd_MapIteratorOfPackedMapOfInteger cit(children); cit.More(); cit.Next() )
{
const int childId = cit.Key();
out << Whitespace
<< NodeLetter << parentId
<< " -> "
<< NodeLetter << childId
<< ";\n";
}
}
out << "\n";
out << "}\n";
}
//-----------------------------------------------------------------------------
void XCAFDoc_AssemblyGraph::CalculateSummary(int& numRoots,
int& numSubassemblies,
int& numPartOccurrences,
int& numParts) const
{
numRoots = 0;
numSubassemblies = 0;
numPartOccurrences = 0;
numParts = 0;
// Loop over the nodes
for ( int n = 1; n <= this->GetNodes().Extent(); ++n )
{
if ( !m_nodeTypes.IsBound(n) ) continue; // This should never happen
switch ( m_nodeTypes(n) )
{
case NodeType_Root: ++numRoots; break;
case NodeType_Subassembly: ++numSubassemblies; break;
case NodeType_PartOccurrence: ++numPartOccurrences; break;
case NodeType_Part: ++numParts; break;
default: break;
}
}
}
//-----------------------------------------------------------------------------
void XCAFDoc_AssemblyGraph::buildGraph()
{
// Get shape tool
Handle(XCAFDoc_ShapeTool)
shapeTool = XCAFDoc_DocumentTool::ShapeTool( m_model->Main() );
// We start from those shapes which are "free" in terms of XDE
TDF_LabelSequence roots;
//
shapeTool->GetFreeShapes(roots);
//
for ( TDF_LabelSequence::Iterator it(roots); it.More(); it.Next() )
{
const TDF_Label& label = it.Value();
// Get entry of the current label
XCAFDoc_ObjectId objectId;
TDF_Tool::Entry(label, objectId);
// Free shapes are root nodes of the assembly graph
const int iObjectId = m_nodes.Add(objectId);
// Mark as root
m_nodeTypes.Bind(iObjectId, NodeType_Root);
//
m_roots.Add(iObjectId);
// Add components (the objects nested into the current one)
this->addComponents(label, iObjectId);
}
}
//-----------------------------------------------------------------------------
void XCAFDoc_AssemblyGraph::addComponents(const TDF_Label& parent,
const int iParentId)
{
// Get shape tool
Handle(XCAFDoc_ShapeTool)
shapeTool = XCAFDoc_DocumentTool::ShapeTool( m_model->Main() );
const bool isSubassembly = shapeTool->IsAssembly(parent);
// Bind topological type. We check that no attribute is associated to
// prevent multiple tagging of the same node from different directions
// of traversal.
if ( !m_nodeTypes.IsBound(iParentId) )
{
if ( isSubassembly )
m_nodeTypes.Bind(iParentId, NodeType_Subassembly);
else
{
m_nodeTypes.Bind(iParentId, NodeType_PartOccurrence);
// If parts are requested to participate in the graph, we add more nodes
if ( m_bWithParts )
{
// Get entry of the current label which is the original label
XCAFDoc_ObjectId partId;
TDF_Tool::Entry(parent, partId);
// Add node
const int iPartId = m_nodes.Add(partId);
// Add arc
if ( !m_arcs.IsBound(iParentId) )
m_arcs.Bind( iParentId, TColStd_PackedMapOfInteger() );
//
m_arcs(iParentId).Add(iPartId);
// Bind type
if ( !m_nodeTypes.IsBound(iPartId) )
m_nodeTypes.Bind(iPartId, NodeType_Part);
}
}
}
if ( !isSubassembly )
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 cit(parent); cit.More(); cit.Next() )
{
TDF_Label child = cit.Value();
// Get entry of the current label
XCAFDoc_ObjectId childId;
TDF_Tool::Entry(child, childId);
// Add node
const int iChildId = m_nodes.Add(childId);
// Add arc
if ( !m_arcs.IsBound(iParentId) )
m_arcs.Bind( iParentId, TColStd_PackedMapOfInteger() );
//
m_arcs(iParentId).Add(iChildId);
// Jump to the referred object (the original)
TDF_Label childOriginal;
Handle(TDataStd_TreeNode) jumpTreeNode;
child.FindAttribute(XCAFDoc::ShapeRefGUID(), jumpTreeNode);
//
if ( !jumpTreeNode.IsNull() && jumpTreeNode->HasFather() )
childOriginal = jumpTreeNode->Father()->Label(); // Declaration-level origin
// Process children: add components recursively
if ( !childOriginal.IsNull() )
this->addComponents(childOriginal, iChildId);
}
}
//-----------------------------------------------------------------------------
bool XCAFDoc_AssemblyGraph::getObjectName(const XCAFDoc_ObjectId& id,
TCollection_ExtendedString& name) const
{
// Get label for object ID
TDF_Label label;
TDF_Tool::Label(m_model->GetData(), id, label);
// Access name
Handle(TDataStd_Name) nameAttr;
if ( !label.FindAttribute(TDataStd_Name::GetID(), nameAttr) )
{
name = "";
return false;
}
//
name = nameAttr->Get();
return true;
}

View File

@@ -0,0 +1,292 @@
// Created on: 2017-08-22
// Created by: Sergey SLYADNEV
// Copyright (c) 2017 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 _XCAFDoc_AssemblyGraph_HeaderFile
#define _XCAFDoc_AssemblyGraph_HeaderFile
// XDE includes
#include <XCAFDoc_ObjectId.hxx>
// Other OCCT includes
#include <NCollection_DataMap.hxx>
#include <TColStd_PackedMapOfInteger.hxx>
#include <TDocStd_Document.hxx>
//! \brief Assembly graph.
//!
//! This tool gives clear OCAF-agnostic interface to
//! the assembly structure of a product. A graph is essentially a set of
//! nodes {N} and a set of arcs {A} as defined formally.
//!
//! <pre>
//! G = <N, A>
//! </pre>
//!
//! Using this tool, you can map XDE assembly items to a formal graph
//! structure. Each node in the graph preserves a link to the data storage
//! (OCAF document) by means of \ref XCAFDoc_ObjectId.
//!
//! \sa XCAFDoc_ObjectId
class XCAFDoc_AssemblyGraph : public Standard_Transient
{
public:
//! \brief Type of the graph node.
enum NodeType
{
NodeType_UNDEFINED = 0, //!< Undefined node type.
//
NodeType_Root, //!< Root node (has no entry arcs).
NodeType_Subassembly, //!< Intermediate node (non-leaf node which has entry arcs).
NodeType_PartOccurrence, //!< Part usage occurrence.
NodeType_Part //!< Optional leaf node to represent parts. Note that
//!< this node type is activated by a dedicated flag in
//!< the constructor. If activated, the part occurrence nodes
//!< are not leafs anymore.
};
public:
// OCCT RTTI
DEFINE_STANDARD_RTTI_INLINE(XCAFDoc_AssemblyGraph, Standard_Transient)
public:
//! \brief Graph iterator.
class Iterator
{
public:
//! Default ctor.
Iterator() : m_iCurrentIndex(0) {}
//! ctor accepting the assembly graph to iterate.
//! \param[in] asmGraph assembly graph to iterate.
Iterator(const Handle(XCAFDoc_AssemblyGraph)& asmGraph)
{
this->Init(asmGraph);
}
public:
//! Initializes iterator with assembly graph.
//! \param[in] asmGraph assembly graph to iterate.
void Init(const Handle(XCAFDoc_AssemblyGraph)& asmGraph)
{
m_graph = asmGraph;
m_iCurrentIndex = 1;
}
//! Checks if there are more graph nodes to iterate.
//! \return true/false.
bool More() const
{
return m_iCurrentIndex <= m_graph->GetNodes().Extent();
}
//! \return 1-based ID of the current node.
int GetCurrentNode() const
{
return m_iCurrentIndex;
}
//! Moves iterator to the next position.
void Next()
{
++m_iCurrentIndex;
}
protected:
Handle(XCAFDoc_AssemblyGraph) m_graph; //!< Assembly graph to iterate.
int m_iCurrentIndex; //!< Current 1-based node ID.
};
public:
//! Type definition for graph adjacency matrix. This is how parent-component
//! links are realized in the assembly graph.
typedef NCollection_DataMap<int, TColStd_PackedMapOfInteger> t_adjacency;
public:
//! \brief Initializes graph from Data Model.
//!
//! Construction of a formal graph will be done immediately at ctor.
//!
//! \param[in] M Data Model to iterate.
//! \param[in] withParts indicates whether to add nodes representing the
//! instanced parts to the assembly graph.
Standard_EXPORT
XCAFDoc_AssemblyGraph(const Handle(TDocStd_Document)& M,
const bool withParts = false);
public:
//! \brief Dumps graph structure to output stream.
//!
//! The output format is DOT. You may use graph rendering tools like
//! Graphviz to parse the output.
//!
//! \param[out] out output stream.
Standard_EXPORT void
Dump(Standard_OStream& out) const;
//! \brief Calculates short summary for the assembly.
//!
//! Short summary gives you the total number of nodes of a particular
//! type. Note that the number of parts will be calculated only if parts
//! are available in the graph (which is the option by construction).
//!
//! \param[out] numRoots number of root nodes.
//! \param[out] numSubassemblies number of subassembly nodes.
//! \param[out] numPartOccurrences number of part usage occurrence nodes.
//! \param[out] numParts number of parts (if available).
Standard_EXPORT void
CalculateSummary(int& numRoots,
int& numSubassemblies,
int& numPartOccurrences,
int& numParts) const;
public:
//! \brief Returns IDs of the root nodes.
//! \return IDs of the root nodes.
const TColStd_PackedMapOfInteger& GetRoots() const
{
return m_roots;
}
//! \brief Checks whether the assembly graph contains (n1, n2) directed arc.
//! \param[in] n1 one-based ID of the first node.
//! \param[in] n2 one-based ID of the second node.
//! \return true/false.
bool HasArc(const int n1, const int n2) const
{
if ( !this->HasChildren(n1) )
return false;
return this->GetChildren(n1).Contains(n2);
}
//! \brief Checks whether children exist for the given node.
//! \param[in] oneBasedNodeId one-based node ID.
//! \return true/false.
bool HasChildren(const int oneBasedNodeId) const
{
return m_arcs.IsBound(oneBasedNodeId);
}
//! \brief Returns IDs of child nodes for the given node.
//! \param[in] oneBasedNodeId one-based node ID.
//! \return set of child IDs.
const TColStd_PackedMapOfInteger& GetChildren(const int oneBasedNodeId) const
{
return m_arcs(oneBasedNodeId);
}
//! \brief Returns the node type from \ref NodeType enum.
//! \param[in] oneBasedNodeId one-based node ID.
//! \return node type.
//! \sa NodeType
NodeType GetNodeType(const int oneBasedNodeId) const
{
if ( !m_nodeTypes.IsBound(oneBasedNodeId) )
return NodeType_UNDEFINED;
return m_nodeTypes(oneBasedNodeId);
}
//! \brief returns object ID by node ID.
//! \param[in] oneBasedNodeId one-based node ID.
//! \return persistent ID.
const XCAFDoc_ObjectId& GetPersistentId(const int oneBasedNodeId) const
{
return m_nodes(oneBasedNodeId);
}
//! \brief Returns the unordered set of graph nodes.
//! \return graph nodes.
const NCollection_IndexedMap<XCAFDoc_ObjectId>& GetNodes() const
{
return m_nodes;
}
//! \brief Returns the number of graph nodes.
//! \return number of graph nodes.
int GetNumberOfNodes() const
{
return m_nodes.Extent();
}
//! \brief Returns the collection of graph arcs in form of adjacency matrix.
//! \return graph arcs.
const t_adjacency& GetArcs() const
{
return m_arcs;
}
//! \brief Returns the number of graph arcs.
//! \return number of graph arcs.
int GetNumberOfArcs() const
{
int numArcs = 0;
//
for ( t_adjacency::Iterator it(m_arcs); it.More(); it.Next() )
numArcs += it.Value().Extent();
return numArcs;
}
protected:
//! Builds graph out of OCAF XDE structure.
Standard_EXPORT void
buildGraph();
//! Adds components for the given root to the graph structure.
//! \param[in] parent OCAF label of the parent object.
//! \param[in] iParentId ID of the already registered node
//! representing the parent object in the assembly
//! graph being populated.
Standard_EXPORT void
addComponents(const TDF_Label& parent,
const int iParentId);
//! Returns object name for the given persistent ID.
//! \param[in] id persistent ID.
//! \param[out] name object name.
//! \return false if no name is associated with the object or the object
//! does not exist.
Standard_EXPORT bool
getObjectName(const XCAFDoc_ObjectId& id,
TCollection_ExtendedString& name) const;
protected:
// INPUTS
Handle(TDocStd_Document) m_model; //!< Data Model instance.
bool m_bWithParts; //!< Indicates whether to include parts to the graph.
// OUTPUTS
TColStd_PackedMapOfInteger m_roots; //!< IDs of the root nodes.
NCollection_IndexedMap<XCAFDoc_ObjectId> m_nodes; //!< Graph nodes.
t_adjacency m_arcs; //!< "Part-of" relations.
NCollection_DataMap<int, NodeType> m_nodeTypes; //!< Node types (cached for efficiency).
};
#endif

View File

@@ -0,0 +1,25 @@
// Created on: 2017-08-22
// Created by: Sergey SLYADNEV
// Copyright (c) 2017 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 _XCAFDoc_ObjectId_HeaderFile
#define _XCAFDoc_ObjectId_HeaderFile
// OCCT includes
#include <TCollection_AsciiString.hxx>
//! Persistent object ID.
typedef TCollection_AsciiString XCAFDoc_ObjectId;
#endif

View File

@@ -1,9 +1,13 @@
XDEDRAW.cxx
XDEDRAW.hxx
XDEDRAW_Assemblies.hxx
XDEDRAW_Assemblies.cxx
XDEDRAW_Colors.cxx
XDEDRAW_Colors.hxx
XDEDRAW_Common.cxx
XDEDRAW_Common.hxx
XDEDRAW_DrawableAssemblyGraph.cxx
XDEDRAW_DrawableAssemblyGraph.hxx
XDEDRAW_Layers.cxx
XDEDRAW_Layers.hxx
XDEDRAW_Props.cxx

View File

@@ -80,6 +80,7 @@
#include <XCAFPrs.hxx>
#include <XCAFPrs_Driver.hxx>
#include <XDEDRAW.hxx>
#include <XDEDRAW_Assemblies.hxx>
#include <XDEDRAW_Colors.hxx>
#include <XDEDRAW_Common.hxx>
#include <XDEDRAW_Layers.hxx>
@@ -1165,6 +1166,7 @@ void XDEDRAW::Init(Draw_Interpretor& di)
di.Add ("XTestDoc", "XTestDoc shape", __FILE__, testDoc, g);
// Specialized commands
XDEDRAW_Assemblies::InitCommands ( di );
XDEDRAW_Shapes::InitCommands ( di );
XDEDRAW_Colors::InitCommands ( di );
XDEDRAW_Layers::InitCommands ( di );

View File

@@ -0,0 +1,308 @@
// Created on: 2017-08-22
// Created by: Sergey SLYADNEV
// Copyright (c) 2017 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.
// Own include
#include <XDEDRAW_Assemblies.hxx>
// Other OCCT includes
#include <DDocStd.hxx>
#include <Draw.hxx>
#include <NCollection_Vector.hxx>
#include <XDEDRAW_DrawableAssemblyGraph.hxx>
// Standard includes
#include <vector>
//-----------------------------------------------------------------------------
std::vector< std::pair<TCollection_AsciiString, XCAFDoc_AssemblyGraph::NodeType> >
XAssembly_NodeTypes = {
{"-roots", XCAFDoc_AssemblyGraph::NodeType_Root},
{"-subassemblies", XCAFDoc_AssemblyGraph::NodeType_Subassembly},
{"-partoccurrences", XCAFDoc_AssemblyGraph::NodeType_PartOccurrence},
{"-parts", XCAFDoc_AssemblyGraph::NodeType_Part}
};
//-----------------------------------------------------------------------------
//! Returns true if the passed command line option specifies node type.
//! \param[in] opt option to check.
//! \return true/false.
bool XAssembly_IsKeywordNodeType(const TCollection_AsciiString& opt)
{
for ( size_t s = 0; s < XAssembly_NodeTypes.size(); ++s )
if ( opt == XAssembly_NodeTypes[s].first )
return true;
return false;
}
//-----------------------------------------------------------------------------
//! Checks if the given graph node is of expected type.
//! \param[in] what node to check.
//! \param[in] opt expected type.
//! \param[in] asmGraph assembly graph.
//! \return true/false.
bool XAssembly_IsOfExpectedType(const int n,
const TCollection_AsciiString& opt,
const Handle(XCAFDoc_AssemblyGraph)& asmGraph)
{
const XCAFDoc_AssemblyGraph::NodeType actualType = asmGraph->GetNodeType(n);
// Check against registered types
TCollection_AsciiString expectedOpt;
for ( size_t t = 0; t < XAssembly_NodeTypes.size(); ++t )
{
if ( actualType == XAssembly_NodeTypes[t].second )
{
expectedOpt = XAssembly_NodeTypes[t].first;
break;
}
}
if ( expectedOpt.IsEmpty() )
return false;
return (expectedOpt == opt);
}
//-----------------------------------------------------------------------------
//! Builds assembly graph for the given model.
//! \param[in] di Draw interpreter instance.
//! \param[in] argc number of arguments.
//! \param[in] argv list of arguments.
//! \return execution result.
static int XAssemblyGraph(Draw_Interpretor& di, int argc, const char** argv)
{
// Preliminary checks
if ( argc != 4 )
{
std::cout << "Incorrect number of arguments. Check help for details..." << std::endl;
return 1; // Failure
}
// Get document
Handle(TDocStd_Document) doc;
DDocStd::GetDocument(argv[1], doc);
if ( doc.IsNull() )
{
di << argv[1] << " is not a document\n"; return 1;
}
// Whether to include parts to assembly graph or not
const bool withParts = ( atoi(argv[2]) > 0 );
// Construct assembly graph
Handle(XCAFDoc_AssemblyGraph) asmGraph = new XCAFDoc_AssemblyGraph(doc, withParts);
// Register assembly graph in Draw
Draw::Set( argv[3], new XDEDRAW_DrawableAssemblyGraph(asmGraph) );
return 0; // Success
}
//-----------------------------------------------------------------------------
//! Checks assembly graph.
//! \param[in] di Draw interpreter instance.
//! \param[in] argc number of arguments.
//! \param[in] argv list of arguments.
//! \return execution result.
static int XAssemblyGraphCheck(Draw_Interpretor& di, int argc, const char** argv)
{
// Preliminary checks
if ( argc < 3 )
{
std::cout << "Incorrect number of arguments. Check help for details..." << std::endl;
return 1; // Failure
}
// Get assembly graph
Handle(XDEDRAW_DrawableAssemblyGraph)
DAG = Handle(XDEDRAW_DrawableAssemblyGraph)::DownCast( Draw::Get(argv[1]) );
//
if ( DAG.IsNull() )
{
std::cout << "Error: Drawable Assembly Graph is NULL" << std::endl;
return 1; // Failure
}
//
Handle(XCAFDoc_AssemblyGraph) asmGraph = DAG->GetGraph();
// Get summary
int numRoots = 0;
int numSubassemblies = 0;
int numPartInstances = 0;
int numParts = 0;
//
asmGraph->CalculateSummary(numRoots, numSubassemblies, numPartInstances, numParts);
// Check according to the argument keys
for ( int i = 2; i < argc; ++i )
{
TCollection_AsciiString opt(argv[i]);
opt.LowerCase();
// Check the number of graph nodes
if ( opt == "-numnodes" )
{
const int num = atoi( argv[++i] );
//
if ( num != asmGraph->GetNumberOfNodes() )
{
di << 0; // FALSE
std::cout << "Error: unexpected number of nodes" << std::endl;
return 0;
}
}
// Check the number of graph arcs
else if ( opt == "-numarcs" )
{
const int num = atoi( argv[++i] );
//
if ( num != asmGraph->GetNumberOfArcs() )
{
di << 0; // FALSE
std::cout << "Error: unexpected number of arcs" << std::endl;
return 0;
}
}
// Check the number of roots
else if ( opt == "-numroots" )
{
const int num = atoi( argv[++i] );
//
if ( num != numRoots )
{
di << 0; // FALSE
std::cout << "Error: unexpected number of roots" << std::endl;
return 0;
}
}
// Check the number of subassemblies
else if ( opt == "-numsubassemblies" )
{
const int num = atoi( argv[++i] );
//
if ( num != numSubassemblies )
{
di << 0; // FALSE
std::cout << "Error: unexpected number of subassemblies" << std::endl;
return 0;
}
}
// Check the number of part occurrences
else if ( opt == "-numpartoccurrences" )
{
const int num = atoi( argv[++i] );
//
if ( num != numPartInstances )
{
di << 0; // FALSE
std::cout << "Error: unexpected number of part occurrences" << std::endl;
return 0;
}
}
// Check the number of parts
else if ( opt == "-numparts" )
{
const int num = atoi( argv[++i] );
//
if ( num != numParts )
{
di << 0; // FALSE
std::cout << "Error: unexpected number of parts" << std::endl;
return 0;
}
}
// Check individual arc
else if ( opt == "-arc" )
{
const int n1 = atoi( argv[++i] );
const int n2 = atoi( argv[++i] );
//
if ( !asmGraph->HasArc(n1, n2) )
{
di << 0; // FALSE
std::cout << "Error: arc (" << n1 << ", " << n2 << ") does not exist" << std::endl;
return 0;
}
}
// Check individual node types
else if ( XAssembly_IsKeywordNodeType(opt) )
{
do
{
// Get node index
const int n = atoi( argv[++i] );
// Check type
if ( !XAssembly_IsOfExpectedType(n, opt, asmGraph) )
{
di << 0; // FALSE
std::cout << "Error: unexpected type for node " << n << std::endl;
return 0;
}
}
while ( i < (argc - 1) && !XAssembly_IsKeywordNodeType(argv[i + 1]) );
}
}
di << 1; // TRUE
return 0; // Success
}
//=======================================================================
//function : InitCommands
//purpose :
//=======================================================================
void XDEDRAW_Assemblies::InitCommands(Draw_Interpretor& di)
{
static Standard_Boolean initactor = Standard_False;
if (initactor)
{
return;
}
initactor = Standard_True;
Standard_CString grp = "XDE assembly commands";
di.Add("XAssemblyGraph", "XAssemblyGraph doc withParts graph",
__FILE__, XAssemblyGraph, grp);
di.Add("XAssemblyGraphCheck", "XAssemblyGraphCheck [-numnodes num] "
"[-numarcs num] "
"[-numroots num] "
"[-numsubassemblies num] "
"[-numpartoccurrences num] "
"[-numparts num] "
"[-arc n1 n2] "
"[-arc n2 n3] "
" ... "
"[-roots n1 n2 ...] "
"[-subassemblies n3 n4 ...] "
"[-partoccurrences n5 n6 ...] "
"[-parts n7 n8 ...] ",
__FILE__, XAssemblyGraphCheck, grp);
}

View File

@@ -0,0 +1,32 @@
// Created on: 2017-08-22
// Created by: Sergey SLYADNEV
// Copyright (c) 2017 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 _XDEDRAW_Assemblies_HeaderFile
#define _XDEDRAW_Assemblies_HeaderFile
#include <Draw_Interpretor.hxx>
//! Draw commands for new XDE interface dedicated to assemblies.
class XDEDRAW_Assemblies
{
public:
DEFINE_STANDARD_ALLOC
Standard_EXPORT static void InitCommands(Draw_Interpretor& theCommands);
};
#endif // _XDEDRAW_Assemblies_HeaderFile

View File

@@ -0,0 +1,52 @@
// Created on: 2017-08-22
// Created by: Sergey SLYADNEV
// Copyright (c) 2017 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.
// Own include
#include <XDEDRAW_DrawableAssemblyGraph.hxx>
//-----------------------------------------------------------------------------
XDEDRAW_DrawableAssemblyGraph::XDEDRAW_DrawableAssemblyGraph(const Handle(XCAFDoc_AssemblyGraph)& asmGraph)
: Draw_Drawable3D (),
m_graph (asmGraph)
{}
//-----------------------------------------------------------------------------
inline const Handle(XCAFDoc_AssemblyGraph)& XDEDRAW_DrawableAssemblyGraph::GetGraph() const
{
return m_graph;
}
//-----------------------------------------------------------------------------
void XDEDRAW_DrawableAssemblyGraph::DrawOn(Draw_Display&) const
{
this->Dump(std::cout);
}
//-----------------------------------------------------------------------------
void XDEDRAW_DrawableAssemblyGraph::Dump(Standard_OStream& out) const
{
m_graph->Dump(out);
}
//-----------------------------------------------------------------------------
void XDEDRAW_DrawableAssemblyGraph::Whatis(Draw_Interpretor& di) const
{
di << "Assembly graph";
}

View File

@@ -0,0 +1,63 @@
// Created on: 2017-08-22
// Created by: Sergey SLYADNEV
// Copyright (c) 2017 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 _XDEDRAW_DrawableAssemblyGraph_HeaderFile
#define _XDEDRAW_DrawableAssemblyGraph_HeaderFile
// XDE includes
#include <XCAFDoc_AssemblyGraph.hxx>
// OCCT includes
#include <Draw_Drawable3D.hxx>
//! Drawable container for assembly graph.
class XDEDRAW_DrawableAssemblyGraph : public Draw_Drawable3D
{
public:
// OCCT RTTI
DEFINE_STANDARD_RTTI_INLINE(XDEDRAW_DrawableAssemblyGraph, Draw_Drawable3D)
public:
//! Ctor accepting an assembly graph.
//! \param[in] asmGraph assembly graph to have as drawable.
Standard_EXPORT
XDEDRAW_DrawableAssemblyGraph(const Handle(XCAFDoc_AssemblyGraph)& asmGraph);
public:
//! \return stored assembly graph.
Standard_EXPORT const Handle(XCAFDoc_AssemblyGraph)&
GetGraph() const;
public:
Standard_EXPORT void
DrawOn(Draw_Display& dis) const Standard_OVERRIDE;
Standard_EXPORT virtual void
Dump(Standard_OStream& out) const Standard_OVERRIDE;
Standard_EXPORT virtual void
Whatis(Draw_Interpretor& di) const Standard_OVERRIDE;
private:
Handle(XCAFDoc_AssemblyGraph) m_graph; //!< Assembly graph to "draw".
};
#endif

69
tests/bugs/xde/bug29032_1 Normal file
View File

@@ -0,0 +1,69 @@
puts "============"
puts "CR29032"
puts "============"
puts ""
pload VISUALIZATION
##########################################################################
# Provide XDE interface for exploration of assembly structure
##########################################################################
ReadStep d [locate_data_file trj3_as1-tc-214.stp]
XShow d
vfit
vsetdispmode 1
checkview -screenshot -3d -path ${imagedir}/${::casename}_1.png
# Build assembly graph with parts
if { [XAssemblyGraph d 1 DAG] == 0 } {
puts "Error: cannot build assembly graph"
}
dump DAG
# Check assembly graph
set ret [XAssemblyGraphCheck DAG \
-numnodes 19 \
-numarcs 28 \
-numroots 1 \
-numsubassemblies 6 \
-numpartoccurrences 7 \
-numparts 5 \
-arc 1 2 \
-arc 1 12 \
-arc 1 14 \
-arc 1 15 \
-arc 2 3 \
-arc 2 5 \
-arc 2 10 \
-arc 2 11 \
-arc 3 4 \
-arc 5 6 \
-arc 5 8 \
-arc 6 7 \
-arc 8 9 \
-arc 10 6 \
-arc 10 8 \
-arc 11 6 \
-arc 11 8 \
-arc 12 13 \
-arc 14 3 \
-arc 14 5 \
-arc 14 10 \
-arc 14 11 \
-arc 15 16 \
-arc 15 18 \
-arc 15 19 \
-arc 16 17 \
-arc 18 7 \
-arc 19 7 \
-roots 1 \
-subassemblies 2 5 10 11 14 15 \
-partoccurrences 3 8 6 12 16 18 19 \
-parts 4 7 9 13 17]
if { $ret == 0 } {
puts "Error: unexpected contents of assembly graph"
}

36
tests/bugs/xde/bug29032_2 Normal file
View File

@@ -0,0 +1,36 @@
puts "============"
puts "CR29032"
puts "============"
puts ""
pload VISUALIZATION
##########################################################################
# Provide XDE interface for exploration of assembly structure
##########################################################################
ReadStep d [locate_data_file OCC137-ANC101-Solid.stp]
XShow d
vfit
vsetdispmode 1
checkview -screenshot -3d -path ${imagedir}/${::casename}_1.png
# Build assembly graph with parts
if { [XAssemblyGraph d 1 DAG] == 0 } {
puts "Error: cannot build assembly graph"
}
dump DAG
# Check assembly graph
set ret [XAssemblyGraphCheck DAG \
-numnodes 1 \
-numarcs 0 \
-numroots 1 \
-numsubassemblies 0 \
-roots 1]
if { $ret == 0 } {
puts "Error: unexpected contents of assembly graph"
}