From 714fb6b5161c61af461fb6f804c3257e7c255e26 Mon Sep 17 00:00:00 2001 From: snn Date: Fri, 13 May 2022 12:53:03 +0300 Subject: [PATCH] 0032954: Tool for applying transformation to OCAF document New XCAFDoc classes: - XCAFDoc_AssemblyIterator: iterator in depth along the assembly tree - XCAFDoc_AssemblyGraph: assembly graph with iterator - XCAFDoc_AssemblyTool: provides generic methods for traversing assembly tree and graph A method for re-scaling (sub-)assembly geometry is added to XCAFDoc_Editor. New DRAW commands: - XDumpAssemblyTree: iterates through the assembly tree in depth up to the specified level, if any - XDumpAssemblyGraph: prints assembly graph structure - XDumpNomenclature: prints number of (sub-)assembly/part instances - XRescaleGeometry: applies geometrical scale to (sub-)assembly --- src/XCAFDoc/FILES | 5 + src/XCAFDoc/XCAFDoc_AssemblyGraph.cxx | 270 ++++++++++++ src/XCAFDoc/XCAFDoc_AssemblyGraph.hxx | 220 ++++++++++ src/XCAFDoc/XCAFDoc_AssemblyIterator.cxx | 193 +++++++++ src/XCAFDoc/XCAFDoc_AssemblyIterator.hxx | 72 ++++ src/XCAFDoc/XCAFDoc_AssemblyTool.hxx | 97 +++++ src/XCAFDoc/XCAFDoc_Editor.cxx | 524 ++++++++++++++++++++++- src/XCAFDoc/XCAFDoc_Editor.hxx | 18 +- src/XDEDRAW/XDEDRAW.cxx | 373 ++++++++++++++++ tests/xcaf/end | 86 +++- tests/xcaf/grids.list | 4 +- tests/xcaf/rescale/A1 | 11 + tests/xcaf/rescale/A2 | 11 + tests/xcaf/rescale/B1 | 11 + tests/xcaf/rescale/C1 | 11 + tests/xcaf/traverse/A1 | 73 ++++ tests/xcaf/traverse/A2 | 22 + tests/xcaf/traverse/A3 | 35 ++ tests/xcaf/traverse/B1 | 192 +++++++++ 19 files changed, 2222 insertions(+), 6 deletions(-) create mode 100644 src/XCAFDoc/XCAFDoc_AssemblyGraph.cxx create mode 100644 src/XCAFDoc/XCAFDoc_AssemblyGraph.hxx create mode 100644 src/XCAFDoc/XCAFDoc_AssemblyIterator.cxx create mode 100644 src/XCAFDoc/XCAFDoc_AssemblyIterator.hxx create mode 100644 src/XCAFDoc/XCAFDoc_AssemblyTool.hxx create mode 100644 tests/xcaf/rescale/A1 create mode 100644 tests/xcaf/rescale/A2 create mode 100644 tests/xcaf/rescale/B1 create mode 100644 tests/xcaf/rescale/C1 create mode 100644 tests/xcaf/traverse/A1 create mode 100644 tests/xcaf/traverse/A2 create mode 100644 tests/xcaf/traverse/A3 create mode 100644 tests/xcaf/traverse/B1 diff --git a/src/XCAFDoc/FILES b/src/XCAFDoc/FILES index f2af5883ac..2398d99643 100755 --- a/src/XCAFDoc/FILES +++ b/src/XCAFDoc/FILES @@ -6,6 +6,11 @@ XCAFDoc_AssemblyItemId.cxx XCAFDoc_AssemblyItemId.hxx XCAFDoc_AssemblyItemRef.cxx XCAFDoc_AssemblyItemRef.hxx +XCAFDoc_AssemblyIterator.hxx +XCAFDoc_AssemblyIterator.cxx +XCAFDoc_AssemblyGraph.hxx +XCAFDoc_AssemblyGraph.cxx +XCAFDoc_AssemblyTool.hxx XCAFDoc_PartId.hxx XCAFDoc_Area.cxx XCAFDoc_Area.hxx diff --git a/src/XCAFDoc/XCAFDoc_AssemblyGraph.cxx b/src/XCAFDoc/XCAFDoc_AssemblyGraph.cxx new file mode 100644 index 0000000000..b344faec96 --- /dev/null +++ b/src/XCAFDoc/XCAFDoc_AssemblyGraph.cxx @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ======================================================================= +// function : XCAFDoc_AssemblyGraph constructor +// purpose : Builds an assembly graph from the OCAF document +// ======================================================================= + +XCAFDoc_AssemblyGraph::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 : XCAFDoc_AssemblyGraph constructor +// purpose : Builds an assembly graph from the OCAF label +// ======================================================================= + +XCAFDoc_AssemblyGraph::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 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 +// ======================================================================= + +XCAFDoc_AssemblyGraph::NodeType +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 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 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 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 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 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. +// ======================================================================= + +XCAFDoc_AssemblyGraph::Iterator::Iterator(const Handle(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; +} diff --git a/src/XCAFDoc/XCAFDoc_AssemblyGraph.hxx b/src/XCAFDoc/XCAFDoc_AssemblyGraph.hxx new file mode 100644 index 0000000000..96638b1f46 --- /dev/null +++ b/src/XCAFDoc/XCAFDoc_AssemblyGraph.hxx @@ -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 _XCAFDoc_AssemblyGraph_HeaderFile +#define _XCAFDoc_AssemblyGraph_HeaderFile + +#include +#include +#include +#include +#include +#include +#include + +class TDF_Label; +class TDocStd_Document; +class XCAFDoc_ShapeTool; + +class XCAFDoc_AssemblyGraph; +DEFINE_STANDARD_HANDLE(XCAFDoc_AssemblyGraph, Standard_Transient) + +// Assembly graph. +class 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 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(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(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 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 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 myNodeTypes; //!< Node types. + NCollection_DataMap myUsages; //!< Occurrences usage. + +}; + +#endif // _XCAFDoc_AssemblyGraph_HeaderFile diff --git a/src/XCAFDoc/XCAFDoc_AssemblyIterator.cxx b/src/XCAFDoc/XCAFDoc_AssemblyIterator.cxx new file mode 100644 index 0000000000..83a319df4e --- /dev/null +++ b/src/XCAFDoc/XCAFDoc_AssemblyIterator.cxx @@ -0,0 +1,193 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ======================================================================= +// function : XCAFDoc_AssemblyIterator constructor +// purpose : Starts from free shapes +// ======================================================================= + +XCAFDoc_AssemblyIterator::XCAFDoc_AssemblyIterator(const Handle(TDocStd_Document)& theDoc, + const Standard_Integer theLevel) + : myMaxLevel(theLevel) + , mySeedLevel(1) +{ + Standard_NullObject_Raise_if(theDoc.IsNull(), "Null document!"); + + myShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDoc->Main()); + Standard_NoSuchObject_Raise_if(myShapeTool.IsNull(), "No XCAFDoc_ShapeTool attribute!"); + + Standard_RangeError_Raise_if(myMaxLevel < 0, "Null document!"); + + TDF_LabelSequence aRoots; + myShapeTool->GetFreeShapes(aRoots); + + AuxAssemblyItem anAuxItem; + TColStd_ListOfAsciiString aParentPath; + for (TDF_LabelSequence::Iterator anIt(aRoots); anIt.More(); anIt.Next()) + { + createItem(anIt.Value(), aParentPath, anAuxItem); + myFringe.Append(anAuxItem); + } +} + +// ======================================================================= +// function : XCAFDoc_AssemblyIterator constructor +// purpose : Starts from the specified root +// ======================================================================= + +XCAFDoc_AssemblyIterator::XCAFDoc_AssemblyIterator(const Handle(TDocStd_Document)& theDoc, + const XCAFDoc_AssemblyItemId& theRoot, + const Standard_Integer theLevel) + : myMaxLevel(theLevel) + , mySeedLevel(theRoot.GetPath().Size()) +{ + Standard_NullObject_Raise_if(theDoc.IsNull(), "Null document!"); + + myShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDoc->Main()); + Standard_NoSuchObject_Raise_if(myShapeTool.IsNull(), "No XCAFDoc_ShapeTool attribute!"); + + Standard_NullObject_Raise_if(theRoot.IsNull(), "Null assembly item!"); + + Standard_RangeError_Raise_if(myMaxLevel < 0, "Null document!"); + + AuxAssemblyItem aSeed; + aSeed.myItem = theRoot; + TDF_Tool::Label(theDoc->GetData(), theRoot.GetPath().Last(), aSeed.myLabel); + + if (aSeed.myLabel.IsNull()) + return; + + TDF_Label anOriginal; + if (myShapeTool->GetReferredShape(aSeed.myLabel, anOriginal)) + { + if (!myShapeTool->IsAssembly(aSeed.myLabel)) + { + aSeed.myLabel = anOriginal; + } + else + { + TCollection_AsciiString aPathStr = theRoot.ToString(); + Standard_Integer anIndex = aPathStr.SearchFromEnd("/"); + if (anIndex != -1) + { + aPathStr.Remove(anIndex, aPathStr.Length() - anIndex + 1); + } + aSeed.myItem.Init(aPathStr); + } + } + + myFringe.Append(aSeed); +} + +// ======================================================================= +// function : More +// purpose : Checks possibility to continue iteration +// ======================================================================= + +Standard_Boolean XCAFDoc_AssemblyIterator::More() const +{ + return !myFringe.IsEmpty(); +} + +// ======================================================================= +// function : Next +// purpose : Moves to the next position +// ======================================================================= + +void XCAFDoc_AssemblyIterator::Next() +{ + if (!More()) + return; // No next item. + + // Pop item + AuxAssemblyItem aCurrent = myFringe.Last(); + myFringe.Remove(myFringe.Size()); + + // Check current depth of iteration (root level is 0-level by convention) + const int aCurrentDepth = aCurrent.myItem.GetPath().Size() - mySeedLevel; + + if (aCurrentDepth < myMaxLevel) + { + // If current item is an assembly, then the next items to iterate in + // depth-first order are the components of this assembly + TDF_LabelSequence aComponents; + if (myShapeTool->IsAssembly(aCurrent.myLabel)) + { + myShapeTool->GetComponents(aCurrent.myLabel, aComponents); + } + else if (myShapeTool->IsComponent(aCurrent.myLabel)) + { + aComponents.Append(aCurrent.myLabel); + } + + // Put all labels pending for iteration to the fringe + AuxAssemblyItem anAuxItem; + for (Standard_Integer l = aComponents.Length(); l >= 1; --l) + { + TDF_Label aLabel = aComponents(l); // Insertion-level label + createItem(aLabel, aCurrent.myItem.GetPath(), anAuxItem); + + // Set item to iterate + myFringe.Append(anAuxItem); + } + } +} + +// ======================================================================= +// function : Current +// purpose : Returns current assembly item +// ======================================================================= + +XCAFDoc_AssemblyItemId XCAFDoc_AssemblyIterator::Current() const +{ + return myFringe.Last().myItem; +} + +// ======================================================================= +// function : createItem +// purpose : Makes an assembly item id from the specified label +// ======================================================================= + +void XCAFDoc_AssemblyIterator::createItem(const TDF_Label& theLabel, + const TColStd_ListOfAsciiString& theParentPath, + AuxAssemblyItem& theAuxItem) const +{ + TCollection_AsciiString anEntry; + TDF_Tool::Entry(theLabel, anEntry); + + TDF_Label anOriginal; + if (myShapeTool->GetReferredShape(theLabel, anOriginal)) + { + theAuxItem.myLabel = anOriginal; + } + else + { + theAuxItem.myLabel = theLabel; + } + + TColStd_ListOfAsciiString aPath = theParentPath; + aPath.Append(anEntry); + theAuxItem.myItem.Init(aPath); +} diff --git a/src/XCAFDoc/XCAFDoc_AssemblyIterator.hxx b/src/XCAFDoc/XCAFDoc_AssemblyIterator.hxx new file mode 100644 index 0000000000..f2c5e2b1bd --- /dev/null +++ b/src/XCAFDoc/XCAFDoc_AssemblyIterator.hxx @@ -0,0 +1,72 @@ +// 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 _XCAFDoc_AssemblyIterator_HeaderFile +#define _XCAFDoc_AssemblyIterator_HeaderFile + +#include +#include + +class TDF_Label; +class TDocStd_Document; +class XCAFDoc_ShapeTool; + +//! Iterator in depth along the assembly tree. +class XCAFDoc_AssemblyIterator +{ +public: + + //! Constructs iterator starting from assembly roots. + //! \param [in] theDoc - document to iterate. + //! \param [in, opt] theLevel - max level of hierarchy to reach (INT_MAX is for no limit). + Standard_EXPORT XCAFDoc_AssemblyIterator(const Handle(TDocStd_Document)& theDoc, + const Standard_Integer theLevel = INT_MAX); + + //! Constructs iterator starting from the specified position in the assembly tree. + //! \param [in] theDoc - document to iterate. + //! \param [in] theRoot - assembly item to start iterating from. + //! \param [in, opt] theLevel - max level of hierarchy to reach (INT_MAX is for no limit). + Standard_EXPORT XCAFDoc_AssemblyIterator(const Handle(TDocStd_Document)& theDoc, + const XCAFDoc_AssemblyItemId& theRoot, + const Standard_Integer theLevel = INT_MAX); + + //! \return true if there is still something to iterate, false -- otherwise. + Standard_EXPORT Standard_Boolean More() const; + + //! Moves depth-first iterator to the next position. + Standard_EXPORT void Next(); + + //! \return current item. + Standard_EXPORT XCAFDoc_AssemblyItemId Current() const; + +private: + + struct AuxAssemblyItem + { + TDF_Label myLabel; + XCAFDoc_AssemblyItemId myItem; + }; + + void createItem(const TDF_Label& theLabel, const TColStd_ListOfAsciiString& theParentPath, + AuxAssemblyItem& theAuxItem) const; + +private: + + Handle(XCAFDoc_ShapeTool) myShapeTool; //!< Document shape tool. + NCollection_Sequence myFringe; //!< Items pending for iteration. + Standard_Integer myMaxLevel; //!< Limit on max depth of iteration. + Standard_Integer mySeedLevel; //!< Level of hierarchy where we start. +}; + +#endif // _XCAFDoc_AssemblyIterator_HeaderFile diff --git a/src/XCAFDoc/XCAFDoc_AssemblyTool.hxx b/src/XCAFDoc/XCAFDoc_AssemblyTool.hxx new file mode 100644 index 0000000000..a7891ed1a8 --- /dev/null +++ b/src/XCAFDoc/XCAFDoc_AssemblyTool.hxx @@ -0,0 +1,97 @@ +// 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 _XCAFDoc_AssemblyTool_HeaderFile +#define _XCAFDoc_AssemblyTool_HeaderFile + +#include +#include +#include +#include +#include + +class TDocStd_Document; +class XCAFDoc_ShapeTool; + +//! Provides generic methods for traversing assembly tree and graph +class XCAFDoc_AssemblyTool +{ +public: + + //! \brief Generic method for traversing assembly tree. + //! Performs in-depth traversing of the assembly tree and calls + //! user defined function for each assembly tree node. + //! User function takes single argument of XCAFDoc_AssemblyItemId type + //! and returns true/false to continue/break. + //! ~~~~~{.cpp} + //! Standard_Boolean Print(const XCAFDoc_AssemblyItemId& theItem) + //! { + //! std::cout << theItem.ToString() << std::endl; + //! return Standard_True; + //! } + //! ~~~~~ + //! \param [in] theIterator - starting position in the assembly tree. + //! \param [in] theFunc - user function called for each assembly tree node. + template + static void Traverse(XCAFDoc_AssemblyIterator theIterator, + Func theFunc) + { + for (; theIterator.More(); theIterator.Next()) + { + if (!theFunc(theIterator.Current())) + break; + } + } + + //! \brief Generic method for traversing assembly graph. + //! Performs in-depth traversing of the assembly graph beginning from root nodes + //! and calls user defined function for each assembly graph node accepted + //! by the user defined filtering function. Filtering function takes + //! the assembly graph passed for traversing, current graph node ID + //! and returns true/false to accept/reject node. + //! ~~~~~{.cpp} + //! Standard_Boolean AcceptPartOnly(const Handle(XCAFDoc_AssemblyGraph)& theGraph, + //! const Standard_Integer theNode) + //! { + //! return (theGraph->GetNodeType(theNode) == XCAFDoc_AssemblyGraph::NodeType_Part); + //! } + //! ~~~~~ + //! User function theFunc takes the assembly graph passed for traversing, current + //! graph node ID and returns true/false to continue/break. + //! \param [in] theGraph - assembly graph. + //! \param [in] theFilter - user filtering function called for each assembly graph node. + //! \param [in] theFunc - user function called for accepted assembly graph node. + //! \param [in] theNode - starting positive one-based graph node ID. + template + static void Traverse(const Handle(XCAFDoc_AssemblyGraph)& theGraph, + Filter theFilter, + Func theFunc, + const Standard_Integer theNode = 1) + { + Standard_NullObject_Raise_if(theGraph.IsNull(), "Null assembly graph!"); + + for (XCAFDoc_AssemblyGraph::Iterator anIt(theGraph, theNode); anIt.More(); anIt.Next()) + { + const Standard_Integer aN = anIt.Current(); + if (theFilter(theGraph, aN)) + { + if (!theFunc(theGraph, aN)) + break; + } + } + } + +}; + +#endif // _XCAFDoc_AssemblyTool_HeaderFile diff --git a/src/XCAFDoc/XCAFDoc_Editor.cxx b/src/XCAFDoc/XCAFDoc_Editor.cxx index 11cff3dc44..944351b7ae 100644 --- a/src/XCAFDoc/XCAFDoc_Editor.cxx +++ b/src/XCAFDoc/XCAFDoc_Editor.cxx @@ -16,25 +16,44 @@ #include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include #include #include #include #include #include +#include +#include +#include +#include #include #include #include #include +#include #include #include #include #include #include +#include +#include #include #include -#include //======================================================================= //function : Expand @@ -475,3 +494,506 @@ void XCAFDoc_Editor::CloneMetaData(const TDF_Label& theSrcLabel, } } } + +//======================================================================= +//function : rescaleDimensionRefLabels +//purpose : Applies geometrical scale to dimension's reference shapes +// not belonging to the assembly graph +//======================================================================= + +static void rescaleDimensionRefLabels(const TDF_LabelSequence& theRefLabels, + BRepBuilderAPI_Transform& theBRepTrsf, + const Handle(XCAFDoc_AssemblyGraph)& theGraph, + const TCollection_AsciiString& theEntryDimension) +{ + for (TDF_LabelSequence::Iterator anIt(theRefLabels); anIt.More(); anIt.Next()) + { + const TDF_Label& aL = anIt.Value(); + if (!theGraph->GetNodes().Contains(aL)) + { + Handle(TNaming_NamedShape) aNS; + if (aL.FindAttribute(TNaming_NamedShape::GetID(), aNS)) + { + TopoDS_Shape aShape = aNS->Get(); + theBRepTrsf.Perform(aShape, Standard_True); + if (!theBRepTrsf.IsDone()) + { + Standard_SStream aSS; + aSS << "Dimmension PMI " << theEntryDimension << " is not scaled."; + Message::SendWarning(aSS.str().c_str()); + } + else + { + TopoDS_Shape aScaledShape = theBRepTrsf.Shape(); + TNaming_Builder aBuilder(aL); + aBuilder.Generated(aShape, aScaledShape); + } + } + } + } +} + +//======================================================================= +//function : shouldRescaleAndCheckRefLabels +//purpose : Checks if all PMI reference shapes belong to the assembly +// graph. Returns true if at least one reference shape belongs +// to the assembly graph. +//======================================================================= + +static Standard_Boolean shouldRescaleAndCheckRefLabels( + const Handle(TDF_Data)& theData, + const TDF_LabelSequence& theRefLabels, + const Handle(XCAFDoc_AssemblyGraph)& theGraph, + Standard_Boolean& theAllInG) +{ + theAllInG = Standard_True; + Standard_Boolean aShouldRescale = Standard_False; + for (TDF_LabelSequence::Iterator anIt1(theRefLabels); anIt1.More(); anIt1.Next()) + { + const TDF_Label& aL = anIt1.Value(); + if (theGraph->GetNodes().Contains(aL)) + { + aShouldRescale = Standard_True; + } + else + { + Handle(XCAFDoc_AssemblyItemRef) anItemRefAttr; + if (!aL.FindAttribute(XCAFDoc_AssemblyItemRef::GetID(), anItemRefAttr)) + { + theAllInG = Standard_False; + continue; + } + const XCAFDoc_AssemblyItemId& anItemId = anItemRefAttr->GetItem(); + if (anItemId.IsNull()) + { + theAllInG = Standard_False; + continue; + } + TDF_Label aLRef; + TDF_Tool::Label(theData, anItemId.GetPath().Last(), aLRef, Standard_False); + if (aLRef.IsNull() || !theGraph->GetNodes().Contains(aLRef)) + { + theAllInG = Standard_False; + continue; + } + aShouldRescale = Standard_True; + } + } + return aShouldRescale; +} + +//======================================================================= +//function : RescaleGeometry +//purpose : Applies geometrical scale to all assembly parts, component +// locations and related attributes +//======================================================================= + +Standard_Boolean XCAFDoc_Editor::RescaleGeometry(const TDF_Label& theLabel, + const Standard_Real theScaleFactor, + const Standard_Boolean theForceIfNotRoot) +{ + if (theLabel.IsNull()) + { + Message::SendFail("Null label."); + return Standard_False; + } + + if (Abs(theScaleFactor) <= 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; + } + + if (!theForceIfNotRoot && aShapeTool->Label() != theLabel) + { + TDF_LabelSequence aFreeLabels; + aShapeTool->GetFreeShapes(aFreeLabels); + Standard_Boolean aFound = Standard_False; + for (TDF_LabelSequence::Iterator anIt(aFreeLabels); anIt.More(); anIt.Next()) + { + if (theLabel == anIt.Value()) + { + aFound = Standard_True; + break; + } + } + if (!aFound) + { + TCollection_AsciiString anEntry; + TDF_Tool::Entry(theLabel, anEntry); + Standard_SStream aSS; + aSS << "Label " << anEntry << " is not a root. Set ForceIfNotRoot true to rescale forcibly."; + Message::SendFail(aSS.str().c_str()); + return Standard_False; + } + } + + Handle(XCAFDoc_AssemblyGraph) aG = new XCAFDoc_AssemblyGraph(theLabel); + if (aG.IsNull()) + { + Message::SendFail("Couldn't create assembly graph."); + return Standard_False; + } + + Standard_Boolean anIsDone = Standard_True; + + gp_Trsf aTrsf; aTrsf.SetScaleFactor(theScaleFactor); + BRepBuilderAPI_Transform aBRepTrsf(aTrsf); + + XCAFDoc_AssemblyTool::Traverse(aG, + [](const Handle(XCAFDoc_AssemblyGraph)& theGraph, + const Standard_Integer theNode) -> Standard_Boolean + { + const XCAFDoc_AssemblyGraph::NodeType aNodeType = theGraph->GetNodeType(theNode); + return (aNodeType == XCAFDoc_AssemblyGraph::NodeType_Part) || + (aNodeType == XCAFDoc_AssemblyGraph::NodeType_Occurrence); + }, + [&](const Handle(XCAFDoc_AssemblyGraph)& theGraph, + const Standard_Integer theNode) -> Standard_Boolean + { + const TDF_Label& aLabel = theGraph->GetNode(theNode); + const XCAFDoc_AssemblyGraph::NodeType aNodeType = theGraph->GetNodeType(theNode); + + if (aNodeType == 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); + } + + Handle(XCAFDoc_Area) aArea; + if (aLabel.FindAttribute(XCAFDoc_Area::GetID(), aArea)) + { + aArea->Set(aArea->Get() * theScaleFactor * theScaleFactor); + } + + Handle(XCAFDoc_Centroid) aCentroid; + if (aLabel.FindAttribute(XCAFDoc_Centroid::GetID(), aCentroid)) + { + aCentroid->Set(aCentroid->Get().XYZ() * theScaleFactor); + } + + Handle(XCAFDoc_Volume) aVolume; + if (aLabel.FindAttribute(XCAFDoc_Volume::GetID(), aVolume)) + { + aVolume->Set(aVolume->Get() * theScaleFactor * theScaleFactor * theScaleFactor); + } + } + else if (aNodeType == XCAFDoc_AssemblyGraph::NodeType_Occurrence) + { + TopLoc_Location aLoc = aShapeTool->GetLocation(aLabel); + gp_Trsf aTrsf = aLoc.Transformation(); + aTrsf.SetTranslationPart(aTrsf.TranslationPart() * theScaleFactor); + XCAFDoc_Location::Set(aLabel, aTrsf); + } + + return Standard_True; + } + ); + + if (!anIsDone) + { + return Standard_False; + } + + aShapeTool->UpdateAssemblies(); + + Handle(XCAFDoc_DimTolTool) aDimTolTool = XCAFDoc_DocumentTool::DimTolTool(theLabel); + if (!aDimTolTool.IsNull()) + { + TDF_LabelSequence aDimensions; + aDimTolTool->GetDimensionLabels(aDimensions); + for (TDF_LabelSequence::Iterator anItD(aDimensions); anItD.More(); anItD.Next()) + { + const TDF_Label& aDimension = anItD.Value(); + + TCollection_AsciiString anEntryDimension; + TDF_Tool::Entry(aDimension, anEntryDimension); + + Handle(XCAFDoc_Dimension) aDimAttr; + if (aDimension.FindAttribute(XCAFDoc_Dimension::GetID(), aDimAttr)) + { + Standard_Boolean aShouldRescale = Standard_False; + Standard_Boolean aFirstLInG = Standard_True; + Standard_Boolean aSecondLInG = Standard_True; + TDF_LabelSequence aShapeLFirst, aShapeLSecond; + Standard_Boolean aHasShapeRefs = aDimTolTool->GetRefShapeLabel(aDimension, aShapeLFirst, aShapeLSecond); + if (aHasShapeRefs) + { + aShouldRescale = shouldRescaleAndCheckRefLabels(theLabel.Data(), aShapeLFirst, aG, aFirstLInG) || + shouldRescaleAndCheckRefLabels(theLabel.Data(), aShapeLSecond, aG, aSecondLInG); + } + + if (!aShouldRescale) + { + Standard_SStream aSS; + aSS << "Dimension PMI " << anEntryDimension << " is not scaled!"; + Message::SendWarning(aSS.str().c_str()); + continue; + } + + Handle(XCAFDimTolObjects_DimensionObject) aDimObj = aDimAttr->GetObject(); + + if (aDimObj->HasTextPoint()) + { + aDimObj->SetPointTextAttach(aDimObj->GetPointTextAttach().XYZ() * theScaleFactor); + } + + if (aDimObj->HasPoint()) + { + aDimObj->SetPoint(aDimObj->GetPoint().XYZ() * theScaleFactor); + } + + if (aDimObj->HasPoint2()) + { + aDimObj->SetPoint2(aDimObj->GetPoint2().XYZ() * theScaleFactor); + } + + if (aDimObj->HasPlane()) + { + gp_Ax2 aPln = aDimObj->GetPlane(); + aPln.SetLocation(aPln.Location().XYZ() * theScaleFactor); + aDimObj->SetPlane(aPln); + } + + Handle(TColStd_HArray1OfReal) aValues = aDimObj->GetValues(); + if (!aValues.IsNull()) + { + if (!aFirstLInG || !aSecondLInG) + { + Standard_SStream aSS; + aSS << "Dimension PMI " << anEntryDimension << " base shapes do not belong to the rescaled assembly!"; + Message::SendWarning(aSS.str().c_str()); + continue; + } + Standard_Boolean aRescaleOtherValues = Standard_False; + TColStd_Array1OfReal& anArray = aValues->ChangeArray1(); + switch (aDimObj->GetType()) + { + case XCAFDimTolObjects_DimensionType_Location_None: + case XCAFDimTolObjects_DimensionType_Location_CurvedDistance: + { + Standard_SStream aSS; + aSS << "Dimension PMI " << anEntryDimension << " is not scaled."; + Message::SendWarning(aSS.str().c_str()); + } + break; + case XCAFDimTolObjects_DimensionType_Location_LinearDistance: + case XCAFDimTolObjects_DimensionType_Location_LinearDistance_FromCenterToOuter: + case XCAFDimTolObjects_DimensionType_Location_LinearDistance_FromCenterToInner: + case XCAFDimTolObjects_DimensionType_Location_LinearDistance_FromOuterToCenter: + case XCAFDimTolObjects_DimensionType_Location_LinearDistance_FromOuterToOuter: + case XCAFDimTolObjects_DimensionType_Location_LinearDistance_FromOuterToInner: + case XCAFDimTolObjects_DimensionType_Location_LinearDistance_FromInnerToCenter: + case XCAFDimTolObjects_DimensionType_Location_LinearDistance_FromInnerToOuter: + case XCAFDimTolObjects_DimensionType_Location_LinearDistance_FromInnerToInner: + anArray.ChangeFirst() *= theScaleFactor; + aRescaleOtherValues = Standard_True; + break; + case XCAFDimTolObjects_DimensionType_Location_Angular: + case XCAFDimTolObjects_DimensionType_Size_Angular: + break; + case XCAFDimTolObjects_DimensionType_Location_Oriented: + case XCAFDimTolObjects_DimensionType_Location_WithPath: + { + Standard_SStream aSS; + aSS << "Dimension PMI " << anEntryDimension << " is not scaled."; + Message::SendWarning(aSS.str().c_str()); + } + break; + case XCAFDimTolObjects_DimensionType_Size_CurveLength: + case XCAFDimTolObjects_DimensionType_Size_Diameter: + case XCAFDimTolObjects_DimensionType_Size_SphericalDiameter: + case XCAFDimTolObjects_DimensionType_Size_Radius: + case XCAFDimTolObjects_DimensionType_Size_SphericalRadius: + case XCAFDimTolObjects_DimensionType_Size_ToroidalMinorDiameter: + case XCAFDimTolObjects_DimensionType_Size_ToroidalMajorDiameter: + case XCAFDimTolObjects_DimensionType_Size_ToroidalMinorRadius: + case XCAFDimTolObjects_DimensionType_Size_ToroidalMajorRadius: + case XCAFDimTolObjects_DimensionType_Size_ToroidalHighMajorDiameter: + case XCAFDimTolObjects_DimensionType_Size_ToroidalLowMajorDiameter: + case XCAFDimTolObjects_DimensionType_Size_ToroidalHighMajorRadius: + case XCAFDimTolObjects_DimensionType_Size_ToroidalLowMajorRadius: + case XCAFDimTolObjects_DimensionType_Size_Thickness: + case XCAFDimTolObjects_DimensionType_Size_WithPath: + anArray.ChangeFirst() *= theScaleFactor; + aRescaleOtherValues = Standard_True; + break; + case XCAFDimTolObjects_DimensionType_CommonLabel: + case XCAFDimTolObjects_DimensionType_DimensionPresentation: + { + Standard_SStream aSS; + aSS << "Dimension PMI " << anEntryDimension << " is not scaled."; + Message::SendWarning(aSS.str().c_str()); + } + break; + default: + { + Standard_SStream aSS; + aSS << "Dimension PMI of unsupported type " << anEntryDimension << " is not scaled."; + Message::SendWarning(aSS.str().c_str()); + } + } + rescaleDimensionRefLabels(aShapeLFirst, aBRepTrsf, aG, anEntryDimension); + rescaleDimensionRefLabels(aShapeLSecond, aBRepTrsf, aG, anEntryDimension); + if (aRescaleOtherValues) + { + for (Standard_Integer i = anArray.Lower() + 1; i <= anArray.Upper(); ++i) + anArray.ChangeValue(i) *= theScaleFactor; + + Handle(TCollection_HAsciiString) aName = aDimObj->GetSemanticName(); + if (!aName.IsNull()) + { + aName->AssignCat(" (Rescaled to "); + Standard_SStream aSS; aSS << aValues->First(); + aName->AssignCat(aSS.str().c_str()); + aName->AssignCat(")"); + } + } + } + else + { + Standard_SStream aSS; + aSS << "Dimension PMI values " << anEntryDimension << " are not scaled."; + Message::SendWarning(aSS.str().c_str()); + } + + aDimAttr->SetObject(aDimObj); + } + } + + TDF_LabelSequence aDatums; + aDimTolTool->GetDatumLabels(aDatums); + for (TDF_LabelSequence::Iterator anIt(aDatums); anIt.More(); anIt.Next()) + { + const TDF_Label& aDatum = anIt.Value(); + + TCollection_AsciiString anEntryDatum; + TDF_Tool::Entry(aDatum, anEntryDatum); + + Handle(XCAFDoc_Datum) aDatumAttr; + if (aDatum.FindAttribute(XCAFDoc_Datum::GetID(), aDatumAttr)) + { + Handle(XCAFDimTolObjects_DatumObject) aDatumObj = aDatumAttr->GetObject(); + + if (aDatumObj->HasDatumTargetParams()) + { + gp_Ax2 anAxis = aDatumObj->GetDatumTargetAxis(); + anAxis.SetLocation(anAxis.Location().XYZ() * theScaleFactor); + aDatumObj->SetDatumTargetAxis(anAxis); + // TODO: Should we rescale target length and width? + Standard_SStream aSS; + aSS << "Datum PMI target length and width " << anEntryDatum << " are not scaled."; + Message::SendWarning(aSS.str().c_str()); + //aDatumObj->SetDatumTargetLength(aDatumObj->GetDatumTargetLength() * theScaleFactor); + //aDatumObj->SetDatumTargetWidth(aDatumObj->GetDatumTargetWidth() * theScaleFactor); + } + + if (aDatumObj->HasPointText()) + { + aDatumObj->SetPointTextAttach(aDatumObj->GetPointTextAttach().XYZ() * theScaleFactor); + } + + if (aDatumObj->HasPoint()) + { + aDatumObj->SetPoint(aDatumObj->GetPoint().XYZ() * theScaleFactor); + } + + if (aDatumObj->HasPlane()) + { + gp_Ax2 aPln = aDatumObj->GetPlane(); + aPln.SetLocation(aPln.Location().XYZ() * theScaleFactor); + aDatumObj->SetPlane(aPln); + } + + aDatumAttr->SetObject(aDatumObj); + } + } + + TDF_LabelSequence aDimTols; + aDimTolTool->GetDimTolLabels(aDimTols); + for (TDF_LabelSequence::Iterator anIt(aDimTols); anIt.More(); anIt.Next()) + { + const TDF_Label& aDimTol = anIt.Value(); + + TCollection_AsciiString anEntryDimTol; + TDF_Tool::Entry(aDimTol, anEntryDimTol); + + Handle(XCAFDoc_DimTol) aDimTolAttr; + if (aDimTol.FindAttribute(XCAFDoc_DimTol::GetID(), aDimTolAttr)) + { + Standard_SStream aSS; + aSS << "DimTol PMI " << anEntryDimTol << " is not scaled."; + Message::SendWarning(aSS.str().c_str()); + } + } + } + + Handle(XCAFDoc_NotesTool) aNotesTool = XCAFDoc_DocumentTool::NotesTool(theLabel); + if (!aNotesTool.IsNull()) + { + TDF_LabelSequence aNotes; + aNotesTool->GetNotes(aNotes); + for (TDF_LabelSequence::Iterator anIt(aNotes); anIt.More(); anIt.Next()) + { + const TDF_Label& aNote = anIt.Value(); + + Handle(XCAFDoc_Note) aNoteAttr; + if (aNote.FindAttribute(XCAFDoc_NoteComment::GetID(), aNoteAttr) || + aNote.FindAttribute(XCAFDoc_NoteBalloon::GetID(), aNoteAttr) || + aNote.FindAttribute(XCAFDoc_NoteBinData::GetID(), aNoteAttr)) + { + Handle(XCAFNoteObjects_NoteObject) aNoteObj = aNoteAttr->GetObject(); + + if (aNoteObj->HasPointText()) + { + aNoteObj->SetPointText(aNoteObj->GetPointText().XYZ() * theScaleFactor); + } + + if (aNoteObj->HasPoint()) + { + aNoteObj->SetPoint(aNoteObj->GetPoint().XYZ() * theScaleFactor); + } + + if (aNoteObj->HasPlane()) + { + gp_Ax2 aPln = aNoteObj->GetPlane(); + aPln.SetLocation(aPln.Location().XYZ() * theScaleFactor); + aNoteObj->SetPlane(aPln); + } + + aNoteAttr->SetObject(aNoteObj); + } + } + } + + return anIsDone; +} diff --git a/src/XCAFDoc/XCAFDoc_Editor.hxx b/src/XCAFDoc/XCAFDoc_Editor.hxx index 89ac8ac7cf..dffc46bd16 100644 --- a/src/XCAFDoc/XCAFDoc_Editor.hxx +++ b/src/XCAFDoc/XCAFDoc_Editor.hxx @@ -44,7 +44,6 @@ public: //! Converts all compounds shapes in the document to assembly //! @param[in] theDoc input document - //! @param[in] theShape input shape label //! @param[in] theRecursively recursively expand a compound subshape //! @return True if shape successfully expanded Standard_EXPORT static Standard_Boolean Expand(const TDF_Label& theDoc, @@ -98,6 +97,23 @@ public: const Standard_Boolean theToCopyVisMaterial = Standard_True, const Standard_Boolean theToCopyAttributes = Standard_True); + //! Applies geometrical scaling to the following assembly components: + //! - part geometry + //! - sub-assembly/part occurrence location + //! - part's centroid, area and volume attributes + //! - PMIs (warnings and errors are reported if it is impossible to make changes) + //! Normally, should start from a root sub-assembly, but if theForceIfNotRoot true + //! scaling will be applied forcibly. If theLabel corresponds to the shape tool + //! scaling is applied to the whole assembly. + //! @param[in] theLabel starting label + //! @param[in] theScaleFactor scale factor, should be positive + //! @param[in] theForceIfNotRoot allows scaling of a non root assembly if true, + //! otherwise - returns false + //! @return true in case of success, otherwise - false. + Standard_EXPORT static Standard_Boolean RescaleGeometry(const TDF_Label& theLabel, + const Standard_Real theScaleFactor, + const Standard_Boolean theForceIfNotRoot = Standard_False); + }; #endif // _XCAFDoc_Editor_HeaderFile diff --git a/src/XDEDRAW/XDEDRAW.cxx b/src/XDEDRAW/XDEDRAW.cxx index 083ed649d4..dd69cab6f8 100644 --- a/src/XDEDRAW/XDEDRAW.cxx +++ b/src/XDEDRAW/XDEDRAW.cxx @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +71,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -76,6 +81,7 @@ #include #include #include +#include #include #include #include @@ -1299,6 +1305,360 @@ static Standard_Integer XShowFaceBoundary (Draw_Interpretor& di, return 0; } +//======================================================================= +//function : XAssemblyTreeDump +//purpose : Prints assembly tree structure up to the specified level +//======================================================================= + +static Standard_Integer XDumpAssemblyTree(Draw_Interpretor& di, + Standard_Integer argc, + const char ** argv) +{ + if (argc < 2) + { + di << "Usage :\n " << argv[0] << " Doc [-root label] [-level l] [-names]\n" + << " Doc - document name. \n" + << " -root label - starting root label. \n" + << " -level l - depth level (infinite by default). \n" + << " -names - prints names instead of entries. \n"; + + return 1; + } + + // get specified document + Handle(TDocStd_Document) aDoc; + DDocStd::GetDocument(argv[1], aDoc); + if (aDoc.IsNull()) + { + di << argv[1] << " is not a document\n"; + return 1; + } + + XCAFDoc_AssemblyItemId aRoot; + Standard_Integer aLevel = INT_MAX; + Standard_Boolean aPrintNames = Standard_False; + for (Standard_Integer iarg = 2; iarg < argc; ++iarg) + { + if (strcmp(argv[iarg], "-root") == 0) + { + Standard_ProgramError_Raise_if(iarg + 1 >= argc, "Root is expected!"); + aRoot.Init(argv[++iarg]); + } + else if (strcmp(argv[iarg], "-level") == 0) + { + Standard_ProgramError_Raise_if(iarg + 1 >= argc, "Level is expected!"); + TCollection_AsciiString anArg = argv[++iarg]; + Standard_ProgramError_Raise_if(!anArg.IsIntegerValue(), "Integer value is expected!"); + aLevel = anArg.IntegerValue(); + } + else if (strcmp(argv[iarg], "-names") == 0) + { + aPrintNames = Standard_True; + } + } + + Standard_SStream aSS; + + XCAFDoc_AssemblyIterator anIt = aRoot.IsNull() ? XCAFDoc_AssemblyIterator(aDoc, aLevel) + : XCAFDoc_AssemblyIterator(aDoc, aRoot, aLevel); + XCAFDoc_AssemblyTool::Traverse(anIt, [&](const XCAFDoc_AssemblyItemId& theItem) -> Standard_Boolean + { + if (aPrintNames) + { + Standard_Boolean aFirst = Standard_True; + for (TColStd_ListOfAsciiString::Iterator anIt(theItem.GetPath()); anIt.More(); + anIt.Next(), aFirst = Standard_False) + { + if (!aFirst) aSS << "/"; + TDF_Label aL; + TDF_Tool::Label(aDoc->GetData(), anIt.Value(), aL, Standard_False); + if (!aL.IsNull()) + { + TCollection_ExtendedString aName; + Handle(TDataStd_Name) aNameAttr; + if (aL.FindAttribute(TDataStd_Name::GetID(), aNameAttr)) + { + aName = aNameAttr->Get(); + aSS << aName; + continue; + } + } + aSS << anIt.Value(); + } + aSS << std::endl; + } + else + { + aSS << theItem.ToString() << std::endl; + } + return Standard_True; + }); + + di << aSS.str().c_str(); + return 0; +} + +//======================================================================= +//function : graphNodeTypename +//purpose : Returns node type name +//======================================================================= + +static +const char* graphNodeTypename(const XCAFDoc_AssemblyGraph::NodeType theNodeType) +{ + switch (theNodeType) + { + case XCAFDoc_AssemblyGraph::NodeType_AssemblyRoot: return "R"; + case XCAFDoc_AssemblyGraph::NodeType_Subassembly: return "A"; + case XCAFDoc_AssemblyGraph::NodeType_Occurrence: return "O"; + case XCAFDoc_AssemblyGraph::NodeType_Part: return "P"; + case XCAFDoc_AssemblyGraph::NodeType_Subshape: return "S"; + default: return "?"; + } +} + +//======================================================================= +//function : XAssemblyGraphDump +//purpose : Prints assembly graph structure +//======================================================================= + +static Standard_Integer XDumpAssemblyGraph(Draw_Interpretor& di, + Standard_Integer argc, + const char ** argv) +{ + if (argc < 2) + { + di << "Usage :\n " << argv[0] << " Doc [-root label] [-verbose] \n" + << " Doc - is the document name. \n" + << " -root label - is the optional starting label. \n" + << " -names - prints names instead of entries. \n"; + + return 1; + } + + // get specified document + Handle(TDocStd_Document) aDoc; + DDocStd::GetDocument(argv[1], aDoc); + if (aDoc.IsNull()) + { + di << argv[1] << " is not a document\n"; + return 1; + } + + Standard_Boolean aPrintNames = Standard_False; + TDF_Label aLabel = XCAFDoc_DocumentTool::ShapesLabel(aDoc->Main()); + for (Standard_Integer iarg = 2; iarg < argc; ++iarg) + { + if (strcmp(argv[iarg], "-root") == 0) + { + Standard_ProgramError_Raise_if(iarg + 1 >= argc, "Root is expected!"); + TDF_Tool::Label(aDoc->GetData(), argv[++iarg], aLabel, Standard_False); + } + else if (strcmp(argv[iarg], "-names") == 0) + { + aPrintNames = Standard_True; + } + } + + Handle(XCAFDoc_AssemblyGraph) aG = new XCAFDoc_AssemblyGraph(aLabel); + + Standard_SStream aSS; + + XCAFDoc_AssemblyTool::Traverse(aG, + [](const Handle(XCAFDoc_AssemblyGraph)& /*theGraph*/, + const Standard_Integer /*theNode*/) -> Standard_Boolean + { + return Standard_True; + }, + [&](const Handle(XCAFDoc_AssemblyGraph)& theGraph, + const Standard_Integer theNode) -> Standard_Boolean + { + const TDF_Label& aLabel = theGraph->GetNode(theNode); + + const XCAFDoc_AssemblyGraph::NodeType aNodeType = theGraph->GetNodeType(theNode); + + TCollection_AsciiString aNodeEntry; + if (aPrintNames) + { + Handle(TDataStd_Name) aNameAttr; + if (aLabel.FindAttribute(TDataStd_Name::GetID(), aNameAttr)) + { + aNodeEntry.AssignCat("'"); + aNodeEntry.AssignCat(aNameAttr->Get()); + aNodeEntry.AssignCat("'"); + } + } + if (aNodeEntry.IsEmpty()) + { + TDF_Tool::Entry(aLabel, aNodeEntry); + } + + aSS << theNode << " " << graphNodeTypename(aNodeType) << " " << aNodeEntry; + const XCAFDoc_AssemblyGraph::AdjacencyMap& anAdjacencyMap = theGraph->GetLinks(); + const TColStd_PackedMapOfInteger* aLinksPtr = anAdjacencyMap.Seek(theNode); + if (aLinksPtr != NULL) + { + for (TColStd_MapIteratorOfPackedMapOfInteger anIt1(*aLinksPtr); anIt1.More(); anIt1.Next()) + { + aSS << " " << anIt1.Key(); + } + } + aSS << std::endl; + + return Standard_True; + } + ); + + di << aSS.str().c_str(); + return 0; +} + +//======================================================================= +//function : XDumpNomenclature +//purpose : Prints number of assembly instances +//======================================================================= + +static Standard_Integer XDumpNomenclature(Draw_Interpretor& di, + Standard_Integer argc, + const char ** argv) +{ + if (argc < 2) + { + di << "Usage :\n " << argv[0] << " Doc [-names] \n" + << " Doc - is the document name. \n" + << " -names - prints names instead of entries. \n"; + + return 1; + } + + // get specified document + Handle(TDocStd_Document) aDoc; + DDocStd::GetDocument(argv[1], aDoc); + if (aDoc.IsNull()) + { + di << argv[1] << " is not a document\n"; + return 1; + } + + Standard_Boolean aPrintNames = Standard_False; + for (Standard_Integer iarg = 2; iarg < argc; ++iarg) + { + if (strcmp(argv[iarg], "-names") == 0) + { + aPrintNames = Standard_True; + } + } + + Handle(XCAFDoc_AssemblyGraph) aG = new XCAFDoc_AssemblyGraph(aDoc); + + Standard_SStream aSS; + + XCAFDoc_AssemblyTool::Traverse(aG, + [](const Handle(XCAFDoc_AssemblyGraph)& theGraph, + const Standard_Integer theNode) -> Standard_Boolean + { + const XCAFDoc_AssemblyGraph::NodeType aNodeType = theGraph->GetNodeType(theNode); + return (aNodeType == XCAFDoc_AssemblyGraph::NodeType_AssemblyRoot) || + (aNodeType == XCAFDoc_AssemblyGraph::NodeType_Subassembly) || + (aNodeType == XCAFDoc_AssemblyGraph::NodeType_Part); + }, + [&](const Handle(XCAFDoc_AssemblyGraph)& theGraph, + const Standard_Integer theNode) -> Standard_Boolean + { + const TDF_Label& aLabel = theGraph->GetNode(theNode); + + const XCAFDoc_AssemblyGraph::NodeType aNodeType = theGraph->GetNodeType(theNode); + + TCollection_AsciiString aNodeEntry; + if (aPrintNames) + { + Handle(TDataStd_Name) aNameAttr; + if (aLabel.FindAttribute(TDataStd_Name::GetID(), aNameAttr)) + { + aNodeEntry.AssignCat("'"); + aNodeEntry.AssignCat(aNameAttr->Get()); + aNodeEntry.AssignCat("'"); + } + } + if (aNodeEntry.IsEmpty()) + { + TDF_Tool::Entry(aLabel, aNodeEntry); + } + + aSS << theNode << " " << graphNodeTypename(aNodeType) << " " << aNodeEntry << " " + << theGraph->NbOccurrences(theNode) << std::endl; + + return Standard_True; + } + ); + + di << aSS.str().c_str(); + + return 0; +} + +//======================================================================= +//function : XRescaleGeometry +//purpose : Applies geometrical scale to all assembly components +//======================================================================= + +static Standard_Integer XRescaleGeometry(Draw_Interpretor& di, + Standard_Integer argc, + const char ** argv) +{ + if (argc < 3) + { + di << "Usage :\n " << argv[0] << " Doc factor [-root label] [-force]\n" + << " Doc - is the document name. \n" + << " factor - is the scale factor. \n" + << " -root label - is the starting label to apply rescaling. \n" + << " -force - forces rescaling even if the starting label\n" + << " is not a root. \n"; + + return 1; + } + + // get specified document + Handle(TDocStd_Document) aDoc; + DDocStd::GetDocument(argv[1], aDoc); + if (aDoc.IsNull()) + { + di << argv[1] << " is not a document\n"; + return 1; + } + + // get scale factor + Standard_Real aScaleFactor = Draw::Atof(argv[2]); + if (aScaleFactor <= 0) + { + di << "Scale factor must be positive\n"; + return 1; + } + + Standard_Boolean aForce = Standard_False; + TDF_Label aLabel = XCAFDoc_DocumentTool::ShapesLabel(aDoc->Main()); + for (Standard_Integer iarg = 3; iarg < argc; ++iarg) + { + if (strcmp(argv[iarg], "-root") == 0) + { + Standard_ProgramError_Raise_if(iarg + 1 >= argc, "Root is expected!"); + TDF_Tool::Label(aDoc->GetData(), argv[++iarg], aLabel, Standard_False); + } + else if (strcmp(argv[iarg], "-force") == 0) + { + aForce = Standard_True; + } + } + + if (!XCAFDoc_Editor::RescaleGeometry(aLabel, aScaleFactor, aForce)) + { + di << "Geometry rescale failed\n"; + return 1; + } + + return 0; +} + //======================================================================= //function : testDoc //purpose : Method to test destruction of document @@ -1456,6 +1816,19 @@ void XDEDRAW::Init(Draw_Interpretor& di) __FILE__, XShowFaceBoundary, g); di.Add ("XTestDoc", "XTestDoc shape", __FILE__, testDoc, g); + di.Add("XDumpAssemblyTree", + "Doc [-root label] [-level l] [-names]: Iterates through the assembly tree in depth up to the specified level, if any", + __FILE__, XDumpAssemblyTree, g); + di.Add("XDumpAssemblyGraph", + "Doc [-root label] [-names]: Prints assembly graph structure", + __FILE__, XDumpAssemblyGraph, g); + di.Add("XDumpNomenclature", + "Doc [-names]: Prints number of assembly instances", + __FILE__, XDumpNomenclature, g); + di.Add("XRescaleGeometry", + "Doc -scale factor [-root label]: Applies geometrical scale to assembly", + __FILE__, XRescaleGeometry, g); + // Specialized commands XDEDRAW_Shapes::InitCommands ( di ); XDEDRAW_Colors::InitCommands ( di ); diff --git a/tests/xcaf/end b/tests/xcaf/end index c3f5dc48e1..7b42e7c65c 100644 --- a/tests/xcaf/end +++ b/tests/xcaf/end @@ -524,6 +524,84 @@ if { [regexp "LAYERS" $CompareDocumentsMode] || [regexp "ALL" $CompareDocumentsM set DocLayerLabels_First [XGetLayerLabels D_First] set DocShapeLabels_First [XGetTopLevelShapes D_First] } +# Traverse assembly tree +if {[regexp "TRAVERSE_ASSEMBLY_TREE" $CompareDocumentsMode]} { + if {[info exists TRAVERSE_ASSEMBLY_TREE_ARGS]} { + set traverse_assembly_tree_result [XDumpAssemblyTree D_First {*}$TRAVERSE_ASSEMBLY_TREE_ARGS] + } else { + set traverse_assembly_tree_result [XDumpAssemblyTree D_First] + } + set traverse_assembly_tree_result [string trim $traverse_assembly_tree_result] + if {$TRAVERSE_ASSEMBLY_TREE_RESULT != $traverse_assembly_tree_result} { + puts "ERROR: Not expected traverse assembly tree result" + } +} +# Traverse assembly graph +if {[regexp "TRAVERSE_ASSEMBLY_GRAPH" $CompareDocumentsMode]} { + if {[info exists TRAVERSE_ASSEMBLY_GRAPH_ARGS]} { + set traverse_assembly_graph_result [XDumpAssemblyGraph D_First {*}$TRAVERSE_ASSEMBLY_GRAPH_ARGS] + } else { + set traverse_assembly_graph_result [XDumpAssemblyGraph D_First] + } + set traverse_assembly_graph_result [string trim $traverse_assembly_graph_result] + if {$TRAVERSE_ASSEMBLY_GRAPH_RESULT != $traverse_assembly_graph_result} { + puts "ERROR: Not expected traverse assembly graph result" + } +} +# Assembly nomenclature +if {[regexp "ASSEMBLY_NOMENCLATURE" $CompareDocumentsMode]} { + set assembly_nomenclature_result [XDumpNomenclature D_First {*}$ASSEMBLY_NOMENCLATURE_ARGS] + set assembly_nomenclature_result [string trim $assembly_nomenclature_result] + if {$ASSEMBLY_NOMENCLATURE_RESULT != $assembly_nomenclature_result} { + puts "ERROR: Not expected assembly nomenclature result" + } +} +# Rescale assembly +if {[regexp "RESCALE_ASSEMBLY" $CompareDocumentsMode]} { + if {[info exists RESCALE_ASSEMBLY_CHECK_BOUNDING] && $RESCALE_ASSEMBLY_CHECK_BOUNDING} { + XGetOneShape S_First D_First + bounding S_First -noTriangulation -save xmin ymin zmin xmax ymax zmax + set xmin_First [format "%.2f" [dval xmin]] + set ymin_First [format "%.2f" [dval ymin]] + set zmin_First [format "%.2f" [dval zmin]] + set xmax_First [format "%.2f" [dval xmax]] + set ymax_First [format "%.2f" [dval ymax]] + set zmax_First [format "%.2f" [dval zmax]] + set dx_First [expr $xmax_First - $xmin_First] + set dy_First [expr $ymax_First - $ymin_First] + set dz_First [expr $zmax_First - $zmin_First] + } + if {[info exists RESCALE_ASSEMBLY_ARGS]} { + XRescaleGeometry D_First $RESCALE_ASSEMBLY_FACTOR {*}$RESCALE_ASSEMBLY_ARGS + } else { + XRescaleGeometry D_First $RESCALE_ASSEMBLY_FACTOR + } + if {[info exists RESCALE_ASSEMBLY_CHECK_BOUNDING] && $RESCALE_ASSEMBLY_CHECK_BOUNDING} { + XGetOneShape S_Second D_First + bounding S_Second -noTriangulation -save xmin ymin zmin xmax ymax zmax + set xmin_Second [format "%.2f" [dval xmin]] + set ymin_Second [format "%.2f" [dval ymin]] + set zmin_Second [format "%.2f" [dval zmin]] + set xmax_Second [format "%.2f" [dval xmax]] + set ymax_Second [format "%.2f" [dval ymax]] + set zmax_Second [format "%.2f" [dval zmax]] + set dx_Second [expr $xmax_Second - $xmin_Second] + set dy_Second [expr $ymax_Second - $ymin_Second] + set dz_Second [expr $zmax_Second - $zmin_Second] + set dx_Scale [expr $dx_Second / $dx_First] + set dy_Scale [expr $dy_Second / $dy_First] + set dz_Scale [expr $dz_Second / $dz_First] + if { $dx_Scale != $RESCALE_ASSEMBLY_FACTOR } { + puts [format "Error : Compared X scale %f differs from %f specified one" $dx_Scale $RESCALE_ASSEMBLY_FACTOR] + } + if { $dy_Scale != $RESCALE_ASSEMBLY_FACTOR } { + puts [format "Error : Compared Y scale %f differs from %f specified one" $dy_Scale $RESCALE_ASSEMBLY_FACTOR] + } + if { $dz_Scale != $RESCALE_ASSEMBLY_FACTOR } { + puts [format "Error : Compared Z scale %f differs from %f specified one" $dz_Scale $RESCALE_ASSEMBLY_FACTOR] + } + } +} ################## WRITING FILE ##################" ###Open temporary file if { [string compare ${TypeOfFile} ""] == 0 } { @@ -917,9 +995,11 @@ if { [regexp "LAYERS" $CompareDocumentsMode] || [regexp "ALL" $CompareDocumentsM } } -XGetOneShape result D_Second -if {[isdraw result]} { - checkview -display result -2d -path ${imagedir}/${test_image}.png +if {![regexp "SKIP_CHECKVIEW" $CompareDocumentsMode]} { + XGetOneShape result D_Second + if {[isdraw result]} { + checkview -display result -2d -path ${imagedir}/${test_image}.png + } } if {[expr $ErrorCode == 2]} { diff --git a/tests/xcaf/grids.list b/tests/xcaf/grids.list index e0cefc8d22..b1b5ef2bc1 100644 --- a/tests/xcaf/grids.list +++ b/tests/xcaf/grids.list @@ -9,4 +9,6 @@ 009 brep_to_stp_add_CL 010 brep_to_xbf 011 add_ACL_brep -012 brep_add_CL \ No newline at end of file +012 brep_add_CL +013 traverse +014 rescale \ No newline at end of file diff --git a/tests/xcaf/rescale/A1 b/tests/xcaf/rescale/A1 new file mode 100644 index 0000000000..5632196c3e --- /dev/null +++ b/tests/xcaf/rescale/A1 @@ -0,0 +1,11 @@ + +ReadStep D_First [locate_data_file "as1-oc-214-mat.stp"] + +set RESCALE_ASSEMBLY_FACTOR 0.5 +set RESCALE_ASSEMBLY_CHECK_BOUNDING 1 + +set TypeOfFile "" + +set AddToDocument "" + +set CompareDocumentsMode "RESCALE_ASSEMBLY" diff --git a/tests/xcaf/rescale/A2 b/tests/xcaf/rescale/A2 new file mode 100644 index 0000000000..6dac6704a2 --- /dev/null +++ b/tests/xcaf/rescale/A2 @@ -0,0 +1,11 @@ + +ReadStep D_First [locate_data_file "as1-oc-214-mat.stp"] + +set RESCALE_ASSEMBLY_FACTOR 0.5 +set RESCALE_ASSEMBLY_ARGS "-root 0:1:1:9 -force" + +set TypeOfFile "" + +set AddToDocument "" + +set CompareDocumentsMode "RESCALE_ASSEMBLY" diff --git a/tests/xcaf/rescale/B1 b/tests/xcaf/rescale/B1 new file mode 100644 index 0000000000..af85e8aab9 --- /dev/null +++ b/tests/xcaf/rescale/B1 @@ -0,0 +1,11 @@ + +ReadStep D_First [locate_data_file "as1_motor.step"] + +set RESCALE_ASSEMBLY_FACTOR 0.001 +set RESCALE_ASSEMBLY_ARGS "-root 0:1:1:1" + +set TypeOfFile "" + +set AddToDocument "" + +set CompareDocumentsMode "RESCALE_ASSEMBLY" diff --git a/tests/xcaf/rescale/C1 b/tests/xcaf/rescale/C1 new file mode 100644 index 0000000000..786fdfb005 --- /dev/null +++ b/tests/xcaf/rescale/C1 @@ -0,0 +1,11 @@ + +XOpen [locate_data_file "as1_pmi.xbf"] D_First + +set RESCALE_ASSEMBLY_FACTOR 0.5 +set RESCALE_ASSEMBLY_CHECK_BOUNDING 1 + +set TypeOfFile "" + +set AddToDocument "" + +set CompareDocumentsMode "RESCALE_ASSEMBLY" diff --git a/tests/xcaf/traverse/A1 b/tests/xcaf/traverse/A1 new file mode 100644 index 0000000000..02bffe8803 --- /dev/null +++ b/tests/xcaf/traverse/A1 @@ -0,0 +1,73 @@ + +ReadStep D_First [locate_data_file "as1-oc-214-mat.stp"] + +set TRAVERSE_ASSEMBLY_TREE_ARGS "-names" +set TRAVERSE_ASSEMBLY_TREE_RESULT "as1 +as1/rod-assembly_1 +as1/rod-assembly_1/nut_1 +as1/rod-assembly_1/nut_2 +as1/rod-assembly_1/rod_1 +as1/l-bracket-assembly_1 +as1/l-bracket-assembly_1/nut-bolt-assembly_1 +as1/l-bracket-assembly_1/nut-bolt-assembly_1/bolt_1 +as1/l-bracket-assembly_1/nut-bolt-assembly_1/nut_3 +as1/l-bracket-assembly_1/nut-bolt-assembly_2 +as1/l-bracket-assembly_1/nut-bolt-assembly_2/bolt_1 +as1/l-bracket-assembly_1/nut-bolt-assembly_2/nut_3 +as1/l-bracket-assembly_1/nut-bolt-assembly_3 +as1/l-bracket-assembly_1/nut-bolt-assembly_3/bolt_1 +as1/l-bracket-assembly_1/nut-bolt-assembly_3/nut_3 +as1/l-bracket-assembly_1/l-bracket_1 +as1/plate_1 +as1/l-bracket-assembly_2 +as1/l-bracket-assembly_2/nut-bolt-assembly_1 +as1/l-bracket-assembly_2/nut-bolt-assembly_1/bolt_1 +as1/l-bracket-assembly_2/nut-bolt-assembly_1/nut_3 +as1/l-bracket-assembly_2/nut-bolt-assembly_2 +as1/l-bracket-assembly_2/nut-bolt-assembly_2/bolt_1 +as1/l-bracket-assembly_2/nut-bolt-assembly_2/nut_3 +as1/l-bracket-assembly_2/nut-bolt-assembly_3 +as1/l-bracket-assembly_2/nut-bolt-assembly_3/bolt_1 +as1/l-bracket-assembly_2/nut-bolt-assembly_3/nut_3 +as1/l-bracket-assembly_2/l-bracket_1" + +set TRAVERSE_ASSEMBLY_GRAPH_ARGS "-names" +set TRAVERSE_ASSEMBLY_GRAPH_RESULT "1 R 'as1' 2 9 20 22 +2 O 'rod-assembly_1' 3 +3 A 'rod-assembly' 4 6 7 +4 O 'nut_1' 5 +5 P 'nut' +6 O 'nut_2' 5 +7 O 'rod_1' 8 +8 P 'rod' +9 O 'l-bracket-assembly_1' 10 +10 A 'l-bracket-assembly' 11 16 17 18 +11 O 'nut-bolt-assembly_1' 12 +12 A 'nut-bolt-assembly' 13 15 +13 O 'bolt_1' 14 +14 P 'bolt' +15 O 'nut_3' 5 +16 O 'nut-bolt-assembly_2' 12 +17 O 'nut-bolt-assembly_3' 12 +18 O 'l-bracket_1' 19 +19 P 'l-bracket' +20 O 'plate_1' 21 +21 P 'plate' +22 O 'l-bracket-assembly_2' 10" + +set ASSEMBLY_NOMENCLATURE_ARGS "-names" +set ASSEMBLY_NOMENCLATURE_RESULT "1 R 'as1' 1 +3 A 'rod-assembly' 1 +5 P 'nut' 8 +8 P 'rod' 1 +10 A 'l-bracket-assembly' 2 +12 A 'nut-bolt-assembly' 6 +14 P 'bolt' 6 +19 P 'l-bracket' 2 +21 P 'plate' 1" + +set TypeOfFile "" + +set AddToDocument "" + +set CompareDocumentsMode "TRAVERSE_ASSEMBLY_TREE TRAVERSE_ASSEMBLY_GRAPH ASSEMBLY_NOMENCLATURE SKIP_CHECKVIEW" diff --git a/tests/xcaf/traverse/A2 b/tests/xcaf/traverse/A2 new file mode 100644 index 0000000000..bb7f7b0cce --- /dev/null +++ b/tests/xcaf/traverse/A2 @@ -0,0 +1,22 @@ + +ReadStep D_First [locate_data_file "as1-oc-214-mat.stp"] + +set TRAVERSE_ASSEMBLY_TREE_ARGS "-root 0:1:1:1/0:1:1:2 -names" +set TRAVERSE_ASSEMBLY_TREE_RESULT "as1/rod-assembly +as1/rod-assembly/nut_1 +as1/rod-assembly/nut_2 +as1/rod-assembly/rod_1" + +set TRAVERSE_ASSEMBLY_GRAPH_ARGS "-root 0:1:1:2 -names" +set TRAVERSE_ASSEMBLY_GRAPH_RESULT "1 A 'rod-assembly' 2 4 5 +2 O 'nut_1' 3 +3 P 'nut' +4 O 'nut_2' 3 +5 O 'rod_1' 6 +6 P 'rod'" + +set TypeOfFile "" + +set AddToDocument "" + +set CompareDocumentsMode "TRAVERSE_ASSEMBLY_TREE TRAVERSE_ASSEMBLY_GRAPH SKIP_CHECKVIEW" diff --git a/tests/xcaf/traverse/A3 b/tests/xcaf/traverse/A3 new file mode 100644 index 0000000000..13025430c3 --- /dev/null +++ b/tests/xcaf/traverse/A3 @@ -0,0 +1,35 @@ + +XOpen [locate_data_file "as1_pmi.xbf"] D_First + +set TRAVERSE_ASSEMBLY_GRAPH_ARGS "-names" +set TRAVERSE_ASSEMBLY_GRAPH_RESULT "1 R 'as1' 2 9 22 25 +2 O 'rod-assembly_1' 3 +3 A 'rod-assembly' 4 6 7 +4 O 'nut_1' 5 +5 P 'nut' +6 O 'nut_2' 5 +7 O 'rod_1' 8 +8 P 'rod' +9 O 'l-bracket-assembly_1' 10 +10 A 'l-bracket-assembly' 11 16 17 18 +11 O 'nut-bolt-assembly_1' 12 +12 A 'nut-bolt-assembly' 13 15 +13 O 'bolt_1' 14 +14 P 'bolt' +15 O 'nut_3' 5 +16 O 'nut-bolt-assembly_2' 12 +17 O 'nut-bolt-assembly_3' 12 +18 O 'l-bracket_1' 19 +19 P 'l-bracket' 20 21 +20 S 0:1:1:8:1 +21 S 0:1:1:8:2 +22 O 'plate_1' 23 +23 P 'plate' 24 +24 S 0:1:1:9:1 +25 O 'l-bracket-assembly_2' 10" + +set TypeOfFile "" + +set AddToDocument "" + +set CompareDocumentsMode "TRAVERSE_ASSEMBLY_GRAPH SKIP_CHECKVIEW" diff --git a/tests/xcaf/traverse/B1 b/tests/xcaf/traverse/B1 new file mode 100644 index 0000000000..3423d87ff2 --- /dev/null +++ b/tests/xcaf/traverse/B1 @@ -0,0 +1,192 @@ + +ReadStep D_First [locate_data_file "as1_motor.step"] + +set TRAVERSE_ASSEMBLY_TREE_ARGS "-names" +set TRAVERSE_ASSEMBLY_TREE_RESULT "Product 2 +Product 2/as1 +Product 2/as1/rod-assembly_1 +Product 2/as1/rod-assembly_1/nut_1 +Product 2/as1/rod-assembly_1/nut_2 +Product 2/as1/rod-assembly_1/rod_1 +Product 2/as1/l-bracket-assembly_1 +Product 2/as1/l-bracket-assembly_1/nut-bolt-assembly_1 +Product 2/as1/l-bracket-assembly_1/nut-bolt-assembly_1/bolt_1 +Product 2/as1/l-bracket-assembly_1/nut-bolt-assembly_1/nut_3 +Product 2/as1/l-bracket-assembly_1/nut-bolt-assembly_2 +Product 2/as1/l-bracket-assembly_1/nut-bolt-assembly_2/bolt_1 +Product 2/as1/l-bracket-assembly_1/nut-bolt-assembly_2/nut_3 +Product 2/as1/l-bracket-assembly_1/nut-bolt-assembly_3 +Product 2/as1/l-bracket-assembly_1/nut-bolt-assembly_3/bolt_1 +Product 2/as1/l-bracket-assembly_1/nut-bolt-assembly_3/nut_3 +Product 2/as1/l-bracket-assembly_1/l-bracket_1 +Product 2/as1/plate_1 +Product 2/as1/l-bracket-assembly_2 +Product 2/as1/l-bracket-assembly_2/nut-bolt-assembly_1 +Product 2/as1/l-bracket-assembly_2/nut-bolt-assembly_1/bolt_1 +Product 2/as1/l-bracket-assembly_2/nut-bolt-assembly_1/nut_3 +Product 2/as1/l-bracket-assembly_2/nut-bolt-assembly_2 +Product 2/as1/l-bracket-assembly_2/nut-bolt-assembly_2/bolt_1 +Product 2/as1/l-bracket-assembly_2/nut-bolt-assembly_2/nut_3 +Product 2/as1/l-bracket-assembly_2/nut-bolt-assembly_3 +Product 2/as1/l-bracket-assembly_2/nut-bolt-assembly_3/bolt_1 +Product 2/as1/l-bracket-assembly_2/nut-bolt-assembly_3/nut_3 +Product 2/as1/l-bracket-assembly_2/l-bracket_1 +Product 1 +Product 1/35 +Product 1/35/Item_0 +Product 1/35/Item_0/Item_0 +Product 1/35/Item_1 +Product 1/35/Item_1/Item_0 +Product 1/35/Item_2 +Product 1/35/Item_2/Item_0 +Product 1/35/Item_3 +Product 1/35/Item_3/Item_0 +Product 1/35/Item_4 +Product 1/35/Item_4/Item_0 +Product 1/35/Item_5 +Product 1/35/Item_5/Item_0 +Product 1/35/Item_6 +Product 1/35/Item_6/Item_0 +Product 1/35/Item_7 +Product 1/35/Item_7/Item_0 +Product 1/35/Item_8 +Product 1/35/Item_8/Item_0 +Product 1/35/Item_9 +Product 1/35/Item_9/Item_0 +Product 1/35/Item_10 +Product 1/35/Item_10/Item_0 +Product 1/35/Item_11 +Product 1/35/Item_11/Item_0 +Product 1/35/Item_12 +Product 1/35/Item_12/Item_0 +Product 1/35/Item_13 +Product 1/35/Item_13/Item_0 +Product 1/35/Item_14 +Product 1/35/Item_14/Item_0 +Product 1/35/Item_15 +Product 1/35/Item_15/Item_0 +Product 1/35/Item_16 +Product 1/35/Item_16/Item_0" + +set TRAVERSE_ASSEMBLY_GRAPH_ARGS "-names" +set TRAVERSE_ASSEMBLY_GRAPH_RESULT "1 R 'Product 1' 2 +2 O '35' 3 +3 A 'Product 1.1' 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 +4 O 'Item_0' 5 +5 A 'Product 1.1.1' 6 +6 O 'Item_0' 7 +7 P 'Product 1.1.1.1' +8 O 'Item_1' 9 +9 A 'Product 1.1.2' 10 +10 O 'Item_0' 11 +11 P 'Product 1.1.2.1' +12 O 'Item_2' 13 +13 A 'Product 1.1.3' 14 +14 O 'Item_0' 15 +15 P 'Product 1.1.3.1' +16 O 'Item_3' 17 +17 A 'Product 1.1.4' 18 +18 O 'Item_0' 19 +19 P 'Product 1.1.4.1' +20 O 'Item_4' 21 +21 A 'Product 1.1.5' 22 +22 O 'Item_0' 23 +23 P 'Product 1.1.5.1' +24 O 'Item_5' 25 +25 A 'Product 1.1.6' 26 +26 O 'Item_0' 27 +27 P 'Product 1.1.6.1' +28 O 'Item_6' 29 +29 A 'Product 1.1.7' 30 +30 O 'Item_0' 31 +31 P 'Product 1.1.7.1' +32 O 'Item_7' 33 +33 A 'Product 1.1.8' 34 +34 O 'Item_0' 35 +35 P 'Product 1.1.8.1' +36 O 'Item_8' 37 +37 A 'Product 1.1.9' 38 +38 O 'Item_0' 39 +39 P 'Product 1.1.9.1' +40 O 'Item_9' 41 +41 A 'Product 1.1.10' 42 +42 O 'Item_0' 43 +43 P 'Product 1.1.10.1' +44 O 'Item_10' 45 +45 A 'Product 1.1.11' 46 +46 O 'Item_0' 47 +47 P 'Product 1.1.11.1' +48 O 'Item_11' 49 +49 A 'Product 1.1.12' 50 +50 O 'Item_0' 51 +51 P 'Product 1.1.12.1' +52 O 'Item_12' 53 +53 A 'Product 1.1.13' 54 +54 O 'Item_0' 55 +55 P 'Product 1.1.13.1' +56 O 'Item_13' 57 +57 A 'Product 1.1.14' 58 +58 O 'Item_0' 59 +59 P 'Product 1.1.14.1' +60 O 'Item_14' 61 +61 A 'Product 1.1.15' 62 +62 O 'Item_0' 63 +63 P 'Product 1.1.15.1' +64 O 'Item_15' 65 +65 A 'Product 1.1.16' 66 +66 O 'Item_0' 67 +67 P 'Product 1.1.16.1' +68 O 'Item_16' 69 +69 A 'Product 1.1.17' 70 +70 O 'Item_0' 71 +71 P 'Product 1.1.17.1' +72 R 'Product 2' 73 +73 O 'as1' 74 +74 A 'Product 2.1' 75 82 99 101 +75 O 'rod-assembly_1' 76 +76 A 'rod-assembly' 77 79 80 +77 O 'nut_1' 78 +78 P 'nut' +79 O 'nut_2' 78 +80 O 'rod_1' 81 +81 P 'rod' +82 O 'l-bracket-assembly_1' 83 +83 A 'l-bracket-assembly' 84 89 93 97 +84 O 'nut-bolt-assembly_1' 85 +85 A 'nut-bolt-assembly' 86 88 +86 O 'bolt_1' 87 +87 P 'bolt' +88 O 'nut_3' 78 +89 O 'nut-bolt-assembly_2' 90 +90 A 'nut-bolt-assembly' 91 92 +91 O 'bolt_1' 87 +92 O 'nut_3' 78 +93 O 'nut-bolt-assembly_3' 94 +94 A 'nut-bolt-assembly' 95 96 +95 O 'bolt_1' 87 +96 O 'nut_3' 78 +97 O 'l-bracket_1' 98 +98 P 'l-bracket' +99 O 'plate_1' 100 +100 P 'plate' +101 O 'l-bracket-assembly_2' 102 +102 A 'l-bracket-assembly' 103 107 111 115 +103 O 'nut-bolt-assembly_1' 104 +104 A 'nut-bolt-assembly' 105 106 +105 O 'bolt_1' 87 +106 O 'nut_3' 78 +107 O 'nut-bolt-assembly_2' 108 +108 A 'nut-bolt-assembly' 109 110 +109 O 'bolt_1' 87 +110 O 'nut_3' 78 +111 O 'nut-bolt-assembly_3' 112 +112 A 'nut-bolt-assembly' 113 114 +113 O 'bolt_1' 87 +114 O 'nut_3' 78 +115 O 'l-bracket_1' 98" + +set TypeOfFile "" + +set AddToDocument "" + +set CompareDocumentsMode "TRAVERSE_ASSEMBLY_TREE TRAVERSE_ASSEMBLY_GRAPH SKIP_CHECKVIEW"